aarch64-linux-gnu* (gcc,ld,objcopy,objdump)工具总结文章目录aarch64-linux-gnu* (gcc,ld,objcopy,objdump)工具总结aarch64-linux-gnu-gccaarch64-linux-gnu-asaarch64-linux-gnu-ldaarch64-linux-gnu-objdumpaarch64-linux-gnu-objcopyaarch64-linux-gnu-readelfaarch64-linux-gnu-nmaarch64-linux-gnu 工具链家族aarch64-linux-gnu-gcc ← C 编译器 aarch64-linux-gnu-g ← C 编译器 aarch64-linux-gnu-ld ← 链接器 aarch64-linux-gnu-as ← 汇编器 aarch64-linux-gnu-objdump ← 反汇编/查看目标文件 aarch64-linux-gnu-objcopy ← 目标文件格式转换 aarch64-linux-gnu-readelf ← 读取 ELF 信息 aarch64-linux-gnu-strip ← 去除符号表(减小体积)aarch64-linux-gnu-nm ← 列出符号 aarch64-linux-gnu-ar ← 创建/管理静态库(.a)aarch64-linux-gnu-gdb ← 远程调试器 aarch64-linux-gnu-size ← 查看段大小 aarch64-linux-gnu-strings ← 提取可打印字符串aarch64-linux-gnu-gcc命名拆解aarch64-linux-gnu-gcc │ │ │ │ │ │ │ └── GCC: GNU Compiler Collection (编译器本体) │ │ └────── gnu: 使用 glibc (C 标准库) GNU 工具链 ABI │ └──────────── linux: 目标操作系统是 Linux └─────────────────── aarch64: 目标 CPU 架构是 ARMv8 64-bit (AArch64)作用:交叉编译本地编译: x86_64源代码(host机) --gcc– x86_64二进制(目标板)交叉编译: x86_64源代码(host机) --aarch64-linux-gnu-gcc– AArch64二进制(目标板)使用场景内核编译, 在编译脚本加入make ARCHarm64 CROSS_COMPILEaarch64-linux-gnu-普通Makefile中CC aarch64-linux-gnu-gcc app: app.c $(CC) -o app app.c # 或者 ARCH arm64 CROSS_COMPILE aarch64-linux-gnu- make -C $(KDIR) M$(PWD) ARCH$(ARCH) CROSS_COMPILE$(CROSS_COMPILE) ...用户态程序, 执行aarch64-linux-gnu-gcc -o test_i2c test_i2c.c生成 ARM64 ELF 二进制底层原理和普通的gcc的区别在于编译阶段, aarch64的gcc会自动去找glibc┌───────────────────────────────────────────────────────────────┐ │ aarch64-linux-gnu-gcc 编译流水线 │ ├───────────────────────────────────────────────────────────────┤ │ │ │ .c ──▶[预处理]──▶[编译]──▶[汇编]──▶[链接]──▶ ELF │ │ cpp cc1 as ld │ │ │ │ │ ┌────┴────┐ │ │ │ 关键区别 │ │ │ └────┬────┘ │ │ │ │ │ 生成的机器码是 AArch64 指令 │ │ 而不是 x86_64 指令 │ │ │ │ │ 链接的库是 AArch64 版 glibc │ │ 而不是 x86_64 的 │ │ │ │ sysroot: /usr/aarch64-linux-gnu/ │ │ ├── include/ ← AArch64 头文件 │ │ └── lib/ ← AArch64 glibc / crt*.o │ │ │ └───────────────────────────────────────────────────────────────┘验证工具链# 查看版本aarch64-linux-gnu-gcc--version# 查看默认搜索路径 (sysroot, 库路径等)aarch64-linux-gnu-gcc -print-search-dirs# 检查编译出的二进制是否为 AArch64aarch64-linux-gnu-readelf-hyour_binary|grepMachine# → Machine: AArch64# 查看链接了哪些共享库aarch64-linux-gnu-readelf-ayour_binary|grepNEEDED# 显示编译器配套库的名称aarch64-linux-gnu-gcc --print-libgcc-file-nameaarch64-linux-gnu-as作用: as 是 GNU AssemblerGAS把汇编源文件.s / .S翻译成目标文件.o应用场景汇编一个文件:aarch64-linux-gnu-as -o hello.o hello.s生成调试信息:aarch64-linux-gnu-as -g -o hello.o hello.s底层原理┌──────────────────────────────────────────────────────┐ │ 编译流水线中的位置 │ ├──────────────────────────────────────────────────────┤ │ │ │ .c ──▶ cpp ──▶ cc1 ──▶ as ──▶ ld ──▶ ELF │ │ 预处理 编译 汇编 链接 │ │ │ ↑ │ │ │ │ │ │ 生成 .s 你在这里 │ │(汇编)直接写 .s 时用到 │ │ │ │ 两种来源: │ │1. gcc-S自动调 cc1 生成 .s再隐式调 as 生成 .o │ │2. 手写 .s/.S直接调 as │ └──────────────────────────────────────────────────────┘aarch64-linux-gnu-ld作用: GNU Linkerld把多个 .o 目标文件 库合并成最终的可执行文件或共享库。交叉版——在 x86 上链接出 AArch64 ELF应用场景链接几个 .o 成可执行文件aarch64-linux-gnu-ld -o app boot.o main.o utils.o内核中的链接脚本┌──────────────────────────────────────────────────────────────┐ │ 内核 vmlinux.lds.S 关键段布局(简化)│ ├──────────────────────────────────────────────────────────────┤ │ │ │ 0xFFFF800000000000 ┌──────────────────┐ │ │ │ .head.text │ ← head.S(启动头)│ │ ├──────────────────┤ │ │ │ .text │ ← 所有内核代码 │ │ │ .entry.text │ ← 异常入口 │ │ │ .hyp.text │ ← KVM hypervisor │ │ ├──────────────────┤ │ │ │ .rodata │ ← 只读数据 │ │ ├──────────────────┤ │ │ │ .init.data │ ← 启动后释放 │ │ ├──────────────────┤ │ │ │ .data │ ← 可写数据 │ │ ├──────────────────┤ │ │ │ .bss │ ← 清零区 │ │ └──────────────────┘ │ │ │ │ 特殊符号: │ │ _text.text 开始 │ │ _etext.text 结束 │ │ __init_begin.init 开始 │ │ __init_end.init 结束(释放起点)│ │ _end内核映像末尾 │ │ │ │ ARM64 虚拟地址布局: │ │ 内核: 0xFFFF00000000xxxx(TTBR1)│ │ 用户: 0x0000xxxxxxxxxxxx(TTBR0)│ └──────────────────────────────────────────────────────────────┘底层原理┌──────────────────────────────────────────────────────────────┐ │ 编译流水线中 ld 的位置 │ ├──────────────────────────────────────────────────────────────┤ │ │ │ .c ─▶ cpp ─▶ cc1 ─▶ as ─▶ .o ─▶ ld ─▶ ELF │ │ │ │ │ │ 目标文件 你在这里 │ │ │ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │ │ boot.o │ │ main.o │ │ utils.o │ libc.a │ │ └─────────┘ └─────────┘ └─────────┘ └────────┘ │ │ │ │ │ │ │ │ └───────────┴───────────┴──────────┘ │ │ │ │ │ ld │ │ │ │ │ ┌──────────────┐ │ │ │ app(ELF)│ │ │ │ 或 .so / .a │ │ │ └──────────────┘ │ │ │ └──────────────────────────────────────────────────────────────┘aarch64-linux-gnu-objdump作用: 反汇编/分析工具——把 .o / .elf / .ko / .so 里的二进制机器码还原成人类可读的汇编指令同时能看到段、符号、重定位等结构信息┌──────────────────────────────────────────────────────────────┐ │ objdump 在工具链中的定位 │ ├──────────────────────────────────────────────────────────────┤ │ │ │ 正向(构建): │ │ .c → .s → .o → .elf │ │ cc1 as ld │ │ │ │ 逆向(分析): │ │ .elf / .o / .ko / .so → 人类可读信息 │ │ objdump │ │ │ │ 它是编译的逆过程让你看到编译器到底生成了什么 │ └──────────────────────────────────────────────────────────────┘常用命令┌──────────────────────────────────────────────────────────────┐ │ aarch64-linux-gnu-objdump 选项分类 │ ├────────────┬─────────────────────────────────────────────────┤ │ 反汇编 │ │ ├────────────┼─────────────────────────────────────────────────┤ │-d│ 反汇编所有有机器码的段(最常用)│ │-D│ 反汇编所有段(包括 .data, 会误读数据为指令)│ │-S│ 源码汇编交错显示(需要-g编译)│ │-C│ C 函数名 demangle │ │-Mintel │ 用 Intel 语法(ARM64 不太适用, x86 用的)│ │-jSECTION │ 只反汇编指定段:-j.text-j.init.text │ │ --start-addressADDR │ 从指定地址开始 │ │ --stop-addressADDR │ 到指定地址结束 │ ├────────────┼─────────────────────────────────────────────────┤ │ 段/头 │ │ ├────────────┼─────────────────────────────────────────────────┤ │-h│ 显示所有段头(名称、大小、地址、对齐)│ │-x│ 显示所有头信息(ELF 头 段 程序头 符号)│ │-f│ 只显示 ELF 头(架构、入口点等)│ ├────────────┼─────────────────────────────────────────────────┤ │ 符号/重定位 │ │ ├────────────┼─────────────────────────────────────────────────┤ │-t│ 符号表 │ │-T│ 动态符号表(.dynsym, .so 用)│ │-r│ 重定位条目(.o 用, 看链接前需要修正的引用)│ │-R│ 动态重定位(.so 用)│ ├────────────┼─────────────────────────────────────────────────┤ │ 组合常用 │ │ ├────────────┼─────────────────────────────────────────────────┤ │-dr│ 反汇编 重定位(看 .o 里符号怎么引用的)│ │-dS│ 反汇编 源码(调试必备)│ │-dh│ 段头 反汇编 │ │-dx│ 全头信息 反汇编 │ └────────────┴─────────────────────────────────────────────────┘基本格式解读aarch64-linux-gnu-objdump-dvmlinux|head-40vmlinux:fileformatelf64-littleaarch64 ← 文件格式 Disassembly of section .text: ← 当前段 ffff800010000000_text: ← 符号名和地址 ffff800010000000: d503201f nop ← 地址 机器码 汇编 ffff800010000004: d503201f nop ffff800010000008_start: ffff800010000008: d53800a0 mrs x0, mpidr_el1 ffff80001000000c:92400400and x0, x0,#0xffffff800010000010: 540000a1 b.ne ffff800010000024.Lsecondaryffff800010000014:58000140ldr x0, ffff80001000003c_stack_top┌─────────────────────────────────────────────────────────────┐ │ ffff800010000008: d53800a0 mrs x0, mpidr_el1 │ │ ──────────────── ──────── ───────────────── │ │ 地址 机器码 汇编指令 │ │ │ │ 地址: 该指令在 ELF 中的虚拟地址 │ │ 机器码:4字节(ARM64 固定指令长度)│ │ 汇编: objdump 还原的人类可读形式 │ │ │ │ ARM64 特点: 所有指令4字节, 没有变长指令 │ │(对比 x86 的1-15 字节变长指令)│ └─────────────────────────────────────────────────────────────┘使用场景 :aarch64-linux-gnu-objdump -d 二进制aarch64-linux-gnu-objcopy作用: 目标文件格式转换/内容编辑工具——把 ELF 里的段提取、删除、重命名、转换格式或者把原始二进制包装成ELF。它不反汇编、不链接纯粹操作二进制结构底层原理:┌──────────────────────────────────────────────────────────────┐ │ objcopy 在工具链中的定位 │ ├──────────────────────────────────────────────────────────────┤ │ as:.s → .o(汇编)│ │ ld:.o → .elf(链接)│ │ objdump:.elf → 人类可读(分析/反汇编)│ │ objcopy:.elf → .bin/.hex/.elf(格式转换/段编辑)│ │ │ │ 它操作的是容器的结构和内容, 不是代码语义 │ │ │ │ ┌──────────┐ │ │ │ ELF │ │ │ │ ┌──────┐ │ objcopy ┌──────────┐ │ │ │ │.text │ │ ────────────▶ │ raw bin │ │ │ │ │.data │ │ 去掉 ELF 头 │(纯机器码)│ │ │ │ │.bss │ │ 提取纯负载 │ │ │ │ │ └──────┘ │ └──────────┘ │ │ │ ELF头 │ │ │ │ 段头表 │ │ │ │ 符号表 │ ← 这些元数据全去掉 │ │ └──────────┘ │ └──────────────────────────────────────────────────────────────┘aarch64-linux-gnu-readelf作用: ELF 结构专读工具——只读不改比 objdump -x 更清晰、更专一地展示 ELF 文件的每一个结构文件头、段头、程序头、符号表、动态段、重定位、note 段、DWARF 调试信息……全部逐字段解析┌──────────────────────────────────────────────────────────────┐ │ readelf 在工具链中的定位 │ ├──────────────────────────────────────────────────────────────┤ │ │ │ objcopy →搬砖工格式转换、段编辑 │ │ objdump →分析师反汇编 源码对照 │ │ readelf →体检员只读, 把 ELF 结构完整展开 │ │ nm →查号台查符号地址 │ │ │ │ readelf 不关心机器码语义, 它只关心: │ │这个 ELF 的结构是什么? 各字段值是多少?│ │ │ │ ┌───────────────────────────────────────┐ │ │ │ ELF 文件 │ │ │ │ │ │ │ │ ┌─────┐ ← ELF Header ←-h│ │ │ │ │ │ │ │ │ │ ├─────┤ ← Program Headers ←-l│ │ │ │ │ │ │ │ │ │ ├─────┤ ← Section Headers ←-S│ │ │ │ │ │ │ │ │ │ ├─────┤ ← Symbol Table ←-s│ │ │ │ │ │ │ │ │ │ ├─────┤ ← Relocations ←-r│ │ │ │ │ │ │ │ │ │ ├─────┤ ← Dynamic Section ←-d│ │ │ │ │ │ │ │ │ │ ├─────┤ ← Debug Info ← --debug│ │ │ │ │ │ │ │ │ │ └─────┘ │ │ │ └───────────────────────────────────────┘ │ └──────────────────────────────────────────────────────────────┘使用场景快速确认架构:aarch64-linux-gnu-readelf -h app运行时找不到 .so — 检查动态依赖aarch64-linux-gnu-readelf -a app | grep -i need看动态链接器路径对不对:aarch64-linux-gnu-readelf -l app | grep -i interpreter看 RPATH (编译时指定的库搜索路径):aarch64-linux-gnu-readelf -a app | grep -iE RPATH|RUNPATH┌──────────────────────────────────────────────────────────────┐ │ │ │ readelf →体检员查 ELF 结构, 只读不改 │ │ objdump →分析师反汇编 源码对照 │ │ objcopy →搬砖工格式转换、段提取/裁剪 │ │ nm →查号台符号地址速查 │ │ strip →瘦身工删符号/调试信息 │ │ │ │ 典型调试流水线: │ │ │ │板子上程序跑不了│ │ │ │ │ ├── readelf-h→ 架构对吗? │ │ ├── readelf-d→ 缺哪个 .so? │ │ ├── readelf-l→ 动态链接器/对齐对吗? │ │ ├── readelf-A→ 浮点 ABI 一致吗? │ │ └── readelf-V→ glibc 版本够吗? │ │ │ │crash 了, 只有 PC 地址│ │ │ │ │ ├── nm → 找函数基地址 │ │ ├── objdump-dS→ 反汇编定位 C 行号 │ │ └── readelf-S→ 确认段地址范围 │ │ │ │需要反汇编板子 dump│ │ │ │ │ ├── objcopy-Ibinary → 包装成 ELF │ │ ├── objdump-d→ 反汇编 │ │ └── readelf-h→ 确认包装正确 │ │ │ │固件太大了│ │ │ │ │ ├── readelf-S→ 看哪个段大 │ │ ├── nm --size-sort → 找最大符号 │ │ └── objcopy --strip-debug → 去调试信息 │ │ │ └──────────────────────────────────────────────────────────────┘aarch64-linux-gnu-nm作用: 符号表速查工具——从 .o / .elf / .ko / .so / .a 中列出所有符号的名称、地址、类型、大小。它是工具链中最轻量、最高频使用的一个——一行命令就能定位谁在哪、多大、什么类型。┌──────────────────────────────────────────────────────────────┐ │ nm 在工具链中的定位 │ ├──────────────────────────────────────────────────────────────┤ │ │ │ readelf →体检员全结构展开, 逐字段解析 │ │ objdump →分析师反汇编 源码对照 │ │ objcopy →搬砖工格式转换、段编辑 │ │ nm →查号台只查符号, 最快最轻 │ │ │ │ 不关心段布局, 不关心机器码, 不关心 ELF 头 │ │ 只回答一个问题: │ │这个文件里有什么符号?│ │ │ │ ┌─────────────────────────────────────────┐ │ │ │ 符号表 │ │ │ │ │ │ │ │ i2c_dw_xfer T ffff80001001a000│ │ │ │ DW_IC_RAW_INTR_STAT R 0000 │ │ │ │ dev-base ?(需要外部提供)│ │ │ │ │ │ │ │ nm 把这张表用最简洁格式列出来 │ │ │ └─────────────────────────────────────────┘ │ │ │ └──────────────────────────────────────────────────────────────┘