Index: src/space.c =================================================================== --- src/space.c (revision 150) +++ src/space.c (working copy) @@ -498,153 +498,164 @@ find_readonly_space (DSO *dso, GElf_Shdr } /* 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) { - if (addr > shdr[j].sh_offset) - { - 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) - { - 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; - } + memmove (phdr, &phdr[j + 1], + (ehdr->e_phnum - j - 1) * sizeof (GElf_Phdr)); + ehdr->e_phnum--; + } + else + { + addr = ehdr->e_phoff + (ehdr->e_phnum + 1) * ehdr->e_phentsize; + for (j = 1; j < ehdr->e_shnum; ++j) + if (addr > shdr[j].sh_offset) + { + 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; - if (start + shdr[j].sh_size <= endaddr) - { - movesec = j + 1; - break; - } - 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) - for (k = 1; k < movesec; ++k) - if (old_addr[k] == phdr[e].p_vaddr) + switch (shdr[j].sh_type) { - if (phdr[e].p_filesz != shdr[k].sh_size - || phdr[e].p_memsz != shdr[k].sh_size) + 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) { - error (0, 0, "%s: Non-PT_LOAD segment spanning more than one section", - dso->filename); - return 0; + 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; } - 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) + if (start + shdr[j].sh_size <= endaddr) + { + movesec = j + 1; + break; + } + 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; - 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; - } - } - } + } + + 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) + 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) + { + 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; + } + + 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) + { + adjust->move->old_to_new[oldidx] = movedidx; + adjust->move->new_to_old[movedidx] = oldidx; + } + if (movedidx <= ret) + ++ret; + return ret; + } + } + } for (i = 0, j = 0; i < ehdr->e_phnum; ++i) if (phdr[i].p_type == PT_LOAD)