elf_object.cc revision 2423
112SN/A/* 21762SN/A * Copyright (c) 2003-2005 The Regents of The University of Michigan 312SN/A * All rights reserved. 412SN/A * 512SN/A * Redistribution and use in source and binary forms, with or without 612SN/A * modification, are permitted provided that the following conditions are 712SN/A * met: redistributions of source code must retain the above copyright 812SN/A * notice, this list of conditions and the following disclaimer; 912SN/A * redistributions in binary form must reproduce the above copyright 1012SN/A * notice, this list of conditions and the following disclaimer in the 1112SN/A * documentation and/or other materials provided with the distribution; 1212SN/A * neither the name of the copyright holders nor the names of its 1312SN/A * contributors may be used to endorse or promote products derived from 1412SN/A * this software without specific prior written permission. 1512SN/A * 1612SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 1712SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 1812SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 1912SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 2012SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 2112SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 2212SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2312SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2412SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2512SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 2612SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 272665Ssaidi@eecs.umich.edu */ 282665Ssaidi@eecs.umich.edu 292665Ssaidi@eecs.umich.edu#include <string> 3012SN/A 3112SN/A// Because of the -Wundef flag we have to do this 3212SN/A#define __LIBELF_INTERNAL__ 0 3312SN/A// counterintuitive, but the flag below causes libelf to define 342634Sstever@eecs.umich.edu// 64-bit elf types that apparently didn't exist in some older 35468SN/A// versions of Linux. They seem to be there in 2.4.x, so don't 3656SN/A// set this now (it causes things to break on 64-bit platforms). 374484Sbinkertn@umich.edu#define __LIBELF64_LINUX 0 382439SN/A#define __LIBELF_NEED_LINK_H 0 3956SN/A#define __LIBELF_SYMBOL_VERSIONS 0 402423SN/A 412423SN/A#include "libelf/libelf.h" 4212SN/A#include "libelf/gelf.h" 4312SN/A 4412SN/A#include "base/loader/elf_object.hh" 4512SN/A 4612SN/A#include "base/loader/symtab.hh" 47443SN/A 48443SN/A#include "base/trace.hh" // for DPRINTF 492207SN/A 502207SN/A#include "sim/byteswap.hh" 51443SN/A 52468SN/A 531708SN/Ausing namespace std; 541708SN/A 55443SN/AObjectFile * 56468SN/AElfObject::tryFile(const string &fname, int fd, size_t len, uint8_t *data) 57443SN/A{ 58468SN/A Elf *elf; 59443SN/A GElf_Ehdr ehdr; 60443SN/A Arch arch = UnknownArch; 61468SN/A OpSys opSys = UnknownOpSys; 62468SN/A 63443SN/A // check that header matches library version 64443SN/A if (elf_version(EV_CURRENT) == EV_NONE) 65443SN/A panic("wrong elf version number!"); 662476SN/A 672207SN/A // get a pointer to elf structure 682207SN/A elf = elf_memory((char*)data,len); 692207SN/A // will only fail if fd is invalid 702207SN/A assert(elf != NULL); 712207SN/A 724111Sgblack@eecs.umich.edu // Check that we actually have a elf file 734111Sgblack@eecs.umich.edu if (gelf_getehdr(elf, &ehdr) ==0) { 742620SN/A DPRINTFR(Loader, "Not ELF\n"); 754111Sgblack@eecs.umich.edu elf_end(elf); 764111Sgblack@eecs.umich.edu return NULL; 774111Sgblack@eecs.umich.edu } 784111Sgblack@eecs.umich.edu else { 794111Sgblack@eecs.umich.edu //Detect the architecture 802207SN/A //Versioning issues in libelf need to be resolved to get the correct 812207SN/A //SPARC constants. 822472SN/A //If MIPS supports 32 bit executables, this may need to be changed. 834166Sgblack@eecs.umich.edu //Also, there are other MIPS constants which may be used, like 844166Sgblack@eecs.umich.edu //EM_MIPS_RS3_LE and EM_MIPS_X 854166Sgblack@eecs.umich.edu //Since we don't know how to check for alpha right now, we'll 864166Sgblack@eecs.umich.edu //just assume if it wasn't something else and it's 64 bit, that's 874166Sgblack@eecs.umich.edu //what it must be. 884166Sgblack@eecs.umich.edu if (ehdr.e_machine == EM_SPARC64 || 892207SN/A ehdr.e_machine == EM_SPARC || 902207SN/A ehdr.e_machine == EM_SPARCV9) { 915335Shines@cs.fsu.edu arch = ObjectFile::SPARC; 925335Shines@cs.fsu.edu } else if (ehdr.e_machine == EM_MIPS 932207SN/A && ehdr.e_ident[EI_CLASS] == ELFCLASS32) { 942600SN/A arch = ObjectFile::MIPS; 952207SN/A } else if (ehdr.e_ident[EI_CLASS] == ELFCLASS64) { 962207SN/A arch = ObjectFile::Alpha; 972207SN/A } else { 982207SN/A arch = ObjectFile::UnknownArch; 992207SN/A } 1002207SN/A 1012238SN/A //Detect the operating system 1022207SN/A switch (ehdr.e_ident[EI_OSABI]) 1035335Shines@cs.fsu.edu { 1042207SN/A 1052207SN/A case ELFOSABI_LINUX: 1062207SN/A opSys = ObjectFile::Linux; 1072207SN/A break; 1082238SN/A case ELFOSABI_SOLARIS: 1092207SN/A opSys = ObjectFile::Solaris; 1102207SN/A break; 1112238SN/A case ELFOSABI_TRU64: 1122207SN/A opSys = ObjectFile::Tru64; 1132207SN/A break; 1142207SN/A default: 1152207SN/A opSys = ObjectFile::UnknownOpSys; 1162238SN/A } 1172238SN/A 1182600SN/A //take a look at the .note.ABI section 1192238SN/A //It can let us know what's what. 1202238SN/A if (opSys == ObjectFile::UnknownOpSys) 1212238SN/A { 1222238SN/A Elf_Scn *section; 1232238SN/A GElf_Shdr shdr; 1242238SN/A Elf_Data *data; 1252238SN/A uint32_t osAbi;; 1262238SN/A int secIdx = 1; 1272238SN/A 1282238SN/A // Get the first section 1292600SN/A section = elf_getscn(elf, secIdx); 1302238SN/A 1312238SN/A // While there are no more sections 1322238SN/A while (section != NULL) { 1332238SN/A gelf_getshdr(section, &shdr); 1342238SN/A if (shdr.sh_type == SHT_NOTE && !strcmp(".note.ABI-tag", 1352238SN/A elf_strptr(elf, ehdr.e_shstrndx, shdr.sh_name))) { 1362238SN/A // we have found a ABI note section 1372238SN/A // Check the 5th 32bit word for OS 0 == linux, 1 == hurd, 1382238SN/A // 2 == solaris, 3 == freebsd 1392238SN/A data = elf_rawdata(section, NULL); 1402238SN/A assert(data->d_buf); 1412238SN/A if(ehdr.e_ident[EI_DATA] == ELFDATA2LSB) 1422238SN/A osAbi = htole(((uint32_t*)data->d_buf)[4]); 1432238SN/A else 1442238SN/A osAbi = htobe(((uint32_t*)data->d_buf)[4]); 1452238SN/A 1462238SN/A switch(osAbi) { 1472238SN/A case 0: 1482238SN/A opSys = ObjectFile::Linux; 1492238SN/A break; 1502238SN/A case 2: 1512238SN/A opSys = ObjectFile::Solaris; 1522600SN/A break; 1532600SN/A } 1542600SN/A } // if section found 1552600SN/A section = elf_getscn(elf, ++secIdx); 1562600SN/A } // while sections 1572238SN/A } 1582238SN/A elf_end(elf); 1592238SN/A return new ElfObject(fname, fd, len, data, arch, opSys); 1602472SN/A } 1612976Sgblack@eecs.umich.edu} 1622976Sgblack@eecs.umich.edu 1632976Sgblack@eecs.umich.edu 1642976Sgblack@eecs.umich.eduElfObject::ElfObject(const string &_filename, int _fd, 1652976Sgblack@eecs.umich.edu size_t _len, uint8_t *_data, 1662976Sgblack@eecs.umich.edu Arch _arch, OpSys _opSys) 1672976Sgblack@eecs.umich.edu : ObjectFile(_filename, _fd, _len, _data, _arch, _opSys) 1682976Sgblack@eecs.umich.edu 1692976Sgblack@eecs.umich.edu{ 1702976Sgblack@eecs.umich.edu Elf *elf; 1712976Sgblack@eecs.umich.edu GElf_Ehdr ehdr; 1722976Sgblack@eecs.umich.edu 1732976Sgblack@eecs.umich.edu // check that header matches library version 1742976Sgblack@eecs.umich.edu if (elf_version(EV_CURRENT) == EV_NONE) 1752976Sgblack@eecs.umich.edu panic("wrong elf version number!"); 1762976Sgblack@eecs.umich.edu 1772976Sgblack@eecs.umich.edu // get a pointer to elf structure 1782976Sgblack@eecs.umich.edu elf = elf_memory((char*)fileData,len); 1792976Sgblack@eecs.umich.edu // will only fail if fd is invalid 1802976Sgblack@eecs.umich.edu assert(elf != NULL); 1812976Sgblack@eecs.umich.edu 1825143Sgblack@eecs.umich.edu // Check that we actually have a elf file 1832976Sgblack@eecs.umich.edu if (gelf_getehdr(elf, &ehdr) ==0) { 1842976Sgblack@eecs.umich.edu panic("Not ELF, shouldn't be here"); 1852976Sgblack@eecs.umich.edu } 1862976Sgblack@eecs.umich.edu 1872976Sgblack@eecs.umich.edu entry = ehdr.e_entry; 1882976Sgblack@eecs.umich.edu 1892976Sgblack@eecs.umich.edu // initialize segment sizes to 0 in case they're not present 1902976Sgblack@eecs.umich.edu text.size = data.size = bss.size = 0; 1912238SN/A 1922976Sgblack@eecs.umich.edu for (int i = 0; i < ehdr.e_phnum; ++i) { 19312SN/A GElf_Phdr phdr; 19412SN/A if (gelf_getphdr(elf, i, &phdr) == 0) { 19512SN/A panic("gelf_getphdr failed for section %d", i); 19612SN/A } 19712SN/A 198360SN/A // for now we don't care about non-loadable segments 199360SN/A if (!(phdr.p_type & PT_LOAD)) 200360SN/A continue; 201443SN/A 20212SN/A // the headers don't explicitly distinguish text from data, 203443SN/A // but empirically the text segment comes first. 204443SN/A if (text.size == 0) { // haven't seen text segment yet 20512SN/A text.baseAddr = phdr.p_vaddr; 206468SN/A text.size = phdr.p_filesz; 2071708SN/A text.fileImage = fileData + phdr.p_offset; 2081708SN/A // if there's any padding at the end that's not in the 20912SN/A // file, call it the bss. This happens in the "text" 210468SN/A // segment if there's only one loadable segment (as for 211443SN/A // kernel images). 212468SN/A bss.size = phdr.p_memsz - phdr.p_filesz; 213443SN/A bss.baseAddr = phdr.p_vaddr + phdr.p_filesz; 21412SN/A bss.fileImage = NULL; 215468SN/A } 216468SN/A else if (data.size == 0) { // have text, this must be data 217443SN/A data.baseAddr = phdr.p_vaddr; 21812SN/A data.size = phdr.p_filesz; 21912SN/A data.fileImage = fileData + phdr.p_offset; 220468SN/A // if there's any padding at the end that's not in the 22112SN/A // file, call it the bss. Warn if this happens for both 222468SN/A // the text & data segments (should only have one bss). 223468SN/A if (phdr.p_memsz - phdr.p_filesz > 0 && bss.size != 0) { 224468SN/A warn("Two implied bss segments in file!\n"); 2255090Sgblack@eecs.umich.edu } 2265090Sgblack@eecs.umich.edu bss.size = phdr.p_memsz - phdr.p_filesz; 2275090Sgblack@eecs.umich.edu bss.baseAddr = phdr.p_vaddr + phdr.p_filesz; 2285090Sgblack@eecs.umich.edu bss.fileImage = NULL; 2295090Sgblack@eecs.umich.edu } 2305090Sgblack@eecs.umich.edu } 2315090Sgblack@eecs.umich.edu 2325090Sgblack@eecs.umich.edu // should have found at least one loadable segment 2335090Sgblack@eecs.umich.edu assert(text.size != 0); 2345090Sgblack@eecs.umich.edu 2355090Sgblack@eecs.umich.edu DPRINTFR(Loader, "text: 0x%x %d\ndata: 0x%x %d\nbss: 0x%x %d\n", 2365090Sgblack@eecs.umich.edu text.baseAddr, text.size, data.baseAddr, data.size, 2375090Sgblack@eecs.umich.edu bss.baseAddr, bss.size); 2385090Sgblack@eecs.umich.edu 2395090Sgblack@eecs.umich.edu elf_end(elf); 2405090Sgblack@eecs.umich.edu 2415090Sgblack@eecs.umich.edu // We will actually read the sections when we need to load them 2425090Sgblack@eecs.umich.edu} 2435090Sgblack@eecs.umich.edu 2445090Sgblack@eecs.umich.edu 2455090Sgblack@eecs.umich.edubool 2465090Sgblack@eecs.umich.eduElfObject::loadSomeSymbols(SymbolTable *symtab, int binding) 2475090Sgblack@eecs.umich.edu{ 2485090Sgblack@eecs.umich.edu Elf *elf; 2495090Sgblack@eecs.umich.edu int sec_idx = 1; // there is a 0 but it is nothing, go figure 2505090Sgblack@eecs.umich.edu Elf_Scn *section; 2515090Sgblack@eecs.umich.edu GElf_Shdr shdr; 2525090Sgblack@eecs.umich.edu Elf_Data *data; 2535090Sgblack@eecs.umich.edu int count, ii; 2545090Sgblack@eecs.umich.edu bool found = false; 2555090Sgblack@eecs.umich.edu GElf_Sym sym; 256468SN/A 257468SN/A if (!symtab) 258468SN/A return false; 2595090Sgblack@eecs.umich.edu 260468SN/A // check that header matches library version 261468SN/A if (elf_version(EV_CURRENT) == EV_NONE) 262468SN/A panic("wrong elf version number!"); 263468SN/A 264468SN/A // get a pointer to elf structure 265468SN/A elf = elf_memory((char*)fileData,len); 2665090Sgblack@eecs.umich.edu 2675143Sgblack@eecs.umich.edu assert(elf != NULL); 2685143Sgblack@eecs.umich.edu 2695090Sgblack@eecs.umich.edu // Get the first section 2705143Sgblack@eecs.umich.edu section = elf_getscn(elf, sec_idx); 2715090Sgblack@eecs.umich.edu 2725090Sgblack@eecs.umich.edu // While there are no more sections 2735090Sgblack@eecs.umich.edu while (section != NULL) { 2745090Sgblack@eecs.umich.edu gelf_getshdr(section, &shdr); 2755090Sgblack@eecs.umich.edu 2765152Sgblack@eecs.umich.edu if (shdr.sh_type == SHT_SYMTAB) { 2775152Sgblack@eecs.umich.edu found = true; 2785143Sgblack@eecs.umich.edu data = elf_getdata(section, NULL); 279468SN/A count = shdr.sh_size / shdr.sh_entsize; 2802420SN/A DPRINTF(Loader, "Found Symbol Table, %d symbols present\n", count); 2815152Sgblack@eecs.umich.edu 2825152Sgblack@eecs.umich.edu // loop through all the symbols, only loading global ones 2835143Sgblack@eecs.umich.edu for (ii = 0; ii < count; ++ii) { 284468SN/A gelf_getsym(data, ii, &sym); 2852420SN/A if (GELF_ST_BIND(sym.st_info) == binding) { 2862476SN/A symtab->insert(sym.st_value, 2875090Sgblack@eecs.umich.edu elf_strptr(elf, shdr.sh_link, sym.st_name)); 2885143Sgblack@eecs.umich.edu } 2895090Sgblack@eecs.umich.edu } 2905090Sgblack@eecs.umich.edu } 2915090Sgblack@eecs.umich.edu ++sec_idx; 292468SN/A section = elf_getscn(elf, sec_idx); 293468SN/A } 294468SN/A 295468SN/A elf_end(elf); 296468SN/A 297468SN/A return found; 298468SN/A} 299468SN/A 300468SN/Abool 301468SN/AElfObject::loadGlobalSymbols(SymbolTable *symtab) 302443SN/A{ 303443SN/A return loadSomeSymbols(symtab, STB_GLOBAL); 304468SN/A} 30512SN/A 30612SN/Abool 30712SN/AElfObject::loadLocalSymbols(SymbolTable *symtab) 30812SN/A{ 309468SN/A return loadSomeSymbols(symtab, STB_LOCAL); 31012SN/A} 311443SN/A