for example:
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
this procedure won't work as well and I understood it has something to do with pushing and popping SP in the command pusha/popa and then it messes up the command-
mov bp,sp
and my question is, is there a way to use pusha/popa without SP? or should I stick to pushing and popping without those commands?
CodePudding user response:
pusha
unavoidably changes SP by 8x 2 (or 8x 4 in 32-bit mode) and stores to the stack. If you don't like that, don't use it; it's not efficient anyway, only good for code size. (Especially if you don't need to actually save all 8 registers including SP). e.g. you could use push bx
after a normal BP setup, and also push ax
if you want to save/restore it for some reason, even though your caller needs to overwrite parts of AX right away.
It would be inefficient to save BP twice, but you could push bp
/ mov bp, sp
/ pusha
if you really want, so BP would be pointing to the normal position relative to the return address and stack args. If you want slow but simplistic, that's the obvious way to do it.
Or as Jester says, simply account for the different offset when calculating the distance, like [bp 14 4]
. Or, after pusha
/ mov bp,sp
, you could add bp, 14
.
(If you could assume 386 features, lea bp, [esp 14]
could replace the mov add. I'm still assuming 16-bit mode, so you're only going to use 16-bit BP, not EBP. If SP is correctly zero-extended into ESP (which is a good idea), you could omit the frame pointer entirely, mov ax, [esp 14 4]
.)
Of course for your tiny function, you only need BP and one temp register for mov ax, [bp ...]
/ add ax, [bp ...]
, and normally you leave some call-clobbered registers you can use without saving/restoring so you can write small functions without the inefficiency of pusha/popa. Saving and restoring everything in every function is slow.
Even better, pass two args in registers so you don't need to set up BP to get them off the stack.