3.15. STRINGS TRIMMING
je SHORT $LN2@str_trim
cmp al, 10
jne SHORT $LN15@str_trim
$LN2@str_trim:
; the last character has a 13 or 10 code
; write zero at this place:
mov BYTE PTR [rcx], 0
; decrement address of the last character,
; so it will point to the character before the one which has just been erased:
dec rcx
lea rax, QWORD PTR [r8+rcx]
; RAX = 1 - s + address of the current last character
; thus we can determine if we reached the first character and we need to stop, if it is so
test rax, rax
jne SHORT $LL6@str_trim
$LN15@str_trim:
mov rax, rdx
ret 0
str_trim ENDP
First, MSVC inlined thestrlen()function code, because it concluded this is to be faster than the usual
strlen()work + the cost of calling it and returning from it. This is called inlining:3.11 on page 507.
The first instruction of the inlinedstrlen()is
OR RAX, 0xFFFFFFFFFFFFFFFF.
MSVC often usesORinstead ofMOV RAX, 0xFFFFFFFFFFFFFFFF, because resulting opcode is shorter.
And of course, it is equivalent: all bits are set, and a number with all bits set is− 1 in two’s complement
arithmetic:2.2 on page 452.
Why would the− 1 number be used instrlen(), one might ask. Due to optimizations, of course. Here is
the code that MSVC generated:
Listing 3.63: Inlinedstrlen()by MSVC 2013 x64
; RCX = pointer to the input string
; RAX = current string length
or rax, -1
label:
inc rax
cmp BYTE PTR [rcx+rax], 0
jne SHORT label
; RAX = string length
Try to write shorter if you want to initialize the counter at 0! OK, let’ try:
Listing 3.64: Our version ofstrlen()
; RCX = pointer to the input string
; RAX = current string length
xor rax, rax
label:
cmp byte ptr [rcx+rax], 0
jz exit
inc rax
jmp label
exit:
; RAX = string length
We failed. We have to use additionalJMPinstruction!
SowhattheMSVC2013compilerdidistomovetheINCinstructiontotheplacebeforetheactualcharacter
loading.
If the first character is 0, that’s OK,RAXis 0 at this moment, so the resulting string length is 0.
The rest in this function seems easy to understand.