PB173 - Binární programování Linux VII. Linker skripty Jiri Slabý Fakulta informatiky Masarykova univerzita 12. 11. 2015 Jiri Slabý (Fakulta informatiky, MU) PB173/05 12. 11. 2015 1 /16 Q Linker skripty Q Verzování funkcí Jiri Slabý (Fakulta informatiky, MU) PB173/05 12.11.2015 2/ 16 Linker skripty • ldscripts • Linker se jimi řídí při linkování objektů • Tj. vždy se nějaký použije • Udávají • Kde která sekce leží • Např. pro embedded, kód musí být na adrese X a data na adrese Y • Výstupní formát • Kam skočit po načtení • A další • Může přidávat i symboly • Např. „toto" je adresa začátku sekce Z • Dokumentace pinfo ld • (http://sourceware.org/binutils/) Jiri Slabý (Fakulta informatiky, MU) PB173/05 12. 11. 2015 3/ 16 Formát skriptu • Textové soubory • Příkazy • Pozice první instrukce, kterou spustit: entry • Výstupní formát: output.format • Seznam sekcí a jejich obsah: sections • Verzování: version • ... • Komentáře • /**/jako v C • Linkeru se předává při linkování • gcc -T skript.x ... • ld -T skript.x ... • Demo: výchozí skript Jiri Slabý (Fakulta informatiky, MU) PB173/05 12. 11. 2015 4/16 Základní příkazy • entry • Udává, kam se má skočit po zavedení • Např. ENTRY (main) • output.format • Výstupní BFD formát • 0UTPUT_F0RMAT(nelf64-x86-64n) (popř. elf32-i386) Jiri Slabý (Fakulta informatiky, MU) PB173/05 12. 11. 2015 5/16 Úkol Základní skript O Vytvořte si linker skript O Bude obsahovat pouze entry a output.format O Vytvořte zdrojový soubor s jednou funkcí • Bude obsahovat nekonečný cyklus • Jméno bude stejné jako v entry O Přeložte a slinkujte skriptem • gcc -Wl,--build-id=none -nostdlib -t skript.x ... O Podívejte se na rozložení sekcí • Měly by začínat okolo adresy 0 O Spusťte program • Bude fungovat jen pokud sysctl vm.mmap_min_addr je 0 • Pokud není, změňte Jiri Slabý (Fakulta informatiky, MU) PB173/05 12. 11. 2015 6/16 Sekce • Blok sections { . . . } • Záznamy typu .vystupni_sekce : { soubor(.vstupni_sekce)} • soubor může být * • /discard/ je speciální výstupní sekce • Obsah se zahodí Příklad SECTIONS { .text : { *(.text) } .data : { *(.data) soubor.o(.data.special) } .bss : { *(.bss) } } /DISCARD/: { *(.debug*) *(.comment*) *(.eh_frame*)} Jiri Slabý (Fakulta informatiky, MU) PB173/05 12. 11. 2015 7/16 Úkol Skript se sekcemi O Rozšiřte skript, aby výsledek obsahoval pouze sekci .text O Přeložte O Ověřte pomocí objdump -h O Spusťte Jiri Slabý (Fakulta informatiky, MU) PB173/05 12. 11. 2015 8/16 Sekce - adresování • Každému bodu ve skriptu lze přiřadit adresu • Aktuální adresa je . (tečka) • . = 0x10000; • Každou sekci lze: • Vložit na nějakou adresu: .sekce Oxioooo :{...} • Zarovnat: .sekce ALIGN(...): { ... } • Pro každou adresu lze vložit symbol • symbol = .; • V kódu pak extern unsigned long symbol; Příklad SECTIONS { . = 0x40000; my_start = .; .text : { *(.text) } .data 0x50000 : { *(.data) } Jiri Slabý (Fakulta informatiky, MU) PB173/05 12. 11. 2015 9/16 Úkol Skript se sekcemi a adresami O Rozšiřte zdrojový soubor o další 2 funkce, tedy: • 1 (původní): s nekonečným cyklem, dejte ji do sekce .text .t2 • 2: bude volat extern void my_fun(void), do sekce .text.tl • 3: bude volat adresu 0x401000, nastavte entry na její jméno O Rozšiřte skript • Aby všechny sekce začínaly za hranicí 0x400000 • . = ... na začátku bloku sections • Přidejte novou výstupní sekci .text.t na adresu Ox40iooo • Obsah .text.tl • Nový symbol my_f un na aktuální adrese • Obsah .text.t2 (tedy my_fun ukazuje na začátek .text.t2) O Přeložte O Ověřte pomocí ob j dump -haobjdump -t Q Spusťte Jiri Slabý (Fakulta informatiky, MU) PB173/05 12. 11. 2015 10/16 Sekce 2 Verzování funkcí Jiri Slabý (Fakulta informatiky, MU) PB173/05 12. 11. 2015 11/16 Verzování funkcí • Pro zachování zpětné kompatibility knihovních funkcí • V knihovnách se v průběhu času opravují chyby • Ale někteří „uživatelé" knihovny spoléhali na chyby • Jak zachovat zpětnou kompatibilitu nějaké funkce? • Chceme 2 funkce s týmž názvem, ale s jinou funkcionalitou • Podle verze použité při linkování Před opravou chyby Po opravě chyby void fun() { putsfOLD"); } void fun() { putsfNEW"); } libXvl libX v2 Řešením jsou linker skripty s verzováním Jiri Slabý (Fakulta informatiky, MU) PB173/05 12. 11. 2015 12/16 Verzování funkcí • Každé funkci lze ve skriptu: • Přiřadit verzi (f un v1, f un v2 nebo výchozí) • Určit její viditelnost • Blok version { . . . } • Obsah version lze předat i samostatně na příkazové řádce • Odpadá nutnost psaní celého linker skriptu • ld --version-script=verze.x ... • gcc -Wl,--version-script=verze.x ... • Zobrazení pomocí readelf -v • Dokumentace pinfo ld • U. Drepper: How To Write Shared Libraries, kap. 3 Jiri Slabý (Fakulta informatiky, MU) PB173/05 12. 11. 2015 13/16 Verze ve skriptu Obsah sekce version ve skriptech • Strom verzí - dědičnost • Uzly obsahují funkce • Uzly mohou obsahovat i označení viditelnosti • globál: • local: Příklad VERSJ.1 { globál: fun; local: old_fun*; }; VERS_1.2{ new_functionality_fun; } VERS_1.1; /* inheritance */ Jiri Slabý (Fakulta informatiky, MU) PB173/05 12. 11. 2015 14/16 Verze ve zdrojovém souboru • Ve zdrojových souborech je třeba přiřadit verze • Globální asm direktiva • Neverzovaná: asm(" .symver fun_oldl,fun@"); • Pro určitou verzi: asm(" .symver fun_old2,fun@VERS_l"); • Výchozí: asm(".symver fun_new,fun@@VERS_2"); Příklad void fun_old() { puts("OLD"); } asm(".symver fun_old,fun@"); void fun_new() { puts("NEW"); } asm(".symver fun_new,fun@@VERS_2"); Jiri Slabý (Fakulta informatiky, MU) PB173/05 12. 11. 2015 15/16 Úkol Verzování O Otevřete Si pbl73-bin/07/ O Projděte 3 verze knihovny versíl,2,3}. c • Definuje funkci bubák • bubák v nich má 3 různé sémantiky podle verze Q Projděte soubor, který ji používá x. c • Volá funkci bubák • (Pro 3. verzi předává i parametr) O Přeložte • Standardně pomocí make 0 Spusťte x{ 1,2,3} O Projděte verze v x{i, 2,3} za pomoci readelf -v O Pokračujte domácím úkolem, částí 2 Jiri Slabý (Fakulta informatiky, MU) PB173/05 12. 11. 2015 16/16