【问题标题】:Remove dead code before linking链接前删除死代码
【发布时间】:2017-03-29 20:51:18
【问题描述】:

在一个包含多个静态链接对象文件的项目中,我将其中一个替换为单独的实现。我想在实现替换的目标文件提供的每个符号之前测试我的代码,所以我使用-Wl,--unresolved-symbols=ignore-all 让链接器不会抱怨丢失的符号。

但是当我测试代码时,它在尝试使用未定义的符号之一时会崩溃。因此,我正在寻找一种方法来告诉链接器“请在链接之前删除所有未引用的代码,然后告诉我在从入口点可到达的代码中是否还有未引用的符号”。这可能吗?

【问题讨论】:

  • 目标文件是从生成的 LLVM IR(而不是 C 代码)生成的,如果这有区别的话。
  • 通过 opt 传递 IR 就足够了吗?听起来像deadstriping然后正常链接就可以了
  • 不,我不认为opt 有帮助,因为opt 一次只查看一个模块,对吧?
  • 我正在考虑使用 llvm-link 将各种 IR 放在一起,然后选择(尤其是 -dce、-globaldce)进行剥离。将 IR 转换为目标代码。然后链接器获取一个文件,并且仍然会警告任何实际可访问的符号。
  • 嗯,这可能可行,但很难集成到现有的构建系统中(在最终链接之前将每个 .ll 编译为 .o 文件)。

标签: linker undefined-symbol dead-code link-time-optimization


【解决方案1】:

根据我在自己的代码库中发现的用途,根据 cmets 写出一个答案,并检查该方法是否适合我。

int do_things(void);

int application_main(void)
{
  return do_things();
}

int test_main(void)
{
  return 42;
}

int main(void)
{
  return test_main();
}

布局大致反映了我的用例。一个给定的 IR 块可能有两个入口点,一个用于运行单元测试,一个用于执行代码的用途。单元测试需要整个模块所需的符号子集。能够在不构建其他所有内容的情况下构建单元测试部分是一个优势。

Deadstripping 比我之前的 -Wl,--unresolved-symbols=ignore-all 方法有了明显的改进

clang demo.c     # undefined reference to `do_things'
clang -O3 demo.c # undefined reference to `do_things'
clang demo.c -c -emit-llvm -o demo.bc # OK

llvm-nm demo.bc 
---------------- T application_main
                 U do_things
---------------- T main
---------------- T test_main
clang demo.bc    # undefined reference to `do_things'

opt -o stripped.bc -internalize -internalize-public-api-list=main -globaldce demo.bc
llvm-nm stripped.bc 
---------------- T main
---------------- t test_main
clang stripped.bc # OK

公共符号列表可以从 ir 文件中导出(至少在我的情况下),因此 opt 调用实际上是

 opt -internalize -internalize-public-api-list=`llvm-nm -extern-only -defined-only -just-symbol-name some-file.bc` -globaldce -O2

【讨论】:

    猜你喜欢
    • 2018-11-25
    • 2016-07-14
    • 1970-01-01
    • 2013-08-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多