例如:
var1 dw 8
var2 dw 1
res dw ?
CODESEG
proc plus
pusha
mov bp,sp
mov ax, [bp 6];var1
mov bx, [bp 4];var2
add ax, bx
mov [res], ax
popa
ret 4
endp plus
start :
mov ax, @data
mov ds, ax
push [var1]
push [var2]
call plus
mov dl, [byte ptr res]
add dl,30h
mov ah,2h
int 21h
這個程序不能很好地作業,我知道它與在命令 pusha/popa 中推送和彈出 SP 有關,然后它弄亂了命令-
mov bp,sp
我的問題是,有沒有辦法在沒有 SP 的情況下使用 pusha/popa?還是我應該堅持在沒有這些命令的情況下推動和彈出?
uj5u.com熱心網友回復:
pusha不可避免地將 SP 更改 8x 2(或 32 位模式下的 8x 4)并存盤到堆疊中。如果您不喜歡,請不要使用它;無論如何它效率不高,只對代碼大小有好處。(特別是如果您不需要實際保存包括 SP 在內的所有 8 個暫存器)。例如,您可以push bx 在正常的 BP 設定之后使用,并且push ax如果您出于某種原因想要保存/恢復它,即使您的呼叫者需要立即覆寫 AX 的部分內容。
保存 BP 兩次會效率低下,但如果你真的想要,你可以 push bp// mov bp, sp,pusha所以 BP 將指向相對于回傳地址和堆疊引數的正常位置。如果您想要緩慢但簡單,那是顯而易見的方法。
或者正如 Jester 所說,在計算距離時只需考慮不同的偏移量,例如[bp 14 4]. 或者,在pusha/之后mov bp,sp,您可以add bp, 14.
(如果您可以假設 386 個功能,lea bp, [esp 14]可以替換 mov add。我仍然假設 16 位模式,所以您只會使用 16 位 BP,而不是 EBP。如果 SP 正確地零擴展為 ESP (這是個好主意),您可以完全省略幀指標,mov ax, [esp 14 4]。)
[bp 14]是回傳地址正下方的堆疊槽,因此 4 和 6 是回傳地址上方堆疊上的前兩個字,相對于指向傳統位置的幀指標,您將使用相同的偏移量。
讓 BP 不指向已保存的 BP 將破壞遵循傳統幀指標設定創建的 BP/回傳值對的鏈接串列的堆疊展開(回溯),如果這對您很重要的話。如果您始終在所有函式中執行此操作,則可以在 GDB 中使用自定義堆疊展開腳本或偏移已保存 BP 以到達下一個已保存 BP 的東西。
當然,對于您的小功能,您只需要 BP 和一個用于mov ax, [bp ...]/的臨時暫存器add ax, [bp ...],并且通常您會留下一些可以在不保存/恢復的情況下使用的呼叫破壞暫存器,這樣您就可以撰寫小功能而不會像 pusha/popa 那樣低效。保存和恢復每個函式中的所有內容都很慢。
更好的是,在暫存器中傳遞兩個引數,這樣您就不需要將它們從堆疊中取出,因此不需要設定 BP。
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/495924.html
上一篇:NASM中STOSB的分段錯誤
下一篇:GDB不從NASM加載源代碼行
