標籤:資料拷貝 src 空格 offset 區分 公眾號 copy ng2 style
十八、字串處理
前文介紹過字串的處理,字串是byte類型 的數組,現在實現一段代碼,將字串string1資料copy到字串string2中
代碼如下
.datastring1 byte "Hello World!", 0string2 byte 12 dup(?), 0 .codemov ecx, 12mov ebx,0.repeatmov al, string1[ebx]mov string2[ebx], alinc ebx.untilcxz
通過ecx遞減,將字串string1每個字元一次copy給string2中,其中用到了ebx基底位址暫存器。
也可以通過esi和edi寄存器
.datastring1 byte "Hello World!"stirng2 byte 12 dup(?), 0 .codemov ecx,12lea esi, string1lea edi, string2.repeatmov al,[esi]mov [edi],alinc ediinc esi.untilcxz
這些代碼可以通過字串操作的其他指令替代,使代碼更簡潔
1 movsb指令
movsb是字串移動指令,將esi指向的字元移動到edi指向的空間,並且將ecx減1,寄存器esi和edi內容增加1或者減少1
如果僅僅使用movsb指令作用不大,配合迴圈使用,功能很強大。cld指令表示方向標誌值清0,調用movsb會使esi和edi內容增加1
std指令表示設定方向標誌值,調用movsb會使esi和edi內容減少1
還是上面的需求,這次使用movsb完成目標
mov ecx,12 ; 字串大小為12mov esi, offset string1 ; esi指向string1起始位置mov edi, offset string2 ; edi指向string2起始位置cld ; cld指令調用後 ,調用movsb會使esi和edi分別加1.repeat movsb ; 先將esi指向的空間資料拷貝到edi指向的空間 ; 然後esi和edi分別加1,並且ecx值減少1.untilcxz
和movsb配合使用的幾個首碼:
rep 重複操作,等於迴圈,直到ecx為0退出迴圈
repe 如果相等,則重複操作,如果不等,那麼退出迴圈,或者ecx為0退出迴圈
repne 不相等,則重複操作,相等則退出迴圈,或者ecx為0退出迴圈
上面的代碼可以使用 rep movsb更改,完成同樣的目的
mov ecx, 12lea esi, string1lea edi, string2cldrep movsb ;迴圈直到ecx為0結束
2 scasb指令
scasb指令用於在edi寄存器指定的空間中搜尋al所儲存的字元。scasb指令操作流程為:將要查詢的字元放入al寄存器中,
如果要在字串string中尋找匹配的字元,那麼將edi儲存string的首地址,調用scasb進行匹配,scasb指令調用後會將edi
儲存數值加1,並且ecx值-1,為了完成字串string中逐個字元匹配,需要在scasb前面加上repne指令,這樣在不相等時繼續
尋找,直到尋找到指定字元退出迴圈。此時edi指向的位置為字串string中匹配字元位置的下一個位置。
舉例實現:
.dataname1 byte "Abe Lincoln".codemov al, ‘ ‘ ; 在al寄存器中儲存空格,為了在name1中尋找該空格mov ecx, lengthof name1 ;ecx儲存name1字串長度,為11lea edi, name1 ;edi指向name1首地址repne scasb ;匹配edi指向空間的字元和空格是否相等,不相等則edi加1 ;ecx減1,直到相等或者ecx為0退出迴圈
運行後ecx為7,edi執行字元L的位置
如下:
3 stosb指令
stosb用於把寄存器al儲存的資料放入寄存器edi所指向的空間,指令完成後edi增加1
stosb等價於:
mov [edi],al
inc edi
4 lodsb指令
lodsb用於把寄存器esi所指向的空間資料儲存到al寄存器中,指令完成後esi增加1
lodsb等價於:
mov al, [esi]
inc esi
下面實現將字串姓名倒置功能,並將名字和姓中間添加字元“ ”和“,”
如“Abe Lincoln”變為“Lincoln, Abe”
.dataname1 byte "Abe Lincoln"name2 byte 12 dup (?) .codemov al, ‘‘mov ecx, lengthof name1lea edi, name1repne scasbpush ecxmov esi, edilea edi, name2rep movsbmov al, ‘ ‘stosb mov al, ‘ ‘stosbmov ecx, lengthof name2pop eaxsub ecx, eaxdec ecxlea esi , name1rep movsb
5 cmpsb指令
字串比較指令,該指令和movsb差不多,比較edi和esi指向空間資料大小,並且edi和esi增加1或者減少1,
可通過cld或std設定,並且ecx減少1
比較“James” 和 “James”
代碼如下:
.dataname1 byte "James"name2 byte "James".codemov ecx, lengthof name1lea esi, name1lea edi, name2cldrepe cmpsb
相等情況下ecx為0,edi和esi都指向字串最後一個字元的下一個位置
如果比較的字元為“James”和“Jamie”,那麼效果如下:
如果比較字元為“Marci”和“Marcy”,那麼上述代碼就沒辦法區分是否相等了,因為此時ecx也為0
如果ecx大於0,那麼兩個字串肯定不相等的,如果ecx為0,那麼將esi和edi都-1,得到最後一個元素,
再將esi和edi指向空間的資料比較即可。
下面將上述代碼完善一下,比較兩個長度相等的字串name1和name2
mov ecx, lengthof name1lea esi, name1lea edi, name2cld repe cmpsb.if ecx > 0;輸出不相等.else dec esi dec edi mov al, [esi] .if al != [edi] ; 輸出不相等 .else ;輸出相等 .endif.endif
十九、字串總結
1 movsb 指令將寄存器esi指向的位元組類型字串的內容移動到寄存器edi指向的位置,通過cld或std設定esi和edi增加還是減少
2 cmpsb 指令對寄存器的esi指向的字串中的一個字元和edi所指向的一個字元進行比較,通過cld或std設定esi和edi增加還是減少
3 movsb指令前邊的rep首碼會讓該指令重複執行,迴圈次數等於ecx的值,每一次迴圈ecx的值減1,直到為0停止。
4 cmpsb指令前面的repe首碼的作用類似於rep首碼,當ecx為0是,停止執行指令。或者當esi和edi所指向的兩個空間的位元組內容不同,迴圈也會停止。
repne當esi和edi所指向的兩個空間的位元組內容相同時,停止。
5 scasb指令將一個字串進行搜尋,尋找字串中是否存在寄存器al中所儲存的字元。如果找到該字元,那麼edi指向的地址比該字元的地址靠後一個位元組。
stosb將al寄存器的內容儲存在edi所指向的字串的位置中。lodsb指令將把寄存器esi所指向的字串的位置中的字元複製到al寄存器中。
我的公眾號,謝謝關註:
組合語言學習筆記(六)