Page 149 - ARM 64 Bit Assembly Language
P. 149
Structured programming 135
Listing 5.27 A function call using stp to push arguments on the stack.
.
1 . .
2 // marshaling onto the stack.
3 ldr w9, [x19, #(4*7)] // w9 = p
4 ldr w10, [x19, #(4*8)] // w10 = q
5 ldr w11, [x19, #(4*9)] // w11 = r
6 stp x9, x10, [sp, #-32]! // 8 bytes per parameter
7 str x11, [sp, #16]
8
9 // call printf
10 bl printf
11
12 // pop p, q, and r from the stack
13 add sp, sp, #32
.
14 . .
of thirty two bytes (each argument required 8 bytes, but the stack is only allowed to grow or
shrink in multiples of 16 bytes). Therefore, all we need to do is add thirty two to the stack
pointer, thereby restoring its original value.
5.4.6 Writing subroutines
We have looked at the conventions that programmers use to pass arguments when calling
functions. Now we will examine these same conventions from the point of view of the func-
tion being called. Because of the calling conventions, the programmer writing a function can
assume that
• the first eight parameters are in x0–x7,
• any additional parameters can be accessed with ldr Rd, [sp, #offset],
• the calling function will remove parameters from the stack, if necessary,
• if the function return type is not void, then they must ensure that the return value is in x0
(and possibly x1, x2,and x3, if the function returns multiple values), and
• the return address will be in x30.
Also because of the conventions, there are certain registers that can be used freely, while oth-
ers must be preserved or restored so that the calling function can continue operating correctly.
Registers which can be used freely are referred to as volatile, and registers which must be pre-
served or restored before returning are referred to as non-volatile. When writing a subroutine
(function),
• registers x0-x18 are volatile,