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 0x00000000
test関数の引数
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
retq
movq (%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