LoginSignup
3
1

More than 5 years have passed since last update.

リンク前に不必要なシンボルを削除する

Posted at

StackOverflowで気になる質問を見つけたので調査した結果を共有します
https://stackoverflow.com/questions/43103922/remove-dead-code-before-linking

問題

demo.c
int do_things(void);

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

int test_main(void) {
  return 42;
}

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

元の問題は、application_maintest_mainを(おそらくはプリプロセッサで)切り替えたいのですが、ライブラリに関数do_thingsが実装されていないためリンクが失敗します。

/tmp/demo-d19626.o: 関数 `application_main' 内:
demo.c:(.text+0x5): `do_things' に対する定義されていない参照です
clang-6.0: error: linker command failed with exit code 1 (use -v to see invocation)

このdo_thingsをリンク前に除けるかという問題です。

global DCE (dead code elimination)

今回はLLVMの最適化ツールoptによって削除する作戦で行きましょう。optは入力されたIRを変換するPassに通すためのコマンドです。Passについては例えば大学院生のためのLLVMなどに詳しく解説してあります。

まずLLVM IRに変換します

clang demo.c -c -emit-llvm -o demo.bc # OK

これには当然do_thingsのシンボルが定義されています

$ llvm-nm demo.bc
---------------- T application_main
                 U do_things
---------------- T main
---------------- T test_main

次にoptを適用していきましょう。ここではglobaldce Passを使用しましょう。これは使っていない内部関数を削除するためのPassです。しかし、do_thingsは内部関数ではないので内部関数にする必要があります。それにはinternalize Passを使います

$ opt -o stripped.bc -internalize -globaldce demo.bc
$ llvm-nm stripped.bc # 何も出力されない

残念全部消えてしまいました(´・ω・`)
どうやらmainまで内部関数に指定されてしまったようです。mainを内部関数にしないためにはinternalize-public-api-listを使用するようです

$ 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
3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1