String instructions do not exclusively apply only to string Data types, but are called so, because they often do.
Strings REPetition instructions are known for being slow under Intel Processors. Usually programmers tend to optimize their Coding by replacing them by other, not so slow, Instructions, doing 'by hand' what these Strings Instructions are supposed to do. Do not be afraid of slowing down your Applications with these. This is not our job, as programmers, to take care of Intel Processors speed. AMD Strings Instructions are perfectly effective and fast. So, if your Applications slow down, because of Intel, this is not your problem. This is Intel's problem. RosAsm itself is at least 4 times slower under Intel equivalent Processors, and I don't feel, in any manner, concerned with this.
Lodsb / Lodsw / Lodsd (LODSB)
Read a Byte / Word / Dword at the address pointed by ESI register, store the content encoded value in AL / AX / EAX and increment ESI, according with the chosen Data size.
[StringData: 'abcd', 0]
mov esi StringData | lodsb ; al = 'a'
lodsb ; al = 'b'
lodsb ; al = 'c'
Lodsb does the same as:
mov al B$esi | inc esi
lodsd does the same as:
mov eax D$esi | add esi 4
Std / Cld (STD CLD)
The default behavior of the String Instructions is to work forward, but you can have them working backward with STD instruction (Set Direction Flag on).
[String: B$ 'abcdefg' EndOfString: 0]
mov esi EndOfString
lodsb ; al = 0
lodsb ; al = 'g'
lodsb ; al = 'f'
lodsb ; al = 'e'
CLD (Clear Direction Flag) resets the flag to zero. You have to consider this flag state (Off) as the default one, and to indent STD / CLD nested instructions (consider unpairing a disastrous fault with these instructions of the same gravity you would consider as with PUSH / POP unpairing...).
Stosb / Stosw / Stosd (STOSB)
Just do the reverse of Lodsb, ... operations. They store Bytes, Words, Dwords given in AL / AX / EAX at the location pointed by EDI and increase / decrease EDI according with the Data size and Direction Flag.
mov edi PointsString
mov al 'a' | stosb
mov al 'b' | stosb
mov al 'c' | stosb
; Now, the Memory at PointsString is: 'abc.......'
The REPetition Instruction(s) gives all the desirable power to String Instructions. It can be extended with condition markers: REPE (repeat while Equal), REPNE (Repeat while Not Equal), and so on.
REP repeats attached instruction ECX times.
[Table: B$ ? #100]
mov edi Table | mov ecx 90 | mov al 'x' | rep stosb
; 'Table' Memory is 'xxxxxxxxxxx............' (90 'x')
; Searching for the end of Table String:
mov edi Table | mov al 0 | mov ecx 100 | repne scasb
; (edi now point to the second first zero in Table).
Movsb / Movsw / Movsd (MOVSB)
Movsb reads a byte at ESI and writes this byte at EDI. Then, it increases ESI and EDI. Movsb does the same as a paired Lodsb / Stosb, but AL / AX / EAX registers are not modified.
[String1: 'abcde' String1Length: Len]
[String2: B$ 0 #100]
mov esi String1 | mov edi String2 | mov ecx D$String1Lenght | rep movsb
; Now, The Memory at String2 is: 'abcde', 0 0 0 0 ...
Cmpsb / Cmpsw / Cmpsd (CMPSB)
... Compare(s) the byte(s) at EDI with the byte(s) at ESI and increments ESI and EDI. The Flags' status are set according with the result of the comparison, (to be tested with Conditional JMPs):.
[String1: 'abcde' 0]
[String2: 'abcde' 0]
mov esi String1 | mov edi String2 | mov ecx 5
repe cmpsb | je Same
; If here, the strings were different
Same: ; If here, the strings were same.
Scasb / Scasw / Scasd (SCASB)
Is (are) used to search at EDI for a given value previously stored in AL (AX, EAX). Let us end this Chapter with a real life example. Screen Savers are run by Zindoz with a Command Line that can have several forms. This Command Line could be, for examples:
'S' and 'P' are to define in what mode the Saver is expected to run (S > Saver mode / P > Preview mode, ...). When the line is ended by a decimal ASCII number, this number is the Handle of the caller (The Screen Savers installer main window Handle). We are going to retrieve these parameters :
call 'KERNEL32.GetModuleHandleA' 0 | mov D$hInstance eax
call 'KERNEL32.GetCommandLineA' | mov D$CommandLine eax
; Go to the end of Command Line:
mov edi eax, al 0, ecx 0FF | repne scasb | sub edi 2 | mov esi edi
; After ''repne scasb'', EDI points to the character following the ending zero.
; We get back 2 characters so that:
; EDI now points to either '6' or 'S' in each upper Command Lines examples.
mov eax 0, ecx 0
L0: On B$esi-1 < '0', jmp L1> ; Search for the start of
On B$esi-1 > '9', jmp L1> ; possible Decimal number Handle.
L1: push esi ; esi > either '1' or 'P' in upper example.
On al > '9', jmp L9> ; Compute possible Handle
On al < '0', jmp L9>
sub al '0' ; convert Decimal to binary:
lea ecx D$ecx+ecx*4 ; ecx = ecx * 5
lea ecx D$eax+ecx*2 ; ecx = eax + old ecx * 10
L9: pop esi
; If the Command Line was our first example, ecx = 1176 and al = 'P'.
; If the Command Line was our second example, ecx = 0 and al = 'S'.