5

Windows ホストで RVDS コンパイラを使用して、オブジェクト コード ファイル (C ソース コード) を使用して共有ライブラリ ( *.so) を作成しました。*.o

この共有オブジェクトをアプリケーション ( gccLinux ホスト上の ARM ターゲットに使用) にリンクし、実行時にセグメンテーション エラーを生成する実行可能ファイルを取得します。(私はそれをデバッグしなければならないことを知っています!)

共有ライブラリを作成する代わりに、同じソース ファイルを使用して静的ライブラリを作成し、アプリケーションとリンクしてアプリケーションを実行すると、期待どおりに動作します。

だから私の質問は:

  1. アプリケーションとリンクしたときに正常に動作するように、いくつかの構成を使用してソース ファイル内のシンボル (アプリケーションにエクスポートされた関数) またはその他のシンボルを明示的にエクスポートする必要がありますか? 何が必要で、どうすればよいですか?

  2. 共有ライブラリはどのように機能しますか? つまり、関数がロードされて実行されるアドレスは、ライブラリが作成されたときにライブラリに与えられます。main()アプリケーション ( ) は、ライブラリ関数が実行されるアドレスをどのように解決しますか?

  3. スタティック ライブラリはどのように機能しますか。つまり、スタティック ライブラリの場合、このアドレス指定と解決はどのように行われるのでしょうか?

4

3 に答える 3

13

Linux での動作は次のとおりです。

1) いいえ、何もする必要はありません。ただし、gcc-fvisibilityコマンド ライン引数を使用して変数のエクスポートを制限し、エクスポートされたエントリに可視性属性で明示的にフラグを立てることができます。

2) 実行可能ファイルには、インポートするすべての関数のテーブルがあります (これらはすべてデフォルトの可視性を持つ関数です)。ローダー/リンカーは、ライブラリをロードするアドレスを選択し、実行直前にこのテーブルを埋めます。これらの関数への呼び出しは間接呼び出しです。(これは共有オブジェクトにも当てはまることに注意してください)

3) 静的リンクはリンク時 (コンパイル後) に実行されます。実際のアドレスはアセンブリで置換され、直接呼び出しになります。

注: PIC (位置独立コード) というものがあります。私の知る限り、これは同じ共有オブジェクト内のデータ/関数への参照を処理するため、リンカーはライブラリをロードするときにライブラリのコードの半分を上書きする必要はありません。独自のデータ。あなたはそれを試してみることができます。

于 2009-04-16T14:32:49.460 に答える
3
  1. gccデフォルトですべてのシンボルがエクスポートされるため、 でシンボルをエクスポートする必要はありません。ただし、RVDS は同じことを行う場合としない場合があります。RVDS コンパイラのドキュメントを確認してください (' Relocatable ELF ' 出力用に設定してみてください)。

  2. ベースアドレスは実行時に決定されるため、Linux の共有ライブラリは再配置可能である必要があります。ライブラリの再配置に必要な作業量が減るため、位置に依存しないコードを生成するのが理想的です。ライブラリが再配置可能でない場合、クラッシュします (つまり、動的ライブラリを作成する前に、オブジェクト ファイルから再配置情報を取り除かないでください) ベースアドレスが選択され、内部参照が再配置された後、シンボルは実行時にアドレスに解決されます。

  3. スタティック ライブラリでは、すべてのシンボルの解決、再配置、およびロード アドレスの割り当てがコンパイル時に行われます。

私の唯一の推測は、どういうわけか、コンパイラが出力しているコードは実行時に再配置できないということです。静的ライブラリも壊さずにどうやってそれが起こるのかは謎です...

静的ライブラリと共有ライブラリを RVDS から直接生成している場合、1 つのオプションは、その静的ライブラリを共有ライブラリに変換することです。

gcc -shared -o libfoo.so libfoo.a

これで問題が解決する場合は、RVDS の共有ライブラリ リンカー (またはその構成) が壊れている可能性があります。

于 2011-04-02T03:22:26.037 に答える
0

クラッシュの原因について何か知っていますか?

共有ライブラリを動的に(たとえば、経由で)ロードしている場合の1つの可能性dlopen()は、ライブラリがロードされていないのに正常にロードされたと想定し、nullポインタを介して関数を実行しようとしていることです。

于 2009-05-20T05:23:25.167 に答える