elf_object.cc revision 2423
12929Sktlim@umich.edu/* 22929Sktlim@umich.edu * Copyright (c) 2003-2005 The Regents of The University of Michigan 32932Sktlim@umich.edu * All rights reserved. 42929Sktlim@umich.edu * 52929Sktlim@umich.edu * Redistribution and use in source and binary forms, with or without 62929Sktlim@umich.edu * modification, are permitted provided that the following conditions are 72929Sktlim@umich.edu * met: redistributions of source code must retain the above copyright 82929Sktlim@umich.edu * notice, this list of conditions and the following disclaimer; 92929Sktlim@umich.edu * redistributions in binary form must reproduce the above copyright 102929Sktlim@umich.edu * notice, this list of conditions and the following disclaimer in the 112929Sktlim@umich.edu * documentation and/or other materials provided with the distribution; 122929Sktlim@umich.edu * neither the name of the copyright holders nor the names of its 132929Sktlim@umich.edu * contributors may be used to endorse or promote products derived from 142929Sktlim@umich.edu * this software without specific prior written permission. 152929Sktlim@umich.edu * 162929Sktlim@umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 172929Sktlim@umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 182929Sktlim@umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 192929Sktlim@umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 202929Sktlim@umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 212929Sktlim@umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 222929Sktlim@umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 232929Sktlim@umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 242929Sktlim@umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 252929Sktlim@umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 262929Sktlim@umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 272929Sktlim@umich.edu */ 282932Sktlim@umich.edu 292932Sktlim@umich.edu#include <string> 302932Sktlim@umich.edu 312929Sktlim@umich.edu// Because of the -Wundef flag we have to do this 326007Ssteve.reinhardt@amd.com#define __LIBELF_INTERNAL__ 0 337735SAli.Saidi@ARM.com// counterintuitive, but the flag below causes libelf to define 342929Sktlim@umich.edu// 64-bit elf types that apparently didn't exist in some older 352929Sktlim@umich.edu// versions of Linux. They seem to be there in 2.4.x, so don't 362929Sktlim@umich.edu// set this now (it causes things to break on 64-bit platforms). 372929Sktlim@umich.edu#define __LIBELF64_LINUX 0 382929Sktlim@umich.edu#define __LIBELF_NEED_LINK_H 0 392929Sktlim@umich.edu#define __LIBELF_SYMBOL_VERSIONS 0 402929Sktlim@umich.edu 418947Sandreas.hansson@arm.com#include "libelf/libelf.h" 428947Sandreas.hansson@arm.com#include "libelf/gelf.h" 438947Sandreas.hansson@arm.com 442929Sktlim@umich.edu#include "base/loader/elf_object.hh" 452929Sktlim@umich.edu 462929Sktlim@umich.edu#include "base/loader/symtab.hh" 472929Sktlim@umich.edu 482929Sktlim@umich.edu#include "base/trace.hh" // for DPRINTF 492929Sktlim@umich.edu 506007Ssteve.reinhardt@amd.com#include "sim/byteswap.hh" 516007Ssteve.reinhardt@amd.com 526007Ssteve.reinhardt@amd.com 536007Ssteve.reinhardt@amd.comusing namespace std; 546007Ssteve.reinhardt@amd.com 556007Ssteve.reinhardt@amd.comObjectFile * 566007Ssteve.reinhardt@amd.comElfObject::tryFile(const string &fname, int fd, size_t len, uint8_t *data) 576007Ssteve.reinhardt@amd.com{ 586007Ssteve.reinhardt@amd.com Elf *elf; 596007Ssteve.reinhardt@amd.com GElf_Ehdr ehdr; 606007Ssteve.reinhardt@amd.com Arch arch = UnknownArch; 616007Ssteve.reinhardt@amd.com OpSys opSys = UnknownOpSys; 626007Ssteve.reinhardt@amd.com 636007Ssteve.reinhardt@amd.com // check that header matches library version 646007Ssteve.reinhardt@amd.com if (elf_version(EV_CURRENT) == EV_NONE) 656007Ssteve.reinhardt@amd.com panic("wrong elf version number!"); 669435SAndreas.Sandberg@ARM.com 679435SAndreas.Sandberg@ARM.com // get a pointer to elf structure 689435SAndreas.Sandberg@ARM.com elf = elf_memory((char*)data,len); 696007Ssteve.reinhardt@amd.com // will only fail if fd is invalid 706007Ssteve.reinhardt@amd.com assert(elf != NULL); 716007Ssteve.reinhardt@amd.com 726007Ssteve.reinhardt@amd.com // Check that we actually have a elf file 736007Ssteve.reinhardt@amd.com if (gelf_getehdr(elf, &ehdr) ==0) { 746007Ssteve.reinhardt@amd.com DPRINTFR(Loader, "Not ELF\n"); 756007Ssteve.reinhardt@amd.com elf_end(elf); 766007Ssteve.reinhardt@amd.com return NULL; 776007Ssteve.reinhardt@amd.com } 786007Ssteve.reinhardt@amd.com else { 792929Sktlim@umich.edu //Detect the architecture 802929Sktlim@umich.edu //Versioning issues in libelf need to be resolved to get the correct 812929Sktlim@umich.edu //SPARC constants. 826007Ssteve.reinhardt@amd.com //If MIPS supports 32 bit executables, this may need to be changed. 836007Ssteve.reinhardt@amd.com //Also, there are other MIPS constants which may be used, like 846007Ssteve.reinhardt@amd.com //EM_MIPS_RS3_LE and EM_MIPS_X 859781Sandreas.hansson@arm.com //Since we don't know how to check for alpha right now, we'll 866007Ssteve.reinhardt@amd.com //just assume if it wasn't something else and it's 64 bit, that's 876007Ssteve.reinhardt@amd.com //what it must be. 882929Sktlim@umich.edu if (ehdr.e_machine == EM_SPARC64 || 892929Sktlim@umich.edu ehdr.e_machine == EM_SPARC || 902929Sktlim@umich.edu ehdr.e_machine == EM_SPARCV9) { 912929Sktlim@umich.edu arch = ObjectFile::SPARC; 922929Sktlim@umich.edu } else if (ehdr.e_machine == EM_MIPS 936011Ssteve.reinhardt@amd.com && ehdr.e_ident[EI_CLASS] == ELFCLASS32) { 946007Ssteve.reinhardt@amd.com arch = ObjectFile::MIPS; 956007Ssteve.reinhardt@amd.com } else if (ehdr.e_ident[EI_CLASS] == ELFCLASS64) { 966007Ssteve.reinhardt@amd.com arch = ObjectFile::Alpha; 976007Ssteve.reinhardt@amd.com } else { 986007Ssteve.reinhardt@amd.com arch = ObjectFile::UnknownArch; 996007Ssteve.reinhardt@amd.com } 1006007Ssteve.reinhardt@amd.com 1016007Ssteve.reinhardt@amd.com //Detect the operating system 1026007Ssteve.reinhardt@amd.com switch (ehdr.e_ident[EI_OSABI]) 1036007Ssteve.reinhardt@amd.com { 1046007Ssteve.reinhardt@amd.com 1056007Ssteve.reinhardt@amd.com case ELFOSABI_LINUX: 1066007Ssteve.reinhardt@amd.com opSys = ObjectFile::Linux; 10710384SCurtis.Dunham@arm.com break; 10810384SCurtis.Dunham@arm.com case ELFOSABI_SOLARIS: 10910384SCurtis.Dunham@arm.com opSys = ObjectFile::Solaris; 11010384SCurtis.Dunham@arm.com break; 1116007Ssteve.reinhardt@amd.com case ELFOSABI_TRU64: 1129781Sandreas.hansson@arm.com opSys = ObjectFile::Tru64; 1139781Sandreas.hansson@arm.com break; 1149781Sandreas.hansson@arm.com default: 1159781Sandreas.hansson@arm.com opSys = ObjectFile::UnknownOpSys; 1167735SAli.Saidi@ARM.com } 1176011Ssteve.reinhardt@amd.com 1186007Ssteve.reinhardt@amd.com //take a look at the .note.ABI section 1199781Sandreas.hansson@arm.com //It can let us know what's what. 1206007Ssteve.reinhardt@amd.com if (opSys == ObjectFile::UnknownOpSys) 1216007Ssteve.reinhardt@amd.com { 1227735SAli.Saidi@ARM.com Elf_Scn *section; 1237735SAli.Saidi@ARM.com GElf_Shdr shdr; 1247735SAli.Saidi@ARM.com Elf_Data *data; 1257735SAli.Saidi@ARM.com uint32_t osAbi;; 1267735SAli.Saidi@ARM.com int secIdx = 1; 1277735SAli.Saidi@ARM.com 1287735SAli.Saidi@ARM.com // Get the first section 1297735SAli.Saidi@ARM.com section = elf_getscn(elf, secIdx); 1307735SAli.Saidi@ARM.com 1317735SAli.Saidi@ARM.com // While there are no more sections 1327735SAli.Saidi@ARM.com while (section != NULL) { 1337735SAli.Saidi@ARM.com gelf_getshdr(section, &shdr); 1347735SAli.Saidi@ARM.com if (shdr.sh_type == SHT_NOTE && !strcmp(".note.ABI-tag", 1357735SAli.Saidi@ARM.com elf_strptr(elf, ehdr.e_shstrndx, shdr.sh_name))) { 1366007Ssteve.reinhardt@amd.com // we have found a ABI note section 1378599Ssteve.reinhardt@amd.com // Check the 5th 32bit word for OS 0 == linux, 1 == hurd, 1388599Ssteve.reinhardt@amd.com // 2 == solaris, 3 == freebsd 1398599Ssteve.reinhardt@amd.com data = elf_rawdata(section, NULL); 1406007Ssteve.reinhardt@amd.com assert(data->d_buf); 1416011Ssteve.reinhardt@amd.com if(ehdr.e_ident[EI_DATA] == ELFDATA2LSB) 1426007Ssteve.reinhardt@amd.com osAbi = htole(((uint32_t*)data->d_buf)[4]); 1436007Ssteve.reinhardt@amd.com else 1446007Ssteve.reinhardt@amd.com osAbi = htobe(((uint32_t*)data->d_buf)[4]); 1456007Ssteve.reinhardt@amd.com 1466007Ssteve.reinhardt@amd.com switch(osAbi) { 1476007Ssteve.reinhardt@amd.com case 0: 1489781Sandreas.hansson@arm.com opSys = ObjectFile::Linux; 1499781Sandreas.hansson@arm.com break; 1509781Sandreas.hansson@arm.com case 2: 1519781Sandreas.hansson@arm.com opSys = ObjectFile::Solaris; 1526007Ssteve.reinhardt@amd.com break; 1536007Ssteve.reinhardt@amd.com } 1546007Ssteve.reinhardt@amd.com } // if section found 1559781Sandreas.hansson@arm.com section = elf_getscn(elf, ++secIdx); 1569781Sandreas.hansson@arm.com } // while sections 1579781Sandreas.hansson@arm.com } 1589781Sandreas.hansson@arm.com elf_end(elf); 15910384SCurtis.Dunham@arm.com return new ElfObject(fname, fd, len, data, arch, opSys); 16010384SCurtis.Dunham@arm.com } 16110384SCurtis.Dunham@arm.com} 1629781Sandreas.hansson@arm.com 1636008Ssteve.reinhardt@amd.com 1646008Ssteve.reinhardt@amd.comElfObject::ElfObject(const string &_filename, int _fd, 1656008Ssteve.reinhardt@amd.com size_t _len, uint8_t *_data, 1666008Ssteve.reinhardt@amd.com Arch _arch, OpSys _opSys) 1676008Ssteve.reinhardt@amd.com : ObjectFile(_filename, _fd, _len, _data, _arch, _opSys) 1689401SAndreas.Sandberg@ARM.com 1699781Sandreas.hansson@arm.com{ 1709781Sandreas.hansson@arm.com Elf *elf; 1716008Ssteve.reinhardt@amd.com GElf_Ehdr ehdr; 1729781Sandreas.hansson@arm.com 1736007Ssteve.reinhardt@amd.com // check that header matches library version 1746007Ssteve.reinhardt@amd.com if (elf_version(EV_CURRENT) == EV_NONE) 1756007Ssteve.reinhardt@amd.com panic("wrong elf version number!"); 1766007Ssteve.reinhardt@amd.com 1779781Sandreas.hansson@arm.com // get a pointer to elf structure 1786007Ssteve.reinhardt@amd.com elf = elf_memory((char*)fileData,len); 1796007Ssteve.reinhardt@amd.com // will only fail if fd is invalid 1802929Sktlim@umich.edu assert(elf != NULL); 1812929Sktlim@umich.edu 1822929Sktlim@umich.edu // Check that we actually have a elf file 1832929Sktlim@umich.edu if (gelf_getehdr(elf, &ehdr) ==0) { 1846007Ssteve.reinhardt@amd.com panic("Not ELF, shouldn't be here"); 1856007Ssteve.reinhardt@amd.com } 1862929Sktlim@umich.edu 1872929Sktlim@umich.edu entry = ehdr.e_entry; 1886007Ssteve.reinhardt@amd.com 1892929Sktlim@umich.edu // initialize segment sizes to 0 in case they're not present 1902929Sktlim@umich.edu text.size = data.size = bss.size = 0; 1918947Sandreas.hansson@arm.com 1928947Sandreas.hansson@arm.com for (int i = 0; i < ehdr.e_phnum; ++i) { 1938947Sandreas.hansson@arm.com GElf_Phdr phdr; 1948947Sandreas.hansson@arm.com if (gelf_getphdr(elf, i, &phdr) == 0) { 1958947Sandreas.hansson@arm.com panic("gelf_getphdr failed for section %d", i); 1968947Sandreas.hansson@arm.com } 1978947Sandreas.hansson@arm.com 1988947Sandreas.hansson@arm.com // for now we don't care about non-loadable segments 1998947Sandreas.hansson@arm.com if (!(phdr.p_type & PT_LOAD)) 2008947Sandreas.hansson@arm.com continue; 20110384SCurtis.Dunham@arm.com 2028947Sandreas.hansson@arm.com // the headers don't explicitly distinguish text from data, 2039781Sandreas.hansson@arm.com // but empirically the text segment comes first. 2049781Sandreas.hansson@arm.com if (text.size == 0) { // haven't seen text segment yet 2058947Sandreas.hansson@arm.com text.baseAddr = phdr.p_vaddr; 2068947Sandreas.hansson@arm.com text.size = phdr.p_filesz; 2079401SAndreas.Sandberg@ARM.com text.fileImage = fileData + phdr.p_offset; 2089781Sandreas.hansson@arm.com // if there's any padding at the end that's not in the 2098947Sandreas.hansson@arm.com // file, call it the bss. This happens in the "text" 2108947Sandreas.hansson@arm.com // segment if there's only one loadable segment (as for 2118947Sandreas.hansson@arm.com // kernel images). 2128947Sandreas.hansson@arm.com bss.size = phdr.p_memsz - phdr.p_filesz; 2138947Sandreas.hansson@arm.com bss.baseAddr = phdr.p_vaddr + phdr.p_filesz; 2148947Sandreas.hansson@arm.com bss.fileImage = NULL; 2152929Sktlim@umich.edu } 2162929Sktlim@umich.edu else if (data.size == 0) { // have text, this must be data 2172929Sktlim@umich.edu data.baseAddr = phdr.p_vaddr; 2182929Sktlim@umich.edu data.size = phdr.p_filesz; 2194937Sstever@gmail.com data.fileImage = fileData + phdr.p_offset; 2204937Sstever@gmail.com // if there's any padding at the end that's not in the 2214937Sstever@gmail.com // file, call it the bss. Warn if this happens for both 2224937Sstever@gmail.com // the text & data segments (should only have one bss). 2238120Sgblack@eecs.umich.edu if (phdr.p_memsz - phdr.p_filesz > 0 && bss.size != 0) { 2244937Sstever@gmail.com warn("Two implied bss segments in file!\n"); 2254937Sstever@gmail.com } 2264937Sstever@gmail.com bss.size = phdr.p_memsz - phdr.p_filesz; 2274937Sstever@gmail.com bss.baseAddr = phdr.p_vaddr + phdr.p_filesz; 2285773Snate@binkert.org bss.fileImage = NULL; 2294937Sstever@gmail.com } 2304937Sstever@gmail.com } 2314937Sstever@gmail.com 2322929Sktlim@umich.edu // should have found at least one loadable segment 2332929Sktlim@umich.edu assert(text.size != 0); 2342929Sktlim@umich.edu 2355773Snate@binkert.org DPRINTFR(Loader, "text: 0x%x %d\ndata: 0x%x %d\nbss: 0x%x %d\n", 2362929Sktlim@umich.edu text.baseAddr, text.size, data.baseAddr, data.size, 2372929Sktlim@umich.edu bss.baseAddr, bss.size); 2382929Sktlim@umich.edu 2392929Sktlim@umich.edu elf_end(elf); 2402929Sktlim@umich.edu 2412929Sktlim@umich.edu // We will actually read the sections when we need to load them 2424937Sstever@gmail.com} 2434937Sstever@gmail.com 2444937Sstever@gmail.com 2454937Sstever@gmail.combool 2464937Sstever@gmail.comElfObject::loadSomeSymbols(SymbolTable *symtab, int binding) 2474937Sstever@gmail.com{ 2484937Sstever@gmail.com Elf *elf; 2494937Sstever@gmail.com int sec_idx = 1; // there is a 0 but it is nothing, go figure 2504937Sstever@gmail.com Elf_Scn *section; 2514937Sstever@gmail.com GElf_Shdr shdr; 2524937Sstever@gmail.com Elf_Data *data; 2534937Sstever@gmail.com int count, ii; 2544937Sstever@gmail.com bool found = false; 2554937Sstever@gmail.com GElf_Sym sym; 2564937Sstever@gmail.com 2572929Sktlim@umich.edu if (!symtab) 2582929Sktlim@umich.edu return false; 2592929Sktlim@umich.edu 2602929Sktlim@umich.edu // check that header matches library version 2612929Sktlim@umich.edu if (elf_version(EV_CURRENT) == EV_NONE) 2622929Sktlim@umich.edu panic("wrong elf version number!"); 2632929Sktlim@umich.edu 2646011Ssteve.reinhardt@amd.com // get a pointer to elf structure 2652929Sktlim@umich.edu elf = elf_memory((char*)fileData,len); 2662929Sktlim@umich.edu 2672929Sktlim@umich.edu assert(elf != NULL); 2682929Sktlim@umich.edu 2692929Sktlim@umich.edu // Get the first section 2702929Sktlim@umich.edu section = elf_getscn(elf, sec_idx); 2712929Sktlim@umich.edu 2722929Sktlim@umich.edu // While there are no more sections 2732997Sstever@eecs.umich.edu while (section != NULL) { 2742997Sstever@eecs.umich.edu gelf_getshdr(section, &shdr); 2752929Sktlim@umich.edu 27610196SCurtis.Dunham@arm.com if (shdr.sh_type == SHT_SYMTAB) { 2772929Sktlim@umich.edu found = true; 27810196SCurtis.Dunham@arm.com data = elf_getdata(section, NULL); 27910196SCurtis.Dunham@arm.com count = shdr.sh_size / shdr.sh_entsize; 28010196SCurtis.Dunham@arm.com DPRINTF(Loader, "Found Symbol Table, %d symbols present\n", count); 28110196SCurtis.Dunham@arm.com 2822929Sktlim@umich.edu // loop through all the symbols, only loading global ones 28310196SCurtis.Dunham@arm.com for (ii = 0; ii < count; ++ii) { 2842997Sstever@eecs.umich.edu gelf_getsym(data, ii, &sym); 2852997Sstever@eecs.umich.edu if (GELF_ST_BIND(sym.st_info) == binding) { 2862997Sstever@eecs.umich.edu symtab->insert(sym.st_value, 2875773Snate@binkert.org elf_strptr(elf, shdr.sh_link, sym.st_name)); 2885773Snate@binkert.org } 2892997Sstever@eecs.umich.edu } 2902997Sstever@eecs.umich.edu } 2919922Ssteve.reinhardt@amd.com ++sec_idx; 2926007Ssteve.reinhardt@amd.com section = elf_getscn(elf, sec_idx); 2932997Sstever@eecs.umich.edu } 2942929Sktlim@umich.edu 2952997Sstever@eecs.umich.edu elf_end(elf); 2968120Sgblack@eecs.umich.edu 2972997Sstever@eecs.umich.edu return found; 2982997Sstever@eecs.umich.edu} 2992997Sstever@eecs.umich.edu 3002997Sstever@eecs.umich.edubool 3012997Sstever@eecs.umich.eduElfObject::loadGlobalSymbols(SymbolTable *symtab) 3022929Sktlim@umich.edu{ 3032997Sstever@eecs.umich.edu return loadSomeSymbols(symtab, STB_GLOBAL); 3042929Sktlim@umich.edu} 3052929Sktlim@umich.edu 3063005Sstever@eecs.umich.edubool 3073005Sstever@eecs.umich.eduElfObject::loadLocalSymbols(SymbolTable *symtab) 3088802Sgblack@eecs.umich.edu{ 3098802Sgblack@eecs.umich.edu return loadSomeSymbols(symtab, STB_LOCAL); 3108802Sgblack@eecs.umich.edu} 3118802Sgblack@eecs.umich.edu