[智能芯片] 可执行文件分析

《智能芯片》课程笔记:可执行文件分析

📋 目录

  1. 获取汇编代码与机器码
  2. 获取函数与变量的地址
  3. 分析工具使用说明
  4. 实例解析

获取汇编代码与机器码

🔧 objdump 工具简介

属性 说明
工具名称 riscv64-unknown-elf-objdump.exe
核心功能 对 ELF 可执行文件进行反汇编,提取汇编代码与机器码
适用场景 分析编译后程序的底层实现、调试、学习指令集

📌 基本使用命令

# 1. 直接在终端显示反汇编结果
riscv64-unknown-elf-objdump.exe -S example.elf

# 2. 将结果重定向保存到文件(推荐)
riscv64-unknown-elf-objdump.exe -S example.elf > example.S.txt

💡 -S 选项:混合显示源代码、汇编代码和机器码,便于对照理解

📖 反汇编输出格式示例解读

image-20260314132349982

🎨 颜色/内容对照表

颜色/位置 内容类型 说明
⚫ 黑色 C源代码 原始高级语言代码
🟢 绿色 存储地址 机器码在内存中的起始地址
🔴 红色 机器码 汇编指令对应的16进制机器码
🔵 蓝色 汇编代码 编译生成的RISC-V汇编指令
⚪ 灰色 注释 编译器添加的辅助信息

获取函数与变量的地址

❓ 问题背景

上一节范例程序中定义了:

  • 变量f, s, t, p, q, a, b
  • 函数main, fun1, fun2

🎯 目标:如何获取这些符号在内存中的具体地址?


🔍 方法一:通过 .map 文件(编译时生成)

📌 前提条件

编译时需添加 -Wl,-Map=example.map 选项:

riscv64-unknown-elf-gcc.exe -march=rv32i -mabi=ilp32 -Wall -O1 -g -nostartfiles -T linker_script_onestep.ld -Wl,-Map=example.map -o example.elf startup.s fun.c main.c

📄 example.map 文件内容截取

上一节生成的 example.map 为例。

.text           0x000000000000004c       0xdc
 *(.text)
 .text          0x000000000000004c        0x0 C:\Users\*****\AppData\Local\Temp\ccXSS4dc.o
 .text          0x000000000000004c       0x64 C:\Users\Lenovo\AppData\Local\Temp\ccNYCzQf.o
                0x000000000000004c                fun1
                0x000000000000006c                fun2
 .text          0x00000000000000b0       0x78 C:\Users\*****\AppData\Local\Temp\ccycWyFb.o
                0x00000000000000b0                main
                0x0000000000000128                . = ALIGN (0x4)
.data           0x0000000000000400        0xc load address 0x0000000000000128
                0x0000000000000400                PROVIDE (_data_start = .)
 *(.data)
 .data          0x0000000000000400        0x0 C:\Users\Lenovo\AppData\Local\Temp\ccXSS4dc.o
 .data          0x0000000000000400        0x0 C:\Users\Lenovo\AppData\Local\Temp\ccNYCzQf.o
 .data          0x0000000000000400        0x0 C:\Users\Lenovo\AppData\Local\Temp\ccycWyFb.o
 *(.sdata)
 .sdata         0x0000000000000400        0xc C:\Users\Lenovo\AppData\Local\Temp\ccycWyFb.o
                0x0000000000000400                a
                0x0000000000000404                p
                0x0000000000000406                s
                0x0000000000000408                f
                0x000000000000040c                . = ALIGN (0x4)
                0x000000000000040c                PROVIDE (_data_end = .)
                0x000000000000040c                PROVIDE (_bss_start = .)

.bss            0x000000000000040c        0x8
 *(.bss)
 .bss           0x000000000000040c        0x0 C:\Users\Lenovo\AppData\Local\Temp\ccXSS4dc.o
 .bss           0x000000000000040c        0x0 C:\Users\Lenovo\AppData\Local\Temp\ccNYCzQf.o
 .bss           0x000000000000040c        0x0 C:\Users\Lenovo\AppData\Local\Temp\ccycWyFb.o
 *(.sbss*)
 .sbss          0x000000000000040c        0x4 C:\Users\Lenovo\AppData\Local\Temp\ccNYCzQf.o
                0x000000000000040c                b
 .sbss          0x0000000000000410        0x4 C:\Users\Lenovo\AppData\Local\Temp\ccycWyFb.o
                0x0000000000000410                q
                0x0000000000000412                t
 *(COMMON)
                0x0000000000000414                . = ALIGN (0x4)
                0x0000000000000414                PROVIDE (_bss_end = .)

📊 提取的地址信息

类型 符号 地址(16进制)
🔹 函数 fun1 0x4c
🔹 函数 fun2 0x6c
🔹 函数 main 0xb0
🔸 变量 a 0x400
🔸 变量 p 0x404
🔸 变量 s 0x406
🔸 变量 f 0x408
🔸 变量 b 0x40c
🔸 变量 q 0x410
🔸 变量 t 0x412

🔍 方法二:使用 nm 工具(分析已编译文件)

📌 使用命令

riscv64-unknown-elf-nm.exe example.elf

📄 输出示例

00000400 A __RAM_BASE
00000400 A __RAM_SIZE
00000000 A __ROM_BASE
00000400 A __ROM_SIZE
00000200 A __STACK_SIZE
00000414 B _bss_end
0000040c D _bss_start
0000040c D _data_end
00000128 T _data_lma
00000400 D _data_start
00000800 B _sp
00000000 T _start
00000400 D a
0000040c B b
00000408 D f
0000004c T fun1
0000006c T fun2
000000b0 T main
00000404 D p
00000410 B q
00000406 D s
00000412 B t

🔑 符号类型说明(第2列字母)

字母 含义 对应段
T / t 文本段(Text)函数 .text,代码区
D / d 数据段(Data)已初始化全局/静态变量 .data
B / b BSS段未初始化全局/静态变量 .bss
A 绝对地址符号,不可重定位 -
U 未定义符号(需链接时解析) -

💡 大写表示全局符号(外部可见),小写表示局部符号(文件内可见)


反汇编代码实例解析 🧪

📝 反汇编代码片段

080000a8<fun1>:
int fun1(int x, int y, float z)
{ 
    char* p = (char*)&a; 
    
    *(p+6) = 0xA9; 
80000a8: 200007b7 lui   a5,0x20000
80000ac: 00478793 addi  a5,a5,4       # a5 = &a
80000b0: fa900713 li   	a4,-87        # a4 = 0xA9
80000b4: 00e78323 sb   	a4,6(a5)      # *(p+6) = 0xA9
    
    *(p+7) = 0x42; 
80000b8: 04200713 li   	a4,66         # a4 = 0x42
80000bc: 00e783a3 sb   	a4,7(a5)      # *(p+7) = 0x42
    
    return y; 
80000c0: 00058513 mv   	a0,a1         # 返回值 = y
80000c4: 00008067 ret                 # 函数返回
}

❓ 问题与解答

问题 解答 分析过程
(1) fun1函数地址? 0x80000a8 函数标签 <fun1> 后的起始地址
(2) 机器码占用字节数? 32 Bytes 0x80000c7 - 0x80000a8 + 1 = 31+1 = 32
(3) 地址 0x80000ae 存储值? 0x47 机器码 00478793 小端存储:[ac]=93, [ad]=87, [ae]=47, [af]=00
(4) *(p+7)=0x42 实现方式? 2条汇编指令,8字节机器码 li a4,66 (4B) + sb a4,7(a5) (4B)

🔍 小端模式(Little-Endian)存储示意

机器码:00478793(32位,16进制)

内存地址(低→高):  80000ac  80000ad  80000ae  80000af
存储内容(16进制):   93       87       47       00
                     ↑低字节                    ↑高字节

💡 RISC-V 采用小端模式:低字节存低地址,高字节存高地址


拓展:分析工具使用说明 🛠️

📦 Binutils 工具集概览

工具 功能 常用场景
objdump 反汇编、查看段信息 分析机器码与汇编对应关系
nm 列出符号表 查找函数/变量地址
size 显示各段大小 分析程序内存占用
objcopy 格式转换、提取段 生成bin/hex文件用于烧录
readelf 解析ELF文件结构 深入理解可执行文件格式

🔎 查看工具帮助信息

# 通用方法:添加 --help 参数
riscv64-unknown-elf-objdump.exe --help
riscv64-unknown-elf-nm.exe --help

# 查看特定选项说明
riscv64-unknown-elf-objdump.exe --help | grep -i "disassemble"

🎯 常用组合命令示例

# 1. 反汇编并过滤特定函数
riscv64-unknown-elf-objdump -S example.elf | grep -A 20 "<fun1>:"

# 2. 查看所有全局符号地址
riscv64-unknown-elf-nm -g example.elf

# 3. 查看程序各段大小
riscv64-unknown-elf-size example.elf
# 输出:text    data     bss     dec     hex filename
#      1234     567      89    1890     762 example.elf

# 4. 提取纯机器码(二进制格式)
riscv64-unknown-elf-objcopy -O binary example.elf example.bin

笔记整理基于《智能芯片》课程课件,适用于《智能芯片》课程学习参考 🚀

📚 主讲人:柳星

📧 邮箱:liu.xing@whut.edu.cn

🎯 课程核心:理解可执行文件的内部结构与分析方法

posted @ 2026-03-14 14:11  H_Elden  阅读(1)  评论(0)    收藏  举报