2013-10-05 53 views
1

例如在我的程序中,我調用了函數foo()。編譯器和彙編程序最終會在二進制文件中寫入jmp someaddr。我知道虛擬內存的概念。該程序會認爲它具有可處理的全部內存,並且開始位置是0x000。這樣彙編器可以計算foo()的位置。操作系統如何在虛擬內存中執行二進制文件?

但事實上,這是不是決定,直到運行時權利?我必須運行程序來知道我在哪裏加載程序,因此地址爲jmp。但是當程序實際運行時,操作系統如何進入並更改jmp的地址?這些是直接的CPU指令嗎?

+0

http://en.wikipedia.org/wiki/Memory_management_unit – Thomas

+0

您是否理解「跳轉相對」的概念...... – Floris

+2

這聽起來像是一個操作系統設計問題,而不是編程問題。答案是,由於地址空間是虛擬的,所以程序可以正確地加載到它想要的地方。這就是虛擬尋址的神奇 –

回答

6

這個問題一般不能回答,因爲它完全依賴於硬件和操作系統。然而,一個典型的答案是,最初加載的程序可以像你說的那樣編譯:由於虛擬機硬件爲每個程序提供了自己的地址空間,所以當程序鏈接時,所有地址都可以被修復。在加載時不需要重新計算地址。

對於動態加載的庫,事情會變得更有趣,因爲初始加載的相同程序使用的兩個程序可能會使用相同的基址進行編譯,因此它們的地址空間會重疊。

解決此問題的一種方法是要求位置獨立代碼在DLL中。在這樣的代碼中,所有地址都與代碼本身有關。跳轉通常與PC相關(儘管也可以使用代碼段寄存器)。數據也與某些數據段或基址寄存器有關。要選擇運行時位置,PIC代碼本身不需要更改。無論何時在每個DLL例程的前奏中,只需要設置段或基本寄存器(s)。

PIC往往比位置相關的代碼慢一點,因爲有附加的地址運算,PC和/或基址寄存器可能會阻礙處理器的指令流水線。

因此,另一種方法是加載程序必要時重新綁定DLL代碼以消除地址空間重疊。爲此,DLL必須包含代碼中所有絕對地址的表格。加載程序計算假設代碼和數據基地址與實際值之間的偏移量,然後遍歷該表,在程序複製到VM時將偏移量添加到每個絕對地址。

DLL還有一個入口點表,以便調用程序知道庫過程的起始位置。這些也必須調整。

重新調整對於性能來說也不是很好。它減緩了負載。此外,它還會破壞DLL代碼的共享。您需要至少一個副本每個rebase偏移量。

由於這些原因,作爲Windows一部分的DLL有意編譯爲不重疊的VM地址空間。這加快了加載速度並允許共享。如果您注意到第三方DLL會嘎吱嘎吱地磁盤並加載速度很慢,而像C運行時庫這樣的MS DLL快速加載,您會看到Windows中重新綁定的效果。

您可以通過閱讀有關目標文件格式推斷更多關於此主題。 Here is one example.

2

與位置無關的代碼是可以從任何地址運行的代碼。如果在位置無關的代碼中有一條jmp指令,它通常是一個相對跳轉,它跳轉到當前位置的偏移量。當您複製代碼時,它不會更改代碼各部分之間的偏移量,因此它仍然可以工作。

可重定位代碼是您可以從任何地址運行的代碼,但您可能必須先修改代碼(也許您不能只複製它)。該代碼將包含一個重定位表,告訴它如何修改。

不可重定位代碼是必須在某個地址加載的代碼,否則它將無法工作。

每個程序都不同,它取決於程序的編寫方式,編譯器設置或其他各種因素。

  • 共享庫通常編譯爲與位置無關的代碼,這允許相同的庫在不同的工藝的不同位置處被裝入,而無需多個副本加載到存儲器中。即使在每個進程中位於不同的地址,進程之間也可以共享相同的副本。

  • 可執行文件通常不可重定位,但它們可以是位置無關的。虛擬內存允許每個程序自己擁有整個地址空間(減去一些開銷),因此每個可執行文件都可以選擇加載的地址,而不必擔心與其他可執行文件發生衝突。一些可執行文件與位置無關,可用於提高安全性(ASLR)。

  • 對象文件和靜態庫通常是可重定位的代碼。鏈接器在將它們組合在一起以創建共享庫,可執行文件或其他圖像時將重新定位它們。

  • 引導裝載程序和操作系統內核幾乎都是不可重定位的。

0

是的,它在運行時。操作系統,管理啓動和切換任務的部分理想情況下處於不同的保護級別,它具有更多的功能。它知道正在使用什麼內存併爲新任務分配一些內存。它配置mmu,以便新任務具有從零開始的虛擬地址空間或任何適用於該操作系統和處理器的規則。如何在該起始地址進入用戶模式,是非常特定於處理器的。

例如,一種方法是在發生中斷時,硬件可能會保存某些狀態,而不僅僅是地址,但可以保存模式或虛擬標識或某些內容,比如說在堆棧上。並且由該處理器定義的中斷指令的返回將地址和狀態/模式從棧中切換並在那裏切換(導致讓我們假設mmu響應於基於新模式而不是舊模式的下次獲取)。對於這樣工作的處理器,您可以通過將正確的項目放在堆棧上來僞造中斷返回,這樣當您踢中斷返回指令時,它基本上會跳轉,並具有模式切換等附加功能。

例如,ARM系列(不是cortex-m)有一個處理器狀態寄存器,用於處理您現在正在運行的任務(在發生中斷或服務調用的情況下)以及第二個狀態寄存器,用於指定來自哪裏的狀態中斷,當你做適當的回報時,你給它的地址,並使用另一個寄存器切換回該模式。您可以直接從非用戶模式訪問該寄存器,以便操縱返回狀態。手臂沒有返回指令,只是跳躍的風格(修改程序計數器),所以它是一種特殊的跳躍。

簡短的回答是,它是非常具體的處理器,你的選擇是跳轉到第一次還是在任務切換到虛擬地址空間中的應用程序模式下正在運行的任務後返回。處理器文檔將直接或間接描述這些模式以及如何更改它們。如果沒有明確說明,那麼你必須根據說明和mmu保護以及如何切換任務來自行解決。

相關問題