PB173 - Binární programování Linux IV. ELF Jiri Slabý ITI, Fakulta informatiky 8. 10. 2013 J. Slabý (ITI, Fl) PB173/07 8. 10. 2013 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 J. Slabý (ITI, Fl) PB173/07 8.10.2013 2/ 15 libelf • 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 o Pracuje na nižší úrovni J. Slabý (ITI, Fl) libelf • Knihovna pro práci s ELF • 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 J. Slabý (ITI, Fl) PB173/07 8. 10. 2013 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.errnoO Typicky: if (! elf-function (...) ) errx(1, " elf.function : %s", elLerrmsg(-l)); J. Slabý (ITI, Fl) PB173/07 8. 10. 2013 5/ 15 Úkol Inicializujte libelf a otevřete soubor O Zavolejte elf _version(EV_CURRENT) 0 Zkontrolujte návratovou hodnotu • Nesmí být ev_none • V případě chyby ji vypište (elf _errmsg(-l)) O Pomocí standardního open otevřete soubor z příkazové řádky O Přeložte a spusťte J. Slabý (ITI, Fl) PB173/07 8. 10. 2013 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_none, elf_k_ar, elf_k_elf • Konec práce a int elf_end(Elf *elf) Bez ověření chyb: int fd =open(file, O.RDONLY); Elf *elf = elf.begin(fd, ELF.C.READ, NULL); elf.end(elf); close(fd); J. Slabý (ITI, Fl) PB173/07 8. 10. 2013 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 0 Přeložte a spusťte J. Slabý (ITI, Fl) PB173/07 8. 10. 2013 8/ 15 libelf: sekce • Držátko: Elf _Scn a Hlavička: GElf_Shdr (gelf.h) • 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, . . . o sh_size: velikost • Data: Elf _Data » d_buf: data o d_type:ELF_T_BYTE, ELF_T_ADDR, . . . a d_size: velikost dat J. Slabý (ITI, Fl) PB173/07 8. 10. 2013 9/ 15 libelf: funkce pro sekce o Index sekce .shstrtab (sekce s názvy sekcí): int elf_getshdrstrndx(Elf *elf, size_t *dst) • 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) a Iterace přes obsah: Elf_Data *elf_getdata(Elf_Scn *scn, Elf_Data *data) EILScn *scn = NULL; while ((sen = elf.nextscn(elf, sen))) { GElLShdr shdr; EILData *data= NULL; gelLgetshdr(scn, &shdr); /* shdr */ while ((data = elf.getdata(scn, data))) /* data */; } J. Slabý (ITI, Fl) PB173/07 8. 10. 2013 10/15 Úkol Hexdump sekcí O Iterujte přes sekce (elf _nextscn) O Vypište hlavičku každé sekce (gelf_getshdr) » Index • Offset do sekce názvů • Velikost • Flagy O Vypište data každé sekce (elf _getdata) • Uvažte jen první elf _getdata (neiterujte přes data) 0 Hexdump prvních 16 bytů obsahu O Přeložte a vyzkoušejte O Porovnejte S readelf -s J. Slabý (ITI, Fl) PB173/07 8. 10. 2013 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 • p_type:PT_NULL, PT_L0AD, PT_INTERP, . . . • p_off set: offset v souboru 0 p_fiiesz: velikost v souboru • p_memsz: velikost v paměti (po načtení) J. Slabý (ITI, Fl) PB173/07 8. 10. 2013 12/15 Úkol Výpis programových hlaviček O Otevřete ELF soubor pro čtení O Vypište programové hlavičky O Přeložte a vyzkoušejte O Porovnejte S readelf -1 J. Slabý (ITI, Fl) 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) a cmd:ELF_C_WRITE J. Slabý (ITI, Fl) PB173/07 8. 10. 2013 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 O Přeložte a vyzkoušejte O Zobrazte Obsah sekce .comment.my pomocí readelf -x J. Slabý (ITI, Fl) PB173/07 8. 10. 2013 15/15