ARM64 程序調(diào)用標(biāo)準
1 ARM64 函數(shù)調(diào)用實例
下圖是介紹一個簡單函數(shù)調(diào)用的示例,在該示例中簡單介紹了棧的使用。
2 對應(yīng)代碼的分析
2.1 main函數(shù)及其對應(yīng)的匯編程序
2.1.1 main的C代碼實現(xiàn)
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.2 main函數(shù)對應(yīng)匯編及其分析
-
0000000000000114 <main>:
main函數(shù)的入口 -
114: a9be7bfd stp x29, x30, [sp, #-32]!
將sp = sp - 32,為main函數(shù)開一個32Byte的棧空間,然后將x29(FP),X30(LR)寄存器的值存放在SP和SP + 8的位置處。 -
118: 910003fd mov x29, sp
將SP寄存器的值存放到X29(FP)寄存器中,即FP寄存器指向當(dāng)前main函數(shù)的棧頂。 -
11c: d2800020 mov x0, #0x1 // #1
將局部變量a的值保存到x0寄存器中 -
120: f9000be0 str x0, [sp, #16]
將局部變量a的值保存到sp + 16的位置處。 -
124: d2800040 mov x0, #0x2 // #2
將局部變量b的值保存到x0寄存器中 -
128: f9000fe0 str x0, [sp, #24]
將局部變量b的值保存到sp + 24棧內(nèi)存處 -
12c: f9400fe3 ldr x3, [sp, #24]
從棧中加載局部變量b的值到x3寄存器中 -
130: f9400be2 ldr x2, [sp, #16]
從棧中加載局部變量a的值到x2寄存器中 -
134: 90000000 adrp x0, 0 <test_fun_b>
加載test_func_b函數(shù)的地址到x0寄存器中 -
138: 91000001 add x1, x0, #0x0
將x0 + 0的值保存到x1寄存器中 -
13c: 90000000 adrp x0, 0 <test_fun_b>
加載test_func_b函數(shù)的地址到x0寄存器中 -
140: 91000000 add x0, x0, #0x0
將x0 + 0的值保存到x0寄存器中 -
144: 94000000 bl 0 <printf>
調(diào)用函數(shù)printf -
148: d2800023 mov x3, #0x1 // #1
將1保存到x3寄存器中,作為調(diào)用test_fun_a函數(shù)的第4個參數(shù) -
14c: d2800002 mov x2, #0x0 // #0
將0保存到寄存器x2中,作為調(diào)用test_fun_a函數(shù)的第3個參數(shù) -
150: f9400fe1 ldr x1, [sp, #24]
從棧中取出局部變量b的值,放到x1寄存器中,作為調(diào)用test_fun_a的第2個參數(shù) -
154: f9400be0 ldr x0, [sp, #16]
從棧中取出局部變量a的值,放到x0寄存器中,作為調(diào)用test_fun_a的第1個參數(shù) -
158: 94000000 bl 80 <test_fun_a>
調(diào)用test_func_a函數(shù),其參數(shù)分別為前面的x0 ~ x3寄存器的值 -
15c: f9400be1 ldr x1, [sp, #16]
加載局部變量a的值到x1寄存器 -
160: f9400fe0 ldr x0, [sp, #24]
加載局部變量b的值到x0寄存器 -
164: 8b000020 add x0, x1, x0
a = a + b -
168: f9000be0 str x0, [sp, #16]
將計算到的局部變量a的值重新存到棧中 -
16c: f9400fe1 ldr x1, [sp, #24]
從棧中取出局部變量b的值 -
170: f9400be0 ldr x0, [sp, #16]
從棧中取出局部變量a的值 -
174: 8b000020 add x0, x1, x0
b = a + b -
178: f9000fe0 str x0, [sp, #24]
將新計算得到的局部變量b的值重新保存到棧中 -
17c: 52800000 mov w0, #0x0 // #0
給w0寄存器賦值為0,該操作是用在ret指令執(zhí)行時,返回0值。 -
180: a8c27bfd ldp x29, x30, [sp], #32
恢復(fù)x29(FP)和X30(LR)的值,同時SP = SP + 32 -
184: d65f03c0 ret
返回調(diào)用的指令,該指令執(zhí)行的時候會返回lr寄存器指向的函數(shù)中。
0000000000000114 <main>:
114: a9be7bfd stp x29, x30, [sp, #-32]!
118: 910003fd mov x29, sp
11c: d2800020 mov x0, #0x1 // #1
120: f9000be0 str x0, [sp, #16]
124: d2800040 mov x0, #0x2 // #2
128: f9000fe0 str x0, [sp, #24]
12c: f9400fe3 ldr x3, [sp, #24]
130: f9400be2 ldr x2, [sp, #16]
134: 90000000 adrp x0, 0 <test_fun_b>
138: 91000001 add x1, x0, #0x0
13c: 90000000 adrp x0, 0 <test_fun_b>
140: 91000000 add x0, x0, #0x0
144: 94000000 bl 0 <printf>
148: d2800023 mov x3, #0x1 // #1
14c: d2800002 mov x2, #0x0 // #0
150: f9400fe1 ldr x1, [sp, #24]
154: f9400be0 ldr x0, [sp, #16]
158: 94000000 bl 80 <test_fun_a>
15c: f9400be1 ldr x1, [sp, #16]
160: f9400fe0 ldr x0, [sp, #24]
164: 8b000020 add x0, x1, x0
168: f9000be0 str x0, [sp, #16]
16c: f9400fe1 ldr x1, [sp, #24]
170: f9400be0 ldr x0, [sp, #16]
174: 8b000020 add x0, x1, x0
178: f9000fe0 str x0, [sp, #24]
17c: 52800000 mov w0, #0x0 // #0
180: a8c27bfd ldp x29, x30, [sp], #32
184: d65f03c0 ret
2.1.3 執(zhí)行完成之后棧的存放情況
2.2 test_fun_a函數(shù)及其對應(yīng)的匯編程序
2.2.1 test_fun_a函數(shù)的C實現(xiàn)
void test_fun_a(long m, long n, long x, long y)
{
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, 0, 2);
b = b + c + m;
c = b + c + n;
}
2.2.2 test_fun_a函數(shù)對應(yīng)匯編及其分析
-
0000000000000080 <test_fun_a>:
test_fun_a函數(shù)的入口 -
80: a9bc7bfd stp x29, x30, [sp, #-64]!
為test_fun_a函數(shù)開棧64B,同時把X29(FP),X30(LR)保存到棧頂sp和sp + 8的棧內(nèi)存位置處 -
84: 910003fd mov x29, sp
將sp保存到x29(FP)寄存器中,相當(dāng)于FP指向棧的棧頂 -
88: f90017e0 str x0, [sp, #40]
將參數(shù)1保存到棧的sp + 40棧內(nèi)存位置處 -
8c: f90013e1 str x1, [sp, #32]
將參數(shù)2保存到棧sp + 32的棧內(nèi)存位置處 -
90: f9000fe2 str x2, [sp, #24]
將參數(shù)3保存到棧sp + 24棧內(nèi)存位置處 -
94: f9000be3 str x3, [sp, #16]
將參數(shù)4保存到棧sp + 16棧內(nèi)存位置處 -
98: d2800040 mov x0, #0x2 // #2
將test_fun_a函數(shù)的局部變量b保存到x0寄存器中 -
9c: f9001be0 str x0, [sp, #48]
將test_fun_a函數(shù)的局部變量b保存到sp + 48棧內(nèi)存位置處 -
a0: d2800060 mov x0, #0x3 // #3
將test_fun_a函數(shù)的局部變量c保存到x1寄存器中 -
a4: f9001fe0 str x0, [sp, #56]
將test_fun_a函數(shù)的局部變量c保存到棧sp + 56棧內(nèi)存位置處 -
a8: f9401fe3 ldr x3, [sp, #56]
從棧中取出局部變量c的值放到x3寄存器中 -
ac: f9401be2 ldr x2, [sp, #48]
從棧中取出局部變量b的值放到x2寄存器中 -
b0: 90000000 adrp x0, 0 <test_fun_b>
將test_fun_b函數(shù)的地址加載到x0寄存器中 -
b4: 91000001 add x1, x0, #0x0
x1 = x0 + 0,其中x0保存的是test_fun_b的起始地址 -
b8: 90000000 adrp x0, 0 <test_fun_b>
將test_fun_b函數(shù)的地址加載到x0寄存器中 -
bc: 91000000 add x0, x0, #0x0
x0 = x0 + 0,其中x0保存的是test_fun_b的起始地址 -
c0: 94000000 bl 0 <printf>
調(diào)用函數(shù)printf -
c4: d2800043 mov x3, #0x2 // #2
給x3寄存器賦值為2,作為test_fun_b的第4個參數(shù) -
c8: d2800002 mov x2, #0x0 // #0
給x2寄存器賦值為0,作為test_func_b的第三個參數(shù) -
cc: f9401fe1 ldr x1, [sp, #56]
從棧中取出局部變量c,存放到x1寄存器,作為test_fun_b的第二個參數(shù) -
d0: f9401be0 ldr x0, [sp, #48]
從棧中取出局部變量b,存放到x0寄存器,作為test_fun_b的第一個參數(shù) -
d4: 94000000 bl 0 <test_fun_b>
調(diào)用test_fun_b函數(shù),x0 ~ x3作為test_fun_a的四個參數(shù) -
d8: f9401be1 ldr x1, [sp, #48]
從棧中取出test_fun_a的局部變量b,放到x1寄存器中 -
dc: f9401fe0 ldr x0, [sp, #56]
從棧中取出test_fun_a的局部變量c,放到x0寄存器中 -
e0: 8b000020 add x0, x1, x0
c = b + c,將c的結(jié)果保存到x0寄存器中。 -
e4: f94017e1 ldr x1, [sp, #40]
從棧中取出調(diào)用test_fun_a時傳入的第1個參數(shù)取出,放到x1寄存器中 -
e8: 8b000020 add x0, x1, x0
c = c + m,將計算的結(jié)果放到x0寄存器中 -
ec: f9001be0 str x0, [sp, #48]
將計算的結(jié)果x0的值重新保存到局部變量b的棧內(nèi)存位置處 -
f0: f9401be1 ldr x1, [sp, #48]
從棧中取出局部變量b的值放到x1寄存器中。 -
f4: f9401fe0 ldr x0, [sp, #56]
從棧中取出局部變量x的值放到x0寄存器中 -
f8: 8b000020 add x0, x1, x0
c = b + c -
fc: f94013e1 ldr x1, [sp, #32]
從棧中取出調(diào)用test_fun_a函數(shù)時傳入的第2個參數(shù)放到x1寄存器中 -
100: 8b000020 add x0, x1, x0
c = c + n,計算的結(jié)果放到x0寄存器中 -
104: f9001fe0 str x0, [sp, #56]
將計算的新值存放到原局部變量c的棧內(nèi)存位置處 -
108: d503201f nop
空操作 -
10c: a8c47bfd ldp x29, x30, [sp], #64
恢復(fù)X29(FP),X30(LR)寄存器的值,同時sp = sp + 64棧指針寄存器 -
110: d65f03c0 ret
返回X30(LR)寄存器保存的返回函數(shù)處
0000000000000080 <test_fun_a>:
80: a9bc7bfd stp x29, x30, [sp, #-64]!
84: 910003fd mov x29, sp
88: f90017e0 str x0, [sp, #40]
8c: f90013e1 str x1, [sp, #32]
90: f9000fe2 str x2, [sp, #24]
94: f9000be3 str x3, [sp, #16]
98: d2800040 mov x0, #0x2 // #2
9c: f9001be0 str x0, [sp, #48]
a0: d2800060 mov x0, #0x3 // #3
a4: f9001fe0 str x0, [sp, #56]
a8: f9401fe3 ldr x3, [sp, #56]
ac: f9401be2 ldr x2, [sp, #48]
b0: 90000000 adrp x0, 0 <test_fun_b>
b4: 91000001 add x1, x0, #0x0
b8: 90000000 adrp x0, 0 <test_fun_b>
bc: 91000000 add x0, x0, #0x0
c0: 94000000 bl 0 <printf>
c4: d2800043 mov x3, #0x2 // #2
c8: d2800002 mov x2, #0x0 // #0
cc: f9401fe1 ldr x1, [sp, #56]
d0: f9401be0 ldr x0, [sp, #48]
d4: 94000000 bl 0 <test_fun_b>
d8: f9401be1 ldr x1, [sp, #48]
dc: f9401fe0 ldr x0, [sp, #56]
e0: 8b000020 add x0, x1, x0
e4: f94017e1 ldr x1, [sp, #40]
e8: 8b000020 add x0, x1, x0
ec: f9001be0 str x0, [sp, #48]
f0: f9401be1 ldr x1, [sp, #48]
f4: f9401fe0 ldr x0, [sp, #56]
f8: 8b000020 add x0, x1, x0
fc: f94013e1 ldr x1, [sp, #32]
100: 8b000020 add x0, x1, x0
104: f9001fe0 str x0, [sp, #56]
108: d503201f nop
10c: a8c47bfd ldp x29, x30, [sp], #64
110: d65f03c0 ret
2.2.3 執(zhí)行完成之后棧幀的使用情況
文章來源:http://www.zghlxwxcb.cn/news/detail-670264.html
2.3 test_fun_b函數(shù)及其對應(yīng)的匯編程序
2.3.1 test_func_b函數(shù)的C實現(xiàn)
void test_fun_b(long m, long n, long x, long y)
{
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;
d = c + d + n;
}
2.3.2 test_fun_b函數(shù)對應(yīng)匯編及其分析
-
0000000000000000 <test_fun_b>:
test_fun_b函數(shù)的入口 -
0: a9bc7bfd stp x29, x30, [sp, #-64]!
為test_fun_b函數(shù)開棧64B,同時把X29(FP),X30(LR)保存到棧頂sp和sp + 8的棧內(nèi)存位置處 -
4: 910003fd mov x29, sp
將sp保存到x29(FP)寄存器中,相當(dāng)于FP指向棧的棧頂 -
8: f90017e0 str x0, [sp, #40]
將參數(shù)1保存到棧的sp + 40棧內(nèi)存位置處 -
c: f90013e1 str x1, [sp, #32]
將參數(shù)2保存到棧sp + 32的棧內(nèi)存位置處 -
10: f9000fe2 str x2, [sp, #24]
將參數(shù)3保存到棧sp + 24棧內(nèi)存位置處 -
14: f9000be3 str x3, [sp, #16]
將參數(shù)4保存到棧sp + 16棧內(nèi)存位置處 -
18: d2800060 mov x0, #0x3 // #3
將test_fun_b函數(shù)的局部變量c保存到x0寄存器中 -
1c: f9001be0 str x0, [sp, #48]
將test_fun_b函數(shù)的局部變量c保存到sp + 48棧內(nèi)存位置處 -
20: d2800080 mov x0, #0x4 // #4
將test_fun_b函數(shù)的局部變量d保存到x1寄存器中 -
24: f9001fe0 str x0, [sp, #56]
將test_fun_b函數(shù)的局部變量d保存到棧sp + 56棧內(nèi)存位置處 -
28: f9401fe3 ldr x3, [sp, #56]
從棧中取出局部變量d的值放到x3寄存器中 -
2c: f9401be2 ldr x2, [sp, #48]
從棧中取出局部變量c的值放到x2寄存器中 -
30: 90000000 adrp x0, 0 <test_fun_b>
將test_fun_b函數(shù)的地址加載到x0寄存器中 -
34: 91000001 add x1, x0, #0x0
x1 = x0 + 0,其中x0保存的是test_fun_b的起始地址 -
38: 90000000 adrp x0, 0 <test_fun_b>
將test_fun_b函數(shù)的地址加載到x0寄存器中 -
3c: 91000000 add x0, x0, #0x0
x0 = x0 + 0,其中x0保存的是test_fun_b的起始地址 -
40: 94000000 bl 0 <printf>
調(diào)用函數(shù)printf -
44: f9401be1 ldr x1, [sp, #48]
從棧中取出局部變量c,存放到x1寄存器 -
48: f9401fe0 ldr x0, [sp, #56]
從棧中取出局部變量d,存放到x0寄存器 -
4c: 8b000020 add x0, x1, x0
d = c + d,將d的結(jié)果保存到x0寄存器中。 -
50: f94017e1 ldr x1, [sp, #40]
從棧中取出調(diào)用test_fun_b時傳入的第1個參數(shù)取出,放到x1寄存器中 -
54: 8b000020 add x0, x1, x0
d = d + m -
58: f9001be0 str x0, [sp, #48]
將計算的結(jié)果x0的值重新保存到局部變量c的棧內(nèi)存位置處 -
5c: f9401be1 ldr x1, [sp, #48]
從棧中取出局部變量c的值放到x1寄存器中。 -
60: f9401fe0 ldr x0, [sp, #56]
從棧中取出局部變量d的值放到x0寄存器中 -
64: 8b000020 add x0, x1, x0
c = c + d -
68: f94013e1 ldr x1, [sp, #32]
從棧中取出調(diào)用test_fun_b函數(shù)時傳入的第2個參數(shù)放到x1寄存器中 -
6c: 8b000020 add x0, x1, x0
c = c + n -
70: f9001fe0 str x0, [sp, #56]
將計算的新值存放到原局部變量d的棧內(nèi)存位置處 -
74: d503201f nop
空操作 -
78: a8c47bfd ldp x29, x30, [sp], #64
恢復(fù)X29(FP),X30(LR)寄存器的值,同時sp = sp + 64棧指針寄存器 -
7c: d65f03c0 ret
返回X30(LR)寄存器保存的返回函數(shù)處
0000000000000000 <test_fun_b>:
0: a9bc7bfd stp x29, x30, [sp, #-64]!
4: 910003fd mov x29, sp
8: f90017e0 str x0, [sp, #40]
c: f90013e1 str x1, [sp, #32]
10: f9000fe2 str x2, [sp, #24]
14: f9000be3 str x3, [sp, #16]
18: d2800060 mov x0, #0x3 // #3
1c: f9001be0 str x0, [sp, #48]
20: d2800080 mov x0, #0x4 // #4
24: f9001fe0 str x0, [sp, #56]
28: f9401fe3 ldr x3, [sp, #56]
2c: f9401be2 ldr x2, [sp, #48]
30: 90000000 adrp x0, 0 <test_fun_b>
34: 91000001 add x1, x0, #0x0
38: 90000000 adrp x0, 0 <test_fun_b>
3c: 91000000 add x0, x0, #0x0
40: 94000000 bl 0 <printf>
44: f9401be1 ldr x1, [sp, #48]
48: f9401fe0 ldr x0, [sp, #56]
4c: 8b000020 add x0, x1, x0
50: f94017e1 ldr x1, [sp, #40]
54: 8b000020 add x0, x1, x0
58: f9001be0 str x0, [sp, #48]
5c: f9401be1 ldr x1, [sp, #48]
60: f9401fe0 ldr x0, [sp, #56]
64: 8b000020 add x0, x1, x0
68: f94013e1 ldr x1, [sp, #32]
6c: 8b000020 add x0, x1, x0
70: f9001fe0 str x0, [sp, #56]
74: d503201f nop
78: a8c47bfd ldp x29, x30, [sp], #64
7c: d65f03c0 ret
2.3.3 執(zhí)行完成之后棧幀的使用情況
文章來源地址http://www.zghlxwxcb.cn/news/detail-670264.html
到了這里,關(guān)于ARM64函數(shù)調(diào)用流程分析的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!