简体   繁体   English

是否可以在没有'cmp`的情况下在汇编中使用条件跳转?

[英]Is it possible to use a conditional jump in assembly without a `cmp` first?

So I'm reading through some assembly source code for learning purposes and came across something very strange (or I may just be a newb): 所以我正在阅读一些用于学习目的的汇编源代码 ,并且遇到了一些非常奇怪的东西(或者我可能只是一个新东西):

.ver:
    mov al, [redoxfs.header + Header.version +  bx]
    mov ah, [.version + bx]
    cmp al, ah
    jne .ver_err
    inc bx
    jl .ver

So in this sub-label we have two jump instructions. 所以在这个子标签中我们有两个跳转指令。

However, about the last jump instruction jl . 但是,关于最后一次跳转指令jl Correct me if I'm wrong, but shouldn't there be a cmp before the jump since it's conditional? 如果我错了,请纠正我,但是在跳转之前不应该有cmp ,因为它是有条件的吗?

I initially thought it was based on cmp al, ah , but jne jumps if not equal anyway. 我最初认为它是基于cmp al, ah ,但如果不相等的话jne跳。

Am I missing something? 我错过了什么吗?

Consider these 3 kinds of instructions: 考虑以下3种说明:

  • All of the conditional jumps (like jne , jl , and many more) will jump based on the current setting of one or more of the bits in the FLAGS register. 所有条件跳转(如jnejl等等)都将根据FLAGS寄存器中一个或多个位的当前设置跳转。
  • Besides the cmp instruction, there are many more instructions that will modify some of these bits in the FLAGS register (like test , add , and many more). 除了cmp指令外,还有更多指令可以修改FLAGS寄存器中的某些位(如testadd等等)。
  • And then there are lots of instructions that don't modify any of the flags (like mov , push , and many more). 然后有很多指令不会修改任何标志(如movpush等等)。

Examples 例子

cmp al, ah
jne .ver_err

The jne .ver_err jumps based on the flagbits set by the most recent flags modifying instruction which is cmp al, ah in this case. jne .ver_err根据最近的标志修改指令设置的jne .ver_err跳转,这种指令在本例中是cmp al, ah

inc bx
jl .ver

The jl .ver jumps based on the flagbits set by the most recent flags modifying instruction which is inc bx in this case. jl .ver .ver基于最近的标志修改指令设置的标志位跳转,在这种情况下是inc bx

inc bx
lea si, [si+1]
jl .ver

Since this interjected lea instruction does not modify any flags, the jl .ver instruction still jumps based on the flagbits set by the inc bx instruction because that's still the most recent flags modifying instruction . 由于这个插入的lea指令不修改任何标志,因此jl .ver .ver指令仍然根据inc bx指令设置的flagbits跳转,因为它仍然是最新的标志修改指令

The jump-instructions just check the flags corresponding to the suffix. 跳转指令只检查对应于后缀的标志。 There is no need for a cmp-instruction before the jump. 在跳转之前不需要cmp指令。 In this case, The inc-instruction just increases the register, but the flags set by the cmp-instructions are tested by the jl instruction. 在这种情况下, inc-instruction只增加寄存器,但cmp指令设置的标志由jl指令测试。 The inc-instructions can set or reset flags. inc指令可以设置或重置标志。 Eg. 例如。 On overflow, the overflow flag is set. 溢出时,溢出标志置位。 Most processors implement cmp, by substracting the registers, but only write to the flags. 大多数处理器通过减去寄存器来实现cmp,但只写入标志。 So the sub-instruction sets the same flags and can also be used for a comparison. 因此子指令设置相同的标志,也可以用于比较。 Multiple branches after each other are also allowed, where the flags are rechecked by the jump-instructions. 还允许彼此之后的多个分支,其中通过跳转指令重新检查标志。

cmp eax, ecx
jl lbl_less
je lbl_equal
jg lbl_greater

You can also explicitly set flags, eg. 您还可以显式设置标志,例如。 in a called function, which can be checked later by the jump-instructions. 在被调用的函数中,稍后可以通过跳转指令来检查。

stc ;; set carry-flag

;; instructions, which not unintentionally change the carry-flag

clc ;; clear carry-flag

;; ...

jc lbl_carry_is_set ;; check and jump

In your case it does not make sence, that there is the jl-instruction, because all cases of inequality(which includes "less than") are checked by the jne-instruction, so the branch never occurs from the last line. 在你的情况下,它没有出现,有jl指令,因为所有不等式(包括“小于”)的情况都由jne-instruction检查,所以分支永远不会从最后一行发生。 Maybe there is missing something. 也许有遗漏的东西。 The jl tests if the operand of inc is negative. jl测试inc的操作数是否为负数。

This behaviour of the instructions is dependent of the processor you have, so x86 behaves differently to Arm and other processors. 指令的这种行为取决于您拥有的处理器,因此x86的行为与Arm和其他处理器的行为不同。 (In this case, I read a page of the inc instruction where there is no much detail about the flags. (A C-compiler needs to know, which flags are modified by the instructions, it can optimize int i = a - b; if(a < b) {...} to just a substraction- and a jump-instruction.) (在这种情况下,我读取了inc指令的页面 ,其中没有关于标志的详细信息。(C编译器需要知道,哪些标志被指令修改,它可以优化int i = a - b; if(a < b) {...}只是减法和跳转指令。)

You can have as many instructions as you like between the instruction that sets the flags, and the instruction thats tests them, so long as none of them affect the flags you want to test, and detailed knowledge of the instructions and/or a good reference are essential. 您可以在设置标志的指令和测试它们的指令之间拥有任意数量的指令,只要它们都不会影响您要测试的标志,并详细了解指令和/或良好的参考至关重要。

cmp eax,edx
xchg eax,edx
jne label

But you don't need a cmp instruction specifically - any instruction that sets flags can then be followed by an instruction that tests the flags. 但是你不需要专门的cmp指令 - 任何设置标志的指令都可以跟随一个测试标志的指令。 For example 例如

sub eax, edx
js label

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM