Bazı paylaşılan kütüphaneler niçin ve nasıl çalıştırılabilirler?


55

32-bit Linux sistemlerinde bunu çağırmak

$ /lib/libc.so.6

ve 64 bit sistemlerde bu

$ /lib/x86_64-linux-gnu/libc.so.6

Bir kabuğun içinde şöyle bir çıktı sağlar:

GNU C Library stable release version 2.10.1, by Roland McGrath et al.
Copyright (C) 2009 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE.
Compiled by GNU CC version 4.4.0 20090506 (Red Hat 4.4.0-4).
Compiled on a Linux >>2.6.18-128.4.1.el5<< system on 2009-08-19.
Available extensions:
    The C stubs add-on version 2.1.2.
    crypt add-on version 2.1 by Michael Glad and others
    GNU Libidn by Simon Josefsson
    Native POSIX Threads Library by Ulrich Drepper et al
    BIND-8.2.3-T5B
    RT using linux kernel aio
For bug reporting instructions, please see:
<http://www.gnu.org/software/libc/bugs.html>.

Bu neden ve nasıl oluyor ve aynı paylaşılan diğer kütüphanelerde aynı şeyi nasıl mümkün kılıyor?

/usr/libYürütülebilir dosyaları bulmak için baktım ve buldum /usr/lib/libvlc.so.5.5.0. Çalıştırılması segmentasyon hatasına neden oldu . : - /


Aşağıdaki cevapların hepsine ek olarak, hatırlattığım şey, x bitini paylaşılan bir kütüphaneye ayarladıysanız, r bit temiz olsa bile bir yürütülebilir dosyadan yüklemek mümkün olabilir (belki de hala mümkün). Bir zamanlar dünyadan sistem yürütülebilenler ve kütüphanelerden uzak durulması iyi bir güvenlik uygulaması olarak kabul edildi. Yaygın açık kaynaklı olması nedeniyle, bu gerçekten sadece isimsiz ftp direktörünün / bin / ls için geçerlidir. Bana göre, x bit setini bırakmak, o eski uygulamanın vesayetine benziyor.
Joshua,

Yanıtlar:


52

Bu kitaplığın bir main()işlevi veya eşdeğeri bir giriş noktası vardır ve hem çalıştırılabilir hem de paylaşılan bir nesne olarak yararlı olacak şekilde derlenmiştir.

İşte benim için işe yaramadığı halde, bunun nasıl yapılacağına dair bir öneri .

Burada , SO hakkında benzer bir soruya cevap olarak , utanmadan intihal edeceğim, ince ayar yapacağım ve biraz açıklama ekleyeceğim.

İlk olarak, örnek kütüphanemizin kaynağı test.c:

#include <stdio.h>                  

void sayHello (char *tag) {         
    printf("%s: Hello!\n", tag);    
}                                   

int main (int argc, char *argv[]) { 
    sayHello(argv[0]);              
    return 0;                       
}                   

Bunu derleyin:

gcc -fPIC -pie -o libtest.so test.c -Wl,-E

Burada, paylaşılan bir kütüphaneyi ( -fPIC) derliyoruz , ancak linker'e bunun düzenli bir çalıştırılabilir ( -pie) olduğunu ve sembol tablosunu -Wl,-Eçıkarılabilir şekilde ( ) yararlı bir şekilde bağlanabileceğini söylüyoruz.

Ve filebunun paylaşılan bir nesne olduğunu söylese de, çalıştırılabilir olarak çalışıyor:

> ./libtest.so 
./libtest.so: Hello!

Şimdi gerçekten dinamik olarak bağlanıp bağlanmadığını görmemiz gerekiyor. Örnek bir program program.c:

#include <stdio.h>

extern void sayHello (char*);

int main (int argc, char *argv[]) {
    puts("Test program.");
    sayHello(argv[0]);
    return 0;
}

Kullanmak extern, bir başlık oluşturmak zorunda kalmamızı sağlar. Şimdi şunu derleyin:

gcc program.c -L. -ltest

Yürütmeden önce libtest.sodinamik yükleyicinin yolunu eklememiz gerekir :

export LD_LIBRARY_PATH=./

Şimdi:

> ./a.out
Test program.
./a.out: Hello!

Ve ldd a.outbağlantıyı gösterecek libtest.so.

(Bkz muhtemelen glibc'nin kendisi kadar taşınabilir olmadığından Ben, bu glibc aslında derlenmiş nasıl olduğunu şüphe unutmayın man gccbakımından -fPICve -pieanahtarlar), ancak temel mekanizma ortaya koymaktadır. Gerçek detaylar için kaynak dosya dosyasına bakmanız gerekir.


1
Harika cevap, teşekkürler! :-) nmPaylaşılan kütüphanede kullanmaya çalıştım , ancak hata ayıklama sürümü değildi. Peki neden libvlcve diğerleri çöküyor?
Ho1

1
Çoğu paylaşılan kütüphanenin çalıştırılabilir olması amaçlanmadığından, GNU libcbir istisnadır.
goldilocks

İki tane daha buldum: ldve libpthread.
Ho1

@ Ho1 ld.sobaşka şekillerde özeldir. Bir dereceye kadar, dinamik olarak bağlı bir çalıştırılabilir dosyadan daha gerçek bir çalıştırılabilir dosya.
Random832

1
Seçeneklerin üzerinde, çalıştırılabilir paylaşılan kütüphaneyi oluşturmasına rağmen, ancak bir çalıştırılabilir dosya buna bağlanmayı denediğinde, hatayı işaretler. Buraya ayrıntılı örnek referans eklendi: unix.stackexchange.com/a/479334/152034
parasrish

21

Github'da rastgele glibc repodaki bir cevabı için dalış yapalım. Bu sürüm dosyada "banner" sağlar version.c.

Aynı dosyada birkaç ilginç nokta var: __libc_print_versionaynı metne yazdırmayı sağlayan işlev ve __libc_main (void)bir giriş noktası olarak belgelenen sembol . Yani bu sembol kütüphaneyi çalıştırırken çağrılır.

Peki linker / compiler, bunun tam olarak giriş noktası işlevi olduğunu nasıl biliyor?

Makefile dalın . Linker bayraklarında ilginç bayrak var:

# Give libc.so an entry point and make it directly runnable itself.
LDFLAGS-c.so += -e __libc_main

Yani bu kütüphanede giriş noktasını ayarlamak için bağlayıcı bayrağı. Bir kütüphane -e function_nameoluştururken linker için sağlayabilir , çalıştırılabilir davranış oluşturmak. Gerçekten ne işe yarıyor? El kitabına bakalım (biraz tarihli ama yine de geçerli) :

Linker komut dili, özellikle bir çıktı dosyasındaki ilk çalıştırılabilir komutu tanımlamak için bir komut içerir (giriş noktası). Argümanı bir sembol ismidir:

GİRİŞ (sembol)

Sembol atamaları gibi, ENTRY komutu da komut dosyasında bağımsız bir komut olarak veya SECTIONS komutunun içindeki bölüm tanımları arasına yerleştirilebilir - düzeniniz için en uygun olanı.

GİRİŞ, giriş noktasını seçmenin birkaç yolundan sadece biridir. Bunu aşağıdaki yollardan biriyle belirtebilirsiniz (azalan öncelik sırasına göre gösterilmiştir: listedeki daha yüksek yöntemler geçersiz kılma yöntemlerini aşağı indirin).

the `-e' entry command-line option;
the ENTRY(symbol) command in a linker control script;
the value of the symbol start, if present;
the address of the first byte of the .text section, if present;
The address 0. 

Örneğin, bu kuralları bir atama ifadesiyle bir giriş noktası oluşturmak için kullanabilirsiniz: giriş dosyalarınızda herhangi bir sembol başlangıcı tanımlanmadıysa, onu tanımlayabilir ve uygun bir değer atayarak ---

başlangıç ​​= 0x2020;

Örnek mutlak bir adres gösterir, ancak herhangi bir ifadeyi kullanabilirsiniz. Örneğin, giriş nesnesi dosyalarınız giriş noktası için başka bir sembol adı kuralı kullanıyorsa, başlamak için başlangıç ​​adresini içeren herhangi bir sembolün değerini atayabilirsiniz:

start = other_symbol;

(mevcut belgeler burada bulunabilir )

Gerçekten ldlinker, komut satırı seçeneği -e(en pratik çözüm) sağlarsanız, işlev sembolü sağlarsanız startveya montajcıya sembol adresi eklerseniz, giriş noktası işlevli bir çalıştırılabilir dosya yaratır .

Bununla birlikte, diğer linkerlerle çalışmanın kesin olarak garanti edilmediğini lütfen unutmayın (llvm'nin ekranının aynı bayrağa sahip olup olmadığını bilmiyorum). Neden bu dosya hakkında bilgi vermekten başka amaçlar için yararlı olmalıdır, bilmiyorum.


1
Python olsaydı birim testlerini yapardı.
Erik Aronesty,
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.