4

次のような複雑なビルド プロセスを伴う大きなソフトウェア プロジェクトがあります。

  1. 個々のソース ファイルをコンパイルします。
  2. を使用して、各モジュールのオブジェクト ファイルを別の .o に部分的にリンクしますld -r
  3. を使用して、各モジュールのプライベート シンボルを非表示にしますobjcopy -G
  4. 再び を使用して、モジュール オブジェクトを部分的にリンクしますld -r
  5. モジュールを共有オブジェクトにリンクします。

ステップ 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作業が含まれます)ので、誰かが持っているなら、より良い解決策が欲しいです...

4

2 に答える 2

1

あなたが抱えている特定のGOTの問題についてはわかりません。binutils には、GOT、LO16/HI16 に関する多くのバグと問題があります。MIPS16 をターゲットにしている場合を除き (これは行っていないようです)、使用しているバージョンでほとんどが修正されていると思います。LO16 は実際にはそこでのみ必要です。MIPS16 を超えると、32 ビット レジスタがあるため、GOT から完全な 26 ビット オフセットを引き出すことになります。LO16 は必要ありませんが、一部の ABI/API ではまだ正式に必要とされていますが、せいぜい警告であるとごまかされていました (使用している場合は、そのフェーズで -Werror を削除してみてください)。正直なところ、その部分の基本のみを理解しています。残りの状況については、答えではないにしても、いくつかの推奨事項がありました(セットアップの複雑さを考えると、確信が持てません)。

MIPS (および私がよく知っているほとんどのアセンブリ) では、ローカル、グローバル、弱いという基本的な 3 つのレベルの可視性があります。さらに、共有オブジェクト用の通信があります。もちろん、GNU は物事をより複雑にし、さらに追加することを好みます。Gas は、保護、非表示、および内部を提供します (少なくとも、すべての拡張機能についていくのは困難です)。このすべての手順を使用すると、可視性を手動でいじる設定は不要に思えます。

変数の中間的なグローバル性を取り除くことができれば、変数を非グローバルにする必要がなくなるはずです。これは、後で遭遇する GOT の問題を単純化するのに役立つだけです。

全体的な問題は少し混乱しています。隠されたグローバルシンボルが何を意味するのかわかりません。それは少し矛盾しています(もちろん、移植性と特定のプロジェクトはクレイジーな問題と制限をもたらします)。ある段階ではクロス アセンブリ ユニット シンボルが必要ですが、後の段階では必要ないようです。GNU 拡張 (私の本では避けるのが最善の方法) を使用せずに、ステップ 1 から 2 のグローバルを comm および/または weakglobals に置き換えたいと思うかもしれません。プリプロセッサのトリッキーを使用して、ステージで複数のサブユニットを使用しないようにすることもできます (醜いですが、このレベルでは移植可能なコードです)。

実際には、1) サブモジュール 2) サブモジュール -> モジュール 3-5) モジュール -> 共有ライブラリのセットアップがあります。単純化しても問題ありません。2) または 3-5) でいつでも C レベルのインターフェイスを挿入して、GCC がアーキテクチャ用に生成するアセンブリを見つけ、それを可視性をクリーンなインターフェイスに分割するための基礎として使用できます。

オーダーメイドのソリューションを提供できればと思いますが、プロジェクト全体がなければそれは不可能です。MIPS の場所 (特にツールチェーン) には問題がありますが、可視性オプション (特に Gas、libbfd、および gcc を使用している場合) は同じであると確信できます。

于 2012-04-23T21:15:25.187 に答える
0

binutils が古すぎます。2.23 のいくつかの変更セットは、「PLT 参照または GOT 参照なしでシンボルを非表示にする」などの問題を解決する場合があります。

于 2013-09-13T06:53:17.690 に答える