Modüllerin Import ve Export Tabloları
işletim |
Aslında exe ve dll
dosyaları arasında ciddi bir fark yoktur. Yani bir exe dosyası dll dosyası gibi
kullanılabilir. Dll dosyaları için söz konusu olan herşey exe dosyalar için de
geçerlidir.
Export Tablosu
Bir modüldeki bir
fonksiyonun başka bir modül tarafından çağırılabilmesi için o fonksiyonun
modülün export tablosuna yazılması gerekir. Örneğin bir dll dosyasının
içerisinde 100 tane fonksiyon bulunsun. Eğer bunlardan yalnızca biri export
tablosuna yazılmışsa başka bir modül yalnızca bu fonksiyonu çağırabilir. Tabii
bu fonksiyon kendi içerisinde kalan 99 fonksiyonu çağırıyor olabilir. Export tablosunun
genel yapısı aşağıdaki gibidir:
Export tablosu dışarıdan başka bir modül tarafından çağırılacak
fonksiyonlar için fonksiyonların modül içerisindeki başlangıç adreslerini
tutar. Örneğin func isimli bir fonksiyon bir dll içerisinde bulunsun ve bir exe
dosyasından çağırılmış olsun. İşletim sistemi programın akışının bu fonksiyona
geçirilmesi için bu fonksiyonun dll içerisinde nerede olduğunu bilmesi gerekir.
işte bu bilgiyi dll dosyasının export tablosundan elde etmektedir.
Fonksiyon isimleri export
tablosuna alfabetik olarak sıralı bir biçimde yerleştirilir. Export tablosunda
bir fonksiyonu hızlı bir biçimde bulabilmek için ikili arama(binary search)
yöntemi kullanılır. Tabloda fonksiyon
ismi ve sıra numarası bir yapı biçiminde yani ikili kayıtlar biçiminde bulunur.
Ancak fonksiyon adresleri sütunu bağımsız bir sütundur.
Export Tablosundaki Fonksiyonun Adreinin Tespit
Edilmesi
İsimden hareketle bir
fonksiyonun adresi şöyle bulunur:
1. Fonksiyon ismi ikili arama yöntemi kullanılarak fonksiyon ismi sütununda
aranır. Buradan fonksiyon adresinin sıra numarası elde edilir.
2. Bu sıra numarası fonsiyon adresi sütununa index yapılarak fonksiyon
adresi çekilir.
Arama işlemi def
dosyası(module definition file) kullanılarak doğrudan sıra numarasına göre de
yapılabilir. Bu durumda yalnızca fonksiyonun fonksiyon sütunundaki sıra
numarası bilinir. Fonksiyon adresi doğrudan bu sütundan çekilir. Yani bir
exportable fonksiyon fonksiyon ismi bilenerek ya da sıra numarası bilinerek aranabilir.
Sıra numarası bilinerek yapılan arama çok daha hızlı bir sonuca ulaştırır.
Export tablosuna yazılacak fonksiyonların isimleri ve sıra numaraları programcı
tarafından belirlenebilmektedir.
Export tablosundaki
fonksiyonların adresleri modülün ilk byte'ın sıfır olacak biçimde göreli olarak
düzenlenmiştir.
Import Tablosu
Bir program içerisinde bir
dll çağırılmışsa derleyici bunun makina kodunu CALL [adr] biçiminde yazar. Bu
çağırma biçimine sembolik makina dilinde dolaylı çağırma(indirect call) denir.
Bu makina komutu şu anlama gelmektedir: "Mikroişlemci adr ile belirtilen
adrese git, orada fonksiyonun başlangıç adresi var. O adresi al ve fonksiyona
atla".
Import tablosunun genel
biçimi aşağıdaki gibidir:
Derleyicinin ürettiği
köşeli parantez içindeki adresin değeri import tablosunun dolaylı adres
sütununun satırlarını göstermektedir. Yani runtime sırasında dolaylı adres
sütununda belirtilen adreslere programın akışı geçirilmektedir. Dolaylı adres
sütunu yükleyici tarafından modüllerin export tablolarına bakılarak
doldurulmaktadır. Bu durumda bir dll yüklenmesinde şunlar yapılmaktadır.
1. Yükleyici exe dosyayı yükler
2. Yükleyici dll dosyalarını yükler.
3. Yükleyici dll'lerin export tablolarına bakarak, fonksiyonların göreli
adreslerini elde eder. Bu değerlere dll dosyalarının yükleme adreslerini
ekleyerek gerçek adresleri bulur.
4. Yükleyici bu adresleri import tablosunun dolaylı adres sütunlarına
yazar.
Import ve export
tablolarının her ikisi de hem dll dosyaları içerisinde hem de exe dosyaları
içerisinde vardır. Bir dll dosyası içerisindeki fonksiyon başka bir dll dosyası
içerisindeki başka bir fonksiyonu çağırabilir.
dllexport ve dllimport Bildirimleri
Bir fonksiyonu başka bir
modülden çağırabilmek için o fonksiyonun export tablosuna yerleştirilmesi
gerekir. Bir fonksiyonu export tablosuna yerleştirmek için fonksiyon
prototipinin başına __dllspec(dllexport) ifadesinin yerleştirilmesi gerekir.
__declspec(dllexport) fonksiyon tanımlaması sırasında da kullanılabilir(Hem
prototipte hem de tanımlama sırasında kullanılabilir). Başka bir modülün export
tablosunda belirtilmiş bir fonksiyonun çağırılması için özel bir işleme
gereksinim yoktur. Çünkü linker çağırılan fonksyonları programın diğer
modüllerinde bulamazsa otomatik olarak dll içerisinde de arar. Ancak bir dll
içerisindeki bir fonksiyonun çağırılması söz konusuysa bu fonksiyon
prototipinin önüne __declspec(dllimport) ifadesini yerleştirmek linker'ın işini
kolaylaştırır.
Bir DLL'in Kullanıma Hazır Hale Getirilmesi
Bir dll bir kütüphanedir
ve içerisinde fonksiyonlar vardır. Bir dll'e ilişkin kaynak dosya C ya da CPP
dosyası biçiminde yazılabilir. Bir dll'in oluşturulabilmesi için en iyi yöntem
x.h ve x.c biçiminde iki dosya kullanılmasıdır. x.h dosyası dll içerisindeki
fonksiyonların prototiplerini barındırır. Bu dosya hem x.c dosyası içerisinden,
hem de dll'i kullanan bir modül içerisinden include edilir. Bu dosya
içerisindeki prototiplerin başında dll için derleme yapılıyorsa
__declspec(dllexport), başka bir modülden kullanılıyorsa __declspec(dllimport)
ifadelerinin yazılması gerekir. Bu durumda ön işlemci komutlarıyla x.h
dosyasına hiç dokunmadan fonksiyon prototipinin başındaki ifadeyi dışarıdan
değiştirebiliriz. Tipik bir dll başlık dosyası şöyle organize edilebilir:
Dll dosyası kendisi derlenirken __MYLIB__ define edilir, kullanım kodunda
kullanılmaz.
Bir dll oluşturabilmek
için project menüsünden proje türü olarak "Win32 Dynamic Linked
Library" seçilmelidir. Bir dll kendi başına çalışamaz. Oysa bir exe kendi
başına WinMain fonksiyonundan çalışır. Bir dll derlendiğinde ve link
edildiğinde geliştirme ortamı dll ve lib uzantılı iki dosya oluşturur. Lib
dosyasına "Import Library" denir ve normal bir lib formatında
değildir. Import library dosyasından dll kullanılırken faydalanılır.
/*-----dll.dsw-----*/
Bir Dll'in Uygulama İçerisinden Kullanılması
Bir dll'i oluşturduktan
sonra dll içerisindeki fonksiyonlar başka bir modülden çağırılabilir. Bir dll
sırasıyla şu dizinler içerisinde aranır:
1. Exe dosyasının bulunduğu dizin içerisinde
2. O anda bulunulan dizin içerisinde. O anda bulunulan geçerli dizin eğer
prompt içerisindeysek programın çalıştırıldğı dizindir. Ancak prompt içerisinde
değilsek yani örneğin masa üstündeki bir simgeyi çift tıklayarak çalıştırmışsak
ya da Windows Explorer aracılığıyla programı çalıştırmışsak manuel yöntemle
belirlenebilir. Aslında bir exe programını çalıştıran CreateProcess isimli bir
API fonksiyonu vardır. Bu API fonksiyonunun bir parametresi de geçerli dizini
belirtir. Aslında masa üstünde ya da Windows Explorer içerisinde programı
çalıştırmak istesek Windows'un kendisi de programı CreateProcess isimli API
fonksiyonuyla çalıştırır. Yani mouse'un sağ tuşuna basılarak geçerli dizin set
edildiğinde Windows bu bilgiyi CreateProcess ile programı çalıştırırken
kullanır.
3. Windows dizininin altındaki System dizininde
4. Windows dizininde
5. Path ile belirtilen dizinlerde(Bu path autoexec.bat'taki path değildir)
6. Registry içerisinde özel bir yöntemle belirtilerek
Dll uygun dizin içerisine
çekildikten sonra dll'i kullanacak programın proje dosyası oluşturulur. Import
Library dosyasını projeye dahil etmek gerekir. Bu sayede linker çağırılan bir
fonksiyonun hangi dll içerisinde olduğunu tespit eder. Import Library'nin
projeye dahil edilmesi "Add files to project" seçeneğiyle ya da
"Project=>Settings=>Link=>Object/library" modules içine
yazarak yapılabilir. Sonuş olarak şu işlemlerin yapılması gerekir:
1. Dll’in uygun bir dizine kopyalanması
2. Başlık dosyasının kullanılacak dosyadan include edilmesi
3. Import Library'nin projeye eklenmesi
Import
Library linker için, başlık dosyası derleyici için dll dosyası ise yükleyici
için bulundurulmaktadır. Import Library ile aynı görevde olan bir def dosyası
da vardır. Dll dosyasından Import Lıbrary ya da def dosyası elde edilemez.
DLL'lerin Sonradan Yüklenmesi
Normal bir dll import
library kullanılarak link edilmişse exe program yüklenirken işletim sistemi
tarafından otomatik olarak belleğe yüklenir. Oysa bir dll dosyası programım
çalışmasının herhangi bir aşamasında LoadLibrary API fonksiyonuyla
yüklenebilir. Bir dll böyle kullanılacaksa projeye import library'i eklenmez.
Fonksiyonun parametresi yüklenecek dll dosyasının ismidir. Fonksiyonun geri
dönüş değeri dll dosyasının yüklendiği bellek adresidir. Başarısızlık durumunda
NULL değeriyle geri döner. Örneğin dll dosyası WM_CREATE mesajı içerisinde
dinamik olarak yüklenebilir. Dosya ismi bir path ifadesi içerebilir. Eğer
içeriyorsa dosya yalnızca o dizinde aranır, içermiyorsa daha önce belirtilen
sırada aranır. LoadLibrary fonksiyonuyla yüklenen dll istenildiği zaman
FreeLibrary fonksiyonuyla hafızadan çıkarılabilir.
Fonksiyon LoadLibrary fonksiyonundan elde edilen geri dönüş değerini
parametre olarak alır ve dll dosyasını hafızadan çıkarır. Örneğin bu API
fonksiyonu WM_DESTROY mesajında kullanılabilir.
Bir dll LoadLibrary ile
daha sonra yüklenmişse dll içerisindeki bir fonksiyonun çağırılması için o
fonksiyonun adresinin runtime sırasında GetProcAddress API fonksiyonuyla elde
edilmesi gerekir. Bu biçimde bir fonksiyonun çağırılabilmesi için fonksiyonun
isminin ve parametrik yapısının bilinmesi gerekir. Ancak fonksiyon isimleri dll
içerisine bazı nedenlerden dolayı değiştirilerek yazılmaktadır. Bu durumda bir
fonksiyonun gerçek isminin elde edilmesi gerekir. Bu isim aslında programcı
tarafından belirlenebilir, ya da Dumpbin programıyla:
Dumpbin /exports
seçeneğiyle elde edilebilir. Fonksiyon ismi yerine export tablosundaki sıra
numarası da kullanılabilir. Sıra numaraları dumpbin programıyla ya da programcı
tarafından hazırlanan def dosyası ile elde edilebilir. Dumpbin.exe programı
sisteme ilişkin dosya formatlarını anliz etmeye yarayan Visual C++ paketiyle verilen
özel bir programdır.
Fonksiyonun birinci parametresi LoadLibrary fonksiyonundan elde edilen
handle değeridir. İkinci parametre fonksiyonun dll içerisindeki ismidir. İkinci
parametre ile verilen adresin yüksek anlamlı iki byte'ı 0 ise fonksiyon düşük
anlamlı iki byte'ında export tablosundaki sıra numarasının bulunduğunu düşünür.
Böyle bir durumda bu parametre:
0 yorum: