# Swift 二进制布局:mangling 语法 / swift5 反射段 / witness table / 闭包 Swift 产物相对 C/C++ 产物多两类结构:mangled 符号名(全部顶层符号经 `$s` 编码)与 `__swift5_*` 反射元数据段(协议一致性、类型描述、字段描述)。两者互补:符号名给"名字",反射段给"结构"。 ## mangling 前缀变体 | 前缀 | 时期 | 说明 | |---|---|---| | `$s` | Swift 5+ | 当前稳定 mangling(本技能默认处理对象) | | `$S` | Swift 4.2 | 4.2 过渡期变体 | | `_T0` | Swift 4.0 | 4.0 变体 | | `_T` / `_Tt` | Swift 3.x 及更早 | ObjC 时代 mangling(`_TtC3foo3bar` 形态) | | `$e` | — | Embedded Swift(不稳定) | | `@__swiftmacro_` | — | 宏展开的文件名符号 | ## 编码语法(`$s` 稳定格式) ### 基本单元 | 单元 | 规则 | 示例 | |---|---|---| | 标识符 | 十进制长度 + ASCII 字符串(非 ASCII 用 Punycode,前缀 `00`) | `4Test` → "Test";`13ExampleModule` → "ExampleModule" | | 类型字母 | C=类 O=枚举 V=结构体 P=协议 E=扩展 | `3FooC` → 类 Foo | | 标准库缩写 | Si=Int SS=String Sq=Optional Sa=Array Sd=Double Sb=Bool | `Si` → Swift.Int | | 模块缩写 | s=Swift So=C/ObjC 模块 SC=Clang importer | `s4main` 中 `s` 为 Swift 模块 | | 空元组 | y | `() `(参数或结果为空) | | 函数 | 声明名 + 标签列表 + 签名 + `F`;**签名顺序 = 结果类型在前、参数在后** | `3bar Si y F` → `bar() -> Int` | ### 后缀修饰(实体级) | 后缀 | 含义 | |---|---| | `_To` | @objc 桥接 thunk(与本体成对出现,ObjC 侧经它进 Swift 实现) | | `TE` | distributed thunk | | `Tg5`/`Tg` 等 | 泛型特化(generic specialization) | | `TA` | 闭包 partial apply forwarder | | `TW` | 协议 witness thunk(`{T:} protocol witness for ...`) | | `TI` | 可派发 thunk(method dispatch thunk) | ### 替换与符号化引用 - 替换表(substitution):`A` 起的小写字母引用已出现的模块/类型(压缩重复前缀) - 符号化引用(symbolic reference):mangled 名内嵌 `\x01-\x1f` 控制字符 + 指针大小字节——**不是 \0 结尾的普通字符串**,`strings`/strlen 处理会截断(见 SKILL.md 坑 6) ### 手读示例(官方测试向量) ``` $s4main6myFuncyyF → main.myFunc() -> () └模块"main"└函数"myFunc"└结果y(())└参数y(())└F $s3foo3barC3bas3zimyAaEC_tF → foo.bar.bas(zim: foo.zim) -> () └模块foo └类bar └方法bas └标签zim └参数y └结果(替换A→foo.zim)└F $s3foo3barC3bas3zimyAaEC_tFTo → {T:...,C} @objc foo.bar.bas(zim: foo.zim) -> () (同符号 + _To = @objc 桥接 thunk) $s4main3fooyySiFyyXEfU_TA.1 → {T:} partial apply forwarder for closure #1 () -> () in main.foo(Swift.Int) -> ()(闭包) ``` ## swift5 反射段(Mach-O 名 / ELF 名 / COFF 名) | 内容 | Mach-O(__TEXT 段内) | ELF | COFF | |---|---|---|---| | 协议一致性(conformance 记录) | `__swift5_proto` | `swift5_protocol_conformances` | `.sw5prtc$B` | | 协议描述符 | `__swift5_protos` | `swift5_protocols` | `.sw5prt$B` | | 类型描述符 | `__swift5_types` | `swift5_types` | `.sw5tyd$B` | | 字段描述(类型内布局) | `__swift5_fieldmd` | `swift5_fieldmd` | `.sw5fld$B` | | 类型引用字符串池 | `__swift5_typeref` | `swift5_typeref` | `.sw5tyr$B` | | 反射字符串 | `__swift5_reflstr` | `swift5_reflstr` | `.sw5rfl$B` | | 闭包捕获描述 | `__swift5_capture` | `swift5_capture` | `.sw5cpt$B` | | 关联类型 | `__swift5_assocty` | `swift5_assocty` | `.sw5ast$B` | | 内建类型 | `__swift5_builtin` | `swift5_builtin` | `.sw5bui$B` | | 多态枚举 | `__swift5_mpenum` | `swift5_mpenum` | `.sw5mpe$B` | | 可访问性 | `__swift5_accessible` | `swift5_accessible` | `.sw5acc$B` | | 替换范围 | `__swift5_replace` | `swift5_replace` | `.sw5rpc$B` | | 模块哈希 | `__swift_modhash` | `swift_modhash` | `.sw5mh$B` | 定位命令:Mach-O `otool -l sample | grep -A2 swift5_`;ELF `readelf -S sample | grep -i swift5`。这些段是数据段(常驻内存),**strip 不删除**——stripped Swift 产物靠它们重建类型/协议关系。 ## witness table 与 conformance 记录 - conformance 记录(`__swift5_proto`)指向:witness table(若间接)、conformance 描述符、名义类型描述符、协议描述符 - witness table 槽位 = 协议要求方法的实现地址数组;槽序与协议声明顺序一致 - 定位入口:`_swift_getWitnessTable`(直接取)或 `swift_getWitnessTable`(查表)调用点;调用处的第二个参数即 conformance 记录 - 无符号名时:找到 witness method 调用点(泛型函数内对协议方法的间接调用),其函数指针表即 witness table ## 闭包 context 布局 ``` swift_allocObject(闭包布局描述符, size, align) → context 对象 context 头部 = 指向闭包捕获布局描述符的指针(swift5_capture 段条目) 其后按捕获顺序排列字段:值类型=内联值;引用类型=强引用指针(配 swift_retain/release) ``` 定位:`swift_allocObject` 调用点的常量参数 = 捕获布局描述符(含捕获字段数/类型);闭包入点是 partial apply forwarder(`TA` 后缀符号)。 ## 运行时符号(swift_ 前缀,导入确认) | 符号 | 含义 | |---|---| | swift_retain / swift_release | 强引用增/减(引用语义字段标记) | | swift_allocObject / swift_allocBox | 堆对象/闭包 box 分配 | | swift_beginAccess / swift_endAccess | 独占访问修饰(exclusivity) | | swift_getWitnessTable / _swift_getWitnessTable | 协议 witness table 获取 | | swift_getTypeByMangledName | 按 mangled 名查类型元数据 | | swift_dynamicCast | 动态类型转换 | ## 版本差异要点 - mangling 前缀三代($s/$S/_T0),工具链与产物同代或更新才能解码 - Swift 4 及更早产物无 `__swift5_*` 段(反射系统 5.0 引入);老产物靠符号名 + ObjC 段(__objc_classlist)恢复 - 泛型特化数量随版本增长(编译器更激进);`Tg5` 特化符号与原型共存 ## 使用注意 - 与 [[re-format-macho]](段定位)、[[re-cpp-abi]](vtable 思路)、[[re-ios]]/[[re-macos]](ObjC 层)配合 - 符号提取走符号表(llvm-nm/readelf -s),不用 strings(symbolic reference 会截断)