ARM64 程序调用标准
下图是介绍一个简单函数调用的示例,在该示例中简单介绍了栈的使用。
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;
}
0000000000000114 :
main函数的入口114: a9be7bfd stp x29, x30, [sp, #-32]!
将sp = sp - 32,为main函数开一个32Byte的栈空间,然后将x29(FP),X30(LR)寄存器的值存放在SP和SP + 8的位置处。118: 910003fd mov x29, sp
将SP寄存器的值存放到X29(FP)寄存器中,即FP寄存器指向当前main函数的栈顶。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栈内存处12c: f9400fe3 ldr x3, [sp, #24]
从栈中加载局部变量b的值到x3寄存器中130: f9400be2 ldr x2, [sp, #16]
从栈中加载局部变量a的值到x2寄存器中134: 90000000 adrp x0, 0
加载test_func_b函数的地址到x0寄存器中138: 91000001 add x1, x0, #0x0
将x0 + 0的值保存到x1寄存器中13c: 90000000 adrp x0, 0
加载test_func_b函数的地址到x0寄存器中140: 91000000 add x0, x0, #0x0
将x0 + 0的值保存到x0寄存器中144: 94000000 bl 0
调用函数printf148: d2800023 mov x3, #0x1 // #1
将1保存到x3寄存器中,作为调用test_fun_a函数的第4个参数14c: d2800002 mov x2, #0x0 // #0
将0保存到寄存器x2中,作为调用test_fun_a函数的第3个参数150: f9400fe1 ldr x1, [sp, #24]
从栈中取出局部变量b的值,放到x1寄存器中,作为调用test_fun_a的第2个参数154: f9400be0 ldr x0, [sp, #16]
从栈中取出局部变量a的值,放到x0寄存器中,作为调用test_fun_a的第1个参数158: 94000000 bl 80
调用test_func_a函数,其参数分别为前面的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 + b168: 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 + b178: f9000fe0 str x0, [sp, #24]
将新计算得到的局部变量b的值重新保存到栈中17c: 52800000 mov w0, #0x0 // #0
给w0寄存器赋值为0,该操作是用在ret指令执行时,返回0值。180: a8c27bfd ldp x29, x30, [sp], #32
恢复x29(FP)和X30(LR)的值,同时SP = SP + 32184: d65f03c0 ret
返回调用的指令,该指令执行的时候会返回lr寄存器指向的函数中。
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
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;
}
0000000000000080 :
test_fun_a函数的入口 80: a9bc7bfd stp x29, x30, [sp, #-64]!
为test_fun_a函数开栈64B,同时把X29(FP),X30(LR)保存到栈顶sp和sp + 8的栈内存位置处 84: 910003fd mov x29, sp
将sp保存到x29(FP)寄存器中,相当于FP指向栈的栈顶 88: f90017e0 str x0, [sp, #40]
将参数1保存到栈的sp + 40栈内存位置处 8c: f90013e1 str x1, [sp, #32]
将参数2保存到栈sp + 32的栈内存位置处 90: f9000fe2 str x2, [sp, #24]
将参数3保存到栈sp + 24栈内存位置处 94: f9000be3 str x3, [sp, #16]
将参数4保存到栈sp + 16栈内存位置处 98: d2800040 mov x0, #0x2 // #2
将test_fun_a函数的局部变量b保存到x0寄存器中 9c: f9001be0 str x0, [sp, #48]
将test_fun_a函数的局部变量b保存到sp + 48栈内存位置处 a0: d2800060 mov x0, #0x3 // #3
将test_fun_a函数的局部变量c保存到x1寄存器中 a4: f9001fe0 str x0, [sp, #56]
将test_fun_a函数的局部变量c保存到栈sp + 56栈内存位置处 a8: f9401fe3 ldr x3, [sp, #56]
从栈中取出局部变量c的值放到x3寄存器中 ac: f9401be2 ldr x2, [sp, #48]
从栈中取出局部变量b的值放到x2寄存器中 b0: 90000000 adrp x0, 0
将test_fun_b函数的地址加载到x0寄存器中 b4: 91000001 add x1, x0, #0x0
x1 = x0 + 0,其中x0保存的是test_fun_b的起始地址 b8: 90000000 adrp x0, 0
将test_fun_b函数的地址加载到x0寄存器中 bc: 91000000 add x0, x0, #0x0
x0 = x0 + 0,其中x0保存的是test_fun_b的起始地址 c0: 94000000 bl 0
调用函数printf c4: d2800043 mov x3, #0x2 // #2
给x3寄存器赋值为2,作为test_fun_b的第4个参数 c8: d2800002 mov x2, #0x0 // #0
给x2寄存器赋值为0,作为test_func_b的第三个参数 cc: f9401fe1 ldr x1, [sp, #56]
从栈中取出局部变量c,存放到x1寄存器,作为test_fun_b的第二个参数 d0: f9401be0 ldr x0, [sp, #48]
从栈中取出局部变量b,存放到x0寄存器,作为test_fun_b的第一个参数 d4: 94000000 bl 0
调用test_fun_b函数,x0 ~ x3作为test_fun_a的四个参数 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的结果保存到x0寄存器中。 e4: f94017e1 ldr x1, [sp, #40]
从栈中取出调用test_fun_a时传入的第1个参数取出,放到x1寄存器中 e8: 8b000020 add x0, x1, x0
c = c + m,将计算的结果放到x0寄存器中 ec: f9001be0 str x0, [sp, #48]
将计算的结果x0的值重新保存到局部变量b的栈内存位置处 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]
从栈中取出调用test_fun_a函数时传入的第2个参数放到x1寄存器中 100: 8b000020 add x0, x1, x0
c = c + n,计算的结果放到x0寄存器中 104: f9001fe0 str x0, [sp, #56]
将计算的新值存放到原局部变量c的栈内存位置处 108: d503201f nop
空操作 10c: a8c47bfd ldp x29, x30, [sp], #64
恢复X29(FP),X30(LR)寄存器的值,同时sp = sp + 64栈指针寄存器 110: d65f03c0 ret
返回X30(LR)寄存器保存的返回函数处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
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;
}
0000000000000000 :
test_fun_b函数的入口 0: a9bc7bfd stp x29, x30, [sp, #-64]!
为test_fun_b函数开栈64B,同时把X29(FP),X30(LR)保存到栈顶sp和sp + 8的栈内存位置处 4: 910003fd mov x29, sp
将sp保存到x29(FP)寄存器中,相当于FP指向栈的栈顶 8: f90017e0 str x0, [sp, #40]
将参数1保存到栈的sp + 40栈内存位置处 c: f90013e1 str x1, [sp, #32]
将参数2保存到栈sp + 32的栈内存位置处 10: f9000fe2 str x2, [sp, #24]
将参数3保存到栈sp + 24栈内存位置处 14: f9000be3 str x3, [sp, #16]
将参数4保存到栈sp + 16栈内存位置处 18: d2800060 mov x0, #0x3 // #3
将test_fun_b函数的局部变量c保存到x0寄存器中 1c: f9001be0 str x0, [sp, #48]
将test_fun_b函数的局部变量c保存到sp + 48栈内存位置处 20: d2800080 mov x0, #0x4 // #4
将test_fun_b函数的局部变量d保存到x1寄存器中 24: f9001fe0 str x0, [sp, #56]
将test_fun_b函数的局部变量d保存到栈sp + 56栈内存位置处 28: f9401fe3 ldr x3, [sp, #56]
从栈中取出局部变量d的值放到x3寄存器中 2c: f9401be2 ldr x2, [sp, #48]
从栈中取出局部变量c的值放到x2寄存器中 30: 90000000 adrp x0, 0
将test_fun_b函数的地址加载到x0寄存器中 34: 91000001 add x1, x0, #0x0
x1 = x0 + 0,其中x0保存的是test_fun_b的起始地址 38: 90000000 adrp x0, 0
将test_fun_b函数的地址加载到x0寄存器中 3c: 91000000 add x0, x0, #0x0
x0 = x0 + 0,其中x0保存的是test_fun_b的起始地址 40: 94000000 bl 0
调用函数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的结果保存到x0寄存器中。 50: f94017e1 ldr x1, [sp, #40]
从栈中取出调用test_fun_b时传入的第1个参数取出,放到x1寄存器中 54: 8b000020 add x0, x1, x0
d = d + m 58: f9001be0 str x0, [sp, #48]
将计算的结果x0的值重新保存到局部变量c的栈内存位置处 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]
从栈中取出调用test_fun_b函数时传入的第2个参数放到x1寄存器中 6c: 8b000020 add x0, x1, x0
c = c + n 70: f9001fe0 str x0, [sp, #56]
将计算的新值存放到原局部变量d的栈内存位置处 74: d503201f nop
空操作 78: a8c47bfd ldp x29, x30, [sp], #64
恢复X29(FP),X30(LR)寄存器的值,同时sp = sp + 64栈指针寄存器 7c: d65f03c0 ret
返回X30(LR)寄存器保存的返回函数处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