First steps toward getting full system to work with
[gem5.git] / base / loader / elf_object.cc
index 6dfbce28c2f23a276bcae310a62e5a070360a10b..165501e1c1a9198e27a0b42996b361315ea74324 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003-2004 The Regents of The University of Michigan
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
 #define __LIBELF_NEED_LINK_H    0
 #define __LIBELF_SYMBOL_VERSIONS 0
 
-#include <libelf/libelf.h>
-#include <libelf/gelf.h>
+#include "libelf/libelf.h"
+#include "libelf/gelf.h"
 
 #include "base/loader/elf_object.hh"
+#include "base/misc.hh"
 
-#include "mem/functional_mem/functional_memory.hh"
 #include "base/loader/symtab.hh"
 
 #include "base/trace.hh"       // for DPRINTF
 
+#include "sim/byteswap.hh"
+
 
 using namespace std;
 
@@ -56,9 +58,12 @@ ElfObject::tryFile(const string &fname, int fd, size_t len, uint8_t *data)
 {
     Elf *elf;
     GElf_Ehdr ehdr;
+    Arch arch = UnknownArch;
+    OpSys opSys = UnknownOpSys;
 
     // check that header matches library version
-    assert(elf_version(EV_CURRENT) != EV_NONE);
+    if (elf_version(EV_CURRENT) == EV_NONE)
+        panic("wrong elf version number!");
 
     // get a pointer to elf structure
     elf = elf_memory((char*)data,len);
@@ -70,19 +75,89 @@ ElfObject::tryFile(const string &fname, int fd, size_t len, uint8_t *data)
         DPRINTFR(Loader, "Not ELF\n");
         elf_end(elf);
         return NULL;
-    }
-    else {
-        if (ehdr.e_ident[EI_CLASS] == ELFCLASS32)
-            panic("32 bit ELF Binary, Not Supported");
-        /* @todo this emachine value isn't offical yet.
-         *       so we probably shouldn't check it. */
-//        if (ehdr.e_machine != EM_ALPHA)
-//            panic("Non Alpha Binary, Not Supported");
+    } else {
+        //Detect the architecture
+        //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.
+        if (ehdr.e_machine == EM_SPARC64 ||
+                ehdr.e_machine == EM_SPARC ||
+                ehdr.e_machine == EM_SPARCV9) {
+            arch = ObjectFile::SPARC;
+        } else if (ehdr.e_machine == EM_MIPS
+                && ehdr.e_ident[EI_CLASS] == ELFCLASS32) {
+            arch = ObjectFile::Mips;
+        } else if (ehdr.e_ident[EI_CLASS] == ELFCLASS64) {
+            arch = ObjectFile::Alpha;
+        } else {
+            warn("Unknown architecture: %d\n", ehdr.e_machine);
+            arch = ObjectFile::UnknownArch;
+        }
 
-        elf_end(elf);
+        //Detect the operating system
+        switch (ehdr.e_ident[EI_OSABI])
+        {
+
+          case ELFOSABI_LINUX:
+            opSys = ObjectFile::Linux;
+            break;
+          case ELFOSABI_SOLARIS:
+            opSys = ObjectFile::Solaris;
+            break;
+          case ELFOSABI_TRU64:
+            opSys = ObjectFile::Tru64;
+            break;
+          default:
+            opSys = ObjectFile::UnknownOpSys;
+        }
 
-        return new ElfObject(fname, fd, len, data,
-                             ObjectFile::Alpha, ObjectFile::Linux);
+        //take a look at the .note.ABI section
+        //It can let us know what's what.
+        if (opSys == ObjectFile::UnknownOpSys) {
+            Elf_Scn *section;
+            GElf_Shdr shdr;
+            Elf_Data *data;
+            uint32_t osAbi;;
+            int secIdx = 1;
+
+            // Get the first section
+            section = elf_getscn(elf, secIdx);
+
+            // While there are no more sections
+            while (section != NULL && opSys == ObjectFile::UnknownOpSys) {
+                gelf_getshdr(section, &shdr);
+                if (shdr.sh_type == SHT_NOTE && !strcmp(".note.ABI-tag",
+                            elf_strptr(elf, ehdr.e_shstrndx, shdr.sh_name))) {
+                    // we have found a ABI note section
+                    // Check the 5th 32bit word for OS  0 == linux, 1 == hurd,
+                    // 2 == solaris, 3 == freebsd
+                    data = elf_rawdata(section, NULL);
+                    assert(data->d_buf);
+                    if(ehdr.e_ident[EI_DATA] == ELFDATA2LSB)
+                        osAbi = htole(((uint32_t*)data->d_buf)[4]);
+                    else
+                        osAbi = htobe(((uint32_t*)data->d_buf)[4]);
+
+                    switch(osAbi) {
+                      case 0:
+                        opSys = ObjectFile::Linux;
+                        break;
+                      case 2:
+                        opSys = ObjectFile::Solaris;
+                        break;
+                    }
+                } // if section found
+                if (!strcmp(".SUNW_version", elf_strptr(elf, ehdr.e_shstrndx, shdr.sh_name)))
+                        opSys = ObjectFile::Solaris;
+                if (!strcmp(".stab.index", elf_strptr(elf, ehdr.e_shstrndx, shdr.sh_name)))
+                        opSys = ObjectFile::Solaris;
+
+            section = elf_getscn(elf, ++secIdx);
+            } // while sections
+        }
+
+        elf_end(elf);
+        return new ElfObject(fname, fd, len, data, arch, opSys);
     }
 }
 
@@ -97,7 +172,8 @@ ElfObject::ElfObject(const string &_filename, int _fd,
     GElf_Ehdr ehdr;
 
     // check that header matches library version
-    assert(elf_version(EV_CURRENT) != EV_NONE);
+    if (elf_version(EV_CURRENT) == EV_NONE)
+        panic("wrong elf version number!");
 
     // get a pointer to elf structure
     elf = elf_memory((char*)fileData,len);
@@ -111,6 +187,7 @@ ElfObject::ElfObject(const string &_filename, int _fd,
 
     entry = ehdr.e_entry;
 
+
     // initialize segment sizes to 0 in case they're not present
     text.size = data.size = bss.size = 0;
 
@@ -129,20 +206,18 @@ ElfObject::ElfObject(const string &_filename, int _fd,
         if (text.size == 0) {  // haven't seen text segment yet
             text.baseAddr = phdr.p_vaddr;
             text.size = phdr.p_filesz;
-            // remember where the data is for loadSections()
-            fileTextBits = fileData + phdr.p_offset;
+            text.fileImage = fileData + phdr.p_offset;
             // if there's any padding at the end that's not in the
             // file, call it the bss.  This happens in the "text"
             // segment if there's only one loadable segment (as for
             // kernel images).
             bss.size = phdr.p_memsz - phdr.p_filesz;
             bss.baseAddr = phdr.p_vaddr + phdr.p_filesz;
-        }
-        else if (data.size == 0) { // have text, this must be data
+            bss.fileImage = NULL;
+        else if (data.size == 0) { // have text, this must be data
             data.baseAddr = phdr.p_vaddr;
             data.size = phdr.p_filesz;
-            // remember where the data is for loadSections()
-            fileDataBits = fileData + phdr.p_offset;
+            data.fileImage = fileData + phdr.p_offset;
             // if there's any padding at the end that's not in the
             // file, call it the bss.  Warn if this happens for both
             // the text & data segments (should only have one bss).
@@ -151,6 +226,11 @@ ElfObject::ElfObject(const string &_filename, int _fd,
             }
             bss.size = phdr.p_memsz - phdr.p_filesz;
             bss.baseAddr = phdr.p_vaddr + phdr.p_filesz;
+            bss.fileImage = NULL;
+        } else {
+            warn("More than two loadable segments in ELF object.");
+            warn("Ignoring segment @ 0x%x length 0x%x.",
+                 phdr.p_vaddr, phdr.p_filesz);
         }
     }
 
@@ -167,28 +247,6 @@ ElfObject::ElfObject(const string &_filename, int _fd,
 }
 
 
-bool
-ElfObject::loadSections(FunctionalMemory *mem, bool loadPhys)
-{
-    Addr textAddr = text.baseAddr;
-    Addr dataAddr = data.baseAddr;
-
-    if (loadPhys) {
-        textAddr &= (ULL(1) << 40) - 1;
-        dataAddr &= (ULL(1) << 40) - 1;
-    }
-
-    // Since we don't really have an MMU and all memory is
-    // zero-filled, there's no need to set up the BSS segment.
-    if (text.size != 0)
-        mem->prot_write(textAddr, fileTextBits, text.size);
-    if (data.size != 0)
-        mem->prot_write(dataAddr, fileDataBits, data.size);
-
-    return true;
-}
-
-
 bool
 ElfObject::loadSomeSymbols(SymbolTable *symtab, int binding)
 {
@@ -205,7 +263,8 @@ ElfObject::loadSomeSymbols(SymbolTable *symtab, int binding)
         return false;
 
     // check that header matches library version
-    assert(elf_version(EV_CURRENT) != EV_NONE);
+    if (elf_version(EV_CURRENT) == EV_NONE)
+        panic("wrong elf version number!");
 
     // get a pointer to elf structure
     elf = elf_memory((char*)fileData,len);