アセンブリ言語の中心でHello, Worldを叫ぶ

はじめに

世界の中心で愛を叫ぼうとしたが、そもそも世界の中心がどこかわからなかった。 ということで、アセンブリ言語の中心で愛を叫ぶことにした。

Environment

  • ArchLinux 64bit.
  • intel corei7 x86-64 ISA

C言語の世界

以下のコードが対象。test.c

#include <stdio.h>

int main() {
  printf("Hello, World!!");
  return 0;
}

デバッグ情報つきでコンパイル。

gcc -g test.c

a.outができる。

アセンブリ言語の世界へ

次に、アセンブラファイルを生成。test.sができる。

gcc -S test.c
    .file   "test.c"
    .section    .rodata
.LC0:
    .string "Hello, World!!"
    .text
    .globl  main
    .type   main, @function
main:
.LFB0:
    .cfi_startproc
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset 6, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register 6
    movl    $.LC0, %edi
    movl    $0, %eax
    call    printf
    movl    $0, %eax
    popq    %rbp
    .cfi_def_cfa 7, 8
    ret
    .cfi_endproc
.LFE0:
    .size   main, .-main
    .ident  "GCC: (GNU) 4.9.0 20140604 (prerelease)"
    .section    .note.GNU-stack,"",@progbits

objdump -d a.outでディスアセンブルすると詳細なアセンブリ情報を得られる。

それでは自力で書いてみる

カンペ情報がいろいろ手に入ったので、自力で書いてみる。

    .globl  main # mainからはじまる
main:
    pushq   %rbp # ベースレジスタ退避
    movq    %rsp, %rbp # ベースレジスタにスタックポインタ設定
    movl    $.LC0, %edi # $ediレジスタに文字列格納
    movl    $0, %eax   # $eaxに戻り値が入るので0初期化
    call    printf     # printfをcall  
    movl    $0, %eax   # 戻り値を除去
    popq    %rbp # ベースレジスタ取り出し
    ret     # 終了
.LC0:
    .string "Hello, World!!"

gcc test2.sでコンパイルして、a.outができた。

gdbで解読

gdbで解読。自分が書いたアセンブリコードと違う!どういうことだ??

(gdb) b main
(gdb) disas
Dump of assembler code for function main:
   0x0000000000400506 <+0>: push   %rbp
   0x0000000000400507 <+1>: mov    %rsp,%rbp
   0x000000000040050a <+4>: mov    $0x400520,%edi
   0x000000000040050f <+9>: mov    $0x0,%eax
   0x0000000000400514 <+14>:    callq  0x4003e0 <printf@plt>
   0x0000000000400519 <+19>:    mov    $0x0,%eax
   0x000000000040051e <+24>:    pop    %rbp
   0x000000000040051f <+25>:    retq   
   0x0000000000400520 <+26>:    rex.W
   0x0000000000400521 <+27>:    gs
   0x0000000000400522 <+28>:    insb   (%dx),%es:(%rdi)
   0x0000000000400523 <+29>:    insb   (%dx),%es:(%rdi)
   0x0000000000400524 <+30>:    outsl  %ds:(%rsi),(%dx)
   0x0000000000400525 <+31>:    sub    $0x20,%al
   0x0000000000400527 <+33>:    push   %rdi
   0x0000000000400528 <+34>:    outsl  %ds:(%rsi),(%dx)
   0x0000000000400529 <+35>:    jb     0x400597
   0x000000000040052b <+37>:    and    %esp,%fs:(%rcx)
   0x000000000040052e <+40>:    or     (%rax),%al
End of assembler dump.

(gdb) x /s 0x400520
0x400520 <main+26>: "Hello, World!!\n"

(gdb) info register
rax            0x400506 4195590
rbx            0x0  0
rcx            0x0  0
rdx            0x7fffffffe858   140737488349272
rsi            0x7fffffffe848   140737488349256
rdi            0x1  1
rbp            0x7fffffffe760   0x7fffffffe760
rsp            0x7fffffffe760   0x7fffffffe760
r8             0x7ffff7dd7e50   140737351876176
r9             0x7ffff7deb470   140737351955568
r10            0x7fffffffe600   140737488348672
r11            0x7ffff7a4df10   140737348165392
r12            0x400410 4195344
r13            0x7fffffffe840   140737488349248
r14            0x0  0
r15            0x0  0
rip            0x40050a 0x40050a <main+4>
eflags         0x246    [ PF ZF IF ]
cs             0x33 51
ss             0x2b 43
ds             0x0  0
es             0x0  0
fs             0x0  0
gs             0x0  0