Role of Assembler
Basic SIC assembler directive
指示(directive)與指令(instruction)不同的是,「指令」為讓CPU可以實際執行的命令(e.g. LDA, ADD…);而「指示」並非真正的指令,主要是為了告訴Assembler要做什麼事(e.g. 保留空間、程式開始與結束…)
- START, END 程式開始與結束
- e.g. START 1000 => 代表此程式從記憶體位址0x1000開始(如下圖)
- WORD 宣告一個Word的標籤做為常數使用
- BYTE 宣告數個Byte的標籤做為常數使用
- RESW 保留一個Word的空間當作變數使用
- RESB 保留數個Byte的空間當作變數使用
- p.s. 常數:不可修改;變數:可修改(後來再賦予值)
SIC Code Example (含Object Code)
Fundamental functions of assembler
- 將 助憶碼(mnemonic operation codes) 轉換成機器碼
- e.g. LDA => 0x00
- 將 符號運算元(symbolic operands) 轉換為對應的記憶體位址
- e.g. RDREC => 0x2039
- 依照指令格式建立指令
- 將常數資料轉換成機器內部的表示方式
- e.g.
EOF BYTE C'EOF'
=> 454F46
- e.g.
- 產生目的碼程式 (Object program) 和組譯列表
obj檔內容(皆以16進制表示)
下圖為上面範例放入obj檔的樣子
其中:
- record (每行首個字元)
- H (Header):Obj檔第一行
- 該行第2~7個字元:程式名稱
- 該行第8~13個字元:程式起始位址
- 該行第14~19個字元:程式總共使用的記憶體長度
- 以上圖為例的話,2079-1000+1=107A
- T (Text):指令碼
- 該行第2~7個字元:該行的起始位址
- 該行第8~9個字元:該行長度
- 該行10~69個字元:Object Code,以16進制表示
- OBJ檔中,Object Code每Byte為2字元,因此每行最多只能放30 Bytes
- (69-10+1)/2 = 30
- 指令普遍為格式3,指令碼為6個字元,則普遍情況下,該行最多只能存放(69-10+1)/6=10個指令
- E (End):Obj檔最後一行
- 該行第2~7個字元:程式中第一個可執行指令的位址
- H (Header):Obj檔第一行
Address Translation Problem
Forward reference (前向參考問題)
- 組譯時會遇到的問題
- 參考的標籤位於該行後方(尚未定義)
Solution : Two passes assembler
- Pass 1
- 分配記憶體位址給程式中每一行指令
- 判斷指令長度(透過OPTAB)
- 計算LOCCTR
- 儲存所有標籤(Labels)的位址到SYMTAB
- 對一些指示要進行處理
- Pass 2
- 透過SYMTAB,帶入Pass 1沒有處理的symbol
- 透過OPTABLE產生機器碼
- 藉由BYTE, WORD定義,生成常數標籤的數值
- 寫入obj檔和組譯列表
細節
- 運算碼表 (Operation Code Table, OPTAB)
- 儲存助憶指令與機器碼之關連
- 使用Hash Table,使用助憶碼作為key
- Pass 1時用來檢驗運算碼及計算指令長度
- Pass 2時用來轉換運算碼至機器碼
- Static結構
- 符號表 (Symbol Table, SYMTAB)
- 儲存Labels與其對應記憶體位址
- 包含Labels名稱、位址、長度、型態和error flags
- 使用Hash Table加速
- Dynamic結構
- 程式計數器 (Location Counter, LOCCTR)
- 初始值為START指派的值
- 記錄下一個指令的位址
- Intermediate file
- 由pass1寫入並當pass2的input
- 包含:
- 在Pass 1所得到的記憶體位址
- 錯誤指示(避免Pass 1發現錯,卻還進入Pass 2)
一些SIC/XE指令符號代表的定址模式
- 定址模式請參考這裡
- +: Extended Addressing Mode
- e.g.
+JSUB
- e.g.
- #: Immediate Addressing Mode
- e.g.
LDA #3
- e.g.
- @: Indirect Addressing Mode
- e.g.
J @RETADR
- e.g.
- ,X: Indexing Addressing Mode
- e.g.
LDA ARRAY, X
- e.g.
- 如沒以上符號
- 原則上,組譯時先嘗試使用PC相對定址
- 若超出範圍則試著使用Base定址
- 若兩者都不適用則會有錯誤訊息
Program Relocation (程式重新定址問題)
- SIC有一個absolute loader (絕對載入器)
- 程式必須被載入到指定的起始位址
- 如果被載入到與指定的不同,則指令的位址需要更改
- 因OS記憶體配置較彈性,因此程式每次執行可能會被放在不同的起始位址
Relocatable program
- Assembler無法自己改變記憶體位址
- 但可透過OBJ檔告訴loader記憶體位址需要被修正。
- 會受影響的指令碼(需被Relocate的指令)
- SIC版本
- 常數資料的指令碼絕對不會影響
- e.g.
EOF BYTE C'EOF'
=> 454F46
- e.g.
- 大多指令都是直接定址,因此幾乎都會影響
- 所以暫時逃避不談xD
- 常數資料的指令碼絕對不會影響
- SIC/XE版本
- 只有Extended定址會受影響,因為其他定址模式都是相對的
- 簡單來說,相對定址和常數資料的指令碼不受影響
- SIC版本
- OBJ檔中的修正方式:
- 使用record
- M (Modification):修正會放在E record前
- 該行第2~7個字元:需修改的位址欄位與程式起始位址的距離
- 該行第8~9個字元:修正長度(以Nibble為單位,1 Nibble = 0.5 Byte)
- e.g. 有一XE的obj檔如下
- 標示如上圖所示,每兩個16進制字元為1 Byte
- 因此藍標,M 000007 05
- 去Relocation相對程式起始位址第7個Byte
- 並修正5個Nibbles(2.5個Bytes)
- 第7個Byte是10,那為何是從0開始取5 Nibbles,而不是從1開始取?
- 原因:因為存放在記憶體的方式是littleEndian,所以1個Nibble是從第7個Byte的後面開始算
- 其他以此類推
- 因此藍標,M 000007 05
- 標示如上圖所示,每兩個16進制字元為1 Byte
- M (Modification):修正會放在E record前
- 使用record