elf_object.cc revision 11873
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; 11411723Sar4jc@virginia.edu } else if (ehdr.e_machine == EM_RISCV) { 11511723Sar4jc@virginia.edu arch = Riscv; 11611391Sbrandon.potter@amd.com } else if (ehdr.e_machine == EM_PPC && 11711391Sbrandon.potter@amd.com ehdr.e_ident[EI_CLASS] == ELFCLASS32) { 11811391Sbrandon.potter@amd.com arch = Power; 11911391Sbrandon.potter@amd.com if (ehdr.e_ident[EI_DATA] != ELFDATA2MSB) { 12011391Sbrandon.potter@amd.com fatal("The binary you're trying to load is compiled for " 12111391Sbrandon.potter@amd.com "little endian Power.\ngem5 only supports big " 12211391Sbrandon.potter@amd.com "endian Power. Please recompile your binary.\n"); 12311391Sbrandon.potter@amd.com } 12411391Sbrandon.potter@amd.com } else if (ehdr.e_machine == EM_PPC64) { 12511391Sbrandon.potter@amd.com fatal("The binary you're trying to load is compiled for 64-bit " 12611391Sbrandon.potter@amd.com "Power. M5\n only supports 32-bit Power. Please " 12711391Sbrandon.potter@amd.com "recompile your binary.\n"); 12811391Sbrandon.potter@amd.com } else if (ehdr.e_ident[EI_CLASS] == ELFCLASS64) { 12911391Sbrandon.potter@amd.com // Since we don't know how to check for alpha right now, we'll 13011391Sbrandon.potter@amd.com // just assume if it wasn't something else and it's 64 bit, that's 13111391Sbrandon.potter@amd.com // what it must be. 13211391Sbrandon.potter@amd.com arch = Alpha; 1332476SN/A } else { 13411391Sbrandon.potter@amd.com warn("Unknown architecture: %d\n", ehdr.e_machine); 13511391Sbrandon.potter@amd.com arch = UnknownArch; 13611391Sbrandon.potter@amd.com } 1372207SN/A 13811391Sbrandon.potter@amd.com // Detect the operating system 13911391Sbrandon.potter@amd.com OpSys op_sys; 14011391Sbrandon.potter@amd.com switch (ehdr.e_ident[EI_OSABI]) { 14111391Sbrandon.potter@amd.com case ELFOSABI_LINUX: 14211391Sbrandon.potter@amd.com op_sys = Linux; 14311391Sbrandon.potter@amd.com break; 14411391Sbrandon.potter@amd.com case ELFOSABI_SOLARIS: 14511391Sbrandon.potter@amd.com op_sys = Solaris; 14611391Sbrandon.potter@amd.com break; 14711391Sbrandon.potter@amd.com case ELFOSABI_TRU64: 14811391Sbrandon.potter@amd.com op_sys = Tru64; 14911391Sbrandon.potter@amd.com break; 15011391Sbrandon.potter@amd.com case ELFOSABI_ARM: 15111391Sbrandon.potter@amd.com op_sys = LinuxArmOABI; 15211391Sbrandon.potter@amd.com break; 15311391Sbrandon.potter@amd.com case ELFOSABI_FREEBSD: 15411391Sbrandon.potter@amd.com op_sys = FreeBSD; 15511391Sbrandon.potter@amd.com break; 15611391Sbrandon.potter@amd.com default: 15711391Sbrandon.potter@amd.com op_sys = UnknownOpSys; 15811391Sbrandon.potter@amd.com } 1592207SN/A 16011391Sbrandon.potter@amd.com // Take a look at the .note.ABI section. 16111391Sbrandon.potter@amd.com // It can let us know what's what. 16211391Sbrandon.potter@amd.com if (op_sys == UnknownOpSys) { 16311391Sbrandon.potter@amd.com int sec_idx = 1; 16411391Sbrandon.potter@amd.com 16511391Sbrandon.potter@amd.com // Get the first section 16611391Sbrandon.potter@amd.com Elf_Scn *section = elf_getscn(elf, sec_idx); 16711391Sbrandon.potter@amd.com 16811391Sbrandon.potter@amd.com // While there are no more sections 16911391Sbrandon.potter@amd.com while (section && op_sys == UnknownOpSys) { 1702238SN/A GElf_Shdr shdr; 17111391Sbrandon.potter@amd.com gelf_getshdr(section, &shdr); 1722238SN/A 17311391Sbrandon.potter@amd.com char *e_str = elf_strptr(elf, ehdr.e_shstrndx, shdr.sh_name); 17411391Sbrandon.potter@amd.com if (shdr.sh_type == SHT_NOTE && 17511391Sbrandon.potter@amd.com !strcmp(".note.ABI-tag", e_str)) { 17611391Sbrandon.potter@amd.com // we have found a ABI note section 17711391Sbrandon.potter@amd.com // Check the 5th 32bit word for OS 0 == linux, 1 == hurd, 17811391Sbrandon.potter@amd.com // 2 == solaris, 3 == freebsd 17911391Sbrandon.potter@amd.com Elf_Data *raw_data = elf_rawdata(section, NULL); 18011391Sbrandon.potter@amd.com assert(raw_data && raw_data->d_buf); 1812238SN/A 18211391Sbrandon.potter@amd.com uint32_t raw_abi = ((uint32_t*)raw_data->d_buf)[4]; 18311391Sbrandon.potter@amd.com bool is_le = ehdr.e_ident[EI_DATA] == ELFDATA2LSB; 18411391Sbrandon.potter@amd.com uint32_t os_abi = is_le ? htole(raw_abi) : htobe(raw_abi); 1852238SN/A 18611391Sbrandon.potter@amd.com switch (os_abi) { 18711391Sbrandon.potter@amd.com case 0: 18811391Sbrandon.potter@amd.com op_sys = Linux; 18911391Sbrandon.potter@amd.com break; 19011391Sbrandon.potter@amd.com case 1: 19111391Sbrandon.potter@amd.com fatal("gem5 does not support the HURD ABI.\n"); 19211391Sbrandon.potter@amd.com case 2: 19311391Sbrandon.potter@amd.com op_sys = Solaris; 19411391Sbrandon.potter@amd.com break; 19511391Sbrandon.potter@amd.com case 3: 19611391Sbrandon.potter@amd.com op_sys = FreeBSD; 1972976Sgblack@eecs.umich.edu break; 1982976Sgblack@eecs.umich.edu } 19911391Sbrandon.potter@amd.com } // if section found 2002976Sgblack@eecs.umich.edu 20111391Sbrandon.potter@amd.com if (!strcmp(".SUNW_version", e_str) || 20211391Sbrandon.potter@amd.com !strcmp(".stab.index", e_str)) 20311391Sbrandon.potter@amd.com op_sys = Solaris; 2042976Sgblack@eecs.umich.edu 20511391Sbrandon.potter@amd.com section = elf_getscn(elf, ++sec_idx); 20611391Sbrandon.potter@amd.com } // while sections 20711391Sbrandon.potter@amd.com } 20811389Sbrandon.potter@amd.com 20911391Sbrandon.potter@amd.com ElfObject * result = new ElfObject(fname, len, data, arch, op_sys); 21011389Sbrandon.potter@amd.com 21111391Sbrandon.potter@amd.com // The number of headers in the file 21211391Sbrandon.potter@amd.com result->_programHeaderCount = ehdr.e_phnum; 21311391Sbrandon.potter@amd.com // Record the size of each entry 21411391Sbrandon.potter@amd.com result->_programHeaderSize = ehdr.e_phentsize; 21511391Sbrandon.potter@amd.com result->_programHeaderTable = 0; 21611391Sbrandon.potter@amd.com if (result->_programHeaderCount) { // If there is a program header table 21711391Sbrandon.potter@amd.com // Figure out the virtual address of the header table in the 21811391Sbrandon.potter@amd.com // final memory image. We use the program headers themselves 21911391Sbrandon.potter@amd.com // to translate from a file offset to the address in the image. 22011391Sbrandon.potter@amd.com GElf_Phdr phdr; 22111391Sbrandon.potter@amd.com uint64_t e_phoff = ehdr.e_phoff; 22211389Sbrandon.potter@amd.com 22311391Sbrandon.potter@amd.com for (int i = 0; i < result->_programHeaderCount; i++) { 22411391Sbrandon.potter@amd.com gelf_getphdr(elf, i, &phdr); 22511391Sbrandon.potter@amd.com // Check if we've found the segment with the headers in it 22611391Sbrandon.potter@amd.com if (phdr.p_offset <= e_phoff && 22711391Sbrandon.potter@amd.com phdr.p_offset + phdr.p_filesz > e_phoff) { 22811391Sbrandon.potter@amd.com result->_programHeaderTable = 22911391Sbrandon.potter@amd.com phdr.p_paddr + (e_phoff - phdr.p_offset); 23011389Sbrandon.potter@amd.com break; 23111389Sbrandon.potter@amd.com } 23211389Sbrandon.potter@amd.com } 23311391Sbrandon.potter@amd.com } 23411389Sbrandon.potter@amd.com 23511391Sbrandon.potter@amd.com if (!skip_interp_check) { 23611391Sbrandon.potter@amd.com for (int i = 0; i < ehdr.e_phnum; i++) { 23711391Sbrandon.potter@amd.com GElf_Phdr phdr; 23811391Sbrandon.potter@amd.com M5_VAR_USED void *check_p = gelf_getphdr(elf, i, &phdr); 23911391Sbrandon.potter@amd.com assert(check_p != nullptr); 24011391Sbrandon.potter@amd.com 24111391Sbrandon.potter@amd.com if (phdr.p_type != PT_INTERP) 24211391Sbrandon.potter@amd.com continue; 24311391Sbrandon.potter@amd.com 24411391Sbrandon.potter@amd.com char *interp_path = (char*)data + phdr.p_offset; 24511391Sbrandon.potter@amd.com int fd = open(interp_path, O_RDONLY); 24611391Sbrandon.potter@amd.com if (fd == -1) 24711391Sbrandon.potter@amd.com fatal("Unable to open dynamic executable's interpreter.\n"); 24811391Sbrandon.potter@amd.com 24911391Sbrandon.potter@amd.com struct stat sb; 25011391Sbrandon.potter@amd.com M5_VAR_USED int check_i = fstat(fd, &sb); 25111391Sbrandon.potter@amd.com assert(check_i == 0); 25211391Sbrandon.potter@amd.com 25311391Sbrandon.potter@amd.com void *mm = mmap(nullptr, sb.st_size, PROT_READ, 25411391Sbrandon.potter@amd.com MAP_PRIVATE, fd, 0); 25511391Sbrandon.potter@amd.com assert(mm != MAP_FAILED); 25611391Sbrandon.potter@amd.com close(fd); 25711391Sbrandon.potter@amd.com 25811391Sbrandon.potter@amd.com uint8_t *interp_image = (uint8_t*)mm; 25911391Sbrandon.potter@amd.com ObjectFile *obj = tryFile(interp_path, sb.st_size, 26011391Sbrandon.potter@amd.com interp_image, true); 26111391Sbrandon.potter@amd.com assert(obj != nullptr); 26211391Sbrandon.potter@amd.com result->interpreter = dynamic_cast<ElfObject*>(obj); 26311391Sbrandon.potter@amd.com assert(result->interpreter != nullptr); 26411391Sbrandon.potter@amd.com break; 26511391Sbrandon.potter@amd.com } 26612SN/A } 26711391Sbrandon.potter@amd.com 26811391Sbrandon.potter@amd.com elf_end(elf); 26911391Sbrandon.potter@amd.com return result; 27012SN/A} 27112SN/A 27211391Sbrandon.potter@amd.comElfObject::ElfObject(const std::string &_filename, size_t _len, 27311391Sbrandon.potter@amd.com uint8_t *_data, Arch _arch, OpSys _op_sys) 27411391Sbrandon.potter@amd.com : ObjectFile(_filename, _len, _data, _arch, _op_sys), 27511389Sbrandon.potter@amd.com _programHeaderTable(0), _programHeaderSize(0), _programHeaderCount(0), 27611389Sbrandon.potter@amd.com interpreter(nullptr), ldBias(0), relocate(true), 27711389Sbrandon.potter@amd.com ldMin(std::numeric_limits<Addr>::max()), 27811389Sbrandon.potter@amd.com ldMax(std::numeric_limits<Addr>::min()) 27912SN/A{ 280468SN/A // check that header matches library version 2811708SN/A if (elf_version(EV_CURRENT) == EV_NONE) 2821708SN/A panic("wrong elf version number!"); 28312SN/A 284468SN/A // get a pointer to elf structure 28511391Sbrandon.potter@amd.com Elf *elf = elf_memory((char*)fileData,len); 28611391Sbrandon.potter@amd.com assert(elf); 28712SN/A 288468SN/A // Check that we actually have a elf file 28911391Sbrandon.potter@amd.com GElf_Ehdr ehdr; 290468SN/A if (gelf_getehdr(elf, &ehdr) ==0) { 291443SN/A panic("Not ELF, shouldn't be here"); 29212SN/A } 29312SN/A 294468SN/A entry = ehdr.e_entry; 29512SN/A 296468SN/A // initialize segment sizes to 0 in case they're not present 297468SN/A text.size = data.size = bss.size = 0; 2989186SAli.Saidi@ARM.com text.baseAddr = data.baseAddr = bss.baseAddr = 0; 299468SN/A 30011391Sbrandon.potter@amd.com int sec_idx = 1; 3015090Sgblack@eecs.umich.edu 3025090Sgblack@eecs.umich.edu // The first address of some important sections. 30311391Sbrandon.potter@amd.com Addr text_sec_start = 0; 30411391Sbrandon.potter@amd.com Addr data_sec_start = 0; 30511391Sbrandon.potter@amd.com Addr bss_sec_start = 0; 3065090Sgblack@eecs.umich.edu 3075090Sgblack@eecs.umich.edu // Get the first section 30811391Sbrandon.potter@amd.com Elf_Scn *section = elf_getscn(elf, sec_idx); 3095090Sgblack@eecs.umich.edu 3105090Sgblack@eecs.umich.edu // Find the beginning of the most interesting sections. 31111391Sbrandon.potter@amd.com while (section) { 31211391Sbrandon.potter@amd.com GElf_Shdr shdr; 3135090Sgblack@eecs.umich.edu gelf_getshdr(section, &shdr); 31411391Sbrandon.potter@amd.com char *sec_name = elf_strptr(elf, ehdr.e_shstrndx, shdr.sh_name); 3155090Sgblack@eecs.umich.edu 31611391Sbrandon.potter@amd.com if (sec_name) { 31711391Sbrandon.potter@amd.com if (!strcmp(".text", sec_name)) { 31811391Sbrandon.potter@amd.com text_sec_start = shdr.sh_addr; 31911391Sbrandon.potter@amd.com } else if (!strcmp(".data", sec_name)) { 32011391Sbrandon.potter@amd.com data_sec_start = shdr.sh_addr; 32111391Sbrandon.potter@amd.com } else if (!strcmp(".bss", sec_name)) { 32211391Sbrandon.potter@amd.com bss_sec_start = shdr.sh_addr; 3238350Sgblack@eecs.umich.edu } 3248350Sgblack@eecs.umich.edu } else { 3258350Sgblack@eecs.umich.edu Elf_Error errorNum = (Elf_Error)elf_errno(); 3268350Sgblack@eecs.umich.edu if (errorNum != ELF_E_NONE) { 3278350Sgblack@eecs.umich.edu const char *errorMessage = elf_errmsg(errorNum); 3288350Sgblack@eecs.umich.edu fatal("Error from libelf: %s.\n", errorMessage); 3298350Sgblack@eecs.umich.edu } 3305090Sgblack@eecs.umich.edu } 3315090Sgblack@eecs.umich.edu 33211391Sbrandon.potter@amd.com section = elf_getscn(elf, ++sec_idx); 3335090Sgblack@eecs.umich.edu } 3345090Sgblack@eecs.umich.edu 3355090Sgblack@eecs.umich.edu // Go through all the segments in the program, record them, and scrape 3365090Sgblack@eecs.umich.edu // out information about the text, data, and bss areas needed by other 3375090Sgblack@eecs.umich.edu // code. 338468SN/A for (int i = 0; i < ehdr.e_phnum; ++i) { 339468SN/A GElf_Phdr phdr; 340468SN/A if (gelf_getphdr(elf, i, &phdr) == 0) { 3415090Sgblack@eecs.umich.edu panic("gelf_getphdr failed for segment %d.", i); 342468SN/A } 343468SN/A 344468SN/A // for now we don't care about non-loadable segments 345468SN/A if (!(phdr.p_type & PT_LOAD)) 346468SN/A continue; 347468SN/A 34811389Sbrandon.potter@amd.com ldMin = std::min(ldMin, phdr.p_vaddr); 34911389Sbrandon.potter@amd.com ldMax = std::max(ldMax, phdr.p_vaddr + phdr.p_memsz); 35011389Sbrandon.potter@amd.com 3515090Sgblack@eecs.umich.edu // Check to see if this segment contains the bss section. 35211391Sbrandon.potter@amd.com if (phdr.p_paddr <= bss_sec_start && 35311391Sbrandon.potter@amd.com phdr.p_paddr + phdr.p_memsz > bss_sec_start && 35411391Sbrandon.potter@amd.com phdr.p_memsz - phdr.p_filesz > 0) { 3555143Sgblack@eecs.umich.edu bss.baseAddr = phdr.p_paddr + phdr.p_filesz; 3565090Sgblack@eecs.umich.edu bss.size = phdr.p_memsz - phdr.p_filesz; 3575090Sgblack@eecs.umich.edu bss.fileImage = NULL; 3585090Sgblack@eecs.umich.edu } 3595090Sgblack@eecs.umich.edu 3605090Sgblack@eecs.umich.edu // Check to see if this is the text or data segment 36111391Sbrandon.potter@amd.com if (phdr.p_vaddr <= text_sec_start && 36211391Sbrandon.potter@amd.com phdr.p_vaddr + phdr.p_filesz > text_sec_start) { 36311389Sbrandon.potter@amd.com 36411389Sbrandon.potter@amd.com // If this value is nonzero, we need to flip the relocate flag. 36511389Sbrandon.potter@amd.com if (phdr.p_vaddr != 0) 36611389Sbrandon.potter@amd.com relocate = false; 36711389Sbrandon.potter@amd.com 3685143Sgblack@eecs.umich.edu text.baseAddr = phdr.p_paddr; 369468SN/A text.size = phdr.p_filesz; 3702420SN/A text.fileImage = fileData + phdr.p_offset; 37111391Sbrandon.potter@amd.com } else if (phdr.p_vaddr <= data_sec_start && 37211391Sbrandon.potter@amd.com phdr.p_vaddr + phdr.p_filesz > data_sec_start) { 3735143Sgblack@eecs.umich.edu data.baseAddr = phdr.p_paddr; 374468SN/A data.size = phdr.p_filesz; 3752420SN/A data.fileImage = fileData + phdr.p_offset; 3762476SN/A } else { 37711320Ssteve.reinhardt@amd.com // If it's none of the above but is loadable, 3785759Shsul@eecs.umich.edu // load the filesize worth of data 3795090Sgblack@eecs.umich.edu Segment extra; 3805143Sgblack@eecs.umich.edu extra.baseAddr = phdr.p_paddr; 3815090Sgblack@eecs.umich.edu extra.size = phdr.p_filesz; 3825090Sgblack@eecs.umich.edu extra.fileImage = fileData + phdr.p_offset; 3835090Sgblack@eecs.umich.edu extraSegments.push_back(extra); 384468SN/A } 385468SN/A } 386468SN/A 387468SN/A // should have found at least one loadable segment 38811561Sandreas.sandberg@arm.com warn_if(text.size == 0, 38911559Sandreas.sandberg@arm.com "Empty .text segment in '%s'. ELF file corrupted?\n", 39011559Sandreas.sandberg@arm.com filename); 391468SN/A 392468SN/A DPRINTFR(Loader, "text: 0x%x %d\ndata: 0x%x %d\nbss: 0x%x %d\n", 393468SN/A text.baseAddr, text.size, data.baseAddr, data.size, 394468SN/A bss.baseAddr, bss.size); 395468SN/A 396443SN/A elf_end(elf); 397443SN/A 398468SN/A // We will actually read the sections when we need to load them 39912SN/A} 40012SN/A 40112SN/A 40212SN/Abool 40311392Sbrandon.potter@amd.comElfObject::loadSomeSymbols(SymbolTable *symtab, int binding, Addr mask, 40411392Sbrandon.potter@amd.com Addr base, Addr offset) 40512SN/A{ 406443SN/A if (!symtab) 407443SN/A return false; 408443SN/A 409468SN/A // check that header matches library version 4101708SN/A if (elf_version(EV_CURRENT) == EV_NONE) 4111708SN/A panic("wrong elf version number!"); 412443SN/A 413468SN/A // get a pointer to elf structure 41411391Sbrandon.potter@amd.com Elf *elf = elf_memory((char*)fileData,len); 415443SN/A assert(elf != NULL); 416443SN/A 417468SN/A // Get the first section 41811391Sbrandon.potter@amd.com int sec_idx = 1; // there is a 0 but it is nothing, go figure 41911391Sbrandon.potter@amd.com Elf_Scn *section = elf_getscn(elf, sec_idx); 420443SN/A 421468SN/A // While there are no more sections 42211391Sbrandon.potter@amd.com bool found = false; 423468SN/A while (section != NULL) { 42411391Sbrandon.potter@amd.com GElf_Shdr shdr; 425443SN/A gelf_getshdr(section, &shdr); 426443SN/A 427468SN/A if (shdr.sh_type == SHT_SYMTAB) { 428443SN/A found = true; 42911391Sbrandon.potter@amd.com Elf_Data *data = elf_getdata(section, NULL); 43011391Sbrandon.potter@amd.com int count = shdr.sh_size / shdr.sh_entsize; 431443SN/A DPRINTF(Loader, "Found Symbol Table, %d symbols present\n", count); 432443SN/A 433468SN/A // loop through all the symbols, only loading global ones 43411391Sbrandon.potter@amd.com for (int i = 0; i < count; ++i) { 43511391Sbrandon.potter@amd.com GElf_Sym sym; 43611391Sbrandon.potter@amd.com gelf_getsym(data, i, &sym); 437836SN/A if (GELF_ST_BIND(sym.st_info) == binding) { 4387589SAli.Saidi@arm.com char *sym_name = elf_strptr(elf, shdr.sh_link, sym.st_name); 4397589SAli.Saidi@arm.com if (sym_name && sym_name[0] != '$') { 44011392Sbrandon.potter@amd.com Addr value = sym.st_value - base + offset; 44111392Sbrandon.potter@amd.com if (symtab->insert(value & mask, sym_name)) { 44211392Sbrandon.potter@amd.com DPRINTF(Loader, "Symbol: %-40s value %#x\n", 44311392Sbrandon.potter@amd.com sym_name, value); 44411392Sbrandon.potter@amd.com } 4457589SAli.Saidi@arm.com } 446443SN/A } 447443SN/A } 448443SN/A } 449454SN/A ++sec_idx; 450454SN/A section = elf_getscn(elf, sec_idx); 451443SN/A } 452443SN/A 453443SN/A elf_end(elf); 454443SN/A 455443SN/A return found; 45612SN/A} 45712SN/A 45812SN/Abool 45911392Sbrandon.potter@amd.comElfObject::loadAllSymbols(SymbolTable *symtab, Addr base, Addr offset, 46011392Sbrandon.potter@amd.com Addr addr_mask) 461468SN/A{ 46211392Sbrandon.potter@amd.com return (loadGlobalSymbols(symtab, base, offset, addr_mask) && 46311392Sbrandon.potter@amd.com loadLocalSymbols(symtab, base, offset, addr_mask) && 46411392Sbrandon.potter@amd.com loadWeakSymbols(symtab, base, offset, addr_mask)); 465468SN/A} 466468SN/A 467468SN/Abool 46811392Sbrandon.potter@amd.comElfObject::loadGlobalSymbols(SymbolTable *symtab, Addr base, Addr offset, 46911392Sbrandon.potter@amd.com Addr addr_mask) 47012SN/A{ 47111392Sbrandon.potter@amd.com if (interpreter) { 47211392Sbrandon.potter@amd.com interpreter->loadSomeSymbols(symtab, STB_GLOBAL, addr_mask, 47311392Sbrandon.potter@amd.com base, offset); 47411392Sbrandon.potter@amd.com } 47511392Sbrandon.potter@amd.com return loadSomeSymbols(symtab, STB_GLOBAL, addr_mask, base, offset); 47612SN/A} 4773917Ssaidi@eecs.umich.edu 4785090Sgblack@eecs.umich.edubool 47911392Sbrandon.potter@amd.comElfObject::loadLocalSymbols(SymbolTable *symtab, Addr base, Addr offset, 48011392Sbrandon.potter@amd.com Addr addr_mask) 4819641Sguodeyuan@tsinghua.org.cn{ 48211392Sbrandon.potter@amd.com if (interpreter) { 48311392Sbrandon.potter@amd.com interpreter->loadSomeSymbols(symtab, STB_LOCAL, addr_mask, 48411392Sbrandon.potter@amd.com base, offset); 48511392Sbrandon.potter@amd.com } 48611392Sbrandon.potter@amd.com return loadSomeSymbols(symtab, STB_LOCAL, addr_mask, base, offset); 48711392Sbrandon.potter@amd.com} 48811392Sbrandon.potter@amd.com 48911392Sbrandon.potter@amd.combool 49011392Sbrandon.potter@amd.comElfObject::loadWeakSymbols(SymbolTable *symtab, Addr base, Addr offset, 49111392Sbrandon.potter@amd.com Addr addr_mask) 49211392Sbrandon.potter@amd.com{ 49311392Sbrandon.potter@amd.com if (interpreter) { 49411392Sbrandon.potter@amd.com interpreter->loadSomeSymbols(symtab, STB_WEAK, addr_mask, 49511392Sbrandon.potter@amd.com base, offset); 49611392Sbrandon.potter@amd.com } 49711392Sbrandon.potter@amd.com return loadSomeSymbols(symtab, STB_WEAK, addr_mask, base, offset); 4989641Sguodeyuan@tsinghua.org.cn} 4999641Sguodeyuan@tsinghua.org.cn 5009641Sguodeyuan@tsinghua.org.cnbool 50111391Sbrandon.potter@amd.comElfObject::loadSections(PortProxy& mem_proxy, Addr addr_mask, Addr offset) 5025090Sgblack@eecs.umich.edu{ 50311391Sbrandon.potter@amd.com if (!ObjectFile::loadSections(mem_proxy, addr_mask, offset)) 5045090Sgblack@eecs.umich.edu return false; 5055090Sgblack@eecs.umich.edu 50611391Sbrandon.potter@amd.com for (auto seg : extraSegments) { 50711391Sbrandon.potter@amd.com if (!loadSection(&seg, mem_proxy, addr_mask, offset)) { 5085090Sgblack@eecs.umich.edu return false; 5095090Sgblack@eecs.umich.edu } 5105090Sgblack@eecs.umich.edu } 51111389Sbrandon.potter@amd.com 51211389Sbrandon.potter@amd.com if (interpreter) 51311391Sbrandon.potter@amd.com interpreter->loadSections(mem_proxy, addr_mask, offset); 51411389Sbrandon.potter@amd.com 5155090Sgblack@eecs.umich.edu return true; 5165090Sgblack@eecs.umich.edu} 5175090Sgblack@eecs.umich.edu 5185070Ssaidi@eecs.umich.eduvoid 5195070Ssaidi@eecs.umich.eduElfObject::getSections() 5203917Ssaidi@eecs.umich.edu{ 5215070Ssaidi@eecs.umich.edu assert(!sectionNames.size()); 5225070Ssaidi@eecs.umich.edu 5233917Ssaidi@eecs.umich.edu // check that header matches library version 5243917Ssaidi@eecs.umich.edu if (elf_version(EV_CURRENT) == EV_NONE) 5253917Ssaidi@eecs.umich.edu panic("wrong elf version number!"); 5263917Ssaidi@eecs.umich.edu 5273917Ssaidi@eecs.umich.edu // get a pointer to elf structure 52811391Sbrandon.potter@amd.com Elf *elf = elf_memory((char*)fileData,len); 5293917Ssaidi@eecs.umich.edu assert(elf != NULL); 5303917Ssaidi@eecs.umich.edu 5313917Ssaidi@eecs.umich.edu // Check that we actually have a elf file 53211391Sbrandon.potter@amd.com GElf_Ehdr ehdr; 5333917Ssaidi@eecs.umich.edu if (gelf_getehdr(elf, &ehdr) ==0) { 5343917Ssaidi@eecs.umich.edu panic("Not ELF, shouldn't be here"); 5353917Ssaidi@eecs.umich.edu } 5363917Ssaidi@eecs.umich.edu 5373917Ssaidi@eecs.umich.edu // Get the first section 53811391Sbrandon.potter@amd.com int sec_idx = 1; // there is a 0 but it is nothing, go figure 53911391Sbrandon.potter@amd.com Elf_Scn *section = elf_getscn(elf, sec_idx); 5403917Ssaidi@eecs.umich.edu 5413917Ssaidi@eecs.umich.edu // While there are no more sections 54211391Sbrandon.potter@amd.com while (section) { 54311391Sbrandon.potter@amd.com GElf_Shdr shdr; 5443917Ssaidi@eecs.umich.edu gelf_getshdr(section, &shdr); 5455070Ssaidi@eecs.umich.edu sectionNames.insert(elf_strptr(elf, ehdr.e_shstrndx, shdr.sh_name)); 5463917Ssaidi@eecs.umich.edu section = elf_getscn(elf, ++sec_idx); 5473917Ssaidi@eecs.umich.edu } // while sections 54811873Sbrandon.potter@amd.com 54911873Sbrandon.potter@amd.com elf_end(elf); 5503917Ssaidi@eecs.umich.edu} 5513917Ssaidi@eecs.umich.edu 5525070Ssaidi@eecs.umich.edubool 55311391Sbrandon.potter@amd.comElfObject::sectionExists(std::string sec) 5545070Ssaidi@eecs.umich.edu{ 5555070Ssaidi@eecs.umich.edu if (!sectionNames.size()) 5565070Ssaidi@eecs.umich.edu getSections(); 55711391Sbrandon.potter@amd.com 5585070Ssaidi@eecs.umich.edu return sectionNames.find(sec) != sectionNames.end(); 5595070Ssaidi@eecs.umich.edu} 5603917Ssaidi@eecs.umich.edu 5615070Ssaidi@eecs.umich.edu 56211389Sbrandon.potter@amd.comvoid 56311389Sbrandon.potter@amd.comElfObject::updateBias(Addr bias_addr) 56411389Sbrandon.potter@amd.com{ 56511389Sbrandon.potter@amd.com // Record the bias. 56611389Sbrandon.potter@amd.com ldBias = bias_addr; 56711389Sbrandon.potter@amd.com 56811389Sbrandon.potter@amd.com // Patch the entry point with bias_addr. 56911389Sbrandon.potter@amd.com entry += bias_addr; 57011389Sbrandon.potter@amd.com 57111389Sbrandon.potter@amd.com // Patch segments with the bias_addr. 57211389Sbrandon.potter@amd.com text.baseAddr += bias_addr; 57311389Sbrandon.potter@amd.com data.baseAddr += bias_addr; 57411389Sbrandon.potter@amd.com bss.baseAddr += bias_addr; 57511389Sbrandon.potter@amd.com for (auto &segment : extraSegments) 57611389Sbrandon.potter@amd.com segment.baseAddr += bias_addr; 57711389Sbrandon.potter@amd.com} 578