源码和二进制插桩

举报
黄生 发表于 2026/09/30 10:15:22 2026/09/30
【摘要】 先上表:Sanitizer 类插桩BOLT 插桩操作对象源码已编译好的二进制何时插桩编译期编译之后、运行之前需要源码吗需要不需要典型工具ASan / TSan / MSanllvm-bolt -instrumentSanitizer 是源码级插桩:编译器在生成代码时,往每个函数入口、每个内存访问前后插入检查逻辑,然后重新编译。所以你必须有源码。BOLT 是二进制级插桩:拿到的已经是编译好的 ...

先上表:

Sanitizer 类插桩 BOLT 插桩
操作对象 源码 已编译好的二进制
何时插桩 编译期 编译之后、运行之前
需要源码吗 需要 不需要
典型工具 ASan / TSan / MSan llvm-bolt -instrument

Sanitizer 是源码级插桩:编译器在生成代码时,往每个函数入口、每个内存访问前后插入检查逻辑,然后重新编译。所以你必须有源码。

BOLT 是二进制级插桩:拿到的已经是编译好的 ELF 文件(如mysqld),BOLT 直接读它的机器码,在每条分支指令处插入计数逻辑,生成一个新的二进制(mysqld.inst)。整个过程不碰源码。

BOLT 具体怎么做

  1. 读二进制:解析 ELF,找到所有基本块和分支指令。
  2. 插入计数代码:在每个基本块入口或分支处,写一段额外的机器码,用来记录"这个块被执行了多少次"“这条分支跳去了哪里”。这些计数数据写到一块单独的内存区域。
  3. 生成新二进制:mysqld.inst 体积比原版大,运行也慢一些,但它会在退出时把计数数据写进 .fdata 文件。
  4. 跑负载:正常运行 mysqld.inst,它一边干活一边计数。
  5. 优化:BOLT 读 .fdata,知道哪些块热、哪些分支常走,再对原始二进制做重排,生成最终优化版。

为什么它能做到不改源码

因为机器码本身携带了足够的信息:函数边界、基本块划分、跳转指令的目标地址,都在 ELF 的符号表和指令流里。BOLT 不需要知道"这行 C 代码是什么意思",它只需要知道"这条 b.eq 跳去了哪个地址,那个地址被执行了多少次"。

这也是 BOLT 相比 PGO 的独特之处:PGO (Profile-Guided Optimization,剖面引导优化)是源码级/编译期优化,BOLT 是二进制级/链接后优化。两者可以叠加,比如先 PGO 编译,再用 BOLT 对产物二次重排。

鲲鹏场景

Sanitizer 改源码,BOLT 改二进制。在鲲鹏 920 假设没有 BRBE 的情况下,那就用软件来帮忙,这种二进制级插桩恰好绕开了硬件限制——不需要硬件帮忙记录分支,BOLT 自己在代码里埋计数器。代价就是插桩版跑得慢一些,且只适合离线采集 Profile,不能直接上生产。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。