Linux 上 C 程序的内存布局

2018-01-05 19:42:21来源:cnblogs.com作者:宁阳人点击

分享

在仔细研究这个问题之前,我认为 C 程序在内存中只有代码段,堆和栈三部分构成。前几天面试被问到了这个问题,才发现自己的印象是不完全的。

在本文中通过解析析一个 C 程序中变量和函数的地址来分析 C 程序在内存中的布局。

首先简单介绍一下Linux上C程序的内存分布。

一般情况下从低地址到高地址分布着:

  • 程序代码段及只读数据段
    • 程序代码,以及字符串常量等都存储在这里
  • 可读可写数据段
    • 全局变量,静态变量存储在这里  
  • 数据堆
    • 程序中动态分配的内存在这一块 
  • 共享库
    • 程序加载的共享库加载在这个地方
  • 数据栈
    • 局部变量,函数参数,函数返回地址等存储在这里
  • 内核地址
    • 操作系统内核内存空间

C语言代码如下(var_memory.c)

 1 #include <stdio.h> 2 #include <stdlib.h> 3  4 #include <sys/types.h> 5 #include <unistd.h> 6 #include <errno.h> 7 #include <argp.h> 8  9 int global = 123;10 static int static_global = 123;11 12 int main()13 {14     char *string_literal = "hello";15     static int static_local = 456;16     char local_array[100] = {'a', 'b', 'c'};17     int *malloced = (int *)malloc(10*sizeof(int));18 19     pid_t pid = getpid();20     printf("pid: %ld/n", (long)pid);21 22     // string_literaling literal and function in this module are loaded23     // into readonly and excutable segment24     printf("%.8p: addr of main/n", &main);25     printf("%.8p: addr of local string_literal literal/n", string_literal);26     puts("");27 28     // static and global variables are allocated in data segment29     printf("%.8p: addr of global int/n", &global);30     printf("%.8p: addr of global static int/n", &static_global);31     printf("%.8p: addr of local static int/n", &static_local);32     puts("");33 34     // allocated in heap35     printf("%.8p: addr of local malloc/n", malloced);36     puts("");37 38     // errno is from a library39     printf("%.8p: addr of errno/n", &errno);40     puts("");41 42     // printf is from a library43     printf("%.8p: addr of printf/n", &printf);44     puts("");45 46     printf("%.8p: addr of  argp_program_verstatic_localon_hook/n", & argp_program_version_hook);47     puts("");48 49     // local variable in stack50     printf("%.8p: addr of local pid/n", &pid);51     printf("%.8p: addr of local array/n", local_array);52     puts("");53 54     scanf("%s", local_array);55     return 0;56 }

在linux命令行 

make var_memory.c

生成var_memory可执行文件,运行

./var_memory

输出如下:

 1 pid: 4760 2 0x004b26dd: addr of main 3 0x004b29d0: addr of local string_literal literal 4  5 0x004b4008: addr of global int 6 0x004b400c: addr of global static int 7 0x004b4010: addr of local static int 8  9 0x00d30160: addr of local malloc10 11 0xb7db86b4: addr of errno12 13 0xb7e0b1c0: addr of printf14 15 0xb7f8f798: addr of  argp_program_verstatic_localon_hook16 17 0xbf85518c: addr of local pid18 0xbf855198: addr of local array

打开另外一个终端窗口,根据上面输出的pid,运行命令

 pmap 4760 # 进程id以上面输出为准

 输出如下

 1 4760:   ./var_memory 2 004b2000      4K r-x-- var_memory 3 004b3000      4K r---- var_memory 4 004b4000      4K rw--- var_memory 5 00d30000    136K rw---   [ anon ] 6 b7db8000      8K rw---   [ anon ] 7 b7dba000   1852K r-x-- libc-2.26.so 8 b7f89000      4K ----- libc-2.26.so 9 b7f8a000      8K r---- libc-2.26.so10 b7f8c000      4K rw--- libc-2.26.so11 b7f8d000     12K rw---   [ anon ]12 b7fbb000      8K rw---   [ anon ]13 b7fbd000     12K r----   [ anon ]14 b7fc0000      8K r-x--   [ anon ]15 b7fc2000    148K r-x-- ld-2.26.so16 b7fe7000      4K r---- ld-2.26.so17 b7fe8000      4K rw--- ld-2.26.so18 bf836000    132K rw---   [ stack ]19  total     2352K

从运行C语言程序与pmap的输出可以看出。

  • main函数(0x004b26dd)和字符串常量(0x004b29d0)被分配在了内存区域
    • 004b2000      4K r-x-- var_memory,其中rx代表只读和可执行
  • 全局变量global(0x004b4008),全局静态变量 static_global(0x004b400c),局部静态变量(0x004b4010)被分配在了数据段
    • 004b4000      4K rw--- var_memory,其中rw代表可以读和写
  • 使用malloc分配的空间(0x00d30160)处在堆(heap)里
    • 00d30000    136K rw---   [ anon ]
  • 共享库提供的全局变量errno(0xb7db86b4),被分配在共享库数据段里
    • b7db8000      8K rw---   [ anon ]
  • 共享库提供的函数printf(0xb7e0b1c0),被分配在共享库代码段里
    • b7dba000   1852K r-x-- libc-2.26.so
  • 局部变量(0xbf85518c,0xbf855198)被分配在了栈上
  • bf836000    132K rw---   [ stack ]

希望这篇文章,对同样困惑于C程序在内存中布局的你有所帮助。

最新文章

123

最新摄影

闪念基因

微信扫一扫

第七城市微信公众平台