在 x86 Linux 搭建 QEMU ARM 环境
在 x86 Linux 搭建 QEMU ARM 环境
准备
- x86 Linux 环境,最好使用最新的 Debian。如果装在其他机器上,可以使用 Remote-SSH 进行开发,见VSCode远程SSH连接方法
安装 qemu for arm
1
sudo apt install qemu-system-arm
- 安装 Arm GNU Toolchain
开发
创建一个 ARM 项目,参考 github 上的 qemu_arm_samples,进行一些修改:
vectors.s
:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
.cpu cortex-m0
.thumb
.thumb_func
.global _start
_start:
stacktop: .word 0x20001000
.word reset
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.thumb_func
reset:
bl notmain
b hang
.thumb_func
hang: b .
.thumb_func
.globl PUT32
PUT32:
str r1,[r0]
bx lr
.thumb_func
.globl EXITPROGRAM
EXITPROGRAM:
mov r0, #0x18
mov r1, #0
bkpt 0xAB
vectors.s
添加了 EXITPROGRAM 退出函数,用于退出 QEMU 环境。PUT32 函数用于在终端打印字符。hang 函数使用 b
指令跳转的自身地址(.
符号) 实现无限循环。
memmap:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
MEMORY
{
ROM (rx) : ORIGIN = 0x00000000, LENGTH = 0x1000
RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x100000
}
_estack = ORIGIN(RAM) + LENGTH(RAM);
SECTIONS
{
.text : {
*(.text*)
} > ROM
.rodata : { *(.rodata*) } > ROM
.data : { *(.data*) } > RAM AT > ROM
.bss :
{
_sbss = .;
*(.bss*)
. = ALIGN(4);
_ebss = .;
} > RAM
}
Makefile:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
ARMGNU = arm-none-eabi
AOPS = --warn --fatal-warnings -mcpu=cortex-m0
COPS = -fstack-usage -Wall -Werror -mthumb -O3 -nostdlib -nostartfiles -ffreestanding \
-mcpu=cortex-m0 -std=c++20 -fno-rtti -fno-exceptions
SRCS := $(wildcard *.cpp)
OBJS := $(SRCS:.cpp=.o)
all : notmain.bin
clean:
rm -f *.bin
rm -f *.o
rm -f *.elf
rm -f *.list
run:
qemu-system-arm -M lm3s811evb -m 1M -nographic -no-reboot -semihosting -kernel notmain.bin
vectors.o : vectors.s
$(ARMGNU)-as $(AOPS) vectors.s -o vectors.o
%.o : %.cpp
$(ARMGNU)-g++ $(COPS) -c $< -o $@
notmain.bin : memmap vectors.o $(OBJS)
$(ARMGNU)-g++ -nostartfiles -o notmain.elf -T memmap vectors.o $(OBJS)
$(ARMGNU)-size notmain.elf
$(ARMGNU)-objdump -D notmain.elf > notmain.list
$(ARMGNU)-objcopy notmain.elf notmain.bin -O binary
其他文件自行实现,notmain 函数为入口函数,注意如果是 cpp,要使用 extern "C"
让其符号变成 C 风格的。在 notmain return 前,如果没有调用 EXITPROGRAM()
,则会进入 hang
无限循环,此时 QEMU 将无法退出。
编译链接:
1
make
运行:
1
make run
结果:
1
2
3
4
dev@dev:~/repo/stackpool$ make run
qemu-system-arm -M lm3s811evb -m 1M -nographic -no-reboot -semihosting -kernel notmain.bin
Timer with period zero, disabling
0make: *** [Makefile:22: run] Error 1
使用 PUT32 打印了一个 0,然后退出 qemu 环境。
参考
本文由作者按照 CC BY 4.0 进行授权