来源-语料图
本页上的每个数字都是
libtpu-0.0.40-cp314-cp314-manylinux_2_31_x86_64.whl的出处清单。分析的有效负载是两个ELF64共享对象:libtpu.so(781,691,048字节,build-id89edbbe81c5b328a958fe628a9f2207d,wheel0.0.40)和sdk.so(22,541,240字节,build-id4e9025466f71009fccb46a803806411c63744a0a)。其他wheel版本重命名包并重新哈希每个build-id。
摘要
此附录是语料库清单:经过分析以构建此 wiki 的所有内容的字节精确清单,因此任何其他页面上的任何声明都可以追溯到它来自的工件。它在四个级别回答了一个问题——到底什么是“二进制文件”?:PyPI 轮及其解压的文件树、其中的两个 ELF 对象、这些 ELF 对象嵌入命名节中的资源,以及静态分析实际运行的 IDA-Pro 派生的 sidecar 语料库。这里没有什么是逆向工程行为;它是输入集的基本事实。
管理整个 wiki 的区别建立在 两二进制分割 上:轮子运送两个独立的链接单元,而不是一个。 libtpu.so 是 PJRT TPU 插件(版本化的 C-ABI 共享对象); sdk.so 是导出 PyInit_sdk 的 CPython 3.14 扩展。两者均未在 DT_NEEDED 中列出对方;两者都不导入对方定义的符号。他们共享一个目录和一个轮子,除此之外别无其他。因此,wiki 中的每个“函数计数”都是针对每个对象的,从未进行求和——早期笔记中出现的大约 979k 的数字是添加两个不相关的 IDA 数据库的产物。
该页面分为四个目录,每个目录在每个事实表上都有一个“置信度”列:wheel 文件树(路径 → 类型 → 大小)、ELF 对象(通过 readelf 确认的标头事实和构建 ID)、嵌入式资源(filewrapper_toc 和 protodesc_cold 部分,编目于完整的附录页面),以及 IDA sidecar 语料库(每个函数的反编译/反汇编/图形树以及数据库范围的 JSON sidecar)。所有计数均直接针对文件系统进行确认;如果先前的注释与磁盘上的字节不一致,则 > **CORRECTION —** 记录分辨率。
| 轮子 | libtpu-0.0.40-cp314-cp314-manylinux_2_31_x86_64.whl |
| 分布 | libtpu 0.0.40 (PyPI)、Requires-Python: >=3.11、标签 cp314-cp314-manylinux_2_31_x86_64 |
| 分析对象 | libtpu.so (745 MiB) + sdk.so (21.5 MiB) |
| libtpu.so build-id | 89edbbe81c5b328a958fe628a9f2207d(GNU,16字节) |
| sdk.so build-id | 4e9025466f71009fccb46a803806411c63744a0a(GNU,20字节) |
| libtpu.so 函数 (IDA) | 884,832(记录;884,843 个工件文件 — 请参阅 CORPUS-2) |
| sdk.so函数(IDA) | 94,732 |
| 嵌入式模式描述符 | 760 FileDescriptorProto protodesc_cold 中的斑点 |
| 嵌入虚拟文件 | filewrapper_toc 注册表中的 61 个条目 |
轮子及其文件树
用途
语料库根是从 PyPI 下载的单个二进制轮。解压它(轮子是一个 ZIP)会生成一个 Python 包目录 libtpu/,以及安装程序读取的 .dist-info 元数据目录。 wiki 分析的所有内容都位于 libtpu/ 下; .dist-info/ 目录是出处,而不是有效负载。
文件树
完整的解压树,每个文件都有其确切的字节大小。尺寸来自stat; .dist-info/RECORD SHA-256 摘要(如下)独立固定每个文件的内容。
libtpu-0.0.40-cp314-cp314-manylinux_2_31_x86_64/
├── libtpu/
│ ├── libtpu.so 781,691,048 B ← PJRT TPU plugin (analyzed)
│ ├── sdk.so 22,541,240 B ← CPython 3.14 extension (analyzed)
│ ├── __init__.py 1,131 B ← path-config shim
│ ├── LICENSE 229 B
│ ├── THIRD_PARTY_NOTICES.txt 731,537 B
│ └── SDK_THIRD_PARTY_NOTICES.txt 103,306 B
└── libtpu-0.0.40.dist-info/
├── METADATA 1,186 B
├── RECORD 787 B
├── WHEEL 113 B
└── top_level.txt 7 B
```text
| 路径 | 型 | 尺寸(B) | 角色 |
|---|---|---:|---|
| `libtpu/libtpu.so` | ELF64共享对象 | 781,691,048 | PJRT插件——主要分析目标 |
| `libtpu/sdk.so` | ELF64共享对象 | 22,541,240 | CPython 扩展 `PyInit_sdk` — 次要目标 |
| `libtpu/__init__.py` | Python源码 | 1,131 | 在导入时将 `TPU_LIBRARY_PATH` 设置为捆绑的 `libtpu.so` |
| `libtpu/LICENSE` | 正文 | 229 | Google Cloud Platform 条款参考 (`Copyright [2026] Google LLC`) |
| `libtpu/THIRD_PARTY_NOTICES.txt` | 正文 | 731,537 | OSS 属性供应到 `libtpu.so` |
| `libtpu/SDK_THIRD_PARTY_NOTICES.txt` | 正文 | 103,306 | OSS 属性供应到 `sdk.so` |
| `libtpu-0.0.40.dist-info/METADATA` | 车轮元数据 | 1,186 | 名称/版本/摘要,`Requires-Python: >=3.11` |
| `libtpu-0.0.40.dist-info/RECORD` | 车轮清单 | 787 | 每个文件 SHA-256 + 大小;内容完整性预言机 |
| `libtpu-0.0.40.dist-info/WHEEL` | 轮头 | 113 | `Generator: setuptools (82.0.1)`、`Tag: cp314-cp314-manylinux_2_31_x86_64`、`Root-Is-Purelib: false` |
| `libtpu-0.0.40.dist-info/top_level.txt` | 正文 | 7 | 单线:`libtpu` |
> **更正 (CORPUS-1) —** 早期暂存库存将包装描述为仅在 `libtpu/` 下携带 `libtpu.so`、`sdk.so` 和 `__init__.py`。解压后的树包含**三个额外的有效负载文件** - `LICENSE` (229 B)、`THIRD_PARTY_NOTICES.txt` (731,537 B) 和 `SDK_THIRD_PARTY_NOTICES.txt` (103,306 B) - 所有这些都列在 `RECORD` 中。它们是归属文本,而不是代码,但它们是发货包的一部分,并记录在此处以确保完整性。
### `RECORD` 完整性预言机
`RECORD` 是权威内容清单:每个文件一个 CSV 行,`path,sha256=<urlsafe-b64-digest>,size`。两个分析对象引脚为:
```text
libtpu/libtpu.so,sha256=RW59bm-rG1hnBr5kZ8Z6PtjVdu9bZhcR6_TMMHhK4DM,781691048
libtpu/sdk.so,sha256=aSTl9uVX4PFjRzpBtpaqLJU964lNqu2Iacx3mhIMMTI,22541240这些是与轮相关的摘要(SHA-256 的 base64url)。 IDA 管道通过相同的文件计算自己的十六进制 SHA-256:libtpu.so → 456e7d6e6fab1b586706be6467c67a3ed8d576ef5b661711ebf4cc30784ae033、sdk.so → 6924e5f6e557e0f163473a41b696aa2c953deb894daaed8869cc779a120c3132。任一摘要唯一地标识所分析的字节; build-id 是更方便的短句柄。
注意 —
__init__.py是轮子中唯一可执行的 Python。它的唯一工作是configure_library_path(),它将TPU_LIBRARY_PATH环境变量设置为捆绑的libtpu.so的绝对路径,除非它已经设置。 JAX/PyTorch/TF 然后是dlopen该路径。 Python 层不携带 TPU 逻辑——它是一个单文件定位器 shim。
ELF 对象
用途
这两个.so文件是实际的逆向工程主题。它们的 ELF 标头、构建 ID 和节/段形状是 wiki 其余部分引用的硬锚点。以下所有事实均来自 readelf -h / readelf -n 直接在提取的文件上运行。
标头事实
| 事实 | libtpu.so | sdk.so |
|---|---|---|
| 文件大小 | 781,691,048 B (745 MiB) | 22,541,240 B (21.5 MiB) |
| 类/字节序 | ELF64 / 小端 | ELF64 / 小端 |
| 操作系统/ABI | UNIX – 系统 V | UNIX – GNU |
| 型 | DYN(共享对象) | DYN(共享对象) |
| 机 | x86-64 | x86-64 |
| 入口点 | 0x0(库,无_start) | 0x0 |
| 程序头 | 11 | 9 |
| 节标题 | 52 | 38 |
| Build-id(GNU 注释) | 89edbbe81c5b328a958fe628a9f2207d | 4e9025466f71009fccb46a803806411c63744a0a |
GOTCHA — 这两个对象的不同之处在于
OS/ABI(SYSV与GNU)和构建 ID 长度 —libtpu.so携带 16 字节(128 位)构建 ID,sdk.so携带 20 字节(160 位)一个。这是对两个二进制分割论文的独立证实:它们是由不同的链接配置产生的,而不是单个链接器调用。固定到完整的构建 ID,切勿固定到可能发生冲突的截断前缀。明白了 — 轮子通俗地称为“剥离的 745 MB 插件”,但两个对象都没有被剥离。两者都保留了完整的
.symtab—libtpu.so中的1,233,710符号表条目(1,232,970 本地 + 740 全局),带有约 172 MiB.strtab— 这正是 IDA 恢复约 884k 命名函数而不是sub_空白的原因。.symtab不是SHF_ALLOC(它永远不会在运行时加载;运行时只能看到 741 项.dynsym),但它存在于磁盘上,并且使深度静态分析成为可能。这里的分析深度由幸存的.symtab决定,而不是由小型.dynsym决定。有关完整的节/段表,请参阅 精灵解剖。
角色
这两个对象扮演着截然不同的角色,总结如下并在 两二进制分割 上详细介绍:
| 对象 | ABI 表面 | 联动 | 它是什么 |
|---|---|---|---|
libtpu.so | 226 条目 C-ABI(218 个 @@VERS_1.0 版本 + 8 个链接器集边界;GetPjrtApi 系列) | sdk.so 上没有 DT_NEEDED | TPU 编译器 + 运行时:XLA/HLO、ICI 集体、deepsea ISA 后端 |
sdk.so | PyInit_sdk(一个 CPython 初始化导出) | libtpu.so 上没有 DT_NEEDED | 用于直接 TPU/SDK 交互的 CPython 3.14 扩展模块 |
嵌入式资源
用途
libtpu.so 不仅仅是代码:它嵌入了其他附录页面完整目录的两个不同的二进制数据注册表。它们被记录在这里,以便语料库清单命名 wiki 所利用的每个资源池。两者都位于命名的 ELF 部分中,并且只能通过符号表和 .init_array 构造函数访问 - 两个部分都不是自描述的。
protodesc_cold — protobuf 模式池
只读 PROGBITS 部分(0xbe8af30–0xc1bf0b0,~3.2 MiB),保存静态链接到插件中的 每个 .proto 模式的序列化 google.protobuf.FileDescriptorProto - 每个编译一个 blob .proto。
| 属性 | 值 |
|---|---|
| 部分 | protodesc_cold,标头 [12],标志 A(分配,只读) |
| 描述符计数 | 760 (760 descriptor_table_protodef_* blob ↔ 760 descriptor_table_* 注册商) |
不同的 .proto 路径字符串 | 769(9 字符串多余部分是仅导入依赖项) |
| 第一个斑点 | descriptor_table_protodef_zzRDQFgX_23 @ 0xbe8af80 (pjrt_tpu_topo_desc_name_mapping.proto) |
| 注册 | descriptor_table_* 结构在 static-init 处由 .init_array 中的 _GLOBAL__sub_I_ ctor 遍历 |
760 架构涵盖 XLA/HLO 编译器、适用于五个芯片系列的 Deepsea TPU ISA、运行时拓扑和程序格式、XPlane/xprof 分析器、Megascale 集合和 PJRT 分布式协调。完整的每根、每域分类位于 protodesc_cold目录 中。
filewrapper_toc — 嵌入式文件注册表
可写 (WA) 部分,ELF 部分索引 38,保存指向嵌入式虚拟文件系统的指针表 - 运行时的捆绑数据文件(预编译资产、配置 blob)在内存中而不是在磁盘上具体化。
| 属性 | 值 |
|---|---|
| 部分 | filewrapper_toc,ELF 部分索引 38,标志 WA |
| 布局 | entry_count × 8 字节指针,每个 R_X86_64_RELATIVE 重定位到 .data.rel.ro 中的 40 字节描述符 |
| 条目计数 | 61 条目(约 5.5 MiB 的索引有效负载) |
| 桌锚 | filewrapper_toc @ 0x224bf798(488 B 阵列) |
| 注册锚 | _ZL7toc_ptr @ 0x224bf918,由 *_memfile_embed_internal_create() 设置 |
注意 — 不要将 61 项
filewrapper_toc注册表 与二进制文件中其他地方更大的(anonymous namespace)::filewrapper_*符号池混淆。注册表是索引的嵌入式文件系统;较大的符号池是不相关的包装器机制。 61 个条目的完整目录位于 filewrapper_toc 目录 中。
ELF 节表中存在的两个节以及填充它们的静态初始化注册机制均归 定制型材 所有。第三个嵌入式资源是在最后一个 ELF 部分之后雕刻的尾部 zstd 压缩 blob,记录在 尾随 zstd Blob 上; binwalk 通过 libtpu.so 准确地刻出了该文件。
IDA Sidecar 语料库
用途
静态分析并未单独在原始 .so 字节上运行。 IDA Pro 批处理过程为每个对象生成一个 .i64 数据库,以及每个函数和每个数据库 sidecar 文件的大量扇出(反编译的 C、反汇编、控制流图以及名称/外部引用/字符串/结构的数据库范围 JSON 导出)。 wiki 的功能级声明是针对这些 sidecar 的;本节对它们进行盘点,以便任何地址引用都可以追溯到支持它的文件。
每个对象的覆盖率
两个对象均经过处理以实现按功能的完全覆盖。 IDA 运行清单记录了每个目标的函数计数和处理模式:
| 对象 | 功能 | 模式 | 每功能树 | .i64 数据库 | binwalk |
|---|---|---|---|---|---|
libtpu.so | 884,832 | 快 | 上下文+反编译+反汇编+图表 | 是 | 1 个文件雕刻(尾随斑点) |
sdk.so | 94,732 | 全 | 上下文+反编译+反汇编+图表 | 是 | 待定 |
更正 (CORPUS-2) —
libtpu.so有两个不同的计数,不得混为一谈。 函数记录计数 —functionssidecar 的length,以及每隔一页引用的“函数计数”数字 — 为 884,832。context/、decompiled/和disasm/树中的 每个函数工件文件计数 为 884,843,正好高出 11:少量 thunk/alias/data-stub 条目接收工件文件,而不会被预订为完整函数记录。对任何函数 count 引用 884,832 (匹配 二进制布局、证据锚索引 和 方法论(深));引用884,843仅用于工件文件覆盖范围。sdk.so是 94,732。明白了 — IDA 模式标签是违反直觉的。
libtpu.so— 745 MiB 主要目标 — 在fast模式下运行;小型sdk.so以full模式运行。 “完整”与“快速”控制着每个函数的反编译器彻底性,而不是覆盖广度:两个对象都达到了 100% 函数覆盖率(零canonical_deficits)。读取反编译的libtpu.so主体的重新实现者应按照快速传递的预期处理边缘反编译器工件,并针对反汇编树进行交叉检查。
每功能树 (libtpu.so)
对于每个函数,都会发出四个工件树; context/、decompiled/ 和 disasm/ 树各保存 884,843 个文件 — 比 884,832 个函数记录多 11 个(请参阅 CORPUS-2)。这些树木巨大,仅作为分析脚手架存在;它们从来没有被完整地阅读过。
| 树 | 文件 | 总字节数 | 目录 |
|---|---|---|---|
context/ | 884,843 | ~10.06 GB | 每个功能上下文捆绑(签名、调用者/被调用者、本地) |
decompiled/ | 884,843 | ~2.62 GB | Hex-Rays 伪 C 每个函数 |
disasm/ | 884,843 | ~6.66 GB | x86-64 按功能反汇编 |
graphs/ | 1,769,686 | ~11.94 GB | 每功能 CFG — 每个两个文件 (.dot + .json) |
注意 —
graphs/每个函数恰好保存两个文件(同一 CFG 的.dot和.json渲染),这就是其文件计数为2 × 884,843 = 1,769,686的原因。其他三棵树是每个函数一个文件。
数据库范围的 JSON sidecar (libtpu.so)
除了每个函数树之外,IDA 还发出一组固定的整个数据库导出(每个类别一个文件)以及按地址窗口切割的分片 ctree/split 导出(off<N>_lim<M> 命名)。单文件 sidecar 是跨数据库查询的实用入口点。
| 边车 | 角色 |
|---|---|
names.json / functions.json / function_addresses.json | 符号→地址映射(维基引用的命名脊柱) |
callgraph.json (~1.8 GB) / callgraph.dot | 函数级调用图 — “谁调用 X”预言 |
xrefs.json (~39 GB) | 全局代码+数据交叉引用图 — 流式传输,从不完整加载 |
strings.json | 恢复的字符串文字 |
rtti.json | RTTI / typeinfo 记录 |
structures.json / enums.json / prototypes.json | 恢复的类型信息 |
imports.json / native_imports.json / native_exports.json | 动态导入/导出表面 |
segments.json / entries.json / fixups.json / frames.json | 段映射、入口点、重定位、堆栈帧 |
data_tables.json / switches.json / tryblks.json | 跳转表、开关调度、异常 try 块 |
comments.json (~496 MB) | 每个地址自动评论 |
metadata.json / problems.json | 运行元数据、反编译器问题日志 |
ctree_*(97 个分片,~2.87 GB) | AST (ctree) 导出按地址窗口切割 |
split_*(~192 个文件) | 每个窗口完成/元数据对 |
decompilation_failures_*(19个文件) | 每个窗口的函数列表 Hex-Rays 无法反编译 |
明白了 —
xrefs.json是该系列中最大的工件 — 容量约为 39 GB,大约是libtpu.so本身大小的 50 倍。它是全局交叉引用图,按地址切片,从不完整加载;callgraph.json(~1.8 GB)是其函数级投影,是实际用于调用关系查询的工件。将任何“X 引用自 Y”声明视为xrefs的一部分,而不是整个文件扫描。
sdk.so 边车集以 1/9 的规模(94,732 个功能)反映了这一布局,其中一个整合的 ctree 边车而不是 97 个分片。该方法——这些 sidecar 是如何生成和使用的——记录在 方法论(深) 上。
交叉引用
- 两二进制分割 — 确定车轮运送两个独立的链接单元;拥有此处总结的每个对象 ABI/链接证据。
- 取证概述 —
libtpu.so尺寸、截面模型和版本来源的顶层定位。 - 精灵解剖 — 完整节/段表、
.symtab/.dynsym拆分以及 LOAD 段 vaddr/偏移量转换。 - 定制型材 — 拥有
filewrapper_toc和protodesc_cold节头及其静态初始化注册。 - 尾随 zstd Blob — 一个文件 binwalk 切过了最后一个 ELF 部分。
- filewrapper_toc 目录 — 由
filewrapper_toc索引的 61 个嵌入式虚拟文件。 - protodesc_cold目录 —
protodesc_cold中的 760 个FileDescriptorProto模式。 - 方法论(深) — IDA sidecar 语料库的生成和使用方式。
- 二进制布局 — 每个函数树索引的
libtpu.so的地址带映射。