栈是 高地址向低地址 递增的结构,拥有后入先出的特点。
在程序运行时,程序段代码是不可变的,所以 需要借助栈来动态的 取出存放计算结果.
每个程序 在运行时 都需要一个栈来协助存储运行时的动态数据,C语言 对每次 调用(Call) 一个方法时,都会用 ebp 保存调用者的栈 位置 esp ,这样每次 方法调用完毕了 将 esp 设置为上一个栈所在位置 就可以 恢复栈了 通俗的说 就像存档点一样 每一次 打怪前 存一下档 只不过 不一样的是 打完怪了 计算机里面 我们每次打完怪了 要恢复成存档点 前的状态,但是 打怪的成果 怎么办呢? 通常C语言 通过eax 传递 返回参数 也就是 调用完子程序后,其他东西都没有变化只有 eax 寄存器 可能保存返回的值 或返回值的指针。
了解了栈 我们 还得 了解 局部变量的
假设我们在一个方法里面 定义了 一个变量

int main(){int a = 0;
int b = *a;
}

定义了 总要有个地方存放这个值吧 ,得知道他 放在哪 才能知道 去哪找到它 并 使用它。

在 C语言里面 局部变量 是由作用域的,作用域 就是 被{} 锁包裹的范围内,
当我们 在main 函数内 声明一个变量,那么它的作用域 就 限制于 main 生命周期 当然main 是整个程序的运行生命周期 所以 main 函数内部的 也就是全局变量 ,
就像上图 所展示的 一样 局部变量会被分配在 栈上。

栈方法调用

void swap(int * a, int *b) {int c;
c = *a; *a = *b; *b = c;
}int main(){int a, b;a=16;b=32;swap(&a, &b);return (a - b);
}

上面 是一个 普通的C语言 程序,但是 通过汇编 来分析上面的程序 可以加深我们对计算机内部原理的认识,同时 也可以更好的 了解栈 指针在程序里面到底是怎样的存在.


我们都知道CPU的计算器 就那么几个,然而在运算时 那么多复杂的计算 寄存器是不够的用的 所以 我们要借助内存可以是栈 把 寄存器的值 暂时 保存一下,然后再去干其它计算。然后用到 这个值的时候再 恢复出来使用。这样 即使靠 几个寄存器 就能完成各种计算任务, 所以 栈就是用来 保存运行时 数据的一个结构。

上面的程序 我们定义了 a b 所以 我们需要在栈里申请空间去存放它,esp 指向的是栈顶 32 位下 栈每次 压入4个字节 往下 压栈 就是 - 4 往上 出栈 就是 + 4。 当我们视试图调用 一个方法 时 ,代码是没有状态的 它并不知道 谁调用了它,但是 调用一个方法一定是要执行 一定的运算 然后给调用者 答案 啊,那怎么办呢 我们说过栈是用来存储运行时数据的地方,那么 我调用后 把 调用者 记录下 在栈内 计算完成后 我到栈里面找到调用者 返回给它不就行了嘛,所以当Call 被执行后 CPU会把 调用者的栈ip(near调用)记录在栈内。 当我们 要掉用 一个栈里面的数据时 我们希望栈方法调用完成后 要把 被调用方法产生的 运算时 栈数据 清除 我们只要结果,要不然 每调用一个方法 就要消耗一点栈内存 这多大内存都挺不住啊,。
那 其实只要记录下,方法调用前 栈的位置 调用完成后 咱们就不要管后面的数据了 当做垃圾数据覆盖掉就好了,所以每次调用方法 记录下 栈的位置 方法调用完成后 把栈的位置 恢复下就好了。
所以 就有了常见的

保存 栈信息

push ebp ;保存上一个栈的位置
mov ebp,esp ;保存当前栈的位置

恢复栈信息:

mov ebp,esp ;保存 esp的值
pop ebp ;恢复上一个栈的位置

当我们 执行完后 只需要 恢复上一个栈的位置,这样 我们 就可以在子程序中使用 栈 当程序运行完毕后只要恢复成 上一个调用栈的地址,有点像链表的意思,每个链表挂一个方法,执行完成后 返回上一个链表所在位置。

悬垂指针

int * getstackval(int * args) {(*args) = 1;int c = 0;return &c;
}int main(){int m = 0;//当 getstackval() 运行完成后 栈就会被回收 之后函数运行 运行时数据 就可能覆盖 指针指向的值int * val = getstackval(&m);//每次打印出不一样的值printf("\n%d\n",val);//被子函数 修改printf("\n%d\n",m);
}

由于 局部变量是 存放在 栈上的,假设A方法 内部声明了一个局部变量 然后 返回指向这个 变量的指针 ,但是 当这个方法 运行完毕后 这个被分配的栈内存空间 就会被回收 再次使用 那么 我们返回的这个指针 指向地址 如果被其他方法 给 覆盖掉的话,那么 这个值 就毫无异议了,但在像GO 语言 会使用 变量逃逸分析,如果这个值 在作用域 范围外 被使用 那么 它会捕获 这个变量 就会 丢到堆里面去 堆比 栈 要慢很多。
而在Rust 中 就显示的 引入了 声明周期 这个概念 如果你 返回的指针 的生命周期 要大于等于 传入参数的生命周期 否则编译器 就会报错。


上图 演示了当call
一个函数栈发生的变化 ,可以看到 当栈return 后 栈 的esp
,ebp 变成了 第一幅图的 一开始的值,并且 返回的指针 被赋予val 其实是 指向运行时栈的地址,当方法返回后 这块栈 就可能会被后面的方法重新利用所以,就会产生 悬垂指针 得到不可预料的值。

从以上分析可知,C 语言在调用函数时是在堆栈上临时存放被调函数参数的值,即 C 语言是传值类语 言,没有直接的方法可用来在被调用函数中修改调用者变量的值。因此为了达到修改的目的就需要向函数 传递变量的指针(即变量的地址)。

通过 汇编了解C语言 指针 悬垂指针概念相关推荐

  1. 野指针   悬垂指针   迷途指针

    一.悬垂指针 当所指向的对象被释放或者收回,但是对该指针没有作任何的修改,以至于该指针仍旧指向已经回收的内存地址,此情况下该指针便称悬垂指针(也叫迷途指针).若操作系统将这部分已经释放的内存重新分配给 ...

  2. 悬垂指针(Dangling pointer)和野指针(Wild pointer)

    转自:http://www.cnblogs.com/submarine/archive/2013/03/02/2940169.html 参看维基百科: Dangling pointer 迷途指针 == ...

  3. C语言开发里指针到底快还是不快?(底层汇编解释)

    C语言开发里指针到底快还是不快? 答:不快,甚至比一般变量要慢! 近日我能看到网上很多人说指针快,我非常纳闷,因为我在学习汇编和cpu底层架构时去翻译过c语言的一些指针代码,给我的答案是:指针从来不快 ...

  4. 【C 语言】指针 与 数组 ( 指针 | 数组 | 指针运算 | 数组访问方式 | 字符串 | 指针数组 | 数组指针 | 多维数组 | 多维指针 | 数组参数 | 函数指针 | 复杂指针解读)

    相关文章链接 : 1.[嵌入式开发]C语言 指针数组 多维数组 2.[嵌入式开发]C语言 命令行参数 函数指针 gdb调试 3.[嵌入式开发]C语言 结构体相关 的 函数 指针 数组 4.[嵌入式开发 ...

  5. C语言,把指针按地上摩擦,爽

    不要陷在指针里面,最好的方法是跳出指针,我们从最终结果来思考问题.于是我的解题思路总是很偏,但是直指本质. 我们写一段代码: 编译,反编译,反编译这里我们用objdump -d hello >1 ...

  6. 【RTOS训练营】课程学习方法和C语言知识(指针、结构体、函数指针、链表)和学员问题

    一.课程学习方法 因为有些学员是刚进群,所以这里再把学习方法讲一下. 1. 预习 我们会在每一节晚课之后会通知要预习的章节,学员需要按如下操作观看相关视频. 1.1 打开百问网官网 ​1.2 点击首页 ...

  7. c语言数组实际作用,要玩转C语言 就要深入指针和数组这两个概念

    原标题:要玩转C语言 就要深入指针和数组这两个概念 指针 预备知识 在深入理解指针之前,我认为有必要先复习或者学习一下计算机原理的基础知识. 计算机是如何从内存中进行取指的? 计算机的总线可以分为3种 ...

  8. 关于C语言中的数组指针、指针数组以及二级指针

    概念解释 数组指针:首先它是一个指针,它指向一个数组,即指向数组的指针:在32 位系统下永远是占4 个字节,至于它指向的数组占多少字节,不知道.数组指针指向的是数组中的一个具体元素,而不是整个数组,所 ...

  9. c语言中程序偏离,C语言中的指针加减偏移量

    首先看一段程序: #include int main() { int a[5] = {1, 2, 3, 4, 5}; int* p = (int*)(&a + 1); printf(" ...

最新文章

  1. SCVMM2012 SP1 之虚拟机模板的创建
  2. 三层架构实战篇—系统登录实例
  3. 网络小贷迎来最强监管,八成公司恐将面临转型或淘汰
  4. 计算机组装与维修案例分析,计算机组装毕业论文
  5. 15岁杀人犯监狱学编程,37岁保释年薪70万
  6. 4月12日 webform基本控件
  7. linux之tmp文件夹
  8. mysql允许两个用户远程连接,配置MySQL服务允许用户远程连接
  9. Knapsack Cryptosystem【折半+查找】
  10. Java笔记-多线程中同步加锁相关
  11. testservice小项目总结
  12. 如何自定义安装mysql_安装MySQL
  13. mysql升级:rpm包安装升级
  14. 操作 神通数据库_国产神通数据库操作备忘(Linux)
  15. Highcharts - Bar Chart Column Chart
  16. 李勇强seo,李勇强SEO
  17. win10 C盘满 清理终极大法
  18. Mathorcup数学建模竞赛第四届-【妈妈杯】A题:“2048”游戏的数学基础及其取胜策略研究(附赛题解析及MATLAB代码)
  19. iphone13哪个颜色好看
  20. jsp页面如何调用本机的应用程序?例如c:/netterm.exe?(转载)

热门文章

  1. 单页应用SEO解决方案
  2. [洛谷P1856] [USACO5.5]矩形周长Picture
  3. IBM Storwize V5000资源管理柜
  4. mirror命令详解
  5. 怎么使用GK888CN打印机批量打印条码
  6. 关于Bonobo Git Server的安装
  7. 中学教学参考杂志中学教学参考编辑部中学教学参考杂志社2022年第18期目录
  8. 斗鱼连续6个季度亏损:活跃用户降幅明显,虎牙市值是前者的两倍
  9. MySQL:ERROR 1819 (HY000): Your password does not satisfy the current policy requirements
  10. 基于深度学习的x射线图像骨龄自动特征提取