記憶體模型與elf檔案

2022-08-03 12:03:15 字數 3920 閱讀 9420

bss段(bss segment)用於存放程式中未經初始化的全域性變數和靜態區域性變數。在目標檔案中,這個段並不佔據實際空間,它僅僅只是乙個佔位符。

bss段屬於靜態記憶體分配

資料段(data segment)通常是指用來存放程式中已初始化的全域性變數和靜態區域性變數的一塊記憶體區域,讀寫屬性

資料段屬於靜態記憶體分配

**段(code segment/text segment)通常是指用來存放程式執行**的一塊記憶體區域,也有可能包含一些唯讀的常數變數(例如字串常量等)唯讀屬性

這部分區域的大小在程式執行前就已經確定,並且記憶體區域通常屬於唯讀(某些架構也允許**段為可寫,即允許修改程式)。

堆是用於存放程序執行中被動態分配的記憶體段,它的大小並不固定,可動態擴張或縮減。

當程序呼叫malloc等函式分配記憶體時,新分配的記憶體就被動態新增到堆上(堆被擴張);

當利用free等函式釋放記憶體時,被釋放的記憶體從堆中被剔除(堆被縮減)。

棧又稱堆疊,是使用者存放程式臨時建立的區域性變數,

也就是說我們函式括弧「{}」中定義的變數(但不包括static宣告的變數,static意味著在資料段中存放變數)。

除此以外,在函式被呼叫時,其引數也會被壓入發起呼叫的程序棧中,並且待到呼叫結束後,函式的返回值也會被存放回棧中。

由於棧的先進先出(fifo)特點,所以棧特別方便用來儲存/恢復呼叫現場。

從這個意義上講,我們可以把堆疊看成乙個寄存、交換臨時資料的記憶體區。

## 解剖 linux c 程式.

file

#檢視檔案屬性

xxd #二進位制格式檔案轉hex格式 例: xxd t1.o > t1.hex

#elf 檔案基本介紹

readelf

objdump

# 如何精簡 linux c 小程式

stdlibc #介紹 (gnulibc), 如何去掉鏈結stdlibc

注:mac os x下沒有這兩個命令,可以用brew來安裝,brew update && brew install binutils,然後用greadelf和gobjdump。

這樣的概念,不知道最初**於**的規定,但在當前的計算機程式設計中是很重要的乙個基本概念。

而且在嵌入式系統的設計中也非常重要,牽涉到嵌入式系統執行時的記憶體大小分配,儲存單元占用空間大小的問題。

在採用段式記憶體管理的架構中(比如intel的80x86系統),bss段通常是指用來存放程式中未初始化的全域性變數的一塊記憶體區域,

一般在初始化時bss 段部分將會清零。bss段屬於靜態記憶體分配,即程式一開始就將其清零了。

比如,在c語言之類的程式編譯完成之後,已初始化的全域性變數儲存在.data 段中,未初始化的全域性變數儲存在.bss 段中。

text和data段都在可執行檔案中(在嵌入式系統裡一般是固化在映象檔案中),由系統從可執行檔案中載入;

而bss段不在可執行檔案中,由系統初始化。

全域性的未初始化變數存在於.bss段中,具體體現為乙個佔位符;

全域性的已初始化變數存於.data段中;

而函式內的自動變數都在棧上分配空間;

.bss是不占用檔案空間的,其內容由作業系統初始化(清零);

.data卻需要占用,其內容由程式初始化。因此造成了上述情況。

bss段(未手動初始化的資料)並不給該段的資料分配空間,只是記錄資料所需空間的大小;

bss段的大小從可執行檔案中得到 ,然後鏈結器得到這個大小的記憶體塊,緊跟在資料段後面。

data段(已手動初始化的資料)則為資料分配空間,資料儲存在目標檔案中;

data段包含經過初始化的全域性變數以及它們的值。當這個記憶體區進入程式的位址空間後全部清零。

包含data段和bss段的整個區段此時通常稱為資料區。

// t1.c

int a =1;

static

int b =4;

int c;

static

int d;

char

*s1 =

"1234"

;int

main()

編譯除錯檔案

gcc test1.c -o test1.o 		//編譯

objdump -sx t1.o //除錯

sections:

idx name size vma lma file off algn

……15 .rodata 0000001a 0000000000400570 0000000000400570 00000570 23

contents, alloc, load, readonly, data

……24 .data 00000018 0000000000601020 0000000000601020 00001020 23

contents, alloc, load, data

25 .bss 00000010 0000000000601038 0000000000601038 00001038 2**2

alloc

sections展示了不同的段的大小。

symbol table:

000000000060102c l o .data 0000000000000004 b

000000000060103c l o .bss 0000000000000004 d

……0000000000601030 g o .data 0000000000000008 s1

0000000000601040 g o .bss 0000000000000004 c

0000000000601028 g o .data 0000000000000004 a

symbol table展示了不同的變數是存在哪的。這裡就可以看到

data段有:

bss段有:

contents of section .rodata:

400550 01000200 31323334 00333435 3600 ..

..1234.3456.

contents of section .data:

6008a8 00000000 00000000 00000000 00000000 ..

....

....

....

.. 6008b8 01000000 04000000 54054000 00000000 ..

....

..t.@..

...

可以看到rodata段中有我們定義的1234和3456

而data段裡有1和4(小端)分別對應a和b

還可以讀取elf檔案,命令是readelf

二、編譯和鏈結

三、目標檔案解析

四、靜態鏈結

使用readelf和objdump解析目標檔案

修改ELF檔案統計記憶體洩露

本篇不走尋常路,想要正常的記憶體除錯手段請查閱核心相關的記憶體debug功能.程式開發了很長時間,參與開發的人也很多,今天我想用實驗統計來證明我們寫的核心module沒有產生記憶體洩露,通常的做法是封裝記憶體的api,中間加上統計邏輯,但是我不想改他們的 有什麼辦法嗎?我翻了一下code,裡面有上百...

ELF與BIN檔案區別

gcc 編譯出來的是elf檔案。通常gcc o test test.c,生成的test檔案就是elf格式的,在linuxshell下輸入 test就可以執行。bin 檔案是經過壓縮的可執行檔案,去掉elf格式的東西。是直接的記憶體映像的表示。在系統沒有載入作業系統的時候可以執行。elf execut...

ELF檔案 介紹

elf 檔案格式是乙個開放標準,各種unix系統的可執行檔案都採用elf格式,它有三種不同的型別 在這裡先詳細解釋一下程式的彙編 鏈結 執行過程 1 寫乙個匯程式設計序儲存成文字檔案max.s。2 彙編器讀取這個文字檔案轉換成目標檔案max.o,目標檔案由若干個section組成,我們在匯程式設計序...