C++でx64アセンブラを覚える(その1)

C++のアセンブラも眺めたくなりました。
今回はこのサンプルのアセンブラを見てみます。

takk@deb9:~/tmp$ cat -n t.cpp
     1  class Sample{
     2          int a;
     3  public:
     4          Sample(int a){
     5                  this->a = a;
     6          }
     7          int Get_a(){
     8                  return this->a;
     9          }
    10  };
    11
    12  int main()
    13  {
    14          Sample *o = new Sample(100);
    15
    16          return o->Get_a();
    17  }
takk@deb9:~/tmp$

実行すると、コマンドの戻り値に100を返してくれます。

takk@deb9:~/tmp$ g++ t.cpp
takk@deb9:~/tmp$ ./a.out;echo $?
100
takk@deb9:~/tmp$

ではアセンブラコード全文です。

takk@deb9:~/tmp$ g++ -S t.cpp
takk@deb9:~/tmp$ cat -n t.s
     1          .file   "t.cpp"
     2          .section        .text._ZN6SampleC2Ei,"axG",@progbits,_ZN6SampleC5Ei,comdat
     3          .align 2
     4          .weak   _ZN6SampleC2Ei
     5          .type   _ZN6SampleC2Ei, @function
     6  _ZN6SampleC2Ei:
     7  .LFB1:
     8          .cfi_startproc
     9          pushq   %rbp
    10          .cfi_def_cfa_offset 16
    11          .cfi_offset 6, -16
    12          movq    %rsp, %rbp
    13          .cfi_def_cfa_register 6
    14          movq    %rdi, -8(%rbp)
    15          movl    %esi, -12(%rbp)
    16          movq    -8(%rbp), %rax
    17          movl    -12(%rbp), %edx
    18          movl    %edx, (%rax)
    19          nop
    20          popq    %rbp
    21          .cfi_def_cfa 7, 8
    22          ret
    23          .cfi_endproc
    24  .LFE1:
    25          .size   _ZN6SampleC2Ei, .-_ZN6SampleC2Ei
    26          .weak   _ZN6SampleC1Ei
    27          .set    _ZN6SampleC1Ei,_ZN6SampleC2Ei
    28          .section        .text._ZN6Sample5Get_aEv,"axG",@progbits,_ZN6Sample5Get_aEv,comdat
    29          .align 2
    30          .weak   _ZN6Sample5Get_aEv
    31          .type   _ZN6Sample5Get_aEv, @function
    32  _ZN6Sample5Get_aEv:
    33  .LFB3:
    34          .cfi_startproc
    35          pushq   %rbp
    36          .cfi_def_cfa_offset 16
    37          .cfi_offset 6, -16
    38          movq    %rsp, %rbp
    39          .cfi_def_cfa_register 6
    40          movq    %rdi, -8(%rbp)
    41          movq    -8(%rbp), %rax
    42          movl    (%rax), %eax
    43          popq    %rbp
    44          .cfi_def_cfa 7, 8
    45          ret
    46          .cfi_endproc
    47  .LFE3:
    48          .size   _ZN6Sample5Get_aEv, .-_ZN6Sample5Get_aEv
    49          .text
    50          .globl  main
    51          .type   main, @function
    52  main:
    53  .LFB4:
    54          .cfi_startproc
    55          pushq   %rbp
    56          .cfi_def_cfa_offset 16
    57          .cfi_offset 6, -16
    58          movq    %rsp, %rbp
    59          .cfi_def_cfa_register 6
    60          pushq   %rbx
    61          subq    $24, %rsp
    62          .cfi_offset 3, -24
    63          movl    $4, %edi
    64          call    _Znwm@PLT
    65          movq    %rax, %rbx
    66          movl    $100, %esi
    67          movq    %rbx, %rdi
    68          call    _ZN6SampleC1Ei
    69          movq    %rbx, -24(%rbp)
    70          movq    -24(%rbp), %rax
    71          movq    %rax, %rdi
    72          call    _ZN6Sample5Get_aEv
    73          addq    $24, %rsp
    74          popq    %rbx
    75          popq    %rbp
    76          .cfi_def_cfa 7, 8
    77          ret
    78          .cfi_endproc
    79  .LFE4:
    80          .size   main, .-main
    81          .ident  "GCC: (Debian 6.3.0-18+deb9u1) 6.3.0 20170516"
    82          .section        .note.GNU-stack,"",@progbits
takk@deb9:~/tmp$

C言語と比べてコードが長くなりました。
この行で、Sampleコンストラクタの呼び出しをして、

    68          call    _ZN6SampleC1Ei

この行で、Get_aメソッドの呼び出しをしてるだけですね。

    72          call    _ZN6Sample5Get_aEv

C言語の時と同じで、アセンブラでも関数をcallしてるだけってことが分かりました。

インスタンスを増やしても同じでしょうか。
別インスタンス作って実行してみます。

takk@deb9:~/tmp$ cat -n t.cpp
     1  class Sample{
     2          int a;
     3  public:
     4          Sample(int a){
     5                  this->a = a;
     6          }
     7          int Get_a(){
     8                  return this->a;
     9          }
    10  };
    11
    12  int main()
    13  {
    14          Sample *o1 = new Sample(100);
    15          Sample *o2 = new Sample(150);
    16
    17          return o1->Get_a() + o2->Get_a();
    18  }
takk@deb9:~/tmp$

生成アセンブラを比較。

takk@deb9:~/tmp$ mv t.s t1.s
takk@deb9:~/tmp$ g++ -o t2.s -S t.cpp
takk@deb9:~/tmp$ diff t1.s t2.s
69a70,76
>       movl    $4, %edi
>       call    _Znwm@PLT
>       movq    %rax, %rbx
>       movl    $150, %esi
>       movq    %rbx, %rdi
>       call    _ZN6SampleC1Ei
>       movq    %rbx, -32(%rbp)
72a80,84
>       movl    %eax, %ebx
>       movq    -32(%rbp), %rax
>       movq    %rax, %rdi
>       call    _ZN6Sample5Get_aEv
>       addl    %ebx, %eax
takk@deb9:~/tmp$

インスタンスを増やしても、所詮は関数呼び出しなので、callしてるだけでしたね。

Leave a Reply

Your email address will not be published. Required fields are marked *

CAPTCHA