linux堆栈模型问题???(500分)

fojiao21 2003-10-30 10:28:44
int main()
{
return 0;
}
gcc的汇编如下:Redhat linux8.0 9.0

.file "test.c"
.text
.globl main
.type main,@function
main:
pushl %ebp
movl %esp, %ebp
subl $8, %esp
andl $-16, %esp
movl $0, %eax
subl %eax, %esp
movl $0, %eax
leave
ret
.Lfe1:
.size main,.Lfe1-main
.ident "GCC: (GNU) 3.2.2 20030222 (Red Hat Linux 3.2.2-5)"

想问一下
subl $8, %esp
andl $-16, %esp
到底什么作用?
...全文
43 14 打赏 收藏 转发到动态 举报
写回复
用AI写文章
14 条回复
切换为时间正序
请发表友善的回复…
发表回复
fojiao21 2003-11-11
  • 打赏
  • 举报
回复
up!
fojiao21 2003-11-07
  • 打赏
  • 举报
回复
up!
fojiao21 2003-10-31
  • 打赏
  • 举报
回复
谢谢楼上:
不过
上面我已经说了
我早就知道以前的版本
正是因为与以前的版本不太一样
我才来问的

我想知道为什么这样改,
vc++ 也是预先分了的栈,与这个类似

这样一定有原因,那位编译高手帮一下哈





CoolQ 2003-10-31
  • 打赏
  • 举报
回复
我上边不是跟你说过么?具体的堆栈情况跟 __你的编译器的版本__ 有关系
我回去给你试了一下,如果用gcc-2.96,编译你的程序(就是第一个),结果如下
#gcc -S test.c && cat test.s
.file "test.c"
.version "01.01"
gcc2_compiled.:
.text
.align 4
.globl main
.type main,@function
main:
pushl %ebp
movl %esp, %ebp
movl $0, %eax
popl %ebp
ret
.Lfe1:
.size main,.Lfe1-main
.ident "GCC: (GNU) 2.96 20000731 (Red Hat Linux 7.1 2.96-98)"

#gcc -S -O3 test.c && cat test.s
.file "test.c"
.version "01.01"
gcc2_compiled.:
.text
.align 4
.globl main
.type main,@function
main:
pushl %ebp
xorl %eax, %eax
movl %esp, %ebp
popl %ebp
ret
.Lfe1:
.size main,.Lfe1-main
.ident "GCC: (GNU) 2.96 20000731 (Red Hat Linux 7.1 2.96-98)"

看到了吧?早期的版本是没有这些东西的。现在看看gcc-3.2.2
#gcc -S test.c && cat test.s
.file "test.c"
.text
.globl main
.type main,@function
main:
pushl %ebp
movl %esp, %ebp
subl $8, %esp
andl $-16, %esp
movl $0, %eax
subl %eax, %esp
movl $0, %eax
leave
ret
.Lfe1:
.size main,.Lfe1-main
.ident "GCC: (GNU) 3.2.2 20030222 (Red Hat Linux 3.2.2-5)"

#gcc -S -O3 test.c && cat test.s
.file "test.c"
.text
.p2align 2,,3
.globl main
.type main,@function
main:
pushl %ebp
movl %esp, %ebp
subl $8, %esp
andl $-16, %esp
xorl %eax, %eax
leave
ret
.Lfe1:
.size main,.Lfe1-main
.ident "GCC: (GNU) 3.2.2 20030222 (Red Hat Linux 3.2.2-5)"
/////////////////////////////////////////////////////////////////////////////
最后的总结就是:具体的情况跟编译器的版本有关系,有些东西不用太清楚,如果你真想搞清楚,那只能看编译器的源代码了。int i的情况我还没分析,你自己弄一下吧
fojiao21 2003-10-30
  • 打赏
  • 举报
回复
实际上多一个本地变量后
int i;
汇编没有变化
好像提前呀栈 并且对齐了
fojiao21 2003-10-30
  • 打赏
  • 举报
回复
只把这句废话优化了
movl $0, %eax
subl %eax, %esp
fojiao21 2003-10-30
  • 打赏
  • 举报
回复
用o o2 后,没有变化
CoolQ 2003-10-30
  • 打赏
  • 举报
回复
这个么,你不用具体关心这几条指令的,因为这个编译器的具体实现有关
编译器在生成代码的时候,需要做一系列的分析,所以你的程序和具体的汇编之间并不一定是一一对应的关系,汇编里可能有很多废指令,如果你用优化,也就是-O选项,这些指令可能就没了。不过如果你优化的过头了,一个结果是生成的汇编跟你的源程序完全不一样,还有可能产生SideEffect,所以说一般用 -O就可以了,最好不要用-O2或者-O3,除非你很了解
linaxing 2003-10-30
  • 打赏
  • 举报
回复
关注
fojiao21 2003-10-30
  • 打赏
  • 举报
回复
subl $8, %esp
andl $-16, %esp

而且 不仅subl时, 8 24 40 预分配栈桢
而且 用andl $-16, &esp又作了一次地址对齐

不知如何考虑? 不过这样分配有点像内存分配 用2的n次方大小成块分配
释放的时候 确实方便多了

jkjium 2003-10-30
  • 打赏
  • 举报
回复
gcc编译器在处理这里的时候好像是很令人费解,我做过试验.局部变量8字节以内1字节变量分配1字节,2字节变量分配2字节,3字节变量就分配24字节了,不知道为什么可能是因为内存对齐吧。5,6,7字节变量分配的分别也是24字节,8字节变量就是8字节。在默认的编译命令下函数中的局部变量占用8字节以上的一次性分配16字节.也就是说8字节时分配8字节,9字节时分配24字节,局部变量占25字节时分配40字节,以此类推......
fojiao21 2003-10-30
  • 打赏
  • 举报
回复
当然,如果 压栈的参数超过 8字节,
比如9字节 ,优化前后就是: sub 24,esp : sub 8, esp;
btw:
栈桢的递增是: sub 8, esp -->sub 24,esp--->sub 40,esp

1 ,3, 5 * 8
谁知道有什么讲究:
不会没有原因的东西吧
fojiao21 2003-10-30
  • 打赏
  • 举报
回复
也不是int i 被优化了
因为 ebp没有变
如果int i=1;的话
只是多一句
movl $1, -4(%ebp)
其实也是放进了 subl $8, %esp的堆栈中

我知道以前的版本没有这两句。
现在搞网络安全,不搞清楚,没法做缓冲区溢出。。



CoolQ 2003-10-30
  • 打赏
  • 举报
回复
如果你int i但是没有使用的话,优化当然就给去掉了
至于你说的 subl $8, %esp
andl $-16, %esp
不用太关心的,这个跟GCC的版本都有很大的关系的,如果你用别的版本,结果可能就不是这样。这些是废代码,我记得GCC编译的时候还有一个选项可以不用StackFrame,不过忘了具体的参数了。

23,120

社区成员

发帖
与我相关
我的任务
社区描述
Linux/Unix社区 应用程序开发区
社区管理员
  • 应用程序开发区社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧