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