位址空間分布

2022-07-09 22:09:11 字數 4299 閱讀 9415

最近看了本書,突然對於位址空間有些疑惑。在深入理解linux核心中把位址分為三類:邏輯位址(組合語言中運算元位址或指令的位址,對於80x86的cup,邏輯位址是段+段內偏移位址)、線性位址(也叫虛擬位址)和實體地址。但在stott maxwell的《linux core kernel commentrary》中確是這樣分的:邏輯位址(也叫虛擬位址)、線性位址和實體地址。按照386 cpu總設計師 john crowford的解釋,虛擬位址是保護模式下段和段內偏移量組成的位址,而邏輯位址就是**段內偏移量,或稱程序的邏輯位址。其實對於linux來說,這三種說法都沒錯,由於linux下並不主張將程式分段,而是主張分頁,所以即使是在80x86的體系結構下,段的基位址也是0。因此邏輯位址、線性位址、虛擬位址在linux中其實是相同的。所以對於linux下的elf可執行檔案來說,**段的起始位址0x08048000既是邏輯位址,也是線性位址也是虛擬位址。

實體地址空間的頂部以下一段空間,被pci

裝置的i/o

記憶體對映佔據,它們的大小和布局由

pci規範所決定。

640k~1m

這段位址空間被

bios

和vga

介面卡所佔據。

linux系統在初始化時,會根據實際的物理記憶體的大小,為每個物理頁面建立乙個

page

物件,所有的

page

物件構成乙個

mem_map

陣列。 

進一步,針對不同的用途,linux

核心將所有的物理頁面劃分到

3類記憶體管理區中,如圖,分別為zone_dma,zone_normal,zone_highmem。

zone_dma的範圍是

0~16m

,該區域的物理頁面專門供

i/o裝置的

dma使用。之所以需要單獨管理

dma的物理頁面,是因為

dma使用實體地址訪問記憶體,不經過

mmu,並且需要連續的緩衝區,所以為了能夠提供物理上連續的緩衝區,必須從實體地址空間專門劃分一段區域用於

dma。

zone_normal的範圍是

16m~896m

,該區域的物理頁面是核心能夠直接使用的。

zone_highmem的範圍是

896m~

結束,該區域即為高階記憶體,核心不能直接使用。

2 linux虛擬位址核心空間分布

在kernel image下面有16m的核心空間用於dma操作。位於核心空間高階的128m位址主要由3部分組成,分別為vmalloc area,持久化核心對映區,臨時核心對映區。

由於zone_normal和核心線性空間存在直接對映關係,所以核心會將頻繁使用的資料如kernel**、gdt、idt、pgd、mem_map陣列等放在zone_normal裡。而將使用者資料、頁表(pt)等不常用資料放在zone_ highmem裡,只在要訪問這些資料時才建立對映關係(kmap())。比如,當核心要訪問i/o裝置儲存空間時,就使用ioremap()將位於實體地址高階的mmio區記憶體對映到核心空間的vmalloc area中,在使用完之後便斷開對映關係。

上面描述預設都是32位的機器,對於64位的機器,page_offset為0x0xffff880000000000,使用者位址空間範圍:0x0000000000000000 - 0x00007fffffffffff,核心**位址空間:0x

ffffffff80000000 - 0xffffffffa0000000。

3 linux虛擬位址使用者空間分布

使用者程序的**區一般從虛擬位址空間的0x08048000

開始,這是為了便於檢查空指標。**區之上便是資料區,未初始化資料區,堆區,棧區,以及引數、全域性環境變數。

4 linux虛擬位址與物理位址對映的關係

linux將

4g的線性位址空間分為

2部分,

0~3g

為user space

,3g~4g

為kernel space

。由於開啟了分頁機制,核心想要訪問實體地址空間的話,必須先建立對映關係,然後通過虛擬位址來訪問。為了能夠訪問所有的實體地址空間,就要將全部實體地址空間對映到1g

的核心線性空間中,這顯然不可能。於是,核心將

0~896m

的實體地址空間一對一對映到自己的線性位址空間中,這樣它便可以隨時訪問

zone_dma

和zone_normal

裡的物理頁面;此時核心剩下的

128m

線性位址空間不足以完全對映所有的

zone_highmem

,linux

採取了動態對映的方法,即按需的將

zone_highmem

裡的物理頁面對映到

kernel space

的最後128m

線性位址空間裡,使用完之後釋放對映關係,以供其它物理頁面對映。雖然這樣存在效率的問題,但是核心畢竟可以正常的訪問所有的實體地址空間了。

5 linux中可執行程式與虛擬位址空間的對映關係

虛擬記憶體區域(vma,virtual memory area)是linux中程序虛擬位址空間中的乙個段,在

windows

裡面叫虛擬段。當作業系統建立執行緒後,會在程序相應的資料結構中設定乙個

.text

段的vma

,它在虛擬空間中的位址為

0x08048000~0x08049000

,它對應

elf檔案中的偏移為0的

.text

。可以檢視作業系統為執行的程序維護的資訊:

從上面的圖可以看出,虛擬空間位址為0x08048000~0x08049000的

vma對映為

elf檔案中的乙個段(

segment

),並且是按整頁進行對映的。

由於linux下的elf可執行

檔案會有很多個段(

section

),所以如果把每個

section

都對映為乙個

vma,那麼沒有乙個頁大小的段(

section

)也會被對映為乙個頁的

vma,這樣就浪費了物理空間,由於不足會用

0補充。故

elf有乙個裝載的段(

segment

),與前面的段(

section

)不同,前面的段(

section

)主要用於鏈結,而段(

segment

)主要用於裝載進記憶體。

可以看出段(segment)02包含了很多的段(

section

),那鏈結器怎樣將段(

section

)合併到乙個段(

segment

)中的呢?可以通過段(

section

)的許可權來合併,如以**段為代表的許可權為可讀可執行許可權;以資料段和

bss段為代表的許可權為可讀可寫的段;以唯讀資料為代表的許可權為唯讀許可權。

elf與

linux

程序虛擬空間對映關係如下圖所示:

即使把多個段(section)合併到幾個段(segment),每個段(segment)還是又很能產生較大的頁內碎片,怎樣解決這個問題呢?unix巧妙的通過各個段(segment)接壤部分共享乙個物理頁來解決這個問題。

參考:深入理解linux核心、linux core kernel commentrary、程式設計師的自我修養。

程序位址空間分布

對於乙個程序,其空間分布如下圖所示 c程式一般分為 1.程式段 程式段為程式 在記憶體中的對映.乙個程式可以在記憶體中多有個副本.2.初始化過的資料 在程式執行值初已經對變數進行初始化的 3.未初始化過的資料 在程式執行初未對變數進行初始化的資料 4.堆 stack 儲存區域性,臨時變數,在程式塊開...

Linux 虛擬位址空間分布 筆記

linux系統下,核心程序和使用者程序所佔的虛擬記憶體比例為1 3 windows系統下,核心程序和使用者程序所佔的虛擬記憶體比例為2 2 也可以修改為1 3 虛擬位址通過頁表對映到實體地址,頁表由作業系統維護並被處理器引用。linux系統通過對棧 堆 記憶體對映段的起始位址加上隨機偏移量來打亂布局...

Linux 應用程式的位址空間分布

linux 應用程式在被核心調入記憶體中執行後就成為乙個程序,因此分析應用程式的位址空間實際上就是分析程序的位址空間分布。應用程式的位址空間實際上由以下幾個部分組成 段 初始化資料段 未初始化資料段 bss段 堆 棧。其在記憶體中的分布如下 apue給出了各個段所包含內容的詳細介紹,這裡筆者用乙個比...