Skip to content

自定义节

本页中的所有地址均适用于 libtpu-0.0.40-cp314 wheel 中的 libtpu.so(build-id 89edbbe81c5b328a958fe628a9f2207d)。其他构建会有所不同。下面的每个节名、地址、大小和标志集合都已通过 readelf -SWreadelf -x 确认。

摘要

教科书式的 x86-64 共享对象有十几个众所周知的节 — .text.rodata.data.bss.dynsym.eh_frame — 逆向工程师可以预期其中每一个。libtpu.so52 个节头,其中约三分之一不在那本教科书里。有些是该二进制如何编译出来的必然产物(LLVM/clang 大代码模型构建会把 rodata、data 和 bss 拆成 .lrodata/.ldata/.lbss,因为小数据的 2 GiB 窗口容不下 745 MiB 的镜像)。另一些则是 Google 内部库发明的链接器数组节 — google_malloc__rseq_csprotodesc_coldlinkarr_upb_AllExts__lcxx_overridefilewrapper_toc — 每一个都是一段连续的对象或跳板,启动例程或运行时会通过其 __start_/__stop_ 封装符号遍历。若逆向工程师把这些当作填充或垃圾,就会漏掉 tcmalloc 的每 CPU 快路径、protobuf 描述符池和 PJRT API 单例。

本页是带注释的子集:它不会重新列表全部 52 个节(这是 ELF 剖析 页的职责,那里维护权威的完整表、PT_LOAD 段映射和动态数组)。这里我们只挑出值得注意且真正奇特的节,并对每个节回答一个问题:里面有什么,为什么存在。换成更熟悉的表述:可以把它看作一个单体 Abseil/protobuf/MLIR/XLA 巨块经 LLVM/lld 大代码模型链接后的结果,与一个普通小型 .so 的区别 — 额外的节就是在 32 位 R_X86_64_PC32 位移不再够用的规模上进行单体静态链接所付出的代价。

对重新实现 / 分析而言,契约是:

  • 大代码模型拆分 — 为什么 .lrodata(108 MiB)、.ldata.lbss 作为 .rodata/.data/.bss 的同级节存在,l(large)标志和较高的 0x1884a00+ 加载地址如何表明 -mcmodel=large,以及 PJRT API vtable 单例位于 .lbss
  • 描述符 / proto 数据protodesc_cold(protobuf 描述符池)、linkarr_upb_AllExts(upb 扩展注册器)、pb_defaults
  • 运行时 / 分配器节google_mallocgoogle_malloc_datagoogle_malloc_bss__rseq_cs__rseq_cs_ptr_arraymalloc_hook — tcmalloc 每 CPU 可重启序列机制。
  • 展开和 notes.eh_frame/.eh_frame_hdr/.gcc_except_table,以及固定版本的 .note.gnu.build-id
  • 真正的异类__lcxx_overridefilewrapper_toc.text.split(零字节),以及该二进制携带完整 .symtab并非经典意义上已剥离这一事实。
节头数量52(头索引 50 = .shstrtab
文件大小781,691,048 字节(约 745 MiB)
代码模型LLVM/clang -mcmodel=large(带 l 标志的节)
最大显著节.lrodata0x6c0e7d0(108.1 MiB),标志 AMSl
PJRT API 单例_ZZN4pjrt10tpu_plugin13GetTpuPjrtApiEvE8pjrt_api @ 0x227ba840.lbss,1120 B)
build-id89edbbe81c5b328a958fe628a9f2207d.note.gnu.build-id,32 B)
已剥离?否 — 存在 .symtab(1,233,710 项,28.2 MiB)

显著节一览(省略教科书式的 .text/.rodata/.data/.dynsym/.plt/.got — 见 ELF 剖析):

VAddr大小标志内容
[10] .lrodata0x1884a000x6c0e7d0(108.1 MiB)AMSl大模型只读数据:const 表、字符串池、vtables
[12] protodesc_cold0xbe8af300x334180(3.2 MiB)Aprotobuf descriptor_table_protodef_* + TableStruct_*::offsets
[13] .gcc_except_table0xc1bf0b00x10d584(1.05 MiB)AC++ 异常 landing pad 的 LSDA 表
[14] .eh_frame_hdr0xc2cc6340x6bd684(6.74 MiB)A指向 .eh_frame 的二分搜索索引
[15] .eh_frame0xc989cb80x1cab86c(28.7 MiB)ADWARF CFI 展开描述符
[19] google_malloc0xe6373c00x46f2(17.7 KiB)AXotcmalloc 每 CPU rseq 跳板 + 检查失败辅助函数
[20] .text.split0xe63bab20x0(0 B)AXo空的 split-text 标记节
[24] google_init_cold0x213e9d800x60f1(24.2 KiB)AX冷路径静态初始化代码
[25] malloc_hook0x213efe800x89e(2.2 KiB)AXAbseil LowLevelAlloc 分配钩子
[26] __lcxx_override0x213f07200x105(261 B)AX被覆盖的 libc++ operator new/delete 跳板
[30] .init_array0x215f26f00x5aa0(22.7 KiB)WAo2900 个构造函数指针(普查 → 静态初始化)
[31] .fini_array0x215f81900x10(16 B)WA2 个析构函数指针
[33] .preinit_array0x22048b300x10(16 B)WA2 个预初始化指针(在库中很少见)
[38] filewrapper_toc0x224bf7980x1e8(488 B)WA嵌入文件目录表(磁盘上填零)
[39] __rseq_cs0x224bf9800x2260(8.8 KiB)WAtcmalloc 可重启序列临界区描述符
[40] __rseq_cs_ptr_array0x224c1be00x898(2.2 KiB)WA指向 __rseq_cs 的 275 个指针
[41] linkarr_upb_AllExts0x224c24800x4a0(1.2 KiB)WAo37 × 32 B upb proto 扩展注册器
[42] pb_defaults0x224c29200x18(24 B)WAprotobuf C++ 特性默认实例指针
[43] google_malloc_data0x224c29380x48(72 B)WAtcmalloc 可写全局变量
[46] .ldata0x22798c300x21c00(135 KiB)WAl大模型可写数据
[47] .lbss0x227ba8400x9f940(638 KiB)WAl大模型零初始化数据 — PJRT API 单例
[48] google_malloc_bss0x2285a1800x5100(20.2 KiB)WAltcmalloc 大模型零初始化全局变量
[1] .note.gnu.build-id0x2a80x20(32 B)AGNU build-id note(版本锚点)

注意 — Flags 列使用 readelf 的字母:A alloc、W write、X execute、M merge、S strings、l large(SHF_X86_64_LARGE)、o OS-specific(SHF_GNU_RETAIN / link-order)。.lrodata/.ldata/.lbss/google_malloc_bss 上的 l 标志是明确的大代码模型指纹。


大代码模型节

为什么它们存在

x86-64 小/中代码模型假定代码和数据位于一个 ±2 GiB 窗口内,可通过 32 位有符号 RIP 相对位移(R_X86_64_PC32)到达。libtpu.so 是 745 MiB 镜像,仅 .text 就有 0x12bdb484 ≈ 300 MiB,vaddr 为 0xe63c000;一旦 rodata 和 code 合计超出 2 GiB 位移预算,编译器就必须为“大”对象发出 64 位寻址。clang/LLVM 的 -mcmodel=large 答案是把大对象隔离到自己的节中,标记为 SHF_X86_64_LARGEl),并把它们放到小数据窗口之外。这里正是这种布局:.rodata(小型、可合并只读数据)位于 0x84a0000,而大型只读数据是一个单独的 .lrodata,放在更早的 0x1884a00,大型可写数据 .ldata/.lbss 则最后放置,高于 0x22000000

特性 — 同时存在 .rodata.lrodata(以及 .data/.ldata.bss/.lbss)不是重复错误 — 它是 LLVM -mcmodel=large 构建的定义性标志。小模型 .so 没有 .l* 同级节。只 grep .rodata 的逆向工程师会错过二进制中最重要的 108 MiB 常量数据。

.lrodata — 108 MiB 常量存储

text
  [10] .lrodata          PROGBITS  0000000001884a00 1884a00 6c0e7d0 00 AMSl  0   0 16
```text

`0x6c0e7d0` = **113,305,552 字节(108.1 MiB)** — 比 `.rodata`(57.9 MiB)大将近 2×,也是文件中迄今最大的非代码、非 symtab 节。标志 `AMSl`:已分配、可合并(`M`)、包含字符串(`S`)、large(`l`),16 字节对齐。这里存放只读程序数据的主体:MLIR/LLVM 静态 op 表、解修饰类型名字符串池、RTTI type-info 记录,以及 vtables 的只读部分。`M`+`S` 标志意味着链接器在此合并了重复字符串常量;16 字节对齐是大型节的默认值。由于它是可合并只读数据,它会映射进第一个可执行+可读 `PT_LOAD`,并在进程之间共享。

### .ldata 和 .lbss — 大型可写数据

```text
  [46] .ldata            PROGBITS  0000000022798c30 22198c30 021c00 00 WAl  0   0 16
  [47] .lbss             NOBITS    00000000227ba840 221ba830 09f940 00 WAl  0   0 64

.ldata0x21c00(135 KiB)的已初始化大型可写数据;.lbss0x9f940(638 KiB)的零初始化大型可写数据(一个 NOBITS 节 — 不占文件字节,只保留内存)。两者都带 l 标志。

.lbss 中最重要的驻留对象是 PJRT plugin API table 单例。符号表把一个 1120 字节的 LOCAL OBJECT 放在该节的精确起始位置:

text
  1448: 00000000227ba840  1120 OBJECT  LOCAL  DEFAULT  47 _ZZN4pjrt10tpu_plugin13GetTpuPjrtApiEvE8pjrt_api
```text

解修饰后是 `pjrt::tpu_plugin::GetTpuPjrtApi()::pjrt_api` — 静态 `PJRT_Api` 结构体(函数指针表),导出的 `GetPjrtApi` 入口点(`0xe6a83a0`,5 字节,位于 `.text`)会把它返回给框架。它的 Meyers 单例 guard variable 单独位于 `.bss`:

```text
  1447: 00000000224c3f90     8 OBJECT  LOCAL  DEFAULT  45 _ZGVZN4pjrt10tpu_plugin13GetTpuPjrtApiEvE8pjrt_api

注意 — 整个插件中最常被调用进入的对象 — PJRT 分发表 — 正是因为这是大模型构建而位于 .lbss。在小模型 .so 中,它会是普通 .bss 对象。带 l 标志的位置纯粹是寻址模型的后果,不是安全或布局选择。该表的运行时构造由 .init_array 构造函数完成;见 static-init


描述符 / Proto 数据节

protodesc_cold — 描述符池

text
  [12] protodesc_cold    PROGBITS  000000000be8af30 be8af30 334180 00   A  0   0 16
```text

`0x334180` = **3,359,104 字节(3.2 MiB)**,只读(`A`)。这是 protobuf C++ 运行时的*冷*描述符数据 — 序列化的 `.proto` schema,`descriptor_table_*` 初始化器会在启动时把它们送入全局描述符池。符号表直接确认了内容:

```text
  1620: 000000000be8af80 497 OBJECT LOCAL .. _ZL37descriptor_table_protodef_zzRDQFgX_23
  1642: 000000000be8af30  76 OBJECT LOCAL .. _ZN23TableStruct_zzRDQFgX_237offsetsE
  2506: 000000000be8b210 461 OBJECT LOCAL .. _ZL37descriptor_table_protodef_eguDetDQC_5

每个 descriptor_table_protodef_* blob 都是一个序列化的 FileDescriptorProto;每个 TableStruct_*::offsets 数组把 message 字段映射到其内存内偏移。_cold 后缀是 clang 附加到仅在一次性描述符注册期间触及的数据上的节放置提示 — 分组可让热 .rodata 保持缓存密集。proto 文件名被混淆了(zzRDQFgX_23eguDetDQC_5),这是构建系统产物,不是加密。

陷阱 — protodesc_cold 尽管位置靠近可执行区域,但它不是代码 — 它只有 A 标志,没有 X。“cold” 命名约定(也见于 google_init_cold.text.unlikely)是 clang 对很少执行的字节进行的 profile/启发式分区,这里应用于数据。不要假定 *_cold 节是可执行的。

linkarr_upb_AllExts — upb 扩展注册器

text
  [41] linkarr_upb_AllExts PROGBITS 00000000224c2480 220c2480 0004a0 00 WAo  0   0 16
```text

`0x4a0` = 1184 字节 = **37 个 32 字节条目**,由封装符号 `__start_linkarr_upb_AllExts`(`0x224c2480`)和 `__stop_linkarr_upb_AllExts`(`0x224c2920`)括住。这是一个*链接器数组*:每个定义 upb(micro-protobuf)proto 扩展的翻译单元都会把一个 32 字节注册器记录放入这个命名节,启动例程会迭代 `[__start, __stop)`,把每个扩展注册到全局注册表。内容有名称:

```text
  1161430: 00000000224c2480 32 OBJECT LOCAL .. envoy_annotations_disallowed_by_default_ext
  1161431: 00000000224c24a0 32 OBJECT LOCAL .. envoy_annotations_deprecated_at_minor_version_ext

o 标志(SHF_GNU_RETAIN)会保留这些记录,即使没有符号直接引用它们 — 它们只通过 __start_/__stop_ 扫描到达,因此必须告诉链接器不要把它们垃圾回收。

pb_defaults

text
  [42] pb_defaults       PROGBITS  00000000224c2920 220c2920 000018 00  WA  0   0  8
```text

24 字节。一个很小的可写表,protobuf C++ 运行时用它保存 `CppFeatures` 默认实例指针和 edition-defaults 偏移。Hexdump 显示它基本为零,带一个 `0x18` 长度字段 — 它会在静态初始化时被填充。

---

## 运行时 / 分配器节

该二进制静态链接了 Google 的 tcmalloc,而 tcmalloc 的每 CPU 快路径建立在 Linux **restartable sequences**(`rseq`)内核 ABI 上。该机制需要三个协作的节 — 代码跳板、临界区描述符和指针数组 — 外加可写全局变量。

### google_malloc — tcmalloc rseq 跳板

```text
  [19] google_malloc     PROGBITS  000000000e6373c0 e6373c0 0046f2 00 AXo  0   0 64

0x46f2 = 18,162 字节的可执行代码(AX),保留(o),64 字节对齐,由 __start_google_malloc/__stop_google_malloc 括住。这是每 CPU 分配器热路径 — 内核可能在抢占时中止并重启的可重启序列函数:

text
  1228043: 000000000e637480 33 FUNC LOCAL .. RseqFunction_PerCpuCmpxchg64
  1228044: 000000000e637440 42 FUNC LOCAL .. RseqFunction_PerCpuTryLock
  1228047: 000000000e6374c0 43 FUNC LOCAL .. RseqFunction_PerCpuCmpxchgCheck64
```text

这些函数位于自己独立的 retained 节中,因为 `__rseq_cs` 描述符(见下)指向它们内部精确的 start/commit/abort 指令地址;该节让它们保持连续,并防止链接器重排或消除这些精心布置的提交窗口。

### __rseq_cs 和__rseq_cs_ptr_array

```text
  [39] __rseq_cs           PROGBITS 00000000224bf980 220bf980 002260 00 WA  0   0 32
  [40] __rseq_cs_ptr_array PROGBITS 00000000224c1be0 220c1be0 000898 00 WA  0   0  8

__rseq_cs0x2260(8800 字节)的 32 字节 struct rseq_cs 描述符 — 每个都是一个 {version, flags, start_ip, post_commit_offset, abort_ip} 记录,告诉内核“如果此线程在其指令指针位于 [start_ip, start_ip+post_commit_offset) 内时被抢占,则跳转到 abort_ip”。__rseq_cs_ptr_array0x898 = 275 个八字节指针,指向 __rseq_cs,即 tcmalloc 向内核注册的间接表。start_ip/abort_ip 字段指向 google_malloc。hexdump 中内联显示了描述符的 flags/version 字段和偏移(0x1a0x16 等)。

特性 — __rseq_cs 必须是可写的(WA):内核 rseq(2) 注册会写回这些描述符,加载器也会重定位嵌入的指令指针字段。把它们当作 const 的重新实现者会在注册时触发 fault。

malloc_hook, google_malloc_data, google_malloc_bss

text
  [25] malloc_hook        PROGBITS 00000000213efe80 213efe80 00089e 00 AX  0   0 32
  [43] google_malloc_data PROGBITS 00000000224c2938 220c2938 000048 00 WA  0   0  8
  [48] google_malloc_bss  NOBITS   000000002285a180 221ba830 005100 00 WAl 0   0 16
```text

`malloc_hook`(`0x89e`,可执行)保存 Abseil 的低级分配器入口点 — `absl::base_internal::LowLevelAlloc::Alloc`/`Free`/`AllocWithArena` — 即 tcmalloc 初始化前使用的 bootstrap 分配器,由 `__start_malloc_hook`/`__stop_malloc_hook` 括住。`google_malloc_data`(72 字节,可写)和 `google_malloc_bss`(`0x5100` = 20,736 B / 20.2 KiB,零初始化,带 large 标志)保存 tcmalloc 的可变全局变量 — 每 size-class 空闲链表头、采样状态、central cache。`google_malloc_bss` 带 `l` 标志,因此连分配器的 BSS 也被推入大模型区域。

### google_init_cold

```text
  [24] google_init_cold  PROGBITS  00000000213e9d80 213e9d80 0060f1 00 AX  0   0 32

0x60f1 = 24,817 字节的可执行冷路径初始化代码 — 静态构造函数中很少采用的分支,由 clang 从 .text.startup 分区出来,使常见初始化路径保持缓存密集。它是 .text.unlikely 的伴随节。


展开与 Note 节

.eh_frame / .eh_frame_hdr / .gcc_except_table

text
  [13] .gcc_except_table PROGBITS 000000000c1bf0b0 c1bf0b0 10d584 00 A  0   0  4
  [14] .eh_frame_hdr     PROGBITS 000000000c2cc634 c2cc634 6bd684 00 A  0   0  4
  [15] .eh_frame         PROGBITS 000000000c989cb8 c989cb8 1cab86c 00 A  0   0  8
```text

`.eh_frame` 是 **28.7 MiB** 的 DWARF Call Frame Information — 每个函数一个 FDE,描述在异常传播和栈展开期间如何恢复栈。`.eh_frame_hdr`(6.74 MiB)是排序后的二分搜索索引,C++ personality 例程用它以 `O(log n)` 而不是扫描的方式定位故障 PC 对应的 FDE。`.gcc_except_table`(1.05 MiB)保存 LSDA(Language-Specific Data Area)表 — 从每函数的 call-site PC 范围到 landing-pad 地址和 catch-type 过滤器的映射。

其庞大大小(合计 36.5 MiB)反映了约 100 万个函数,且都启用了异常。注意该节命名为 `.gcc_except_table`,尽管工具链是 clang/LLVM — 这个名称是平台 ABI 约定,不是 GCC 的证据。

> **注意 —** 这三个节在*种类*上是教科书式的,但在*大小*上极不寻常,并且是该二进制 RTTI/异常机制的骨干。剥离异常的重新实现者可减少约 5% 文件体积。封装 `.eh_frame_hdr` 的 `PT_GNU_EH_FRAME` 段的 unwinder 类型是 `X86_64_UNWIND`。

### .note.gnu.build-id

```text
  [1] .note.gnu.build-id NOTE  00000000000002a8 0002a8 000020 00 A  0   0  4

这个 32 字节 GNU note 将整个 wiki 锚定到一个构建。其布局是标准 Elf_Nhdrnamesz=4"GNU\0")、descsz=0x10type=3NT_GNU_BUILD_ID),后跟 16 字节 hash:

text
  0x000002a8 04000000 10000000 03000000 474e5500  ............GNU.
  0x000002b8 89edbbe8 1c5b328a 958fe628 a9f2207d  .....[2....(.. }
```text

→ build-id `89edbbe81c5b328a958fe628a9f2207d`。这是文件中第一个已分配节(vaddr `0x2a8`,紧跟 program headers 之后),也是每个页面版本固定 blockquote 中引用的规范版本键。

---

## 真正的异类

### __lcxx_override — 被覆盖的全局 new/delete

```text
  [26] __lcxx_override   PROGBITS  00000000213f0720 213f0720 000105 00 AX  0   0 32

261 字节的可执行代码,保存替换后的全局分配运算符,libc++(__lcxx 前缀)会把它们路由到 tcmalloc,而不是默认 malloc:

text
  1231661: 00000000213f0720  69 FUNC LOCAL .. _Znwm                 // operator new(size_t)
  1231663: 00000000213f07a0 104 FUNC LOCAL .. _ZnwmSt11align_val_t  // operator new(size_t, align_val_t)
  1231665: 00000000213f0780   5 FUNC LOCAL .. _Znam                 // operator new[](size_t)
  1231669: 00000000213f0820   5 FUNC LOCAL .. _ZnamSt11align_val_t  // operator new[](size_t, align_val_t)
```text

把 operator-new/delete 覆盖隔离到命名节中,可以让链接保证它们优先于 libc++ 默认实现(插桩/符号介入顺序),并让运行时验证覆盖确实存在。看到 `__lcxx_override` 的逆向工程师应立即把它理解为“这个二进制替换了全局分配器” — 整个 745 MiB 镜像中的每个 C++ `new` 都会经由这四个跳板流入 tcmalloc。

### filewrapper_toc

```text
  [38] filewrapper_toc   PROGBITS  00000000224bf798 220bf798 0001e8 00 WA  0   0  8

488 字节,可写,磁盘上填零(hexdump 全为 00)。这是 Google file_wrapper/嵌入文件机制的目录表 — 一个编译进二进制的资源注册表,由重定位在静态初始化时填充,而不是在磁盘上携带已初始化字节。在没有非零磁盘内容的情况下,无法仅凭字节恢复精确 schema;其用途是根据符号名以及 WA + 零填充模式推断的(对精确记录格式为 MEDIUM 置信度)。

.text.split — 空节

text
  [20] .text.split       PROGBITS  000000000e63bab2 e63bab2 000000 00 AXo  0   0  1
```text

一个 **零字节** 可执行节,位于 `google_malloc` 和 `.text` 之间。它是 clang 的 machine-function-splitting pass 发出的标记/锚点,用于界定 split-text 区域;在此构建中,拆分出的冷代码落在了别处(`.text.unlikely`、`google_init_cold`),留下这个空但存在的节。它无害,但逆向工程师扫描节表时不应被 0 字节 `PROGBITS X` 条目吓到 — 它不包含代码。

### 未剥离 — 完整 .symtab

```text
  [49] .symtab           SYMTAB  0000000000000000 221ba830 1c3cc50 18  51 1232970  8
  [51] .strtab           STRTAB  0000000000000000 23df76c3 ab824de 00   0   0  1
  # note: the [49] Inf field 1232970 is readelf's "first global" index, not the
  # entry count; the table holds 1,233,710 entries (size 0x1c3cc50 ÷ 24).

尽管是生产插件,libtpu.so 随附其完整 .symtab — 1,233,710 项(28.2 MiB;大小 0x1c3cc50 ÷ 24),外加 171.5 MiB 的 .strtab,其中是它们的 mangled names — 此外还有加载时 .dynsym(741 个符号)。因此它不是经典意义上已剥离:每个局部函数和对象都有可读的修饰名,这就是为什么本 wiki 能按名称而不只是地址解析 descriptor_table_protodef_*RseqFunction_PerCpuCmpxchg64 和 PJRT 单例。

特性 — .symtab + .strtab 这一对是非分配的(vaddr 0x0,无 A 标志)— 它不消耗运行时内存,但增加约 200 MiB 文件大小。Google 发布它是为了 crash-symbolication。对逆向工程师来说,这是巨大的礼物:该二进制实际上是自文档化的。运行 strip --strip-debug 后,200 MiB 和所有局部名称都会消失,只剩 741 个 .dynsym 导出。

注意: 一个包含零大小 .tm_clone_table 的 “sections: 88” 汇总,是把两个 ELF 对象(libtpu.so + sdk.so)一起计数。仅 libtpu.soreadelf -h/readelf -S 计算正好有 52 个节头,并且 libtpu.so 没有 .tm_clone_table(该行属于同级 sdk.so)。本页表格只描述 libtpu.so

注意: .lbss0x9f940 = 653,632 字节(638 KiB),.ldata0x21c00 = 138,240 字节(135 KiB)。PJRT 单例位于该节的精确基址 0x227ba840,由 .symtab 项确认,而不只是“靠近”它。


交叉引用

  • ELF 剖析 — 维护权威的完整 52 节表、PT_LOAD 段映射和动态数组;本页是显著节的带注释子集。
  • 静态初始化 — 维护 .init_array 普查(2900 个构造函数槽);本页只固定该数组的位置,并说明它构建的 PJRT 单例。
  • 尾随 zstd Blob — 负责回答是否存在任何嵌入/尾随切分载荷的问题;本页只覆盖已命名 ELF 节。
  • 二进制取证概览 — 整个取证部分的地图,以及每个节的深入分析所在位置。
  • 双二进制拆分 — 为什么 libtpu.sosdk.so 是独立对象,以及 .tm_clone_table / 合并节数数字来自何处。
  • 嵌入库图谱 — 本页列举的命名节所属的第三方库(tcmalloc、protobuf/upb、libc++、Abseil)。