Reputation: 13
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
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
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
)
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
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
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