PB173 - Binární programování Linux IV. ELF Jiri Slabý Fakulta informatiky Masarykova univerzita 7. 10. 2014 Jiri Slabý (Fakulta informatiky, MU) PB173/03 7.10.2014 1/15 ELF (opakování) Executable and Linkable Format • Hlavní souborový formát na Linuxu a Přenositelný, relokovatelný, rozšiřitelný • Struktura • ELF hlavička • Hlavičky programové • Při spouštění • Hlavičky sekcí • Při linkování, ladění apod. • Sekce • Odkazovány z obou typů hlaviček • Podpora pro ladicí informace • Příště « System V Application Binary Interface Jiri Slabý (Fakulta informatiky, MU) PB173/03 7.10.2014 2/ 15 libelf • libbfdje 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 a libebi je nadstavba libelf • Nemá moc uživatelů Jiri Slabý (Fakulta informatiky, MU) PB173/03 7.10.2014 3/ 15 libelf • Knihovna pro práci s ELF a Implementuje dvě API • ELF (libelf.h) • GELF - více abstraktní, generické (gelf .h) • Lze použít současně a míchat a Dokumentace • Pro BSD port: A tutoriál introduction to libelf • V hlavičkových souborech • Knihovny při překladu: gcc ... -lelf • První je třeba volat elf_version(EV_CURRENT) Úkol: najděte a otevřete si dokumentaci uvedenou nahoře Jiri Slabý (Fakulta informatiky, MU) PB173/03 7.10.2014 4/ 15 libelf: chyby Jak zjistit, co se stalo? • Poslední chyba: int elf_errno() • Převod na text: const char *elf _errmsg(int error) • -1 jako error je zkratka pro elf _errno() Typicky: if (! exjunction (...) ) errx(1, "elMunction : %s", elf_errmsg(-1)); Jiri Slabý (Fakulta informatiky, MU) PB173/03 7.10.2014 5/ 15 Úkol Inicializujte libelf a otevřete soubor O Zavolejte elf_version(EV_CURRENT) O Zkontrolujte návratovou hodnotu • Nesmí být ev_nqne • V případě chyby ji vypište (elf _errmsg(-D) O Pomocí standardního open otevřete soubor z příkazové řádky O Přeložte a spusťte Jiri Slabý (Fakulta informatiky, MU) PB173/03 7.10.2014 6/ 15 libelf: soubory • libelf pracuje s file deskriptory • 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 je NULL • Ověření typu sobouru • Elf_Kind elf_kind(Elf *elf) • Návratová hodnota je jedno z elf_k_nqne, elf_k_ar, elf_k_elf • Konec práce 9 int elf_end(Elf *elf) 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/03 7.10.2014 7/ 15 Ú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 Q Přeložte a spusťte Jiri Slabý (Fakulta informatiky, MU) PB173/03 7.10.2014 8/ 15 libelf: sekce • Držátko: Elf _Scn • Hlavička: GElf _Shdr (gelf .h) • sh_name: offset do dat sekce . shstrtab • sh_type:SHT_NULL, SHT_PRQGBITS, SHT_SYMTAB, SHT_STRTAB, . . . • sh_flags:SHF_WRITE, SHF_ALLQC, SHF_EXECINSTR, . . . • sh_size: velikost • Data: Elf _Data 9 d_buf: data • d_type:ELF_T_BYTE, ELF_T_ADDR, . . . a d_size: velikost dat Jiri Slabý (Fakulta informatiky, MU) PB173/03 7.10.2014 9/ 15 libelf: funkce pro sekce • Index sekce . shstrtab (sekce s názvy sekcí): int elf_getshdrstrndx(Elf *elf, size_t *dst) a X-tá sekce: Elf_Scn *elf_getscn(Elf *elf, size_t index) • Iterace: Elf_Scn *elf_nextscn(Elf *elf, Elf_Scn *scn) • Získání hlavičky: GElf_Shdr *gelf_getshdr(Elf_Scn *scn, GElf_Shdr *dst) ■ Iterace přes obsah: Elf_Data *elf_getdata(Elf_Scn *scn, Elf_Data *data) Elf_Scn *scn = NULL; while ((sen = elf_nextscn(elf, sen))) { GEIf_Shdr shdr; Elf_Data *data= NULL; gelf_getshdr(scn, &shdr); /* shdr */ while ((data = elf_getdata(scn, data))) /* data */; } Jiri Slabý (Fakulta informatiky, MU) PB173/03 7.10.2014 10/15 Ú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 Q Vypište data každé sekce (elf _getdata) • Uvažte jen první elf _getdata (neiterujte přes data) • Hexdump prvních 16 bytů obsahu O Přeložte a vyzkoušejte O Porovnejte S readelf -S Jiri Slabý (Fakulta informatiky, MU) PB173/03 7.10.2014 11/15 libelf: programové hlavičky • Počet: int elf_getphdrnum(Elf *elf, size_t *dst) • x-tá hlavička: GElf_Phdr *gelf_getphdr(Elf *elf, int index, GElf_Phdr *dst) • Hlavička: GElf _Phdr 0 p_type:PT_NULL, PT_LQAD, PT_INTERP, . . . • p_off set: offset v souboru • p_fiiesz: velikost v souboru • p_memsz: velikost v paměti (po načtení) Jiri Slabý (Fakulta informatiky, MU) PB173/03 7.10.2014 12/15 Úkol Výpis programových hlaviček O Otevřete ELF soubor pro čtení Q Vypište programové hlavičky 0 Přeložte a vyzkoušejte O Porovnejte S readelf -i Jiri Slabý (Fakulta informatiky, MU) libelf: úpravy ELFu • Otevření s elf_c_write/elf_c_rdwr • 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/03 7.10.2014 14/15 Ú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 0 Přeložte a vyzkoušejte O Zobrazte Obsah sekce . comment, my pomocí readelf -x Jiri Slabý (Fakulta informatiky, MU) PB173/03 7.10.2014 15/15