系統程式 – 理論與實務

第 4 章、組譯器

作者:陳鍾誠
旗標出版社

第 4 章、組譯器
4.1 組譯器簡介
4.2 組譯器的演算法
4.3 完整的組譯範例
4.4 進階的組譯器功能
4.5 實務案例
 4.5.1
 4.5.2

微軟的組譯工具
GNU 組譯工具

4.1 組譯器簡介
何謂組譯器?
組譯器乃是將組合語言轉換為目的

的工具。

是組合語言程式設計師所使用的主要工具。

圖 4.1 組譯器的過程示意圖
組合語言

MUL
ADD
ADD

R5, R2, R2
R1, R2, R5
R2, R4, R2

目的檔

組譯器
Assembler

15 52 20 00
13 12 50 00
13 24 20 00

範例 4.1 簡單的組合語言程式
行號
1
2
3
4
5
6

組合語言程式碼
EX1
START
0x0100
LD
R1, B
ST
R1, A
A
RESW 1
B
WORD 29
END EX1

說明
程式開始
載入記憶體變數 B 到暫存器 R1 當中
將暫存器 R1 存回記憶體變數 A 當中
保留一個字組 (Word) 給變數 A
宣告變數 B 為字組,並設初值為 29
程式結束

範例 4.2 為組合語言程式加上目的碼
行號 記憶體位址 程式碼
(16 進位 )
1
2
3
4
5
6

EX1
00000100
00000104
00000108 A
0000010C B

START
LD
ST
RESW
WORD
END

0x0100
R1, B
R1, A
1
29
EX1

目的碼 A
( 絕對定址 )
( 較差 )

目的碼 B
( 相對定址 )
( 較好 )

T(0010010
C)
T(0110010
8)
B(0004)
T(0000001
D)

T(001F000C)
T(011F0004)
B(0004)
T(0000001D)

範例 4.3 組譯器的輸出 - 目的 的範例
T 0100 { 001F000C 011F0004 }
T 010C { 0000001D }

表格 4.1 載入儲存的指令編碼表






格式 指令 OP

意義

範例

說明

B
B
B
B

載入
(word)
儲存
(word)
載入
(byte)
儲存 (byte)

LD Ra
[Rb+Mx]
ST
Ra [Rb+
Mx] Ra [Rb+
LDB
Mx] Ra [Rb+
STB
Mx]

Ra[Rb+ Mx]
Ra[ Rb+ Mx]
Ra(byte)[Rb+
Mx]
Ra(byte)[Rb+
Mx]

LD
ST
LDB
STB

00
01
02
03

絕對定址 v.s. 相對定址
LD
LD
00

Ra,
R1,
1

[Rb

+

0

Cx]
B
010C

圖 4.2 將 LD R1, B 指令以絕對定址法編為目的

指令編碼
LD
Rd,
LD
R1,
00
1

[Ra +
PC+
F

圖 4.3 將 LD R1, B 指令以相對於

Cx 值的計算 (Cx=BCx]
PC) 0x010C
(B-PC)
(B)
0008
0x0104
(PC)
PC 的方法編為目的碼
=
0x0008

組譯器的步驟
1. 運算元轉換:將助憶運算碼 (OP) 轉換為機器語
言,例如 LD 轉為 00 , ST 轉為 01 等。
2. 參數轉換:將符號運算元轉換成機器位址,例如
A 轉為 0108 , B 轉為 010C 等。
3. 資料轉換:將原始程式當中的資料常數轉換為內
部的機器碼,例如 29 轉換為 001D 。
4. 目的碼產生:以適當的格式建立機器指令,產生
目的程式。

4.2 組譯器的演算法
第一階段 (PASS1)
計算符號位址

第二階段 (PASS2)
產生目的碼

第一階段 ( 計算符號位址 )
 1. 決定每一個指令與假指令所占記憶空間的大小
 例如決定 WORD 、 RESW 等指令所定義的資料長度,以及

LD 、 ST 等指令所佔空間的大小。

 2. 指定程式當中所有指令與資料的位址
 像是行號 2 為 0100 ,行號 3 為 0104 等。

 3. 儲存每一個標籤與變數的記憶體位址
 方便第二階段使用。像是變數 A 為 0108 ,變數 B 為 010C

等。

第二階段 ( 組譯指令與資料 )
1. 轉換組合語言指令助憶碼為機器碼
例如 LD 轉換為 00 , ST 轉換為 01 等。

2. 轉換指令參數為機器碼
例如 R1 轉換為 1, B 轉換為 0 01 0C 等。

3. 轉換資料定譯指令為位元
例如 WORD B 29 轉為 00 00 00 1D 等。

4. 產生目的碼並輸出到目的檔當中。

組譯器的資料結構
範例 4.4 資料結構 1 - 指令表格
LD
00
ST
01
LDB 02
....
範例 4.5 資料結構 2 – 符號表

A
B

00000108
0000010C

第一階段演算法 ( 計算符號位址 ) (1)
Algorithm AssemblerPass1
// 組譯器的第一階段演算法
input AssmeblyFile
// 輸入:組合語言檔
ouptut SymbolTable
// 輸出:符號表
begin
SymbolTable = new Table;
// 建立空的符號表
file = open(AssemblyFile)
// 開啟組合語言檔作為輸入
while not file.end
// 當檔案還沒結束前,繼續讀檔
line = readLine(file)
// 讀下一行
if line is comment
// 如果該行為註解
continue
// 則忽略此行,繼續下一輪迴圈
label= label(line)
// 取得該行中的標記
if label is not null
// 如果該行有標記
symbolRecord = symbolTable.search(label) // 於符號表中尋找該標記
if symbolRecord is not null
//
如果找到該標記
report error
// 則報告錯誤 - 標記重複定義
end if

第一階段演算法 ( 計算符號位址 ) (2)
op = operator(line)
opRecord = opTable.search(op);
if opRecord is not null
address += 4;

// 取得該行中的指令部分 ( 助憶符號 )
// 於指令表中尋找該指令
// 如果找到該指令
// 則將位址加 4
// ( 因為 CPU0 的每個指令都是 4 byte)
else if op is ‘START’
// 如果指令是 START
address = (parameter 1 as integer) // 則將位址設定為參數 1 所代表的位址
else if op is ‘BYTE’
// 如果指令是 BYTE
address += 1*length(parameters) // 則將位址加 1
else if op is ‘WORD’
// 如果指令是 WORD
address += 4 * length(parameters) // 則將位址加 4 (CPU0 的 word 是 4 byte)
else if op is ‘RESB’
// 如果指令是 RESB
address += length(parameter 1)
// 則將位址加上參數所占的 byte 數目
else if op is ‘RESW’
// 如果指令是 RESW
address += 4 * length(parameter 1) // 則將位址加上 4* 參數所占的 Word 數
else
// 如果不屬於上述情形之一,則代表該指令
report error
// 可能拼寫有誤,於是顯示錯誤訊息
end if
end while
End

第二階段演算法 ( 產生目的碼 )
(1)
Algorithm AssemblerPass2

// 組譯器的第二階段演算法

input AssmeblyFile, SymbolTable

// 輸入:組合語言檔,符號表

ouptut ObjFile

// 輸出:目的檔

begin
file = open(AssemblyFile)
while not file.end

// 開啟組合語言檔作為輸入
// 當檔案還沒結束前,繼續讀檔

line = readLine(file)

// 讀下一行

op = operator(line)

// 取得該行中的指令部分 ( 助憶符號 )

opRecord = opTable.search(op) // 於指令表中尋找該指令
if opRecord is not null

// 如果找到該指令

objCode = translateInstruction(line, address) // 將指令轉換為目的碼
address += length(objCode)

// 計算下一個指令位址

第二階段演算法 ( 產生目的碼 )
(2)
else if op is ‘WORD’ or ‘BYTE‘

// 如果指令是 WORD 或 BYTE

objCode = translateData(line)

//

address += length(objCode)

// 計算下一個指令位址

else if op is ‘START’

將資料轉換為目的碼

// 如果指令是 START

address = (parameter 1 as integer) // 則將位址設定為參數 1 所代表的位址
else if op is ‘RESB’

// 如果指令是 RESB

address += length(parameter 1) // 則將記憶體位址加上參數所占的 byte 數
else if op is ‘RESW’

// 如果指令是 RESW

address += 4 * length(parameter 1) //

則將位址加上 4 * 參數的 Word 數

end if
output ObjCode to ObjFile
end while
end

// 將目的碼寫入目的檔當中。

第二階段演算法 ( 指令轉換 ) (3)
Algorithm TranslateInstruction
// 轉換指令為目的碼。
Input line, pc, opRecord
// 輸入:指令、程式計數器
Output objCode
// 輸出:目的碼
if (opRecord.type is L)
// 如果是 L 型指令
Ra = parameters[1]
// 設定 Ra 參數
if (parameters[3] is Constant)
// 如果是常數
Cx = toInteger(parameter[2]); // 設定 Cx 為該常數。
if (parameters[3] is Variable)
// 如果是變數
Cx = address(Variable) – pc
// 設定 Cx 為位移 ( 標記 -PC) 。
Rb = parameters[2]
// 設定 Rb 參數。
end if
objCode = opRecord.opCode+id(Ra)+hex(Cx); // 設定目的碼。
else if (op.type is A)
// 如果是 A 型指令
Ra = parameter[1]
// 取得 Ra
Rb = parameter[2]
// 取得 Rb
Rc = parameter[3]
// 取得 Rc
objCode = opRecord.opCode+id(Ra)+id(Rb)+id(Rc) // 將目的碼寫入目的檔。
….
// … 處理 A 型與資料宣告…
End

4.3 完整的組譯範例
組合語言
組譯報表
目的檔

範例 4.6 組合語言 ( 加總功能 )

範例 4.6 的組譯報表

範例 4.6 的目的

4.4 進階的組譯器功能
 定址範圍的問題

 實字 (Literal) :直接將常數寫在指令中

 LTORG : 將實字列出

 ORG : 回到某個位址

 EQU : 以名稱代表常數或符號運算式

定址範圍的問題

常數值的表示法

範例 4.11 實字 (Literal) 的組合語
言程式範例

範例 4.12 以 LTORG 提早展開實字的範

範例 4.13 使用 EQU 假指令的組合
語言程式片段

範例 4.14 使用 EQU 進行相對位址
模擬 C 語言的 struct 結構

範例 4.15 使用 EQU 與星號 * 模擬
C 語言的 struct 結構

範例 4.16 使用 ORG 假指令的組合
語言程式片段

範例 4.17 使用運算式計算陣列大小
的組合語言程式片段

範例 4.18 以 USE 區塊解決巨大陣列
所造成的定址問題

4.5 實務案例
4.5.1 微軟的組譯工具

4.5.2 GNU 組譯工具

4.5.1 微軟的組譯工具
Visual Studio Express (C++)
該書的網址為 http://kipirvine.com/asm/
其中書籍的前三章與所有範例程式,可以免費下載。
Getting Started with MASM
http://www.kipirvine.com/asm/gettingStarted/index.h

tm

範例 4.19 以 Visual Studio 撰寫
MASM 組合語言的範例

圖 4.7 在 Visual Studio 中執行組合語

圖 4.8 在 Visual Studio 中執行
MASM 組合語言的結果

圖 4.9 用組合語言輸出字串到螢幕

4.5.2 GNU 組譯工具
GNU 的 gcc, as 均可用來組譯
使用 gcc 較方便,因為可同時編譯連結
還可將 C 語言編譯為組合語言
本節將使用 gcc 將 C 編譯為組合語言後再修改

之,以連結 C 語言的基礎環境,繞過保護模式的
障礙。

範例 4.20 C 語言程式範例

範例 4.21 轉換為組合語言後 (1)

範例 4.21 轉換為組合語言後
(2)

範例 4.21 轉換為組合語言後
(3)

範例 4.21 轉換為組合語言後
(4)



4
.
2
1




範例 4.21 的執行結果

在 C 語言中內嵌組合語言
內嵌組合語言
gcc 可使用 asm {…} 語法內嵌組合語言於 C 語言

當中。

範例 4.24 內嵌組合語言的 C 程式 (1)

範例 4.24 的執行過程

表格 4.1 GNU 嵌入式組合語言的限
制條件 ( 針對 IA32 處理器 )

將內嵌程式展開為組合語言

範例 4.26 將 < 範例 4.26> 的條件放
寬為 r

範例 4.27 < 範例 4.24> 與 < 範例
4.26> 的組合語言對照 (1)

範例 4.27 < 範例 4.24> 與 < 範例
4.26> 的組合語言對照 (2)

第 4 章、組譯器 ( 摘要 1)
4.1 組譯器簡介
組譯器:將組合語言轉換為機器碼

4.2 組譯器的演算法
第一階段:計算符號位址
第二階段:將指令轉為目的碼

4.3 完整的組譯範例
 陣列加總功能

第 4 章、組譯器 ( 摘要 2)
4.4 進階的組譯器功能
 Literal ( 實字 ) 、常數、 EQU, ORG, *, …

4.5 實務案例
 4.5.1

微軟的組譯工具

o 在 Visual Studio 中撰寫組合語言
 4.5.2

GNU 組譯工具

o 使用 gcc 編譯 C 程式為組合語言,並修改之
o 於 C 語言中內嵌組合語言 ( 使用 GNU 的內嵌語法 )

Sign up to vote on this title
UsefulNot useful