elf_object.cc revision 2420
1695SN/A/* 21762SN/A * Copyright (c) 2003-2005 The Regents of The University of Michigan 3695SN/A * All rights reserved. 4695SN/A * 5695SN/A * Redistribution and use in source and binary forms, with or without 6695SN/A * modification, are permitted provided that the following conditions are 7695SN/A * met: redistributions of source code must retain the above copyright 8695SN/A * notice, this list of conditions and the following disclaimer; 9695SN/A * redistributions in binary form must reproduce the above copyright 10695SN/A * notice, this list of conditions and the following disclaimer in the 11695SN/A * documentation and/or other materials provided with the distribution; 12695SN/A * neither the name of the copyright holders nor the names of its 13695SN/A * contributors may be used to endorse or promote products derived from 14695SN/A * this software without specific prior written permission. 15695SN/A * 16695SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17695SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18695SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19695SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20695SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21695SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22695SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23695SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24695SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25695SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26695SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 272665Ssaidi@eecs.umich.edu */ 282665Ssaidi@eecs.umich.edu 29695SN/A#include <string> 30695SN/A 31873SN/A// Because of the -Wundef flag we have to do this 32873SN/A#define __LIBELF_INTERNAL__ 0 33873SN/A// counterintuitive, but the flag below causes libelf to define 34873SN/A// 64-bit elf types that apparently didn't exist in some older 353918Ssaidi@eecs.umich.edu// versions of Linux. They seem to be there in 2.4.x, so don't 368230Snate@binkert.org// set this now (it causes things to break on 64-bit platforms). 373918Ssaidi@eecs.umich.edu#define __LIBELF64_LINUX 0 383918Ssaidi@eecs.umich.edu#define __LIBELF_NEED_LINK_H 0 396129Snate@binkert.org#define __LIBELF_SYMBOL_VERSIONS 0 406129Snate@binkert.org 418230Snate@binkert.org#include <libelf/libelf.h> 426129Snate@binkert.org#include <libelf/gelf.h> 436129Snate@binkert.org 448229Snate@binkert.org#include "base/loader/elf_object.hh" 45695SN/A 462621SN/A#include "base/loader/symtab.hh" 47695SN/A 48695SN/A#include "base/trace.hh" // for DPRINTF 498229Snate@binkert.org 508229Snate@binkert.org 516129Snate@binkert.orgusing namespace std; 52695SN/A 536129Snate@binkert.orgObjectFile * 54695SN/AElfObject::tryFile(const string &fname, int fd, size_t len, uint8_t *data) 55695SN/A{ 56695SN/A Elf *elf; 57695SN/A GElf_Ehdr ehdr; 58695SN/A 59695SN/A // check that header matches library version 60695SN/A if (elf_version(EV_CURRENT) == EV_NONE) 61695SN/A panic("wrong elf version number!"); 62695SN/A 63695SN/A // get a pointer to elf structure 64695SN/A elf = elf_memory((char*)data,len); 65695SN/A // will only fail if fd is invalid 66695SN/A assert(elf != NULL); 67695SN/A 68695SN/A // Check that we actually have a elf file 69695SN/A if (gelf_getehdr(elf, &ehdr) ==0) { 70695SN/A DPRINTFR(Loader, "Not ELF\n"); 71695SN/A elf_end(elf); 72695SN/A return NULL; 73695SN/A } 74695SN/A else { 75695SN/A if (ehdr.e_ident[EI_CLASS] == ELFCLASS32) 76695SN/A panic("32 bit ELF Binary, Not Supported"); 77695SN/A /* @todo this emachine value isn't offical yet. 78695SN/A * so we probably shouldn't check it. */ 79729SN/A// if (ehdr.e_machine != EM_ALPHA) 80695SN/A// panic("Non Alpha Binary, Not Supported"); 816129Snate@binkert.org 826129Snate@binkert.org elf_end(elf); 83695SN/A 846126Snate@binkert.org return new ElfObject(fname, fd, len, data, 85695SN/A ObjectFile::Alpha, ObjectFile::Linux); 86695SN/A } 87695SN/A} 88695SN/A 896126Snate@binkert.org 90695SN/AElfObject::ElfObject(const string &_filename, int _fd, 91695SN/A size_t _len, uint8_t *_data, 92695SN/A Arch _arch, OpSys _opSys) 93695SN/A : ObjectFile(_filename, _fd, _len, _data, _arch, _opSys) 94695SN/A 956126Snate@binkert.org{ 96695SN/A Elf *elf; 97695SN/A GElf_Ehdr ehdr; 98695SN/A 99695SN/A // check that header matches library version 100695SN/A if (elf_version(EV_CURRENT) == EV_NONE) 101695SN/A panic("wrong elf version number!"); 102695SN/A 103695SN/A // get a pointer to elf structure 104695SN/A elf = elf_memory((char*)fileData,len); 105695SN/A // will only fail if fd is invalid 106695SN/A assert(elf != NULL); 107695SN/A 108695SN/A // Check that we actually have a elf file 109695SN/A if (gelf_getehdr(elf, &ehdr) ==0) { 110695SN/A panic("Not ELF, shouldn't be here"); 111695SN/A } 112695SN/A 113695SN/A entry = ehdr.e_entry; 114695SN/A 115695SN/A // initialize segment sizes to 0 in case they're not present 116695SN/A text.size = data.size = bss.size = 0; 1175581Ssaidi@eecs.umich.edu 1185581Ssaidi@eecs.umich.edu for (int i = 0; i < ehdr.e_phnum; ++i) { 119695SN/A GElf_Phdr phdr; 120695SN/A if (gelf_getphdr(elf, i, &phdr) == 0) { 121695SN/A panic("gelf_getphdr failed for section %d", i); 122695SN/A } 123695SN/A 124695SN/A // for now we don't care about non-loadable segments 125695SN/A if (!(phdr.p_type & PT_LOAD)) 126695SN/A continue; 127695SN/A 128695SN/A // the headers don't explicitly distinguish text from data, 1295581Ssaidi@eecs.umich.edu // but empirically the text segment comes first. 1305581Ssaidi@eecs.umich.edu if (text.size == 0) { // haven't seen text segment yet 131695SN/A text.baseAddr = phdr.p_vaddr; 132695SN/A text.size = phdr.p_filesz; 133695SN/A text.fileImage = fileData + phdr.p_offset; 134695SN/A // if there's any padding at the end that's not in the 135695SN/A // file, call it the bss. This happens in the "text" 1365581Ssaidi@eecs.umich.edu // segment if there's only one loadable segment (as for 137695SN/A // kernel images). 138695SN/A bss.size = phdr.p_memsz - phdr.p_filesz; 139695SN/A bss.baseAddr = phdr.p_vaddr + phdr.p_filesz; 1408296Snate@binkert.org bss.fileImage = NULL; 141695SN/A } 142695SN/A else if (data.size == 0) { // have text, this must be data 1438296Snate@binkert.org data.baseAddr = phdr.p_vaddr; 1448296Snate@binkert.org data.size = phdr.p_filesz; 1458296Snate@binkert.org data.fileImage = fileData + phdr.p_offset; 1468296Snate@binkert.org // if there's any padding at the end that's not in the 1478296Snate@binkert.org // file, call it the bss. Warn if this happens for both 148695SN/A // the text & data segments (should only have one bss). 149695SN/A if (phdr.p_memsz - phdr.p_filesz > 0 && bss.size != 0) { 150695SN/A warn("Two implied bss segments in file!\n"); 151695SN/A } 152695SN/A bss.size = phdr.p_memsz - phdr.p_filesz; 1535886Snate@binkert.org bss.baseAddr = phdr.p_vaddr + phdr.p_filesz; 154695SN/A bss.fileImage = NULL; 1557462Snate@binkert.org } 156695SN/A } 157695SN/A 1585886Snate@binkert.org // should have found at least one loadable segment 159695SN/A assert(text.size != 0); 160695SN/A 161695SN/A DPRINTFR(Loader, "text: 0x%x %d\ndata: 0x%x %d\nbss: 0x%x %d\n", 162695SN/A text.baseAddr, text.size, data.baseAddr, data.size, 163695SN/A bss.baseAddr, bss.size); 164695SN/A 1656126Snate@binkert.org elf_end(elf); 166695SN/A 167695SN/A // We will actually read the sections when we need to load them 168695SN/A} 1698946Sandreas.hansson@arm.com 170695SN/A 171695SN/Abool 172695SN/AElfObject::loadSomeSymbols(SymbolTable *symtab, int binding) 173695SN/A{ 174695SN/A Elf *elf; 175695SN/A int sec_idx = 1; // there is a 0 but it is nothing, go figure 176695SN/A Elf_Scn *section; 177695SN/A GElf_Shdr shdr; 178695SN/A Elf_Data *data; 1798982Snate@binkert.org int count, ii; 180695SN/A bool found = false; 181695SN/A GElf_Sym sym; 182695SN/A 183695SN/A if (!symtab) 184695SN/A return false; 185695SN/A 186695SN/A // check that header matches library version 187695SN/A if (elf_version(EV_CURRENT) == EV_NONE) 188695SN/A panic("wrong elf version number!"); 189695SN/A 1906130Snate@binkert.org // get a pointer to elf structure 191695SN/A elf = elf_memory((char*)fileData,len); 192695SN/A 193695SN/A assert(elf != NULL); 194695SN/A 195695SN/A // Get the first section 1966211Snate@binkert.org section = elf_getscn(elf, sec_idx); 1979743Snilay@cs.wisc.edu 198695SN/A // While there are no more sections 199695SN/A while (section != NULL) { 200695SN/A gelf_getshdr(section, &shdr); 2016211Snate@binkert.org 2026211Snate@binkert.org if (shdr.sh_type == SHT_SYMTAB) { 2036211Snate@binkert.org found = true; 2046211Snate@binkert.org data = elf_getdata(section, NULL); 2056211Snate@binkert.org count = shdr.sh_size / shdr.sh_entsize; 2066211Snate@binkert.org DPRINTF(Loader, "Found Symbol Table, %d symbols present\n", count); 2076211Snate@binkert.org 2086211Snate@binkert.org // loop through all the symbols, only loading global ones 2096211Snate@binkert.org for (ii = 0; ii < count; ++ii) { 2106211Snate@binkert.org gelf_getsym(data, ii, &sym); 2119743Snilay@cs.wisc.edu if (GELF_ST_BIND(sym.st_info) == binding) { 212695SN/A symtab->insert(sym.st_value, 21310011Snilay@cs.wisc.edu elf_strptr(elf, shdr.sh_link, sym.st_name)); 2148946Sandreas.hansson@arm.com } 215695SN/A } 216695SN/A } 217695SN/A ++sec_idx; 218695SN/A section = elf_getscn(elf, sec_idx); 2198946Sandreas.hansson@arm.com } 220695SN/A 221695SN/A elf_end(elf); 2228946Sandreas.hansson@arm.com 223695SN/A return found; 224695SN/A} 2259743Snilay@cs.wisc.edu 2269743Snilay@cs.wisc.edubool 2279743Snilay@cs.wisc.eduElfObject::loadGlobalSymbols(SymbolTable *symtab) 2289743Snilay@cs.wisc.edu{ 2299743Snilay@cs.wisc.edu return loadSomeSymbols(symtab, STB_GLOBAL); 2309743Snilay@cs.wisc.edu} 231695SN/A 2329743Snilay@cs.wisc.edubool 2339743Snilay@cs.wisc.eduElfObject::loadLocalSymbols(SymbolTable *symtab) 2349743Snilay@cs.wisc.edu{ 2359743Snilay@cs.wisc.edu return loadSomeSymbols(symtab, STB_LOCAL); 2369743Snilay@cs.wisc.edu} 237695SN/A