aarch64-linux-gnu* (gcc,ld,objcopy,objdump)工具总结

aarch64-linux-gnu* (gcc,ld,objcopy,objdump)工具总结

文章目录

aarch64-linux-gnu 工具链家族

sh 复制代码
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二进制(目标板)

  • 使用场景

    1. 内核编译, 在编译脚本加入make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu-

    2. 普通Makefile中

      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) ...
    3. 用户态程序, 执行aarch64-linux-gnu-gcc -o test_i2c test_i2c.c 生成 ARM64 ELF 二进制

  • 底层原理

    和普通的gcc的区别在于编译阶段, aarch64的gcc会自动去找glibc

    shell 复制代码
      ┌───────────────────────────────────────────────────────────────┐
      │              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                   │
      │                                                               │
      └───────────────────────────────────────────────────────────────┘
  • 验证工具链

    shell 复制代码
    # 查看版本
    aarch64-linux-gnu-gcc --version
    
    # 查看默认搜索路径 (sysroot, 库路径等)
    aarch64-linux-gnu-gcc -print-search-dirs
    
    # 检查编译出的二进制是否为 AArch64
    aarch64-linux-gnu-readelf -h your_binary | grep Machine
    # → Machine: AArch64
    
    # 查看链接了哪些共享库
    aarch64-linux-gnu-readelf -a your_binary | grep NEEDED
    
    # 显示编译器配套库的名称
    aarch64-linux-gnu-gcc --print-libgcc-file-name 

aarch64-linux-gnu-as

  • 作用: as 是 GNU Assembler(GAS),把汇编源文件(.s / .S)翻译成目标文件(.o)

  • 应用场景

    • 汇编一个文件: aarch64-linux-gnu-as -o hello.o hello.s
    • 生成调试信息: aarch64-linux-gnu-as -g -o hello.o hello.s
  • 底层原理

    shell 复制代码
    ┌──────────────────────────────────────────────────────┐
    │                  编译流水线中的位置                     │
    ├──────────────────────────────────────────────────────┤
    │                                                      │
    │  .c ──▶ cpp ──▶ cc1 ──▶ as ──▶ ld ──▶ ELF            │
    │         预处理    编译    汇编    链接                  │
    │                    │      ↑                          │
    │                    │      │                          │
    │                生成 .s    你在这里                     │
    │                (汇编)     直接写 .s 时用到              │
    │                                                      │
    │  两种来源:                                            │
    │  1. gcc -S 自动调 cc1 生成 .s,再隐式调 as 生成 .o       │
    │  2. 手写 .s/.S,直接调 as                              │
    └──────────────────────────────────────────────────────┘

aarch64-linux-gnu-ld

  • 作用: GNU Linker(ld),把多个 .o 目标文件 + 库合并成最终的可执行文件或共享库。交叉版------在 x86 上链接出 AArch64 ELF

  • 应用场景

    1. 链接几个 .o 成可执行文件 aarch64-linux-gnu-ld -o app boot.o main.o utils.o
  • 内核中的链接脚本

    shell 复制代码
    ┌──────────────────────────────────────────────────────────────┐
    │           内核 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)                         │
    └──────────────────────────────────────────────────────────────┘
  • 底层原理

    shell 复制代码
    ┌──────────────────────────────────────────────────────────────┐
    │                    编译流水线中 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 里的二进制机器码还原成人类可读的汇编指令,同时能看到段、符号、重定位等结构信息

    shell 复制代码
    ┌──────────────────────────────────────────────────────────────┐
    │              objdump 在工具链中的定位                           │
    ├──────────────────────────────────────────────────────────────┤
    │                                                              │
    │  正向 (构建):                                                 │
    │  .c → .s → .o → .elf                                         │
    │   cc1   as    ld                                             │
    │                                                              │
    │  逆向 (分析):                                                 │
    │  .elf / .o / .ko / .so → 人类可读信息                          │
    │         objdump                                              │
    │                                                              │
    │  它是"编译的逆过程",让你看到编译器到底生成了什么                    │
    └──────────────────────────────────────────────────────────────┘
  • 常用命令

    shell 复制代码
    ┌──────────────────────────────────────────────────────────────┐
    │           aarch64-linux-gnu-objdump 选项分类                  │
    ├────────────┬─────────────────────────────────────────────────┤
    │ 反汇编      │                                                 │
    ├────────────┼─────────────────────────────────────────────────┤
    │ -d         │ 反汇编所有有机器码的段 (最常用)                      │
    │ -D         │ 反汇编所有段 (包括 .data, 会误读数据为指令)          │ 
    │ -S         │ 源码+汇编交错显示 (需要 -g 编译)                 	 │
    │ -C         │ C++ 函数名 demangle                              │
    │ -M intel   │ 用 Intel 语法 (ARM64 不太适用, x86 用的)           │
    │ -j SECTION │ 只反汇编指定段: -j .text -j .init.text            │
    │ --start-address=ADDR │ 从指定地址开始                          │
    │ --stop-address=ADDR  │ 到指定地址结束                          │
    ├────────────┼─────────────────────────────────────────────────┤
    │ 段/头       │                                                 │
    ├────────────┼─────────────────────────────────────────────────┤
    │ -h         │ 显示所有段头 (名称、大小、地址、对齐)                 │
    │ -x         │ 显示所有头信息 (ELF 头 + 段 + 程序头 + 符号)         │
    │ -f         │ 只显示 ELF 头 (架构、入口点等)                      │
    ├────────────┼─────────────────────────────────────────────────┤
    │ 符号/重定位  │                                                 │
    ├────────────┼─────────────────────────────────────────────────┤
    │ -t         │ 符号表                                           │
    │ -T         │ 动态符号表 (.dynsym, .so 用)                      │
    │ -r         │ 重定位条目 (.o 用, 看链接前需要修正的引用)            │
    │ -R         │ 动态重定位 (.so 用)                               │
    ├────────────┼─────────────────────────────────────────────────┤
    │ 组合常用    │                                                 │
    ├────────────┼─────────────────────────────────────────────────┤
    │ -dr        │ 反汇编 + 重定位 (看 .o 里符号怎么引用的)             │
    │ -dS        │ 反汇编 + 源码 (调试必备)                           │
    │ -dh        │ 段头 + 反汇编                                     │
    │ -dx        │ 全头信息 + 反汇编                                 │
    └────────────┴─────────────────────────────────────────────────┘
  • 基本格式解读

    shell 复制代码
    aarch64-linux-gnu-objdump -d vmlinux | head -40
    
    vmlinux:     file format elf64-littleaarch64    ← 文件格式
    
    Disassembly of section .text:                  ← 当前段
    
    ffff800010000000 <_text>:                      ← 符号名和地址
    ffff800010000000:   d503201f    nop             ←  地址   机器码   汇编
    ffff800010000004:   d503201f    nop
    
    ffff800010000008 <_start>:
    ffff800010000008:   d53800a0    mrs  x0, mpidr_el1
    ffff80001000000c:   92400400    and  x0, x0, #0xff
    ffff800010000010:   540000a1    b.ne ffff800010000024 <.Lsecondary>
    ffff800010000014:   58000140    ldr  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。它不反汇编、不链接,纯粹操作二进制结构

  • 底层原理:

    shell 复制代码
    ┌──────────────────────────────────────────────────────────────┐
    │              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 调试信息......全部逐字段解析

    shell 复制代码
    ┌──────────────────────────────────────────────────────────────┐
    │              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"

      shell 复制代码
      ┌──────────────────────────────────────────────────────────────┐
      │                                                              │
      │  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 -I binary → 包装成 ELF                        │
      │    ├── objdump -d → 反汇编                                   │
      │    └── readelf -h → 确认包装正确                              │
      │                                                              │
      │  "固件太大了"                                                 │
      │    │                                                         │
      │    ├── readelf -S → 看哪个段大                                │
      │    ├── nm --size-sort → 找最大符号                            │
      │    └── objcopy --strip-debug → 去调试信息                      │
      │                                                              │
      └──────────────────────────────────────────────────────────────┘

aarch64-linux-gnu-nm

  • 作用: 符号表速查工具------从 .o / .elf / .ko / .so / .a 中列出所有符号的名称、地址、类型、大小。它是工具链中最轻量、最高频使用的一个------一行命令就能定位"谁在哪、多大、什么类型"。

    shell 复制代码
    ┌──────────────────────────────────────────────────────────────┐
    │              nm 在工具链中的定位                                │
    ├──────────────────────────────────────────────────────────────┤
    │                                                              │
    │  readelf → "体检员"   全结构展开, 逐字段解析                     │
    │  objdump → "分析师"   反汇编 + 源码对照                         │
    │  objcopy → "搬砖工"   格式转换、段编辑                          │
    │  nm      → "查号台"   只查符号, 最快最轻                         │
    │                                                              │
    │  不关心段布局, 不关心机器码, 不关心 ELF 头                        │
    │  只回答一个问题:                                               │
    │    "这个文件里有什么符号?"                                      │
    │                                                              │
    │  ┌─────────────────────────────────────────┐                 │
    │  │ 符号表                                  │                  │
    │  │                                         │                 │
    │  │   i2c_dw_xfer        T  ffff80001001a000│                 │
    │  │   DW_IC_RAW_INTR_STAT R  0000           │                 │
    │  │   dev->base          ?  (需要外部提供)   │                  │
    │  │                                         │                 │
    │  │ nm 把这张表用最简洁格式列出来             │                   │
    │  └─────────────────────────────────────────┘                 │
    │                                                              │
    └──────────────────────────────────────────────────────────────┘
相关推荐
A.说学逗唱的Coke1 小时前
【运维专题】playbooks保姆级使用指南
运维·开发语言·python
豆是浪个1 小时前
Linux(Centos 7.6)命令详解:xargs
linux·运维·服务器
shchojj2 小时前
gitlab推送触发jekins编译
运维·gitlab
Java开发追求者2 小时前
oracle解决服务器正常使用但是互联网无法使用问题
运维·服务器·ora-12154·windows监听问题·oracle互联网无法访问
日取其半万世不竭2 小时前
Palworld《幻兽帕鲁》 服务器搜不到怎么办?端口和防火墙排查清单
运维·服务器
大树882 小时前
一滴冷却液,烧掉2000万算力
大数据·运维·服务器·人工智能
qq_366566502 小时前
内容出海工具链搭建实战:从0到CI/CD自动化
运维·ci/cd·自动化
李白的天不白2 小时前
服务器地址在哪里 pwd
运维·前端·nginx
AC赳赳老秦2 小时前
技术文章素材收集自动化:用 OpenClaw 自动爬取行业资讯、技术热点、优质文章
运维·开发语言·python·自动化·wpf·deepseek·openclaw