以C语言的hellow world为例
gcc正常编译后反汇编的main函数代码
1 | lea 0x4(%esp),%ecx ;保存esp+4的原始偏移量 |
会发现在函数序和函数跋多出几条奇怪的指令
如注释所言多出来指令作用便是对堆栈边界进行16字节对齐,并以16字节的倍数分配堆栈空间,这里可以使用-mpreferred-stack-boundary=num进行控制。如果使用-mpreferred-stack-boundary=2(2²=4byte对齐),因为堆栈边界始终至少为4字节对齐,便不会产生对齐的代码。
1 | push %ebp |
根据gcc手册 -mpreferred-stack-boundary=num在未指定时num默认为4(2^4=16byte对齐)。
至于为什么默认是16bytes对齐,这和CPU相关,Intel在Pentium III推出了SSE指令集,SSE 加入新的 8 个16bytes寄存器(XMM0~XMM7)。最初的时候,这些寄存器智能用来做单精度浮点数计算,自从SSE2开始,这些寄存器可以被用来计算任何基本数据类型的数据了。往XMM0~XMM7里存放数据,是以16字节为单位,所以呢 内存变量首地址必须要对齐16字节,否则会引起CPU异常,导致指令执行失败。所以这就是gcc默认采用16bytes进行栈对齐的原因。
还有就是在SSE扩展被关闭时,-mpreferred-stack-boundary参数值虽然可以修改的。但是在修改后编译链接16bytes栈对齐的库时,会导致错误。