使用 `-lto-embed-bitcode`

问题描述

目标:从 ELF 二进制文件中提取完整程序(合并)后 LTO 位码。

该程序恰好是用 Rust 编写的,但我认为这不是关键细节。

我可以使用以下 Cargo 调用将 Rust 程序编译为带有 .llvmbc 部分的 ELF 二进制文件:

RUSTFLAGS="-C linker_plugin_lto -C linker=clang -C link-arg=-fuse-ld=lld -C link-arg=-Wl,--plugin-opt=-lto-embed-bitcode=optimized" \
    cargo build --release

然后我可以使用 readelf -S | grep llvmbc 来验证该部分是否存在。确实如此。太棒了!

我现在想提取完整的程序后 LTO 位码并反汇编它:

$ objcopy target/release/world --dump-section .llvmbc=llvm.bc
$ llvm-dis llvm.bc
LLVM ERROR: Invalid encoding
PLEASE submit a bug report to https://bugs.llvm.org/ and include the crash backtrace.
Stack dump:
0.      Program arguments: llvm-dis llvm.bc
 #0 0x000055c06f7ae78c llvm::sys::PrintStackTrace(llvm::raw_ostream&,int) (/home/vext01/research/yorick/llvm-project/inst/bin/llvm-dis+0x1b578c)
 #1 0x000055c06f7ac6e4 llvm::sys::RunSignalHandlers() (/home/vext01/research/yorick/llvm-project/inst/bin/llvm-dis+0x1b36e4)
 #2 0x000055c06f7ac843 SignalHandler(int) (/home/vext01/research/yorick/llvm-project/inst/bin/llvm-dis+0x1b3843)
 #3 0x00007f6c62eaf730 __restore_rt (/lib/x86_64-linux-gnu/libpthread.so.0+0x12730)
 #4 0x00007f6c627957bb raise /build/glibc-vjB4T1/glibc-2.28/signal/../sysdeps/unix/sysv/linux/raise.c:51:1
 #5 0x00007f6c62780535 abort /build/glibc-vjB4T1/glibc-2.28/stdlib/abort.c:81:7
 #6 0x000055c06f783753 llvm::report_fatal_error(llvm::Twine const&,bool) (/home/vext01/research/yorick/llvm-project/inst/bin/llvm-dis+0x18a753)
 #7 0x000055c06f783868 (/home/vext01/research/yorick/llvm-project/inst/bin/llvm-dis+0x18a868)
 #8 0x000055c06f7bb703 llvm::BitstreamCursor::ReadAbbrevRecord() (/home/vext01/research/yorick/llvm-project/inst/bin/llvm-dis+0x1c2703)
 #9 0x000055c06f64a49d llvm::BitstreamCursor::advance(unsigned int) (.constprop.1679) (/home/vext01/research/yorick/llvm-project/inst/bin/llvm-dis+0x5149d)
#10 0x000055c06f658abd llvm::getBitcodeFileContents(llvm::MemoryBufferRef) (/home/vext01/research/yorick/llvm-project/inst/bin/llvm-dis+0x5fabd)
#11 0x000055c06f63e159 main (/home/vext01/research/yorick/llvm-project/inst/bin/llvm-dis+0x45159)
#12 0x00007f6c6278209b __libc_start_main /build/glibc-vjB4T1/glibc-2.28/csu/../csu/libc-start.c:342:3
#13 0x000055c06f6436ea _start (/home/vext01/research/yorick/llvm-project/inst/bin/llvm-dis+0x4a6ea)
Aborted

如果我在二进制文件中搜索 LLVM 标头的魔术字节 0x4243c0de,则会有多次命中。此外,如果我告诉 rustc 使用单个代码生成单元 (-C codegen-units=1),那么魔术字节的点击次数就会减少(正好两个)。

我认为正在发生的是链接器将中间对象的 .llvmbc 部分与 LTO 后位码连接起来,这让 llvm-dis 感到困惑。

假设是这样,我如何才能明确地仅提取 LTO 后的位码?我对尝试根据魔术字节分开不同的模块感到不舒服。这似乎很容易出错,因为该字节序列可能会巧合地出现在其他地方(即根本不标记位代码对象的开始)。

是否有办法让 libLTO 将 LTO 后的位码放入不同名称的专用部分?阅读源代码后,我认为不修改是不可能的。

谢谢

编辑

使用 clang 而不是 rustc 重复实验似乎确实有效,所以我开始怀疑这是否真的是一个 rust 错误。也许 rustc 在不该传递的时候传递了旧的预合并位代码?

$ clang  -fuse-ld=lld -flto -Wl,--plugin-opt=-lto-embed-bitcode=optimized world.c
$ objcopy a.out --dump-section .llvmbc=llvm.bc
$ llvm-dis llvm.bc
$ head -5 llvm.ll
; ModuleID = 'llvm.bc'
source_filename = "ld-temp.o"
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...