ARM64函数调用流程分析
- 1 ARM64 函数调用实例
- 2 对应代码的分析
- 2.1 main函数及其对应的汇编程序
- 2.1.1 main的C代码实现
- 2.1.2 main函数对应汇编及其分析
- 2.1.3 执行完成之后栈的存放情况
- 2.2 test_fun_a函数及其对应的汇编程序
- 2.2.1 test_fun_a函数的C实现
- 2.2.2 test_fun_a函数对应汇编及其分析
- 2.2.3 执行完成之后栈帧的使用情况
- 2.3 test_fun_b函数及其对应的汇编程序
- 2.3.1 test_func_b函数的C实现
- 2.3.2 test_fun_b函数对应汇编及其分析
- 2.3.3 执行完成之后栈帧的使用情况
ARM64 程序调用标准
1 ARM64 函数调用实例
下图是介绍一个简单函数调用的示例,在该示例中简单介绍了栈的使用。
2 对应代码的分析
2.1 main函数及其对应的汇编程序
2.1.1 main的C代码实现
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函数对应汇编及其分析
0000000000000114 <main>:
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_fun_b>
加载test_func_b函数的地址到x0寄存器中138: 91000001 add x1, x0, #0x0
将x0 + 0的值保存到x1寄存器中13c: 90000000 adrp x0, 0 <test_fun_b>
加载test_func_b函数的地址到x0寄存器中140: 91000000 add x0, x0, #0x0
将x0 + 0的值保存到x0寄存器中144: 94000000 bl 0 <printf>
调用函数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_fun_a>
调用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, sp11c: d2800020 mov x0, #0x1 // #1120: f9000be0 str x0, [sp, #16]124: d2800040 mov x0, #0x2 // #2128: 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, #0x013c: 90000000 adrp x0, 0 <test_fun_b>140: 91000000 add x0, x0, #0x0144: 94000000 bl 0 <printf>148: d2800023 mov x3, #0x1 // #114c: d2800002 mov x2, #0x0 // #0150: 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, x0168: f9000be0 str x0, [sp, #16]16c: f9400fe1 ldr x1, [sp, #24]170: f9400be0 ldr x0, [sp, #16]174: 8b000020 add x0, x1, x0178: f9000fe0 str x0, [sp, #24]17c: 52800000 mov w0, #0x0 // #0180: a8c27bfd ldp x29, x30, [sp], #32184: d65f03c0 ret
2.1.3 执行完成之后栈的存放情况
2.2 test_fun_a函数及其对应的汇编程序
2.2.1 test_fun_a函数的C实现
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函数对应汇编及其分析
0000000000000080 <test_fun_a>:
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>
将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>
将test_fun_b函数的地址加载到x0寄存器中bc: 91000000 add x0, x0, #0x0
x0 = x0 + 0,其中x0保存的是test_fun_b的起始地址c0: 94000000 bl 0 <printf>
调用函数printfc4: 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>
调用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 + cfc: 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, #0x0b8: 90000000 adrp x0, 0 <test_fun_b>bc: 91000000 add x0, x0, #0x0c0: 94000000 bl 0 <printf>c4: d2800043 mov x3, #0x2 // #2c8: d2800002 mov x2, #0x0 // #0cc: 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, x0e4: f94017e1 ldr x1, [sp, #40]e8: 8b000020 add x0, x1, x0ec: f9001be0 str x0, [sp, #48]f0: f9401be1 ldr x1, [sp, #48]f4: f9401fe0 ldr x0, [sp, #56]f8: 8b000020 add x0, x1, x0fc: f94013e1 ldr x1, [sp, #32]100: 8b000020 add x0, x1, x0104: f9001fe0 str x0, [sp, #56]108: d503201f nop10c: a8c47bfd ldp x29, x30, [sp], #64110: d65f03c0 ret
2.2.3 执行完成之后栈帧的使用情况
2.3 test_fun_b函数及其对应的汇编程序
2.3.1 test_func_b函数的C实现
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函数对应汇编及其分析
0000000000000000 <test_fun_b>:
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>
将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>
将test_fun_b函数的地址加载到x0寄存器中3c: 91000000 add x0, x0, #0x0
x0 = x0 + 0,其中x0保存的是test_fun_b的起始地址40: 94000000 bl 0 <printf>
调用函数printf44: 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 + m58: 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 + d68: f94013e1 ldr x1, [sp, #32]
从栈中取出调用test_fun_b函数时传入的第2个参数放到x1寄存器中6c: 8b000020 add x0, x1, x0
c = c + n70: 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, sp8: 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 // #31c: f9001be0 str x0, [sp, #48]20: d2800080 mov x0, #0x4 // #424: 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, #0x038: 90000000 adrp x0, 0 <test_fun_b>3c: 91000000 add x0, x0, #0x040: 94000000 bl 0 <printf>44: f9401be1 ldr x1, [sp, #48]48: f9401fe0 ldr x0, [sp, #56]4c: 8b000020 add x0, x1, x050: f94017e1 ldr x1, [sp, #40]54: 8b000020 add x0, x1, x058: f9001be0 str x0, [sp, #48]5c: f9401be1 ldr x1, [sp, #48]60: f9401fe0 ldr x0, [sp, #56]64: 8b000020 add x0, x1, x068: f94013e1 ldr x1, [sp, #32]6c: 8b000020 add x0, x1, x070: f9001fe0 str x0, [sp, #56]74: d503201f nop 78: a8c47bfd ldp x29, x30, [sp], #647c: d65f03c0 ret