From 943f5b03eb22d65f841478ddde2a4124dda0a541 Mon Sep 17 00:00:00 2001 From: Mike Hommey Date: Mon, 10 Dec 2012 10:33:08 +0100 Subject: [PATCH] Bug 816494 part 4 - Add a -r option to elfhack that re-merges the split PT_LOADs. r=nfroyd Sections are positioned accordingly, which means the resulting ELF binary will have a big gap full of zero between .rel.plt and .plt. --- build/unix/elfhack/elf.cpp | 19 +++++++++++ build/unix/elfhack/elfhack.cpp | 59 ++++++++++++++++++++++++++++++++++ build/unix/elfhack/elfxx.h | 4 +++ 3 files changed, 82 insertions(+) diff --git a/build/unix/elfhack/elf.cpp b/build/unix/elfhack/elf.cpp index 49a838867c21..4ff2445fd0da 100644 --- a/build/unix/elfhack/elf.cpp +++ b/build/unix/elfhack/elf.cpp @@ -343,6 +343,18 @@ ElfSegment *Elf::getSegmentByType(unsigned int type, ElfSegment *last) return NULL; } +void Elf::removeSegment(ElfSegment *segment) +{ + if (!segment) + return; + std::vector::iterator seg; + seg = std::find(segments.begin(), segments.end(), segment); + if (seg == segments.end()) + return; + segment->clear(); + segments.erase(seg); +} + ElfDynamic_Section *Elf::getDynSection() { for (std::vector::iterator seg = segments.begin(); seg != segments.end(); seg++) @@ -621,6 +633,13 @@ unsigned int ElfSegment::getAddr() return sections.empty() ? 0 : sections.front()->getAddr(); } +void ElfSegment::clear() +{ + for (std::list::iterator i = sections.begin(); i != sections.end(); ++i) + (*i)->removeFromSegment(this); + sections.clear(); +} + ElfValue *ElfDynamic_Section::getValueForType(unsigned int tag) { for (unsigned int i = 0; i < shdr.sh_size / shdr.sh_entsize; i++) diff --git a/build/unix/elfhack/elfhack.cpp b/build/unix/elfhack/elfhack.cpp index 4c61b4ea5c17..d54cfacf06d2 100644 --- a/build/unix/elfhack/elfhack.cpp +++ b/build/unix/elfhack/elfhack.cpp @@ -644,11 +644,66 @@ void do_file(const char *name, bool backup = false, bool force = false) } } +void undo_file(const char *name, bool backup = false) +{ + std::ifstream file(name, std::ios::in|std::ios::binary); + Elf elf(file); + unsigned int size = elf.getSize(); + fprintf(stderr, "%s: ", name); + if (elf.getType() != ET_DYN) { + fprintf(stderr, "Not a shared object. Skipping\n"); + return; + } + + ElfSection *data = NULL, *text = NULL; + for (ElfSection *section = elf.getSection(1); section != NULL; + section = section->getNext()) { + if (section->getName() && + (strcmp(section->getName(), elfhack_data) == 0)) + data = section; + if (section->getName() && + (strcmp(section->getName(), elfhack_text) == 0)) + text = section; + } + + if (!data || !text) { + fprintf(stderr, "Not elfhacked. Skipping\n"); + return; + } + if (data != text->getNext()) { + fprintf(stderr, elfhack_data " section not following " elfhack_text ". Skipping\n"); + return; + } + + ElfSegment *first = elf.getSegmentByType(PT_LOAD); + ElfSegment *second = elf.getSegmentByType(PT_LOAD, first); + if (second->getFlags() != first->getFlags()) { + fprintf(stderr, "First two PT_LOAD segments don't have the same flags. Skipping\n"); + return; + } + // Move sections from the second PT_LOAD to the first, and remove the + // second PT_LOAD segment. + for (std::list::iterator section = second->begin(); + section != second->end(); ++section) + first->addSection(*section); + + elf.removeSegment(second); + + if (backup && backup_file(name) != 0) { + fprintf(stderr, "Couln't create backup file\n"); + } else { + std::ofstream ofile(name, std::ios::out|std::ios::binary|std::ios::trunc); + elf.write(ofile); + fprintf(stderr, "Grown by %d bytes\n", elf.getSize() - size); + } +} + int main(int argc, char *argv[]) { int arg; bool backup = false; bool force = false; + bool revert = false; char *lastSlash = rindex(argv[0], '/'); if (lastSlash != NULL) rundir = strndup(argv[0], lastSlash - argv[0]); @@ -657,6 +712,10 @@ int main(int argc, char *argv[]) force = true; else if (strcmp(argv[arg], "-b") == 0) backup = true; + else if (strcmp(argv[arg], "-r") == 0) + revert = true; + else if (revert) + undo_file(argv[arg], backup); else do_file(argv[arg], backup, force); } diff --git a/build/unix/elfhack/elfxx.h b/build/unix/elfhack/elfxx.h index 1bee33eb5e27..5b9951c58a37 100644 --- a/build/unix/elfhack/elfxx.h +++ b/build/unix/elfhack/elfxx.h @@ -288,6 +288,8 @@ public: segments.insert(prev + 1, segment); } + void removeSegment(ElfSegment *segment); + private: Elf_Ehdr *ehdr; ElfLocation eh_entry; @@ -456,6 +458,8 @@ public: std::list::iterator begin() { return sections.begin(); } std::list::iterator end() { return sections.end(); } + + void clear(); private: unsigned int type; int v_p_diff; // Difference between physical and virtual address