大戰系統程式 - 控制段組譯與連結載入
前面我們講了基本的組譯流程,而這篇主要要講的是怎麼樣合併兩個程式,因為通常我們寫完的程式碼不會只有一份檔案,而是會有數份。
這裡的細節爆炸多,所以一定要仔細看。第一步的組譯過程和之前一樣,我會把不一樣的地方寫出來,其它相同的地方不會再重複。
下方的內容如果有錯誤,歡迎來信更正!
組譯
下方的題目取自席家年教授的練習題,如有侵權請來信告知!
下方為練習卷
可以發現到有兩份程式碼需要組譯,而且兩份程式碼裡面都出現了之前沒有出現的字。第一個步驟就是先把位址寫一寫,這裡位址和之前一樣。
第一份程式:
| 地址 | 標記符號 | 指令 | 運算元 |
|---|---|---|---|
| 0000 | TSTPGM | START | 0 |
| EXTDEF | REF4 | ||
| EXTREF | NXTREF | ||
| ... | |||
| 0029 | REF1 | LDX | #ENDA-TSTA |
| 002C | REF2 | LDA | TSTA,X |
| 002F | REF3 | +LDS | NXTREF-24 |
| 0033 | REF4 | EQU | * |
| ... | |||
| 0050 | TSTA | EDU | * |
| ... | |||
| 0084 | ENDA | EDU | * |
| 0084 | REF5 | WORD | TSTA+8 |
| 0087 | RESB | 12 | |
| 0093 | END | REF1 |
上面這張表格跟之前的其實沒有什麼差別,但可以發現到有兩個比較特別的是 EXTDEF 和 EXTREF,這兩個就是外部引用的程式。
還有一個東西是 EDU,後面的運算元是一個 *,而這個我們就當成保留,不佔用空間。
第二份程式碼發現到地址幫我們上好,但我一樣寫在下面。
| 地址 | 標記符號 | 指令 | 運算元 |
|---|---|---|---|
| 0000 | NXTPGM | START | 0 |
| EXTDEF | NXTREF | ||
| ... | |||
| 0052 | NXTREF | LDA | NXTREF+20 |
| 0055 | NXT1 | LDB | #NXTREF |
| ... | |||
| 0090 | NXT2 | WORD | NXT2-6 |
| 0093 | RESW | 5 | |
| 00A2 | END |
接下來就是把目地的碼算出來,過程跟之前都一樣。
第一份程式碼:
| 地址 | 標記符號 | 指令 | 運算元 | 目地碼 |
|---|---|---|---|---|
| 0000 | TSTPGM | START | 0 | |
| EXTDEF | REF4 | |||
| EXTREF | NXTREF | |||
| ... | ||||
| 0029 | REF1 | LDX | #ENDA-TSTA | 050034 |
| 002C | REF2 | LDA | TSTA,X | 03A021 |
| 002F | REF3 | +LDS | NXTREF-24 | 6F1FFFF8 |
| 0033 | REF4 | EQU | * | |
| ... | ||||
| 0050 | TSTA | EDU | * | |
| ... | ||||
| 0084 | ENDA | EDU | * | |
| 0084 | REF5 | WORD | TSTA+8 | 000058 |
| 0087 | RESB | 12 | ||
| 0093 | END | REF1 |
第二份程式碼:
| 地址 | 標記符號 | 指令 | 運算元 | 目地碼 |
|---|---|---|---|---|
| 0000 | NXTPGM | START | 0 | |
| EXTDEF | NXTREF | |||
| ... | ||||
| 0052 | NXTREF | LDA | NXTREF+20 | 032011 |
| 0055 | NXT1 | LDB | #NXTREF | 692FFA |
| ... | ||||
| 0090 | NXT2 | WORD | NXT2-6 | 00008A |
| 0093 | RESW | 5 | ||
| 00A2 | END |
目的程式
跟之前一樣會有兩份目的程式,但這裡跟之前不太一樣,差別在於有 EXTREF 和 EXTDEF,這兩個都會生成比較特別的紀錄。
第一份
先從第一份程式碼開始,一樣的先從表頭紀錄開始
H,TSTPGM,000000,000093
接下來我們會有兩種新的紀錄,分別是 D 紀錄和 R 紀錄,D 紀錄在代表的是自己給別人用的程式,而 R 紀錄正好相反,代表的是自己使用別人的程式。
先寫 D 紀錄,要依序寫入的資訊如下:
- 開頭字母
D - 六格的標紀符號,對應到 EXTDEF 後面所寫的標紀錄號
- 六格的標紀符號所在位址
D,REF4☐☐,000033
再來寫 R 紀錄,和 D 紀錄相同,要依序寫入的資訊如下:
- 開頭字母
R - 六格的標紀符號,對應到 EXTREF 後面所寫的標紀符號
R,NXTREF
接下來的本文紀錄和之前相同,下面不再重複。
T,000029,0A,050034,03A021,6F1FFFE8
T,000084,03,000058
再來是修正紀錄基本上和之前一樣,但是有一個紀錄不太一樣。
注意到標紀位址在 REF3 那一行,可以發現到計算的時候使用到了 NXTREF 這個標紀符號,仔細看就會發現到這個使用到了 EXTREF 所標紀的符號,所以修正紀錄也要基於 NXTREF,而不是 START 的 TSTPGM,換句話說就是這裡是基於外部的程式。
M,000030,05,+NXTREF
還有一行需要修正的是 REF5,這行的話沒有什麼特別的,修正紀錄如下:
M,000084,06,+TSTPGM
最後的結束紀錄和之前一樣,沒什麼特別的
E,000029
第二份
表頭紀錄如下:
H,NXTPGM,000000,0000A2
D 紀錄如下:
D,NXTREF,000052
本文紀錄如下:
T,000052,06,032011,692FFA
T,000090,03,00008A
修正紀錄一個,如下:
M,000090,06,+NXTPGM
結束紀錄就一個 E。
連結載入
接下來就是要模擬在電腦中實際載入兩份程式碼之後會發生的事,假設載入的起始位址的 5000。
而外部符號表要處理的地方比較多,控制段其實就是程式的外稱,像 TSTPGM 指的就是第一份程式碼。符號名稱就是 EXTDEF 後面寫的標紀符號,位址的話就是 START 的位址跟 END 的位址,長度就是兩者相減。
第二份程式碼跟第一份的步驟相同,但是位址要接在第一份之後。
| 控制段 | 符號名稱 | 位址 | 長度 |
|---|---|---|---|
| TSTPGM | REF4 | 5000~5093 | 93 |
| NXTPGM | NXTREF | 5093~50E5 | A8 |
實際上執行的時候修正紀錄就會發揮作用,下面舉幾個例子,也就是練習卷的題目。
REF3 +LDS NXTREF-24 載入到記憶體的位址為 502F,修正後的目的碼為 6F1050CD。
目的碼的算法就是看修正紀錄怎麼寫就怎麼做,像這題的修正紀錄是 M,000030,05,+NXTREF,所以我們要做的就是把 1FFFF8 拿出來加上 NXTREF,而 NXTREF 的值為 50E5,可以對應到剛剛的外部符號表。
REF5 WORD TST+8 載入到記憶體的位址為 5084,修正後的目的碼為 005058。
NXT1 LDB #NXTREF 載入到記憶體的位址為 50E8。
而最後,程式開始的地方就是第一條本文記錄開始的地方,需要注意一下要再加上初始地址,得到 5029。