为什么 repe 和 repne 在 movsb 之前做同样的事情?
why do repe and repne do the same before movsb?
我马上要进行组装测试,在准备的过程中,我发现了一些奇怪的事情。
repe movsb
在 ZF=0 时重复,我被告知 repe
应该在 CX 不等于零且 ZF=1 时重复。
我做了一些测试,发现在 movsb
之前,rep
、repe
和 repne
指令工作相同。
对此有何解释?
编辑:
这是代码:
.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
rep
和 repe
具有相同的操作码; rep
对INS、OUTS、MOVS、LODS、STOS指令有效; repe
/repne
对 CMPS 和 SCAS 指令有效(它们会影响零标志)。
因为他们的操作码相同,所以repe
自然就和rep
一样;从技术上讲,您不能在 MOVS 指令前使用 repne
,尽管处理器似乎将其视为与 rep
相同(至少在您尝试过的处理器上)。
TL;DR: repne movsb
是一个 invalid/undocumented 指令,所有的赌注都关闭了。你不应该依赖它。 repe movsb
在技术上是无效的,但您的汇编程序将其编码为 rep movsb
。
在机器码中,其实只有两个不同的前缀字节。
0xF3
与 MOVS/LODS/STOS/INS/OUTS 一起使用时称为 REP(不影响标志的指令)
0xF3
与 CMPS/SCAS 一起使用时称为 REPE 或 REPZ
0xF2
在与 CMPS/SCAS 一起使用时被称为 REPNE 或 REPNZ,并且没有记录其他指令。
Intel 的 insn reference manual REP entry 仅记录 F3
REP 的 MOVS,而不是 F2 前缀。恭喜,您找到了 REP MOVSB 的未记录编码,至少在您测试过的 CPU 上是这样。 :)
另请参阅 this appendix of the NASM manual which includes other undocumented opcodes, but not this F2 A4
REPNE MOVSB. (linked from the x86 标签 wiki)。
通常情况下,不影响指令的前缀会被忽略,所以我希望 REPNE MOVSB 到 运行 与仅 MOVSB 相同。例如TZCNT 被编码为 REP BSF,在不支持 BMI1 的 CPUs 上,它简单地执行为 BSF。 (做同样的事情,除非源为零。)
同样,REP RET是引入padding的常用技巧to work around a limitation of AMD K8/K10 branch predictors,运行与RET相同
但英特尔警告说,这种行为并不能保证,因为新指令可以使用一种编码,而这种编码曾经是带有忽略前缀的不同指令。例如LZCNT(编码为 REP BSR)产生与 BSR 相反的结果,因此由于某种原因包含 REP BSR 的旧代码将停止在新的 CPUs 上工作。
请注意,在原始 8086 上,rep mul/imul
negates the result!! So historically it hasn't always been completely ignored, and that's probably why Intel only ever documents the ignoring for specific cases when the backwards-compatibility is actually useful (like rep nop
= pause
, stuff like HLE and BND prefixes, as well as TZCNT = BSF for non-zero inputs.) See also my and other answers on a retrocomputing Q&A。
我马上要进行组装测试,在准备的过程中,我发现了一些奇怪的事情。
repe movsb
在 ZF=0 时重复,我被告知 repe
应该在 CX 不等于零且 ZF=1 时重复。
我做了一些测试,发现在 movsb
之前,rep
、repe
和 repne
指令工作相同。
对此有何解释?
编辑: 这是代码:
.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
rep
和 repe
具有相同的操作码; rep
对INS、OUTS、MOVS、LODS、STOS指令有效; repe
/repne
对 CMPS 和 SCAS 指令有效(它们会影响零标志)。
因为他们的操作码相同,所以repe
自然就和rep
一样;从技术上讲,您不能在 MOVS 指令前使用 repne
,尽管处理器似乎将其视为与 rep
相同(至少在您尝试过的处理器上)。
TL;DR: repne movsb
是一个 invalid/undocumented 指令,所有的赌注都关闭了。你不应该依赖它。 repe movsb
在技术上是无效的,但您的汇编程序将其编码为 rep movsb
。
在机器码中,其实只有两个不同的前缀字节。
0xF3
与 MOVS/LODS/STOS/INS/OUTS 一起使用时称为 REP(不影响标志的指令)0xF3
与 CMPS/SCAS 一起使用时称为 REPE 或 REPZ
0xF2
在与 CMPS/SCAS 一起使用时被称为 REPNE 或 REPNZ,并且没有记录其他指令。
Intel 的 insn reference manual REP entry 仅记录 F3
REP 的 MOVS,而不是 F2 前缀。恭喜,您找到了 REP MOVSB 的未记录编码,至少在您测试过的 CPU 上是这样。 :)
另请参阅 this appendix of the NASM manual which includes other undocumented opcodes, but not this F2 A4
REPNE MOVSB. (linked from the x86 标签 wiki)。
通常情况下,不影响指令的前缀会被忽略,所以我希望 REPNE MOVSB 到 运行 与仅 MOVSB 相同。例如TZCNT 被编码为 REP BSF,在不支持 BMI1 的 CPUs 上,它简单地执行为 BSF。 (做同样的事情,除非源为零。)
同样,REP RET是引入padding的常用技巧to work around a limitation of AMD K8/K10 branch predictors,运行与RET相同
但英特尔警告说,这种行为并不能保证,因为新指令可以使用一种编码,而这种编码曾经是带有忽略前缀的不同指令。例如LZCNT(编码为 REP BSR)产生与 BSR 相反的结果,因此由于某种原因包含 REP BSR 的旧代码将停止在新的 CPUs 上工作。
请注意,在原始 8086 上,rep mul/imul
negates the result!! So historically it hasn't always been completely ignored, and that's probably why Intel only ever documents the ignoring for specific cases when the backwards-compatibility is actually useful (like rep nop
= pause
, stuff like HLE and BND prefixes, as well as TZCNT = BSF for non-zero inputs.) See also my and other answers on a retrocomputing Q&A。