Wiiiii
Wiiiii

Reputation: 13

assembly code with MOVS

As a beginner with assembly code, I'm confused with the movs. The resulting contents of the nine bytes starting at y would be (’a’,’b’,’c’,’a’,’b’,’c’,’a’,’b’,’c’), but i don't know why. I know movs is to copy from one memory to another, but how does the following code work?

1 .data
2    x: .string "abcde" # 5 characters plus a null
3    y: .space 9
4
5 .text
6 .globl _start
7 _start:
8    movl $x, %esi              #esi point to x as source
9    movl %esi, %edi            #edi point to x as destination
10   addl $3, %edi              #why we add 3 to edi?
11   movl $6, %ecx              #counter
12   rep movsb                  #what does it exactly do?
13 done:

Upvotes: 0

Views: 2018

Answers (4)

Peter Cordes
Peter Cordes

Reputation: 365667

Intel's manual is linked from https://stackoverflow.com/tags/x86/info. You will find an exact and detailed description of everything that movsb does. The direction of pointer increments depends on the "direction" flag, but the common ABIs require the direction flag to be cleared on function entry (so esi/edi are incremented, not decremented). Unless you're writing a bootloader (that should make as few assumptions as possible about initial state), you can assume that DF is cleared unless you set it yourself.

Overlapping source and dest will produce something like this. Instead of reading a d, the 4th byte read is an a that was written as the first byte. The add $3, %edi obviously sets the destination to x+3, I guess to demonstrate an overlapping copy. Better code would have been to replace the mov/add pair with one lea 3(%esi), %edi insn.

Are you sure that abcabcabc is what you found at y? That's exactly what you should find at x, with the trailing zero-byte being one that was originally there in y (not one that movs copied).


Even though rep movs's microcode implementation will use 64bit loads/stores for high performance, it does still handle the special case of closely-overlapping src and dest. (IDK about performance in this case. It might fall back to a slower version, or figure out the repeated pattern and sort of stos that.)

Upvotes: 2

enhzflep
enhzflep

Reputation: 13109

Run it in a debugger and see!

Basically, esi (source) and edi (dest) both point to the .string variable.Then edi is set to point to 3 chars past the start of the string, that is it points to the memory that holds 'd'. At this point the following is executed 6 times (in the form of the rep movsb)

  • mov 1 byte from [esi] to [edi]
  • increment esi
  • increment edi

EDIT: As pointed out by Michael - whether ESI and EDI are incremented or decremented depends on the direction-flag. If it is (already) set, the registers are decremented. /edit

So, the destination is 3 bytes in front of the source at all times. Therefore, after 3 bytes have been copied, the source now points to where the dest was before the rep movsb instruction started.

Upvotes: 1

Jester
Jester

Reputation: 58822

How the instructions work is written in the instruction set reference.

addl $3, %edi #why we add 3 to edi?

That adjusts the destination address so it points to the 4th character.

rep movsb #what does it exactly do?

Performs ecx iterations, each time copying a byte from [ds:esi] to [es:edi] and incrementing both by one (assuming direction flag is clear, which it normally is).

As such, that code is equivalent to:

for(i = 0; i < 6; i++) x[i + 3] = x[i];

This will of course copy 6 characters starting from the beginning of the string over itself offset by 3. However when i >= 3 it will read bytes already copied:

1. abcae
2. abcab
3. abcabc
4. abcabca
5. abcabcab
6. abcabcabc

Upvotes: 3

Michael
Michael

Reputation: 58507

All x86 instructions are described in Intel's manuals, so I suggest that you download them.

The description for MOVSB is:

A4    MOVSB       For legacy mode, Move byte from address
                  DS:(E)SI to ES:(E)DI. For 64-bit mode move
                  byte from address (R|E)SI to (R|E)DI.

With the following operation pseudo-code:

DEST ← SRC;

IF (Byte move)
  THEN IF DF = 0
    THEN
      (E)SI ← (E)SI + 1;
      (E)DI ← (E)DI + 1;
    ELSE
      (E)SI ← (E)SI – 1;
      (E)DI ← (E)DI – 1;
    FI;
...

And the REP prefix simply means:

Repeats a string instruction the number of times specified in the count register.

The count register in this case is ecx.

Upvotes: 2

Related Questions