天天看點

【作業系統】程式的編譯、裝入、連結

下面的内容都是我自己的一些想法,可能不正确,如有錯,請指出來,我會及時更改。

首先,我先編寫一個main.asm彙編源程式,要明确的是,不同的彙編指令轉化成二進制機器指令時,會有多個位元組,不同指令所占用的位元組是不同的。知道占用多個位元組就可以了。

看下圖,反彙編下指令的位址和機器指令,我編寫的main.asm轉化為機器指令,指令的位址是從076B:0000開始的。

【作業系統】程式的編譯、裝入、連結

編譯

編譯将我所寫的main.asm檔案轉化為main.obj檔案,生成一個目标檔案。

轉化為目标檔案的規則:假設我有一條語句是jmp next反彙編之後,就是變成了jmp 2500,那麼這個2500就是相對我自己寫的代碼段的偏移位址。

再假設我有一條語句是 mov ax,Y 那麼轉化成機器語言之後,再反彙編就是

mov ax,[0002]就是相對資料段的偏移位址為2的内容送至ax。

雖然程式是按編譯->連結->裝入的方式執行的,但是可以先跳到裝入的内容看一下。

連結

就是将多個目标子產品連結成一個大目标子產品。

每個子產品中的指令位址都是從0開始的。

比如三個目标子產品A,B,C

A所有指令位址為0 - L-1, B所有指令位址為0 - M-1,C所有指令位址為0 - N-1。

裝入

這些内容都是按着時間線慢慢發展起來的,針對當時的不同的條件,所思考出的不同政策。

1.絕對裝入方式

隻适合運作單程式。

每次将程式裝入記憶體中初位址為R的地方,那麼執行jmp 2500就是跳到jmp R+2500的地方,繼續執行。

2.可重定位裝入方式

适用于多程式

可重定位就是給cpu配置兩個寄存器基址寄存器、變址寄存器

首先,OS會給程式配置設定一個起始位址,假設10000,儲存在基址寄存器中,從這個起始位址,将程式的所有指令依次放入記憶體中。那麼原來的指令jmp 2500放入記憶體中就會變成jmp 12500。

變址寄存器是存放代碼的長度,防止越界的。

3.動态運作時的裝入方式

考慮一個程式會被分成多個部分,而這些部分可能會被多次換出,又被多次換入,放入記憶體中的實體位址就會改變。顯然,可重定位裝入方式就不适用了。

那麼對應其解決的政策就是原本的指令jmp 2500依舊放入記憶體中,當程式運作時,再将其轉化為jmp12500執行,如果,這段代碼更改位址了,可能會執行jmp 32500(由這段代碼所在實體位址決定)。

再扯一點,因為隻有一個基址寄存器,當有多個程序在記憶體中,那麼應該儲存哪個程序的起始位址呢?

實際上,每次會給一個剛運作的程式配置設定一個起始位址,當程序變為阻塞、切換其他程序時,會将這個起始位址儲存在這個程序的PCB中。并且會把基址寄存器的内容修改為下一個将要運作程序的起始位址(在PCB中檢視是否有起始位址,沒有的話則系統配置設定一個)。

每個程序都有自己的PCB。

繼續閱讀