I have been programming with ARM64 assembly, and my goal has been the following:
- Reserve a register to store sensitive information (e.g., randomly generated key)
- Access this reserved register to load the sensitive information and use it for the purposes such as encryption and decryption
- Do this multiple times without jeopardizing the values stored in the register (basically, I hope that this reserved register is not wiped away and will keep its stored value until I specifically wish to clear it).
These links have gave me some good ideas and starting points:
- Reserve registers for a specific part of code using GCC compiler
- arm; inline asm; use scratch register;
- Using ASM to retrieve register values
However, I am facing this weird undefined behavior and trying to figure out what is happening, which prompted me to write this post.
I have these two codes:
The first code is a main.c
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include "test_lib.h"
register uint64_t rand_key asm ("x11");
int main(int argc, char const *argv[]) {
gen_rand_key();
uint64_t test = rand_key;
printf("Random Key:\t\t0x%lx\n", test);
printf("Random Key:\t\t0x%lx\n", rand_key);
return 0;
}
The second is a test_lib.c compiled as a shared library for my main.c program.
#include <stdint.h>
uint64_t gen_rand_key() {
asm volatile (
"eor x11, x11, x11\n\t"
"mrs x11, rndr\n\t"
:
:
: "x11"
);
}
// rndr instruction is only available from ARMv8.5,
// this instruction can be replaced with any other instructions that perform some bit manipulation.
Here is the output upon executing the main.c:
~ ➤ LD_LIBRARY_PATH=./ ./main.out
Random Key: 0x4fee674452b68da3
Random Key: 0xffffcc5ebd48
To explain what is happening above, I first call gen_rand_key() function from the test_lib.so which is going to use the rndr instruction (https://developer.arm.com/documentation/ddi0595/2021-06/AArch64-Registers/RNDR--Random-Number), to generate a random number 0x4fee674452b68da3 and store this value into x11 register. After that, I use the rand_key variable to access the x11 register and store this value into the test variable. Next, I print test and then rand_key in that order. (Just as a side note), I have specifically created a shared library to make this functionality portable across different applications
Now I see that the test value outputs the correct randomly generated number, but when I use the rand_key variable, I expect the value 0x4fee674452b68da3 to show again, but I get 0xffffcc5ebd48.
Therefore, I have been trying to figure out why this weird behavior is happening, but to no avail. I guess that as soon as this x11 register is read from accessing rand_key, this value is freed from the register? But I wasn't sure whether that was correct or not.
To summarize my questions:
Why has the x11 register value disappeared after accessing it?
Also, I'm wondering whether there is a better way to achieve the stated goals, as I feel accessing a register is a bit finicky.
Please let me know if anything I mentioned above doesn't make sense, and I will try to clarify it.