C/C++的实现问题
关于C/C++函数调用实现的问题有如下程序intFUNCA(){inta=0;}intmain(){inta=0;FUNCA();return0;}编译生成的汇编代码是这...
关于C/C++函数调用实现的问题
有如下程序
int FUNCA()
{
int a = 0;
}
int main()
{
int a = 0;
FUNCA();
return 0;
}
编译生成的汇编代码是这样的(GCC4.4.4,Fedora13)
FUNCA函数
0x8048444 push ebp
0x8048445 mov ebp,esp
0x8048447 sub esp,0x10
0x804844a mov DWORD PTR [ebp-0x4],0x1
0x8048451 leave
0x8048452 ret
主函数
0x8048453 push ebp
0x8048454 mov ebp,esp
0x8048456 sub esp,0x10
0x8048459 mov DWORD PTR [ebp-0x4],0x0
0x8048460 call 0x8048444 <FUNCA()>
0x8048465 mov eax,0x0
0x804846a leave
0x804846b ret
主函数调用FUNCA时将EBP入栈
而后将ESP的值传入EBP
这样是否是将系统栈的第一个栈帧整体上移?也就是原来的栈顶成为了新的栈底?如果系统栈栈帧移动,要把EBP入栈保存很好理解,但是为什么没有将ESP入栈?这样操作ESP不是会将原来的栈结构破坏掉吗?
随后的sub esp, 0x10是否是为了FUNCA函数预留存储空间?
如果是为了预留存储空间为什么是
sub esp,0x10?
这样不是将ESP向栈底移动了吗?要预留空间不是应该将ESP向上移动吗?这个是不是和x86架构的小尾序有关?
leave是不是一条伪指令?就像INVOKE?
是不是实现了
add esp ,0x10
mov esp,ebp
pop ebp
这三条指令?
通过esp指针的移动,是否就实现了函数内部局部变量的销毁?如果局部变量加上了static限定符,编译器会怎么处理?
依然是ESP移动方向的问题,这样将ESP上移不是挪出了10个byte的空闲空间吗?如何达到销毁变量的作用? 展开
有如下程序
int FUNCA()
{
int a = 0;
}
int main()
{
int a = 0;
FUNCA();
return 0;
}
编译生成的汇编代码是这样的(GCC4.4.4,Fedora13)
FUNCA函数
0x8048444 push ebp
0x8048445 mov ebp,esp
0x8048447 sub esp,0x10
0x804844a mov DWORD PTR [ebp-0x4],0x1
0x8048451 leave
0x8048452 ret
主函数
0x8048453 push ebp
0x8048454 mov ebp,esp
0x8048456 sub esp,0x10
0x8048459 mov DWORD PTR [ebp-0x4],0x0
0x8048460 call 0x8048444 <FUNCA()>
0x8048465 mov eax,0x0
0x804846a leave
0x804846b ret
主函数调用FUNCA时将EBP入栈
而后将ESP的值传入EBP
这样是否是将系统栈的第一个栈帧整体上移?也就是原来的栈顶成为了新的栈底?如果系统栈栈帧移动,要把EBP入栈保存很好理解,但是为什么没有将ESP入栈?这样操作ESP不是会将原来的栈结构破坏掉吗?
随后的sub esp, 0x10是否是为了FUNCA函数预留存储空间?
如果是为了预留存储空间为什么是
sub esp,0x10?
这样不是将ESP向栈底移动了吗?要预留空间不是应该将ESP向上移动吗?这个是不是和x86架构的小尾序有关?
leave是不是一条伪指令?就像INVOKE?
是不是实现了
add esp ,0x10
mov esp,ebp
pop ebp
这三条指令?
通过esp指针的移动,是否就实现了函数内部局部变量的销毁?如果局部变量加上了static限定符,编译器会怎么处理?
依然是ESP移动方向的问题,这样将ESP上移不是挪出了10个byte的空闲空间吗?如何达到销毁变量的作用? 展开
1个回答
展开全部
咱们一个问题问题来看:
1.主函数调用FUNCA时将EBP入栈问题:
链接器在最终链接所有目标文件生成可执行文件的时候,会寻找你的程序入口点main,main实际上会被运行时库中的某个函数所调用(main并非是程序真正的入口点,真正的入口点在运行时库中的某个函数,具体跟平台有关),所以在main函数中,首先保存原来的ebp值(push ebp),然后将原来的栈顶设为栈底(mov ebp, esp),到这里已经开辟一个新的栈帧。
为什么没有把esp入栈呢,因为esp已经保存到ebp中了,而ebp已经入栈了,如果要恢复以前的栈帧的话,只需要把ebp的值放入esp,从栈中弹出保存的ebp值到ebp寄存器即可,所以根本没有保存esp的必要。你可以按这个解释画个草图,一画便知。x86下,栈是向小地址方向增长的,即压栈会导致esp的值减小。
然后就是为局部变量分配存储空间(sub esp,0x10),这里为何用减呢?原因上面已经说过,栈是向小地址方向增长的,所以应该用减。跟小尾序表示无关,小尾序仅仅代表数字在内存中的存储布局。
2.其余的问题
leave并非是一个伪指令,而是一个真正的x86指令。它相当于mov esp,ebp; pop ebp这两条指令。前面已经说过,ebp中放的是上一个栈帧中esp的值,所以mov esp,ebp将恢复esp的值。因为esp这时已经和ebp一样,故pop ebp弹出的恰好是已经保存的ebp的值。这样,leave指令执行完毕后,main函数的栈帧就被销毁,所以函数内部的局部变量也就被销毁了。
如果局部变量加上了static限定符,该局部变量实际上并不是在当前函数的栈帧中,而是在初始化数据段里,该变量的地址是固定的,所以编译器无须为该静态变量分配栈空间,所有对该变量的引用都是通过一个固定地址来进行的。栈空间就是通过基址寄存器ebp和栈顶指针寄存器esp来限定的,故esp上移实际上导致了释放出一部分空闲空间,因为在ebp到esp这段地址范围内已经无法找到以前的临时变量,故我们说变量已经被销毁。
兄弟,看在哥哥写这么长的份儿上,给分儿吧!
1.主函数调用FUNCA时将EBP入栈问题:
链接器在最终链接所有目标文件生成可执行文件的时候,会寻找你的程序入口点main,main实际上会被运行时库中的某个函数所调用(main并非是程序真正的入口点,真正的入口点在运行时库中的某个函数,具体跟平台有关),所以在main函数中,首先保存原来的ebp值(push ebp),然后将原来的栈顶设为栈底(mov ebp, esp),到这里已经开辟一个新的栈帧。
为什么没有把esp入栈呢,因为esp已经保存到ebp中了,而ebp已经入栈了,如果要恢复以前的栈帧的话,只需要把ebp的值放入esp,从栈中弹出保存的ebp值到ebp寄存器即可,所以根本没有保存esp的必要。你可以按这个解释画个草图,一画便知。x86下,栈是向小地址方向增长的,即压栈会导致esp的值减小。
然后就是为局部变量分配存储空间(sub esp,0x10),这里为何用减呢?原因上面已经说过,栈是向小地址方向增长的,所以应该用减。跟小尾序表示无关,小尾序仅仅代表数字在内存中的存储布局。
2.其余的问题
leave并非是一个伪指令,而是一个真正的x86指令。它相当于mov esp,ebp; pop ebp这两条指令。前面已经说过,ebp中放的是上一个栈帧中esp的值,所以mov esp,ebp将恢复esp的值。因为esp这时已经和ebp一样,故pop ebp弹出的恰好是已经保存的ebp的值。这样,leave指令执行完毕后,main函数的栈帧就被销毁,所以函数内部的局部变量也就被销毁了。
如果局部变量加上了static限定符,该局部变量实际上并不是在当前函数的栈帧中,而是在初始化数据段里,该变量的地址是固定的,所以编译器无须为该静态变量分配栈空间,所有对该变量的引用都是通过一个固定地址来进行的。栈空间就是通过基址寄存器ebp和栈顶指针寄存器esp来限定的,故esp上移实际上导致了释放出一部分空闲空间,因为在ebp到esp这段地址范围内已经无法找到以前的临时变量,故我们说变量已经被销毁。
兄弟,看在哥哥写这么长的份儿上,给分儿吧!
推荐律师服务:
若未解决您的问题,请您详细描述您的问题,通过百度律临进行免费专业咨询