PB173 - Binární programování Linux IV. ELF I. Jiri Slabý Fakulta informatiky Masarykova univerzita 11. 10. 2016 Jiri Slabý (Fakulta informatiky, MU) PB173/05 11. 10. 2016 1 /18 ELF Executable and Linkable Format • Hlavní souborový formát na Linuxu • Přenositelný, relokovatelný, rozšiřitelný • Podpora pro ladicí informace • Prespriste • readelf je specializovaný objdump pro ELF • libelf je specializovaná libbf d pro ELF • Literatura • System V Application Binary Interface Jiri Slabý (Fakulta informatiky MU) PB173/05 11. 10. 2016 2/18 libelf Srovnání a libbfd je nezávislá na binárním formátu • Ale neumí vše, co podporuje ELF • libelf umí jen ELF • Ale zvládá téměř všechno, co ELF podporuje • Pracuje na nižší úrovni • libebi je nadstavba libelf • Nemá moc uživatelů Jiri Slabý (Fakulta informatiky, MU) PB173/05 11.10.2016 3/18 libelf Detaily o Knihovna pro práci s ELF a Nabízí dvě API • ELF (libelf .h) • GELF - více abstraktní, generické (gelf .h) • Lze použít současně a míchat • Dokumentace • Pro BSD port: A tutorial introduction to libelf • V hlavičkových souborech o Knihovny při překladu: gcc ... -lelf • První je třeba volat elf .version (ev.current) • Nesmí vrátit ev_none Jiri Slabý (Fakulta informatiky, MU) PB173/05 11.10.2016 4/18 libelf Ošetření chyb Jak zjistit, co se stalo? o Poslední chyba:int elf_errno() • Převod na text: const char *elf _errmsg(int error) • -1 jako error je zkratka pro elf _errno() Typicky_J if (! elfjunction (...) ) errx(1, "elMunction : %s", elf_errmsg(-1)); Jiri Slabý (Fakulta informatiky, MU) PB173/05 11.10.2016 5/18 Úkol Inicializace íibelf a otevření souboru O Najděte a otevřete si BSD dokumentaci O Upravujte pbl73/04/ O Zavolejte elf _version(EV_CURRENT) O Zkontrolujte návratovou hodnotu • Nesmí být ev_none • V případě chyby chybu vypište (elf _errmsg(-l)) O Pomocí standardního open otevřete soubor z příkazové řádky • Pro čtení O Přeložte a spusťte Jiri Slabý (Fakulta informatiky, MU) PB173/05 11. 10. 2016 6/18 libelf Soubory • libelf pracuje s file deskriptory o Začátek práce • Elf *elf_begin(int fd, Elf_Cmd cmd, Elf *ref) • cmd je jedno z elf_c_read, elf_c_write, elf_c_rdwr • ref jeNULL Zjištění typu sobouru • Elf_Kind elf_kind(Elf *elf) • Návratová hodnota je jedno z elf_k_none, elf_k_ar, elf_k_elf 9 Konec práce • int elf_end(Elf *elf) Příklad (bez ověření chyb) int fd =open(file, 0_RDONLY); Elf *elf = elf_begin(fd, ELF_C_READ, NULL); elf_end(elf); close(fd); Jiri Slabý (Fakulta informatiky MU) PB173/05 11. 10. 2016 7/18 Úkol Doplňte načtení souboru zadaného jako parametr O Zavolejte elf _begin O Zavolejte elf _kind • Ověřte, že soubor je typu elf_k_elf • Pokud ne, program ukončete s chybou O Zavolejte elf _end O Ověřujte návratové hodnoty O Přeložte a spusťte Jiri Slabý (Fakulta informatiky, MU) PB173/05 11. 10. 2016 8/18 Struktura ELFu • ELF hlavička 9 Hlavičky sekcí • Popis dat pro linkování, ladění apod. o Pro překladač, debugger, ... o Hlavičky programové • Pohled na data pro spuštění • Pro interpretr • Data • Odkazovány z obou typů hlaviček Jiri Slabý (Fakulta informatiky, MU) PB173/05 11. 10. 2016 9/18 ELF hlavička • readelf -h • Magické číslo (0x7f 'E' 'L' 'F') 9 Typ, cílová architektura, stroj, systém, ... • Metadata popisující hlavičky • V libelf (gelf .h) Struktura GElf _Ehdr • GElf_Ehdr *gelf_getehdr(Elf *elf, GElf_Ehdr *dest) Jiri Slabý (Fakulta informatiky MU) PB173/05 11. 10. 2016 10/18 Úkol Výpis ELF hlavičky O Vypište si ELF hlavičku pomocí readelf O Ze svého programu vypište • Velikost ELF hlavičky • Architekturu, pro kterou ELF je • Počet programových hlaviček • Počet hlaviček sekcí O Přeložte a spusťte Jiri Slabý (Fakulta informatiky, MU) PB173/05 11. 10. 2016 11/18 Sekce • readelf -S (obsah sekce: readelf -x, popř. text readelf -p) • Vytvářené překladačem/linkerem • Ctěné překladačem/linkerem/interpretrem 9 Předdefinované sekce: • .text:kód • .data: nekonstantní data (proměnné) • .rodata: konstantní data (řetězce apod.) • .bss: data, která se inicializují při startu na 0 • . interp: interpretr • .symtab: tabulka symbolů pro ladění (strip) • .dynsym: tabulka symbolů pro dynamický linker • .gnu_debugiink: odkaz na soubor s ladicími informacemi Jiri Slabý (Fakulta informatiky MU) PB173/05 11. 10. 2016 12/18 Úkol Práce se sekcemi O Vytvořte si soubor s kódem puts ("hello") a puts ("world") O Vytvořte si vlastní sekci s daty int _attribute_((section(".data.my_section"))) x = 3; O Vytvořte si vlastní sekci s funkcí (.text.my.section) O Přeložte do .o a poté i slinkujte • mějte 2 soubory O Vypište si seznam sekcí v obou souborech (readelf -s) O Vypište si obsah sekcí (readelf -x): • .rodata (zkuste i readelf -p) • V .o: .data.my_section • V .o: . text .my_ se cti on (zkuste i ob j dump -d) Pozn.: tyto soubory nezahazujte. Jiri Slabý (Fakulta informatiky MU) PB173/05 11. 10. 2016 13/18 libelf Sekce • Držátko: struktura Elf _Scn Obsah nedefinovaný • Hlavička: struktura GElf _Shdr (gelf .h) • Získání hlavičky: GElf_Shdr *gelf_getshdr(Elf_Scn *scn, GElf_Shdr *dst) • sh_name: offset do dat Sekce . shstrtab • sh_type: SHT_NULL, SHT_PROGBITS, SHT_SYMTAB, SHT_STRTAB, .. . • sh_flags: SHF_WRITE, SHF_ALL0C, SHF_EXECINSTR, ... • sh_size: velikost o Data: struktura Elf _Data (obsah probereme příště) • Iterace přes Obsah: Elf _Data *elf_getdata(Elf_Scn *scn, Elf_Data *data) • d_buf: data d_type:ELF_T_BYTE, ELF_T_ADDR, . . . • d_size: velikost dat Jiri Slabý (Fakulta informatiky MU) PB173/05 11. 10. 2016 14/18 libelf Vyhledání sekcí • X-tá sekce: Elf_Scn *elf_getscn(Elf *elf, size_t index) • Iterace: Elf_Scn *elf_nextscn(Elf *elf, Elf.Scn *Scn 9 Index sekce s názvy sekcí . shstrtab: int elf_getshdrstrndx(Elf *elf, size_t *dst) Příklad Elf_Scn *scn = NULL; while ((sen = elf_nextscn(elf, sen))) { GEIf_Shdrshdr; Elf_Data *data = NULL; gelf_getshdr(scn, &shdr); /* shdr */ while ((data = elf_getdata(scn, data))) /* data */; } Jiri Slabý (Fakulta informatiky, MU) PB173/05 11. 10. 2016 15/18 Úkol Hexdump sekcí O Iterujte přes sekce (elf _nextscn) O Vypište hlavičku každé sekce (gelf _getshdr) • Index (elf _ndxscn) • Offset do sekce názvů • Velikost • Flagy O Vypište data každé sekce (elf .getdata) • Uvažte jen první elf _getdata (tj. neiterujte přes data) o Hexdump prvních 16 bytů obsahu O Přeložte a vyzkoušejte O Porovnejte S readelf -S Jiri Slabý (Fakulta informatiky, MU) PB173/05 11.10.2016 16/18 libelf Úpravy ELFu Otevření s elf_c_write/elf_c_rdwr 9 Nová Sekce: Elf_Scn *elf_newscn(Elf *elf) • gelf _getshdr jako předtím a naplnění Po naplnění: int gelf _update_shdr(Elf _Scn *scn, GElf _Shdr *src) Vytvoření dat: Elf _Data *elf _newdata(Elf_Scn *scn) • Zápis do souboru • loff_t elf_update(Elf *elf, Elf_Cmd cmd) • cmd: ELF C WRITE Jiri Slabý (Fakulta informatiky MU) PB173/05 11. 10. 2016 17/18 Úkol Přidání sekce do ELFu/ověření (ne)funkčnosti libelf O Otevřete ELF soubor pro čtení a zápis O Vytvořte novou sekci .comment.my • Typu sht_N0TE O Vložte do ní nějaká data • Typu elf_t_byte O Zavolejte elf .update • S parametrem elf_c_write O Přeložte a vyzkoušejte O Zobrazte Obsah sekce .comment .my pomocí readelf -x Jiri Slabý (Fakulta informatiky MU) PB173/05 11. 10. 2016 18/18