真假常量——const和define

常量,一般指在程序中出现的数字1,2,3,等,字符串Hello World,以及数组名称等,他们都属于常量。在程序中是不容许修改他们的值程序员

虚假常量const挑战真正常量define数组

下面一段程序:函数

代码前面定义了:工具

#define ZS 2234;测试

程序调试,反汇编以下:spa

如上图所示:命令行

首先:程序是将当即数8BAh(当即数能够做为汇编的操做数)直接存储到const修饰的常量cNum中,其地址为ebp-0Ch指针

第一条cout指令输出cNum的地址:ebp-0Ch,同时将其存入ecx并进栈,做为cout函数调用的参数;调试

第二条cout指令输出cNum的值:内存

能够看到,程序中并无使用到cNum变量的地址[ebp-0Ch],而是经过直接将当即数:8BAh(=2234)直接压栈,做为cout函数的参数;

也就是说当程序中须要用到cNum的值得时候,系统已经用“真正的值”对其进行了替换。

综上所述,能够发现,所谓的const修饰的常量,其本质仍是变量,程序依然是在堆栈中进行空间分配。那么程序又是经过什么来阻止程序员修改const修饰的变量的呢?《C++反汇编与逆向分析技术揭秘》一书中曾提到,const关键字的做用域是在程序编译过程当中,也就是说程序在编译过程当中经过某种检测可以阻止对const修饰的变量的修改。能够尝试对cNum变量进行修改,而后对文件进行编译,发现编译过程当中就会出现错误。那么到底怎么才能修改cNum内存中的数值呢?如今的限制条件只有const关键字一条,那么咱们能够将cNum的地址复制给一个没有const修饰的指针,例如pNum,而后经过pNum来修改内存中的值。尝试以下。

int *pNum=(int*)&cNum;

*pNum=1111;

cout<<(int*)pNum<<endl;

cout<<*pNum<<endl;

cout<<cNum<<endl;

能够发现,输出结果为:

1111

2234

cNum所指向的内存空间中的数值已经修改,可是编译过的程序中出现cNum的地方仍是维持原来的数值(2234

(既然在出现cNum的地方,编译器已经用已知的预设值对其进行了替换,那么修改变量内存中的值起始对程序应该是没有任何影响的。)

真正的常量:数字、字符、字符串

程序中的数字、字符都是直接做为当即数参与汇编指令运算。即其存储位置是代码段。结果以下图:(利用VS2008自带的反汇编窗口,选中“显示代码字节”)

可见,十六进制的数:0x12345678直接被编译成了汇编指令,存储在代码段:0x00411554h位置。

也可利用微软Visual Studio提供的命令行编译工具:dumpbin.exe(一般存在的路径是:C:\Program Files\Microsoft Visual Studio 9.0\VC\bin\

dumpbin /all  XXX.exe,结果截图以下:

下面看一下字符串的存储:

(测试代码同上)

如上图所示:

第一条指令:

将“Hello World”传递给str字符串的时候,直接从文件的只读区00417810h读取,从反汇编代码能够看出,程序利用eaxecxedx三个寄存器将00417810h只读区域的字符串常量“Hello World”拷贝到str所表明的内存堆栈空间ebp-38h中。

第二条指令:定义了一个字符串指针,能够看到其汇编指令只有短短的一行,只是将字符串在只读区域的地址00417880h传递给了指针所指向的堆栈空间。

继续查看利用字符串名和字符串指针来输出的代码:

二者指令彻底相同,都是将所指向的字符串的地址传递给了I/O流函数cin

一样利用dumpbin.exe工具能够看到只读区域的原始代码以下:

相关文章
相关标签/搜索