zboralski/agx

GitHub: zboralski/agx

针对 Apple AGX GPU 指令集的逆向工程工具,提供静态反汇编、结构执行与分析能力。

Stars: 1 | Forks: 0

# agx 针对 Apple AGX GPU 二进制文件的静态反汇编器、汇编器和模拟器。 ## 概述 agx 是用于 Apple AGX(G15-G18 类)GPU 指令流的逆向工程工具包。 它将不透明的二进制文件转换为可读内容。 Apple 未发布 AGX3 指令集的规范。此处的解码和命名来源于观察编译后的二进制文件,并逐步缩小每条指令的可能行为范围。在实践中,这意味着构建一个可工作的模型,在大量真实着色器上进行测试,并排除不成立的解释。 最终结果并非官方规范,而是对 ISA 的一致且可用的视图。 ### ISA 基础 AGX3(M3-M5)使用固定宽度的 32 位指令字,按 VLIW 子句组织。 每个子句以序言开始,包含 ALU、内存和控制流指令的混合,并以尾声或终止符结束。这与早期代(G13/M1、G14/M2)使用的变长格式不同。 解码表覆盖 12 种格式的 262 条指令条目。针对系统框架、MPS、MLX、CoreImage 和 Xcode 着色器中的 10M+ 条指令进行了测试,零解码失败。 ### 前期工作 - [Dougall Johnson](https://github.com/dougallj/applegpu) 通过手动反汇编记录了 G13(M1)ISA - [Mesa/Asahi](https://docs.mesa3d.org/drivers/asahi.html) 反向工程了 G13/G14 以构建其开源驱动 本工具覆盖后续架构 G15-G18(M3-M5),其采用不同的固定宽度编码,现有工具无法处理。 ## 功能 ### 快速解码 约 12M 指令/秒(单条解码),约 2M 指令/秒(完整语料库),在 Apple Silicon 上运行。 78 纳秒/条,21 字节/条,每条指令 2 次分配。 ### 规范指令命名 分离: - 指令做什么(`fadd`、`fmul`) - 与硬件如何执行它(`alu`、`cf`、`reg`) 因为这两者并不相同。 ### 可读输出 ``` 0x0050 00290000 fadd r0, r0, {m:0x00} ; Float add 0x0054 802a1005 alu r8, #5, #8 ; FMA config r8 ``` LowALU `fadd` 形式始终将其第三操作数槽暴露为 `{m:0xNN}`(修饰符/选择器位)。这些位的确切语义(立即数、常量表选择器、源宽度标志)是特定于操作码的且未完全记录;该槽位以诚实的方式显示而非丢弃。 流水线配置注解如 `FMA config` 或 `Extended math` 用于标识指令所属的流水线阶段,而非其完整的算术语义。 超越运算 / FMA 链可见为结构序列,但该链中每个修饰符字段的确切作用仍不完整。 显示的是“实际运行了什么”,而非“如何编码”。 ### 原始模式 ``` agxdis -raw file.bin ``` 展示硬件实际看到的内容: ``` fma.cfg r8, #5, #8 ``` 可读性较低,但更忠实。 ### 分析 除了反汇编,agx 还提供编译着色器的结构分析: - **控制流图** - 基本块、边、子句配对、分裂区域 - **支配树** - Cooper-Harvey-Kennedy 迭代算法 - **循环检测** - 通过回边分类的自然循环 - **寄存器生命周期** - 定义/使用跟踪、死写、压力分析 - **谓词分类** - 检测谓词控制流与分支控制流 - **子句模型** - VLIW 子句边界与配对链接 ### 输出格式 ``` agxdis file.bin # annotated disassembly (default) agxdis -raw file.bin # decode-level names agxdis -cfg file.bin # control flow graph (Graphviz dot) agxdis -trace file.bin # execution trace (JSON) agxdis -summary file.bin # instruction mix summary ``` ## 设计 ### 规范与原始 同一机器的两种视图: | 模式 | 输出 | |------|------| | 规范 | `alu r8, #5, #8` | | 原始 | `fma.cfg r8, #5, #8` | 一个告诉你发生了什么,另一个告诉你如何发生。 ### 命名模型 指令分为: - **语义**:`fadd`、`fmul`、`ld.dev`、`atom`、`sel`、`barrier` - **结构**:`alu`、`cf`、`reg`、`mem`、`nop`、`end` 规范输出避免泄露流水线阶段、生成特性和解码 artifacts。设置流水线状态的配置指令标记为 `alu`,而非赋予计算名称。若注释显示“config”,助记符则为 `alu`。 ### 执行模型 agxemu 提供单一结构执行引擎。`Execute()` 将指令流拆分为 VLIW 子句,逐条处理指令,跟踪寄存器读写与流水线状态,生成包含子句级结构、寄存器生命周期和依赖边的 `Trace`。 由此可构建 CFG、计算支配树、检测循环,并对谓词模式进行分类。一次执行,多种投影。 ## 用法 ### 反汇编 ``` agxdis shader.bin # raw ISA stream agxdis shader.gpuarchive # fat Mach-O GPU archive agxdis shader.metallib # compile + disassemble all functions agxdis shader.metallib my_kernel # single function ``` ### 分析 ``` agxdis -cfg shader.bin # CFG as Graphviz dot agxdis -trace shader.bin # execution trace as JSON agxdis -cfg shader.bin | dot -Tpng -o cfg.png # render CFG ``` ### 跨架构比较 ``` agxdis -diff shader.metal kernel_name # all default targets agxdis -diff shader.metal kernel_name M4 M5 # 2-way comparison agxdis -diff shader.metal kernel_name M3 A18Pro # M3 vs A18 Pro ``` 需要 Metal 工具链(Xcode)。 ### 目标平台 | 目标 | GPU | |-------|------| | M3 | G15 | | M3Pro | G15s | | M3Max | G15d | | M4 | G16 | | A18 | G16p | | M4Pro | G16s | | A18Pro| G17p | | M5 | G17 | | M5Pro | G17s | | A19Pro| G18p | 目标平台根据本地环境自动解析。若目标与当前机器匹配,则使用运行时编译;否则,Metal 工具链会离线编译对应目标。 支持在 ISA 层面定义。同一 GPU 类别内的变体(例如 Pro/Max)共享相同的指令编码。 ### CLI 标志 | 标志 | 描述 | |------|------| | `-raw` | 显示解码层级的名称而非规范形式 | | `-cfg` | 以 Graphviz dot 格式输出 CFG | | `-trace` | 以 JSON 格式输出执行跟踪 | | `-clean` | 纯输出(无十六进制、无注释) | | `-no-comments` | 抑制注解注释 | | `-summary` | 附加指令混合摘要 | | `-diff` | 跨架构比较模式 | ## 示例 规范(`agxdis file.bin`): ``` 0x0040 0610a01c cf #0x10, #32, #4, #1 ; CF prologue [ALU] 0x0048 c0102218 00800041 st.dev #0x10, #0x2218, #0x800041 ; Device store sub=0 desc=0x10 [2w] 0x0050 00290000 fadd r0, r0, {m:0x00} ; Float add 0x0054 802a1005 alu r8, #5, #8 ; FMA config r8 0x0058 000b0aac fmul r12, r5, #4 ; Float multiply 0x005c 10000010 b .+0x20 ; Branch (fallthrough) -> 0x007c 0x0060 810b0102 math r14, #2, #0 ; Extended math r14 0x0068 000f0090 cf.branch r0, r1 ; Branch setup 0x006c 06010203 cf #1, #2, #3 ; CF return ``` 原始(`agxdis -raw file.bin`): ``` 0x0040 0610a01c cf #0x10, #32, #4, #1 ; CF prologue [ALU] 0x0048 c0102218 00800041 mem.store #0x10, #0x2218, #0x800041 ; Device store sub=0 desc=0x10 [2w] 0x0050 00290000 fadd r0, r0, {m:0x00} ; Float add 0x0054 802a1005 fma.cfg r8, #5, #8 ; FMA config r8 0x0058 000b0aac fmul r12, r5, #4 ; Float multiply 0x005c 10000010 b .+0x20 ; Branch (fallthrough) -> 0x007c 0x0060 810b0102 math.ext r14, #2, #0 ; Extended math r14 0x0068 000f0090 cf.bsetup r0, r1 ; Branch setup 0x006c 06010203 cf #1, #2, #3 ; CF return ``` CFG(`agxdis -cfg file.bin`): ``` digraph "shader" { rankdir=TB; node [shape=box fontname=monospace fontsize=10]; b0040 [label="0x0040\n6 insts"]; b0060 [label="0x0060\n4 insts"]; b0040 -> b0060 [style=dashed]; b0040 -> b0040 [label="loop" color=blue]; } ``` ## 安装 ``` go install github.com/zboralski/agx/cmd/agxdis@latest ``` ## 软件包 - `agxasm` - 解码、编码、格式化指令 - `agxemu` - 结构执行、CFG、寄存器分析、谓词分类 - `cmd/agxdis` - CLI 反汇编器 ### agxasm 解码并打印带注解的指令: ``` words := make([]uint32, len(data)/4) for i := range words { words[i] = binary.LittleEndian.Uint32(data[i*4:]) } insts, _ := agxasm.DecodeAll(words) for _, inst := range insts { fmt.Println(agxasm.FormatInstLineAnnotated(inst)) } ``` 往返:`decode(encode(decode(encode(raw)))) == raw` 对每条指令成立。 ``` insts, _ := agxasm.DecodeAll(words) for _, inst := range insts { encoded, _ := agxasm.Assemble(inst) // encoded[0] == inst.W[0] } ``` 在 5.9M 条指令上测试,0 不匹配。 ### agxemu 执行并检查结构跟踪: ``` insts, _ := agxasm.DecodeAll(words) state := agxemu.NewState() trace := agxemu.Execute(insts, state) fmt.Printf("instructions: %d\n", trace.NumInsts) fmt.Printf("clauses: %d\n", trace.NumClauses) fmt.Printf("halted: %v\n", trace.Halted) ``` 构建 CFG 并检测循环: ``` cfg := agxemu.BuildCFGFromTrace("shader", insts, trace) dt := agxemu.BuildDomTree(&cfg) loops := agxemu.DetectLoops(&cfg, dt) fmt.Printf("blocks: %d, loops: %d\n", len(cfg.Blocks), len(loops.Loops)) // Output CFG as Graphviz dot: fmt.Print(cfg.FormatDot()) ``` 寄存器生命周期分析: ``` metrics := agxemu.ComputeDataflowMetrics(trace) fmt.Printf("dead writes: %d (%.1f%%)\n", metrics.DeadWrites, metrics.DeadWritePct) ``` ### 关键类型 | 类型 | 包 | 描述 | |------|----|------| | `Inst` | agxasm | 解码后的指令:操作码、参数、字段 | | `Op` | agxasm | 指令操作码枚举(262 项) | | `InstFields` | agxasm | 解码后的位字段(零分配结构体) | | `State` | agxemu | 执行状态:寄存器、生命周期、流水线 | | `Trace` | agxemu | 执行跟踪:子句、步骤、依赖边 | | `CFGResult` | agxemu | 控制流图:块、边、分裂 | | `DomTree` | agxemu | 支配树 | | `LoopNest` | agxemu | 检测到的自然循环 | | `DataflowMetrics` | agxemu 寄存器压力、死写分析 | ### 关键函数 | 函数 | 包 | 描述 | |------|----|------| | `Decode` | agxasm | 从字流解码单条指令 | | `DecodeAll` | agxasm | 解码整个字流 | | `Assemble` | agxasm | 从解码后的指令重建原始字 | | `CanonicalName` | agxasm | 操作码的用户可见助记符 | | `FormatInstLineAnnotated` | agxasm | 带注解的完整反汇编行 | | `Execute` | agxemu | 在指令流上执行结构执行 | | `BuildCFGFromTrace` | agxemu | 从跟踪构建控制流图 | | `BuildDomTree` | agxemu | 计算支配树(Cooper-Harvey-Kennedy) | | `DetectLoops` | agxemu | 通过回边检测自然循环 | | `ExtractPredicationFeatures` | agxemu | 分类谓词模式 | | `ComputeDataflowMetrics` | agxemu | 寄存器压力和死写分析 | ## 支持的格式 | 格式 | 描述 | |------|------| | `.bin` | 原始 ISA 流 | | `.gpuarchive` | Fat Mach-O GPU 归档 | | `.metallib` | 运行时编译、提取、反汇编 | ### 获取二进制文件 GPU 着色器二进制文件无法直接访问磁盘。获取方式: 1. **从 Metal 源码编译**:`xcrun metal -c -o shader.air shader.metal && xcrun metallib -o shader.metallib shader.air` 2. **从应用中提取**:GPU 归档嵌入在应用包和框架中 3. **运行时捕获**:使用 `gpu_compile` 将 metallib 编译为本地 GPU 归档 agxdis 可直接处理 metallib 文件——它调用 `gpu_compile` 编译每个函数,提取其中的 ISA 并进行反汇编。 ## 要求 - Go 1.23+ - macOS 搭配 Xcode(用于 metallib 和跨架构功能) 检查当前工具链: ``` xcode-select -p xcrun metal --version ``` 若跨架构编译失败,请确认已选择正确的 Xcode。 ## 限制 - **推断的语义**:指令名称和行为来源于观察,非厂商文档。某些分类可能错误。 - **仅静态分析**:无动态 instrumentation,无 GPU 侧运行时探测。 - **结构执行**:模拟器追踪寄存器依赖与子句结构,而非数值结果。不模拟浮点运算。 - **覆盖缺口**:262 条指令条目中,52 条具有具体的 ALU 语义。其余约 200 条为流水线基础设施(调度、路由、配置),以状态转移和依赖跟踪执行。 - **ALU 形式的部分操作数语义**:LowALU 拥有第三操作数槽(修饰符/选择器位),其确切含义特定于操作码且未完全解码;该槽位以 `{m:0xNN}` 形式呈现而非隐藏。对于 FMA/超越流水线,结构化链可见,但链中每个修饰符字段的确切作用仍不完整。 - **不支持 M1/M2**:早期代(G13/G14)采用变长编码,本工具无法处理。请使用 [dougallj/applegpu](https://github.com/dougallj/applegpu)。 ## 状态 - decode:稳定(262 项,10M+ 条指令,零失败) - 汇编器:稳定(5.9M 条指令往返,0 不匹配) - 执行:统一模型(子句级 + 寄存器生命周期) - 分析:CFG、支配树、循环、谓词、数据流 - 命名:规范层已实现 - 跨架构:10 个 GPU 目标(M3-M5、A18-A19 Pro) v0.1 ## 许可证 MIT
标签:A18, A19, AGX, Apple M3, Apple M4, Apple M5, Asahi, CoreImage, EVTX分析, Findomain, GPU, GPU指令集, ISA, MLX, MPS, URL提取, VLIW, Wayback Machine, Xcode, 云资产清单, 反汇编, 反编译, 固定宽度指令, 开源驱动, 性能优化, 指令命名, 日志审计, 检测绕过, 汇编器, 着色器, 系统框架, 解码, 逆向工程, 高速解码