在開發我的匯編程式時,我遇到了一個問題。在匯編語言中,我們可以定義資料值(例如msg db 'Hi')并將此資料的地址粘貼到任何地方,甚至在此資料之上。然而,當匯編代碼時,匯編器不知道資料的地址,直到沒有處理這些資料的行。
當然,匯編器可以記住機器代碼的地址,我們使用定義資料的地址,并在處理代碼后將記住的地址中的值替換為我們資料的地址。但是,如果我們在 2 位元組地址(例如在 01 F1)中定義資料,則匯編器會將記住地址中的 1 個位元組替換為 2 個位元組的地址(01 F1),因此立即欄位大小將更改(imm8 -> imm16)和匯編程式應在同一地址重寫指令(更改操作碼中的位 w 和 s,并可能設定前綴 0x66)。如果匯編器將設定前綴 0x66 并且我們的資料定義在此指令之后,則應重寫立即欄位位元組(增量地址值)。
此演算法的說明:
以下代碼:
mov dh, 09h
add dx, msg
;...
msg db 'Hello$'
將按照以下原則組裝:
- 準備代碼:
Comment : |===> Remember address of this byte (0x0004)
Comment : | ADD DX,MSG |
Address : 0000 0001 |0002 0003 0004| ... 01F1 01F2 01F3 01F4 01F5 01F6
Code : B4 09 | 83 C2 00 | ... 48 65 6C 6C 6F 24
Comment : ---------------- H e l l o $
- 在記住的地址中重寫代碼:
Comment : |=============|-This address (msg)
Comment : | ADD DX,01F1 | v
Address : 0000 0001 |0002 0003 0004 0005| ... 01F2 01F3 01F4 01F5 01F6 01F7
Code : B4 09 | 83 C2 F1 01 | ... 48 65 6C 6C 6F 24
Comment : --------------------- H e l l o $
- 重寫指令的操作碼
83h -> 81h(10000011b -> 10000001b:位s=0):
Comment : |=============|-This address (msg)
Comment : | ADD DX,01F1 | v
Address : 0000 0001 |0002 0003 0004 0005| ... 01F2 01F3 01F4 01F5 01F6 01F7
Code : B4 09 | 81 C2 F1 01 | ... 48 65 6C 6C 6F 24
Comment : --------------------- H e l l o $
- 將資料的新地址 (
0x01F2)寫入立即數欄位:
Comment : |=============|-This address (msg)
Comment : | ADD DX,01F2 | v
Address : 0000 0001 |0002 0003 0004 0005| ... 01F2 01F3 01F4 01F5 01F6 01F7
Code : B4 09 | 81 C2 F2 01 | ... 48 65 6C 6C 6F 24
Comment : --------------------- H e l l o $
我認為這個演算法很難。是否可以簡化它?
uj5u.com熱心網友回復:
如果匯編器不發出平面二進制檔案(即也是聯結器),則匯編器必須假設符號地址可能是 2 個位元組,因為在匯編器完成后,直到鏈接時間才會知道最終絕對地址. (因此它只會為 2 位元組地址和聯結器的重定位留出空間來填充它)。
但是,如果您直接組裝成平面二進制檔案并想要進行此優化,大概您會將其視為具有小開始演算法的分支位移并進行多遍優化,直到一切都適合為止。 實際上,您可以將其作為查看jmp/jcc rel8vs.的相同傳遞的一部分來執行jmp/jcc rel16。(為什么分支位移的“開始小”演算法不是最佳的? - 如果您沒有類似的東西align 8,它是最佳的,否則在某些極端情況下它可以但不是最佳的。)
這些優化程序只是在代表代碼的內部資料結構上回圈,而不是在每一步實際撰寫最終的機器代碼。 直到最后一次優化通過之后,才需要計算或查找實際的操作碼和 ModRM 編碼。
您只需要您的優化器知道指令大小的規則,例如add reg, imm83 位元組,add reg, imm164 位元組(AX 除外,其中 AXadd ax, imm16具有 3 位元組特殊編碼,與 相同add ax, imm8,因此添加到 AX 不需要成為多遍優化,它可以在我們知道所有符號地址后到達它時選擇一種編碼。)
請注意,使用地址作為立即數更為常見,因為mov它根本不允許使用窄立即數(mov reg, imm16始終為 3 個位元組)。但是這種優化對于尋址模式中的 disp8 與 disp16 也是相關的,例如,xor cl, [di msg]對于小地址可以使用 reg disp8,因此值得進行這種優化。
同樣,您的優化器通過會知道[di disp8]在 ModRM 之后需要 1 個位元組,[di disp16]需要 2 個額外的位元組。
并且[msg]總是在 ModRM 之后占用 2 個位元組,沒有[disp8]編碼。如果 asm 源想要對小地址利用 disp8,則它需要有一個歸零的暫存器。
當然,一個簡單的或一次性的匯編程式總是可以假設地址是 16 位的,并相應地對機器代碼的其他部分進行編碼,只有在看到未決議的符號時才回傳填充數字地址。(或者在最后發出重定位資訊供聯結器執行。)
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/352224.html
