MOVS汇编代码

时间:2015-11-16 11:58:20

标签: assembly x86

作为汇编代码的初学者,我对movs很困惑。从y开始的九个字节的结果内容将是('a','b','c','a','b','c','a','b','c'),但我不知道为什么。我知道movs是从一个内存复制到另一个内存,但以下代码如何工作?

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:

4 个答案:

答案 0 :(得分:3)

指令的工作原理写在指令集参考中。

  

addl $ 3,%edi #why我们将3添加到edi?

调整目标地址,使其指向第4个字符。

  

rep movsb#究竟是做什么的?

执行ecx次迭代,每次将一个字节从[ds:esi]复制到[es:edi]并将两者递增(假设方向标志是清除的,通常是这样)。

因此,该代码相当于:

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

这当然会复制从字符串开头开始的6个字符,而不是3。但是当i >= 3它将读取已复制的字节时:

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

答案 1 :(得分:2)

英特尔手册与https://stackoverflow.com/tags/x86/info相关联。您将找到movsb所做的所有事情的准确而详细的描述。指针增量的方向取决于&#34;方向&#34;标志,但是公共ABI要求在函数入口上清除方向标志(因此esi / edi递增,不递减)。除非您正在编写引导加载程序(应该尽可能少地假设初始状态),否则您可以假设DF被清除,除非您自己设置它。

重叠的source和dest会生成这样的东西。读取的第4个字节不是读取d,而是写为第一个字节的aadd $3, %edi显然将目的地设置为x+3,我猜是要展示重叠的副本。更好的代码就是用mov/add insn替换lea 3(%esi), %edi对。

您确定abcabcabc是您在y找到的内容吗?这正是您应该在x找到的内容,尾随的零字节是y中最初的那个(不是movs复制的那个)。

即使rep movs的微代码实现将使用64位加载/存储以获得高性能,它仍然可以处理紧密重叠的src和dest的特殊情况。 (在这种情况下IDK关于性能。它可能会回落到较慢的版本,或者找出重复的模式和stos的那种。)

答案 2 :(得分:2)

Intel's manuals中描述了所有x86指令,因此我建议您下载它们。

MOVSB的说明是:

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.

使用以下操作伪代码:

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;
...

REP前缀仅表示:

  

在计数寄存器中指定的次数重复字符串指令。

在这种情况下,计数寄存器为ecx

答案 3 :(得分:1)

在调试器中运行它,看看!

基本上,esi(source)和edi(dest)都指向.string变量。然后将edi设置为指向超过字符串开头的3个字符,即它指向保存的内存'D'。 此时,以下执行6次(以rep movsb

的形式
  • 从[esi]到[edi]
  • 移动1个字节
  • 增量esi
  • 增加edi

编辑:正如Michael指出的那样 - ESI和EDI是递增还是递减取决于direction-flag。如果(已)设置,则寄存器递减。 /编辑

因此,目标始终位于源前3个字节。因此,在复制了3个字节之后,源现在指向dest在rep movsb指令开始之前的位置。