14-movesb指令和movesw指令

1. movesb指令

movsb可以理解为 move string byte,即字节传送指令。

 

来看一个示例,汇编代码如下:

mov ax,0x0050
mov es,ax

mov ax,0x07C0
mov ds,ax

jmp near Code

;把这5个数据复制到起始地址0x00500的位置
Data:
db 0xAA,0x11,0x22,0x33,0x44


Code:
mov al,byte[ds:Data+0]
mov byte[es:0],al


mov al,byte[ds:Data+1]
mov byte[es:1],al

mov al,byte[ds:Data+2]
mov byte[es:2],al

mov al,byte[ds:Data+3]
mov byte[es:3],al

mov al,byte[ds:Data+4]
mov byte[es:4],al

End:
jmp near End

times 510-($-$$) db 0x00
db 0x55,0xAA

如果你已经看完了前面的文章,那么这个程序对你来说很容易理解,上面这段代码的作用是将0xAA,0x11,0x22,0x33,0x44这几个数据复制到0x00500内存地址的位置,但是这个程序有很多重复性的代码,有同学可能会说可以用loop指令来代替做这些重复的工作

mov ax,0x07C0
mov ds,ax

jmp near Code

;把这5个数据复制到起始地址0x00500的位置
Data:
db 0xAA,0x11,0x22,0x33,0x44


Code:
mov ax,0x0050
mov es,ax	     ;目标地址段寄存器初始化
mov di,0+4	     ;目标地址段偏移寄存器初始化

mov ax,0x07c0
mov ds,ax	      ;源地址段寄存器初始化
mov si,Data+4         ;源地址段偏移寄存器初始化


mov cx,Code-Data      ;循环次数(移动次数)


StartMove:
mov al, byte[ds:si]
mov byte[es:di],al
dec si
dec di
loop StartMove	      ;循环体定义了移动的方向和每次移动的字节

End:
jmp near End

times 510-($-$$) db 0x00
db 0x55,0xAA

这段代码可以理解为:

  1. 初始化数据的原始内存地址。
  2. 初始化数据的目标内存地址。
  3. 初始化数据的移动次数。
  4. 初始化移动的方向。

 

即便是使用loop指令,上面的代码还是没有简化很多。在我们汇编指令中有一个指令,它的作用就是专业负责,把一个地方的内存数据,复制到另外一个地方,那就是movsb指令。

给出的汇编代码如下:

mov ax,0x07C0
mov ds,ax

jmp near Code

;把这5个数据复制到起始地址0x00500的位置
Data:
db 0xAA,0x11,0x22,0x33,0x44

Code:
mov ax,0x0050
mov es,ax	       ;目标地址段寄存器初始化
mov di,0	       ;目标地址段偏移寄存器初始化

mov ax,0x07c0
mov ds,ax	       ;源地址段寄存器初始化
mov si,Data            ;源地址段偏移寄存器初始化

movsb                  ;通过movsb指令复制

End:
jmp near End

times 510-($-$$) db 0x00
db 0x55,0xAA

执行结果:

14-movesb指令和movesw指令_第1张图片

movsb这条指令编译后,在内部中实际上变成了movsb byte ptr es:[di], byte ptr ds:[si]了,这条指令的意思就是从源地址中复制一个字节数据到目的地址,其中es:[di]表示目的内存地址,而ds:[si]表示源内存地址,寄存器ES和寄存器DS就说明了这一点。

 

需要注意的是movsb指令每次执行完成之后,di和si都会加1或者减1,也就是说你可以多次执行movsb指令复制数据,例如更改代码为:

movsb   ;执行5次movsb指令
movsb
movsb
movsb
movsb

执行结果如下:

14-movesb指令和movesw指令_第2张图片

 

那有同学可能会问了,什么时候movsb指令会让di和si都减一呢?,不知道大家是否还记得我们之前学过的标志寄存器EFL,在这个标志寄存器中有一个DF标志位,如下图所示:

14-movesb指令和movesw指令_第3张图片

DF标志位是一个方向标志,顾名思义,当DF标志位=0的时候,movsb指令执行完成之后, di和si就会加1。当DF标志位=1的时候,movsb指令执行完成之后, di和si就会减1。可以使用cld和std指令来设置DF标志寄存器的值,cld会设置DF标志位的值为0,std会设置DF标志位的值为1。

修改代码:

std		;设置DF标志位为1
movsb           ;通过movsb指令复制
movsb
movsb
movsb
movsb

 

执行结果如下:

14-movesb指令和movesw指令_第4张图片

当执行std指令时,就会把DF标志位的值修改为1。

 

以上的代码还是可以继续优化的,例如当有大量的数据时每次都要重复执行movsb指令,如果还是按照之前的方法的话,就会出现大量的重复代码,因此我们可以使用rep movsb指令,这条指令的作用是,只要寄存器CX不为0,就会重复执行movsb指令,直到CX等于0为止。

 

最终的汇编代码如下:

mov ax,0x07C0
mov ds,ax

jmp near Code

;把这5个数据复制到起始地址0x00500的位置
Data:
db 0xAA,0x11,0x22,0x33,0x44

Code:
mov ax,0x0050
mov es,ax	       ;目标地址段寄存器初始化
mov di,0+4	       ;目标地址段偏移寄存器初始化

mov ax,0x07c0
mov ds,ax	       ;源地址段寄存器初始化
mov si,Data+4          ;源地址段偏移寄存器初始化

mov cx,Code-Data
std	               ;设置DF标志位的值为1
rep movsb	       ;如果CX不为0就重复执行movsb指令

End:
jmp near End

times 510-($-$$) db 0x00
db 0x55,0xAA

 

2. movsw指令

学会了movsb指令,那么对于movsw指令就可以举一反三了,movsw的意思是mov string word ,字传送指令。配合cx寄存器和rep movsw这个指令,也可以实现批量复制。执行完movsw或者rep movsw指令,si和di的值会增加2,或者减少2,这取决于DF标志位的值是1还是0。

下面直接给出代码:

jmp near Code 
Data:
db 0xAA,0x11,0x22,0x33,0x44,0x55

Code:
mov ax,0x0050
mov es,ax		;目标地址段寄存器初始化
mov di,0		;目标地址偏移寄存器初始化

mov ax,0x07C0
mov ds,ax		;原始地址段寄存器初始化
mov si,Data		;原始地址偏移寄存器初始化

mov cx,(Code-Data)/2
rep movsw		;一次性复制一个字,即两个字节的数据

End:
jmp near End

times 510-($-$$) db 0x00
db 0x55,0xAA 

 

你可能感兴趣的:(汇编修炼心法)