Bug 816494 part 4 - Add a -r option to elfhack that re-merges the split PT_LOADs. r=nfroyd
authorMike Hommey <mh+mozilla@glandium.org>
Mon, 10 Dec 2012 10:33:08 +0100
changeset 124580 0e9bc6febd7f0592e61556235d66caa53ae92ebe
parent 124579 d2ebcd9235d106fd42b5a16a5c866873fe75823e
child 124581 31b16bc75897d91e3ecaeedf3f0a29740192de50
push id2151
push userlsblakk@mozilla.com
push dateTue, 19 Feb 2013 18:06:57 +0000
treeherdermozilla-beta@4952e88741ec [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnfroyd
bugs816494
milestone20.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
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
build/unix/elfhack/elfhack.cpp
build/unix/elfhack/elfxx.h
--- a/build/unix/elfhack/elf.cpp
+++ b/build/unix/elfhack/elf.cpp
@@ -338,16 +338,28 @@ ElfSegment *Elf::getSegmentByType(unsign
     } else
         seg = segments.begin();
     for (; seg != segments.end(); seg++)
         if ((*seg)->getType() == type)
             return *seg;
     return NULL;
 }
 
+void Elf::removeSegment(ElfSegment *segment)
+{
+    if (!segment)
+        return;
+    std::vector<ElfSegment *>::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<ElfSegment *>::iterator seg = segments.begin(); seg != segments.end(); seg++)
         if (((*seg)->getType() == PT_DYNAMIC) && ((*seg)->getFirstSection() != NULL) &&
             (*seg)->getFirstSection()->getType() == SHT_DYNAMIC)
             return (ElfDynamic_Section *)(*seg)->getFirstSection();
 
     return NULL;
@@ -616,16 +628,23 @@ unsigned int ElfSegment::getAddr()
 {
     if ((type == PT_GNU_RELRO) && !sections.empty() &&
         (sections.front()->getAddr() != vaddr))
         throw std::runtime_error("PT_GNU_RELRO segment doesn't start on a section start");
 
     return sections.empty() ? 0 : sections.front()->getAddr();
 }
 
+void ElfSegment::clear()
+{
+    for (std::list<ElfSection *>::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++)
         if (dyns[i].tag == tag)
             return dyns[i].value;
 
     return NULL;
 }
--- a/build/unix/elfhack/elfhack.cpp
+++ b/build/unix/elfhack/elfhack.cpp
@@ -639,28 +639,87 @@ void do_file(const char *name, bool back
         } else {
             std::ofstream ofile(name, std::ios::out|std::ios::binary|std::ios::trunc);
             elf.write(ofile);
             fprintf(stderr, "Reduced by %d bytes\n", size - elf.getSize());
         }
     }
 }
 
+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<ElfSection *>::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]);
     for (arg = 1; arg < argc; arg++) {
         if (strcmp(argv[arg], "-f") == 0)
             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);
     }
 
     free(rundir);
     return 0;
 }
--- a/build/unix/elfhack/elfxx.h
+++ b/build/unix/elfhack/elfxx.h
@@ -283,16 +283,18 @@ public:
     char getMachine();
     unsigned int getSize();
 
     void insertSegmentAfter(ElfSegment *previous, ElfSegment *segment) {
         std::vector<ElfSegment *>::iterator prev = std::find(segments.begin(), segments.end(), previous);
         segments.insert(prev + 1, segment);
     }
 
+    void removeSegment(ElfSegment *segment);
+
 private:
     Elf_Ehdr *ehdr;
     ElfLocation eh_entry;
     ElfStrtab_Section *eh_shstrndx;
     ElfSection **sections;
     std::vector<ElfSegment *> segments;
     ElfSection *shdr_section, *phdr_section;
     /* Values used only during initialization */
@@ -451,16 +453,18 @@ public:
     unsigned int getOffset();
     unsigned int getAddr();
 
     void addSection(ElfSection *section);
     void removeSection(ElfSection *section);
 
     std::list<ElfSection *>::iterator begin() { return sections.begin(); }
     std::list<ElfSection *>::iterator end() { return sections.end(); }
+
+    void clear();
 private:
     unsigned int type;
     int v_p_diff; // Difference between physical and virtual address
     unsigned int flags;
     unsigned int align;
     std::list<ElfSection *> sections;
     // The following are only really used for PT_GNU_RELRO until something
     // better is found.