Assembly 带MOVS的汇编代码

Assembly 带MOVS的汇编代码,assembly,x86,Assembly,X86,作为汇编代码的初学者,我对MOV感到困惑。从y开始的九个字节的结果内容是('a','b','c','a','b','c','a','b','c'),但我不知道为什么。我知道MOV是从一个内存复制到另一个内存,但是下面的代码是如何工作的 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

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

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:

英特尔的手册链接自。您将找到
movsb
所做的一切的准确详细描述。指针增量的方向取决于“方向”标志,但通用ABI要求在函数输入时清除方向标志(因此esi/edi是递增的,而不是递减的)。除非您正在编写引导加载程序(应该尽可能少地假设初始状态),否则您可以假设DF已清除,除非您自己设置它

重叠的source和dest将产生类似的结果。读取的第4个字节不是
d
,而是作为第一个字节写入的
a
add$3,%edi
显然将目的地设置为
x+3
,我想这是为了演示重叠副本。更好的代码是将
mov/add
对替换为一个
lea3(%esi),%edi
insn

您确定
abcabc
就是您在
y
找到的吗?这正是您应该在
x
中找到的,尾随的零字节是
y
中最初存在的字节(而不是
movs
复制的字节)



尽管
rep movs
的微码实现将使用64位加载/存储来实现高性能,但它仍然能够处理src和dest紧密重叠的特殊情况。(IDK关于本例中的性能。它可能会退回到较慢的版本,或者找出重复的模式和排序。

中描述了所有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美元,edi#为什么我们在edi中增加3美元

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

rep movsb#它到底有什么作用

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

因此,该代码相当于:

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

在调试器中运行它,然后查看

基本上,esi(source)和edi(dest)都指向
.string
变量。然后将edi设置为指向字符串开头后的3个字符,即指向保存“d”的内存。 此时将执行6次以下操作(以
rep movsb
的形式)

  • 从[esi]到[edi]的mov 1字节
  • 增量esi
  • 增量edi
编辑:正如Michael指出的那样-ESI和EDI是递增还是递减取决于方向标志。如果已设置,则寄存器递减/编辑


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

dest上的好捕捉是
x
,而不是
y
。结果就是书中所说的。我不确定这本书是对是错。这本书是错的,
y
处的9个字节将是最后一个
abc
和6个字节的零。作为唯一提到方向标志值依赖性的人,你的答案似乎有点不受欢迎。imho,你的观点非常重要。作为唯一提到在调试器中运行它的人,你的答案似乎有点不受欢迎为了记录在案,我还提到了方向旗。只要它是6次,它应该是abcabc而不是abcabc,对吗?@wiiii-不太对。您忘了考虑目标在源前面3个字节这一事实。因此,您将获得前3个字节“abc”,然后再获得另外6个字节“abcabc”。在调试器中运行这种类型的练习是非常有用的时间开销。
1. abcae
2. abcab
3. abcabc
4. abcabca
5. abcabcab
6. abcabcabc