Linux'ta kitaplıkları yüklemek için hangi sistem çağrısı kullanılır?


23

In straceçıkışları, yürütülebilir dediğimiz kütüphanelere yolları için çağrılarda bulunmaktadır open(). Bu, sistem çağrısı dinamik olarak bağlanmış olan çalıştırılabilirler tarafından kullanılıyor mu? Ne hakkında dlopen()? open()Tahmin ettiğim bir çağrı değil, programların yürütülmesinde rol oynayacağını tahmin ediyorum.

Yanıtlar:


33

dlopensistem çağrısı değil, libdl kütüphanesindeki bir kütüphane işlevidir . Sadece sistem çağrıları geliyor strace.

Linux ve diğer pek çok platformda (özellikle ELF formatını çalıştırılabilirler için kullananlar), dlopenhedef kitaplığı açarak open()ve onu belleğe eşleyerek uygulanmaktadır mmap(). mmap()Burada gerçekten kritik olan kısım, kütüphaneyi işlemin adres alanına dahil eden şeydir, böylece CPU kodunu çalıştırabilir. Ama open()yapmadan önce dosyaya ihtiyacın var mmap()!


2
"mmap () gerçekten kritik bir parçadır": Ve sonra dinamik bağlayıcının yer değiştirme, başlatma vb. işlemi yapması gerekir (ancak bu, sistem çağrısı düzeyinde görülmez).
ysdx

1
Kütüphanelerin yüklenmesi bir kütüphane fonksiyonu tarafından yapıldığından, çalıştırılabilirin kendisinin ld-linuxeklendiğini ve çekirdeğin execvesistem çağrısının bir parçası olarak eşleştirildiğini eklemenin uygun olacağını düşünüyorum .
kasperd,

Bu cevaba göre mmap. Ayrıca, her bir kütüphaneyi "açtıktan" sonra, bazı (832) bayt mmap çağrısından önce okunur, kütüphanenin geçerli olup olmadığını kontrol ediyorum.
Johan

@ kasperd Peki Linux çekirdeği dinamik yükleyiciden haberdar mı? Uygulama çalıştırıldığında onu çağırıyor mu? Yoksa uygulamanın kendisi bunu mu yapıyor? İkincisi ise, başka bir yürütülebilir dosyanın uygulamanın belleğine erişimi nedir?
Melab

@Melab Evet, çekirdek dinamik linkerin farkındadır. Çekirdek, dinamik bağlayıcının yolunu yürütülebilir başlığından okuyacaktır. Ve çekirdek her ikisini de hafızaya eşler. Çekirdek aktarım denetiminin ilk başta kontrol ettiği giriş noktasının bağlayıcı veya çalıştırılabilir içinde olup olmadığını bilmiyorum. Uygulamıyor olsaydım, büyük olasılıkla çekirdek aktarım denetimini, bağlayıcıdaki bir giriş noktasına, çalıştırılabilir giriş noktasına işaret eden yığında bir geri dönüş adresine sahip olacaktım.
kasperd

5

dlopen'in, düşündüğünüz gibi paylaşılan kütüphanelerle hiçbir ilgisi yok. Paylaşılan bir nesneyi yüklemenin iki yöntemi vardır:

  1. Derleme zamanı bağlayıcısına (genellikle derleyici aracılığıyla adlandırılmış olmasına rağmen) belirli bir paylaşılan kütüphanedeki işlevleri kullanmak istediğinizi söylersiniz. Bu yaklaşımla, derleme zamanı bağlayıcısı çalıştırıldığında kitaplığın adının ne olacağını bilmeniz gerekir, ancak kitaplığın işlevlerini programınıza statik olarak bağlıymış gibi çağırabilirsiniz. Uygulama çalıştırıldığında, dinamik, çalışma zamanı bağlayıcısı (ld.so), mainişlev çağrılmadan hemen önce çağrılacak ve uygulamanın kitaplık işlevlerini bulması için uygulamanın işlem alanını ayarlayacaktır. Bu, open()kayganlaştırıcıyı ve ardından da mmap()onu yerleştirmeyi ve ardından bazı arama tabloları oluşturmayı içerir.
  2. Sen ile bağlantıya istediğiniz derleme zamanı linker söyleyecektir libdlçağırabilir Kendisinden sonra (ilk yöntemini kullanarak), dlopen()vedlsym()fonksiyonlar. Dlopen ile, belirli bir işleve bir işlev işaretçisi almak için dlsym ile kullanabileceğiniz kütüphaneye bir tutamaç elde edersiniz. Bu yöntem programcı için ilk yöntemden çok daha karmaşıktır (çünkü kurulumu sizin için otomatik olarak yapması yerine kurulumu el ile yapmanız gerekir) ve ayrıca daha kırılgandır (derleme alamadığınız için -time, ilk yöntemde aldığınız gibi doğru argüman tiplerine sahip işlevleri çağırdığınızı kontrol eder), ancak avantaj, çalışma zamanında hangi paylaşılan nesneyi yükleyeceğine karar verebilmenizdir (ya da hatta yüklenip yüklenmeyeceği). Bu eklenti tipi işlevselliği için bir arayüz. Son olarak, dlopen arayüzü de diğerlerinden daha az taşınabilir çünkü mekanikler dinamik bağlayıcının tam olarak uygulanmasına bağlıdır (dolayısıyla libtoollibltdlBu farklılıkları ortadan kaldırmaya çalışır).

ilginç; Bu nedenle, dinamik olarak yüklenmiş kitaplığa dinamik olarak bağlı kitaplıklar denir, çünkü ikili dosyaları belleğe yüklemek zor kısım değildir, kullanılan adresleri mantıklı kılar. Dinamik bir kütüphane yüklemek istediğimde, gerçekte kütüphaneyi adres alanıma bağlamak (veya bağlantısını kaldırmak) istiyorum.
Dmitry

4

Bugün, çoğu işletim sistemi 1987 yılının sonlarında SunOS-4.0 tarafından tanıtılan paylaşılan kütüphaneler için yöntemi kullanmaktadır. Bu yöntem, mmap () ile bellek eşleştirmeye dayanır.

1990’ların başlarında Sun’ın eski eski kodları (o zamanki Solaris zaten ELF’ye dayalı) FreeBSD’ye bağışladığı ve bu kodun daha sonra birçok sisteme (Linux dahil) verildiği gerçeği göz önüne alındığında neden platformlar arasında büyük bir fark olmadığını anlayabilirsiniz.


3

ltrace -SMinimal bir örneğin analizi mmapglibc 2.23’de kullanılanları göstermektedir.

Glibc 2.23, Ubuntu 16.04’de, ile birlikte latrace -Skullanılan minimal bir program üzerinde çalışıyor dlopen:

ltrace -S ./dlopen.out

gösterileri:

dlopen("libcirosantilli_ab.so", 1 <unfinished ...>
SYS_open("./x86_64/libcirosantilli_ab.so", 524288, 06267650550)      = -2
SYS_open("./libcirosantilli_ab.so", 524288, 06267650550)             = 3
SYS_read(3, "\177ELF\002\001\001", 832)                              = 832
SYS_brk(0)                                                           = 0x244c000
SYS_brk(0x246d000)                                                   = 0x246d000
SYS_fstat(3, 0x7fff42f9ce30)                                         = 0
SYS_getcwd("/home/ciro/bak/git/cpp-cheat"..., 128)                   = 54
SYS_mmap(0, 0x201028, 5, 2050)                                       = 0x7f1c323fe000
SYS_mprotect(0x7f1c323ff000, 2093056, 0)                             = 0
SYS_mmap(0x7f1c325fe000, 8192, 3, 2066)                              = 0x7f1c325fe000
SYS_close(3)                                                         = 0
SYS_mprotect(0x7f1c325fe000, 4096, 1)                                = 0

bu yüzden hemen + dlopençağırdığını görüyoruz .openmmap

Müthiş ltracearaç hem kütüphane aramalarını hem de sistem aramalarını izler ve bu durumda neler olup bittiğini incelemek için mükemmeldir.

Daha yakın bir analiz, opendosya tanımlayıcısını döndürdüğünü gösterir 3(sonra stdin, out ve err sonrası bir sonraki boş).

readdaha sonra bu dosya tanımlayıcısını kullanır, ancak TODO neden mmapargümanlarının dördü ile sınırlıdır ve oradaki 5. argüman olduğu için hangi fd'nin kullanıldığını göremiyoruz . straceBeklendiği gibi olduğunu onaylar 3ve evrenin düzeni geri yüklenir.

Cesur ruhlar aynı zamanda glibc koduna da girebilir, ancak mmaphızlı bir grep sonrası bulamadım ve tembelim.

GitHub'da build boilerplate ile bu minimal örnekte test edilmiştir .


2

stracesistem çağrıları hakkında raporlar (yani doğrudan çekirdek tarafından uygulanan işlevler). Dinamik kütüphaneler bir çekirdek işlevi değildir; dlopençekirdeğin değil, C kütüphanesinin bir parçasıdır. Uygulanması dlopenirade çağrısı openkullanıldığında okunabilir böylece (bir sistem çağrısıdır) kütüphane dosyasını açmak için.


5
Kütüphane aramaları kullanılarak görülebilir ltrace.
kasperd,

@kasperd ltrace -So da gösteriler sistem çağrıları olarak bu analiz etmek mükemmeldir: unix.stackexchange.com/a/462710/32558
Ciro Santilli新疆改造中心法轮功六四事件
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.