はじめに
世界の中心で愛を叫ぼうとしたが、そもそも世界の中心がどこかわからなかった。 ということで、アセンブリ言語の中心で愛を叫ぶことにした。
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