ebp 函数堆栈esp_什么是堆栈?

堆与栈是两种数据结构,并不是一种数据结构,堆是堆,栈是栈。

1、栈:是一种只能在一端进行插入和删除的数据结构。

允许插入与删除的一端被称为栈顶,另一端被称为栈底。

按照先进后出的顺序存储数据。最先进入的数据存放在栈底,最后进入的数据存放在栈顶。

当栈里的元素为空时,称为空栈。

在函数调用的时候用于存储断点,递归的时候,也需要用到栈。

栈一般包含以下两个方面的信息:

(1)函数的返回地址和参数。

(2)临时变量:包括函数的非静态局部变量及编译器自动生成的其他临时变量。

在汇编语言中,栈顶由esp寄存器进行定位,压栈的操作使得栈顶的地址减小,弹出的操作使得栈顶的地址增大。

2、堆:是一种动态的存储结构,实际上是数据段中的自由存储区,常用语存储、分配动态数据。

堆中存入的数据地址向增加方向变动。

堆可以不断的进行分配直到没有堆空间为止,也可以随时进行释放、在分配,不存在顺序问题。

在C语言中,堆空间的分配通常通过malloc()、calloc()、realloc()三个函数来实现的,而堆的释放是通过free()函数来进行释放分配的空间。

3、栈的体验

如何通过栈将数组里面的数据通过print函数打印出来呢?

print函数没有参数,应该在print函数里面填充什么代码,可以实现将arr数组里面的数据全部打印出来呢?

#include void print(){}int main(){ int a = 1; int b = 2; char c = 'c'; int arr[] = { 11,12,13,14,15,16,17 }; print(); return 0;}

那么这就涉及到汇编的一些东西了,具体汇编如下:

1、push操作先移动栈顶指针,之后将信息入栈。

2、eps为栈顶指针,压栈的操作使得栈顶的地址减小,弹出的操作使得栈顶的地址增大。

3、ebp是32位的bp,是基址指针。bp为基指针寄存器,用它可以直接存取堆栈中的数据,它在调用函数时保存esp,以便函数结束时可以正确返回。

4、默认的函数内部变量的压栈操作为:从上到下,从左到右,采用4字节对齐,数组压栈方法略有不同,即从最后一个元素开始,直到起始元素为止,即采用从右到左的方法压栈。

在main()函数和print()函数的开头都有如下两句汇编指定:

eff4d766166c9955636cf6866e6ce294.png

main函数

f30add9b49a3f2906e3f9d45b9024699.png

print函数

第一个push指针的操作步骤是,首先移动栈顶指针esp,然后将ebp内容压栈,注意此时压栈的ebp的值为上一个函数的esp的值,而esp恰好就是上一个函数的栈底。

所以每个函数一开始push指令就是保存上一个函数的栈底。

由于esp是当前的栈顶指针,所以该指针的作用就是保存当前栈顶指针的值。

由此就可以得出,ebp存放的就是此刻栈顶的地址,也就是说,ebp是一个指针,指向栈顶,而栈顶存放的数据就是上一个函数的ebp的值,就上一个函数的栈底。

所以我们只需要在print函数中得到main函数的栈底,就可以去取出数组中的每一个元素了。

具体实现方法如下:

void print(){ unsigned int _ebp; __asm { mov _ebp, ebp; } int *p = (int *)(*(int *)_ebp - 4 - 4 - 4 - 4 * 7 ); for (int i = 0; i < 7; i++) { printf("%d
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值