Understanding ARM64 Registers and Memory Management

ARM64 Registers

  • X0 – X7: Arguments/Results (no preserved call)
  • X8: Indirect result location register (no preserved call)
  • X9 – X15: Temporary registers (no preserved call)
  • X16: Linker as a scratch register, otherwise, temporary (no preserved call)
  • X17: Linker as a scratch register, otherwise, temporary (no preserved call)
  • X18: Platform register for platform independent code, otherwise, temporary (no preserved call)
  • X19 – X27: Saved (preserved call)
  • X28: Stack pointer (preserved call)
  • X29: Frame pointer (preserved call)
  • X30: Link register/return address (current instruction +4) (preserved call)
  • XZR: Constant value of 0

Memory Management

  • The stack is not a region in the set of registers
  • The BL instruction doesn’t copy registers to the stack
  • FALSE: A procedure should copy all of registers X9-X17 and X19-X28 to the stack before executing the procedure’s computations.
  • FALSE: If a procedure will update registers X19, X20, X21, and X22, the procedure should make room on the stack by adding 32 to SP.
  • If P is not a leaf procedure, P should always save LR on the stack
  • If P will write to X0 to pass a parameter to Q, P might first need to save X0 to the stack.
  • FALSE: When P calls Q, P should expect that Q might pop less from the stack than Q pushed to the stack.
  • All of the saved registers and local variables for a procedure call are referred to as an activation record.
  • If a running program should create a new array, the array is normally stored on the heap.
  • The heap typically grows upwards in memory, while the stack grows downwards.
  • If a program allocated huge arrays, the program may cause the heap to run into the stack, causing an error.

Addressing Modes

  • Immediate addressing: The operand is a constant within the instruction itself
  • Register addressing: The operand is a register
  • Base addressing / displacement addressing: The operand is at the memory location whose address is the sum of a register and a constant in the instruction
  • PC-relative addressing: The branch address is the sum of the PC and a constant in the instruction

Example Functions

  • long long int leaf_example (long long int g, long long int h, long long int i, long long int j) {
  • long long int f;
  • f = (g+h) – (i+j);
  • return f;

ASM

  • leaf_example:
  • SUBI SP, SP, #24 // adjust stack to make room for 3 items
  • STUR X10, [SP,#16] // save register X10 for use afterwards
  • STUR X9, [SP,#8] // save register X9 for use afterwards
  • STUR X19, [SP,#0] // save register X19 for use afterwards
  • ADD X9,X0,X1 // register X9 contains g + h

x8FDa3NDwle7QAAAABJRU5ErkJggg==

  • ADD X10,X2,X3 // register X10 contains i + j
  • SUB X19,X9,X10 // f = X9 – X10, which is (g + h) – (i + j)
  • ADD X0,X19,XZR // returns f (X0 = X19 + 0)
  • LDUR X19, [SP,#0] // restore register X19 for caller
  • LDUR X9, [SP,#8] // restore register X9 for caller
  • LDUR X10, [SP,#16] // restore register X10 for caller
  • ADDI SP,SP,#24 // adjust stack to delete 3 items
  • BR LR // branch back to calling routine

ASM

  • long long int fact (long long int n)
  • {
  • if (n
    else return (n * fact(n – 1));
  • }

ASM

  • fact:
  • SUBI SP, SP, #16 // adjust stack for 2 items
  • STUR LR, [SP,#8] // save the return address
  • STUR X0, [SP,#0] // save the argument n
  • SUBIS ZXR,X0, #1 // test for n
    B.GE L1 // if n >= 1, go to L1
  • ADDI X1,XZR, #1 // return 1
  • ADDI SP,SP,#16 // pop 2 items off stack
  • BR LR // return to caller
  • L1: SUBI X0,X0,#1 // n >= 1: argument gets (n – 1)
  • BL fact // call fact with (n – 1)
  • LDUR X0, [SP,#0] // return from BL: restore argument n
  • LDUR LR, [SP,#8] // restore the return address
  • ADDI SP, SP, #16 // adjust stack pointer to pop 2 items
  • MUL X1,X0,X1 // return n * fact (n – 1)
  • BR LR // return to the caller

ASM

  • MOVZ X19, 7, LSL 16
  • Output:
  • 00000000 00000000 00000000 00000000 00000000 00000111 00000000 00000000

ASM

  • MOVK X19, 8, LSL 0
  • Output:
  • 00000000 00000000 00000000 00000000 00000000 00000111 00000000 00001000

Arithmetic Operations

  • LDURB, LDURH are load instructions used for byte and halfword arithmetic operations.
  • ADD, SUB, MULT, DIV, are arithmetic instructions or byte and halfword arithmetic operations.
  • STURB, STURH are store instructions used for byte and halfword arithmetic operations.
  • If we ignore the sign bits, the length of the multiplication of an n-bit multiplicand and an m-bit multiplier is a product that is n + m bits long.

Multiplication Process

  • OLD
  • The multiplication process involves shifting the multiplicand and multiplier registers to obtain the product.
  • Each step of the multiplication shifts the multiplier 1 bit to the right.
  • The multiplier register is 64 bits long.
  • Each step of the multiplication shifts the multiplicand register 1 bit to the left.
  • The multiplicand register is 128 bits long.
  • The product register is 128 bits long.
  • Each iteration of the multiplication consists of 3 basic steps.
  • NEW
  • The speed up comes from performing the operations in parallel: the multiplier and multiplicand are shifted while the multiplicand is added to the product if the multiplier bit is a 1.
  • The product register is 128 bits long.
  • Signed multiplication involves converting the multiplier and multiplicand to positive numbers and then remembering their original signs.
  • The algorithms should next be run for 31 iterations, leaving the signs out of the calculation.
  • When the algorithm completes, the lower doubleword would have the 64-bit product.
  • To produce a properly signed or unsigned 128-bit product, LEGv8 has three instructions:
  • To get the integer 64-bit product, the programmer uses MUL.
  • To get the upper 64 bits of the 128-bit product, the programmer uses either SMULH (signed) or UMULH (unsigned), depending on the types of multiplier and multiplicand.

2Q== 9k=

9k= 2Q==

2Q==