You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

QEMU(aarch64)无法正常执行汇编脚本的问题排查

AArch64 Cortex-A72 内核启动异常:寄存器未正确初始化

我正在为aarch64(cortex-a72)架构编写简易内核,纯粹出于兴趣尝试,在M1 Pro macOS上用LLVM开发。代码能正常编译,QEMU也能启动,但执行info registers时显示所有寄存器为空,X13也没有预期的0x1337魔数。

代码及配置

loader.s

.global _reset
_reset:
    # 设置栈指针
    LDR X2, =stack_top
    MOV SP, X2
    # 魔数
    MOV X13, #0x1337
    # 调用内核入口
    bl start
    # 无限循环
    B .

main.c

void start(void) {
    for(;;) {

    }
}

linker.ld

SECTIONS {
    . = 0x40100000;
    .text : { *(.text) }
    . = ALIGN(8);
    . = . + 0x1000; 
    stack_top = .;
}

Makefile

BUILD_DIR=build
LLVM_BIN=/opt/homebrew/opt/llvm/bin
BINTOOLS_BIN=/opt/homebrew/Cellar/aarch64-elf-binutils/2.41/bin
OBJCOPY=$(LLVM_BIN)/llvm-objcopy
OBJDUMP=$(LLVM_BIN)/llvm-objdump
HEXDUMP=hexdump
CC=/$(LLVM_BIN)/clang
AS=$(BINTOOLS_BIN)/aarch64-elf-as
LD=$(BINTOOLS_BIN)/aarch64-elf-ld
QEMU_VERSION=8.1.1

all: kernel

kernel: linker
    $(OBJCOPY) $(BUILD_DIR)/kernel.elf -O binary $(BUILD_DIR)/kernel.bin

linker: loader.o main.o
    $(LD) -m aarch64elf -nostdlib -T linker.ld $(BUILD_DIR)/loader.o $(BUILD_DIR)/main.o -o $(BUILD_DIR)/kernel.elf

loader.o: mkdir
    $(AS) loader.s -o $(BUILD_DIR)/loader.o

main.o: mkdir
    $(CC) -c --target=aarch64-none-linux -Wall -O2 -fomit-frame-pointer -fno-exceptions -fno-asynchronous-unwind-tables -fno-unwind-tables main.c -o $(BUILD_DIR)/main.o

mkdir:
    mkdir -p $(BUILD_DIR)

dump:
    $(OBJDUMP) -D $(BUILD_DIR)/kernel.elf

dump_binary:
    $(HEXDUMP) -C $(BUILD_DIR)/kernel.bin

run:
    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 \
        -s \
        -S

clean:
    rm -rf $(BUILD_DIR)/*.o

问题现象

QEMU启动后执行info registers输出:

QEMU 8.1.1 monitor - type 'help' for more information
(qemu) info registers

CPU#0
 PC=0000000040100000 X00=0000000000000000 X01=0000000000000000
X02=0000000000000000 X03=0000000000000000 X04=0000000000000000
X05=0000000000000000 X06=0000000000000000 X07=0000000000000000
X08=0000000000000000 X09=0000000000000000 X10=0000000000000000
X11=0000000000000000 X12=0000000000000000 X13=0000000000000000
X14=0000000000000000 X15=0000000000000000 X16=0000000000000000
X17=0000000000000000 X18=0000000000000000 X19=0000000000000000
X20=0000000000000000 X21=0000000000000000 X22=0000000000000000
X23=0000000000000000 X24=0000000000000000 X25=0000000000000000
X26=0000000000000000 X27=0000000000000000 X28=0000000000000000
X29=0000000000000000 X30=0000000000000000  SP=0000000000000000
PSTATE=400003c5 -Z-- EL1h    FPU disabled

kernel.elf反汇编信息

/opt/homebrew/opt/llvm/bin/llvm-objdump -D build/kernel.elf

build/kernel.elf:       file format elf64-littleaarch64

Disassembly of section .text:

0000000040100000 <_reset>:
40100000: 580000c2      ldr     x2, 0x40100018 <_reset+0x18>
40100004: 9100005f      mov     sp, x2
40100008: d28266ed      mov     x13, #0x1337            // =4919
4010000c: 94000005      bl      0x40100020 <start>
40100010: 14000000      b       0x40100010 <_reset+0x10>
40100014: 00000000      udf     #0x0

0000000040100018 <$d>:
40100018: 28 10 10 40   .word   0x40101028
4010001c: 00 00 00 00   .word   0x00000000

0000000040100020 <start>:
40100020: 14000000      b       0x40100020 <start>

Disassembly of section .comment:

0000000000000000 <.comment>:
       0: 656d6f48      fnmls   z8.h, p3/m, z26.h, z13.h
       4: 77657262      <unknown>
       8: 616c6320      <unknown>
       c: 7620676e      <unknown>
      10: 69737265      ldpsw   x5, x28, [x19, #-0x68]
      14: 31206e6f      adds    w15, w19, #0x81b
      18: 2e302e37      uqsub   v23.8b, v17.8b, v16.8b
      1c: 31 00         <unknown>

000000000000001d <$d.1>:
      1d: 00            .byte   0x00

Disassembly of section .symtab:

0000000000000000 <.symtab>:
                ...
      1c: 00010003      <unknown>
      20: 40100000      <unknown>
                ...
      34: 00020003      <unknown>
                ...
      48: 00000001      udf     #0x1
      4c: fff10004      <unknown>
                ...
      60: 0000000a      udf     #0xa
      64: 00010000      <unknown>
      68: 40100000      <unknown>
                ...
      78: 0000000d      udf     #0xd
      7c: 00010000      <unknown>
      80: 40100018      <unknown>
                ...
      90: 00000010      udf     #0x10
      94: fff10004      <unknown>
                ...
      a8: 00000017      udf     #0x17
      ac: 00010000      <unknown>
      b0: 40100020      <unknown>
                ...
      c0: 0000001c      udf     #0x1c
      c4: 00020000      <unknown>
      c8: 0000001d      udf     #0x1d
                ...
      d8: 00000021      udf     #0x21
      dc: 00010010      <unknown>
      e0: 40101028      <unknown>
                ...
      f0: 0000002b      udf     #0x2b
      f4: 00010010      <unknown>
      f8: 40100000      <unknown>
                ...
     108: 00000032      udf     #0x32
     10c: 00010012      <unknown>
     110: 40100020      <unknown>
     114: 00000000      udf     #0x0
     118: 00000004      udf     #0x4
     11c: 00000000      udf     #0x0

Disassembly of section .strtab:

0000000000000000 <.strtab>:
       0: 616f6c00      <unknown>
       4: 2e726564      umax    v4.4h, v11.4h, v18.4h
       8: 7824006f      ldaddh  w4, w15, [x3]
       c: 00642400      <unknown>
      10: 6e69616d      rsubhn2 v13.8h, v11.4s, v9.4s
      14: 2400632e      cmplt   p14.b, p0/z, z25.b, z0.d
      18: 00302e78      <unknown>
      1c: 312e6424      adds    w4, w1, #0xb99
      20: 61747300      <unknown>
      24: 745f6b63      <unknown>
      28: 5f00706f      <unknown>
      2c: 65736572      fnmls   z18.h, p1/m, z11.h, z19.h
      30: 74730074      <unknown>
      34: 00747261      <unknown>

Disassembly of section .shstrtab:

0000000000000000 <.shstrtab>:
       0: 79732e00      ldrh    w0, [x16, #0x1996]
       4: 6261746d      <unknown>
       8: 74732e00      <unknown>
       c: 62617472      <unknown>
      10: 68732e00      <unknown>
      14: 74727473      <unknown>
      18: 2e006261      <unknown>
      1c: 74786574      <unknown>
      20: 6f632e00      <unknown>
      24: 6e656d6d      umin    v13.8h, v11.8h, v5.8h
      28: 74 00         <unknown>

请问我哪里出错了?


解决方案

1. QEMU加载命令重复冲突

启动命令里同时使用两个-device loader参数会导致加载逻辑混乱:

-device loader,file=$(BUILD_DIR)/kernel.elf \
-device loader,addr=0x40100000,cpu-num=0 \

第一个loader会自动解析ELF文件的入口地址并完成加载,第二个参数强制重复加载,干扰正常执行流程。保留第一个参数即可:

-device loader,file=$(BUILD_DIR)/kernel.elf

2. 编译目标架构错误

当前用--target=aarch64-none-linux编译C代码,该目标针对Linux用户态程序,包含内核相关隐含规则,不适合裸机开发。替换为纯裸机目标:

--target=aarch64-none-elf

修改Makefile中main.o的编译规则:

main.o: mkdir
    $(CC) -c --target=aarch64-none-elf -Wall -O2 -fomit-frame-pointer -fno-exceptions -fno-asynchronous-unwind-tables -fno-unwind-tables main.c -o $(BUILD_DIR)/main.o

3. 栈地址未映射问题

从PSTATE可知CPU处于EL1模式,但链接脚本中栈顶地址0x40101028是虚拟地址,未开启MMU时该地址无物理映射,会导致栈初始化异常。改用QEMU virt平台的物理内存起始范围(0x40000000)调整链接脚本:

SECTIONS {
    . = 0x40000000;
    .text : { *(.text) }
    . = ALIGN(8);
    . = . + 0x1000; 
    stack_top = .;
}

4. 未启动CPU执行

启动命令中的-S参数会让CPU暂停在初始状态,此时代码未执行,寄存器自然无变化。需在QEMU monitor中输入c启动执行,再按Ctrl+C暂停后查看寄存器值。


内容的提问

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 00:02:59