查看完整版本 : Weekend 寫個 8086 Assembler in Haskell (4):MASM

assembly.jc 2019-4-27 15:34

不知不覺這個 topic 寫左 4 個星期,上次完成左 assemble 部份,終於可以 compile d binary 出來做測試,之前說了,test 的方法是比較 Masm 和 Nasm compile 出來的 binary。

首先比較的是 MASM。但在比對過程中,發覺 MASM 的 Encoding 政策都幾混亂下,可能唔同部份由唔同 programmer 負責,中間又無人協調,結果出現不一致的情況。此話怎說呢?大家都知,一條條 assemble 的 instruction,compile 之後都會變成 binary,例如:

add al, ah

compile 之後變成: 02C4

add [bx], al

就變成: 0007

其中,
00, 02 代表 add,
C4    代表 (al, ah),
07    代表 ([bx], al)。

問題來了,當 cpu 接收到 02C4 時,它如何知道將相加的結果放回 al, 而唔係 ah 呢? 沒錯,答案是...

00, 02,點解要用 2 個 code 代表 add 呢? 原因是 02 代表將運算的結果放回 register,00 就將結果放回其他 "地方"。看看 00, 02 的 binary:

00 = 0000 0000
02 = 0000 0010         

其中,第 7 個 bit 叫做 direction bit。1 = 將運算的結果放回 register

Okay? 看看 add al, ah,再看看上面的解釋 「將運算的結果放回 register」,好明顯 ,在你我眼中,al, ah 都是 register,那又回到上面的問題,相加的結果放那裡??

答案係 al,此話怎講? 再看看

C4 = 11 000 100

所謂的 mod r/m reg,可分成三部份:

2 bit | 3 bit | 3 bit
mod | reg   |r/m   

其中
mod = mode (暫時可以不理)
reg = register
r/m = register or memory

在 cpu 眼中,在 reg 欄位才是 register,在 r/m 欄位的叫做 EA: effective address,EA 包含了 register 和 memory。Okay,在 direction bit 和 mod r/m reg 的配合下,我們終於知道將運算結果放到那裡了。現在問題是,當你 encode

add al, ah

時,到底將 al 當成 register 還是 EA 呢?如果當成 EA,那 add 就 encode 成 00,register 就 encode 成 02。其實二種方法都可行。如果將 add al, ah 一般化成

add op1, op2

那可簡化成一條簡單的規則:

當 op1 是 register 時,direction bit 就是 1,否則就是 0。

MASM 對 add 的處理就用了這規則,但當 encode cmp al, ah 時,又放棄這規則,把 al 當成 EA,ah 當成 register。但但是,cmp ax, bx 又採用返上面的規則,即 ax 當成 register,bx 當 EA。

這方面 NASM 可能做得比較好,因為就以上幾個 instructions ,我在 NASM 上測試了一下,NASM 沒有這情況,它都採取統一的規則: 當 op1, op2 都是 Register,op1 當成 EA。但 NASM 未有全面測試,要到全面測試完結才有正確的結論。

[[i] 本帖最後由 assembly.jc 於 2019-4-27 03:53 PM 編輯 [/i]]

assembly.jc 2019-5-4 15:50

終於測試完! 最終都係放棄用 MASM 做參考,改用 NASM,NASM 基本上無唔一致的地方,generate 出來的萬多 instructions 好順利咁完成比對。

但可惜的是,比對唔到 far call, jmp,即係 call, jmp 32 bit operand,因為 NASM 生成的 binary是針對 32 bit CPU 的,如:

call dword [bx]

8086 16 bit 嘅 CPU encode: FF1F,但 32 bit 嘅 CPU encode: 66 FF17,66 就是所謂 operand-size override prefix,80386 之後才有,意思是用 ebx 中的 bx 部份。
而且,FF17 唔係 FAR call,FF1F 才是,這不是 NASM 的錯,因為 32 bit 對於 32 bit 嘅 CPU 來說是 near call。就算用左 [BITS 16],結果都係一樣。我唔知有什麼方法解決,結果無試到 far call/jmp。

有興趣可看看。

[[i] 本帖最後由 assembly.jc 於 2023-10-22 03:37 編輯 [/i]]

sswroom 2019-5-4 16:08

[quote]原帖由 [i]assembly.jc[/i] 於 2019-5-4 03:50 PM 發表 [url=https://computer.discuss.com.hk/redirect.php?goto=findpost&pid=498778381&ptid=28183178][img]https://computer.discuss.com.hk/images/common/back.gif[/img][/url]
終於測試完! 最終都係放棄用 MASM 做參考,改用 NASM,NASM 基本上無唔一致的地方,generate 出來的萬多 instructions 好順利咁完成比對。

但可惜的是,比對唔到 far call, jmp,即係 call, jmp 32 bit operand,因為 NASM 生成的 binary是針對 32 bit CPU 的,如:

call dword

80 ... [/quote]REP MOVSB
REP MOVSW
這2個指令?

INT 3 = CC 還是 CD 03?

assembly.jc 2019-5-4 17:55

[quote]原帖由 [i]sswroom[/i] 於 2019-5-4 04:08 PM 發表 [url=https://computer.discuss.com.hk/redirect.php?goto=findpost&pid=498779100&ptid=28183178][img]https://computer.discuss.com.hk/images/common/back.gif[/img][/url]
REP MOVSB
REP MOVSW
這2個指令?

INT 3 = CC 還是 CD 03? [/quote]

REP LODSB
REPE CMPSB
REPZ CMPSB
REPNZ CMPSB
REPNE CMPSB
主要試 rep, repe ... prefix encoding。rep 後面的 mnemonic 應該不會影響 encoding的。

Int3 應該是 CC 的。但 NASM 出 CD 03,我跟了它...
頁: [1]
查看完整版本: Weekend 寫個 8086 Assembler in Haskell (4):MASM