elf_object.cc revision 2634
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. 2712SN/A */ 2812SN/A 2912SN/A#include <string> 3012SN/A 31468SN/A// Because of the -Wundef flag we have to do this 32468SN/A#define __LIBELF_INTERNAL__ 0 33468SN/A#define __LIBELF_NEED_LINK_H 0 34661SN/A#define __LIBELF_SYMBOL_VERSIONS 0 35468SN/A 362634Sstever@eecs.umich.edu#include "gelf.h" 37468SN/A 3856SN/A#include "base/loader/elf_object.hh" 392439SN/A#include "base/misc.hh" 4012SN/A 4156SN/A#include "base/loader/symtab.hh" 4212SN/A 4356SN/A#include "base/trace.hh" // for DPRINTF 4412SN/A 452423SN/A#include "sim/byteswap.hh" 462423SN/A 4712SN/A 4812SN/Ausing namespace std; 4912SN/A 5012SN/AObjectFile * 5112SN/AElfObject::tryFile(const string &fname, int fd, size_t len, uint8_t *data) 5212SN/A{ 53443SN/A Elf *elf; 54443SN/A GElf_Ehdr ehdr; 552207SN/A Arch arch = UnknownArch; 562207SN/A OpSys opSys = UnknownOpSys; 57443SN/A 58468SN/A // check that header matches library version 591708SN/A if (elf_version(EV_CURRENT) == EV_NONE) 601708SN/A panic("wrong elf version number!"); 61443SN/A 62468SN/A // get a pointer to elf structure 63443SN/A elf = elf_memory((char*)data,len); 64468SN/A // will only fail if fd is invalid 65443SN/A assert(elf != NULL); 66443SN/A 67468SN/A // Check that we actually have a elf file 68468SN/A if (gelf_getehdr(elf, &ehdr) ==0) { 69443SN/A DPRINTFR(Loader, "Not ELF\n"); 70443SN/A elf_end(elf); 71443SN/A return NULL; 722476SN/A } else { 732207SN/A //Detect the architecture 742207SN/A //Since we don't know how to check for alpha right now, we'll 752207SN/A //just assume if it wasn't something else and it's 64 bit, that's 762207SN/A //what it must be. 772207SN/A if (ehdr.e_machine == EM_SPARC64 || 782207SN/A ehdr.e_machine == EM_SPARC || 792620SN/A ehdr.e_machine == EM_SPARCV9) { 802207SN/A arch = ObjectFile::SPARC; 812207SN/A } else if (ehdr.e_machine == EM_MIPS 822207SN/A && ehdr.e_ident[EI_CLASS] == ELFCLASS32) { 832472SN/A arch = ObjectFile::Mips; 842207SN/A } else if (ehdr.e_ident[EI_CLASS] == ELFCLASS64) { 852207SN/A arch = ObjectFile::Alpha; 862207SN/A } else { 872600SN/A warn("Unknown architecture: %d\n", ehdr.e_machine); 882207SN/A arch = ObjectFile::UnknownArch; 892207SN/A } 902207SN/A 912207SN/A //Detect the operating system 922207SN/A switch (ehdr.e_ident[EI_OSABI]) 932207SN/A { 942238SN/A 952207SN/A case ELFOSABI_LINUX: 962207SN/A opSys = ObjectFile::Linux; 972207SN/A break; 982207SN/A case ELFOSABI_SOLARIS: 992207SN/A opSys = ObjectFile::Solaris; 1002238SN/A break; 1012207SN/A case ELFOSABI_TRU64: 1022207SN/A opSys = ObjectFile::Tru64; 1032238SN/A break; 1042207SN/A default: 1052207SN/A opSys = ObjectFile::UnknownOpSys; 1062207SN/A } 1072207SN/A 1082238SN/A //take a look at the .note.ABI section 1092238SN/A //It can let us know what's what. 1102600SN/A if (opSys == ObjectFile::UnknownOpSys) { 1112238SN/A Elf_Scn *section; 1122238SN/A GElf_Shdr shdr; 1132238SN/A Elf_Data *data; 1142238SN/A uint32_t osAbi;; 1152238SN/A int secIdx = 1; 1162238SN/A 1172238SN/A // Get the first section 1182238SN/A section = elf_getscn(elf, secIdx); 1192238SN/A 1202238SN/A // While there are no more sections 1212600SN/A while (section != NULL && opSys == ObjectFile::UnknownOpSys) { 1222238SN/A gelf_getshdr(section, &shdr); 1232238SN/A if (shdr.sh_type == SHT_NOTE && !strcmp(".note.ABI-tag", 1242238SN/A elf_strptr(elf, ehdr.e_shstrndx, shdr.sh_name))) { 1252238SN/A // we have found a ABI note section 1262238SN/A // Check the 5th 32bit word for OS 0 == linux, 1 == hurd, 1272238SN/A // 2 == solaris, 3 == freebsd 1282238SN/A data = elf_rawdata(section, NULL); 1292238SN/A assert(data->d_buf); 1302238SN/A if(ehdr.e_ident[EI_DATA] == ELFDATA2LSB) 1312238SN/A osAbi = htole(((uint32_t*)data->d_buf)[4]); 1322238SN/A else 1332238SN/A osAbi = htobe(((uint32_t*)data->d_buf)[4]); 1342238SN/A 1352238SN/A switch(osAbi) { 1362238SN/A case 0: 1372238SN/A opSys = ObjectFile::Linux; 1382238SN/A break; 1392238SN/A case 2: 1402238SN/A opSys = ObjectFile::Solaris; 1412238SN/A break; 1422238SN/A } 1432238SN/A } // if section found 1442600SN/A if (!strcmp(".SUNW_version", elf_strptr(elf, ehdr.e_shstrndx, shdr.sh_name))) 1452600SN/A opSys = ObjectFile::Solaris; 1462600SN/A if (!strcmp(".stab.index", elf_strptr(elf, ehdr.e_shstrndx, shdr.sh_name))) 1472600SN/A opSys = ObjectFile::Solaris; 1482600SN/A 1492238SN/A section = elf_getscn(elf, ++secIdx); 1502238SN/A } // while sections 1512238SN/A } 1522472SN/A 1532238SN/A elf_end(elf); 1542207SN/A return new ElfObject(fname, fd, len, data, arch, opSys); 15512SN/A } 15612SN/A} 15712SN/A 15812SN/A 15912SN/AElfObject::ElfObject(const string &_filename, int _fd, 160360SN/A size_t _len, uint8_t *_data, 161360SN/A Arch _arch, OpSys _opSys) 162360SN/A : ObjectFile(_filename, _fd, _len, _data, _arch, _opSys) 163443SN/A 16412SN/A{ 165443SN/A Elf *elf; 166443SN/A GElf_Ehdr ehdr; 16712SN/A 168468SN/A // check that header matches library version 1691708SN/A if (elf_version(EV_CURRENT) == EV_NONE) 1701708SN/A panic("wrong elf version number!"); 17112SN/A 172468SN/A // get a pointer to elf structure 173443SN/A elf = elf_memory((char*)fileData,len); 174468SN/A // will only fail if fd is invalid 175443SN/A assert(elf != NULL); 17612SN/A 177468SN/A // Check that we actually have a elf file 178468SN/A if (gelf_getehdr(elf, &ehdr) ==0) { 179443SN/A panic("Not ELF, shouldn't be here"); 18012SN/A } 18112SN/A 182468SN/A entry = ehdr.e_entry; 18312SN/A 1842472SN/A 185468SN/A // initialize segment sizes to 0 in case they're not present 186468SN/A text.size = data.size = bss.size = 0; 187468SN/A 188468SN/A for (int i = 0; i < ehdr.e_phnum; ++i) { 189468SN/A GElf_Phdr phdr; 190468SN/A if (gelf_getphdr(elf, i, &phdr) == 0) { 191468SN/A panic("gelf_getphdr failed for section %d", i); 192468SN/A } 193468SN/A 194468SN/A // for now we don't care about non-loadable segments 195468SN/A if (!(phdr.p_type & PT_LOAD)) 196468SN/A continue; 197468SN/A 198468SN/A // the headers don't explicitly distinguish text from data, 199468SN/A // but empirically the text segment comes first. 200468SN/A if (text.size == 0) { // haven't seen text segment yet 201468SN/A text.baseAddr = phdr.p_vaddr; 202468SN/A text.size = phdr.p_filesz; 2032420SN/A text.fileImage = fileData + phdr.p_offset; 204468SN/A // if there's any padding at the end that's not in the 205468SN/A // file, call it the bss. This happens in the "text" 206468SN/A // segment if there's only one loadable segment (as for 207468SN/A // kernel images). 208468SN/A bss.size = phdr.p_memsz - phdr.p_filesz; 209468SN/A bss.baseAddr = phdr.p_vaddr + phdr.p_filesz; 2102420SN/A bss.fileImage = NULL; 2112476SN/A } else if (data.size == 0) { // have text, this must be data 212468SN/A data.baseAddr = phdr.p_vaddr; 213468SN/A data.size = phdr.p_filesz; 2142420SN/A data.fileImage = fileData + phdr.p_offset; 215468SN/A // if there's any padding at the end that's not in the 216468SN/A // file, call it the bss. Warn if this happens for both 217468SN/A // the text & data segments (should only have one bss). 218468SN/A if (phdr.p_memsz - phdr.p_filesz > 0 && bss.size != 0) { 219468SN/A warn("Two implied bss segments in file!\n"); 220468SN/A } 221468SN/A bss.size = phdr.p_memsz - phdr.p_filesz; 222468SN/A bss.baseAddr = phdr.p_vaddr + phdr.p_filesz; 2232420SN/A bss.fileImage = NULL; 2242476SN/A } else { 2252476SN/A warn("More than two loadable segments in ELF object."); 2262476SN/A warn("Ignoring segment @ 0x%x length 0x%x.", 2272476SN/A phdr.p_vaddr, phdr.p_filesz); 228468SN/A } 229468SN/A } 230468SN/A 231468SN/A // should have found at least one loadable segment 232468SN/A assert(text.size != 0); 233468SN/A 234468SN/A DPRINTFR(Loader, "text: 0x%x %d\ndata: 0x%x %d\nbss: 0x%x %d\n", 235468SN/A text.baseAddr, text.size, data.baseAddr, data.size, 236468SN/A bss.baseAddr, bss.size); 237468SN/A 238443SN/A elf_end(elf); 239443SN/A 240468SN/A // We will actually read the sections when we need to load them 24112SN/A} 24212SN/A 24312SN/A 24412SN/Abool 245468SN/AElfObject::loadSomeSymbols(SymbolTable *symtab, int binding) 24612SN/A{ 247443SN/A Elf *elf; 248766SN/A int sec_idx = 1; // there is a 0 but it is nothing, go figure 249443SN/A Elf_Scn *section; 250443SN/A GElf_Shdr shdr; 251443SN/A Elf_Data *data; 252443SN/A int count, ii; 253443SN/A bool found = false; 254443SN/A GElf_Sym sym; 255443SN/A 256443SN/A if (!symtab) 257443SN/A return false; 258443SN/A 259468SN/A // check that header matches library version 2601708SN/A if (elf_version(EV_CURRENT) == EV_NONE) 2611708SN/A panic("wrong elf version number!"); 262443SN/A 263468SN/A // get a pointer to elf structure 264443SN/A elf = elf_memory((char*)fileData,len); 265443SN/A 266443SN/A assert(elf != NULL); 267443SN/A 268468SN/A // Get the first section 269454SN/A section = elf_getscn(elf, sec_idx); 270443SN/A 271468SN/A // While there are no more sections 272468SN/A while (section != NULL) { 273443SN/A gelf_getshdr(section, &shdr); 274443SN/A 275468SN/A if (shdr.sh_type == SHT_SYMTAB) { 276443SN/A found = true; 277443SN/A data = elf_getdata(section, NULL); 278443SN/A count = shdr.sh_size / shdr.sh_entsize; 279443SN/A DPRINTF(Loader, "Found Symbol Table, %d symbols present\n", count); 280443SN/A 281468SN/A // loop through all the symbols, only loading global ones 282468SN/A for (ii = 0; ii < count; ++ii) { 283443SN/A gelf_getsym(data, ii, &sym); 284836SN/A if (GELF_ST_BIND(sym.st_info) == binding) { 285468SN/A symtab->insert(sym.st_value, 286468SN/A elf_strptr(elf, shdr.sh_link, sym.st_name)); 287443SN/A } 288443SN/A } 289443SN/A } 290454SN/A ++sec_idx; 291454SN/A section = elf_getscn(elf, sec_idx); 292443SN/A } 293443SN/A 294443SN/A elf_end(elf); 295443SN/A 296443SN/A return found; 29712SN/A} 29812SN/A 29912SN/Abool 300468SN/AElfObject::loadGlobalSymbols(SymbolTable *symtab) 301468SN/A{ 302468SN/A return loadSomeSymbols(symtab, STB_GLOBAL); 303468SN/A} 304468SN/A 305468SN/Abool 30612SN/AElfObject::loadLocalSymbols(SymbolTable *symtab) 30712SN/A{ 308468SN/A return loadSomeSymbols(symtab, STB_LOCAL); 30912SN/A} 310