BATCH 3 | Lab 05, Part 2 - x86_64 Server

 LAB 5 - Server x86-64


Hello everyone. In this lab, I will continue my work on the x86-64 server, building on Lab 5, which I previously completed on the aarch64 server. 

STEP 1: To begin, I extracted the archive from our home directory, which resulted in the following directory structure:

Command used: 
  • cd ~
  • tar xvf /public/spo600-assembler-lab-examples.tgz

















STEP 2: I navigated to the ~/spo600/examples/hello/c directory to run the C program and then executed the make command.

Commands used: 
  • cd ~/spo600/examples/hello/c
  • make
Since I was working on this server and no files needed rebuilding, running make produced the output: "make: Nothing to be done for 'all'." Despite this, I still wanted to make sure and deleted files ending in .o. After doing that, I was safe to rebuild and had the following files:



Printed out the object code by using the command below:
  • objdump -d hello

OBJECT CODE:

hello:     file format elf64-x86-64



Disassembly of section .init:


0000000000401000 <_init>:

  401000: f3 0f 1e fa          endbr64

  401004: 48 83 ec 08          sub    $0x8,%rsp

  401008: 48 8b 05 d1 2f 00 00 mov    0x2fd1(%rip),%rax        # 403fe0 <__gmon_start__@Base>

  40100f: 48 85 c0             test   %rax,%rax

  401012: 74 02                je     401016 <_init+0x16>

  401014: ff d0                call   *%rax

  401016: 48 83 c4 08          add    $0x8,%rsp

  40101a: c3                   ret


Disassembly of section .plt:


0000000000401020 <printf@plt-0x10>:

  401020: ff 35 ca 2f 00 00    push   0x2fca(%rip)        # 403ff0 <_GLOBAL_OFFSET_TABLE_+0x8>

  401026: ff 25 cc 2f 00 00    jmp    *0x2fcc(%rip)        # 403ff8 <_GLOBAL_OFFSET_TABLE_+0x10>

  40102c: 0f 1f 40 00          nopl   0x0(%rax)


0000000000401030 <printf@plt>:

  401030: ff 25 ca 2f 00 00    jmp    *0x2fca(%rip)        # 404000 <printf@GLIBC_2.2.5>

  401036: 68 00 00 00 00       push   $0x0

  40103b: e9 e0 ff ff ff       jmp    401020 <_init+0x20>


Disassembly of section .text:


0000000000401040 <_start>:

  401040: f3 0f 1e fa          endbr64

  401044: 31 ed                xor    %ebp,%ebp

  401046: 49 89 d1             mov    %rdx,%r9

  401049: 5e                   pop    %rsi

  40104a: 48 89 e2             mov    %rsp,%rdx

  40104d: 48 83 e4 f0          and    $0xfffffffffffffff0,%rsp

  401051: 50                   push   %rax

  401052: 54                   push   %rsp

  401053: 45 31 c0             xor    %r8d,%r8d

  401056: 31 c9                xor    %ecx,%ecx

  401058: 48 c7 c7 26 11 40 00 mov    $0x401126,%rdi

  40105f: ff 15 73 2f 00 00    call   *0x2f73(%rip)        # 403fd8 <__libc_start_main@GLIBC_2.34>

  401065: f4                   hlt

  401066: 66 2e 0f 1f 84 00 00 cs nopw 0x0(%rax,%rax,1)

  40106d: 00 00 00 


0000000000401070 <_dl_relocate_static_pie>:

  401070: f3 0f 1e fa          endbr64

  401074: c3                   ret

  401075: 66 2e 0f 1f 84 00 00 cs nopw 0x0(%rax,%rax,1)

  40107c: 00 00 00 

  40107f: 90                   nop


0000000000401080 <deregister_tm_clones>:

  401080: b8 10 40 40 00       mov    $0x404010,%eax

  401085: 48 3d 10 40 40 00    cmp    $0x404010,%rax

  40108b: 74 13                je     4010a0 <deregister_tm_clones+0x20>

  40108d: b8 00 00 00 00       mov    $0x0,%eax

  401092: 48 85 c0             test   %rax,%rax

  401095: 74 09                je     4010a0 <deregister_tm_clones+0x20>

  401097: bf 10 40 40 00       mov    $0x404010,%edi

  40109c: ff e0                jmp    *%rax

  40109e: 66 90                xchg   %ax,%ax

  4010a0: c3                   ret

  4010a1: 66 66 2e 0f 1f 84 00 data16 cs nopw 0x0(%rax,%rax,1)

  4010a8: 00 00 00 00 

  4010ac: 0f 1f 40 00          nopl   0x0(%rax)


00000000004010b0 <register_tm_clones>:

  4010b0: be 10 40 40 00       mov    $0x404010,%esi

  4010b5: 48 81 ee 10 40 40 00 sub    $0x404010,%rsi

  4010bc: 48 89 f0             mov    %rsi,%rax

  4010bf: 48 c1 ee 3f          shr    $0x3f,%rsi

  4010c3: 48 c1 f8 03          sar    $0x3,%rax

  4010c7: 48 01 c6             add    %rax,%rsi

  4010ca: 48 d1 fe             sar    $1,%rsi

  4010cd: 74 11                je     4010e0 <register_tm_clones+0x30>

  4010cf: b8 00 00 00 00       mov    $0x0,%eax

  4010d4: 48 85 c0             test   %rax,%rax

  4010d7: 74 07                je     4010e0 <register_tm_clones+0x30>

  4010d9: bf 10 40 40 00       mov    $0x404010,%edi

  4010de: ff e0                jmp    *%rax

  4010e0: c3                   ret

  4010e1: 66 66 2e 0f 1f 84 00 data16 cs nopw 0x0(%rax,%rax,1)

  4010e8: 00 00 00 00 

  4010ec: 0f 1f 40 00          nopl   0x0(%rax)


00000000004010f0 <__do_global_dtors_aux>:

  4010f0: f3 0f 1e fa          endbr64

  4010f4: 80 3d 11 2f 00 00 00 cmpb   $0x0,0x2f11(%rip)        # 40400c <completed.0>

  4010fb: 75 13                jne    401110 <__do_global_dtors_aux+0x20>

  4010fd: 55                   push   %rbp

  4010fe: 48 89 e5             mov    %rsp,%rbp

  401101: e8 7a ff ff ff       call   401080 <deregister_tm_clones>

  401106: c6 05 ff 2e 00 00 01 movb   $0x1,0x2eff(%rip)        # 40400c <completed.0>

  40110d: 5d                   pop    %rbp

  40110e: c3                   ret

  40110f: 90                   nop

  401110: c3                   ret

  401111: 66 66 2e 0f 1f 84 00 data16 cs nopw 0x0(%rax,%rax,1)

  401118: 00 00 00 00 

  40111c: 0f 1f 40 00          nopl   0x0(%rax)


0000000000401120 <frame_dummy>:

  401120: f3 0f 1e fa          endbr64

  401124: eb 8a                jmp    4010b0 <register_tm_clones>


0000000000401126 <main>:

  401126: 55                   push   %rbp

  401127: 48 89 e5             mov    %rsp,%rbp

  40112a: bf 10 20 40 00       mov    $0x402010,%edi

  40112f: b8 00 00 00 00       mov    $0x0,%eax

  401134: e8 f7 fe ff ff       call   401030 <printf@plt>

  401139: b8 00 00 00 00       mov    $0x0,%eax

  40113e: 5d                   pop    %rbp

  40113f: c3                   ret


Disassembly of section .fini:


0000000000401140 <_fini>:

  401140: f3 0f 1e fa          endbr64

  401144: 48 83 ec 08          sub    $0x8,%rsp

  401148: 48 83 c4 08          add    $0x8,%rsp

  40114c: c3                   ret



STEP 4: Now it's time to execute the following hello files down below.

msandrino@x86-001:~/spo600/examples/hello/c$ ls

hello  hello2  hello2.c  hello3  hello3.c  hello.c  hello-opt  hello-static  Makefile


msandrino@x86-001:~/spo600/examples/hello/c$ ./hello

Hello World!

msandrino@x86-001:~/spo600/examples/hello/c$ ./hello2

Hello World!

msandrino@x86-001:~/spo600/examples/hello/c$ ./hello3

Hello World!

msandrino@x86-001:~/spo600/examples/hello/c$ ./hello-opt

Hello World!

msandrino@x86-001:~/spo600/examples/hello/c$ ./hello-static

Hello World!



 As you may have noticed, they all produce the same output, but that does not mean the implementations are exactly identical. 

STEP 5: Down below is a loop code in x86-64 as a reference that is taken from Chris Tyler's Wiki.

 .text
 .globl    _start
 min = 0                         /* starting value for the loop index; **note that this is a symbol (constant)**, not a variable */
 max = 5                        /* loop exits when the index hits this number (loop condition is i<max) */
 _start:
     mov     $min,%r15           /* loop index */
 loop:
     /* ... body of the loop ... do something useful here ... */
     inc     %r15                /* increment the loop index */
     cmp     $max,%r15           /* see if we've hit the max */
     jne     loop                /* if not, then continue the loop */
     
     mov     $0,%rdi             /* set exit status to 0 */
     mov     $60,%rax            /* exit is syscall #60  */
     syscall                     /* invoke syscall */
STEP 6: Modifying message to include the loop index values, showing each digit from 0 to 9:

section .data
    msg     db "Loop: ", 0       
    msg_len equ $ - msg          
    nl      db 10                

section .bss
    digit   resb 1               

section .text
    global _start

_start:
    mov r15, 0                 

.loop:
    ; Write "Loop: "
    mov rax, 1                 
    mov rdi, 1                 
    mov rsi, msg               
    mov rdx, msg_len          
    syscall

    ; Convert loop counter to ASCII digit and store in buffer
    mov rax, r15              
    add rax, 48               
    mov [digit], al            

    ; Write the digit
    mov rax, 1                
    mov rdi, 1                 
    mov rsi, digit            
    mov rdx, 1                
    syscall

    ; Write newline
    mov rax, 1                 
    mov rdi, 1               
    mov rsi, nl               
    mov rdx, 1                
    syscall

    ; Increment loop counter
    inc r15
    cmp r15, 10              
    jl .loop                 

    ; Exit the program
    mov rax, 60              
    xor rdi, rdi             
    syscall

OUTPUT:

msandrino@x86-001:~/spo600/examples/hello/c$ ./loop

Loop: 0

Loop: 1

Loop: 2

Loop: 3

Loop: 4

Loop: 5

Loop: 6

Loop: 7

Loop: 8

Loop: 9


Section Declarations

.data - holds initialized data.

.bss - reserves space for uninitialized data.

.text - holds the executable instructions.

Registers Used

rax - used for the system call number.

rdi, rsi, and rdx - used as arguments for system calls.

r15 - used a loop counter.

sys_write Call

rax = 1 (sys_write)

rdi = file descriptor (1 for stdout)

rsi = memory address of data to write

rdx = number of bytes to write

Converting the Counter to ASCII

Adding 48 to a number 0..9 produces the ASCII codes for 0..9.

Loop Control

Each iteration prints "Loop: ", the index and a newline.

The loop continues until r15 reaches 10 which produces Loop: 0 to Loop: 9

Exiting

The sys_exit system call (number 60) terminates the program with an exit status of 0.


STEP 7: Printing each value as a 2-digit decimal value and suppressing the leading 0 such as printing out 1-9 instead of 01-09. Down below is the updated code:

section .data
    msg     db "Loop: ", 0       
    msg_len equ $ - msg         
    nl      db 10               

section .bss
    digit1  resb 1              
    digit2  resb 1              
section .text
    global _start

_start:
    mov r15, 0                  
.loop:
    ; Print "Loop: "
    mov rax, 1                  
    mov rdi, 1                 
    mov rsi, msg                 
    mov rdx, msg_len            
    syscall

    ; Copy loop counter for conversion
    mov rax, r15
    cmp rax, 10
    jb  .print_single            

    xor rdx, rdx                
    mov rbx, 10                 
    div rbx                     
                              

    add rax, '0'              
    mov [digit1], al           

    ; Save the remainder (ones digit) before syscall clobbers RDX
    push rdx

    ; Write the tens digit
    mov rax, 1                   ; sys_write
    mov rdi, 1                   ; stdout
    mov rsi, digit1              ; pointer to tens digit
    mov rdx, 1                   ; write 1 byte
    syscall

    ; Restore the remainder
    pop rdx

    add rdx, '0'                 ; convert remainder to ASCII
    mov [digit2], dl             ; store ones digit

    ; Write the ones digit
    mov rax, 1                   ; sys_write
    mov rdi, 1                   ; stdout
    mov rsi, digit2              ; pointer to ones digit
    mov rdx, 1                   ; write 1 byte
    syscall

    jmp .after_num

.print_single:
    add rax, '0'                 
    mov [digit1], al            
    mov rax, 1                   
    mov rdi, 1                  
    mov rsi, digit1           
    mov rdx, 1                   
    syscall

.after_num:
    ; Print newline
    mov rax, 1
    mov rdi, 1
    mov rsi, nl
    mov rdx, 1
    syscall

    ; Increment loop counter and loop until R15 equals 33 (0–32)
    inc r15
    cmp r15, 33
    jl .loop

    ; Exit
    mov rax, 60                 
    xor rdi, rdi               
    syscall


OUTPUT:

msandrino@x86-001:~/spo600/examples/hello/c$ ./loopno00

Loop: 0

Loop: 1

Loop: 2

Loop: 3

Loop: 4

Loop: 5

Loop: 6

Loop: 7

Loop: 8

Loop: 9

Loop: 10

Loop: 11

Loop: 12

Loop: 13

Loop: 14

Loop: 15

Loop: 16

Loop: 17

Loop: 18

Loop: 19

Loop: 20

Loop: 21

Loop: 22

Loop: 23

Loop: 24

Loop: 25

Loop: 26

Loop: 27

Loop: 28

Loop: 29

Loop: 30

Loop: 31

Loop: 32



STEP 8: Converting to Hexadecimal. Down below is the code and output:

section .data
    msg     db "Loop: ", 0      
    msg_len equ $ - msg         
    nl      db 10               

section .bss
    digit1  resb 1              
    digit2  resb 1              

section .text
    global _start

_start:
    mov r15, 0                  

.loop:
    ; Print "Loop: "
    mov rax, 1               
    mov rdi, 1               
    mov rsi, msg               
    mov rdx, msg_len            
    syscall

    ; Convert loop counter to hexadecimal.
    mov rax, r15
    cmp rax, 16                
    jb .print_single_hex

    mov rbx, rax               
    shr rbx, 4               
    cmp rbx, 10
    jl .high_is_num            
    add rbx, 55               
    jmp .store_high
.high_is_num:
    add rbx, 48              
.store_high:
    mov [digit1], bl          

    mov rbx, rax
    and rbx, 0xF           
    cmp rbx, 10
    jl .low_is_num
    add rbx, 55              
    jmp .store_low
.low_is_num:
    add rbx, 48          
.store_low:
    mov [digit2], bl         

    ; Write the two hex digits
    mov rax, 1
    mov rdi, 1
    mov rsi, digit1
    mov rdx, 1
    syscall

    mov rax, 1
    mov rdi, 1
    mov rsi, digit2
    mov rdx, 1
    syscall

    jmp .after_hex

.print_single_hex:
    cmp rax, 10
    jl .single_digit_is_num
    add rax, 55               ; for A-F
    jmp .store_single
.single_digit_is_num:
    add rax, 48               ; for 0-9
.store_single:
    mov [digit1], al

    ; Write the single hex digit
    mov rax, 1
    mov rdi, 1
    mov rsi, digit1
    mov rdx, 1
    syscall

.after_hex:
    ; Print newline
    mov rax, 1
    mov rdi, 1
    mov rsi, nl
    mov rdx, 1
    syscall

    ; Increment loop counter and loop until R15 equals 33 (0 to 32)
    inc r15
    cmp r15, 33
    jl .loop

    ; Exit the program
    mov rax, 60           
    xor rdi, rdi             
    syscall

OUTPUT:

msandrino@x86-001:~/spo600/examples/hello/c$ ./loophex

Loop: 0

Loop: 1

Loop: 2

Loop: 3

Loop: 4

Loop: 5

Loop: 6

Loop: 7

Loop: 8

Loop: 9

Loop: A

Loop: B

Loop: C

Loop: D

Loop: E

Loop: F

Loop: 10

Loop: 11

Loop: 12

Loop: 13

Loop: 14

Loop: 15

Loop: 16

Loop: 17

Loop: 18

Loop: 19

Loop: 1A

Loop: 1B

Loop: 1C

Loop: 1D

Loop: 1E

Loop: 1F

Loop: 20



REFLECTION:

Learning assembly language has been a steep learning curve compared to high-level languages. Keeping track of memory access requires deeper understanding of the hardware, making basic concepts like arithmetic and looping much more complex when you are working at the machine level. Moreover, adapting to x86_64 posed additional challenges, much like my experience with aarch64. Despite these obstacles, I appreciate that mastering low-level programming provides invaluable insights and control over every aspect of a program. Looking forward to learning more!

Comments

Popular posts from this blog

BATCH 4 | Clone-Prune Analysis Code Pass On Both Architectures

BATCH 3 | Project Stage 2, Part 3 - Cloned Functions Comparison and Reflection

Lab 01 - Experiments, Calculating Performance and Modifying Code