前回のソースコードのコンパイル結果がどんな感じになっているか見る。
アセンブラを見ると、
$ arm-linux-gnueabi-gcc -S sample.c
$ cat sample.s
.cpu arm9tdmi
.fpu softvfp
.eabi_attribute 20, 1
.eabi_attribute 21, 1
.eabi_attribute 23, 3
.eabi_attribute 24, 1
.eabi_attribute 25, 1
.eabi_attribute 26, 2
.eabi_attribute 30, 6
.eabi_attribute 18, 4
.file "sample.c"
.section .rodata
.align 2
.LC0:
.ascii "Hello world.\000"
.text
.align 2
.global main
.type main, %function
main:
@ Function supports interworking.
@ args = 0, pretend = 0, frame = 0
@ frame_needed = 1, uses_anonymous_args = 0
mov ip, sp
stmfd sp!, {fp, ip, lr, pc}
sub fp, ip, #4
ldr r0, .L3
bl puts
mov r3, #0
mov r0, r3
sub sp, fp, #12
ldmfd sp, {fp, sp, lr}
bx lr
.L4:
.align 2
.L3:
.word .LC0
.size main, .-main
.ident "GCC: (Debian 4.3.5-4) 4.3.5"
.section .note.GNU-stack,"",%progbits
途中で、puts を呼んでいる。
a.out は、puts を知らないのでそのままでは実行できない。libc が必要。
$ arm-linux-gnueabi-nm a.out | grep " U "
U __libc_start_main@@GLIBC_2.4
U abort@@GLIBC_2.4
U puts@@GLIBC_2.4
$ qemu-arm ./a.out
/lib/ld-linux.so.3: No such file or directory
qemu-arm 実行時に -L で libc の ARM バイナリの位置を与えると実行できる。
$ qemu-arm -L /usr/arm-linux-gnueabi ./a.out
Hello world.
puts などを静的リンクしておくこともできる。
$ arm-linux-gnueabi-gcc sample.c -static
$ arm-linux-gnueabi-nm a.out | grep " U "
$ qemu-arm ./a.out
Hello world.
puts 内部では、システムコール write を呼ぶ。
qemu-arm では、write システムコールをホストマシンの write システムコール実行に置き換える。
write 以外にこんなシステムコールが使われている。
$ qemu-arm -strace -L /usr/arm-linux-gnueabi/ a.out
1698 brk(NULL) = 0x00011000
1698 uname(0x4006f7a0) = 0
1698 access("/etc/ld.so.nohwcap",F_OK) = -1 errno=2 (No such file or directory)
1698 mmap2(NULL,4096,PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_ANONYMOUS,-1,0) = 0x42071000
1698 access("/etc/ld.so.preload",R_OK) = -1 errno=2 (No such file or directory)
1698 open("/etc/ld.so.cache",O_RDONLY) = 3
1698 fstat64(3,0x4006f3b8) = 0
1698 mmap2(NULL,26461,PROT_READ,MAP_PRIVATE,3,0) = 0x42072000
1698 close(3) = 0
1698 access("/etc/ld.so.nohwcap",F_OK) = -1 errno=2 (No such file or directory)
1698 open("/lib/libc.so.6",O_RDONLY) = 3
1698 read(3,0x4006f4cc,512) = 512
1698 fstat64(3,0x4006f3f0) = 0
1698 mmap2(NULL,4096,PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_ANONYMOUS,-1,0) = 0x42079000
1698 mmap2(NULL,1242372,PROT_EXEC|PROT_READ,MAP_PRIVATE|MAP_DENYWRITE,3,0) = 0x4207a000
1698 mprotect(0x4219d000,28672,PROT_NONE) = 0
1698 mmap2(0x421a4000,12288,PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_DENYWRITE|MAP_FIXED,3,0x122) = 0x421a4000
1698 mmap2(0x421a7000,9476,PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED,-1,0) = 0x421a7000
1698 close(3) = 0
1698 mmap2(NULL,4096,PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_ANONYMOUS,-1,0) = 0x421aa000
1698 open("/dev/urandom",O_RDONLY) = 3
1698 read(3,0x4006f96d,3) = 3
1698 close(3) = 0
1698 mprotect(0x421a4000,8192,PROT_READ) = 0
1698 mprotect(0x40095000,4096,PROT_READ) = 0
1698 munmap(0x42072000,26461) = 0
1698 fstat64(1,0x4006fb48) = 0
1698 mmap2(NULL,4096,PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_ANONYMOUS,-1,0) = 0x421ab000
1698 write(1,0x421ab000,13)Hello world.
= 13
1698 exit_group(0)