アセンブリ言語とは
📝機械語を人間にわかりやすい形で記述する、代表的な低水準言語である.
一般的には最適化コンパイラが人手で書かれたアセンブリ言語のコードと同等の性能を発揮すると言われている.
メモリ
Memory Layout
2^n-1
|---------------------|
| Stacks | ローカル変数, プロシージャの内容
| |
| Dynamic Data (Heap) | new や malloc で獲得できる領域
| Static Data | グローバル変数など.
| Literals | 文字列
| Instructions | プログラム. 関数
|---------------------|
0ISA
命令セットアーキテクチャ. (Instruction Set Architecture)
コンピュータのハードウェアに対して命令を伝えるための言葉の語彙.
x86, x64 (x86-64) ISA
インテルや AMD の ISA. 32bit が x86, 64bit が x64.
x86, x86-64 ISA の文法
レジスタ
load / store
- Load data from memory into %reg = Mem[address]
- Store register data into memory Mem[address] = %reg
メモリからメモリへのデータ移動は一回の操作ではできない. Cannot do memory--memory transfer with a single instruction.
レジスタの種類
-
eax, ecx, edx, ebx, esp, ebp, esi, edi … 汎用レジスタ (32 ビット)
-
rax, rcx, rdx, rbx, rsp, rbp, rsi, rdi, r8~15 … 汎用レジスタ (64 ビット)
-
eflags … フラグレジスタ (32 ビット)
-
rflags … フラグレジスタ (64 ビット)
-
eip … プログラムカウンタ (32 ビット)
-
rip … プログラムカウンタ (64 ビット)
-
st (0)~(7) … FPU レジスタ
-
FPU ステータスレジスタ … FPU ステータスレジスタ
-
FPU コントロールレジスタ … FPU コントロールレジスタ
-
xmm0~7 … XMM レジスタ
-
mxcsr … MXCSR コントロール&ステータスレジスタ
参考リンク.
-
x86 registers
caller-Save %eax caller-Save %edx caller-Save %ecx callee-Save %ebx callee-Save %esi callee-Save %edi Special %esp Special %ebp
-
x64 registers
rax return value rbx Caller Saved rcx Argument#4 rdx Argument#3 rsi Argument#2 rdi Argument#1 rsp Stack Pointer rbp Callee saved r8 Argument#5 r9 Argument#6 r10 Caller Saved r11 Caller Saved r12 Callee Saved r13 Callee Saved r14 Callee Saved r15 Callee Saved
汎用レジスタ
-
%eax,%edx, %ecx
Caller saves prior to call if values are used later. 呼び出し元が引数を渡すために利用.
-
%eax
サブルーチンからの戻り値を受けとるために利用することがおおい.
-
%ebx, %esi, %edi
Callee saves if wants to use them.
ベースレジスタ %rsb, %esp
スタックレジスタ %rsp, &esp
スタックポインタはサブルーチンコールの戻りアドレスをメモリに自動的に格納したり, PUSH, POP 命令でレジスタを一時的に退避, 復帰する場合に使われます.
プログラムカウンタ %rip, %eip
次に実行する命令のアドレス
命令
mov
mov 命令は src オペランドを dest オペランドにコピーします.
mov src, destpush, pop
スタックを操作するための命令. スタックとは, ebp と esp ではさまれたメモリのこと.
|---| %ebp
| |
| |
| |
|---| %esp- push スタックに値を入れる
- Fetch value from Src
- Decrement%esp by 4
- Store value at address given by %esp
- pop スタックから値を取り出す
- Load value from address %esp
- Write value to Dest
- Increment %esp by 4
- leave 以下の二つの instruction との糖衣構文
- mov %ebp, %esp
- pop %ebp
call, ret
関数に飛ぶ.
400e79: e8 bf 03 00 00 callq 40123d <strings_not_equal>ret でサブルーチンを抜ける
add, sub
- 加減算
- add eax, ecx => eax = eax + ec
lea
Address Computa?on Instruction . アドレス計算命令. lea 命令は, src オペランドのアドレスを計算し, そのアドレスを dest オペランドにロードします.
lea src, destjmp
- jmp 無条件ジャンプ
- jc, jnc CF が立っているかどうか
- jz, jnz ZF が立っているかどうか
- js, jns SF が立っているかどうか
- jo, jno OF が立っているかどうか
test
- 論理積
- test eax, eax
- eax=0 なら ZF=1 となるので , jz 命令などで分岐
cmp
- 比較
- cmp eax, 0
- eax=0 なら ZF=1 となるので , jz 命令などで分岐
xor
- 排他的論理和
- xor eax, eax
- 同じ値同士なら 0 になるので, test や cmp の準備に多用される.
x86-64 Calling Conventions (呼出規約)
プログラムで関数を呼び出す際に, レジスタやスタックを使いどのように引数を渡すか, 戻り値をどのように受け取るかは呼出規約 (calling convention) で決められている
the x86-64 ISA passes the first six arguments to a function in registers. Registers are used in the following order:
rdi, rsi, rdx, rcx, r8, r9.
The return value for functions is passed in rax.
サブルーチンプロローグ
_function:
push ebp ;ベースポインタを保存
mov ebp, esp ;現在のスタックフレームを指すようベースポインタを変更
sub esp, x ;局所変数 (C でいう自動変数) の大きさの分スタックポインタを減らすサブルーチンエピローグ
mov esp, ebp ;局所変数を除去
pop ebp ;ベースポインタを復帰
ret ;サブルーチンから戻る制御構文
if
すべて, 「二者を比べ」て「結果によってジャンプ」.
int absdiff (int x, int y)
{
int result;
if (x > y) {
result = x-y;
} else {
result = y-x;
}
return result;
}
int goto_ad ( int x, int y)
{
int result;
if (x <= y)
goto Else ;
result = x-y;
Exit :
return result;
Else: result = y-x;
goto Exit ;
}int x %edx
int y %eax
absdiff :
pushl %ebp
movl %esp , %ebp
; body
movl 8 (%ebp), %edx
movl 12 (%ebp), %eax
cmpl %eax , %edx ;
jle .L7
; body end
subl %eax , %edx ; y-x
movl %edx , %eax
.L8:
leave ret
.L7:
subl %edx , %eax ; x-y
jmp .L8while
while ( sum != 0 ) {
<loop body>
}loopTop: cmpl $0, %eax
je loopDone
<loop body code>
jmp loopTop
loopDone:for
for は while の糖衣構文.
switch
Jump Table (indirect jmp) を利用する.
[jump table のアドレス + 8 * (引数)] で求められるアドレスの値 (switch 先のアドレスが格納されている) を参照して, そのアドレスにジャンプする.2 回ジャンプする. それが Indirect という意味.
- Direct: jmp .L61
- Jump target is denoted by label .L61
- Indirect: jmp *.L62 (,%edx,4)
- Start of jump table: . L62
- Must scale by factor of 4 (labels are 32-bits = 4 bytes on IA32)
- Fetch target from effective address .L62 + edx*4
Tools
gdb
デバッカ.
コンパイル時に-g g -O0 オブションをつける必要がある.
$ gcc -g g -O0 ソースコード名| オプション | 意味 |
|---|---|
| -g | ファイルにデバッグ情報を付加する. |
| これがないとデバッグ時に変数名や行番号が表示されない | |
| -O0 | 最適化を行わない. 最適化を行うと, |
| コードの入れ替えや削除が行われてしまい, デバッグしにくくなる |
ステップ実行
-
run (r)
プログラムの実行.
-
step (s)
プログラムをステップ実行. ステップオーバー.
-
stepi
アセンブリコードのステップ実行.
-
next (n)
プログラムをステップ実行. ステップイン.
-
cont (c)
プログラムの再開.
ブレークポイント操作
-
breakpoint (b)
ブレークポイントをはる.
(gdb) b 行番号 (gdb) b 関数名 (gdb) b ファイル名:行番号
-
info b
ブレークポイントの情報を表示.
-
delete (d)
ブレークポイントのクリア.
メモリ情報
-
disas
アセンブリコードの表示
-
info register (info reg)
レジスタの情報を表示
-
x
メモリの状態表示, x/[表示する個数][出力書式][出力単位]
出力単位 意味 b 1 バイト h 2 バイト w 4 バイト g 8 バイト (gdb) x/6xwステップカウンタの 3 ステップ先までを表示
(gdb) x /3i $ripカレントスタックポインタからの情報を表示
(gdb) x /30x $rsp (gdb) x /30xg $rspアドレスの値を文字で表示
(gdb) x /s $eax
-
info locals (i lo)
ローカル変数表示.
その他
-
バックトレース (bt)
バックトレースとは, ユーザ・プログラムが現在いる箇所にどのようにして到達したかを示す要約情報
(gdb) bt #0 0x000000000040174e in read_six_numbers () #1 0x0000000000400eac in phase_2 () #2 0x0000000000400dd5 in main (argc=<optimized out>, argv=0x7fffffffdb58) at bom
Links
objdump
- t ファイルのシンボルテーブルエントリを表示します. nm によって得られる情報とほぼ同じ
- T ファイルの動的なシンボルテーブルエントリを表示します. 「nm -D」とほぼ同じ
- S (可能であれば) ソースコードを逆アセンブル結果と混在させて表示します
- d Use this to disassemble all of the code.
nm
オブジェクトファイルのシンボルをリストする.
Reference
- Intel ® 64 and IA-32 Architectures Software Developer’s Manual V2
- Support & Drivers
- GNU アセンブラ入門 (GAS)