why do repe and repne do the same before movsb?
Asked Answered
H

2

6

I have an assembly test soon, and while preparing, I noticed something strange.
repe movsb was repeating while ZF=0, and I was teached that repe should repeat while CX not equal to zero and while ZF=1.
I did some testing and discovered that before movsb, the rep, repe, and repne instructions work the same.
What is the explanation for this?

edit: here is the code:

.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
Heavyarmed answered 24/10, 2016 at 13:17 Comment(2)
Can you show code that exhibits this phenomenon? Note that repe and repne do not depend on the initial state of zf as zf is immediately set by the first iteration.Rejoinder
I understand that, but movsb does not affect the zero flag.Heavyarmed
M
5

In the machine code, there are actually only two different prefix bytes.

  • 0xF3 is called REP when used with MOVS/LODS/STOS/INS/OUTS (instructions which don't affect flags)
  • 0xF3 is called REPE or REPZ when used with CMPS/SCAS
  • 0xF2 is called REPNE or REPNZ when used with CMPS/SCAS, and is not documented for other instructions.

Intel's insn reference manual REP entry only documents F3 REP for MOVS, not the F2 prefix. Congratulations, you've found an undocumented encoding for REP MOVSB, at least on whatever CPU you tested this on. :)

See also this appendix of the NASM manual which includes other undocumented opcodes, but not this F2 A4 REPNE MOVSB. (linked from the tag wiki).


Normally, prefixes which don't affect an instruction are ignored, so I would have expected REPNE MOVSB to run identically to just MOVSB. e.g. TZCNT is encoded as REP BSF, and on CPUs which don't support BMI1, it simple executes as BSF. (Doing the same thing except when the source is zero.)

Similarly, REP RET is a common trick to introduce padding to work around a limitation of AMD K8/K10 branch predictors, and runs the same as RET.

But Intel cautions that this behaviour is not guaranteed, because new instructions can use an encoding that used to be a different instruction with an ignored prefix. e.g. LZCNT (encoded as REP BSR) produces the opposite result to BSR, so old code that included a REP BSR for some reason would stop working on new CPUs.

Note that on original 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.

Mond answered 24/10, 2016 at 13:42 Comment(5)
thank you for your answer. I did not write this code, I guess that it just a mistake in TASM and in the old test. I should probably ask the teacher about it to get relevant answer for my testHeavyarmed
@user7064593: Oh, I see the repe lodsb in the code you posted. Yes, that seems like a mistake in the code. I don't see it as a mistake in TASM, though. REPE will always assemble to F3. In assembly language, I wouldn't expect an error message, although that might be a good idea for an assembler. (You can always get the machine code you want with a DB directive to assemble bytes directly into the output file, so having the assembler do more checks and reject undocumented combinations of prefix and instruction would at worst stop make someone encode some stuff manually)Mond
@user7064593: I didn't try to understand the code, since that wasn't the point of the question, but perhaps it's trying to use repe movsb as a conditional load? (i.e. like cmove al, [si] but also checking that CX!=0). If so, that's doomed to failure if the ZF check matters. :/ Given all the push/pop and the xchg setup it does, repe lodsb is probably not even the most efficient way to do that, even if it did check ZF.)Mond
it was supposed to be movsb instead of lodsb, I changed it for checking what was wrong and forgot to fix it. I think that it just a mistake in the test, even though my teacher never mentioned that movsb cannot come after rep. She said that after rep will come a string instruction, and apparently that not cmpletly true.Heavyarmed
@user7064593: movsb cannot come after rep, no that's wrong. REP MOVSB is valid (first bullet point of my answer), and implements memcpy(di, si, cx). The only thing that's weird is REPE MOVSB. (And in case I confused you with that stuff about REP BSF, that just tells the assembler to emit an F3 byte before your BSF instruction. It doesn't mean it works as a repeat prefix for other instructions. Your teacher is correct in the sense that it only has the repeat effect if followed by a string instruction. In other uses it's either ignored or is part of the opcode for a different insn.Mond
G
4

rep and repe have the same opcode; rep is valid for the INS, OUTS, MOVS, LODS, and STOS instructions; repe/repne is valid for CMPS and SCAS instructions (which do affect the zero flag).

Because their opcodes are the same, repe is just the same as rep naturally; technically, you can't use repne in front of MOVS instructions, though it seems like the processor just treats it the same as rep (at least on the processor you tried).

TL;DR: repne movsb is an invalid/undocumented instruction and all bets are off. You shouldn't rely on it. repe movsb is technically invalid but your assembler encodes it exactly as rep movsb.

Source.

Genu answered 24/10, 2016 at 13:40 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.