elf_object.cc revision 5383
17513SN/A/*
27513SN/A * Copyright (c) 2003-2005 The Regents of The University of Michigan
37513SN/A * All rights reserved.
410036SN/A *
58835SN/A * Redistribution and use in source and binary forms, with or without
610036SN/A * modification, are permitted provided that the following conditions are
77935SN/A * met: redistributions of source code must retain the above copyright
87935SN/A * notice, this list of conditions and the following disclaimer;
97935SN/A * redistributions in binary form must reproduce the above copyright
107513SN/A * notice, this list of conditions and the following disclaimer in the
117513SN/A * documentation and/or other materials provided with the distribution;
127513SN/A * neither the name of the copyright holders nor the names of its
1310315SN/A * contributors may be used to endorse or promote products derived from
148835SN/A * this software without specific prior written permission.
159885SN/A *
169885SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1710036SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
1811312Santhony.gutierrez@amd.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
198835SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
208835SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2110315SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
228835SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2310038SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
249481SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
259481SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
268721SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2711066Snilay@cs.wisc.edu *
2811219Snilay@cs.wisc.edu * Authors: Steve Reinhardt
298721SN/A *          Ali Saidi
308835SN/A */
318835SN/A
3211440SCurtis.Dunham@arm.com#include <string>
3311440SCurtis.Dunham@arm.com
347935SN/A#include "gelf.h"
357935SN/A
367935SN/A#include "base/loader/elf_object.hh"
377935SN/A#include "base/loader/symtab.hh"
387935SN/A#include "base/misc.hh"
397935SN/A#include "base/trace.hh"	// for DPRINTF
407935SN/A#include "sim/byteswap.hh"
418893SN/A
427513SN/Ausing namespace std;
439885SN/A
449885SN/AObjectFile *
459885SN/AElfObject::tryFile(const string &fname, int fd, size_t len, uint8_t *data)
4610315SN/A{
4710036SN/A    Elf *elf;
4810315SN/A    GElf_Ehdr ehdr;
499885SN/A    Arch arch = UnknownArch;
509885SN/A    OpSys opSys = UnknownOpSys;
517513SN/A
527513SN/A    // check that header matches library version
5310038SN/A    if (elf_version(EV_CURRENT) == EV_NONE)
5410315SN/A        panic("wrong elf version number!");
557513SN/A
569885SN/A    // get a pointer to elf structure
577513SN/A    elf = elf_memory((char*)data,len);
587513SN/A    // will only fail if fd is invalid
598835SN/A    assert(elf != NULL);
607513SN/A
6110038SN/A    // Check that we actually have a elf file
627513SN/A    if (gelf_getehdr(elf, &ehdr) ==0) {
6310036SN/A        DPRINTFR(Loader, "Not ELF\n");
647513SN/A        elf_end(elf);
657513SN/A        return NULL;
668835SN/A    } else {
679481SN/A        //Detect the architecture
6810038SN/A        //Since we don't know how to check for alpha right now, we'll
697513SN/A        //just assume if it wasn't something else and it's 64 bit, that's
707513SN/A        //what it must be.
717513SN/A        if (ehdr.e_machine == EM_SPARC64 ||
727513SN/A                (ehdr.e_machine == EM_SPARC &&
737513SN/A                 ehdr.e_ident[EI_CLASS] == ELFCLASS64)||
747513SN/A                ehdr.e_machine == EM_SPARCV9) {
758835SN/A            arch = ObjectFile::SPARC64;
767513SN/A        } else if (ehdr.e_machine == EM_SPARC32PLUS ||
779885SN/A                        (ehdr.e_machine == EM_SPARC &&
7810315SN/A                         ehdr.e_ident[EI_CLASS] == ELFCLASS32)) {
799481SN/A            arch = ObjectFile::SPARC32;
807513SN/A        } else if (ehdr.e_machine == EM_MIPS
817513SN/A                && ehdr.e_ident[EI_CLASS] == ELFCLASS32) {
827513SN/A            if (ehdr.e_ident[EI_DATA] == ELFDATA2LSB) {
837513SN/A                arch = ObjectFile::Mips;
847513SN/A            } else {
857513SN/A                fatal("The binary you're trying to load is compiled for big "
867513SN/A                        "endian MIPS. M5\nonly supports little endian MIPS. "
8711066Snilay@cs.wisc.edu                        "Please recompile your binary.\n");
889885SN/A            }
898893SN/A        } else if (ehdr.e_machine == EM_X86_64 &&
907513SN/A                ehdr.e_ident[EI_CLASS] == ELFCLASS64) {
919885SN/A            //In the future, we might want to differentiate between 32 bit
9211219Snilay@cs.wisc.edu            //and 64 bit x86 processes in case there are differences in their
9311066Snilay@cs.wisc.edu            //initial stack frame.
9410036SN/A            arch = ObjectFile::X86;
959481SN/A        } else if (ehdr.e_ident[EI_CLASS] == ELFCLASS64) {
9611066Snilay@cs.wisc.edu            arch = ObjectFile::Alpha;
977513SN/A        } else if (ehdr.e_machine == EM_ARM) {
989481SN/A            arch = ObjectFile::Arm;
997513SN/A        } else {
1008835SN/A            warn("Unknown architecture: %d\n", ehdr.e_machine);
1019481SN/A            arch = ObjectFile::UnknownArch;
10210036SN/A        }
1037513SN/A
1048835SN/A        //Detect the operating system
1059885SN/A        switch (ehdr.e_ident[EI_OSABI])
1069481SN/A        {
1077513SN/A
10811219Snilay@cs.wisc.edu          case ELFOSABI_LINUX:
1097513SN/A          case ELFOSABI_ARM:
1108893SN/A            opSys = ObjectFile::Linux;
1117513SN/A            break;
1129885SN/A          case ELFOSABI_SOLARIS:
1139885SN/A            opSys = ObjectFile::Solaris;
1149885SN/A            break;
1159885SN/A          case ELFOSABI_TRU64:
1169885SN/A            opSys = ObjectFile::Tru64;
11710036SN/A            break;
1189885SN/A          default:
11910036SN/A            opSys = ObjectFile::UnknownOpSys;
1209885SN/A        }
1219885SN/A
12210038SN/A        //take a look at the .note.ABI section
12310038SN/A        //It can let us know what's what.
12410038SN/A        if (opSys == ObjectFile::UnknownOpSys) {
12510038SN/A            Elf_Scn *section;
12610038SN/A            GElf_Shdr shdr;
12711066Snilay@cs.wisc.edu            Elf_Data *data;
12810038SN/A            uint32_t osAbi;;
12910038SN/A            int secIdx = 1;
13010038SN/A
13110038SN/A            // Get the first section
13210038SN/A            section = elf_getscn(elf, secIdx);
13310038SN/A
13410038SN/A            // While there are no more sections
13510038SN/A            while (section != NULL && opSys == ObjectFile::UnknownOpSys) {
13610038SN/A                gelf_getshdr(section, &shdr);
13710038SN/A                if (shdr.sh_type == SHT_NOTE && !strcmp(".note.ABI-tag",
13810038SN/A                            elf_strptr(elf, ehdr.e_shstrndx, shdr.sh_name))) {
13910038SN/A                    // we have found a ABI note section
14010038SN/A                    // Check the 5th 32bit word for OS  0 == linux, 1 == hurd,
14110038SN/A                    // 2 == solaris, 3 == freebsd
14210038SN/A                    data = elf_rawdata(section, NULL);
14310038SN/A                    assert(data->d_buf);
14410038SN/A                    if(ehdr.e_ident[EI_DATA] == ELFDATA2LSB)
14510038SN/A                        osAbi = htole(((uint32_t*)data->d_buf)[4]);
1467513SN/A                    else
1477513SN/A                        osAbi = htobe(((uint32_t*)data->d_buf)[4]);
1488835SN/A
14910036SN/A                    switch(osAbi) {
15010038SN/A                      case 0:
1517513SN/A                        opSys = ObjectFile::Linux;
1528835SN/A                        break;
1538835SN/A                      case 2:
1548835SN/A                        opSys = ObjectFile::Solaris;
1558835SN/A                        break;
1569885SN/A                    }
15710036SN/A                } // if section found
15810038SN/A                if (!strcmp(".SUNW_version", elf_strptr(elf, ehdr.e_shstrndx, shdr.sh_name)))
1599265SN/A                        opSys = ObjectFile::Solaris;
1608835SN/A                if (!strcmp(".stab.index", elf_strptr(elf, ehdr.e_shstrndx, shdr.sh_name)))
1618893SN/A                        opSys = ObjectFile::Solaris;
1627513SN/A
1637513SN/A            section = elf_getscn(elf, ++secIdx);
16411066Snilay@cs.wisc.edu            } // while sections
1659885SN/A        }
1668893SN/A
1677513SN/A        ElfObject * result = new ElfObject(fname, fd, len, data, arch, opSys);
1689885SN/A
16911219Snilay@cs.wisc.edu        //The number of headers in the file
17011066Snilay@cs.wisc.edu        result->_programHeaderCount = ehdr.e_phnum;
17110036SN/A        //Record the size of each entry
1729481SN/A        result->_programHeaderSize = ehdr.e_phentsize;
17311066Snilay@cs.wisc.edu        if(result->_programHeaderCount) //If there is a program header table
1747513SN/A        {
1759481SN/A            //Figure out the virtual address of the header table in the
1767513SN/A            //final memory image. We use the program headers themselves
1778835SN/A            //to translate from a file offset to the address in the image.
1789481SN/A            GElf_Phdr phdr;
17910036SN/A            uint64_t e_phoff = ehdr.e_phoff;
1807513SN/A            result->_programHeaderTable = 0;
1818835SN/A            for(int hdrnum = 0; hdrnum < result->_programHeaderCount; hdrnum++)
1829885SN/A            {
1839481SN/A                gelf_getphdr(elf, hdrnum, &phdr);
1847513SN/A                //Check if we've found the segment with the headers in it
18511219Snilay@cs.wisc.edu                if(phdr.p_offset <= e_phoff &&
1867513SN/A                        phdr.p_offset + phdr.p_filesz > e_phoff)
1878893SN/A                {
1887513SN/A                    result->_programHeaderTable = phdr.p_paddr + e_phoff;
1899885SN/A                    break;
1909885SN/A                }
1919885SN/A            }
1929885SN/A        }
1939885SN/A        else
19410036SN/A            result->_programHeaderTable = 0;
1959885SN/A
19610036SN/A
1979885SN/A        elf_end(elf);
1989885SN/A        return result;
1998835SN/A    }
2008835SN/A}
20110036SN/A
2028835SN/A
2039481SN/AElfObject::ElfObject(const string &_filename, int _fd,
2049481SN/A                     size_t _len, uint8_t *_data,
20511219Snilay@cs.wisc.edu                     Arch _arch, OpSys _opSys)
20610036SN/A    : ObjectFile(_filename, _fd, _len, _data, _arch, _opSys)
2079481SN/A
20810038SN/A{
20910038SN/A    Elf *elf;
21010038SN/A    GElf_Ehdr ehdr;
21110038SN/A
21210038SN/A    // check that header matches library version
21310038SN/A    if (elf_version(EV_CURRENT) == EV_NONE)
21410038SN/A        panic("wrong elf version number!");
21510038SN/A
21610038SN/A    // get a pointer to elf structure
21710038SN/A    elf = elf_memory((char*)fileData,len);
2189481SN/A    // will only fail if fd is invalid
2199481SN/A    assert(elf != NULL);
2209481SN/A
2219481SN/A    // Check that we actually have a elf file
2229481SN/A    if (gelf_getehdr(elf, &ehdr) ==0) {
2239481SN/A        panic("Not ELF, shouldn't be here");
22410038SN/A    }
2259481SN/A
2269481SN/A    entry = ehdr.e_entry;
22710038SN/A
2289481SN/A    // initialize segment sizes to 0 in case they're not present
22910038SN/A    text.size = data.size = bss.size = 0;
23010038SN/A
23111066Snilay@cs.wisc.edu    int secIdx = 1;
23210038SN/A    Elf_Scn *section;
23310038SN/A    GElf_Shdr shdr;
23410038SN/A
23510038SN/A    // The first address of some important sections.
23610038SN/A    Addr textSecStart = 0;
23710038SN/A    Addr dataSecStart = 0;
23810038SN/A    Addr bssSecStart = 0;
23911066Snilay@cs.wisc.edu
24010038SN/A    // Get the first section
24110038SN/A    section = elf_getscn(elf, secIdx);
24210038SN/A
24310038SN/A    // Find the beginning of the most interesting sections.
24410038SN/A    while (section != NULL) {
24510038SN/A        gelf_getshdr(section, &shdr);
24610038SN/A        char * secName = elf_strptr(elf, ehdr.e_shstrndx, shdr.sh_name);
24710038SN/A
24810038SN/A        if (!strcmp(".text", secName)) {
24910038SN/A            textSecStart = shdr.sh_addr;
25010038SN/A        } else if (!strcmp(".data", secName)) {
25110038SN/A            dataSecStart = shdr.sh_addr;
25210038SN/A        } else if (!strcmp(".bss", secName)) {
25310038SN/A            bssSecStart = shdr.sh_addr;
25410038SN/A        }
25510038SN/A
25610038SN/A        section = elf_getscn(elf, ++secIdx);
2579481SN/A    }
2587513SN/A
2597513SN/A    // Go through all the segments in the program, record them, and scrape
2608835SN/A    // out information about the text, data, and bss areas needed by other
26110036SN/A    // code.
26210038SN/A    for (int i = 0; i < ehdr.e_phnum; ++i) {
2637513SN/A        GElf_Phdr phdr;
2648835SN/A        if (gelf_getphdr(elf, i, &phdr) == 0) {
2658835SN/A            panic("gelf_getphdr failed for segment %d.", i);
2668835SN/A        }
2678835SN/A
2689885SN/A        // for now we don't care about non-loadable segments
26910036SN/A        if (!(phdr.p_type & PT_LOAD))
27010038SN/A            continue;
2719265SN/A
2728835SN/A        // Check to see if this segment contains the bss section.
2738893SN/A        if (phdr.p_paddr <= bssSecStart &&
2747513SN/A                phdr.p_paddr + phdr.p_memsz > bssSecStart &&
2757513SN/A                phdr.p_memsz - phdr.p_filesz > 0) {
27611066Snilay@cs.wisc.edu            bss.baseAddr = phdr.p_paddr + phdr.p_filesz;
2779885SN/A            bss.size = phdr.p_memsz - phdr.p_filesz;
2788893SN/A            bss.fileImage = NULL;
2799481SN/A        }
2809885SN/A
28111219Snilay@cs.wisc.edu        // Check to see if this is the text or data segment
28211066Snilay@cs.wisc.edu        if (phdr.p_vaddr <= textSecStart &&
28310036SN/A                phdr.p_vaddr + phdr.p_filesz > textSecStart) {
2849481SN/A            text.baseAddr = phdr.p_paddr;
28511066Snilay@cs.wisc.edu            text.size = phdr.p_filesz;
2867513SN/A            text.fileImage = fileData + phdr.p_offset;
2879481SN/A        } else if (phdr.p_vaddr <= dataSecStart &&
2887513SN/A                phdr.p_vaddr + phdr.p_filesz > dataSecStart) {
2898835SN/A            data.baseAddr = phdr.p_paddr;
2909481SN/A            data.size = phdr.p_filesz;
29110036SN/A            data.fileImage = fileData + phdr.p_offset;
2927513SN/A        } else {
2938835SN/A            Segment extra;
2949885SN/A            extra.baseAddr = phdr.p_paddr;
2959481SN/A            extra.size = phdr.p_filesz;
2967513SN/A            extra.fileImage = fileData + phdr.p_offset;
29711219Snilay@cs.wisc.edu            extraSegments.push_back(extra);
2988893SN/A        }
2998893SN/A    }
3007513SN/A
3019885SN/A    // should have found at least one loadable segment
3029885SN/A    assert(text.size != 0);
3039885SN/A
3049885SN/A    DPRINTFR(Loader, "text: 0x%x %d\ndata: 0x%x %d\nbss: 0x%x %d\n",
3059885SN/A             text.baseAddr, text.size, data.baseAddr, data.size,
30610036SN/A             bss.baseAddr, bss.size);
3079885SN/A
30810036SN/A    elf_end(elf);
3099885SN/A
3109885SN/A    // We will actually read the sections when we need to load them
3117513SN/A}
31210451SN/A
31311219Snilay@cs.wisc.edu
3149885SN/Abool
31510036SN/AElfObject::loadSomeSymbols(SymbolTable *symtab, int binding)
31611066Snilay@cs.wisc.edu{
31711066Snilay@cs.wisc.edu    Elf *elf;
31811388Ssteve.reinhardt@amd.com    int sec_idx = 1; // there is a 0 but it is nothing, go figure
31911066Snilay@cs.wisc.edu    Elf_Scn *section;
32011219Snilay@cs.wisc.edu    GElf_Shdr shdr;
32111066Snilay@cs.wisc.edu    Elf_Data *data;
3229885SN/A    int count, ii;
3237524SN/A    bool found = false;
3249481SN/A    GElf_Sym sym;
3258893SN/A
32611066Snilay@cs.wisc.edu    if (!symtab)
3277513SN/A        return false;
32811219Snilay@cs.wisc.edu
32911219Snilay@cs.wisc.edu    // check that header matches library version
33011219Snilay@cs.wisc.edu    if (elf_version(EV_CURRENT) == EV_NONE)
33111219Snilay@cs.wisc.edu        panic("wrong elf version number!");
33211219Snilay@cs.wisc.edu
33311219Snilay@cs.wisc.edu    // get a pointer to elf structure
33411219Snilay@cs.wisc.edu    elf = elf_memory((char*)fileData,len);
3357513SN/A
3367513SN/A    assert(elf != NULL);
33710036SN/A
3387513SN/A    // Get the first section
3397513SN/A    section = elf_getscn(elf, sec_idx);
3407513SN/A
3417513SN/A    // While there are no more sections
34211066Snilay@cs.wisc.edu    while (section != NULL) {
34311066Snilay@cs.wisc.edu        gelf_getshdr(section, &shdr);
3447513SN/A
3457513SN/A        if (shdr.sh_type == SHT_SYMTAB) {
3467513SN/A            found = true;
3477513SN/A            data = elf_getdata(section, NULL);
34810036SN/A            count = shdr.sh_size / shdr.sh_entsize;
34911388Ssteve.reinhardt@amd.com            DPRINTF(Loader, "Found Symbol Table, %d symbols present\n", count);
3507513SN/A
3517513SN/A            // loop through all the symbols, only loading global ones
35211066Snilay@cs.wisc.edu            for (ii = 0; ii < count; ++ii) {
3537513SN/A                gelf_getsym(data, ii, &sym);
3547513SN/A                if (GELF_ST_BIND(sym.st_info) == binding) {
3557513SN/A                   symtab->insert(sym.st_value,
3567513SN/A                                  elf_strptr(elf, shdr.sh_link, sym.st_name));
3577513SN/A                }
3587513SN/A            }
3597513SN/A        }
36010451SN/A        ++sec_idx;
3617513SN/A        section = elf_getscn(elf, sec_idx);
3629885SN/A    }
3639885SN/A
3649885SN/A    elf_end(elf);
36510315SN/A
36610036SN/A    return found;
36710315SN/A}
3689885SN/A
3699885SN/Abool
37010315SN/AElfObject::loadGlobalSymbols(SymbolTable *symtab, Addr addrMask)
37110315SN/A{
37210315SN/A    return loadSomeSymbols(symtab, STB_GLOBAL);
37310315SN/A}
37410315SN/A
37510315SN/Abool
37610315SN/AElfObject::loadLocalSymbols(SymbolTable *symtab, Addr addrMask)
37710315SN/A{
3787513SN/A    return loadSomeSymbols(symtab, STB_LOCAL);
37910451SN/A}
3809885SN/A
38110036SN/Abool
38211066Snilay@cs.wisc.eduElfObject::loadSections(Port *memPort, Addr addrMask)
38311066Snilay@cs.wisc.edu{
38411388Ssteve.reinhardt@amd.com    if (!ObjectFile::loadSections(memPort, addrMask))
38511066Snilay@cs.wisc.edu        return false;
38610451SN/A
38711066Snilay@cs.wisc.edu    vector<Segment>::iterator extraIt;
3889885SN/A    for (extraIt = extraSegments.begin();
3897524SN/A            extraIt != extraSegments.end(); extraIt++) {
39011066Snilay@cs.wisc.edu        if (!loadSection(&(*extraIt), memPort, addrMask)) {
3919265SN/A            return false;
3928893SN/A        }
3937513SN/A    }
3947513SN/A    return true;
3958983SN/A}
3969265SN/A
3979885SN/Avoid
3989885SN/AElfObject::getSections()
39910036SN/A{
4008983SN/A    Elf *elf;
4017513SN/A    int sec_idx = 1; // there is a 0 but it is nothing, go figure
4027513SN/A    Elf_Scn *section;
4037513SN/A    GElf_Shdr shdr;
4047513SN/A
4058893SN/A    GElf_Ehdr ehdr;
4067513SN/A
4079885SN/A    assert(!sectionNames.size());
4089885SN/A
40910036SN/A    // check that header matches library version
4109885SN/A    if (elf_version(EV_CURRENT) == EV_NONE)
4119885SN/A        panic("wrong elf version number!");
412
413    // get a pointer to elf structure
414    elf = elf_memory((char*)fileData,len);
415    assert(elf != NULL);
416
417    // Check that we actually have a elf file
418    if (gelf_getehdr(elf, &ehdr) ==0) {
419        panic("Not ELF, shouldn't be here");
420    }
421
422    // Get the first section
423    section = elf_getscn(elf, sec_idx);
424
425    // While there are no more sections
426    while (section != NULL) {
427        gelf_getshdr(section, &shdr);
428        sectionNames.insert(elf_strptr(elf, ehdr.e_shstrndx, shdr.sh_name));
429        section = elf_getscn(elf, ++sec_idx);
430    } // while sections
431}
432
433bool
434ElfObject::sectionExists(string sec)
435{
436    if (!sectionNames.size())
437        getSections();
438    return sectionNames.find(sec) != sectionNames.end();
439}
440
441
442