关于函数调用堆栈的问题。

harry330 2010-09-19 02:58:28
在看深入理解计算机系统中有一段不是很明白,请高手解答。
若有如下函数 int test(int x, int y, int z)
则参数xyz分别存放在存储器中相对于%ebp中地址偏移8,12,16的地方?

我的理解:
由于栈是向低位扩展的,所以从上可以得出,文中的参数入栈的顺序是从左到右的。不是我们一般所采用的从右到左,这个跟调用约定有关。不明白的地方是,第一个参数入栈前的8个字节是啥?我所知道的是,函数调用时,会先将下一条指令压栈,使得函数在返回时,能继续往下执行。还有另外四个字节是什么呢?
...全文
204 15 打赏 收藏 转发到动态 举报
写回复
用AI写文章
15 条回复
切换为时间正序
请发表友善的回复…
发表回复
suchx 2010-09-20
  • 打赏
  • 举报
回复
The offset 8, 12 and 16 is right, because the parameters are in position
[ebp+offset], so x in [ebp+8], y in [ebp+12] and z in [ebp+16]. You can see that
x in low address and z in high address.
jhlong 2010-09-19
  • 打赏
  • 举报
回复
书上讲的也不一定是对的或者说是不全面的
还要看编译选项
比如VC的release版开O2选项的话,很多时候是用esp去寻址
在函数的开头并没有 push esp; mov esp, ebp 这样的代码产生
那么这几个参数相对EBP的位置就不再是8 12 16...
小魔菇 2010-09-19
  • 打赏
  • 举报
回复
堆栈内容

ebp <-- ebp
eip
x +8
y +12
z +16
南之倩倩 2010-09-19
  • 打赏
  • 举报
回复
学习下,汇编都忘了.
whut_lcy 2010-09-19
  • 打赏
  • 举报
回复
观察回复内容太短了!
lly212 2010-09-19
  • 打赏
  • 举报
回复
c/c++ 默认是_cdecl 调用者清理堆栈
int test(int x, int y, int z)
{
return 0;
}

int main()
{

test(1, 2, 3);

return 0;
}


我大概给你看看真实的情况 简单的做了下解释


00401020 /> \55 PUSH EBP
00401021 |. 8BEC MOV EBP,ESP
00401023 |. 83EC 40 SUB ESP,40
00401026 |. 53 PUSH EBX
00401027 |. 56 PUSH ESI
00401028 |. 57 PUSH EDI
00401029 |. 8D7D C0 LEA EDI,DWORD PTR SS:[EBP-40]
0040102C |. B9 10000000 MOV ECX,10
00401031 |. B8 CCCCCCCC MOV EAX,CCCCCCCC
00401036 |. F3:AB REP STOS DWORD PTR ES:[EDI]
// 函数栈初始化 大小40 都变成int3


00401038 |. 33C0 XOR EAX,EAX


// 修复堆栈
0040103A |. 5F POP EDI
0040103B |. 5E POP ESI
0040103C |. 5B POP EBX
0040103D |. 8BE5 MOV ESP,EBP
0040103F |. 5D POP EBP


00401040 \. C3 RETN

下面是相对于EBP传进去的3个值

EBP-58 > 00000001 |Arg1 = 00000001
EBP-54 > 00000002 |Arg2 = 00000002
EBP-50 > 00000003 \Arg3 = 00000003

希望对你有所帮助
harry330 2010-09-19
  • 打赏
  • 举报
回复
[Quote=引用 6 楼 harry330 的回复:]
引用 1 楼 qf17331733 的回复:
呵呵,你理解的挺透呀~那你注意下红字部分,估计你就明白了,后四个应该是返回值~
int test(int x, int y, int z)

入栈顺序根据调用约定是不同的。文中所用的是GCC,可能跟我们常用的编译器有些不一样。如果是从右到左的顺序的话,参数xyz分别存放在存储器中相对于%ebp中地址偏移8,12,16的地方是解释不通的,那应该是……
[/Quote]
不过还是有一点不是很清楚,push ebp有什么用呢?
harry330 2010-09-19
  • 打赏
  • 举报
回复
[Quote=引用 6 楼 harry330 的回复:]
引用 1 楼 qf17331733 的回复:
呵呵,你理解的挺透呀~那你注意下红字部分,估计你就明白了,后四个应该是返回值~
int test(int x, int y, int z)

入栈顺序根据调用约定是不同的。文中所用的是GCC,可能跟我们常用的编译器有些不一样。如果是从右到左的顺序的话,参数xyz分别存放在存储器中相对于%ebp中地址偏移8,12,16的地方是解释不通的,那应该是……
[/Quote]

正解,多谢多谢。
不明白的可以参考如下链接:
http://blog.sina.com.cn/s/blog_63fe27080100hfru.html
wjb_yd 2010-09-19
  • 打赏
  • 举报
回复
call函数的时候,push了eip,这是4个字节。
进入函数体后,会push ebp,这又是4个字节。
然后才是局部变量。

lz可以自己写一个很简单的程序,用vc调试,对照反汇编代码即可。(alt + 8)
harry330 2010-09-19
  • 打赏
  • 举报
回复
[Quote=引用 1 楼 qf17331733 的回复:]
呵呵,你理解的挺透呀~那你注意下红字部分,估计你就明白了,后四个应该是返回值~
int test(int x, int y, int z)
[/Quote]
入栈顺序根据调用约定是不同的。文中所用的是GCC,可能跟我们常用的编译器有些不一样。如果是从右到左的顺序的话,参数xyz分别存放在存储器中相对于%ebp中地址偏移8,12,16的地方是解释不通的,那应该是16,12,8才对。
harry330 2010-09-19
  • 打赏
  • 举报
回复
[Quote=引用楼主 harry330 的回复:]
在看深入理解计算机系统中有一段不是很明白,请高手解答。
若有如下函数 int test(int x, int y, int z)
则参数xyz分别存放在存储器中相对于%ebp中地址偏移8,12,16的地方?

我的理解:
由于栈是向低位扩展的,所以从上可以得出,文中的参数入栈的顺序是从左到右的。不是我们一般所采用的从右到左,这个跟调用约定有关。不明白的地方是,第一个参数入栈前的8个字节是……
[/Quote]
不是吧。当是void的时候也是这样的。而且一般这种返回值是放在eax寄存器的。
harry330 2010-09-19
  • 打赏
  • 举报
回复
[Quote=引用楼主 harry330 的回复:]
在看深入理解计算机系统中有一段不是很明白,请高手解答。
若有如下函数 int test(int x, int y, int z)
则参数xyz分别存放在存储器中相对于%ebp中地址偏移8,12,16的地方?

我的理解:
由于栈是向低位扩展的,所以从上可以得出,文中的参数入栈的顺序是从左到右的。不是我们一般所采用的从右到左,这个跟调用约定有关。不明白的地方是,第一个参数入栈前的8个字节是……
[/Quote]
不是吧。当是void的时候也是这样的。而且一般这种返回值是放在eax寄存器的。
冻结 2010-09-19
  • 打赏
  • 举报
回复
qf17331733 2010-09-19
  • 打赏
  • 举报
回复
呵呵,你理解的挺透呀~那你注意下红字部分,估计你就明白了,后四个应该是返回值~
int test(int x, int y, int z)
乐CC 2010-09-19
  • 打赏
  • 举报
回复
入栈是从右至左的z->y->x

69,373

社区成员

发帖
与我相关
我的任务
社区描述
C语言相关问题讨论
社区管理员
  • C语言
  • 花神庙码农
  • 架构师李肯
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

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