任何方式来停止此汇编代码中的代码重复
Any way to stop duplication of code in this assembly code
我才刚刚开始学习x86架构的汇编语言。我正在做一些基于条件分支的练习。到目前为止,我已经介绍了 JMP、JZ 和 JNZ 指令就代码分支而言。这是练习的 link。第 5 点表示如果输入为 0
,程序就会出错。这是公平的,因为 dec eax
会导致 eax
寄存器保持 0xffffffff
。我需要解决这个问题。这是我想出的-
添加一条伪指令 add eax, 0h
只是为了检查这是否会导致 zero-flag
被设置,如果设置则跳转到代码中的某个位置,打印出所需的值并退出程序。
start:
; The program begins here:
call read_hex
add eax, 0h; my code
jz lb2; my code
mov ecx,1
lb1:
add ecx,ecx
dec eax
jnz lb1
mov eax,ecx
jmp lb3
lb2:
inc eax
call print_eax
; Exit the process:
push 0
call [ExitProcess]
lb3:
call print_eax
; Exit the process:
push 0
call [ExitProcess]
让我感到不舒服的是我在 lb2
和 lb3
中有重复的代码,我不太确定是否有任何解决方法。
start:
; The program begins here:
call read_hex
add eax, 0h; my code
jz lb2; my code
mov ecx,1
lb1:
add ecx,ecx
dec eax
jnz lb1
mov eax,ecx
jmp lb3
lb2:
inc eax
lb3:
call print_eax
; Exit the process:
push 0
call [ExitProcess]
如果您想一次保持左移一位(使用 add same,same
)循环,简化对 count=0 情况的处理,只需跳过移位循环到 mov
指令,允许您删除 jmp lb3
test eax,eax
是根据EAX是否为零来设置ZF的最佳方式。 (不是 add eax,0
)
start:
; The program begins here:
call read_hex
mov ecx,1
test eax, eax
jz no_shift
shift_loop: ; like shl ecx, eax without wrapping the shift count
add ecx,ecx
dec eax
jnz shift_loop
no_shift:
mov eax,ecx
call print_eax
; Exit the process:
push 0
call [ExitProcess]
请参阅 了解更多关于处理底部分支循环的信息,即使在循环可能需要 运行 0 次的情况下也是如此。
在您的情况下,对于 EAX=0 的情况,数据依赖于 EAX 没有任何好处。 (inc eax
)。这破坏了分支预测+该案例的推测执行的一些好处;使用 mov eax, ecx
使 EAX=1 意味着分支之后的代码可以在 EAX 的旧值准备好让分支实际检查预测之前使用 EAX。 (如果预测正确的话。)
您根本不需要为此进行任何分支。 x86 有移位指令,可以很容易地创建 1 << n
.
start:
; The program begins here:
call read_hex
xor edx, edx ; edx = 0
bts edx, eax ; edx |= 1<<eax
mov eax, edx
call print_eax
push 0
call [ExitProcess]
这比使用变量计数 shl
(在 Sandybridge 系列上为 3 微指令)甚至更有效,但包装移位计数的语义完全相同:
mov ecx, eax
mov eax, 1
shl eax, cl
如果您确实需要大输入来将位一直移出并保留零,您可以为此分支,或者您可以考虑使用 SSE2 或 MMX 整数移位,它们会使移位计数饱和而不是将其环绕。 (即 count & 0x3f
)
我才刚刚开始学习x86架构的汇编语言。我正在做一些基于条件分支的练习。到目前为止,我已经介绍了 JMP、JZ 和 JNZ 指令就代码分支而言。这是练习的 link。第 5 点表示如果输入为 0
,程序就会出错。这是公平的,因为 dec eax
会导致 eax
寄存器保持 0xffffffff
。我需要解决这个问题。这是我想出的-
添加一条伪指令 add eax, 0h
只是为了检查这是否会导致 zero-flag
被设置,如果设置则跳转到代码中的某个位置,打印出所需的值并退出程序。
start:
; The program begins here:
call read_hex
add eax, 0h; my code
jz lb2; my code
mov ecx,1
lb1:
add ecx,ecx
dec eax
jnz lb1
mov eax,ecx
jmp lb3
lb2:
inc eax
call print_eax
; Exit the process:
push 0
call [ExitProcess]
lb3:
call print_eax
; Exit the process:
push 0
call [ExitProcess]
让我感到不舒服的是我在 lb2
和 lb3
中有重复的代码,我不太确定是否有任何解决方法。
start:
; The program begins here:
call read_hex
add eax, 0h; my code
jz lb2; my code
mov ecx,1
lb1:
add ecx,ecx
dec eax
jnz lb1
mov eax,ecx
jmp lb3
lb2:
inc eax
lb3:
call print_eax
; Exit the process:
push 0
call [ExitProcess]
如果您想一次保持左移一位(使用 add same,same
)循环,简化对 count=0 情况的处理,只需跳过移位循环到 mov
指令,允许您删除 jmp lb3
test eax,eax
是根据EAX是否为零来设置ZF的最佳方式。 (不是 add eax,0
)
start:
; The program begins here:
call read_hex
mov ecx,1
test eax, eax
jz no_shift
shift_loop: ; like shl ecx, eax without wrapping the shift count
add ecx,ecx
dec eax
jnz shift_loop
no_shift:
mov eax,ecx
call print_eax
; Exit the process:
push 0
call [ExitProcess]
请参阅
在您的情况下,对于 EAX=0 的情况,数据依赖于 EAX 没有任何好处。 (inc eax
)。这破坏了分支预测+该案例的推测执行的一些好处;使用 mov eax, ecx
使 EAX=1 意味着分支之后的代码可以在 EAX 的旧值准备好让分支实际检查预测之前使用 EAX。 (如果预测正确的话。)
您根本不需要为此进行任何分支。 x86 有移位指令,可以很容易地创建 1 << n
.
start:
; The program begins here:
call read_hex
xor edx, edx ; edx = 0
bts edx, eax ; edx |= 1<<eax
mov eax, edx
call print_eax
push 0
call [ExitProcess]
这比使用变量计数 shl
(在 Sandybridge 系列上为 3 微指令)甚至更有效,但包装移位计数的语义完全相同:
mov ecx, eax
mov eax, 1
shl eax, cl
如果您确实需要大输入来将位一直移出并保留零,您可以为此分支,或者您可以考虑使用 SSE2 或 MMX 整数移位,它们会使移位计数饱和而不是将其环绕。 (即 count & 0x3f
)