Assembly 部件自动跳到下一个标签

Assembly 部件自动跳到下一个标签,assembly,x86,x86-64,Assembly,X86,X86 64,我在汇编中编写了一个程序,如下所示: %macro print 1 push rbp mov rdi, %1 xor rax, rax call _printf pop rbp %endmacro section .data e db 'Equal', 0 l db 'Less than', 0 g db 'Greater than', 0 section .text global start

我在汇编中编写了一个程序,如下所示:

%macro print 1

    push rbp

    mov rdi, %1
    xor rax, rax

    call _printf

    pop rbp

%endmacro    
section .data
    e db 'Equal', 0
    l db 'Less than', 0
    g db 'Greater than', 0
section .text
        global start
        extern _printf
    start:
        mov rax, 5
        mov rbx, 5
        cmp rax, rbx ; Compare 4 and 5
        je _equal ; je = jump if equal
        cmp rax, rbx
        jl _less ; jl = jump if less
        cmp rax, rbx
        jg _greater ; jg = jump if greater

        ret

_equal:
    print e
_less:
    print l
_greater:
    print g

但当我运行程序时,它跳到
\u equal
,然后跳到
\u less
\u greer
。如何禁用此自动跳转功能?

您需要在每个案例(打印宏展开)后添加跳转指令。它只是在跳转,而不是跳转。

您需要在每种情况下(打印宏展开)后放置跳转指令。它只是掉下来,不是跳

这是一种写
mov-eax,5
的低效方法。如果只将32位值移动到64位寄存器中,则不需要将64位寄存器指定为操作数。只需指定32位寄存器,然后

同样的事情:

您只需编写异或eax、eax,并让上面的32位隐式归零

因为您知道只比较32位值,所以可以编写
cmp eax、ebx
来只比较32位下半部。这是更小和更有效的。如果您确实想要比较这些寄存器中的整个64位值,则只需要
cmp-rax,rbx

当然,整个代码有点傻,因为您已经知道4和5的比较结果——这不需要在运行时执行

但是让我们假设这些是运行时值,您确实需要进行比较。您仍然只需要进行一次比较。所以这个代码:

可简化为:

因为条件跳转指令不会改变标志

但当我运行程序时,它跳到
\u equal
,然后跳到
\u less
\u greer
。如何禁用此自动跳跃

正如在评论和另一个答案中已经指出的,它实际上并没有跳过任何指令,因为它并没有跳过任何指令。这只是下一个标签

正如user3344003建议的那样,防止这种情况发生的一种方法是在每种情况后添加一条无条件跳转指令。比如:

    cmp rax, rbx
    je  _equal
    jl  _less
    jg  _greater
finished:
    ret

_equal:
    print e
    jmp   finished
_less:
    print l
    jmp   finished
_greater:
    print g
    jmp   finished
事实上,你所做的只是跳回去。单个
ret
指令的大小比
jmp
指令小,而且效率更高,因为不需要执行分支。只有在返回之前需要运行一堆清理代码时,才能使用此模式。在这种简单的情况下,您可以执行以下操作:

    cmp rax, rbx
    je  _equal
    jl  _less
    jg  _greater

_equal:
    print e
    ret
_less:
    print l
    ret
_greater:
    print g
    ret
注意,我在
jg
指令之后省略了
ret
。你不需要它相等,更少,和更大,详尽地覆盖每一种可能性,所以三个分支中的一个保证被采用。事实上,这意味着您可以重新排列代码以消除其中一个分支,利用最初让您感到困惑的漏洞:

    cmp rax, rbx
    jl  _less
    jg  _greater

    ; fall through to 'equal' case
    print e
    ret

_less:
    print l
    ret

_greater:
    print g
    ret
有趣的事实:

这是一种写
mov-eax,5
的低效方法。如果只将32位值移动到64位寄存器中,则不需要将64位寄存器指定为操作数。只需指定32位寄存器,然后

同样的事情:

您只需编写异或eax、eax,并让上面的32位隐式归零

因为您知道只比较32位值,所以可以编写
cmp eax、ebx
来只比较32位下半部。这是更小和更有效的。如果您确实想要比较这些寄存器中的整个64位值,则只需要
cmp-rax,rbx

当然,整个代码有点傻,因为您已经知道4和5的比较结果——这不需要在运行时执行

但是让我们假设这些是运行时值,您确实需要进行比较。您仍然只需要进行一次比较。所以这个代码:

可简化为:

因为条件跳转指令不会改变标志

但当我运行程序时,它跳到
\u equal
,然后跳到
\u less
\u greer
。如何禁用此自动跳跃

正如在评论和另一个答案中已经指出的,它实际上并没有跳过任何指令,因为它并没有跳过任何指令。这只是下一个标签

正如user3344003建议的那样,防止这种情况发生的一种方法是在每种情况后添加一条无条件跳转指令。比如:

    cmp rax, rbx
    je  _equal
    jl  _less
    jg  _greater
finished:
    ret

_equal:
    print e
    jmp   finished
_less:
    print l
    jmp   finished
_greater:
    print g
    jmp   finished
事实上,你所做的只是跳回去。单个
ret
指令的大小比
jmp
指令小,而且效率更高,因为不需要执行分支。只有在返回之前需要运行一堆清理代码时,才能使用此模式。在这种简单的情况下,您可以执行以下操作:

    cmp rax, rbx
    je  _equal
    jl  _less
    jg  _greater

_equal:
    print e
    ret
_less:
    print l
    ret
_greater:
    print g
    ret
注意,我在
jg
指令之后省略了
ret
。你不需要它相等,更少,和更大,详尽地覆盖每一种可能性,所以三个分支中的一个保证被采用。事实上,这意味着您可以重新排列代码以消除其中一个分支,利用最初让您感到困惑的漏洞:

    cmp rax, rbx
    jl  _less
    jg  _greater

    ; fall through to 'equal' case
    print e
    ret

_less:
    print l
    ret

_greater:
    print g
    ret

有趣的事实:。

当然,除非另有说明,否则cpu将继续执行下一条指令。您可以通过添加一个显式跳转来“禁用”它,以跳过您不需要的部分。它还可以从
mov-rax,5
自动跳转到
mov-rbx,5
,同样的事情。在
print e
之后,您希望代码做什么?跳转到退出标签。当然,除非另有说明,否则cpu将继续执行下一条指令。您可以通过添加一个显式跳转来“禁用”它,以跳过不需要的部分。它还可以从
mov-rax,5
自动跳转到
mov-rbx,5
,同样的事情。在
print e
之后,您希望代码做什么?跳转到退出标签。或者更好,因为这三种情况都使用不同的数据调用相同的函数,根据比较选择数据,然后仅使用
print
宏onc
    cmp rax, rbx
    je  _equal
    jl  _less
    jg  _greater

_equal:
    print e
    ret
_less:
    print l
    ret
_greater:
    print g
    ret
    cmp rax, rbx
    jl  _less
    jg  _greater

    ; fall through to 'equal' case
    print e
    ret

_less:
    print l
    ret

_greater:
    print g
    ret