次のような複雑なビルド プロセスを伴う大きなソフトウェア プロジェクトがあります。
- 個々のソース ファイルをコンパイルします。
- を使用して、各モジュールのオブジェクト ファイルを別の .o に部分的にリンクします
ld -r
。 - を使用して、各モジュールのプライベート シンボルを非表示にします
objcopy -G
。 - 再び を使用して、モジュール オブジェクトを部分的にリンクします
ld -r
。 - モジュールを共有オブジェクトにリンクします。
ステップ 3 は、プロジェクトの残りの部分にエクスポートされないモジュール プライベート グローバル変数を許可するために必要です。
これはすべて、ARM と IA32 で正常に動作します。残念ながら、今は mips (具体的には Android 用の mipsel-linux-gnu) で動作させる必要があります。また、MIPS 共有オブジェクト ABI は、他のプラットフォームよりもはるかに複雑であり、機能していません。
何が起こっているかというと、ステップ 5 が次のエラーで失敗しています。
CALL16 reloc at 0x1234 not against global symbol
これは、コンパイラが別のコンパイル単位で関数を呼び出すために CALL16 再配置を生成するためと思われますが、CALL16 ではグローバル シンボルの呼び出ししか許可されません。また、手順 3 のために、呼び出しようとしているシンボルの一部が呼び出されません。もはやグローバル。
この時点で、いくつかの可能なオプションが表示されます。
- ステップ 2 で、CALL16 再配置を通常のコンパイル単位内 PC 相対呼び出しに解決するようにリンカを説得します。
- 同上ですが、ステップ 4 または 5 です。
- コンパイル ユニット間の関数呼び出しに対して CALL16 再配置を生成しないようにコンパイラに指示します。
- 他の。
残念ながら、ステップ 3 を無効にすることは、外部要件のためオプションではありません。
私が本当にやりたいことは、ロード時に正しいアドレスにパッチされる絶対コードを生成することです。より小さく、はるかに高速で、非常に単純であり、プロセス間でライブラリを共有する必要はありません。残念ながら、Androiddlopen()
はこれをサポートしていないようです。
現在、私は私の深さから外れています。誰にも提案はありますか?
これは gcc 4.4.5 (Emdebian から)、binutils 2.20.1 です。ターゲット BFD は elf32-tradlittlemips です。ホスト OS は Linux で、Android 用にクロスコンパイルしています。
補遺
手順 4 から、このような警告も表示されます。
$MODULE.o: Can't find matching LO16 reloc against `$SYMBOLNAME' for R_MIPS_GOT16 at 0x18 in section `.text.$SYMBOLNAME'
ステップ 4 への入力の逆アセンブリを見ると、コンパイラが生成したコードが次のようになっていることがわかります。
50: 8f9e0000 lw s8,0(gp)
50: R_MIPS_GOT16 $SYMBOLNAME
54: 8fd9001c lw t9,28(s8)
58: 0320f809 jalr t9
5c: 00a02021 move a0,a1
GOT16 はアドレスの上位半分まで修正されず、下位半分には LO16 が続く必要がありますか? しかし、コードは GOT 間接化を実行しようとしているように見えます。これは私を困惑させます。これが以前の問題に関連しているのか、別の問題なのか、それともまったく問題ではないのか、私にはわかりません...
アップデート
どうやら MIPSは非表示のグローバル シンボルをサポートしていないようです!
隠されているはずのシンボルの名前をマングリングして、誰もそれらが何であるかを知ることができないようにすることで、これを回避しました。これは外部要件をかなり押し付けていますが、出荷可能な製品を入手する唯一の方法であると指摘して、私は管理者に売り込みました。
それはまったく恐ろしいことです(そして、行うには非常に嫌なmakefile作業が含まれます)ので、誰かが持っているなら、より良い解決策が欲しいです...