如何解决系统V ABI-AMD64-GCC发出的程序集中的堆栈对齐方式
对于下面的C代码,Compiler Explorer的GCC x86-64 10.2发出了我在下面进一步粘贴的程序集。
一条指令是subq $40,%rsp
。问题是,如何从%rsp
中减去40个字节不会使堆栈未对齐?
我的理解是:
- 在
call foo
之前,堆栈对齐了16个字节; -
call foo
在堆栈上放置8个字节的返回地址,因此堆栈未对齐; - 但是
pushq %rbp
开头的foo
在堆栈上又放置了8个字节,因此它又重新对齐了16个字节; - 因此,堆栈在
subq $40,%rsp
前对齐了16个字节。结果,将%rsp
减少40个字节是否会破坏对齐?
很明显,就保持堆栈对齐而言,GCC发出了有效的程序集,因此我肯定缺少一些东西。
(我尝试用CLANG替换GCC,而CLANG发出subq $48,%rsp
-正如我的直觉期望。)
那么,在GCC生成的程序集中我缺少什么?如何使堆栈保持16个字节对齐?
int bar(int i) { return i; }
int foo(int p0,int p1,int p2,int p3,int p4,int p5,int p6) {
int sum = p0 + p1 + p2 + p3 + p4 + p5 + p6;
return bar(sum);
}
int main() {
return foo(0,1,2,3,4,5,6);
}
bar:
pushq %rbp
movq %rsp,%rbp
movl %edi,-4(%rbp)
movl -4(%rbp),%eax
popq %rbp
ret
foo:
pushq %rbp
movq %rsp,%rbp
subq $40,%rsp
movl %edi,-20(%rbp)
movl %esi,-24(%rbp)
movl %edx,-28(%rbp)
movl %ecx,-32(%rbp)
movl %r8d,-36(%rbp)
movl %r9d,-40(%rbp)
movl -20(%rbp),%edx
movl -24(%rbp),%eax
addl %eax,%edx
movl -28(%rbp),%edx
movl -32(%rbp),%edx
movl -36(%rbp),%edx
movl -40(%rbp),%edx
movl 16(%rbp),%eax
addl %edx,%eax
movl %eax,%edi
call bar
leave
ret
main:
pushq %rbp
movq %rsp,%rbp
pushq $6
movl $5,%r9d
movl $4,%r8d
movl $3,%ecx
movl $2,%edx
movl $1,%esi
movl $0,%edi
call foo
addq $8,%rsp
leave
ret
解决方法
16字节对齐的目的是使函数在当前的以下的任何级别调用,如果它们需要对齐的本地变量,则不必担心对齐其堆栈。
在没有ABI保证的情况下,需要此功能的每个函数都必须and
带有一定值的堆栈指针以确保其正确对齐,例如:
and %rsp,$0xfffffffffffffff0
但是,在这种特殊情况下没有必要 的原因-bar()
函数是一个叶子函数,意味着编译器具有 full 知识级别或以下级别的任何对齐要求(它没有本地语言,并且不调用任何函数,因此也没有要求)。
foo()
函数在下面也没有要求,因为它调用的唯一内容是bar()
。这似乎也决定了它的自己当地人也不需要这种对齐级别。
即使从即时翻译单位外部调用了bar()
或foo()
(由于没有标记为static
,所以它们也是 ),并不会改变不需要对齐的事实。
例如,bar
在单独的翻译单元中,或者在无法确定不需要对齐的情况下调用了其他函数,则情况会有所不同。
这将意味着gcc
不会完全了解其对齐要求。而且,的确,如果您在Godbolt中注释掉bar
定义行(有效地隐藏了定义),您将看到该行更改:
// int bar(int i) { return i; }
--> subq $48,%rsp ; no longer $40
顺便说一句,尽管在这种情况下16字节对齐在技术上不是不必要,但我认为可能使gcc
使用系统V AMD64 ABI。在该ABI中似乎没有任何允许这种偏差的地方,文本(PDF)表示(略述,用我的粗体显示):
输入自变量区域的末尾应在16个字节边界上对齐(如果
__m256
在堆栈上通过则为32个字节)。换句话说,当控制权转移到函数入口点时,值%rsp + 8
是 总是16的倍数(或32)。 堆栈指针{{ 1}}始终指向最新分配的堆栈帧的结尾。
尽管已知在这种情况下不会引起问题,但以使观察到的行为兼容的任何方式解释这似乎没有什么余地。
是否有人认为足以担心的问题超出了此答案的范围,我对此没有任何判断:-)
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。