Decomp Academy:从GameCube游戏反编译到匹配C代码的完整课程
1. 课程概览
课程内容:阅读汇编(asm)·编写C代码·编译器逐字节评分。跳回 → 0 / 264 个匹配函数已重建 0 进行中 0 XP 新兵 已解决 已尝试 未开始 概念(阅读) 难度 1–5
2. 基础入门
I 热身 学习阅读机器代码 0 / 6 1 基础 从这里继续 什么是反编译、PowerPC寄存器、以及阅读MWCC输出。约30分钟 0 / 6 你的第一个匹配 继续 参数也存在于寄存器中 两个寄存器相加 减法反转其操作数 立即数:与常量进行数学运算 取反与零寄存器
3. 核心惯用法
II 核心惯用法 C编译成的每种形状 0 / 164 2 整数算术 加、减、乘、除、立即数和位操作惯用法。约164分钟 0 / 24 一个加法然后一个减法 两个加法,重新关联 一个减法然后一个加法 一个三指令链 两个寄存器相乘 乘以2的幂 乘以一个小常量 一个仿射表达式 无符号除以2的幂 有符号除以2的幂 真正的除法 取模没有指令 乘法然后加法 优先级改变顺序 两个乘积相减 一个三指令混合链 当乘法是移位时 混合链中的移位 除法然后加法 当除法是移位时 移位除法链 除法和乘法,然后减法 乘法和除法结合 所有四个算术运算符 3 位运算移位 AND/OR/XOR、掩码、移位以及MWCC喜爱的rlwinm家族。约122分钟 0 / 16 用AND掩码位 用OR组合位 用XOR翻转位 设置单个标志位 清除位:rlwinm的惊喜 测试位是否设置 左移常量 逻辑右移(无符号) 算术右移(有符号) 按变量量移位 用一个rlwinm提取位域 用移位和OR打包两个值 合并两个字段:rlwinm + rlwimi 跨三个值链接XOR 位选择(多路复用):AND、ANDC、OR 顶点:将三个值打包到一个字中 4 控制流 if/else、三元运算符、switch以及至关重要的有符号与无符号比较。约151分钟 0 / 19 将比较作为布尔值返回 不等于有自己的惯用法 If / Else:比较馈送分支 二进制补码、srawi和andc手动实现 概念 无分支钳位到零 有符号比较:cmpw 无符号比较:cmplw 与常量比较:cmpwi vs cmplwi 守卫子句/提前返回 三元最大值 三元最小值 短路与|| Switch:比较链 在两个边界之间钳位 if / else-if阶梯 用||拒绝超出范围的范围测试 多条件守卫 顶点:带守卫的钳位更新 5 循环 for、while、do-while、归纳变量和计数循环。约125分钟 0 / 15 计数循环的结构 While是同一个循环 Do-While:最紧凑的循环 向下计数更便宜 按索引遍历数组 寻找最大值 遍历指针到哨兵 提前跳出 心智模型:循环的五部分 概念 强度降低的归纳 内部有更多工作的循环 嵌套循环 在二维数组上嵌套 当内层边界跟随外层时 顶点:在网格扫描中计数对 6 类型 宽度 u8/s8/u16/s16 加载、符号与零扩展、以及宽度驱动的匹配,逐步构建到混合宽度和混合符号表达式。约141分钟 0 / 17 加载一个字节 加载一个半字 有符号加载符号扩展 存储一个字节截断 存储一个半字 u8,不是char(虚假的extsb) 加宽:零扩展与符号扩展 用掩码截断 符号扩展的强制转换 在有符号宽度之间转换 比较操作码跟随类型 增加一个字节计数器 读取、缩放、截断 一个有符号半字读-修改-写 组合两个宽度 一个表达式中的混合符号 顶点:一个函数中的宽度和符号 7 指针 内存加载和存储、寻址模式、指针算术和数组。约148分钟 0 / 18 解引用指针 通过指针存储 常量索引变为位移 在常量索引处写入 指针算术是缩放后的 变量索引需要缩放然后索引 字节数组不需要移位 半字数组移位1 遍历字符串 比较两个指针 防范NULL 通过指针交换 读取两个元素并组合 在组合前缩放一个元素 解引用,然后与参数计算 从计算偏移量索引邻居 在相同索引处组合两个数组 顶点:一个表达式中的多个解引用 8 结构体、联合体、位域 从单个字段到跨嵌套结构体、成员数组、联合体和位域组合多个字段。约168分钟 0 / 22 读取结构体字段 写入结构体字段 窄字段:字节和半字加载 存储字节字段 对齐填充移位偏移量 组合两个字段 跨三个字段计算 嵌套结构体展平为一个偏移量 跨嵌套结构体组合字段 结构体数组:缩放索引 结构体内部的数组 联合体重叠相同的字节 单比特标志:li;rlwimi 多比特位域写入 读取位域:rlwinm提取 遍历链表 通过函数指针调用 复制整个结构体 八字节对齐通过浮点寄存器复制 大结构体在循环中复制 将复制与字段更新结合 顶点:读取整个结构体 9 浮点数 f32 vs f64、frsp、融合乘加和浮点比较。约183分钟 0 / 23 浮点数存在于不同的寄存器文件中 单精度乘法 减法保持其顺序 浮点除法是真正的除法 除以常量变为乘法 双精度去掉's' ★ 虚假的frsp:f32 vs double 辅助函数 从SDA加载浮点常量 ★ 融合乘加 整数到浮点:魔法数字技巧 浮点到整数:fctiwz和存储/加载舞蹈 比较浮点数:fcmpo馈送分支 绝对值和取反 链接两个浮点加法 在一个链中混合加法和减法 加权和折叠为一个fmadds Lerp惯用法 — fsubs馈送fmadds 两个乘积求和 — 2D点积 累加三个乘积 — 3D点积 选择较大者:fcmpo + 条件fmr 在两个常量之间钳位 混合f32和f64 — 双精度数学,然后frsp ★ 顶点:带钳位的浮点步进 10 综合应用 将算术、位运算、控制流、循环、类型、指针和结构体组合成一个真实函数体的完整函数。约98分钟 0 / 10 缩放,然后钳位 一个64位全局累加器 一个带掩码的守卫累加器 调用、读取全局、钳位 在循环中构建位掩码 全局变量、字面量和调度器 对结构体字段求和,然后钳位 ★ 一个易失性读取的跳转表 一个守卫浮点累加器 ★ 64位全局变量、向下转换、钳位
4. 真实ABI
III 真实ABI 帧、全局变量、优化器、64位 0 / 80 11 函数 ABI 参数寄存器、保存寄存器、栈帧和声明顺序着色。约118分钟 0 / 14 整数参数寄存器 到达第五个参数 浮点数使用自己的寄存器 叶子函数没有栈帧 栈帧和链接寄存器 为调用编排参数 在调用中存活:保存寄存器 声明顺序着色寄存器 直接返回调用结果 当参数溢出到栈时 链接:保留一个值,编排其余部分 链接:将一个调用的结果管道输入下一个 链接:两个幸存者馈送最终调用 链接:一个函数中的完整ABI 12 全局变量、SDA池 r13/r2小数据寻址、@sda21/@ha/@l重定位和rodata池。约145分钟 0 / 15 通过小数据区读取全局变量 写入全局变量 操作码跟随类型 一个全局浮点数和第二个小数据区 浮点字面量变为池化常量 取地址:SDA li vs. @ha/@l对 索引全局数组 读取两个全局变量、计算、写回 一个全局浮点数乘以池化字面量 读取宽、存储窄 写入全局数组 索引数组、窄化结果 读-修改-写数组元素 ★ 一个浮点数组元素,缩放到全局变量 ★ 顶点:一个光照更新函数 13 优化 调度 -O4,p、窥孔优化、指令调度以及控制它们的编译指示。约142分钟 0 / 14 -O4,p实际做了什么 指令调度:隐藏延迟 窥孔优化器:点形式合并 #pragma peephole off:解融合合并 #pragma scheduling off:冻结顺序 调度浮点工作 fp_contract:融合乘加 循环中的强度降低 公共子表达式消除 链接:CSE馈送强度降低 链接:调度加点合并 链接:FP调度和fp_contract在三元组中 链接:融合乘加内部的重用乘积 顶点:调度与fp_contract相遇 14 高级惯用法 配对单精度、switch跳转表、枚举和volatile — 大师的工具箱。约128分钟 0 / 12 Switch:跳转表 表还是链?密度规则 序言中的配对单精度FPR保存 内联asm{}何时发挥作用:psq_l / psq_st 枚举是int大小:恢复是命名 Volatile击败CSE:两次读取、两次加载 Volatile硬件寄存器 链:通过表切换的枚举 链:在硬件寄存器上切换 链:枚举守卫,然后volatile求和 顶点:一个volatile守卫的枚举状态机 顶点II:通过switch分派的保存浮点数 15 64位整数 long long跨两个寄存器 — 进位链、ABI配对、向下转换指纹和内部函数。约125分钟 0 / 15 两个寄存器组成一个long long 概念 添加64位整数(addc / adde) 减去64位整数(subfc / subfe) 奇数寄存器对齐规则 向下转换指纹 乘以64位整数 除法调用内部函数 移位也调用内部函数 位运算只是两半 比较64位整数 链接:进位进入借位 链接:位运算对馈送进位链 链接:向下转换修剪链 链接:求和馈送64位比较 链接:一个函数体中的进位、借位和掩码 16 完整ABI一次性 融合帧、全局变量、优化器和64位工作的完整真实函数体 — 每个章节汇聚在一个符号中。约98分钟 0 / 10 缩放,然后钳位 一个64位全局累加器 一个带掩码的守卫累加器 调用、读取全局、钳位 在循环中构建位掩码 全局变量、字面量和调度器 对结构体字段求和,然后钳位 ★ 一个易失性读取的跳转表 一个守卫浮点累加器 ★ 64位全局变量、向下转换、钳位
5. 实战演练场
IV 实战演练场 真实的《星际火狐大冒险》函数,从头到尾 0 / 14 17 真实世界精通 真实的《星际火狐大冒险》函数,从热身到完整顶点。约162分钟 0 / 14 一个真实的设置器:状态、浮点微调和布尔返回 带偏差复制位置 辅助调用后的标志切换 将浮点数钳制到范围内 事件数组上的循环 轨道数学:fmadds、fdivs和保存的浮点寄存器 相位状态机 每帧更新:旋转、标志和分支 守卫碰撞检测:NULL链和类型检查 顶点:完整重置到空闲 peephole off:当你必须自己编写(s16)强制转换时 两个运行总和,手工编织:引导,p调度器 参数反转:谁获得保存的寄存器 声明顺序是寄存器顺序:手工着色保存的寄存器
🔗 原文链接:https://decomp-academy.dev