Tautan dinamis - Linux Vs. Windows

10

Di Windows, ketika saya mengkompilasi kode C / C ++ dalam proyek DLL di MSVC saya mendapatkan 2 file:

  1. MyDll.dll
  2. MyDll.lib

di mana sejauh yang saya mengerti MyDll.libmengandung beberapa jenis tabel pointer yang menunjukkan lokasi fungsi di dll. Ketika menggunakan dll ini, katakanlah dalam file exe, MyDll.libtertanam ke dalam file exe selama hubungan sehingga dalam runtime itu "tahu" di mana fungsi berada MyDll.dlldan dapat menggunakannya.

Tetapi jika saya mengkompilasi kode yang sama di Linux saya hanya mendapatkan satu file MySo.sotanpa MySo.a(setara dengan libfile di Linux) jadi bagaimana cara file yang dapat dieksekusi di Linux tahu di mana fungsi berada MySo.sojika tidak ada yang tertanam di dalamnya selama menghubungkan?

Benny K
sumber

Jawaban:

1

Di Linux, linker (bukan dynamic linker) mencari melalui shared library yang ditentukan pada waktu link dan membuat referensi ke dalamnya di dalam executable. Ketika tautan dinamis memuat executable ini, ia memuat pustaka bersama yang mereka perlukan ke dalam memori dan menyelesaikan simbol, yang memungkinkan binari dijalankan.

MySo.a, jika dibuat, akan benar-benar menyertakan simbol yang akan dihubungkan langsung ke biner alih-alih "tabel pencarian simbol" yang digunakan pada Windows.

Jawaban rustyx menjelaskan proses pada Windows lebih menyeluruh daripada yang saya bisa; sudah lama sejak saya menggunakan Windows.

SS Anne
sumber
1
"Windows mengambil pendekatan yang berbeda ... tentukan ke sistem operasi persis di mana simbol berada di DLL" - ini bertentangan dengan wiki , yang mengatakan bahwa nama fungsi masih diselesaikan (saat startup atau saat panggilan pertama ke fungsi perpustakaan) bahkan ketika Anda gunakan ordinals (kecuali jika pengikatan alamat langsung digunakan yang tidak akan dilakukan siapa pun karena memaksa pengguna perpustakaan untuk mengkompilasi ulang dan menggunakan kembali kode mereka setiap kali pustaka berubah).
yugr
@Yugr Dihapus bagian itu, saya tetap mencoba sedotan.
SS Anne
4

MSVC linker dapat menautkan bersama-sama file objek (.obj) dan objek perpustakaan (.lib) untuk menghasilkan .EXE atau .DLL.

Untuk menautkan dengan DLL, proses dalam MSVC adalah dengan menggunakan apa yang disebut perpustakaan impor (.LIB) yang bertindak sebagai perekat antara nama fungsi C dan tabel ekspor DLL (dalam DLL fungsi dapat diekspor dengan nama atau oleh ordinal - yang terakhir sering digunakan untuk API tidak berdokumen).

Namun, dalam kebanyakan kasus tabel ekspor DLL memiliki semua nama fungsi dan dengan demikian pustaka impor (.LIB) sebagian besar berisi informasi yang berlebihan (" fungsi impor ABC -> fungsi yang diekspor ABC ", dll).
Bahkan dimungkinkan untuk menghasilkan .LIB dari .DLL yang ada.

Linker di platform lain tidak memiliki "fitur" ini dan dapat terhubung dengan perpustakaan dinamis secara langsung.

rustyx
sumber
"Linker pada platform lain tidak memiliki fitur ini" - meskipun mudah untuk mengimplementasikannya (misalnya Implib.so melakukannya untuk Linux) untuk mencapai pemuatan yang tertunda dan barang lainnya.
Yugr
@Yugr: itu sebabnya "fitur" dalam tanda kutip - itu bukan sesuatu yang umumnya ingin Anda lakukan dan merupakan pekerjaan tambahan yang harus Anda lakukan pada Windows.
Chris Dodd
1

Perbedaan yang Anda lihat adalah lebih detail implementasi - di bawah kap Linux dan Windows bekerja dengan cara yang sama - kode Anda memanggil fungsi rintisan yang terhubung secara statis di executable Anda dan tulisan rintisan ini kemudian memuat DLL / shlib jika perlu (jika terjadi penundaan Memuat , jika perpustakaan dimuat ketika program dimulai) dan (panggilan pertama) menyelesaikan simbol melalui GetProcAddress/ dlsym.

Satu-satunya perbedaan adalah bahwa di Linux fungsi rintisan ini (yang disebut PLT bertopik) dihasilkan secara dinamis ketika Anda menautkan aplikasi Anda dengan perpustakaan dinamis (perpustakaan berisi informasi yang cukup untuk menghasilkannya), sedangkan di Linux mereka dihasilkan ketika DLL itu sendiri dibuat, dalam .libfile terpisah .

Kedua pendekatan ini sangat mirip sehingga sebenarnya mungkin untuk meniru perpustakaan impor Windows di Linux (lihat proyek Implib.so ).

Yugr
sumber
0

Di Linux, Anda meneruskan MySo.soke linker dan hanya dapat mengekstraksi apa yang diperlukan untuk fase tautan, memasukkan referensi yang MySo.sodiperlukan pada saat run time.

Pemrogram
sumber
-3

.dllatau .soshared libs (ditautkan dalam runtime), sementara.a dan .libmerupakan pustaka statis (ditautkan dalam waktu kompilasi). Ini tidak ada perbedaan antara Windows dan Linux.

Bedanya, bagaimana mereka ditangani. Catatan: perbedaannya hanya di bea cukai, bagaimana mereka digunakan. Tidak akan terlalu sulit untuk membuat Linux dibangun berdasarkan cara Windows dan sebaliknya, kecuali bahwa praktis tidak ada yang melakukan ini.

Jika kita menggunakan dll, atau kita memanggil fungsi bahkan dari biner kita sendiri, ada cara yang sederhana dan jelas. Misalnya, dalam C, kita melihat bahwa:

int example(int x) {
  ...do_something...
}

int ret = example(42);

Namun, pada tingkat ASM, mungkin ada banyak perbedaan. Misalnya, pada x86, callopcode dieksekusi, dan 42diberikan pada stack. Atau di beberapa register. Atau dimana saja. Tidak ada yang tahu itu sebelum menulis dll , bagaimana ini akan digunakan. Atau bagaimana proyek ingin menggunakannya, mungkin ditulis dengan kompiler (atau dalam bahasa!) Yang bahkan tidak ada sekarang (atau tidak diketahui oleh pengembang dll).

Sebagai contoh, secara default, C dan Pascal menempatkan argumen (dan mendapatkan nilai balik) dari stack - tetapi mereka melakukannya dalam urutan yang berbeda . Anda juga dapat bertukar argumen antara fungsi Anda di register dengan beberapa - pengoptimalan-bergantung-kompiler.

Seperti yang Anda lihat dengan benar, kebiasaan Windows adalah membangun dll, kami juga membuat minimal .a/ .libdengannya. Pustaka statis minimal ini hanya pembungkus, simbol (fungsi) dll yang dicapai melaluinya. Ini membuat konversi panggilan tingkat-asm yang diperlukan.

Keuntungannya adalah kompatibilitas. Kerugiannya adalah bahwa jika Anda hanya memiliki .dll, Anda dapat mengalami kesulitan untuk mencari tahu, bagaimana fungsinya ingin dipanggil. Ini membuat penggunaan dll sebagai tugas peretasan, jika pengembang dll tidak memberi Anda.a . Dengan demikian, ini melayani sebagian besar tujuan penutupan, misalnya jadi apakah lebih mudah untuk mendapatkan uang tunai tambahan untuk SDK.

Kerugian lainnya adalah daripada bahkan jika Anda menggunakan perpustakaan dinamis, Anda perlu mengkompilasi pembungkus kecil ini secara statis.

Di Linux, antarmuka biner dari dll adalah standar dan mengikuti konvensi C. Dengan demikian, tidak .adiperlukan dan ada kompatibilitas biner antara lib yang dibagikan, sebagai gantinya kami tidak memiliki kelebihan dari kebiasaan microsoft.

peterh - Pasang kembali Monica
sumber
1
Harap berikan tautan bukti bahwa fungsi rintisan dapat mengubah urutan argumen. Saya belum pernah mendengar tentang ini sebelumnya dan sulit untuk percaya, mengingat seberapa besar overhead kinerja akan.
Yugr
@Yugr. Daftar ulang sederhana register / stack bukan overhead kinerja. Jika Anda menggunakan dll yang dikompilasi msvc dari binary yang dikompilasi msvc, maka jelas tidak terlalu banyak yang akan terjadi, tetapi itu bisa terjadi.
peterh
1
Kami dapat memperdebatkan hal ini, tetapi jika Anda benar, akan mudah untuk memberikan tautan bukti bahwa fungsi rintisan mampu memproses argumen non-sepele (dan lebih dari sekadar trampolin tiruan).
Yugr
@yugr Rintisan bertopik memiliki akses ke tanda tangan fungsi dll, yang membuat sepele pemrosesan non-sepele.
peterh
1
Saya hanya menyarankan Anda mengisi jawaban Anda dengan beberapa bukti terkait dengan apa yang dilakukan perpustakaan impor (karena beberapa klaim dipertanyakan).
Yugr