intel64 (emt64) のアセンブラ

Menu Menu

intel64はlittle-endianであり、メモリにはメモリのアドレスが小さい方に、 数値の小さい桁から格納される。また、%raxレジスタは、高い方の桁が8bit %ahレジスタ、低い方の桁が8bit レジスタ%alとなっている。32bit の int %eaxに入る。以下の数値は16進表記とする。

以下のソースを使う。

test1.c

    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

Shinji KONO / Fri Oct 28 16:48:15 2016