導航:首頁 > 源碼編譯 > 編譯鏈接裝入物理地址

編譯鏈接裝入物理地址

發布時間:2022-12-21 08:07:20

Ⅰ c語言,或者是masm等,怎樣給程序編譯成絕對地址

可執行程序要靠操作系統裝入才能運行,裝入時,必定會給一個偏移量,所以編譯器產生的程序不可能是絕對地址。

除非你回到原始的計算機,只有硬體,沒有軟體,從撥開關,加電開始,給機器碼指令,一條條,一拍拍地做。

Ⅱ 在編譯時為內存分配了邏輯地址,之後連接生成了可執行文件,邏輯地址在運行時會發生變化嗎

應該不會沖突,每個程序在內存中佔用的空間都是獨立的,邏輯地址只是在它自己的空間里的相對地址,正常情況下不會有交集。

Ⅲ 源程序中的寄存器變數如何定位到實際的物理地址

將寄存器變數定位到存儲器物理地址方法如下
unsigned char temp_A@0x00; //定義無符號變數temp_A,強制其地址為0x00
unsigned char temp_B@0x100; //定義無符號變數temp_B,強制其地址為0x100
@tiny unsigned char temp_C; //定義無符號變數temp_C,由編譯器自動在地址小於0x100的RAM中為其分配一個地址
@near unsigned char temp_D; //定義無符號變數temp_D,由編譯器自動在地址大於0xFF的RAM中為其分配一個地址
另外也可以採用偽指令"pragma"將函數或者變數定義到指定的section中,例如:
#pragma section [name] // 將下面定義的未初始化變數定義到.name section中
Unsigned char data1;
Unsigned int data2;

Ⅳ 高級語言源程序編譯後產生的地址是邏輯地址還是物理地址

由於操作系統技術的發展,可重用二進製程序技術使用了內存重定位技術,所以從匯編的角度來看即不是邏輯地址也不是物理地址。而且這個概念有些不同,編譯後產生的地址是相對地址,是相對於可執行頭部位置的地址。而邏輯地址是指在指令系統內部使用的用來訪問內存的一個邏輯表示,通常表現為相對於某個段基地址的偏移量。
當可執行程序被載入內存之後,才會有邏輯地址存在,此時可執行程序被如何載入於何處,地址為多少,由操作系統決定,此時cpu訪問程序用的是邏輯地址。一個程序一旦被編譯確定之後基本上變數初始化的順序固定,資源分配位置也固定,設置有編譯器使用預分配機制,然後採用相對地址引用。
注意:某些工具書也稱二進制可執行文件內所有的相對地址范圍是邏輯地址空間,相對地址就是邏輯地址。因為兩者的訪問方式相似,邏輯地址變換依賴cpu或者附加變換機構(硬體),而二進製程序地址空間變換需要操作系統插手管理。
反匯編分析中常常將二進制內部地址稱為邏輯地址,因為反匯編器不能還原原來匯編代碼的地址跳轉空間特性,因此得到一個相對於二進制數據起點位置的相對地址,而和內存和物理存儲都沒有關系。

Ⅳ 請問下虛擬地址的問題

那個賬號提交有問題,換個賬號回答你。

首先,虛擬地址和邏輯地址是一樣的概念。

linux分段的時候把不同進程映射到不同的線性地址,是在linux 0.11內核代碼中出現的。之所以這樣是因為,0.11版本雖然開啟了分頁機制,但是所有進程共享了同一個頁目錄,所以進程們只能分配其中一段使用。這時候每個進程的線性地址空間沒有那麼大(沒有4GB)。

後來linux內核為了增大單個進程的線性地址空間,就不再共享頁目錄,也就是每個進程有獨立的頁目錄,此時進程的段地址基址就可以設置為0,而不會再相互干涉。

每個進程基址都從0開始,並且都擁有4GB的線性地址空間,這就相當於沒有使用分段機制,實際上分段和分頁都採用了。

Ⅵ 在存儲管理中,地址重i定位的目的是什麼

源程序時,由於程序沒有裝入內存,沒有地址,因此使用變數名替代地址。如上圖所示,load a data1指令是將data1中的3456送寄存器a。

當編譯鏈接後生產目標代碼,此時,程序仍然沒有裝入內存,沒有地址。而目標代碼中無法再使用變數。編譯器生成邏輯地址,以程序頭為0地址進行編址。

在程序運行時,程序裝入內存,但由於地址為0的地方被操作系統使用。程序中的邏輯地址與實際的物理地址不一致。而地址重定位就是將程序中的邏輯地址調整為物理地址。

Ⅶ 關於C語言中內存物理地址的含義,有誰能通俗說一下物理地址這個概念的含義,本人在此感激不盡。

在C語言中,對變數的使用實質上是對計算機內存中存儲內容的訪問,通過對內存空間的引用來實現寫入和讀取。(註:C中有一個特殊的關鍵字register,

用來聲明非存儲在內存當中的變數,register用來要求將變數存儲在計算機的寄存器當中,這樣的變數主要的目的是加快CPU訪問的速率)REGISTER關鍵字是

特定時期的產物,在內存訪問速度很慢的時代用register定義的變數,確實存儲在計算機CPU的寄存器當中,現在來說由於內存的訪問速率也很快,很多編譯器在

編譯的時候,會將register變數也存儲在內存當中。這里主要討論簡介引用和解析引用,因此對register就不再討論。

間接引用是指在匯編語言指令中不直接指出內存的地址,而是通過一個寄存器或者一個內存空間來訪問另外一個內存空間。

簡單的打個比喻。你在網上賣東西。你的商品在你的家中。如果是同城的人家直接到你家來買。這就像訪問物理地址。直接到目標精準有效率。
如果使用變數,就像你要把商品由快遞送到買家手裡,這個過程是有中間環節的「快遞」所以效率可能不夠高(就同城而言)非同城當然是快遞比較好。

Ⅷ 內存管理的基本問題

內存管理
操作系統對內存的劃分和動態分配,就是內存管理的概念。有效的內存管理在多道程序設計中非常重要,不僅方便用戶使用存儲器、提高內存利用率,還可以通過虛擬技術從邏輯上擴充存儲器。內存管理的功能有:

內存空間的分配與回收
地址轉換:在多道程序環境下,程序中的邏輯地址與內存中的物理地址不可能一致,因此存儲管理必須提供地址變換功能,把邏輯地址轉換成相應的物理地址。
內存空間的擴充:利用虛擬存儲技術或自動覆蓋技術,從邏輯上擴充內存。
存儲保護:保證各道作業在各自的存儲空間內運行,互不幹擾。
程序裝入和鏈接
創建進程首先要將程序和數據裝入內存。將用戶源程序變為可在內存中執行的程序,通常需要以下幾個步驟:

編譯:由編譯程序將用戶源代碼編譯成若干個目標模塊。
鏈接:由鏈接程序將編譯後形成的一組目標模塊,以及所需庫函數鏈接在一起,形成一個完整的裝入模塊。
裝入:由裝入程序將裝入模塊裝入內存運行。

程序的鏈接有以下三種方式:

靜態鏈接:在程序運行之前,先將各目標模塊及它們所需的庫函數鏈接成一個完整的可執行程序,以後不再拆開。
裝入時動態鏈接:將用戶源程序編譯後所得到的一組目標模塊,在裝入內存時,釆用邊裝入邊鏈接的鏈接方式。
運行時動態鏈接:對某些目標模塊的鏈接,是在程序執行中需要該目標模塊時,才對它進行的鏈接。其優點是便於修改和更新,便於實現對目標模塊的共享。
模塊在裝入內存時,同樣有以下三種方式:

絕對裝入。在編譯時,如果知道程序將駐留在內存的某個位置,編譯程序將產生絕對地址的目標代碼。絕對裝入程序按照裝入模塊中的地址,將程序和數據裝入內存。由於程序中的邏輯地址與實際內存地址完全相同,故不需對程序和數據的地址進行修改。
可重定位裝入。在多道程序環境下,多個目標模塊的起始地址通常都是從0開始,程序中的其他地址都是相對於起始地址的,此時應釆用可重定位裝入方式。根據內存的當前情況,將裝入模塊裝入到內存的適當位置。裝入時對目標程序中指令和數據的修改過程稱為重定位,地址變換通常是在裝入時一次完成的,所以又稱為靜態重定位。靜態重定位的特點是在一個作業裝入內存時,必須分配其要求的全部內存空間,如果沒有足夠的內存,就不能裝入該作業。此外,作業一旦進入內存後,在整個運行期間不能在內存中移動,也不能再申請內存空間。
動態運行時裝入,也稱為動態重定位,程序在內存中如果發生移動,就需要釆用動態的裝入方式。裝入程序在把裝入模塊裝入內存後,並不立即把裝入模塊中的相對地址轉換為絕對地址,而是把這種地址轉換推遲到程序真正要執行時才進行。因此,裝入內存後的所有地址均為相對地址,這種方式需要一個重定位寄存器的支持。動態重定位的特點是可以將程序分配到不連續的存儲區中;在程序運行之前可以只裝入它的部分代碼即可投入運行,然後在程序運行期間,根據需要動態申請分配內存;便於程序段的共享,可以向用戶提供一個比存儲空間大得多的地址空間。

Ⅸ 操作系統中 區分編譯後的形成邏輯地址和鏈接後的形成的最終邏輯地址 什麼意思啊

編譯後產生若干個目標模塊,編譯後的邏輯地址指的是每個模塊都從0號單元開始編址,而鏈接將這些模塊鏈接在一起,形成一個完整的裝入模塊,此時的邏輯地址會重新編址,也就是說鏈接後的邏輯地址是將整個模塊從0號單元開始編址。

Ⅹ 程序裝載進入內存

上一講,我們看到了如何通過鏈接器,把多個文件合並成一個最終可執行文件。在運行這些可執行文件的時候,我們其實是通過一個裝載器,解析 ELF 或者 PE 格式的可執行文件。裝載器會把對應的指令和數據載入到內存裡面來,讓 CPU 去執行。

說起來只是裝載到內存裡面這一句話的事兒,實際上裝載器需要滿足兩個要求。

第一,可執行程序載入後佔用的內存空間應該是連續的 ,執行指令的時候,程序計數器是順序地一條一條指令執行下去。這也就意味著,這一條條指令需要連續地存儲在一起。

第二,我們需要同時載入很多個程序,並且不能讓程序自己規定在內存中載入的位置。 雖然編譯出來的指令里已經有了對應的各種各樣的內存地址,但是實際載入的時候,我們其實沒有辦法確保,這個程序一定載入在哪一段內存地址上。因為我們現在的計算機通常會同時運行很多個程序,可能你想要的內存地址已經被其他載入了的程序佔用了。

要滿足這兩個基本的要求,我們很容易想到一個辦法。那就是我們可以在內存裡面,找到一段連續的內存空間,然後分配給裝載的程序,然後把這段連續的內存空間地址,和整個程序指令里指定的內存地址做一個映射。

我們把指令里用到的內存地址叫作 虛擬內存地址 (Virtual Memory Address),實際在內存硬體裡面的空間地址,我們叫 物理內存地址 (Physical Memory Address)。

程序里有指令和各種內存地址,我們只需要關心虛擬內存地址就行了。對於任何一個程序來說,它看到的都是同樣的內存地址。我們維護一個虛擬內存到物理內存的映射表,這樣實際程序指令執行的時候,會通過虛擬內存地址,找到對應的物理內存地址,然後執行。因為是連續的內存地址空間,所以我們只需要維護映射關系的起始地址和對應的空間大小就可以了。

內存分段

這種找出一段連續的物理內存和虛擬內存地址進行映射的方法,我們叫分段(Segmentation)。這里的段,就是指系統分配出來的那個連續的內存空間。

分段的辦法很好,解決了程序本身不需要關心具體的物理內存地址的問題,但它也有一些不足之處,第一個就是內存碎片(Memory Fragmentation)的問題。

我們來看這樣一個例子。我現在手頭的這台電腦,有 1GB 的內存。我們先啟動一個圖形渲染程序,佔用了 512MB 的內存,接著啟動一個 Chrome 瀏覽器,佔用了 128MB 內存,再啟動一個 Python 程序,佔用了 256MB 內存。這個時候,我們關掉 Chrome,於是空閑內存還有 1024 - 512 - 256 = 256MB。按理來說,我們有足夠的空間再去裝載一個200MB 的程序。但是,這 256MB 的內存空間不是連續的,而是被分成了兩段 128MB 的內存。因此,實際情況是,我們的程序沒辦法載入進來。

當然,這個我們也有辦法解決。解決的辦法叫 內存交換 (Memory Swapping)。

我們可以把 Python 程序佔用的那 256MB 內存寫到硬碟上,然後再從硬碟上讀回來到內存裡面。不過讀回來的時候,我們不再把它載入到原來的位置,而是緊緊跟在那已經被佔用了的 512MB 內存後面。這樣,我們就有了連續的 256MB 內存空間,就可以去載入一個新的200MB 的程序。如果你自己安裝過 Linux 操作系統,你應該遇到過分配一個 swap 硬碟分區的問題。這塊分出來的磁碟空間,其實就是專門給 Linux 操作系統進行內存交換用的。

虛擬內存、分段,再加上內存交換,看起來似乎已經解決了計算機同時裝載運行很多個程序的問題。不過,你千萬不要大意,這三者的組合仍然會遇到一個性能瓶頸。硬碟的訪問速度要比內存慢很多,而每一次內存交換,我們都需要把一大段連續的內存數據寫到硬碟上。所以,如果內存交換的時候,交換的是一個很占內存空間的程序,這樣整個機器都會顯得卡頓。

內存分頁

既然問題出在內存碎片和內存交換的空間太大上,那麼解決問題的辦法就是,少出現一些內存碎片。另外,當需要進行內存交換的時候,讓需要交換寫入或者從磁碟裝載的數據更少一點,這樣就可以解決這個問題。這個辦法,在現在計算機的內存管理裡面,就叫作 內存分頁 (Paging)。

和分段這樣分配一整段連續的空間給到程序相比,分頁是把整個物理內存空間切成一段段固定尺寸的大小 。而對應的程序所需要佔用的虛擬內存空間,也會同樣切成一段段固定尺寸的大小。這樣一個連續並且尺寸固定的內存空間,我們叫頁(Page)。從虛擬內存到物理內存的映射,不再是拿整段連續的內存的物理地址,而是按照一個一個頁來的。頁的尺寸一般遠遠小於整個程序的大小。在 Linux 下,我們通常只設置成 4KB。你可以通過命令看看你手頭的 Linux 系統設置的頁的大小。

getconf PAGE_SIZE

由於內存空間都是預先劃分好的,也就沒有了不能使用的碎片,而只有被釋放出來的很多4KB 的頁。即使內存空間不夠,需要讓現有的、正在運行的其他程序,通過內存交換釋放出一些內存的頁出來,一次性寫入磁碟的也只有少數的一個頁或者幾個頁,不會花太多時間,讓整個機器被內存交換的過程給卡住。

更進一步地,分頁的方式使得我們在載入程序的時候,不再需要一次性都把程序載入到物理內存中。我們完全可以在進行虛擬內存和物理內存的頁之間的映射之後,並不真的把頁載入到物理內存里,而是只在程序運行中,需要用到對應虛擬內存頁裡面的指令和數據時,再載入到物理內存裡面去。

實際上,我們的操作系統,的確是這么做的。當要讀取特定的頁,卻發現數據並沒有載入到物理內存里的時候,就會觸發一個來自於 CPU 的 缺頁錯誤 (Page Fault)。我們的操作系統會捕捉到這個錯誤,然後將對應的頁,從存放在硬碟上的虛擬內存里讀取出來,載入到物理內存里。這種方式,使得我們可以運行那些遠大於我們實際物理內存的程序。同時,這樣一來,任何程序都不需要一次性載入完所有指令和數據,只需要載入當前需要用到就行了。

通過虛擬內存、內存交換和內存分頁這三個技術的組合,我們最終得到了一個讓程序不需要考慮實際的物理內存地址、大小和當前分配空間的解決方案。這些技術和方法,對於我們程序的編寫、編譯和鏈接過程都是透明的。這也是我們在計算機的軟硬體開發中常用的一種方法,就是 加入一個間接層 。

通過引入虛擬內存、頁映射和內存交換,我們的程序本身,就不再需要考慮對應的真實的內存地址、程序載入、內存管理等問題了。任何一個程序,都只需要把內存當成是一塊完整而連續的空間來直接使用。

總結延伸

現在回到開頭我問你的問題,我們的電腦只要 640K 內存就夠了嗎?很顯然,現在來看,比爾·蓋茨的這個判斷是不合理的,那為什麼他會這么認為呢?因為他也是一個很優秀的程序員啊!

在虛擬內存、內存交換和內存分頁這三者結合之下,你會發現,其實要運行一個程序,「必需」的內存是很少的。CPU 只需要執行當前的指令,極限情況下,內存也只需要載入一頁就好了。再大的程序,也可以分成一頁。每次,只在需要用到對應的數據和指令的時候,從硬碟上交換到內存裡面來就好了。以我們現在 4K 內存一頁的大小,640K 內存也能放下足足 160 頁呢,也無怪乎在比爾·蓋茨會說出「640K ought to be enough for anyone」這樣的話。

不過呢,硬碟的訪問速度比內存慢很多,所以我們現在的計算機,沒有個幾 G 的內存都不好意思和人打招呼。

那麼,除了程序分頁裝載這種方式之外,我們還有其他優化內存使用的方式么?下一講,我們就一起來看看「動態裝載」,學習一下讓兩個不同的應用程序,共用一個共享程序庫的辦法。

閱讀全文

與編譯鏈接裝入物理地址相關的資料

熱點內容
騰訊雲連接不上伺服器 瀏覽:221
不能用來表示演算法的是 瀏覽:859
6軸機器人演算法 瀏覽:890
手機主題照片在哪個文件夾 瀏覽:294
安卓手機後期用什麼軟體調色 瀏覽:628
cad修改快捷鍵的命令 瀏覽:242
好錢包app怎麼登錄不了 瀏覽:859
樹莓派都用python不用c 瀏覽:757
access文件夾樹的構造 瀏覽:662
安卓多指操作怎麼設置 瀏覽:658
linux樹形目錄 瀏覽:727
平方根的簡單演算法 瀏覽:898
千牛訂單頁面信息加密取消 瀏覽:558
單片機自製紅外遙控燈 瀏覽:719
伺服器最小配置怎麼弄 瀏覽:853
ibm伺服器硬體如何升級 瀏覽:923
全球程序員節點贊 瀏覽:986
php函數傳遞數組 瀏覽:632
人工峰群演算法的目標函數 瀏覽:469
如何刪加密文檔 瀏覽:105