assembly 在程序集中有条件地调用子例程

iih3973s  于 2022-12-04  发布在  其他
关注(0)|答案(3)|浏览(135)

我正在学习x86汇编。我想知道如何执行条件调用子例程。据我所知,跳转到标签是不起作用的,因为返回地址没有存储,因此它不知道从哪里返回。

cmp bx, 0
 jz zero ; how do I do this correctly ?
 ; do something else and exit

 zero:
 ; do something
 ret
pxiryf3j

pxiryf3j1#

简单的方法是:

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

对于if-else情况,我不知道更好的方法。好的,如果两个分支都必须在之后直接返回,可以执行以下操作:

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

notzero:
    ; handle case for not zero here
    ret

如果某些处理必须在ret之前发生(例如弹出先前推送的值),则应使用第一种方法。

uqjltbpv

uqjltbpv2#

如果你不需要返回到那个地址,它是有效的。通常你可以这样构造你的代码。
否则,你就必须使用Jxx指令来执行分支,这些指令会在调用点周围跳转,或者用其他方式来构建代码来避开这个限制。

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

2016年04月25日第二次世界大战正如@Peter Cordes在评论中提到的,下面的代码可能会表现得很糟糕。请参见this article以了解原因。*
@Manny Ds在评论中的建议启发了我写了下面的内容。它可能不会更干净或更好,但它是另一种结构方式:

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

它显式地将返回地址压入堆栈,这样zero函数就可以返回值(add esp, 4),或者如果我们不调用该函数(重新调整到堆栈),就可以从堆栈中弹出值(add esp, 4)。注意,如果你想让它在16位或64位模式下工作,你需要做一些细微的调整。

dhxwm5r4

dhxwm5r43#

我认为正确的方法是使用call指令,这相当于高级编程语言中的函数调用,PC存储在堆栈中,因此zero:子例程末尾的ret执行它应该执行的操作。

相关问题