Pull out existing re-layouting code
[centaur.git] / src / model / reladd.c
index bc13b97b35e355a9a77ac726d75ef784434fdb0a..ffd02f48e03cddd01d66dca90d68f0e08bcbdbb2 100644 (file)
@@ -6,224 +6,6 @@
 #include <libelfu/libelfu.h>
 
 
-
-static GElf_Word makeSpaceAtOffset(ElfuElf *me, GElf_Off offset, GElf_Word size)
-{
-  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;
-      }
-    }
-  }
-
-  CIRCLEQ_FOREACH(ms, &me->orphanScnList, elemChildScn) {
-    if (ms->shdr.sh_offset >= offset) {
-      if (ms->shdr.sh_addralign > align) {
-        align = ms->shdr.sh_addralign;
-      }
-    }
-  }
-
-  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;
-}
-
-
-
-/* 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 *first = NULL;
-  ElfuPhdr *last = NULL;
-  ElfuPhdr *mp;
-
-  assert(!(w && x));
-
-  /* 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;
-        }
-      }
-
-      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;
-      }
-    }
-
-    /* Move our PHDRs */
-    CIRCLEQ_FOREACH(mp, &first->childPhdrList, elemChildPhdr) {
-      if (mp->phdr.p_offset >= injOffset) {
-        mp->phdr.p_offset += size;
-      } else {
-        mp->phdr.p_vaddr -= size;
-        mp->phdr.p_paddr -= size;
-      }
-    }
-
-    /* Move other PHDRs and sections */
-    assert(size <= makeSpaceAtOffset(me, injOffset, size));
-
-    /* Remap ourselves */
-    first->phdr.p_vaddr -= size;
-    first->phdr.p_paddr -= size;
-    first->phdr.p_filesz += size;
-    first->phdr.p_memsz += size;
-
-    injOffset = ROUNDUP(injOffset, align);
-
-    if (injPhdr) {
-      *injPhdr = first;
-    }
-    return first->phdr.p_vaddr + (injOffset - first->phdr.p_offset);
-  }
-
-  ERROR:
-  if (injPhdr) {
-    *injPhdr = NULL;
-  }
-  return 0;
-}
-
-
-
-
 static ElfuScn* insertSection(ElfuElf *me, ElfuElf *mrel, ElfuScn *oldscn)
 {
   ElfuScn *newscn = NULL;
@@ -238,11 +20,12 @@ static ElfuScn* insertSection(ElfuElf *me, ElfuElf *mrel, ElfuScn *oldscn)
     }
 
 
-    injAddr = getSpaceInPhdr(me, newscn->shdr.sh_size,
-                             newscn->shdr.sh_addralign,
-                             newscn->shdr.sh_flags & SHF_WRITE,
-                             newscn->shdr.sh_flags & SHF_EXECINSTR,
-                             &injPhdr);
+    injAddr = elfu_mLayoutGetSpaceInPhdr(me,
+                                         newscn->shdr.sh_size,
+                                         newscn->shdr.sh_addralign,
+                                         newscn->shdr.sh_flags & SHF_WRITE,
+                                         newscn->shdr.sh_flags & SHF_EXECINSTR,
+                                         &injPhdr);
 
     if (!injPhdr) {
       ELFU_WARN("insertSection: Could not find a place to insert section.\n");