Code of Poem
Unknown programmer's programming note.

ポインタとアセンブラコードの実験

C++のポインタを使うコードがどのようにコンパイルされるかの実験です。

C++のソースコードからアセンブラコードを生成するためには、次のようなMakefileを使いました。

TARGETS = code1.s code2.s
CXXFLAGS = -O0 -fno-asynchronous-unwind-tables -fno-dwarf2-cfi-asm

.PHONY: all
all: ${TARGETS}

%.s: %.cpp
	${CXX} ${CXXFLAGS} -S $<

.PHONY: clean
clean:
	${RM} ${TARGETS} *.o

先に比較のためにポインタを使わない、ただ変数を定義するだけのコードを書いてみます。

// code1.cpp
void foo()
{
    int a = 2;
    int b = 3;
    int c = a + b;
}

このコードをGCCでアセンブラコードを出力するようにすると次のようになります。コメントは追加したものです。

.file   "code1.cpp"
      .text
      .globl  _Z3foov
      .type   _Z3foov, @function
_Z3foov:
.LFB0:
      pushq   %rbp
.LCFI0:
      movq    %rsp, %rbp
.LCFI1:
      movl    $2, -4(%rbp)    # 定数2をスタックにコピー(変数a) int a=2
      movl    $3, -8(%rbp)    # 定数3をスタックにコピー(変数b) int b=3
      movl    -4(%rbp), %edx  # スタック(変数a)から%edxに値をコピー %edx=a: 
      movl    -8(%rbp), %eax  # スタック(変数b)から%daxに値をコピー %eax=b
      addl    %edx, %eax      # 加算して結果を%eaxに保存 %eax=a+b
      movl    %eax, -12(%rbp) # 加算の結果をスタックにコピー(変数c) int c=%eax
      nop
      popq    %rbp
.LCFI2:
      ret
.LFE0:
      .size   _Z3foov, .-_Z3foov
      .ident  "GCC: (Debian 8.3.0-6) 8.3.0"
      .section        .note.GNU-stack,"",@progbits

ポインタを使ったコードを書きます。

// code2.cpp
void foo()
{
        int a = 3;
        int b = 4;
        int* pa = &a;
        int* pb = &b;
        int c = *pa + *pb;
}

GCCでアセンブラコードを出力します。少し整形してコメントを足してあります。

.file   "code2.cpp"
      .text
      .globl  _Z3foov
      .type   _Z3foov, @function
_Z3foov:
.LFB0:
      pushq   %rbp
.LCFI0:
      movq    %rsp, %rbp
.LCFI1:
      movl    $3, -24(%rbp)   # 定数3をスタックにコピー(変数a) int a=3
      movl    $4, -28(%rbp)   # 定数4をスタックにコピー(変数b) int b=4

      leaq    -24(%rbp), %rax # 変数aのアドレスを%raxにコピー &a
      movq    %rax, -8(%rbp)  # 直前でコピーしたaのアドレスをスタックに置く(変数pa)
                              # int* pa=%rax

      leaq    -28(%rbp), %rax # 変数bのアドレスを%raxにコピー &b
      movq    %rax, -16(%rbp) # 直前でコピーしたbのアドレスをスタックに置く(変数pb)
                              # int* pb=%rax

      movq    -8(%rbp), %rax  # 変数paの値(aのアドレス)を%raxにコピー %rax=*pa
      movl    (%rax), %edx    # %raxをアドレスとして参照先の値を%eaxにコピー %edx=*%rax 

      movq    -16(%rbp), %rax # 変数pbの値(bのアドレス)を%raxにコピー %rax=*pb
      movl    (%rax), %eax    # %raxをアドレスとして参照先の値を%eaxにコピー %eax=*%rax

      addl    %edx, %eax      # %edxと%eaxを加算して%eaxに保存 %eax=*pa+*pb
      movl    %eax, -20(%rbp) # 加算の結果をスタックにコピー(変数c) int c=%eax
      nop
      popq    %rbp
.LCFI2:
      ret
.LFE0:
      .size   _Z3foov, .-_Z3foov
      .ident  "GCC: (Debian 8.3.0-6) 8.3.0"
      .section        .note.GNU-stack,"",@progbits