X-Git-Url: https://git.enpas.org/?a=blobdiff_plain;f=src%2Fmodel%2Freladd.c;h=ffd02f48e03cddd01d66dca90d68f0e08bcbdbb2;hb=bd748f84aeea9600063bf822312a802bf09d1839;hp=bc13b97b35e355a9a77ac726d75ef784434fdb0a;hpb=d5c411ba043ef62c81e4941990f0625bd3ea3814;p=centaur.git diff --git a/src/model/reladd.c b/src/model/reladd.c index bc13b97..ffd02f4 100644 --- a/src/model/reladd.c +++ b/src/model/reladd.c @@ -6,224 +6,6 @@ #include - -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");