Aztán márcsak a progbits section-ok értelmezése van hátra.Ööö, ez alatt mit értesz pontosan? Ez eléggé bonyi is tud lenni ám... Nem váletlenül írtam, hogy "ha értelmezni meg ellenőrizni is akarod, na az már más kérdés".
De azon is agyalok hogy a memory block-ok automatikusan kialakulnak a progbits/nobits-ekbőlNem, ez nem egészen így működik. Megpróbálom lehető legegyszerűbben elmagyarázni. Először is, nincs olyan, hogy memory block, a MEMORY csak linker script absztrakció, ELF-ben nincs ilyesmi. Ott segmentek vannak (ELF szóhasználatban program headers, PHDRS, amik PT_LOAD típusúak), és ezek sem automatikusak, hanem a linker script sorolja be a sectionöket valamelyikbe (ezt az összerendelést a readelf egyébként ki is írja). Ilyen segmentek mindig kell, hogy legyenek előre definiálva, ha más nem, akkor a fordító "internal linker script"-jéből jönnek. Alapvetően kétféle ELF "nézet" van: - section: Shdr rekordok, ezt használja a fordító és ez a linker bemenete. Semmi köze semmihez, teljesen ad-hoc logikai elrendezés, akár minden függvény külön sectionbe rakható, ha akarod. - segment: Phdr rekordok, futtatáskor meg csak ezeket használja. Jellemzően lapozási hozzáférési jogosultságonként szokott lenni egy-egy (futtatható szegmens, csak olvasható szegmens, írható-olvasható szegmens). Persze az ELF nagyon rugalmas, bármi elképzelhető. A memory block (linker script MEMORY kulcsszava) ezeknek a címeivel zsonglőrködik. Namost simán lehet, hogy futtatható fájlban egyáltalán nincs section infó (pl. ha strip parancsot hívtak rá). Ilyenkor Elf64_Shdr helyett az Elf64_Phdr structokat kell nézni:
for(i = 0; i < ehdr->e_phnum; i++) {
phdr = (Elf32_Phdr *)(data + ehdr->e_phoff + i * elf->e_phentsize);
printf("ELF segment %p %d bytes (bss %d bytes)\n", phdr->p_vaddr, phdr->p_filesz, phdr->p_memsz - phdr->p_filesz);
}
Ezek jóval egyszerűbbek és kevesebb infót tárolnak egy-egy blokkról (nincs pl láthatóság, szimbólumnév se bennük), van viszont fájloffszet, virtuális cím és kétféle méret (fájlban és memóriában mennyi), valamint rengeteg fajta technikai típus is van ezekből.
Például ha shared object (.so), akkor kell lennie a Phdr között egy PT_DYNAMIC típusúnak, ebbe kerülnek azok a szimbólumok, melyek kívülről hívhatóak (de csak azok!) és amik általában szerpelnek a Global Offset Table-ben is. Futtatható esetén meg egy INTERPRETER szokott lenni, egy kis kód, ami a futás idejű shared object linkelést végzi általában. Ezeken kívül még számos egyéb Phdr bejegyzésfajta is található, amikre igazából nincs szükség a futáshoz, vagy automatikusan generálódnak a kódból, stb. és ezeknek egyértelmű section megfelelőjük sincs (tipikus példa a lazy dynlink PLT rekordjai, a hash tábla, vagy épp a statikus stack, build azonosító, relokációs táblák stb).
Mivel sokkal többféle program header típus van (a PT_LOAD csak egy közülük), ezért nem épp triviális a section leképezés, pl. progbits-e csak a sectionnek van, és az ilyen sectionöket tartalmazó segment mindig PT_LOAD flaget kap, ugyanakkor van egy csomó más PT_LOAD-al megjelölt segment, amikhez nem tartozik progbits-es section egyáltalán, és egy section több program headersbe is bekerülhet (kód, PLT, relokáció, stb.).
Ezért kérdezem, hogy mire gondoltál, mert ha nm-nél részletesebb kimenetet akarsz, akkor amint látod, nagyon gyorsan eszkalálódni tud a helyzet.
Ha elég annyi, hogy a fájl melyik része hova kell kerüljön a memóriába, akkor az viszonylag egyszerű, csak a fentebbi Phdr listázás fog kelleni.