自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Linux內(nèi)核編譯后地址空間的整理

運(yùn)維 系統(tǒng)運(yùn)維
Linux內(nèi)核在編譯之后有不少地方需要整理和規(guī)范,內(nèi)核編譯后地址空間如何范圍?我們可以用Linux的實(shí)用程序objdump對(duì)你的程序進(jìn)行反匯編,從而知曉其地址范圍。

有這么一系列的問(wèn)題,是否在困擾著你:用戶程序編譯連接形成的地址空間在什么范圍內(nèi)??jī)?nèi)核編譯后地址空間在什么范圍內(nèi)?要對(duì)外設(shè)進(jìn)行訪問(wèn),I/O的地址空間又是什么樣的?

先回答***個(gè)問(wèn)題。Linux最常見的可執(zhí)行文件格式為elf(Executable and Linkable Format)。在elf格式的可執(zhí)行代碼中,ld總是從0x8000000開始安排程序的“代碼段”,對(duì)每個(gè)程序都是這樣。至于程序執(zhí)行時(shí)在物理內(nèi)存中的實(shí)際地址,則由內(nèi)核為其建立內(nèi)存映射時(shí)臨時(shí)分配,具體地址取決于當(dāng)時(shí)所分配的物理內(nèi)存頁(yè)面。

我們可以用Linux的實(shí)用程序objdump對(duì)你的程序進(jìn)行反匯編,從而知曉其地址范圍。

例如:假定我們有一個(gè)簡(jiǎn)單的C程序Hello.c

 

  1. # include <stdio.h> 
  2. greeting ( )  
  3. {  
  4. printf(“Hello,world!\n”);  
  5. }  
  6. main()  
  7. {  
  8. greeting();  

 

之所以把這樣簡(jiǎn)單的程序?qū)懗蓛蓚€(gè)函數(shù),是為了說(shuō)明指令的轉(zhuǎn)移過(guò)程。我們用gcc和ld對(duì)其進(jìn)行編譯和連接,得到可執(zhí)行代碼hello。然后,用Linux的實(shí)用程序objdump對(duì)其進(jìn)行反匯編:

 

  1. $objdump -d hello 

得到的主要片段為:

 

  1. 08048568 <greeting>:  
  2. 8048568: pushl %ebp  
  3. 8048569: movl %esp, %ebp  
  4. 804856b: pushl $0x809404  
  5. 8048570: call 8048474 <_init+0x84> 
  6. 8048575: addl $0x4, %esp  
  7. 8048578: leave  
  8. 8048579: ret  
  9. 804857a: movl %esi, %esi  
  10. 0804857c <main>:  
  11. 804857c: pushl %ebp  
  12. 804857d: movl %esp, %ebp  
  13. 804857f: call 8048568 <greeting> 
  14. 8048584: leave  
  15. 8048585: ret  
  16. 8048586: nop  
  17. 8048587: nop 

 

其中,像08048568這樣的地址,就是我們常說(shuō)的虛地址(這個(gè)地址實(shí)實(shí)在在的存在,只不過(guò)因?yàn)槲锢淼刂返拇嬖?,顯得它是“虛”的罷了)。

虛擬內(nèi)存、內(nèi)核空間和用戶空間

Linux虛擬內(nèi)存的大小為2^32(在32位的x86機(jī)器上),內(nèi)核將這4G字節(jié)的空間分為兩部分。***的1G字節(jié)(從虛地址0xC0000000到0xFFFFFFFF)供內(nèi)核使用,稱為“內(nèi)核空間”。而較低的3G字節(jié)(從虛地址0x00000000到0xBFFFFFFF),供各個(gè)進(jìn)程使用,稱為“用戶空間”。因?yàn)槊總€(gè)進(jìn)程可以通過(guò)系統(tǒng)調(diào)用進(jìn)入內(nèi)核,因此,Linux內(nèi)核空間由系統(tǒng)內(nèi)的所有進(jìn)程共享。于是,從具體進(jìn)程的角度來(lái)看,每個(gè)進(jìn)程可以擁有4G字節(jié)的虛擬地址空間(也叫虛擬內(nèi)存)。

每個(gè)進(jìn)程有各自的私有用戶空間(0~3G),這個(gè)空間對(duì)系統(tǒng)中的其他進(jìn)程是不可見的。***的1GB內(nèi)核空間則為所有進(jìn)程以及內(nèi)核所共享。另外,進(jìn)程的“用戶空間”也叫“地址空間”,在后面的敘述中,我們對(duì)這兩個(gè)術(shù)語(yǔ)不再區(qū)分。

用戶空間不是進(jìn)程共享的,而是進(jìn)程隔離的。每個(gè)進(jìn)程***都可以有3GB的用戶空間。一個(gè)進(jìn)程對(duì)其中一個(gè)地址的訪問(wèn),與其它進(jìn)程對(duì)于同一地址的訪問(wèn)絕不沖突。比如,一個(gè)進(jìn)程從其用戶空間的地址0x1234ABCD處可以讀出整數(shù)8,而另外一個(gè)進(jìn)程從其用戶空間的地址0x1234ABCD處可以讀出整數(shù)20,這取決于進(jìn)程自身的邏輯。

任意一個(gè)時(shí)刻,在一個(gè)CPU上只有一個(gè)進(jìn)程在運(yùn)行。所以對(duì)于此CPU來(lái)講,在這一時(shí)刻,整個(gè)系統(tǒng)只存在一個(gè)4GB的虛擬地址空間,這個(gè)虛擬地址空間是面向此進(jìn)程的。當(dāng)進(jìn)程發(fā)生切換的時(shí)候,虛擬地址空間也隨著切換。由此可以看出,每個(gè)進(jìn)程都有自己的虛擬地址空間,只有此進(jìn)程運(yùn)行的時(shí)候,其虛擬地址空間才被運(yùn)行它的CPU所知。在其它時(shí)刻,其虛擬地址空間對(duì)于CPU來(lái)說(shuō),是不可知的。所以盡管每個(gè)進(jìn)程都可以有4 GB的虛擬地址空間,但在CPU眼中,只有一個(gè)虛擬地址空間存在。虛擬地址空間的變化,隨著進(jìn)程切換而變化。

從上面我們知道,一個(gè)程序編譯連接后形成的地址空間是一個(gè)虛擬地址空間,但是程序最終還是要運(yùn)行在物理內(nèi)存中。因此,應(yīng)用程序所給出的任何虛地址最終必須被轉(zhuǎn)化為物理地址,所以,虛擬地址空間必須被映射到物理內(nèi)存空間中,這個(gè)映射關(guān)系需要通過(guò)硬件體系結(jié)構(gòu)所規(guī)定的數(shù)據(jù)結(jié)構(gòu)來(lái)建立。這就是我們所說(shuō)的段描述符表和頁(yè)表,Linux主要通過(guò)頁(yè)表來(lái)進(jìn)行映射。

于是,我們得出一個(gè)結(jié)論,如果給出的頁(yè)表不同,那么CPU將某一虛擬地址空間中的地址轉(zhuǎn)化成的物理地址就會(huì)不同。所以我們?yōu)槊恳粋€(gè)進(jìn)程都建立其頁(yè)表,將每個(gè)進(jìn)程的虛擬地址空間根據(jù)自己的需要映射到物理地址空間上。既然某一時(shí)刻在某一CPU上只能有一個(gè)進(jìn)程在運(yùn)行,那么當(dāng)進(jìn)程發(fā)生切換的時(shí)候,將頁(yè)表也更換為相應(yīng)進(jìn)程的頁(yè)表,這就可以實(shí)現(xiàn)每個(gè)進(jìn)程都有自己的虛擬地址空間而互不影響。所以,在任意時(shí)刻,對(duì)于一個(gè)CPU來(lái)說(shuō),只需要有當(dāng)前進(jìn)程的頁(yè)表,就可以實(shí)現(xiàn)其虛擬地址到物理地址的轉(zhuǎn)化。

內(nèi)核空間到物理內(nèi)存的映射

內(nèi)核空間對(duì)所有的進(jìn)程都是共享的,其中存放的是內(nèi)核代碼和數(shù)據(jù),而進(jìn)程的用戶空間中存放的是用戶程序的代碼和數(shù)據(jù),不管是內(nèi)核程序還是用戶程序,它們被編譯和連接以后,所形成的指令和符號(hào)地址都是虛地址(參見2.5節(jié)中的例子),而不是物理內(nèi)存中的物理地址。

雖然內(nèi)核空間占據(jù)了每個(gè)虛擬空間中的***1GB字節(jié),但映射到物理內(nèi)存卻總是從***地址(0x00000000)開始的,如圖4.2所示,之所以這么規(guī)定,是為了在內(nèi)核空間與物理內(nèi)存之間建立簡(jiǎn)單的線性映射關(guān)系。其中,3GB(0xC0000000)就是物理地址與虛擬地址之間的位移量,在Linux代碼中就叫做PAGE_OFFSET。

我們來(lái)看一下在include/asm/i386/page.h頭文件中對(duì)內(nèi)核空間中地址映射的說(shuō)明及定義:

 

  1. #define __PAGE_OFFSET (0xC0000000)  
  2. ……  
  3. #define PAGE_OFFSET ((unsigned long)__PAGE_OFFSET)  
  4. #define __pa(x) ((unsigned long)(x)-PAGE_OFFSET)  
  5. #define __va(x) ((void *)((unsigned long)(x)+PAGE_OFFSET)) 

 

對(duì)于內(nèi)核空間而言,給定一個(gè)虛地址x,其物理地址為“x- PAGE_OFFSET”,給定一個(gè)物理地址x,其虛地址為“x+ PAGE_OFFSET”。

這里再次說(shuō)明,宏__pa()僅僅把一個(gè)內(nèi)核空間的虛地址映射到物理地址,而決不適用于用戶空間,用戶空間的地址映射要復(fù)雜得多,它通過(guò)分頁(yè)機(jī)制完成。

【編輯推薦】

  1. 三大常見的Linux引導(dǎo)問(wèn)題與解決方案
  2. Linux加入Windows域之完整操作步驟
  3. 一個(gè)Linux愛好者對(duì)未來(lái)的期待
  4. inotify監(jiān)控Linux文件系統(tǒng)的必備利器
責(zé)任編輯:張浩 來(lái)源: IT實(shí)驗(yàn)室
相關(guān)推薦

2021-01-08 05:59:39

Linux應(yīng)用程序Linux系統(tǒng)

2021-03-22 11:43:07

Linux運(yùn)維Linux系統(tǒng)

2009-10-16 09:45:41

Linux內(nèi)核操作系統(tǒng)

2017-03-27 18:05:49

Linux內(nèi)核編譯與開發(fā)

2019-07-10 12:40:29

Linux虛擬地址空間物理地址空間

2023-05-08 08:05:42

內(nèi)核模塊Linux

2012-05-03 08:27:20

Linux進(jìn)程

2021-05-26 07:53:58

Linux運(yùn)維Linux系統(tǒng)

2018-05-18 09:07:43

Linux內(nèi)核內(nèi)存

2010-03-02 16:13:56

Linux升級(jí)

2009-12-17 15:18:47

2023-10-05 15:47:04

Linux內(nèi)核編譯

2011-01-04 17:00:32

Linux內(nèi)核編譯

2009-09-07 08:58:23

VMWare編譯lin

2009-12-01 12:59:50

編譯Suse Linu

2017-08-24 11:00:56

Linux用戶空間內(nèi)核空間

2023-07-25 15:17:38

Linux操作系統(tǒng)開發(fā)

2010-07-20 10:04:25

Linux內(nèi)核編譯

2022-02-18 00:15:58

Linux指令CPU

2020-11-11 11:11:23

Linux內(nèi)核源碼
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)