elf_object.cc revision 11391
112SN/A/* 210037SARM gem5 Developers * Copyright (c) 2011-2013 ARM Limited 310037SARM gem5 Developers * All rights reserved 410037SARM gem5 Developers * 510037SARM gem5 Developers * The license below extends only to copyright in the software and shall 610037SARM gem5 Developers * not be construed as granting a license to any other intellectual 710037SARM gem5 Developers * property including but not limited to intellectual property relating 810037SARM gem5 Developers * to a hardware implementation of the functionality of the software 910037SARM gem5 Developers * licensed hereunder. You may use the software subject to the license 1010037SARM gem5 Developers * terms below provided that you ensure that this notice is replicated 1110037SARM gem5 Developers * unmodified and in its entirety in all distributions of the software, 1210037SARM gem5 Developers * modified or unmodified, in source code or in binary form. 1310037SARM gem5 Developers * 141762SN/A * Copyright (c) 2003-2005 The Regents of The University of Michigan 1512SN/A * All rights reserved. 1612SN/A * 1712SN/A * Redistribution and use in source and binary forms, with or without 1812SN/A * modification, are permitted provided that the following conditions are 1912SN/A * met: redistributions of source code must retain the above copyright 2012SN/A * notice, this list of conditions and the following disclaimer; 2112SN/A * redistributions in binary form must reproduce the above copyright 2212SN/A * notice, this list of conditions and the following disclaimer in the 2312SN/A * documentation and/or other materials provided with the distribution; 2412SN/A * neither the name of the copyright holders nor the names of its 2512SN/A * contributors may be used to endorse or promote products derived from 2612SN/A * this software without specific prior written permission. 2712SN/A * 2812SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 2912SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 3012SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 3112SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 3212SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 3312SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 3412SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 3512SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 3612SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 3712SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 3812SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 392665Ssaidi@eecs.umich.edu * 402665Ssaidi@eecs.umich.edu * Authors: Steve Reinhardt 412665Ssaidi@eecs.umich.edu * Ali Saidi 4212SN/A */ 4312SN/A 4411389Sbrandon.potter@amd.com#include "base/loader/elf_object.hh" 4511389Sbrandon.potter@amd.com 4611389Sbrandon.potter@amd.com#include <fcntl.h> 4711389Sbrandon.potter@amd.com#include <sys/mman.h> 4811389Sbrandon.potter@amd.com#include <sys/stat.h> 4911389Sbrandon.potter@amd.com#include <sys/types.h> 5011389Sbrandon.potter@amd.com#include <unistd.h> 5111389Sbrandon.potter@amd.com 525616Snate@binkert.org#include <cassert> 5312SN/A#include <string> 5412SN/A 5511389Sbrandon.potter@amd.com#include "base/bitfield.hh" 564484Sbinkertn@umich.edu#include "base/loader/symtab.hh" 572439SN/A#include "base/misc.hh" 587676Snate@binkert.org#include "base/trace.hh" 598232Snate@binkert.org#include "debug/Loader.hh" 6011389Sbrandon.potter@amd.com#include "gelf.h" 612423SN/A#include "sim/byteswap.hh" 622423SN/A 6312SN/AObjectFile * 6411391Sbrandon.potter@amd.comElfObject::tryFile(const std::string &fname, size_t len, uint8_t *data, 6511389Sbrandon.potter@amd.com bool skip_interp_check) 6612SN/A{ 67468SN/A // check that header matches library version 681708SN/A if (elf_version(EV_CURRENT) == EV_NONE) 691708SN/A panic("wrong elf version number!"); 70443SN/A 71468SN/A // get a pointer to elf structure 7211391Sbrandon.potter@amd.com // Check that we actually have a elf file 7311391Sbrandon.potter@amd.com Elf *elf = elf_memory((char*)data, len); 7411391Sbrandon.potter@amd.com assert(elf); 75443SN/A 7611391Sbrandon.potter@amd.com GElf_Ehdr ehdr; 7710037SARM gem5 Developers if (gelf_getehdr(elf, &ehdr) == 0) { 78443SN/A DPRINTFR(Loader, "Not ELF\n"); 79443SN/A elf_end(elf); 80443SN/A return NULL; 8111391Sbrandon.potter@amd.com } 8211391Sbrandon.potter@amd.com 8311391Sbrandon.potter@amd.com // Detect the architecture 8411391Sbrandon.potter@amd.com Arch arch = UnknownArch; 8511391Sbrandon.potter@amd.com if (ehdr.e_machine == EM_SPARC64 || 8611391Sbrandon.potter@amd.com (ehdr.e_machine == EM_SPARC && 8711391Sbrandon.potter@amd.com ehdr.e_ident[EI_CLASS] == ELFCLASS64) || 8811391Sbrandon.potter@amd.com ehdr.e_machine == EM_SPARCV9) { 8911391Sbrandon.potter@amd.com arch = SPARC64; 9011391Sbrandon.potter@amd.com } else if (ehdr.e_machine == EM_SPARC32PLUS || 9111391Sbrandon.potter@amd.com (ehdr.e_machine == EM_SPARC && 9211391Sbrandon.potter@amd.com ehdr.e_ident[EI_CLASS] == ELFCLASS32)) { 9311391Sbrandon.potter@amd.com arch = SPARC32; 9411391Sbrandon.potter@amd.com } else if (ehdr.e_machine == EM_MIPS && 9511391Sbrandon.potter@amd.com ehdr.e_ident[EI_CLASS] == ELFCLASS32) { 9611391Sbrandon.potter@amd.com arch = Mips; 9711391Sbrandon.potter@amd.com if (ehdr.e_ident[EI_DATA] != ELFDATA2LSB) { 9811391Sbrandon.potter@amd.com fatal("The binary you're trying to load is compiled for big " 9911391Sbrandon.potter@amd.com "endian MIPS. gem5\nonly supports little endian MIPS. " 10011391Sbrandon.potter@amd.com "Please recompile your binary.\n"); 10111391Sbrandon.potter@amd.com } 10211391Sbrandon.potter@amd.com } else if (ehdr.e_machine == EM_X86_64 && 10311391Sbrandon.potter@amd.com ehdr.e_ident[EI_CLASS] == ELFCLASS64) { 10411391Sbrandon.potter@amd.com arch = X86_64; 10511391Sbrandon.potter@amd.com } else if (ehdr.e_machine == EM_386 && 10611391Sbrandon.potter@amd.com ehdr.e_ident[EI_CLASS] == ELFCLASS32) { 10711391Sbrandon.potter@amd.com arch = I386; 10811391Sbrandon.potter@amd.com } else if (ehdr.e_machine == EM_ARM && 10911391Sbrandon.potter@amd.com ehdr.e_ident[EI_CLASS] == ELFCLASS32) { 11011391Sbrandon.potter@amd.com arch = bits(ehdr.e_entry, 0) ? Thumb : Arm; 11111391Sbrandon.potter@amd.com } else if (ehdr.e_machine == EM_AARCH64 && 11211391Sbrandon.potter@amd.com ehdr.e_ident[EI_CLASS] == ELFCLASS64) { 11311391Sbrandon.potter@amd.com arch = Arm64; 11411391Sbrandon.potter@amd.com } else if (ehdr.e_machine == EM_PPC && 11511391Sbrandon.potter@amd.com ehdr.e_ident[EI_CLASS] == ELFCLASS32) { 11611391Sbrandon.potter@amd.com arch = Power; 11711391Sbrandon.potter@amd.com if (ehdr.e_ident[EI_DATA] != ELFDATA2MSB) { 11811391Sbrandon.potter@amd.com fatal("The binary you're trying to load is compiled for " 11911391Sbrandon.potter@amd.com "little endian Power.\ngem5 only supports big " 12011391Sbrandon.potter@amd.com "endian Power. Please recompile your binary.\n"); 12111391Sbrandon.potter@amd.com } 12211391Sbrandon.potter@amd.com } else if (ehdr.e_machine == EM_PPC64) { 12311391Sbrandon.potter@amd.com fatal("The binary you're trying to load is compiled for 64-bit " 12411391Sbrandon.potter@amd.com "Power. M5\n only supports 32-bit Power. Please " 12511391Sbrandon.potter@amd.com "recompile your binary.\n"); 12611391Sbrandon.potter@amd.com } else if (ehdr.e_ident[EI_CLASS] == ELFCLASS64) { 12711391Sbrandon.potter@amd.com // Since we don't know how to check for alpha right now, we'll 12811391Sbrandon.potter@amd.com // just assume if it wasn't something else and it's 64 bit, that's 12911391Sbrandon.potter@amd.com // what it must be. 13011391Sbrandon.potter@amd.com arch = Alpha; 1312476SN/A } else { 13211391Sbrandon.potter@amd.com warn("Unknown architecture: %d\n", ehdr.e_machine); 13311391Sbrandon.potter@amd.com arch = UnknownArch; 13411391Sbrandon.potter@amd.com } 1352207SN/A 13611391Sbrandon.potter@amd.com // Detect the operating system 13711391Sbrandon.potter@amd.com OpSys op_sys; 13811391Sbrandon.potter@amd.com switch (ehdr.e_ident[EI_OSABI]) { 13911391Sbrandon.potter@amd.com case ELFOSABI_LINUX: 14011391Sbrandon.potter@amd.com op_sys = Linux; 14111391Sbrandon.potter@amd.com break; 14211391Sbrandon.potter@amd.com case ELFOSABI_SOLARIS: 14311391Sbrandon.potter@amd.com op_sys = Solaris; 14411391Sbrandon.potter@amd.com break; 14511391Sbrandon.potter@amd.com case ELFOSABI_TRU64: 14611391Sbrandon.potter@amd.com op_sys = Tru64; 14711391Sbrandon.potter@amd.com break; 14811391Sbrandon.potter@amd.com case ELFOSABI_ARM: 14911391Sbrandon.potter@amd.com op_sys = LinuxArmOABI; 15011391Sbrandon.potter@amd.com break; 15111391Sbrandon.potter@amd.com case ELFOSABI_FREEBSD: 15211391Sbrandon.potter@amd.com op_sys = FreeBSD; 15311391Sbrandon.potter@amd.com break; 15411391Sbrandon.potter@amd.com default: 15511391Sbrandon.potter@amd.com op_sys = UnknownOpSys; 15611391Sbrandon.potter@amd.com } 1572207SN/A 15811391Sbrandon.potter@amd.com // Take a look at the .note.ABI section. 15911391Sbrandon.potter@amd.com // It can let us know what's what. 16011391Sbrandon.potter@amd.com if (op_sys == UnknownOpSys) { 16111391Sbrandon.potter@amd.com int sec_idx = 1; 16211391Sbrandon.potter@amd.com 16311391Sbrandon.potter@amd.com // Get the first section 16411391Sbrandon.potter@amd.com Elf_Scn *section = elf_getscn(elf, sec_idx); 16511391Sbrandon.potter@amd.com 16611391Sbrandon.potter@amd.com // While there are no more sections 16711391Sbrandon.potter@amd.com while (section && op_sys == UnknownOpSys) { 1682238SN/A GElf_Shdr shdr; 16911391Sbrandon.potter@amd.com gelf_getshdr(section, &shdr); 1702238SN/A 17111391Sbrandon.potter@amd.com char *e_str = elf_strptr(elf, ehdr.e_shstrndx, shdr.sh_name); 17211391Sbrandon.potter@amd.com if (shdr.sh_type == SHT_NOTE && 17311391Sbrandon.potter@amd.com !strcmp(".note.ABI-tag", e_str)) { 17411391Sbrandon.potter@amd.com // we have found a ABI note section 17511391Sbrandon.potter@amd.com // Check the 5th 32bit word for OS 0 == linux, 1 == hurd, 17611391Sbrandon.potter@amd.com // 2 == solaris, 3 == freebsd 17711391Sbrandon.potter@amd.com Elf_Data *raw_data = elf_rawdata(section, NULL); 17811391Sbrandon.potter@amd.com assert(raw_data && raw_data->d_buf); 1792238SN/A 18011391Sbrandon.potter@amd.com uint32_t raw_abi = ((uint32_t*)raw_data->d_buf)[4]; 18111391Sbrandon.potter@amd.com bool is_le = ehdr.e_ident[EI_DATA] == ELFDATA2LSB; 18211391Sbrandon.potter@amd.com uint32_t os_abi = is_le ? htole(raw_abi) : htobe(raw_abi); 1832238SN/A 18411391Sbrandon.potter@amd.com switch (os_abi) { 18511391Sbrandon.potter@amd.com case 0: 18611391Sbrandon.potter@amd.com op_sys = Linux; 18711391Sbrandon.potter@amd.com break; 18811391Sbrandon.potter@amd.com case 1: 18911391Sbrandon.potter@amd.com fatal("gem5 does not support the HURD ABI.\n"); 19011391Sbrandon.potter@amd.com case 2: 19111391Sbrandon.potter@amd.com op_sys = Solaris; 19211391Sbrandon.potter@amd.com break; 19311391Sbrandon.potter@amd.com case 3: 19411391Sbrandon.potter@amd.com op_sys = FreeBSD; 1952976Sgblack@eecs.umich.edu break; 1962976Sgblack@eecs.umich.edu } 19711391Sbrandon.potter@amd.com } // if section found 1982976Sgblack@eecs.umich.edu 19911391Sbrandon.potter@amd.com if (!strcmp(".SUNW_version", e_str) || 20011391Sbrandon.potter@amd.com !strcmp(".stab.index", e_str)) 20111391Sbrandon.potter@amd.com op_sys = Solaris; 2022976Sgblack@eecs.umich.edu 20311391Sbrandon.potter@amd.com section = elf_getscn(elf, ++sec_idx); 20411391Sbrandon.potter@amd.com } // while sections 20511391Sbrandon.potter@amd.com } 20611389Sbrandon.potter@amd.com 20711391Sbrandon.potter@amd.com ElfObject * result = new ElfObject(fname, len, data, arch, op_sys); 20811389Sbrandon.potter@amd.com 20911391Sbrandon.potter@amd.com // The number of headers in the file 21011391Sbrandon.potter@amd.com result->_programHeaderCount = ehdr.e_phnum; 21111391Sbrandon.potter@amd.com // Record the size of each entry 21211391Sbrandon.potter@amd.com result->_programHeaderSize = ehdr.e_phentsize; 21311391Sbrandon.potter@amd.com result->_programHeaderTable = 0; 21411391Sbrandon.potter@amd.com if (result->_programHeaderCount) { // If there is a program header table 21511391Sbrandon.potter@amd.com // Figure out the virtual address of the header table in the 21611391Sbrandon.potter@amd.com // final memory image. We use the program headers themselves 21711391Sbrandon.potter@amd.com // to translate from a file offset to the address in the image. 21811391Sbrandon.potter@amd.com GElf_Phdr phdr; 21911391Sbrandon.potter@amd.com uint64_t e_phoff = ehdr.e_phoff; 22011389Sbrandon.potter@amd.com 22111391Sbrandon.potter@amd.com for (int i = 0; i < result->_programHeaderCount; i++) { 22211391Sbrandon.potter@amd.com gelf_getphdr(elf, i, &phdr); 22311391Sbrandon.potter@amd.com // Check if we've found the segment with the headers in it 22411391Sbrandon.potter@amd.com if (phdr.p_offset <= e_phoff && 22511391Sbrandon.potter@amd.com phdr.p_offset + phdr.p_filesz > e_phoff) { 22611391Sbrandon.potter@amd.com result->_programHeaderTable = 22711391Sbrandon.potter@amd.com phdr.p_paddr + (e_phoff - phdr.p_offset); 22811389Sbrandon.potter@amd.com break; 22911389Sbrandon.potter@amd.com } 23011389Sbrandon.potter@amd.com } 23111391Sbrandon.potter@amd.com } 23211389Sbrandon.potter@amd.com 23311391Sbrandon.potter@amd.com if (!skip_interp_check) { 23411391Sbrandon.potter@amd.com for (int i = 0; i < ehdr.e_phnum; i++) { 23511391Sbrandon.potter@amd.com GElf_Phdr phdr; 23611391Sbrandon.potter@amd.com M5_VAR_USED void *check_p = gelf_getphdr(elf, i, &phdr); 23711391Sbrandon.potter@amd.com assert(check_p != nullptr); 23811391Sbrandon.potter@amd.com 23911391Sbrandon.potter@amd.com if (phdr.p_type != PT_INTERP) 24011391Sbrandon.potter@amd.com continue; 24111391Sbrandon.potter@amd.com 24211391Sbrandon.potter@amd.com char *interp_path = (char*)data + phdr.p_offset; 24311391Sbrandon.potter@amd.com int fd = open(interp_path, O_RDONLY); 24411391Sbrandon.potter@amd.com if (fd == -1) 24511391Sbrandon.potter@amd.com fatal("Unable to open dynamic executable's interpreter.\n"); 24611391Sbrandon.potter@amd.com 24711391Sbrandon.potter@amd.com struct stat sb; 24811391Sbrandon.potter@amd.com M5_VAR_USED int check_i = fstat(fd, &sb); 24911391Sbrandon.potter@amd.com assert(check_i == 0); 25011391Sbrandon.potter@amd.com 25111391Sbrandon.potter@amd.com void *mm = mmap(nullptr, sb.st_size, PROT_READ, 25211391Sbrandon.potter@amd.com MAP_PRIVATE, fd, 0); 25311391Sbrandon.potter@amd.com assert(mm != MAP_FAILED); 25411391Sbrandon.potter@amd.com close(fd); 25511391Sbrandon.potter@amd.com 25611391Sbrandon.potter@amd.com uint8_t *interp_image = (uint8_t*)mm; 25711391Sbrandon.potter@amd.com ObjectFile *obj = tryFile(interp_path, sb.st_size, 25811391Sbrandon.potter@amd.com interp_image, true); 25911391Sbrandon.potter@amd.com assert(obj != nullptr); 26011391Sbrandon.potter@amd.com result->interpreter = dynamic_cast<ElfObject*>(obj); 26111391Sbrandon.potter@amd.com assert(result->interpreter != nullptr); 26211391Sbrandon.potter@amd.com break; 26311391Sbrandon.potter@amd.com } 26412SN/A } 26511391Sbrandon.potter@amd.com 26611391Sbrandon.potter@amd.com elf_end(elf); 26711391Sbrandon.potter@amd.com return result; 26812SN/A} 26912SN/A 27011391Sbrandon.potter@amd.comElfObject::ElfObject(const std::string &_filename, size_t _len, 27111391Sbrandon.potter@amd.com uint8_t *_data, Arch _arch, OpSys _op_sys) 27211391Sbrandon.potter@amd.com : ObjectFile(_filename, _len, _data, _arch, _op_sys), 27311389Sbrandon.potter@amd.com _programHeaderTable(0), _programHeaderSize(0), _programHeaderCount(0), 27411389Sbrandon.potter@amd.com interpreter(nullptr), ldBias(0), relocate(true), 27511389Sbrandon.potter@amd.com ldMin(std::numeric_limits<Addr>::max()), 27611389Sbrandon.potter@amd.com ldMax(std::numeric_limits<Addr>::min()) 27712SN/A{ 278468SN/A // check that header matches library version 2791708SN/A if (elf_version(EV_CURRENT) == EV_NONE) 2801708SN/A panic("wrong elf version number!"); 28112SN/A 282468SN/A // get a pointer to elf structure 28311391Sbrandon.potter@amd.com Elf *elf = elf_memory((char*)fileData,len); 28411391Sbrandon.potter@amd.com assert(elf); 28512SN/A 286468SN/A // Check that we actually have a elf file 28711391Sbrandon.potter@amd.com GElf_Ehdr ehdr; 288468SN/A if (gelf_getehdr(elf, &ehdr) ==0) { 289443SN/A panic("Not ELF, shouldn't be here"); 29012SN/A } 29112SN/A 292468SN/A entry = ehdr.e_entry; 29312SN/A 294468SN/A // initialize segment sizes to 0 in case they're not present 295468SN/A text.size = data.size = bss.size = 0; 2969186SAli.Saidi@ARM.com text.baseAddr = data.baseAddr = bss.baseAddr = 0; 297468SN/A 29811391Sbrandon.potter@amd.com int sec_idx = 1; 2995090Sgblack@eecs.umich.edu 3005090Sgblack@eecs.umich.edu // The first address of some important sections. 30111391Sbrandon.potter@amd.com Addr text_sec_start = 0; 30211391Sbrandon.potter@amd.com Addr data_sec_start = 0; 30311391Sbrandon.potter@amd.com Addr bss_sec_start = 0; 3045090Sgblack@eecs.umich.edu 3055090Sgblack@eecs.umich.edu // Get the first section 30611391Sbrandon.potter@amd.com Elf_Scn *section = elf_getscn(elf, sec_idx); 3075090Sgblack@eecs.umich.edu 3085090Sgblack@eecs.umich.edu // Find the beginning of the most interesting sections. 30911391Sbrandon.potter@amd.com while (section) { 31011391Sbrandon.potter@amd.com GElf_Shdr shdr; 3115090Sgblack@eecs.umich.edu gelf_getshdr(section, &shdr); 31211391Sbrandon.potter@amd.com char *sec_name = elf_strptr(elf, ehdr.e_shstrndx, shdr.sh_name); 3135090Sgblack@eecs.umich.edu 31411391Sbrandon.potter@amd.com if (sec_name) { 31511391Sbrandon.potter@amd.com if (!strcmp(".text", sec_name)) { 31611391Sbrandon.potter@amd.com text_sec_start = shdr.sh_addr; 31711391Sbrandon.potter@amd.com } else if (!strcmp(".data", sec_name)) { 31811391Sbrandon.potter@amd.com data_sec_start = shdr.sh_addr; 31911391Sbrandon.potter@amd.com } else if (!strcmp(".bss", sec_name)) { 32011391Sbrandon.potter@amd.com bss_sec_start = shdr.sh_addr; 3218350Sgblack@eecs.umich.edu } 3228350Sgblack@eecs.umich.edu } else { 3238350Sgblack@eecs.umich.edu Elf_Error errorNum = (Elf_Error)elf_errno(); 3248350Sgblack@eecs.umich.edu if (errorNum != ELF_E_NONE) { 3258350Sgblack@eecs.umich.edu const char *errorMessage = elf_errmsg(errorNum); 3268350Sgblack@eecs.umich.edu fatal("Error from libelf: %s.\n", errorMessage); 3278350Sgblack@eecs.umich.edu } 3285090Sgblack@eecs.umich.edu } 3295090Sgblack@eecs.umich.edu 33011391Sbrandon.potter@amd.com section = elf_getscn(elf, ++sec_idx); 3315090Sgblack@eecs.umich.edu } 3325090Sgblack@eecs.umich.edu 3335090Sgblack@eecs.umich.edu // Go through all the segments in the program, record them, and scrape 3345090Sgblack@eecs.umich.edu // out information about the text, data, and bss areas needed by other 3355090Sgblack@eecs.umich.edu // code. 336468SN/A for (int i = 0; i < ehdr.e_phnum; ++i) { 337468SN/A GElf_Phdr phdr; 338468SN/A if (gelf_getphdr(elf, i, &phdr) == 0) { 3395090Sgblack@eecs.umich.edu panic("gelf_getphdr failed for segment %d.", i); 340468SN/A } 341468SN/A 342468SN/A // for now we don't care about non-loadable segments 343468SN/A if (!(phdr.p_type & PT_LOAD)) 344468SN/A continue; 345468SN/A 34611389Sbrandon.potter@amd.com ldMin = std::min(ldMin, phdr.p_vaddr); 34711389Sbrandon.potter@amd.com ldMax = std::max(ldMax, phdr.p_vaddr + phdr.p_memsz); 34811389Sbrandon.potter@amd.com 3495090Sgblack@eecs.umich.edu // Check to see if this segment contains the bss section. 35011391Sbrandon.potter@amd.com if (phdr.p_paddr <= bss_sec_start && 35111391Sbrandon.potter@amd.com phdr.p_paddr + phdr.p_memsz > bss_sec_start && 35211391Sbrandon.potter@amd.com phdr.p_memsz - phdr.p_filesz > 0) { 3535143Sgblack@eecs.umich.edu bss.baseAddr = phdr.p_paddr + phdr.p_filesz; 3545090Sgblack@eecs.umich.edu bss.size = phdr.p_memsz - phdr.p_filesz; 3555090Sgblack@eecs.umich.edu bss.fileImage = NULL; 3565090Sgblack@eecs.umich.edu } 3575090Sgblack@eecs.umich.edu 3585090Sgblack@eecs.umich.edu // Check to see if this is the text or data segment 35911391Sbrandon.potter@amd.com if (phdr.p_vaddr <= text_sec_start && 36011391Sbrandon.potter@amd.com phdr.p_vaddr + phdr.p_filesz > text_sec_start) { 36111389Sbrandon.potter@amd.com 36211389Sbrandon.potter@amd.com // If this value is nonzero, we need to flip the relocate flag. 36311389Sbrandon.potter@amd.com if (phdr.p_vaddr != 0) 36411389Sbrandon.potter@amd.com relocate = false; 36511389Sbrandon.potter@amd.com 3665143Sgblack@eecs.umich.edu text.baseAddr = phdr.p_paddr; 367468SN/A text.size = phdr.p_filesz; 3682420SN/A text.fileImage = fileData + phdr.p_offset; 36911391Sbrandon.potter@amd.com } else if (phdr.p_vaddr <= data_sec_start && 37011391Sbrandon.potter@amd.com phdr.p_vaddr + phdr.p_filesz > data_sec_start) { 3715143Sgblack@eecs.umich.edu data.baseAddr = phdr.p_paddr; 372468SN/A data.size = phdr.p_filesz; 3732420SN/A data.fileImage = fileData + phdr.p_offset; 3742476SN/A } else { 37511320Ssteve.reinhardt@amd.com // If it's none of the above but is loadable, 3765759Shsul@eecs.umich.edu // load the filesize worth of data 3775090Sgblack@eecs.umich.edu Segment extra; 3785143Sgblack@eecs.umich.edu extra.baseAddr = phdr.p_paddr; 3795090Sgblack@eecs.umich.edu extra.size = phdr.p_filesz; 3805090Sgblack@eecs.umich.edu extra.fileImage = fileData + phdr.p_offset; 3815090Sgblack@eecs.umich.edu extraSegments.push_back(extra); 382468SN/A } 383468SN/A } 384468SN/A 385468SN/A // should have found at least one loadable segment 386468SN/A assert(text.size != 0); 387468SN/A 388468SN/A DPRINTFR(Loader, "text: 0x%x %d\ndata: 0x%x %d\nbss: 0x%x %d\n", 389468SN/A text.baseAddr, text.size, data.baseAddr, data.size, 390468SN/A bss.baseAddr, bss.size); 391468SN/A 392443SN/A elf_end(elf); 393443SN/A 394468SN/A // We will actually read the sections when we need to load them 39512SN/A} 39612SN/A 39712SN/A 39812SN/Abool 3997581SAli.Saidi@arm.comElfObject::loadSomeSymbols(SymbolTable *symtab, int binding, Addr mask) 40012SN/A{ 401443SN/A if (!symtab) 402443SN/A return false; 403443SN/A 404468SN/A // check that header matches library version 4051708SN/A if (elf_version(EV_CURRENT) == EV_NONE) 4061708SN/A panic("wrong elf version number!"); 407443SN/A 408468SN/A // get a pointer to elf structure 40911391Sbrandon.potter@amd.com Elf *elf = elf_memory((char*)fileData,len); 410443SN/A assert(elf != NULL); 411443SN/A 412468SN/A // Get the first section 41311391Sbrandon.potter@amd.com int sec_idx = 1; // there is a 0 but it is nothing, go figure 41411391Sbrandon.potter@amd.com Elf_Scn *section = elf_getscn(elf, sec_idx); 415443SN/A 416468SN/A // While there are no more sections 41711391Sbrandon.potter@amd.com bool found = false; 418468SN/A while (section != NULL) { 41911391Sbrandon.potter@amd.com GElf_Shdr shdr; 420443SN/A gelf_getshdr(section, &shdr); 421443SN/A 422468SN/A if (shdr.sh_type == SHT_SYMTAB) { 423443SN/A found = true; 42411391Sbrandon.potter@amd.com Elf_Data *data = elf_getdata(section, NULL); 42511391Sbrandon.potter@amd.com int count = shdr.sh_size / shdr.sh_entsize; 426443SN/A DPRINTF(Loader, "Found Symbol Table, %d symbols present\n", count); 427443SN/A 428468SN/A // loop through all the symbols, only loading global ones 42911391Sbrandon.potter@amd.com for (int i = 0; i < count; ++i) { 43011391Sbrandon.potter@amd.com GElf_Sym sym; 43111391Sbrandon.potter@amd.com gelf_getsym(data, i, &sym); 432836SN/A if (GELF_ST_BIND(sym.st_info) == binding) { 4337589SAli.Saidi@arm.com char *sym_name = elf_strptr(elf, shdr.sh_link, sym.st_name); 4347589SAli.Saidi@arm.com if (sym_name && sym_name[0] != '$') { 4357589SAli.Saidi@arm.com DPRINTF(Loader, "Symbol: %-40s value %#x\n", 4367589SAli.Saidi@arm.com sym_name, sym.st_value); 4377589SAli.Saidi@arm.com symtab->insert(sym.st_value & mask, sym_name); 4387589SAli.Saidi@arm.com } 439443SN/A } 440443SN/A } 441443SN/A } 442454SN/A ++sec_idx; 443454SN/A section = elf_getscn(elf, sec_idx); 444443SN/A } 445443SN/A 446443SN/A elf_end(elf); 447443SN/A 448443SN/A return found; 44912SN/A} 45012SN/A 45112SN/Abool 45211391Sbrandon.potter@amd.comElfObject::loadGlobalSymbols(SymbolTable *symtab, Addr addr_mask) 453468SN/A{ 45411391Sbrandon.potter@amd.com return loadSomeSymbols(symtab, STB_GLOBAL, addr_mask); 455468SN/A} 456468SN/A 457468SN/Abool 45811391Sbrandon.potter@amd.comElfObject::loadLocalSymbols(SymbolTable *symtab, Addr addr_mask) 45912SN/A{ 46011391Sbrandon.potter@amd.com bool found_local = loadSomeSymbols(symtab, STB_LOCAL, addr_mask); 46111391Sbrandon.potter@amd.com bool found_weak = loadSomeSymbols(symtab, STB_WEAK, addr_mask); 4629810Sguodeyuan@tsinghua.org.cn return found_local || found_weak; 46312SN/A} 4643917Ssaidi@eecs.umich.edu 4655090Sgblack@eecs.umich.edubool 46611391Sbrandon.potter@amd.comElfObject::loadWeakSymbols(SymbolTable *symtab, Addr addr_mask) 4679641Sguodeyuan@tsinghua.org.cn{ 46811391Sbrandon.potter@amd.com return loadSomeSymbols(symtab, STB_WEAK, addr_mask); 4699641Sguodeyuan@tsinghua.org.cn} 4709641Sguodeyuan@tsinghua.org.cn 4719641Sguodeyuan@tsinghua.org.cnbool 47211391Sbrandon.potter@amd.comElfObject::loadSections(PortProxy& mem_proxy, Addr addr_mask, Addr offset) 4735090Sgblack@eecs.umich.edu{ 47411391Sbrandon.potter@amd.com if (!ObjectFile::loadSections(mem_proxy, addr_mask, offset)) 4755090Sgblack@eecs.umich.edu return false; 4765090Sgblack@eecs.umich.edu 47711391Sbrandon.potter@amd.com for (auto seg : extraSegments) { 47811391Sbrandon.potter@amd.com if (!loadSection(&seg, mem_proxy, addr_mask, offset)) { 4795090Sgblack@eecs.umich.edu return false; 4805090Sgblack@eecs.umich.edu } 4815090Sgblack@eecs.umich.edu } 48211389Sbrandon.potter@amd.com 48311389Sbrandon.potter@amd.com if (interpreter) 48411391Sbrandon.potter@amd.com interpreter->loadSections(mem_proxy, addr_mask, offset); 48511389Sbrandon.potter@amd.com 4865090Sgblack@eecs.umich.edu return true; 4875090Sgblack@eecs.umich.edu} 4885090Sgblack@eecs.umich.edu 4895070Ssaidi@eecs.umich.eduvoid 4905070Ssaidi@eecs.umich.eduElfObject::getSections() 4913917Ssaidi@eecs.umich.edu{ 4925070Ssaidi@eecs.umich.edu assert(!sectionNames.size()); 4935070Ssaidi@eecs.umich.edu 4943917Ssaidi@eecs.umich.edu // check that header matches library version 4953917Ssaidi@eecs.umich.edu if (elf_version(EV_CURRENT) == EV_NONE) 4963917Ssaidi@eecs.umich.edu panic("wrong elf version number!"); 4973917Ssaidi@eecs.umich.edu 4983917Ssaidi@eecs.umich.edu // get a pointer to elf structure 49911391Sbrandon.potter@amd.com Elf *elf = elf_memory((char*)fileData,len); 5003917Ssaidi@eecs.umich.edu assert(elf != NULL); 5013917Ssaidi@eecs.umich.edu 5023917Ssaidi@eecs.umich.edu // Check that we actually have a elf file 50311391Sbrandon.potter@amd.com GElf_Ehdr ehdr; 5043917Ssaidi@eecs.umich.edu if (gelf_getehdr(elf, &ehdr) ==0) { 5053917Ssaidi@eecs.umich.edu panic("Not ELF, shouldn't be here"); 5063917Ssaidi@eecs.umich.edu } 5073917Ssaidi@eecs.umich.edu 5083917Ssaidi@eecs.umich.edu // Get the first section 50911391Sbrandon.potter@amd.com int sec_idx = 1; // there is a 0 but it is nothing, go figure 51011391Sbrandon.potter@amd.com Elf_Scn *section = elf_getscn(elf, sec_idx); 5113917Ssaidi@eecs.umich.edu 5123917Ssaidi@eecs.umich.edu // While there are no more sections 51311391Sbrandon.potter@amd.com while (section) { 51411391Sbrandon.potter@amd.com GElf_Shdr shdr; 5153917Ssaidi@eecs.umich.edu gelf_getshdr(section, &shdr); 5165070Ssaidi@eecs.umich.edu sectionNames.insert(elf_strptr(elf, ehdr.e_shstrndx, shdr.sh_name)); 5173917Ssaidi@eecs.umich.edu section = elf_getscn(elf, ++sec_idx); 5183917Ssaidi@eecs.umich.edu } // while sections 5193917Ssaidi@eecs.umich.edu} 5203917Ssaidi@eecs.umich.edu 5215070Ssaidi@eecs.umich.edubool 52211391Sbrandon.potter@amd.comElfObject::sectionExists(std::string sec) 5235070Ssaidi@eecs.umich.edu{ 5245070Ssaidi@eecs.umich.edu if (!sectionNames.size()) 5255070Ssaidi@eecs.umich.edu getSections(); 52611391Sbrandon.potter@amd.com 5275070Ssaidi@eecs.umich.edu return sectionNames.find(sec) != sectionNames.end(); 5285070Ssaidi@eecs.umich.edu} 5293917Ssaidi@eecs.umich.edu 5305070Ssaidi@eecs.umich.edu 53111389Sbrandon.potter@amd.comvoid 53211389Sbrandon.potter@amd.comElfObject::updateBias(Addr bias_addr) 53311389Sbrandon.potter@amd.com{ 53411389Sbrandon.potter@amd.com // Record the bias. 53511389Sbrandon.potter@amd.com ldBias = bias_addr; 53611389Sbrandon.potter@amd.com 53711389Sbrandon.potter@amd.com // Patch the entry point with bias_addr. 53811389Sbrandon.potter@amd.com entry += bias_addr; 53911389Sbrandon.potter@amd.com 54011389Sbrandon.potter@amd.com // Patch segments with the bias_addr. 54111389Sbrandon.potter@amd.com text.baseAddr += bias_addr; 54211389Sbrandon.potter@amd.com data.baseAddr += bias_addr; 54311389Sbrandon.potter@amd.com bss.baseAddr += bias_addr; 54411389Sbrandon.potter@amd.com for (auto &segment : extraSegments) 54511389Sbrandon.potter@amd.com segment.baseAddr += bias_addr; 54611389Sbrandon.potter@amd.com} 547