Start page1 page2 page3 page4 page5 page6 page7 page8 page9 page10
We can, of course, define subroutines in Arm64. A subroutine needs a starting address, mostly some parameters, a way to return a result, and a return address.
To do all this we need a few things.
bl
. The b
is
the same as the branch instruction, and the l
is
for assigning the return address to the link register, lr
,
which is just another name for x30
.ret
takes whatever is in the link register,
lr
and jumps to it.x0
to x7
, and a return value in register x0
. x0
to x7
(and a few more), and some
are expected to survive, x19
to x28
.It is complicated, and there is more to the story, like using the stack. We may look at that later.
First we need to play with the simplest subroutine we can imagine: add one to a register. Place the following code after the code that stops the program:
inc1: add x0,x0,1
ret
Just make sure it is not executed in the normal flow of the program. Now
call it when you have a known value in x0
, and before you print the
value:
bl inc1
Check the value actually has increased by one. Then change your code to call it twice, and check.
We have one parameter, the number to be printed. In our example it is
already in x0
. So we move the 20-some lines of code that prints the
hex value down near the inc1
-subroutine:
phex: movz x3,16
adr x2,message
again: ror x0,x0,60
and x1,x0,0xF
cmp x1,10
bge isAtoF
add x1,x1,48
b done
isAtoF: add x1,x1,55
done: strb w1,[x2]
add x2,x2,1
subs x3,x3,1
bne again
mov x0,1
adr x1,message
mov x2,17
mov x8,0x40
svc 0
ret
And we also added a ret
. Registers x0
, x1
,
x2
, x3
and x8
are used, and changed. We may do that by
convention. Actually x8
hasn't been mentioned as such - need to investigate.
We call it in the place where we had the code before, like this:
bl phex
And it prints the value in x0. Just for fun: call it twice:
bl phex
bl phex
Now that is a surprise: it prints 0000000000000011 the second time, and
not the same value as the first. But I did tell you, didn't I. The value
in x0
is not expected to survive a call to a subroutine. The 0x11 is
decimal 17, and is the number of bytes printed.
We could save the value in x0
in a register, that by convention
survives a call to a subroutine
mov x19,x0
bl phex
mov x0,x19
bl phex
Make a new subroutine:
exit
, with the code that stops the program from running. In this case
we don't need a ret
.
On the next page we will put the subroutines exit
and phex
in a separate file, and link them to our program in the assembly process.
Start page1 page2 page3 page4 page5 page6 page7 page8 page9 page10
2025-06-16