İçe Aktarma Kitaplığı nasıl çalışır? Detaylar?


90

Bunun inekler için oldukça basit görünebileceğini biliyorum. Ama bunu çok net hale getirmek istiyorum.

Bir Win32 DLL kullanmak istediğimde, genellikle sadece LoadLibrary () ve GetProcAdderss () gibi API'leri çağırırım. Ancak son zamanlarda DirectX9 ile geliştiriyorum ve d3d9.lib , d3dx9.lib vb. Dosyaları eklemem gerekiyor .

LIB'nin statik bağlantı için olduğunu ve DLL'nin dinamik bağlantı için olduğunu yeterince duydum.

Dolayısıyla şu anki anlayışım, LIB'nin yöntemlerin uygulamasını içerdiği ve son EXE dosyasının bir parçası olarak bağlantı anında statik olarak bağlantılı olduğu. DLL, çalışma zamanında dinamik olarak yüklenir ve son EXE dosyasının bir parçası değildir.

Ancak bazen DLL dosyalarıyla birlikte gelen bazı LIB dosyaları vardır , bu nedenle:

  • Bu LIB dosyaları ne için?
  • Amaçlarını nasıl elde ederler?
  • Bu LIB dosyalarının iç kısımlarını incelememe izin verecek herhangi bir araç var mı?

Güncelleme 1

Wikipedia'yı kontrol ettikten sonra, bu LIB dosyalarına içe aktarma kitaplığı denildiğini hatırlıyorum . Ancak ana uygulamamla ve dinamik olarak yüklenecek DLL'lerle nasıl çalıştığını merak ediyorum.

Güncelleme 2

RBerteig'in dediği gibi, LIB dosyalarında DLL'lerden doğan bazı saplama kodları vardır. Yani arama sırası şu şekilde olmalıdır:

Ana uygulamam -> LIB'deki saplama -> gerçek hedef DLL

Peki bu LIB'lerde hangi bilgiler yer almalıdır? Aşağıdakileri düşünebilirim:

  • LIB dosyası, ilgili DLL'nin tam yolunu içermelidir; Böylece DLL çalışma zamanı tarafından yüklenebilir.
  • Her DLL dışa aktarma yönteminin giriş noktasının göreli adresi (veya dosya konumu?) Saplamada kodlanmalıdır; Böylece doğru atlamalar / yöntem çağrıları yapılabilir.

Ben haklı mıyım? Daha fazlası var mı?

BTW: Bir ithalat kitaplığını inceleyebilecek herhangi bir araç var mı? Eğer görebilirsem, daha fazla şüphem kalmayacak.


4
İçe aktarma kitaplığını inceleyebilen araçlarla ilgili olarak, sorunuzun son kısmına kimsenin değinmediğini görüyorum. Visual C ++ ile bunu yapmanın en az iki yolu vardır: lib /list xxx.libve link /dump /linkermember xxx.lib. Bu Stack Overflow sorusuna bakın .
Alan

Ayrıca, ve yardımcı programlarına dumpbin -headers xxx.libkıyasla biraz daha ayrıntılı bilgi sağlar . liblink
m_katsifarakis

Yanıtlar:


105

Bir DLL dosyasına bağlanma, dolaylı olarak derleme bağlantı zamanında veya çalışma zamanında açıkça gerçekleşebilir. Her iki durumda da DLL, işlemlerin bellek alanına yüklenir ve dışa aktarılan tüm giriş noktaları uygulama tarafından kullanılabilir.

Çalışma zamanında açıkça kullanılırsa, kullanmak LoadLibrary()ve GetProcAddress()el ile aramak gereken işlevlere işaretçileri DLL yüklenemedi ve olsun.

Program oluşturulduğunda örtük olarak bağlanırsa, program tarafından kullanılan her bir DLL dışa aktarımının saplamaları, bir içe aktarma kitaplığından programa bağlanır ve bu saplamalar, işlem başladığında EXE ve DLL yüklenirken güncellenir. (Evet, burada biraz daha basitleştirdim ...)

Bu taslakların bir yerden gelmesi gerekir ve Microsoft araç zincirinde içe aktarma kitaplığı adı verilen özel bir .LIB dosyası biçiminden gelirler . Gerekli .LIB genellikle DLL ile aynı anda oluşturulur ve DLL'den dışa aktarılan her işlev için bir saplama içerir.

Kafa karıştırıcı bir şekilde, aynı kitaplığın statik bir sürümü de .LIB dosyası olarak gönderilir. Bunları ayırmanın önemsiz bir yolu yoktur, ancak DLL'ler için içe aktarım kitaplıkları olan LIB'ler, eşleşen statik LIB'nin olacağından genellikle daha küçük (genellikle çok daha küçük) olacaktır.

GCC araç zincirini kullanırsanız, bu arada, DLL'lerinizle eşleşecek içe aktarma kitaplıklarına ihtiyacınız yoktur. Windows'a taşınan Gnu bağlayıcısının sürümü, DLL'leri doğrudan anlar ve gerekli olan çoğu saplamayı anında sentezleyebilir.

Güncelleme

Tüm somunların ve cıvataların gerçekte nerede olduğunu ve gerçekte neler olduğunu bilmeye direnemiyorsanız, MSDN'de her zaman yardımcı olacak bir şeyler vardır. Matt Pietrek'in Win32 Taşınabilir Yürütülebilir Dosya Biçimine Derinlemesine Bir Bakış adlı makalesi , EXE dosyasının biçimine ve nasıl yüklenip çalıştırılacağına dair eksiksiz bir genel bakış niteliğindedir. Hatta, ilk olarak MSDN Magazine'de göründüğünden beri .NET ve daha fazlasını kapsayacak şekilde güncellendi. 2002.

Ayrıca, bir program tarafından tam olarak hangi DLL'lerin kullanıldığını öğrenmek yararlı olabilir. Bunun için kullanılan araç Dependency Walker, aka ports.exe'dir. Bir sürümü Visual Studio'da bulunur, ancak en son sürümü yazarından http://www.dependencywalker.com/ adresinden edinilebilir . Bağlantı zamanında belirtilen tüm DLL'leri tanımlayabilir (hem erken yükleme hem de gecikmeli yükleme) ve ayrıca programı çalıştırabilir ve çalışma zamanında yüklediği ek DLL'leri izleyebilir.

Güncelleme 2

Yeniden okurken açıklığa kavuşturmak ve MSDN ile tutarlılık için sanat koşullarını örtük ve açık bir şekilde kullanmak için önceki metnin bazılarını yeniden ifade ettim .

Bu nedenle, kütüphane işlevlerinin bir program tarafından kullanılmak üzere sunulması için üç yolumuz var. O zaman aşikar olan takip sorusu şudur: "Hangi yolu nasıl seçerim?"

Statik bağlantı, programın büyük bir kısmının nasıl bağlantılı olduğudur. Tüm nesne dosyalarınız listelenir ve birleştirici tarafından EXE dosyasında toplanır. Yol boyunca bağlayıcı, modüllerinizin birbirlerinin işlevlerini çağırabilmesi için küresel sembollere referansları düzeltmek gibi küçük işleri halleder. Kitaplıklar ayrıca statik olarak bağlanabilir. Kütüphaneyi oluşturan nesne dosyaları, bir kütüphaneci tarafından bir .LIB dosyasında toplanır ve linker gerekli olan sembolleri içeren modülleri arar. Statik bağlantının bir etkisi, yalnızca program tarafından kullanılan kitaplıktaki modüllerin ona bağlanmasıdır; diğer modüller dikkate alınmaz. Örneğin, geleneksel C matematik kitaplığı birçok trigonometri işlevi içerir. Ama buna karşı bağlar ve kullanırsanızcos(), Sizin için bir kod kopyasıyla sonunda yok sin()ya tan()da bu işlevleri denir sürece. Zengin özelliklere sahip büyük kitaplıklar için, modüllerin bu seçici şekilde dahil edilmesi önemlidir. Gömülü sistemler gibi birçok platformda, kitaplıkta kullanılabilen toplam kod boyutu, cihazda bir yürütülebilir dosyayı depolamak için mevcut alana kıyasla büyük olabilir. Seçici dahil etme olmadan, bu platformlar için program oluşturma ayrıntılarını yönetmek daha zor olurdu.

Bununla birlikte, çalışan her programda aynı kütüphanenin bir kopyasına sahip olmak, normalde çok sayıda işlem çalıştıran bir sisteme yük oluşturur. Doğru türden sanal bellek sistemiyle, aynı içeriğe sahip bellek sayfalarının sistemde yalnızca bir kez bulunması gerekir, ancak birçok işlem tarafından kullanılabilir. Bu, kod içeren sayfaların, mümkün olduğu kadar çok sayıda diğer çalışan işlemdeki bazı sayfalarla aynı olma olasılığını artırmak için bir fayda sağlar. Ancak, programlar çalışma zamanı kitaplığına statik olarak bağlanırsa, her biri farklı konumlarda bellek haritasını işleyen her biri farklı bir işlev karışımına sahiptir ve kendi başına bir program olmadığı sürece pek çok paylaşılabilir kod sayfası yoktur. süreçten daha fazlasını çalıştırın. Böylece bir DLL fikri başka, büyük bir avantaj kazandı.

Bir kitaplık için DLL, herhangi bir istemci programı tarafından kullanıma hazır olan tüm işlevlerini içerir. Birçok program bu DLL dosyasını yüklerse, hepsi kod sayfalarını paylaşabilir. Herkes kazanır. (Bir DLL dosyasını yeni sürümle güncelleyene kadar, ancak bu hikayenin bir parçası değil. Hikayenin bu tarafı için Google DLL Hell.)

Dolayısıyla, yeni bir proje planlarken yapılacak ilk büyük seçim, dinamik ve statik bağlantı arasındadır. Statik bağlantı ile, yüklemek için daha az dosyanız olur ve kullandığınız bir DLL dosyasını üçüncü tarafların güncellemelerine karşı bağışıksınızdır. Bununla birlikte, programınız daha büyük ve Windows ekosisteminin pek de iyi vatandaşı değil. Dinamik bağlantı ile, yüklemeniz gereken daha fazla dosya vardır, kullandığınız bir DLL dosyasını üçüncü bir tarafın güncellemesiyle ilgili sorunlar yaşayabilirsiniz, ancak genellikle sistemdeki diğer işlemlere karşı daha dostça davranırsınız.

Bir DLL'nin en büyük avantajı, ana programı yeniden derlemeden ve hatta yeniden bağlamadan yüklenip kullanılabilmesidir. Bu, bir üçüncü taraf kitaplık sağlayıcısının (örneğin, Microsoft ve C çalışma zamanını düşünün) kitaplıklarındaki bir hatayı düzeltmesine ve dağıtmasına izin verebilir. Bir son kullanıcı güncellenmiş DLL'yi yükledikten sonra, o DLL'yi kullanan tüm programlarda bu hata düzeltmesinden hemen faydalanır. (Bir şeyleri bozmadığı sürece. Bkz. DLL Cehennemi.)

Diğer avantaj, örtük ve açık yükleme arasındaki ayrımdan gelir. Ekstra açık yükleme çabasına girerseniz, DLL, program yazılırken ve yayınlanırken bile mevcut olmayabilir. Bu, örneğin eklentileri bulabilen ve yükleyebilen uzantı mekanizmalarına izin verir.


4
Gönderimi silip buna destek vermek, çünkü işleri benden daha iyi açıklıyorsunuz;) Güzel cevap.
ereOn

2
@RBerteig: Harika cevabınız için teşekkürler. Buraya göre ( msdn.microsoft.com/en-us/library/9yd93633.aspx ) sadece küçük bir düzeltme, bir DLL'ye 2 tür dinamik bağlantı, yükleme zamanı örtük bağlama ve çalışma zamanı açık bağlama vardır . Hiçbir derleme zamanı bağlama . Şimdi, geleneksel Statik Bağlama (tam uygulamayı içeren bir * .lib dosyasına bağlanma) ile bir DLL'ye Yükleme Süresi dinamik bağlama (içe aktarma kitaplığı aracılığıyla) arasındaki farkın ne olduğunu merak ediyorum.
smwikipedia

1
Devam: Statik Bağlama ve Yükleme Süresi dinamik bağlamanın artıları ve eksileri nelerdir? Görünüşe göre bu 2 yaklaşım, bir sürecin başlangıcında gerekli tüm dosyaları adres alanına yüklüyor. Neden 2 tanesine ihtiyacımız var? Teşekkürler.
smwikipedia

1
Bir .lib dosyasının içine göz atmak ve bunun bir içe aktarma kitaplığı mı yoksa gerçek bir statik kitaplık mı olduğunu anlamak için "objdump" gibi bir araç kullanabilirsiniz. Linux'ta, bir Windows hedefine çapraz derleme yaparken, .a dosyalarında (.lib dosyalarının mingw sürümü) 'ar' veya 'nm' çalıştırmak mümkündür ve içe aktarma kitaplıklarının genel .o dosya adlarına sahip olduğunu ve kod içermediğini unutmayın. (sadece bir 'jmp' talimatı), statik kitaplıkların içinde birçok işlev ve kod bulunur.
Parlak don

1
Küçük düzeltme: Ayrıca çalışma zamanında örtük olarak da bağlantı kurabilirsiniz . Gecikmeli Yüklenen DLL'ler için Bağlayıcı Desteği bunu ayrıntılı olarak açıklar. DLL arama yolunu dinamik olarak değiştirmek veya içe aktarma çözümleme hatasını incelikle işlemek istiyorsanız (örneğin yeni işletim sistemi özelliklerini desteklemek, ancak yine de eski sürümlerde çalıştırmak için) bu yararlıdır.
IInspectable

5

Bu .LIB içe aktarma kitaplık dosyaları Linker->Input->Additional Dependencies, bağlantı anında içe aktarma kitaplığı .LIB dosyaları tarafından sağlanan ek bilgilere ihtiyaç duyan bir dizi dll oluştururken aşağıdaki proje özelliğinde kullanılır . Aşağıdaki örnekte linker hatalarını almamak için lib dosyaları aracılığıyla dll'nin A, B, C ve D'sine başvurmam gerekiyor. (Bağlayıcının bu dosyaları bulması için dağıtım yollarını eklemeniz gerekebilir, Linker->General->Additional Library Directoriesaksi takdirde sağlanan kitaplık dosyalarının hiçbirini bulamama konusunda bir yapı hatası alırsınız.)

Bağlayıcı-> Girdi-> Ek Bağımlılıklar

Çözümünüz tüm dinamik kitaplıkları oluşturuyorsa, bunun yerine Common Properties->Framework and Referencesiletişim kutusu altında gösterilen referans bayraklarına güvenerek bu açık bağımlılık belirtimini önleyebilirsiniz . Bu bayraklar, * .lib dosyalarını kullanarak sizin adınıza otomatik olarak bağlantı yapıyor gibi görünür. Çerçeve ve Referanslar

Ancak bu, yapılandırmaya veya platforma özgü olmayan bir Ortak Özellikler dediği gibidir . Uygulamamızda olduğu gibi karma bir yapı senaryosunu desteklemeniz gerekiyorsa, statik bir yapı oluşturmak için bir yapı yapılandırmasına ve dinamik kitaplıklar olarak dağıtılan bir derlemelerin alt kümesinin kısıtlı bir yapısını oluşturan özel bir yapılandırmaya sahibiz. Oluşturulacak şeyleri elde etmek için ve daha sonra işleri basitleştirmek için çeşitli durumlarda doğruya ayarlanmış Use Library Dependency Inputs ve Link Library Dependenciesbayraklarını kullandım, ancak kodumu statik yapılara tanıtırken bir ton bağlayıcı uyarısı ekledim ve yapı statik yapılar için inanılmaz derecede yavaştı. Bir sürü bu tür uyarılar getirdim ...

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

Ve Additional Dependenciesdinamik yapılar için bağlayıcıyı tatmin etmek için manuel spesifikasyonu kullanarak, statik kurucuları onları yavaşlatan ortak bir özellik kullanmayarak mutlu tuttum . Dinamik alt küme yapısını konuşlandırdığımda, yalnızca dll dosyalarını dağıtırım çünkü bu kitaplık dosyaları çalışma zamanında değil, yalnızca bağlantı anında kullanılır.


3

Üç tür kitaplık vardır: statik, paylaşılan ve dinamik olarak yüklenen kitaplıklar.

Statik kitaplıklar, bağlama aşamasında kodla bağlantılıdır, bu nedenle bunlar, paylaşılan kitaplık dosyasında aranacak yalnızca koçanlara (sembollere) sahip olan paylaşılan kitaplığın aksine, aslında çalıştırılabilir durumdadırlar. ana işlev çağrılır.

Dinamik olarak yüklenenler, yazdığınız kod tarafından ihtiyaç duyulduğunda ve ortaya çıktığında yüklenmeleri dışında, paylaşılan kitaplıklara çok benzer.


Teşekkürler zacsek. Ancak paylaşılan kitaplık hakkındaki ifadenizden emin değilim.
smwikipedia

@smwikipedia: Linux'ta var, onları kullanıyorum, bu yüzden kesinlikle varlar. Ayrıca şunu okuyun: en.wikipedia.org/wiki/Library_(computing)
Zoltán Szőcs

3
Bu ince bir fark. Paylaşılan ve dinamik kitaplıkların her ikisi de DLL dosyalarıdır. Fark, yüklendikleri zamandır. Paylaşılan kitaplıklar, EXE ile birlikte işletim sistemi tarafından yüklenir. Dinamik kitaplıklar, kod çağırma LoadLibrary()ve ilgili API'ler tarafından yüklenir .
RBerteig

[1] 'den bu DLL'nin Microsoft'un Paylaşılan Kitaplık konseptini uygulaması olduğunu okudum. [1]: en.wikipedia.org/wiki/Dynamic-link_library#Import_libraries
smwikipedia

Bunun ince bir fark olduğuna katılmıyorum, programlama görünümünden, paylaşılan kitaplığın dinamik olarak yüklenip yüklenmemesi büyük bir fark yaratıyor (eğer dinamik olarak yüklenmişse, o zaman işlevlere erişmek için standart kod eklemeniz gerekir).
Zoltán Szőcs

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.