I have the next awful code:
void print(const char* text) {
unsigned long address = 0x9000000;
unsigned long counter = 0;
char ch = *text;
while (ch != '\0') {
address += counter;
asm volatile(
"MOV X10, %[address];"
"MOV W9, %w[ch];"
"STRB W9, [X10];"
:[address]"+r"(address), [ch]"+r"(ch)
);
++counter;
ch = *(text + counter);
}
}
void start(void) {
print("Hello, World!");
}
Unfortunately, even this code doesn't work correctly and prints: Hel instead of Hello, World!
However, I would prefer to re-write all loop logic in the embed/inline assembler but I can't get how to read and iterate over C-array (text) in assembler. I've tried a lot of variants and all successfully failed.
This code was created for aarch64 (cortex-a72) and it's launched in Qemu by command:
qemu-system-aarch64 -M virt \
-cpu cortex-a72 \
-bios "/opt/homebrew/Cellar/qemu/$(QEMU_VERSION)/share/qemu/edk2-aarch64-code.fd" \
-m 128M \
-nographic \
-device loader,file=$(BUILD_DIR)/kernel.elf \
-device loader,addr=0x40100000,cpu-num=0
P.S. I use LLVM clang and aarch64-elf-binutils compilers and linker on macOS (M1 Pro) to build kernel.elf.
Oh, maybe someone is the same noobie like me and it will help him.
Firstly, the solution:
How does it work?
0x9000000.addressandtextvariables intoX10andX11registers (there is no strict rules which registers you will use). Notetextis a pointer so in fact we loaded an address of our string into register, not a value.X9register the next string character that's located by an address inX11register.0x9000000.X11register's value, in other words we just switch our pointer to the next character in the string.PRINT_STRif theW9register contains non-zero value (C-strings end with\0).UPD: Second thoughts are best... I wanted to use assembler due to I thought C code will be ugly and still mixed with assembler. But I forgot it's mr. "C", pointers are the power!