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
相关推荐
chlk1231 天前
Linux文件权限完全图解:读懂 ls -l 和 chmod 755 背后的秘密
linux·操作系统
舒一笑1 天前
Ubuntu系统安装CodeX出现问题
linux·后端
改一下配置文件1 天前
Ubuntu24.04安装NVIDIA驱动完整指南(含Secure Boot解决方案)
linux
深紫色的三北六号2 天前
Linux 服务器磁盘扩容与目录迁移:rsync + bind mount 实现服务无感迁移(无需修改配置)
linux·扩容·服务迁移
SudosuBash2 天前
[CS:APP 3e] 关于对 第 12 章 读/写者的一点思考和题解 (作业 12.19,12.20,12.21)
linux·并发·操作系统(os)
哈基咪怎么可能是AI2 天前
为什么我就想要「线性历史 + Signed Commits」GitHub 却把我当猴耍 🤬🎙️
linux·github
十日十行3 天前
Linux和window共享文件夹
linux
木心月转码ing3 天前
WSL+Cpp开发环境配置
linux
崔小汤呀4 天前
最全的docker安装笔记,包含CentOS和Ubuntu
linux·后端
何中应5 天前
vi编辑器使用
linux·后端·操作系统