变量那些事

1.局部变量

第一次提出局部变量,是在1960年的 ALGOL 60 语言,现在广泛使用的C语言就继承与它(语言图谱)。局部变量让一段代码相对独立,让给纸带打孔的码农从全局变量中解脱。说到与局部变量,一定会想到子程序。从现代语言看,子程序和局部变量就如前门大少与杀毒哥,如胶似漆♂形影不离。有趣的是这两个概念并不是同时出现,子程序早于局部变量,是1958年由
FORTRAN II
语言提出。当时计算机硬件还没有栈的概念,子程序的返回地址不是通过压栈,而是通过一个固定地址存储。历史上除了现在熟悉的寄存器指向内存方式的栈,还出现过寄存器栈,就是由几个固定的寄存器存储压栈数据,只能实现固定大小的栈,1971年
Intel 第一款 CPU Intel 4004 就是这样的设计,有三个栈寄存器。顺带提一下,第一款 x86 CPU  Intel 8086 在1978年发布。

虽然CPU通过SP寄存器、PUSH、POP等指令提供了对局部变量的支持,但是在底层并没有局部变量的概念,局部变量特殊在,它的访问是通过SP寄存器指向的一块内存。早期CPU没有SP寄存器,可以专门拿出一个通用寄存器,用软件指令模拟。当然现在也可以,不过现在栈使用非常频繁,使用通用寄存器加指令模拟的方式会降低速度,所以CPU设计专用寄存器和专门的指令,提高处理速度。

一个重要的概念,堆栈平衡。其实没堆的事情,准确说应该称作“栈平衡”,不知为何被称作堆栈平衡,也许是怕听得人只记得一个“贱”字(笑)?。前面我们提到了栈是CPU提供的一个寄存器指向的内存地址,同一个线程中,代码使用同一个栈。这就涉及一个问题,如果前面有代码PUSH了栈但是没POP,后面的代码怎么知道现在SP指向什么数据?堆栈平衡就是说某段使用了栈的代码,在调用前和调用后,SP指针应该指向相同的位置,对后面的代码来说,栈就像没有发生过变化。

这又引出了调用约定的概念,是调用者处理堆栈平衡还是子程序自己处理堆栈平衡。注意,调用子程序后,栈实际承载了三部分数据,分别是:函数参数,调用返回地址,局部变量。调用约定处理的是函数参数使用的栈,子程序内部的局部变量还是由自己处理。常见的调用约定有
stdcall,cdecl,fastcall,naked,thiscall,调用约定还指定了多个参数的压栈顺序,有兴趣可以搜下,不展开了。

让我们看看局部变量被扒光是什么样子,对大多数子程序,局部变量的框架会是下面这个样子:


push    ebp                     ;保存ebp
mov ebp, esp ;获取当前栈顶
sub esp, 0CC ;申请栈空间
... ;
...
...实现功能
...
...
mov esp, ebp ;注意这句
pop ebp ;
retn ;

代码短小精悍,解释一下在做什么,esp是栈专用寄存器,push或pop一下,值就变了。如果基于它来访问局部变量栈,需要考虑push和pop指令对esp的干扰,再计算局部变量偏移,非常复杂。通过上面的代码可以发现,刚进入子程序时保存了ebp并且将当时的esp赋值给ebp。从这之后,ebp不再发生变化,局部变量和传递的参数都通过“ebp+偏移”的方式,以ebp为基地址进行访问。实际上ebp也是一个专用寄存器,全名是EBP
Extended (Stack) Base Pointer
栈基指针寄存器。函数退出时,只需要把ebp赋值给esp,再还原ebp,栈就像是什么都没发生过,局部变量占用的栈就彻底被释放了。

局部变量更像是编译器维护的一个内存池,通过作用域控制内存的申请和释放。局部变量除了解决了全局变量维护复杂,代码无法复用外,还解决了另外一个困扰程序员的老大难的问题,给变量起名(笑)。

有人好奇过栈的大小吗?栈大小由编译器决定,可以通过参数改变,VC默认大小是1M。编译器实际是通过PE文件头的栈大小参数来决定PE文件载入内存时系统给栈分配多大内存。如果局部变量过大,超过1M,会报栈溢出异常,一般发生在多个函数嵌套累计申请了过多局部变量或者递归过深。

前几天前门大少调试程序,修改eip程序没崩,有点反直觉。因为根据堆栈平衡,如果有对栈的操作,并且修改了eip,堆栈是被破坏的状态,在函数返回取返回地址时一定会崩溃,但是没崩,为什么呢?就是因为上面代码中的那行“注意这句”,函数的堆栈平衡是通过ebp直接还原状态,没有通过push和pop配对的方式,所以修改eip可能会造成逻辑错误,但是不会让程序崩溃。如果修改的是ebp,那就回天乏术了。

2.全局变量

(待续)

变量那些事,布布扣,bubuko.com

时间: 2024-10-11 21:03:43

变量那些事的相关文章

03.关于Shell变量那些事

Shell支持自定义变量. 定义变量 定义变量时,变量名不加美元符号($),如: variableName="value" 注意,变量名和等号之间不能有空格,这可能和你熟悉的所有编程语言都不一样.同时,变量名的命名须遵循如下规则: 首个字符必须为字母(a-z,A-Z). 中间不能有空格,可以使用下划线(_). 不能使用标点符号. 不能使用bash里的关键字(可用help命令查看保留关键字). 变量定义举例: hello="world" huawei="坑爹

MAC JAVA 环境变量那些事

1,查看 JAVA 的版本号 akdeMacBook-Pro:bin AK$ java -version java version "1.6.0_65" Java(TM) SE Runtime Environment (build 1.6.0_65-b14-466.1-11M4716) Java HotSpot(TM) 64-Bit Server VM (build 20.65-b04-466.1, mixed mode) 2,切换不同 JAVA 版本号 1)cd /usr/bin/

linux使用c shell 、b shell 环境变量的问题

(睡醒午觉后,头脑特别清晰,于是整理一篇把曹同学的昨天问题解答了^_^,收集资料的过程,也是学习的过程) 背景: 昨天快下班时,每次赶燕郊班车的曹同学都会准时跑掉,可是都已经快7点了,曹同学还在座位无动于衷,这很反常,过了一小会,曹同学跑过来. 曹同学:我犯错误了~~~把一台linux机器搞挂了~~~ me:10.10.0.5?告警中层? 曹同学:是的 me:挂了是什么情况? 曹同学:把mqadmin用户改成c shell后,所有命令都失效了... me:(觉得很神奇,但只要不是丢文件,只是登录

基础篇:8.如何定义变量?js变量有什么特点?

书接上文,废话不多说,直接进入正题,下面我们一起来讨论js中的变量那些事! 那什么是变量? 变量是存储信息的容器,可以存储任何类型的数据. 如何定义变量呢? 变量可以使用短名称,如x,y:也可以是长名称,如information,construction;但是定义变量也是有要求的,变量的首字母必须是由字母(a-zA-Z)或下划线(_)或美元符($)开头,不能是数字, 后面的可以是字母(a-zA-Z)或下划线(_)或美元符($)或者是数字,并且是区分大小写的,如:name和Name是不同的2个变量

【系统那点事】bash代码注入的安全漏洞【转】

本次日记来自网络(点) 很多人或许对上半年发生的安全问题“心脏流血”(Heartbleed Bug)事件记忆颇深,这两天,又出现了另外一个“毁灭级”的漏洞——Bash软件安全漏洞.这个漏洞由法国GNU/Linux爱好者Stéphane Chazelas所发现.随后,美国电脑紧急应变中心(US-CERT).红帽以及多家从事安全的公司于周三(北京时间9月24日)发出警告. 关于这个安全漏洞的细节可参看美国政府计算安全的这两个漏洞披露:CVE-2014-6271 和 CVE-2014-7169. 这个

ORA-01034:ORACLE not available问题的解决方法

同时在自己电脑上装了oracle客户端和服务器,上次还能用呢,这次突然用不了. [[email protected] oracle]$ sqlplus scott/tiger SQL*Plus: Release 9.2.0.4.0 - Production on Mon Nov 24 11:06:50 2008 Copyright (c) 1982, 2002, Oracle Corporation. All rights reserved.ERROR:ORA-01034: ORACLE not

JAVA实践红黑树-小试牛刀

前言 第一感觉是和AVL树差别不是特别大,没有很直观的感受到效率的巨大提升,作为一个小小的强迫症患者,还是AVL树更好看. 不过讲道理,平衡被破坏次数相同情况下,红黑树的确少了那么一些旋转... 因为插入节点后平衡被破坏时,红黑树的会选择旋转或变色. AVL树则只有旋转. 另外我发现其他的大神写法,跟我的有点差距...有心人可以帮我瞄一眼,我是不是哪里错了,在此先谢过了~~ 另外一个参考网站.博客.PDF: 红黑树的可视化,插入.删除节点都有动画效果哦~ 神奇的讲义,略的比较多,但就胜在简略 一

Google C++ 风格指南内容整理

之前一直没有全面的看过Google C++风格指南,现在很多公司进行C++开发都要求按照Google C++风格.在这个网站 http://zh-google-styleguide.readthedocs.org/en/latest/contents/  有人已经把其翻译成中文.为了便于以后查看,下面的内容完全是来自于这个网站,只是把多个网页的内容整理放在了一起. 1.      头文件: 通常每一个.cc文件都有一个对应的.h文件.也有一些常见例外,如单元测试代码和只包含main()函数的.c

ORA-01034 报错

问题描述: 执行任何DB语句都会有如下报错: Copyright (c) 1982, 2002, Oracle Corporation. All rights reserved.ERROR:ORA-01034: ORACLE not availableORA-27101: shared memory realm does not exist 原因: 1,数据库没有打开时,其它用户是联不上的.2,如果用sys也打不开数据库,则可能是坏境变量的事了. 解决方法: SQL> startup 源博客: