I'm learning x86 assembly. I was wondering how you perform call a subroutine conditionally. As far as I understand, jumping to a label doesn't work because the return address is not stored and therefore it does not know where to return.
cmp bx, 0
jz zero ; how do I do this correctly ?
; do something else and exit
zero:
; do something
ret
Well it works if you don't need to return to that address. Often times you can structure your code such that this is the case.
Otherwise you'll have to do the branching with Jxx
instructions that jump around the call site or in other ways structure your code around this limitation. In this case inverting the test should work:
cmp bx, 0
jnz not_zero
call zero
; fall through here, return or do what you want
not_zero:
; do something else and exit
; ...
ret
zero:
; do something
ret
EDIT 2016-04-25: As @Peter Cordes mentions in the comments, the below code will probably perform terribly. See e.g. this article for an explanation why.
@Manny Ds suggestion in the comments inspired me to write the following. It might not be cleaner or better, but it's another way to structure it:
push back_from_zero ; Push where we want to return after possibly branching to 'zero'
cmp bx, 0
jz zero ; branch if bx==0
add esp, 4 ; adjust stack in case we didn't branch
back_from_zero: ; returning from the zero branch here or continuing from above
; do something else and exit
zero:
; do something
ret
It explicitly pushes the return address on the stack so the zero
function can return or pops the value (add esp, 4
) from the stack if we don't call the function (to readjust to stack). Note that you need to do some slight adjustments if you want this to work in either 16- or 64-bit mode.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With