为什么 repe 和 repne 在 movsb 之前做同样的事情?

use*_*593 6 x86 assembly machine-code repeat instructions

我很快就有了一个组装测试,在准备的时候,我注意到了一些奇怪的事情。
repe movsb在 ZF=0 时重复,我被教导repe应该在 CX 不等于 0 和 ZF=1 时重复。
我做了一些测试,发现之前movsbrepreperepne指令的工作方式相同。
对此有何解释?

编辑:这是代码:

.model small
    .data
    A db   '   This     is    a    test '
    N  db  27
    .stack 10h
    .code
    mov ax,@data
    mov ds,ax
    mov es,ax
    cld
    mov al,' '
    mov cl,N
    xor ch,ch
    mov di,offset  A
    next:  repe scasb
    jcxz cont        ; jump if cx=0
    dec di
    inc cx
    xchg  si,di      ; swap between si and di
    push  cx
    push  di
    repe  movsb
    pop   di
    pop   cx
    repne scasb
    mov si,di
    jmp next
    cont: .exit
    end
Run Code Online (Sandbox Code Playgroud)

Pet*_*des 5

在机器码中,实际上只有两个不同的前缀字节。

  • 0xF3 与 MOVS/LODS/STOS/INS/OUTS(不影响标志的指令)一起使用时称为 REP
  • 0xF3 与 CMPS/SCAS 一起使用时称为 REPE 或 REPZ
  • 0xF2 与 CMPS/SCAS 一起使用时称为 REPNE 或 REPNZ,并且没有记录在其他说明中。

Intel 的insn 参考手册 REP 条目仅记录F3了 MOVS 的 REP,而不是 F2 前缀。恭喜,您已经找到了一种未公开的 REP MOVSB 编码,至少在您测试过的任何 CPU 上都是如此。:)

另请参阅NASM 手册的此附录,其中包含其他未记录的操作码,但不包含此F2 A4REPNE MOVSB。(链接自标签维基)。


通常,不影响指令的前缀会被忽略,所以我希望 REPNE MOVSB 与 MOVSB 运行相同。例如,TZCNT被编码为 REP BSF,并且在不支持 BMI1 的 CPU 上,它简单地作为 BSF 执行。(做同样的事情,除非源为零。)

类似地,REP RET 是引入填充以解决 AMD K8/K10 分支预测器限制的常见技巧,并且运行方式与 RET 相同。

但英特尔警告说,这种行为是不能保证的,因为新指令可以使用一种编码,该编码曾经是带有忽略前缀的不同指令。例如,LZCNT(编码为 REP BSR)产生与 BSR 相反的结果,因此由于某种原因包含 REP BSR 的旧代码将停止在新 CPU 上工作。

请注意,在原始 8086 上,rep mul/imul否定结果!所以从历史上看,它并不总是被完全忽略,这可能就是为什么英特尔只在向后兼容性实际上有用的情况下才记录对特定情况的忽略(例如rep nop= pause,HLE 和 BND 前缀之类的东西,以及 TZCNT = BSF for非零输入。)另请参阅我和其他关于逆向计算问答的答案。