1 X86_64寄存器使用標準
- %rdi, %rsi, %rdx, %rcx, %r8, %r9分別用于函數(shù)調(diào)用過程中的前6個參數(shù),對于6的參數(shù)存放在棧中傳遞
- %rsp用做棧指針寄存器,指向棧頂
- %rbp用作??蚣拇嫫鳎赶驐5?/li>
- %rax用做函數(shù)返回值的第一個寄存器
2 對應代碼的分析
2.1 main函數(shù)及其對應的匯編程序
int main(void)
{
long a = 1;
long b = 2;
printf("The current function is %s a:%ld b:%ld\r\n", __func__, a, b);
test_fun_a(a, b, 0, 1);
a = a + b;
b = a + b;
return 0;
}
2.1.1 main的C代碼實現(xiàn)
2.1.2 main函數(shù)對應匯編及其分析
這段匯編代碼實現(xiàn)了一個簡單的程序,其功能如下:
- 首先,
endbr64
指令用于清除處理器的前瞻指令緩存,確保后面的指令正確執(zhí)行。 -
push %rbp
和mov %rsp,%rbp
這兩個指令用于保存和設置棧幀的基址指針(Base Pointer)。 -
sub $0x10,%rsp
指令用于為局部變量和保存的寄存器值分配棧空間。 -
movq $0x1,-0x10(%rbp)
和movq $0x2,-0x8(%rbp)
這兩個指令用于將字面量1和2存儲到棧中的特定位置。 -
mov -0x8(%rbp),%rdx
和mov -0x10(%rbp),%rax
這兩個指令用于從棧中獲取之前保存的值。 -
mov %rdx,%rcx
和mov %rax,%rdx
這兩個指令用于將寄存器的值進行傳遞,為后面的函數(shù)調(diào)用做準備。 -
lea 0xdf8(%rip),%rsi
和lea 0xda6(%rip),%rdi
這兩個指令用于設置printf函數(shù)的參數(shù),分別對應格式字符串和要打印的變量。 -
mov $0x0,%eax
指令用于設置系統(tǒng)調(diào)用的編號(這里為0,即系統(tǒng)調(diào)用號)。 -
callq 1050 <printf@plt>
這個指令發(fā)起系統(tǒng)調(diào)用,執(zhí)行printf函數(shù),打印輸出指定的字符串和數(shù)值。 - 接下來,
mov -0x8(%rbp),%rsi
、mov -0x10(%rbp),%rax
、mov $0x1,%ecx
、mov $0x0,%edx
和mov %rax,%rdi
這些指令用于設置函數(shù)test_fun_a
的參數(shù)。 -
callq 11e8 <test_fun_a>
這個指令調(diào)用函數(shù)test_fun_a
,執(zhí)行其代碼。 - 在函數(shù)
test_fun_a
執(zhí)行完成后,通過一系列的移動和加法操作,將返回值存儲回原始的參數(shù)位置。 - 最后,
mov $0x0,%eax
、leaveq
和retq
這些指令用于清理棧幀、結束當前函數(shù)并返回。
這段匯編代碼的功能是調(diào)用函數(shù)test_fun_a
,并打印輸出兩個數(shù)值1和2,然后調(diào)用函數(shù)test_fun_a
并將返回值存儲回原始的參數(shù)位置。
000000000000128a <main>:
128a: f3 0f 1e fa endbr64
128e: 55 push %rbp
128f: 48 89 e5 mov %rsp,%rbp
1292: 48 83 ec 10 sub $0x10,%rsp
1296: 48 c7 45 f0 01 00 00 movq $0x1,-0x10(%rbp)
129d: 00
129e: 48 c7 45 f8 02 00 00 movq $0x2,-0x8(%rbp)
12a5: 00
12a6: 48 8b 55 f8 mov -0x8(%rbp),%rdx
12aa: 48 8b 45 f0 mov -0x10(%rbp),%rax
12ae: 48 89 d1 mov %rdx,%rcx
12b1: 48 89 c2 mov %rax,%rdx
12b4: 48 8d 35 f8 0d 00 00 lea 0xdf8(%rip),%rsi # 20b3 <__func__.2519>
12bb: 48 8d 3d a6 0d 00 00 lea 0xda6(%rip),%rdi # 2068 <_IO_stdin_used+0x68>
12c2: b8 00 00 00 00 mov $0x0,%eax
12c7: e8 84 fd ff ff callq 1050 <printf@plt>
12cc: 48 8b 75 f8 mov -0x8(%rbp),%rsi
12d0: 48 8b 45 f0 mov -0x10(%rbp),%rax
12d4: b9 01 00 00 00 mov $0x1,%ecx
12d9: ba 00 00 00 00 mov $0x0,%edx
12de: 48 89 c7 mov %rax,%rdi
12e1: e8 02 ff ff ff callq 11e8 <test_fun_a>
12e6: 48 8b 45 f8 mov -0x8(%rbp),%rax
12ea: 48 01 45 f0 add %rax,-0x10(%rbp)
12ee: 48 8b 45 f0 mov -0x10(%rbp),%rax
12f2: 48 01 45 f8 add %rax,-0x8(%rbp)
12f6: b8 00 00 00 00 mov $0x0,%eax
12fb: c9 leaveq
12fc: c3 retq
12fd: 0f 1f 00 nopl (%rax)
2.1.3 執(zhí)行完成之后棧的存放情況
2.1.3.1 main函數(shù)執(zhí)行開棧以及局部變量壓棧之后的棧結構
2.1.3.2 main函數(shù)調(diào)用test_fun_a時的棧結構
- 執(zhí)行
callq 11e8 <test_fun_a>
時會把調(diào)用test_fun_a的返回地址壓到棧頂,會導致%rsp向下偏移8Byte
2.2 test_fun_a函數(shù)及其對應的匯編程序
2.2.1 test_fun_a函數(shù)的C實現(xiàn)
void test_fun_a(long m, long n, long x, long y)
{
long a = x;
long b = 2;
long c = 3;
printf("The current function is %s b:%ld c:%ld\r\n", __func__, b, c);
test_fun_b(b, c, a, 2);
b = b + c + m;
c = b + c + n;
}
2.2.2 test_fun_a函數(shù)對應匯編及其分析
這段匯編代碼是一個函數(shù)test_fun_a
的實現(xiàn),其功能大致如下:
-
push %rbp
和mov %rsp,%rbp
用于保存和設置棧幀的基址指針(Base Pointer)。 -
sub $0x40,%rsp
用于為局部變量和保存的寄存器值分配棧空間。 -
mov %rdi,-0x28(%rbp)
、mov %rsi,-0x30(%rbp)
、mov %rdx,-0x38(%rbp)
和mov %rcx,-0x40(%rbp)
用于將參數(shù)傳遞到棧幀中的指定位置。 -
mov %rax,-0x18(%rbp)
將某個值(可能是函數(shù)內(nèi)的臨時變量或計算結果)保存到棧幀的另一個位置。 -
movq $0x2,-0x10(%rbp)
和movq $0x3,-0x8(%rbp)
用于將字面量值2和3存儲到棧中的特定位置。 -
mov -0x8(%rbp),%rdx
和mov -0x10(%rbp),%rax
用于從棧中獲取之前保存的值。 -
lea 0xe77(%rip),%rsi
和lea 0xe00(%rip),%rdi
用于設置printf函數(shù)的參數(shù),分別對應格式字符串和要打印的變量。 -
mov $0x0,%eax
用于設置系統(tǒng)調(diào)用的編號(這里為0,即系統(tǒng)調(diào)用號)。 -
callq 1050 <printf@plt>
發(fā)起系統(tǒng)調(diào)用,執(zhí)行printf函數(shù),打印輸出指定的字符串和數(shù)值。 -
mov -0x18(%rbp),%rdx
、mov -0x8(%rbp),%rsi
、mov -0x10(%rbp),%rax
、mov $0x2,%ecx
和mov %rax,%rdi
用于設置函數(shù)test_fun_b
的參數(shù)。 -
callq 1149 <test_fun_b>
調(diào)用函數(shù)test_fun_b
,執(zhí)行其代碼。 - 在函數(shù)
test_fun_b
執(zhí)行完成后,將返回值存儲到棧幀的特定位置。 - 最后,通過一系列的移動和加法操作,將計算結果存儲回原始的第一個參數(shù)的位置。
-
48 8b 45 d0 mov -0x30(%rbp),%rax
: 將棧幀中偏移為-0x30的位置的值加載到寄存器rax中。 -
48 01 d0 add %rdx,%rax
: 將rax和rdx寄存器的值相加,并將結果存儲回rax寄存器中。 -
48 89 45 f8 mov %rax,-0x8(%rbp)
: 將rax寄存器的值存儲回棧幀中偏移為-0x8的位置。 -
90
: 無操作,用于填充指令。 -
c9
:leaveq
指令用于撤銷棧幀,恢復調(diào)用前的堆棧狀態(tài)。 -
c3
:retq
指令用于從當前函數(shù)返回,返回到調(diào)用者的代碼位置。
00000000000011e8 <test_fun_a>:
11e8: f3 0f 1e fa endbr64
11ec: 55 push %rbp
11ed: 48 89 e5 mov %rsp,%rbp
11f0: 48 83 ec 40 sub $0x40,%rsp
11f4: 48 89 7d d8 mov %rdi,-0x28(%rbp)
11f8: 48 89 75 d0 mov %rsi,-0x30(%rbp)
11fc: 48 89 55 c8 mov %rdx,-0x38(%rbp)
1200: 48 89 4d c0 mov %rcx,-0x40(%rbp)
1204: 48 8b 45 c8 mov -0x38(%rbp),%rax
1208: 48 89 45 e8 mov %rax,-0x18(%rbp)
120c: 48 c7 45 f0 02 00 00 movq $0x2,-0x10(%rbp)
1213: 00
1214: 48 c7 45 f8 03 00 00 movq $0x3,-0x8(%rbp)
121b: 00
121c: 48 8b 55 f8 mov -0x8(%rbp),%rdx
1220: 48 8b 45 f0 mov -0x10(%rbp),%rax
1224: 48 89 d1 mov %rdx,%rcx
1227: 48 89 c2 mov %rax,%rdx
122a: 48 8d 35 77 0e 00 00 lea 0xe77(%rip),%rsi # 20a8 <__func__.2513>
1231: 48 8d 3d 00 0e 00 00 lea 0xe00(%rip),%rdi # 2038 <_IO_stdin_used+0x38>
1238: b8 00 00 00 00 mov $0x0,%eax
123d: e8 0e fe ff ff callq 1050 <printf@plt>
1242: 48 8b 55 e8 mov -0x18(%rbp),%rdx
1246: 48 8b 75 f8 mov -0x8(%rbp),%rsi
124a: 48 8b 45 f0 mov -0x10(%rbp),%rax
124e: b9 02 00 00 00 mov $0x2,%ecx
1253: 48 89 c7 mov %rax,%rdi
1256: e8 ee fe ff ff callq 1149 <test_fun_b>
125b: 48 8b 55 f0 mov -0x10(%rbp),%rdx
125f: 48 8b 45 f8 mov -0x8(%rbp),%rax
1263: 48 01 c2 add %rax,%rdx
1266: 48 8b 45 d8 mov -0x28(%rbp),%rax
126a: 48 01 d0 add %rdx,%rax
126d: 48 89 45 f0 mov %rax,-0x10(%rbp)
1271: 48 8b 55 f0 mov -0x10(%rbp),%rdx
1275: 48 8b 45 f8 mov -0x8(%rbp),%rax
1279: 48 01 c2 add %rax,%rdx
127c: 48 8b 45 d0 mov -0x30(%rbp),%rax
1280: 48 01 d0 add %rdx,%rax
1283: 48 89 45 f8 mov %rax,-0x8(%rbp)
1287: 90 nop
1288: c9 leaveq
1289: c3 retq
2.2.3 執(zhí)行完成之后棧幀的使用情況
2.2.3.1 test_fun_a函數(shù)執(zhí)行開棧之后的棧結構示意圖
2.2.3.2 test_fun_a函數(shù)執(zhí)行參數(shù)壓棧以及局部變量壓棧之后的棧結構示意圖
2.2.3.3 test_fun_a函數(shù)調(diào)用test_fun_b之后的棧結構示意圖
-
callq 1149 <test_fun_b>
該調(diào)指令會導致%rsp向下偏移8Byte以保存test_fun_a函數(shù)調(diào)用test_fun_b的返回地址
2.3 test_fun_b函數(shù)及其對應的匯編程序
2.3.1 test_func_b函數(shù)的C實現(xiàn)
void test_fun_b(long m, long n, long x, long y)
{
long a = y;
long b = m;
long c = 3;
long d = 4;
printf("The current function is %s c:%ld d:%ld\r\n", __func__, c, d);
c = c + d + m + a;
d = c + d + n + b;
}
2.3.2 test_fun_b函數(shù)對應匯編及其分析
這段匯編代碼是一個函數(shù)test_fun_b
的實現(xiàn)。下面是對代碼的逐行解釋:
1149: f3 0f 1e fa
- endbr64
指令用于結束64位BR(Branch Prediction)指令的預測。
114d: 55
- push %rbp
將當前棧幀的基址指針(Base Pointer,簡稱RBp)壓入棧中,為新的棧幀做準備。
114e: 48 89 e5
- mov %rsp,%rbp
將當前棧幀的棧指針(Stack Pointer,簡稱SP)復制給基址指針(RBp),建立新的棧幀。
1151: 48 83 ec 40
- sub $0x40,%rsp
從SP中減去0x40個字節(jié),擴展棧空間。
1155: 48 89 7d d8
- mov %rdi,-0x28(%rbp)
將函數(shù)參數(shù)rdi的值存儲到當前棧幀的-0x28位置。
1159: 48 89 75 d0
- mov %rsi,-0x30(%rbp)
將函數(shù)參數(shù)rsi的值存儲到當前棧幀的-0x30位置。
115d: 48 89 55 c8
- mov %rdx,-0x38(%rbp)
將函數(shù)參數(shù)rdx的值存儲到當前棧幀的-0x38位置。
1161: 48 89 4d c0
- mov %rcx,-0x40(%rbp)
將函數(shù)參數(shù)rcx的值存儲到當前棧幀的-0x40位置。
1165: 48 8b 45 c0
- mov -0x40(%rbp),%rax
將當前棧幀的-0x40位置的值加載到寄存器rax中。
1169: 48 89 45 e0
- mov %rax,-0x20(%rbp)
將寄存器rax的值存儲到當前棧幀的-0x20位置。
116d: 48 8b 45 d8
- mov -0x28(%rbp),%rax
將當前棧幀的-0x28位置的值加載到寄存器rax中。
1171: 48 89 45 e8
- mov %rax,-0x18(%rbp)
將寄存器rax的值存儲到當前棧幀的-0x18位置。
1175: 48 c7 45 f0 03 00 00 00
- movq $0x3,-0x10(%rbp)
將立即數(shù)0x3存儲到當前棧幀的-0x10位置。
117d: 48 c7 45 f8 04 00 00 00
- movq $0x4,-0x8(%rbp)
將立即數(shù)0x4存儲到當前棧幀的-0x8位置。
1185: 48 8b 55 f8
- mov -0x8(%rbp),%rdx
將當前棧幀的-0x8位置的值加載到寄存器rdx中。
1189: 48 8b 45 f0
- mov -0x10(%rbp),%rax
將當前棧幀的-0x10位置的值加載到寄存器rax中。
118d: 48 89 d1
- mov %rdx,%rcx
將寄存器rdx的值復制給rcx。
1190: 48 89 c2
- mov %rax,%rdx
將寄存器rax的值復制給rdx。
1193: 48 8d 35 fe 0e 00 00
- lea 0xefe(%rip),%rsi
將相對地址0xefe處的值加載到寄存器rsi。
119a: 48 8d 3d 67 0e 00 00
- lea 0xe67(%rip),%rdi
將相對地址0xe67處的值加載到寄存器rdi。
11a1: b8 00 00 00 00
- mov $0x0,%eax
將立即數(shù)0x0加載到寄存器eax。
11a6: e8 a5 fe ff ff
- callq 1050 <printf@plt>
調(diào)用函數(shù)plt的printf函數(shù),跳轉(zhuǎn)到地址1050處執(zhí)行。
接下來的指令繼續(xù)處理計算結果,并執(zhí)行一些算術操作。
11ab: 48 8b 55 f0
- mov -0x10(%rbp),%rdx
將當前棧幀的-0x10位置的值加載到寄存器rdx中。
11af: 48 8b 45 f8
- mov -0x8(%rbp),%rax
將當前棧幀的-0x8位置的值加載到寄存器rax中。
11b3: 48 01 c2
- add %rax,%rdx
將寄存器rax和rdx的值相加,結果存儲在rdx中。
11b6: 48 8b 45 d8
- mov -0x28(%rbp),%rax
將當前棧幀的-0x28位置的值加載到寄存器rax中。
11bd: 48 01 c2
- add %rax,%rdx
將寄存器rax和rdx的值相加,結果存儲在rdx中。
11c1: 48 8b 45 e0
- mov -0x20(%rbp),%rax
將當前棧幀的-0x20位置的值加載到寄存器rax中。
11c4: 48 01 d0
- add %rdx,%rax
將寄存器rdx和rax的值相加,結果存儲在rax中。
11c8: 48 89 45 f0
- mov %rax,-0x10(%rbp)
將寄存器rax的值存儲到當前棧幀的-0x10位置。
11cc: 48 8b 45 f8 mov -0x8(%rbp),%rax
將當前棧幀的-0x8位置的值加載到rax寄存器中
11d0: 48 01 c2 add %rax,%rdx
將寄存器rax和rdx的值相加,結果存儲在rdx中。
11d3: 48 8b 45 d0 mov -0x30(%rbp),%rax
將當前棧幀的-0x30位置的值加載到rax寄存器中
11d7: 48 01 c2 add %rax,%rdx
將寄存器rax和rdx的值相加,結果存儲在rdx中。
11da: 48 8b 45 e8 mov -0x18(%rbp),%rax
將當前棧幀的-0x18位置的值加載到rax寄存器中
11de: 48 01 d0 add %rdx,%rax
將寄存器rdx和rax的值相加,結果存儲在rax中。
11e1: 48 89 45 f8 mov %rax,-0x8(%rbp)
將寄存器rax的值存儲到當前棧幀的-0x8位置。
11e5: 90 nop
11e6: c9 leaveq
撤銷棧幀,恢復調(diào)用前的堆棧狀態(tài)。
11e7: c3 retq
從當前函數(shù)返回,返回到調(diào)用者的代碼位置。
0000000000001149 <test_fun_b>:
1149: f3 0f 1e fa endbr64
114d: 55 push %rbp
114e: 48 89 e5 mov %rsp,%rbp
1151: 48 83 ec 40 sub $0x40,%rsp
1155: 48 89 7d d8 mov %rdi,-0x28(%rbp)
1159: 48 89 75 d0 mov %rsi,-0x30(%rbp)
115d: 48 89 55 c8 mov %rdx,-0x38(%rbp)
1161: 48 89 4d c0 mov %rcx,-0x40(%rbp)
1165: 48 8b 45 c0 mov -0x40(%rbp),%rax
1169: 48 89 45 e0 mov %rax,-0x20(%rbp)
116d: 48 8b 45 d8 mov -0x28(%rbp),%rax
1171: 48 89 45 e8 mov %rax,-0x18(%rbp)
1175: 48 c7 45 f0 03 00 00 movq $0x3,-0x10(%rbp)
117c: 00
117d: 48 c7 45 f8 04 00 00 movq $0x4,-0x8(%rbp)
1184: 00
1185: 48 8b 55 f8 mov -0x8(%rbp),%rdx
1189: 48 8b 45 f0 mov -0x10(%rbp),%rax
118d: 48 89 d1 mov %rdx,%rcx
1190: 48 89 c2 mov %rax,%rdx
1193: 48 8d 35 fe 0e 00 00 lea 0xefe(%rip),%rsi # 2098 <__func__.2503>
119a: 48 8d 3d 67 0e 00 00 lea 0xe67(%rip),%rdi # 2008 <_IO_stdin_used+0x8>
11a1: b8 00 00 00 00 mov $0x0,%eax
11a6: e8 a5 fe ff ff callq 1050 <printf@plt>
11ab: 48 8b 55 f0 mov -0x10(%rbp),%rdx
11af: 48 8b 45 f8 mov -0x8(%rbp),%rax
11b3: 48 01 c2 add %rax,%rdx
11b6: 48 8b 45 d8 mov -0x28(%rbp),%rax
11ba: 48 01 c2 add %rax,%rdx
11bd: 48 8b 45 e0 mov -0x20(%rbp),%rax
11c1: 48 01 d0 add %rdx,%rax
11c4: 48 89 45 f0 mov %rax,-0x10(%rbp)
11c8: 48 8b 55 f0 mov -0x10(%rbp),%rdx
11cc: 48 8b 45 f8 mov -0x8(%rbp),%rax
11d0: 48 01 c2 add %rax,%rdx
11d3: 48 8b 45 d0 mov -0x30(%rbp),%rax
11d7: 48 01 c2 add %rax,%rdx
11da: 48 8b 45 e8 mov -0x18(%rbp),%rax
11de: 48 01 d0 add %rdx,%rax
11e1: 48 89 45 f8 mov %rax,-0x8(%rbp)
11e5: 90 nop
11e6: c9 leaveq
11e7: c3 retq
2.3.3 執(zhí)行完成之后棧幀的使用情況
2.3.3.1 test_fun_b函數(shù)執(zhí)行開棧之后的棧結構示意圖
2.3.3.2 test_fun_a函數(shù)執(zhí)行參數(shù)壓棧以及局部變量壓棧之后的棧結構示意圖
3 X86_64 函數(shù)調(diào)用示例及其棧幀示意圖
文章來源:http://www.zghlxwxcb.cn/news/detail-699581.html
4 編譯和反匯編的命令
4.1 編譯的命令
x86_64-linux-gnu-gcc -Wl,--no-as-needed main.c -o x86_test
4.2 反匯編的命令
若是想把生成的反匯編程序保存的文件可以使用這個反匯編的命令:x86_64-linux-gnu-objdump -S -d x86_test > x86_64_test.S
文章來源地址http://www.zghlxwxcb.cn/news/detail-699581.html
x86_64-linux-gnu-objdump -S -d x86_test
到了這里,關于X86_64函數(shù)調(diào)用匯編程序分析的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!