編譯原理之可重定位代碼

原文鏈接:https://blog.csdn.net/yesyes120/article/details/78944991

可重定位代碼 是什麼意思呢?
顧名思義,可重定位 就是 可以重新定位  的意思。
我們都知道,在寫代碼時,代碼裏的各種跳轉代碼/指令,比如C語言裏的goto,彙編裏的jmp、jz等等,它們都是跳到某一地址,然後在該地址繼續往下執行代碼 的意思,我們寫的代碼時用的內存空間是邏輯空間,但是代碼在實際運行時,用到的卻是貨真價實的物理地址空間。

既然如此,那麼在程序編譯時,就需要有一個從  邏輯地址空間到   物理地址空間  的映射,如果這個映射做得不好,那麼就會影響代碼的正確執行。

打個比方,下面有一段代碼:
    AAAA;(假設這裏是代碼的起始地址0)


    ...        (中間經略過了187個地址)


    XXXX;(假設這一行的邏輯地址是188)
circle:
   YYYY;(那麼這一行就應該是189)
   ZZZZ;(190)
   MMM;(191)

goto circle;(又跳到circle,也就是地址爲189那裏)


因爲操作系統給進程分配的內存的起始位置是無法確定的,換句話說,也就是程序 在運行時實際的物理起始位置是不確定,所以不能在編譯時就把地址給寫死,否則,如果實際運行時物理空間起始位置與編譯時寫死的起始地址  不一致的話,程序就會出問題。

舉個栗子,就拿上面的代碼來講,假設編譯時,按照起始地址爲0,給每一行代碼都定死了地址(地址爲右邊括號裏的數字),然而在實際運行這段程序時,系統可能給這個進程分配的 物理地址 起始地址爲 2000,那麼當代碼執行到 goto circle;這一句時,本應該跳到的地址爲2189,但是因爲編譯時已經把調轉地址給寫死了,實際卻跳到地址189,至於這個189是哪一個進程的什麼代碼我們不知道,但可以肯定得是,這已經跳出了自己的物理空間,跳到別人的物理空間執行別人的代碼去了,毫無疑問這樣會出問題的。

爲了解決這個問題,科學家們就把心思放在編譯這一步驟上。

如果我們編譯時,涉及  地址跳轉,某個地址對應信息的讀取、寫入   等等之類與地址有關的操作,代碼裏所有地址都採用動態調整的方式,也就是可以根據操作系統實際給進程分配的  實際物理內存 的起始位置 ,而進行調整的話,那麼代碼就不會出錯啦。

同樣拿上面的例子來說,假設運行該代碼時,系統給這個進程分配的 物理地址 起始位置爲 2000,而代碼自動根據這個起始位置調整自己的地址,那麼代碼實際上是:
    AAAA;(假設這裏是代碼的起始地址2000)


    ...        (中間經略過了187個地址)


    XXXX;(假設這一行的邏輯地址是2188)
circle:
   YYYY;(那麼這一行就應該是2189)
   ZZZZ;(2190)
   MMM;(2191)

goto circle;(又跳到circle,也就是2189那裏)


這樣的話,代碼的執行就不會出錯啦。

這種可以使地址平移的代碼就叫做可重定位代碼,它是在加載的時候,也就是系統給進程確定了物理地址時,才生成絕對地址的。

重定位是由操作系統安排的。在裝入程序前,系統會計算未使用的內存,然後將程序裝入,並記下開始地址。在執行有相對地址的指令時,會將所有的地址加個剛纔記下的開始地址,就叫重定位。它是實現多道程序在內存中同時運行的基礎。

實際上使得代碼可重定位方式有兩種,分別是動態重定位與靜態重定位。
1、靜態重定位:即在程序裝入內存的過程中完成,是指在程序開始運行前,程序中的各個地址有關的項均已完成重定位,地址變換通常是在裝入時一次完成的,以後不再改變,故成爲靜態重定位。
2、動態重定位:它不是在程序裝入內存時完成的,而是CPU每次訪問內存時 由動態地址變換機構(硬件)自動進行把相對地址轉換爲絕對地址。動態重定位需要軟件和硬件相互配合完成。

這裏不講述第2種,能理解第1種就可以啦。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章