PB173 - Binární programování Linux XII. Knihovny Jiri Slabý Fakulta informatiky Masarykova univerzita 6. 12. 2016 Jiri Slabý (Fakulta informatiky, MU) PB173/05 6. 12. 2016 1/15 Obsah cvičení Q Knihovny Q Vytváření dynamických knihoven Jiri Slabý (Fakulta informatiky, MU) PB173/05 6. 12. 2016 2/15 Sekce 1 Knihovny Jiri Slabý (Fakulta informatiky, MU) PB173/05 6. 12. 2016 3/15 Knihovny • Statické knihovny o ar archiv • Jejích obsah je v každé binárce, kam se linkovaly • Zvyšují velikost na disku Binárka ale nemá žádné externí závislosti • Výroba: gcc -ca ar rcs lib. a *.o • Dynamické knihovny • ELF, který se linkuje za chodu • Podpora pluginů • Ale zpomaluje spuštění 9 Dynamický linker ld.so (man ld.so) • Výroba: gcc -shared Jiri Slabý (Fakulta informatiky, MU) PB173/05 6. 12. 2016 4/15 Úkol Výroba statické knihovny O Proveďte make V pbl73-bin/12 O Z lib.o vyrobte statickou knihovnu libX. 9 ar rcs ... O Knihovnu prilinkujte k main.o • gcc -L. -IX O Spusťte výsledek Jiri Slabý (Fakulta informatiky, MU) PB173/05 6. 12. 2016 5/15 Použití dynamické knihovny O Přilinkování pomocí linkeru • gcc -lknihovna • id.so před spuštěním načte a slinkuje potřebné symboly • Demo: ídd k ověření O Načtení explicitně až za běhu • Viz dále O Proměnnými prostředí • ld_preload nahraje knihovnu před spuštěním Jiri Slabý (Fakulta informatiky, MU) PB173/05 6. 12. 2016 6/15 Načtení dynamické knihovny • Knihovna dl (linkujte s -ídi) (dif cn.h) 9 OtGVÍení: void *dlopen(const char *filename, int flags) • filename: jméno knihovny, nebo cesta • flags: rtld_lazy nebo rtld_now spolu s dalšími • Návratová hodnota: držátko knihovny nebo null při chybě 9 Zavření: int dlclose(void *handle) Symbol Z knihovny: void *dlsym(void *handle, const char *Symbol) handle: držátko Z dlopen • symbol: název symbolu (funkce, proměnné, ...) • Návratová hodnota: ukazatel na začátek symbolu • Řetězec Chyby: char *dlerror(void) Jiri Slabý (Fakulta informatiky MU) PB173/05 6. 12. 2016 7/15 Načtení dynamické knihovny - příklad #include #include #include int main(void) { void *h = dlopen("libm.so.6", RTLDLAZY); if (!h) errx (1, "dlopen: %s", dlerror ()); double (*kos)(double) = dlsym(h, "cos"); if (!kos) errx(1, "dlsym(cos): %s", dlerror ()); printf ("%f\n", kos(O)); dlclose(h); return 0; } Jiri Slabý (Fakulta informatiky, MU) PB173/05 6. 12. 2016 8/15 Úkol Načtení dynamické knihovny O Načtěte dynamickou knihovnu • Zadaná na příkazové řádce Q Načtěte symbol • Zadaný také na příkazové řádce O Zavolejte symbol • S řetězcem jako parametr O Vyzkoušejte • Např. ./main libc.so.6 puts • A printf • A fclose? Jiri Slabý (Fakulta informatiky, MU) PB173/05 6. 12. 2016 9/15 Sekce 2 Vytváření dynamických knihoven Jiri Slabý (Fakulta informatiky MU) PB173/05 6. 12. 2016 10/15 Pojmenování dynamických knihoven • Jméno knihovny („soname") • libXXX.so.maj_verze • Např. libelf .so.O • Reálné jméno (soubor) • libXXX.so.maj _verze.min_verze.release Např. libelf . so . 0.8.13 9 Jméno pro linker • libXXX.so • Např. libelf .so Jiri Slabý (Fakulta informatiky, MU) PB173/05 6.12.2016 11 /15 Vytváření dynamických knihoven Všechen kód musí být nezávislý na pozici, kde bude nahrán 9 nutno překládat i linkovat s -f pic, popř. lépe s -f pic • Linker by měl znát soname • nutno linkovat S -Wl,- soname, j meno 9 Linkovat sdílené 9 nutno linkovat S -shared Příklad vytvoření knihovny gcc -fpic -g -c -Wall a.c gcc -fpic -g -c -Wall b.c gcc -fpic -shared -Wl,-soname,libmylib.so.1 -o libmylib.so.1.2.3 a.o b.o -Ic Jiri Slabý (Fakulta informatiky MU) PB173/05 6. 12. 2016 12/15 Úkol Vytvoření dynamické knihovny O Z lib.o vytvořte dynamickou knihovnu • gcc -shared -Wl,-soname,... Q Knihovnu prilinkujte kmain.o namísto statické • gcc -L. -IX O Ověte pomocí ídd O Spusťte výsledek Jiri Slabý (Fakulta informatiky MU) PB173/05 6. 12. 2016 13/15 Přesměrování funkcí • Knihovny mohou podvrhnout své implementace funkcí Např. mailoc pro sledování paměti • Podmínka: funkce musí být z dynamické knihovny • ld.preload nahraje knihovnu i se zvláštní implementací • disym lze použít k nalezení originálu • void *dlsym(void *handle, const char *symbol) • Speciální handle - RTLD_NEXT ' Příklad 1 void *malloc(size t size) { static void *(*c_malloc)(size_t); if (!c mailoc) c_malloc = dlsym (RTLDN EXT, "mailoc"); write (1, "Somebody called malloc!\n", 24); return c malloc(size); } Jiri Slabý (Fakulta informatiky, MU) PB173/05 6. 12. 2016 14/15 Úkol Přesměrování mailoc (domácí) O Vytvořte novou knihovnu O Přesměrujte volání mailoc a f ree do své knihovny • Volejte originály • Originály zjistěte v konstruktoru O Spočítejte, kolikrát se oba zavolají O Spočítejte, kolik MiB se alokovalo a uvolnilo O Na konci vypište statistiku • A tu vepište do commitlogu • Můžete použít např. atexit nebo destructor O Spusťte na libovolném programu, který používá alokace O Zkuste z mailoc občas vrátit null • Co se stane? Jiri Slabý (Fakulta informatiky MU) PB173/05 6.12.2016 15/15