08048394 <bar>: int bar(int c, int d) { 8048394: 55 push %ebp 8048395: 89 e5 mov %esp,%ebp 8048397: 83 ec 10 sub $0x10,%esp int e = c + d; 804839a: 8b 45 0c mov 0xc(%ebp),%eax 804839d: 8b 55 08 mov 0x8(%ebp),%edx 80483a0: 8d 04 02 lea (%edx,%eax,1),%eax 80483a3: 89 45 fc mov %eax,-0x4(%ebp) return e; 80483a6: 8b 45 fc mov -0x4(%ebp),%eax } 80483a9: c9 leave 80483aa: c3 ret 你好,return e的汇编与源码为何不一致呢? 我的gcc version 4.4.5 (Debian 4.4.5-8)
图19.1 ,画的不好理解啊, 左边的地址 和右边的指针 都对不上 相应的 内存单元,建议将,左边的地址 和 右边的指针,与内存单元对其 而不要与 单元间的分割线对齐。画图不就是为了好理解吗? 详见王爽的汇编书里的画法,看上去一目了然。
把地址写在线上是为了强调地址是内存单元的首地址。很多书都遵循这一惯例。This won't change.
原文中: “foo函数调用完之后要返回到call的下一条指令继续执行,所以把call的下一条指令的地址0x80483e9压栈,同时把esp的值减4,esp的值现在是0xbf822d18。” 从图19.1来看,esp的值应该为0xbff1c418才是,怀疑原文有误,后面凡是涉及到esp的值都有类似的问题。
的确,这里有严重的不一致,多谢指出!
在执行返回的过程中,mov %esp, %ebp; esp+4.最终esp指向的是CALL的下一条语句的地址,但是在执行函数调用前,函数的参数有压栈。所以我觉得esp的值是不是还应该加一条语句:esp+参数个数*4。 这里不是很懂!
你提的问题很好,不过书上讲的也并没有错。你自己写段程序反汇编研究一下就明白了。
int bar(int c, int d) { 8048394: 55 push %ebp 8048395: 89 e5 mov %esp,%ebp 8048397: 83 ec 10 sub $0x10,%esp int e = c + d; 804839a: 8b 55 0c mov 0xc(%ebp),%edx 804839d: 8b 45 08 mov 0x8(%ebp),%eax 80483a0: 01 d0 add %edx,%eax 80483a2: 89 45 fc mov %eax,-0x4(%ebp) 在push %ebb, 和 Mov %esp, %ebp之后,为什么要把esp减16?没有读懂。
esp减是为了给局部变量e留出空间,所以才能访问-0x4(%ebp),esp减16是为了对齐到16字节边界。
这节已经看不懂了。。。。
"所以下面的指令把参数a和b再次压栈,为调用bar函数做准备,然后把返回地址压栈,调用bar函数: return bar(a, b); 80483b0: 8b 45 0c mov 0xc(%ebp),%eax 80483b3: 89 44 24 04 mov %eax,0x4(%esp) 80483b7: 8b 45 08 mov 0x8(%ebp),%eax 80483ba: 89 04 24 mov %eax,(%esp) 80483bd: e8 d2 ff ff ff call 8048394 <bar>" 这里的意思是否是变量b、a赋值成3、2的意思,如果不是那之前0xbff1c41c和0xbff1c420地址对应内存单元应该是3和2而不是b:3和a:2吧,如果是那此时esp值为0xbff1c414,+4和+0分别对应0xbff1c418和0xbff1c41c,将3和2给此2内存单元又不对?对“把参数a和b再次压栈”这个概念不清楚呀
如果您有建设性意见,哪怕只是纠正一个错别字,也请不吝赐教,您留下的姓名和email将会出现在本书前言的致谢中。再次感谢您的宝贵意见!