Loader: Load all segments of an elf, rather than just the "text" and "data".
authorGabe Black <gblack@eecs.umich.edu>
Wed, 26 Sep 2007 03:03:51 +0000 (20:03 -0700)
committerGabe Black <gblack@eecs.umich.edu>
Wed, 26 Sep 2007 03:03:51 +0000 (20:03 -0700)
--HG--
extra : convert_revision : b28bb9ac5cde72878e948d64f629de6e4b42c2e8

src/base/loader/elf_object.cc
src/base/loader/elf_object.hh

index ecce175b2d17faae6da1cc8b322abe918b7aafc4..553723e74286e5ec55caf262207de8f2aa875655 100644 (file)
@@ -216,50 +216,76 @@ ElfObject::ElfObject(const string &_filename, int _fd,
 
     entry = ehdr.e_entry;
 
-
     // initialize segment sizes to 0 in case they're not present
     text.size = data.size = bss.size = 0;
 
+    int secIdx = 1;
+    Elf_Scn *section;
+    GElf_Shdr shdr;
+
+    // The first address of some important sections.
+    Addr textSecStart = 0;
+    Addr dataSecStart = 0;
+    Addr bssSecStart = 0;
+
+    // Get the first section
+    section = elf_getscn(elf, secIdx);
+
+    // Find the beginning of the most interesting sections.
+    while (section != NULL) {
+        gelf_getshdr(section, &shdr);
+        char * secName = elf_strptr(elf, ehdr.e_shstrndx, shdr.sh_name);
+
+        if (!strcmp(".text", secName)) {
+            textSecStart = shdr.sh_addr;
+        } else if (!strcmp(".data", secName)) {
+            dataSecStart = shdr.sh_addr;
+        } else if (!strcmp(".bss", secName)) {
+            bssSecStart = shdr.sh_addr;
+        }
+
+        section = elf_getscn(elf, ++secIdx);
+    }
+
+    // Go through all the segments in the program, record them, and scrape
+    // out information about the text, data, and bss areas needed by other
+    // code.
     for (int i = 0; i < ehdr.e_phnum; ++i) {
         GElf_Phdr phdr;
         if (gelf_getphdr(elf, i, &phdr) == 0) {
-            panic("gelf_getphdr failed for section %d", i);
+            panic("gelf_getphdr failed for segment %d.", i);
         }
 
         // for now we don't care about non-loadable segments
         if (!(phdr.p_type & PT_LOAD))
             continue;
 
-        // the headers don't explicitly distinguish text from data,
-        // but empirically the text segment comes first.
-        if (text.size == 0) {  // haven't seen text segment yet
+        // Check to see if this segment contains the bss section.
+        if (phdr.p_vaddr <= bssSecStart &&
+                phdr.p_vaddr + phdr.p_memsz > bssSecStart &&
+                phdr.p_memsz - phdr.p_filesz > 0) {
+            bss.baseAddr = phdr.p_vaddr + phdr.p_filesz;
+            bss.size = phdr.p_memsz - phdr.p_filesz;
+            bss.fileImage = NULL;
+        }
+
+        // Check to see if this is the text or data segment
+        if (phdr.p_vaddr <= textSecStart &&
+                phdr.p_vaddr + phdr.p_filesz > textSecStart) {
             text.baseAddr = phdr.p_vaddr;
             text.size = phdr.p_filesz;
             text.fileImage = fileData + phdr.p_offset;
-            // if there's any padding at the end that's not in the
-            // file, call it the bss.  This happens in the "text"
-            // segment if there's only one loadable segment (as for
-            // kernel images).
-            bss.size = phdr.p_memsz - phdr.p_filesz;
-            bss.baseAddr = phdr.p_vaddr + phdr.p_filesz;
-            bss.fileImage = NULL;
-        } else if (data.size == 0) { // have text, this must be data
+        } else if (phdr.p_vaddr <= dataSecStart &&
+                phdr.p_vaddr + phdr.p_filesz > dataSecStart) {
             data.baseAddr = phdr.p_vaddr;
             data.size = phdr.p_filesz;
             data.fileImage = fileData + phdr.p_offset;
-            // if there's any padding at the end that's not in the
-            // file, call it the bss.  Warn if this happens for both
-            // the text & data segments (should only have one bss).
-            if (phdr.p_memsz - phdr.p_filesz > 0 && bss.size != 0) {
-                warn("Two implied bss segments in file!\n");
-            }
-            bss.size = phdr.p_memsz - phdr.p_filesz;
-            bss.baseAddr = phdr.p_vaddr + phdr.p_filesz;
-            bss.fileImage = NULL;
         } else {
-            warn("More than two loadable segments in ELF object.");
-            warn("Ignoring segment @ 0x%x length 0x%x.",
-                 phdr.p_vaddr, phdr.p_filesz);
+            Segment extra;
+            extra.baseAddr = phdr.p_vaddr;
+            extra.size = phdr.p_filesz;
+            extra.fileImage = fileData + phdr.p_offset;
+            extraSegments.push_back(extra);
         }
     }
 
@@ -343,6 +369,22 @@ ElfObject::loadLocalSymbols(SymbolTable *symtab, Addr addrMask)
     return loadSomeSymbols(symtab, STB_LOCAL);
 }
 
+bool
+ElfObject::loadSections(Port *memPort, Addr addrMask)
+{
+    if (!ObjectFile::loadSections(memPort, addrMask))
+        return false;
+
+    vector<Segment>::iterator extraIt;
+    for (extraIt = extraSegments.begin();
+            extraIt != extraSegments.end(); extraIt++) {
+        if (!loadSection(&(*extraIt), memPort, addrMask)) {
+            return false;
+        }
+    }
+    return true;
+}
+
 void
 ElfObject::getSections()
 {
index 3e7c85874a681e0b2fb8140fbb72ec6d97107b65..5c5f6907deaddafc5d2735abbdf7463d7fefa76c 100644 (file)
 
 #include "base/loader/object_file.hh"
 #include <set>
+#include <vector>
 
 class ElfObject : public ObjectFile
 {
   protected:
 
+    //The global definition of a "Section" is closest to elf's segments.
+    typedef ObjectFile::Section Segment;
+
     //These values are provided to a linux process by the kernel, so we
     //need to keep them around.
     Addr _programHeaderTable;
@@ -55,9 +59,13 @@ class ElfObject : public ObjectFile
     void getSections();
     bool sectionExists(std::string sec);
 
+    std::vector<Segment> extraSegments;
+
   public:
     virtual ~ElfObject() {}
 
+    bool loadSections(Port *memPort,
+            Addr addrMask = std::numeric_limits<Addr>::max());
     virtual bool loadGlobalSymbols(SymbolTable *symtab, Addr addrMask =
             std::numeric_limits<Addr>::max());
     virtual bool loadLocalSymbols(SymbolTable *symtab, Addr addrMask =