开发者

call subroutines conditionally in assembly

I'm learning x86 assembly. I was wondering how you perform call a subroutine conditionally. As far as I understand, jumping to 开发者_如何学Goa 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


The clean way to do it is simply:

    cmp bx,0
    jnz notzero
    ; handle case for zero here
    jmp after_notzero
notzero:
    ; handle case for not zero here
after_notzero:
    ; continue with rest of processing

I know no better way for an if-else situation. Ok, if both branches must return directly afterward, you can do:

    cmp bx,0
    jnz notzero
    ; handle case for zero here
    ret

notzero:
    ; handle case for not zero here
    ret

If some processing must take place before the ret (e.g. popping values previously pushed), you should use the first approach.


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.


I believe the right way to do it is with the call instruction. This is equivalent to a function call in a higher programming language. The PC is stored on the stack, and therefore the ret at the end of your zero: subroutine does what it's supposed to.


if I understand correctly what you are looking for is for example if CMP yields zero then make a CALL instead of JMP. one workaround is using a temp subfunction to call the intended function

example: below program at #4 you do CMP then Jz to (made_up) label, then use that (made_up) label to call the actual function you want.

    #1 instruction xxx,xxx
    #2 instruction xxx,xxx
    #3 instruction xxx,xxx
    #4 CMP XXX , XXX 
    #5 JZ Made_up
    #6 Made_up:
    #7  call your_function
    #8 next instruction address will be pushed to stack as your return address.


    cmp xxx, xxx
    jz Made_up

    Made_UP:
        call your_Function
    ;now you will have the return address saved onto the stack to return to.

hope this helps...

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜