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
相关推荐
wheeldown9 小时前
【Linux】 Linux网络编程入门:Soket编程详解
linux·运维·网络
zfxwasaboy16 小时前
DRM KMS 子系统(4)Planes/Encoder/Connector
linux·c语言
良许Linux16 小时前
单片机上的IO引脚都有什么作用?
单片机·嵌入式硬件
阿华hhh16 小时前
单片机day4
单片机·嵌入式硬件
暮色_年华16 小时前
随想 2:对比 linux内核侵入式链表和 STL 非侵入链表
linux·c++·链表
TEC_INO17 小时前
stm32_13:RFID-RC522项目代码
stm32·单片机·嵌入式硬件
dnncool17 小时前
【Linux】操作系统发展
linux
文言一心17 小时前
LINUX离线升级 Python 至 3.11.9 操作手册
linux·运维·python
具身智能之心18 小时前
上海交大发布U-Arm:突破成本壁垒,实现超低成本通用机械臂遥操作系统
arm开发·机械臂·具身智能