内存分区
- 堆区 (Heap)
特点:动态申请 可读可写
- 栈区 (Stack)
特点:由系统进行内存的管理。主要存放函数的参数以及局部变量。
在函数完成执行,系统自行释放栈区内存,不需要用户管理。
- 代码区
存放程序的二进制代码。比如我们写的函数,都是在代码区的。特点: 可读可写可执行,存放程序编译后的二进制代码,不可寻址区。
- 全局/静态存储区
特点:可读可写
静态存储区内的变量在程序编译阶段已经分配好内存空间并初始化。这块内存在程序的整个运行期间都存在,它主要存放静态变量、全局变量和常量。
包括:常量区(静态常量区),全局区(全局变量区)和静态变量区(静态区)。
- 常量区
特点: 只读!
字符串常量区和常变量区。
计算机寻找原理
如以下的函数:
int f = 10;
int func (int a, int b){
printf("hahha");
int c = a + f;
return c;
}
int main(int argc, char * argv[]) {
printf("%d",func(1, 2));
return 0;
}
寻找常量和全局变量:
注意上面的 adrp 指令 (adrp:address page 常量)
adrp x0, 1
1. 将1的值,左移12位 1 0000 0000 0000 == 0x1000
2.将PC寄存器的低12位清零 pc = 0x0000000100fe2874; 0x100fe2874 ==> 0x100fe2000
3.将将1 和 2 的结果相加 给 X0 寄存器!!
adrp 是计算指定的数据地址 到当前PC值的相对偏移;
由于得到的结果是低12bit为0,
2^10 == 1024 Byte
2^12 == 4KB
所以要寻找的地址和当前 pc 的值的误差即4 kb, 也就是要寻找的(常量所在的)地址一定会在这 4KB 里面。现在找到的是一个粗略的基址,以这个基址可以在(再加上)偏移4 kb 的范围内找到。
要算准确的地址呢?
第二句:add x0, x0, #0xf28 中的偏移 #0xf28,计算机编译的时候知道的偏移地址,和此时的 pc 为:
Printing description of $pc:
(unsigned long) pc = 0x0000000100fe2888
可以得到:
0x100fe2888—> 0x100fe3000—>0x100fe3f28
计算过程:
p (char *) 0x100fe2000 + 0x1000 + 0xf28 = 0x100fe3f28
可以看到结果如下:
第二个 adrp (全局变量)
此时的 (unsigned long) pc = 0x0000000100fe2894
通过推算,准确的地址为:0x0000000100fe4d10
打印结果如下:
可以看到,找到的则为全局变量 f 的值。
注意:需要说明的一点是:要打印地址的值,即为指针做指向的值,p (Int *) 打印的还是这个地址,要打印该地址的值则为:p *(int *) + 地址。