summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorEelco Dolstra <e.dolstra@tudelft.nl>2005-10-01 01:05:50 (GMT)
committerEelco Dolstra <e.dolstra@tudelft.nl>2005-10-01 01:05:50 (GMT)
commitdd77b207083013aeed5c62b50ffa99638fb0adf2 (patch)
tree94f6611ac5a47933c646db189f4d0d59620964da /src
parent2369d8b2def0775b0666350fd266bdc0abb07b0d (diff)
downloadpatchelf-dd77b207083013aeed5c62b50ffa99638fb0adf2.zip
patchelf-dd77b207083013aeed5c62b50ffa99638fb0adf2.tar.gz
patchelf-dd77b207083013aeed5c62b50ffa99638fb0adf2.tar.bz2
* Handle the case where no RPATH is present, so the .dynamic table has
to be increased.
Diffstat (limited to 'src')
-rw-r--r--src/patchelf.cc204
1 files changed, 129 insertions, 75 deletions
diff --git a/src/patchelf.cc b/src/patchelf.cc
index f93e89d..760687b 100644
--- a/src/patchelf.cc
+++ b/src/patchelf.cc
@@ -78,6 +78,63 @@ static void readFile(string fileName, mode_t * fileMode)
}
+static void checkPointer(void * p, unsigned int size)
+{
+ unsigned char * q = (unsigned char *) p;
+ assert(q >= contents && q + size <= contents + fileSize);
+}
+
+
+static void parseElf()
+{
+ /* Check the ELF header for basic validity. */
+ if (fileSize < sizeof(Elf32_Ehdr)) error("missing ELF header");
+
+ hdr = (Elf32_Ehdr *) contents;
+
+ if (memcmp(hdr->e_ident, ELFMAG, 4) != 0)
+ error("not an ELF executable");
+
+ if (contents[EI_CLASS] != ELFCLASS32 ||
+ contents[EI_DATA] != ELFDATA2LSB ||
+ contents[EI_VERSION] != EV_CURRENT)
+ error("ELF executable is not 32-bit, little-endian, version 1");
+
+ if (hdr->e_type != ET_EXEC && hdr->e_type != ET_DYN)
+ error("wrong ELF type");
+
+ if (hdr->e_phoff + hdr->e_phnum * hdr->e_phentsize > fileSize)
+ error("missing program headers");
+
+ if (hdr->e_shoff + hdr->e_shnum * hdr->e_shentsize > fileSize)
+ error("missing section headers");
+
+ if (hdr->e_phentsize != sizeof(Elf32_Phdr))
+ error("program headers have wrong size");
+
+ /* Copy the program and section headers. */
+ for (int i = 0; i < hdr->e_phnum; ++i)
+ phdrs.push_back(* ((Elf32_Phdr *) (contents + hdr->e_phoff) + i));
+
+ for (int i = 0; i < hdr->e_shnum; ++i)
+ shdrs.push_back(* ((Elf32_Shdr *) (contents + hdr->e_shoff) + i));
+
+ /* Get the section header string table section (".shstrtab"). Its
+ index in the section header table is given by e_shstrndx field
+ of the ELF header. */
+ unsigned int shstrtabIndex = hdr->e_shstrndx;
+ assert(shstrtabIndex < shdrs.size());
+ unsigned int shstrtabSize = shdrs[shstrtabIndex].sh_size;
+ char * shstrtab = (char * ) contents + shdrs[shstrtabIndex].sh_offset;
+ checkPointer(shstrtab, shstrtabSize);
+
+ assert(shstrtabSize > 0);
+ assert(shstrtab[shstrtabSize - 1] == 0);
+
+ sectionNames = string(shstrtab, shstrtabSize);
+}
+
+
static void writeFile(string fileName, mode_t fileMode)
{
string fileName2 = fileName + "_patchelf_tmp";
@@ -133,18 +190,11 @@ static void shiftFile(unsigned int extraPages, Elf32_Addr startPage)
phdr.p_offset = 0;
phdr.p_vaddr = phdr.p_paddr = startPage;
phdr.p_filesz = phdr.p_memsz = shift;
- phdr.p_flags = PF_R;
+ phdr.p_flags = PF_R | PF_W;
phdr.p_align = 4096;
}
-static void checkPointer(void * p, unsigned int size)
-{
- unsigned char * q = (unsigned char *) p;
- assert(q >= contents && q + size <= contents + fileSize);
-}
-
-
static string getSectionName(const Elf32_Shdr & shdr)
{
return string(sectionNames.c_str() + shdr.sh_name);
@@ -185,8 +235,8 @@ static void rewriteSections()
for (ReplacedSections::iterator i = replacedSections.begin();
i != replacedSections.end(); ++i)
- fprintf(stderr, "replacing section `%s' with size %d, content `%s'\n",
- i->first.c_str(), i->second.size(), i->second.c_str());
+ fprintf(stderr, "replacing section `%s' with size %d\n",
+ i->first.c_str(), i->second.size());
/* What is the index of the last replaced section? */
@@ -215,8 +265,8 @@ static void rewriteSections()
string sectionName = getSectionName(shdr);
fprintf(stderr, "looking at section `%s'\n", sectionName.c_str());
if (replacedSections.find(sectionName) != replacedSections.end()) continue;
- if (true /* XXX shdr.sh_type == SHT_PROGBITS && sectionName !=
- ".interp" */) {
+ //if (shdr.sh_type == SHT_PROGBITS && sectionName != ".interp") {
+ if (true) {
startOffset = shdr.sh_offset;
startAddr = shdr.sh_addr;
lastReplaced = i - 1;
@@ -274,23 +324,24 @@ static void rewriteSections()
/* Write out the replaced sections. */
for (ReplacedSections::iterator i = replacedSections.begin();
- i != replacedSections.end(); ++i)
+ i != replacedSections.end(); )
{
+ string sectionName = i->first;
fprintf(stderr, "rewriting section `%s' to offset %d\n",
- i->first.c_str(), curOff);
+ sectionName.c_str(), curOff);
memcpy(contents + curOff, (unsigned char *) i->second.c_str(),
i->second.size());
/* Update the section header for this section. */
- Elf32_Shdr & shdr = findSection(i->first);
+ Elf32_Shdr & shdr = findSection(sectionName);
shdr.sh_offset = curOff;
shdr.sh_addr = startPage + curOff;
shdr.sh_size = i->second.size();
shdr.sh_addralign = 4;
/* If this is the .interp section, then the PT_INTERP segment
- has to be sync'ed with it. */
- if (i->first == ".interp") {
+ must be sync'ed with it. */
+ if (sectionName == ".interp") {
for (int j = 0; j < phdrs.size(); ++j)
if (phdrs[j].p_type == PT_INTERP) {
phdrs[j].p_offset = shdr.sh_offset;
@@ -299,19 +350,24 @@ static void rewriteSections()
}
}
- /* If this is the .dynstr section, then the .dynamic section
- has to be sync'ed with it. */
- if (i->first == ".dynstr") {
- Elf32_Shdr & shdrDynamic = findSection(".dynamic");
- Elf32_Dyn * dyn = (Elf32_Dyn *) (contents + shdrDynamic.sh_offset);
- for ( ; dyn->d_tag != DT_NULL; dyn++)
- if (dyn->d_tag == DT_STRTAB)
- dyn->d_un.d_ptr = shdr.sh_addr;
+ /* If this is the .dynamic section, then the PT_DYNAMIC segment
+ must be sync'ed with it. */
+ if (sectionName == ".dynamic") {
+ for (int j = 0; j < phdrs.size(); ++j)
+ if (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(), 4);
+
+ ++i;
+ replacedSections.erase(sectionName);
}
+ assert(replacedSections.empty());
assert(curOff == neededSpace);
@@ -332,6 +388,30 @@ static void rewriteSections()
assert(hdr->e_shnum == shdrs.size());
for (int i = 1; i < hdr->e_shnum; ++i)
* ((Elf32_Shdr *) (contents + hdr->e_shoff) + i) = shdrs[i];
+
+ /* Update all those nasty virtual addresses in the .dynamic
+ section. */
+ Elf32_Shdr & shdrDynamic = findSection(".dynamic");
+ Elf32_Dyn * dyn = (Elf32_Dyn *) (contents + shdrDynamic.sh_offset);
+ for ( ; dyn->d_tag != DT_NULL; dyn++)
+ if (dyn->d_tag == DT_STRTAB)
+ dyn->d_un.d_ptr = findSection(".dynstr").sh_addr;
+ else if (dyn->d_tag == DT_STRSZ)
+ dyn->d_un.d_val = findSection(".dynstr").sh_size;
+#if 0
+ else if (dyn->d_tag == DT_SYMTAB)
+ dyn->d_un.d_ptr = findSection(".dynsym").sh_addr;
+ else if (dyn->d_tag == DT_HASH)
+ dyn->d_un.d_ptr = findSection(".hash").sh_addr;
+ else if (dyn->d_tag == DT_JMPREL)
+ dyn->d_un.d_ptr = findSection(".rel.plt").sh_addr;
+ else if (dyn->d_tag == DT_REL)
+ dyn->d_un.d_ptr = findSection(".rel.dyn").sh_addr;
+ else if (dyn->d_tag == DT_VERNEED)
+ dyn->d_un.d_ptr = findSection(".gnu.version_r").sh_addr;
+ else if (dyn->d_tag == DT_VERSYM)
+ dyn->d_un.d_ptr = findSection(".gnu.version").sh_addr;
+#endif
}
@@ -479,58 +559,32 @@ static void modifyRPath(RPathOp op, string newRPath)
setSubstr(newDynStr, shdrDynStr.sh_size, newRPath + '\0');
/* Update the DT_RPATH entry. */
- assert(dynRPath != 0);
- dynRPath->d_un.d_val = shdrDynStr.sh_size;
-}
-
+ if (dynRPath)
+ dynRPath->d_un.d_val = shdrDynStr.sh_size;
-static void parseElf()
-{
- /* Check the ELF header for basic validity. */
- if (fileSize < sizeof(Elf32_Ehdr)) error("missing ELF header");
-
- hdr = (Elf32_Ehdr *) contents;
-
- if (memcmp(hdr->e_ident, ELFMAG, 4) != 0)
- error("not an ELF executable");
+ else {
+ /* There is no DT_RPATH entry in the .dynamic section, so we
+ have to grow the .dynamic section. */
+ string & newDynamic = replaceSection(".dynamic",
+ shdrDynamic.sh_size + sizeof(Elf32_Dyn));
- if (contents[EI_CLASS] != ELFCLASS32 ||
- contents[EI_DATA] != ELFDATA2LSB ||
- contents[EI_VERSION] != EV_CURRENT)
- error("ELF executable is not 32-bit, little-endian, version 1");
+ unsigned int idx = 0;
+ dyn = (Elf32_Dyn *) newDynamic.c_str();
+ for ( ; dyn->d_tag != DT_NULL; dyn++, idx++) ;
- if (hdr->e_type != ET_EXEC && hdr->e_type != ET_DYN)
- error("wrong ELF type");
-
- if (hdr->e_phoff + hdr->e_phnum * hdr->e_phentsize > fileSize)
- error("missing program headers");
-
- if (hdr->e_shoff + hdr->e_shnum * hdr->e_shentsize > fileSize)
- error("missing section headers");
-
- if (hdr->e_phentsize != sizeof(Elf32_Phdr))
- error("program headers have wrong size");
-
- /* Copy the program and section headers. */
- for (int i = 0; i < hdr->e_phnum; ++i)
- phdrs.push_back(* ((Elf32_Phdr *) (contents + hdr->e_phoff) + i));
-
- for (int i = 0; i < hdr->e_shnum; ++i)
- shdrs.push_back(* ((Elf32_Shdr *) (contents + hdr->e_shoff) + i));
-
- /* Get the section header string table section (".shstrtab"). Its
- index in the section header table is given by e_shstrndx field
- of the ELF header. */
- unsigned int shstrtabIndex = hdr->e_shstrndx;
- assert(shstrtabIndex < shdrs.size());
- unsigned int shstrtabSize = shdrs[shstrtabIndex].sh_size;
- char * shstrtab = (char * ) contents + shdrs[shstrtabIndex].sh_offset;
- checkPointer(shstrtab, shstrtabSize);
-
- assert(shstrtabSize > 0);
- assert(shstrtab[shstrtabSize - 1] == 0);
-
- sectionNames = string(shstrtab, shstrtabSize);
+ fprintf(stderr, "DT_NULL index is %d\n", idx);
+
+ Elf32_Dyn newDyn;
+ newDyn.d_tag = DT_RPATH;
+ newDyn.d_un.d_val = shdrDynStr.sh_size;
+ setSubstr(newDynamic, idx * sizeof(Elf32_Dyn),
+ string((char *) &newDyn, sizeof(Elf32_Dyn)));
+
+ newDyn.d_tag = DT_NULL;
+ newDyn.d_un.d_val = 0;
+ setSubstr(newDynamic, (idx + 1) * sizeof(Elf32_Dyn),
+ string((char *) &newDyn, sizeof(Elf32_Dyn)));
+ }
}