Bagaimana cara kerja Perpustakaan Impor? Detailnya?

90

Saya tahu ini mungkin tampak cukup mendasar bagi para geek. Tapi saya ingin membuatnya sangat jelas.

Ketika saya ingin menggunakan Win32 DLL, biasanya saya hanya memanggil API seperti LoadLibrary () dan GetProcAdderss (). Tetapi baru-baru ini, saya mengembangkan dengan DirectX9, dan saya perlu menambahkan file d3d9.lib , d3dx9.lib , dll.

Saya sudah cukup mendengar bahwa LIB untuk tautan statis dan DLL untuk tautan dinamis.

Jadi pemahaman saya saat ini adalah bahwa LIB berisi implementasi metode dan terhubung secara statis pada waktu tautan sebagai bagian dari file EXE akhir. Sementara DLL dinamis dimuat saat runtime dan bukan merupakan bagian dari file EXE akhir.

Tetapi terkadang, ada beberapa file LIB yang disertakan dengan file DLL, jadi:

  • Untuk apa file LIB ini?
  • Bagaimana mereka mencapai tujuan mereka?
  • Apakah ada alat yang memungkinkan saya memeriksa bagian dalam file LIB ini?

Perbarui 1

Setelah memeriksa wikipedia, saya ingat bahwa file LIB ini disebut pustaka impor . Tapi saya bertanya-tanya bagaimana cara kerjanya dengan aplikasi utama saya dan DLL yang akan dimuat secara dinamis.

Perbarui 2

Seperti yang dikatakan RBerteig, ada beberapa kode rintisan di file LIB yang lahir dengan DLL. Jadi urutan pemanggilannya harus seperti ini:

Aplikasi utama saya -> rintisan di LIB -> DLL target nyata

Jadi informasi apa yang harus dimuat dalam LIB ini? Saya bisa memikirkan yang berikut:

  • File LIB harus berisi jalur lengkap dari DLL yang sesuai; Jadi DLL dapat dimuat oleh runtime.
  • Alamat relatif (atau file offset?) Dari setiap titik masuk metode ekspor DLL harus dikodekan dalam stub; Jadi lompatan / panggilan metode yang benar dapat dilakukan.

Apakah saya benar dalam hal ini? Apakah ada yang lebih dari itu?

BTW: Apakah ada alat yang dapat memeriksa perpustakaan impor? Jika saya bisa melihatnya, tidak akan ada keraguan lagi.

smwikipedia
sumber
4
Saya melihat bahwa tidak ada yang menjawab bagian terakhir dari pertanyaan Anda, yang berkaitan dengan alat yang dapat memeriksa pustaka impor. Dengan Visual C ++, setidaknya ada dua cara untuk melakukannya: lib /list xxx.libdan link /dump /linkermember xxx.lib. Lihat pertanyaan Stack Overflow ini .
Alan
Juga, dumpbin -headers xxx.libberikan beberapa informasi yang lebih rinci, dibandingkan dengan utilitas libdan link.
m_katsifarakis

Jawaban:

105

Menautkan ke file DLL dapat terjadi secara implisit pada waktu kompilasi tautan, atau secara eksplisit pada waktu proses. Either way, DLL akhirnya dimuat ke dalam ruang memori proses, dan semua titik masuk yang diekspor tersedia untuk aplikasi.

Jika digunakan secara eksplisit pada waktu proses, Anda menggunakan LoadLibrary()dan GetProcAddress()memuat DLL secara manual dan mendapatkan petunjuk ke fungsi yang perlu Anda panggil.

Jika ditautkan secara implisit saat program dibuat, maka stub untuk setiap ekspor DLL yang digunakan oleh program akan ditautkan ke program dari pustaka impor, dan stub tersebut diperbarui saat EXE dan DLL dimuat saat proses diluncurkan. (Ya, saya telah menyederhanakan lebih dari sedikit di sini ...)

Rintisan tersebut harus berasal dari suatu tempat, dan dalam rantai alat Microsoft mereka berasal dari bentuk khusus file .LIB yang disebut pustaka impor . .LIB yang diperlukan biasanya dibangun pada waktu yang sama dengan DLL, dan berisi rintisan untuk setiap fungsi yang diekspor dari DLL.

Yang membingungkan, versi statis dari pustaka yang sama juga akan dikirim sebagai file .LIB. Tidak ada cara sepele untuk membedakannya, kecuali bahwa LIB yang merupakan pustaka impor untuk DLL biasanya akan lebih kecil (seringkali jauh lebih kecil) daripada LIB statis yang cocok.

Jika Anda menggunakan toolchain GCC, secara kebetulan, Anda sebenarnya tidak memerlukan pustaka impor untuk mencocokkan DLL Anda. Versi linker Gnu yang di-porting ke Windows memahami DLL secara langsung, dan dapat mensintesis hampir semua stub yang diperlukan dengan cepat.

Memperbarui

Jika Anda tidak dapat menahan diri untuk tidak mengetahui di mana semua mur dan baut sebenarnya dan apa yang sebenarnya terjadi, selalu ada sesuatu di MSDN untuk membantu. Artikel Matt Pietrek, Pandangan Mendalam tentang Format File Eksekusi Portabel Win32 adalah gambaran umum yang sangat lengkap tentang format file EXE dan bagaimana itu dimuat dan dijalankan. Bahkan telah diperbarui untuk mencakup .NET dan lebih banyak lagi sejak pertama kali muncul di Majalah MSDN ca. 2002.

Selain itu, akan sangat membantu untuk mengetahui cara mempelajari dengan tepat DLL apa yang digunakan oleh suatu program. Alat untuk itu adalah Dependency Walker, alias depend.exe. Versi itu disertakan dengan Visual Studio, tetapi versi terbaru tersedia dari pembuatnya di http://www.dependencywalker.com/ . Ini dapat mengidentifikasi semua DLL yang ditentukan pada waktu tautan (baik pemuatan awal dan pemuatan tunda) dan juga dapat menjalankan program dan mengawasi setiap DLL tambahan yang dimuat pada waktu berjalan.

Perbarui 2

Saya telah mengubah beberapa teks sebelumnya untuk memperjelasnya saat membaca ulang, dan menggunakan istilah seni yang secara implisit dan eksplisit menghubungkan untuk konsistensi dengan MSDN.

Jadi, kami memiliki tiga cara agar fungsi perpustakaan dapat tersedia untuk digunakan oleh program. Pertanyaan selanjutnya yang jelas adalah: "Bagaimana saya memilih cara yang mana?"

Penautan statis adalah cara menghubungkan sebagian besar program itu sendiri. Semua file objek Anda terdaftar, dan dikumpulkan bersama ke file EXE oleh linker. Sepanjang jalan, linker menangani tugas-tugas kecil seperti memperbaiki referensi ke simbol global sehingga modul Anda dapat memanggil fungsi satu sama lain. Perpustakaan juga dapat ditautkan secara statis. File objek yang membentuk pustaka dikumpulkan bersama oleh pustakawan dalam file .LIB yang dicari linker untuk modul yang berisi simbol yang diperlukan. Salah satu efek dari tautan statis adalah bahwa hanya modul-modul dari perpustakaan yang digunakan oleh program yang ditautkan ke sana; modul lain diabaikan. Misalnya, pustaka matematika C tradisional mencakup banyak fungsi trigonometri. Tetapi jika Anda menautkannya dan menggunakancos(), Anda tidak akan mendapatkan salinan kode untuk sin()atau tan()kecuali Anda juga memanggil fungsi itu. Untuk perpustakaan besar dengan sekumpulan fitur yang kaya, penyertaan modul secara selektif ini penting. Pada banyak platform seperti sistem tertanam, ukuran total kode yang tersedia untuk digunakan di perpustakaan bisa lebih besar dibandingkan dengan ruang yang tersedia untuk menyimpan file yang dapat dieksekusi di perangkat. Tanpa inklusi selektif, akan lebih sulit untuk mengelola detail program pembangunan untuk platform tersebut.

Namun, memiliki salinan pustaka yang sama di setiap program yang berjalan menciptakan beban pada sistem yang biasanya menjalankan banyak proses. Dengan jenis sistem memori virtual yang tepat, halaman memori yang memiliki konten identik hanya perlu ada sekali di sistem, tetapi dapat digunakan oleh banyak proses. Hal ini memberikan manfaat untuk meningkatkan peluang bahwa halaman yang berisi kode cenderung identik dengan beberapa halaman dalam sebanyak mungkin proses yang berjalan. Namun, jika program secara statis menautkan ke pustaka runtime, maka masing-masing memiliki campuran fungsi yang berbeda yang masing-masing diatur dalam memproses peta memori di lokasi yang berbeda, dan tidak banyak halaman kode yang dapat dibagikan kecuali jika program itu sendiri adalah program yang berdiri sendiri. berjalan lebih dari sekedar proses. Jadi gagasan tentang DLL memperoleh keuntungan besar lainnya.

DLL untuk pustaka berisi semua fungsinya, siap digunakan oleh program klien apa pun. Jika banyak program memuat DLL itu, mereka semua dapat berbagi halaman kodenya. Semua orang menang. (Nah, sampai Anda memperbarui DLL dengan versi baru, tapi itu bukan bagian dari cerita ini. Google DLL Neraka untuk sisi kisah itu.)

Jadi, pilihan besar pertama yang harus diambil ketika merencanakan proyek baru adalah antara hubungan dinamis dan statis. Dengan tautan statis, Anda memiliki lebih sedikit file untuk diinstal, dan Anda kebal dari pihak ketiga yang memperbarui DLL yang Anda gunakan. Namun, program Anda lebih besar, dan itu tidak cukup baik untuk ekosistem Windows. Dengan tautan dinamis, Anda memiliki lebih banyak file untuk diinstal, Anda mungkin memiliki masalah dengan pihak ketiga yang memperbarui DLL yang Anda gunakan, tetapi Anda secara umum lebih ramah terhadap proses lain di sistem.

Keuntungan besar dari DLL adalah ia dapat dimuat dan digunakan tanpa kompilasi ulang atau bahkan menautkan ulang program utama. Ini memungkinkan penyedia pustaka pihak ketiga (misalnya Microsoft dan runtime C) untuk memperbaiki bug di pustaka mereka dan mendistribusikannya. Setelah pengguna akhir menginstal DLL yang diperbarui, mereka segera mendapatkan manfaat dari perbaikan bug tersebut di semua program yang menggunakan DLL tersebut. (Kecuali itu merusak banyak hal. Lihat DLL Hell.)

Keuntungan lainnya berasal dari perbedaan antara pemuatan implisit dan eksplisit. Jika Anda melakukan upaya ekstra untuk memuat eksplisit, DLL mungkin bahkan tidak ada saat program ditulis dan diterbitkan. Ini memungkinkan mekanisme ekstensi yang dapat menemukan dan memuat plugin, misalnya.

RBerteig
sumber
4
Menghapus posting saya dan meningkatkan ini, karena Anda menjelaskan hal-hal dengan cara yang lebih baik daripada yang saya lakukan;) Jawaban yang bagus.
sebelum tanggal
2
@RBerteig: Terima kasih atas jawaban Anda yang luar biasa. Hanya sedikit koreksi, menurut di sini ( msdn.microsoft.com/en-us/library/9yd93633.aspx ), ada 2 jenis tautan dinamis ke DLL, tautan implisit waktu muat dan tautan eksplisit run-time . Tidak ada waktu kompilasi yang menghubungkan . Sekarang saya bertanya-tanya apa perbedaan antara Static Linking tradisional (menautkan ke file * .lib yang berisi implementasi penuh) dan penautan dinamis Waktu Muat ke DLL (melalui pustaka impor)?
smwikipedia
1
Lanjutkan: Apa pro dan kontra dari Static Linking dan Load-Time dynamic linking ? Tampaknya 2 pendekatan ini memuat semua file yang diperlukan ke dalam ruang alamat pada awal proses. Mengapa kita membutuhkan 2 dari mereka? Terima kasih.
smwikipedia
1
Anda mungkin dapat menggunakan alat seperti "objdump" untuk mengintip ke dalam file .lib dan mencari tahu apakah itu perpustakaan impor atau perpustakaan statis yang sebenarnya. di Linux ketika mengkompilasi silang ke target Windows, dimungkinkan untuk menjalankan 'ar' atau 'nm' pada file .a (versi mingw dari file .lib) dan perhatikan bahwa lib impor memiliki nama file .o generik dan tidak ada kode (hanya instruksi 'jmp'), sedangkan libs statis memiliki banyak fungsi dan kode di dalamnya.
jangan terang
1
Koreksi kecil: Anda juga dapat menautkan secara implisit pada waktu proses. Dukungan Linker untuk DLL yang Dimuat Tertunda menjelaskan hal ini secara mendetail. Ini berguna jika Anda ingin mengubah jalur pencarian DLL secara dinamis, atau menangani kegagalan resolusi impor dengan baik (untuk mendukung fitur OS baru, tetapi masih berjalan di versi yang lebih lama, misalnya).
IInspectable
5

File pustaka impor .LIB ini digunakan dalam properti proyek berikut Linker->Input->Additional Dependencies, ketika membuat sekumpulan dll yang membutuhkan informasi tambahan pada waktu tautan yang disediakan oleh pustaka impor. File .LIB. Dalam contoh di bawah ini untuk tidak mendapatkan kesalahan linker saya perlu merujuk ke dll A, B, C, dan D melalui file lib mereka. (perhatikan agar linker menemukan file ini, Anda mungkin perlu menyertakan jalur penerapannya, Linker->General->Additional Library Directoriesjika tidak, Anda akan mendapatkan error build karena tidak dapat menemukan file lib yang disediakan.)

Linker-> Input-> Dependensi Tambahan

Jika solusi Anda membangun semua pustaka dinamis, Anda mungkin dapat menghindari spesifikasi ketergantungan eksplisit ini dengan mengandalkan bendera referensi yang ditampilkan di bawah Common Properties->Framework and Referencesdialog. Bendera ini tampaknya secara otomatis melakukan penautan atas nama Anda menggunakan file * .lib. Kerangka dan Referensi

Namun ini seperti yang dikatakan Properti Umum , yang tidak spesifik konfigurasi atau platform. Jika Anda perlu mendukung skenario build campuran seperti dalam aplikasi kami, kami memiliki konfigurasi build untuk merender build statis dan konfigurasi khusus yang membangun build terbatas dari subset rakitan yang diterapkan sebagai library dinamis. Saya telah menggunakan Use Library Dependency Inputs and Link Library Dependenciesflags yang disetel ke true dalam berbagai kasus untuk mendapatkan sesuatu untuk dibangun dan kemudian disadari untuk menyederhanakan hal-hal tetapi ketika memperkenalkan kode saya ke build statis, saya memperkenalkan banyak peringatan linker dan build itu sangat lambat untuk build statis. Saya akhirnya memperkenalkan banyak peringatan semacam ini ...

warning LNK4006: "bool __cdecl XXX::YYY() already defined in CoreLibrary.lib(JSource.obj); second definition ignored  D.lib(JSource.obj)

Dan saya akhirnya menggunakan spesifikasi manual Additional Dependenciesuntuk memenuhi linker untuk build dinamis sambil menjaga agar pembuat statis senang dengan tidak menggunakan properti umum yang memperlambatnya. Ketika saya menyebarkan subset dinamis membangun saya hanya menyebarkan file dll karena file lib ini hanya digunakan pada waktu link, bukan saat runtime.

jxramos.dll
sumber
3

Ada tiga jenis pustaka: pustaka statis, bersama dan dimuat secara dinamis.

Pustaka statis ditautkan dengan kode pada fase penautan, jadi sebenarnya pustaka tersebut dapat dieksekusi, tidak seperti pustaka bersama, yang hanya memiliki stub (simbol) untuk dicari di file pustaka bersama, yang dimuat pada waktu proses sebelum fungsi utama dipanggil.

Yang dimuat secara dinamis sangat mirip dengan pustaka bersama, kecuali mereka dimuat ketika dan jika perlu muncul oleh kode yang Anda tulis.

Zoltán Szőcs
sumber
@Tokopedia Tapi saya tidak yakin dengan pernyataan Anda tentang perpustakaan bersama.
smwikipedia
@smwikipedia: Linux memilikinya, saya menggunakannya, jadi mereka pasti ada. Baca juga: en.wikipedia.org/wiki/Library_(computing)
Zoltán Szőcs
3
Ini perbedaan yang halus. Pustaka bersama dan dinamis adalah file DLL. Perbedaannya adalah saat dimuat. Perpustakaan bersama dimuat oleh OS bersama dengan EXE. Library dinamis dimuat dengan pemanggilan kode LoadLibrary()dan API terkait.
RBerteig
Saya membaca dari [1] bahwa DLL adalah implementasi konsep Perpustakaan Bersama dari Microsoft. [1]: en.wikipedia.org/wiki/Dynamic-link_library#Import_libraries
smwikipedia
Saya tidak setuju bahwa ini adalah perbedaan yang halus, dari tampilan pemrograman itu membuat perbedaan besar apakah pustaka bersama dimuat secara dinamis atau tidak (jika dimuat secara dinamis, maka Anda harus menambahkan kode boilerplate untuk mengakses fungsi).
Zoltán Szőcs