您好,登錄后才能下訂單哦!
c語言在嵌入式、操作系統、圖像處理方面應用廣泛,是一種比較底層的語言。本文主要介紹c語言的內存分配,進程在內存中的布局。
環境:
Linux zhuzhu 4.2.0-27-generic #32~14.04.1-Ubuntu SMP
gcc version 4.4.7
首先上一張進程在內存中的布局圖:
注: 該圖僅表示進程在32位linux操作系統下的布局,對于windows內存布局并不是這樣的,有興趣的可以將下面的程序在VC6.0上運行試試,會發現與此布局相差很大。
從圖中可以看到:
1、高地址空間0xBFFFFFFF-0xFFFFFFFF為內核空間,用戶程序無法直接訪問;
2、用于存放環境變量、main函數傳進來的參數存放空間;
3、棧空間主要用于存放局部變量、函數參數等,其從高地址向低地址增長;
4、未分配區,主要作用是供棧、堆動態擴展用和mmap映射;
5、主要用于動態內存分配空間,從低地址向高地址增長;
6、BSS用于存放未初始化的全局變量、初始化為零的全局變量;
7、數據段主要用來存放初始化的全局變量,靜態全局、局部變量,常量,只讀變量;
8、代碼段用于存放可執行的代碼,為只讀。
注: 對于ARM架構來說函數傳參,前四個參數是放在R0-R3寄存器中的,超過四個的參數才會放堆區。
例:
#include <stdio.h> #include <stdlib.h> #include <string.h> #define STR_SIZE 32 int g_un_init; int g_init[100000] = {0}; int g_init_a = 521; static int g_static_data = 125; int main(int argc, char *argv[]) { int local_a; static int local_static_b; char *str = "xiaozhu"; char *local_str = NULL; local_str = malloc(STR_SIZE); if (local_str == NULL) { printf("no mem \n"); return -1; } printf("argv[1] = %p \n", argv[1]); printf("g_un_init = %p \n", &g_un_init); printf("g_init = %p \n", g_init); printf("g_init_a = %p \n", &g_init_a); printf("g_static_data = %p \n", &g_static_data); printf("local_a = %p \n", &local_a); printf("local_static_b = %p \n", &local_static_b); printf("str = %p \n", str); printf("local_str = %p \n", local_str); free(local_str); return 0; }
編譯程序,對編譯結果在ubuntu上執行:readelf -h a.out 來獲取程序的入口地址為0x8048390:
程序執行結果為:
root@zhuzhu:blog# ./a.out zhu argv[1] = 0xbfa80633 g_un_init = 0x80abae4 g_init = 0x804a060 g_init_a = 0x804a028 g_static_data = 0x804a02c local_a = 0xbfa8025c local_static_b = 0x80abae0 str = 0x8048640 local_str = 0x8d0b008
在命令行下執行:readelf -S a.out 獲取程序詳細段大小:
root@zhuzhu:blog# readelf -S a.out There are 30 section headers, starting at offset 0x117c: Section Headers: [Nr] Name Type Addr Off Size ES Flg Lk Inf Al [ 0] NULL 00000000 000000 000000 00 0 0 0 [ 1] .interp PROGBITS 08048154 000154 000013 00 A 0 0 1 [ 2] .note.ABI-tag NOTE 08048168 000168 000020 00 A 0 0 4 [ 3] .note.gnu.build-i NOTE 08048188 000188 000024 00 A 0 0 4 [ 4] .gnu.hash GNU_HASH 080481ac 0001ac 000020 04 A 5 0 4 [ 5] .dynsym DYNSYM 080481cc 0001cc 000070 10 A 6 1 4 [ 6] .dynstr STRTAB 0804823c 00023c 000058 00 A 0 0 1 [ 7] .gnu.version VERSYM 08048294 000294 00000e 02 A 5 0 2 [ 8] .gnu.version_r VERNEED 080482a4 0002a4 000020 00 A 6 1 4 [ 9] .rel.dyn REL 080482c4 0002c4 000008 08 A 5 0 4 [10] .rel.plt REL 080482cc 0002cc 000028 08 A 5 12 4 [11] .init PROGBITS 080482f4 0002f4 00002d 00 AX 0 0 4 [12] .plt PROGBITS 08048330 000330 000060 04 AX 0 0 16 [13] .text PROGBITS 08048390 000390 00028a 00 AX 0 0 16 [14] .fini PROGBITS 0804861c 00061c 000019 00 AX 0 0 4 [15] .rodata PROGBITS 08048638 000638 0000ad 00 A 0 0 4 [16] .eh_frame_hdr PROGBITS 080486e8 0006e8 000024 00 A 0 0 4 [17] .eh_frame PROGBITS 0804870c 00070c 000090 00 A 0 0 4 [18] .ctors PROGBITS 08049f20 000f20 000008 00 WA 0 0 4 [19] .dtors PROGBITS 08049f28 000f28 000008 00 WA 0 0 4 [20] .jcr PROGBITS 08049f30 000f30 000004 00 WA 0 0 4 [21] .dynamic DYNAMIC 08049f34 000f34 0000c8 08 WA 6 0 4 [22] .got PROGBITS 08049ffc 000ffc 000004 04 WA 0 0 4 [23] .got.plt PROGBITS 0804a000 001000 000020 04 WA 0 0 4 [24] .data PROGBITS 0804a020 001020 000010 00 WA 0 0 4 [25] .bss NOBITS 0804a040 001030 061aa8 00 WA 0 0 32 [26] .comment PROGBITS 00000000 001030 00004e 01 MS 0 0 1 [27] .shstrtab STRTAB 00000000 00107e 0000fc 00 0 0 1 [28] .symtab SYMTAB 00000000 00162c 000490 10 29 48 4 [29] .strtab STRTAB 00000000 001abc 00025e 00 0 0 1
從上面結果可以看到其代碼段、數據段、BSS段的起始地址和長度
結合執行結果可以看出:
argv[1] = 0xbfa80633
local_a = 0xbfa8025c
和理論布局是對應的,位置大致一致。
g_un_init = 0x80abae4 g_init = 0x804a060 local_static_b = 0x80abae0
位于BSS段起始地址為0x804a040,大小為0x61aa8,表示未初始化或初始化為零的全局變量位于BSS段,且未初始化的局部靜態變量也位于此段。
g_init_a = 0x804a028 g_static_data = 0x804a02
初始化的全局變量和靜態全局變量都位于數據段.data。
str = 0x8048640
常量字符串位于只讀數據段.rodata。
local_str = 0x8d0b008
位于堆空間
注: 向只讀段、內核空間、未分配區賦值都會引發段錯誤,如在程序中加入:
*(unsigned int *)0xa0000000 = 1;
就會引發段錯誤。
注:要養成malloc與free成對使用的習慣,負責代碼量大了,容易內存泄漏。
思考:什么malloc需要指定分配的大小,而free是只需一個地址參數即可?
剛開始寫博客,理解不是很深入,希望大家多討論,共同學習,共同進步。。。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。