根據Assembly Primer For Hackers (Part 2) Virtual Memory Organization,Linux程序.text
部分從0x0804800
開始,堆棧頂部從0xbffffff
開始。這些數字的意義是什麼?爲什麼不開始.text
在0x0000000
(或0x0000020
或0x0000040
去接下來32或64位通過NULL
)?爲什麼不在0xfffffff
開始堆棧的頂部?爲什麼Linux程序的.text部分從0x0804800開始,堆棧頂部從0xbffffff開始?
回答
我們首先說一下:大多數時候,各個部分不需要放置在特定位置,更重要的是佈局。如今,棧頂實際上是隨機的,見here。
0x08048000是ld在Linux/x86上啓動第一個PT_LOAD
段的默認地址。在Linux/amd64上,默認值爲0x400000,您可以使用自定義鏈接腳本更改默認值。您還可以更改.text部分從-Wl,-Ttext,0xNNNNNNNN
標誌開始到gcc。爲了理解爲什麼.text未映射到地址0,請記住,爲了方便起見,NULL指針通常映射到((void *)0)。那麼,零頁面被映射爲不可訪問以捕獲NULL指針的使用是有用的。 .text開始之前的內存實際上被很多事情使用;採取cat /proc/self/maps
爲例:
$ cat /proc/self/maps
001c0000-00317000 r-xp 00000000 08:01 245836 /lib/libc-2.12.1.so
00317000-00318000 ---p 00157000 08:01 245836 /lib/libc-2.12.1.so
00318000-0031a000 r--p 00157000 08:01 245836 /lib/libc-2.12.1.so
0031a000-0031b000 rw-p 00159000 08:01 245836 /lib/libc-2.12.1.so
0031b000-0031e000 rw-p 00000000 00:00 0
00376000-00377000 r-xp 00000000 00:00 0 [vdso]
00852000-0086e000 r-xp 00000000 08:01 245783 /lib/ld-2.12.1.so
0086e000-0086f000 r--p 0001b000 08:01 245783 /lib/ld-2.12.1.so
0086f000-00870000 rw-p 0001c000 08:01 245783 /lib/ld-2.12.1.so
08048000-08051000 r-xp 00000000 08:01 2244617 /bin/cat
08051000-08052000 r--p 00008000 08:01 2244617 /bin/cat
08052000-08053000 rw-p 00009000 08:01 2244617 /bin/cat
09ab5000-09ad6000 rw-p 00000000 00:00 0 [heap]
b7502000-b7702000 r--p 00000000 08:01 4456455 /usr/lib/locale/locale-archive
b7702000-b7703000 rw-p 00000000 00:00 0
b771b000-b771c000 r--p 002a1000 08:01 4456455 /usr/lib/locale/locale-archive
b771c000-b771e000 rw-p 00000000 00:00 0
bfbd9000-bfbfa000 rw-p 00000000 00:00 0 [stack]
我們在這裏看到的是C庫,動態加載器ld.so和內核VDSO(內核映射動態代碼庫,提供了一些接口,內核)。請注意,堆的開始也是隨機的。
沒有太大意義。
堆棧通常向下(向較低地址)增長,因此將其放置在高地址並且有一定空間用於向較低地址擴展是合理的(但不是強制性的)。
至於程序段沒有使用地址0,這裏有一些邏輯。首先,很多軟件在NULL
中使用0,這是C和C++中的一個合法無效指針,不應該解除引用。許多軟件都存在缺陷,它實際上試圖在沒有正確指針驗證的情況下在地址0處讀或寫內存。如果你使地址0的內存區域不能被程序訪問,你可以發現其中一些錯誤(程序將在調試器中崩潰或停止)。另外,由於NULL
是一個合法的無效指針,因此該地址不應該有數據或代碼(如果存在,您無法區分指向它的指針,從NULL
)。
在x86平臺上,地址0周圍的內存通常無法通過虛擬到物理地址轉換進行訪問。頁面表的設置方式使得虛擬地址0的條目不會被一頁物理內存備份,並且頁面的大小通常是4 KB,而不僅僅是幾個字節。這就是爲什麼如果你拿出地址0,你也可以從1到4095取出地址。在地址0處取出超過4KB的地址空間也是合理的。其原因是指向C和C++中的結構。你可以有一個NULL
指針指向一個結構,當你取消引用它時,嘗試的內存訪問發生在指針(0)中包含的地址加上你嘗試訪問的結構成員和結構開始之間的距離( 0表示第一個成員,其餘大於0)。
對於爲程序選擇特定地址範圍可能還有其他一些考慮因素,但我不能全部爲它們說話。操作系統可能希望在程序本身中保留一些與程序相關的東西(數據結構),爲什麼不在地址空間的可訪問部分的接近一端使用固定位置?
- 1. Scrollview不從頂部開始
- 2. 刪除開始,從堆棧
- 3. 活動從在活動堆棧頂部打開的通知開始
- 4. 更改y_axis從頂部開始0
- 5. UITextView文本不從頂部開始
- 6. 片段沒有從頂部開始
- 7. NestedScrollview不會從頂部開始
- 8. 在Android導航堆棧頂部開始活動
- 9. 從PHP開始外部程序
- 10. JS滾動從底部開始。我希望它開始在頂部
- 11. 從底部開始的UITextView
- 12. rowindex始終從零開始......爲什麼?
- 13. 爲什麼應該從0開始而不是從1開始?
- 14. 爲什麼sqlite3_bind_ *從索引1開始,但sqlite3_column_ *從0開始?
- 15. 爲什麼這個元素不是從其父元素的頂部開始的?
- 16. 從底部開始UITableView
- 17. Recyclerview從底部開始
- 18. MvvmCross ShowViewModel從內部開始()
- 19. Div的內部Div從底部開始
- 20. 始終從頂部開始垂直滾動條
- 21. CSS - 列表項不從無序列表的頂部開始
- 22. 爲什麼當region-before存在時region-start從頁面頂部開始?
- 23. 如何讓ABPeoplePicker每次打開時從頂部開始?
- 24. 從Impersonate開始外部過程問題
- 25. ScrollView從tabbar開始,但需要從佈局的頂部滾動
- 26. 當touchesBegan從UIImageView開始時,爲什麼UIImageView會全部瘋狂?
- 27. 從零開始的angular2全棧教程
- 28. 開始Cloudformation棧從ansible
- 29. Linux - 獲取線程的堆棧內存的開始和結束
- 30. 將textView設置爲從頂部開始(Swift)
這一切都有道理,但是這比'NULL'(0x0004096與0x804800)大200個數量級。你也沒有提到棧不是從內存的字面頂部開始(0xfffffff) – 2013-02-10 06:28:18
我不知道爲什麼.text開始那麼高。但爲什麼不能呢?我已經解決了最後一段中的堆棧位置。 – 2013-02-10 06:31:07
32位Linux內核通常使用0xC0000000以上的地址。通常,在用戶模式下訪問此地址範圍的任何嘗試都會導致seg故障。 – Dipstick 2013-02-10 07:45:29