プログラムはなぜ動くのか - ニーモニックをまとめてみる
最近アセンブリ言語の章を読む際に、コードを書きながらアセンブリを出力させて遊んでいるのだが、
オペコード/オペランドの種類
まずは、オペコード/オペランドの種類を表にまとめてみた。オペコード | オペランド | 機能 |
push | A | Aの値をスタックに格納 |
pop | A | スタックから値を取りだしAに格納 |
mov | A B | Aの値をBに格納 |
sub | A B | Bの値からAの値を引いてBに格納 |
lea | A B | Aのアドレスが指す領域の値をBに格納?? |
and | A B | Bの値をAでアラインしてBに格納 |
call | A | Aという手続きを呼び出す |
leave | これ何?? | |
ret | 手続きの読みだし元に処理を戻す | |
ちなみにmovの場合だと、movb、movw、movlなど後ろに1文字付くものが出てくる。これは取り扱う変数の桁に応じて変わるみたいで、
- 32bit (int型/long型) の場合、movl
- 16bit (short型) の場合、movw
- 8bit (char型) の場合、movb
例
以下のような、ソースコードを用意void func( void )
{
char a;
short b;
int c;a = 1;
b = 2;
c = 3;
}
コンパイルしてobjdumpしてみる。
$ gcc -g -c -O0 show-opcode.c -o show-opcode
$ objdump -S show-opcode > show-opcode.asm
gccのオプションで"-g"、objdumpのオプションで"-S"を付けると、アセンブラコードにソースコードを混ぜたものを出力してくれる。
アセンブラのコードを見ると、
show-opcode: file format elf32-i386Disassembly of section .text:
00000000
: void func( void )
{
0: 55 push %ebp
1: 89 e5 mov %esp,%ebp
3: 83 ec 10 sub $0x10,%esp
char a;
short b;
int c;a = 1;
6: c6 45 ff 01 movb $0x1,0xffffffff(%ebp)
b = 2;
a: 66 c7 45 fc 02 00 movw $0x2,0xfffffffc(%ebp)
c = 3;
10: c7 45 f8 03 00 00 00 movl $0x3,0xfffffff8(%ebp)
}
17: c9 leave
18: c3 ret
movb、movw、movlと分けて使われていることがわかる。
レジスタの種類
これもプロセッサによって異なるらしいが、以下の種類のレジスタがあるみたい。レジスタ名 | 名前 | 主な機能 |
eax | アキュムレータ | 演算に使う |
ebx | ベース・レジスタ | メモリアドレスを格納 |
ecx | カウント・レジスタ | ループ回数をカウント |
ebp | ベースポインタ・レジスタ | データを格納する領域のメモリアドレスを格納 |
esp | スタックポインタ・レジスタ | スタック領域のメモリアドレス(=スタックポインタ)を格納 |
レジスタ名の頭に"e"が付くのは、元々はレジスタのサイズは16bitでありレジスタ名もax、bx、…だったらしいが、そのレジスタを32bitに拡張した時の名残で"e"が付いたらしい。
アセンブリのコード例
以上を踏まえて、いくつか例を上げてみる。pop %ebpスタック領域から値を取りだし、ベースポインタ・レジスタに格納する。
ちなみに、レジスタの前には"%"プリフィックスを付けるのがルールらしい。
mov %esp, %ebpスタックポインタ・レジスタの値を、ベースポインタ・レジスタに格納する。
すなわち、現時点でのスタックポインタを他のレジスタに退避させている。
mov -8(%ebp), %eax"(%レジスタ)"と括弧が付く場合は、「レジスタが格納しているアドレスのメモリ」と解釈される。
さらに括弧の前の値はオフセットを表していて、"オフセット(%レジスタ)"の場合は「レジスタが格納しているアドレス+オフセットのメモリ」と解釈させる。
よって、ebpに格納しているアドレス+オフセットのメモリの値をアキュムレータに格納する、ということになる。
図にしてみた
文章で書いていても分かりにくいので、OOoで図に書いてみた。こんな感じで合っているだろうか。ちなみに、間違えてpopとすべきところをpopl、movとすべき所をmovlとしてしまってます… そこは読み替えて下さい (--; → 直しました。
続きはまた今度。