elf_object.cc revision 10360:919c02740209
13569Sgblack@eecs.umich.edu/*
23569Sgblack@eecs.umich.edu * Copyright (c) 2011-2013 ARM Limited
33569Sgblack@eecs.umich.edu * All rights reserved
43569Sgblack@eecs.umich.edu *
53569Sgblack@eecs.umich.edu * The license below extends only to copyright in the software and shall
63569Sgblack@eecs.umich.edu * not be construed as granting a license to any other intellectual
73569Sgblack@eecs.umich.edu * property including but not limited to intellectual property relating
83569Sgblack@eecs.umich.edu * to a hardware implementation of the functionality of the software
93569Sgblack@eecs.umich.edu * licensed hereunder.  You may use the software subject to the license
103569Sgblack@eecs.umich.edu * terms below provided that you ensure that this notice is replicated
113569Sgblack@eecs.umich.edu * unmodified and in its entirety in all distributions of the software,
123569Sgblack@eecs.umich.edu * modified or unmodified, in source code or in binary form.
133569Sgblack@eecs.umich.edu *
143569Sgblack@eecs.umich.edu * Copyright (c) 2003-2005 The Regents of The University of Michigan
153569Sgblack@eecs.umich.edu * All rights reserved.
163569Sgblack@eecs.umich.edu *
173569Sgblack@eecs.umich.edu * Redistribution and use in source and binary forms, with or without
183569Sgblack@eecs.umich.edu * modification, are permitted provided that the following conditions are
193569Sgblack@eecs.umich.edu * met: redistributions of source code must retain the above copyright
203569Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer;
213569Sgblack@eecs.umich.edu * redistributions in binary form must reproduce the above copyright
223569Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer in the
233569Sgblack@eecs.umich.edu * documentation and/or other materials provided with the distribution;
243569Sgblack@eecs.umich.edu * neither the name of the copyright holders nor the names of its
253569Sgblack@eecs.umich.edu * contributors may be used to endorse or promote products derived from
263569Sgblack@eecs.umich.edu * this software without specific prior written permission.
273569Sgblack@eecs.umich.edu *
283804Ssaidi@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
293569Sgblack@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
303569Sgblack@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
313918Ssaidi@eecs.umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
323918Ssaidi@eecs.umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
333804Ssaidi@eecs.umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
343811Ssaidi@eecs.umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
353569Sgblack@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
363824Ssaidi@eecs.umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
373811Ssaidi@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
383811Ssaidi@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
393823Ssaidi@eecs.umich.edu *
403823Ssaidi@eecs.umich.edu * Authors: Steve Reinhardt
413823Ssaidi@eecs.umich.edu *          Ali Saidi
424103Ssaidi@eecs.umich.edu */
433569Sgblack@eecs.umich.edu
443804Ssaidi@eecs.umich.edu#include <cassert>
453804Ssaidi@eecs.umich.edu#include <string>
464088Sbinkertn@umich.edu
473569Sgblack@eecs.umich.edu#include "base/loader/elf_object.hh"
485034Smilesck@eecs.umich.edu#include "base/loader/symtab.hh"
495358Sgblack@eecs.umich.edu#include "base/bitfield.hh"
503881Ssaidi@eecs.umich.edu#include "base/misc.hh"
513804Ssaidi@eecs.umich.edu#include "base/trace.hh"
523804Ssaidi@eecs.umich.edu#include "debug/Loader.hh"
533804Ssaidi@eecs.umich.edu#include "sim/byteswap.hh"
545555Snate@binkert.org#include "gelf.h"
553569Sgblack@eecs.umich.edu
563804Ssaidi@eecs.umich.eduusing namespace std;
573918Ssaidi@eecs.umich.edu
583881Ssaidi@eecs.umich.eduObjectFile *
593881Ssaidi@eecs.umich.eduElfObject::tryFile(const string &fname, int fd, size_t len, uint8_t *data)
603881Ssaidi@eecs.umich.edu{
614990Sgblack@eecs.umich.edu    Elf *elf;
624990Sgblack@eecs.umich.edu    GElf_Ehdr ehdr;
634990Sgblack@eecs.umich.edu    Arch arch = UnknownArch;
644990Sgblack@eecs.umich.edu    OpSys opSys = UnknownOpSys;
654990Sgblack@eecs.umich.edu
664990Sgblack@eecs.umich.edu    // check that header matches library version
674990Sgblack@eecs.umich.edu    if (elf_version(EV_CURRENT) == EV_NONE)
684990Sgblack@eecs.umich.edu        panic("wrong elf version number!");
694990Sgblack@eecs.umich.edu
703804Ssaidi@eecs.umich.edu    // get a pointer to elf structure
713569Sgblack@eecs.umich.edu    elf = elf_memory((char*)data,len);
723804Ssaidi@eecs.umich.edu    // will only fail if fd is invalid
733804Ssaidi@eecs.umich.edu    assert(elf != NULL);
743804Ssaidi@eecs.umich.edu
753804Ssaidi@eecs.umich.edu    // Check that we actually have a elf file
763881Ssaidi@eecs.umich.edu    if (gelf_getehdr(elf, &ehdr) == 0) {
773804Ssaidi@eecs.umich.edu        DPRINTFR(Loader, "Not ELF\n");
783804Ssaidi@eecs.umich.edu        elf_end(elf);
793804Ssaidi@eecs.umich.edu        return NULL;
803804Ssaidi@eecs.umich.edu    } else {
813804Ssaidi@eecs.umich.edu        //Detect the architecture
823804Ssaidi@eecs.umich.edu        //Since we don't know how to check for alpha right now, we'll
833804Ssaidi@eecs.umich.edu        //just assume if it wasn't something else and it's 64 bit, that's
843569Sgblack@eecs.umich.edu        //what it must be.
853569Sgblack@eecs.umich.edu        if (ehdr.e_machine == EM_SPARC64 ||
863804Ssaidi@eecs.umich.edu                (ehdr.e_machine == EM_SPARC &&
873804Ssaidi@eecs.umich.edu                 ehdr.e_ident[EI_CLASS] == ELFCLASS64)||
883826Ssaidi@eecs.umich.edu                ehdr.e_machine == EM_SPARCV9) {
893804Ssaidi@eecs.umich.edu            arch = ObjectFile::SPARC64;
903804Ssaidi@eecs.umich.edu        } else if (ehdr.e_machine == EM_SPARC32PLUS ||
913826Ssaidi@eecs.umich.edu                        (ehdr.e_machine == EM_SPARC &&
923907Ssaidi@eecs.umich.edu                         ehdr.e_ident[EI_CLASS] == ELFCLASS32)) {
933826Ssaidi@eecs.umich.edu            arch = ObjectFile::SPARC32;
943811Ssaidi@eecs.umich.edu        } else if (ehdr.e_machine == EM_MIPS
953836Ssaidi@eecs.umich.edu                && ehdr.e_ident[EI_CLASS] == ELFCLASS32) {
963915Ssaidi@eecs.umich.edu            if (ehdr.e_ident[EI_DATA] == ELFDATA2LSB) {
973907Ssaidi@eecs.umich.edu                arch = ObjectFile::Mips;
983881Ssaidi@eecs.umich.edu            } else {
993881Ssaidi@eecs.umich.edu                fatal("The binary you're trying to load is compiled for big "
1003881Ssaidi@eecs.umich.edu                        "endian MIPS. M5\nonly supports little endian MIPS. "
1013881Ssaidi@eecs.umich.edu                        "Please recompile your binary.\n");
1023907Ssaidi@eecs.umich.edu            }
1033881Ssaidi@eecs.umich.edu        } else if (ehdr.e_machine == EM_X86_64 &&
1045555Snate@binkert.org                ehdr.e_ident[EI_CLASS] == ELFCLASS64) {
1055555Snate@binkert.org            arch = ObjectFile::X86_64;
1065555Snate@binkert.org        } else if (ehdr.e_machine == EM_386 &&
1073881Ssaidi@eecs.umich.edu                ehdr.e_ident[EI_CLASS] == ELFCLASS32) {
1083881Ssaidi@eecs.umich.edu            arch = ObjectFile::I386;
1093907Ssaidi@eecs.umich.edu        } else if (ehdr.e_machine == EM_ARM &&
1103907Ssaidi@eecs.umich.edu                ehdr.e_ident[EI_CLASS] == ELFCLASS32) {
1113907Ssaidi@eecs.umich.edu            if (bits(ehdr.e_entry, 0)) {
1123907Ssaidi@eecs.umich.edu                arch = ObjectFile::Thumb;
1133907Ssaidi@eecs.umich.edu            } else {
1143907Ssaidi@eecs.umich.edu                arch = ObjectFile::Arm;
1153907Ssaidi@eecs.umich.edu            }
1163907Ssaidi@eecs.umich.edu        } else if ((ehdr.e_machine == EM_AARCH64) &&
1173907Ssaidi@eecs.umich.edu                ehdr.e_ident[EI_CLASS] == ELFCLASS64) {
1183907Ssaidi@eecs.umich.edu            arch = ObjectFile::Arm64;
1193907Ssaidi@eecs.umich.edu        } else if (ehdr.e_ident[EI_CLASS] == ELFCLASS64) {
1203907Ssaidi@eecs.umich.edu            arch = ObjectFile::Alpha;
1213907Ssaidi@eecs.umich.edu        } else if (ehdr.e_machine == EM_PPC &&
1223907Ssaidi@eecs.umich.edu                ehdr.e_ident[EI_CLASS] == ELFCLASS32) {
1233907Ssaidi@eecs.umich.edu            if (ehdr.e_ident[EI_DATA] == ELFDATA2MSB) {
1243907Ssaidi@eecs.umich.edu                  arch = ObjectFile::Power;
1253907Ssaidi@eecs.umich.edu            } else {
1263907Ssaidi@eecs.umich.edu                  fatal("The binary you're trying to load is compiled for "
1273907Ssaidi@eecs.umich.edu                        "little endian Power.\nM5 only supports big "
1283907Ssaidi@eecs.umich.edu                        "endian Power. Please recompile your binary.\n");
1293907Ssaidi@eecs.umich.edu            }
1303907Ssaidi@eecs.umich.edu        } else if (ehdr.e_machine == EM_PPC64) {
1313881Ssaidi@eecs.umich.edu            fatal("The binary you're trying to load is compiled for 64-bit "
1323881Ssaidi@eecs.umich.edu                  "Power. M5\n only supports 32-bit Power. Please "
1333881Ssaidi@eecs.umich.edu                  "recompile your binary.\n");
1343881Ssaidi@eecs.umich.edu        } else {
1353881Ssaidi@eecs.umich.edu            warn("Unknown architecture: %d\n", ehdr.e_machine);
1363881Ssaidi@eecs.umich.edu            arch = ObjectFile::UnknownArch;
1373881Ssaidi@eecs.umich.edu        }
1383881Ssaidi@eecs.umich.edu
1393881Ssaidi@eecs.umich.edu        //Detect the operating system
1403881Ssaidi@eecs.umich.edu        switch (ehdr.e_ident[EI_OSABI]) {
1413881Ssaidi@eecs.umich.edu          case ELFOSABI_LINUX:
1423881Ssaidi@eecs.umich.edu            opSys = ObjectFile::Linux;
1433907Ssaidi@eecs.umich.edu            break;
1443811Ssaidi@eecs.umich.edu          case ELFOSABI_SOLARIS:
1453826Ssaidi@eecs.umich.edu            opSys = ObjectFile::Solaris;
1463826Ssaidi@eecs.umich.edu            break;
1473826Ssaidi@eecs.umich.edu          case ELFOSABI_TRU64:
1483826Ssaidi@eecs.umich.edu            opSys = ObjectFile::Tru64;
1493881Ssaidi@eecs.umich.edu            break;
1503881Ssaidi@eecs.umich.edu          case ELFOSABI_ARM:
1513881Ssaidi@eecs.umich.edu            opSys = ObjectFile::LinuxArmOABI;
1523881Ssaidi@eecs.umich.edu            break;
1533881Ssaidi@eecs.umich.edu          default:
1543881Ssaidi@eecs.umich.edu            opSys = ObjectFile::UnknownOpSys;
1553881Ssaidi@eecs.umich.edu        }
1563881Ssaidi@eecs.umich.edu
1573881Ssaidi@eecs.umich.edu        //take a look at the .note.ABI section
1583881Ssaidi@eecs.umich.edu        //It can let us know what's what.
1593881Ssaidi@eecs.umich.edu        if (opSys == ObjectFile::UnknownOpSys) {
1603881Ssaidi@eecs.umich.edu            Elf_Scn *section;
1613881Ssaidi@eecs.umich.edu            GElf_Shdr shdr;
1623881Ssaidi@eecs.umich.edu            Elf_Data *data;
1633881Ssaidi@eecs.umich.edu            uint32_t osAbi;;
1643826Ssaidi@eecs.umich.edu            int secIdx = 1;
1653826Ssaidi@eecs.umich.edu
1663826Ssaidi@eecs.umich.edu            // Get the first section
1673826Ssaidi@eecs.umich.edu            section = elf_getscn(elf, secIdx);
1683826Ssaidi@eecs.umich.edu
1693881Ssaidi@eecs.umich.edu            // While there are no more sections
1703569Sgblack@eecs.umich.edu            while (section != NULL && opSys == ObjectFile::UnknownOpSys) {
1713569Sgblack@eecs.umich.edu                gelf_getshdr(section, &shdr);
1723881Ssaidi@eecs.umich.edu                if (shdr.sh_type == SHT_NOTE && !strcmp(".note.ABI-tag",
1733804Ssaidi@eecs.umich.edu                            elf_strptr(elf, ehdr.e_shstrndx, shdr.sh_name))) {
1743881Ssaidi@eecs.umich.edu                    // we have found a ABI note section
1753826Ssaidi@eecs.umich.edu                    // Check the 5th 32bit word for OS  0 == linux, 1 == hurd,
1763881Ssaidi@eecs.umich.edu                    // 2 == solaris, 3 == freebsd
1773881Ssaidi@eecs.umich.edu                    data = elf_rawdata(section, NULL);
1783881Ssaidi@eecs.umich.edu                    assert(data->d_buf);
1793907Ssaidi@eecs.umich.edu                    if(ehdr.e_ident[EI_DATA] == ELFDATA2LSB)
1803907Ssaidi@eecs.umich.edu                        osAbi = htole(((uint32_t*)data->d_buf)[4]);
1813929Ssaidi@eecs.umich.edu                    else
1823929Ssaidi@eecs.umich.edu                        osAbi = htobe(((uint32_t*)data->d_buf)[4]);
1833907Ssaidi@eecs.umich.edu
1843907Ssaidi@eecs.umich.edu                    switch(osAbi) {
1853804Ssaidi@eecs.umich.edu                      case 0:
1863804Ssaidi@eecs.umich.edu                        opSys = ObjectFile::Linux;
1873881Ssaidi@eecs.umich.edu                        break;
1883804Ssaidi@eecs.umich.edu                      case 2:
1893804Ssaidi@eecs.umich.edu                        opSys = ObjectFile::Solaris;
1903804Ssaidi@eecs.umich.edu                        break;
1913804Ssaidi@eecs.umich.edu                    }
1923804Ssaidi@eecs.umich.edu                } // if section found
1933804Ssaidi@eecs.umich.edu                if (!strcmp(".SUNW_version", elf_strptr(elf, ehdr.e_shstrndx, shdr.sh_name)))
1943804Ssaidi@eecs.umich.edu                        opSys = ObjectFile::Solaris;
1953569Sgblack@eecs.umich.edu                if (!strcmp(".stab.index", elf_strptr(elf, ehdr.e_shstrndx, shdr.sh_name)))
1963863Ssaidi@eecs.umich.edu                        opSys = ObjectFile::Solaris;
1973863Ssaidi@eecs.umich.edu
1983804Ssaidi@eecs.umich.edu            section = elf_getscn(elf, ++secIdx);
1995555Snate@binkert.org            } // while sections
2005555Snate@binkert.org        }
2013804Ssaidi@eecs.umich.edu
2023804Ssaidi@eecs.umich.edu        ElfObject * result = new ElfObject(fname, fd, len, data, arch, opSys);
2033804Ssaidi@eecs.umich.edu
2043804Ssaidi@eecs.umich.edu        //The number of headers in the file
2053804Ssaidi@eecs.umich.edu        result->_programHeaderCount = ehdr.e_phnum;
2063569Sgblack@eecs.umich.edu        //Record the size of each entry
2073804Ssaidi@eecs.umich.edu        result->_programHeaderSize = ehdr.e_phentsize;
2083804Ssaidi@eecs.umich.edu        if(result->_programHeaderCount) //If there is a program header table
2093804Ssaidi@eecs.umich.edu        {
2105555Snate@binkert.org            //Figure out the virtual address of the header table in the
2115555Snate@binkert.org            //final memory image. We use the program headers themselves
2123804Ssaidi@eecs.umich.edu            //to translate from a file offset to the address in the image.
2133804Ssaidi@eecs.umich.edu            GElf_Phdr phdr;
2143804Ssaidi@eecs.umich.edu            uint64_t e_phoff = ehdr.e_phoff;
2153804Ssaidi@eecs.umich.edu            result->_programHeaderTable = 0;
2163804Ssaidi@eecs.umich.edu            for(int hdrnum = 0; hdrnum < result->_programHeaderCount; hdrnum++)
2173811Ssaidi@eecs.umich.edu            {
2183811Ssaidi@eecs.umich.edu                gelf_getphdr(elf, hdrnum, &phdr);
2193804Ssaidi@eecs.umich.edu                //Check if we've found the segment with the headers in it
2203804Ssaidi@eecs.umich.edu                if(phdr.p_offset <= e_phoff &&
2215312Sgblack@eecs.umich.edu                        phdr.p_offset + phdr.p_filesz > e_phoff)
2223804Ssaidi@eecs.umich.edu                {
2233804Ssaidi@eecs.umich.edu                    result->_programHeaderTable =
2243804Ssaidi@eecs.umich.edu                        phdr.p_paddr + (e_phoff - phdr.p_offset);
2253804Ssaidi@eecs.umich.edu                    break;
2263804Ssaidi@eecs.umich.edu                }
2273804Ssaidi@eecs.umich.edu            }
2283804Ssaidi@eecs.umich.edu        }
2293811Ssaidi@eecs.umich.edu        else
2303804Ssaidi@eecs.umich.edu            result->_programHeaderTable = 0;
2313804Ssaidi@eecs.umich.edu
2323804Ssaidi@eecs.umich.edu
2333804Ssaidi@eecs.umich.edu        elf_end(elf);
2343804Ssaidi@eecs.umich.edu        return result;
2353826Ssaidi@eecs.umich.edu    }
2363826Ssaidi@eecs.umich.edu}
2374070Ssaidi@eecs.umich.edu
2385555Snate@binkert.org
2395555Snate@binkert.orgElfObject::ElfObject(const string &_filename, int _fd,
2404070Ssaidi@eecs.umich.edu                     size_t _len, uint8_t *_data,
2413804Ssaidi@eecs.umich.edu                     Arch _arch, OpSys _opSys)
2423804Ssaidi@eecs.umich.edu    : ObjectFile(_filename, _fd, _len, _data, _arch, _opSys),
2433804Ssaidi@eecs.umich.edu      _programHeaderTable(0), _programHeaderSize(0), _programHeaderCount(0)
2443804Ssaidi@eecs.umich.edu
2453804Ssaidi@eecs.umich.edu{
2463804Ssaidi@eecs.umich.edu    Elf *elf;
2473804Ssaidi@eecs.umich.edu    GElf_Ehdr ehdr;
2483804Ssaidi@eecs.umich.edu
2493804Ssaidi@eecs.umich.edu    // check that header matches library version
2503804Ssaidi@eecs.umich.edu    if (elf_version(EV_CURRENT) == EV_NONE)
2513804Ssaidi@eecs.umich.edu        panic("wrong elf version number!");
2523804Ssaidi@eecs.umich.edu
2533826Ssaidi@eecs.umich.edu    // get a pointer to elf structure
2543826Ssaidi@eecs.umich.edu    elf = elf_memory((char*)fileData,len);
2553826Ssaidi@eecs.umich.edu    // will only fail if fd is invalid
2563863Ssaidi@eecs.umich.edu    assert(elf != NULL);
2573826Ssaidi@eecs.umich.edu
2583826Ssaidi@eecs.umich.edu    // Check that we actually have a elf file
2593826Ssaidi@eecs.umich.edu    if (gelf_getehdr(elf, &ehdr) ==0) {
2603826Ssaidi@eecs.umich.edu        panic("Not ELF, shouldn't be here");
2613826Ssaidi@eecs.umich.edu    }
2623826Ssaidi@eecs.umich.edu
2633826Ssaidi@eecs.umich.edu    entry = ehdr.e_entry;
2643826Ssaidi@eecs.umich.edu
2653826Ssaidi@eecs.umich.edu    // initialize segment sizes to 0 in case they're not present
2663804Ssaidi@eecs.umich.edu    text.size = data.size = bss.size = 0;
2673804Ssaidi@eecs.umich.edu    text.baseAddr = data.baseAddr = bss.baseAddr = 0;
2683804Ssaidi@eecs.umich.edu
2693804Ssaidi@eecs.umich.edu    int secIdx = 1;
2703804Ssaidi@eecs.umich.edu    Elf_Scn *section;
2713804Ssaidi@eecs.umich.edu    GElf_Shdr shdr;
2723804Ssaidi@eecs.umich.edu
2733863Ssaidi@eecs.umich.edu    // The first address of some important sections.
2743863Ssaidi@eecs.umich.edu    Addr textSecStart = 0;
2753863Ssaidi@eecs.umich.edu    Addr dataSecStart = 0;
2763836Ssaidi@eecs.umich.edu    Addr bssSecStart = 0;
2773836Ssaidi@eecs.umich.edu
2783804Ssaidi@eecs.umich.edu    // Get the first section
2793804Ssaidi@eecs.umich.edu    section = elf_getscn(elf, secIdx);
2805312Sgblack@eecs.umich.edu
2813804Ssaidi@eecs.umich.edu    // Find the beginning of the most interesting sections.
2823804Ssaidi@eecs.umich.edu    while (section != NULL) {
2833804Ssaidi@eecs.umich.edu        gelf_getshdr(section, &shdr);
2843804Ssaidi@eecs.umich.edu        char * secName = elf_strptr(elf, ehdr.e_shstrndx, shdr.sh_name);
2853804Ssaidi@eecs.umich.edu
2863804Ssaidi@eecs.umich.edu        if (secName) {
2873804Ssaidi@eecs.umich.edu            if (!strcmp(".text", secName)) {
2883863Ssaidi@eecs.umich.edu                textSecStart = shdr.sh_addr;
2893804Ssaidi@eecs.umich.edu            } else if (!strcmp(".data", secName)) {
2903804Ssaidi@eecs.umich.edu                dataSecStart = shdr.sh_addr;
2913804Ssaidi@eecs.umich.edu            } else if (!strcmp(".bss", secName)) {
2923804Ssaidi@eecs.umich.edu                bssSecStart = shdr.sh_addr;
2933804Ssaidi@eecs.umich.edu            }
2943881Ssaidi@eecs.umich.edu        } else {
2953804Ssaidi@eecs.umich.edu            Elf_Error errorNum = (Elf_Error)elf_errno();
2963804Ssaidi@eecs.umich.edu            if (errorNum != ELF_E_NONE) {
2973804Ssaidi@eecs.umich.edu                const char *errorMessage = elf_errmsg(errorNum);
2983804Ssaidi@eecs.umich.edu                fatal("Error from libelf: %s.\n", errorMessage);
2993804Ssaidi@eecs.umich.edu            }
3003804Ssaidi@eecs.umich.edu        }
3013804Ssaidi@eecs.umich.edu
3023863Ssaidi@eecs.umich.edu        section = elf_getscn(elf, ++secIdx);
3033863Ssaidi@eecs.umich.edu    }
3043836Ssaidi@eecs.umich.edu
3055555Snate@binkert.org    // Go through all the segments in the program, record them, and scrape
3063804Ssaidi@eecs.umich.edu    // out information about the text, data, and bss areas needed by other
3073804Ssaidi@eecs.umich.edu    // code.
3083881Ssaidi@eecs.umich.edu    for (int i = 0; i < ehdr.e_phnum; ++i) {
3093881Ssaidi@eecs.umich.edu        GElf_Phdr phdr;
3103881Ssaidi@eecs.umich.edu        if (gelf_getphdr(elf, i, &phdr) == 0) {
3113804Ssaidi@eecs.umich.edu            panic("gelf_getphdr failed for segment %d.", i);
3123804Ssaidi@eecs.umich.edu        }
3133804Ssaidi@eecs.umich.edu
3143804Ssaidi@eecs.umich.edu        // for now we don't care about non-loadable segments
3153804Ssaidi@eecs.umich.edu        if (!(phdr.p_type & PT_LOAD))
3163804Ssaidi@eecs.umich.edu            continue;
3173804Ssaidi@eecs.umich.edu
3183804Ssaidi@eecs.umich.edu        // Check to see if this segment contains the bss section.
3193804Ssaidi@eecs.umich.edu        if (phdr.p_paddr <= bssSecStart &&
3203804Ssaidi@eecs.umich.edu                phdr.p_paddr + phdr.p_memsz > bssSecStart &&
3213804Ssaidi@eecs.umich.edu                phdr.p_memsz - phdr.p_filesz > 0) {
3223804Ssaidi@eecs.umich.edu            bss.baseAddr = phdr.p_paddr + phdr.p_filesz;
3233804Ssaidi@eecs.umich.edu            bss.size = phdr.p_memsz - phdr.p_filesz;
3243863Ssaidi@eecs.umich.edu            bss.fileImage = NULL;
3253836Ssaidi@eecs.umich.edu        }
3265555Snate@binkert.org
3275288Sgblack@eecs.umich.edu        // Check to see if this is the text or data segment
3285288Sgblack@eecs.umich.edu        if (phdr.p_vaddr <= textSecStart &&
3295288Sgblack@eecs.umich.edu                phdr.p_vaddr + phdr.p_filesz > textSecStart) {
3303804Ssaidi@eecs.umich.edu            text.baseAddr = phdr.p_paddr;
3313804Ssaidi@eecs.umich.edu            text.size = phdr.p_filesz;
3323804Ssaidi@eecs.umich.edu            text.fileImage = fileData + phdr.p_offset;
3333804Ssaidi@eecs.umich.edu        } else if (phdr.p_vaddr <= dataSecStart &&
3343804Ssaidi@eecs.umich.edu                phdr.p_vaddr + phdr.p_filesz > dataSecStart) {
3353804Ssaidi@eecs.umich.edu            data.baseAddr = phdr.p_paddr;
3363804Ssaidi@eecs.umich.edu            data.size = phdr.p_filesz;
3373804Ssaidi@eecs.umich.edu            data.fileImage = fileData + phdr.p_offset;
3383804Ssaidi@eecs.umich.edu        } else {
3393804Ssaidi@eecs.umich.edu            // If it's none of the above but is loadable,
3403804Ssaidi@eecs.umich.edu            // load the filesize worth of data
3413804Ssaidi@eecs.umich.edu            Segment extra;
3423804Ssaidi@eecs.umich.edu            extra.baseAddr = phdr.p_paddr;
3433836Ssaidi@eecs.umich.edu            extra.size = phdr.p_filesz;
3445555Snate@binkert.org            extra.fileImage = fileData + phdr.p_offset;
3453836Ssaidi@eecs.umich.edu            extraSegments.push_back(extra);
3465555Snate@binkert.org        }
3473881Ssaidi@eecs.umich.edu    }
3483881Ssaidi@eecs.umich.edu
3493804Ssaidi@eecs.umich.edu    // should have found at least one loadable segment
3503907Ssaidi@eecs.umich.edu    assert(text.size != 0);
3513804Ssaidi@eecs.umich.edu
3523804Ssaidi@eecs.umich.edu    DPRINTFR(Loader, "text: 0x%x %d\ndata: 0x%x %d\nbss: 0x%x %d\n",
3533804Ssaidi@eecs.umich.edu             text.baseAddr, text.size, data.baseAddr, data.size,
3543804Ssaidi@eecs.umich.edu             bss.baseAddr, bss.size);
3553804Ssaidi@eecs.umich.edu
3565555Snate@binkert.org    elf_end(elf);
3575555Snate@binkert.org
3583881Ssaidi@eecs.umich.edu    // We will actually read the sections when we need to load them
3593881Ssaidi@eecs.umich.edu}
3603881Ssaidi@eecs.umich.edu
3613804Ssaidi@eecs.umich.edu
3623881Ssaidi@eecs.umich.edubool
3633881Ssaidi@eecs.umich.eduElfObject::loadSomeSymbols(SymbolTable *symtab, int binding, Addr mask)
3643881Ssaidi@eecs.umich.edu{
3653881Ssaidi@eecs.umich.edu    Elf *elf;
3663804Ssaidi@eecs.umich.edu    int sec_idx = 1; // there is a 0 but it is nothing, go figure
3673804Ssaidi@eecs.umich.edu    Elf_Scn *section;
3683804Ssaidi@eecs.umich.edu    GElf_Shdr shdr;
3695555Snate@binkert.org    Elf_Data *data;
3705555Snate@binkert.org    int count, ii;
3713804Ssaidi@eecs.umich.edu    bool found = false;
3723804Ssaidi@eecs.umich.edu    GElf_Sym sym;
3733881Ssaidi@eecs.umich.edu
3743881Ssaidi@eecs.umich.edu    if (!symtab)
3753804Ssaidi@eecs.umich.edu        return false;
3763881Ssaidi@eecs.umich.edu
3773881Ssaidi@eecs.umich.edu    // check that header matches library version
3783881Ssaidi@eecs.umich.edu    if (elf_version(EV_CURRENT) == EV_NONE)
3793804Ssaidi@eecs.umich.edu        panic("wrong elf version number!");
3803804Ssaidi@eecs.umich.edu
3813804Ssaidi@eecs.umich.edu    // get a pointer to elf structure
3823804Ssaidi@eecs.umich.edu    elf = elf_memory((char*)fileData,len);
3833804Ssaidi@eecs.umich.edu
3843804Ssaidi@eecs.umich.edu    assert(elf != NULL);
3853804Ssaidi@eecs.umich.edu
3863804Ssaidi@eecs.umich.edu    // Get the first section
3873804Ssaidi@eecs.umich.edu    section = elf_getscn(elf, sec_idx);
3883804Ssaidi@eecs.umich.edu
3893804Ssaidi@eecs.umich.edu    // While there are no more sections
3903804Ssaidi@eecs.umich.edu    while (section != NULL) {
3913804Ssaidi@eecs.umich.edu        gelf_getshdr(section, &shdr);
3923804Ssaidi@eecs.umich.edu
3933804Ssaidi@eecs.umich.edu        if (shdr.sh_type == SHT_SYMTAB) {
3943804Ssaidi@eecs.umich.edu            found = true;
3954990Sgblack@eecs.umich.edu            data = elf_getdata(section, NULL);
3963804Ssaidi@eecs.umich.edu            count = shdr.sh_size / shdr.sh_entsize;
3973804Ssaidi@eecs.umich.edu            DPRINTF(Loader, "Found Symbol Table, %d symbols present\n", count);
3983804Ssaidi@eecs.umich.edu
3993804Ssaidi@eecs.umich.edu            // loop through all the symbols, only loading global ones
4003804Ssaidi@eecs.umich.edu            for (ii = 0; ii < count; ++ii) {
4013804Ssaidi@eecs.umich.edu                gelf_getsym(data, ii, &sym);
4023804Ssaidi@eecs.umich.edu                if (GELF_ST_BIND(sym.st_info) == binding) {
4033804Ssaidi@eecs.umich.edu                    char *sym_name = elf_strptr(elf, shdr.sh_link, sym.st_name);
4043804Ssaidi@eecs.umich.edu                    if (sym_name && sym_name[0] != '$') {
4053804Ssaidi@eecs.umich.edu                        DPRINTF(Loader, "Symbol: %-40s value %#x\n",
4063804Ssaidi@eecs.umich.edu                                sym_name, sym.st_value);
4073804Ssaidi@eecs.umich.edu                        symtab->insert(sym.st_value & mask, sym_name);
4083804Ssaidi@eecs.umich.edu                    }
4093804Ssaidi@eecs.umich.edu                }
4103804Ssaidi@eecs.umich.edu            }
4113826Ssaidi@eecs.umich.edu        }
4124990Sgblack@eecs.umich.edu        ++sec_idx;
4133826Ssaidi@eecs.umich.edu        section = elf_getscn(elf, sec_idx);
4143916Ssaidi@eecs.umich.edu    }
4153916Ssaidi@eecs.umich.edu
4163916Ssaidi@eecs.umich.edu    elf_end(elf);
4174990Sgblack@eecs.umich.edu
4183826Ssaidi@eecs.umich.edu    return found;
4193804Ssaidi@eecs.umich.edu}
4203804Ssaidi@eecs.umich.edu
4214990Sgblack@eecs.umich.edubool
4223804Ssaidi@eecs.umich.eduElfObject::loadGlobalSymbols(SymbolTable *symtab, Addr addrMask)
4233811Ssaidi@eecs.umich.edu{
4243811Ssaidi@eecs.umich.edu    return loadSomeSymbols(symtab, STB_GLOBAL, addrMask);
4254990Sgblack@eecs.umich.edu}
4263804Ssaidi@eecs.umich.edu
4273804Ssaidi@eecs.umich.edubool
4283804Ssaidi@eecs.umich.eduElfObject::loadLocalSymbols(SymbolTable *symtab, Addr addrMask)
4294990Sgblack@eecs.umich.edu{
4303804Ssaidi@eecs.umich.edu    bool found_local = loadSomeSymbols(symtab, STB_LOCAL, addrMask);
4313804Ssaidi@eecs.umich.edu    bool found_weak = loadSomeSymbols(symtab, STB_WEAK, addrMask);
4323811Ssaidi@eecs.umich.edu    return found_local || found_weak;
4333811Ssaidi@eecs.umich.edu}
4344990Sgblack@eecs.umich.edu
4354990Sgblack@eecs.umich.edubool
4363804Ssaidi@eecs.umich.eduElfObject::loadWeakSymbols(SymbolTable *symtab, Addr addrMask)
4373804Ssaidi@eecs.umich.edu{
4383804Ssaidi@eecs.umich.edu    return loadSomeSymbols(symtab, STB_WEAK, addrMask);
4395894Sgblack@eecs.umich.edu}
4403804Ssaidi@eecs.umich.edu
4414172Ssaidi@eecs.umich.edubool
4423833Ssaidi@eecs.umich.eduElfObject::loadSections(PortProxy& memProxy, Addr addrMask, Addr offset)
4433836Ssaidi@eecs.umich.edu{
4443836Ssaidi@eecs.umich.edu    if (!ObjectFile::loadSections(memProxy, addrMask, offset))
4453836Ssaidi@eecs.umich.edu        return false;
4463836Ssaidi@eecs.umich.edu
4473836Ssaidi@eecs.umich.edu    vector<Segment>::iterator extraIt;
4483836Ssaidi@eecs.umich.edu    for (extraIt = extraSegments.begin();
4493836Ssaidi@eecs.umich.edu            extraIt != extraSegments.end(); extraIt++) {
4503836Ssaidi@eecs.umich.edu        if (!loadSection(&(*extraIt), memProxy, addrMask, offset)) {
4513836Ssaidi@eecs.umich.edu            return false;
4523836Ssaidi@eecs.umich.edu        }
4533836Ssaidi@eecs.umich.edu    }
4543836Ssaidi@eecs.umich.edu    return true;
4553836Ssaidi@eecs.umich.edu}
4565555Snate@binkert.org
4575555Snate@binkert.orgvoid
4583836Ssaidi@eecs.umich.eduElfObject::getSections()
4593836Ssaidi@eecs.umich.edu{
4603836Ssaidi@eecs.umich.edu    Elf *elf;
4613836Ssaidi@eecs.umich.edu    int sec_idx = 1; // there is a 0 but it is nothing, go figure
4623836Ssaidi@eecs.umich.edu    Elf_Scn *section;
4633836Ssaidi@eecs.umich.edu    GElf_Shdr shdr;
4643836Ssaidi@eecs.umich.edu
4653833Ssaidi@eecs.umich.edu    GElf_Ehdr ehdr;
4663833Ssaidi@eecs.umich.edu
4673833Ssaidi@eecs.umich.edu    assert(!sectionNames.size());
4683833Ssaidi@eecs.umich.edu
4693833Ssaidi@eecs.umich.edu    // check that header matches library version
4703833Ssaidi@eecs.umich.edu    if (elf_version(EV_CURRENT) == EV_NONE)
4713833Ssaidi@eecs.umich.edu        panic("wrong elf version number!");
4723833Ssaidi@eecs.umich.edu
4733833Ssaidi@eecs.umich.edu    // get a pointer to elf structure
4743804Ssaidi@eecs.umich.edu    elf = elf_memory((char*)fileData,len);
4753804Ssaidi@eecs.umich.edu    assert(elf != NULL);
4763804Ssaidi@eecs.umich.edu
4773804Ssaidi@eecs.umich.edu    // Check that we actually have a elf file
4783804Ssaidi@eecs.umich.edu    if (gelf_getehdr(elf, &ehdr) ==0) {
4793833Ssaidi@eecs.umich.edu        panic("Not ELF, shouldn't be here");
4803833Ssaidi@eecs.umich.edu    }
4813811Ssaidi@eecs.umich.edu
4823804Ssaidi@eecs.umich.edu    // Get the first section
4833804Ssaidi@eecs.umich.edu    section = elf_getscn(elf, sec_idx);
4843804Ssaidi@eecs.umich.edu
4853804Ssaidi@eecs.umich.edu    // While there are no more sections
4863804Ssaidi@eecs.umich.edu    while (section != NULL) {
4873804Ssaidi@eecs.umich.edu        gelf_getshdr(section, &shdr);
4883804Ssaidi@eecs.umich.edu        sectionNames.insert(elf_strptr(elf, ehdr.e_shstrndx, shdr.sh_name));
4893833Ssaidi@eecs.umich.edu        section = elf_getscn(elf, ++sec_idx);
4903804Ssaidi@eecs.umich.edu    } // while sections
4913804Ssaidi@eecs.umich.edu}
4923833Ssaidi@eecs.umich.edu
4933836Ssaidi@eecs.umich.edubool
4943836Ssaidi@eecs.umich.eduElfObject::sectionExists(string sec)
4953836Ssaidi@eecs.umich.edu{
4963836Ssaidi@eecs.umich.edu    if (!sectionNames.size())
4973804Ssaidi@eecs.umich.edu        getSections();
4983804Ssaidi@eecs.umich.edu    return sectionNames.find(sec) != sectionNames.end();
4993804Ssaidi@eecs.umich.edu}
5003836Ssaidi@eecs.umich.edu
5013836Ssaidi@eecs.umich.edu
5024990Sgblack@eecs.umich.edu