リンカヌ初心者ガむド

David Drysdale 、 リンカヌの初心者向けガむド  http://www.lurklurk.org/linkers/linkers.html 。

この蚘事の目的は、CおよびC ++プログラマヌがリンカの本質を理解できるようにするこずです。 過去数幎にわたっお、私はこれを倚くの同僚に説明し、最終的にこの資料を玙に移し、よりアクセスしやすくするこずにしたしたしたがっお、再床説明する必芁はありたせんでした。 [2009幎3月の曎新Windowsのレむアりト機胜に関する远加情報ず、より詳现な1定矩ルヌルが远加されたした。

私が助けを求められた兞型的な䟋は、次のレむアりト゚ラヌです。
g++ -o test1 test1a.o test1b.o test1a.o(.text+0x18): In function `main': : undefined reference to `findmax(int, int)' collect2: ld returned 1 exit status 

あなたの反応が「おそらくextern“ C”を忘れた」なら、この蚘事で䞎えられおいるすべおを知っおいるでしょう。

内容



定矩Cファむルには䜕が含たれおいたすか


この章では、Cファむルのさたざたなコンポヌネントに぀いお簡単に説明したす。 以䞋のリストのすべおが理にかなっおいる堎合は、この章をスキップしお次の章に進んでください。

たず、宣蚀ず定矩の違いを理解する必芁がありたす。 定矩は 、名前を実装に関連付けたす。実装は、コヌドたたはデヌタのいずれかです。

この宣蚀は、関数たたは倉数の定矩特定の名前を持぀がプログラム内の別の堎所、おそらく別のCファむルに存圚するこずをコンパむラヌに䌝えたす。 定矩はアナりンスでもあるこずに泚意しおください-実際、それはプログラムの他の堎所が珟圚のものず䞀臎するアナりンスです。

倉数には2皮類の定矩がありたす。

さらに、「䜿甚可胜」ずいう甚語は、「定矩時に倉数に関連付けられた名前で参照できる」ず理解する必芁がありたす。

初めおでは明らかではない特別なケヌスがいく぀かありたす。

関数を静的ずしお定矩するこずにより、この関数に名前でアクセスできる堎所の数が単玔に枛るこずに泚意しおください。

グロヌバル倉数ずロヌカル倉数では、初期化された倉数ず初期化されおいない倉数を区別できたす。 メモリ内の倉数甚に予玄されたスペヌスが特定の倀で満たされるかどうか。

最埌に、 mallocたたはnewを䜿甚しお動的に割り圓おられた情報をメモリに保存できたす。 この堎合、割り圓おられたメモリに名前でアクセスするこずはできないため、ポむンタ-名前のないメモリ領域のアドレスを含む名前付き倉数を䜿甚する必芁がありたす。 このメモリ領域は、 freeたたはdeleteを䜿甚しお解攟するこずもできたす。 この堎合、「動的割り圓お」を扱っおいたす。

芁玄するず
コヌドデヌタ
グロヌバルロヌカルダむナミック
むニシア
リシロ
バスルヌム
非開始
リシロ
バスルヌム
むニシア
リシロ
バスルヌム
非開始
リシロ
バスルヌム
発衚
怠laz
int fn(int x);extern int x;extern int x;N / aN / aN / a
定矩する
怠laz
int fn(int x) { ... }int x = 1;
スコヌプ
-ファむル
int x;
スコヌプ-ファむル
int x = 1;
スコヌプ-機胜
int x;
スコヌプ-機胜
int* p = malloc(sizeof(int));

おそらく最も簡単な孊習方法は、サンプルプログラムを芋るだけです。
 /*     */ int x_global_uninit; /*     */ int x_global_init = 1; /*    ,   *         C  */ static int y_global_uninit; /*    ,   *         C  */ static int y_global_init = 2; /*   ,   - *     */ extern int z_global; /*  ,   -   *  (    "extern",   * ) */ int fn_a(int x, int y); /*  .     static,   *        C . */ static int fn_b(int x) { return x+1; } /*  . */ /*     . */ int fn_c(int x_local) { /*     */ int y_local_uninit; /*     */ int y_local_init = 3; /* ,       , *      */ x_global_uninit = fn_a(x_local, x_global_init); y_local_uninit = fn_a(x_local, y_local_init); y_local_uninit += fn_b(z_global); return (x_global_uninit + y_local_uninit); } 


Cコンパむラが行うこず


Cコンパむラの仕事は、テキスト通垞を人間が読める圢匏に倉換しお、コンピュヌタヌが理解できるものにするこずです。 出力で、コンパむラはオブゞェクトファむルを生成したす 。 UNIXプラットフォヌムでは、これらのファむルには通垞、接尟蟞.oが付いおいたす。 Windowsでは、接尟蟞.obj。 オブゞェクトファむルの内容は、本質的に2぀のものです。

この堎合、コヌドずデヌタには名前が関連付けられたす。定矩に関連付けられおいる関数たたは倉数の名前です。

オブゞェクトコヌドは、プログラマヌによっお曞かれたC呜什に察応する適切に構成された機械呜什のシヌケンスです。これらはすべおifずwhileおよびgotoさえもです。 これらの呪文は特定の皮類の情報を操䜜する必芁があり、情報はどこかにある必芁がありたす-このためには倉数が必芁です。 コヌドは他のコヌド特に、プログラム内の他のC関数を参照する堎合もありたす。

コヌドが倉数たたは関数を参照する堎合はい぀でも、コンパむラは 、以前にその倉数たたは関数の宣蚀を芋た堎合にのみこれを蚱可したす。 アナりンスは、定矩がプログラムの他の堎所に存圚するずいう玄束です。

リンカの仕事はこれらの玄束を怜蚌するこずです。 しかし、コンパむラはオブゞェクトファむルを生成するずきにこれらのすべおの玄束をどうしたすか

基本的に、コンパむラは空のスペヌスを残したす。 空の堎所リンクには名前がありたすが、この名前に察応する倀はただわかっおいたせん。

これにより、 䞊蚘のプログラムに察応するオブゞェクトファむルを次のように衚瀺できたす。
オブゞェクトファむル図

オブゞェクトファむルの解析


これたでのずころ、すべおを高いレベルで怜蚎しおきたした。 ただし、これが実際にどのように機胜するかを芋るず䟿利です。 䞻なツヌルはnmコマンドで、UNIXプラットフォヌム䞊のオブゞェクトファむルのシンボルに関する情報を提䟛したす。 Windowsの堎合、 /symbolsオプションを指定したdumpbinコマンドはほが同等です。 nm.exeを含むWindows甚に移怍された GNU binutilsツヌルもありたす。

䞊蚘の䟋から取埗したオブゞェクトファむルに察しおnm生成するものを芋おみたしょう。
 Symbols from c_parts.o: Name Value Class Type Size Line Section fn_a | | U | NOTYPE| | |*UND* z_global | | U | NOTYPE| | |*UND* fn_b |00000000| t | FUNC|00000009| |.text x_global_init |00000000| D | OBJECT|00000004| |.data y_global_uninit |00000000| b | OBJECT|00000004| |.bss x_global_uninit |00000004| C | OBJECT|00000004| |*COM* y_global_init |00000004| d | OBJECT|00000004| |.data fn_c |00000009| T | FUNC|00000055| |.text 

結果はプラットフォヌムによっお倚少異なるように芋える堎合がありたす関連情報に぀いおはman問い合わせおくださいが、重芁な情報は各文字のクラスずそのサむズ存圚する堎合です。 クラスにはさたざたな意味がありたす。

゜ヌスCコヌドの䞀郚ではない文字も衚瀺できたす。 通垞はコンパむラの内郚メカニズムの䞀郚であるため、これに泚意を集䞭するこずはありたせん。したがっお、プログラムは埌でコンパむルできたす。

リンカの機胜パヌト1


前に、関数たたは倉数の宣蚀はコンパむラヌぞの玄束であり、プログラムの他のどこかにその関数たたは倉数の定矩があり、リンカヌの仕事はその玄束をするこずであるず述べたした。 オブゞェクトファむルの図を芋るず、このプロセスを「空のスペヌスを埋める」ず説明できたす 。

䞊蚘の䟋に加えお、別のCファむルを考慮した䟋を䜿甚しおこれを説明したす。
 /*    */ int z_global = 11; /*      y_global_init,    static */ static int y_global_init = 2; /*     */ extern int x_global_init; int fn_a(int x, int y) { return(x+y); } int main(int argc, char *argv) { const char *message = "Hello, world"; return fn_a(11,12); } 

オブゞェクトファむルの抂略図

䞡方の図に基づいお、すべおのポむントを接続できるこずがわかりたす接続されおいない堎合、リンカヌぱラヌメッセヌゞを衚瀺したす。 すべおのものには独自の堎所があり、すべおの堎所には独自の堎所がありたす。 たた、リンカヌは、ここに瀺すようにすべおの空のスペヌスを埋めるこずができたすUNIXシステムでは、通垞、リンクプロセスはldコマンドによっお呌び出されたす。

オブゞェクトファむルの抂略図

オブゞェクトファむルず同様に、 nmを䜿甚しお最終的な実行可胜ファむルを調べるこずができたす。
 Symbols from sample1.exe: Name Value Class Type Size Line Section _Jv_RegisterClasses | | w | NOTYPE| | |*UND* __gmon_start__ | | w | NOTYPE| | |*UND* __libc_start_main@@GLIBC_2.0 | U | FUNC|000001ad| |*UND* _init |08048254| T | FUNC| | |.init _start |080482c0| T | FUNC| | |.text __do_global_dtors_aux|080482f0| t | FUNC| | |.text frame_dummy |08048320| t | FUNC| | |.text fn_b |08048348| t | FUNC|00000009| |.text fn_c |08048351| T | FUNC|00000055| |.text fn_a |080483a8| T | FUNC|0000000b| |.text main |080483b3| T | FUNC|0000002c| |.text __libc_csu_fini |080483e0| T | FUNC|00000005| |.text __libc_csu_init |080483f0| T | FUNC|00000055| |.text __do_global_ctors_aux|08048450| t | FUNC| | |.text _fini |08048478| T | FUNC| | |.fini _fp_hw |08048494| R | OBJECT|00000004| |.rodata _IO_stdin_used |08048498| R | OBJECT|00000004| |.rodata __FRAME_END__ |080484ac| r | OBJECT| | |.eh_frame __CTOR_LIST__ |080494b0| d | OBJECT| | |.ctors __init_array_end |080494b0| d | NOTYPE| | |.ctors __init_array_start |080494b0| d | NOTYPE| | |.ctors __CTOR_END__ |080494b4| d | OBJECT| | |.ctors __DTOR_LIST__ |080494b8| d | OBJECT| | |.dtors __DTOR_END__ |080494bc| d | OBJECT| | |.dtors __JCR_END__ |080494c0| d | OBJECT| | |.jcr __JCR_LIST__ |080494c0| d | OBJECT| | |.jcr _DYNAMIC |080494c4| d | OBJECT| | |.dynamic _GLOBAL_OFFSET_TABLE_|08049598| d | OBJECT| | |.got.plt __data_start |080495ac| D | NOTYPE| | |.data data_start |080495ac| W | NOTYPE| | |.data __dso_handle |080495b0| D | OBJECT| | |.data p.5826 |080495b4| d | OBJECT| | |.data x_global_init |080495b8| D | OBJECT|00000004| |.data y_global_init |080495bc| d | OBJECT|00000004| |.data z_global |080495c0| D | OBJECT|00000004| |.data y_global_init |080495c4| d | OBJECT|00000004| |.data __bss_start |080495c8| A | NOTYPE| | |*ABS* _edata |080495c8| A | NOTYPE| | |*ABS* completed.5828 |080495c8| b | OBJECT|00000001| |.bss y_global_uninit |080495cc| b | OBJECT|00000004| |.bss x_global_uninit |080495d0| B | OBJECT|00000004| |.bss _end |080495d4| A | NOTYPE| | |*ABS* 

䞡方のオブゞェクトファむルの文字が含たれおおり、未定矩の参照はすべお衚瀺されなくなりたした。 シンボルは、同様のタむプが䞀緒になるように䞊べ替えられたす。 たた、OSが実行可胜ファむルなどを凊理するのに圹立぀いく぀かのアドオンもありたす。

結論が耇雑になるほど倚くの耇雑な詳现がありたすが、アンダヌスコアで始たるものをすべお捚おるず、はるかに簡単になりたす。

重耇する文字


前の章では、リンクが芋぀かったシンボルの定矩を芋぀けるこずができない堎合、リンカぱラヌメッセヌゞを出すず述べたした。 たた、レむアりト䞭にキャラクタヌの2぀の定矩が芋぀かった堎合はどうなりたすか

C ++では、゜リュヌションは簡単です。 この蚀語には1぀の定矩のルヌルずしお知られる制限があり、レむアりト䞭に遭遇する各文字に察しお1぀だけの定矩が必芁であり、それ以䞊ではありたせん。 C ++暙準の察応する章は3.2であり、いく぀かの䟋倖に぀いおも蚀及しおいたす。これに぀いおは埌で説明したす 。

Cの堎合、事態はそれほど明癜ではありたせん。 関数ず初期化されたグロヌバル倉数の定矩は正確に1぀でなければなりたせんが、初期化されおいない倉数の定矩は予備的な定矩ずしお解釈できたす。 したがっお、C蚀語は、さたざたな゜ヌスファむルに同じオブゞェクトの予備的な定矩を含めるこずを蚱可したす少なくずも犁止したせん。

ただし、リンカはCおよびC ++以倖の蚀語を凊理できる必芁がありたす。CおよびC ++では、1぀の定矩の芏則が必ずしも尊重されたせん。 たずえば、Fortranがそれを参照するすべおのファむルのすべおのグロヌバル倉数のコピヌを保持するのは正垞です。 次に、リンカヌは、1぀のコピヌサむズが異なる堎合は最倧の代衚を遞択しお重耇を削陀し、残りを砎棄する必芁がありたす。 このモデルは、Fortran COMMON共通キヌワヌドにより、レむアりトの「䞀般モデル」ず呌ばれるこずもありたす。

結果ずしお、少なくずも初期化されおいないグロヌバル倉数の重耇文字である堎合、UNIXリンカが重耇文字の存圚を誓わないこずは非垞に䞀般的ですこのレむアりトモデルは「疎結合のモデル」ず呌ばれるこずもありたす[ translに泚意しおください。 defモデル。より良い提案を歓迎したす]。 これが気になる堎合おそらく気になるはずです、リンカのドキュメントを参照しお、その動䜜を緩和する-work ---オプションを芋぀けおください。 たずえば、GNUツヌルチェヌンでは、 -fno-commonコンパむラオプションを䜿甚するず、共通COMMONブロックを生成する代わりに、BBSセグメントに初期化されおいない倉数を匷制-fno-commonに配眮できたす。

オペレヌティングシステムは䜕をしたすか


リンカが実行可胜ファむルを生成し、シンボルぞの各リンクに適切な定矩を割り圓おたので、実行のためにプログラムを実行するずきにオペレヌティングシステムが䜕を行うかを簡単に理解できたす。

もちろんプログラムを実行するには、マシンコヌドの実行が必芁です。 OSは明らかに、実行可胜ファむルのマシンコヌドをハヌドディスクからオペレヌティングメモリに転送する必芁があり、そこからCPUがそれを取埗できたす。 これらの郚分は、コヌドセグメントコヌドセグメントたたはテキストセグメントず呌ばれたす。

デヌタのないコヌドはそれ自䜓では圹に立ちたせん。 したがっお、すべおのグロヌバル倉数にはコンピュヌタヌのメモリ内の堎所も必芁です。 ただし、初期化されたグロヌバル倉数ず初期化されおいないグロヌバル倉数には違いがありたす。 初期化された倉数には特定の開始倀があり、これもオブゞェクトおよび実行可胜ファむルに保存する必芁がありたす。 プログラムが開始時に開始されるず、OSはこれらの倀をプログラムの仮想空間のデヌタセグメントにコピヌしたす。

初期化されおいない倉数の堎合、OSはすべおの倉数が初期倀ずしお0を持っおいるず想定する堎合がありたす。 倀をコピヌする必芁はありたせん。 れロに初期化されるメモリの䞀郚は、bssセグメントず呌ばれたす。

぀たり、グロヌバル倉数甚のスペヌスは、ディスクに保存されおいる実行可胜ファむルに割り圓おるこずができたす。 初期化された倉数の堎合、その初期倀を保存する必芁がありたすが、初期化されおいない倉数の堎合、サむズを保存するだけです。



お気づきかもしれたせんが、これたでオブゞェクトファむルずリンカに関するすべおの議論で、グロヌバル倉数に぀いおのみ話しおきたした。 前述のロヌカル倉数ず動的に占有されるメモリに぀いおは蚀及したせんでした 。

このデヌタは、プログラムの実行䞭に有効期間が開始および終了するため、リンカヌの介入を必芁ずしたせん。これは、リンカヌがすでにゞョブを実行したよりもずっず埌のこずです。 ただし、説明を完党にするために、次のこずを簡単に瀺したす。

図を完成させるには、実行䞭のプロセスのメモリ空間がどのようなものかを远加する䟡倀がありたす。 ヒヌプずスタックは動的にサむズを倉曎できるため、スタックが䞀方向に成長し、ヒヌプが反察方向に成長するこずは非垞に䞀般的です。 したがっお、スタックずヒヌプが䞭間のどこかで出䌚った堎合にのみ、プログラムは空きメモリ䞍足の゚ラヌを出したすこの堎合、プログラムのメモリ空間は本圓にいっぱいになりたす。



リンカが行うこず; パヌト2


リンカが行うこずの基本を説明したので、より耇雑な郚分の説明を、リンカに远加されたずきずほが同じ順序で説明したす。

リンカの機胜に圱響する䞻な芳察事項は次のずおりです倚数の異なるプログラムが同じこず画面ぞの出力、ハヌドディスクからのファむルの読み取りなどを行う堎合、このコヌドを特定の堎所に分離しお他の人に䞎えるこずは明らかに理にかなっおいたすそれを䜿甚するプログラム。

考えられる解決策の1぀は、同じオブゞェクトファむルを䜿甚するこずですが、オブゞェクトファむルのコレクション党䜓を...簡単にアクセスできる1぀の堎所に保存する方がはるかに䟿利です。

技術的な䜙談この章では、リンカヌの重芁なプロパティである再配眮を完党に省略しおいたす。 異なるプログラムには異なるサむズがありたす。 共有ラむブラリがさたざたなプログラムのアドレス空間にマップされおいる堎合、異なるアドレスになりたす。 , . , (« +1020 ») (« 0x102218BF»), , . — relocation . , , C/C++ — .


— . , (share), ; .

UNIX ar , , , *.a. «lib» "-l" (.. "-lfred" «libfred.a»).
( , ranlib , , . ar .)

Windows .LIB LIB, , «import library», , DLL — Windows DLL

リンカは、オブゞェクトファむルのコレクションを反埩凊理しおそれらを結合するずきに、ただ実装できない文字のリストを保持したす。明瀺的に指定されたすべおのオブゞェクトファむルが凊理されるずすぐに、リンカヌはリスト内に残っおいる文字を怜玢するための新しい堎所、぀たりラむブラリになりたす。ラむブラリオブゞェクトの1぀で未実珟シンボルが定矩されおいる堎合、オブゞェクトがナヌザヌによっおオブゞェクトファむルのリストに远加されたかのようにオブゞェクトが远加され、レむアりトが続行されたす。

ラむブラリから远加されるものの粒床に泚意しおください特定の文字を定矩する必芁がある堎合は、オブゞェクト党䜓 , , . , , — , .

— ; , , . , , , , , .

, ; , ao, bo, -lxおよび-ly。

ファむルaobolibx.aliby.a
察象aobox1.ox2.ox3.oy1.oy2.oy3.o
Oprede-
Lenia
a1, a2, a3b1, b2x11, x12, x13x21, x22, x23x31, x32y11, y12y21, y22y31, y32
解決できない
shonnyeの
リンク
b2, x12a3, y22x23, y12y11y21x31

ao bo , b2 a3 , x12 y22 . libx.a , x1.o , x12 ; , x23 y12 ( y22, x23, y12 ).

libx.a , x23 , x2.o libx.a . y11 ( y22, y12, y11 ). libx.aそのため、リンカはに䜿甚されliby.aたす。

ここでも同じこずが起こり、リンカヌにはずが含たy1.oれy2.oたす。最初のオブゞェクトにぞのリンクが远加されたすがy21、y2.oただ含たれるため、このリンクは単玔に解決されたす。このプロセスの結果、未定矩の参照はすべお解決され、䞀郚のすべおではないラむブラリオブゞェクトが最終的な実行可胜ファむルに含たれたす。

たずえば、ぞboのリンクがあった堎合は、状況が倚少倉わるこずに泚意しおくださいy32。その堎合、レむアりトlibx.aも発生したすが、凊理にliby.aは包含が必芁になりたすy3.o。このオブゞェクトを含めるこずにより、远加したすx31未解決の文字のリストに远加するず、このリンクは未解決のたたになりたす。この段階では、リンカはすでに凊理libx.aを完了しおいるため、このシンボルの定矩は芋぀かりたせんc x3.o。

ちなみに、この䟋はラむブラリlibx.aずラむブラリの間に呚期的な䟝存関係がありliby.aたす;これは通垞Windowsで特に悪いです

動的共有ラむブラリ


C ( libc ) — . , printf , fopen , .

, . - printf , , .

, ( .so .dll Windows .dylibMac OS X。このタむプのラむブラリの堎合、リンカヌは必ずしもすべおのポむントを接続するずは限りたせん。代わりに、リンカヌは「IOU」タむプのクヌポンを発行し私はあなたを借りる=私はあなたを借りる、プログラムが開始するたでこのクヌポンの換金を遅らせたす。

これらすべおは、特定の文字の定矩が共有ラむブラリにあるこずをリンカヌが発芋した堎合、最終的な実行可胜ファむルにこの定矩を含めないずいう事実に芁玄されたす。代わりに、リンカは、シンボルの名前ず、そのシンボルが衚瀺されるはずのラむブラリを曞き蟌みたす。

プログラムが実行のために呌び出されるず、OSは、ビルドプロセスの残りの郚分がプログラムの開始前に時間通りに完了するこずを保蚌したす。関数が呌び出される前mainに、リンカヌの小さなバヌゞョン倚くの堎合、ld.so ) — .

, printf . printf , libc.so — printf .

, . ( printf libc.so ), . , , .

, ( , ar ), . , nm — : , , liby.so x31 . : y32 bc , y3.o x3.o .

, — ldd ; Unix , ( ), , . , . ( , LD_LIBRARY_PATH .)
 /usr/bin:ldd xeyes linux-gate.so.1 => (0xb7efa000) libXext.so.6 => /usr/lib/libXext.so.6 (0xb7edb000) libXmu.so.6 => /usr/lib/libXmu.so.6 (0xb7ec6000) libXt.so.6 => /usr/lib/libXt.so.6 (0xb7e77000) libX11.so.6 => /usr/lib/libX11.so.6 (0xb7d93000) libSM.so.6 => /usr/lib/libSM.so.6 (0xb7d8b000) libICE.so.6 => /usr/lib/libICE.so.6 (0xb7d74000) libm.so.6 => /lib/libm.so.6 (0xb7d4e000) libc.so.6 => /lib/libc.so.6 (0xb7c05000) libXau.so.6 => /usr/lib/libXau.so.6 (0xb7c01000) libxcb-xlib.so.0 => /usr/lib/libxcb-xlib.so.0 (0xb7bff000) libxcb.so.1 => /usr/lib/libxcb.so.1 (0xb7be8000) libdl.so.2 => /lib/libdl.so.2 (0xb7be4000) /lib/ld-linux.so.2 (0xb7efb000) libXdmcp.so.6 => /usr/lib/libXdmcp.so.6 (0xb7bdf000) 

, , , , . , , ( bss — , , , strtok ). , , . , ao co , bo co , .

Windows DLL


共有ラむブラリの䞀般的な原則はUnixずWindowsの䞡方のプラットフォヌムでほが同じであるずいう事実にもかかわらず、初心者が理解できるいく぀かの詳现がただありたす。

゚クスポヌトされたシンボル

最倧の違いは、Windowsラむブラリでは文字が自動的に゚クスポヌトされないこずです。Unixでは、共有ラむブラリに察しお認蚌されたすべおのオブゞェクトファむルのすべおの文字が、このラむブラリのナヌザヌに衚瀺されたす。Windowsでは、プログラマは明瀺的に䞀郚の文字を衚瀺する必芁がありたす。それらを゚クスポヌトしたす。

シンボルずWindows DLLを゚クスポヌトするには3぀の方法がありたすこれら3぀の方法はすべお同じラむブラリに混圚させるこずができたす。

C ++がこのmishmashに接続されるずすぐに、これらのオプションの最初のオプションが最も簡単になりたす。この堎合、コンパむラは名前の装食を匕き受けるためです。

.LIB およびその他のラむブラリ関連ファむル

Windowsラむブラリに関連する2番目の困難に盎面したす。゚クスポヌトされたシンボルに関する情報は、リンカヌが他のシンボルず関連付ける必芁がありたすが、それ自䜓には含たれおいたせんDLL。代わりに、この情報は察応する.LIBファむルに含たれおいたす。

.LIBに関連付けられおいるファむルはDLL、どの゚クスポヌトされた文字がDLLその堎所ずずもに含たれおいるかを説明したす。を䜿甚するバむナリは、文字を正しく関連付けるためにファむルにDLLアクセスする必芁がありたす.LIB。

物事をさらに混乱させるために、拡匵機胜は.LIB静的ラむブラリにも䜿甚されたす。

実際、Windowsラむブラリに䜕らかの圢で関連する可胜性のあるさたざたなファむルがいく぀かありたす。ずずもに.LIBファむル、およびオプションの.DEFファむルを䜿甚するず、Windowsラむブラリに関連付けられおいる次のすべおのファむルを衚瀺できたす。

これは、これらすべおの远加ファむルに含たれるほがすべおの情報が単にラむブラリ自䜓に远加されるUnixずの倧きな違いです。

むンポヌトされたキャラクタヌ

DLLは、゚クスポヌトされた文字を明瀺的に宣蚀するための芁件に加えお、ラむブラリコヌドを䜿甚しおむンポヌトする文字を明瀺的に宣蚀するバむナリも蚱可したす。これは必須ではありたせんが、16ビットりィンドりの履歎プロパティによっお匕き起こされる速床の最適化を提䟛したす。

これを行うには、次のように゜ヌスコヌドで__declspecdllimportずしお文字を宣蚀したす。
 __declspec(dllimport) int function_from_some_dll(int x, double y); __declspec(dllimport) extern int global_var_from_some_dll; 

C. : DLL, / , , DLL, .

— .
 #ifdef EXPORTING_XYZ_DLL_SYMS #define XYZ_LINKAGE __declspec(dllexport) #else #define XYZ_LINKAGE __declspec(dllimport) #endif XYZ_LINKAGE int xyz_exported_function(int x); XYZ_LINKAGE extern int xyz_exported_variable; 

DLL, , EXPORTING_XYZ_DLL_SYMS ( #define ) . , .

, DLL, , Windows , . Unix , , .. , , , , . Windows .

— . , , — , , ,

, , . X.DLL Y.DLL , Y.DLL X.DLL , : , .

Windows .

しかし、呚期的な䟝存関係を回避するような方法でラむブラリを再線成するこずは確かに優れおいたす...

画像を補完するC ++


C++ , C, . — C++ C, . , , .


C++ , , , ( ):
 int max(int x, int y) { if (x>y) return x; else return y; } float max(float x, float y) { if (x>y) return x; else return y; } double max(double x, double y) { if (x>y) return x; else return y; } 

: - max , ?

(name mangling), (to mangle = , , .. ) , . . .

( ), , , , (, nm — !):
 Symbols from fn_overload.o: Name Value Class Type Size Line Section __gxx_personality_v0| | U | NOTYPE| | |*UND* _Z3maxii |00000000| T | FUNC|00000021| |.text _Z3maxff |00000022| T | FUNC|00000029| |.text _Z3maxdd |0000004c| T | FUNC|00000041| |.text 

max , , , «max» — «i» int , «f» float «d» double ( , , , !).

, , , . (, c++filt ) ( --demangle GNU nm), - :
 Symbols from fn_overload.o: Name Value Class Type Size Line Section __gxx_personality_v0| | U | NOTYPE| | |*UND* max(int, int) |00000000| T | FUNC|00000021| |.text max(float, float) |00000022| T | FUNC|00000029| |.text max(double, double) |0000004c| T | FUNC|00000041| |.text 

, , C C++. , C++ , ; , C , , . , C++ extern "C" . C++ , — C++ , C, C , C++.

, , , - extern "C" C C++ .
 g++ -o test1 test1a.o test1b.o test1a.o(.text+0x18): In function `main': : undefined reference to `findmax(int, int)' collect2: ld returned 1 exit status 

玠晎らしいヒントは、゚ラヌメッセヌゞに関数の眲名が含たれおいるこずです。これは、単に芋぀からなかったずいうメッセヌゞではありfindmaxたせん。぀たり、C ++コヌドはのようなものを探したすが、"_Z7findmaxii"のみを芋぀け"findmax"たす。したがっお、レむアりト゚ラヌが発生したす。

ずころで、extern "C"クラスのメンバヌ関数では宣蚀が無芖されるこずに泚意しおくださいC ++暙準の7.5.4

静的オブゞェクトの初期化


C++, , — . — , . , , .

, . C — : , ---.

C ++では、初期化プロセスは単に固定倀をコピヌするよりもはるかに耇雑になる可胜性がありたす。プログラム自䜓が実際に実行を開始する前に、クラス階局党䜓のさたざたなコンストラクタヌのすべおのコヌドを実行する必芁がありたす。

これを凊理するために、コンパむラは各C ++ファむルのオブゞェクトファむルに少し䜙分な情報を配眮したす。぀たり、これは特定のファむルに察しお呌び出す必芁があるコンストラクタのリストです。リンク時に、リンカヌはこれらのリストをすべお1぀の倧きなリストに結合し、リスト党䜓を通過するコヌドを配眮しお、すべおのグロヌバルオブゞェクトのコンストラクタヌを呌び出したす。順序に

泚意しおください , — , . (. « C++» — 47 , 4 )

, nm . C++ :
 class Fred { private: int x; int y; public: Fred() : x(1), y(2) {} Fred(int z): x(z), y(3) {} }; Fred theFred; Fred theOtherFred(55); 

( ) nm :
 Symbols from global_obj.o: Name Value Class Type Size Line Section __gxx_personality_v0| | U | NOTYPE| | |*UND* __static_initialization_and_destruction_0(int, int) |00000000| t | FUNC|00000039| |.text Fred::Fred(int) |00000000| W | FUNC|00000017| |.text._ZN4FredC1Ei Fred::Fred() |00000000| W | FUNC|00000018| |.text._ZN4FredC1Ev theFred |00000000| B | OBJECT|00000008| |.bss theOtherFred |00000008| B | OBJECT|00000008| |.bss global constructors keyed to theFred |0000003a| t | FUNC|0000001a| |.text 

, , W ( «» («weak» symbol)) ".gnu.linkonce.t. stuff ". , «Name» , — .

パタヌン


先ほど、関数の3぀の異なる実装の䟋を瀺したしたmax。それぞれがさたざたな型の匕数を取りたした。ただし、関数の本䜓コヌドは3぀のケヌスすべおで同䞀であるこずがわかりたす。そしお、同じコヌドを耇補するこずは、悪いプログラミングトヌンであるこずを知っおいたす。

C ++ではテンプレヌトの抂念が導入されおいるため、すべおのケヌスで以䞋のコヌドを䞀床に䜿甚できたす。max_template.h関数コヌドのコピヌを1぀だけ持぀ヘッダヌファむルを䜜成できたすmax。
 template <class T> T max(T x, T y) { if (x>y) return x; else return y; } 

このファむルを゜ヌスファむルに含めお、テンプレヌト関数を詊しおください。
 #include "max_template.h" int main() { int a=1; int b=2; int c; c = max(a,b); //   ,    max<int>(int,int) double x = 1.1; float y = 2.2; double z; z = max<double>(x,y); //    ,   max<double>(double,double) return 0; } 

C++ max<int>(int,int) max<double>(double,double) . , - . , , max<float>(float,float) max<MyFloatingPointClass>(MyFloatingPointClass,MyFloatingPointClass) .

. , , , ( , ).

これはどのように行われたすか通垞、アクションの2぀のパスがありたす。反埩する暩限を間匕くか、むンスタンスをビルドフェヌズに延期するかのいずれかです通垞、これらのアプロヌチをSunのスマヌトパスおよびパスず呌びたす。

むンスタンスを繰り返す間匕き方法は、各オブゞェクトファむルに、怜出されたすべおのパタヌンのコヌドが含たれおいるこずを意味したす。たずえば、䞊蚘のファむルの堎合、オブゞェクトファむルの内容は次のようになりたす。
 Symbols from max_template.o: Name Value Class Type Size Line Section __gxx_personality_v0 | | U | NOTYPE| | |*UND* double max<double>(double, double) |00000000| W | FUNC|00000041| |.text _Z3maxIdET_S0_S0_ int max<int>(int, int) |00000000| W | FUNC|00000021| |.text._Z3maxIiET_S0_S0_ main |00000000| T | FUNC|00000073| |.text 

max<int>(int,int) max<double>(double,double) .

, , ( , ). — .

( Solaris C++) — , . , , , .

, , C++ ( )


, , — . , , . .

dlopen dlsym ( Windows LoadLibrary GetProcAddress ). . , , dlopen .

dlopen , , ( RTLD_NOW ) ( RTLD_LAZY ). , dlopen , , , — .

, . , , , . . dlsym芋぀かった文字の名前を報告するリテラルパラメヌタを受け取り、その堎所ぞのポむンタを返したすたたはNULL文字が芋぀からない堎合。

C ++ずの盞互䜜甚


, C++, ?

. dlsym , , . , , .. .

, , C++ . , — C- , ( ), .

䞊蚘を芁玄するず、次のこずに泚意しおください。通垞extern "C"、゚ントリポむントに1人の囚人を眮く方が適切dlsymです。この゚ントリポむントは、C ++クラスのすべおのむンスタンスぞのポむンタヌを返すファクトリメ゜ッドで、C ++のすべおのチャヌムにアクセスできたす。ラむブラリが動的にロヌドたたはアンロヌドされた堎合、ラむブラリに远加でき、リンカによっお呌び出されるロヌドたたは実行䞭は関係ありたせんいく぀かの特殊文字がある

ため、コンパむラはロヌドされるラむブラリのグロヌバルオブゞェクトのデザむナをうたく凊理dlopenできたす。ここで、コンストラクタたたはデストラクタぞの必芁な呌び出しを行うこずができたす。 Unixでは、これらは関数で_initあり、_fini , , GNU , __attribute__((constructor)) __attribute__((destructor)) . Windows — DllMain DWORD fdwReason DLL_PROCESS_ATTACH DLL_PROCESS_DETACH .

, « », ; « », « » , ( , ). , .

オプショナル


, , , 95% , .

, :


このペヌゞに関する有甚な提案をしおくれたMike CappずEd Wilsonに感謝したす。


Copyright©2004-2005,2009-2010 David Drysdale

このドキュメントは、GNU Free Documentation Licenseバヌゞョン1.1たたはFree Software Foundationが発行するそれ以降のバヌゞョンの条件の䞋で、コピヌ、配垃、および/たたは倉曎する蚱可を䞎えられおいたす。䞍倉セクション、フロントカバヌテキスト、バックカバヌテキストはありたせん。ラむセンスのコピヌはこちらから入手できたす。

Source: https://habr.com/ru/post/J150327/


All Articles