elf_object.cc revision 2420
19538Satgutier@umich.edu/*
29538Satgutier@umich.edu * Copyright (c) 2003-2005 The Regents of The University of Michigan
39538Satgutier@umich.edu * All rights reserved.
49538Satgutier@umich.edu *
59538Satgutier@umich.edu * Redistribution and use in source and binary forms, with or without
69538Satgutier@umich.edu * modification, are permitted provided that the following conditions are
79538Satgutier@umich.edu * met: redistributions of source code must retain the above copyright
89538Satgutier@umich.edu * notice, this list of conditions and the following disclaimer;
99538Satgutier@umich.edu * redistributions in binary form must reproduce the above copyright
109538Satgutier@umich.edu * notice, this list of conditions and the following disclaimer in the
119538Satgutier@umich.edu * documentation and/or other materials provided with the distribution;
129538Satgutier@umich.edu * neither the name of the copyright holders nor the names of its
139538Satgutier@umich.edu * contributors may be used to endorse or promote products derived from
149538Satgutier@umich.edu * this software without specific prior written permission.
159538Satgutier@umich.edu *
169538Satgutier@umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
179538Satgutier@umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
189538Satgutier@umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
199538Satgutier@umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
209538Satgutier@umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
219538Satgutier@umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
229538Satgutier@umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
239538Satgutier@umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
249538Satgutier@umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
259538Satgutier@umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
269538Satgutier@umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
279538Satgutier@umich.edu */
289538Satgutier@umich.edu
299538Satgutier@umich.edu#include <string>
309538Satgutier@umich.edu
3111761Sbrandon.potter@amd.com// Because of the -Wundef flag we have to do this
3211761Sbrandon.potter@amd.com#define __LIBELF_INTERNAL__     0
339538Satgutier@umich.edu// counterintuitive, but the flag below causes libelf to define
349538Satgutier@umich.edu// 64-bit elf types that apparently didn't exist in some older
359538Satgutier@umich.edu// versions of Linux.  They seem to be there in 2.4.x, so don't
369538Satgutier@umich.edu// set this now (it causes things to break on 64-bit platforms).
379538Satgutier@umich.edu#define __LIBELF64_LINUX        0
389538Satgutier@umich.edu#define __LIBELF_NEED_LINK_H    0
399538Satgutier@umich.edu#define __LIBELF_SYMBOL_VERSIONS 0
4011793Sbrandon.potter@amd.com
419538Satgutier@umich.edu#include <libelf/libelf.h>
429538Satgutier@umich.edu#include <libelf/gelf.h>
4310880SCurtis.Dunham@arm.com
449538Satgutier@umich.edu#include "base/loader/elf_object.hh"
459538Satgutier@umich.edu
469538Satgutier@umich.edu#include "base/loader/symtab.hh"
4710880SCurtis.Dunham@arm.com
489538Satgutier@umich.edu#include "base/trace.hh"	// for DPRINTF
499538Satgutier@umich.edu
509538Satgutier@umich.edu
519538Satgutier@umich.eduusing namespace std;
529538Satgutier@umich.edu
539538Satgutier@umich.eduObjectFile *
5410880SCurtis.Dunham@arm.comElfObject::tryFile(const string &fname, int fd, size_t len, uint8_t *data)
559538Satgutier@umich.edu{
5610880SCurtis.Dunham@arm.com    Elf *elf;
579538Satgutier@umich.edu    GElf_Ehdr ehdr;
589538Satgutier@umich.edu
599538Satgutier@umich.edu    // check that header matches library version
609538Satgutier@umich.edu    if (elf_version(EV_CURRENT) == EV_NONE)
619538Satgutier@umich.edu        panic("wrong elf version number!");
629538Satgutier@umich.edu
639538Satgutier@umich.edu    // get a pointer to elf structure
649538Satgutier@umich.edu    elf = elf_memory((char*)data,len);
659538Satgutier@umich.edu    // will only fail if fd is invalid
669538Satgutier@umich.edu    assert(elf != NULL);
679538Satgutier@umich.edu
689538Satgutier@umich.edu    // Check that we actually have a elf file
699538Satgutier@umich.edu    if (gelf_getehdr(elf, &ehdr) ==0) {
709538Satgutier@umich.edu        DPRINTFR(Loader, "Not ELF\n");
719538Satgutier@umich.edu        elf_end(elf);
729538Satgutier@umich.edu        return NULL;
739538Satgutier@umich.edu    }
749538Satgutier@umich.edu    else {
759538Satgutier@umich.edu        if (ehdr.e_ident[EI_CLASS] == ELFCLASS32)
769538Satgutier@umich.edu            panic("32 bit ELF Binary, Not Supported");
779538Satgutier@umich.edu        /* @todo this emachine value isn't offical yet.
789538Satgutier@umich.edu         *       so we probably shouldn't check it. */
799538Satgutier@umich.edu//        if (ehdr.e_machine != EM_ALPHA)
809538Satgutier@umich.edu//            panic("Non Alpha Binary, Not Supported");
819538Satgutier@umich.edu
829538Satgutier@umich.edu        elf_end(elf);
839538Satgutier@umich.edu
849538Satgutier@umich.edu        return new ElfObject(fname, fd, len, data,
859538Satgutier@umich.edu                             ObjectFile::Alpha, ObjectFile::Linux);
869538Satgutier@umich.edu    }
879538Satgutier@umich.edu}
889538Satgutier@umich.edu
899538Satgutier@umich.edu
909538Satgutier@umich.eduElfObject::ElfObject(const string &_filename, int _fd,
919538Satgutier@umich.edu                     size_t _len, uint8_t *_data,
929538Satgutier@umich.edu                     Arch _arch, OpSys _opSys)
939538Satgutier@umich.edu    : ObjectFile(_filename, _fd, _len, _data, _arch, _opSys)
949538Satgutier@umich.edu
959538Satgutier@umich.edu{
969538Satgutier@umich.edu    Elf *elf;
979538Satgutier@umich.edu    GElf_Ehdr ehdr;
989538Satgutier@umich.edu
999538Satgutier@umich.edu    // check that header matches library version
1009538Satgutier@umich.edu    if (elf_version(EV_CURRENT) == EV_NONE)
1019538Satgutier@umich.edu        panic("wrong elf version number!");
1029538Satgutier@umich.edu
1039538Satgutier@umich.edu    // get a pointer to elf structure
1049538Satgutier@umich.edu    elf = elf_memory((char*)fileData,len);
1059538Satgutier@umich.edu    // will only fail if fd is invalid
1069538Satgutier@umich.edu    assert(elf != NULL);
1079538Satgutier@umich.edu
1089538Satgutier@umich.edu    // Check that we actually have a elf file
1099538Satgutier@umich.edu    if (gelf_getehdr(elf, &ehdr) ==0) {
1109538Satgutier@umich.edu        panic("Not ELF, shouldn't be here");
1119538Satgutier@umich.edu    }
11211189Sandreas.hansson@arm.com
11311189Sandreas.hansson@arm.com    entry = ehdr.e_entry;
11411189Sandreas.hansson@arm.com
11511189Sandreas.hansson@arm.com    // initialize segment sizes to 0 in case they're not present
1169538Satgutier@umich.edu    text.size = data.size = bss.size = 0;
1179538Satgutier@umich.edu
1189538Satgutier@umich.edu    for (int i = 0; i < ehdr.e_phnum; ++i) {
1199538Satgutier@umich.edu        GElf_Phdr phdr;
1209538Satgutier@umich.edu        if (gelf_getphdr(elf, i, &phdr) == 0) {
1219538Satgutier@umich.edu            panic("gelf_getphdr failed for section %d", i);
1229538Satgutier@umich.edu        }
1239538Satgutier@umich.edu
1249538Satgutier@umich.edu        // for now we don't care about non-loadable segments
1259538Satgutier@umich.edu        if (!(phdr.p_type & PT_LOAD))
1269538Satgutier@umich.edu            continue;
1279538Satgutier@umich.edu
1289538Satgutier@umich.edu        // the headers don't explicitly distinguish text from data,
1299538Satgutier@umich.edu        // but empirically the text segment comes first.
1309538Satgutier@umich.edu        if (text.size == 0) {  // haven't seen text segment yet
1319538Satgutier@umich.edu            text.baseAddr = phdr.p_vaddr;
1329538Satgutier@umich.edu            text.size = phdr.p_filesz;
1339538Satgutier@umich.edu            text.fileImage = fileData + phdr.p_offset;
1349538Satgutier@umich.edu            // if there's any padding at the end that's not in the
1359538Satgutier@umich.edu            // file, call it the bss.  This happens in the "text"
1369538Satgutier@umich.edu            // segment if there's only one loadable segment (as for
1379538Satgutier@umich.edu            // kernel images).
1389538Satgutier@umich.edu            bss.size = phdr.p_memsz - phdr.p_filesz;
1399538Satgutier@umich.edu            bss.baseAddr = phdr.p_vaddr + phdr.p_filesz;
1409538Satgutier@umich.edu            bss.fileImage = NULL;
1419538Satgutier@umich.edu        }
1429538Satgutier@umich.edu        else if (data.size == 0) { // have text, this must be data
1439538Satgutier@umich.edu            data.baseAddr = phdr.p_vaddr;
1449538Satgutier@umich.edu            data.size = phdr.p_filesz;
1459538Satgutier@umich.edu            data.fileImage = fileData + phdr.p_offset;
1469538Satgutier@umich.edu            // if there's any padding at the end that's not in the
1479538Satgutier@umich.edu            // file, call it the bss.  Warn if this happens for both
1489538Satgutier@umich.edu            // the text & data segments (should only have one bss).
1499538Satgutier@umich.edu            if (phdr.p_memsz - phdr.p_filesz > 0 && bss.size != 0) {
1509538Satgutier@umich.edu                warn("Two implied bss segments in file!\n");
1519538Satgutier@umich.edu            }
1529538Satgutier@umich.edu            bss.size = phdr.p_memsz - phdr.p_filesz;
1539538Satgutier@umich.edu            bss.baseAddr = phdr.p_vaddr + phdr.p_filesz;
1549538Satgutier@umich.edu            bss.fileImage = NULL;
15510508SAli.Saidi@ARM.com        }
15610508SAli.Saidi@ARM.com    }
15710508SAli.Saidi@ARM.com
15810508SAli.Saidi@ARM.com    // should have found at least one loadable segment
15910508SAli.Saidi@ARM.com    assert(text.size != 0);
16010508SAli.Saidi@ARM.com
16110508SAli.Saidi@ARM.com    DPRINTFR(Loader, "text: 0x%x %d\ndata: 0x%x %d\nbss: 0x%x %d\n",
16210508SAli.Saidi@ARM.com             text.baseAddr, text.size, data.baseAddr, data.size,
16310508SAli.Saidi@ARM.com             bss.baseAddr, bss.size);
16410508SAli.Saidi@ARM.com
16510508SAli.Saidi@ARM.com    elf_end(elf);
16610508SAli.Saidi@ARM.com
16710508SAli.Saidi@ARM.com    // We will actually read the sections when we need to load them
16810508SAli.Saidi@ARM.com}
16910508SAli.Saidi@ARM.com
17010508SAli.Saidi@ARM.com
17110508SAli.Saidi@ARM.combool
17210508SAli.Saidi@ARM.comElfObject::loadSomeSymbols(SymbolTable *symtab, int binding)
17310508SAli.Saidi@ARM.com{
17411392Sbrandon.potter@amd.com    Elf *elf;
17511392Sbrandon.potter@amd.com    int sec_idx = 1; // there is a 0 but it is nothing, go figure
17611392Sbrandon.potter@amd.com    Elf_Scn *section;
17711392Sbrandon.potter@amd.com    GElf_Shdr shdr;
17811392Sbrandon.potter@amd.com    Elf_Data *data;
17911392Sbrandon.potter@amd.com    int count, ii;
18010508SAli.Saidi@ARM.com    bool found = false;
1819538Satgutier@umich.edu    GElf_Sym sym;
18211392Sbrandon.potter@amd.com
18311392Sbrandon.potter@amd.com    if (!symtab)
1849538Satgutier@umich.edu        return false;
1859538Satgutier@umich.edu
1869538Satgutier@umich.edu    // check that header matches library version
1879538Satgutier@umich.edu    if (elf_version(EV_CURRENT) == EV_NONE)
1889538Satgutier@umich.edu        panic("wrong elf version number!");
1899538Satgutier@umich.edu
19011392Sbrandon.potter@amd.com    // get a pointer to elf structure
19111392Sbrandon.potter@amd.com    elf = elf_memory((char*)fileData,len);
1929538Satgutier@umich.edu
1939538Satgutier@umich.edu    assert(elf != NULL);
1949538Satgutier@umich.edu
1959538Satgutier@umich.edu    // Get the first section
196    section = elf_getscn(elf, sec_idx);
197
198    // While there are no more sections
199    while (section != NULL) {
200        gelf_getshdr(section, &shdr);
201
202        if (shdr.sh_type == SHT_SYMTAB) {
203            found = true;
204            data = elf_getdata(section, NULL);
205            count = shdr.sh_size / shdr.sh_entsize;
206            DPRINTF(Loader, "Found Symbol Table, %d symbols present\n", count);
207
208            // loop through all the symbols, only loading global ones
209            for (ii = 0; ii < count; ++ii) {
210                gelf_getsym(data, ii, &sym);
211                if (GELF_ST_BIND(sym.st_info) == binding) {
212                   symtab->insert(sym.st_value,
213                                  elf_strptr(elf, shdr.sh_link, sym.st_name));
214                }
215            }
216        }
217        ++sec_idx;
218        section = elf_getscn(elf, sec_idx);
219    }
220
221    elf_end(elf);
222
223    return found;
224}
225
226bool
227ElfObject::loadGlobalSymbols(SymbolTable *symtab)
228{
229    return loadSomeSymbols(symtab, STB_GLOBAL);
230}
231
232bool
233ElfObject::loadLocalSymbols(SymbolTable *symtab)
234{
235    return loadSomeSymbols(symtab, STB_LOCAL);
236}
237