全局变量作用于整个程序,一直都存在这个我们稍微了解任何一门编程语言都知道,他放在全局变量的内存区;而局部变量则是存在于函数的堆栈区,当函数调用结束后便消失.在大多数程序中,常数一般放在全局变量中,如一些注册版标记 测试版标记等.
在大多数情况下,在汇编代码中识别全局变量比其他结构要容易的多.全局变量通常位于数据块(.data)的一个固定地址上,当程序需要访问全局变量时,一般会用一个固定的硬编码的地址直接对内存寻址.比如说这样:mov eax,dword ptr [4084c0h] ;直接调用全局变量,其中4084c0h是全局变量的地址.
全局变量可以被同一个文件中所有的函数修改,某个函数改变了全局变量的值,就能影响到其他函数,相当于各个函数间的传递通道.因此就可以利用全局变量传递参数 传递函数返回值等.全局变量在程序的全部执行过程中都占用内存单元,而不像局部变量需要时才开辟空间.
来看一个利用全局变量传递参数的实例,具体代码如下:
- int z; //全局变量z
- int add (int x,int y);
- int main(void)
- {
- int a=5,b=6;
- z=7;
- add (a,b);
- return 0;
- }
- int add(int x,int y)
- {
- return (x+y+z);
- }
将其编译成EXE然后反汇编后,代码就是下面这种样子了:
- psuh ebp
- mov ebp,esp
- sub esp,00000008
- mov [ebp-04],00000005 ;[ebp-04]是局部变量,放参数1
- mov [ebp-08],00000006 ;[ebp-08]是局部变量,放参数2
- mov dword ptr [004084C0],07 ;对全局变量[004084C0]初始化
- mov eax,dword ptr [ebp-08]
- psuh eax
- mov ecx,dword ptr [ebp-04]
- push ecx
- call 00401034
- add esp,000008
- xor eax,eax
- mov esp,ebp
- pop ebp
- ret
;add (x,y)函数的代码
- push ebp
- mov ebp,esp
- mov eax,dword ptr [ebp+08] ;[ebp+08]为参数1
- add eax,dword ptr [ebp+0c] ;[ebp+0c]为参数2
- add eax,dword ptr [004084C0] ;调用了全局变量[004084c0]
- pop ebp
- ret
全局变量4084C0h所在的区段是.data区块,这个区块的属性是可读可写.
这种对内存直接寻址的硬编码方式,比较容易识别出这是一个全局变量.一般编译器会将全局变量放到可读写的区块里,如果放到只读区块里,那么这是一个常量.另外,与全局变量类似的是静态变量,都可以按直接方式寻址等,所不同的是,静态变量作用范围是有限的,仅在定义这些函数内有效.
然后是数组
数组是相同数据类型的元素的集合.它们在内存中按照顺序连续存放在一起.汇编状态下访问数组一般是基址加上某变量来实现的.看实例:
- int main(void)
- {
- static int a[3]={0x11,0x22,0x33};
- int i,s=0,b[3];
- for (i=0;i<3;i++)
- {
- s=s+a;
- b=s;
- }
- for (i=0,i<3;i+=)
- {
- printf("%d/n",b);
- }
- return 0;
- }
编译完毕后,反汇编代码如下:
- sub esp,0c ;为局部变量分配内存,用来存放b
- xor ecx,ecx ;s=0
- xor eax,eax ;i=0
- push esi
- push edi
- @@:
- mov edi,dword ptr [eax+407030] ;407030只想数组a[],即数组的基址
- add eax,4 ;访问数组的索引
- add ecx,edi ;s=s+a
- cmp eax,0c
- mov dword ptr [esp+eax+4],ecx ;b=s
- jl @F
- lea esi,dword ptr[esp+8]
- mov edi,3 ;计数器
- @@:
- mov eax,dword pttr [esi] ;esi指向b[]数组
- push eax
- push 40703c
- call 00401050 ;printf ("%d/n",b)
- add esp,8
- add esi,4 ;指向数组下一元素
- dec edi
- jnz @F
数组在内存中可以存在于堆栈 数据段以及动态内存中.我这次说的数组a[]就保存在.data段中,其寻址可以用"基址+偏移量" 来实现.
mov eax,[407030h+eax]
| |
基址 偏移量
这种间接寻址一般出现在给一些数组或结构赋值情况下,其寻址形式一般式[基址+n],其中基址可以是常量也可以是寄存器,为定值.随着n值的不同,就可对结构中相应单元赋值了.
b[]数组放在堆栈中,这些堆栈是编译时刻进行分配的.数组在声明时可以直接计算偏移地址,针对数组成员寻址是采用实际的偏移量完成的.