#include <stdio.h> void f1(int p1, int p2, int p3, int p4, int p5) { p5++; } void main() { int d = 4; f1(d, d, d, d, d); }
然后编译:arm-linux-gnueabihf-gcc test.c -o test7
然后看看汇编代码:arm-linux-gnueabihf-objdump -D test7
0000835c <f1>:836c: f103 0301 add.w r3, r3, #1
参数5是从母函数的栈里获取的:sp+20是自己新开辟的栈,而sp+24却是母函数的栈!
8370: 61bb str r3, [r7, #24]
接下来与前几篇讲过的一样,准备恢复老的r7,并返回母函数:
2 8376: b084 sub sp, #16
r7指向sp新开辟出来的空间的中间:
3 8378: af02 add r7, sp, #8
d = 4
4 837a: f04f 0304 mov.w r3, #4
存储d的值到自己的栈(内存): *(sp + (4 + 8) = r3
5 837e: 607b str r3, [r7, #4]
6 取出d的值,赋值给r3寄存器:
7 8380: 687b ldr r3, [r7, #4]
存储最后一个参数(参数5)到自己的栈: *(sp + 0) = r3
8 8382: 9300 str r3, [sp, #0]
r0-r3依次存储: (参数1,参数2,参数3,参数4):
16 8396: bd80 pop {r7, pc}
绿色的文字是上一篇讲过的,利用寄存器r0-r3存储4个参数到子函数f1。注意参数5的传递--蓝色文字描述的。编译器为了传递第5个参数,可谓“煞费苦心”,不惜让子函数访问母函数的栈内容。
这就是大于4个参数时,子函数调用参数传递的全部秘密。可够让编译器为难了,呵呵。
细心的人会发现,有些指令带有后缀,比如mov.w r3, #4,这是为何呢?下一篇我们讲讲指令的后缀。