目录
字符串你很熟悉了,我们定义了无数次了!
%macro ANNOUNCE_STRING 2 %1 db %2 %1_LEN equ $ - %1 %endmacro
当然,我们现在来学习一个比较新的定义方式,那就是跟C语言一样安插一个哨兵字符\0,它的ASCII值就是0
message DB 'I am loving it!', 0
后面我们会写一个函数叫做strlen函数!这里需要提示的就是我们的哨兵字符0会发挥最用!
字符串的指令
每个字符串指令可能需要一个源操作数,一个目标操作数或两者。对于32位段,字符串指令使用ESI和EDI寄存器分别指向源和目标操作数。但是,对于16位段,SI和DI寄存器分别用于指向源和目标。
有五个用于处理字符串的基本说明。他们是-
-
MOVS-该指令将1字节,字或双字数据从存储位置移到另一个位置。
-
LODS-该指令从存储器加载。如果操作数是一个字节,则将其加载到AL寄存器中;如果操作数是一个字,则将其加载到AX寄存器中,并将双字加载到EAX寄存器中。
-
STOS-该指令将数据从寄存器(AL,AX或EAX)存储到存储器。
-
CMPS-该指令比较内存中的两个数据项。数据可以是字节大小,字或双字。
-
SCAS-该指令将寄存器(AL,AX或EAX)的内容与内存中项目的内容进行比较。
上面的每个指令都有字节,字和双字版本,并且可以通过使用重复前缀来重复字符串指令。这些指令使用ES:DI和DS:SI对寄存器,其中DI和SI寄存器包含有效的偏移地址,这些地址指向存储在存储器中的字节。SI通常与DS(数据段)相关联,DI通常与ES(额外段)相关联。DS:SI(或ESI)和ES:DI(或EDI)寄存器分别指向源和目标操作数。假定源操作数位于内存中的DS:SI(或ESI),目标操作数位于ES:DI(或EDI)。
对于16位地址,使用SI和DI寄存器,对于32位地址,使用ESI和EDI寄存器。
基本指令 | 操作的寄存器 | 字节运算 | 字运算 | 双字运算 |
---|---|---|---|---|
MOVS | ES:DI,DS:SI | MOVSB | MOVSW | MOVSD |
LODS | DS:SI | LODSB | LODSW | LODSD |
STOS | ES:DI,AX | STOSB | STOS | STOSD |
CMPS | DS:SI,ES:DI | CMPSB | CMPSW | CMPSD |
SCAS | ES:DI,AX | SCASB | SCASW | SCASD |
movs 字符串传送
这是字符串的传送指令,我的意思是:想要知道字符串如何传送,实际上需要ees, eds, edi, esi,ecx这几个寄存器。字符串的传送比较麻烦,因为你需要提供字符串的源地址(如果很长那还需要es, ds),以及传送的长度如何。
当然,传送长度就需要请出我们的ECX作为我们的Indexer了。下面我来露一手:
; -------------------------------------------------- ; Program written in 10.21 2024 ; Author: Charlie chen ; Functionality: usage of movsb ; -------------------------------------------------- %macro ANNOUNCE_STRING 2 %1 db %2 %1_LEN equ $ - %1 %endmacro ; fast use of common value %define MY_STDOUT 1 %define MY_SYS_WRITE 4 ; print string in a simple way %macro PRINT_STRING 2 mov edx, %2 mov ecx, %1 mov ebx, MY_STDOUT mov eax, MY_SYS_WRITE int 0x80 %endmacro %macro EASY_PRINT_STRING 1 PRINT_STRING %1, %1_LEN %endmacro section .data ANNOUNCE_STRING SOURCE, {"Charliechen is handsome", 0xA} BUFFER resb SOURCE_LEN section .text global _start _start: mov ecx, SOURCE_LEN mov edi, BUFFER mov esi, SOURCE cld ; 设置我们的拷贝顺序是从左到右 rep movsb PRINT_STRING BUFFER, SOURCE_LEN mov ebx, 0 mov eax, 1 int 0x80
lods, stos使用
我们的这个指令是用来存储和加载字符串的,操作方式是对之做每一个定长大小做操作。举个例子,我们想要对每一个字符加上一个2,变成一个面目全非的字符串,我们可以这样做:
; -------------------------------------------------- ; Program written in 10.21 2024 ; Author: Charlie chen ; Functionality: usage of stosb, lodsb ; -------------------------------------------------- %macro ANNOUNCE_STRING 2 %1 db %2 %1_LEN equ $ - %1 %endmacro ; fast use of common value %define MY_STDOUT 1 %define MY_SYS_WRITE 4 %define MY_STDIN 0 %define MY_SYS_READ 3 ; print string in a simple way %macro PRINT_STRING 2 mov edx, %2 mov ecx, %1 mov ebx, MY_STDOUT mov eax, MY_SYS_WRITE int 0x80 %endmacro %macro EASY_PRINT_STRING 1 PRINT_STRING %1, %1_LEN %endmacro section .data ANNOUNCE_STRING SOURCE, {"Charliechen is handsome", 0xA} section .bss BUFFER resb SOURCE_LEN section .text global _start _start: mov ecx, SOURCE_LEN mov edi, BUFFER mov esi, SOURCE do_add: lodsb add al, 0x2 stosb loop do_add cld rep movsb PRINT_STRING BUFFER, SOURCE_LEN mov ebx, 0 mov eax, 1 int 0x80
cmpsb的使用
cmpsb是一个一个比特的比较,自动看ecx作为比较的次数。你看,这里是一个简单的比较键盘输入的两个字符串的程序
; -------------------------------------------------- ; Program written in 10.21 2024 ; Author: Charlie chen ; Functionality: usage of cmpsb ; -------------------------------------------------- %macro ANNOUNCE_STRING 2 %1 db %2 %1_LEN equ $ - %1 %endmacro ; fast use of common value %define MY_STDOUT 1 %define MY_SYS_WRITE 4 %define MY_STDIN 0 %define MY_SYS_READ 3 ; print string in a simple way %macro PRINT_STRING 2 mov edx, %2 mov ecx, %1 mov ebx, MY_STDOUT mov eax, MY_SYS_WRITE int 0x80 %endmacro %macro EASY_PRINT_STRING 1 PRINT_STRING %1, %1_LEN %endmacro %macro READ_FROM_CONSOLE 2 mov edx, %2 mov ecx, %1 mov ebx, MY_STDIN mov eax, MY_SYS_READ int 0x80 %endmacro section .data ANNOUNCE_STRING INPUT_SRC1, "Tell me your first input:> " ANNOUNCE_STRING INPUT_SRC2, "Tell me your second input:> " ANNOUNCE_STRING IS_EQUAL, {"The String is equal!",0xA} ANNOUNCE_STRING IS_NOT_EQUAL, {"The String is not equal!",0xA} section .bss SOURCE1 resb 20 SOURCE2 resb 20 section .text global _start _start: EASY_PRINT_STRING INPUT_SRC1 READ_FROM_CONSOLE SOURCE1, 20 EASY_PRINT_STRING INPUT_SRC2 READ_FROM_CONSOLE SOURCE2, 20 mov esi, SOURCE1 mov edi, SOURCE2 mov ecx, 20 cld repe cmpsb jecxz EQUAL jmp NOT_EQUAL EQUAL: EASY_PRINT_STRING IS_EQUAL jmp EXIT NOT_EQUAL: EASY_PRINT_STRING IS_NOT_EQUAL jmp EXIT EXIT: mov ebx, 0 mov eax, 1 int 0x80
SCASB的使用
SCAS指令用于搜索字符串中的特定字符或一组字符。要搜索的数据项应该在AL(对于SCASB),AX(对于SCASW)或EAX(对于SCASD)寄存器中。要搜索的字符串应在内存中,并由ES:DI(或EDI)寄存器指向。
section .text global _start ;must be declared for using gcc _start: ;tell linker entry point mov ecx,len mov edi,my_string mov al , 'e' cld repne scasb je found ; when found ; If not not then the following code mov eax,4 mov ebx,1 mov ecx,msg_notfound mov edx,len_notfound int 80h jmp exit found: mov eax,4 mov ebx,1 mov ecx,msg_found mov edx,len_found int 80h exit: mov eax,1 mov ebx,0 int 80h section .data my_string db 'hello world', 0 len equ $-my_string msg_found db 'found!', 0xa len_found equ $-msg_found msg_notfound db 'not found!' len_notfound equ $-msg_notfound标签:汇编,教程,STRING,mov,PRINT,寄存器,字符串,MY From: https://blog.csdn.net/charlie114514191/article/details/143134013