进程--程序地址空间(引文)上篇
目录1.程序地址空间回顾具体作用和解释典型输出规律x86-64 Linux程序地址空间是内存吗1.程序地址空间回顾图1可是我们对他并不理解可以先对其进行各区域分布验证[user1iZ5waahoxw3q2bZ 26-4-24]$ cat code.c #include stdio.h #include unistd.h #include stdlib.h int g_unval; int g_val 100; int main(int argc, char *argv[], char *env[]) { const char *str helloworld; printf(code addr: %p\n, main); printf(init global addr: %p\n, g_val); printf(uninit global addr: %p\n, g_unval); static int test 10; char *heap_mem (char*)malloc(10); char *heap_mem1 (char*)malloc(10); char *heap_mem2 (char*)malloc(10); char *heap_mem3 (char*)malloc(10); printf(heap addr: %p\n, heap_mem); //heap_mem(0), heap_mem(1) printf(heap addr: %p\n, heap_mem1); //heap_mem(0), heap_mem(1) printf(heap addr: %p\n, heap_mem2); //heap_mem(0), heap_mem(1) printf(heap addr: %p\n, heap_mem3); //heap_mem(0), heap_mem(1) printf(test static addr: %p\n, test); //heap_mem(0), heap_mem(1) printf(stack addr: %p\n, heap_mem); //heap_mem(0), heap_mem(1) printf(stack addr: %p\n, heap_mem1); //heap_mem(0), heap_mem(1) printf(stack addr: %p\n, heap_mem2); //heap_mem(0), heap_mem(1) printf(stack addr: %p\n, heap_mem3); //heap_mem(0), heap_mem(1) printf(read only string addr: %p\n, str); for(int i 0 ;i argc; i) { printf(argv[%d]: %p\n, i, argv[i]); } for(int i 0; env[i]; i) { printf(env[%d]: %p\n, i, env[i]); } return 0; }[user1iZ5waahoxw3q2bZ 26-4-24]$ cat Makefile code:code.c gcc -o $ $^ -stdc99 .PHONY:clean clean: rm -f code [user1iZ5waahoxw3q2bZ 26-4-24]$ make gcc -o code code.c -stdc99[user1iZ5waahoxw3q2bZ 26-4-24]$ ./code code addr: 0x40055d 代码区 init global addr: 0x601034 已初始化区 uninit global addr: 0x601040 为初始化区 heap addr: 0x18b8010 堆区 heap addr: 0x18b8030 heap addr: 0x18b8050 heap addr: 0x18b8070 test static addr: 0x601038 静态局部变量 stack addr: 0x7ffd05093ef8 栈区 stack addr: 0x7ffd05093ef0 stack addr: 0x7ffd05093ee8 stack addr: 0x7ffd05093ee0 read only string addr: 0x400800 只读字符串地址 argv[0]: 0x7ffd050947f6 argv[0] 地址 env[0]: 0x7ffd050947fd 环境变量 地址 env[1]: 0x7ffd05094811 env[2]: 0x7ffd0509482a env[3]: 0x7ffd05094835 env[4]: 0x7ffd05094845 env[5]: 0x7ffd05094853 env[6]: 0x7ffd05094876 env[7]: 0x7ffd0509489e env[8]: 0x7ffd050948b1 env[9]: 0x7ffd050948bc env[10]: 0x7ffd05094e58 env[11]: 0x7ffd05094e73 env[12]: 0x7ffd05094ed1 env[13]: 0x7ffd05094efe env[14]: 0x7ffd05094f0f env[15]: 0x7ffd05094f26 env[16]: 0x7ffd05094f2e env[17]: 0x7ffd05094f3f env[18]: 0x7ffd05094f4d env[19]: 0x7ffd05094f82 env[20]: 0x7ffd05094fa5 env[21]: 0x7ffd05094fc4 env[22]: 0x7ffd05094fd0 env[23]: 0x7ffd05094fdc env[24]: 0x7ffd05094fe8这个程序的主要目的是观察和展示 Linux 进程中不同内存区域的地址分布。它通过打印各种变量、函数、动态分配内存、命令行参数、环境变量等的地址让我们直观地理解进程的虚拟地址空间布局如代码段、数据段、堆、栈、命令行参数和环境变量区等。具体作用和解释打印函数地址代码段printf(code addr: %p\n, main);→ 打印main函数的地址位于代码段.text。打印全局变量地址g_val是已初始化的全局变量位于数据段.data。g_unval是未初始化的全局变量位于 BSS 段.bss。二者都位于静态存储区。打印堆地址malloc分配的内存位于堆区。多次调用可以看到堆地址通常向上增长地址逐渐增大。打印静态局部变量地址static int test存放在静态存储区BSS 或数据段取决于是否初始化与全局变量相邻。打印栈地址局部变量heap_mem本身存放在栈上heap_mem打印的是栈地址。多个栈变量地址通常向下增长地址逐渐减小。打印只读字符串地址helloworld是字符串常量存放在只读数据段.rodata。打印命令行参数和环境变量地址argv[i]和env[i]指向的字符串位于进程启动时由内核布置在栈顶的命令行参数和环境变量区。典型输出规律x86-64 Linux运行程序后可以看到地址从低到高大致顺序取决于 ASLR代码段main地址最低。只读数据段字符串常量稍高。已初始化全局/静态g_val和未初始化全局/静态g_unval、test在数据段和 BSS 段地址介于代码段和堆之间。堆heap_mem等地址更高且连续分配时地址递增。栈heap_mem等地址最高通常位于堆之上且栈向下增长不同变量地址递减。命令行参数和环境变量的字符串位于栈顶附近地址可能与栈变量相近或更高。堆栈空间之间有一大段的镂空空间程序地址空间是内存吗---不是内存所以图一的那个是进程地址空间虚拟地址空间--它是一个系统的概念不是语言的概念证明不是物理内存[user1iZ5waahoxw3q2bZ 26-4-24]$ cat code.c #includestdio.h #includeunistd.h int gval 100; int main() { pid_t id fork(); if(id0) { while(1) { printf(子:gval:%d,gval:%p,pid:%d,ppid:%d\n,gval,gval,getpid(),getppid()); sleep(1); gval; } } else { while(1) { printf(父:gval:%d,gval:%p,pid:%d,ppid:%d\n,gval,gval,getpid(),getppid()); sleep(1); } } }[user1iZ5waahoxw3q2bZ 26-4-24]$ cat Makefile code:code.c gcc -o $ $^ .PHONY:clean clean: rm -f code [user1iZ5waahoxw3q2bZ 26-4-24]$ make gcc -o code code.c[user1iZ5waahoxw3q2bZ 26-4-24]$ ./code 父:gval:100,gval:0x60104c,pid:27204,ppid:26909 子:gval:100,gval:0x60104c,pid:27205,ppid:27204 父:gval:100,gval:0x60104c,pid:27204,ppid:26909 子:gval:101,gval:0x60104c,pid:27205,ppid:27204 父:gval:100,gval:0x60104c,pid:27204,ppid:26909 子:gval:102,gval:0x60104c,pid:27205,ppid:27204 子:gval:103,gval:0x60104c,pid:27205,ppid:27204 父:gval:100,gval:0x60104c,pid:27204,ppid:26909 子:gval:104,gval:0x60104c,pid:27205,ppid:27204 父:gval:100,gval:0x60104c,pid:27204,ppid:26909 子:gval:105,gval:0x60104c,pid:27205,ppid:27204 父:gval:100,gval:0x60104c,pid:27204,ppid:26909发现地址一样如果对应是内存地址出bug。---所以不是内存地址---虚拟地址C/C指针用到的地址全部都是虚拟地址所有语言在系统层面上都是虚拟地址期待我们下篇程序地址空间进程地址空间见