arm-linux 汇编 (4) – 函数调用规则
本篇主要考虑整数 (更精确点是 32 位整数) 作为参数和函数返回值时的传递规则.
网上很多资料都在说 arm 汇编中如果参数小于四个 (整数) 的话, 使用 r0, r1, r2, r3 来传递. 当大于 4 个时使用栈来传递. 但是究竟放到 sp 的上面还是下面, 顺序如何. 这次就来试一试到底是怎么样的.
1 | int a7(int a, int b, int c, int d, int e, int f, int g) |
编译以上代码 arm-linux-gnueabi-gcc -c arg.c 生成 arg.o 文件. 然后使用 arm-linux-gnueabi-objdump -d 来反编译. o 文件.
1 | 000001b4 <a7>: |
得到以上文件
下面来分析一下.
在 test 函数中. 我们先不管 fp 寄存器, 只看 sp 寄存器. sp 寄存器一上来就向下移了 16 个字节 (4 个 int). 我们知道, arm 的栈是 FD 的 (Full decrease, 既 sp 指向栈顶元素, 栈向低地址增长). 所以就是说明新开辟了 4 个 int 的空间.
然后 224 到 238 这段. 是将 5, 6, 7 这三个参数存到 sp 和 sp 上面. 使用了 3 个 int 的空间.
之后, 又将 1, 2, 3, 4 这四个参数分别保存到 r0, r1, r2, r3 中.
最后, bl 调用函数.
由上面分析可知, 当我们调用一个函数前, 应当:
前四个参数使用寄存器传递
后面的参数使用栈传递
使用栈传递时, 从后向前依次压入参数. 压栈完成后, sp 指向最后一个参数
sp 是 8 字节对齐的 [我猜想的]
刚刚的分析中, 我们只需要额外传递 3 个参数, 可是我们在栈上分配了 16 个字节, 另外我尝试传递 5 个参数时分配了 8 个字节 (也是多一个) 所以我猜想 sp 可能需要 8 字节对齐.
然后对于被调用的函数来说, 它知道的信息就是: “我的前四个参数在寄存器中, 我的 sp 指针指向最后一个参数, 依次向上可以得到全部参数.”
然后对于被调用函数来说, 它会将 fp 指向参数的后一个字. 让 sp 指向栈顶. fp 和 sp 之间保存断点信息 (保护上一函数的寄存器) 和自己的局部变量.
[EOF]