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