如何使用嵌入汇编器(aarch64)循环C数组?

问题描述 投票:0回答:1

我有下一个糟糕的代码:

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!");
}

不幸的是,即使这个代码也无法正常工作并打印:

Hel
而不是
Hello, World!

但是,我更愿意在嵌入/内联汇编器中重写所有循环逻辑,但我无法了解如何在汇编器中读取和迭代 C 数组(

text
)。我尝试了很多变体,但都成功失败了。

此代码是为 aarch64 (cortex-a72) 创建的,并通过命令在 Qemu 中启动:

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. 我在 macOS (M1 Pro) 上使用 LLVM clang 和 aarch64-elf-binutils 编译器和链接器来构建 kernel.elf

c clang qemu arm64 assemble
1个回答
0
投票
哦,也许有人和我一样是菜鸟,这会对他有帮助。

首先是解决方案:

void print(const char* text) { unsigned long address = 0x9000000; asm volatile( "MOV X10, %[address];" "MOV X11, %[text];" :[address]"+r"(address), [text]"+r"(text) ); PRINT_STR: asm volatile( "LDR X9, [X11];" "STRB W9, [X10];" "ADD X11, X11, #0x1;" ); asm goto ("CBNZ W9, %l0"::::PRINT_STR); } void start(void) { print("Hello, World!"); }

它是如何工作的?

    声明视频内存的地址(如果我错了,请纠正我)。在我们的例子中是
  1. 0x9000000
  2. address
    text
     变量加载到 
    X10
    X11
     寄存器中(对于将使用哪个寄存器没有严格的规则)。注意 
    text
     是一个指针,所以实际上我们将字符串的地址加载到寄存器中,而不是一个值。
  3. 声明一个标签以便稍后跳转到该标签。
  4. 加载到
  5. X9
     寄存器中,由 
    X11
     寄存器中的地址定位的下一个字符串字符。
  6. 将加载的值复制到
  7. 0x9000000
  8. 增加
  9. X11
    寄存器的值,换句话说,我们只是将指针切换到字符串中的下一个字符。
  10. 最后,如果
  11. PRINT_STR
     寄存器包含非零值(C 字符串以 
    W9
     结尾),则跳转到 
    \0
© www.soinside.com 2019 - 2024. All rights reserved.