elf_object.cc revision 2600
17584SN/A/* 28869SAli.Saidi@ARM.com * Copyright (c) 2003-2005 The Regents of The University of Michigan 37584SN/A * All rights reserved. 47584SN/A * 57584SN/A * Redistribution and use in source and binary forms, with or without 67584SN/A * modification, are permitted provided that the following conditions are 77584SN/A * met: redistributions of source code must retain the above copyright 87584SN/A * notice, this list of conditions and the following disclaimer; 97584SN/A * redistributions in binary form must reproduce the above copyright 107584SN/A * notice, this list of conditions and the following disclaimer in the 117584SN/A * documentation and/or other materials provided with the distribution; 127584SN/A * neither the name of the copyright holders nor the names of its 137584SN/A * contributors may be used to endorse or promote products derived from 147584SN/A * this software without specific prior written permission. 157584SN/A * 167584SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 177584SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 187584SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 197584SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 207584SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 217584SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 227584SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 237584SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 247584SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 257584SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 267584SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 277584SN/A */ 287584SN/A 297584SN/A#include <string> 307584SN/A 317584SN/A// Because of the -Wundef flag we have to do this 327584SN/A#define __LIBELF_INTERNAL__ 0 337584SN/A// counterintuitive, but the flag below causes libelf to define 347584SN/A// 64-bit elf types that apparently didn't exist in some older 357584SN/A// versions of Linux. They seem to be there in 2.4.x, so don't 367584SN/A// set this now (it causes things to break on 64-bit platforms). 377584SN/A#define __LIBELF64_LINUX 0 387584SN/A#define __LIBELF_NEED_LINK_H 0 397584SN/A#define __LIBELF_SYMBOL_VERSIONS 0 407584SN/A 418869SAli.Saidi@ARM.com#include "libelf/libelf.h" 427584SN/A#include "libelf/gelf.h" 438245SN/A 448245SN/A#include "base/loader/elf_object.hh" 458869SAli.Saidi@ARM.com#include "base/misc.hh" 468869SAli.Saidi@ARM.com 478869SAli.Saidi@ARM.com#include "base/loader/symtab.hh" 487584SN/A 497584SN/A#include "base/trace.hh" // for DPRINTF 507584SN/A 518869SAli.Saidi@ARM.com#include "sim/byteswap.hh" 529808Sstever@gmail.com 539808Sstever@gmail.com 549808Sstever@gmail.comusing namespace std; 557584SN/A 567584SN/AObjectFile * 577584SN/AElfObject::tryFile(const string &fname, int fd, size_t len, uint8_t *data) 587584SN/A{ 597584SN/A Elf *elf; 608869SAli.Saidi@ARM.com GElf_Ehdr ehdr; 617584SN/A Arch arch = UnknownArch; 627584SN/A OpSys opSys = UnknownOpSys; 637584SN/A 647584SN/A // check that header matches library version 657584SN/A if (elf_version(EV_CURRENT) == EV_NONE) 668869SAli.Saidi@ARM.com panic("wrong elf version number!"); 677584SN/A 688869SAli.Saidi@ARM.com // get a pointer to elf structure 698869SAli.Saidi@ARM.com elf = elf_memory((char*)data,len); 708869SAli.Saidi@ARM.com // will only fail if fd is invalid 718869SAli.Saidi@ARM.com assert(elf != NULL); 728869SAli.Saidi@ARM.com 738869SAli.Saidi@ARM.com // Check that we actually have a elf file 748869SAli.Saidi@ARM.com if (gelf_getehdr(elf, &ehdr) ==0) { 758869SAli.Saidi@ARM.com DPRINTFR(Loader, "Not ELF\n"); 768869SAli.Saidi@ARM.com elf_end(elf); 778869SAli.Saidi@ARM.com return NULL; 788869SAli.Saidi@ARM.com } else { 798869SAli.Saidi@ARM.com //Detect the architecture 808869SAli.Saidi@ARM.com //Since we don't know how to check for alpha right now, we'll 818869SAli.Saidi@ARM.com //just assume if it wasn't something else and it's 64 bit, that's 828869SAli.Saidi@ARM.com //what it must be. 838869SAli.Saidi@ARM.com if (ehdr.e_machine == EM_SPARC64 || 848869SAli.Saidi@ARM.com ehdr.e_machine == EM_SPARC || 858869SAli.Saidi@ARM.com ehdr.e_machine == EM_SPARCV9 || 868869SAli.Saidi@ARM.com ehdr.e_machine == EM_SPARC32PLUS) { 878869SAli.Saidi@ARM.com arch = ObjectFile::SPARC; 888869SAli.Saidi@ARM.com } else if (ehdr.e_machine == EM_MIPS 898869SAli.Saidi@ARM.com && ehdr.e_ident[EI_CLASS] == ELFCLASS32) { 908869SAli.Saidi@ARM.com arch = ObjectFile::Mips; 918869SAli.Saidi@ARM.com } else if (ehdr.e_ident[EI_CLASS] == ELFCLASS64) { 928869SAli.Saidi@ARM.com arch = ObjectFile::Alpha; 939806Sstever@gmail.com } else { 948869SAli.Saidi@ARM.com warn("Unknown architecture: %d\n", ehdr.e_machine); 958869SAli.Saidi@ARM.com arch = ObjectFile::UnknownArch; 968869SAli.Saidi@ARM.com } 978869SAli.Saidi@ARM.com 988869SAli.Saidi@ARM.com //Detect the operating system 998869SAli.Saidi@ARM.com switch (ehdr.e_ident[EI_OSABI]) 1008869SAli.Saidi@ARM.com { 1018869SAli.Saidi@ARM.com 1028869SAli.Saidi@ARM.com case ELFOSABI_LINUX: 1038869SAli.Saidi@ARM.com opSys = ObjectFile::Linux; 1048869SAli.Saidi@ARM.com break; 1058869SAli.Saidi@ARM.com case ELFOSABI_SOLARIS: 1068869SAli.Saidi@ARM.com opSys = ObjectFile::Solaris; 1078869SAli.Saidi@ARM.com break; 1088869SAli.Saidi@ARM.com case ELFOSABI_TRU64: 1098869SAli.Saidi@ARM.com opSys = ObjectFile::Tru64; 1108869SAli.Saidi@ARM.com break; 1118869SAli.Saidi@ARM.com default: 1128869SAli.Saidi@ARM.com opSys = ObjectFile::UnknownOpSys; 1138869SAli.Saidi@ARM.com } 1148869SAli.Saidi@ARM.com 1158869SAli.Saidi@ARM.com //take a look at the .note.ABI section 1168869SAli.Saidi@ARM.com //It can let us know what's what. 1178869SAli.Saidi@ARM.com if (opSys == ObjectFile::UnknownOpSys) { 1187584SN/A Elf_Scn *section; 1197584SN/A GElf_Shdr shdr; 1207584SN/A Elf_Data *data; 1217584SN/A uint32_t osAbi;; 1227584SN/A int secIdx = 1; 1238869SAli.Saidi@ARM.com 1247584SN/A // Get the first section 1257584SN/A section = elf_getscn(elf, secIdx); 1267584SN/A 1277584SN/A // While there are no more sections 1287584SN/A while (section != NULL && opSys == ObjectFile::UnknownOpSys) { 1298869SAli.Saidi@ARM.com gelf_getshdr(section, &shdr); 1307584SN/A if (shdr.sh_type == SHT_NOTE && !strcmp(".note.ABI-tag", 1318869SAli.Saidi@ARM.com elf_strptr(elf, ehdr.e_shstrndx, shdr.sh_name))) { 1328869SAli.Saidi@ARM.com // we have found a ABI note section 1338869SAli.Saidi@ARM.com // Check the 5th 32bit word for OS 0 == linux, 1 == hurd, 1348869SAli.Saidi@ARM.com // 2 == solaris, 3 == freebsd 1358869SAli.Saidi@ARM.com data = elf_rawdata(section, NULL); 1368869SAli.Saidi@ARM.com assert(data->d_buf); 1378869SAli.Saidi@ARM.com if(ehdr.e_ident[EI_DATA] == ELFDATA2LSB) 1388869SAli.Saidi@ARM.com osAbi = htole(((uint32_t*)data->d_buf)[4]); 1398869SAli.Saidi@ARM.com else 1408869SAli.Saidi@ARM.com osAbi = htobe(((uint32_t*)data->d_buf)[4]); 1418869SAli.Saidi@ARM.com 1428869SAli.Saidi@ARM.com switch(osAbi) { 1438869SAli.Saidi@ARM.com case 0: 1448869SAli.Saidi@ARM.com opSys = ObjectFile::Linux; 1458869SAli.Saidi@ARM.com break; 1468869SAli.Saidi@ARM.com case 2: 1478869SAli.Saidi@ARM.com opSys = ObjectFile::Solaris; 1488869SAli.Saidi@ARM.com break; 1498869SAli.Saidi@ARM.com } 1508869SAli.Saidi@ARM.com } // if section found 1518869SAli.Saidi@ARM.com if (!strcmp(".SUNW_version", elf_strptr(elf, ehdr.e_shstrndx, shdr.sh_name))) 1528869SAli.Saidi@ARM.com opSys = ObjectFile::Solaris; 1538869SAli.Saidi@ARM.com if (!strcmp(".stab.index", elf_strptr(elf, ehdr.e_shstrndx, shdr.sh_name))) 1548869SAli.Saidi@ARM.com opSys = ObjectFile::Solaris; 1558869SAli.Saidi@ARM.com 1569806Sstever@gmail.com section = elf_getscn(elf, ++secIdx); 1578869SAli.Saidi@ARM.com } // while sections 1588869SAli.Saidi@ARM.com } 1598869SAli.Saidi@ARM.com 1608869SAli.Saidi@ARM.com elf_end(elf); 1618869SAli.Saidi@ARM.com return new ElfObject(fname, fd, len, data, arch, opSys); 1627584SN/A } 1637584SN/A} 1647584SN/A 1657584SN/A 1667584SN/AElfObject::ElfObject(const string &_filename, int _fd, 1678869SAli.Saidi@ARM.com size_t _len, uint8_t *_data, 1687584SN/A Arch _arch, OpSys _opSys) 1698869SAli.Saidi@ARM.com : ObjectFile(_filename, _fd, _len, _data, _arch, _opSys) 1708869SAli.Saidi@ARM.com 1718869SAli.Saidi@ARM.com{ 1728869SAli.Saidi@ARM.com Elf *elf; 1738869SAli.Saidi@ARM.com GElf_Ehdr ehdr; 1748869SAli.Saidi@ARM.com 1758869SAli.Saidi@ARM.com // check that header matches library version 1768869SAli.Saidi@ARM.com if (elf_version(EV_CURRENT) == EV_NONE) 1778869SAli.Saidi@ARM.com panic("wrong elf version number!"); 1788869SAli.Saidi@ARM.com 1798869SAli.Saidi@ARM.com // get a pointer to elf structure 1808869SAli.Saidi@ARM.com elf = elf_memory((char*)fileData,len); 1818869SAli.Saidi@ARM.com // will only fail if fd is invalid 1828869SAli.Saidi@ARM.com assert(elf != NULL); 1838869SAli.Saidi@ARM.com 1848869SAli.Saidi@ARM.com // Check that we actually have a elf file 1858869SAli.Saidi@ARM.com if (gelf_getehdr(elf, &ehdr) ==0) { 1868869SAli.Saidi@ARM.com panic("Not ELF, shouldn't be here"); 1878869SAli.Saidi@ARM.com } 1888869SAli.Saidi@ARM.com 1898869SAli.Saidi@ARM.com entry = ehdr.e_entry; 1908869SAli.Saidi@ARM.com 1918993SAli.Saidi@ARM.com 1928869SAli.Saidi@ARM.com // initialize segment sizes to 0 in case they're not present 1938869SAli.Saidi@ARM.com text.size = data.size = bss.size = 0; 1947584SN/A 1957584SN/A for (int i = 0; i < ehdr.e_phnum; ++i) { 1967584SN/A GElf_Phdr phdr; 1977584SN/A if (gelf_getphdr(elf, i, &phdr) == 0) { 1988869SAli.Saidi@ARM.com panic("gelf_getphdr failed for section %d", i); 1997584SN/A } 2008869SAli.Saidi@ARM.com 2018869SAli.Saidi@ARM.com // for now we don't care about non-loadable segments 2028869SAli.Saidi@ARM.com if (!(phdr.p_type & PT_LOAD)) 2038869SAli.Saidi@ARM.com continue; 2048869SAli.Saidi@ARM.com 2058869SAli.Saidi@ARM.com // the headers don't explicitly distinguish text from data, 2068869SAli.Saidi@ARM.com // but empirically the text segment comes first. 2078869SAli.Saidi@ARM.com if (text.size == 0) { // haven't seen text segment yet 2087584SN/A text.baseAddr = phdr.p_vaddr; 2098869SAli.Saidi@ARM.com text.size = phdr.p_filesz; 2107733SN/A text.fileImage = fileData + phdr.p_offset; 2117733SN/A // if there's any padding at the end that's not in the 2127733SN/A // file, call it the bss. This happens in the "text" 2137733SN/A // segment if there's only one loadable segment (as for 2148869SAli.Saidi@ARM.com // kernel images). 2157733SN/A bss.size = phdr.p_memsz - phdr.p_filesz; 2167733SN/A bss.baseAddr = phdr.p_vaddr + phdr.p_filesz; 2177733SN/A bss.fileImage = NULL; 2187733SN/A } else if (data.size == 0) { // have text, this must be data 2197733SN/A data.baseAddr = phdr.p_vaddr; 2208869SAli.Saidi@ARM.com data.size = phdr.p_filesz; 2217733SN/A data.fileImage = fileData + phdr.p_offset; 2228869SAli.Saidi@ARM.com // if there's any padding at the end that's not in the 2237733SN/A // file, call it the bss. Warn if this happens for both 2248869SAli.Saidi@ARM.com // the text & data segments (should only have one bss). 2258869SAli.Saidi@ARM.com if (phdr.p_memsz - phdr.p_filesz > 0 && bss.size != 0) { 2268869SAli.Saidi@ARM.com warn("Two implied bss segments in file!\n"); 2278869SAli.Saidi@ARM.com } 2287733SN/A bss.size = phdr.p_memsz - phdr.p_filesz; 2298869SAli.Saidi@ARM.com bss.baseAddr = phdr.p_vaddr + phdr.p_filesz; 2307733SN/A bss.fileImage = NULL; 2317733SN/A } else { 2327733SN/A warn("More than two loadable segments in ELF object."); 2337733SN/A warn("Ignoring segment @ 0x%x length 0x%x.", 2347733SN/A phdr.p_vaddr, phdr.p_filesz); 2357733SN/A } 2367733SN/A } 2377733SN/A 2388869SAli.Saidi@ARM.com // should have found at least one loadable segment 2397733SN/A assert(text.size != 0); 2407733SN/A 2417733SN/A DPRINTFR(Loader, "text: 0x%x %d\ndata: 0x%x %d\nbss: 0x%x %d\n", 2427733SN/A text.baseAddr, text.size, data.baseAddr, data.size, 2437584SN/A bss.baseAddr, bss.size); 2448869SAli.Saidi@ARM.com 2458869SAli.Saidi@ARM.com elf_end(elf); 2467584SN/A 2478869SAli.Saidi@ARM.com // We will actually read the sections when we need to load them 2487584SN/A} 249 250 251bool 252ElfObject::loadSomeSymbols(SymbolTable *symtab, int binding) 253{ 254 Elf *elf; 255 int sec_idx = 1; // there is a 0 but it is nothing, go figure 256 Elf_Scn *section; 257 GElf_Shdr shdr; 258 Elf_Data *data; 259 int count, ii; 260 bool found = false; 261 GElf_Sym sym; 262 263 if (!symtab) 264 return false; 265 266 // check that header matches library version 267 if (elf_version(EV_CURRENT) == EV_NONE) 268 panic("wrong elf version number!"); 269 270 // get a pointer to elf structure 271 elf = elf_memory((char*)fileData,len); 272 273 assert(elf != NULL); 274 275 // Get the first section 276 section = elf_getscn(elf, sec_idx); 277 278 // While there are no more sections 279 while (section != NULL) { 280 gelf_getshdr(section, &shdr); 281 282 if (shdr.sh_type == SHT_SYMTAB) { 283 found = true; 284 data = elf_getdata(section, NULL); 285 count = shdr.sh_size / shdr.sh_entsize; 286 DPRINTF(Loader, "Found Symbol Table, %d symbols present\n", count); 287 288 // loop through all the symbols, only loading global ones 289 for (ii = 0; ii < count; ++ii) { 290 gelf_getsym(data, ii, &sym); 291 if (GELF_ST_BIND(sym.st_info) == binding) { 292 symtab->insert(sym.st_value, 293 elf_strptr(elf, shdr.sh_link, sym.st_name)); 294 } 295 } 296 } 297 ++sec_idx; 298 section = elf_getscn(elf, sec_idx); 299 } 300 301 elf_end(elf); 302 303 return found; 304} 305 306bool 307ElfObject::loadGlobalSymbols(SymbolTable *symtab) 308{ 309 return loadSomeSymbols(symtab, STB_GLOBAL); 310} 311 312bool 313ElfObject::loadLocalSymbols(SymbolTable *symtab) 314{ 315 return loadSomeSymbols(symtab, STB_LOCAL); 316} 317