elf_object.cc revision 10360:919c02740209
13569Sgblack@eecs.umich.edu/* 23569Sgblack@eecs.umich.edu * Copyright (c) 2011-2013 ARM Limited 33569Sgblack@eecs.umich.edu * All rights reserved 43569Sgblack@eecs.umich.edu * 53569Sgblack@eecs.umich.edu * The license below extends only to copyright in the software and shall 63569Sgblack@eecs.umich.edu * not be construed as granting a license to any other intellectual 73569Sgblack@eecs.umich.edu * property including but not limited to intellectual property relating 83569Sgblack@eecs.umich.edu * to a hardware implementation of the functionality of the software 93569Sgblack@eecs.umich.edu * licensed hereunder. You may use the software subject to the license 103569Sgblack@eecs.umich.edu * terms below provided that you ensure that this notice is replicated 113569Sgblack@eecs.umich.edu * unmodified and in its entirety in all distributions of the software, 123569Sgblack@eecs.umich.edu * modified or unmodified, in source code or in binary form. 133569Sgblack@eecs.umich.edu * 143569Sgblack@eecs.umich.edu * Copyright (c) 2003-2005 The Regents of The University of Michigan 153569Sgblack@eecs.umich.edu * All rights reserved. 163569Sgblack@eecs.umich.edu * 173569Sgblack@eecs.umich.edu * Redistribution and use in source and binary forms, with or without 183569Sgblack@eecs.umich.edu * modification, are permitted provided that the following conditions are 193569Sgblack@eecs.umich.edu * met: redistributions of source code must retain the above copyright 203569Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer; 213569Sgblack@eecs.umich.edu * redistributions in binary form must reproduce the above copyright 223569Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer in the 233569Sgblack@eecs.umich.edu * documentation and/or other materials provided with the distribution; 243569Sgblack@eecs.umich.edu * neither the name of the copyright holders nor the names of its 253569Sgblack@eecs.umich.edu * contributors may be used to endorse or promote products derived from 263569Sgblack@eecs.umich.edu * this software without specific prior written permission. 273569Sgblack@eecs.umich.edu * 283804Ssaidi@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 293569Sgblack@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 303569Sgblack@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 313918Ssaidi@eecs.umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 323918Ssaidi@eecs.umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 333804Ssaidi@eecs.umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 343811Ssaidi@eecs.umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 353569Sgblack@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 363824Ssaidi@eecs.umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 373811Ssaidi@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 383811Ssaidi@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 393823Ssaidi@eecs.umich.edu * 403823Ssaidi@eecs.umich.edu * Authors: Steve Reinhardt 413823Ssaidi@eecs.umich.edu * Ali Saidi 424103Ssaidi@eecs.umich.edu */ 433569Sgblack@eecs.umich.edu 443804Ssaidi@eecs.umich.edu#include <cassert> 453804Ssaidi@eecs.umich.edu#include <string> 464088Sbinkertn@umich.edu 473569Sgblack@eecs.umich.edu#include "base/loader/elf_object.hh" 485034Smilesck@eecs.umich.edu#include "base/loader/symtab.hh" 495358Sgblack@eecs.umich.edu#include "base/bitfield.hh" 503881Ssaidi@eecs.umich.edu#include "base/misc.hh" 513804Ssaidi@eecs.umich.edu#include "base/trace.hh" 523804Ssaidi@eecs.umich.edu#include "debug/Loader.hh" 533804Ssaidi@eecs.umich.edu#include "sim/byteswap.hh" 545555Snate@binkert.org#include "gelf.h" 553569Sgblack@eecs.umich.edu 563804Ssaidi@eecs.umich.eduusing namespace std; 573918Ssaidi@eecs.umich.edu 583881Ssaidi@eecs.umich.eduObjectFile * 593881Ssaidi@eecs.umich.eduElfObject::tryFile(const string &fname, int fd, size_t len, uint8_t *data) 603881Ssaidi@eecs.umich.edu{ 614990Sgblack@eecs.umich.edu Elf *elf; 624990Sgblack@eecs.umich.edu GElf_Ehdr ehdr; 634990Sgblack@eecs.umich.edu Arch arch = UnknownArch; 644990Sgblack@eecs.umich.edu OpSys opSys = UnknownOpSys; 654990Sgblack@eecs.umich.edu 664990Sgblack@eecs.umich.edu // check that header matches library version 674990Sgblack@eecs.umich.edu if (elf_version(EV_CURRENT) == EV_NONE) 684990Sgblack@eecs.umich.edu panic("wrong elf version number!"); 694990Sgblack@eecs.umich.edu 703804Ssaidi@eecs.umich.edu // get a pointer to elf structure 713569Sgblack@eecs.umich.edu elf = elf_memory((char*)data,len); 723804Ssaidi@eecs.umich.edu // will only fail if fd is invalid 733804Ssaidi@eecs.umich.edu assert(elf != NULL); 743804Ssaidi@eecs.umich.edu 753804Ssaidi@eecs.umich.edu // Check that we actually have a elf file 763881Ssaidi@eecs.umich.edu if (gelf_getehdr(elf, &ehdr) == 0) { 773804Ssaidi@eecs.umich.edu DPRINTFR(Loader, "Not ELF\n"); 783804Ssaidi@eecs.umich.edu elf_end(elf); 793804Ssaidi@eecs.umich.edu return NULL; 803804Ssaidi@eecs.umich.edu } else { 813804Ssaidi@eecs.umich.edu //Detect the architecture 823804Ssaidi@eecs.umich.edu //Since we don't know how to check for alpha right now, we'll 833804Ssaidi@eecs.umich.edu //just assume if it wasn't something else and it's 64 bit, that's 843569Sgblack@eecs.umich.edu //what it must be. 853569Sgblack@eecs.umich.edu if (ehdr.e_machine == EM_SPARC64 || 863804Ssaidi@eecs.umich.edu (ehdr.e_machine == EM_SPARC && 873804Ssaidi@eecs.umich.edu ehdr.e_ident[EI_CLASS] == ELFCLASS64)|| 883826Ssaidi@eecs.umich.edu ehdr.e_machine == EM_SPARCV9) { 893804Ssaidi@eecs.umich.edu arch = ObjectFile::SPARC64; 903804Ssaidi@eecs.umich.edu } else if (ehdr.e_machine == EM_SPARC32PLUS || 913826Ssaidi@eecs.umich.edu (ehdr.e_machine == EM_SPARC && 923907Ssaidi@eecs.umich.edu ehdr.e_ident[EI_CLASS] == ELFCLASS32)) { 933826Ssaidi@eecs.umich.edu arch = ObjectFile::SPARC32; 943811Ssaidi@eecs.umich.edu } else if (ehdr.e_machine == EM_MIPS 953836Ssaidi@eecs.umich.edu && ehdr.e_ident[EI_CLASS] == ELFCLASS32) { 963915Ssaidi@eecs.umich.edu if (ehdr.e_ident[EI_DATA] == ELFDATA2LSB) { 973907Ssaidi@eecs.umich.edu arch = ObjectFile::Mips; 983881Ssaidi@eecs.umich.edu } else { 993881Ssaidi@eecs.umich.edu fatal("The binary you're trying to load is compiled for big " 1003881Ssaidi@eecs.umich.edu "endian MIPS. M5\nonly supports little endian MIPS. " 1013881Ssaidi@eecs.umich.edu "Please recompile your binary.\n"); 1023907Ssaidi@eecs.umich.edu } 1033881Ssaidi@eecs.umich.edu } else if (ehdr.e_machine == EM_X86_64 && 1045555Snate@binkert.org ehdr.e_ident[EI_CLASS] == ELFCLASS64) { 1055555Snate@binkert.org arch = ObjectFile::X86_64; 1065555Snate@binkert.org } else if (ehdr.e_machine == EM_386 && 1073881Ssaidi@eecs.umich.edu ehdr.e_ident[EI_CLASS] == ELFCLASS32) { 1083881Ssaidi@eecs.umich.edu arch = ObjectFile::I386; 1093907Ssaidi@eecs.umich.edu } else if (ehdr.e_machine == EM_ARM && 1103907Ssaidi@eecs.umich.edu ehdr.e_ident[EI_CLASS] == ELFCLASS32) { 1113907Ssaidi@eecs.umich.edu if (bits(ehdr.e_entry, 0)) { 1123907Ssaidi@eecs.umich.edu arch = ObjectFile::Thumb; 1133907Ssaidi@eecs.umich.edu } else { 1143907Ssaidi@eecs.umich.edu arch = ObjectFile::Arm; 1153907Ssaidi@eecs.umich.edu } 1163907Ssaidi@eecs.umich.edu } else if ((ehdr.e_machine == EM_AARCH64) && 1173907Ssaidi@eecs.umich.edu ehdr.e_ident[EI_CLASS] == ELFCLASS64) { 1183907Ssaidi@eecs.umich.edu arch = ObjectFile::Arm64; 1193907Ssaidi@eecs.umich.edu } else if (ehdr.e_ident[EI_CLASS] == ELFCLASS64) { 1203907Ssaidi@eecs.umich.edu arch = ObjectFile::Alpha; 1213907Ssaidi@eecs.umich.edu } else if (ehdr.e_machine == EM_PPC && 1223907Ssaidi@eecs.umich.edu ehdr.e_ident[EI_CLASS] == ELFCLASS32) { 1233907Ssaidi@eecs.umich.edu if (ehdr.e_ident[EI_DATA] == ELFDATA2MSB) { 1243907Ssaidi@eecs.umich.edu arch = ObjectFile::Power; 1253907Ssaidi@eecs.umich.edu } else { 1263907Ssaidi@eecs.umich.edu fatal("The binary you're trying to load is compiled for " 1273907Ssaidi@eecs.umich.edu "little endian Power.\nM5 only supports big " 1283907Ssaidi@eecs.umich.edu "endian Power. Please recompile your binary.\n"); 1293907Ssaidi@eecs.umich.edu } 1303907Ssaidi@eecs.umich.edu } else if (ehdr.e_machine == EM_PPC64) { 1313881Ssaidi@eecs.umich.edu fatal("The binary you're trying to load is compiled for 64-bit " 1323881Ssaidi@eecs.umich.edu "Power. M5\n only supports 32-bit Power. Please " 1333881Ssaidi@eecs.umich.edu "recompile your binary.\n"); 1343881Ssaidi@eecs.umich.edu } else { 1353881Ssaidi@eecs.umich.edu warn("Unknown architecture: %d\n", ehdr.e_machine); 1363881Ssaidi@eecs.umich.edu arch = ObjectFile::UnknownArch; 1373881Ssaidi@eecs.umich.edu } 1383881Ssaidi@eecs.umich.edu 1393881Ssaidi@eecs.umich.edu //Detect the operating system 1403881Ssaidi@eecs.umich.edu switch (ehdr.e_ident[EI_OSABI]) { 1413881Ssaidi@eecs.umich.edu case ELFOSABI_LINUX: 1423881Ssaidi@eecs.umich.edu opSys = ObjectFile::Linux; 1433907Ssaidi@eecs.umich.edu break; 1443811Ssaidi@eecs.umich.edu case ELFOSABI_SOLARIS: 1453826Ssaidi@eecs.umich.edu opSys = ObjectFile::Solaris; 1463826Ssaidi@eecs.umich.edu break; 1473826Ssaidi@eecs.umich.edu case ELFOSABI_TRU64: 1483826Ssaidi@eecs.umich.edu opSys = ObjectFile::Tru64; 1493881Ssaidi@eecs.umich.edu break; 1503881Ssaidi@eecs.umich.edu case ELFOSABI_ARM: 1513881Ssaidi@eecs.umich.edu opSys = ObjectFile::LinuxArmOABI; 1523881Ssaidi@eecs.umich.edu break; 1533881Ssaidi@eecs.umich.edu default: 1543881Ssaidi@eecs.umich.edu opSys = ObjectFile::UnknownOpSys; 1553881Ssaidi@eecs.umich.edu } 1563881Ssaidi@eecs.umich.edu 1573881Ssaidi@eecs.umich.edu //take a look at the .note.ABI section 1583881Ssaidi@eecs.umich.edu //It can let us know what's what. 1593881Ssaidi@eecs.umich.edu if (opSys == ObjectFile::UnknownOpSys) { 1603881Ssaidi@eecs.umich.edu Elf_Scn *section; 1613881Ssaidi@eecs.umich.edu GElf_Shdr shdr; 1623881Ssaidi@eecs.umich.edu Elf_Data *data; 1633881Ssaidi@eecs.umich.edu uint32_t osAbi;; 1643826Ssaidi@eecs.umich.edu int secIdx = 1; 1653826Ssaidi@eecs.umich.edu 1663826Ssaidi@eecs.umich.edu // Get the first section 1673826Ssaidi@eecs.umich.edu section = elf_getscn(elf, secIdx); 1683826Ssaidi@eecs.umich.edu 1693881Ssaidi@eecs.umich.edu // While there are no more sections 1703569Sgblack@eecs.umich.edu while (section != NULL && opSys == ObjectFile::UnknownOpSys) { 1713569Sgblack@eecs.umich.edu gelf_getshdr(section, &shdr); 1723881Ssaidi@eecs.umich.edu if (shdr.sh_type == SHT_NOTE && !strcmp(".note.ABI-tag", 1733804Ssaidi@eecs.umich.edu elf_strptr(elf, ehdr.e_shstrndx, shdr.sh_name))) { 1743881Ssaidi@eecs.umich.edu // we have found a ABI note section 1753826Ssaidi@eecs.umich.edu // Check the 5th 32bit word for OS 0 == linux, 1 == hurd, 1763881Ssaidi@eecs.umich.edu // 2 == solaris, 3 == freebsd 1773881Ssaidi@eecs.umich.edu data = elf_rawdata(section, NULL); 1783881Ssaidi@eecs.umich.edu assert(data->d_buf); 1793907Ssaidi@eecs.umich.edu if(ehdr.e_ident[EI_DATA] == ELFDATA2LSB) 1803907Ssaidi@eecs.umich.edu osAbi = htole(((uint32_t*)data->d_buf)[4]); 1813929Ssaidi@eecs.umich.edu else 1823929Ssaidi@eecs.umich.edu osAbi = htobe(((uint32_t*)data->d_buf)[4]); 1833907Ssaidi@eecs.umich.edu 1843907Ssaidi@eecs.umich.edu switch(osAbi) { 1853804Ssaidi@eecs.umich.edu case 0: 1863804Ssaidi@eecs.umich.edu opSys = ObjectFile::Linux; 1873881Ssaidi@eecs.umich.edu break; 1883804Ssaidi@eecs.umich.edu case 2: 1893804Ssaidi@eecs.umich.edu opSys = ObjectFile::Solaris; 1903804Ssaidi@eecs.umich.edu break; 1913804Ssaidi@eecs.umich.edu } 1923804Ssaidi@eecs.umich.edu } // if section found 1933804Ssaidi@eecs.umich.edu if (!strcmp(".SUNW_version", elf_strptr(elf, ehdr.e_shstrndx, shdr.sh_name))) 1943804Ssaidi@eecs.umich.edu opSys = ObjectFile::Solaris; 1953569Sgblack@eecs.umich.edu if (!strcmp(".stab.index", elf_strptr(elf, ehdr.e_shstrndx, shdr.sh_name))) 1963863Ssaidi@eecs.umich.edu opSys = ObjectFile::Solaris; 1973863Ssaidi@eecs.umich.edu 1983804Ssaidi@eecs.umich.edu section = elf_getscn(elf, ++secIdx); 1995555Snate@binkert.org } // while sections 2005555Snate@binkert.org } 2013804Ssaidi@eecs.umich.edu 2023804Ssaidi@eecs.umich.edu ElfObject * result = new ElfObject(fname, fd, len, data, arch, opSys); 2033804Ssaidi@eecs.umich.edu 2043804Ssaidi@eecs.umich.edu //The number of headers in the file 2053804Ssaidi@eecs.umich.edu result->_programHeaderCount = ehdr.e_phnum; 2063569Sgblack@eecs.umich.edu //Record the size of each entry 2073804Ssaidi@eecs.umich.edu result->_programHeaderSize = ehdr.e_phentsize; 2083804Ssaidi@eecs.umich.edu if(result->_programHeaderCount) //If there is a program header table 2093804Ssaidi@eecs.umich.edu { 2105555Snate@binkert.org //Figure out the virtual address of the header table in the 2115555Snate@binkert.org //final memory image. We use the program headers themselves 2123804Ssaidi@eecs.umich.edu //to translate from a file offset to the address in the image. 2133804Ssaidi@eecs.umich.edu GElf_Phdr phdr; 2143804Ssaidi@eecs.umich.edu uint64_t e_phoff = ehdr.e_phoff; 2153804Ssaidi@eecs.umich.edu result->_programHeaderTable = 0; 2163804Ssaidi@eecs.umich.edu for(int hdrnum = 0; hdrnum < result->_programHeaderCount; hdrnum++) 2173811Ssaidi@eecs.umich.edu { 2183811Ssaidi@eecs.umich.edu gelf_getphdr(elf, hdrnum, &phdr); 2193804Ssaidi@eecs.umich.edu //Check if we've found the segment with the headers in it 2203804Ssaidi@eecs.umich.edu if(phdr.p_offset <= e_phoff && 2215312Sgblack@eecs.umich.edu phdr.p_offset + phdr.p_filesz > e_phoff) 2223804Ssaidi@eecs.umich.edu { 2233804Ssaidi@eecs.umich.edu result->_programHeaderTable = 2243804Ssaidi@eecs.umich.edu phdr.p_paddr + (e_phoff - phdr.p_offset); 2253804Ssaidi@eecs.umich.edu break; 2263804Ssaidi@eecs.umich.edu } 2273804Ssaidi@eecs.umich.edu } 2283804Ssaidi@eecs.umich.edu } 2293811Ssaidi@eecs.umich.edu else 2303804Ssaidi@eecs.umich.edu result->_programHeaderTable = 0; 2313804Ssaidi@eecs.umich.edu 2323804Ssaidi@eecs.umich.edu 2333804Ssaidi@eecs.umich.edu elf_end(elf); 2343804Ssaidi@eecs.umich.edu return result; 2353826Ssaidi@eecs.umich.edu } 2363826Ssaidi@eecs.umich.edu} 2374070Ssaidi@eecs.umich.edu 2385555Snate@binkert.org 2395555Snate@binkert.orgElfObject::ElfObject(const string &_filename, int _fd, 2404070Ssaidi@eecs.umich.edu size_t _len, uint8_t *_data, 2413804Ssaidi@eecs.umich.edu Arch _arch, OpSys _opSys) 2423804Ssaidi@eecs.umich.edu : ObjectFile(_filename, _fd, _len, _data, _arch, _opSys), 2433804Ssaidi@eecs.umich.edu _programHeaderTable(0), _programHeaderSize(0), _programHeaderCount(0) 2443804Ssaidi@eecs.umich.edu 2453804Ssaidi@eecs.umich.edu{ 2463804Ssaidi@eecs.umich.edu Elf *elf; 2473804Ssaidi@eecs.umich.edu GElf_Ehdr ehdr; 2483804Ssaidi@eecs.umich.edu 2493804Ssaidi@eecs.umich.edu // check that header matches library version 2503804Ssaidi@eecs.umich.edu if (elf_version(EV_CURRENT) == EV_NONE) 2513804Ssaidi@eecs.umich.edu panic("wrong elf version number!"); 2523804Ssaidi@eecs.umich.edu 2533826Ssaidi@eecs.umich.edu // get a pointer to elf structure 2543826Ssaidi@eecs.umich.edu elf = elf_memory((char*)fileData,len); 2553826Ssaidi@eecs.umich.edu // will only fail if fd is invalid 2563863Ssaidi@eecs.umich.edu assert(elf != NULL); 2573826Ssaidi@eecs.umich.edu 2583826Ssaidi@eecs.umich.edu // Check that we actually have a elf file 2593826Ssaidi@eecs.umich.edu if (gelf_getehdr(elf, &ehdr) ==0) { 2603826Ssaidi@eecs.umich.edu panic("Not ELF, shouldn't be here"); 2613826Ssaidi@eecs.umich.edu } 2623826Ssaidi@eecs.umich.edu 2633826Ssaidi@eecs.umich.edu entry = ehdr.e_entry; 2643826Ssaidi@eecs.umich.edu 2653826Ssaidi@eecs.umich.edu // initialize segment sizes to 0 in case they're not present 2663804Ssaidi@eecs.umich.edu text.size = data.size = bss.size = 0; 2673804Ssaidi@eecs.umich.edu text.baseAddr = data.baseAddr = bss.baseAddr = 0; 2683804Ssaidi@eecs.umich.edu 2693804Ssaidi@eecs.umich.edu int secIdx = 1; 2703804Ssaidi@eecs.umich.edu Elf_Scn *section; 2713804Ssaidi@eecs.umich.edu GElf_Shdr shdr; 2723804Ssaidi@eecs.umich.edu 2733863Ssaidi@eecs.umich.edu // The first address of some important sections. 2743863Ssaidi@eecs.umich.edu Addr textSecStart = 0; 2753863Ssaidi@eecs.umich.edu Addr dataSecStart = 0; 2763836Ssaidi@eecs.umich.edu Addr bssSecStart = 0; 2773836Ssaidi@eecs.umich.edu 2783804Ssaidi@eecs.umich.edu // Get the first section 2793804Ssaidi@eecs.umich.edu section = elf_getscn(elf, secIdx); 2805312Sgblack@eecs.umich.edu 2813804Ssaidi@eecs.umich.edu // Find the beginning of the most interesting sections. 2823804Ssaidi@eecs.umich.edu while (section != NULL) { 2833804Ssaidi@eecs.umich.edu gelf_getshdr(section, &shdr); 2843804Ssaidi@eecs.umich.edu char * secName = elf_strptr(elf, ehdr.e_shstrndx, shdr.sh_name); 2853804Ssaidi@eecs.umich.edu 2863804Ssaidi@eecs.umich.edu if (secName) { 2873804Ssaidi@eecs.umich.edu if (!strcmp(".text", secName)) { 2883863Ssaidi@eecs.umich.edu textSecStart = shdr.sh_addr; 2893804Ssaidi@eecs.umich.edu } else if (!strcmp(".data", secName)) { 2903804Ssaidi@eecs.umich.edu dataSecStart = shdr.sh_addr; 2913804Ssaidi@eecs.umich.edu } else if (!strcmp(".bss", secName)) { 2923804Ssaidi@eecs.umich.edu bssSecStart = shdr.sh_addr; 2933804Ssaidi@eecs.umich.edu } 2943881Ssaidi@eecs.umich.edu } else { 2953804Ssaidi@eecs.umich.edu Elf_Error errorNum = (Elf_Error)elf_errno(); 2963804Ssaidi@eecs.umich.edu if (errorNum != ELF_E_NONE) { 2973804Ssaidi@eecs.umich.edu const char *errorMessage = elf_errmsg(errorNum); 2983804Ssaidi@eecs.umich.edu fatal("Error from libelf: %s.\n", errorMessage); 2993804Ssaidi@eecs.umich.edu } 3003804Ssaidi@eecs.umich.edu } 3013804Ssaidi@eecs.umich.edu 3023863Ssaidi@eecs.umich.edu section = elf_getscn(elf, ++secIdx); 3033863Ssaidi@eecs.umich.edu } 3043836Ssaidi@eecs.umich.edu 3055555Snate@binkert.org // Go through all the segments in the program, record them, and scrape 3063804Ssaidi@eecs.umich.edu // out information about the text, data, and bss areas needed by other 3073804Ssaidi@eecs.umich.edu // code. 3083881Ssaidi@eecs.umich.edu for (int i = 0; i < ehdr.e_phnum; ++i) { 3093881Ssaidi@eecs.umich.edu GElf_Phdr phdr; 3103881Ssaidi@eecs.umich.edu if (gelf_getphdr(elf, i, &phdr) == 0) { 3113804Ssaidi@eecs.umich.edu panic("gelf_getphdr failed for segment %d.", i); 3123804Ssaidi@eecs.umich.edu } 3133804Ssaidi@eecs.umich.edu 3143804Ssaidi@eecs.umich.edu // for now we don't care about non-loadable segments 3153804Ssaidi@eecs.umich.edu if (!(phdr.p_type & PT_LOAD)) 3163804Ssaidi@eecs.umich.edu continue; 3173804Ssaidi@eecs.umich.edu 3183804Ssaidi@eecs.umich.edu // Check to see if this segment contains the bss section. 3193804Ssaidi@eecs.umich.edu if (phdr.p_paddr <= bssSecStart && 3203804Ssaidi@eecs.umich.edu phdr.p_paddr + phdr.p_memsz > bssSecStart && 3213804Ssaidi@eecs.umich.edu phdr.p_memsz - phdr.p_filesz > 0) { 3223804Ssaidi@eecs.umich.edu bss.baseAddr = phdr.p_paddr + phdr.p_filesz; 3233804Ssaidi@eecs.umich.edu bss.size = phdr.p_memsz - phdr.p_filesz; 3243863Ssaidi@eecs.umich.edu bss.fileImage = NULL; 3253836Ssaidi@eecs.umich.edu } 3265555Snate@binkert.org 3275288Sgblack@eecs.umich.edu // Check to see if this is the text or data segment 3285288Sgblack@eecs.umich.edu if (phdr.p_vaddr <= textSecStart && 3295288Sgblack@eecs.umich.edu phdr.p_vaddr + phdr.p_filesz > textSecStart) { 3303804Ssaidi@eecs.umich.edu text.baseAddr = phdr.p_paddr; 3313804Ssaidi@eecs.umich.edu text.size = phdr.p_filesz; 3323804Ssaidi@eecs.umich.edu text.fileImage = fileData + phdr.p_offset; 3333804Ssaidi@eecs.umich.edu } else if (phdr.p_vaddr <= dataSecStart && 3343804Ssaidi@eecs.umich.edu phdr.p_vaddr + phdr.p_filesz > dataSecStart) { 3353804Ssaidi@eecs.umich.edu data.baseAddr = phdr.p_paddr; 3363804Ssaidi@eecs.umich.edu data.size = phdr.p_filesz; 3373804Ssaidi@eecs.umich.edu data.fileImage = fileData + phdr.p_offset; 3383804Ssaidi@eecs.umich.edu } else { 3393804Ssaidi@eecs.umich.edu // If it's none of the above but is loadable, 3403804Ssaidi@eecs.umich.edu // load the filesize worth of data 3413804Ssaidi@eecs.umich.edu Segment extra; 3423804Ssaidi@eecs.umich.edu extra.baseAddr = phdr.p_paddr; 3433836Ssaidi@eecs.umich.edu extra.size = phdr.p_filesz; 3445555Snate@binkert.org extra.fileImage = fileData + phdr.p_offset; 3453836Ssaidi@eecs.umich.edu extraSegments.push_back(extra); 3465555Snate@binkert.org } 3473881Ssaidi@eecs.umich.edu } 3483881Ssaidi@eecs.umich.edu 3493804Ssaidi@eecs.umich.edu // should have found at least one loadable segment 3503907Ssaidi@eecs.umich.edu assert(text.size != 0); 3513804Ssaidi@eecs.umich.edu 3523804Ssaidi@eecs.umich.edu DPRINTFR(Loader, "text: 0x%x %d\ndata: 0x%x %d\nbss: 0x%x %d\n", 3533804Ssaidi@eecs.umich.edu text.baseAddr, text.size, data.baseAddr, data.size, 3543804Ssaidi@eecs.umich.edu bss.baseAddr, bss.size); 3553804Ssaidi@eecs.umich.edu 3565555Snate@binkert.org elf_end(elf); 3575555Snate@binkert.org 3583881Ssaidi@eecs.umich.edu // We will actually read the sections when we need to load them 3593881Ssaidi@eecs.umich.edu} 3603881Ssaidi@eecs.umich.edu 3613804Ssaidi@eecs.umich.edu 3623881Ssaidi@eecs.umich.edubool 3633881Ssaidi@eecs.umich.eduElfObject::loadSomeSymbols(SymbolTable *symtab, int binding, Addr mask) 3643881Ssaidi@eecs.umich.edu{ 3653881Ssaidi@eecs.umich.edu Elf *elf; 3663804Ssaidi@eecs.umich.edu int sec_idx = 1; // there is a 0 but it is nothing, go figure 3673804Ssaidi@eecs.umich.edu Elf_Scn *section; 3683804Ssaidi@eecs.umich.edu GElf_Shdr shdr; 3695555Snate@binkert.org Elf_Data *data; 3705555Snate@binkert.org int count, ii; 3713804Ssaidi@eecs.umich.edu bool found = false; 3723804Ssaidi@eecs.umich.edu GElf_Sym sym; 3733881Ssaidi@eecs.umich.edu 3743881Ssaidi@eecs.umich.edu if (!symtab) 3753804Ssaidi@eecs.umich.edu return false; 3763881Ssaidi@eecs.umich.edu 3773881Ssaidi@eecs.umich.edu // check that header matches library version 3783881Ssaidi@eecs.umich.edu if (elf_version(EV_CURRENT) == EV_NONE) 3793804Ssaidi@eecs.umich.edu panic("wrong elf version number!"); 3803804Ssaidi@eecs.umich.edu 3813804Ssaidi@eecs.umich.edu // get a pointer to elf structure 3823804Ssaidi@eecs.umich.edu elf = elf_memory((char*)fileData,len); 3833804Ssaidi@eecs.umich.edu 3843804Ssaidi@eecs.umich.edu assert(elf != NULL); 3853804Ssaidi@eecs.umich.edu 3863804Ssaidi@eecs.umich.edu // Get the first section 3873804Ssaidi@eecs.umich.edu section = elf_getscn(elf, sec_idx); 3883804Ssaidi@eecs.umich.edu 3893804Ssaidi@eecs.umich.edu // While there are no more sections 3903804Ssaidi@eecs.umich.edu while (section != NULL) { 3913804Ssaidi@eecs.umich.edu gelf_getshdr(section, &shdr); 3923804Ssaidi@eecs.umich.edu 3933804Ssaidi@eecs.umich.edu if (shdr.sh_type == SHT_SYMTAB) { 3943804Ssaidi@eecs.umich.edu found = true; 3954990Sgblack@eecs.umich.edu data = elf_getdata(section, NULL); 3963804Ssaidi@eecs.umich.edu count = shdr.sh_size / shdr.sh_entsize; 3973804Ssaidi@eecs.umich.edu DPRINTF(Loader, "Found Symbol Table, %d symbols present\n", count); 3983804Ssaidi@eecs.umich.edu 3993804Ssaidi@eecs.umich.edu // loop through all the symbols, only loading global ones 4003804Ssaidi@eecs.umich.edu for (ii = 0; ii < count; ++ii) { 4013804Ssaidi@eecs.umich.edu gelf_getsym(data, ii, &sym); 4023804Ssaidi@eecs.umich.edu if (GELF_ST_BIND(sym.st_info) == binding) { 4033804Ssaidi@eecs.umich.edu char *sym_name = elf_strptr(elf, shdr.sh_link, sym.st_name); 4043804Ssaidi@eecs.umich.edu if (sym_name && sym_name[0] != '$') { 4053804Ssaidi@eecs.umich.edu DPRINTF(Loader, "Symbol: %-40s value %#x\n", 4063804Ssaidi@eecs.umich.edu sym_name, sym.st_value); 4073804Ssaidi@eecs.umich.edu symtab->insert(sym.st_value & mask, sym_name); 4083804Ssaidi@eecs.umich.edu } 4093804Ssaidi@eecs.umich.edu } 4103804Ssaidi@eecs.umich.edu } 4113826Ssaidi@eecs.umich.edu } 4124990Sgblack@eecs.umich.edu ++sec_idx; 4133826Ssaidi@eecs.umich.edu section = elf_getscn(elf, sec_idx); 4143916Ssaidi@eecs.umich.edu } 4153916Ssaidi@eecs.umich.edu 4163916Ssaidi@eecs.umich.edu elf_end(elf); 4174990Sgblack@eecs.umich.edu 4183826Ssaidi@eecs.umich.edu return found; 4193804Ssaidi@eecs.umich.edu} 4203804Ssaidi@eecs.umich.edu 4214990Sgblack@eecs.umich.edubool 4223804Ssaidi@eecs.umich.eduElfObject::loadGlobalSymbols(SymbolTable *symtab, Addr addrMask) 4233811Ssaidi@eecs.umich.edu{ 4243811Ssaidi@eecs.umich.edu return loadSomeSymbols(symtab, STB_GLOBAL, addrMask); 4254990Sgblack@eecs.umich.edu} 4263804Ssaidi@eecs.umich.edu 4273804Ssaidi@eecs.umich.edubool 4283804Ssaidi@eecs.umich.eduElfObject::loadLocalSymbols(SymbolTable *symtab, Addr addrMask) 4294990Sgblack@eecs.umich.edu{ 4303804Ssaidi@eecs.umich.edu bool found_local = loadSomeSymbols(symtab, STB_LOCAL, addrMask); 4313804Ssaidi@eecs.umich.edu bool found_weak = loadSomeSymbols(symtab, STB_WEAK, addrMask); 4323811Ssaidi@eecs.umich.edu return found_local || found_weak; 4333811Ssaidi@eecs.umich.edu} 4344990Sgblack@eecs.umich.edu 4354990Sgblack@eecs.umich.edubool 4363804Ssaidi@eecs.umich.eduElfObject::loadWeakSymbols(SymbolTable *symtab, Addr addrMask) 4373804Ssaidi@eecs.umich.edu{ 4383804Ssaidi@eecs.umich.edu return loadSomeSymbols(symtab, STB_WEAK, addrMask); 4395894Sgblack@eecs.umich.edu} 4403804Ssaidi@eecs.umich.edu 4414172Ssaidi@eecs.umich.edubool 4423833Ssaidi@eecs.umich.eduElfObject::loadSections(PortProxy& memProxy, Addr addrMask, Addr offset) 4433836Ssaidi@eecs.umich.edu{ 4443836Ssaidi@eecs.umich.edu if (!ObjectFile::loadSections(memProxy, addrMask, offset)) 4453836Ssaidi@eecs.umich.edu return false; 4463836Ssaidi@eecs.umich.edu 4473836Ssaidi@eecs.umich.edu vector<Segment>::iterator extraIt; 4483836Ssaidi@eecs.umich.edu for (extraIt = extraSegments.begin(); 4493836Ssaidi@eecs.umich.edu extraIt != extraSegments.end(); extraIt++) { 4503836Ssaidi@eecs.umich.edu if (!loadSection(&(*extraIt), memProxy, addrMask, offset)) { 4513836Ssaidi@eecs.umich.edu return false; 4523836Ssaidi@eecs.umich.edu } 4533836Ssaidi@eecs.umich.edu } 4543836Ssaidi@eecs.umich.edu return true; 4553836Ssaidi@eecs.umich.edu} 4565555Snate@binkert.org 4575555Snate@binkert.orgvoid 4583836Ssaidi@eecs.umich.eduElfObject::getSections() 4593836Ssaidi@eecs.umich.edu{ 4603836Ssaidi@eecs.umich.edu Elf *elf; 4613836Ssaidi@eecs.umich.edu int sec_idx = 1; // there is a 0 but it is nothing, go figure 4623836Ssaidi@eecs.umich.edu Elf_Scn *section; 4633836Ssaidi@eecs.umich.edu GElf_Shdr shdr; 4643836Ssaidi@eecs.umich.edu 4653833Ssaidi@eecs.umich.edu GElf_Ehdr ehdr; 4663833Ssaidi@eecs.umich.edu 4673833Ssaidi@eecs.umich.edu assert(!sectionNames.size()); 4683833Ssaidi@eecs.umich.edu 4693833Ssaidi@eecs.umich.edu // check that header matches library version 4703833Ssaidi@eecs.umich.edu if (elf_version(EV_CURRENT) == EV_NONE) 4713833Ssaidi@eecs.umich.edu panic("wrong elf version number!"); 4723833Ssaidi@eecs.umich.edu 4733833Ssaidi@eecs.umich.edu // get a pointer to elf structure 4743804Ssaidi@eecs.umich.edu elf = elf_memory((char*)fileData,len); 4753804Ssaidi@eecs.umich.edu assert(elf != NULL); 4763804Ssaidi@eecs.umich.edu 4773804Ssaidi@eecs.umich.edu // Check that we actually have a elf file 4783804Ssaidi@eecs.umich.edu if (gelf_getehdr(elf, &ehdr) ==0) { 4793833Ssaidi@eecs.umich.edu panic("Not ELF, shouldn't be here"); 4803833Ssaidi@eecs.umich.edu } 4813811Ssaidi@eecs.umich.edu 4823804Ssaidi@eecs.umich.edu // Get the first section 4833804Ssaidi@eecs.umich.edu section = elf_getscn(elf, sec_idx); 4843804Ssaidi@eecs.umich.edu 4853804Ssaidi@eecs.umich.edu // While there are no more sections 4863804Ssaidi@eecs.umich.edu while (section != NULL) { 4873804Ssaidi@eecs.umich.edu gelf_getshdr(section, &shdr); 4883804Ssaidi@eecs.umich.edu sectionNames.insert(elf_strptr(elf, ehdr.e_shstrndx, shdr.sh_name)); 4893833Ssaidi@eecs.umich.edu section = elf_getscn(elf, ++sec_idx); 4903804Ssaidi@eecs.umich.edu } // while sections 4913804Ssaidi@eecs.umich.edu} 4923833Ssaidi@eecs.umich.edu 4933836Ssaidi@eecs.umich.edubool 4943836Ssaidi@eecs.umich.eduElfObject::sectionExists(string sec) 4953836Ssaidi@eecs.umich.edu{ 4963836Ssaidi@eecs.umich.edu if (!sectionNames.size()) 4973804Ssaidi@eecs.umich.edu getSections(); 4983804Ssaidi@eecs.umich.edu return sectionNames.find(sec) != sectionNames.end(); 4993804Ssaidi@eecs.umich.edu} 5003836Ssaidi@eecs.umich.edu 5013836Ssaidi@eecs.umich.edu 5024990Sgblack@eecs.umich.edu