brk(), sbrk() 用法详解【转】
轉(zhuǎn)自:http://blog.csdn.net/sgbfblog/article/details/7772153
貼上原文地址,好不容易找到了:brk(), sbrk() -- 改變數(shù)據(jù)段長(zhǎng)度
?
brk() , sbrk() 的聲明如下:
?
[cpp]?view plaincopy
這兩個(gè)函數(shù)都用來(lái)改變 "program break" (程序間斷點(diǎn))的位置,這個(gè)位置可參考下圖:
?
如 man 里說(shuō)的:
引用 brk()??and??sbrk() change the location of the program break, which defines the end of the process's data segment (i.e., the program break is the first location after the end of the uninitialized data segment).?brk() 和 sbrk() 改變 "program brek" 的位置,這個(gè)位置定義了進(jìn)程數(shù)據(jù)段的終止處(也就是說(shuō),program break 是在未初始化數(shù)據(jù)段終止處后的第一個(gè)位置)。
如此翻譯過(guò)來(lái),似乎會(huì)讓人認(rèn)為這個(gè) program break 是和上圖中矛盾的,上圖中的 program break 是在堆的增長(zhǎng)方向的第一個(gè)位置處(堆和棧的增長(zhǎng)方向是相對(duì)的),而按照說(shuō)明手冊(cè)來(lái)理解,似乎是在 bss segment 結(jié)束那里(因?yàn)槲闯跏蓟瘮?shù)據(jù)段一般認(rèn)為是 bss segment)。
?
首先說(shuō)明一點(diǎn),一個(gè)程序一旦編譯好后,text segment ,data segment 和 bss segment 是確定下來(lái)的,這也可以通過(guò) objdump 觀察到。下面通過(guò)一個(gè)程序來(lái)測(cè)試這個(gè) program break 是不是在 bss segment 結(jié)束那里:
?
[cpp]?view plaincopy
下面,我們分別運(yùn)行兩次程序,并查看其輸出:
?
引用 [beyes@localhost C]./sbrkendofbsssection:0x8049938pmem:0x82ec0081?gapbetweenheapandbss:2762448pmem:0x82ec0082?gapbetweenheapandbss:2762448[beyes@localhostC]./sbrkendofbsssection:0x8049938pmem:0x82ec0081?gapbetweenheapandbss:2762448pmem:0x82ec0082?gapbetweenheapandbss:2762448[beyes@localhostC]?./sbrk?end of bss section:0x8049938
pmem:0x8dbc008
1-gap between heap and bss:14100176
pmem:0x8dbc008
2-gap between heap and bss:14100176
從上面的輸出中,可以發(fā)現(xiàn)幾點(diǎn):
1. bss 段一旦在在程序編譯好后,它的地址就已經(jīng)規(guī)定下來(lái)。
2. 一般及簡(jiǎn)單的情況下,使用 malloc() 申請(qǐng)的內(nèi)存,釋放后,仍然歸還回原處,再次申請(qǐng)同樣大小的內(nèi)存區(qū)時(shí),還是從第 1 次那里獲得。
3. bss segment 結(jié)束處和堆的開始處的空隙大小,并不因?yàn)?sbrk() 的調(diào)整而改變,也就是說(shuō)明了 program break 不是調(diào)整堆頭部。
所以,man 手冊(cè)里所說(shuō)的??“program break 是在未初始化數(shù)據(jù)段終止處后的第一個(gè)位置” ,不能將這個(gè)位置理解為堆頭部。這時(shí),可以猜想應(yīng)該是在堆尾部,也就是堆增長(zhǎng)方向的最前方。下面用程序進(jìn)行檢驗(yàn):
當(dāng) sbrk() 中的參數(shù)為 0 時(shí),我們可以找到 program break 的位置。那么根據(jù)這一點(diǎn),檢查一下每次在程序加載時(shí),系統(tǒng)給堆的分配是不是等同大小的:
?
?
[cpp]?view plaincopy
運(yùn)行上面的程序 3 次:
?
引用 [beyes@localhost C]./sbrkpmem:0x80c9008heapsizeoneachload:135160[beyes@localhostC]./sbrkpmem:0x80c9008heapsizeoneachload:135160[beyes@localhostC]?./sbrk?pmem:0x9682008
heap size on each load: 135160
[beyes@localhost C]./sbrkpmem:0x9a7d008heapsizeoneachload:135160[beyes@localhostC]./sbrkpmem:0x9a7d008heapsizeoneachload:135160[beyes@localhostC]?./sbrk?
pmem:0x8d92008
heap size on each load: 135160
[beyes@localhost C]$ vi sbrk.c
從輸出可以看到,雖然堆的頭部地址在每次程序加載后都不一樣,但是每次加載后,堆的大小默認(rèn)分配是一致的。但是這不是不能改的,可以使用 sysctl 命令修改一下內(nèi)核參數(shù):
引用 #sysctl -w kernel/randomize_va_space=0這么做之后,再運(yùn)行 3 次這個(gè)程序看看:
引用 [beyes@localhost C]./sbrkpmem:0x804a008heapsizeoneachload:135160[beyes@localhostC]./sbrkpmem:0x804a008heapsizeoneachload:135160[beyes@localhostC]?./sbrk?pmem:0x804a008
heap size on each load: 135160
[beyes@localhost C]$ ./sbrk?
pmem:0x804a008
heap size on each load: 135160
從輸出看到,每次加載后,堆頭部的其實(shí)地址都一樣了。但我們不需要這么做,每次堆都一樣,容易帶來(lái)緩沖區(qū)溢出攻擊(以前老的 linux 內(nèi)核就是特定地址加載的),所以還是需要保持 randomize_va_space 這個(gè)內(nèi)核變量值為 1 。
下面就來(lái)驗(yàn)證 sbrk() 改變的 program break 位置在堆的增長(zhǎng)方向處:
?
?
[cpp]?view plaincopy
運(yùn)行輸出:
?
引用 [beyes@localhost C]$ ./sbrk?pmem:0x804a008
1
2
3
4
5
... ...
61
62
63
64
從輸出看到,sbrk(1) 每次讓堆往棧的方向增加 1 個(gè)字節(jié)的大小空間。
?
而 brk() 這個(gè)函數(shù)的參數(shù)是一個(gè)地址,假如你已經(jīng)知道了堆的起始地址,還有堆的大小,那么你就可以據(jù)此修改 brk() 中的地址參數(shù)已達(dá)到調(diào)整堆的目的。
實(shí)際上,在應(yīng)用程序中,基本不直接使用這兩個(gè)函數(shù),取而代之的是 malloc() 一類函數(shù),這一類庫(kù)函數(shù)的執(zhí)行效率會(huì)更高。還需要注意一點(diǎn),當(dāng)使用 malloc() 分配過(guò)大的空間,比如超出 0x20ff8 這個(gè)常數(shù)(在我的系統(tǒng)(Fedora15)上是這樣,別的系統(tǒng)可能會(huì)有變)時(shí),malloc 不再?gòu)亩阎蟹峙淇臻g,而是使用 mmap() 這個(gè)系統(tǒng)調(diào)用從映射區(qū)尋找可用的內(nèi)存空間。
本文轉(zhuǎn)自張昺華-sky博客園博客,原文鏈接:http://www.cnblogs.com/sky-heaven/p/6283441.html,如需轉(zhuǎn)載請(qǐng)自行聯(lián)系原作者
總結(jié)
以上是生活随笔為你收集整理的brk(), sbrk() 用法详解【转】的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 计算机网络基础回顾
- 下一篇: yield next和yield* ne