为什么跳转签名指令相反地起作用

时间:2019-05-16 15:39:26

标签: assembly x86 masm flags

我知道,如果设置了标志标志,js指令将被跳转。我想做一个比较数组中每个元素并计算差异的过程 两个元素的总和小于5。

CountMatch proc
    push ebp
    mov ebp, esp
    push esi
    push edi
    mov ecx, [ebp + 12]; length of arrays
    mov esi, [ebp + 20]; address of array1
    mov edi, [ebp + 16]; address of array2

CHKMATCH :
    mov eax, [esi]
    sub eax, [edi]
    jns ELSEloop    ;this line is problem
    neg eax
    cmp eax,5
    ja CONTINUE
    inc count
    jmp CONTINUE
ELSEloop:
    cmp eax,5
    ja CONTINUE
    inc count

CONTINUE :
    add esi, 4
    add edi, 4
    loop CHKMATCH

    mov eax, count
    call writeint
    call crlf
    pop edi
    pop esi
    pop ebp
    ret 16
CountMatch endp

程序正在运行CHKMATCH循环时,它可能会正确运行,因为如果差异为负,则会设置符号标志。因此可以将其取反并与5进行比较。但是它不起作用,因此我将其更改为jns。 在调试模式下,我找不到符号标志,但可以看到PL标志。

1 个答案:

答案 0 :(得分:1)

您发布的代码是正确的;我不知道您为什么首先想到了js

请注意,这样做会更简单:

    mov eax, [esi]
    sub eax, [edi]      ;eax = difference maybe (if it didn't overflow)
    jns NOT_NEGATIVE    ;If difference is not negative (sign flag not set), don't negate
    neg eax             ;Difference was negative, so negate it to make it positive
NOT_NEGATIVE:
    cmp eax,5
    ja CONTINUE
    inc count
CONTINUE:

也;您说(在问题的描述中)“计算两个元素之差是否小于5”,而代码实际上执行“计算两个元素之差小于或等于5”。根据您的实际需求,可能需要使用jae CONTINUE(或其同义词jnb CONTINUE)。

最后,将count保留在寄存器中(例如,可能保留在edx中可能更快);如果这样做,使用类似以下的技巧来避免分支可能更快:

NOT_NEGATIVE:
    cmp eax,5          ;Set carry flag if difference < 5
    adc edx,0          ;Add carry flag to count
CONTINUE:

在这种情况下,您还可以通过在各处交换mov eax,counteax来摆脱edx;也许吧:

CountMatch proc
    push ebp
    mov ebp, esp
    push esi
    push edi
    mov ecx, [ebp + 12]   ; length of arrays
    mov esi, [ebp + 20]   ; address of array1
    mov edi, [ebp + 16]   ; address of array2
    xor eax,eax           ; eax = count = 0

CHKMATCH :
    mov edx, [esi]
    sub edx, [edi]      ;edx = difference maybe (if it didn't overflow)
    jns NOT_NEGATIVE    ;If difference is not negative (sign flag not set), don't negate
    neg edx             ;Difference was negative, so negate it to make it positive
NOT_NEGATIVE:
    cmp edx,5          ;Set carry flag if difference < 5
    adc eax,0          ;Add carry flag to count
CONTINUE:
    add esi, 4
    add edi, 4
    loop CHKMATCH

    ; eax = count already

    call writeint
    call crlf
    pop edi
    pop esi
    pop ebp
    ret 16
CountMatch endp