2014-10-05 102 views
-1

我真的不明白为什么gcc在调用函数之前已经减去12来esp。汇编堆栈管理通过%esp

pushl %ebp 
    movl %esp,%ebp 
    sub $12,%esp 

    socket(AF_INET,SOCK_STREAM,IPPROTO_TCP); 
    movl $AF_INET,(%esp) 
+0

'sub'是减法不加法;)它是分配局部变量,与套接字调用没有任何关系。 – Jester 2014-10-05 17:19:00

+0

呵呵:-)编辑。我试图让this.esp指向栈,从它减去一些值使它指向一个较低的地址,然后它之间的内存用于变量?我是否有意义? – asla 2014-10-05 17:24:36

+0

是的,就是这样。 – Jester 2014-10-05 17:26:46

回答

1

目前* 86 ABI要求堆栈指针对齐在函数调用时模16。这是堆栈指针无法解释的调整的典型原因。

*我说目前,因为GCC实际上单方面改变了ABI,并在3.x系列的某个地方引入了这个要求。我没有方便的参考,但也许有人可以提供它们。此更改旨在优化SIMD指令的使用,但实际上并非实现此目的所必需的,并且在旧代码回调到假定对齐的新代码时,最终会破坏与旧代码的ABI兼容性。整个故事是一个大混乱。

+0

如果在调用时堆栈在16字节边界上对齐,则在32位X86上,该调用将4字节返回地址压入堆栈,堆栈不再位于16字节的边界上。也只有被调用函数的第一个参数将在16字节的边界上,其余的将取决于第一个参数的大小以及其余参数的对齐规则。我不确定这是什么意思。 – rcgldr 2014-10-06 00:49:43

+0

@rcgldr:关键是被调用者在进入时可以知道堆栈指针16的对齐方式,从而可以创建与16字节边界对齐的自动存储对象,而不必对齐堆栈指针本身。当然,对齐堆栈指针本身并不重要,只会将需要对象对齐到16个字节的函数花费在成本上,并且避免了破坏与旧ABI的兼容性,这就是为什么整个约定完全愚蠢的原因。但是,这是历史...... – 2014-10-06 02:03:59

+0

或者被调用者可以只添加一条指令到典型的输入序列:推ebp | mov ebp,esp |和esp,0fffffff0h | 。 – rcgldr 2014-10-06 03:18:09

0

首先,您正在推动减少堆栈指针值的基址指针的值。由于推送操作实际上会导致地址断开。然后,c程序的堆栈框架由代码段组成,在代码段上面有函数的参数,上面的函数位于sp上。现在,当你想访问传递给函数的第一个参数时,你需要添加12个字节,因为最后需要弹出3个单词来获取该参数。

http://www.cs.umd.edu/class/sum2003/cmsc311/Notes/Mips/stack.html

,我发现这个资源非常有用