簡體   English   中英

segment:以常數偏移

[英]segment:offset in a constant

我正在嘗試學習匯編。 我已經編寫了這個簡短的實模式函數,該函數可以按我的意願工作。

getndrives:
        push    bx
        push    es
        push    si
            mov     bx,0040h
            mov     es,bx
            mov     si,0075h
            mov     al,byte [es:si]
        pop     si
        pop     es
        pop     bx
    ret

我想將segment:offset設置為常量,而無需推送/彈出es + si。 就像是

biosmem EQU 0040h:0075h
mov al,[biosmem]

上面的代碼可以編譯,但不會返回預期的結果。

x86沒有一種方法可以在一條指令中從立即數常量指針加載。 有一個很遠的jmp ptr16:16可以將cs:ip設置為32位立即數,但是對於負載,我看不到任何不使用段寄存器的選項。


NASM文檔建議在16位調用約定中將DS保留為通話是很常見的,但出於您的確切原因, ES可以被認為是呼叫擁擠的(在內存模型中,不能將所有內容保存在單段)。

因此,您可以考慮對該函數使用調用約定,以使其能夠破壞ES (如果您的代碼僅需要在386或更高版本上運行,則為FSGS 。)

您也可以通過對段重復使用相同的寄存器來保存指令。 您可能兩次都使用了si而不是bx ,因為一旦設置es ,就完成了bx

getndrives:
 ;; return in AL (zero-extended to AX; the upper byte of 0040h happens to be 0)
 ;; clobbers: AH, ES
    mov     ax, 0x0040
    mov     es, ax
    mov     al, [es:0x0475]
    ret

另外,您需要加載到AL中,以便它可以使用mov的特殊moffs編碼來跳過ModR / M字節,因此它只是(ES段覆蓋前綴)+ A0 75 04

當然,如果需要,您仍然可以在此周圍推/彈出es和/或ax ,但這顯然比較笨拙。 並且,如果您要保存/恢復段寄存器,@ Fifoernik指出,最好在DS上保存mov前綴(除非您有任何假定DS保持不變的中斷處理程序)。

getndrives:
 ;; return in AL (zero-extended to AX; the upper byte of 0040h happens to be 0)
 ;; clobbers: AH,  or nothing if you uncomment the push/pop of AX
    push    es
    ;push    ax                 ; you might as well use a reg other than AX to simplify this, if you do want to preserve AH, too.  And also for performance on CPUs that don't rename low8 partial regs separately, so mov al,[mem] has a dependency on the pop.
      mov     ax, 0x0040
      mov     es, ax            ; or use DS if you don't need it in any interrupt handler
    ;pop     ax
      mov     al, [es:0x0475]
    pop     es
    ret

如果你只關心186,更新, push 0040h / pop es將避免重挫啊。 (8086沒有push imm8/imm16 )。


在您的情況下,您可能可以避免一開始就修改段寄存器 注意, 0040h:0075h是的線性地址0475h ,這可以用只是一個從任何偏移訪問DS從值047h (在實模式下, linear = (segment << 4) + offset ,即左移一位十六進制數字)。

在DS = 0的情況下,您仍然可以訪問引導扇區代碼/數據( 根據此PC內存映射 ,加載於07C0:0 ,又稱為0:7C00 )以及低64kB內存中的任何其他位置。

我實際上並沒有編寫16位代碼,所以我不確定您如何告訴NASM您將要設置DS=0 ,然后使其相應地生成偏移量。 但是希望這是可能的。

另外,它節省了代碼大小: xor ax,ax小於mov ax, imm16 但是我想如果您要優化代碼大小,則可以push 0 / pop ds (但是8086沒有后push imm )。 而且我猜想,如果您希望堆棧指針與其他指針兼容,則需要mov ss, ax / mov sp, whatever等等,這需要更多代碼。

但是無論如何,您的函數將如下所示。

getndrives:
 ;; return in AL
 ;; requires/assumes: DS=0
    mov     al, [0x0475]
    ret

在這一點上使其發揮作用是愚蠢的。 將其設為宏,或者更好,或者%define BIOS_BDA_ndrives 0x0475以便您可以執行諸如add dl, [BIOS_BDA_ndrives] 或者可能是%define BIOS_BDA_ndrives byte [0x0475]以進行構建時類型檢查,例如mov ax, BIOS_BDA_ndrives將無法以操作數大小不匹配的方式進行組裝。

地址的段部分始終使用段寄存器。 您可以使用常數作為偏移量。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM