elf_object.cc revision 661
15647Sgblack@eecs.umich.edu/*
29544Sandreas.hansson@arm.com * Copyright (c) 2003 The Regents of The University of Michigan
38922Swilliam.wang@arm.com * All rights reserved.
48922Swilliam.wang@arm.com *
58922Swilliam.wang@arm.com * Redistribution and use in source and binary forms, with or without
68922Swilliam.wang@arm.com * modification, are permitted provided that the following conditions are
78922Swilliam.wang@arm.com * met: redistributions of source code must retain the above copyright
88922Swilliam.wang@arm.com * notice, this list of conditions and the following disclaimer;
98922Swilliam.wang@arm.com * redistributions in binary form must reproduce the above copyright
108922Swilliam.wang@arm.com * notice, this list of conditions and the following disclaimer in the
118922Swilliam.wang@arm.com * documentation and/or other materials provided with the distribution;
128922Swilliam.wang@arm.com * neither the name of the copyright holders nor the names of its
138922Swilliam.wang@arm.com * contributors may be used to endorse or promote products derived from
145647Sgblack@eecs.umich.edu * this software without specific prior written permission.
155647Sgblack@eecs.umich.edu *
165647Sgblack@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
177087Snate@binkert.org * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
187087Snate@binkert.org * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
197087Snate@binkert.org * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
207087Snate@binkert.org * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
217087Snate@binkert.org * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
227087Snate@binkert.org * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
237087Snate@binkert.org * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
247087Snate@binkert.org * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
255647Sgblack@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
267087Snate@binkert.org * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
277087Snate@binkert.org */
287087Snate@binkert.org
297087Snate@binkert.org#include <string>
307087Snate@binkert.org
317087Snate@binkert.org// Because of the -Wundef flag we have to do this
327087Snate@binkert.org#define __LIBELF_INTERNAL__     0
337087Snate@binkert.org// counterintuitive, but the flag below causes libelf to define
345647Sgblack@eecs.umich.edu// 64-bit elf types that apparently didn't exist in some older
357087Snate@binkert.org// versions of Linux.  They seem to be there in 2.4.x, so don't
365647Sgblack@eecs.umich.edu// set this now (it causes things to break on 64-bit platforms).
375647Sgblack@eecs.umich.edu#define __LIBELF64_LINUX        0
385647Sgblack@eecs.umich.edu#define __LIBELF_NEED_LINK_H    0
395647Sgblack@eecs.umich.edu#define __LIBELF_SYMBOL_VERSIONS 0
405647Sgblack@eecs.umich.edu
415647Sgblack@eecs.umich.edu#include <libelf/libelf.h>
425647Sgblack@eecs.umich.edu#include <libelf/gelf.h>
435647Sgblack@eecs.umich.edu
445647Sgblack@eecs.umich.edu#include "base/loader/elf_object.hh"
455647Sgblack@eecs.umich.edu
465647Sgblack@eecs.umich.edu#include "mem/functional_mem/functional_memory.hh"
475647Sgblack@eecs.umich.edu#include "base/loader/symtab.hh"
485647Sgblack@eecs.umich.edu
495647Sgblack@eecs.umich.edu#include "base/trace.hh"	// for DPRINTF
505647Sgblack@eecs.umich.edu
515647Sgblack@eecs.umich.edu
5211793Sbrandon.potter@amd.comusing namespace std;
5311793Sbrandon.potter@amd.com
5410474Sandreas.hansson@arm.comObjectFile *
5510474Sandreas.hansson@arm.comElfObject::tryFile(const string &fname, int fd, size_t len, uint8_t *data)
5611793Sbrandon.potter@amd.com{
578229Snate@binkert.org    Elf *elf;
585647Sgblack@eecs.umich.edu    GElf_Ehdr ehdr;
598232Snate@binkert.org
606137Sgblack@eecs.umich.edu    // check that header matches library version
616137Sgblack@eecs.umich.edu    assert(elf_version(EV_CURRENT) != EV_NONE);
626137Sgblack@eecs.umich.edu
635654Sgblack@eecs.umich.edu    // get a pointer to elf structure
6411793Sbrandon.potter@amd.com    elf = elf_memory((char*)data,len);
656046Sgblack@eecs.umich.edu    // will only fail if fd is invalid
665647Sgblack@eecs.umich.edu    assert(elf != NULL);
675648Sgblack@eecs.umich.edu
685648Sgblack@eecs.umich.edu    // Check that we actually have a elf file
695647Sgblack@eecs.umich.edu    if (gelf_getehdr(elf, &ehdr) ==0) {
705647Sgblack@eecs.umich.edu        DPRINTFR(Loader, "Not ELF\n");
715647Sgblack@eecs.umich.edu        elf_end(elf);
725647Sgblack@eecs.umich.edu        return NULL;
735647Sgblack@eecs.umich.edu    }
745647Sgblack@eecs.umich.edu    else {
755647Sgblack@eecs.umich.edu        if (ehdr.e_ident[EI_CLASS] == ELFCLASS32)
765647Sgblack@eecs.umich.edu            panic("32 bit ELF Binary, Not Supported");
775647Sgblack@eecs.umich.edu        if (ehdr.e_machine != EM_ALPHA)
785648Sgblack@eecs.umich.edu            panic("Non Alpha Binary, Not Supported");
795647Sgblack@eecs.umich.edu
805648Sgblack@eecs.umich.edu        elf_end(elf);
815648Sgblack@eecs.umich.edu
825648Sgblack@eecs.umich.edu        return new ElfObject(fname, fd, len, data,
835648Sgblack@eecs.umich.edu                             ObjectFile::Alpha, ObjectFile::Linux);
845648Sgblack@eecs.umich.edu    }
855648Sgblack@eecs.umich.edu}
865648Sgblack@eecs.umich.edu
875648Sgblack@eecs.umich.edu
885648Sgblack@eecs.umich.eduElfObject::ElfObject(const string &_filename, int _fd,
895648Sgblack@eecs.umich.edu                     size_t _len, uint8_t *_data,
905648Sgblack@eecs.umich.edu                     Arch _arch, OpSys _opSys)
915648Sgblack@eecs.umich.edu    : ObjectFile(_filename, _fd, _len, _data, _arch, _opSys)
925648Sgblack@eecs.umich.edu
935648Sgblack@eecs.umich.edu{
945648Sgblack@eecs.umich.edu    Elf *elf;
955648Sgblack@eecs.umich.edu    GElf_Ehdr ehdr;
965648Sgblack@eecs.umich.edu
975648Sgblack@eecs.umich.edu    // check that header matches library version
985648Sgblack@eecs.umich.edu    assert(elf_version(EV_CURRENT) != EV_NONE);
995648Sgblack@eecs.umich.edu
1005648Sgblack@eecs.umich.edu    // get a pointer to elf structure
1015648Sgblack@eecs.umich.edu    elf = elf_memory((char*)fileData,len);
1025648Sgblack@eecs.umich.edu    // will only fail if fd is invalid
1035648Sgblack@eecs.umich.edu    assert(elf != NULL);
1045648Sgblack@eecs.umich.edu
1055648Sgblack@eecs.umich.edu    // Check that we actually have a elf file
1065648Sgblack@eecs.umich.edu    if (gelf_getehdr(elf, &ehdr) ==0) {
1075648Sgblack@eecs.umich.edu        panic("Not ELF, shouldn't be here");
1085648Sgblack@eecs.umich.edu    }
1095648Sgblack@eecs.umich.edu
1105648Sgblack@eecs.umich.edu    entry = ehdr.e_entry;
1115648Sgblack@eecs.umich.edu
1125648Sgblack@eecs.umich.edu    // initialize segment sizes to 0 in case they're not present
1135648Sgblack@eecs.umich.edu    text.size = data.size = bss.size = 0;
1145648Sgblack@eecs.umich.edu
1155648Sgblack@eecs.umich.edu    for (int i = 0; i < ehdr.e_phnum; ++i) {
1165648Sgblack@eecs.umich.edu        GElf_Phdr phdr;
1175648Sgblack@eecs.umich.edu        if (gelf_getphdr(elf, i, &phdr) == 0) {
1185648Sgblack@eecs.umich.edu            panic("gelf_getphdr failed for section %d", i);
1195648Sgblack@eecs.umich.edu        }
1205648Sgblack@eecs.umich.edu
1215648Sgblack@eecs.umich.edu        // for now we don't care about non-loadable segments
1225648Sgblack@eecs.umich.edu        if (!(phdr.p_type & PT_LOAD))
12311479Sbaz21@cam.ac.uk            continue;
1245648Sgblack@eecs.umich.edu
1255648Sgblack@eecs.umich.edu        // the headers don't explicitly distinguish text from data,
1265648Sgblack@eecs.umich.edu        // but empirically the text segment comes first.
1275648Sgblack@eecs.umich.edu        if (text.size == 0) {  // haven't seen text segment yet
1285648Sgblack@eecs.umich.edu            text.baseAddr = phdr.p_vaddr;
1295648Sgblack@eecs.umich.edu            text.size = phdr.p_filesz;
1305648Sgblack@eecs.umich.edu            // remember where the data is for loadSections()
1315648Sgblack@eecs.umich.edu            fileTextBits = fileData + phdr.p_offset;
1325648Sgblack@eecs.umich.edu            // if there's any padding at the end that's not in the
13311479Sbaz21@cam.ac.uk            // file, call it the bss.  This happens in the "text"
1345648Sgblack@eecs.umich.edu            // segment if there's only one loadable segment (as for
1355648Sgblack@eecs.umich.edu            // kernel images).
1365648Sgblack@eecs.umich.edu            bss.size = phdr.p_memsz - phdr.p_filesz;
1375648Sgblack@eecs.umich.edu            bss.baseAddr = phdr.p_vaddr + phdr.p_filesz;
1385648Sgblack@eecs.umich.edu        }
1395648Sgblack@eecs.umich.edu        else if (data.size == 0) { // have text, this must be data
1405648Sgblack@eecs.umich.edu            data.baseAddr = phdr.p_vaddr;
1415648Sgblack@eecs.umich.edu            data.size = phdr.p_filesz;
1425648Sgblack@eecs.umich.edu            // remember where the data is for loadSections()
14311479Sbaz21@cam.ac.uk            fileDataBits = fileData + phdr.p_offset;
1445648Sgblack@eecs.umich.edu            // if there's any padding at the end that's not in the
1455648Sgblack@eecs.umich.edu            // file, call it the bss.  Warn if this happens for both
1465648Sgblack@eecs.umich.edu            // the text & data segments (should only have one bss).
1475648Sgblack@eecs.umich.edu            if (phdr.p_memsz - phdr.p_filesz > 0 && bss.size != 0) {
1485648Sgblack@eecs.umich.edu                warn("Two implied bss segments in file!\n");
1495648Sgblack@eecs.umich.edu            }
1505648Sgblack@eecs.umich.edu            bss.size = phdr.p_memsz - phdr.p_filesz;
1515648Sgblack@eecs.umich.edu            bss.baseAddr = phdr.p_vaddr + phdr.p_filesz;
1525648Sgblack@eecs.umich.edu        }
1535648Sgblack@eecs.umich.edu    }
1545648Sgblack@eecs.umich.edu
1555648Sgblack@eecs.umich.edu    // should have found at least one loadable segment
1565648Sgblack@eecs.umich.edu    assert(text.size != 0);
1575648Sgblack@eecs.umich.edu
1585648Sgblack@eecs.umich.edu    DPRINTFR(Loader, "text: 0x%x %d\ndata: 0x%x %d\nbss: 0x%x %d\n",
1595648Sgblack@eecs.umich.edu             text.baseAddr, text.size, data.baseAddr, data.size,
1605648Sgblack@eecs.umich.edu             bss.baseAddr, bss.size);
1615648Sgblack@eecs.umich.edu
1625648Sgblack@eecs.umich.edu    elf_end(elf);
1635648Sgblack@eecs.umich.edu
1645648Sgblack@eecs.umich.edu    // We will actually read the sections when we need to load them
1655648Sgblack@eecs.umich.edu}
1665648Sgblack@eecs.umich.edu
1675648Sgblack@eecs.umich.edu
1685648Sgblack@eecs.umich.edubool
1695648Sgblack@eecs.umich.eduElfObject::loadSections(FunctionalMemory *mem, bool loadPhys)
1705648Sgblack@eecs.umich.edu{
1715648Sgblack@eecs.umich.edu    Addr textAddr = text.baseAddr;
1725648Sgblack@eecs.umich.edu    Addr dataAddr = data.baseAddr;
1735648Sgblack@eecs.umich.edu
1745648Sgblack@eecs.umich.edu    if (loadPhys) {
1755648Sgblack@eecs.umich.edu        textAddr &= (ULL(1) << 40) - 1;
1765648Sgblack@eecs.umich.edu        dataAddr &= (ULL(1) << 40) - 1;
1775648Sgblack@eecs.umich.edu    }
1785648Sgblack@eecs.umich.edu
1795648Sgblack@eecs.umich.edu    // Since we don't really have an MMU and all memory is
1805648Sgblack@eecs.umich.edu    // zero-filled, there's no need to set up the BSS segment.
1815648Sgblack@eecs.umich.edu    if (text.size != 0)
1825648Sgblack@eecs.umich.edu        mem->prot_write(textAddr, fileTextBits, text.size);
1835648Sgblack@eecs.umich.edu    if (data.size != 0)
1845648Sgblack@eecs.umich.edu        mem->prot_write(dataAddr, fileDataBits, data.size);
1855648Sgblack@eecs.umich.edu
1865648Sgblack@eecs.umich.edu    return true;
1875648Sgblack@eecs.umich.edu}
1885648Sgblack@eecs.umich.edu
1895648Sgblack@eecs.umich.edu
1905648Sgblack@eecs.umich.edubool
1915648Sgblack@eecs.umich.eduElfObject::loadSomeSymbols(SymbolTable *symtab, int binding)
1925648Sgblack@eecs.umich.edu{
1935648Sgblack@eecs.umich.edu    Elf *elf;
19414293Sgabeblack@google.com    int secidx = 1; // there is a 0 but it is nothing, go figure
1955648Sgblack@eecs.umich.edu    Elf_Scn *section;
1965648Sgblack@eecs.umich.edu    GElf_Shdr shdr;
1975648Sgblack@eecs.umich.edu    Elf_Data *data;
1985648Sgblack@eecs.umich.edu    int count, ii;
1995649Sgblack@eecs.umich.edu    bool found = false;
2005649Sgblack@eecs.umich.edu    GElf_Sym sym;
2015649Sgblack@eecs.umich.edu
2025648Sgblack@eecs.umich.edu    if (!symtab)
2035898Sgblack@eecs.umich.edu        return false;
2049805Sstever@gmail.com
2055648Sgblack@eecs.umich.edu    // check that header matches library version
2065648Sgblack@eecs.umich.edu    assert(elf_version(EV_CURRENT) != EV_NONE);
2075648Sgblack@eecs.umich.edu
2085648Sgblack@eecs.umich.edu    // get a pointer to elf structure
2095648Sgblack@eecs.umich.edu    elf = elf_memory((char*)fileData,len);
2105648Sgblack@eecs.umich.edu
21114293Sgabeblack@google.com    assert(elf != NULL);
2125648Sgblack@eecs.umich.edu
2135648Sgblack@eecs.umich.edu    // Get the first section
2145648Sgblack@eecs.umich.edu    section = elf_getscn(elf, secidx);
2155648Sgblack@eecs.umich.edu
2165648Sgblack@eecs.umich.edu    // While there are no more sections
2175649Sgblack@eecs.umich.edu    while (section != NULL) {
2185649Sgblack@eecs.umich.edu        gelf_getshdr(section, &shdr);
2195649Sgblack@eecs.umich.edu
2205648Sgblack@eecs.umich.edu        if (shdr.sh_type == SHT_SYMTAB) {
2215898Sgblack@eecs.umich.edu            found = true;
2229805Sstever@gmail.com            data = elf_getdata(section, NULL);
2235647Sgblack@eecs.umich.edu            count = shdr.sh_size / shdr.sh_entsize;
2245691Sgblack@eecs.umich.edu            DPRINTF(Loader, "Found Symbol Table, %d symbols present\n", count);
2255691Sgblack@eecs.umich.edu
2265691Sgblack@eecs.umich.edu            // loop through all the symbols, only loading global ones
2275691Sgblack@eecs.umich.edu            for (ii = 0; ii < count; ++ii) {
2285691Sgblack@eecs.umich.edu                gelf_getsym(data, ii, &sym);
2295691Sgblack@eecs.umich.edu                if (GELF_ST_BIND(sym.st_info) & binding) {
2305691Sgblack@eecs.umich.edu                   symtab->insert(sym.st_value,
2315691Sgblack@eecs.umich.edu                                  elf_strptr(elf, shdr.sh_link, sym.st_name));
2325691Sgblack@eecs.umich.edu                }
2335691Sgblack@eecs.umich.edu            }
2345691Sgblack@eecs.umich.edu        }
2355691Sgblack@eecs.umich.edu        ++secidx;
2365691Sgblack@eecs.umich.edu        section = elf_getscn(elf, secidx);
2375691Sgblack@eecs.umich.edu    }
2385691Sgblack@eecs.umich.edu
2395691Sgblack@eecs.umich.edu    elf_end(elf);
2405691Sgblack@eecs.umich.edu
2415691Sgblack@eecs.umich.edu    return found;
2425691Sgblack@eecs.umich.edu}
2435691Sgblack@eecs.umich.edu
2445691Sgblack@eecs.umich.edubool
2455691Sgblack@eecs.umich.eduElfObject::loadGlobalSymbols(SymbolTable *symtab)
2465691Sgblack@eecs.umich.edu{
2475691Sgblack@eecs.umich.edu    return loadSomeSymbols(symtab, STB_GLOBAL);
2485691Sgblack@eecs.umich.edu}
2495691Sgblack@eecs.umich.edu
2505691Sgblack@eecs.umich.edubool
2515691Sgblack@eecs.umich.eduElfObject::loadLocalSymbols(SymbolTable *symtab)
2525691Sgblack@eecs.umich.edu{
2535691Sgblack@eecs.umich.edu    return loadSomeSymbols(symtab, STB_LOCAL);
2545691Sgblack@eecs.umich.edu}
2555691Sgblack@eecs.umich.edu