1 Mart 2018 Perşembe

Posix ve Shared Object (DLL) API'si

Giriş
Aşağıda shared object kütüphaneleri ile çalışırken aldığım bazı notlar var.

DLL ve Static Alanlar
İlginç olduğunu düşündüğüm bir konu hakkında not almak istedim. DLL içinde static bir değişken varsa, anladığım kadarıyla dll her yüklendiğinde bu alan yeni bir değer alıyor. Örneğin POSIX'te DLL'i ikinci kere yüklemek mümkün değil. Dolayısıyla static alan sadece bir değer alabilir. Ancak C# AppDomain kavramı ile DLL'i birden fazla yüklemeye müsade ediyor. Bu durumda static alan farklı değerler alabilir.

POSIX
Bir shared object dosyası (so) bir de fazla yazılım tarafından yükleniyorsa, ve so içinde const olmayan değişkenler varsa, her yazılım bu değişkenin ayrı bir kopyasını kullanır.
POSİX ile aşağıdaki metodunu kullanmak için şu dosya include edilir.
#include <dlfcn.h>
Sonra ldl kütüphanesi ile linklemek gerekir.
g++ LinuxGcc.cpp -ldl
dlopen metodu
dlopen metodu yazısına taşıdım.

dlsym metodu
dlsym metodu yazısına taşıdım.

dlclose metodu
dlclose metoduyla dlopen ile yüklenmiş olan shared object kapatılır. Burada anlatıldığı gibi shared object bir kere kapatıldıktan sonra, erişmeye çalışmak bir hatadır.
The function dlclose() decrements the reference count on the dynamic library handle handle. If the reference count drops to zero and no other loaded libraries use symbols in it, then the dynamic library is unloaded.
Esasında dlclose() çağırıldıktan sonra, shared object bellekten silinmek zorunda değil. Halen kullanılıyor olabilir, ancak elimizdeki handle artık işe yaramaz hale gelmiştir.Çok basit bir örnek olarak şöyle yaparız.
void *handle  = dlopen("mylib.so", RTLD_LOCAL | RTLD_LAZY);
int eret = dlclose (handle);

ldd komutu
ldd komutu yazısına taşıdım.

WIN32
Giriş
İster Implicit Loading ister Explicit Loading kullanalım, DLL metodlarının export edilmesi gerekir.

Implicit Loading
Windows'ta DLL derlerken hem DLL, hem de .lib uzantılı iki dosya üretilir. Bir başka projeye .lib uzantılı dosyayı da eklemek gerekir. .lib uzantılı dosyada DLL ile export edilen metodları otomatik yüklemek için kod bulunur.

Eğer elimizde sadece dll varsa, bir .lib dosyası üretebilmek halen mümkün. Bu yöntem aşağıdaki explicit loading yöntemine göre çok daha kolay. İşlem için "dumpbin" ve "lib" araçları kullanılıyor.

Explicit Loading
Eğer elimizde DLL için .h dosyası bulunmuyorsa bu yöntem kullanılır. LoadLibrary ve GetProcAddress ile imzası bilinen bir metodu bulmak ve çağırmak mümkün.
Örnek
Şöyle yaparız
HINSTANCE hDLL = LoadLibrary("C:\\cusp.dll");
if(hDLL == NULL)
{
    cout<< "Failed to load DLL" <<endl;
}

typedef void(*fnPtr)(int *, double);

fnPtr pfn;

pfn=(fnPtr)GetProcAddress(hDLL,"cuspDsolver");

if(pfn)
{
    pfn(rowOffset,0.9);
}

FreeLibrary(hDLL);
Örnek - farklı call convention
Windows DLL metodları otomatik olarak "__stdcall convention"'ı uygular. DLL ve çağıran kodun call convention'ları uyumlu olmalı. Elimizde şöyle bir kod olsun.
extern "C" __declspec(dllexport) int Add(int a,int b)
{
  return a+b;
}
Çağırmak için şöyle yapalım. f function pointer'ı __stdcall kullanıyor ancak DLL böyle tanımlı değil. Hata alırız.
typedef int(__stdcall *f_funci) (int , int);
int main()
{
  HINSTANCE hGetProcIDDLL = LoadLibrary("ConsoleApplication1.dll");
  if (!hGetProcIDDLL) {
    std::cout << "could not load the dynamic library" << std::endl;
    system("pause");
    return EXIT_FAILURE;
  }
  f_funci funci = 0; 
  funci = (f_funci)GetProcAddress(hGetProcIDDLL, "Add");
  if (!funci) {
    std::cout << "could not locate the function" << std::endl;
    system("pause");
    return EXIT_FAILURE;
  }
  int t = 0;
  t= (*funci)(2, 3);
  std::cout << "funci() returned "<<t<< std::endl;
  system("pause");
  return EXIT_SUCCESS;
}
LoadLibrary exe'leri çalıştırmak için kullanılamaz.
auto h = LoadLibrary("cmd.exe");
GetProcAddress() sık çağırılacak aşağıdaki macrolar kullanılabilir.
#define FUNC_DECL(retType, name, param)\
     typedef retType (_stdcall * name##_f)(param);\
     name##_f name;
macrosu ile function pointer tanımlanır. Daha sonra
#define FUNC_LOAD(name, lib)\
     name = (name##_f)GetProcAddress(lib,#name);
macrosu ile metod yüklenir.

DLL'den metod Export Etmek
Windows'ta DLL Geliştirmek yazısına taşıdım.

C#
DllImport Anotasyonu yazısına taşıdım.

Hiç yorum yok:

Yorum Gönder