arch,base: Restructure the object file loaders.

This change creates a distinction between object files which hold
executable code, and flat files which don't. The first type of files
have entry points, symbols, etc., while the others are just blobs which
can be shoved into memory. Rather than have those aspects but stub
them out, this change creates a new base class which simply doesn't
have them.

This change also restructures the ELF loader since it's main function
was quite long and doing multiple jobs.

It stops passing the architecture and operating system to the
ObjectFile constructor, since those might not be known at the very top
of the constructor. Instead, those default to Uknown*, and then are
filled in in the constructor body if appropriate. This removes a lot
of plumbing that was hard to actually use in practice.

It also introduces a mechanism to collect generic object file formats
so that they can be tried one by one by the general createObjectFile
function, rather than listing them all there one by one. It's unlikely
that new types of object files will need to be added in a modular way
without being able to modify the core loader code, but it's cleaner to
have that abstraction and modularization like is already there for
process loaders.

Finally, to make it possible to share the code which handles zipped
files for both true object files and also files which will be loaded
into memory but are just blobs, that mechanism is pulled out into a
new class called ImageFileData. It holds a collection of segments
which are set up by the object file and may refer to regions of the
original file, buffers maintained elsewhere, or even nothing to support
bss-es. shared_ptr is used to make it easier to keep track of that
information without having to do so explicitly or worry about deleting
a buffer before everyone was done using it.

Change-Id: I92890266f2ba0a703803cccad675a3ab41f2c4af
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/21467
Tested-by: kokoro <noreply+kokoro@google.com>
Reviewed-by: Brandon Potter <Brandon.Potter@amd.com>
Maintainer: Gabe Black <gabeblack@google.com>
diff --git a/src/arch/arm/freebsd/system.cc b/src/arch/arm/freebsd/system.cc
index 106c8e4..3f38f2e 100644
--- a/src/arch/arm/freebsd/system.cc
+++ b/src/arch/arm/freebsd/system.cc
@@ -35,7 +35,7 @@
 #include "arch/arm/isa_traits.hh"
 #include "arch/arm/utility.hh"
 #include "arch/generic/freebsd/threadinfo.hh"
-#include "base/loader/dtb_object.hh"
+#include "base/loader/dtb_file.hh"
 #include "base/loader/object_file.hh"
 #include "base/loader/symtab.hh"
 #include "cpu/base.hh"
@@ -110,25 +110,15 @@
     inform("Loading DTB file: %s at address %#x\n", params()->dtb_filename,
             params()->atags_addr + loadAddrOffset);
 
-    ObjectFile *dtb_file = createObjectFile(params()->dtb_filename, true);
-    if (!dtb_file) {
-        fatal("couldn't load DTB file: %s\n", params()->dtb_filename);
+    DtbFile *dtb_file = new DtbFile(params()->dtb_filename);
+
+    if (!dtb_file->addBootCmdLine(params()->boot_osflags.c_str(),
+                                  params()->boot_osflags.size())) {
+        warn("couldn't append bootargs to DTB file: %s\n",
+             params()->dtb_filename);
     }
 
-    DtbObject *_dtb_file = dynamic_cast<DtbObject*>(dtb_file);
-
-    if (_dtb_file) {
-        if (!_dtb_file->addBootCmdLine(params()->boot_osflags.c_str(),
-                                       params()->boot_osflags.size())) {
-            warn("couldn't append bootargs to DTB file: %s\n",
-                 params()->dtb_filename);
-        }
-    } else {
-        warn("dtb_file cast failed; couldn't append bootargs "
-             "to DTB file: %s\n", params()->dtb_filename);
-    }
-
-    Addr ra = _dtb_file->findReleaseAddr();
+    Addr ra = dtb_file->findReleaseAddr();
     if (ra)
         bootReleaseAddr = ra & ~ULL(0x7F);
 
diff --git a/src/arch/arm/linux/system.cc b/src/arch/arm/linux/system.cc
index 740d2e0..acca58a 100644
--- a/src/arch/arm/linux/system.cc
+++ b/src/arch/arm/linux/system.cc
@@ -46,7 +46,7 @@
 #include "arch/arm/linux/atag.hh"
 #include "arch/arm/utility.hh"
 #include "arch/generic/linux/threadinfo.hh"
-#include "base/loader/dtb_object.hh"
+#include "base/loader/dtb_file.hh"
 #include "base/loader/object_file.hh"
 #include "base/loader/symtab.hh"
 #include "cpu/base.hh"
@@ -133,22 +133,12 @@
         inform("Loading DTB file: %s at address %#x\n", params()->dtb_filename,
                 params()->atags_addr + loadAddrOffset);
 
-        ObjectFile *dtb_file = createObjectFile(params()->dtb_filename, true);
-        if (!dtb_file) {
-            fatal("couldn't load DTB file: %s\n", params()->dtb_filename);
-        }
+        DtbFile *dtb_file = new DtbFile(params()->dtb_filename);
 
-        DtbObject *_dtb_file = dynamic_cast<DtbObject*>(dtb_file);
-
-        if (_dtb_file) {
-            if (!_dtb_file->addBootCmdLine(params()->boot_osflags.c_str(),
-                                           params()->boot_osflags.size())) {
-                warn("couldn't append bootargs to DTB file: %s\n",
-                     params()->dtb_filename);
-            }
-        } else {
-            warn("dtb_file cast failed; couldn't append bootargs "
-                 "to DTB file: %s\n", params()->dtb_filename);
+        if (!dtb_file->addBootCmdLine(params()->boot_osflags.c_str(),
+                                      params()->boot_osflags.size())) {
+            warn("couldn't append bootargs to DTB file: %s\n",
+                 params()->dtb_filename);
         }
 
         dtb_file->buildImage().
diff --git a/src/base/SConscript b/src/base/SConscript
index 8d17079..b4b381b 100644
--- a/src/base/SConscript
+++ b/src/base/SConscript
@@ -74,12 +74,12 @@
 Source('types.cc')
 
 Source('loader/aout_object.cc')
-Source('loader/dtb_object.cc')
+Source('loader/dtb_file.cc')
 Source('loader/ecoff_object.cc')
 Source('loader/elf_object.cc')
+Source('loader/image_file_data.cc')
 Source('loader/memory_image.cc')
 Source('loader/object_file.cc')
-Source('loader/raw_object.cc')
 Source('loader/symtab.cc')
 
 Source('stats/group.cc')
diff --git a/src/base/loader/aout_object.cc b/src/base/loader/aout_object.cc
index eb633c1..47f3021 100644
--- a/src/base/loader/aout_object.cc
+++ b/src/base/loader/aout_object.cc
@@ -40,63 +40,44 @@
 using namespace std;
 
 ObjectFile *
-AoutObject::tryFile(const string &fname, size_t len, uint8_t *data)
+AoutObjectFileFormat::load(ImageFileDataPtr ifd)
 {
-    if (!N_BADMAG(*(aout_exechdr *)data)) {
-        // right now this is only used for Alpha PAL code
-        return new AoutObject(fname, len, data,
-                              ObjectFile::Alpha, ObjectFile::UnknownOpSys);
-    } else {
+    if (!N_BADMAG(*(const aout_exechdr *)ifd->data()))
+        return new AoutObject(ifd);
+    else
         return nullptr;
-    }
 }
 
-
-AoutObject::AoutObject(const string &_filename,
-                       size_t _len, uint8_t *_data,
-                       Arch _arch, OpSys _opSys)
-    : ObjectFile(_filename, _len, _data, _arch, _opSys)
+namespace
 {
-    execHdr = (aout_exechdr *)fileData;
+
+AoutObjectFileFormat aoutObjectFileFormat;
+
+} // anonymous namespace
+
+
+AoutObject::AoutObject(ImageFileDataPtr ifd) : ObjectFile(ifd)
+{
+    execHdr = (const aout_exechdr *)imageData->data();
     entry = execHdr->entry;
+
+    // Right now this is only used for Alpha PAL code.
+    arch = Alpha;
 }
 
 MemoryImage
 AoutObject::buildImage() const
 {
     MemoryImage image({
-            { "text", N_TXTADDR(*execHdr),
-              fileData + N_TXTOFF(*execHdr), execHdr->tsize },
-            { "data", N_DATADDR(*execHdr),
-              fileData + N_DATOFF(*execHdr), execHdr->dsize },
-            { "bss", N_BSSADDR(*execHdr), nullptr, execHdr->bsize}
+            MemoryImage::Segment{ "text", N_TXTADDR(*execHdr), imageData,
+              N_TXTOFF(*execHdr), execHdr->tsize },
+            MemoryImage::Segment{ "data", N_DATADDR(*execHdr), imageData,
+              N_DATOFF(*execHdr), execHdr->dsize },
+            MemoryImage::Segment{ "bss", N_BSSADDR(*execHdr), execHdr->bsize}
     });
 
     for (auto &seg: image.segments())
         DPRINTFR(Loader, "%s\n", seg);
+
     return image;
 }
-
-
-bool
-AoutObject::loadAllSymbols(SymbolTable *symtab, Addr base, Addr offset,
-                           Addr addr_mask)
-{
-    return false;
-}
-
-bool
-AoutObject::loadGlobalSymbols(SymbolTable *symtab, Addr base, Addr offset,
-                              Addr addr_mask)
-{
-    // a.out symbols not supported yet
-    return false;
-}
-
-bool
-AoutObject::loadLocalSymbols(SymbolTable *symtab, Addr base, Addr offset,
-                             Addr addr_mask)
-{
-    // a.out symbols not supported yet
-    return false;
-}
diff --git a/src/base/loader/aout_object.hh b/src/base/loader/aout_object.hh
index 4f8c86f..480a30c 100644
--- a/src/base/loader/aout_object.hh
+++ b/src/base/loader/aout_object.hh
@@ -39,26 +39,18 @@
 class AoutObject : public ObjectFile
 {
   protected:
-    aout_exechdr *execHdr;
-
-    AoutObject(const std::string &_filename,
-               size_t _len, uint8_t *_data,
-               Arch _arch, OpSys _opSys);
+    const aout_exechdr *execHdr;
 
   public:
-    virtual ~AoutObject() {}
+    AoutObject(ImageFileDataPtr ifd);
 
     MemoryImage buildImage() const override;
+};
 
-    bool loadAllSymbols(SymbolTable *symtab, Addr base=0,
-                        Addr offset=0, Addr addr_mask = MaxAddr) override;
-    bool loadGlobalSymbols(SymbolTable *symtab, Addr base=0,
-                           Addr offset=0, Addr addr_mask=MaxAddr) override;
-    bool loadLocalSymbols(SymbolTable *symtab, Addr base=0,
-                          Addr offset=0, Addr addr_mask=MaxAddr) override;
-
-    static ObjectFile *tryFile(const std::string &fname,
-                               size_t len, uint8_t *data);
+class AoutObjectFileFormat : public ObjectFileFormat
+{
+  public:
+    ObjectFile *load(ImageFileDataPtr data) override;
 };
 
 #endif // __AOUT_OBJECT_HH__
diff --git a/src/base/loader/dtb_object.cc b/src/base/loader/dtb_file.cc
similarity index 71%
rename from src/base/loader/dtb_object.cc
rename to src/base/loader/dtb_file.cc
index f5b206a..aaae0a2 100644
--- a/src/base/loader/dtb_object.cc
+++ b/src/base/loader/dtb_file.cc
@@ -28,7 +28,7 @@
  * Authors: Anthony Gutierrez
  */
 
-#include "base/loader/dtb_object.hh"
+#include "base/loader/dtb_file.hh"
 
 #include <sys/mman.h>
 #include <unistd.h>
@@ -39,48 +39,34 @@
 #include "libfdt.h"
 #include "sim/byteswap.hh"
 
-ObjectFile *
-DtbObject::tryFile(const std::string &fname, size_t len, uint8_t *data)
+DtbFile::DtbFile(const std::string &filename) :
+    ImageFile(ImageFileDataPtr(new ImageFileData(filename)))
 {
-    // Check if this is a FDT file by looking for magic number
-    if (fdt_magic((void*)data) == FDT_MAGIC) {
-        return new DtbObject(fname, len, data,
-                             ObjectFile::UnknownArch, ObjectFile::UnknownOpSys);
-    } else {
-        return NULL;
-    }
-}
-
-DtbObject::DtbObject(const std::string &_filename, size_t _len, uint8_t *_data,
-                     Arch _arch, OpSys _opSys)
-    : ObjectFile(_filename, _len, _data, _arch, _opSys)
-{
+    panic_if(fdt_magic((const void *)imageData->data()) != FDT_MAGIC,
+            "File %s doesn't seem to be a DTB.\n", filename);
     fileDataMmapped = true;
+    fileData = const_cast<uint8_t *>(imageData->data());
+    length = imageData->len();
 }
 
-DtbObject::~DtbObject()
+DtbFile::~DtbFile()
 {
     // Make sure to clean up memory properly depending
     // on how buffer was allocated.
-    if (fileData && !fileDataMmapped) {
+    if (!fileDataMmapped)
         delete [] fileData;
-        fileData = NULL;
-    } else if (fileData) {
-        munmap(fileData, len);
-        fileData = NULL;
-    }
 }
 
 bool
-DtbObject::addBootCmdLine(const char* _args, size_t len)
+DtbFile::addBootCmdLine(const char *_args, size_t len)
 {
-    const char* root_path = "/";
-    const char* node_name = "chosen";
-    const char* full_path_node_name = "/chosen";
-    const char* property_name = "bootargs";
+    const char *root_path = "/";
+    const char *node_name = "chosen";
+    const char *full_path_node_name = "/chosen";
+    const char *property_name = "bootargs";
 
     // Make a new buffer that has extra space to add nodes/properties
-    int newLen = 2 * this->len;
+    int newLen = 2 * length;
     uint8_t *fdt_buf_w_space = new uint8_t[newLen];
     // Copy and unpack flattened device tree into new buffer
     int ret = fdt_open_into((void *)fileData, (void *)fdt_buf_w_space, newLen);
@@ -130,23 +116,24 @@
     }
 
     // clean up old buffer and set to new fdt blob
-    munmap(fileData, this->len);
+    if (!fileDataMmapped)
+        delete [] fileData;
     fileData = fdt_buf_w_space;
     fileDataMmapped = false;
-    this->len = newLen;
+    length = newLen;
 
     return true;
 }
 
 Addr
-DtbObject::findReleaseAddr()
+DtbFile::findReleaseAddr()
 {
     void *fd = (void *)fileData;
 
     int offset = fdt_path_offset(fd, "/cpus/cpu@0");
     int len;
 
-    const void* temp = fdt_getprop(fd, offset, "cpu-release-addr", &len);
+    const void *temp = fdt_getprop(fd, offset, "cpu-release-addr", &len);
     Addr rel_addr = 0;
 
     if (len > 3)
@@ -160,30 +147,10 @@
 }
 
 MemoryImage
-DtbObject::buildImage() const
+DtbFile::buildImage() const
 {
-    return {{"data", 0, fileData, len}};
-}
-
-bool
-DtbObject::loadAllSymbols(SymbolTable *symtab, Addr base, Addr offset,
-                          Addr addr_mask)
-{
-    return false;
-}
-
-bool
-DtbObject::loadGlobalSymbols(SymbolTable *symtab, Addr base, Addr offset,
-                             Addr addr_mask)
-{
-    // nothing to do here
-    return false;
-}
-
-bool
-DtbObject::loadLocalSymbols(SymbolTable *symtab, Addr base, Addr offset,
-                            Addr addr_mask)
-{
-    // nothing to do here
-    return false;
+    if (fileDataMmapped)
+        return {{ "data", imageData }};
+    else
+        return {{ "data", 0, fileData, length }};
 }
diff --git a/src/base/loader/dtb_object.hh b/src/base/loader/dtb_file.hh
similarity index 67%
rename from src/base/loader/dtb_object.hh
rename to src/base/loader/dtb_file.hh
index 1284025..53bc13e 100644
--- a/src/base/loader/dtb_object.hh
+++ b/src/base/loader/dtb_file.hh
@@ -28,29 +28,29 @@
  * Authors: Anthony Gutierrez
  */
 
-#ifndef __DTB_OBJECT_HH__
-#define __DTB_OBJECT_HH__
+#ifndef __BASE_LOADER_DTB_FILE_HH__
+#define __BASE_LOADER_DTB_FILE_HH__
 
-#include "base/loader/object_file.hh"
+#include "base/loader/image_file.hh"
 
 /** @file
- * This implements an object file format to support loading
+ * This implements an image file format to support loading
  * and modifying flattened device tree blobs for use with
  * current and future ARM Linux kernels.
  */
-class DtbObject : public ObjectFile
+class DtbFile : public ImageFile
 {
   protected:
-    DtbObject(const std::string &_filename, size_t _len, uint8_t *_data,
-              Arch _arch, OpSys _opSys);
-
     /** Bool marking if this dtb file has replaced the original
      *  read in DTB file with a new modified buffer
      */
     bool fileDataMmapped;
+    uint8_t *fileData = nullptr;
+    size_t length = 0;
 
   public:
-    virtual ~DtbObject();
+    DtbFile(const std::string &name);
+    ~DtbFile();
 
     /** Adds the passed in Command Line options for the kernel
       * to the proper location in the device tree.
@@ -67,23 +67,6 @@
     Addr findReleaseAddr();
 
     MemoryImage buildImage() const override;
-
-    bool loadAllSymbols(SymbolTable *symtab, Addr base=0,
-                        Addr offset=0, Addr addrMask=MaxAddr) override;
-    bool loadGlobalSymbols(SymbolTable *symtab, Addr base=0,
-                           Addr offset=0, Addr addrMask=MaxAddr) override;
-    bool loadLocalSymbols(SymbolTable *symtab, Addr base=0,
-                          Addr offset=0, Addr addrMask=MaxAddr) override;
-
-    /** Static function that tries to load file as a
-      * flattened device tree blob.
-      * @param fname path to file
-      * @param len length of file
-      * @param data mmap'ed data buffer containing file contents
-      * @return ObjectFile representing closest match of file type
-      */
-    static ObjectFile *tryFile(const std::string &fname,
-                               size_t len, uint8_t *data);
 };
 
-#endif //__DTB_OBJECT_HH__
+#endif //__BASE_LOADER_DTB_FILE_HH__
diff --git a/src/base/loader/ecoff_object.cc b/src/base/loader/ecoff_object.cc
index cecc68d..2f53431 100644
--- a/src/base/loader/ecoff_object.cc
+++ b/src/base/loader/ecoff_object.cc
@@ -50,39 +50,43 @@
 using namespace std;
 
 ObjectFile *
-EcoffObject::tryFile(const string &fname, size_t len, uint8_t *data)
+EcoffObjectFormat::load(ImageFileDataPtr ifd)
 {
-    if (((ecoff_filehdr *)data)->f_magic == ECOFF_MAGIC_ALPHA) {
-        // it's Alpha ECOFF
-        return new EcoffObject(fname, len, data,
-                               ObjectFile::Alpha, ObjectFile::Tru64);
-    }
-    else {
-        return NULL;
-    }
+    if (((const ecoff_filehdr *)ifd->data())->f_magic == ECOFF_MAGIC_ALPHA)
+        return new EcoffObject(ifd);
+    else
+        return nullptr;
 }
 
-
-EcoffObject::EcoffObject(const string &_filename, size_t _len, uint8_t *_data,
-                         Arch _arch, OpSys _opSys)
-    : ObjectFile(_filename, _len, _data, _arch, _opSys)
+namespace
 {
-    execHdr = (ecoff_exechdr *)fileData;
+
+EcoffObjectFormat ecoffObjectFormat;
+
+} // anonymous namespace
+
+
+EcoffObject::EcoffObject(ImageFileDataPtr ifd) : ObjectFile(ifd)
+{
+    execHdr = (const ecoff_exechdr *)imageData->data();
     fileHdr = &(execHdr->f);
     aoutHdr = &(execHdr->a);
 
     entry = aoutHdr->entry;
+    // it's Alpha ECOFF
+    arch = Alpha;
+    opSys = Tru64;
 }
 
 MemoryImage
 EcoffObject::buildImage() const
 {
     MemoryImage image({
-            { "text", aoutHdr->text_start,
-              fileData + ECOFF_TXTOFF(execHdr), aoutHdr->tsize },
-            { "data", aoutHdr->data_start,
-              fileData + ECOFF_DATOFF(execHdr), aoutHdr->dsize },
-            { "bss", aoutHdr->bss_start, nullptr, aoutHdr->bsize }
+            { "text", aoutHdr->text_start, imageData,
+              ECOFF_TXTOFF(execHdr), aoutHdr->tsize },
+            { "data", aoutHdr->data_start, imageData,
+              ECOFF_DATOFF(execHdr), aoutHdr->dsize },
+            { "bss", aoutHdr->bss_start, aoutHdr->bsize }
     });
 
     for (auto &seg: image.segments())
@@ -108,21 +112,24 @@
         return false;
 
     if (fileHdr->f_magic != ECOFF_MAGIC_ALPHA) {
-        warn("loadGlobalSymbols: wrong magic on %s\n", filename);
+        warn("loadGlobalSymbols: wrong magic on %s\n", imageData->filename());
         return false;
     }
 
-    ecoff_symhdr *syms = (ecoff_symhdr *)(fileData + fileHdr->f_symptr);
+    auto *syms = (const ecoff_symhdr *)(imageData->data() + fileHdr->f_symptr);
     if (syms->magic != magicSym2) {
-        warn("loadGlobalSymbols: bad symbol header magic on %s\n", filename);
+        warn("loadGlobalSymbols: bad symbol header magic on %s\n",
+                imageData->filename());
         return false;
     }
 
-    ecoff_extsym *ext_syms = (ecoff_extsym *)(fileData + syms->cbExtOffset);
+    auto *ext_syms = (const ecoff_extsym *)(
+            imageData->data() + syms->cbExtOffset);
 
-    char *ext_strings = (char *)(fileData + syms->cbSsExtOffset);
+    auto *ext_strings =
+        (const char *)(imageData->data() + syms->cbSsExtOffset);
     for (int i = 0; i < syms->iextMax; i++) {
-        ecoff_sym *entry = &(ext_syms[i].asym);
+        const ecoff_sym *entry = &(ext_syms[i].asym);
         if (entry->iss != -1)
             symtab->insert(entry->value, ext_strings + entry->iss);
     }
@@ -138,23 +145,25 @@
         return false;
 
     if (fileHdr->f_magic != ECOFF_MAGIC_ALPHA) {
-        warn("loadGlobalSymbols: wrong magic on %s\n", filename);
+        warn("loadGlobalSymbols: wrong magic on %s\n", imageData->filename());
         return false;
     }
 
-    ecoff_symhdr *syms = (ecoff_symhdr *)(fileData + fileHdr->f_symptr);
+    auto *syms = (const ecoff_symhdr *)(imageData->data() + fileHdr->f_symptr);
     if (syms->magic != magicSym2) {
-        warn("loadGlobalSymbols: bad symbol header magic on %s\n", filename);
+        warn("loadGlobalSymbols: bad symbol header magic on %s\n",
+                imageData->filename());
         return false;
     }
 
-    ecoff_sym *local_syms = (ecoff_sym *)(fileData + syms->cbSymOffset);
-    char *local_strings = (char *)(fileData + syms->cbSsOffset);
-    ecoff_fdr *fdesc = (ecoff_fdr *)(fileData + syms->cbFdOffset);
+    auto *local_syms =
+        (const ecoff_sym *)(imageData->data() + syms->cbSymOffset);
+    auto *local_strings = (const char *)(imageData->data() + syms->cbSsOffset);
+    auto *fdesc = (const ecoff_fdr *)(imageData->data() + syms->cbFdOffset);
 
     for (int i = 0; i < syms->ifdMax; i++) {
-        ecoff_sym *entry = (ecoff_sym *)(local_syms + fdesc[i].isymBase);
-        char *strings = (char *)(local_strings + fdesc[i].issBase);
+        auto *entry = (const ecoff_sym *)(local_syms + fdesc[i].isymBase);
+        auto *strings = (const char *)(local_strings + fdesc[i].issBase);
         for (int j = 0; j < fdesc[i].csym; j++) {
             if (entry[j].st == stGlobal || entry[j].st == stProc)
                 if (entry[j].iss != -1)
@@ -163,7 +172,7 @@
     }
 
     for (int i = 0; i < syms->isymMax; i++) {
-        ecoff_sym *entry = &(local_syms[i]);
+        const ecoff_sym *entry = &(local_syms[i]);
         if (entry->st == stProc)
             symtab->insert(entry->value, local_strings + entry->iss);
     }
diff --git a/src/base/loader/ecoff_object.hh b/src/base/loader/ecoff_object.hh
index 9481115..9e6c533 100644
--- a/src/base/loader/ecoff_object.hh
+++ b/src/base/loader/ecoff_object.hh
@@ -28,8 +28,8 @@
  * Authors: Steve Reinhardt
  */
 
-#ifndef __ECOFF_OBJECT_HH__
-#define __ECOFF_OBJECT_HH__
+#ifndef __BASE_LOADER_ECOFF_OBJECT_HH__
+#define __BASE_LOADER_ECOFF_OBJECT_HH__
 
 #include "base/loader/object_file.hh"
 
@@ -38,18 +38,21 @@
 struct ecoff_filehdr;
 struct ecoff_aouthdr;
 
+class EcoffObjectFormat : public ObjectFileFormat
+{
+  public:
+    ObjectFile *load(ImageFileDataPtr data) override;
+};
+
 class EcoffObject : public ObjectFile
 {
   protected:
-    ecoff_exechdr *execHdr;
-    ecoff_filehdr *fileHdr;
-    ecoff_aouthdr *aoutHdr;
-
-    EcoffObject(const std::string &_filename, size_t _len, uint8_t *_data,
-                Arch _arch, OpSys _opSys);
+    const ecoff_exechdr *execHdr;
+    const ecoff_filehdr *fileHdr;
+    const ecoff_aouthdr *aoutHdr;
 
   public:
-    virtual ~EcoffObject() {}
+    EcoffObject(ImageFileDataPtr ifd);
 
     MemoryImage buildImage() const override;
 
@@ -59,9 +62,6 @@
                            Addr offset=0, Addr addr_mask=MaxAddr) override;
     bool loadLocalSymbols(SymbolTable *symtab, Addr base=0,
                           Addr offset=0, Addr addr_mask=MaxAddr) override;
-
-    static ObjectFile *tryFile(const std::string &fname,
-                               size_t len, uint8_t *data);
 };
 
-#endif // __ECOFF_OBJECT_HH__
+#endif // __BASE_LOADER_ECOFF_OBJECT_HH__
diff --git a/src/base/loader/elf_object.cc b/src/base/loader/elf_object.cc
index 7a83c0b..e35c28b 100644
--- a/src/base/loader/elf_object.cc
+++ b/src/base/loader/elf_object.cc
@@ -61,309 +61,253 @@
 #include "sim/byteswap.hh"
 
 ObjectFile *
-ElfObject::tryFile(const std::string &fname, size_t len, uint8_t *data,
-                   bool skip_interp_check)
+ElfObjectFormat::load(ImageFileDataPtr ifd)
 {
     // check that header matches library version
     if (elf_version(EV_CURRENT) == EV_NONE)
         panic("wrong elf version number!");
 
+    ObjectFile *object = nullptr;
+
     // get a pointer to elf structure
     // Check that we actually have a elf file
-    Elf *elf = elf_memory((char*)data, len);
+    Elf *elf =
+        elf_memory((char *)const_cast<uint8_t *>(ifd->data()), ifd->len());
     assert(elf);
 
     GElf_Ehdr ehdr;
-    if (gelf_getehdr(elf, &ehdr) == 0) {
+    if (gelf_getehdr(elf, &ehdr) == 0)
         DPRINTFR(Loader, "Not ELF\n");
-        elf_end(elf);
-        return NULL;
-    }
-
-    // Detect the architecture
-    Arch arch = UnknownArch;
-    if (ehdr.e_machine == EM_SPARC64 ||
-        (ehdr.e_machine == EM_SPARC &&
-         ehdr.e_ident[EI_CLASS] == ELFCLASS64) ||
-        ehdr.e_machine == EM_SPARCV9) {
-        arch = SPARC64;
-    } else if (ehdr.e_machine == EM_SPARC32PLUS ||
-               (ehdr.e_machine == EM_SPARC &&
-                ehdr.e_ident[EI_CLASS] == ELFCLASS32)) {
-        arch = SPARC32;
-    } else if (ehdr.e_machine == EM_MIPS &&
-               ehdr.e_ident[EI_CLASS] == ELFCLASS32) {
-        arch = Mips;
-        if (ehdr.e_ident[EI_DATA] != ELFDATA2LSB) {
-            fatal("The binary you're trying to load is compiled for big "
-                  "endian MIPS. gem5\nonly supports little endian MIPS. "
-                  "Please recompile your binary.\n");
-        }
-    } else if (ehdr.e_machine == EM_X86_64 &&
-               ehdr.e_ident[EI_CLASS] == ELFCLASS64) {
-        arch = X86_64;
-    } else if (ehdr.e_machine == EM_386 &&
-               ehdr.e_ident[EI_CLASS] == ELFCLASS32) {
-        arch = I386;
-    } else if (ehdr.e_machine == EM_ARM &&
-               ehdr.e_ident[EI_CLASS] == ELFCLASS32) {
-        arch = bits(ehdr.e_entry, 0) ? Thumb : Arm;
-    } else if (ehdr.e_machine == EM_AARCH64 &&
-               ehdr.e_ident[EI_CLASS] == ELFCLASS64) {
-        arch = Arm64;
-    } else if (ehdr.e_machine == EM_RISCV) {
-        arch = (ehdr.e_ident[EI_CLASS] == ELFCLASS64) ? Riscv64 : Riscv32;
-    } else if (ehdr.e_machine == EM_PPC &&
-               ehdr.e_ident[EI_CLASS] == ELFCLASS32) {
-        arch = Power;
-        if (ehdr.e_ident[EI_DATA] != ELFDATA2MSB) {
-            fatal("The binary you're trying to load is compiled for "
-                  "little endian Power.\ngem5 only supports big "
-                  "endian Power. Please recompile your binary.\n");
-        }
-    } else if (ehdr.e_machine == EM_PPC64) {
-        fatal("The binary you're trying to load is compiled for 64-bit "
-              "Power. M5\n only supports 32-bit Power. Please "
-              "recompile your binary.\n");
-    } else if (ehdr.e_ident[EI_CLASS] == ELFCLASS64) {
-        // Since we don't know how to check for alpha right now, we'll
-        // just assume if it wasn't something else and it's 64 bit, that's
-        // what it must be.
-        arch = Alpha;
-    } else {
-        warn("Unknown architecture: %d\n", ehdr.e_machine);
-        arch = UnknownArch;
-    }
-
-    // Detect the operating system
-    OpSys op_sys;
-    switch (ehdr.e_ident[EI_OSABI]) {
-      case ELFOSABI_LINUX:
-        op_sys = Linux;
-        break;
-      case ELFOSABI_SOLARIS:
-        op_sys = Solaris;
-        break;
-      case ELFOSABI_TRU64:
-        op_sys = Tru64;
-        break;
-      case ELFOSABI_ARM:
-        op_sys = LinuxArmOABI;
-        break;
-      case ELFOSABI_FREEBSD:
-        op_sys = FreeBSD;
-        break;
-      default:
-        op_sys = UnknownOpSys;
-    }
-
-    // Take a look at the .note.ABI section.
-    // It can let us know what's what.
-    if (op_sys == UnknownOpSys) {
-        int sec_idx = 1;
-
-        // Get the first section
-        Elf_Scn *section = elf_getscn(elf, sec_idx);
-
-        // While there are no more sections
-        while (section && op_sys == UnknownOpSys) {
-            GElf_Shdr shdr;
-            gelf_getshdr(section, &shdr);
-
-            char *e_str = elf_strptr(elf, ehdr.e_shstrndx, shdr.sh_name);
-            if (shdr.sh_type == SHT_NOTE &&
-                !strcmp(".note.ABI-tag", e_str)) {
-                // we have found a ABI note section
-                // Check the 5th 32bit word for OS  0 == linux, 1 == hurd,
-                // 2 == solaris, 3 == freebsd
-                Elf_Data *raw_data = elf_rawdata(section, NULL);
-                assert(raw_data && raw_data->d_buf);
-
-                uint32_t raw_abi = ((uint32_t*)raw_data->d_buf)[4];
-                bool is_le = ehdr.e_ident[EI_DATA] == ELFDATA2LSB;
-                uint32_t os_abi = is_le ? htole(raw_abi) : htobe(raw_abi);
-
-                switch (os_abi) {
-                  case 0:
-                    op_sys = Linux;
-                    break;
-                  case 1:
-                    fatal("gem5 does not support the HURD ABI.\n");
-                  case 2:
-                    op_sys = Solaris;
-                    break;
-                  case 3:
-                    op_sys = FreeBSD;
-                    break;
-                }
-            } // if section found
-
-            if (!strcmp(".SUNW_version", e_str) ||
-                !strcmp(".stab.index", e_str))
-                op_sys = Solaris;
-
-            section = elf_getscn(elf, ++sec_idx);
-        } // while sections
-    }
-
-    ElfObject * result = new ElfObject(fname, len, data, arch, op_sys);
-
-    // The number of headers in the file
-    result->_programHeaderCount = ehdr.e_phnum;
-    // Record the size of each entry
-    result->_programHeaderSize = ehdr.e_phentsize;
-    result->_programHeaderTable = 0;
-    if (result->_programHeaderCount) { // If there is a program header table
-        // Figure out the virtual address of the header table in the
-        // final memory image. We use the program headers themselves
-        // to translate from a file offset to the address in the image.
-        GElf_Phdr phdr;
-        uint64_t e_phoff = ehdr.e_phoff;
-
-        for (int i = 0; i < result->_programHeaderCount; i++) {
-            gelf_getphdr(elf, i, &phdr);
-            // Check if we've found the segment with the headers in it
-            if (phdr.p_offset <= e_phoff &&
-                phdr.p_offset + phdr.p_filesz > e_phoff) {
-                result->_programHeaderTable =
-                    phdr.p_paddr + (e_phoff - phdr.p_offset);
-                break;
-            }
-        }
-    }
-
-    if (!skip_interp_check) {
-        for (int i = 0; i < ehdr.e_phnum; i++) {
-            GElf_Phdr phdr;
-            M5_VAR_USED void *check_p = gelf_getphdr(elf, i, &phdr);
-            assert(check_p != nullptr);
-
-           if (phdr.p_type != PT_INTERP)
-                continue;
-
-            char *interp_path = (char*)data + phdr.p_offset;
-            int fd = open(interp_path, O_RDONLY);
-            if (fd == -1)
-                fatal("Unable to open dynamic executable's interpreter.\n");
-
-            struct stat sb;
-            M5_VAR_USED int check_i = fstat(fd, &sb);
-            assert(check_i == 0);
-
-            void *mm = mmap(nullptr, sb.st_size, PROT_READ,
-                            MAP_PRIVATE, fd, 0);
-            assert(mm != MAP_FAILED);
-            close(fd);
-
-            uint8_t *interp_image = (uint8_t*)mm;
-            ObjectFile *obj = tryFile(interp_path, sb.st_size,
-                                      interp_image, true);
-            assert(obj != nullptr);
-            result->interpreter = dynamic_cast<ElfObject*>(obj);
-            assert(result->interpreter != nullptr);
-            break;
-        }
-    }
+    else
+        object = new ElfObject(ifd);
 
     elf_end(elf);
-    return result;
+
+    return object;
 }
 
-ElfObject::ElfObject(const std::string &_filename, size_t _len,
-                     uint8_t *_data, Arch _arch, OpSys _op_sys)
-    : ObjectFile(_filename, _len, _data, _arch, _op_sys),
-      _programHeaderTable(0), _programHeaderSize(0), _programHeaderCount(0),
-      interpreter(nullptr), ldBias(0), relocate(true),
-      ldMin(std::numeric_limits<Addr>::max()),
-      ldMax(std::numeric_limits<Addr>::min())
+namespace
 {
-    // check that header matches library version
-    if (elf_version(EV_CURRENT) == EV_NONE)
-        panic("wrong elf version number!");
 
+ElfObjectFormat elfObjectFormat;
+
+} // anonymous namespace
+
+ElfObject::ElfObject(ImageFileDataPtr ifd) : ObjectFile(ifd)
+{
     // get a pointer to elf structure
-    Elf *elf = elf_memory((char*)fileData,len);
+    elf = elf_memory((char *)const_cast<uint8_t *>(imageData->data()),
+                     imageData->len());
     assert(elf);
+    gelf_getehdr(elf, &ehdr);
 
-    // Check that we actually have a elf file
-    GElf_Ehdr ehdr;
-    if (gelf_getehdr(elf, &ehdr) ==0) {
-        panic("Not ELF, shouldn't be here");
-    }
+    determineArch();
+    determineOpSys();
 
     entry = ehdr.e_entry;
+    _programHeaderCount = ehdr.e_phnum;
+    _programHeaderSize = ehdr.e_phentsize;
 
-    int sec_idx = 1;
-
-    // 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.
+    // Go through all the segments in the program and record them.
     for (int i = 0; i < ehdr.e_phnum; ++i) {
         GElf_Phdr phdr;
         if (gelf_getphdr(elf, i, &phdr) == 0) {
             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;
-
-        ldMin = std::min(ldMin, phdr.p_vaddr);
-        ldMax = std::max(ldMax, phdr.p_vaddr + phdr.p_memsz);
-
-        std::string name;
-
-        // Get the first section
-        Elf_Scn *section = elf_getscn(elf, sec_idx);
-
-        // Name segments after the sections they contain.
-        while (section) {
-            GElf_Shdr shdr;
-            gelf_getshdr(section, &shdr);
-            char *sec_name = elf_strptr(elf, ehdr.e_shstrndx, shdr.sh_name);
-
-            if (!sec_name) {
-                Elf_Error errorNum = (Elf_Error)elf_errno();
-                if (errorNum != ELF_E_NONE) {
-                    const char *errorMessage = elf_errmsg(errorNum);
-                    fatal("Error from libelf: %s.\n", errorMessage);
-                }
-            }
-
-            if (shdr.sh_addr >= ldMin && shdr.sh_addr < ldMax) {
-                if (name != "")
-                    name += ",";
-                name += sec_name;
-            }
-
-            section = elf_getscn(elf, ++sec_idx);
-        }
-
-        image.addSegment(name, phdr.p_paddr, fileData + phdr.p_offset,
-                         phdr.p_filesz);
-        Addr uninitialized = phdr.p_memsz - phdr.p_filesz;
-        if (uninitialized) {
-            // There may be parts of a segment which aren't included in the
-            // file. In those cases, we need to create a new segment with no
-            // data to take up the extra space. This should be zeroed when
-            // loaded into memory.
-            image.addSegment(name + "(uninitialized)",
-                    phdr.p_paddr + phdr.p_filesz, nullptr, uninitialized);
+        if (phdr.p_type == PT_LOAD)
+            handleLoadableSegment(phdr);
+        if (phdr.p_type == PT_INTERP) {
+            // Make sure the interpreter is an valid ELF file.
+            char *interp_path = (char *)imageData->data() + phdr.p_offset;
+            ObjectFile *obj = createObjectFile(interp_path);
+            interpreter = dynamic_cast<ElfObject *>(obj);
+            assert(interpreter != nullptr);
         }
     }
 
     // should have found at least one loadable segment
     warn_if(image.segments().empty(),
-            "No loadable segments in '%s'. ELF file corrupted?\n", filename);
+            "No loadable segments in '%s'. ELF file corrupted?\n",
+            imageData->filename());
 
     for (auto &seg: image.segments())
         DPRINTFR(Loader, "%s\n", seg);
 
-    elf_end(elf);
-
     // We will actually read the sections when we need to load them
 }
 
+void
+ElfObject::determineArch()
+{
+    auto &emach = ehdr.e_machine;
+    auto &eclass = ehdr.e_ident[EI_CLASS];
+    auto &edata = ehdr.e_ident[EI_DATA];
+
+    // Detect the architecture
+    if (emach == EM_SPARC64 || (emach == EM_SPARC && eclass == ELFCLASS64) ||
+        emach == EM_SPARCV9) {
+        arch = SPARC64;
+    } else if (emach == EM_SPARC32PLUS ||
+               (emach == EM_SPARC && eclass == ELFCLASS32)) {
+        arch = SPARC32;
+    } else if (emach == EM_MIPS && eclass == ELFCLASS32) {
+        arch = Mips;
+        if (edata != ELFDATA2LSB) {
+            fatal("The binary you're trying to load is compiled for big "
+                  "endian MIPS. gem5\nonly supports little endian MIPS. "
+                  "Please recompile your binary.\n");
+        }
+    } else if (emach == EM_X86_64 && eclass == ELFCLASS64) {
+        arch = X86_64;
+    } else if (emach == EM_386 && eclass == ELFCLASS32) {
+        arch = I386;
+    } else if (emach == EM_ARM && eclass == ELFCLASS32) {
+        arch = bits(ehdr.e_entry, 0) ? Thumb : Arm;
+    } else if (emach == EM_AARCH64 && eclass == ELFCLASS64) {
+        arch = Arm64;
+    } else if (emach == EM_RISCV) {
+        arch = (eclass == ELFCLASS64) ? Riscv64 : Riscv32;
+    } else if (emach == EM_PPC && eclass == ELFCLASS32) {
+        arch = Power;
+        if (edata != ELFDATA2MSB) {
+            fatal("The binary you're trying to load is compiled for "
+                  "little endian Power.\ngem5 only supports big "
+                  "endian Power. Please recompile your binary.\n");
+        }
+    } else if (emach == EM_PPC64) {
+        fatal("The binary you're trying to load is compiled for 64-bit "
+              "Power. M5\n only supports 32-bit Power. Please "
+              "recompile your binary.\n");
+    } else if (eclass == ELFCLASS64) {
+        // Since we don't know how to check for alpha right now, we'll
+        // just assume if it wasn't something else and it's 64 bit, that's
+        // what it must be.
+        arch = Alpha;
+    } else {
+        warn("Unknown architecture: %d\n", emach);
+    }
+}
+
+void
+ElfObject::determineOpSys()
+{
+    // Detect the operating system
+    switch (ehdr.e_ident[EI_OSABI]) {
+      case ELFOSABI_LINUX:
+        opSys = Linux;
+        return;
+      case ELFOSABI_SOLARIS:
+        opSys = Solaris;
+        return;
+      case ELFOSABI_TRU64:
+        opSys = Tru64;
+        return;
+      case ELFOSABI_ARM:
+        opSys = LinuxArmOABI;
+        return;
+      case ELFOSABI_FREEBSD:
+        opSys = FreeBSD;
+        return;
+      default:
+        opSys = UnknownOpSys;
+    }
+
+    Elf_Scn *section = elf_getscn(elf, 1);
+    for (int sec_idx = 1; section; section = elf_getscn(elf, ++sec_idx)) {
+        GElf_Shdr shdr;
+        gelf_getshdr(section, &shdr);
+
+        char *e_str = elf_strptr(elf, ehdr.e_shstrndx, shdr.sh_name);
+        if (shdr.sh_type == SHT_NOTE && !strcmp(".note.ABI-tag", e_str)) {
+            // we have found a ABI note section
+            // Check the 5th 32bit word for OS  0 == linux, 1 == hurd,
+            // 2 == solaris, 3 == freebsd
+            Elf_Data *raw_data = elf_rawdata(section, nullptr);
+            assert(raw_data && raw_data->d_buf);
+
+            uint32_t raw_abi = ((uint32_t *)raw_data->d_buf)[4];
+            bool is_le = ehdr.e_ident[EI_DATA] == ELFDATA2LSB;
+            uint32_t os_abi = is_le ? htole(raw_abi) : htobe(raw_abi);
+
+            switch (os_abi) {
+              case 0:
+                opSys = Linux;
+                return;
+              case 1:
+                fatal("gem5 does not support the HURD ABI.\n");
+              case 2:
+                opSys = Solaris;
+                return;
+              case 3:
+                opSys = FreeBSD;
+                return;
+            }
+        }
+
+        if (!strcmp(".SUNW_version", e_str) || !strcmp(".stab.index", e_str)) {
+            opSys = Solaris;
+            return;
+        }
+    }
+}
+
+void
+ElfObject::handleLoadableSegment(GElf_Phdr phdr)
+{
+    Addr mem_start = phdr.p_vaddr;
+    Addr mem_end = mem_start + phdr.p_memsz;
+    Addr file_start = phdr.p_offset;
+    Addr file_end = file_start + phdr.p_filesz;
+
+    std::string name;
+
+    // Name segments after the sections they contain.
+    Elf_Scn *section = elf_getscn(elf, 1);
+    for (int sec_idx = 1; section; section = elf_getscn(elf, ++sec_idx)) {
+        GElf_Shdr shdr;
+        gelf_getshdr(section, &shdr);
+        char *sec_name = elf_strptr(elf, ehdr.e_shstrndx, shdr.sh_name);
+
+        if (!sec_name) {
+            Elf_Error errorNum = (Elf_Error)elf_errno();
+            if (errorNum != ELF_E_NONE) {
+                const char *errorMessage = elf_errmsg(errorNum);
+                fatal("Error from libelf: %s.\n", errorMessage);
+            }
+        }
+
+        if (shdr.sh_addr >= mem_start && shdr.sh_addr < mem_end) {
+            if (name != "")
+                name += ",";
+            name += sec_name;
+        }
+    }
+
+    image.addSegment({ name, phdr.p_paddr, imageData,
+                       phdr.p_offset, phdr.p_filesz });
+    Addr uninitialized = phdr.p_memsz - phdr.p_filesz;
+    if (uninitialized) {
+        // There may be parts of a segment which aren't included in the
+        // file. In those cases, we need to create a new segment with no
+        // data to take up the extra space. This should be zeroed when
+        // loaded into memory.
+        image.addSegment({ name + "(uninitialized)",
+                           phdr.p_paddr + phdr.p_filesz, uninitialized });
+    }
+
+    // If there is a program header table, figure out the virtual
+    // address of the header table in the final memory image. We use
+    // the program headers themselves to translate from a file offset
+    // to the address in the image.
+    if (file_start <= ehdr.e_phoff && file_end > ehdr.e_phoff)
+        _programHeaderTable = mem_start + (ehdr.e_phoff - file_start);
+}
+
+ElfObject::~ElfObject()
+{
+    elf_end(elf);
+}
 
 bool
 ElfObject::loadSomeSymbols(SymbolTable *symtab, int binding, Addr mask,
@@ -377,7 +321,8 @@
         panic("wrong elf version number!");
 
     // get a pointer to elf structure
-    Elf *elf = elf_memory((char*)fileData,len);
+    Elf *elf = elf_memory((char *)const_cast<uint8_t *>(
+                imageData->data()), imageData->len());
     assert(elf != NULL);
 
     // Get the first section
@@ -401,7 +346,8 @@
                 GElf_Sym sym;
                 gelf_getsym(data, i, &sym);
                 if (GELF_ST_BIND(sym.st_info) == binding) {
-                    char *sym_name = elf_strptr(elf, shdr.sh_link, sym.st_name);
+                    char *sym_name =
+                        elf_strptr(elf, shdr.sh_link, sym.st_name);
                     if (sym_name && sym_name[0] != '$') {
                         Addr value = sym.st_value - base + offset;
                         if (symtab->insert(value & mask, sym_name)) {
@@ -473,7 +419,9 @@
         panic("wrong elf version number!");
 
     // get a pointer to elf structure
-    Elf *elf = elf_memory((char*)fileData,len);
+    Elf *elf =
+        elf_memory((char *)const_cast<uint8_t *>(imageData->data()),
+                imageData->len());
     assert(elf != NULL);
 
     // Check that we actually have a elf file
diff --git a/src/base/loader/elf_object.hh b/src/base/loader/elf_object.hh
index 0b8c79b..42edc74 100644
--- a/src/base/loader/elf_object.hh
+++ b/src/base/loader/elf_object.hh
@@ -40,56 +40,68 @@
  * Authors: Steve Reinhardt
  */
 
-#ifndef __ELF_OBJECT_HH__
-#define __ELF_OBJECT_HH__
+#ifndef __BASE_LOADER_ELF_OBJECT_HH__
+#define __BASE_LOADER_ELF_OBJECT_HH__
 
 #include <set>
 #include <vector>
 
 #include "base/loader/object_file.hh"
+#include "gelf.h"
+
+class ElfObjectFormat : public ObjectFileFormat
+{
+  public:
+    ObjectFile *load(ImageFileDataPtr data) override;
+};
 
 class ElfObject : public ObjectFile
 {
   protected:
+    Elf *elf;
+    GElf_Ehdr ehdr;
+
+    void determineArch();
+    void determineOpSys();
+    void handleLoadableSegment(GElf_Phdr phdr);
+
     // These values are provided to a linux process by the kernel, so we
     // need to keep them around.
-    Addr _programHeaderTable;
-    uint16_t _programHeaderSize;
-    uint16_t _programHeaderCount;
+    Addr _programHeaderTable = 0;
+    uint16_t _programHeaderSize = 0;
+    uint16_t _programHeaderCount = 0;
     std::set<std::string> sectionNames;
 
-    ElfObject *interpreter;
+    ElfObject *interpreter = nullptr;
 
     // An interpreter load bias is the location in the process address space
     // where the interpreter is chosen to reside. Typically, this is carved
     // out of the top of the mmap reserve section.
-    Addr ldBias;
+    Addr ldBias = 0;
 
     // The interpreter is typically a relocatable shared library and will
     // have a default value of zero which means that it does not care where
     // it is placed. However, the loader can be compiled and linked so that
     // it does care and needs a specific entry point.
-    bool relocate;
+    bool relocate = true;
 
     // The ldMin and ldMax fields are required to know how large of an
     // area is required to map the interpreter.
-    Addr ldMin;
-    Addr ldMax;
+    Addr ldMin = MaxAddr;
+    Addr ldMax = MaxAddr;
 
     /// Helper functions for loadGlobalSymbols() and loadLocalSymbols().
     bool loadSomeSymbols(SymbolTable *symtab, int binding, Addr mask,
                          Addr base, Addr offset);
 
-    ElfObject(const std::string &_filename, size_t _len, uint8_t *_data,
-              Arch _arch, OpSys _opSys);
-
     void getSections();
     bool sectionExists(std::string sec);
 
     MemoryImage image;
 
   public:
-    virtual ~ElfObject() {}
+    ElfObject(ImageFileDataPtr ifd);
+    ~ElfObject();
 
     MemoryImage buildImage() const override { return image; }
 
@@ -111,12 +123,9 @@
 
     bool hasTLS() override { return sectionExists(".tbss"); }
 
-    static ObjectFile *tryFile(const std::string &fname,
-                               size_t len, uint8_t *data,
-                               bool skip_interp_check = false);
     Addr programHeaderTable() {return _programHeaderTable;}
     uint16_t programHeaderSize() {return _programHeaderSize;}
     uint16_t programHeaderCount() {return _programHeaderCount;}
 };
 
-#endif // __ELF_OBJECT_HH__
+#endif // __BASE_LOADER_ELF_OBJECT_HH__
diff --git a/src/base/loader/raw_object.hh b/src/base/loader/image_file.hh
similarity index 61%
copy from src/base/loader/raw_object.hh
copy to src/base/loader/image_file.hh
index 6dc54c7..79d31a4 100644
--- a/src/base/loader/raw_object.hh
+++ b/src/base/loader/image_file.hh
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2006 The Regents of The University of Michigan
+ * Copyright (c) 2002-2004 The Regents of The University of Michigan
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -25,36 +25,28 @@
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
- * Authors: Ali Saidi
+ * Authors: Nathan Binkert
+ *          Steve Reinhardt
  */
 
-#ifndef __BASE_LOADER_RAW_OBJECT_HH__
-#define __BASE_LOADER_RAW_OBJECT_HH__
+#ifndef __BASE_LOADER_IMAGE_FILE_HH__
+#define __BASE_LOADER_IMAGE_FILE_HH__
 
-#include "base/loader/object_file.hh"
+#include <cstdint>
+#include <string>
 
-class RawObject: public ObjectFile
+#include "base/loader/image_file_data.hh"
+#include "base/loader/memory_image.hh"
+
+class ImageFile
 {
   protected:
-    RawObject(const std::string &_filename, size_t _len,
-              uint8_t *_data, Arch _arch, OpSys _opSys);
+    ImageFileDataPtr imageData;
+    ImageFile(ImageFileDataPtr data) : imageData(data) {}
+    virtual ~ImageFile() {}
 
   public:
-    virtual ~RawObject() {}
-
-    MemoryImage buildImage() const override;
-
-    bool loadAllSymbols(SymbolTable *symtab, Addr base=0,
-                        Addr offset=0, Addr addr_mask=MaxAddr) override;
-    bool loadGlobalSymbols(SymbolTable *symtab, Addr base=0,
-                           Addr offset=0, Addr addr_mask=MaxAddr) override;
-    bool loadLocalSymbols(SymbolTable *symtab, Addr base=0,
-                          Addr offset=0, Addr addr_mask=MaxAddr) override;
-
-    static ObjectFile *tryFile(const std::string &fname, size_t len,
-            uint8_t *data);
+    virtual MemoryImage buildImage() const = 0;
 };
 
-
-
-#endif // __BASE_LOADER_RAW_OBJECT_HH__
+#endif // __BASE_LOADER_IMAGE_FILE_HH__
diff --git a/src/base/loader/image_file_data.cc b/src/base/loader/image_file_data.cc
new file mode 100644
index 0000000..12cba77
--- /dev/null
+++ b/src/base/loader/image_file_data.cc
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 2002-2004 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Nathan Binkert
+ *          Steve Reinhardt
+ */
+
+#include "base/loader/image_file_data.hh"
+
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <zlib.h>
+
+#include <cstdio>
+#include <vector>
+
+#include "base/logging.hh"
+
+static bool
+hasGzipMagic(int fd)
+{
+    uint8_t buf[2] = {0};
+    size_t sz = pread(fd, buf, 2, 0);
+    panic_if(sz != 2, "Couldn't read magic bytes from object file");
+    return ((buf[0] == 0x1f) && (buf[1] == 0x8b));
+}
+
+static int
+doGzipLoad(int fd)
+{
+    const size_t blk_sz = 4096;
+
+    gzFile fdz = gzdopen(fd, "rb");
+    if (!fdz) {
+        return -1;
+    }
+
+    size_t tmp_len = strlen(P_tmpdir);
+    char *tmpnam = (char*) malloc(tmp_len + 20);
+    strcpy(tmpnam, P_tmpdir);
+    strcpy(tmpnam+tmp_len, "/gem5-gz-obj-XXXXXX"); // 19 chars
+    fd = mkstemp(tmpnam); // repurposing fd variable for output
+    if (fd < 0) {
+        free(tmpnam);
+        gzclose(fdz);
+        return fd;
+    }
+
+    if (unlink(tmpnam) != 0)
+        warn("couldn't remove temporary file %s\n", tmpnam);
+
+    free(tmpnam);
+
+    auto buf = new uint8_t[blk_sz];
+    int r; // size of (r)emaining uncopied data in (buf)fer
+    while ((r = gzread(fdz, buf, blk_sz)) > 0) {
+        auto p = buf; // pointer into buffer
+        while (r > 0) {
+            auto sz = write(fd, p, r);
+            assert(sz <= r);
+            r -= sz;
+            p += sz;
+        }
+    }
+    delete[] buf;
+    gzclose(fdz);
+    if (r < 0) { // error
+        close(fd);
+        return -1;
+    }
+    assert(r == 0); // finished successfully
+    return fd; // return fd to decompressed temporary file for mmap()'ing
+}
+
+ImageFileData::ImageFileData(const std::string &fname)
+{
+    _filename = fname;
+
+    // Open the file.
+    int fd = open(fname.c_str(), O_RDONLY);
+    panic_if(fd < 0, "Failed to open file %s.\n", fname);
+
+    // Decompress GZ files.
+    if (hasGzipMagic(fd)) {
+        fd = doGzipLoad(fd);
+        panic_if(fd < 0, "Failed to unzip file %s.\n", fname);
+    }
+
+    // Find the length of the file by seeking to the end.
+    off_t off = lseek(fd, 0, SEEK_END);
+    fatal_if(off < 0, "Failed to determine size of file %s.\n", fname);
+    _len = static_cast<size_t>(off);
+
+    // Mmap the whole shebang.
+    _data = (uint8_t *)mmap(NULL, _len, PROT_READ, MAP_SHARED, fd, 0);
+    close(fd);
+
+    panic_if(_data == MAP_FAILED, "Failed to mmap file %s.\n", fname);
+}
+
+ImageFileData::~ImageFileData()
+{
+    munmap((void *)_data, _len);
+}
diff --git a/src/base/loader/raw_object.hh b/src/base/loader/image_file_data.hh
similarity index 61%
copy from src/base/loader/raw_object.hh
copy to src/base/loader/image_file_data.hh
index 6dc54c7..8810ae4 100644
--- a/src/base/loader/raw_object.hh
+++ b/src/base/loader/image_file_data.hh
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2006 The Regents of The University of Michigan
+ * Copyright (c) 2002-2004 The Regents of The University of Michigan
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -25,36 +25,33 @@
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
- * Authors: Ali Saidi
+ * Authors: Nathan Binkert
+ *          Steve Reinhardt
  */
 
-#ifndef __BASE_LOADER_RAW_OBJECT_HH__
-#define __BASE_LOADER_RAW_OBJECT_HH__
+#ifndef __BASE_LOADER_IMAGE_FILE_DATA_HH__
+#define __BASE_LOADER_IMAGE_FILE_DATA_HH__
 
-#include "base/loader/object_file.hh"
+#include <cstdint>
+#include <memory>
+#include <string>
 
-class RawObject: public ObjectFile
+class ImageFileData
 {
-  protected:
-    RawObject(const std::string &_filename, size_t _len,
-              uint8_t *_data, Arch _arch, OpSys _opSys);
+  private:
+    std::string _filename;
+    uint8_t *_data;
+    size_t _len;
 
   public:
-    virtual ~RawObject() {}
+    const std::string &filename() const { return _filename; }
+    uint8_t const *data() const { return _data; }
+    size_t len() const { return _len; }
 
-    MemoryImage buildImage() const override;
-
-    bool loadAllSymbols(SymbolTable *symtab, Addr base=0,
-                        Addr offset=0, Addr addr_mask=MaxAddr) override;
-    bool loadGlobalSymbols(SymbolTable *symtab, Addr base=0,
-                           Addr offset=0, Addr addr_mask=MaxAddr) override;
-    bool loadLocalSymbols(SymbolTable *symtab, Addr base=0,
-                          Addr offset=0, Addr addr_mask=MaxAddr) override;
-
-    static ObjectFile *tryFile(const std::string &fname, size_t len,
-            uint8_t *data);
+    ImageFileData(const std::string &f_name);
+    virtual ~ImageFileData();
 };
 
+typedef std::shared_ptr<ImageFileData> ImageFileDataPtr;
 
-
-#endif // __BASE_LOADER_RAW_OBJECT_HH__
+#endif // __BASE_LOADER_IMAGE_FILE_DATA_HH__
diff --git a/src/base/loader/memory_image.hh b/src/base/loader/memory_image.hh
index 866e956..a10daba 100644
--- a/src/base/loader/memory_image.hh
+++ b/src/base/loader/memory_image.hh
@@ -32,37 +32,63 @@
 #ifndef __BASE_LOADER_MEMORY_IMAGE_HH__
 #define __BASE_LOADER_MEMORY_IMAGE_HH__
 
+#include <algorithm>
 #include <functional>
 #include <initializer_list>
 #include <memory>
 #include <string>
 #include <vector>
 
+#include "base/loader/image_file_data.hh"
 #include "base/logging.hh"
 #include "base/types.hh"
 
 class PortProxy;
-class Process;
-class ProcessParams;
-class SymbolTable;
 
 class MemoryImage
 {
   public:
     struct Segment
     {
+        Segment(const std::string &_name, Addr _base,
+                const uint8_t *_data, size_t _size) :
+            name(_name), base(_base), data(_data), size(_size)
+        {}
+
+        Segment(const std::string &_name, Addr _base, size_t _size) :
+            name(_name), base(_base), size(_size)
+        {}
+
+        Segment(const std::string &_name, Addr _base,
+                const ImageFileDataPtr &_ifd, Addr offset, size_t _size) :
+            ifd(_ifd), name(_name), base(_base), size(_size)
+        {
+            panic_if(offset + size > ifd->len(),
+                    "Segment outside the bounds of the image data");
+            data = ifd->data() + offset;
+        }
+
+        Segment(const std::string &_name, const ImageFileDataPtr &_ifd) :
+            Segment(_name, 0, _ifd, 0, _ifd->len())
+        {}
+
+        ImageFileDataPtr ifd;
         std::string name;
-        Addr base;
-        uint8_t *data;
-        size_t size;
+        Addr base = 0;
+        const uint8_t *data = nullptr;
+        size_t size = 0;
     };
 
     MemoryImage() {}
 
-    MemoryImage(std::initializer_list<Segment> new_segs)
+    MemoryImage(const Segment &seg)
     {
-        for (auto &seg: new_segs)
-            addSegment(seg);
+        addSegment(seg);
+    }
+
+    MemoryImage(std::initializer_list<Segment> segs)
+    {
+        addSegments(segs);
     }
 
   private:
@@ -83,9 +109,10 @@
     }
 
     void
-    addSegment(std::string name, Addr base, uint8_t *data, size_t size)
+    addSegments(std::initializer_list<Segment> segs)
     {
-        _segments.push_back(Segment({name, base, data, size}));
+        for (auto &seg: segs)
+            addSegment(seg);
     }
 
     bool write(const PortProxy &proxy) const;
@@ -104,11 +131,8 @@
     maxAddr() const
     {
         Addr max = 0;
-        for (auto &seg: _segments) {
-            Addr end = seg.base + seg.size;
-            if (end > max)
-                max = end;
-        }
+        for (auto &seg: _segments)
+            max = std::max(max, seg.base + seg.size);
         return max;
     }
 
@@ -117,8 +141,7 @@
     {
         Addr min = MaxAddr;
         for (auto &seg: _segments)
-            if (seg.base < min)
-                min = seg.base;
+            min = std::min(min, seg.base);
         return min;
     }
 
diff --git a/src/base/loader/object_file.cc b/src/base/loader/object_file.cc
index afecd21..b7e0542 100644
--- a/src/base/loader/object_file.cc
+++ b/src/base/loader/object_file.cc
@@ -31,44 +31,16 @@
 
 #include "base/loader/object_file.hh"
 
-#include <fcntl.h>
-#include <sys/mman.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include <zlib.h>
-
-#include <cstdio>
-#include <list>
 #include <string>
 #include <vector>
 
-#include "base/cprintf.hh"
-#include "base/loader/aout_object.hh"
-#include "base/loader/dtb_object.hh"
-#include "base/loader/ecoff_object.hh"
-#include "base/loader/elf_object.hh"
-#include "base/loader/raw_object.hh"
+#include "base/loader/raw_image.hh"
 #include "base/loader/symtab.hh"
 #include "mem/port_proxy.hh"
 
 using namespace std;
 
-ObjectFile::ObjectFile(const string &_filename,
-                       size_t _len, uint8_t *_data,
-                       Arch _arch, OpSys _op_sys)
-    : filename(_filename), fileData(_data), len(_len),
-      arch(_arch), opSys(_op_sys), entry(0)
-{}
-
-
-ObjectFile::~ObjectFile()
-{
-    if (fileData) {
-        ::munmap((char*)fileData, len);
-        fileData = NULL;
-    }
-}
-
+ObjectFile::ObjectFile(ImageFileDataPtr ifd) : ImageFile(ifd) {}
 
 namespace
 {
@@ -101,117 +73,37 @@
     return nullptr;
 }
 
-static bool
-hasGzipMagic(int fd)
+namespace {
+
+typedef std::vector<ObjectFileFormat *> ObjectFileFormatList;
+
+ObjectFileFormatList &
+object_file_formats()
 {
-    uint8_t buf[2] = {0};
-    size_t sz = pread(fd, buf, 2, 0);
-    panic_if(sz != 2, "Couldn't read magic bytes from object file");
-    return ((buf[0] == 0x1f) && (buf[1] == 0x8b));
+    static ObjectFileFormatList formats;
+    return formats;
 }
 
-static int
-doGzipLoad(int fd)
+} // anonymous namespace
+
+ObjectFileFormat::ObjectFileFormat()
 {
-    const size_t blk_sz = 4096;
-
-    gzFile fdz = gzdopen(fd, "rb");
-    if (!fdz) {
-        return -1;
-    }
-
-    size_t tmp_len = strlen(P_tmpdir);
-    char *tmpnam = (char*) malloc(tmp_len + 20);
-    strcpy(tmpnam, P_tmpdir);
-    strcpy(tmpnam+tmp_len, "/gem5-gz-obj-XXXXXX"); // 19 chars
-    fd = mkstemp(tmpnam); // repurposing fd variable for output
-    if (fd < 0) {
-        free(tmpnam);
-        gzclose(fdz);
-        return fd;
-    }
-
-    if (unlink(tmpnam) != 0)
-        warn("couldn't remove temporary file %s\n", tmpnam);
-
-    free(tmpnam);
-
-    auto buf = new uint8_t[blk_sz];
-    int r; // size of (r)emaining uncopied data in (buf)fer
-    while ((r = gzread(fdz, buf, blk_sz)) > 0) {
-        auto p = buf; // pointer into buffer
-        while (r > 0) {
-            auto sz = write(fd, p, r);
-            assert(sz <= r);
-            r -= sz;
-            p += sz;
-        }
-    }
-    delete[] buf;
-    gzclose(fdz);
-    if (r < 0) { // error
-        close(fd);
-        return -1;
-    }
-    assert(r == 0); // finished successfully
-    return fd; // return fd to decompressed temporary file for mmap()'ing
+    object_file_formats().emplace_back(this);
 }
 
 ObjectFile *
-createObjectFile(const string &fname, bool raw)
+createObjectFile(const std::string &fname, bool raw)
 {
-    // open the file
-    int fd = open(fname.c_str(), O_RDONLY);
-    if (fd < 0) {
-        return NULL;
-    }
+    ImageFileDataPtr ifd(new ImageFileData(fname));
 
-    // decompress GZ files
-    if (hasGzipMagic(fd)) {
-        fd = doGzipLoad(fd);
-        if (fd < 0) {
-            return NULL;
-        }
-    }
-
-    // find the length of the file by seeking to the end
-    off_t off = lseek(fd, 0, SEEK_END);
-    fatal_if(off < 0,
-             "Failed to determine size of object file %s\n", fname);
-    auto len = static_cast<size_t>(off);
-
-    // mmap the whole shebang
-    uint8_t *file_data = (uint8_t *)mmap(NULL, len, PROT_READ, MAP_SHARED,
-                                         fd, 0);
-    close(fd);
-
-    if (file_data == MAP_FAILED) {
-        return NULL;
-    }
-
-    ObjectFile *file_obj = NULL;
-
-    // figure out what we have here
-    if ((file_obj = ElfObject::tryFile(fname, len, file_data)) != NULL) {
-        return file_obj;
-    }
-
-    if ((file_obj = EcoffObject::tryFile(fname, len, file_data)) != NULL) {
-        return file_obj;
-    }
-
-    if ((file_obj = AoutObject::tryFile(fname, len, file_data)) != NULL) {
-        return file_obj;
-    }
-
-    if ((file_obj = DtbObject::tryFile(fname, len, file_data)) != NULL) {
-        return file_obj;
+    for (auto &format: object_file_formats()) {
+        ObjectFile *file_obj = format->load(ifd);
+        if (file_obj)
+            return file_obj;
     }
 
     if (raw)
-        return RawObject::tryFile(fname, len, file_data);
+        return new RawImage(ifd);
 
-    // don't know what it is
-    munmap((char*)file_data, len);
-    return NULL;
+    return nullptr;
 }
diff --git a/src/base/loader/object_file.hh b/src/base/loader/object_file.hh
index 669afeb..da35db1 100644
--- a/src/base/loader/object_file.hh
+++ b/src/base/loader/object_file.hh
@@ -29,24 +29,22 @@
  *          Steve Reinhardt
  */
 
-#ifndef __OBJECT_FILE_HH__
-#define __OBJECT_FILE_HH__
+#ifndef __BASE_LOADER_OBJECT_FILE_HH__
+#define __BASE_LOADER_OBJECT_FILE_HH__
 
-#include <limits>
-#include <memory>
 #include <string>
-#include <vector>
 
+#include "base/loader/image_file.hh"
+#include "base/loader/image_file_data.hh"
 #include "base/loader/memory_image.hh"
 #include "base/logging.hh"
 #include "base/types.hh"
 
-class PortProxy;
 class Process;
 class ProcessParams;
 class SymbolTable;
 
-class ObjectFile
+class ObjectFile : public ImageFile
 {
   public:
 
@@ -76,37 +74,51 @@
     };
 
   protected:
-    const std::string filename;
-    uint8_t *fileData;
-    size_t len;
+    Arch arch = UnknownArch;
+    OpSys opSys = UnknownOpSys;
 
-    Arch arch;
-    OpSys opSys;
-
-    ObjectFile(const std::string &_filename, size_t _len, uint8_t *_data,
-               Arch _arch, OpSys _opSys);
+    ObjectFile(ImageFileDataPtr ifd);
 
   public:
-    virtual ~ObjectFile();
+    virtual ~ObjectFile() {};
 
-    virtual MemoryImage buildImage() const = 0;
-
-    virtual bool loadAllSymbols(SymbolTable *symtab, Addr base = 0,
-                                Addr offset=0, Addr mask=MaxAddr) = 0;
-    virtual bool loadGlobalSymbols(SymbolTable *symtab, Addr base = 0,
-                                   Addr offset=0, Addr mask=MaxAddr) = 0;
-    virtual bool loadLocalSymbols(SymbolTable *symtab, Addr base=0,
-                                  Addr offset=0, Addr mask=MaxAddr) = 0;
-    virtual bool loadWeakSymbols(SymbolTable *symtab, Addr base=0,
-                                 Addr offset=0, Addr mask=MaxAddr)
-    { return false; }
+    virtual bool
+    loadAllSymbols(SymbolTable *symtab, Addr base=0,
+            Addr offset=0, Addr mask=MaxAddr)
+    {
+        return true;
+    };
+    virtual bool
+    loadGlobalSymbols(SymbolTable *symtab, Addr base=0,
+                      Addr offset=0, Addr mask=MaxAddr)
+    {
+        return true;
+    }
+    virtual bool
+    loadLocalSymbols(SymbolTable *symtab, Addr base=0,
+                     Addr offset=0, Addr mask=MaxAddr)
+    {
+        return true;
+    }
+    virtual bool
+    loadWeakSymbols(SymbolTable *symtab, Addr base=0,
+                    Addr offset=0, Addr mask=MaxAddr)
+    {
+        return true;
+    }
 
     virtual ObjectFile *getInterpreter() const { return nullptr; }
     virtual bool relocatable() const { return false; }
-    virtual Addr mapSize() const
-    { panic("mapSize() should only be called on relocatable objects\n"); }
-    virtual void updateBias(Addr bias_addr)
-    { panic("updateBias() should only be called on relocatable objects\n"); }
+    virtual Addr
+    mapSize() const
+    {
+        panic("mapSize() should only be called on relocatable objects\n");
+    }
+    virtual void
+    updateBias(Addr bias_addr)
+    {
+        panic("updateBias() should only be called on relocatable objects\n");
+    }
     virtual Addr bias() const { return 0; }
 
     virtual bool hasTLS() { return false; }
@@ -115,7 +127,7 @@
     OpSys getOpSys() const { return opSys; }
 
   protected:
-    Addr entry;
+    Addr entry = 0;
 
   public:
     Addr entryPoint() const { return entry; }
@@ -153,7 +165,18 @@
     static Process *tryLoaders(ProcessParams *params, ObjectFile *obj_file);
 };
 
-ObjectFile *createObjectFile(const std::string &fname, bool raw = false);
+class ObjectFileFormat
+{
+  protected:
+    ObjectFileFormat();
 
+  public:
+    ObjectFileFormat(const ObjectFileFormat &) = delete;
+    void operator=(const ObjectFileFormat &) = delete;
 
-#endif // __OBJECT_FILE_HH__
+    virtual ObjectFile *load(ImageFileDataPtr data) = 0;
+};
+
+ObjectFile *createObjectFile(const std::string &fname, bool raw=false);
+
+#endif // __BASE_LOADER_OBJECT_FILE_HH__
diff --git a/src/base/loader/raw_object.hh b/src/base/loader/raw_image.hh
similarity index 66%
rename from src/base/loader/raw_object.hh
rename to src/base/loader/raw_image.hh
index 6dc54c7..aae82a3 100644
--- a/src/base/loader/raw_object.hh
+++ b/src/base/loader/raw_image.hh
@@ -28,33 +28,27 @@
  * Authors: Ali Saidi
  */
 
-#ifndef __BASE_LOADER_RAW_OBJECT_HH__
-#define __BASE_LOADER_RAW_OBJECT_HH__
+#ifndef __BASE_LOADER_RAW_IMAGE_HH__
+#define __BASE_LOADER_RAW_IMAGE_HH__
 
 #include "base/loader/object_file.hh"
 
-class RawObject: public ObjectFile
+class RawImage: public ObjectFile
 {
-  protected:
-    RawObject(const std::string &_filename, size_t _len,
-              uint8_t *_data, Arch _arch, OpSys _opSys);
-
   public:
-    virtual ~RawObject() {}
+    RawImage(ImageFileDataPtr ifd) : ObjectFile(ifd) {}
 
-    MemoryImage buildImage() const override;
+    RawImage(const std::string &filename) :
+        RawImage(ImageFileDataPtr(new ImageFileData(filename)))
+    {}
 
-    bool loadAllSymbols(SymbolTable *symtab, Addr base=0,
-                        Addr offset=0, Addr addr_mask=MaxAddr) override;
-    bool loadGlobalSymbols(SymbolTable *symtab, Addr base=0,
-                           Addr offset=0, Addr addr_mask=MaxAddr) override;
-    bool loadLocalSymbols(SymbolTable *symtab, Addr base=0,
-                          Addr offset=0, Addr addr_mask=MaxAddr) override;
-
-    static ObjectFile *tryFile(const std::string &fname, size_t len,
-            uint8_t *data);
+    MemoryImage
+    buildImage() const override
+    {
+        return {{ "data", imageData }};
+    }
 };
 
 
 
-#endif // __BASE_LOADER_RAW_OBJECT_HH__
+#endif // __BASE_LOADER_RAW_IMAGE_HH__
diff --git a/src/base/loader/raw_object.cc b/src/base/loader/raw_object.cc
deleted file mode 100644
index 35ed485..0000000
--- a/src/base/loader/raw_object.cc
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright (c) 2006 The Regents of The University of Michigan
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met: redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer;
- * redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution;
- * neither the name of the copyright holders nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Authors: Steve Reinhardt
- */
-
-#include "base/loader/raw_object.hh"
-
-#include "base/loader/symtab.hh"
-#include "base/trace.hh"
-#include "debug/Loader.hh"
-
-ObjectFile *
-RawObject::tryFile(const std::string &fname, size_t len, uint8_t *data)
-{
-    return new RawObject(fname, len, data, ObjectFile::UnknownArch,
-            ObjectFile::UnknownOpSys);
-}
-
-RawObject::RawObject(const std::string &_filename, size_t _len,
-        uint8_t *_data, Arch _arch, OpSys _opSys)
-    : ObjectFile(_filename, _len, _data, _arch, _opSys)
-{
-}
-
-MemoryImage
-RawObject::buildImage() const
-{
-    return {{ "data", 0, fileData, len }};
-}
-
-bool
-RawObject::loadAllSymbols(SymbolTable *symtab, Addr base, Addr offset,
-                          Addr addr_mask)
-{
-    return true;
-}
-
-bool
-RawObject::loadGlobalSymbols(SymbolTable *symtab, Addr base, Addr offset,
-                             Addr addr_mask)
-{
-    return true;
-}
-
-bool
-RawObject::loadLocalSymbols(SymbolTable *symtab, Addr base, Addr offset,
-                            Addr addr_mask)
-{
-    return true;
-}