首页 > 代码库 > 内存的分区

内存的分区

内存一共4个区 
1.任何在函数内部声明的非static变量,其变量地址本身在栈区。栈是向低地址扩展的数据结构,即栈顶的地址和栈的最大容量是系统预先规定好的。
2.任何全局变量或者静态局部变量,其变量地址本身在全局区
3.任何指针变量 如果用malloc,relloc,calloc,或者c++中的new ,指针指向的内存在堆区。堆是向高地址扩展的
4.代码、字符常量在代码区

例1:
char  sz[] = "string";  这条语句,该语句是按照数组的形式来一个个存放的,编译器将其解释为
char   sz[] = {‘s‘,‘t‘,‘r‘,‘i‘,‘n‘,‘g‘,‘/0‘}; 如果在函数内部出现的话,这几个字符将存放在堆栈中,所以不是字符串常量。
char *psz = "string"; 这条语句,该语句定义了一个指向"string"字符串的指针,并没有空间存放"string"字符串,显然把“string”当做字符串常量并存放在常量区是最合适的选择。并且语句 psz[4] = ‘x‘; 在编译时不会报错,执行时会产生异常,原因是“string”存放在只读存储区,不可以修改。这和C++中 const char *psz = "string";一句是一样的,所以最好显示的加上const关键字从而让编译器检测出“修改常量“错误。
函数中行参为数组时应怎么看待?
如:void  foo(char sz[100], int ival[10]);
答案是将其理解为指针的形式:
void  foo(char *sz, int *ival);
例2:
int a = 1234;   //全局区int main(){    char *b = "Hello!~~";   //指针指向代码区,b变量本身也在栈区    int c = 5678;   //栈区    int *d = (int*)malloc( sizeof(int) ); //指针指向堆区,d变量本身同样在栈区    *d = 9999;    static char e = 0;   //全局区    static int (*f)() = main;  //指向代码区,f本身在全局区        return 0;}

例3:函数递归是通过栈来实现的,栈中是函数返回地址

procedure A1(…);  procedure A2(…);  procedure A3(…);
   begin         begin         begin
      ┇          ┇        ┇
    r:A2(…);      t:A3(…);     end;
    r1
:┇         t1: ┇
   end;         end;



 
 
 



top

 
 

r1


top
 

 
t1
r1



top

 
 
r1


 
 
 

top
 

 
调用A2前
  
调用A2后
  
调用A3后
  
返回A2后

top
 

 
返回A1后

具体地,当调用(call)一个函数时,主调函数将声明中的参数表以逆序压栈,然后将当前的代码执行指针(eip)压栈,跳转到被调函数的入口点。

VarType Func (Arg1, Arg2, Arg3, ... ArgN) {     VarType Var1, Var2, Var3, ...VarN;    //...     return VarN; }

假设sizeof(VarType) = 4(DWORD), 则一次函数调用汇编代码示例为:

调用方代码:

push ArgN ; 依次逆序压入调用参数
push ... 
push Arg1 
call Func_Address ; 压入当前EIP后跳转(EIP:指令寄存器,extended instruction pointer,指向下一条等待执行的指令地址)

跳转至被调方代码:

push ebp ; 备份调用方EBP指针(EBP:基址指针,base pointer,指向系统栈最上面一个栈帧的底部)
mov ebp, esp ; 建立被调方栈底(ESP:堆栈指针,stack pointer,指向系统栈最上面一个栈帧的栈顶)
sub esp, N * 4; 为局部变量分配空间(栈是从高地址向低地址拓展,即栈顶在低地址处)

                      内存低地址 | ESP - - - - - - - - - - - - - - - - EBP - - - - - - - - - - - - - - - - - - - - - >| 内存高地址

mov dword ptr[esp - 4 * 1 ], 0 ; 初始化各个局部变量 = 0 这里假定VarType不是类 
mov dword ptr[esp - 4 * ... ], 0
mov dword ptr[esp - 4 * N ], 0
. . . . . . ; 这里执行一些函数功能语句(比如将第N个参数[ebp + N * 4]存入局部变量), 功能完成后将函数返回值存至eax
add esp, N * 4 ; 销毁局部变量
mov esp, ebp ; 恢复主调方栈顶
pop ebp ; 恢复主调方栈底
ret ; 弹出EIP 返回主调方代码

接上面调用方代码: 
add esp, N * 4 ; 释放参数空间, 恢复调用前的栈 
mov dword ptr[ebp - 4], eax ; 将返回值保存进调用方的某个VarType型局部变量

(eax:4个字节;AX:eax的低2个字节;AH:AX的高字节;AL:AX的低字节)

内存的分区