summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorEelco Dolstra <e.dolstra@tudelft.nl>2008-05-28 09:19:49 (GMT)
committerEelco Dolstra <e.dolstra@tudelft.nl>2008-05-28 09:19:49 (GMT)
commit15ba1450c3e9878e6e9aa8dad28a64f39b51bc6c (patch)
tree41e9a0851bcc9a0aacec534b5cbd645aab527be7 /src
parent704c22c6a8fc49a902b3b29636f7b78af97124a6 (diff)
downloadpatchelf-15ba1450c3e9878e6e9aa8dad28a64f39b51bc6c.zip
patchelf-15ba1450c3e9878e6e9aa8dad28a64f39b51bc6c.tar.gz
patchelf-15ba1450c3e9878e6e9aa8dad28a64f39b51bc6c.tar.bz2
* A first attempt at --set-rpath support for libraries. This is very
useful for the NVIDIA libGL.so, since setting an RPATH on libGL.so to include its dependencies (like libXext and libGLcore) makes it unnecessary to set an RPATH on the executables that use it. This is especially important for executables that use RUNPATH (like Wine) since there the paths in RUNPATH are ignored when resolving the dependencies of dependencies (i.e. RUNPATH is scoped).
Diffstat (limited to 'src')
-rw-r--r--src/patchelf.cc173
1 files changed, 170 insertions, 3 deletions
diff --git a/src/patchelf.cc b/src/patchelf.cc
index d8187bb..27e220d 100644
--- a/src/patchelf.cc
+++ b/src/patchelf.cc
@@ -459,10 +459,175 @@ void ElfFile<ElfFileParamNames>::rewriteSections()
unsigned int sectionAlignment = sizeof(Elf_Off);
+ if (!findSection2(".interp")) {
+ debug("no .interp section; this is a dynamic library\n");
+
+
+ /* For dynamic libraries, we just place the replacement
+ sections at the end of the file. They're mapped into
+ memory by a PT_LOAD segment located directly after the last
+ virtual address page of other segments. */
+ Elf_Addr lastPage = 0;
+ for (unsigned int i = 0; i < phdrs.size(); ++i) {
+ Elf_Addr thisPage = roundUp(rdi(phdrs[i].p_vaddr) + rdi(phdrs[i].p_memsz), pageSize);
+ if (thisPage > lastPage) lastPage = thisPage;
+ }
+
+ debug("last page is 0x%llx\n", (unsigned long long) lastPage);
+
+
+ /* Compute the total space needed for the replaced sections
+ and the program headers. */
+ off_t neededSpace = (phdrs.size() + 1) * sizeof(Elf_Phdr);
+ for (ReplacedSections::iterator i = replacedSections.begin();
+ i != replacedSections.end(); ++i)
+ neededSpace += roundUp(i->second.size(), sectionAlignment);
+ debug("needed space is %d\n", neededSpace);
+
+
+ off_t startOffset = roundUp(fileSize, pageSize);
+
+ growFile(startOffset + neededSpace);
+
+
+ /* Add a segment that maps the replaced sections and program
+ headers into memory.. */
+ phdrs.resize(rdi(hdr->e_phnum) + 1);
+ wri(hdr->e_phnum, rdi(hdr->e_phnum) + 1);
+ Elf_Phdr & phdr = phdrs[rdi(hdr->e_phnum) - 1];
+ wri(phdr.p_type, PT_LOAD);
+ wri(phdr.p_offset, startOffset);
+ wri(phdr.p_vaddr, wri(phdr.p_paddr, lastPage));
+ wri(phdr.p_filesz, wri(phdr.p_memsz, neededSpace));
+ wri(phdr.p_flags, PF_R | PF_W);
+ wri(phdr.p_align, 4096);
+
+
+ /* Write out the replaced sections. */
+ off_t curOff = startOffset + phdrs.size() * sizeof(Elf_Phdr);
+ for (ReplacedSections::iterator i = replacedSections.begin();
+ i != replacedSections.end(); )
+ {
+ string sectionName = i->first;
+ Elf_Shdr & shdr = findSection(sectionName);
+ debug("rewriting section `%s' from offset %d to offset %d\n",
+ sectionName.c_str(), rdi(shdr.sh_offset), curOff);
+
+ memset(contents + rdi(shdr.sh_offset), 'X', rdi(shdr.sh_size));
+ memcpy(contents + curOff, (unsigned char *) i->second.c_str(),
+ i->second.size());
+
+ /* Update the section header for this section. */
+ wri(shdr.sh_offset, curOff);
+ wri(shdr.sh_addr, lastPage + (curOff - startOffset));
+ wri(shdr.sh_size, i->second.size());
+ wri(shdr.sh_addralign, sectionAlignment);
+
+ /* If this is the .interp section, then the PT_INTERP segment
+ must be sync'ed with it. */
+ if (sectionName == ".interp") {
+ for (unsigned int j = 0; j < phdrs.size(); ++j)
+ if (rdi(phdrs[j].p_type) == PT_INTERP) {
+ phdrs[j].p_offset = shdr.sh_offset;
+ phdrs[j].p_vaddr = phdrs[j].p_paddr = shdr.sh_addr;
+ phdrs[j].p_filesz = phdrs[j].p_memsz = shdr.sh_size;
+ }
+ }
+
+ /* If this is the .dynamic section, then the PT_DYNAMIC segment
+ must be sync'ed with it. */
+ if (sectionName == ".dynamic") {
+ for (unsigned int j = 0; j < phdrs.size(); ++j)
+ if (rdi(phdrs[j].p_type) == PT_DYNAMIC) {
+ phdrs[j].p_offset = shdr.sh_offset;
+ phdrs[j].p_vaddr = phdrs[j].p_paddr = shdr.sh_addr;
+ phdrs[j].p_filesz = phdrs[j].p_memsz = shdr.sh_size;
+ }
+ }
+
+ curOff += roundUp(i->second.size(), sectionAlignment);
+
+ ++i;
+ replacedSections.erase(sectionName);
+ }
+
+ assert(replacedSections.empty());
+ assert((off_t) curOff == startOffset + neededSpace);
+
+
+ /* !!! cut&paste */
+
+ /* Rewrite the program header table. */
+ wri(hdr->e_phoff, startOffset);
+
+ /* If there is a segment for the program header table, update
+ it. (According to the ELF spec, it must be the first
+ entry.) */
+ if (rdi(phdrs[0].p_type) == PT_PHDR) {
+ phdrs[0].p_offset = hdr->e_phoff;
+ abort();
+ // !!! wri(phdrs[0].p_vaddr, wri(phdrs[0].p_paddr, firstPage + rdi(hdr->e_phoff)));
+ wri(phdrs[0].p_filesz, wri(phdrs[0].p_memsz, phdrs.size() * sizeof(Elf_Phdr)));
+ }
+
+ sortPhdrs();
+
+ for (unsigned int i = 0; i < phdrs.size(); ++i)
+ * ((Elf_Phdr *) (contents + rdi(hdr->e_phoff)) + i) = phdrs[i];
+
+
+ /* Rewrite the section header table. For neatness, keep the
+ sections sorted. */
+ assert(rdi(hdr->e_shnum) == shdrs.size());
+ //sortShdrs(); !!! breaks the library
+ for (unsigned int i = 1; i < rdi(hdr->e_shnum); ++i)
+ * ((Elf_Shdr *) (contents + rdi(hdr->e_shoff)) + i) = shdrs[i];
+
+
+ /* Update all those nasty virtual addresses in the .dynamic
+ section. */
+ Elf_Shdr & shdrDynamic = findSection(".dynamic");
+ Elf_Dyn * dyn = (Elf_Dyn *) (contents + rdi(shdrDynamic.sh_offset));
+ unsigned int d_tag;
+ for ( ; (d_tag = rdi(dyn->d_tag)) != DT_NULL; dyn++)
+ if (d_tag == DT_STRTAB)
+ dyn->d_un.d_ptr = findSection(".dynstr").sh_addr;
+ else if (d_tag == DT_STRSZ)
+ dyn->d_un.d_val = findSection(".dynstr").sh_size;
+ else if (d_tag == DT_SYMTAB)
+ dyn->d_un.d_ptr = findSection(".dynsym").sh_addr;
+ else if (d_tag == DT_HASH)
+ dyn->d_un.d_ptr = findSection(".hash").sh_addr;
+ else if (d_tag == DT_JMPREL) {
+ Elf_Shdr * shdr = findSection2(".rel.plt");
+ if (!shdr) shdr = findSection2(".rela.plt"); /* 64-bit Linux, x86-64 */
+ if (!shdr) shdr = findSection2(".rela.IA_64.pltoff"); /* 64-bit Linux, IA-64 */
+ if (!shdr) error("cannot find section corresponding to DT_JMPREL");
+ dyn->d_un.d_ptr = shdr->sh_addr;
+ }
+ else if (d_tag == DT_REL) { /* !!! hack! */
+ Elf_Shdr * shdr = findSection2(".rel.dyn");
+ /* no idea if this makes sense, but it was needed for some
+ program */
+ if (!shdr) shdr = findSection2(".rel.got");
+ if (!shdr) error("cannot find .rel.dyn or .rel.got");
+ dyn->d_un.d_ptr = shdr->sh_addr;
+ }
+ /* should probably update DT_RELA */
+ else if (d_tag == DT_VERNEED)
+ dyn->d_un.d_ptr = findSection(".gnu.version_r").sh_addr;
+ else if (d_tag == DT_VERSYM)
+ dyn->d_un.d_ptr = findSection(".gnu.version").sh_addr;
+
+
+ return;
+ }
+
+
/* Sort the sections by offset, otherwise we won't correctly find
all the sections before the last replaced section. */
sortShdrs();
-
+
/* What is the index of the last replaced section? */
unsigned int lastReplaced = 0;
@@ -622,6 +787,7 @@ void ElfFile<ElfFileParamNames>::rewriteSections()
for (unsigned int i = 0; i < phdrs.size(); ++i)
* ((Elf_Phdr *) (contents + rdi(hdr->e_phoff)) + i) = phdrs[i];
+
/* Rewrite the section header table. For neatness, keep the
sections sorted. */
assert(rdi(hdr->e_shnum) == shdrs.size());
@@ -629,6 +795,7 @@ void ElfFile<ElfFileParamNames>::rewriteSections()
for (unsigned int i = 1; i < rdi(hdr->e_shnum); ++i)
* ((Elf_Shdr *) (contents + rdi(hdr->e_shoff)) + i) = shdrs[i];
+
/* Update all those nasty virtual addresses in the .dynamic
section. */
Elf_Shdr & shdrDynamic = findSection(".dynamic");
@@ -808,8 +975,8 @@ void ElfFile<ElfFileParamNames>::modifyRPath(RPathOp op, string newRPath)
changed = true;
- /* Zero out the previous rpath to prevent retained
- dependencies in Nix. */
+ /* Zero out the previous rpath to prevent retained dependencies in
+ Nix. */
unsigned int rpathSize = 0;
if (rpath) {
rpathSize = strlen(rpath);