From 93156d059749102d3dfef793f00c63c8c1c27ee0 Mon Sep 17 00:00:00 2001 From: norly Date: Fri, 31 May 2013 17:14:27 +0100 Subject: [PATCH] Auto-layout file after --reladd --- include/libelfu/modelops.h | 1 + src/model/layout.c | 97 ++++++++++++++++++++++++++++++++++++++ src/model/reladd.c | 3 ++ 3 files changed, 101 insertions(+) diff --git a/include/libelfu/modelops.h b/include/libelfu/modelops.h index 8374b02..c1d30e3 100644 --- a/include/libelfu/modelops.h +++ b/include/libelfu/modelops.h @@ -22,6 +22,7 @@ ElfuScn** elfu_mScnSortedByOffset(ElfuElf *me, size_t *count); GElf_Addr elfu_mLayoutGetSpaceInPhdr(ElfuElf *me, GElf_Word size, GElf_Word align, int w, int x, ElfuPhdr **injPhdr); +int elfu_mLayoutAuto(ElfuElf *me); int elfu_mCheck(ElfuElf *me); diff --git a/src/model/layout.c b/src/model/layout.c index 2febed1..d5d49d8 100644 --- a/src/model/layout.c +++ b/src/model/layout.c @@ -215,3 +215,100 @@ GElf_Addr elfu_mLayoutGetSpaceInPhdr(ElfuElf *me, GElf_Word size, } return 0; } + + + + +static int cmpPhdrOffs(const void *mp1, const void *mp2) +{ + assert(mp1); + assert(mp2); + + ElfuPhdr *p1 = *(ElfuPhdr**)mp1; + ElfuPhdr *p2 = *(ElfuPhdr**)mp2; + + assert(p1); + assert(p2); + + + if (p1->phdr.p_offset < p2->phdr.p_offset) { + return -1; + } else if (p1->phdr.p_offset == p2->phdr.p_offset) { + return 0; + } else /* if (p1->phdr.p_offset > p2->phdr.p_offset) */ { + return 1; + } +} + +int elfu_mLayoutAuto(ElfuElf *me) +{ + ElfuPhdr *mp; + ElfuScn *ms; + ElfuPhdr **phdrArr; + GElf_Off lastend = 0; + size_t i, j; + + assert(me); + + phdrArr = malloc(elfu_mPhdrCount(me) * sizeof(*phdrArr)); + if (!phdrArr) { + ELFU_WARN("elfu_mLayoutAuto: malloc failed for phdrArr.\n"); + return 1; + } + + i = 0; + CIRCLEQ_FOREACH(mp, &me->phdrList, elem) { + if (mp->phdr.p_type != PT_LOAD) { + continue; + } + + phdrArr[i] = mp; + i++; + } + + /* Assume we have at least one LOAD PHDR, + * and that it ends after EHDR and PHDRs */ + assert(i > 1); + + /* Sort array by file offset */ + qsort(phdrArr, i, sizeof(*phdrArr), cmpPhdrOffs); + + lastend = OFFS_END(phdrArr[0]->phdr.p_offset, phdrArr[0]->phdr.p_filesz); + + /* Wiggle offsets of 2nd, 3rd etc so take minimum space */ + for (j = 1; j < i; j++) { + GElf_Off subalign = phdrArr[j]->phdr.p_offset % phdrArr[j]->phdr.p_align; + + if ((lastend % phdrArr[j]->phdr.p_align) <= subalign) { + lastend += subalign - (lastend % phdrArr[j]->phdr.p_align); + } else { + lastend += phdrArr[j]->phdr.p_align - ((lastend % phdrArr[j]->phdr.p_align) - subalign); + } + + phdrArr[j]->phdr.p_offset = lastend; + + elfu_mPhdrUpdateChildOffsets(phdrArr[j]); + + lastend = OFFS_END(phdrArr[j]->phdr.p_offset, phdrArr[j]->phdr.p_filesz); + } + + free(phdrArr); + + + /* Place orphaned sections afterwards, maintaining alignment */ + CIRCLEQ_FOREACH(ms, &me->orphanScnList, elemChildScn) { + lastend = ROUNDUP(lastend, ms->shdr.sh_addralign); + + ms->shdr.sh_offset = lastend; + + lastend = OFFS_END(ms->shdr.sh_offset, SCNFILESIZE(&ms->shdr)); + } + + + /* Move SHDRs to end */ + lastend = ROUNDUP(lastend, 8); + me->ehdr.e_shoff = lastend; + + + return 0; +} diff --git a/src/model/reladd.c b/src/model/reladd.c index ffd02f4..2de03dc 100644 --- a/src/model/reladd.c +++ b/src/model/reladd.c @@ -160,4 +160,7 @@ void elfu_mReladd(ElfuElf *me, ElfuElf *mrel) /* Do relocations and other stuff */ elfu_mScnForall(mrel, subScnAdd2, me, NULL); + + /* Re-layout to accommodate new contents */ + elfu_mLayoutAuto(me); } -- 2.30.2