78

udis86ライブラリを使用するプログラムをコンパイルしようとしています。実際には、ライブラリのユーザー マニュアルに記載されているサンプル プログラムを使用しています。しかし、コンパイル中にエラーが発生します。私が得るエラーは次のとおりです。

example.c:(.text+0x7): undefined reference to 'ud_init'
example.c:(.text+0x7): undefined reference to 'ud_set_input_file'
.
.
example.c:(.text+0x7): undefined reference to 'ud_insn_asm'

私が使用しているコマンドは次のとおりです。

$ gcc -ludis86 example.c -o example 

ユーザーマニュアルの指示に従ってください。

明らかに、リンカは libudis ライブラリをリンクできません。しかし、コマンドを次のように変更すると:

$ gcc example.c -ludis86 -o example 

それは働き始めます。誰かが最初のコマンドの問題を説明できますか?

4

3 に答える 3

114

それは、GNU リンカが使用するリンク アルゴリズムがどのように機能するかによるものです (少なくとも、静的ライブラリのリンクに関しては)。リンカーはシングル パス リンカーであり、一度表示されたライブラリを再度参照することはありません。

ライブラリは、オブジェクト ファイルのコレクション (アーカイブ) です。オプションを使用してライブラリを追加すると、リンカはライブラリからすべてのオブジェクト ファイルを-l無条件に取得す​​るわけではありません。現在必要なオブジェクト ファイル、つまり現在未解決の (保留中の) シンボルを解決するファイルのみを取得します。その後、リンカーはそのライブラリを完全に忘れます。

保留中のシンボルのリストは、リンカーが入力オブジェクト ファイルを左から右に次々と処理するときに、リンカーによって継続的に維持されます。各オブジェクト ファイルを処理するときに、一部のシンボルが解決されてリストから削除され、他の新しく発見された未解決のシンボルがリストに追加されます。

そのため、 を使用してライブラリを含めた場合-l、リンカーはそのライブラリを使用して、現在保留中のシンボルを可能な限り解決し、そのライブラリを完全に忘れます。後で突然、そのライブラリから追加のオブジェクト ファイルが必要になったことが判明した場合、リンカはそのライブラリに「戻って」それらの追加のオブジェクト ファイルを取得することはありません。もう手遅れです。

このため、リンカーのコマンド ラインの後半-lでオプションを使用することを常にお勧めします。これにより、リンカーが必要なオブジェクト ファイルと不要なオブジェクト ファイルを確実に判断できるようになります。オプションをリンカーの最初のパラメーターとして配置することは、一般にまったく意味がありません。最初は、保留中のシンボルのリストは空です (または、より正確には、単一のシンボルで構成されます)。つまり、リンカーは何も取得しません。まったく図書館。-l-lmain

あなたの場合、オブジェクトファイルexample.oにはシンボルなどへの参照が含まれていますud_initud_set_input_fileリンカーは最初にそのオブジェクトファイルを受け取る必要があります。これらのシンボルを保留中のシンボルのリストに追加します。その後、-lオプションを使用してライブラリを追加できます: -ludis86. リンカーはライブラリを検索し、保留中のシンボルを解決するすべてのものをライブラリから取得します。

コマンドラインの最初にオプションを配置する-ludis86と、リンカはライブラリを効果的に無視ud_initします。これは、最初は などが必要であることを認識していないためですud_set_input_file。後で処理example.oするときに、これらのシンボルを検出し、保留中のシンボルに追加します。リスト。しかし、これらのシンボルは、-ludis86既に処理されている (事実上無視されている) ため、最後まで未解決のままになります。

2 つ (またはそれ以上) のライブラリが相互に循環的に参照する場合-l、同じライブラリでオプションを 2 回使用して、そのライブラリから必要なオブジェクト ファイルを取得する機会をリンカーに 2 回与える必要がある場合もあります。

于 2012-08-10T01:00:04.273 に答える
10

私はしばらく前にこれと同じ問題にぶつかりました。結論として、gnuツールは、欠落しているシンボルを解決するためにライブラリリストを常に「検索バック」するとは限りません。簡単な修正は次のいずれかです。

  1. libsとobjを依存関係の順序で指定するだけです(上記で発見したように)

  2. または、循環依存関係がある場合(libAはlibBの関数を参照しますが、libBはlibAの関数を参照します)、コマンドラインでlibsを2回指定するだけです。これは、マニュアルページでも提案されていることです。例えば

    gcc foo.c -lfoo -lbar -lfoo
    
  3. -(and paramsを使用して、-)このような循環依存関係を持つアーカイブのグループを指定します。--start-groupおよびのGNUリンカーマニュアルを参照して--end-groupください。詳細については、こちらをご覧ください。

オプション2または3を使用すると、リンクのパフォーマンスコストが発生する可能性があります。リンクするものがそれほど多くない場合は、問題にならない可能性があります。

于 2012-08-10T01:26:17.993 に答える