arch, base: Stop assuming object files have three segments.
authorGabe Black <gabeblack@google.com>
Tue, 1 Oct 2019 08:25:53 +0000 (01:25 -0700)
committerGabe Black <gabeblack@google.com>
Thu, 10 Oct 2019 01:25:17 +0000 (01:25 +0000)
The ObjectFile class has hardcoded assumptions that there are three
segments, text, bss and data. There are some files which have one
"segment" like raw files, where the entire file's contents are
considered a single segment. There are also ELF files which can have
an arbitrary number of segments, and those segments can hold any
number of sections, including the text, data and/or bss sections.

Removing this assumption frees up some object file formats from having
to twist themselves to fit in that structure, possibly introducing
ambiguities when some segments may fulfill multiple roles.

Change-Id: I976e06a3a90ef852b17a6485e2595b006b2090d5
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/21463
Tested-by: kokoro <noreply+kokoro@google.com>
Reviewed-by: Andreas Sandberg <andreas.sandberg@arm.com>
Maintainer: Gabe Black <gabeblack@google.com>

23 files changed:
src/arch/alpha/process.cc
src/arch/alpha/system.cc
src/arch/arm/freebsd/system.cc
src/arch/arm/linux/system.cc
src/arch/arm/process.cc
src/arch/mips/process.cc
src/arch/power/process.cc
src/arch/riscv/process.cc
src/arch/sparc/process.hh
src/arch/sparc/system.cc
src/arch/x86/process.cc
src/base/loader/aout_object.cc
src/base/loader/dtb_object.cc
src/base/loader/dtb_object.hh
src/base/loader/ecoff_object.cc
src/base/loader/elf_object.cc
src/base/loader/elf_object.hh
src/base/loader/object_file.cc
src/base/loader/object_file.hh
src/base/loader/raw_object.cc
src/base/loader/raw_object.hh
src/sim/syscall_emul.hh
src/sim/system.cc

index d0bfa79c8af66ef287a2542985e894aba59f3442..59cbebc1c664f98a3091b0aa689cd430e8484c9c 100644 (file)
@@ -54,12 +54,10 @@ AlphaProcess::AlphaProcess(ProcessParams *params, ObjectFile *objFile)
       objFile)
 {
     fatal_if(params->useArchPT, "Arch page tables not implemented.");
-    Addr brk_point = objFile->dataBase() + objFile->dataSize() +
-                     objFile->bssSize();
-    brk_point = roundUp(brk_point, PageBytes);
+    Addr brk_point = roundUp(objFile->maxSegmentAddr(), PageBytes);
 
     // Set up stack.  On Alpha, stack goes below the image.
-    Addr stack_base = objFile->textBase() - (409600 + 4096);
+    Addr stack_base = objFile->minSegmentAddr() - (409600 + 4096);
 
     // Set up region for mmaps.
     Addr mmap_end = 0x10000;
index 7bff6da014504c3a637f5bed75bab11a120c3571..31e7aa062a4c42298cede3b08c58b5bb5acdf5bc 100644 (file)
@@ -57,11 +57,13 @@ AlphaSystem::AlphaSystem(Params *p)
      */
     // Load Console Code
     console = createObjectFile(params()->console);
+    console->setLoadMask(loadAddrMask);
     if (console == NULL)
         fatal("Could not load console file %s", params()->console);
 
     // Load pal file
     pal = createObjectFile(params()->pal);
+    pal->setLoadMask(loadAddrMask);
     if (pal == NULL)
         fatal("Could not load PALcode file %s", params()->pal);
 
@@ -109,8 +111,8 @@ AlphaSystem::initState()
     System::initState();
 
     // Load program sections into memory
-    pal->loadSegments(physProxy, loadAddrMask);
-    console->loadSegments(physProxy, loadAddrMask);
+    pal->loadSegments(physProxy);
+    console->loadSegments(physProxy);
 
     /**
      * Copy the osflags (kernel arguments) into the consoles
index 6e544a70ea60b62f409eb867027927c726ead473..764f036b42076e083f5c4cd588bab65fd4f945c7 100644 (file)
@@ -132,7 +132,7 @@ FreebsdArmSystem::initState()
     if (ra)
         bootReleaseAddr = ra & ~ULL(0x7F);
 
-    dtb_file->setTextBase(params()->atags_addr + loadAddrOffset);
+    dtb_file->setLoadOffset(params()->atags_addr + loadAddrOffset);
     dtb_file->loadSegments(physProxy);
     delete dtb_file;
 
index f03a5c6cb98f298c64243b57368fc0a50d2ce2f4..a0869b46a892479401608a3d5af11e0cfa827cee 100644 (file)
@@ -151,7 +151,7 @@ LinuxArmSystem::initState()
                  "to DTB file: %s\n", params()->dtb_filename);
         }
 
-        dtb_file->setTextBase(params()->atags_addr + loadAddrOffset);
+        dtb_file->setLoadOffset(params()->atags_addr + loadAddrOffset);
         dtb_file->loadSegments(physProxy);
         delete dtb_file;
     } else {
index 1a1d4a2a0d2965bb4e63cf0b6e01651338d95e39..f98572690995d3ff47f8ab33bc4aea58e32ce7d1 100644 (file)
@@ -75,8 +75,7 @@ ArmProcess32::ArmProcess32(ProcessParams *params, ObjectFile *objFile,
                            ObjectFile::Arch _arch)
     : ArmProcess(params, objFile, _arch)
 {
-    Addr brk_point = roundUp(objFile->dataBase() + objFile->dataSize() +
-                             objFile->bssSize(), PageBytes);
+    Addr brk_point = roundUp(objFile->maxSegmentAddr(), PageBytes);
     Addr stack_base = 0xbf000000L;
     Addr max_stack_size = 8 * 1024 * 1024;
     Addr next_thread_stack_base = stack_base - max_stack_size;
@@ -90,8 +89,7 @@ ArmProcess64::ArmProcess64(ProcessParams *params, ObjectFile *objFile,
                            ObjectFile::Arch _arch)
     : ArmProcess(params, objFile, _arch)
 {
-    Addr brk_point = roundUp(objFile->dataBase() + objFile->dataSize() +
-                             objFile->bssSize(), PageBytes);
+    Addr brk_point = roundUp(objFile->maxSegmentAddr(), PageBytes);
     Addr stack_base = 0x7fffff0000L;
     Addr max_stack_size = 8 * 1024 * 1024;
     Addr next_thread_stack_base = stack_base - max_stack_size;
index e3405fdaacf076b30a137b0c5379256532248d12..1808372d95f4f770212231a41ff3d173edb389f9 100644 (file)
@@ -65,8 +65,7 @@ MipsProcess::MipsProcess(ProcessParams *params, ObjectFile *objFile)
     Addr next_thread_stack_base = stack_base - max_stack_size;
 
     // Set up break point (Top of Heap)
-    Addr brk_point = objFile->dataBase() + objFile->dataSize() +
-                     objFile->bssSize();
+    Addr brk_point = objFile->maxSegmentAddr();
     brk_point = roundUp(brk_point, PageBytes);
 
     // Set up region for mmaps.  Start it 1GB above the top of the heap.
index 467c820f2fa798bc1a7a7530ac52d429a7fd6087..b391773ee606b66a773122358377767a1669bd53 100644 (file)
@@ -56,8 +56,7 @@ PowerProcess::PowerProcess(ProcessParams *params, ObjectFile *objFile)
 {
     fatal_if(params->useArchPT, "Arch page tables not implemented.");
     // Set up break point (Top of Heap)
-    Addr brk_point = objFile->dataBase() + objFile->dataSize() +
-                     objFile->bssSize();
+    Addr brk_point = objFile->maxSegmentAddr();
     brk_point = roundUp(brk_point, PageBytes);
 
     Addr stack_base = 0xbf000000L;
index ca3f0e2b866a879cdf519816eb722b1d94131939..e15197d786e835cccffcf7aa53b3f0e6f0fb2ddf 100644 (file)
@@ -75,8 +75,7 @@ RiscvProcess64::RiscvProcess64(ProcessParams *params, ObjectFile *objFile) :
     const Addr stack_base = 0x7FFFFFFFFFFFFFFFL;
     const Addr max_stack_size = 8 * 1024 * 1024;
     const Addr next_thread_stack_base = stack_base - max_stack_size;
-    const Addr brk_point = roundUp(objFile->bssBase() + objFile->bssSize(),
-            PageBytes);
+    const Addr brk_point = roundUp(objFile->maxSegmentAddr(), PageBytes);
     const Addr mmap_end = 0x4000000000000000L;
     memState = make_shared<MemState>(brk_point, stack_base, max_stack_size,
             next_thread_stack_base, mmap_end);
@@ -88,8 +87,7 @@ RiscvProcess32::RiscvProcess32(ProcessParams *params, ObjectFile *objFile) :
     const Addr stack_base = 0x7FFFFFFF;
     const Addr max_stack_size = 8 * 1024 * 1024;
     const Addr next_thread_stack_base = stack_base - max_stack_size;
-    const Addr brk_point = roundUp(objFile->bssBase() + objFile->bssSize(),
-            PageBytes);
+    const Addr brk_point = roundUp(objFile->maxSegmentAddr(), PageBytes);
     const Addr mmap_end = 0x40000000L;
     memState = make_shared<MemState>(brk_point, stack_base, max_stack_size,
                                      next_thread_stack_base, mmap_end);
index eeb267116382f79fa42bac07c39d20e2bcfd1a70..f8f19f2905828bd82d0d2c6b8480f6557940922c 100644 (file)
@@ -78,8 +78,7 @@ class Sparc32Process : public SparcProcess
     Sparc32Process(ProcessParams * params, ObjectFile *objFile)
         : SparcProcess(params, objFile, 0)
     {
-        Addr brk_point = objFile->dataBase() + objFile->dataSize() +
-                         objFile->bssSize();
+        Addr brk_point = objFile->maxSegmentAddr();
         brk_point = roundUp(brk_point, SparcISA::PageBytes);
 
         // Reserve 8M for main stack.
@@ -123,8 +122,7 @@ class Sparc64Process : public SparcProcess
     Sparc64Process(ProcessParams * params, ObjectFile *objFile)
         : SparcProcess(params, objFile, 2047)
     {
-        Addr brk_point = objFile->dataBase() + objFile->dataSize() +
-                         objFile->bssSize();
+        Addr brk_point = objFile->maxSegmentAddr();
         brk_point = roundUp(brk_point, SparcISA::PageBytes);
 
         Addr max_stack_size = 8 * 1024 * 1024;
index 5896061a6b9752092c9cb70360da09195b2e1a90..e9615b00c59e176791144f92fa5cd1cfd027b213 100644 (file)
@@ -137,22 +137,22 @@ SparcSystem::initState()
     System::initState();
 
     // Load reset binary into memory
-    reset->setTextBase(params()->reset_addr);
+    reset->setLoadOffset(params()->reset_addr);
     reset->loadSegments(physProxy);
     // Load the openboot binary
-    openboot->setTextBase(params()->openboot_addr);
+    openboot->setLoadOffset(params()->openboot_addr);
     openboot->loadSegments(physProxy);
     // Load the hypervisor binary
-    hypervisor->setTextBase(params()->hypervisor_addr);
+    hypervisor->setLoadOffset(params()->hypervisor_addr);
     hypervisor->loadSegments(physProxy);
     // Load the nvram image
-    nvram->setTextBase(params()->nvram_addr);
+    nvram->setLoadOffset(params()->nvram_addr);
     nvram->loadSegments(physProxy);
     // Load the hypervisor description image
-    hypervisor_desc->setTextBase(params()->hypervisor_desc_addr);
+    hypervisor_desc->setLoadOffset(params()->hypervisor_desc_addr);
     hypervisor_desc->loadSegments(physProxy);
     // Load the partition description image
-    partition_desc->setTextBase(params()->partition_desc_addr);
+    partition_desc->setLoadOffset(params()->partition_desc_addr);
     partition_desc->loadSegments(physProxy);
 
 
index 60f4f474b039f1d79149783c157367f01f99386c..c743685d0bfd533adefd25a16779901c00ecb79e 100644 (file)
@@ -136,8 +136,7 @@ X86_64Process::X86_64Process(ProcessParams *params, ObjectFile *objFile,
     vsyscallPage.vtimeOffset = 0x400;
     vsyscallPage.vgettimeofdayOffset = 0x0;
 
-    Addr brk_point = roundUp(objFile->dataBase() + objFile->dataSize() +
-                             objFile->bssSize(), PageBytes);
+    Addr brk_point = roundUp(objFile->maxSegmentAddr(), PageBytes);
     Addr stack_base = 0x7FFFFFFFF000ULL;
     Addr max_stack_size = 8 * 1024 * 1024;
     Addr next_thread_stack_base = stack_base - max_stack_size;
@@ -176,8 +175,7 @@ I386Process::I386Process(ProcessParams *params, ObjectFile *objFile,
     vsyscallPage.vsyscallOffset = 0x400;
     vsyscallPage.vsysexitOffset = 0x410;
 
-    Addr brk_point = roundUp(objFile->dataBase() + objFile->dataSize() +
-                             objFile->bssSize(), PageBytes);
+    Addr brk_point = roundUp(objFile->maxSegmentAddr(), PageBytes);
     Addr stack_base = _gdtStart;
     Addr max_stack_size = 8 * 1024 * 1024;
     Addr next_thread_stack_base = stack_base - max_stack_size;
index e3f703e1d7d9e5bc47904b63ba2d93b674e1a66c..97651586fedb66c77fbe27cea3a49fb280cd97cb 100644 (file)
@@ -61,21 +61,14 @@ AoutObject::AoutObject(const string &_filename,
 
     entry = execHdr->entry;
 
-    text.base = N_TXTADDR(*execHdr);
-    text.size = execHdr->tsize;
-    text.data = fileData + N_TXTOFF(*execHdr);
-
-    data.base = N_DATADDR(*execHdr);
-    data.size = execHdr->dsize;
-    data.data = fileData + N_DATOFF(*execHdr);
-
-    bss.base = N_BSSADDR(*execHdr);
-    bss.size = execHdr->bsize;
-    bss.data = NULL;
-
-    DPRINTFR(Loader, "text: 0x%x %d\ndata: 0x%x %d\nbss: 0x%x %d\n",
-             text.base, text.size, data.base, data.size,
-             bss.base, bss.size);
+    addSegment("text", N_TXTADDR(*execHdr), fileData + N_TXTOFF(*execHdr),
+            execHdr->tsize);
+    addSegment("data", N_DATADDR(*execHdr), fileData + N_DATOFF(*execHdr),
+            execHdr->dsize);
+    addSegment("bss", N_BSSADDR(*execHdr), nullptr, execHdr->bsize);
+
+    for (auto &seg: segments)
+        DPRINTFR(Loader, "%s\n", *seg);
 }
 
 
index 92e305ffa9403482aae274bf9f8c5b49e6d37465..275139a8c9a958c98aad9c4b4241fc84b0ea75d6 100644 (file)
@@ -53,20 +53,10 @@ DtbObject::tryFile(const std::string &fname, size_t len, uint8_t *data)
 
 DtbObject::DtbObject(const std::string &_filename, size_t _len, uint8_t *_data,
                      Arch _arch, OpSys _opSys)
-    : ObjectFile(_filename, _len, _data, _arch, _opSys)
+    : ObjectFile(_filename, _len, _data, _arch, _opSys),
+    data(new Segment{ "data", 0, fileData, len })
 {
-    text.base = 0;
-    text.size = len;
-    text.data = fileData;
-
-    data.base = 0;
-    data.size = 0;
-    data.data = nullptr;
-
-    bss.base = 0;
-    bss.size = 0;
-    bss.data = nullptr;
-
+    segments.emplace_back(data);
     fileDataMmapped = true;
 }
 
@@ -92,10 +82,10 @@ DtbObject::addBootCmdLine(const char* _args, size_t len)
     const char* property_name = "bootargs";
 
     // Make a new buffer that has extra space to add nodes/properties
-    int newLen = 2*this->len;
-    uint8_tfdt_buf_w_space = new uint8_t[newLen];
+    int newLen = 2 * this->len;
+    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));
+    int ret = fdt_open_into((void *)fileData, (void *)fdt_buf_w_space, newLen);
     if (ret < 0) {
         warn("Error resizing buffer of flattened device tree, "
              "errno: %d\n", ret);
@@ -104,14 +94,15 @@ DtbObject::addBootCmdLine(const char* _args, size_t len)
     }
 
     // First try finding the /chosen node in the dtb
-    int offset = fdt_path_offset((void*)fdt_buf_w_space, full_path_node_name);
+    int offset = fdt_path_offset((void *)fdt_buf_w_space, full_path_node_name);
     if (offset < 0) {
         // try adding the node by walking dtb tree to proper insertion point
-        offset = fdt_path_offset((void*)fdt_buf_w_space, root_path);
-        offset = fdt_add_subnode((void*)fdt_buf_w_space, offset, node_name);
+        offset = fdt_path_offset((void *)fdt_buf_w_space, root_path);
+        offset = fdt_add_subnode((void *)fdt_buf_w_space, offset, node_name);
         // if we successfully add the subnode, get the offset
         if (offset >= 0)
-          offset = fdt_path_offset((void*)fdt_buf_w_space, full_path_node_name);
+          offset = fdt_path_offset((void *)fdt_buf_w_space,
+                                   full_path_node_name);
 
         if (offset < 0) {
             warn("Error finding or adding \"chosen\" subnode to flattened "
@@ -122,8 +113,8 @@ DtbObject::addBootCmdLine(const char* _args, size_t len)
     }
 
     // Set the bootargs property in the /chosen node
-    ret = fdt_setprop((void*)fdt_buf_w_space, offset, property_name,
-                      (const void*)_args, len+1);
+    ret = fdt_setprop((void *)fdt_buf_w_space, offset, property_name,
+                      (const void *)_args, len+1);
     if (ret < 0) {
         warn("Error setting \"bootargs\" property to flattened device tree, "
              "errno: %d\n", ret);
@@ -132,7 +123,7 @@ DtbObject::addBootCmdLine(const char* _args, size_t len)
     }
 
     // Repack the dtb for kernel use
-    ret = fdt_pack((void*)fdt_buf_w_space);
+    ret = fdt_pack((void *)fdt_buf_w_space);
     if (ret < 0) {
         warn("Error re-packing flattened device tree structure, "
              "errno: %d\n", ret);
@@ -140,8 +131,8 @@ DtbObject::addBootCmdLine(const char* _args, size_t len)
         return false;
     }
 
-    text.size = newLen;
-    text.data = fdt_buf_w_space;
+    data->size = newLen;
+    data->data = fdt_buf_w_space;
 
     // clean up old buffer and set to new fdt blob
     munmap(fileData, this->len);
@@ -155,7 +146,7 @@ DtbObject::addBootCmdLine(const char* _args, size_t len)
 Addr
 DtbObject::findReleaseAddr()
 {
-    void *fd = (void*)fileData;
+    void *fd = (void *)fileData;
 
     int offset = fdt_path_offset(fd, "/cpus/cpu@0");
     int len;
@@ -164,9 +155,11 @@ DtbObject::findReleaseAddr()
     Addr rel_addr = 0;
 
     if (len > 3)
-        rel_addr = betoh(*static_cast<const uint32_t*>(temp));
-    if (len == 8)
-        rel_addr = (rel_addr << 32) | betoh(*(static_cast<const uint32_t*>(temp)+1));
+        rel_addr = betoh(*static_cast<const uint32_t *>(temp));
+    if (len == 8) {
+        rel_addr = (rel_addr << 32) |
+            betoh(*(static_cast<const uint32_t *>(temp) + 1));
+    }
 
     return rel_addr;
 }
index c49b144ac804403f338cafcb945e42be4029c757..7cb842e434bfede9206bc56890dc13fa39ec78b5 100644 (file)
@@ -49,6 +49,8 @@ class DtbObject : public ObjectFile
          */
         bool fileDataMmapped;
 
+        Segment *data;
+
     public:
         virtual ~DtbObject();
 
index 76b91dd662988237106edf79f01ce99de5268797..56f9b35fc77d1066fe767fc2e7b61c05f12a97f3 100644 (file)
@@ -73,21 +73,14 @@ EcoffObject::EcoffObject(const string &_filename, size_t _len, uint8_t *_data,
 
     entry = aoutHdr->entry;
 
-    text.base = aoutHdr->text_start;
-    text.size = aoutHdr->tsize;
-    text.data = fileData + ECOFF_TXTOFF(execHdr);
-
-    data.base = aoutHdr->data_start;
-    data.size = aoutHdr->dsize;
-    data.data = fileData + ECOFF_DATOFF(execHdr);
-
-    bss.base = aoutHdr->bss_start;
-    bss.size = aoutHdr->bsize;
-    bss.data = nullptr;
-
-    DPRINTFR(Loader, "text: %#x %d\ndata: %#x %d\nbss: %#x %d\n",
-             text.base, text.size, data.base, data.size,
-             bss.base, bss.size);
+    addSegment("text", aoutHdr->text_start, fileData + ECOFF_TXTOFF(execHdr),
+            aoutHdr->tsize);
+    addSegment("data", aoutHdr->data_start, fileData + ECOFF_DATOFF(execHdr),
+            aoutHdr->dsize);
+    addSegment("bss", aoutHdr->bss_start, nullptr, aoutHdr->bsize);
+
+    for (auto &seg: segments)
+        DPRINTFR(Loader, "%s\n", *seg);
 }
 
 bool
index 3279195401dd190fba1c38065808869f3db3f3ab..4dee7d2c08bf29cb4cc7cfc61888a6835d97b593 100644 (file)
@@ -293,45 +293,8 @@ ElfObject::ElfObject(const std::string &_filename, size_t _len,
 
     entry = ehdr.e_entry;
 
-    // initialize segment sizes to 0 in case they're not present
-    text.size = data.size = bss.size = 0;
-    text.base = data.base = bss.base = 0;
-
     int sec_idx = 1;
 
-    // The first address of some important sections.
-    Addr text_sec_start = 0;
-    Addr data_sec_start = 0;
-    Addr bss_sec_start = 0;
-
-    // Get the first section
-    Elf_Scn *section = elf_getscn(elf, sec_idx);
-
-    // Find the beginning of the most interesting sections.
-    while (section) {
-        GElf_Shdr shdr;
-        gelf_getshdr(section, &shdr);
-        char *sec_name = elf_strptr(elf, ehdr.e_shstrndx, shdr.sh_name);
-
-        if (sec_name) {
-            if (!strcmp(".text", sec_name)) {
-                text_sec_start = shdr.sh_addr;
-            } else if (!strcmp(".data", sec_name)) {
-                data_sec_start = shdr.sh_addr;
-            } else if (!strcmp(".bss", sec_name)) {
-                bss_sec_start = shdr.sh_addr;
-            }
-        } else {
-            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);
-            }
-        }
-
-        section = elf_getscn(elf, ++sec_idx);
-    }
-
     // 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.
@@ -348,50 +311,54 @@ ElfObject::ElfObject(const std::string &_filename, size_t _len,
         ldMin = std::min(ldMin, phdr.p_vaddr);
         ldMax = std::max(ldMax, phdr.p_vaddr + phdr.p_memsz);
 
-        // Check to see if this segment contains the bss section.
-        if (phdr.p_paddr <= bss_sec_start &&
-            phdr.p_paddr + phdr.p_memsz > bss_sec_start &&
-            phdr.p_memsz - phdr.p_filesz > 0) {
-            bss.base = phdr.p_paddr + phdr.p_filesz;
-            bss.size = phdr.p_memsz - phdr.p_filesz;
-            bss.data = nullptr;
+        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);
         }
 
-        // Check to see if this is the text or data segment
-        if (phdr.p_vaddr <= text_sec_start &&
-            phdr.p_vaddr + phdr.p_filesz > text_sec_start) {
-
-            // If this value is nonzero, we need to flip the relocate flag.
-            if (phdr.p_vaddr != 0)
-                relocate = false;
-
-            text.base = phdr.p_paddr;
-            text.size = phdr.p_filesz;
-            text.data = fileData + phdr.p_offset;
-        } else if (phdr.p_vaddr <= data_sec_start &&
-                   phdr.p_vaddr + phdr.p_filesz > data_sec_start) {
-            data.base = phdr.p_paddr;
-            data.size = phdr.p_filesz;
-            data.data = fileData + phdr.p_offset;
-        } else {
-            // If it's none of the above but is loadable,
-            // load the filesize worth of data
-            Segment extra;
-            extra.base = phdr.p_paddr;
-            extra.size = phdr.p_filesz;
-            extra.data = fileData + phdr.p_offset;
-            extraSegments.push_back(extra);
+        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.
+            addSegment(name + "(uninitialized)", phdr.p_paddr + phdr.p_filesz,
+                    nullptr, uninitialized);
         }
     }
 
     // should have found at least one loadable segment
-    warn_if(text.size == 0,
-            "Empty .text segment in '%s'. ELF file corrupted?\n",
+    warn_if(segments.empty(),
+            "No loadable segments in '%s'. ELF file corrupted?\n",
             filename);
 
-    DPRINTFR(Loader, "text: %#x %d\ndata: %#x %d\nbss: %#x %d\n",
-             text.base, text.size, data.base, data.size,
-             bss.base, bss.size);
+    for (auto &seg: segments)
+        DPRINTFR(Loader, "%s\n", *seg);
 
     elf_end(elf);
 
@@ -498,20 +465,13 @@ ElfObject::loadWeakSymbols(SymbolTable *symtab, Addr base, Addr offset,
 }
 
 bool
-ElfObject::loadSegments(const PortProxy& mem_proxy, Addr addr_mask,
-                        Addr offset)
+ElfObject::loadSegments(const PortProxy &mem_proxy)
 {
-    if (!ObjectFile::loadSegments(mem_proxy, addr_mask, offset))
+    if (!ObjectFile::loadSegments(mem_proxy))
         return false;
 
-    for (auto seg : extraSegments) {
-        if (!loadSegment(&seg, mem_proxy, addr_mask, offset)) {
-            return false;
-        }
-    }
-
     if (interpreter)
-        interpreter->loadSegments(mem_proxy, addr_mask, offset);
+        interpreter->loadSegments(mem_proxy);
 
     return true;
 }
@@ -570,9 +530,6 @@ ElfObject::updateBias(Addr bias_addr)
     entry += bias_addr;
 
     // Patch segments with the bias_addr.
-    text.base += bias_addr;
-    data.base += bias_addr;
-    bss.base  += bias_addr;
-    for (auto &segment : extraSegments)
-        segment.base += bias_addr;
+    for (auto &segment : segments)
+        segment->base += bias_addr;
 }
index 244b9fc3fd0e6ef9a0f287a7c3b1649b641662fa..f2af4142a0572057abd333b5fc4aa70cf426036a 100644 (file)
@@ -86,13 +86,10 @@ class ElfObject : public ObjectFile
     void getSections();
     bool sectionExists(std::string sec);
 
-    std::vector<Segment> extraSegments;
-
   public:
     virtual ~ElfObject() {}
 
-    bool loadSegments(const PortProxy& mem_proxy, Addr addr_mask = maxAddr,
-                      Addr offset = 0) override;
+    bool loadSegments(const PortProxy &mem_proxy) override;
 
     virtual bool loadAllSymbols(SymbolTable *symtab, Addr base = 0,
                                 Addr offset = 0, Addr addr_mask = maxAddr)
index 8a6b063de323b454ca61ef5c2cf7745d95e6c47d..d63b2221be7ecb2f136b347387c4a7bd900c3b3b 100644 (file)
@@ -57,10 +57,8 @@ 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),
-      text{0, nullptr, 0}, data{0, nullptr, 0}, bss{0, nullptr, 0}
-{
-}
+      arch(_arch), opSys(_op_sys), entry(0)
+{}
 
 
 ObjectFile::~ObjectFile()
@@ -73,11 +71,10 @@ ObjectFile::~ObjectFile()
 
 
 bool
-ObjectFile::loadSegment(Segment *seg, const PortProxy& mem_proxy,
-                        Addr addr_mask, Addr offset)
+ObjectFile::loadSegment(Segment *seg, const PortProxy &mem_proxy)
 {
     if (seg->size != 0) {
-        Addr addr = (seg->base & addr_mask) + offset;
+        Addr addr = (seg->base & loadMask) + loadOffset;
         if (seg->data) {
             mem_proxy.writeBlob(addr, seg->data, seg->size);
         } else {
@@ -90,12 +87,12 @@ ObjectFile::loadSegment(Segment *seg, const PortProxy& mem_proxy,
 
 
 bool
-ObjectFile::loadSegments(const PortProxy& mem_proxy, Addr addr_mask,
-                         Addr offset)
+ObjectFile::loadSegments(const PortProxy &proxy)
 {
-    return (loadSegment(&text, mem_proxy, addr_mask, offset)
-            && loadSegment(&data, mem_proxy, addr_mask, offset)
-            && loadSegment(&bss, mem_proxy, addr_mask, offset));
+    for (auto &seg: segments)
+        if (!loadSegment(seg.get(), proxy))
+            return false;
+    return true;
 }
 
 namespace
index db995f5d7bc28c343df52f6889ed6f34749ca5b3..e5053ad8211e3b392a2fdb39a19df1ac3d3af258 100644 (file)
@@ -33,7 +33,9 @@
 #define __OBJECT_FILE_HH__
 
 #include <limits>
+#include <memory>
 #include <string>
+#include <vector>
 
 #include "base/logging.hh"
 #include "base/types.hh"
@@ -72,10 +74,14 @@ class ObjectFile
         FreeBSD
     };
 
+    static const Addr maxAddr = std::numeric_limits<Addr>::max();
+
   protected:
     const std::string filename;
     uint8_t *fileData;
     size_t len;
+    Addr loadOffset=0;
+    Addr loadMask=maxAddr;
 
     Arch arch;
     OpSys opSys;
@@ -86,10 +92,7 @@ class ObjectFile
   public:
     virtual ~ObjectFile();
 
-    static const Addr maxAddr = std::numeric_limits<Addr>::max();
-
-    virtual bool loadSegments(const PortProxy &mem_proxy,
-                              Addr mask=maxAddr, Addr offset=0);
+    virtual bool loadSegments(const PortProxy &mem_proxy);
 
     virtual bool loadAllSymbols(SymbolTable *symtab, Addr base = 0,
                                 Addr offset=0, Addr mask=maxAddr) = 0;
@@ -114,41 +117,76 @@ class ObjectFile
     Arch  getArch()  const { return arch; }
     OpSys getOpSys() const { return opSys; }
 
-  protected:
-
     struct Segment
     {
+        std::string name;
         Addr base;
         uint8_t *data;
         size_t size;
     };
 
+  protected:
     Addr entry;
 
-    Segment text;
-    Segment data;
-    Segment bss;
+    std::vector<std::unique_ptr<Segment>> segments;
 
-    bool loadSegment(Segment *seg, const PortProxy &mem_proxy, Addr mask,
-                     Addr offset=0);
+    void
+    addSegment(std::string name, Addr base, uint8_t *data, size_t size)
+    {
+        Segment *seg = new Segment;
+        seg->name = name;
+        seg->base = base;
+        seg->data = data;
+        seg->size = size;
+        segments.emplace_back(seg);
+    }
+
+    bool loadSegment(Segment *seg, const PortProxy &mem_proxy);
 
   public:
     Addr entryPoint() const { return entry; }
 
-    Addr textBase() const { return text.base; }
-    Addr dataBase() const { return data.base; }
-    Addr bssBase() const { return bss.base; }
-
-    size_t textSize() const { return text.size; }
-    size_t dataSize() const { return data.size; }
-    size_t bssSize() const { return bss.size; }
+    Addr
+    maxSegmentAddr() const
+    {
+        Addr max = 0;
+        for (auto &seg: segments) {
+            Addr end = seg->base + seg->size;
+            if (end > max)
+                max = end;
+        }
+        return max;
+    }
+
+    Addr
+    minSegmentAddr() const
+    {
+        Addr min = maxAddr;
+        for (auto &seg: segments)
+            if (seg->base < min)
+                min = seg->base;
+        return min;
+    }
+
+    bool
+    contains(Addr addr) const
+    {
+        for (auto &seg: segments) {
+            Addr start = seg->base;
+            Addr end = seg->base + seg->size;
+            if (addr >= start && addr < end)
+                return true;
+        }
+        return false;
+    }
 
     /* This function allows you to override the base address where
      * a binary is going to be loaded or set it if the binary is just a
      * blob that doesn't include an object header.
      * @param a address to load the binary/text section at
      */
-    void setTextBase(Addr a) { text.base = a; }
+    void setLoadOffset(Addr val) { loadOffset = val; }
+    void setLoadMask(Addr val) { loadMask = val; }
 
     /**
      * Each instance of a Loader subclass will have a chance to try to load
@@ -183,6 +221,13 @@ class ObjectFile
     static Process *tryLoaders(ProcessParams *params, ObjectFile *obj_file);
 };
 
+static inline std::ostream &
+operator << (std::ostream &os, const ObjectFile::Segment &seg)
+{
+    ccprintf(os, "%s: %#x %d", seg.name, seg.base, seg.size);
+    return os;
+}
+
 ObjectFile *createObjectFile(const std::string &fname, bool raw = false);
 
 
index 9662d8613004f276a6aee86e919706dc1957979a..b0ece3ba2aa43399e5185675583717cf99bb1651 100644 (file)
@@ -43,23 +43,10 @@ RawObject::tryFile(const std::string &fname, size_t len, uint8_t *data)
 
 RawObject::RawObject(const std::string &_filename, size_t _len,
         uint8_t *_data, Arch _arch, OpSys _opSys)
-    : ObjectFile(_filename, _len, _data, _arch, _opSys)
+    : ObjectFile(_filename, _len, _data, _arch, _opSys),
+    data(new Segment{ "data", 0, fileData, len })
 {
-    text.base = 0;
-    text.size = len;
-    text.data = fileData;
-
-    data.base = 0;
-    data.size = 0;
-    data.data = nullptr;
-
-    bss.base = 0;
-    bss.size = 0;
-    bss.data = nullptr;
-
-    DPRINTFR(Loader, "text: %#x %d\ndata: %#x %d\nbss: %#x %d\n",
-             text.base, text.size, data.base, data.size,
-             bss.base, bss.size);
+    segments.emplace_back(data);
 }
 
 bool
index 6931a1321948bde7778795120d2a978f1b90f8b0..9eb9291078a2733c756f26f91497f7235f8d1980 100644 (file)
@@ -38,6 +38,9 @@ class RawObject: public ObjectFile
   protected:
     RawObject(const std::string &_filename, size_t _len,
               uint8_t *_data, Arch _arch, OpSys _opSys);
+
+    Segment *data;
+
   public:
     virtual ~RawObject() {}
 
index fb6e9a168b46aa4d2bfeb47bdf4be3d13163c920..6c3b172c245d47ac28d26fbe08ce0262aea754a3 100644 (file)
@@ -1888,19 +1888,14 @@ mmapImpl(SyscallDesc *desc, int num, ThreadContext *tc, bool is_mmap2)
         // this will not work since there is a single global symbol table.
         ObjectFile *interpreter = p->getInterpreter();
         if (interpreter) {
-            Addr text_start = interpreter->textBase();
-            Addr text_end = text_start + interpreter->textSize();
-
-            Addr pc = tc->pcState().pc();
-
-            if (pc >= text_start && pc < text_end) {
+            if (interpreter->contains(tc->pcState().instAddr())) {
                 std::shared_ptr<FDEntry> fdep = (*p->fds)[tgt_fd];
                 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>(fdep);
                 ObjectFile *lib = createObjectFile(ffdp->getFileName());
 
                 if (lib) {
                     lib->loadAllSymbols(debugSymbolTable,
-                                        lib->textBase(), start);
+                                        lib->minSegmentAddr(), start);
                 }
             }
         }
index 73f93a257820601fbf1f77881742affcca50397a..bf8b45239ba71e537105887f83c885d0b3745029 100644 (file)
@@ -152,14 +152,16 @@ System::System(Params *p)
         } else {
             // Get the kernel code
             kernel = createObjectFile(params()->kernel);
+            kernel->setLoadOffset(loadAddrOffset);
+            kernel->setLoadMask(loadAddrMask);
             inform("kernel located at: %s", params()->kernel);
 
             if (kernel == NULL)
                 fatal("Could not load kernel file %s", params()->kernel);
 
             // setup entry points
-            kernelStart = kernel->textBase();
-            kernelEnd = kernel->bssBase() + kernel->bssSize();
+            kernelStart = kernel->minSegmentAddr();
+            kernelEnd = kernel->maxSegmentAddr();
             kernelEntry = kernel->entryPoint();
 
             // If load_addr_mask is set to 0x0, then auto-calculate
@@ -168,6 +170,7 @@ System::System(Params *p)
             if (loadAddrMask == 0) {
                 Addr shift_amt = findMsbSet(kernelEnd - kernelStart) + 1;
                 loadAddrMask = ((Addr)1 << shift_amt) - 1;
+                kernel->setLoadMask(loadAddrMask);
             }
 
             // load symbols
@@ -192,6 +195,8 @@ System::System(Params *p)
             ObjectFile *obj = createObjectFile(obj_name);
             fatal_if(!obj, "Failed to additional kernel object '%s'.\n",
                      obj_name);
+            obj->setLoadOffset(loadAddrOffset);
+            obj->setLoadMask(loadAddrMask);
             kernelExtras.push_back(obj);
         }
     }
@@ -327,11 +332,9 @@ System::initState()
                 }
             }
             // Load program sections into memory
-            kernel->loadSegments(physProxy, loadAddrMask, loadAddrOffset);
-            for (const auto &extra_kernel : kernelExtras) {
-                extra_kernel->loadSegments(physProxy, loadAddrMask,
-                                           loadAddrOffset);
-            }
+            kernel->loadSegments(physProxy);
+            for (const auto &extra_kernel : kernelExtras)
+                extra_kernel->loadSegments(physProxy);
 
             DPRINTF(Loader, "Kernel start = %#x\n", kernelStart);
             DPRINTF(Loader, "Kernel end   = %#x\n", kernelEnd);