summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/main.c14
-rw-r--r--src/model/check.c63
-rw-r--r--src/model/clone.c7
-rw-r--r--src/model/count.c55
-rw-r--r--src/model/dump.c20
-rw-r--r--src/model/expandNobits.c116
-rw-r--r--src/model/fromFile.c9
-rw-r--r--src/model/insert.c289
-rw-r--r--src/model/phdr.c17
-rw-r--r--src/model/reladd.c494
-rw-r--r--src/model/section-by-type.c22
-rw-r--r--src/model/section-in-segment.c56
-rw-r--r--src/model/section-name.c23
-rw-r--r--src/model/section.c170
-rw-r--r--src/model/toFile.c30
-rw-r--r--src/options.c20
16 files changed, 563 insertions, 842 deletions
diff --git a/src/main.c b/src/main.c
index 0eb6e00..a179fcd 100644
--- a/src/main.c
+++ b/src/main.c
@@ -59,18 +59,6 @@ int main(int argc, char **argv)
if (!opts.fnOutput) {
printf("No output file specified - no further operations performed.\n");
} else {
- if (opts.expandNobitsOffs) {
- elfu_mExpandNobits(me, opts.expandNobitsOffs);
- }
-
- if (opts.insertBeforeSz) {
- elfu_mInsertSpaceBefore(me, opts.insertBeforeOffs, opts.insertBeforeSz);
- }
-
- if (opts.insertAfterSz) {
- elfu_mInsertSpaceAfter(me, opts.insertAfterOffs, opts.insertAfterSz);
- }
-
if (opts.fnReladd) {
ELFHandles hRel = { 0 };
ElfuElf *mrel = NULL;
@@ -90,12 +78,12 @@ int main(int argc, char **argv)
elfu_mReladd(me, mrel);
}
}
-
}
elfu_mCheck(me);
printf("Output model checked.\n");
+ elfu_mDumpElf(me);
openElf(&hOut, opts.fnOutput, ELF_C_WRITE);
if (!hOut.e) {
diff --git a/src/model/check.c b/src/model/check.c
index 6dc0694..5234bef 100644
--- a/src/model/check.c
+++ b/src/model/check.c
@@ -4,66 +4,16 @@
#include <libelfu/libelfu.h>
-
-static int isOverlapping(size_t off1, size_t sz1, size_t off2, size_t sz2)
-{
- size_t end1 = off1 + sz1;
- size_t end2 = off2 + sz2;
-
- if (off2 >= off1 && off2 < end1) {
- return 1;
- } else if (off1 >= off2 && off1 < end2) {
- return 1;
- } else {
- return 0;
- }
-}
-
-
-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;
- }
-}
-
-
int elfu_mCheck(ElfuElf *me)
{
- ElfuScn *ms;
size_t numSecs;
ElfuScn **sortedSecs;
size_t i;
- /* Sort sections by offset in file */
- numSecs = elfu_mCountScns(me);
- sortedSecs = malloc(numSecs * sizeof(*sortedSecs));
+ sortedSecs = elfu_mScnSortedByOffset(me, &numSecs);
if (!sortedSecs) {
- ELFU_WARN("elfu_check: Failed to allocate memory.\n");
- }
-
- i = 0;
- CIRCLEQ_FOREACH(ms, &me->scnList, elem) {
- sortedSecs[i] = ms;
- i++;
+ return -1;
}
- assert(i == numSecs);
-
- qsort(sortedSecs, numSecs, sizeof(*sortedSecs), cmpScnOffs);
/* Check for overlapping sections */
@@ -88,15 +38,16 @@ int elfu_mCheck(ElfuElf *me)
/* Check for sections overlapping with PHDRs */
for (i = 0; i < numSecs; i++) {
- if (isOverlapping(sortedSecs[i]->shdr.sh_offset,
- SCNFILESIZE(&sortedSecs[i]->shdr),
- me->ehdr.e_phoff,
- me->ehdr.e_phentsize * me->ehdr.e_phnum)) {
+ if (OVERLAPPING(sortedSecs[i]->shdr.sh_offset,
+ SCNFILESIZE(&sortedSecs[i]->shdr),
+ me->ehdr.e_phoff,
+ me->ehdr.e_phentsize * me->ehdr.e_phnum)) {
ELFU_WARN("elfu_check: Found section overlapping with PHDRs: %s.\n",
elfu_mScnName(me, sortedSecs[i]));
}
}
+
free(sortedSecs);
return 0;
diff --git a/src/model/clone.c b/src/model/clone.c
index 3dbbc54..644647c 100644
--- a/src/model/clone.c
+++ b/src/model/clone.c
@@ -15,8 +15,6 @@ ElfuScn* elfu_mCloneScn(ElfuScn *ms)
return NULL;
}
-
-
newscn->shdr = ms->shdr;
newscn->data = ms->data;
if (ms->data.d_buf) {
@@ -31,5 +29,10 @@ ElfuScn* elfu_mCloneScn(ElfuScn *ms)
newscn->data.d_buf = newbuf;
}
+ newscn->linkptr = NULL;
+ newscn->infoptr = NULL;
+
+ newscn->oldptr = ms;
+
return newscn;
}
diff --git a/src/model/count.c b/src/model/count.c
deleted file mode 100644
index 671767e..0000000
--- a/src/model/count.c
+++ /dev/null
@@ -1,55 +0,0 @@
-#include <assert.h>
-#include <sys/types.h>
-#include <libelfu/libelfu.h>
-
-
-size_t elfu_mScnIndex(ElfuElf *me, ElfuScn *ms)
-{
- ElfuScn *ms2;
- size_t i = 1;
-
- assert(me);
- assert(ms);
-
- CIRCLEQ_FOREACH(ms2, &me->scnList, elem) {
- if (ms2 == ms) {
- return i;
- }
-
- i++;
- }
-
- /* Section is not in ELF model. This means the calling code is broken. */
- assert(0);
-}
-
-
-/* NULL section is not counted! */
-size_t elfu_mCountScns(ElfuElf *me)
-{
- ElfuScn *ms;
- size_t i = 0;
-
- assert(me);
-
- CIRCLEQ_FOREACH(ms, &me->scnList, elem) {
- i++;
- }
-
- return i;
-}
-
-
-size_t elfu_mCountPhdrs(ElfuElf *me)
-{
- ElfuPhdr *mp;
- size_t i = 0;
-
- assert(me);
-
- CIRCLEQ_FOREACH(mp, &me->phdrList, elem) {
- i++;
- }
-
- return i;
-}
diff --git a/src/model/dump.c b/src/model/dump.c
index 67a498a..5f0642a 100644
--- a/src/model/dump.c
+++ b/src/model/dump.c
@@ -184,6 +184,19 @@ void elfu_mDumpEhdr(ElfuElf *me)
}
+
+static int subScnDump(ElfuElf *me, ElfuScn *ms, void *aux1, void *aux2)
+{
+ (void) aux1;
+ (void) aux2;
+
+ printf(" [%4d] ", elfu_mScnIndex(me, ms));
+ elfu_mDumpScn(me, ms);
+
+ return 0;
+}
+
+
void elfu_mDumpElf(ElfuElf *me)
{
ElfuPhdr *mp;
@@ -221,11 +234,6 @@ void elfu_mDumpElf(ElfuElf *me)
ELFU_INFO("Sections:\n");
ELFU_INFO(" # Name sh_type sh_addr sh_offset sh_size ES Fl Al sh_link sh_info \n");
ELFU_INFO(" | | | | | | | | | | \n");
- i = 1;
- CIRCLEQ_FOREACH(ms, &me->scnList, elem) {
- printf(" [%4d] ", i);
- elfu_mDumpScn(me, ms);
- i++;
- }
+ elfu_mScnForall(me, subScnDump, &i, NULL);
ELFU_INFO("\n");
}
diff --git a/src/model/expandNobits.c b/src/model/expandNobits.c
deleted file mode 100644
index d12990e..0000000
--- a/src/model/expandNobits.c
+++ /dev/null
@@ -1,116 +0,0 @@
-#include <assert.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <libelf/gelf.h>
-#include <libelfu/libelfu.h>
-
-
-void elfu_mExpandNobits(ElfuElf *me, GElf_Off off)
-{
- ElfuScn *ms;
- ElfuPhdr *mp;
- GElf_Xword expansionSize;
-
- assert(me);
-
- expansionSize = 0;
-
- /* Find the maximum amount we need to expand by. Check PHDRs first */
- CIRCLEQ_FOREACH(mp, &me->phdrList, elem) {
- GElf_Off off2 = mp->phdr.p_offset;
- GElf_Off end2 = mp->phdr.p_offset + mp->phdr.p_filesz;
- if (end2 == off) {
- GElf_Xword size2 = mp->phdr.p_memsz - mp->phdr.p_filesz;
- if (size2 > expansionSize) {
- expansionSize = size2;
- }
- } else if (end2 > off) {
- if (off2 < off) {
- /*
- * Found a PHDR whose file contents overlaps with the section
- * to be filled. This means that it relies on the NOBITS area
- * being actually 0 bytes, and the expansion would ruin it.
- */
- ELFU_WARN("mExpandNobits: Found PHDR spanning expansion offset. Aborting.\n");
- return;
- }
- } else {
- // end2 < off, and the PHDR is unaffected.
- continue;
- }
- }
-
- /* Now check SHDRs */
- CIRCLEQ_FOREACH(ms, &me->scnList, elem) {
- if (ms->shdr.sh_offset == off) {
- if (ms->shdr.sh_type == SHT_NOBITS) {
- if (ms->shdr.sh_size > expansionSize) {
- expansionSize = ms->shdr.sh_size;
- }
- }
- }
- }
-
-
-
- /* Expand! */
-
-
- /* Move all following PHDR offsets further down the file. */
- CIRCLEQ_FOREACH(mp, &me->phdrList, elem) {
- GElf_Off off2 = mp->phdr.p_offset;
- GElf_Off end2 = mp->phdr.p_offset + mp->phdr.p_filesz;
-
- if (off2 >= off) {
- mp->phdr.p_offset += expansionSize;
- } else {
- if (end2 == off) {
- /* This PHDR now has corresponding bytes in the file for every
- * byte in memory. */
- mp->phdr.p_filesz = mp->phdr.p_memsz;
- }
- }
- }
-
- /* Move the following sections */
- CIRCLEQ_FOREACH(ms, &me->scnList, elem) {
- if (ms->shdr.sh_offset >= off) {
- if (ms->shdr.sh_offset > off
- || ms->shdr.sh_type != SHT_NOBITS) {
- ms->shdr.sh_offset += expansionSize;
- }
- }
- }
-
- /* Move SHDR/PHDR tables */
- if (me->ehdr.e_shoff >= off) {
- me->ehdr.e_shoff += expansionSize;
- }
-
- if (me->ehdr.e_phoff >= off) {
- me->ehdr.e_phoff += expansionSize;
- }
-
-
- /* Convert any NOBITS at off to PROGBITS */
- CIRCLEQ_FOREACH(ms, &me->scnList, elem) {
- if (ms->shdr.sh_offset == off) {
- if (ms->shdr.sh_type == SHT_NOBITS) {
- ms->data.d_buf = malloc(ms->shdr.sh_size);
- memset(ms->data.d_buf, '\0', ms->shdr.sh_size);
- if (!ms->data.d_buf) {
- ELFU_WARN("mExpandNobits: Could not allocate %jd bytes for NOBITS expansion.\n", ms->shdr.sh_size);
- }
-
- ms->data.d_align = 1;
- ms->data.d_off = 0;
- ms->data.d_type = ELF_T_BYTE;
- ms->data.d_size = ms->shdr.sh_size;
- ms->data.d_version = elf_version(EV_NONE);
-
- ms->shdr.sh_type = SHT_PROGBITS;
- }
- }
- }
-}
diff --git a/src/model/fromFile.c b/src/model/fromFile.c
index cb09352..ee0536d 100644
--- a/src/model/fromFile.c
+++ b/src/model/fromFile.c
@@ -132,6 +132,8 @@ static ElfuScn* modelFromSection(Elf_Scn *scn)
ms->linkptr = NULL;
ms->infoptr = NULL;
+ ms->oldptr = NULL;
+
return ms;
@@ -165,7 +167,6 @@ ElfuElf* elfu_mFromElf(Elf *e)
/* General stuff */
- CIRCLEQ_INIT(&me->scnList);
CIRCLEQ_INIT(&me->phdrList);
CIRCLEQ_INIT(&me->orphanScnList);
me->shstrtab = NULL;
@@ -291,12 +292,6 @@ ElfuElf* elfu_mFromElf(Elf *e)
CIRCLEQ_INSERT_TAIL(&me->orphanScnList, ms, elemChildScn);
}
}
-
-
- /* Put sections into list of all sections */
- for (i = 0; i < numShdr - 1; i++) {
- CIRCLEQ_INSERT_TAIL(&me->scnList, secArray[i], elem);
- }
}
diff --git a/src/model/insert.c b/src/model/insert.c
deleted file mode 100644
index b18aa8a..0000000
--- a/src/model/insert.c
+++ /dev/null
@@ -1,289 +0,0 @@
-#include <assert.h>
-#include <sys/types.h>
-#include <libelf/gelf.h>
-#include <libelfu/libelfu.h>
-
-
-// TODO: Take p_align into account
-
-
-
-/*
- * Insert space at a given position in the file by moving everything
- * after it towards the end of the file, and everything before it
- * towards lower memory regions where it is mapped.
- *
- * off must not be in the middle of any data structure, such as
- * PHDRs, SHDRs, or sections. Behaviour is undefined if it is.
- *
- * PHDRs will be patched such that everything AFTER off is mapped to
- * the same address in memory, and everything BEFORE it is shifted to
- * lower addresses, making space for the new data in-between.
- */
-GElf_Xword elfu_mInsertSpaceBefore(ElfuElf *me, GElf_Off off, GElf_Xword size)
-{
- ElfuScn *ms;
- ElfuPhdr *mp;
-
- assert(me);
-
- /* Round up size to 4096 bytes to keep page alignment on x86 when
- * remapping existing data to lower addresses. */
- size += (4096 - (size % 4096)) % 4096;
- // TODO: Find alignment size by checking p_align in PHDRs
-
- /* Move SHDRs and PHDRs */
- if (me->ehdr.e_shoff >= off) {
- me->ehdr.e_shoff += size;
- }
-
- if (me->ehdr.e_phoff >= off) {
- me->ehdr.e_phoff += size;
- }
-
- /* Patch PHDRs to include new data */
- CIRCLEQ_FOREACH(mp, &me->phdrList, elem) {
- GElf_Off end = mp->phdr.p_offset + mp->phdr.p_filesz;
-
- if (mp->phdr.p_offset >= off) {
- /* Insertion before PHDR's content, so it's just shifted */
- mp->phdr.p_offset += size;
- } else {
- /* mp->phdr.p_offset < off */
-
- if (off < end) {
- /* Insertion in the middle of PHDR, so let it span the new data */
- mp->phdr.p_filesz += size;
- mp->phdr.p_memsz += size;
- mp->phdr.p_vaddr -= size;
- mp->phdr.p_paddr -= size;
- } else {
- /* Insertion after PHDR's content, so it may need to be
- remapped. This will happen in a second pass.
- */
- }
- }
- }
-
- /* For each LOAD header, find clashing headers that need to be
- remapped to lower memory areas.
- */
- CIRCLEQ_FOREACH(mp, &me->phdrList, elem) {
- if (mp->phdr.p_type == PT_LOAD) {
- ElfuPhdr *mp2;
-
- CIRCLEQ_FOREACH(mp2, &me->phdrList, elem) {
- if (mp2->phdr.p_type != PT_LOAD
- && mp2->phdr.p_offset + mp2->phdr.p_filesz <= off) {
- /* The PHDR ends in the file before the injection site */
- GElf_Off vend1 = mp->phdr.p_vaddr + mp->phdr.p_memsz;
- GElf_Off pend1 = mp->phdr.p_paddr + mp->phdr.p_memsz;
- GElf_Off vend2 = mp2->phdr.p_vaddr + mp2->phdr.p_memsz;
- GElf_Off pend2 = mp2->phdr.p_paddr + mp2->phdr.p_memsz;
-
- /* If mp and mp2 now overlap in memory */
- if ((mp2->phdr.p_vaddr < vend1 && vend2 > mp->phdr.p_vaddr)
- || (mp2->phdr.p_paddr < pend1 && pend2 > mp->phdr.p_paddr)) {
- /* Move mp2 down in memory, as mp has been resized.
- Maintaining the relative offset between them is the best
- guess at maintaining consistency.
- */
- mp2->phdr.p_vaddr -= size;
- mp2->phdr.p_paddr -= size;
- }
- }
- }
- }
- }
-
- /* Move the sections themselves */
- CIRCLEQ_FOREACH(ms, &me->scnList, elem) {
- if (ms->shdr.sh_offset >= off) {
- ms->shdr.sh_offset += size;
- } else {
- /* sh_offset < off */
-
- /* If this was in a LOAD segment, it has been adjusted there
- and this synchronises it.
- If not, it doesn't matter anyway.
- */
- ms->shdr.sh_addr -= size;
- }
- }
-
- return size;
-}
-
-
-
-/*
- * Insert space at a given position in the file by moving everything
- * after it towards the end of the file, and towards higher memory
- * regions where it is mapped.
- *
- * off must not be in the middle of any data structure, such as
- * PHDRs, SHDRs, or sections. Behaviour is undefined if it is.
- *
- * PHDRs will be patched such that everything AFTER off is shifted to
- * higher addresses, making space for the new data in-between.
- *
- * CAUTION: This also moves NOBITS sections. If such are present,
- * use mExpandNobits() first and then inject at the end of
- * the expansion site.
- */
-GElf_Xword elfu_mInsertSpaceAfter(ElfuElf *me, GElf_Off off, GElf_Xword size)
-{
- ElfuScn *ms;
- ElfuPhdr *mp;
-
- assert(me);
-
-/* Move SHDRs and PHDRs */
- if (me->ehdr.e_shoff >= off) {
- me->ehdr.e_shoff += size;
- }
-
- if (me->ehdr.e_phoff >= off) {
- me->ehdr.e_phoff += size;
- }
-
- /* Patch PHDRs to include new data */
- CIRCLEQ_FOREACH(mp, &me->phdrList, elem) {
- GElf_Off end = mp->phdr.p_offset + mp->phdr.p_filesz;
-
- if (mp->phdr.p_offset >= off) {
- /* Insertion before PHDR's content, so it's shifted. */
- mp->phdr.p_offset += size;
-
- /* It may also need to be remapped. See second pass below. */
- } else {
- /* mp->phdr.p_offset < off */
-
- if (off < end) {
- /* Insertion in the middle of PHDR, so let it span the new data */
- mp->phdr.p_filesz += size;
- mp->phdr.p_memsz += size;
- } else {
- /* Insertion after PHDR's content. Nothing to do. */
- }
- }
- }
-
- /* For each LOAD header, find clashing headers that need to be
- remapped to higher memory areas.
- */
- CIRCLEQ_FOREACH(mp, &me->phdrList, elem) {
- if (mp->phdr.p_type == PT_LOAD) {
- ElfuPhdr *mp2;
-
- CIRCLEQ_FOREACH(mp2, &me->phdrList, elem) {
- if (mp2->phdr.p_type != PT_LOAD
- && mp2->phdr.p_offset + mp2->phdr.p_filesz > off) {
- /* The PHDR now ends in the file after the injection site */
- GElf_Off vend1 = mp->phdr.p_vaddr + mp->phdr.p_memsz;
- GElf_Off pend1 = mp->phdr.p_paddr + mp->phdr.p_memsz;
- GElf_Off vend2 = mp2->phdr.p_vaddr + mp2->phdr.p_memsz;
- GElf_Off pend2 = mp2->phdr.p_paddr + mp2->phdr.p_memsz;
-
- /* If mp and mp2 now overlap in memory */
- if ((mp2->phdr.p_vaddr < vend1 && vend2 > mp->phdr.p_vaddr)
- || (mp2->phdr.p_paddr < pend1 && pend2 > mp->phdr.p_paddr)) {
- /* Move mp2 up in memory, as mp has been resized.
- Maintaining the relative offset between them is the best
- guess at maintaining consistency.
- */
-
- mp2->phdr.p_vaddr += size;
- mp2->phdr.p_paddr += size;
- }
- }
- }
- }
- }
-
- /* Move the sections themselves */
- CIRCLEQ_FOREACH(ms, &me->scnList, elem) {
- if (ms->shdr.sh_offset >= off) {
- ms->shdr.sh_offset += size;
-
- /* If this was in a LOAD segment, it has been adjusted there
- and this synchronises it.
- If not, it doesn't matter anyway.
- */
- ms->shdr.sh_addr += size;
- }
- }
-
- return size;
-}
-
-
-
-
-
-/* Update cross-references */
-static void shiftSections(ElfuElf *me, ElfuScn *first)
-{
- ElfuScn *ms = first;
- size_t firstIndex = elfu_mScnIndex(me, first);
-
- do {
- if (ms == me->shstrtab) {
- me->ehdr.e_shstrndx++;
- }
-
- ms = CIRCLEQ_LOOP_NEXT(&me->scnList, ms, elem);
- } while (ms != CIRCLEQ_FIRST(&me->scnList));
-
- CIRCLEQ_FOREACH(ms, &me->scnList, elem) {
- switch (ms->shdr.sh_type) {
- case SHT_REL:
- case SHT_RELA:
- if (ms->shdr.sh_info >= firstIndex) {
- ms->shdr.sh_info++;
- }
- 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 >= firstIndex) {
- ms->shdr.sh_link++;
- }
- }
- }
-}
-
-
-/*
- * Insert a section into an ELF model, /before/ a given other section
- */
-void elfu_mInsertScnInChainBefore(ElfuElf *me, ElfuScn *oldscn, ElfuScn *newscn)
-{
- assert(me);
- assert(oldscn);
- assert(newscn);
-
- shiftSections(me, oldscn);
-
- CIRCLEQ_INSERT_BEFORE(&me->scnList, oldscn, newscn, elem);
-}
-
-
-/*
- * Insert a section into an ELF model, /after/ a given other section
- */
-void elfu_mInsertScnInChainAfter(ElfuElf *me, ElfuScn *oldscn, ElfuScn *newscn)
-{
- assert(me);
- assert(oldscn);
- assert(newscn);
-
- if (oldscn != CIRCLEQ_LAST(&me->scnList)) {
- shiftSections(me, CIRCLEQ_NEXT(oldscn, elem));
- }
-
- CIRCLEQ_INSERT_AFTER(&me->scnList, oldscn, newscn, elem);
-}
diff --git a/src/model/phdr.c b/src/model/phdr.c
new file mode 100644
index 0000000..26a26e3
--- /dev/null
+++ b/src/model/phdr.c
@@ -0,0 +1,17 @@
+#include <assert.h>
+#include <libelfu/libelfu.h>
+
+
+size_t elfu_mPhdrCount(ElfuElf *me)
+{
+ ElfuPhdr *mp;
+ size_t i = 0;
+
+ assert(me);
+
+ CIRCLEQ_FOREACH(mp, &me->phdrList, elem) {
+ i++;
+ }
+
+ return i;
+}
diff --git a/src/model/reladd.c b/src/model/reladd.c
index 549afcf..bc13b97 100644
--- a/src/model/reladd.c
+++ b/src/model/reladd.c
@@ -1,177 +1,292 @@
#include <assert.h>
#include <stdlib.h>
+#include <string.h>
#include <sys/types.h>
#include <libelf/gelf.h>
#include <libelfu/libelfu.h>
-typedef enum Destsegment {
- DS_UNKNOWN,
- DS_TEXT,
- DS_DATA,
-} Destsegment;
-static Destsegment destsegment(ElfuScn *ms)
+static GElf_Word makeSpaceAtOffset(ElfuElf *me, GElf_Off offset, GElf_Word size)
{
- if (!(ms->shdr.sh_flags & SHF_ALLOC)) {
- return DS_UNKNOWN;
+ ElfuPhdr *mp;
+ ElfuScn *ms;
+ /* Force a minimum alignment, just to be sure. */
+ GElf_Word align = 64;
+
+ /* Find maximum alignment size by which we have to shift.
+ * Assumes alignment sizes are always 2^x. */
+ CIRCLEQ_FOREACH(mp, &me->phdrList, elem) {
+ if (mp->phdr.p_offset >= offset) {
+ if (mp->phdr.p_align > align) {
+ align = mp->phdr.p_align;
+ }
+ }
}
- if (!(ms->shdr.sh_flags & SHF_WRITE)
- && (ms->shdr.sh_flags & SHF_EXECINSTR)) {
- return DS_TEXT;
- } else if ((ms->shdr.sh_flags & SHF_WRITE)
- && !(ms->shdr.sh_flags & SHF_EXECINSTR)) {
- return DS_DATA;
+ CIRCLEQ_FOREACH(ms, &me->orphanScnList, elemChildScn) {
+ if (ms->shdr.sh_offset >= offset) {
+ if (ms->shdr.sh_addralign > align) {
+ align = ms->shdr.sh_addralign;
+ }
+ }
}
- return DS_UNKNOWN;
+ size = ROUNDUP(size, align);
+
+ /* Shift stuff */
+ CIRCLEQ_FOREACH(mp, &me->phdrList, elem) {
+ if (mp->phdr.p_type != PT_LOAD) {
+ continue;
+ }
+
+ if (mp->phdr.p_offset >= offset) {
+ ElfuScn *ms;
+ ElfuPhdr *mpc;
+
+ mp->phdr.p_offset += size;
+ CIRCLEQ_FOREACH(mpc, &mp->childPhdrList, elemChildPhdr) {
+ mpc->phdr.p_offset += size;
+ }
+ CIRCLEQ_FOREACH(ms, &mp->childScnList, elemChildScn) {
+ ms->shdr.sh_offset += size;
+ }
+ }
+ }
+
+ CIRCLEQ_FOREACH(ms, &me->orphanScnList, elemChildScn) {
+ if (ms->shdr.sh_offset >= offset) {
+ ms->shdr.sh_offset += size;
+ }
+ }
+
+ if (me->ehdr.e_phoff >= offset) {
+ me->ehdr.e_phoff += size;
+ }
+
+ if (me->ehdr.e_shoff >= offset) {
+ me->ehdr.e_shoff += size;
+ }
+
+ return size;
}
-static ElfuScn* insertSection(ElfuElf *me, ElfuElf *mrel, ElfuScn *ms)
+/* Finds a suitable PHDR to insert a hole into and expands it
+ * if necessary.
+ * Returns memory address the hole will be mapped to, or 0 if
+ * the operation failed. */
+static GElf_Addr getSpaceInPhdr(ElfuElf *me, GElf_Word size,
+ GElf_Word align, int w, int x,
+ ElfuPhdr **injPhdr)
{
- ElfuPhdr *mp;
ElfuPhdr *first = NULL;
ElfuPhdr *last = NULL;
- ElfuScn *newscn = NULL;
- ElfuPhdr *injAnchor;
- int searchForCode = 0;
-
- switch (destsegment(ms)) {
- case DS_TEXT:
- searchForCode = 1;
- case DS_DATA:
- newscn = elfu_mCloneScn(ms);
- if (!newscn) {
- return NULL;
- }
+ ElfuPhdr *mp;
- /* Find first and last LOAD PHDRs. */
- CIRCLEQ_FOREACH(mp, &me->phdrList, elem) {
- if (mp->phdr.p_type != PT_LOAD) {
- continue;
- }
+ assert(!(w && x));
- if (!first || mp->phdr.p_vaddr < first->phdr.p_vaddr) {
- first = mp;
- }
- if (!last || mp->phdr.p_vaddr > last->phdr.p_vaddr) {
- /* No need to check p_memsz as segments may not overlap in memory. */
- last = mp;
+ /* Find first and last LOAD PHDRs.
+ * Don't compare p_memsz - segments don't overlap in memory. */
+ CIRCLEQ_FOREACH(mp, &me->phdrList, elem) {
+ if (mp->phdr.p_type != PT_LOAD) {
+ continue;
+ }
+ if (!first || mp->phdr.p_vaddr < first->phdr.p_vaddr) {
+ first = mp;
+ }
+ if (!last || mp->phdr.p_vaddr > last->phdr.p_vaddr) {
+ last = mp;
+ }
+ }
+
+ if ((w && (last->phdr.p_flags & PF_W))
+ || (x && (last->phdr.p_flags & PF_X))) {
+ /* Need to append. */
+ GElf_Off injOffset = OFFS_END(last->phdr.p_offset, last->phdr.p_filesz);
+ GElf_Word injSpace = 0;
+ GElf_Word nobitsize = last->phdr.p_memsz - last->phdr.p_filesz;
+
+ /* Expand NOBITS if any */
+ if (nobitsize > 0) {
+ GElf_Off endOff = OFFS_END(last->phdr.p_offset, last->phdr.p_filesz);
+ GElf_Off endAddr = OFFS_END(last->phdr.p_vaddr, last->phdr.p_filesz);
+ ElfuScn *ms;
+
+ ELFU_INFO("Expanding NOBITS at address 0x%jx...\n", endAddr);
+
+ CIRCLEQ_FOREACH(ms, &last->childScnList, elemChildScn) {
+ if (ms->shdr.sh_offset == endOff) {
+ assert(ms->shdr.sh_type == SHT_NOBITS);
+ assert(ms->shdr.sh_size == nobitsize);
+ ms->data.d_buf = malloc(ms->shdr.sh_size);
+ memset(ms->data.d_buf, '\0', ms->shdr.sh_size);
+ if (!ms->data.d_buf) {
+ ELFU_WARN("mExpandNobits: Could not allocate %jd bytes for NOBITS expansion. Data may be inconsistent.\n", ms->shdr.sh_size);
+ assert(0);
+ goto ERROR;
+ }
+
+ ms->data.d_align = 1;
+ ms->data.d_off = 0;
+ ms->data.d_type = ELF_T_BYTE;
+ ms->data.d_size = ms->shdr.sh_size;
+ ms->data.d_version = elf_version(EV_NONE);
+
+ ms->shdr.sh_type = SHT_PROGBITS;
+ ms->shdr.sh_addr = endAddr;
}
}
- if (searchForCode) {
- if ((first->phdr.p_flags & PF_X) && !(first->phdr.p_flags & PF_W)) {
- injAnchor = first;
- } else if ((last->phdr.p_flags & PF_X) && !(last->phdr.p_flags & PF_W)) {
- injAnchor = last;
- } else {
- injAnchor = NULL;
- }
- } else {
- if ((first->phdr.p_flags & PF_W) && !(first->phdr.p_flags & PF_X)) {
- injAnchor = first;
- } else if ((last->phdr.p_flags & PF_W) && !(last->phdr.p_flags & PF_X)) {
- injAnchor = last;
- } else {
- injAnchor = NULL;
- }
+ injSpace += makeSpaceAtOffset(me, endOff, nobitsize);
+ injSpace -= nobitsize;
+ injOffset += nobitsize;
+ last->phdr.p_filesz += nobitsize;
+ assert(last->phdr.p_filesz == last->phdr.p_memsz);
+ }
+
+ /* Calculate how much space we need, taking alignment into account */
+ size += ROUNDUP(injOffset, align) - injOffset;
+
+ /* If there is not enough space left, create even more. */
+ if (injSpace < size) {
+ injSpace += makeSpaceAtOffset(me, injOffset, size - injSpace);
+ }
+ assert(injSpace >= size);
+
+ /* Remap ourselves */
+ last->phdr.p_filesz += size;
+ last->phdr.p_memsz += size;
+
+ injOffset = ROUNDUP(injOffset, align);
+
+ if (injPhdr) {
+ *injPhdr = last;
+ }
+ return last->phdr.p_vaddr + (injOffset - last->phdr.p_offset);
+ } else if ((w && (first->phdr.p_flags & PF_W))
+ || (x && (first->phdr.p_flags & PF_X))) {
+ /* Need to prepend or split up the PHDR. */
+ GElf_Off injOffset = OFFS_END(first->phdr.p_offset, first->phdr.p_filesz);
+ ElfuScn *ms;
+
+ /* Round up size to take PHDR alignment into account.
+ * We assume that this is a multiple of the alignment asked for. */
+ assert(first->phdr.p_align >= align);
+ size = ROUNDUP(size, first->phdr.p_align);
+
+ /* Find first section. We assume there is at least one. */
+ assert(!CIRCLEQ_EMPTY(&first->childScnList));
+ injOffset = CIRCLEQ_FIRST(&first->childScnList)->shdr.sh_offset;
+
+ /* Move our sections */
+ CIRCLEQ_FOREACH(ms, &first->childScnList, elemChildScn) {
+ if (ms->shdr.sh_offset >= injOffset) {
+ ms->shdr.sh_offset += size;
}
+ }
- if (!injAnchor) {
- ELFU_WARN("insertSection: Could not find injection anchor.\n"
- " It has to be the first or last segment in the memory image.\n");
+ /* Move our PHDRs */
+ CIRCLEQ_FOREACH(mp, &first->childPhdrList, elemChildPhdr) {
+ if (mp->phdr.p_offset >= injOffset) {
+ mp->phdr.p_offset += size;
} else {
- GElf_Off injOffset;
-
- /* If the anchor is first or last, insert before or after */
- if (injAnchor == first) {
- /* Find first section and inject before it */
- ElfuScn *firstScn = elfu_mScnFirstInSegment(me, injAnchor);
- if (!firstScn) {
- ELFU_WARN("insertSection: mScnFirstInSegment failed.\n");
+ mp->phdr.p_vaddr -= size;
+ mp->phdr.p_paddr -= size;
+ }
+ }
- // TODO: Error handling
- } else {
- injOffset = firstScn->shdr.sh_offset;
+ /* Move other PHDRs and sections */
+ assert(size <= makeSpaceAtOffset(me, injOffset, size));
- ELFU_INFO("Inserting %s at offset 0x%jx...\n",
- elfu_mScnName(mrel, ms),
- injOffset);
+ /* Remap ourselves */
+ first->phdr.p_vaddr -= size;
+ first->phdr.p_paddr -= size;
+ first->phdr.p_filesz += size;
+ first->phdr.p_memsz += size;
- /* Make space */
- elfu_mInsertSpaceBefore(me, injOffset, ms->shdr.sh_size);
+ injOffset = ROUNDUP(injOffset, align);
- /* Update memory offset */
- newscn->shdr.sh_addr = injAnchor->phdr.p_vaddr;
+ if (injPhdr) {
+ *injPhdr = first;
+ }
+ return first->phdr.p_vaddr + (injOffset - first->phdr.p_offset);
+ }
- /* Insert into chain of sections */
- elfu_mInsertScnInChainBefore(me, firstScn, newscn);
- }
- } else {
- /* Find last section and inject after it */
- ElfuScn *lastScn = elfu_mScnLastInSegment(me, injAnchor);
- if (!lastScn) {
- ELFU_WARN("insertSection: mScnLastInSegment failed.\n");
+ ERROR:
+ if (injPhdr) {
+ *injPhdr = NULL;
+ }
+ return 0;
+}
- // TODO: Error handling
- } else {
- injOffset = lastScn->shdr.sh_offset + SCNFILESIZE(&lastScn->shdr);
- ELFU_INFO("Expanding at offset 0x%jx...\n",
- injOffset);
- /* Expand NOBITS sections at injection site, if any. */
- elfu_mExpandNobits(me, injOffset);
- /* Recalculate injOffset in case we expanded a NOBITS section */
- lastScn = elfu_mScnLastInSegment(me, injAnchor);
- injOffset = lastScn->shdr.sh_offset + SCNFILESIZE(&lastScn->shdr);
+static ElfuScn* insertSection(ElfuElf *me, ElfuElf *mrel, ElfuScn *oldscn)
+{
+ ElfuScn *newscn = NULL;
+ GElf_Addr injAddr;
+ GElf_Off injOffset;
+ ElfuPhdr *injPhdr;
- ELFU_INFO("Inserting %s at offset 0x%jx...\n",
- elfu_mScnName(mrel, ms),
- injOffset);
+ if (oldscn->shdr.sh_flags & SHF_ALLOC) {
+ newscn = elfu_mCloneScn(oldscn);
+ if (!newscn) {
+ return NULL;
+ }
- /* Make space */
- elfu_mInsertSpaceAfter(me, injOffset, ms->shdr.sh_size);
- /* Update memory offset */
- newscn->shdr.sh_addr = injAnchor->phdr.p_vaddr + (injOffset - injAnchor->phdr.p_offset);
+ injAddr = getSpaceInPhdr(me, newscn->shdr.sh_size,
+ newscn->shdr.sh_addralign,
+ newscn->shdr.sh_flags & SHF_WRITE,
+ newscn->shdr.sh_flags & SHF_EXECINSTR,
+ &injPhdr);
- /* Insert into chain of sections */
- elfu_mInsertScnInChainAfter(me, lastScn, newscn);
- }
- }
+ if (!injPhdr) {
+ ELFU_WARN("insertSection: Could not find a place to insert section.\n");
+ goto ERROR;
+ }
- /* Update file offset in new section BEFORE we do anything else */
- newscn->shdr.sh_offset = injOffset;
+ ELFU_INFO("Inserting %s at address 0x%jx...\n",
+ elfu_mScnName(mrel, oldscn),
+ injAddr);
- /* Inject name */
- // TODO
- newscn->shdr.sh_name = 0;
+ injOffset = injAddr - injPhdr->phdr.p_vaddr + injPhdr->phdr.p_offset;
- // TODO: Relocate
+ newscn->shdr.sh_addr = injAddr;
+ newscn->shdr.sh_offset = injOffset;
- return newscn;
+ if (CIRCLEQ_EMPTY(&injPhdr->childScnList)
+ || CIRCLEQ_LAST(&injPhdr->childScnList)->shdr.sh_offset < injOffset) {
+ CIRCLEQ_INSERT_TAIL(&injPhdr->childScnList, newscn, elemChildScn);
+ } else {
+ ElfuScn *ms;
+ CIRCLEQ_FOREACH(ms, &injPhdr->childScnList, elemChildScn) {
+ if (injOffset < ms->shdr.sh_offset) {
+ CIRCLEQ_INSERT_BEFORE(&injPhdr->childScnList, ms, newscn, elemChildScn);
+ break;
+ }
}
- break;
+ }
- case DS_UNKNOWN:
- ELFU_WARN("insertSection: Don't know where to insert ' %s with flags %jd (type %d).\n",
- elfu_mScnName(mrel, ms),
- ms->shdr.sh_flags,
- ms->shdr.sh_type);
- default:
+ /* Inject name */
+ // TODO
+ newscn->shdr.sh_name = 0;
+
+ // TODO: Relocate
+
+ return newscn;
+ } else {
ELFU_WARN("insertSection: Skipping section %s with flags %jd (type %d).\n",
- elfu_mScnName(mrel, ms),
- ms->shdr.sh_flags,
- ms->shdr.sh_type);
- return NULL;
+ elfu_mScnName(mrel, oldscn),
+ oldscn->shdr.sh_flags,
+ oldscn->shdr.sh_type);
+ goto ERROR;
}
+ ERROR:
if (newscn) {
// TODO: Destroy newscn
}
@@ -179,66 +294,87 @@ static ElfuScn* insertSection(ElfuElf *me, ElfuElf *mrel, ElfuScn *ms)
}
+int subScnAdd1(ElfuElf *mrel, ElfuScn *ms, void *aux1, void *aux2)
+{
+ (void)aux2;
+ ElfuElf *me = (ElfuElf*)aux1;
-void elfu_mReladd(ElfuElf *me, ElfuElf *mrel)
+ ElfuScn *newscn;
+
+ switch(ms->shdr.sh_type) {
+ case SHT_PROGBITS: /* 1 */
+ /* Find a place where it belongs and shove it in. */
+ newscn = insertSection(me, mrel, ms);
+ if (!newscn) {
+ ELFU_WARN("mReladd: Could not insert section %s (type %d), skipping.\n",
+ elfu_mScnName(mrel, ms),
+ ms->shdr.sh_type);
+ }
+ break;
+ }
+
+ return 0;
+}
+
+
+int subScnAdd2(ElfuElf *mrel, ElfuScn *ms, void *aux1, void *aux2)
{
- ElfuScn *ms;
+ (void)aux2;
+ ElfuElf *me = (ElfuElf*)aux1;
+ (void)me;
+
+ switch(ms->shdr.sh_type) {
+ case SHT_NULL: /* 0 */
+ case SHT_PROGBITS: /* 1 */
+ break;
+ case SHT_SYMTAB: /* 2 */
+ case SHT_DYNSYM: /* 11 */
+ /* Merge with the existing table. Take care of string tables also. */
+
+ case SHT_STRTAB: /* 3 */
+ /* May have to be merged with the existing string table for
+ * the symbol table. */
+
+ case SHT_RELA: /* 4 */
+ case SHT_REL: /* 9 */
+ /* Possibly append this in memory to the section model
+ * that it describes. */
+
+ case SHT_NOBITS: /* 8 */
+ /* Expand this to SHT_PROGBITS, then insert as such. */
+
+ case SHT_HASH: /* 5 */
+ case SHT_DYNAMIC: /* 6 */
+ case SHT_SHLIB: /* 10 */
+ case SHT_SYMTAB_SHNDX: /* 18 */
+
+ /* Don't care about the next ones yet. I've never seen
+ * them and they can be implemented when necessary. */
+ case SHT_NOTE: /* 7 */
+ case SHT_INIT_ARRAY: /* 14 */
+ case SHT_FINI_ARRAY: /* 15 */
+ case SHT_PREINIT_ARRAY: /* 16 */
+ case SHT_GROUP: /* 17 */
+ case SHT_NUM: /* 19 */
+ default:
+ ELFU_WARN("mReladd: Skipping section %s (type %d).\n",
+ elfu_mScnName(mrel, ms),
+ ms->shdr.sh_type);
+ }
+
+ return 0;
+}
+
+
+void elfu_mReladd(ElfuElf *me, ElfuElf *mrel)
+{
assert(me);
assert(mrel);
-
/* For each section in object file, guess how to insert it */
- CIRCLEQ_FOREACH(ms, &mrel->scnList, elem) {
- ElfuScn *newscn;
-
- switch(ms->shdr.sh_type) {
- case SHT_NULL: /* 0 */
- continue;
-
- case SHT_PROGBITS: /* 1 */
- /* Find a place where it belongs and shove it in. */
- newscn = insertSection(me, mrel, ms);
- if (!newscn) {
- ELFU_WARN("mReladd: Could not insert section %s (type %d), skipping.\n",
- elfu_mScnName(mrel, ms),
- ms->shdr.sh_type);
- }
- break;
-
- case SHT_SYMTAB: /* 2 */
- case SHT_DYNSYM: /* 11 */
- /* Merge with the existing table. Take care of string tables also. */
-
- case SHT_STRTAB: /* 3 */
- /* May have to be merged with the existing string table for
- * the symbol table. */
-
- case SHT_RELA: /* 4 */
- case SHT_REL: /* 9 */
- /* Possibly append this in memory to the section model
- * that it describes. */
-
- case SHT_NOBITS: /* 8 */
- /* Expand this to SHT_PROGBITS, then insert as such. */
-
- case SHT_HASH: /* 5 */
- case SHT_DYNAMIC: /* 6 */
- case SHT_SHLIB: /* 10 */
- case SHT_SYMTAB_SHNDX: /* 18 */
-
- /* Don't care about the next ones yet. I've never seen
- * them and they can be implemented when necessary. */
- case SHT_NOTE: /* 7 */
- case SHT_INIT_ARRAY: /* 14 */
- case SHT_FINI_ARRAY: /* 15 */
- case SHT_PREINIT_ARRAY: /* 16 */
- case SHT_GROUP: /* 17 */
- case SHT_NUM: /* 19 */
- default:
- ELFU_WARN("mReladd: Skipping section %s (type %d).\n",
- elfu_mScnName(mrel, ms),
- ms->shdr.sh_type);
- }
- }
+ elfu_mScnForall(mrel, subScnAdd1, me, NULL);
+
+ /* Do relocations and other stuff */
+ elfu_mScnForall(mrel, subScnAdd2, me, NULL);
}
diff --git a/src/model/section-by-type.c b/src/model/section-by-type.c
deleted file mode 100644
index e36865a..0000000
--- a/src/model/section-by-type.c
+++ /dev/null
@@ -1,22 +0,0 @@
-#include <assert.h>
-#include <libelf/gelf.h>
-#include <libelfu/libelfu.h>
-
-
-/*
- * Returns the first section with the given type.
- */
-ElfuScn* elfu_mScnByType(ElfuElf *me, Elf32_Word type)
-{
- ElfuScn *ms;
-
- assert(me);
-
- CIRCLEQ_FOREACH(ms, &me->scnList, elem) {
- if (ms->shdr.sh_type == type) {
- return ms;
- }
- }
-
- return NULL;
-}
diff --git a/src/model/section-in-segment.c b/src/model/section-in-segment.c
deleted file mode 100644
index 0e513e2..0000000
--- a/src/model/section-in-segment.c
+++ /dev/null
@@ -1,56 +0,0 @@
-#include <assert.h>
-#include <libelf/gelf.h>
-#include <libelfu/libelfu.h>
-
-
-/*
- * Returns the first section beginning in the segment.
- *
- * Since sections have to be in the file in mapping order to load them
- * as a continuous segment, we only have to search by start offset.
- */
-ElfuScn* elfu_mScnFirstInSegment(ElfuElf *me, ElfuPhdr *mp)
-{
- ElfuScn *ms;
-
- assert(me);
- assert(mp);
-
- CIRCLEQ_FOREACH(ms, &me->scnList, elem) {
- if ((ms->shdr.sh_offset >= mp->phdr.p_offset)
- && (ms->shdr.sh_offset < mp->phdr.p_offset + mp->phdr.p_filesz)) {
- return ms;
- }
- }
-
- return NULL;
-}
-
-
-
-/*
- * Returns the last section ending in the segment.
- *
- * Since sections have to be in the file in mapping order to load them
- * as a continuous segment, we only have to search by end offset.
- */
-ElfuScn* elfu_mScnLastInSegment(ElfuElf *me, ElfuPhdr *mp)
-{
- ElfuScn *last = NULL;
- ElfuScn *ms;
-
- assert(me);
- assert(mp);
-
- CIRCLEQ_FOREACH(ms, &me->scnList, elem) {
- /* Get section size on disk - for NOBITS sections that is 0 bytes. */
- size_t size = SCNFILESIZE(&ms->shdr);
-
- if (((ms->shdr.sh_offset + size >= mp->phdr.p_offset)
- && (ms->shdr.sh_offset + size <= mp->phdr.p_offset + mp->phdr.p_filesz))) {
- last = ms;
- }
- }
-
- return last;
-}
diff --git a/src/model/section-name.c b/src/model/section-name.c
deleted file mode 100644
index 68d9986..0000000
--- a/src/model/section-name.c
+++ /dev/null
@@ -1,23 +0,0 @@
-#include <assert.h>
-#include <stdlib.h>
-#include <libelf/libelf.h>
-#include <libelf/gelf.h>
-#include <libelfu/libelfu.h>
-
-
-
-char* elfu_mScnName(ElfuElf *me, ElfuScn *ms)
-{
- assert(me);
- assert(ms);
-
- if (!me->shstrtab) {
- return NULL;
- }
-
- if (!me->shstrtab->data.d_buf) {
- return NULL;
- }
-
- return &((char*)me->shstrtab->data.d_buf)[ms->shdr.sh_name];
-}
diff --git a/src/model/section.c b/src/model/section.c
new file mode 100644
index 0000000..d7ddc19
--- /dev/null
+++ b/src/model/section.c
@@ -0,0 +1,170 @@
+#include <assert.h>
+#include <stdlib.h>
+#include <libelf/libelf.h>
+#include <libelf/gelf.h>
+#include <libelfu/libelfu.h>
+
+
+/* Meta-functions */
+
+int elfu_mScnForall(ElfuElf *me, SectionHandlerFunc f, void *aux1, void *aux2)
+{
+ ElfuPhdr *mp;
+ ElfuScn *ms;
+
+ // TODO: Sort PHDRs by offset before interating
+
+ CIRCLEQ_FOREACH(mp, &me->phdrList, elem) {
+ if (mp->phdr.p_type != PT_LOAD) {
+ continue;
+ }
+
+ CIRCLEQ_FOREACH(ms, &mp->childScnList, elemChildScn) {
+ int rv = f(me, ms, aux1, aux2);
+
+ if (rv) {
+ return rv;
+ }
+ }
+ }
+
+ CIRCLEQ_FOREACH(ms, &me->orphanScnList, elemChildScn) {
+ int rv = f(me, ms, aux1, aux2);
+
+ if (rv) {
+ return rv;
+ }
+ }
+
+ return 0;
+}
+
+
+
+
+/* Counting */
+
+static int subCounter(ElfuElf *me, ElfuScn *ms, void *aux1, void *aux2)
+{
+ size_t *i = (size_t*)aux1;
+ ElfuScn *otherScn = (ElfuScn*)aux2;
+
+ if (ms == otherScn) {
+ return 1;
+ }
+
+ *i += 1;
+
+ return 0;
+}
+
+
+size_t elfu_mScnCount(ElfuElf *me)
+{
+ /* NULL section *is not* counted */
+ size_t i = 0;
+
+ assert(me);
+
+ elfu_mScnForall(me, subCounter, &i, NULL);
+
+ return i;
+}
+
+
+/* Returns the section index equivalent to the model flattened to ELF */
+size_t elfu_mScnIndex(ElfuElf *me, ElfuScn *ms)
+{
+ /* NULL section *is* counted */
+ size_t i = 1;
+
+ assert(me);
+ assert(ms);
+
+ elfu_mScnForall(me, subCounter, &i, ms);
+
+ /* If this assertion is broken then ms is not a section in me. */
+ assert(i <= elfu_mScnCount(me));
+ return i;
+}
+
+
+
+
+/* Convenience */
+
+char* elfu_mScnName(ElfuElf *me, ElfuScn *ms)
+{
+ assert(me);
+ assert(ms);
+
+ if (!me->shstrtab) {
+ return NULL;
+ }
+
+ if (!me->shstrtab->data.d_buf) {
+ return NULL;
+ }
+
+ return &((char*)me->shstrtab->data.d_buf)[ms->shdr.sh_name];
+}
+
+
+static int subScnsToArray(ElfuElf *me, ElfuScn *ms, void *aux1, void *aux2)
+{
+ ElfuScn **arr = (ElfuScn**)aux1;
+ size_t *i = (size_t*)aux2;
+
+ arr[(*i)] = ms;
+ *i += 1;
+
+ return 0;
+}
+
+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;
+ }
+}
+
+ElfuScn** elfu_mScnSortedByOffset(ElfuElf *me, size_t *count)
+{
+ assert(me);
+
+ size_t numSecs;
+ ElfuScn **sortedSecs;
+ size_t i;
+
+ /* Sort sections by offset in file */
+ numSecs = elfu_mScnCount(me);
+ sortedSecs = malloc(numSecs * sizeof(*sortedSecs));
+ if (!sortedSecs) {
+ ELFU_WARN("elfu_mScnSortedByOffset: Failed to allocate memory.\n");
+ return NULL;
+ }
+
+ i = 0;
+ elfu_mScnForall(me, subScnsToArray, sortedSecs, &i);
+ assert(i == numSecs);
+
+ qsort(sortedSecs, numSecs, sizeof(*sortedSecs), cmpScnOffs);
+
+ *count = numSecs;
+
+ return sortedSecs;
+}
diff --git a/src/model/toFile.c b/src/model/toFile.c
index 729a60e..9410f13 100644
--- a/src/model/toFile.c
+++ b/src/model/toFile.c
@@ -33,18 +33,27 @@ static void modelToPhdrs(ElfuElf *me, Elf *e)
-static void modelToSection(ElfuScn *ms, Elf *e)
+static int modelToSection(ElfuElf *me, ElfuScn *ms, void *aux1, void *aux2)
{
+ (void) me;
+ (void) aux2;
+ Elf *e = (Elf*)aux1;
Elf_Scn *scnOut;
scnOut = elf_newscn(e);
if (!scnOut) {
ELFU_WARNELF("elf_newscn");
- return;
+ return 1;
}
/* SHDR */
+ if (ms->linkptr) {
+ ms->shdr.sh_link = elfu_mScnIndex(me, ms->linkptr);
+ }
+ if (ms->infoptr) {
+ ms->shdr.sh_info = elfu_mScnIndex(me, ms->infoptr);
+ }
if (!gelf_update_shdr(scnOut, &ms->shdr)) {
ELFU_WARNELF("gelf_update_shdr");
}
@@ -64,6 +73,8 @@ static void modelToSection(ElfuScn *ms, Elf *e)
dataOut->d_size = ms->data.d_size;
dataOut->d_version = ms->data.d_version;
}
+
+ return 0;
}
@@ -72,10 +83,11 @@ static void modelToSection(ElfuScn *ms, Elf *e)
void elfu_mToElf(ElfuElf *me, Elf *e)
{
- ElfuScn *ms;
-
/* We control the ELF file's layout now. */
- /* tired's libelf also offers ELF_F_LAYOUT_OVERLAP for overlapping sections. */
+ /* tired's libelf also offers ELF_F_LAYOUT_OVERLAP for overlapping sections,
+ * but we don't want that since we filtered it out in the reading stage
+ * already. It would be too mind-blowing to handle the dependencies between
+ * the PHDRs and sections then... */
elf_flagelf(e, ELF_C_SET, ELF_F_LAYOUT);
@@ -84,15 +96,17 @@ void elfu_mToElf(ElfuElf *me, Elf *e)
ELFU_WARNELF("gelf_newehdr");
}
+ if (me->shstrtab) {
+ me->ehdr.e_shstrndx = elfu_mScnIndex(me, me->shstrtab);
+ }
+
if (!gelf_update_ehdr(e, &me->ehdr)) {
ELFU_WARNELF("gelf_update_ehdr");
}
/* Sections */
- CIRCLEQ_FOREACH(ms, &me->scnList, elem) {
- modelToSection(ms, e);
- }
+ elfu_mScnForall(me, modelToSection, e, NULL);
/* PHDRs */
diff --git a/src/options.c b/src/options.c
index 198f01b..b5018d3 100644
--- a/src/options.c
+++ b/src/options.c
@@ -19,16 +19,16 @@ static void printUsage(char *progname)
// " --print-segments Print program headers\n"
// " --print-sections Print sections\n"
// "\n"
- "Space insertion:\n"
- " off: File offset, not within any structure (headers or sections).\n"
- " sz: A multiple of the maximum alignment of all PHDRs.\n"
- "\n"
- " --expand-nobits off Expand virtual areas (NOBITS sections and similar PHDRs).\n"
- " --insert-before off,sz Insert spacing at given offset,\n"
- " mapping everything before it to lower mem addresses.\n"
- " --insert-after off,sz Insert spacing at given offset,\n"
- " mapping everything after it to higher mem addresses.\n"
- "\n"
+// "Space insertion:\n"
+// " off: File offset, not within any structure (headers or sections).\n"
+// " sz: A multiple of the maximum alignment of all PHDRs.\n"
+// "\n"
+// " --expand-nobits off Expand virtual areas (NOBITS sections and similar PHDRs).\n"
+// " --insert-before off,sz Insert spacing at given offset,\n"
+// " mapping everything before it to lower mem addresses.\n"
+// " --insert-after off,sz Insert spacing at given offset,\n"
+// " mapping everything after it to higher mem addresses.\n"
+// "\n"
"High-level insertion:\n"
" --reladd obj.o Automatically insert object file contents\n"
"\n");