PB173 - Binární programování Linux VII. Linker skripty Jiri Slabý Fakulta informatiky Masarykova univerzita 1. 11. 2016 Jiri Slabý (Fakulta informatiky, MU) PB173/05 1. 11. 2016 1/16 Q Linker skripty Q Verzování funkcí Jiri Slabý (Fakulta informatiky, MU) PB173/05 1. 11. 2016 2/16 Linker skripty o 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 Id. • Nebo http://sourceware.org/binutils/docs/ld/ Jiri Slabý (Fakulta informatiky, MU) PB173/05 1. 11. 2016 3/16 Formát skriptu • Textové soubory • Příkazy Pozice první instrukce, kterou spustit: entry o Výstupní formát: output_format Seznam sekcí a jejich obsah: sections • Verzování: version • ... • Komentáře • /* */jako v C o Linkeru se předává při linkování • gcc -T skript.x ... • ld -T skript.x ... • Demo: výchozí skript (id --verbose) Jiri Slabý (Fakulta informatiky, MU) PB173/05 1.11.2016 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(Melf64-x86-64M) (popř. elf32- Jiri Slabý (Fakulta informatiky, MU) PB173/05 1.11.2016 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 ... 0 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 1. 11. 2016 6/16 Sekce • Blok sections { . . . } • Záznamy typu .vystupni_sekce : { soubory(.vstupni_sekce) } • soubor může být * o /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 1. 11. 2016 7/16 Úkol Skript se sekcemi O Rozšiřte skript, aby výsledek obsahoval pouze sekci .text • Ostatní zahodíte pomocí /discard/ sekce O Přeložte O Ověřte pomocí objdump -h O Spusťte Jiri Slabý (Fakulta informatiky, MU) PB173/05 1. 11. 2016 8/16 Sekce - adresování • Každému bodu ve skriptu lze přiřadit adresu o Aktuální adresa je . (tečka) • . = 0x10000; 9 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) } } _J Jiri Slabý (Fakulta informatiky, MU) PB173/05 1.11.2016 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_f un(void), V sekci .text.tl • 3.: bude volat adresu 0x401000, nastavte entry na její jméno Q 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 0x401000 • 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í objdump -h a objdump -t O Spusťte Jiri Slabý (Fakulta informatiky MU) PB173/05 1.11. 2016 10/16 Sekce 2 Verzování funkcí Jiri Slabý (Fakulta informatiky, MU) PB173/05 1.11. 2016 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 na chyby spoléhali 9 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 překladu 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 1.11. 2016 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 { ... } o 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 9 Dokumentace • pinfo ld • U. Drepper: How To Write Shared Libraries, kap. 3 Jiri Slabý (Fakulta informatiky MU) PB173/05 1.11. 2016 13/16 Verze ve skriptu Obsah sekce versi on ve skriptech • Strom verzí - dědičnost • Uzly obsahují funkce • Uzly mohou obsahovat i označení viditelnosti • globál: o local: Příklad VERSJ.1 { global: fun; local: old_fun*; }; VERS_1.2{ new_functionality_fun; } VERS_1.1; /* inheritance */ Jiri Slabý (Fakulta informatiky, MU) PB173/05 1.11.2016 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,iun@VERS_l") ; • Výchozí: asm(" .symver fun_new,fun@@VERS_2"); ' Příklad 1 void fun old() { putsfOLD"); } asm(".symver fun_old,fun@"); void fun new() { putsfNEW"); } asm(".symver fun_new,fun@@VERS_2"); Jiri Slabý (Fakulta informatiky MU) PB173/05 1.11. 2016 15/16 Úkol Verzování O Otevřete Si pbl73-bin/07/ Q 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 O 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 O Spusťte x{l,2,3} O Projděte verze v x{l,2,3} za pomoci readelf -V Q Pokračujte domácím úkolem, částí 2 Jiri Slabý (Fakulta informatiky, MU) PB173/05 1.11.2016 16/16