任何方式来停止此汇编代码中的代码重复

Any way to stop duplication of code in this assembly code

我才刚刚开始学习x86架构的汇编语言。我正在做一些基于条件分支的练习。到目前为止,我已经介绍了 JMPJZJNZ 指令就代码分支而言。这是练习的 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]

让我感到不舒服的是我在 lb2lb3 中有重复的代码,我不太确定是否有任何解决方法。

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