diff options
Diffstat (limited to 'trunk/src/space.c')
-rw-r--r-- | trunk/src/space.c | 361 |
1 files changed, 187 insertions, 174 deletions
diff --git a/trunk/src/space.c b/trunk/src/space.c index f92348e..4bd4760 100644 --- a/trunk/src/space.c +++ b/trunk/src/space.c @@ -504,206 +504,219 @@ find_readonly_space (DSO *dso, GElf_Shdr *add, GElf_Ehdr *ehdr, } /* We have to create new PT_LOAD if at all possible. */ - addr = ehdr->e_phoff + (ehdr->e_phnum + 1) * ehdr->e_phentsize; - for (j = 1; j < ehdr->e_shnum; ++j) + for (j = 0; j < ehdr->e_phnum; ++j) + if (phdr[j].p_type == PT_NULL) + break; + + if (j < ehdr->e_phnum) + { + memmove (phdr, &phdr[j + 1], + (ehdr->e_phnum - j - 1) * sizeof (GElf_Phdr)); + ehdr->e_phnum--; + } + else { - if (addr > shdr[j].sh_offset) + addr = ehdr->e_phoff + (ehdr->e_phnum + 1) * ehdr->e_phentsize; + for (j = 1; j < ehdr->e_shnum; ++j) { - GElf_Addr start, addstart, endaddr, *old_addr; - GElf_Addr minsize = ~(GElf_Addr) 0; - int movesec = -1, last, k, e; - - if (ehdr->e_phoff < phdr[i].p_offset - || ehdr->e_phoff + (ehdr->e_phnum + 1) * ehdr->e_phentsize - > phdr[i].p_offset + phdr[i].p_filesz - || ! readonly_is_movable (dso, ehdr, shdr, j) - || shdr[j].sh_addr >= phdr[i].p_vaddr + phdr[i].p_filesz) + if (addr > shdr[j].sh_offset) { - error (0, 0, "%s: No space in ELF segment table to add new ELF segment", - dso->filename); - return 0; - } + GElf_Addr start, addstart, endaddr, *old_addr; + GElf_Addr minsize = ~(GElf_Addr) 0; + int movesec = -1, last, k, e; + + if (ehdr->e_phoff < phdr[i].p_offset + || ehdr->e_phoff + (ehdr->e_phnum + 1) * ehdr->e_phentsize + > phdr[i].p_offset + phdr[i].p_filesz + || ! readonly_is_movable (dso, ehdr, shdr, j) + || shdr[j].sh_addr >= phdr[i].p_vaddr + phdr[i].p_filesz) + { + error (0, 0, "%s: No space in ELF segment table to add new ELF segment", + dso->filename); + return 0; + } - start = phdr[i].p_vaddr - phdr[i].p_offset + ehdr->e_phoff - + (ehdr->e_phnum + 1) * ehdr->e_phentsize; - for (last = 1; last < ehdr->e_shnum; ++last) - if (! readonly_is_movable (dso, ehdr, shdr, last) - || shdr[last].sh_addr >= phdr[i].p_vaddr + phdr[i].p_filesz) - break; - for (j = 1; j < last; ++j) - { - addstart = (start + add->sh_addralign - 1) - & ~(add->sh_addralign - 1); - start = (start + shdr[j].sh_addralign - 1) - & ~(shdr[j].sh_addralign - 1); - endaddr = -1; - if (j + 1 < ehdr->e_shnum) - endaddr = shdr[j + 1].sh_addr; - if (phdr[i].p_vaddr + phdr[i].p_filesz < endaddr) - endaddr = phdr[i].p_vaddr + phdr[i].p_filesz; - - switch (shdr[j].sh_type) + start = phdr[i].p_vaddr - phdr[i].p_offset + ehdr->e_phoff + + (ehdr->e_phnum + 1) * ehdr->e_phentsize; + for (last = 1; last < ehdr->e_shnum; ++last) + if (! readonly_is_movable (dso, ehdr, shdr, last) + || shdr[last].sh_addr >= phdr[i].p_vaddr + phdr[i].p_filesz) + break; + for (j = 1; j < last; ++j) { - case SHT_HASH: - case SHT_GNU_HASH: - case SHT_DYNSYM: - case SHT_STRTAB: - case SHT_GNU_verdef: - case SHT_GNU_verneed: - case SHT_GNU_versym: - case SHT_GNU_LIBLIST: - if (endaddr >= start - && endaddr - start < minsize) - { - minsize = endaddr - start; - movesec = j; - } - if (endaddr > addstart - && endaddr - addstart > add->sh_size - && endaddr - addstart - add->sh_size - < minsize) + addstart = (start + add->sh_addralign - 1) + & ~(add->sh_addralign - 1); + start = (start + shdr[j].sh_addralign - 1) + & ~(shdr[j].sh_addralign - 1); + endaddr = -1; + if (j + 1 < ehdr->e_shnum) + endaddr = shdr[j + 1].sh_addr; + if (phdr[i].p_vaddr + phdr[i].p_filesz < endaddr) + endaddr = phdr[i].p_vaddr + phdr[i].p_filesz; + + switch (shdr[j].sh_type) { - minsize = endaddr - addstart - add->sh_size; - movesec = j; - } - break; - case SHT_REL: - case SHT_RELA: - case SHT_NOTE: - /* Don't allow inserting in between reloc sections - if they are adjacent. Similarly for adjacent - note sections. */ - if (j + 1 < ehdr->e_shnum) - { - if (shdr[j].sh_type == SHT_NOTE) + case SHT_HASH: + case SHT_GNU_HASH: + case SHT_DYNSYM: + case SHT_STRTAB: + case SHT_GNU_verdef: + case SHT_GNU_verneed: + case SHT_GNU_versym: + case SHT_GNU_LIBLIST: + if (endaddr >= start + && endaddr - start < minsize) + { + minsize = endaddr - start; + movesec = j; + } + if (endaddr > addstart + && endaddr - addstart > add->sh_size + && endaddr - addstart - add->sh_size + < minsize) + { + minsize = endaddr - addstart - add->sh_size; + movesec = j; + } + break; + case SHT_REL: + case SHT_RELA: + case SHT_NOTE: + /* Don't allow inserting in between reloc sections + if they are adjacent. Similarly for adjacent + note sections. */ + if (j + 1 < ehdr->e_shnum) { - if (shdr[j + 1].sh_type != SHT_NOTE) + if (shdr[j].sh_type == SHT_NOTE) + { + if (shdr[j + 1].sh_type != SHT_NOTE) + break; + } + else if (shdr[j + 1].sh_type != SHT_REL + && shdr[j + 1].sh_type != SHT_RELA) + { + break; + } + + if ((shdr[j].sh_addr + + ((shdr[j].sh_size + 3) & -4)) + != shdr[j + 1].sh_addr) break; - } - else if (shdr[j + 1].sh_type != SHT_REL - && shdr[j + 1].sh_type != SHT_RELA) - { - break; - } - if ((shdr[j].sh_addr - + ((shdr[j].sh_size + 3) & -4)) - != shdr[j + 1].sh_addr) - break; + start += shdr[j].sh_size; + continue; + } + break; + } - start += shdr[j].sh_size; - continue; - } - break; + if (start + shdr[j].sh_size <= endaddr) + { + movesec = j + 1; + break; + } + start += shdr[j].sh_size; } - if (start + shdr[j].sh_size <= endaddr) + if (movesec == -1) { - movesec = j + 1; - break; + error (0, 0, "%s: No space in ELF segment table to add new ELF segment", + dso->filename); + return 0; } - start += shdr[j].sh_size; - } - if (movesec == -1) - { - error (0, 0, "%s: No space in ELF segment table to add new ELF segment", - dso->filename); - return 0; - } - - start = phdr[i].p_vaddr - phdr[i].p_offset + ehdr->e_phoff - + (ehdr->e_phnum + 1) * ehdr->e_phentsize; - old_addr = (GElf_Addr *) alloca (movesec * sizeof (GElf_Addr)); - for (k = 1; k < movesec; ++k) - { - start = (start + shdr[k].sh_addralign - 1) - & ~(shdr[k].sh_addralign - 1); - old_addr[k] = shdr[k].sh_addr; - shdr[k].sh_addr = start; - shdr[k].sh_offset = start + phdr[i].p_offset - - phdr[i].p_vaddr; - start += shdr[k].sh_size; - } - - for (e = 0; e < ehdr->e_phnum; ++e) - if (phdr[e].p_type != PT_LOAD - && phdr[e].p_type != PT_GNU_STACK) + start = phdr[i].p_vaddr - phdr[i].p_offset + ehdr->e_phoff + + (ehdr->e_phnum + 1) * ehdr->e_phentsize; + old_addr = (GElf_Addr *) alloca (movesec * sizeof (GElf_Addr)); for (k = 1; k < movesec; ++k) - if (old_addr[k] == phdr[e].p_vaddr) - { - if (phdr[e].p_filesz != shdr[k].sh_size - || phdr[e].p_memsz != shdr[k].sh_size) + { + start = (start + shdr[k].sh_addralign - 1) + & ~(shdr[k].sh_addralign - 1); + old_addr[k] = shdr[k].sh_addr; + shdr[k].sh_addr = start; + shdr[k].sh_offset = start + phdr[i].p_offset + - phdr[i].p_vaddr; + start += shdr[k].sh_size; + } + + for (e = 0; e < ehdr->e_phnum; ++e) + if (phdr[e].p_type != PT_LOAD + && phdr[e].p_type != PT_GNU_STACK) + for (k = 1; k < movesec; ++k) + if (old_addr[k] == phdr[e].p_vaddr) { - int k1 = -1; - if (phdr[e].p_type == PT_NOTE - && shdr[k].sh_type == SHT_NOTE - && phdr[e].p_filesz == phdr[e].p_memsz) + if (phdr[e].p_filesz != shdr[k].sh_size + || phdr[e].p_memsz != shdr[k].sh_size) { - k1 = k; - while (k1 < movesec) + int k1 = -1; + if (phdr[e].p_type == PT_NOTE + && shdr[k].sh_type == SHT_NOTE + && phdr[e].p_filesz == phdr[e].p_memsz) { - if (shdr[k1].sh_type != SHT_NOTE - || shdr[k1].sh_addr - old_addr[k1] - != shdr[k].sh_addr - old_addr[k] - || old_addr[k1] + shdr[k1].sh_size - > phdr[e].p_vaddr + phdr[e].p_filesz) + k1 = k; + while (k1 < movesec) { - k1 = -1; - break; + if (shdr[k1].sh_type != SHT_NOTE + || shdr[k1].sh_addr - old_addr[k1] + != shdr[k].sh_addr - old_addr[k] + || old_addr[k1] + shdr[k1].sh_size + > phdr[e].p_vaddr + phdr[e].p_filesz) + { + k1 = -1; + break; + } + if (old_addr[k1] + shdr[k1].sh_size + == phdr[e].p_vaddr + phdr[e].p_filesz) + break; + ++k1; } - if (old_addr[k1] + shdr[k1].sh_size - == phdr[e].p_vaddr + phdr[e].p_filesz) - break; - ++k1; + if (k1 == movesec) + k1 = -1; + } + if (k1 == -1) + { + error (0, 0, "%s: Non-PT_LOAD segment spanning more than one section", + dso->filename); + return 0; } - if (k1 == movesec) - k1 = -1; - } - if (k1 == -1) - { - error (0, 0, "%s: Non-PT_LOAD segment spanning more than one section", - dso->filename); - return 0; } + phdr[e].p_vaddr += shdr[k].sh_addr - old_addr[k]; + phdr[e].p_paddr += shdr[k].sh_addr - old_addr[k]; + phdr[e].p_offset += shdr[k].sh_addr - old_addr[k]; + break; } - phdr[e].p_vaddr += shdr[k].sh_addr - old_addr[k]; - phdr[e].p_paddr += shdr[k].sh_addr - old_addr[k]; - phdr[e].p_offset += shdr[k].sh_addr - old_addr[k]; - break; - } - - if (j < last) - /* Now continue as if there was place for a new PT_LOAD - in ElfW(Phdr) table initially. */ - break; - else - { - GElf_Shdr moveshdr; - int newidx, ret, movedidx, oldidx; - - moveshdr = shdr[movesec]; - newidx = remove_readonly_section (ehdr, shdr, movesec, adjust); - oldidx = adjust->move->new_to_old[movesec]; - remove_section (adjust->move, movesec); - ret = find_readonly_space (dso, add, ehdr, phdr, shdr, adjust); - if (ret == 0) - return 0; - movedidx = find_readonly_space (dso, &moveshdr, ehdr, phdr, - shdr, adjust); - if (movedidx == 0) - return 0; - if (newidx != -1) - adjust->new[newidx] = movedidx; - add_section (adjust->move, movedidx); - if (oldidx != -1) + + if (j < last) + /* Now continue as if there was place for a new PT_LOAD + in ElfW(Phdr) table initially. */ + break; + else { - adjust->move->old_to_new[oldidx] = movedidx; - adjust->move->new_to_old[movedidx] = oldidx; + GElf_Shdr moveshdr; + int newidx, ret, movedidx, oldidx; + + moveshdr = shdr[movesec]; + newidx = remove_readonly_section (ehdr, shdr, movesec, adjust); + oldidx = adjust->move->new_to_old[movesec]; + remove_section (adjust->move, movesec); + ret = find_readonly_space (dso, add, ehdr, phdr, shdr, adjust); + if (ret == 0) + return 0; + movedidx = find_readonly_space (dso, &moveshdr, ehdr, phdr, + shdr, adjust); + if (movedidx == 0) + return 0; + if (newidx != -1) + adjust->new[newidx] = movedidx; + add_section (adjust->move, movedidx); + if (oldidx != -1) + { + adjust->move->old_to_new[oldidx] = movedidx; + adjust->move->new_to_old[movedidx] = oldidx; + } + if (movedidx <= ret) + ++ret; + return ret; } - if (movedidx <= ret) - ++ret; - return ret; } } } |