Reverse Engineering for Beginners

(avery) #1

CHAPTER 42. STRING TO NUMBER CONVERSION (ATOI()) CHAPTER 42. STRING TO NUMBER CONVERSION (ATOI())


; exit then.
test r8b, r8b
je SHORT $LN9@my_atoi
$LL2@my_atoi:
lea edx, DWORD PTR [rax+rax4]
; EDX=RAX+RAX
4=rt+rt4=rt5
movsx eax, r8b
; EAX=input character
; load next character to R8D
movzx r8d, BYTE PTR [rcx+1]
; shift pointer in RCX to the next character:
lea rcx, QWORD PTR [rcx+1]
lea eax, DWORD PTR [rax+rdx2]
; EAX=RAX+RDX
2=input character + rt52=input character + rt*10
; correct digit by subtracting 48 (0x30 or '0')
add eax, -48 ; ffffffffffffffd0H
; was last character zero?
test r8b, r8b
; jump to loop begin, if not
jne SHORT $LL2@my_atoi
$LN9@my_atoi:
ret 0
my_atoi ENDP


A character can be loaded in two places: the first character and all subsequent characters. This is done for loop regrouping.
There is no instruction for multiplication by 10, two LEA instruction do this instead. MSVC sometimes uses the ADD
instruction with a negative constant instead of SUB. This is the case. It’s very hard to say why this is better then SUB. But
MSVC does this often.


42.1.2 Optimizing GCC 4.9.1 x64


Optimizing GCC 4.9.1 is more concise, but there is one redundant RET instruction at the end. One would be enough.


Listing 42.2: Optimizing GCC 4.9.1 x64

my_atoi:
; load input character into EDX
movsx edx, BYTE PTR [rdi]
; EAX is allocated for "rt" variable
xor eax, eax
; exit, if loaded character is null byte
test dl, dl
je .L4
.L3:
lea eax, [rax+rax4]
; EAX=RAX
5=rt5
; shift pointer to the next character:
add rdi, 1
lea eax, [rdx-48+rax
2]
; EAX=input character - 48 + RAX2 = input character - '0' + rt10
; load next character:
movsx edx, BYTE PTR [rdi]
; goto loop begin, if loaded character is not null byte
test dl, dl
jne .L3
rep ret
.L4:
rep ret


42.1.3 Optimizing Keil 6/2013 (ARM mode)


Listing 42.3: Optimizing Keil 6/2013 (ARM mode)

my_atoi PROC
; R1 will contain pointer to character
MOV r1,r0
; R0 will contain "rt" variable

Free download pdf