CHAPTER 15. SIMPLE C-STRINGS PROCESSING CHAPTER 15. SIMPLE C-STRINGS PROCESSING
Almost the same as what we saw before, with the exception that thestr−eos− 1 expression can be computed not at the
function’s end, but right in the body of the loop. The-EQ suffix, as we may recall, implies that the instruction executes
only if the operands in theCMPthat was executed before were equal to each other. Thus, ifR0contains 0, bothSUBEQ
instructions executes and result is left in theR0register.
ARM64
Optimizing GCC (Linaro) 4.9
my_strlen:
mov x1, x0
; X1 is now temporary pointer (eos), acting like cursor
.L58:
; load byte from X1 to W2, increment X1 (post-index)
ldrb w2, [x1],1
; Compare and Branch if NonZero: compare W2 with 0, jump to .L58 if it is not
cbnz w2, .L58
; calculate difference between initial pointer in X0 and current address in X1
sub x0, x1, x0
; decrement lowest 32-bit of result
sub w0, w0, #1
ret
The algorithm is the same as in15.1.1 on page 190: find a zero byte, calculate the difference between the pointers and
decrement the result by 1. Some comments were added by the author of this book.
The only thing worth noting is that our example is somewhat wrong:my_strlen()returns 32-bitint, while it has to return
size_tor another 64-bit type.
The reason is that, theoretically,strlen()can be called for a huge blocks in memory that exceeds 4GB, so it must able
to return a 64-bit value on 64-bit platforms. Because of my mistake, the lastSUBinstruction operates on a 32-bit part of
register, while the penultimateSUBinstruction works on full the 64-bit register (it calculates the difference between the
pointers). It’s my mistake, it is better to leave it as is, as an example of how the code could look like in such case.
Non-optimizing GCC (Linaro) 4.9
my_strlen:
; function prologue
sub sp, sp, #32
; first argument (str) will be stored in [sp,8]
str x0, [sp,8]
ldr x0, [sp,8]
; copy "str" to "eos" variable
str x0, [sp,24]
nop
.L62:
; eos++
ldr x0, [sp,24] ; load "eos" to X0
add x1, x0, 1 ; increment X0
str x1, [sp,24] ; save X0 to "eos"
; load byte from memory at address in X0 to W0
ldrb w0, [x0]
; is it zero? (WZR is the 32-bit register always contain zero)
cmp w0, wzr
; jump if not zero (Branch Not Equal)
bne .L62
; zero byte found. now calculate difference.
; load "eos" to X1
ldr x1, [sp,24]
; load "str" to X0
ldr x0, [sp,8]
; calculate difference
sub x0, x1, x0
; decrement result
sub w0, w0, #1
; function epilogue