我正在学习x86程序集.我想知道你是如何有条件地执行子程序的.据我所知,跳转到标签不起作用,因为没有存储返回地址,因此它不知道返回的位置.
cmp bx, 0
jz zero ; how do I do this correctly ?
; do something else and exit
zero:
; do something
ret
Run Code Online (Sandbox Code Playgroud)
如果您不需要返回该地址,它就可以工作.通常情况下,您可以构建代码,以便实现这种情况.
否则,您将不得不使用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
Run Code Online (Sandbox Code Playgroud)
编辑2016-04-25:正如@Peter Cordes在评论中提到的,下面的代码可能会表现得非常糟糕.请参阅例如本文以解释原因.
@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
Run Code Online (Sandbox Code Playgroud)
它显式地在栈上推送返回地址,这样如果我们不调用函数(重新调整到栈),zero
函数就可以add esp, 4
从栈中返回或弹出value().请注意,如果希望在16位或64位模式下工作,则需要进行一些微调.
干净的方法很简单:
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
Run Code Online (Sandbox Code Playgroud)
对于 if-else 情况,我不知道更好的方法。好的,如果两个分支之后必须直接返回,你可以这样做:
cmp bx,0
jnz notzero
; handle case for zero here
ret
notzero:
; handle case for not zero here
ret
Run Code Online (Sandbox Code Playgroud)
如果某些处理必须在 ret 之前进行(例如,弹出先前推送的值),则应使用第一种方法。