summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorEelco Dolstra <e.dolstra@tudelft.nl>2005-09-30 21:22:27 (GMT)
committerEelco Dolstra <e.dolstra@tudelft.nl>2005-09-30 21:22:27 (GMT)
commit460e117720c847675ebf9574f0e1355c039397f5 (patch)
tree5c172d19adab55a8179790e020694392b9d8cb64 /src
parentab3d0a012c406da8a52ca376bcdd802062d44bc3 (diff)
downloadpatchelf-460e117720c847675ebf9574f0e1355c039397f5.zip
patchelf-460e117720c847675ebf9574f0e1355c039397f5.tar.gz
patchelf-460e117720c847675ebf9574f0e1355c039397f5.tar.bz2
* Refactoring continued: `--set-interpreter' works again.
Diffstat (limited to 'src')
-rw-r--r--src/patchelf.cc140
1 files changed, 91 insertions, 49 deletions
diff --git a/src/patchelf.cc b/src/patchelf.cc
index 9362d5e..ae7de10 100644
--- a/src/patchelf.cc
+++ b/src/patchelf.cc
@@ -30,11 +30,8 @@ static unsigned char * contents = 0;
static Elf32_Ehdr * hdr;
static vector<Elf32_Phdr> phdrs;
static vector<Elf32_Shdr> shdrs;
-static unsigned int freeOffset;
-static unsigned int firstPage;
static bool changed = false;
-static bool rewriteHeaders = false;
typedef string SectionName;
typedef map<SectionName, string> ReplacedSections;
@@ -105,48 +102,39 @@ static unsigned int roundUp(unsigned int n, unsigned int m)
}
-static void shiftFile(unsigned int extraPages)
+static void shiftFile(unsigned int extraPages, Elf32_Addr startPage)
{
- /* Move the entire contents of the file one page further. */
+ /* Move the entire contents of the file `extraPages' pages
+ further. */
unsigned int oldSize = fileSize;
+ unsigned int shift = extraPages * pageSize;
growFile(fileSize + extraPages * pageSize);
memmove(contents + extraPages * pageSize, contents, oldSize);
- memset(contents + sizeof(Elf32_Ehdr), 0, extraPages * pageSize - sizeof(Elf32_Ehdr));
-
- /* Update the ELF header. */
- hdr->e_shoff += extraPages * pageSize;
+ memset(contents + sizeof(Elf32_Ehdr), 0, shift - sizeof(Elf32_Ehdr));
+ /* Adjust the ELF header. */
+ hdr->e_phoff = sizeof(Elf32_Ehdr);
+ hdr->e_shoff += shift;
+
/* Update the offsets in the section headers. */
- int i;
- for (i = 0; i < hdr->e_shnum; ++i) {
- shdrs[i].sh_offset += extraPages * pageSize;
- }
+ for (int i = 0; i < hdr->e_shnum; ++i)
+ shdrs[i].sh_offset += shift;
/* Update the offsets in the program headers. */
- for (i = 0; i < hdr->e_phnum; ++i) {
- phdrs[i].p_offset += extraPages * pageSize;
- }
+ for (int i = 0; i < hdr->e_phnum; ++i)
+ phdrs[i].p_offset += shift;
/* Add a segment that maps the new program/section headers and
- PT_INTERP segment into memory. Otherwise glibc will choke. Add
- this after the PT_PHDR segment but before all other PT_LOAD
- segments. */
+ PT_INTERP segment into memory. Otherwise glibc will choke. */
phdrs.resize(hdr->e_phnum + 1);
- for (i = hdr->e_phnum; i > 1; --i)
- phdrs[i] = phdrs[i - 1];
hdr->e_phnum++;
- Elf32_Phdr & phdr = phdrs[1];
+ Elf32_Phdr & phdr = phdrs[hdr->e_phnum - 1];
phdr.p_type = PT_LOAD;
phdr.p_offset = 0;
- firstPage = 0x08047000; /* !!! */
- phdr.p_vaddr = phdr.p_paddr = firstPage;
- phdr.p_filesz = phdr.p_memsz = extraPages * pageSize;
+ phdr.p_vaddr = phdr.p_paddr = startPage;
+ phdr.p_filesz = phdr.p_memsz = shift;
phdr.p_flags = PF_R;
phdr.p_align = 4096;
-
- freeOffset = sizeof(Elf32_Ehdr);
-
- rewriteHeaders = true;
}
@@ -200,6 +188,7 @@ static void rewriteSections()
fprintf(stderr, "replacing section `%s' with size `%d', content `%s'\n",
i->first.c_str(), i->second.size(), i->second.c_str());
+
/* What is the index of the last replaced section? */
unsigned int lastReplaced = 0;
for (unsigned int i = 1; i < hdr->e_shnum; ++i) {
@@ -220,13 +209,15 @@ static void rewriteSections()
since that would invalidate absolute references to them. */
assert(lastReplaced + 1 < shdrs.size()); /* !!! I'm lazy. */
off_t startOffset = shdrs[lastReplaced + 1].sh_offset;
+ Elf32_Addr startAddr = shdrs[lastReplaced + 1].sh_addr;
for (unsigned int i = 1; i <= lastReplaced; ++i) {
Elf32_Shdr & shdr(shdrs[i]);
string sectionName = getSectionName(shdr);
fprintf(stderr, "looking at section `%s'\n", sectionName.c_str());
if (replacedSections.find(sectionName) != replacedSections.end()) continue;
if (shdr.sh_type == SHT_PROGBITS && sectionName != ".interp") {
- startOffset = shdr.sh_addr;
+ startOffset = shdr.sh_offset;
+ startAddr = shdr.sh_addr;
lastReplaced = i - 1;
break;
} else {
@@ -235,7 +226,9 @@ static void rewriteSections()
}
}
- fprintf(stderr, "first reserved offset is %d\n", startOffset);
+ fprintf(stderr, "first reserved offset/addr is %d/0x%x\n",
+ startOffset, startAddr);
+ Elf32_Addr startPage = startAddr / pageSize * pageSize;
/* Right now we assume that the section headers are somewhere near
the end, which appears to be the case most of the time.
@@ -243,6 +236,7 @@ static void rewriteSections()
sections. !!! Fix this. */
assert(hdr->e_shoff >= startOffset);
+
/* Compute the total space needed for the replaced sections, the
ELF header, and the program headers. */
off_t neededSpace = sizeof(Elf32_Ehdr) + phdrs.size() * sizeof(Elf32_Phdr);
@@ -263,10 +257,63 @@ static void rewriteSections()
unsigned int neededPages = roundUp(neededSpace - startOffset, pageSize) / pageSize;
fprintf(stderr, "needed pages is %d\n", neededPages);
+ if (neededPages * pageSize > startPage)
+ error("virtual address space underrun!");
+ startPage -= neededPages * pageSize;
- shiftFile(neededPages);
-
+ shiftFile(neededPages, startPage);
}
+
+
+ /* Write out the replaced sections. */
+ Elf32_Off curOff = sizeof(Elf32_Ehdr) + phdrs.size() * sizeof(Elf32_Phdr);
+ for (ReplacedSections::iterator i = replacedSections.begin();
+ i != replacedSections.end(); ++i)
+ {
+ fprintf(stderr, "rewriting section `%s' to offset %d\n",
+ i->first.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);
+ 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 synced with it. */
+ for (int j = 0; j < phdrs.size(); ++j)
+ if (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;
+ }
+
+ curOff += roundUp(i->second.size(), 4);
+ }
+
+ assert(curOff == neededSpace);
+
+
+ /* Rewrite the program header table. */
+
+ /* If the is a segment for the program header table, update it.
+ (According to the ELF spec, it must be the first entry.) */
+ if (phdrs[0].p_type == PT_PHDR) {
+ phdrs[0].p_offset = hdr->e_phoff;
+ phdrs[0].p_vaddr = phdrs[0].p_paddr = startPage + hdr->e_phoff;
+ phdrs[0].p_filesz = phdrs[0].p_memsz = phdrs.size() * sizeof(Elf32_Phdr);
+ }
+
+ for (int i = 0; i < phdrs.size(); ++i)
+ * ((Elf32_Phdr *) (contents + hdr->e_phoff) + i) = phdrs[i];
+
+ /* Rewrite the section header table. */
+ assert(hdr->e_shnum == shdrs.size());
+ for (int i = 1; i < hdr->e_shnum; ++i)
+ * ((Elf32_Shdr *) (contents + hdr->e_shoff) + i) = shdrs[i];
}
@@ -515,16 +562,22 @@ static void patchElf()
parseElf();
- /* Do what we're supposed to do. */
+
+ if (printInterpreter) {
+ Elf32_Shdr & shdr = findSection(".interp");
+ string interpreter((char *) contents + shdr.sh_offset, shdr.sh_size);
+ printf("%s\n", interpreter.c_str());
+ }
+
if (newInterpreter != "")
setInterpreter(newInterpreter);
- rewriteSections();
+
+ if (changed){
+ rewriteSections();
- if (changed)
writeFile(fileName, fileMode);
- else
- fprintf(stderr, "nothing changed in `%s'\n", fileName.c_str());
+ }
#if 0
/* Find the next free virtual address page so that we can add
@@ -546,17 +599,6 @@ static void patchElf()
assert(!printInterpreter && !printRPath);
if (rewriteHeaders) {
- /* Rewrite the program header table. */
- hdr->e_phoff = freeOffset;
- freeOffset += hdr->e_phnum * sizeof(Elf32_Phdr);
- assert(phdrs[0].p_type == PT_PHDR);
- phdrs[0].p_offset = hdr->e_phoff;
- phdrs[0].p_vaddr = phdrs[0].p_paddr = firstPage + hdr->e_phoff % 4096;
- phdrs[0].p_filesz = phdrs[0].p_memsz = hdr->e_phnum * sizeof(Elf32_Phdr);
- for (int i = 0; i < hdr->e_phnum; ++i)
- * ((Elf32_Phdr *) (contents + hdr->e_phoff) + i) = phdrs[i];
-
- /* Rewrite the section header table. */
hdr->e_shoff = freeOffset;
freeOffset += hdr->e_shnum * sizeof(Elf32_Shdr);
for (int i = 0; i < hdr->e_shnum; ++i)