Open3

Reposoup: シンボル概念の整理と静的ライブラリへの対応

okuokuokuoku

Androidを含めた近代的なPOSIXシステムでは、ELFのシンボルバージョニングを使用して、異なるABIを持つAPIを単一の共有ライブラリに格納できるようにしている。Android NDKは複数のAPI Levelを単一SDKでサポートしているため、これにも対応する必要がある。

ELF symbol versioning

https://johannst.github.io/notes/development/symbolver.html が良い要約だと思う。

かんたんには:

  • .symver ディレクティブでシンボルのバージョン付き別名を設定できる。
  • (gccにはsymver属性もあるが、Clangにはまだ無い https://github.com/llvm/llvm-project/issues/59438 。LTOする場合にはシンボル属性が効かないため必要になる。)
  • dlvsym を使用して .so から特定のバージョンのシンボルを取得できる (Androidのbionicも何故かdlvsymを宣言しているが、Androidは別の方法 https://developer.android.com/ndk/guides/using-newer-apis?hl=ja を提供している -- そもそも他バージョンのシンボルを明示的に使うモチベーションが無い)
okuokuokuoku

新しいシンボルの概念

1つのエントリポイントにはいくつかの名前が付与されることになる(Reposoupの命名):

  • Symbol ID: プロセスイメージ内でユニークな名前 <SONAME>_<Absolute name> または <Absolute name> (静的ライブラリ/LTOライブラリの場合) -- 必要になるシチュエーションは無いはず
  • Absolute name: バージョン込みの名前 <Source name>@<Version> または <Source name>
  • Source name: C/C++ソースコードから呼ばれるシンボル名。

ELFのルールでは、デフォルトは @@ 、そうでないものは @ で区切ることになるが、Reposoupでは @ に正規化する。デフォルトかどうかは別にフラグを持たせる(デフォルト = 素の dlsym で参照される名前)

(FIXME: ReposoupのメインターゲットであるWebAssemblyではどうすんの。。?)

okuokuokuoku

静的ライブラリへの対応

今まで動的ライブラリしか考えてこなかったが、一応Android NDKでは静的ライブラリも提供されているのでそちらも考察することにした。

ただ、静的ライブラリは動的ライブラリとはかなり根本的にアイデアが異なるので専用の考察が相応に必要になる。

要求シンボル

静的ライブラリ、いわゆる .a は、単に .o をアーカイブしたもので、内部の .o 単位でプログラムに影響することになる。

llvm-nm --quiet --extern-only libm.a

のようにしてシンボルをダンプすると:

cosf.o:
                 U __stack_chk_fail
                 U arm_math_inv_pio4
                 U arm_math_invalidf
                 U arm_math_sincosf_table
0000000000000000 T cosf

exp.o:
0000000000000000 T __exp_finite
0000000000000000 T __ieee754_exp
                 U arm_math_exp_data
                 U arm_math_oflow
                 U arm_math_uflow
0000000000000000 T exp

T (text) や U (undefined) なシンボルが表われる。動的ライブラリの場合、ライブラリのユーザーは U になるものを気にする必要は無かったが、静的ライブラリでは U なシンボルを供給するのはユーザーの責任になる (が、 __stack_chk_fail のようなシンボルは基本的にコンパイラがデフォルトで提供してくれるので心配する必要は無い) 。

超ややこしいのは、(通常のシチュエーションでは、) U シンボルが要求されるかどうかは .o 単位で判断されることと言える。上の例だと arm_math_exp_data はプログラムで exp を使うまで要求されない。このため、Reposoupでは .o の単位で提供シンボルと要求シンボルの両方を管理する必要がある。

動的ライブラリと静的ライブラリの両方が提供されるケース

Android NDKでは、標準ライブラリは動的ライブラリと静的ライブラリの両方が存在する。このため、Reposoupは重複シンボルをよく取り扱える必要がある。