2013-02-10 48 views

回答

5

我們首先說一下:大多數時候,各個部分不需要放置在特定位置,更重要的是佈局。如今,棧頂實際上是隨機的,見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(內核映射動態代碼庫,提供了一些接口,內核)。請注意,堆的開始也是隨機的。

3

沒有太大意義。

堆棧通常向下(向較低地址)增長,因此將其放置在高地址並且有一定空間用於向較低地址擴展是合理的(但不是強制性的)。

至於程序段沒有使用地址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

這一切都有道理,但是這比'NULL'(0x0004096與0x804800)大200個數量級。你也沒有提到棧不是從內存的字面頂部開始(0xfffffff) – 2013-02-10 06:28:18

+0

我不知道爲什麼.text開始那麼高。但爲什麼不能呢?我已經解決了最後一段中的堆棧位置。 – 2013-02-10 06:31:07

+1

32位Linux內核通常使用0xC0000000以上的地址。通常,在用戶模式下訪問此地址範圍的任何嘗試都會導致seg故障。 – Dipstick 2013-02-10 07:45:29