I'd like to convert an integer to a string (char *
) so I can print it - in pure aarch64.
This is what I came up with:
; adr x20, ->result // x20 = char *
; mov x14, 0 // x14 = digit counter
; mov x15, 12345 // x15 = number to convert
; mov x16, 10 // x16 = divisor
; ->divide:
; udiv x17, x15, x16 // x17 = quotient
; msub x18, x17, x16, x15 // x18 = remainder
; add x18, x18, 48 // x18 = remainder as char
; strb w18, [x20, x14] // put char in char *
; add x14, x14, 1 // x14 = digit counter
; mov x15, x17 // x16 = remaining number to convert
; cbnz x17, ->divide // repeat until quotient is zero
; ->result:
; .byte 0, 0, 0, 0, 0, 0
Values are hardcoded because I feel it as a comfortable starting point.
This is the logic I'm trying to follow:
- Divide the number by 10: the remainder is the last digit;
- Add 48 to the remainder, so I get the last digit as a ascii char;
- Write that char to a buffer (incrementally);
- Repeat until the quotient becomes zero.
However, the code immediately occurs into a segmentation fault on this instruction strb w18, [x20, x14]
.
Using gdb
, it seemed everything was correct: x18
had 53
(5
- the last digit of 12345
- + 48
).
However, I guess I still don't get how str(b)
works.
First of all, adr x20, ->result
will load the pointer to result
(a pointer to [0, 0, 0, 0, 0, 0]
, the buffer) at x20
, let's say 0x7fb697d40c
.
Then, strb w18, [x20, x14]
should take the least byte of w18
(53
in the first round) and put it at 0x7fb697d40c
+ the content of x14
(0
in the first round).
So I expect 0x7fb697d40c
to point to [53, 0, 0, 0, 0, 0]
.
However, SIGSEGV
occurs and I don't know why.
What am I missing?
Edit Here it is the source code using the usual syntax.
_start:
mov x14, #0
mov x15, #12345
mov x16, #10
adr x20, result
divide:
udiv x17, x15, x16
msub x18, x17, x16, x15
add x18, x18, #48
strb w18, [x20, x14]
add x14, x14, #1
mov x15, x17
cbnz x17, divide
result:
.byte 0, 0, 0, 0, 0, 0
Solution:
As Nate pointed out in the comments, the memory range where the code was located was not writable.
Since I didn't want to involve mprotect
to alter the permissions, I just ended up using the stack.