From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 22955 invoked by alias); 11 Oct 2007 07:34:48 -0000 Received: (qmail 22945 invoked by uid 22791); 11 Oct 2007 07:34:47 -0000 X-Spam-Status: No, hits=-2.3 required=5.0 tests=AWL,BAYES_00,DK_POLICY_SIGNSOME,FORGED_RCVD_HELO X-Spam-Check-By: sourceware.org Received: from smtp.nildram.co.uk (HELO smtp.nildram.co.uk) (195.112.4.54) by sourceware.org (qpsmtpd/0.31) with ESMTP; Thu, 11 Oct 2007 07:34:44 +0000 Received: from firetop.home (85-211-25-104.dyn.gotadsl.co.uk [85.211.25.104]) by smtp.nildram.co.uk (Postfix) with ESMTP id A53092E0FC7 for ; Thu, 11 Oct 2007 08:34:39 +0100 (BST) Received: from richard by firetop.home with local (Exim 4.63) (envelope-from ) id 1IfsZ6-0007kb-UK for prelink@sourceware.org; Thu, 11 Oct 2007 08:34:40 +0100 From: Richard Sandiford To: prelink@sourceware.org Mail-Followup-To: prelink@sourceware.org, rsandifo@nildram.co.uk Subject: Reuse PT_NULL program headers Date: Thu, 11 Oct 2007 07:34:00 -0000 Message-ID: <87przmdrzj.fsf@firetop.home> User-Agent: Gnus/5.110006 (No Gnus v0.6) Emacs/21.4 (gnu/linux) MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" X-Virus-Checked: Checked by ClamAV on sourceware.org X-IsSubscribed: yes Mailing-List: contact prelink-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Post: List-Help: , Sender: prelink-owner@sourceware.org X-SW-Source: 2007-q4/txt/msg00001.txt.bz2 --=-=-= Content-length: 891 My original binutils patches for MIPS prelink support were against 2.17, and reserved room for a program header without actually creating one. The mainline (now 2.18) binutils patches ended up adding a PT_NULL header instead. This was needed because of mainline's SIZEOF_HEADER relaxation and was probably a better idea anyway. The patch below therefore teaches the prelinker to remove a PT_NULL header if it needs to find room for a PT_LOAD header. Tested on the MIPS port, where it allows a sysroot built with the mainline binutils to be fully prelinked. Also tested on x86. The patch involves a lot of reidentation, so for reference, I've attached two versions: first the real patch, then the -b form. Richard 200x-xx-xx Richard Sandiford * src/space.c (find_readonly_space): If a new PT_LOAD header is needed, first try removing a PT_NULL header. --=-=-= Content-Type: text/x-diff Content-Disposition: attachment; filename=reuse-pt-null.diff Content-length: 9324 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) --=-=-= Content-Type: text/x-diff Content-Disposition: attachment; filename=reuse-pt-null-b.diff Content-length: 750 Index: src/space.c =================================================================== --- src/space.c (revision 159199) +++ src/space.c (working copy) @@ -498,9 +498,20 @@ find_readonly_space (DSO *dso, GElf_Shdr } /* We have to create new PT_LOAD if at all possible. */ + 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 + { 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; --=-=-=--