elf_object.cc revision 2423
12929Sktlim@umich.edu/*
22929Sktlim@umich.edu * Copyright (c) 2003-2005 The Regents of The University of Michigan
32932Sktlim@umich.edu * All rights reserved.
42929Sktlim@umich.edu *
52929Sktlim@umich.edu * Redistribution and use in source and binary forms, with or without
62929Sktlim@umich.edu * modification, are permitted provided that the following conditions are
72929Sktlim@umich.edu * met: redistributions of source code must retain the above copyright
82929Sktlim@umich.edu * notice, this list of conditions and the following disclaimer;
92929Sktlim@umich.edu * redistributions in binary form must reproduce the above copyright
102929Sktlim@umich.edu * notice, this list of conditions and the following disclaimer in the
112929Sktlim@umich.edu * documentation and/or other materials provided with the distribution;
122929Sktlim@umich.edu * neither the name of the copyright holders nor the names of its
132929Sktlim@umich.edu * contributors may be used to endorse or promote products derived from
142929Sktlim@umich.edu * this software without specific prior written permission.
152929Sktlim@umich.edu *
162929Sktlim@umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
172929Sktlim@umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
182929Sktlim@umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
192929Sktlim@umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
202929Sktlim@umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
212929Sktlim@umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
222929Sktlim@umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
232929Sktlim@umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
242929Sktlim@umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
252929Sktlim@umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
262929Sktlim@umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
272929Sktlim@umich.edu */
282932Sktlim@umich.edu
292932Sktlim@umich.edu#include <string>
302932Sktlim@umich.edu
312929Sktlim@umich.edu// Because of the -Wundef flag we have to do this
326007Ssteve.reinhardt@amd.com#define __LIBELF_INTERNAL__     0
337735SAli.Saidi@ARM.com// counterintuitive, but the flag below causes libelf to define
342929Sktlim@umich.edu// 64-bit elf types that apparently didn't exist in some older
352929Sktlim@umich.edu// versions of Linux.  They seem to be there in 2.4.x, so don't
362929Sktlim@umich.edu// set this now (it causes things to break on 64-bit platforms).
372929Sktlim@umich.edu#define __LIBELF64_LINUX        0
382929Sktlim@umich.edu#define __LIBELF_NEED_LINK_H    0
392929Sktlim@umich.edu#define __LIBELF_SYMBOL_VERSIONS 0
402929Sktlim@umich.edu
418947Sandreas.hansson@arm.com#include "libelf/libelf.h"
428947Sandreas.hansson@arm.com#include "libelf/gelf.h"
438947Sandreas.hansson@arm.com
442929Sktlim@umich.edu#include "base/loader/elf_object.hh"
452929Sktlim@umich.edu
462929Sktlim@umich.edu#include "base/loader/symtab.hh"
472929Sktlim@umich.edu
482929Sktlim@umich.edu#include "base/trace.hh"	// for DPRINTF
492929Sktlim@umich.edu
506007Ssteve.reinhardt@amd.com#include "sim/byteswap.hh"
516007Ssteve.reinhardt@amd.com
526007Ssteve.reinhardt@amd.com
536007Ssteve.reinhardt@amd.comusing namespace std;
546007Ssteve.reinhardt@amd.com
556007Ssteve.reinhardt@amd.comObjectFile *
566007Ssteve.reinhardt@amd.comElfObject::tryFile(const string &fname, int fd, size_t len, uint8_t *data)
576007Ssteve.reinhardt@amd.com{
586007Ssteve.reinhardt@amd.com    Elf *elf;
596007Ssteve.reinhardt@amd.com    GElf_Ehdr ehdr;
606007Ssteve.reinhardt@amd.com    Arch arch = UnknownArch;
616007Ssteve.reinhardt@amd.com    OpSys opSys = UnknownOpSys;
626007Ssteve.reinhardt@amd.com
636007Ssteve.reinhardt@amd.com    // check that header matches library version
646007Ssteve.reinhardt@amd.com    if (elf_version(EV_CURRENT) == EV_NONE)
656007Ssteve.reinhardt@amd.com        panic("wrong elf version number!");
669435SAndreas.Sandberg@ARM.com
679435SAndreas.Sandberg@ARM.com    // get a pointer to elf structure
689435SAndreas.Sandberg@ARM.com    elf = elf_memory((char*)data,len);
696007Ssteve.reinhardt@amd.com    // will only fail if fd is invalid
706007Ssteve.reinhardt@amd.com    assert(elf != NULL);
716007Ssteve.reinhardt@amd.com
726007Ssteve.reinhardt@amd.com    // Check that we actually have a elf file
736007Ssteve.reinhardt@amd.com    if (gelf_getehdr(elf, &ehdr) ==0) {
746007Ssteve.reinhardt@amd.com        DPRINTFR(Loader, "Not ELF\n");
756007Ssteve.reinhardt@amd.com        elf_end(elf);
766007Ssteve.reinhardt@amd.com        return NULL;
776007Ssteve.reinhardt@amd.com    }
786007Ssteve.reinhardt@amd.com    else {
792929Sktlim@umich.edu        //Detect the architecture
802929Sktlim@umich.edu        //Versioning issues in libelf need to be resolved to get the correct
812929Sktlim@umich.edu        //SPARC constants.
826007Ssteve.reinhardt@amd.com        //If MIPS supports 32 bit executables, this may need to be changed.
836007Ssteve.reinhardt@amd.com        //Also, there are other MIPS constants which may be used, like
846007Ssteve.reinhardt@amd.com        //EM_MIPS_RS3_LE and EM_MIPS_X
859781Sandreas.hansson@arm.com        //Since we don't know how to check for alpha right now, we'll
866007Ssteve.reinhardt@amd.com        //just assume if it wasn't something else and it's 64 bit, that's
876007Ssteve.reinhardt@amd.com        //what it must be.
882929Sktlim@umich.edu        if (ehdr.e_machine == EM_SPARC64 ||
892929Sktlim@umich.edu                ehdr.e_machine == EM_SPARC ||
902929Sktlim@umich.edu                ehdr.e_machine == EM_SPARCV9) {
912929Sktlim@umich.edu            arch = ObjectFile::SPARC;
922929Sktlim@umich.edu        } else if (ehdr.e_machine == EM_MIPS
936011Ssteve.reinhardt@amd.com                && ehdr.e_ident[EI_CLASS] == ELFCLASS32) {
946007Ssteve.reinhardt@amd.com            arch = ObjectFile::MIPS;
956007Ssteve.reinhardt@amd.com        } else if (ehdr.e_ident[EI_CLASS] == ELFCLASS64) {
966007Ssteve.reinhardt@amd.com            arch = ObjectFile::Alpha;
976007Ssteve.reinhardt@amd.com        } else {
986007Ssteve.reinhardt@amd.com            arch = ObjectFile::UnknownArch;
996007Ssteve.reinhardt@amd.com        }
1006007Ssteve.reinhardt@amd.com
1016007Ssteve.reinhardt@amd.com        //Detect the operating system
1026007Ssteve.reinhardt@amd.com        switch (ehdr.e_ident[EI_OSABI])
1036007Ssteve.reinhardt@amd.com        {
1046007Ssteve.reinhardt@amd.com
1056007Ssteve.reinhardt@amd.com          case ELFOSABI_LINUX:
1066007Ssteve.reinhardt@amd.com            opSys = ObjectFile::Linux;
10710384SCurtis.Dunham@arm.com            break;
10810384SCurtis.Dunham@arm.com          case ELFOSABI_SOLARIS:
10910384SCurtis.Dunham@arm.com            opSys = ObjectFile::Solaris;
11010384SCurtis.Dunham@arm.com            break;
1116007Ssteve.reinhardt@amd.com          case ELFOSABI_TRU64:
1129781Sandreas.hansson@arm.com            opSys = ObjectFile::Tru64;
1139781Sandreas.hansson@arm.com            break;
1149781Sandreas.hansson@arm.com          default:
1159781Sandreas.hansson@arm.com            opSys = ObjectFile::UnknownOpSys;
1167735SAli.Saidi@ARM.com        }
1176011Ssteve.reinhardt@amd.com
1186007Ssteve.reinhardt@amd.com        //take a look at the .note.ABI section
1199781Sandreas.hansson@arm.com        //It can let us know what's what.
1206007Ssteve.reinhardt@amd.com        if (opSys == ObjectFile::UnknownOpSys)
1216007Ssteve.reinhardt@amd.com        {
1227735SAli.Saidi@ARM.com            Elf_Scn *section;
1237735SAli.Saidi@ARM.com            GElf_Shdr shdr;
1247735SAli.Saidi@ARM.com            Elf_Data *data;
1257735SAli.Saidi@ARM.com            uint32_t osAbi;;
1267735SAli.Saidi@ARM.com            int secIdx = 1;
1277735SAli.Saidi@ARM.com
1287735SAli.Saidi@ARM.com            // Get the first section
1297735SAli.Saidi@ARM.com            section = elf_getscn(elf, secIdx);
1307735SAli.Saidi@ARM.com
1317735SAli.Saidi@ARM.com            // While there are no more sections
1327735SAli.Saidi@ARM.com            while (section != NULL) {
1337735SAli.Saidi@ARM.com                gelf_getshdr(section, &shdr);
1347735SAli.Saidi@ARM.com                if (shdr.sh_type == SHT_NOTE && !strcmp(".note.ABI-tag",
1357735SAli.Saidi@ARM.com                            elf_strptr(elf, ehdr.e_shstrndx, shdr.sh_name))) {
1366007Ssteve.reinhardt@amd.com                    // we have found a ABI note section
1378599Ssteve.reinhardt@amd.com                    // Check the 5th 32bit word for OS  0 == linux, 1 == hurd,
1388599Ssteve.reinhardt@amd.com                    // 2 == solaris, 3 == freebsd
1398599Ssteve.reinhardt@amd.com                    data = elf_rawdata(section, NULL);
1406007Ssteve.reinhardt@amd.com                    assert(data->d_buf);
1416011Ssteve.reinhardt@amd.com                    if(ehdr.e_ident[EI_DATA] == ELFDATA2LSB)
1426007Ssteve.reinhardt@amd.com                        osAbi = htole(((uint32_t*)data->d_buf)[4]);
1436007Ssteve.reinhardt@amd.com                    else
1446007Ssteve.reinhardt@amd.com                        osAbi = htobe(((uint32_t*)data->d_buf)[4]);
1456007Ssteve.reinhardt@amd.com
1466007Ssteve.reinhardt@amd.com                    switch(osAbi) {
1476007Ssteve.reinhardt@amd.com                      case 0:
1489781Sandreas.hansson@arm.com                        opSys = ObjectFile::Linux;
1499781Sandreas.hansson@arm.com                        break;
1509781Sandreas.hansson@arm.com                      case 2:
1519781Sandreas.hansson@arm.com                        opSys = ObjectFile::Solaris;
1526007Ssteve.reinhardt@amd.com                        break;
1536007Ssteve.reinhardt@amd.com                    }
1546007Ssteve.reinhardt@amd.com                } // if section found
1559781Sandreas.hansson@arm.com            section = elf_getscn(elf, ++secIdx);
1569781Sandreas.hansson@arm.com            } // while sections
1579781Sandreas.hansson@arm.com        }
1589781Sandreas.hansson@arm.com        elf_end(elf);
15910384SCurtis.Dunham@arm.com        return new ElfObject(fname, fd, len, data, arch, opSys);
16010384SCurtis.Dunham@arm.com    }
16110384SCurtis.Dunham@arm.com}
1629781Sandreas.hansson@arm.com
1636008Ssteve.reinhardt@amd.com
1646008Ssteve.reinhardt@amd.comElfObject::ElfObject(const string &_filename, int _fd,
1656008Ssteve.reinhardt@amd.com                     size_t _len, uint8_t *_data,
1666008Ssteve.reinhardt@amd.com                     Arch _arch, OpSys _opSys)
1676008Ssteve.reinhardt@amd.com    : ObjectFile(_filename, _fd, _len, _data, _arch, _opSys)
1689401SAndreas.Sandberg@ARM.com
1699781Sandreas.hansson@arm.com{
1709781Sandreas.hansson@arm.com    Elf *elf;
1716008Ssteve.reinhardt@amd.com    GElf_Ehdr ehdr;
1729781Sandreas.hansson@arm.com
1736007Ssteve.reinhardt@amd.com    // check that header matches library version
1746007Ssteve.reinhardt@amd.com    if (elf_version(EV_CURRENT) == EV_NONE)
1756007Ssteve.reinhardt@amd.com        panic("wrong elf version number!");
1766007Ssteve.reinhardt@amd.com
1779781Sandreas.hansson@arm.com    // get a pointer to elf structure
1786007Ssteve.reinhardt@amd.com    elf = elf_memory((char*)fileData,len);
1796007Ssteve.reinhardt@amd.com    // will only fail if fd is invalid
1802929Sktlim@umich.edu    assert(elf != NULL);
1812929Sktlim@umich.edu
1822929Sktlim@umich.edu    // Check that we actually have a elf file
1832929Sktlim@umich.edu    if (gelf_getehdr(elf, &ehdr) ==0) {
1846007Ssteve.reinhardt@amd.com        panic("Not ELF, shouldn't be here");
1856007Ssteve.reinhardt@amd.com    }
1862929Sktlim@umich.edu
1872929Sktlim@umich.edu    entry = ehdr.e_entry;
1886007Ssteve.reinhardt@amd.com
1892929Sktlim@umich.edu    // initialize segment sizes to 0 in case they're not present
1902929Sktlim@umich.edu    text.size = data.size = bss.size = 0;
1918947Sandreas.hansson@arm.com
1928947Sandreas.hansson@arm.com    for (int i = 0; i < ehdr.e_phnum; ++i) {
1938947Sandreas.hansson@arm.com        GElf_Phdr phdr;
1948947Sandreas.hansson@arm.com        if (gelf_getphdr(elf, i, &phdr) == 0) {
1958947Sandreas.hansson@arm.com            panic("gelf_getphdr failed for section %d", i);
1968947Sandreas.hansson@arm.com        }
1978947Sandreas.hansson@arm.com
1988947Sandreas.hansson@arm.com        // for now we don't care about non-loadable segments
1998947Sandreas.hansson@arm.com        if (!(phdr.p_type & PT_LOAD))
2008947Sandreas.hansson@arm.com            continue;
20110384SCurtis.Dunham@arm.com
2028947Sandreas.hansson@arm.com        // the headers don't explicitly distinguish text from data,
2039781Sandreas.hansson@arm.com        // but empirically the text segment comes first.
2049781Sandreas.hansson@arm.com        if (text.size == 0) {  // haven't seen text segment yet
2058947Sandreas.hansson@arm.com            text.baseAddr = phdr.p_vaddr;
2068947Sandreas.hansson@arm.com            text.size = phdr.p_filesz;
2079401SAndreas.Sandberg@ARM.com            text.fileImage = fileData + phdr.p_offset;
2089781Sandreas.hansson@arm.com            // if there's any padding at the end that's not in the
2098947Sandreas.hansson@arm.com            // file, call it the bss.  This happens in the "text"
2108947Sandreas.hansson@arm.com            // segment if there's only one loadable segment (as for
2118947Sandreas.hansson@arm.com            // kernel images).
2128947Sandreas.hansson@arm.com            bss.size = phdr.p_memsz - phdr.p_filesz;
2138947Sandreas.hansson@arm.com            bss.baseAddr = phdr.p_vaddr + phdr.p_filesz;
2148947Sandreas.hansson@arm.com            bss.fileImage = NULL;
2152929Sktlim@umich.edu        }
2162929Sktlim@umich.edu        else if (data.size == 0) { // have text, this must be data
2172929Sktlim@umich.edu            data.baseAddr = phdr.p_vaddr;
2182929Sktlim@umich.edu            data.size = phdr.p_filesz;
2194937Sstever@gmail.com            data.fileImage = fileData + phdr.p_offset;
2204937Sstever@gmail.com            // if there's any padding at the end that's not in the
2214937Sstever@gmail.com            // file, call it the bss.  Warn if this happens for both
2224937Sstever@gmail.com            // the text & data segments (should only have one bss).
2238120Sgblack@eecs.umich.edu            if (phdr.p_memsz - phdr.p_filesz > 0 && bss.size != 0) {
2244937Sstever@gmail.com                warn("Two implied bss segments in file!\n");
2254937Sstever@gmail.com            }
2264937Sstever@gmail.com            bss.size = phdr.p_memsz - phdr.p_filesz;
2274937Sstever@gmail.com            bss.baseAddr = phdr.p_vaddr + phdr.p_filesz;
2285773Snate@binkert.org            bss.fileImage = NULL;
2294937Sstever@gmail.com        }
2304937Sstever@gmail.com    }
2314937Sstever@gmail.com
2322929Sktlim@umich.edu    // should have found at least one loadable segment
2332929Sktlim@umich.edu    assert(text.size != 0);
2342929Sktlim@umich.edu
2355773Snate@binkert.org    DPRINTFR(Loader, "text: 0x%x %d\ndata: 0x%x %d\nbss: 0x%x %d\n",
2362929Sktlim@umich.edu             text.baseAddr, text.size, data.baseAddr, data.size,
2372929Sktlim@umich.edu             bss.baseAddr, bss.size);
2382929Sktlim@umich.edu
2392929Sktlim@umich.edu    elf_end(elf);
2402929Sktlim@umich.edu
2412929Sktlim@umich.edu    // We will actually read the sections when we need to load them
2424937Sstever@gmail.com}
2434937Sstever@gmail.com
2444937Sstever@gmail.com
2454937Sstever@gmail.combool
2464937Sstever@gmail.comElfObject::loadSomeSymbols(SymbolTable *symtab, int binding)
2474937Sstever@gmail.com{
2484937Sstever@gmail.com    Elf *elf;
2494937Sstever@gmail.com    int sec_idx = 1; // there is a 0 but it is nothing, go figure
2504937Sstever@gmail.com    Elf_Scn *section;
2514937Sstever@gmail.com    GElf_Shdr shdr;
2524937Sstever@gmail.com    Elf_Data *data;
2534937Sstever@gmail.com    int count, ii;
2544937Sstever@gmail.com    bool found = false;
2554937Sstever@gmail.com    GElf_Sym sym;
2564937Sstever@gmail.com
2572929Sktlim@umich.edu    if (!symtab)
2582929Sktlim@umich.edu        return false;
2592929Sktlim@umich.edu
2602929Sktlim@umich.edu    // check that header matches library version
2612929Sktlim@umich.edu    if (elf_version(EV_CURRENT) == EV_NONE)
2622929Sktlim@umich.edu        panic("wrong elf version number!");
2632929Sktlim@umich.edu
2646011Ssteve.reinhardt@amd.com    // get a pointer to elf structure
2652929Sktlim@umich.edu    elf = elf_memory((char*)fileData,len);
2662929Sktlim@umich.edu
2672929Sktlim@umich.edu    assert(elf != NULL);
2682929Sktlim@umich.edu
2692929Sktlim@umich.edu    // Get the first section
2702929Sktlim@umich.edu    section = elf_getscn(elf, sec_idx);
2712929Sktlim@umich.edu
2722929Sktlim@umich.edu    // While there are no more sections
2732997Sstever@eecs.umich.edu    while (section != NULL) {
2742997Sstever@eecs.umich.edu        gelf_getshdr(section, &shdr);
2752929Sktlim@umich.edu
27610196SCurtis.Dunham@arm.com        if (shdr.sh_type == SHT_SYMTAB) {
2772929Sktlim@umich.edu            found = true;
27810196SCurtis.Dunham@arm.com            data = elf_getdata(section, NULL);
27910196SCurtis.Dunham@arm.com            count = shdr.sh_size / shdr.sh_entsize;
28010196SCurtis.Dunham@arm.com            DPRINTF(Loader, "Found Symbol Table, %d symbols present\n", count);
28110196SCurtis.Dunham@arm.com
2822929Sktlim@umich.edu            // loop through all the symbols, only loading global ones
28310196SCurtis.Dunham@arm.com            for (ii = 0; ii < count; ++ii) {
2842997Sstever@eecs.umich.edu                gelf_getsym(data, ii, &sym);
2852997Sstever@eecs.umich.edu                if (GELF_ST_BIND(sym.st_info) == binding) {
2862997Sstever@eecs.umich.edu                   symtab->insert(sym.st_value,
2875773Snate@binkert.org                                  elf_strptr(elf, shdr.sh_link, sym.st_name));
2885773Snate@binkert.org                }
2892997Sstever@eecs.umich.edu            }
2902997Sstever@eecs.umich.edu        }
2919922Ssteve.reinhardt@amd.com        ++sec_idx;
2926007Ssteve.reinhardt@amd.com        section = elf_getscn(elf, sec_idx);
2932997Sstever@eecs.umich.edu    }
2942929Sktlim@umich.edu
2952997Sstever@eecs.umich.edu    elf_end(elf);
2968120Sgblack@eecs.umich.edu
2972997Sstever@eecs.umich.edu    return found;
2982997Sstever@eecs.umich.edu}
2992997Sstever@eecs.umich.edu
3002997Sstever@eecs.umich.edubool
3012997Sstever@eecs.umich.eduElfObject::loadGlobalSymbols(SymbolTable *symtab)
3022929Sktlim@umich.edu{
3032997Sstever@eecs.umich.edu    return loadSomeSymbols(symtab, STB_GLOBAL);
3042929Sktlim@umich.edu}
3052929Sktlim@umich.edu
3063005Sstever@eecs.umich.edubool
3073005Sstever@eecs.umich.eduElfObject::loadLocalSymbols(SymbolTable *symtab)
3088802Sgblack@eecs.umich.edu{
3098802Sgblack@eecs.umich.edu    return loadSomeSymbols(symtab, STB_LOCAL);
3108802Sgblack@eecs.umich.edu}
3118802Sgblack@eecs.umich.edu