1. 程式人生 > >14-movesb指令和movesw指令

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

執行結果:

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

執行結果如下:

 

那有同學可能會問了,什麼時候movsb指令會讓di和si都減一呢?,不知道大家是否還記得我們之前學過的標誌暫存器EFL,在這個標誌暫存器中有一個DF標誌位,如下圖所示:

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

 

執行結果如下:

當執行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