Assembler Lab
Write at very first beginning
After I finally finish all the tasks, I feel that there is a remarkable thing has been accomplished. It was hard at first, I tried hundreds of times, changed every single of element to figure out what does this syntax means. After I could read those code, the logic is simple. Everything has to be placed in its own place(address). I will choose gas, it seems more straight forward to me.Login on x86_64
$ ssh siwen@xerxes.cdot.systems
Download the code examples and unpacking the archive
$ cp /public/spo600-assembler-lab-examples.tgz .
$ tar xvzf spo600-assembler-lab-examples.tgz
hello.c
/* Hello World in traditional C using printf() */
#include <stdio.h>
int main() {
printf("Hello World!\n");
}
hello2.c
/* Hello World with a direct write to stdout (file descriptor 1) */
#include <unistd.h>
int main() {
write(1,"Hello World!\n",13);
}
hello3.c
/* Hello World using a direct kernel system call to write to
file descriptor 1 (stdout) */
#include <unistd.h>
#include <sys/syscall.h>
int main() {
syscall(__NR_write,1,"Hello World!\n",13);
}
Tasks
1. Build and run the three C versions of the program for x86_64. Take a look at the differences in the code.
$ cd spo600/examples/hello/c
$ make
gcc -g -O0 -fno-builtin -o hello hello.c
gcc -g -O0 -fno-builtin -o hello-static -static hello.c
gcc -O3 -g -o hello-opt hello.c
gcc -g -O0 -fno-builtin -o hello2 hello2.c
gcc -g -O0 -fno-builtin -o hello3 hello3.c
2. Use the
objdump -d
command to dump (print) the object code (machine code) and disassemble it into assembler for each of the binaries. Find the <main>
section and take a look at the code. Notice the total amount of code.$ objdump -d hello | less
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 callq 401030 <printf@plt>
401139: b8 00 00 00 00 mov $0x0,%eax
40113e: 5d pop %rbp
40113f: c3 retq
$ objdump -d hello2 | less
0000000000401126 <main>:
401126: 55 push %rbp
401127: 48 89 e5 mov %rsp,%rbp
40112a: ba 0d 00 00 00 mov $0xd,%edx
40112f: be 10 20 40 00 mov $0x402010,%esi
401134: bf 01 00 00 00 mov $0x1,%edi
401139: e8 f2 fe ff ff callq 401030 <write@plt>
40113e: b8 00 00 00 00 mov $0x0,%eax
401143: 5d pop %rbp
401144: c3 retq
401145: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1)
40114c: 00 00 00
40114f: 90 nop
$ objdump -d hello3 | less
0000000000401126 <main>:
401126: 55 push %rbp
401127: 48 89 e5 mov %rsp,%rbp
40112a: b9 0d 00 00 00 mov $0xd,%ecx
40112f: ba 10 20 40 00 mov $0x402010,%edx
401134: be 01 00 00 00 mov $0x1,%esi
401139: bf 01 00 00 00 mov $0x1,%edi
40113e: b8 00 00 00 00 mov $0x0,%eax
401143: e8 e8 fe ff ff callq 401030 <syscall@plt>
401148: b8 00 00 00 00 mov $0x0,%eax
40114d: 5d pop %rbp
40114e: c3 retq
40114f: 90 nop
3. Review, build, and run the x86_64 assembly language programs. Take a look at the code using
objdump -d objectfile
and compare it to the source code. Notice the absence of other code (compared to the C binary, which had a lot of extra code).$ cd spo600/examples/hello/assembler/x86_64
$ make
nasm -g -o hello-nasm.o -f elf64 hello-nasm.s
ld -o hello-nasm hello-nasm.o
as -g -o hello-gas.o hello-gas.s
ld -o hello-gas hello-gas.o
$ nano hello-gas.s
.text
.globl _start
_start:
movq $len,%rdx /* message length */
movq $msg,%rsi /* message location */
movq $1,%rdi /* file descriptor stdout */
movq $1,%rax /* syscall sys_write */
syscall
movq $0,%rdi /* exit status */
movq $60,%rax /* syscall sys_exit */
syscall
.section .rodata
msg: .ascii "Hello, world!\n"
len = . - msg
$ objdump -d hello-gas | less
hello-gas: file format elf64-x86-64
Disassembly of section .text:
0000000000401000 <_start>:
401000: 48 c7 c2 0e 00 00 00 mov $0xe,%rdx
401007: 48 c7 c6 00 20 40 00 mov $0x402000,%rsi
40100e: 48 c7 c7 01 00 00 00 mov $0x1,%rdi
401015: 48 c7 c0 01 00 00 00 mov $0x1,%rax
40101c: 0f 05 syscall
40101e: 48 c7 c7 00 00 00 00 mov $0x0,%rdi
401025: 48 c7 c0 3c 00 00 00 mov $0x3c,%rax
40102c: 0f 05 syscall
4. Build and run the three C versions of the program for aarch64. Verify that you can disassemble the object code in the ELF binary using
objdump -d objectfile
and take a look at the code.Login on ARMv8
$ ssh siwen@aarchie.cdot.systems
Download the code examples and unpacking the archive
$ cp /public/spo600-assembler-lab-examples.tgz .
$ tar xvzf spo600-assembler-lab-examples.tgz
$ cd spo600/examples/hello/c
$make
gcc -g -O0 -fno-builtin -o hello hello.c
gcc -g -O0 -fno-builtin -o hello-static -static hello.c
gcc -O3 -g -o hello-opt hello.c
gcc -g -O0 -fno-builtin -o hello2 hello2.c
gcc -g -O0 -fno-builtin -o hello3 hello3.c
$ objdump -d hello | less
0000000000400594 <main>:
400594: a9bf7bfd stp x29, x30, [sp, #-16]!
400598: 910003fd mov x29, sp
40059c: 90000000 adrp x0, 400000 <_init-0x418>
4005a0: 9119c000 add x0, x0, #0x670
4005a4: 97ffffb7 bl 400480 <printf@plt>
4005a8: 52800000 mov w0, #0x0 // #0
4005ac: a8c17bfd ldp x29, x30, [sp], #16
4005b0: d65f03c0 ret
4005b4: 00000000 .inst 0x00000000 ; undefined
$objdump -d hello2 | less
0000000000400594 <main>:
400594: a9bf7bfd stp x29, x30, [sp, #-16]!
400598: 910003fd mov x29, sp
40059c: d28001a2 mov x2, #0xd // #13
4005a0: 90000000 adrp x0, 400000 <_init-0x418>
4005a4: 9119e001 add x1, x0, #0x678
4005a8: 52800020 mov w0, #0x1 // #1
4005ac: 97ffffb1 bl 400470 <write@plt>
4005b0: 52800000 mov w0, #0x0 // #0
4005b4: a8c17bfd ldp x29, x30, [sp], #16
4005b8: d65f03c0 ret
4005bc: 00000000 .inst 0x00000000 ; undefined
$ objdump -d hello3 | less
0000000000400594 <main>:
400594: a9bf7bfd stp x29, x30, [sp, #-16]!
400598: 910003fd mov x29, sp
40059c: 528001a3 mov w3, #0xd // #13
4005a0: 90000000 adrp x0, 400000 <_init-0x418>
4005a4: 9119e002 add x2, x0, #0x678
4005a8: 52800021 mov w1, #0x1 // #1
4005ac: d2800800 mov x0, #0x40 // #64
4005b0: 97ffffb4 bl 400480 <syscall@plt>
4005b4: 52800000 mov w0, #0x0 // #0
4005b8: a8c17bfd ldp x29, x30, [sp], #16
4005bc: d65f03c0 ret
5. Review, build, and run the aarch64 assembly language programs. Take a look at the code using
objdump -d objectfile
and compare it to the source code. $ cd spo600/examples/hello/assembler/aarch64
$ make
as -g -o hello.o hello.s
ld -o hello hello.o
$ nano hello.s
.text
.globl _start
_start:
mov x0, 1 /* file descriptor: 1 is stdout */
adr x1, msg /* message location (memory address) */
mov x2, len /* message length (bytes) */
mov x8, 64 /* write is syscall #64 */
svc 0 /* invoke syscall */
mov x0, 0 /* status -> 0 */
mov x8, 93 /* exit is syscall #93 */
svc 0 /* invoke syscall */
.data
msg: .ascii "Hello, world!\n"
len= . - msg
$ objdump -d hello | less
00000000004000b0 <_start>:
4000b0: d2800020 mov x0, #0x1 // #1
4000b4: 100800e1 adr x1, 4100d0 <msg>
4000b8: d28001c2 mov x2, #0xe // #14
4000bc: d2800808 mov x8, #0x40 // #64
4000c0: d4000001 svc #0x0
4000c4: d2800000 mov x0, #0x0 // #0
4000c8: d2800ba8 mov x8, #0x5d // #93
4000cc: d4000001 svc #0x0
.text .globl _start start = 0 max = 10 _start: mov $start,%r15 loop: mov $len,%rdx mov $msg,%rsi mov $1,%rdi mov $1,%rax syscall inc %r15 /* increment index */ cmp $max,%r15 /* see if we're done */ jne loop /* loop if we're not */ mov $0,%rdi /* exit status */ mov $60,%rax /* syscall sys_exit */ syscall .section .rodata msg: .ascii "Loop\n" len = . - msg
Then modify the message so that it includes the loop index values, showing each digit from 0 to 9 like this:
.text .globl _start start = 0 max = 10 _start: mov $start,%r15 loop: mov $0x30,%r14 add %r15,%r14 movb %r14b,msg+6 mov $len,%rdx mov $msg,%rsi mov $1,%rdi mov $1,%rax syscall inc %r15 /* increment index */ cmp $max,%r15 /* see if we're done */ jne loop /* loop if we're not */ mov $0,%rdi /* exit status */ mov $60,%rax /* syscall sys_exit */ syscall .section .data msg: .ascii "Loop: \n" len = . - msg
7. Repeat step 6 for aarch64.![]()
.text .globl _start start = 0 max = 10 _start: mov x10,start loop: mov x0, 1 /* file descriptor: 1 is stdout */ adr x1, msg /* message location (memory address) */ mov x2, len /* message length (bytes) */ mov x8, 64 /* write is syscall #64 */ svc 0 /* invoke syscall */ add x10,x10,1 cmp x10,max b.lt loop mov x0, 0 /* status -> 0 */ mov x8, 93 /* exit is syscall #93 */ svc 0 /* invoke syscall */ .data msg: .ascii "Loop\n" len= . - msg
.text .globl _start start = 0 max = 10 _start: mov x10,start loop: mov x0, 1 /* file descriptor: 1 is stdout */ adr x1, msg /* message location (memory address) */ mov x2, len /* message length (bytes) */ add x11,x10,48
adr x12,msg+6
strb w11,[x12] mov x8, 64 /* write is syscall #64 */ svc 0 /* invoke syscall */ add x10,x10,1 cmp x10,max b.lt loop mov x0, 0 /* status -> 0 */ mov x8, 93 /* exit is syscall #93 */ svc 0 /* invoke syscall */ .data msg: .ascii "Loop: \n" len= . - msg
8. Extend the code to loop from 00-30, printing each value as a 2-digit decimal number.
.text .globl _start start = 0 max = 31 _start: mov $start,%r15 loop: mov $0x30,%r13 mov $0x30,%r14 mov $0,%rdx mov %r15,%rax mov $10,%r12 div %r12 add %rax,%r13 add %rdx,%r14 movb %r13b,msg+6 movb %r14b,msg+7 mov $len,%rdx mov $msg,%rsi mov $1,%rdi mov $1,%rax syscall inc %r15 /* increment index */ cmp $max,%r15 /* see if we're done */ jne loop /* loop if we're not */ mov $0,%rdi /* exit status */ mov $60,%rax /* syscall sys_exit */ syscall .section .data msg: .ascii "Loop: \n\n" len = . - msg
9. Repeat step 8 for aarch64.
.text .globl _start start = 0 max = 31 _start: mov x10,start mov x9,10 loop: mov x0, 1 /* file descriptor: 1 is stdout */ adr x1, msg /* message location (memory address) */ mov x2, len /* message length (bytes) */ udiv x11,x10,x9 msub x12,x9,x11,x10 add x11,x11,48 add x12,x12,48 adr x13,msg+6 adr x14,msg+7 strb w11,[x13] strb w12,[x14] mov x8, 64 /* write is syscall #64 */ svc 0 /* invoke syscall */ add x10,x10,1 cmp x10,max b.lt loop mov x0, 0 /* status -> 0 */ mov x8, 93 /* exit is syscall #93 */ svc 0 /* invoke syscall */ .data msg: .ascii "Loop: \n" len= . - msg
Extend the assembler programs (both x86_64 and aarch64) to suppress the high digit when it is 0.
.text .globl _start start = 0 max = 31 _start: mov x10,start mov x9,10 loop: mov x0, 1 /* file descriptor: 1 is stdout */ adr x1, msg /* message location (memory address) */ mov x2, len /* message length (bytes) */ udiv x11,x10,x9 msub x12,x9,x11,x10 cmp x11,0 b.eq ones add x11,x11,48 adr x13,msg+6 strb w11,[x13] ones: add x12,x12,48 adr x14,msg+7 strb w12,[x14] mov x8, 64 /* write is syscall #64 */ svc 0 /* invoke syscall */ add x10,x10,1 cmp x10,max b.lt loop mov x0, 0 /* status -> 0 */ mov x8, 93 /* exit is syscall #93 */ svc 0 /* invoke syscall */ .data msg: .ascii "Loop: \n" len= . - msg
.text .globl _start start = 0 max = 31 _start: mov $start,%r15 loop: mov $0x30,%r13 mov $0x30,%r14 mov $0,%rdx mov %r15,%rax mov $10,%r12 div %r12 add %rax,%r13 add %rdx,%r14 cmp $0x30,%r13 je ones movb %r13b,msg+6 ones: movb %r14b,msg+7 mov $len,%rdx mov $msg,%rsi mov $1,%rdi mov $1,%rax syscall inc %r15 /* increment index */ cmp $max,%r15 /* see if we're done */ jne loop /* loop if we're not */ mov $0,%rdi /* exit status */ mov $60,%rax /* syscall sys_exit */ syscall .section .data msg: .ascii "Loop: \n\n" len = . - msg![]()
Comments
Post a Comment