intel64 (emt64) のアセンブラ
Menu Menuintel64はlittle-endianであり、メモリにはメモリのアドレスが小さい方に、 数値の小さい桁から格納される。また、%raxレジスタは、高い方の桁が8bit %ahレジスタ、低い方の桁が8bit レジスタ%alとなっている。32bit の int %eaxに入る。以下の数値は16進表記とする。
以下のソースを使う。
clang -S test1.cで、test1.s ができる。
clang test1.sで a.out を生成する。
メモリの内容を表すアセンブラが以下のようになっている。
.section __DATA,__data .globl _a ## @a _a: .ascii "\001\002\003\004\005\006\007\bU\022"こうすると、a のアドレスのメモリ上には以下のようなパターンが書き込まれる。それを以下のように確認する。CPU の endian を x/20x と x/20b を使って確認せよ。
% lldb a.out (lldb) target create "a.out" Current executable set to 'a.out' (x86_64). (lldb) b test Breakpoint 1: where = a.out`test, address = 0x0000000100000f00 (lldb) run error: process exited with status -1 (lost connection) 'r' and 'run' are aliases that default to launching through a shell. Try launching without going through a shell by using 'process launch'. (lldb) process launch Process 1197 launched: '/Users/kono/Sites/lecture/compiler/ex/a.out' (x86_64) Process 1197 stopped * thread #1: tid = 0x6b95, 0x0000000100000f00 a.out`test, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1 frame #0: 0x0000000100000f00 a.out`test a.out`test: -> 0x100000f00 <+0>: pushq %rbp 0x100000f01 <+1>: movq %rsp, %rbp 0x100000f04 <+4>: movq %rdi, -0x8(%rbp) 0x100000f08 <+8>: movq %rsi, -0x10(%rbp) (lldb) x/20x &a 0x100001018: 0x04030201 0x08070605 0x00001255 0x00000000 0x100001028: 0x00000000 0x00000000 0x00000000 0x00000000 0x100001038: 0x00000000 0x00000000 0x00000000 0x00000000 0x100001048: 0x00000000 0x00000000 0x00000000 0x00000000 0x100001058: 0x00000000 0x00000000 0x00000000 0x00000000test関数の引数
test(unsigned char *a, long j) { return j; }a は %rdiに、jは%rsiに入る。
(lldb) p $rdi (unsigned long) $1 = 4294971416 (lldb) p $rsi (unsigned long) $2 = 0これにさまざまなアセンブラ命令を入れてためしてみよう。vi/emacsで、test1.s を書き換えて、
clang test1.sでコンパイルして、実行あるいはlldbでのtraceを行う。
_test: ## @test .cfi_startproc ## BB#0: pushq %rbp Ltmp0: .cfi_def_cfa_offset 16 Ltmp1: .cfi_offset %rbp, -16 movq %rsp, %rbp Ltmp2: .cfi_def_cfa_register %rbp movq %rdi, -8(%rbp) movq %rsi, -16(%rbp) movq -16(%rbp), %rax popq %rbp retq .cfi_endprocこれを、
_test: ## @test .cfi_startproc ## BB#0: pushq %rbp Ltmp0: .cfi_def_cfa_offset 16 Ltmp1: .cfi_offset %rbp, -16 movq %rsp, %rbp Ltmp2: .cfi_def_cfa_register %rbp movq %rdi, -8(%rbp) movq %rsi, -16(%rbp) movq $1, %rbx # long rbx = 1 addq %rbx, %rbx # rbx = rbx + rbx movswq (%rdi,%rbx), %rax # short rax = rdi[rbx]; popq %rbp retq .cfi_endprocのように書き換えると、
% lldb a.out (lldb) target create "a.out" Current executable set to 'a.out' (x86_64). (lldb) b test Breakpoint 1: where = a.out`test, address = 0x0000000100000f00 (lldb) process launch Process 1228 launched: '/Users/kono/Sites/lecture/compiler/ex/a.out' (x86_64) Process 1228 stopped * thread #1: tid = 0x74d7, 0x0000000100000f00 a.out`test, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1 frame #0: 0x0000000100000f00 a.out`test a.out`test: -> 0x100000f00 <+0>: pushq %rbp 0x100000f01 <+1>: movq %rsp, %rbp 0x100000f04 <+4>: movq %rdi, -0x8(%rbp) 0x100000f08 <+8>: movq %rsi, -0x10(%rbp) (lldb) stepi Process 1228 stopped * thread #1: tid = 0x74d7, 0x0000000100000f01 a.out`test + 1, queue = 'com.apple.main-thread', stop reason = instruction step into frame #0: 0x0000000100000f01 a.out`test + 1 a.out`test: -> 0x100000f01 <+1>: movq %rsp, %rbp 0x100000f04 <+4>: movq %rdi, -0x8(%rbp) 0x100000f08 <+8>: movq %rsi, -0x10(%rbp) 0x100000f0c <+12>: movq $0x1, %rbx (lldb) Process 1228 stopped * thread #1: tid = 0x74d7, 0x0000000100000f04 a.out`test + 4, queue = 'com.apple.main-thread', stop reason = instruction step into frame #0: 0x0000000100000f04 a.out`test + 4 a.out`test: -> 0x100000f04 <+4>: movq %rdi, -0x8(%rbp) 0x100000f08 <+8>: movq %rsi, -0x10(%rbp) 0x100000f0c <+12>: movq $0x1, %rbx 0x100000f13 <+19>: addq %rbx, %rbx (lldb) Process 1228 stopped * thread #1: tid = 0x74d7, 0x0000000100000f08 a.out`test + 8, queue = 'com.apple.main-thread', stop reason = instruction step into frame #0: 0x0000000100000f08 a.out`test + 8 a.out`test: -> 0x100000f08 <+8>: movq %rsi, -0x10(%rbp) 0x100000f0c <+12>: movq $0x1, %rbx 0x100000f13 <+19>: addq %rbx, %rbx 0x100000f16 <+22>: movswq (%rdi,%rbx), %rax (lldb) Process 1228 stopped * thread #1: tid = 0x74d7, 0x0000000100000f0c a.out`test + 12, queue = 'com.apple.main-thread', stop reason = instruction step into frame #0: 0x0000000100000f0c a.out`test + 12 a.out`test: -> 0x100000f0c <+12>: movq $0x1, %rbx 0x100000f13 <+19>: addq %rbx, %rbx 0x100000f16 <+22>: movswq (%rdi,%rbx), %rax 0x100000f1b <+27>: popq %rbp (lldb) Process 1228 stopped * thread #1: tid = 0x74d7, 0x0000000100000f13 a.out`test + 19, queue = 'com.apple.main-thread', stop reason = instruction step into frame #0: 0x0000000100000f13 a.out`test + 19 a.out`test: -> 0x100000f13 <+19>: addq %rbx, %rbx 0x100000f16 <+22>: movswq (%rdi,%rbx), %rax 0x100000f1b <+27>: popq %rbp 0x100000f1c <+28>: retq (lldb) Process 1228 stopped * thread #1: tid = 0x74d7, 0x0000000100000f16 a.out`test + 22, queue = 'com.apple.main-thread', stop reason = instruction step into frame #0: 0x0000000100000f16 a.out`test + 22 a.out`test: -> 0x100000f16 <+22>: movswq (%rdi,%rbx), %rax 0x100000f1b <+27>: popq %rbp 0x100000f1c <+28>: retq 0x100000f1d <+29>: nopl (%rax) (lldb) p $rbx (unsigned long) $0 = 2 (lldb) p $rdi (unsigned long) $1 = 4294971416 (lldb) x/20x $rdi 0x100001018: 0x04030201 0x08070605 0x00001255 0x00000000 0x100001028: 0x00000000 0x00000000 0x00000000 0x00000000 0x100001038: 0x00000000 0x00000000 0x00000000 0x00000000 0x100001048: 0x00000000 0x00000000 0x00000000 0x00000000 0x100001058: 0x00000000 0x00000000 0x00000000 0x00000000 (lldb) stepi Process 1228 stopped * thread #1: tid = 0x74d7, 0x0000000100000f1b a.out`test + 27, queue = 'com.apple.main-thread', stop reason = instruction step into frame #0: 0x0000000100000f1b a.out`test + 27 a.out`test: -> 0x100000f1b <+27>: popq %rbp 0x100000f1c <+28>: retq 0x100000f1d <+29>: nopl (%rax) a.out`main: 0x100000f20 <+0>: pushq %rbp (lldb) p $rax (unsigned long) $3 = 1027 (lldb) p (void*)$rax (void *) $4 = 0x0000000000000403 (lldb)と、$rax の値は 0x0403 となる。これは、
(lldb) x/20x &a 0x100001018: 0x04030201 0x08070605 0x00001255 0x00000000の値の一部である。(void*)で16進数で表示させている。
次に、test1.s を以下のように変更する。
Ltmp2: .cfi_def_cfa_register %rbp movq %rdi, -8(%rbp) movq %rsi, -16(%rbp) movq (%rdi),%rax popq %rbp retqmovq (%rdi),%raxは、a[0] のアドレスの指す先をlongとして%raxレジスタに格納する。この命令を実行した時、 %raxレジスタの値はいくつになるかを16進で確認せよ。 %ahレジスタは? %alレジスタは? %eax レジスタは?
movq 2(%rdi),%rbxは、a[2] のアドレスの指す先を%rbxレジスタに格納する。%rbx の値はどうなるか?
movq %rdi, %rbx addq $x04, %rbxとすると、 %rbx レジスタが、%rdi+4になる。
そのあとに、movl (%rbx),%eax を実行すると %eax レジスタの値は? (ヒント: %raxの上位の値は変わらない)
incl %rbx を実行したあとに、movq (%rbx),%rax を実行すると %rax レジスタの値は?
その後、movl 4(%rbx,%rax),%ecx を実行すると %ecx レジスタの値はどのアドレスのメモリからロード(取得)されるか?
leaq 4(%rbx,%rax),%rcxで直接に確認することもできる。
movb 2(%rbx),%al を実行すると %eax レジスタの値はどうなるか?
movsbl 2(%rbx),%eax を実行すると %eax レジスタの値はどうなるか?
movsbl 3(%rbx),%eax を実行すると %eax レジスタの値はどうなるか?
movsbq 3(%rbx),%rax を実行すると %rax レジスタの値はどうなるか?
leaq 8(%rbx,%eax),%rcx を実行すると %rcx レジスタの値は?
leaq 8(%rbx,%eax,2),%rcx を実行すると %rcx レジスタの値は?
使用したコード
.align 4, 0x90 _test: ## @test .cfi_startproc ## BB#0: # movq %rdi, -8(%rbp) # a # movq %rsi, -16(%rbp) # x # return a[1]; movq (%rdi), %rax movq 2(%rdi), %rax movq 2(%rdi), %rbx movq %rdi, %rbx addq $0x4, %rbx movl (%rbx), %eax incq %rbx movq (%rbx),%rax movq $0x4, %rax movl 4(%rbx,%rax),%ecx leaq 4(%rbx,%rax),%rcx movb 2(%rbx),%al movsbl 2(%rbx),%eax movsbl 3(%rbx),%eax movsbq 3(%rbx),%rax leaq 8(%rbx,%rax),%rcx leaq 8(%rbx,%rax,2),%rcx ret