本篇介绍下汇编中的字符串。
C语言中定义字符串是会以"\0"结束,汇编中不会这样,只要是一块连续的内存,都可以认为是字符串。 下面是一段操作字符串的代码:
; move_strings.asm
%macro prnt 2
mov rax, 1 ; 1 = write
mov rdi, 1 ; 1 = to stdout
mov rsi, %1
mov rdx, %2
syscall
mov rax, 1
mov rdi, 1
mov rsi, NL
mov rdx, 1
syscall
%endmacro
section .data
length equ 95
NL db 0xa
string1 db "my_string of ASCII:"
string2 db 10,"my_string of zeros:"
string3 db 10,"my_string of ones:"
string4 db 10,"again my_string of ASCII:"
string5 db 10,"copy my_string to other_string:"
string6 db 10,"reverse copy my_string to other_string:"
section .bss
my_string resb length
other_string resb length
section .text
global main
main:
push rbp
mov rbp, rsp
;-----------------------------------------------------------------------
;fill the string with printable ascii characters
prnt string1,18
mov rax,32
mov rdi,my_string
mov rcx, length
str_loop1: mov byte[rdi], al ; the simple method
inc rdi
inc al
loop str_loop1
prnt my_string,length
;-----------------------------------------------------------------------
;fill the string with ascii 0's
prnt string2,20
mov rax,48
mov rdi,my_string
mov rcx, length
str_loop2: stosb ; no inc rdi needed anymore
loop str_loop2
prnt my_string,length
;-----------------------------------------------------------------------
;fill the string with ascii 1's
prnt string3,19
mov rax, 49
mov rdi,my_string
mov rcx, length
rep stosb ; no inc rdi and no loop needed anymore
prnt my_string,length
;-----------------------------------------------------------------------
;fill the string again with printable ascii characters
prnt string4,26
mov rax,32
mov rdi,my_string
mov rcx, length
str_loop3: mov byte[rdi], al ; the simple method
inc rdi
inc al
loop str_loop3
prnt my_string,length
;-----------------------------------------------------------------------
;copy my_string to other_string
prnt string5,32
mov rsi,my_string ;rsi source
mov rdi,other_string ;rdi destination
mov rcx, length
rep movsb
prnt other_string,length
;-----------------------------------------------------------------------
;reverse copy my_string to other_string
prnt string6,40
mov rax, 48 ;clear other_string
mov rdi,other_string
mov rcx, length
rep stosb
lea rsi,[my_string+length-4]
lea rdi,[other_string+length]
mov rcx, 27 ;copy only ten characters
std ;std sets DF, cld clears DF
rep movsb
prnt other_string,length
leave
ret
结果如下:
ngs$ ./move_strings
my_string of ASCII
!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
my_string of zeros:
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
my_string of ones:
11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
again my_string of ASCII:
!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
copy my_string to other_string:
!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
reverse copy my_string to other_string:
000000000000000000000000000000000000000000000000000000000000000000000abcdefghijklmnopqrstuvwxyz
stosb 用于循环赋值,每次一个字节,rcx中存放次数,rax存放源,rdi存放目的地址,每次循环rdi会自动增加1。 movsb 也是循环赋值,每次一个字节,rcx中存放次数,rsi存放源,rdi存放目的地址,每次rsi,rdi会增加1,如果设置DF标记,会每次减1。 再看一个比较字符串的例子:
; strings.asm
extern printf
section .data
string1 db "This is the 1st string.",10,0
string2 db "This is the 2nd string.",10,0
strlen2 equ $-string2-2
string21 db "Comparing strings: The strings do not differ.",10,0
string22 db "Comparing strings: The strings differ, "
db "starting at position: %d.",10,0
string3 db "The quick brown fox jumps over the lazy dog.",0
strlen3 equ $-string3-2
string33 db "Now look at this string: %s",10,0
string4 db "z",0
string44 db "The character '%s' was found at position: %d.",10,0
string45 db "The character '%s' was not found.",10,0
string46 db "Scanning for the character '%s'.",10,0
section .bss
section .text
global main
main:
push rbp
mov rbp,rsp
; print the 2 strings
xor rax,rax
mov rdi, string1
call printf
mov rdi, string2
call printf
; compare 2 strings ------------------------------------------------------------------------------
lea rdi,[string1]
lea rsi,[string2]
mov rdx, strlen2
call compare1
cmp rax,0
jnz not_equal1
;strings are equal, print
mov rdi, string21
call printf
jmp otherversion
;strings are not equal, print
not_equal1:
mov rdi, string22
mov rsi, rax
xor rax,rax
call printf
; compare 2 strings, other verstion -----------------------------------------------------
otherversion:
lea rdi,[string1]
lea rsi,[string2]
mov rdx, strlen2
call compare2
cmp rax,0
jnz not_equal2
;strings are equal, print
mov rdi, string21
call printf
jmp scanning
;strings are not equal, print
not_equal2:
mov rdi, string22
mov rsi, rax
xor rax,rax
call printf
; scan for a character in a string ---------------------------------------------------------------
; first print the string
mov rdi,string33
mov rsi,string3
xor rax,rax
call printf
; then print the search argument, can only be 1 character
mov rdi,string46
mov rsi,string4
xor rax,rax
call printf
scanning:
lea rdi,[string3] ; string
lea rsi,[string4] ; search argument
mov rdx, strlen3
call cscan
cmp rax,0
jz char_not_found
;character found, print
mov rdi,string44
mov rsi,string4
mov rdx,rax
xor rax,rax
call printf
jmp exit
;character not found, print
char_not_found:
mov rdi,string45
mov rsi,string4
xor rax,rax
call printf
exit:
leave
ret
; FUNCTIONS ======================================================================================
; function compare 2 strings ---------------------------------------------------------------------
compare1: mov rcx, rdx
cld
cmpr: cmpsb
jne notequal
loop cmpr
xor rax,rax
ret
notequal: mov rax, strlen2
dec rcx ;compute position
sub rax,rcx ;compute position
ret
xor rax,rax
ret
;------------------------------------------------------------------------------
; function compare 2 strings ---------------------------------------------------------------------
compare2: mov rcx, rdx
cld
repe cmpsb
je equal2
mov rax, strlen2
sub rax,rcx ;compute position
ret
equal2: xor rax,rax
ret
;------------------------------------------------------------------------------
;function scan a string for a character
cscan: mov rcx, rdx
lodsb
cld
repne scasb
jne char_notfound
mov rax, strlen3
sub rax,rcx ;compute position
ret
char_notfound: xor rax,rax
ret
结果如下:
./strings
This is the 1st string.
This is the 2nd string.
Comparing strings: The strings differ, starting at position: 13.
Comparing strings: The strings differ, starting at position: 13.
Now look at this string: The quick brown fox jumps over the lazy dog.
Scanning for the character 'z'.
The character 'z' was found at position: 38
comsb用来比较rsi,rdi指向需要比较的字符串地址,结果会存放到ZF标记中,如果是1表示相等,0则反之, 需要借助loop 才能比较ecx指定的长度。 repe(repeat while equal), repne(repeat while not equal),借助comsb,scasb就可以查找字符串了。