elf_object.cc revision 11559
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 38611559Sandreas.sandberg@arm.com warn_if(text.size != 0, 38711559Sandreas.sandberg@arm.com "Empty .text segment in '%s'. ELF file corrupted?\n", 38811559Sandreas.sandberg@arm.com filename); 389468SN/A 390468SN/A DPRINTFR(Loader, "text: 0x%x %d\ndata: 0x%x %d\nbss: 0x%x %d\n", 391468SN/A text.baseAddr, text.size, data.baseAddr, data.size, 392468SN/A bss.baseAddr, bss.size); 393468SN/A 394443SN/A elf_end(elf); 395443SN/A 396468SN/A // We will actually read the sections when we need to load them 39712SN/A} 39812SN/A 39912SN/A 40012SN/Abool 40111392Sbrandon.potter@amd.comElfObject::loadSomeSymbols(SymbolTable *symtab, int binding, Addr mask, 40211392Sbrandon.potter@amd.com Addr base, Addr offset) 40312SN/A{ 404443SN/A if (!symtab) 405443SN/A return false; 406443SN/A 407468SN/A // check that header matches library version 4081708SN/A if (elf_version(EV_CURRENT) == EV_NONE) 4091708SN/A panic("wrong elf version number!"); 410443SN/A 411468SN/A // get a pointer to elf structure 41211391Sbrandon.potter@amd.com Elf *elf = elf_memory((char*)fileData,len); 413443SN/A assert(elf != NULL); 414443SN/A 415468SN/A // Get the first section 41611391Sbrandon.potter@amd.com int sec_idx = 1; // there is a 0 but it is nothing, go figure 41711391Sbrandon.potter@amd.com Elf_Scn *section = elf_getscn(elf, sec_idx); 418443SN/A 419468SN/A // While there are no more sections 42011391Sbrandon.potter@amd.com bool found = false; 421468SN/A while (section != NULL) { 42211391Sbrandon.potter@amd.com GElf_Shdr shdr; 423443SN/A gelf_getshdr(section, &shdr); 424443SN/A 425468SN/A if (shdr.sh_type == SHT_SYMTAB) { 426443SN/A found = true; 42711391Sbrandon.potter@amd.com Elf_Data *data = elf_getdata(section, NULL); 42811391Sbrandon.potter@amd.com int count = shdr.sh_size / shdr.sh_entsize; 429443SN/A DPRINTF(Loader, "Found Symbol Table, %d symbols present\n", count); 430443SN/A 431468SN/A // loop through all the symbols, only loading global ones 43211391Sbrandon.potter@amd.com for (int i = 0; i < count; ++i) { 43311391Sbrandon.potter@amd.com GElf_Sym sym; 43411391Sbrandon.potter@amd.com gelf_getsym(data, i, &sym); 435836SN/A if (GELF_ST_BIND(sym.st_info) == binding) { 4367589SAli.Saidi@arm.com char *sym_name = elf_strptr(elf, shdr.sh_link, sym.st_name); 4377589SAli.Saidi@arm.com if (sym_name && sym_name[0] != '$') { 43811392Sbrandon.potter@amd.com Addr value = sym.st_value - base + offset; 43911392Sbrandon.potter@amd.com if (symtab->insert(value & mask, sym_name)) { 44011392Sbrandon.potter@amd.com DPRINTF(Loader, "Symbol: %-40s value %#x\n", 44111392Sbrandon.potter@amd.com sym_name, value); 44211392Sbrandon.potter@amd.com } 4437589SAli.Saidi@arm.com } 444443SN/A } 445443SN/A } 446443SN/A } 447454SN/A ++sec_idx; 448454SN/A section = elf_getscn(elf, sec_idx); 449443SN/A } 450443SN/A 451443SN/A elf_end(elf); 452443SN/A 453443SN/A return found; 45412SN/A} 45512SN/A 45612SN/Abool 45711392Sbrandon.potter@amd.comElfObject::loadAllSymbols(SymbolTable *symtab, Addr base, Addr offset, 45811392Sbrandon.potter@amd.com Addr addr_mask) 459468SN/A{ 46011392Sbrandon.potter@amd.com return (loadGlobalSymbols(symtab, base, offset, addr_mask) && 46111392Sbrandon.potter@amd.com loadLocalSymbols(symtab, base, offset, addr_mask) && 46211392Sbrandon.potter@amd.com loadWeakSymbols(symtab, base, offset, addr_mask)); 463468SN/A} 464468SN/A 465468SN/Abool 46611392Sbrandon.potter@amd.comElfObject::loadGlobalSymbols(SymbolTable *symtab, Addr base, Addr offset, 46711392Sbrandon.potter@amd.com Addr addr_mask) 46812SN/A{ 46911392Sbrandon.potter@amd.com if (interpreter) { 47011392Sbrandon.potter@amd.com interpreter->loadSomeSymbols(symtab, STB_GLOBAL, addr_mask, 47111392Sbrandon.potter@amd.com base, offset); 47211392Sbrandon.potter@amd.com } 47311392Sbrandon.potter@amd.com return loadSomeSymbols(symtab, STB_GLOBAL, addr_mask, base, offset); 47412SN/A} 4753917Ssaidi@eecs.umich.edu 4765090Sgblack@eecs.umich.edubool 47711392Sbrandon.potter@amd.comElfObject::loadLocalSymbols(SymbolTable *symtab, Addr base, Addr offset, 47811392Sbrandon.potter@amd.com Addr addr_mask) 4799641Sguodeyuan@tsinghua.org.cn{ 48011392Sbrandon.potter@amd.com if (interpreter) { 48111392Sbrandon.potter@amd.com interpreter->loadSomeSymbols(symtab, STB_LOCAL, addr_mask, 48211392Sbrandon.potter@amd.com base, offset); 48311392Sbrandon.potter@amd.com } 48411392Sbrandon.potter@amd.com return loadSomeSymbols(symtab, STB_LOCAL, addr_mask, base, offset); 48511392Sbrandon.potter@amd.com} 48611392Sbrandon.potter@amd.com 48711392Sbrandon.potter@amd.combool 48811392Sbrandon.potter@amd.comElfObject::loadWeakSymbols(SymbolTable *symtab, Addr base, Addr offset, 48911392Sbrandon.potter@amd.com Addr addr_mask) 49011392Sbrandon.potter@amd.com{ 49111392Sbrandon.potter@amd.com if (interpreter) { 49211392Sbrandon.potter@amd.com interpreter->loadSomeSymbols(symtab, STB_WEAK, addr_mask, 49311392Sbrandon.potter@amd.com base, offset); 49411392Sbrandon.potter@amd.com } 49511392Sbrandon.potter@amd.com return loadSomeSymbols(symtab, STB_WEAK, addr_mask, base, offset); 4969641Sguodeyuan@tsinghua.org.cn} 4979641Sguodeyuan@tsinghua.org.cn 4989641Sguodeyuan@tsinghua.org.cnbool 49911391Sbrandon.potter@amd.comElfObject::loadSections(PortProxy& mem_proxy, Addr addr_mask, Addr offset) 5005090Sgblack@eecs.umich.edu{ 50111391Sbrandon.potter@amd.com if (!ObjectFile::loadSections(mem_proxy, addr_mask, offset)) 5025090Sgblack@eecs.umich.edu return false; 5035090Sgblack@eecs.umich.edu 50411391Sbrandon.potter@amd.com for (auto seg : extraSegments) { 50511391Sbrandon.potter@amd.com if (!loadSection(&seg, mem_proxy, addr_mask, offset)) { 5065090Sgblack@eecs.umich.edu return false; 5075090Sgblack@eecs.umich.edu } 5085090Sgblack@eecs.umich.edu } 50911389Sbrandon.potter@amd.com 51011389Sbrandon.potter@amd.com if (interpreter) 51111391Sbrandon.potter@amd.com interpreter->loadSections(mem_proxy, addr_mask, offset); 51211389Sbrandon.potter@amd.com 5135090Sgblack@eecs.umich.edu return true; 5145090Sgblack@eecs.umich.edu} 5155090Sgblack@eecs.umich.edu 5165070Ssaidi@eecs.umich.eduvoid 5175070Ssaidi@eecs.umich.eduElfObject::getSections() 5183917Ssaidi@eecs.umich.edu{ 5195070Ssaidi@eecs.umich.edu assert(!sectionNames.size()); 5205070Ssaidi@eecs.umich.edu 5213917Ssaidi@eecs.umich.edu // check that header matches library version 5223917Ssaidi@eecs.umich.edu if (elf_version(EV_CURRENT) == EV_NONE) 5233917Ssaidi@eecs.umich.edu panic("wrong elf version number!"); 5243917Ssaidi@eecs.umich.edu 5253917Ssaidi@eecs.umich.edu // get a pointer to elf structure 52611391Sbrandon.potter@amd.com Elf *elf = elf_memory((char*)fileData,len); 5273917Ssaidi@eecs.umich.edu assert(elf != NULL); 5283917Ssaidi@eecs.umich.edu 5293917Ssaidi@eecs.umich.edu // Check that we actually have a elf file 53011391Sbrandon.potter@amd.com GElf_Ehdr ehdr; 5313917Ssaidi@eecs.umich.edu if (gelf_getehdr(elf, &ehdr) ==0) { 5323917Ssaidi@eecs.umich.edu panic("Not ELF, shouldn't be here"); 5333917Ssaidi@eecs.umich.edu } 5343917Ssaidi@eecs.umich.edu 5353917Ssaidi@eecs.umich.edu // Get the first section 53611391Sbrandon.potter@amd.com int sec_idx = 1; // there is a 0 but it is nothing, go figure 53711391Sbrandon.potter@amd.com Elf_Scn *section = elf_getscn(elf, sec_idx); 5383917Ssaidi@eecs.umich.edu 5393917Ssaidi@eecs.umich.edu // While there are no more sections 54011391Sbrandon.potter@amd.com while (section) { 54111391Sbrandon.potter@amd.com GElf_Shdr shdr; 5423917Ssaidi@eecs.umich.edu gelf_getshdr(section, &shdr); 5435070Ssaidi@eecs.umich.edu sectionNames.insert(elf_strptr(elf, ehdr.e_shstrndx, shdr.sh_name)); 5443917Ssaidi@eecs.umich.edu section = elf_getscn(elf, ++sec_idx); 5453917Ssaidi@eecs.umich.edu } // while sections 5463917Ssaidi@eecs.umich.edu} 5473917Ssaidi@eecs.umich.edu 5485070Ssaidi@eecs.umich.edubool 54911391Sbrandon.potter@amd.comElfObject::sectionExists(std::string sec) 5505070Ssaidi@eecs.umich.edu{ 5515070Ssaidi@eecs.umich.edu if (!sectionNames.size()) 5525070Ssaidi@eecs.umich.edu getSections(); 55311391Sbrandon.potter@amd.com 5545070Ssaidi@eecs.umich.edu return sectionNames.find(sec) != sectionNames.end(); 5555070Ssaidi@eecs.umich.edu} 5563917Ssaidi@eecs.umich.edu 5575070Ssaidi@eecs.umich.edu 55811389Sbrandon.potter@amd.comvoid 55911389Sbrandon.potter@amd.comElfObject::updateBias(Addr bias_addr) 56011389Sbrandon.potter@amd.com{ 56111389Sbrandon.potter@amd.com // Record the bias. 56211389Sbrandon.potter@amd.com ldBias = bias_addr; 56311389Sbrandon.potter@amd.com 56411389Sbrandon.potter@amd.com // Patch the entry point with bias_addr. 56511389Sbrandon.potter@amd.com entry += bias_addr; 56611389Sbrandon.potter@amd.com 56711389Sbrandon.potter@amd.com // Patch segments with the bias_addr. 56811389Sbrandon.potter@amd.com text.baseAddr += bias_addr; 56911389Sbrandon.potter@amd.com data.baseAddr += bias_addr; 57011389Sbrandon.potter@amd.com bss.baseAddr += bias_addr; 57111389Sbrandon.potter@amd.com for (auto &segment : extraSegments) 57211389Sbrandon.potter@amd.com segment.baseAddr += bias_addr; 57311389Sbrandon.potter@amd.com} 574