elf_object.cc revision 4484
12817Sksewell@umich.edu/* 28733Sgeoffrey.blake@arm.com * Copyright (c) 2003-2005 The Regents of The University of Michigan 38733Sgeoffrey.blake@arm.com * All rights reserved. 48733Sgeoffrey.blake@arm.com * 58733Sgeoffrey.blake@arm.com * Redistribution and use in source and binary forms, with or without 68733Sgeoffrey.blake@arm.com * modification, are permitted provided that the following conditions are 78733Sgeoffrey.blake@arm.com * met: redistributions of source code must retain the above copyright 88733Sgeoffrey.blake@arm.com * notice, this list of conditions and the following disclaimer; 98733Sgeoffrey.blake@arm.com * redistributions in binary form must reproduce the above copyright 108733Sgeoffrey.blake@arm.com * notice, this list of conditions and the following disclaimer in the 118733Sgeoffrey.blake@arm.com * documentation and/or other materials provided with the distribution; 128733Sgeoffrey.blake@arm.com * neither the name of the copyright holders nor the names of its 138733Sgeoffrey.blake@arm.com * contributors may be used to endorse or promote products derived from 142817Sksewell@umich.edu * this software without specific prior written permission. 152817Sksewell@umich.edu * 162817Sksewell@umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 172817Sksewell@umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 182817Sksewell@umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 192817Sksewell@umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 202817Sksewell@umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 212817Sksewell@umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 222817Sksewell@umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 232817Sksewell@umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 242817Sksewell@umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 252817Sksewell@umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 262817Sksewell@umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 272817Sksewell@umich.edu * 282817Sksewell@umich.edu * Authors: Steve Reinhardt 292817Sksewell@umich.edu * Ali Saidi 302817Sksewell@umich.edu */ 312817Sksewell@umich.edu 322817Sksewell@umich.edu#include <string> 332817Sksewell@umich.edu 342817Sksewell@umich.edu#include "gelf.h" 352817Sksewell@umich.edu 362817Sksewell@umich.edu#include "base/loader/elf_object.hh" 372817Sksewell@umich.edu#include "base/loader/symtab.hh" 382817Sksewell@umich.edu#include "base/misc.hh" 392817Sksewell@umich.edu#include "base/trace.hh" // for DPRINTF 402817Sksewell@umich.edu#include "sim/byteswap.hh" 412817Sksewell@umich.edu 422817Sksewell@umich.eduusing namespace std; 432817Sksewell@umich.edu 442817Sksewell@umich.eduObjectFile * 452817Sksewell@umich.eduElfObject::tryFile(const string &fname, int fd, size_t len, uint8_t *data) 466658Snate@binkert.org{ 478229Snate@binkert.org Elf *elf; 482935Sksewell@umich.edu GElf_Ehdr ehdr; 492817Sksewell@umich.edu Arch arch = UnknownArch; 502834Sksewell@umich.edu OpSys opSys = UnknownOpSys; 512834Sksewell@umich.edu 522834Sksewell@umich.edu // check that header matches library version 538902Sandreas.hansson@arm.com if (elf_version(EV_CURRENT) == EV_NONE) 542834Sksewell@umich.edu panic("wrong elf version number!"); 552817Sksewell@umich.edu 562817Sksewell@umich.edu // get a pointer to elf structure 572817Sksewell@umich.edu elf = elf_memory((char*)data,len); 582817Sksewell@umich.edu // will only fail if fd is invalid 592817Sksewell@umich.edu assert(elf != NULL); 602817Sksewell@umich.edu 612817Sksewell@umich.edu // Check that we actually have a elf file 622817Sksewell@umich.edu if (gelf_getehdr(elf, &ehdr) ==0) { 632817Sksewell@umich.edu DPRINTFR(Loader, "Not ELF\n"); 642817Sksewell@umich.edu elf_end(elf); 652817Sksewell@umich.edu return NULL; 662817Sksewell@umich.edu } else { 672817Sksewell@umich.edu //Detect the architecture 682817Sksewell@umich.edu //Since we don't know how to check for alpha right now, we'll 692817Sksewell@umich.edu //just assume if it wasn't something else and it's 64 bit, that's 702817Sksewell@umich.edu //what it must be. 712817Sksewell@umich.edu if (ehdr.e_machine == EM_SPARC64 || 722817Sksewell@umich.edu (ehdr.e_machine == EM_SPARC && 732817Sksewell@umich.edu ehdr.e_ident[EI_CLASS] == ELFCLASS64)|| 742817Sksewell@umich.edu ehdr.e_machine == EM_SPARCV9) { 752817Sksewell@umich.edu arch = ObjectFile::SPARC64; 762817Sksewell@umich.edu } else if (ehdr.e_machine == EM_SPARC32PLUS || 772817Sksewell@umich.edu (ehdr.e_machine == EM_SPARC && 782817Sksewell@umich.edu ehdr.e_ident[EI_CLASS] == ELFCLASS32)) { 792817Sksewell@umich.edu arch = ObjectFile::SPARC32; 803784Sgblack@eecs.umich.edu } else if (ehdr.e_machine == EM_MIPS 816022Sgblack@eecs.umich.edu && ehdr.e_ident[EI_CLASS] == ELFCLASS32) { 823784Sgblack@eecs.umich.edu arch = ObjectFile::Mips; 833784Sgblack@eecs.umich.edu } else if (ehdr.e_machine == EM_X86_64 && 846022Sgblack@eecs.umich.edu ehdr.e_ident[EI_CLASS] == ELFCLASS64) { 853784Sgblack@eecs.umich.edu //In the future, we might want to differentiate between 32 bit 868887Sgeoffrey.blake@arm.com //and 64 bit x86 processes in case there are differences in their 878733Sgeoffrey.blake@arm.com //initial stack frame. 889023Sgblack@eecs.umich.edu arch = ObjectFile::X86; 899023Sgblack@eecs.umich.edu } else if (ehdr.e_ident[EI_CLASS] == ELFCLASS64) { 909023Sgblack@eecs.umich.edu arch = ObjectFile::Alpha; 919023Sgblack@eecs.umich.edu } else { 929023Sgblack@eecs.umich.edu warn("Unknown architecture: %d\n", ehdr.e_machine); 938541Sgblack@eecs.umich.edu arch = ObjectFile::UnknownArch; 942817Sksewell@umich.edu } 952817Sksewell@umich.edu 962817Sksewell@umich.edu //Detect the operating system 972817Sksewell@umich.edu switch (ehdr.e_ident[EI_OSABI]) 985712Shsul@eecs.umich.edu { 992817Sksewell@umich.edu 1005714Shsul@eecs.umich.edu case ELFOSABI_LINUX: 1015714Shsul@eecs.umich.edu opSys = ObjectFile::Linux; 1025714Shsul@eecs.umich.edu break; 1035714Shsul@eecs.umich.edu case ELFOSABI_SOLARIS: 1045715Shsul@eecs.umich.edu opSys = ObjectFile::Solaris; 1055715Shsul@eecs.umich.edu break; 1065715Shsul@eecs.umich.edu case ELFOSABI_TRU64: 1075715Shsul@eecs.umich.edu opSys = ObjectFile::Tru64; 1082817Sksewell@umich.edu break; 1092817Sksewell@umich.edu default: 1102817Sksewell@umich.edu opSys = ObjectFile::UnknownOpSys; 1112817Sksewell@umich.edu } 1123548Sgblack@eecs.umich.edu 1132817Sksewell@umich.edu //take a look at the .note.ABI section 1142817Sksewell@umich.edu //It can let us know what's what. 1158541Sgblack@eecs.umich.edu if (opSys == ObjectFile::UnknownOpSys) { 1168541Sgblack@eecs.umich.edu Elf_Scn *section; 1178754Sgblack@eecs.umich.edu GElf_Shdr shdr; 1188852Sandreas.hansson@arm.com Elf_Data *data; 1192817Sksewell@umich.edu uint32_t osAbi;; 1208852Sandreas.hansson@arm.com int secIdx = 1; 1213675Sktlim@umich.edu 1228706Sandreas.hansson@arm.com // Get the first section 1238706Sandreas.hansson@arm.com section = elf_getscn(elf, secIdx); 1248799Sgblack@eecs.umich.edu 1258852Sandreas.hansson@arm.com // While there are no more sections 1268706Sandreas.hansson@arm.com while (section != NULL && opSys == ObjectFile::UnknownOpSys) { 1272817Sksewell@umich.edu gelf_getshdr(section, &shdr); 1282817Sksewell@umich.edu if (shdr.sh_type == SHT_NOTE && !strcmp(".note.ABI-tag", 1292817Sksewell@umich.edu elf_strptr(elf, ehdr.e_shstrndx, shdr.sh_name))) { 1302817Sksewell@umich.edu // we have found a ABI note section 1312817Sksewell@umich.edu // Check the 5th 32bit word for OS 0 == linux, 1 == hurd, 1322817Sksewell@umich.edu // 2 == solaris, 3 == freebsd 1332817Sksewell@umich.edu data = elf_rawdata(section, NULL); 1342817Sksewell@umich.edu assert(data->d_buf); 1352817Sksewell@umich.edu if(ehdr.e_ident[EI_DATA] == ELFDATA2LSB) 1362817Sksewell@umich.edu osAbi = htole(((uint32_t*)data->d_buf)[4]); 1379180Sandreas.hansson@arm.com else 1382817Sksewell@umich.edu osAbi = htobe(((uint32_t*)data->d_buf)[4]); 1392817Sksewell@umich.edu 1409180Sandreas.hansson@arm.com switch(osAbi) { 1412817Sksewell@umich.edu case 0: 1422817Sksewell@umich.edu opSys = ObjectFile::Linux; 1439180Sandreas.hansson@arm.com break; 1442817Sksewell@umich.edu case 2: 1452817Sksewell@umich.edu opSys = ObjectFile::Solaris; 1462817Sksewell@umich.edu break; 1472817Sksewell@umich.edu } 1482817Sksewell@umich.edu } // if section found 1498777Sgblack@eecs.umich.edu if (!strcmp(".SUNW_version", elf_strptr(elf, ehdr.e_shstrndx, shdr.sh_name))) 1502817Sksewell@umich.edu opSys = ObjectFile::Solaris; 1512817Sksewell@umich.edu if (!strcmp(".stab.index", elf_strptr(elf, ehdr.e_shstrndx, shdr.sh_name))) 1522817Sksewell@umich.edu opSys = ObjectFile::Solaris; 1532817Sksewell@umich.edu 1542817Sksewell@umich.edu section = elf_getscn(elf, ++secIdx); 1552817Sksewell@umich.edu } // while sections 1562817Sksewell@umich.edu } 1572817Sksewell@umich.edu 1582817Sksewell@umich.edu ElfObject * result = new ElfObject(fname, fd, len, data, arch, opSys); 1592817Sksewell@umich.edu 1602817Sksewell@umich.edu //The number of headers in the file 1612817Sksewell@umich.edu result->_programHeaderCount = ehdr.e_phnum; 1622817Sksewell@umich.edu //Record the size of each entry 1632817Sksewell@umich.edu result->_programHeaderSize = ehdr.e_phentsize; 1642817Sksewell@umich.edu if(result->_programHeaderCount) //If there is a program header table 1652817Sksewell@umich.edu { 1662817Sksewell@umich.edu //Figure out the virtual address of the header table in the 1672817Sksewell@umich.edu //final memory image. We use the program headers themselves 1682817Sksewell@umich.edu //to translate from a file offset to the address in the image. 1692817Sksewell@umich.edu GElf_Phdr phdr; 1702817Sksewell@umich.edu uint64_t e_phoff = ehdr.e_phoff; 1712817Sksewell@umich.edu result->_programHeaderTable = 0; 1722817Sksewell@umich.edu for(int hdrnum = 0; hdrnum < result->_programHeaderCount; hdrnum++) 1732817Sksewell@umich.edu { 1742817Sksewell@umich.edu gelf_getphdr(elf, hdrnum, &phdr); 1752817Sksewell@umich.edu //Check if we've found the segment with the headers in it 1762817Sksewell@umich.edu if(phdr.p_offset <= e_phoff && 1772817Sksewell@umich.edu phdr.p_offset + phdr.p_filesz > e_phoff) 1782817Sksewell@umich.edu { 1792817Sksewell@umich.edu result->_programHeaderTable = phdr.p_vaddr + e_phoff; 1802817Sksewell@umich.edu break; 1812817Sksewell@umich.edu } 1822817Sksewell@umich.edu } 1832817Sksewell@umich.edu } 1842817Sksewell@umich.edu else 1852817Sksewell@umich.edu result->_programHeaderTable = 0; 1862817Sksewell@umich.edu 1872817Sksewell@umich.edu 1882817Sksewell@umich.edu elf_end(elf); 1892817Sksewell@umich.edu return result; 1902817Sksewell@umich.edu } 1917720Sgblack@eecs.umich.edu} 1927720Sgblack@eecs.umich.edu 1937720Sgblack@eecs.umich.edu 1947720Sgblack@eecs.umich.eduElfObject::ElfObject(const string &_filename, int _fd, 1957720Sgblack@eecs.umich.edu size_t _len, uint8_t *_data, 1967720Sgblack@eecs.umich.edu Arch _arch, OpSys _opSys) 1977720Sgblack@eecs.umich.edu : ObjectFile(_filename, _fd, _len, _data, _arch, _opSys) 1988733Sgeoffrey.blake@arm.com 1998733Sgeoffrey.blake@arm.com{ 2002817Sksewell@umich.edu Elf *elf; 2017720Sgblack@eecs.umich.edu GElf_Ehdr ehdr; 2027720Sgblack@eecs.umich.edu 2032817Sksewell@umich.edu // check that header matches library version 2042817Sksewell@umich.edu if (elf_version(EV_CURRENT) == EV_NONE) 2057720Sgblack@eecs.umich.edu panic("wrong elf version number!"); 2067720Sgblack@eecs.umich.edu 2072817Sksewell@umich.edu // get a pointer to elf structure 2087720Sgblack@eecs.umich.edu elf = elf_memory((char*)fileData,len); 2097720Sgblack@eecs.umich.edu // will only fail if fd is invalid 2107720Sgblack@eecs.umich.edu assert(elf != NULL); 2115259Sksewell@umich.edu 2122817Sksewell@umich.edu // Check that we actually have a elf file 2134172Ssaidi@eecs.umich.edu if (gelf_getehdr(elf, &ehdr) ==0) { 2145715Shsul@eecs.umich.edu panic("Not ELF, shouldn't be here"); 2154172Ssaidi@eecs.umich.edu } 2164172Ssaidi@eecs.umich.edu 2174172Ssaidi@eecs.umich.edu entry = ehdr.e_entry; 2182817Sksewell@umich.edu 2195715Shsul@eecs.umich.edu 2202817Sksewell@umich.edu // initialize segment sizes to 0 in case they're not present 2212817Sksewell@umich.edu text.size = data.size = bss.size = 0; 2224172Ssaidi@eecs.umich.edu 2232817Sksewell@umich.edu for (int i = 0; i < ehdr.e_phnum; ++i) { 2242817Sksewell@umich.edu GElf_Phdr phdr; 2252817Sksewell@umich.edu if (gelf_getphdr(elf, i, &phdr) == 0) { 2264172Ssaidi@eecs.umich.edu panic("gelf_getphdr failed for section %d", i); 2272817Sksewell@umich.edu } 2286313Sgblack@eecs.umich.edu 2296313Sgblack@eecs.umich.edu // for now we don't care about non-loadable segments 2306313Sgblack@eecs.umich.edu if (!(phdr.p_type & PT_LOAD)) 2312817Sksewell@umich.edu continue; 2322817Sksewell@umich.edu 2332817Sksewell@umich.edu // the headers don't explicitly distinguish text from data, 2342817Sksewell@umich.edu // but empirically the text segment comes first. 2352817Sksewell@umich.edu if (text.size == 0) { // haven't seen text segment yet 2362817Sksewell@umich.edu text.baseAddr = phdr.p_vaddr; 2372817Sksewell@umich.edu text.size = phdr.p_filesz; 2382817Sksewell@umich.edu text.fileImage = fileData + phdr.p_offset; 2392817Sksewell@umich.edu // if there's any padding at the end that's not in the 2402817Sksewell@umich.edu // file, call it the bss. This happens in the "text" 2412817Sksewell@umich.edu // segment if there's only one loadable segment (as for 2422817Sksewell@umich.edu // kernel images). 2432817Sksewell@umich.edu bss.size = phdr.p_memsz - phdr.p_filesz; 2442817Sksewell@umich.edu bss.baseAddr = phdr.p_vaddr + phdr.p_filesz; 2452817Sksewell@umich.edu bss.fileImage = NULL; 2462817Sksewell@umich.edu } else if (data.size == 0) { // have text, this must be data 2472817Sksewell@umich.edu data.baseAddr = phdr.p_vaddr; 2482817Sksewell@umich.edu data.size = phdr.p_filesz; 2492817Sksewell@umich.edu data.fileImage = fileData + phdr.p_offset; 2505715Shsul@eecs.umich.edu // if there's any padding at the end that's not in the 2512817Sksewell@umich.edu // file, call it the bss. Warn if this happens for both 2522817Sksewell@umich.edu // the text & data segments (should only have one bss). 2532817Sksewell@umich.edu if (phdr.p_memsz - phdr.p_filesz > 0 && bss.size != 0) { 2548777Sgblack@eecs.umich.edu warn("Two implied bss segments in file!\n"); 2555595Sgblack@eecs.umich.edu } 2565595Sgblack@eecs.umich.edu bss.size = phdr.p_memsz - phdr.p_filesz; 2575595Sgblack@eecs.umich.edu bss.baseAddr = phdr.p_vaddr + phdr.p_filesz; 2585595Sgblack@eecs.umich.edu bss.fileImage = NULL; 2595595Sgblack@eecs.umich.edu } else { 2605595Sgblack@eecs.umich.edu warn("More than two loadable segments in ELF object."); 2612817Sksewell@umich.edu warn("Ignoring segment @ 0x%x length 0x%x.", 2622817Sksewell@umich.edu phdr.p_vaddr, phdr.p_filesz); 2632817Sksewell@umich.edu } 264 } 265 266 // should have found at least one loadable segment 267 assert(text.size != 0); 268 269 DPRINTFR(Loader, "text: 0x%x %d\ndata: 0x%x %d\nbss: 0x%x %d\n", 270 text.baseAddr, text.size, data.baseAddr, data.size, 271 bss.baseAddr, bss.size); 272 273 elf_end(elf); 274 275 // We will actually read the sections when we need to load them 276} 277 278 279bool 280ElfObject::loadSomeSymbols(SymbolTable *symtab, int binding) 281{ 282 Elf *elf; 283 int sec_idx = 1; // there is a 0 but it is nothing, go figure 284 Elf_Scn *section; 285 GElf_Shdr shdr; 286 Elf_Data *data; 287 int count, ii; 288 bool found = false; 289 GElf_Sym sym; 290 291 if (!symtab) 292 return false; 293 294 // check that header matches library version 295 if (elf_version(EV_CURRENT) == EV_NONE) 296 panic("wrong elf version number!"); 297 298 // get a pointer to elf structure 299 elf = elf_memory((char*)fileData,len); 300 301 assert(elf != NULL); 302 303 // Get the first section 304 section = elf_getscn(elf, sec_idx); 305 306 // While there are no more sections 307 while (section != NULL) { 308 gelf_getshdr(section, &shdr); 309 310 if (shdr.sh_type == SHT_SYMTAB) { 311 found = true; 312 data = elf_getdata(section, NULL); 313 count = shdr.sh_size / shdr.sh_entsize; 314 DPRINTF(Loader, "Found Symbol Table, %d symbols present\n", count); 315 316 // loop through all the symbols, only loading global ones 317 for (ii = 0; ii < count; ++ii) { 318 gelf_getsym(data, ii, &sym); 319 if (GELF_ST_BIND(sym.st_info) == binding) { 320 symtab->insert(sym.st_value, 321 elf_strptr(elf, shdr.sh_link, sym.st_name)); 322 } 323 } 324 } 325 ++sec_idx; 326 section = elf_getscn(elf, sec_idx); 327 } 328 329 elf_end(elf); 330 331 return found; 332} 333 334bool 335ElfObject::loadGlobalSymbols(SymbolTable *symtab, Addr addrMask) 336{ 337 return loadSomeSymbols(symtab, STB_GLOBAL); 338} 339 340bool 341ElfObject::loadLocalSymbols(SymbolTable *symtab, Addr addrMask) 342{ 343 return loadSomeSymbols(symtab, STB_LOCAL); 344} 345 346bool 347ElfObject::isDynamic() 348{ 349 Elf *elf; 350 int sec_idx = 1; // there is a 0 but it is nothing, go figure 351 Elf_Scn *section; 352 GElf_Shdr shdr; 353 354 GElf_Ehdr ehdr; 355 356 // check that header matches library version 357 if (elf_version(EV_CURRENT) == EV_NONE) 358 panic("wrong elf version number!"); 359 360 // get a pointer to elf structure 361 elf = elf_memory((char*)fileData,len); 362 assert(elf != NULL); 363 364 // Check that we actually have a elf file 365 if (gelf_getehdr(elf, &ehdr) ==0) { 366 panic("Not ELF, shouldn't be here"); 367 } 368 369 // Get the first section 370 section = elf_getscn(elf, sec_idx); 371 372 // While there are no more sections 373 while (section != NULL) { 374 gelf_getshdr(section, &shdr); 375 if (!strcmp(".interp", elf_strptr(elf, ehdr.e_shstrndx, shdr.sh_name))) 376 return true; 377 section = elf_getscn(elf, ++sec_idx); 378 } // while sections 379 return false; 380} 381 382 383