Lab3 - x86_64
Instruction
In this lab, I explored assembly language programming on both x86_64 and Aarch64 platforms. The objective was to understand the differences in assembly code generation between these architectures and to implement a simple loop in assembly for both platforms.
Connect x86_64 server.
ssh username@x86-001.spo600.cdot.systems // replace username
Unpack example code.
once you connect to the server, unpack the example code with below command.
tar -xzvf spo600-assembler-lab-examples.tgz
Tree of spo600 directory
sshin36@x86-001:~$ tree spo600
spo600
└── examples
└── hello
├── assembler
│ ├── aarch64
│ │ ├── hello.s
│ │ └── Makefile
│ ├── Makefile
│ └── x86_64
│ ├── hello-gas.s
│ ├── hello-nasm.s
│ └── Makefile
└── c
├── hello2.c
├── hello3.c
├── hello.c
└── Makefile
Tasks
Task 1: Reviewing Assembly Language Programs
We used objdump -d
to disassemble the compiled binaries and compared the output to the original source code. This helped us understand how the source code translates into machine instructions for both x86_64 and Aarch64 architectures.
For example, after compiling hello.c
:
gcc -g -O0 -fno-builtin -o hello hello.c
I disassembled the binary:
objdump -d hello > hello_x86_64_disassembly.txt
This generated a detailed disassembly of the binary, which we compared with the source code to study the differences in assembly instructions between x86_64 and Aarch64.
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
loop code in x86_64 assembler:
loop:
cmp $max, %r10 /* compare r10 (loop index) with 30 */
jg end_loop /* if r10 is greater than 30, exit loop */
movq %r10, %rax /* store the r10 value into rax for division */
xor %rdx, %rdx /* clear rdx for division */
divq %r9 /* divide rax value by 10 (r9) */
movq %rax, %r14 /* store the quotient into r14 */
movq %rdx, %r15 /* store the remainder into r15 */
add $'0', %r14 /* add '0' to r14 so the value will be ASCII number character value */
add $'0', %r15 /* add '0' to r15 so the value will be ASCII number character value */
movq $msg+6, %r11 /* the tens digit location within string */
movb %r14b, (%r11) /* store the digit at the location */
movq $msg+7, %r12 /* the units digit location within string */
movb %r15b, (%r12) /* store the digit at the location */
movq $len, %rdx /* message length */
movq $msg, %rsi /* message location */
movq $1, %rdi /* file descriptor stdout */
movq $1, %rax /* syscall sys_write */
syscall
inc %r10 /* increment loop index */
jmp loop /* redo the loop subroutine */
end_loop:
movq $0, %rdi /* exit status */
movq $60, %rax /* syscall sys_exit */
syscall
.section .data
msg: .ascii "Loop: #\n"
len = . - msg
min = 1
max = 30
division = 10
sshin36@x86-001:~/spo600/examples/hello/assembler/x86_64$ ./loop
Loop: 01
Loop: 02
Loop: 03
Loop: 04
Loop: 05
Loop: 06
Loop: 07
Loop: 08
Loop: 09
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
Conclusion
This lab demonstrated the differences in assembly language programming between x86_64 and Aarch64 architectures. Writing a loop that prints numbers alongside a message proved to be straightforward in concept but challenging in execution, particularly when formatting the output correctly. The disassembly step provided valuable insights into how high-level code translates into machine instructions on different platforms.
댓글
댓글 쓰기