PB173 - Binární programování Linux VI. Linker skripty Jiri Slabý ITI, Fakulta informatiky 29. 10. 2013 J. Slabý (ITI, Fl) PB173/07 29. 10. 2013 1 / 15 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 XY • Dokumentace: pinfo ld (http://sourceware.org/binutils/) J. Slabý (ITI, Fl) PB173/07 29. 10. 2013 2/ 15 Formát skriptu • Textové soubory a Příkazy • První instrukce: entry • Výstupní formát: output_format • Seznam sekcí a jejich obsah: sections a Verzování: version «... • Komentáře • /**/jako v C a Linkeru se předává při linkování • gcc -T skript.x ... • ld -T skript.x ... • Demo: výchozí skript J. Slabý (ITI, Fl) PB173/07 29.10.2013 3/ 15 Základní příkazy • entry • Udává, kam se má skočit po zavedení Např. ENTRY (main) • dutput_fdrmat • Výstupní BFD formát • 0UTPUT_F0RMAT("elf64-x86-64") (popř. elf32-i386) J. Slabý (ITI, Fl) PB173/07 29. 10. 2013 4/ 15 Úkol Základní skript O Vytvořte si linker skript 0 Bude obsahovat pouze entry a output_format 0 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 0 Spusťte program • Bude fungovat jen pokud sysctl vm.mmap_min_addr je 0 J. Slabý (ITI, Fl) PB173/07 29. 10. 2013 5/ 15 Sekce • sections • Záznamy typu .vystupni_sekce : { *(.vstupni_sekce)> • /discard/ je speciální výstupní sekce SECTIONS { .text : { *(.text) } .data : { *(.data) } .bss : { *(.bss) } /DISCARD/: { *(.debug*) *(.comment*) *(.eh_frame*) } } J. Slaby (ITI, Fl) PB173/07 29. 10. 2013 6/ 15 Ú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 J. Slabý (ITI, Fl) PB173/07 29. 10. 2013 7/ 15 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 void *symbol; SECTIONS { . = 0x40000; my.start = .; .text : { *(.text) } .data 0x50000 : { *(.data) } } J. Slabý (ITI, Fl) PB173/07 29. 10. 2013 8/ 15 Úkol Skript se sekcemi a adresami O Rozšiřte zdrojový soubor o další 2 funkce, tedy: • 1: s nekonečným cyklem, dejte ji do sekce .text.t2 • 2: bude volat extern void my_fun(void), do sekce .text.ti • 3: entry funkce bude volat adresu 0x401000 O Rozšiřte skript • Všechny sekce začínaly za hranicí 0x400000 • Přidejte novou výstupní sekci .text.t na adresu 0x401000 • Obsah .text. 11 • Nový symbol my_fun 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 -h a ob j dump -t ® Spusťte J. Slabý (ITI, Fl) PB173/07 29. 10. 2013 9/ 15 Část I Verzování funkcí J. Slabý (ITI, Fl) PB173/07 29. 10. 2013 10/ 15 Verzování funkcí • Pro zachování zpětné kompatibility knihovních funkcí • Knihovny, které jsou udržované opravují chyby • Ale někteří uživatelé spoléhali na „chyby" • Jak zachovat zpětnou kompatibilitu nějaké funkce? • Chceme 2 funkce s týmž názvem, ale s jinou funkcionalitou Před opravou chyby Po opravě chyby void fun() { putsfX"); }_ void fun() { puts("Y"); }_ Řešením jsou linker skripty J. Slabý (ITI, Fl) PB173/07 29. 10. 2013 11 / 15 Verzování funkcí a Každé funkci lze ve skriptu: • Přiřadit verzi • Určit její viditelnost a versidn { ... > • Obsah versi dn lze předat i samostatně na příkazové řádce • Odpadá nutnost psaní celého linker skriptu • ld —version-script=verze.x ... O gcc -Wl,—version-script=verze.x ... • Zobrazení pomocí readelf -v a Dokumentace • pinfo ld • U. Drepper: How To Write Shared Libraries, kap. 3 J. Slabý (ITI, Fl) PB173/07 29. 10. 2013 12/ 15 Verze ve skriptu Obsah sekce version ve skriptech • Strom verzí • Uzly obsahují funkce • Uzly mohou obsahovat i označení global: a local: VERS-1.1 { global: fun; local: old.fun*; }; VERS-1.2 { new .functionality; } VERS.1.1; /* inheritance */ J. Slabý (ITI, Fl) PB173/07 29. 10. 2013 13/ 15 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"); void fun.oldO { putsf'OLD"); } asm(".symver fun.old,fun@"); void fun.new() { puts("NEW"); } asm(".symver fun_new,fun@@VERS.2"); J. Slabý (ITI, Fl) PB173/07 29. 10. 2013 14/ 15 Úkol Verzování 0 Otevřete si pbi73-bin/06/ 0 Projděte 3 verze knihovny versí 1,2,3}.c 0 Projděte uživatele x.c O Přeložte 0 Spusťte x{ 1,2,3} 0 Projděte verze v x{ 1,2,3} za pomoci readelf -v 0 Pokračujte domácím úkolem, částí 2 J. Slabý (ITI, Fl) PB173/07 29. 10. 2013 15/ 15