elf_object.cc revision 4166
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 * Authors: Steve Reinhardt 292665Ssaidi@eecs.umich.edu * Ali Saidi 3012SN/A */ 3112SN/A 3212SN/A#include <string> 3312SN/A 34468SN/A// Because of the -Wundef flag we have to do this 35468SN/A#define __LIBELF_INTERNAL__ 0 36468SN/A#define __LIBELF_NEED_LINK_H 0 37661SN/A#define __LIBELF_SYMBOL_VERSIONS 0 38468SN/A 392634Sstever@eecs.umich.edu#include "gelf.h" 40468SN/A 4156SN/A#include "base/loader/elf_object.hh" 422439SN/A#include "base/misc.hh" 4312SN/A 4456SN/A#include "base/loader/symtab.hh" 4512SN/A 4656SN/A#include "base/trace.hh" // for DPRINTF 4712SN/A 482423SN/A#include "sim/byteswap.hh" 492423SN/A 5012SN/A 5112SN/Ausing namespace std; 5212SN/A 5312SN/AObjectFile * 5412SN/AElfObject::tryFile(const string &fname, int fd, size_t len, uint8_t *data) 5512SN/A{ 56443SN/A Elf *elf; 57443SN/A GElf_Ehdr ehdr; 582207SN/A Arch arch = UnknownArch; 592207SN/A OpSys opSys = UnknownOpSys; 60443SN/A 61468SN/A // check that header matches library version 621708SN/A if (elf_version(EV_CURRENT) == EV_NONE) 631708SN/A panic("wrong elf version number!"); 64443SN/A 65468SN/A // get a pointer to elf structure 66443SN/A elf = elf_memory((char*)data,len); 67468SN/A // will only fail if fd is invalid 68443SN/A assert(elf != NULL); 69443SN/A 70468SN/A // Check that we actually have a elf file 71468SN/A if (gelf_getehdr(elf, &ehdr) ==0) { 72443SN/A DPRINTFR(Loader, "Not ELF\n"); 73443SN/A elf_end(elf); 74443SN/A return NULL; 752476SN/A } else { 762207SN/A //Detect the architecture 772207SN/A //Since we don't know how to check for alpha right now, we'll 782207SN/A //just assume if it wasn't something else and it's 64 bit, that's 792207SN/A //what it must be. 802207SN/A if (ehdr.e_machine == EM_SPARC64 || 814111Sgblack@eecs.umich.edu (ehdr.e_machine == EM_SPARC && 824111Sgblack@eecs.umich.edu ehdr.e_ident[EI_CLASS] == ELFCLASS64)|| 832620SN/A ehdr.e_machine == EM_SPARCV9) { 844111Sgblack@eecs.umich.edu arch = ObjectFile::SPARC64; 854111Sgblack@eecs.umich.edu } else if (ehdr.e_machine == EM_SPARC32PLUS || 864111Sgblack@eecs.umich.edu (ehdr.e_machine == EM_SPARC && 874111Sgblack@eecs.umich.edu ehdr.e_ident[EI_CLASS] == ELFCLASS32)) { 884111Sgblack@eecs.umich.edu arch = ObjectFile::SPARC32; 892207SN/A } else if (ehdr.e_machine == EM_MIPS 902207SN/A && ehdr.e_ident[EI_CLASS] == ELFCLASS32) { 912472SN/A arch = ObjectFile::Mips; 924166Sgblack@eecs.umich.edu } else if (ehdr.e_machine == EM_X86_64 && 934166Sgblack@eecs.umich.edu ehdr.e_ident[EI_CLASS] == ELFCLASS64) { 944166Sgblack@eecs.umich.edu //In the future, we might want to differentiate between 32 bit 954166Sgblack@eecs.umich.edu //and 64 bit x86 processes in case there are differences in their 964166Sgblack@eecs.umich.edu //initial stack frame. 974166Sgblack@eecs.umich.edu arch = ObjectFile::X86; 982207SN/A } else if (ehdr.e_ident[EI_CLASS] == ELFCLASS64) { 992207SN/A arch = ObjectFile::Alpha; 1002207SN/A } else { 1012600SN/A warn("Unknown architecture: %d\n", ehdr.e_machine); 1022207SN/A arch = ObjectFile::UnknownArch; 1032207SN/A } 1042207SN/A 1052207SN/A //Detect the operating system 1062207SN/A switch (ehdr.e_ident[EI_OSABI]) 1072207SN/A { 1082238SN/A 1092207SN/A case ELFOSABI_LINUX: 1102207SN/A opSys = ObjectFile::Linux; 1112207SN/A break; 1122207SN/A case ELFOSABI_SOLARIS: 1132207SN/A opSys = ObjectFile::Solaris; 1142238SN/A break; 1152207SN/A case ELFOSABI_TRU64: 1162207SN/A opSys = ObjectFile::Tru64; 1172238SN/A break; 1182207SN/A default: 1192207SN/A opSys = ObjectFile::UnknownOpSys; 1202207SN/A } 1212207SN/A 1222238SN/A //take a look at the .note.ABI section 1232238SN/A //It can let us know what's what. 1242600SN/A if (opSys == ObjectFile::UnknownOpSys) { 1252238SN/A Elf_Scn *section; 1262238SN/A GElf_Shdr shdr; 1272238SN/A Elf_Data *data; 1282238SN/A uint32_t osAbi;; 1292238SN/A int secIdx = 1; 1302238SN/A 1312238SN/A // Get the first section 1322238SN/A section = elf_getscn(elf, secIdx); 1332238SN/A 1342238SN/A // While there are no more sections 1352600SN/A while (section != NULL && opSys == ObjectFile::UnknownOpSys) { 1362238SN/A gelf_getshdr(section, &shdr); 1372238SN/A if (shdr.sh_type == SHT_NOTE && !strcmp(".note.ABI-tag", 1382238SN/A elf_strptr(elf, ehdr.e_shstrndx, shdr.sh_name))) { 1392238SN/A // we have found a ABI note section 1402238SN/A // Check the 5th 32bit word for OS 0 == linux, 1 == hurd, 1412238SN/A // 2 == solaris, 3 == freebsd 1422238SN/A data = elf_rawdata(section, NULL); 1432238SN/A assert(data->d_buf); 1442238SN/A if(ehdr.e_ident[EI_DATA] == ELFDATA2LSB) 1452238SN/A osAbi = htole(((uint32_t*)data->d_buf)[4]); 1462238SN/A else 1472238SN/A osAbi = htobe(((uint32_t*)data->d_buf)[4]); 1482238SN/A 1492238SN/A switch(osAbi) { 1502238SN/A case 0: 1512238SN/A opSys = ObjectFile::Linux; 1522238SN/A break; 1532238SN/A case 2: 1542238SN/A opSys = ObjectFile::Solaris; 1552238SN/A break; 1562238SN/A } 1572238SN/A } // if section found 1582600SN/A if (!strcmp(".SUNW_version", elf_strptr(elf, ehdr.e_shstrndx, shdr.sh_name))) 1592600SN/A opSys = ObjectFile::Solaris; 1602600SN/A if (!strcmp(".stab.index", elf_strptr(elf, ehdr.e_shstrndx, shdr.sh_name))) 1612600SN/A opSys = ObjectFile::Solaris; 1622600SN/A 1632238SN/A section = elf_getscn(elf, ++secIdx); 1642238SN/A } // while sections 1652238SN/A } 1662472SN/A 1672976Sgblack@eecs.umich.edu ElfObject * result = new ElfObject(fname, fd, len, data, arch, opSys); 1682976Sgblack@eecs.umich.edu 1692976Sgblack@eecs.umich.edu //The number of headers in the file 1702976Sgblack@eecs.umich.edu result->_programHeaderCount = ehdr.e_phnum; 1712976Sgblack@eecs.umich.edu //Record the size of each entry 1722976Sgblack@eecs.umich.edu result->_programHeaderSize = ehdr.e_phentsize; 1732976Sgblack@eecs.umich.edu if(result->_programHeaderCount) //If there is a program header table 1742976Sgblack@eecs.umich.edu { 1752976Sgblack@eecs.umich.edu //Figure out the virtual address of the header table in the 1762976Sgblack@eecs.umich.edu //final memory image. We use the program headers themselves 1772976Sgblack@eecs.umich.edu //to translate from a file offset to the address in the image. 1782976Sgblack@eecs.umich.edu GElf_Phdr phdr; 1792976Sgblack@eecs.umich.edu uint64_t e_phoff = ehdr.e_phoff; 1802976Sgblack@eecs.umich.edu result->_programHeaderTable = 0; 1812976Sgblack@eecs.umich.edu for(int hdrnum = 0; hdrnum < result->_programHeaderCount; hdrnum++) 1822976Sgblack@eecs.umich.edu { 1832976Sgblack@eecs.umich.edu gelf_getphdr(elf, hdrnum, &phdr); 1842976Sgblack@eecs.umich.edu //Check if we've found the segment with the headers in it 1852976Sgblack@eecs.umich.edu if(phdr.p_offset <= e_phoff && 1862976Sgblack@eecs.umich.edu phdr.p_offset + phdr.p_filesz > e_phoff) 1872976Sgblack@eecs.umich.edu { 1882976Sgblack@eecs.umich.edu result->_programHeaderTable = phdr.p_vaddr + e_phoff; 1892976Sgblack@eecs.umich.edu break; 1902976Sgblack@eecs.umich.edu } 1912976Sgblack@eecs.umich.edu } 1922976Sgblack@eecs.umich.edu } 1932976Sgblack@eecs.umich.edu else 1942976Sgblack@eecs.umich.edu result->_programHeaderTable = 0; 1952976Sgblack@eecs.umich.edu 1962976Sgblack@eecs.umich.edu 1972238SN/A elf_end(elf); 1982976Sgblack@eecs.umich.edu return result; 19912SN/A } 20012SN/A} 20112SN/A 20212SN/A 20312SN/AElfObject::ElfObject(const string &_filename, int _fd, 204360SN/A size_t _len, uint8_t *_data, 205360SN/A Arch _arch, OpSys _opSys) 206360SN/A : ObjectFile(_filename, _fd, _len, _data, _arch, _opSys) 207443SN/A 20812SN/A{ 209443SN/A Elf *elf; 210443SN/A GElf_Ehdr ehdr; 21112SN/A 212468SN/A // check that header matches library version 2131708SN/A if (elf_version(EV_CURRENT) == EV_NONE) 2141708SN/A panic("wrong elf version number!"); 21512SN/A 216468SN/A // get a pointer to elf structure 217443SN/A elf = elf_memory((char*)fileData,len); 218468SN/A // will only fail if fd is invalid 219443SN/A assert(elf != NULL); 22012SN/A 221468SN/A // Check that we actually have a elf file 222468SN/A if (gelf_getehdr(elf, &ehdr) ==0) { 223443SN/A panic("Not ELF, shouldn't be here"); 22412SN/A } 22512SN/A 226468SN/A entry = ehdr.e_entry; 22712SN/A 2282472SN/A 229468SN/A // initialize segment sizes to 0 in case they're not present 230468SN/A text.size = data.size = bss.size = 0; 231468SN/A 232468SN/A for (int i = 0; i < ehdr.e_phnum; ++i) { 233468SN/A GElf_Phdr phdr; 234468SN/A if (gelf_getphdr(elf, i, &phdr) == 0) { 235468SN/A panic("gelf_getphdr failed for section %d", i); 236468SN/A } 237468SN/A 238468SN/A // for now we don't care about non-loadable segments 239468SN/A if (!(phdr.p_type & PT_LOAD)) 240468SN/A continue; 241468SN/A 242468SN/A // the headers don't explicitly distinguish text from data, 243468SN/A // but empirically the text segment comes first. 244468SN/A if (text.size == 0) { // haven't seen text segment yet 245468SN/A text.baseAddr = phdr.p_vaddr; 246468SN/A text.size = phdr.p_filesz; 2472420SN/A text.fileImage = fileData + phdr.p_offset; 248468SN/A // if there's any padding at the end that's not in the 249468SN/A // file, call it the bss. This happens in the "text" 250468SN/A // segment if there's only one loadable segment (as for 251468SN/A // kernel images). 252468SN/A bss.size = phdr.p_memsz - phdr.p_filesz; 253468SN/A bss.baseAddr = phdr.p_vaddr + phdr.p_filesz; 2542420SN/A bss.fileImage = NULL; 2552476SN/A } else if (data.size == 0) { // have text, this must be data 256468SN/A data.baseAddr = phdr.p_vaddr; 257468SN/A data.size = phdr.p_filesz; 2582420SN/A data.fileImage = fileData + phdr.p_offset; 259468SN/A // if there's any padding at the end that's not in the 260468SN/A // file, call it the bss. Warn if this happens for both 261468SN/A // the text & data segments (should only have one bss). 262468SN/A if (phdr.p_memsz - phdr.p_filesz > 0 && bss.size != 0) { 263468SN/A warn("Two implied bss segments in file!\n"); 264468SN/A } 265468SN/A bss.size = phdr.p_memsz - phdr.p_filesz; 266468SN/A bss.baseAddr = phdr.p_vaddr + phdr.p_filesz; 2672420SN/A bss.fileImage = NULL; 2682476SN/A } else { 2692476SN/A warn("More than two loadable segments in ELF object."); 2702476SN/A warn("Ignoring segment @ 0x%x length 0x%x.", 2712476SN/A phdr.p_vaddr, phdr.p_filesz); 272468SN/A } 273468SN/A } 274468SN/A 275468SN/A // should have found at least one loadable segment 276468SN/A assert(text.size != 0); 277468SN/A 278468SN/A DPRINTFR(Loader, "text: 0x%x %d\ndata: 0x%x %d\nbss: 0x%x %d\n", 279468SN/A text.baseAddr, text.size, data.baseAddr, data.size, 280468SN/A bss.baseAddr, bss.size); 281468SN/A 282443SN/A elf_end(elf); 283443SN/A 284468SN/A // We will actually read the sections when we need to load them 28512SN/A} 28612SN/A 28712SN/A 28812SN/Abool 289468SN/AElfObject::loadSomeSymbols(SymbolTable *symtab, int binding) 29012SN/A{ 291443SN/A Elf *elf; 292766SN/A int sec_idx = 1; // there is a 0 but it is nothing, go figure 293443SN/A Elf_Scn *section; 294443SN/A GElf_Shdr shdr; 295443SN/A Elf_Data *data; 296443SN/A int count, ii; 297443SN/A bool found = false; 298443SN/A GElf_Sym sym; 299443SN/A 300443SN/A if (!symtab) 301443SN/A return false; 302443SN/A 303468SN/A // check that header matches library version 3041708SN/A if (elf_version(EV_CURRENT) == EV_NONE) 3051708SN/A panic("wrong elf version number!"); 306443SN/A 307468SN/A // get a pointer to elf structure 308443SN/A elf = elf_memory((char*)fileData,len); 309443SN/A 310443SN/A assert(elf != NULL); 311443SN/A 312468SN/A // Get the first section 313454SN/A section = elf_getscn(elf, sec_idx); 314443SN/A 315468SN/A // While there are no more sections 316468SN/A while (section != NULL) { 317443SN/A gelf_getshdr(section, &shdr); 318443SN/A 319468SN/A if (shdr.sh_type == SHT_SYMTAB) { 320443SN/A found = true; 321443SN/A data = elf_getdata(section, NULL); 322443SN/A count = shdr.sh_size / shdr.sh_entsize; 323443SN/A DPRINTF(Loader, "Found Symbol Table, %d symbols present\n", count); 324443SN/A 325468SN/A // loop through all the symbols, only loading global ones 326468SN/A for (ii = 0; ii < count; ++ii) { 327443SN/A gelf_getsym(data, ii, &sym); 328836SN/A if (GELF_ST_BIND(sym.st_info) == binding) { 329468SN/A symtab->insert(sym.st_value, 330468SN/A elf_strptr(elf, shdr.sh_link, sym.st_name)); 331443SN/A } 332443SN/A } 333443SN/A } 334454SN/A ++sec_idx; 335454SN/A section = elf_getscn(elf, sec_idx); 336443SN/A } 337443SN/A 338443SN/A elf_end(elf); 339443SN/A 340443SN/A return found; 34112SN/A} 34212SN/A 34312SN/Abool 3443812Ssaidi@eecs.umich.eduElfObject::loadGlobalSymbols(SymbolTable *symtab, Addr addrMask) 345468SN/A{ 346468SN/A return loadSomeSymbols(symtab, STB_GLOBAL); 347468SN/A} 348468SN/A 349468SN/Abool 3503812Ssaidi@eecs.umich.eduElfObject::loadLocalSymbols(SymbolTable *symtab, Addr addrMask) 35112SN/A{ 352468SN/A return loadSomeSymbols(symtab, STB_LOCAL); 35312SN/A} 3543917Ssaidi@eecs.umich.edu 3553917Ssaidi@eecs.umich.edubool 3563917Ssaidi@eecs.umich.eduElfObject::isDynamic() 3573917Ssaidi@eecs.umich.edu{ 3583917Ssaidi@eecs.umich.edu Elf *elf; 3593917Ssaidi@eecs.umich.edu int sec_idx = 1; // there is a 0 but it is nothing, go figure 3603917Ssaidi@eecs.umich.edu Elf_Scn *section; 3613917Ssaidi@eecs.umich.edu GElf_Shdr shdr; 3623917Ssaidi@eecs.umich.edu 3633917Ssaidi@eecs.umich.edu GElf_Ehdr ehdr; 3643917Ssaidi@eecs.umich.edu 3653917Ssaidi@eecs.umich.edu // check that header matches library version 3663917Ssaidi@eecs.umich.edu if (elf_version(EV_CURRENT) == EV_NONE) 3673917Ssaidi@eecs.umich.edu panic("wrong elf version number!"); 3683917Ssaidi@eecs.umich.edu 3693917Ssaidi@eecs.umich.edu // get a pointer to elf structure 3703917Ssaidi@eecs.umich.edu elf = elf_memory((char*)fileData,len); 3713917Ssaidi@eecs.umich.edu assert(elf != NULL); 3723917Ssaidi@eecs.umich.edu 3733917Ssaidi@eecs.umich.edu // Check that we actually have a elf file 3743917Ssaidi@eecs.umich.edu if (gelf_getehdr(elf, &ehdr) ==0) { 3753917Ssaidi@eecs.umich.edu panic("Not ELF, shouldn't be here"); 3763917Ssaidi@eecs.umich.edu } 3773917Ssaidi@eecs.umich.edu 3783917Ssaidi@eecs.umich.edu // Get the first section 3793917Ssaidi@eecs.umich.edu section = elf_getscn(elf, sec_idx); 3803917Ssaidi@eecs.umich.edu 3813917Ssaidi@eecs.umich.edu // While there are no more sections 3823917Ssaidi@eecs.umich.edu while (section != NULL) { 3833917Ssaidi@eecs.umich.edu gelf_getshdr(section, &shdr); 3843925Ssaidi@eecs.umich.edu if (!strcmp(".interp", elf_strptr(elf, ehdr.e_shstrndx, shdr.sh_name))) 3853917Ssaidi@eecs.umich.edu return true; 3863917Ssaidi@eecs.umich.edu section = elf_getscn(elf, ++sec_idx); 3873917Ssaidi@eecs.umich.edu } // while sections 3883917Ssaidi@eecs.umich.edu return false; 3893917Ssaidi@eecs.umich.edu} 3903917Ssaidi@eecs.umich.edu 3913917Ssaidi@eecs.umich.edu 392