Updated: 2022-10-30, Posted: 2022-10-30
まずは、x64はどんなレジスタがあるのか。
64bit | 下位32bit | 下位16bit | 下位8bit | 用途 |
---|---|---|---|---|
RAX | EAX | AX | AL | 汎用 |
RCX | ECX | CX | CL | 汎用 |
RDX | EDX | DX | DL | 汎用 |
RBX | EBX | BX | BL | 汎用 |
RSI | ESI | SI | SIL | 汎用 |
RDI | EDI | DI | DIL | 汎用 |
RSP | ESP | SP | SPL | スタックポインタレジスタ |
RBP | EBP | BP | BPL | ベースポインタレジスタ |
R8 | R8D | R8W | R8B | 汎用 |
R9 | R9D | R9W | R9B | 汎用 |
R10 | R10D | R10W | R10B | 汎用 |
R11 | R11D | R11W | R11B | 汎用 |
R12 | R12D | R12W | R12B | 汎用 |
R13 | R13D | R13W | R13B | 汎用 |
R14 | R14D | R14W | R14B | 汎用 |
R15 | R15D | R15W | R15B | 汎用 |
RIP | インストラクションポインタ |
RCX、RDX、R8、および R9
R10,R11
R12,R13,R14,R15,RDI,RSI,RBX,RBP
void entry()
{
func();
}
void func()
{
return;
}
0000000000401000 <entry>:
401000: 48 83 ec 28 sub $0x28,%rsp
401004: e8 07 00 00 00 callq 401010 <func>
401009: 90 nop
40100a: 48 83 c4 28 add $0x28,%rsp
40100e: c3 retq
40100f: 90 nop
0000000000401010 <func>:
401010: c3 retq
401011: 0f 1f 80 00 00 00 00 nopl 0x0(%rax)
0x100+8確保されている
8はアライメントのためかもしれない。(16byteでアライメントしないといけないため)
pushはSPを引いてからストア
スタック | 内容 |
---|---|
0x1000 | str[0] ここが必ず16byteでオフセットされる。 |
0x10FF | str[256] |
0x1108 | アライメント |
0x1110 | リターンアドレス |
// clang abi_test_002.c -o a.exe -eentry -nostartfiles -nostdlib -mwindows -luser32
// objdump -d a.exe
void func()
{
char str[256];
return;
}
void entry()
{
func();
}
0000000000401000 <func>:
401000: 48 81 ec 08 01 00 00 sub $0x108,%rsp
401007: 48 81 c4 08 01 00 00 add $0x108,%rsp
40100e: c3 retq
40100f: 90 nop
0000000000401010 <entry>:
401010: 48 83 ec 28 sub $0x28,%rsp
401014: e8 e7 ff ff ff callq 401000 <func>
401019: 90 nop
40101a: 48 83 c4 28 add $0x28,%rsp
40101e: c3 retq
40101f: 90 nop
// clang abi_test_003.c -o a.exe -eentry -nostartfiles -nostdlib -mwindows -luser32
// objdump -d a.exe
int func()
{
return 1;
}
void entry()
{
func();
}
0000000000401000 <func>:
401000: b8 01 00 00 00 mov $0x1,%eax
401005: c3 retq
401006: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1)
40100d: 00 00 00
0000000000401010 <entry>:
401010: 48 83 ec 28 sub $0x28,%rsp
401014: e8 e7 ff ff ff callq 401000 <func>
401019: 90 nop
40101a: 48 83 c4 28 add $0x28,%rsp
40101e: c3 retq
40101f: 90 nop
スタック | 内容 | RSPの参照先 |
---|---|---|
0x1108 | RAXの値 | <-ここ |
0x1110 | リターンアドレス |
スタック | 内容 | RSPの参照先 |
---|---|---|
0x1108 | RAXの値(下位32bitは破壊される) | <-ここ |
0x110C | 引数1 | |
0x1110 | リターンアドレス |
401000、401009のpush、popが意味分からないが、
おそらくsubするより早いから使っているのだろう。RAX,RCXに意味はないのだろう。
// clang -o a.exe -eentry -nostartfiles -nostdlib -mwindows -luser32 abi_test_004.c
// objdump -d a.exe
int func(int a)
{
return a;
}
void entry()
{
func(10);
}
0000000000401000 <func>:
401000: 50 push %rax
401001: 89 4c 24 04 mov %ecx,0x4(%rsp)
401005: 8b 44 24 04 mov 0x4(%rsp),%eax
401009: 59 pop %rcx
40100a: c3 retq
40100b: 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1)
0000000000401010 <entry>:
401010: 48 83 ec 28 sub $0x28,%rsp
401014: b9 0a 00 00 00 mov $0xa,%ecx
401019: e8 e2 ff ff ff callq 401000 <func>
40101e: 90 nop
40101f: 48 83 c4 28 add $0x28,%rsp
401023: c3 retq
401024: 0f 1f 40 00 nopl 0x0(%rax)
スタック | 内容 | RSPの参照先 |
---|---|---|
0x1108 | RAXの値 | <-ここ |
0x1110 | リターンアドレス |
スタック | 内容 | RSPの参照先 |
---|---|---|
0x1108 | RAXの値 | <-ここ |
0x110C | 引数1 | |
0x1110 | リターンアドレス |
スタック | 内容 | RSPの参照先 |
---|---|---|
0x1108 | ローカル変数 | <-ここ |
0x110C | 引数1 | |
0x1110 | リターンアドレス |
401011からのNOPが興味深い
// clang -o a.exe -eentry -nostartfiles -nostdlib -mwindows -luser32 abi_test_005.c
// objdump -d a.exe
int func(int a)
{
int b;
b = a;
return b;
}
void entry()
{
func(10);
}
0000000000401000 <func>:
401000: 50 push %rax
401001: 89 4c 24 04 mov %ecx,0x4(%rsp)
401005: 8b 44 24 04 mov 0x4(%rsp),%eax
401009: 89 04 24 mov %eax,(%rsp)
40100c: 8b 04 24 mov (%rsp),%eax
40100f: 59 pop %rcx
401010: c3 retq
401011: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1)
401018: 00 00 00
40101b: 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1)
0000000000401020 <entry>:
401020: 48 83 ec 28 sub $0x28,%rsp
401024: b9 0a 00 00 00 mov $0xa,%ecx
401029: e8 d2 ff ff ff callq 401000 <func>
40102e: 90 nop
40102f: 48 83 c4 28 add $0x28,%rsp
401033: c3 retq
401034: 0f 1f 40 00 nopl 0x0(%rax)
push,popがsub,addにやはり変わっている。
スタック | 内容 | RSPの参照先 |
---|---|---|
0x1100 | <-ここ | |
0x1108 | ||
0x1110 | リターンアドレス |
スタック | 内容 | RSPの参照先 |
---|---|---|
0x1100 | ローカル変数 | <-ここ |
0x1108 | rcx 引数1 | |
0x1110 | リターンアドレス |
// clang -o a.exe -eentry -nostartfiles -nostdlib -mwindows -luser32 abi_test_006.c
// objdump -d a.exe
int func(long long int a)
{
long long int b;
b = a;
return b;
}
void entry()
{
func(10);
}
0000000000401000 <func>:
401000: 48 83 ec 10 sub $0x10,%rsp
401004: 48 89 4c 24 08 mov %rcx,0x8(%rsp)
401009: 48 8b 44 24 08 mov 0x8(%rsp),%rax
40100e: 48 89 04 24 mov %rax,(%rsp)
401012: 48 8b 04 24 mov (%rsp),%rax
401016: 48 83 c4 10 add $0x10,%rsp
40101a: c3 retq
40101b: 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1)
0000000000401020 <entry>:
401020: 48 83 ec 28 sub $0x28,%rsp
401024: b9 0a 00 00 00 mov $0xa,%ecx
401029: e8 d2 ff ff ff callq 401000 <func>
40102e: 90 nop
40102f: 48 83 c4 28 add $0x28,%rsp
401033: c3 retq
401034: 0f 1f 40 00 nopl 0x0(%rax)
スタック | 内容 | RSPの参照先 |
---|---|---|
0x1100 | <-ここ | |
0x1104 | ローカル変数 | |
0x1108 | EDX | |
0x110C | ECX | |
0x1110 | リターンアドレス |
// clang -o a.exe -eentry -nostartfiles -nostdlib -mwindows -luser32 abi_test_007.c
// objdump -d a.exe
int func(int a, int b)
{
int c;
c = a;
return b;
}
void entry()
{
func(10, 1);
}
0000000000401000 <func>:
401000: 48 83 ec 10 sub $0x10,%rsp
401004: 89 4c 24 0c mov %ecx,0xc(%rsp)
401008: 89 54 24 08 mov %edx,0x8(%rsp)
40100c: 8b 44 24 0c mov 0xc(%rsp),%eax
401010: 89 44 24 04 mov %eax,0x4(%rsp)
401014: 8b 44 24 08 mov 0x8(%rsp),%eax
401018: 48 83 c4 10 add $0x10,%rsp
40101c: c3 retq
40101d: 0f 1f 00 nopl (%rax)
0000000000401020 <entry>:
401020: 48 83 ec 28 sub $0x28,%rsp
401024: b9 0a 00 00 00 mov $0xa,%ecx
401029: ba 01 00 00 00 mov $0x1,%edx
40102e: e8 cd ff ff ff callq 401000 <func>
401033: 90 nop
401034: 48 83 c4 28 add $0x28,%rsp
401038: c3 retq
401039: 0f 1f 80 00 00 00 00 nopl 0x0(%rax)
呼び出し元で確保している引数1,2,3,4用の領域をなぜか呼び出し先で使用していないのが興味深い。
entry()でcallする直前のスタック状態
スタック | 内容 | RSPの参照先 |
---|---|---|
0x00 | 引数1用の予約領域 | <-ここ |
0x04 | ||
0x08 | 引数2用の予約領域 | |
0x0C | ||
0x10 | 引数3用の予約領域 | |
0x14 | ||
0x18 | 引数4用の予約領域 | |
0x1C | ||
0x20 | 引数5 | |
0x24 | ||
0x28 | 引数6 | |
0x2C |
func()内でのスタック状態
スタック | 内容 | RSPの参照先 |
---|---|---|
0x00 | ローカル変数 | <-ここ |
0x08 | 引数4 | |
0x0C | 引数3 | |
0x10 | (EDX)引数2 | |
0x14 | (ECX)引数1 | |
0x18 | リターンアドレス | |
0x20 | 引数1用の予約領域 | |
0x24 | ||
0x28 | 引数2用の予約領域 | |
0x2C | ||
0x30 | 引数3用の予約領域 | |
0x34 | ||
0x38 | 引数4用の予約領域 | |
0x3C | ||
0x40 | 引数5 | |
0x44 | ||
0x48 | 引数6 | |
0x4C |
// clang -o a.exe -eentry -nostartfiles -nostdlib -mwindows -luser32 abi_test_008.c
// objdump -d a.exe
int func(int a, int b, int c, int d, int e, int f)
{
int g;
g = a;
return g;
}
void entry()
{
func(1, 2, 3, 4, 5, 6);
}
0000000000401000 <func>:
401000: 48 83 ec 18 sub $0x18,%rsp
401004: 8b 44 24 48 mov 0x48(%rsp),%eax
401008: 44 8b 54 24 40 mov 0x40(%rsp),%r10d
40100d: 89 4c 24 14 mov %ecx,0x14(%rsp)
401011: 89 54 24 10 mov %edx,0x10(%rsp)
401015: 44 89 44 24 0c mov %r8d,0xc(%rsp)
40101a: 44 89 4c 24 08 mov %r9d,0x8(%rsp)
40101f: 8b 4c 24 14 mov 0x14(%rsp),%ecx
401023: 89 4c 24 04 mov %ecx,0x4(%rsp)
401027: 8b 4c 24 04 mov 0x4(%rsp),%ecx
40102b: 89 04 24 mov %eax,(%rsp)
40102e: 89 c8 mov %ecx,%eax
401030: 48 83 c4 18 add $0x18,%rsp
401034: c3 retq
401035: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1)
40103c: 00 00 00
40103f: 90 nop
0000000000401040 <entry>:
401040: 48 83 ec 38 sub $0x38,%rsp
401044: b9 01 00 00 00 mov $0x1,%ecx
401049: ba 02 00 00 00 mov $0x2,%edx
40104e: 41 b8 03 00 00 00 mov $0x3,%r8d
401054: 41 b9 04 00 00 00 mov $0x4,%r9d
40105a: c7 44 24 20 05 00 00 movl $0x5,0x20(%rsp)
401061: 00
401062: c7 44 24 28 06 00 00 movl $0x6,0x28(%rsp)
401069: 00
40106a: e8 91 ff ff ff callq 401000 <func>
40106f: 90 nop
401070: 48 83 c4 38 add $0x38,%rsp
401074: c3 retq
401075: 0f 1f 00 nopl (%rax)
RSI→RDI→RBP→RBX→R15→R14→R13→R12と使用していく。
最終的にはスタックを使用する。
R10,R11は呼び出し元で保存しているはずなので自由に使っている。
// clang -o a.exe -eentry -nostartfiles -nostdlib -mwindows -luser32 abi_test_008.c
// objdump -d a.exe
int func(int a, int b, int c, int d, int e, int f)
{
int g;
g = ((a * b) + ((c * d) + ((e * f) + ((a * c) + ((a * c) + ((a * c) + ((a * c) + ((a * c) + (a * c)))))))));
return g;
}
void entry()
{
func(1, 2, 3, 4, 5, 6);
}
0000000000401000 <func>:
401000: 56 push %rsi
401001: 57 push %rdi
401002: 55 push %rbp
401003: 53 push %rbx
401004: 48 83 ec 18 sub $0x18,%rsp
401008: 8b 44 24 68 mov 0x68(%rsp),%eax
40100c: 44 8b 54 24 60 mov 0x60(%rsp),%r10d
401011: 89 4c 24 14 mov %ecx,0x14(%rsp)
401015: 89 54 24 10 mov %edx,0x10(%rsp)
401019: 44 89 44 24 0c mov %r8d,0xc(%rsp)
40101e: 44 89 4c 24 08 mov %r9d,0x8(%rsp)
401023: 8b 4c 24 14 mov 0x14(%rsp),%ecx
401027: 0f af 4c 24 10 imul 0x10(%rsp),%ecx
40102c: 8b 54 24 0c mov 0xc(%rsp),%edx
401030: 0f af 54 24 08 imul 0x8(%rsp),%edx
401035: 44 8b 44 24 60 mov 0x60(%rsp),%r8d
40103a: 44 0f af 44 24 68 imul 0x68(%rsp),%r8d
401040: 44 8b 4c 24 14 mov 0x14(%rsp),%r9d
401045: 44 0f af 4c 24 0c imul 0xc(%rsp),%r9d
40104b: 44 8b 5c 24 14 mov 0x14(%rsp),%r11d
401050: 44 0f af 5c 24 0c imul 0xc(%rsp),%r11d
401056: 8b 74 24 14 mov 0x14(%rsp),%esi
40105a: 0f af 74 24 0c imul 0xc(%rsp),%esi
40105f: 8b 7c 24 14 mov 0x14(%rsp),%edi
401063: 0f af 7c 24 0c imul 0xc(%rsp),%edi
401068: 8b 5c 24 14 mov 0x14(%rsp),%ebx
40106c: 0f af 5c 24 0c imul 0xc(%rsp),%ebx
401071: 8b 6c 24 14 mov 0x14(%rsp),%ebp
401075: 0f af 6c 24 0c imul 0xc(%rsp),%ebp
40107a: 01 eb add %ebp,%ebx
40107c: 01 df add %ebx,%edi
40107e: 01 fe add %edi,%esi
401080: 41 01 f3 add %esi,%r11d
401083: 45 01 d9 add %r11d,%r9d
401086: 45 01 c8 add %r9d,%r8d
401089: 44 01 c2 add %r8d,%edx
40108c: 01 d1 add %edx,%ecx
40108e: 89 4c 24 04 mov %ecx,0x4(%rsp)
401092: 8b 4c 24 04 mov 0x4(%rsp),%ecx
401096: 89 04 24 mov %eax,(%rsp)
401099: 89 c8 mov %ecx,%eax
40109b: 48 83 c4 18 add $0x18,%rsp
40109f: 5b pop %rbx
4010a0: 5d pop %rbp
4010a1: 5f pop %rdi
4010a2: 5e pop %rsi
4010a3: c3 retq
4010a4: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1)
4010ab: 00 00 00
4010ae: 66 90 xchg %ax,%ax
00000000004010b0 <entry>:
4010b0: 48 83 ec 38 sub $0x38,%rsp
4010b4: b9 01 00 00 00 mov $0x1,%ecx
4010b9: ba 02 00 00 00 mov $0x2,%edx
4010be: 41 b8 03 00 00 00 mov $0x3,%r8d
4010c4: 41 b9 04 00 00 00 mov $0x4,%r9d
4010ca: c7 44 24 20 05 00 00 movl $0x5,0x20(%rsp)
4010d1: 00
4010d2: c7 44 24 28 06 00 00 movl $0x6,0x28(%rsp)
4010d9: 00
4010da: e8 21 ff ff ff callq 401000 <func>
4010df: 90 nop
4010e0: 48 83 c4 38 add $0x38,%rsp
4010e4: c3 retq
4010e5: 0f 1f 00 nopl (%rax)
401000: 41 57 push %r15
401002: 41 56 push %r14
401004: 41 55 push %r13
401006: 41 54 push %r12
401008: 56 push %rsi
401009: 57 push %rdi
40100a: 55 push %rbp
40100b: 53 push %rbx
40100c: 48 83 ec 28 sub $0x28,%rsp
401010: 8b 84 24 98 00 00 00 mov 0x98(%rsp),%eax 引数6をEAXへ
401017: 44 8b 94 24 90 00 00 mov 0x90(%rsp),%r10d 引数5をR10Dへ
40101e: 00
40101f: 89 4c 24 24 mov %ecx,0x24(%rsp)
401023: 89 54 24 20 mov %edx,0x20(%rsp)
401027: 44 89 44 24 1c mov %r8d,0x1c(%rsp)
40102c: 44 89 4c 24 18 mov %r9d,0x18(%rsp)
...なにかしらの処理...
401111: 8b 44 24 14 mov 0x14(%rsp),%eax
401115: 48 83 c4 28 add $0x28,%rsp
401119: 5b pop %rbx
40111a: 5d pop %rbp
40111b: 5f pop %rdi
40111c: 5e pop %rsi
40111d: 41 5c pop %r12
40111f: 41 5d pop %r13
401121: 41 5e pop %r14
401123: 41 5f pop %r15
401125: c3 retq