#include <libelfu/libelfu.h>
+static int cmpScnOffs(const void *ms1, const void *ms2)
+{
+ assert(ms1);
+ assert(ms2);
+
+ ElfuScn *s1 = *(ElfuScn**)ms1;
+ ElfuScn *s2 = *(ElfuScn**)ms2;
+
+ assert(s1);
+ assert(s2);
+
+
+ if (s1->shdr.sh_offset < s2->shdr.sh_offset) {
+ return -1;
+ } else if (s1->shdr.sh_offset == s2->shdr.sh_offset) {
+ return 0;
+ } else /* if (s1->shdr.sh_offset > s2->shdr.sh_offset) */ {
+ return 1;
+ }
+}
+
+
+
+static ElfuPhdr* parentPhdr(ElfuElf *me, ElfuScn *ms)
+{
+ ElfuPhdr *mp;
+
+ assert(me);
+ assert(ms);
+
+ CIRCLEQ_FOREACH(mp, &me->phdrList, elem) {
+ if (mp->phdr.p_type != PT_LOAD) {
+ continue;
+ }
+
+ if (PHDR_CONTAINS_SCN_IN_MEMORY(&mp->phdr, &ms->shdr)) {
+ return mp;
+ }
+
+ /* Give sections a second chance if they do not have any sh_addr
+ * at all. */
+ /* Actually we don't, because it's ambiguous.
+ * Re-enable for experiments with strangely-formatted files.
+ if (ms->shdr.sh_addr == 0
+ && PHDR_CONTAINS_SCN_IN_FILE(&mp->phdr, &ms->shdr)
+ && OFFS_END(ms->shdr.sh_offset, ms->shdr.sh_size)
+ <= OFFS_END(mp->phdr.p_offset, mp->phdr.p_memsz)) {
+ return mp;
+ }
+ */
+ }
+
+ return NULL;
+}
+
+
static ElfuPhdr* modelFromPhdr(GElf_Phdr *phdr)
{
ElfuPhdr *mp;
mp->phdr = *phdr;
+ CIRCLEQ_INIT(&mp->childScnList);
+ CIRCLEQ_INIT(&mp->childPhdrList);
+
return mp;
}
}
}
+ ms->linkptr = NULL;
+ ms->infoptr = NULL;
+
+ ms->oldptr = NULL;
+
return ms;
ElfuElf *me;
size_t shstrndx;
size_t i, numPhdr, numShdr;
+ ElfuScn **secArray = NULL;
assert(e);
if (elfu_eCheck(e)) {
/* General stuff */
- CIRCLEQ_INIT(&me->scnList);
CIRCLEQ_INIT(&me->phdrList);
+ CIRCLEQ_INIT(&me->orphanScnList);
me->shstrtab = NULL;
me->elfclass = gelf_getclass(e);
CIRCLEQ_INSERT_TAIL(&me->phdrList, mp, elem);
}
+ if (numPhdr > 0) {
+ ElfuPhdr *mp;
+
+ /* Find PHDR -> PHDR dependencies (needs sorted sections) */
+ CIRCLEQ_FOREACH(mp, &me->phdrList, elem) {
+ ElfuPhdr *mp2;
+
+ if (mp->phdr.p_type != PT_LOAD) {
+ continue;
+ }
+
+ CIRCLEQ_FOREACH(mp2, &me->phdrList, elem) {
+ if (mp2 == mp) {
+ continue;
+ }
+
+ if (mp->phdr.p_vaddr <= mp2->phdr.p_vaddr
+ && OFFS_END(mp2->phdr.p_vaddr, mp2->phdr.p_memsz) <= OFFS_END(mp->phdr.p_vaddr, mp->phdr.p_memsz)) {
+ CIRCLEQ_INSERT_TAIL(&mp->childPhdrList, mp2, elemChildPhdr);
+ }
+ }
+ }
+ }
+
/* Load sections */
assert(!elf_getshdrnum(e, &numShdr));
- for (i = 1; i < numShdr; i++) {
- Elf_Scn *scn;
- ElfuScn *ms;
+ if (numShdr > 1) {
+ secArray = malloc((numShdr - 1) * sizeof(*secArray));
+ if (!secArray) {
+ ELFU_WARN("elfu_mFromElf: malloc() failed for secArray.\n");
+ goto ERROR;
+ }
- scn = elf_getscn(e, i);
- assert(scn);
+ for (i = 1; i < numShdr; i++) {
+ Elf_Scn *scn;
+ ElfuScn *ms;
- ms = modelFromSection(scn);
- if (!ms) {
- goto ERROR;
+ scn = elf_getscn(e, i);
+ assert(scn);
+
+ ms = modelFromSection(scn);
+ if (!ms) {
+ goto ERROR;
+ }
+
+ secArray[i-1] = ms;
+
+ if (i == shstrndx) {
+ me->shstrtab = ms;
+ }
}
- CIRCLEQ_INSERT_TAIL(&me->scnList, ms, elem);
- if (i == shstrndx) {
- me->shstrtab = ms;
+
+ /* Find sh_link dependencies */
+ for (i = 0; i < numShdr - 1; i++) {
+ ElfuScn *ms = secArray[i];
+
+ switch (ms->shdr.sh_type) {
+ case SHT_REL:
+ case SHT_RELA:
+ if (ms->shdr.sh_info > 0) {
+ ms->infoptr = secArray[ms->shdr.sh_info - 1];
+ }
+ case SHT_DYNAMIC:
+ case SHT_HASH:
+ case SHT_SYMTAB:
+ case SHT_DYNSYM:
+ case SHT_GNU_versym:
+ case SHT_GNU_verdef:
+ case SHT_GNU_verneed:
+ if (ms->shdr.sh_link > 0) {
+ ms->linkptr = secArray[ms->shdr.sh_link - 1];
+ }
+ }
}
- }
- /* Find sh_link dependencies */
+ /* Sort sections by file offset */
+ qsort(secArray, numShdr - 1, sizeof(*secArray), cmpScnOffs);
- /* Sort sections by offset */
+ /* Find PHDR -> Section dependencies (needs sorted sections) */
+ for (i = 0; i < numShdr - 1; i++) {
+ ElfuScn *ms = secArray[i];
+ ElfuPhdr *parent = parentPhdr(me, ms);
- /* Find PHDR -> Section dependencies */
+ if (parent) {
+ GElf_Off shaddr = parent->phdr.p_vaddr +
+ (ms->shdr.sh_offset - parent->phdr.p_offset);
+ if (ms->shdr.sh_addr == 0) {
+ ms->shdr.sh_addr = shaddr;
+ } else {
+ assert(ms->shdr.sh_addr == shaddr);
+ }
+
+ CIRCLEQ_INSERT_TAIL(&parent->childScnList, ms, elemChildScn);
+ } else {
+ CIRCLEQ_INSERT_TAIL(&me->orphanScnList, ms, elemChildScn);
+ }
+ }
+ }
return me;
ERROR:
+ if (secArray) {
+ free(secArray);
+ }
if (me) {
// TODO: Free data structures
}