首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C程序內存佈局全解析(二):實戰地址分析與readelf/proc工具實戰

     編輯:關於C語言

C程序內存佈局全解析(二):實戰地址分析與readelf/proc工具實戰

本文通過具體代碼示例,結合readelf與/proc工具,從實際內存地址角度完整演示C程序的四大分區分佈,並驗證各類變量的具體歸屬。

一、示例程序與變量地址輸出

int ga1;           // 未初始化全局變量
int ga2 = 1;       // 已初始化全局變量

int func() {
    int i = 0;                 // 局部非靜態變量
    static int static_la1;     // 未初始化局部靜態變量
    static int static_la2 = 3; // 已初始化局部靜態變量
    printf("Address of i: %p\n", &i);
    printf("Address of static_la1: %p\n", &static_la1);
    printf("Address of static_la2: %p\n", &static_la2);
    while(i++ < 8) sleep(1);
    return 0;
}

int main() {
    int la1;                  // 局部非靜態變量
    int la2 = 2;              // 局部非靜態變量(已初始化)
    int *p = malloc(3*sizeof(int)); // 動態分配內存
    
    printf("Address of ga1: %p\n", &ga1);
    printf("Address of ga2: %p\n", &ga2);
    printf("Address of la1: %p\n", &la1);
    printf("Address of la2: %p\n", &la2);
    printf("Address of p: %p\n", p);  // 堆內存地址
    
    func();
    free(p);
    return 0;
}

二、運行輸出地址記錄

Address of ga1: 0x804a040
Address of ga2: 0x804a030
Address of la1: 0xbfc7e7b4
Address of la2: 0xbfc7e7b8
Address of p: 0x8ffc008
func is running
Address of i: 0xbfc7e78c
Address of static_la1: 0x804a03c
Address of static_la2: 0x804a034

三、readelf靜態分析:確定代碼區與數據區範圍

$ readelf -S program
...
[24] .data PROGBITS 0804a028 001028 000010 00 WA 0 0 4
[25] .bss  NOBITS 0804a038 001038 00000c 00 WA 0 0 4
...
[13] .text PROGBITS 080483e0 0003e0 0002a2 00 AX 0 0 16

關鍵信息提取:

  • 代碼區(.text):0x080483e0 起,大小 0x2a2
  • 數據區.data:0x0804a028 起,大小 0x10 (16字節)
  • 數據區.bss:0x0804a038 起,大小 0xc (12字節)

四、變量歸屬推斷(靜態區)

五、動態區分析:/proc/[pid]/maps 獲取堆棧範圍

後台運行程序,查看進程映射:

$ ./program &
[1] 2736
$ cat /proc/2736/maps
08048000-08049000 r-xp ... /home/test/program  // 代碼區
0804a000-0804b000 rw-p ... /home/test/program  // 數據區(.data/.bss)
0964d000-0966e000 rw-p 00000000 00:00 0 [heap] // 堆區
bfde3000-bfe04000 rw-p 00000000 00:00 0 [stack] // 棧區

提取關鍵範圍:

  • 堆區:0x0964d000 - 0x0966e000
  • 棧區:0xbfde3000 - 0xbfe04000

六、剩餘變量歸屬推斷(動態區)

變量地址分區判定邏輯所屬分區
ga20x804a030在.data範圍內 (0x0804a028 ~ 0x0804a038).data
static_la20x804a034在.data範圍內.data
ga10x804a040≥ .bss起始 (0x0804a038).bss
static_la10x804a03c≥ .bss起始.bss
變量地址分區判定所屬分區
la10xbfe01cf4在棧區範圍內棧區
la20xbfe01cf8在棧區範圍內棧區
p0x0964d008在堆區範圍內堆區
i0xbfe01ccc在棧區範圍內棧區

七、內存模型可視化

C程序內存佈局圖

圖示直觀展示了從低地址到高地址的分區順序,以及堆棧相向增長的動態特性。

八、核心結論與實踐建議

  1. 全局/靜態變量:編譯期確定地址,屬<.data>或<.bss>,多次運行地址不變
  2. 局部非靜態變量:運行時棧上分配,屬棧區,地址隨運行變化
  3. 動態分配內存:運行時堆上分配,屬堆區,地址隨運行變化
  4. 工具組合拳:readelf看靜態段,/proc/maps看動態映射,printf("%p")看具體變量
  5. 調試技巧:懷疑內存越界時,對照maps檢查地址是否在合法映射區內

建議讀者在自己的環境編譯運行示例代碼,親自觀察地址分佈,建立具體的內存空間直覺。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved