00 arm开发环境的搭建

1.下载工具链

1.1安装交叉编译工具链

复制代码
sudo apt update
sudo apt install build-essential gcc-aarch64-linux-gnu gdb-multiarch

1.2安装安装模拟器 (QEMU)

复制代码
sudo apt install qemu-system-arm

可以使用下面两条命令判断是否安装成功

复制代码
aarch64-linux-gnu-gcc --version
qemu-system-aarch64 --version

2.编写测试代码

2.1 编写.S文件

在工程目录下创建test.S文件

asm 复制代码
/* test.S */
.global _start
_start:
    mov x0, #123      /* 把 123 赋值给 X0,调试时我们要看这个值 */
    b .               /* 死循环 (跳转到当前地址) */

2.2 创建链接脚本 linker.ld

复制代码
ENTRY(_start)

/* 新增:定义一个名为 'segment' 的加载段 */
PHDRS
{
    segment PT_LOAD FLAGS(7); /* 7 = Read + Write + Execute */
}

SECTIONS
{
    . = 0x40000000;
    
    /* 在每个段后面加上 :segment,显式归类 */
    .text : { *(.text) } :segment
    .data : { *(.data) } :segment
    .bss  : { *(.bss) } :segment
}
  • Section (.text, .data):是你房间里的零碎物品(衣服、书、牙刷)。编译器只负责制造这些物品。

  • Segment (PHDRS):是搬家用的大纸箱。操作系统(或 QEMU)根本不看你有几件衣服,它只管搬运箱子。

所以这个链接就是申请一个Segment 并规定这个Section 的内容和起始地址

过程 A:编译 (Compile) ------ 制造碎片

每个文件都会生成自己的 .text (代码) 和 .data (数据)。

start.o: 里面有一小段 .text。

main.o: 里面有一小段 .text,也许还有一点 .data (全局变量)。

uart.o: 里面有一小段 .text。

过程 B:链接 (Link) ------ 分类合并

链接器(Linker)根据你的脚本 (linker.ld),会执行"归类"操作:

合并代码:它把 start.o + main.o + uart.o 里的所有 .text 凑在一起,拼成一个巨大的 .text 节。

合并数据:它把所有文件的 .data 凑在一起,拼成一个巨大的 .data 节。

过程 C:装箱 (Segment) ------ 最终打包

最后,根据 PHDRS 的指令,这些巨大的节被放入 Segment 中。

在你目前的脚本里: 你强制把这个巨大的 .text、巨大的 .data、巨大的 .bss 全部塞进了同一个 Segment 里。

3 编译成elf文件并在qemu中运行

3.1 elf文件

一个标准的 ELF 文件由四部分组成:

ELF Header (快递单)

位于文件最开头(第 0 字节)。

内容:魔数(Magic Number,7F 45 4C 46 即 .ELF)、是 32 位还是 64 位、是小端还是大端、入口地址(Entry Point, 你的 _start 地址)。

作用:操作系统拿到文件,先看这里,确认"这货我能不能拆"。

Program Headers (装箱单 - 给 OS 看)

描述了 Segments。

作用:告诉操作系统"请把文件中从偏移量 A 开始的 X 字节,搬到内存地址 Y 去"。

你在 Linker Script 里写的 PHDRS 就是在控制这里。

Section Headers (物品清单 - 给编译器/链接器看)

描述了 Sections。

作用:告诉链接器"这里存放的是代码(.text),那里存放的是调试符号(.debug)"。

Data (实际货物)

实际的代码指令、字符串常量、变量值等。


3.2 编译elf文件

复制代码
aarch64-linux-gnu-gcc -g -nostdlib -Wl,-n -T linker.ld test.S -o test.elf

3.3 运行elf文件

在qemu中打开并等待远程链接

复制代码
qemu-system-aarch64 -M virt -cpu cortex-a57 -nographic -kernel test.elf -S -s

使用gdb远程连接

复制代码
target remote :1234
  • 打断点 break _start

  • 查看寄存器的值info registers x0

    (gdb) info registers x0
    x0 0x7b 123

4 Makefile

为了方便我写成了一个Makefile

复制代码
# ==========================================
#  ARMv8 Mini-Kernel Makefile
# ==========================================

# 1. 工具链定义 (Toolchain Definitions)
CROSS_COMPILE = aarch64-linux-gnu-
CC = $(CROSS_COMPILE)gcc
OBJCOPY = $(CROSS_COMPILE)objcopy
GDB = gdb-multiarch

# 2. 编译参数 (Compiler Flags)
# -g: 生成调试信息
# -nostdlib: 不链接标准库 (裸机必备)
# -Wl,-n: 关闭页对齐 (解决 segment 错误)
CFLAGS = -g -nostdlib -Wl,-n

# 3. 链接脚本 (Linker Script)
LDSCRIPT = linker.ld

# 4. 源文件与目标文件 (Files)
# 以后添加 .c 文件直接在 SRCS 后面追加即可,例如: test.S uart.c
SRCS = test.S
ELF = test.elf
BIN = test.bin

# 5. QEMU 模拟器参数 (Emulator Flags)
QEMU = qemu-system-aarch64
MACH = -M virt -cpu cortex-a57
# -S: 冻结 CPU 等待调试
# -s: 开启 GDB 端口 1234
QEMU_FLAGS = $(MACH) -nographic -kernel $(ELF) -S -s

# ==========================================
#  编译规则 (Build Rules)
# ==========================================

# 默认目标: 输入 'make' 时执行
all: $(ELF) $(BIN)

# 生成 ELF 文件
$(ELF): $(SRCS) $(LDSCRIPT)
	@echo "  CC      $@"
	$(CC) $(CFLAGS) -T $(LDSCRIPT) $(SRCS) -o $@

# 生成 BIN 文件 (给真机用的)
$(BIN): $(ELF)
	@echo "  OBJCOPY $@"
	$(OBJCOPY) -O binary $< $@

# ==========================================
#  调试规则 (Debug Rules)
# ==========================================

# 启动 QEMU (终端 1)
qemu: $(ELF)
	@echo "Starting QEMU... (Waiting for GDB connection on port 1234)"
	$(QEMU) $(QEMU_FLAGS)

# 启动 GDB (终端 2)
# -ex 参数会自动帮你执行 GDB 命令,不用手敲了!
gdb: $(ELF)
	$(GDB) $(ELF) -ex "target remote :1234" -ex "break _start" -ex "continue"

# ==========================================
#  清理规则 (Clean)
# ==========================================
clean:
	rm -f *.elf *.bin *.o

.PHONY: all clean qemu gdb
相关推荐
6极地诈唬2 小时前
【PG漫步】DELETE不会改变本地文件的大小,VACUUM也不会
linux·服务器·数据库
易水寒陈2 小时前
使用J-Link RTT Viewer
stm32·单片机
谷雨不太卷2 小时前
Linux_文件权限
linux·运维·服务器
少一倍的优雅3 小时前
hi3863(ws63)智能小车 (三)PWM驱动马达
单片机·嵌入式硬件·hi3863
无泪无花月隐星沉3 小时前
uos server 1070e lvm格式磁盘扩容分区
linux·运维·uos
xingzhemengyou13 小时前
STM32 内存空间中的选项字节
stm32·单片机
食咗未3 小时前
Linux USB HOST EXTERNAL STORAGE
linux·驱动开发
食咗未3 小时前
Linux USB HOST HID
linux·驱动开发·人机交互
Xの哲學3 小时前
Linux SLAB分配器深度解剖
linux·服务器·网络·算法·边缘计算