Saya sering mendengar istilah 'terhubung secara statis' dan 'terhubung secara dinamis', sering kali mengacu pada kode yang ditulis dalam C , C ++ atau C # . Apa yang mereka, apa yang sebenarnya mereka bicarakan, dan apa yang mereka tautkan?
sumber
Saya sering mendengar istilah 'terhubung secara statis' dan 'terhubung secara dinamis', sering kali mengacu pada kode yang ditulis dalam C , C ++ atau C # . Apa yang mereka, apa yang sebenarnya mereka bicarakan, dan apa yang mereka tautkan?
Ada (dalam kebanyakan kasus, diskon kode ditafsirkan) dua tahap dalam mendapatkan dari kode sumber (apa yang Anda tulis) ke kode yang dapat dieksekusi (apa yang Anda jalankan).
Yang pertama adalah kompilasi yang mengubah kode sumber menjadi modul objek.
Yang kedua, menghubungkan, adalah apa yang menggabungkan modul objek bersama untuk membentuk suatu executable.
Perbedaan dibuat untuk, antara lain, memungkinkan perpustakaan pihak ketiga untuk dimasukkan dalam executable Anda tanpa Anda melihat kode sumbernya (seperti perpustakaan untuk akses database, komunikasi jaringan dan antarmuka pengguna grafis), atau untuk menyusun kode dalam bahasa yang berbeda ( C dan kode assembly misalnya) lalu menghubungkan semuanya.
Saat Anda menautkan file secara statis ke file yang dapat dieksekusi, konten file tersebut disertakan pada waktu tautan. Dengan kata lain, isi file secara fisik dimasukkan ke dalam executable yang akan Anda jalankan.
Ketika Anda menautkan secara dinamis , penunjuk ke file yang ditautkan (misalnya, nama file dari file tersebut) dimasukkan dalam file yang dapat dieksekusi dan isi dari file tersebut tidak termasuk pada waktu tautan. Hanya ketika Anda nanti menjalankan executable file-file yang terhubung secara dinamis ini dibeli dan mereka hanya membeli ke dalam salinan executable yang ada dalam memori, bukan yang ada di disk.
Ini pada dasarnya metode penautan yang ditangguhkan. Ada metode yang bahkan lebih ditangguhkan (disebut keterlambatan mengikat pada beberapa sistem) yang tidak akan membawa file yang terhubung secara dinamis sampai Anda benar-benar mencoba memanggil fungsi di dalamnya.
File yang terhubung secara statis 'dikunci' ke executable pada waktu tautan sehingga tidak pernah berubah. File yang terhubung secara dinamis yang dirujuk oleh yang dapat dieksekusi dapat berubah hanya dengan mengganti file pada disk.
Ini memungkinkan pembaruan fungsionalitas tanpa harus menautkan kembali kode; loader menghubungkan ulang setiap kali Anda menjalankannya.
Ini baik dan buruk - di satu sisi, memungkinkan pembaruan dan perbaikan bug yang lebih mudah, di sisi lain dapat menyebabkan program berhenti bekerja jika pembaruan tidak kompatibel - ini kadang-kadang bertanggung jawab atas "DLL neraka" yang ditakuti sebagian orang sebutkan bahwa aplikasi dapat rusak jika Anda mengganti pustaka yang terhubung secara dinamis dengan pustaka yang tidak kompatibel (pengembang yang seharusnya berharap akan diburu dan dihukum berat, omong-omong).
Sebagai contoh , mari kita lihat kasus pengguna yang mengkompilasi main.c
file mereka untuk tautan statis dan dinamis.
Phase Static Dynamic
-------- ---------------------- ------------------------
+---------+ +---------+
| main.c | | main.c |
+---------+ +---------+
Compile........|.........................|...................
+---------+ +---------+ +---------+ +--------+
| main.o | | crtlib | | main.o | | crtimp |
+---------+ +---------+ +---------+ +--------+
Link...........|..........|..............|...........|.......
| | +-----------+
| | |
+---------+ | +---------+ +--------+
| main |-----+ | main | | crtdll |
+---------+ +---------+ +--------+
Load/Run.......|.........................|..........|........
+---------+ +---------+ |
| main in | | main in |-----+
| memory | | memory |
+---------+ +---------+
Anda dapat melihat dalam kasus statis bahwa program utama dan pustaka runtime C dihubungkan bersama pada waktu tautan (oleh pengembang). Karena pengguna biasanya tidak dapat menautkan kembali yang dapat dieksekusi, mereka terjebak dengan perilaku perpustakaan.
Dalam kasus dinamis, program utama ditautkan dengan pustaka impor runtime C (sesuatu yang menyatakan apa yang ada di pustaka dinamis tetapi tidak benar-benar mendefinisikannya ). Ini memungkinkan tautan untuk menautkan meskipun kode sebenarnya tidak ada.
Kemudian, pada saat runtime, loader sistem operasi melakukan penautan yang terlambat dari program utama dengan DLL runtime C (pustaka tautan dinamis atau pustaka bersama atau nomenklatur lainnya).
Pemilik runtime C dapat menjatuhkan DLL baru kapan saja untuk memberikan pembaruan atau perbaikan bug. Seperti yang dinyatakan sebelumnya, ini memiliki kelebihan dan kekurangan.
.dll
atau.so
ekstensi) - anggap jawabannya menjelaskan konsep daripada menjadi deskripsi yang tepat. Dan, sesuai dengan teks, ini adalah contoh yang menunjukkan penghubung statis dan dinamis untuk hanya file runtime C jadi, ya, itulah yang ditunjukkan oleh `crt pada semuanya.Saya pikir jawaban yang baik untuk pertanyaan ini harus menjelaskan apa linking adalah .
Ketika Anda mengkompilasi beberapa kode C (misalnya), itu diterjemahkan ke bahasa mesin. Hanya urutan byte yang, ketika dijalankan, menyebabkan prosesor untuk menambah, mengurangi, membandingkan, "goto", membaca memori, menulis memori, hal semacam itu. Barang ini disimpan dalam file objek (.o).
Sekarang, dahulu kala, para ilmuwan komputer menemukan benda "subrutin" ini. Jalankan-ini-potongan-kode-dan-kembali-sini. Tidak terlalu lama sebelum mereka menyadari bahwa subrutin yang paling berguna dapat disimpan di tempat khusus dan digunakan oleh program apa pun yang membutuhkannya.
Sekarang di hari-hari awal programmer harus memasukkan alamat memori tempat subrutin ini berada. Sesuatu seperti
CALL 0x5A62
. Ini membosankan dan bermasalah jika alamat memori tersebut perlu diubah.Jadi, prosesnya otomatis. Anda menulis sebuah program yang memanggil
printf()
, dan kompiler tidak tahu alamat memoriprintf
. Jadi kompiler hanya menulisCALL 0x0000
, dan menambahkan catatan ke file objek yang mengatakan "harus mengganti 0x0000 ini dengan lokasi memori printf ".Hubungan statis berarti bahwa program tautan (yang GNU disebut ld ) menambahkan
printf
kode mesin langsung ke file yang dapat dieksekusi, dan mengubah 0x0000 ke alamatprintf
. Ini terjadi ketika executable Anda dibuat.Tautan dinamis berarti bahwa langkah di atas tidak terjadi. File yang dapat dieksekusi masih memiliki catatan yang mengatakan "harus mengganti 0x000 dengan lokasi memori printf". Pemuat sistem operasi perlu menemukan kode printf, memuatnya ke dalam memori, dan memperbaiki alamat CALL, setiap kali program dijalankan .
Adalah umum untuk program memanggil beberapa fungsi yang akan dihubungkan secara statis (fungsi perpustakaan standar seperti
printf
biasanya terhubung secara statis) dan fungsi lain yang terhubung secara dinamis. Yang statis "menjadi bagian" dari yang dapat dieksekusi dan yang dinamis "bergabung" ketika executable dijalankan.Ada kelebihan dan kekurangan untuk kedua metode, dan ada perbedaan antara sistem operasi. Tetapi karena Anda tidak bertanya, saya akan mengakhiri ini di sini.
sumber
ld
dokumentasi GNU .Pustaka yang terhubung secara statis terhubung pada saat kompilasi. Pustaka yang terhubung secara dinamis dimuat pada saat dijalankan. Menghubungkan statis membuat bit perpustakaan menjadi executable Anda. Tautan dinamis yang hanya membuat roti dalam referensi ke perpustakaan; bit untuk perpustakaan dinamis ada di tempat lain dan bisa ditukar nanti.
sumber
Karena tidak ada tulisan di atas yang benar-benar menunjukkan cara menautkan sesuatu secara statis dan melihat bahwa Anda melakukannya dengan benar, maka saya akan mengatasi masalah ini:
Program C sederhana
Tautan secara dinamis program C.
Dan jalankan
file
di biner:Dan itu akan menunjukkan itu terkait secara dinamis sesuatu di sepanjang baris:
"simpleprog: ELF 64-bit LSB dapat dieksekusi, x86-64, versi 1 (SYSV), ditautkan secara dinamis (menggunakan lib bersama), untuk GNU / Linux 2.6.26, BuildID [sha1] = 0xf715572611118b04f686809d90d1c0d75c6028f0f, tidak dilucuti"
Alih-alih, mari kita tautkan secara statis program kali ini:
Menjalankan file pada biner yang terhubung secara statis ini akan menunjukkan:
"simpleprog: ELF 64-bit LSB yang dapat dieksekusi, x86-64, versi 1 (GNU / Linux), terhubung secara statis, untuk GNU / Linux 2.6.26, BuildID [sha1] = 0x8c0b12250801c5a7c7434647b7dc65a644d6132b, tidak dilucuti"
Dan Anda dapat melihatnya terhubung secara statis. Sayangnya, tidak semua perpustakaan mudah untuk secara statis menghubungkan cara ini dan mungkin memerlukan upaya lebih lama menggunakan
libtool
atau menghubungkan kode objek dan perpustakaan C dengan tangan.Untungnya banyak pustaka C yang disematkan suka
musl
menawarkan opsi penautan statis untuk hampir semua pustaka jika tidak semua pustaka mereka.Sekarang
strace
biner yang Anda buat dan Anda dapat melihat bahwa tidak ada perpustakaan yang diakses sebelum program dimulai:Sekarang bandingkan dengan output
strace
pada program yang terhubung secara dinamis dan Anda akan melihat bahwa strace versi yang terhubung secara statis jauh lebih pendek!sumber
(Saya tidak tahu C # tetapi menarik untuk memiliki konsep tautan statis untuk bahasa VM)
Tautan dinamis melibatkan mengetahui cara menemukan fungsionalitas yang diperlukan yang hanya Anda miliki referensi dari program Anda. Anda bahasa runtime atau OS mencari sepotong kode pada sistem file, jaringan atau cache kode yang dikompilasi, mencocokkan referensi, dan kemudian mengambil beberapa langkah untuk mengintegrasikannya ke gambar program Anda di memori, seperti relokasi. Semuanya dilakukan saat runtime. Itu bisa dilakukan secara manual atau oleh kompiler. Ada kemampuan untuk memperbarui dengan risiko mengacaukan (yaitu, DLL neraka).
Menghubungkan statis dilakukan pada waktu kompilasi itu, Anda memberi tahu kompiler di mana semua bagian fungsional berada dan memerintahkannya untuk mengintegrasikannya. Tidak ada pencarian, tidak ada ambiguitas, tidak ada kemampuan untuk memperbarui tanpa kompilasi ulang. Semua dependensi Anda secara fisik menyatu dengan gambar program Anda.
sumber