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"
5712334Sgabeblack@google.com#include "base/logging.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) {
11513634Saustinharris@utexas.edu        arch = (ehdr.e_ident[EI_CLASS] == ELFCLASS64) ? Riscv64 : Riscv32;
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
50114017Sbrandon.potter@amd.comElfObject::loadSections(const PortProxy& mem_proxy, Addr addr_mask,
50214017Sbrandon.potter@amd.com                        Addr offset)
5035090Sgblack@eecs.umich.edu{
50411391Sbrandon.potter@amd.com    if (!ObjectFile::loadSections(mem_proxy, addr_mask, offset))
5055090Sgblack@eecs.umich.edu        return false;
5065090Sgblack@eecs.umich.edu
50711391Sbrandon.potter@amd.com    for (auto seg : extraSegments) {
50811391Sbrandon.potter@amd.com        if (!loadSection(&seg, mem_proxy, addr_mask, offset)) {
5095090Sgblack@eecs.umich.edu            return false;
5105090Sgblack@eecs.umich.edu        }
5115090Sgblack@eecs.umich.edu    }
51211389Sbrandon.potter@amd.com
51311389Sbrandon.potter@amd.com    if (interpreter)
51411391Sbrandon.potter@amd.com        interpreter->loadSections(mem_proxy, addr_mask, offset);
51511389Sbrandon.potter@amd.com
5165090Sgblack@eecs.umich.edu    return true;
5175090Sgblack@eecs.umich.edu}
5185090Sgblack@eecs.umich.edu
5195070Ssaidi@eecs.umich.eduvoid
5205070Ssaidi@eecs.umich.eduElfObject::getSections()
5213917Ssaidi@eecs.umich.edu{
5225070Ssaidi@eecs.umich.edu    assert(!sectionNames.size());
5235070Ssaidi@eecs.umich.edu
5243917Ssaidi@eecs.umich.edu    // check that header matches library version
5253917Ssaidi@eecs.umich.edu    if (elf_version(EV_CURRENT) == EV_NONE)
5263917Ssaidi@eecs.umich.edu        panic("wrong elf version number!");
5273917Ssaidi@eecs.umich.edu
5283917Ssaidi@eecs.umich.edu    // get a pointer to elf structure
52911391Sbrandon.potter@amd.com    Elf *elf = elf_memory((char*)fileData,len);
5303917Ssaidi@eecs.umich.edu    assert(elf != NULL);
5313917Ssaidi@eecs.umich.edu
5323917Ssaidi@eecs.umich.edu    // Check that we actually have a elf file
53311391Sbrandon.potter@amd.com    GElf_Ehdr ehdr;
5343917Ssaidi@eecs.umich.edu    if (gelf_getehdr(elf, &ehdr) ==0) {
5353917Ssaidi@eecs.umich.edu        panic("Not ELF, shouldn't be here");
5363917Ssaidi@eecs.umich.edu    }
5373917Ssaidi@eecs.umich.edu
5383917Ssaidi@eecs.umich.edu    // Get the first section
53911391Sbrandon.potter@amd.com    int sec_idx = 1; // there is a 0 but it is nothing, go figure
54011391Sbrandon.potter@amd.com    Elf_Scn *section = elf_getscn(elf, sec_idx);
5413917Ssaidi@eecs.umich.edu
5423917Ssaidi@eecs.umich.edu    // While there are no more sections
54311391Sbrandon.potter@amd.com    while (section) {
54411391Sbrandon.potter@amd.com        GElf_Shdr shdr;
5453917Ssaidi@eecs.umich.edu        gelf_getshdr(section, &shdr);
5465070Ssaidi@eecs.umich.edu        sectionNames.insert(elf_strptr(elf, ehdr.e_shstrndx, shdr.sh_name));
5473917Ssaidi@eecs.umich.edu        section = elf_getscn(elf, ++sec_idx);
5483917Ssaidi@eecs.umich.edu    } // while sections
54911873Sbrandon.potter@amd.com
55011873Sbrandon.potter@amd.com    elf_end(elf);
5513917Ssaidi@eecs.umich.edu}
5523917Ssaidi@eecs.umich.edu
5535070Ssaidi@eecs.umich.edubool
55411391Sbrandon.potter@amd.comElfObject::sectionExists(std::string sec)
5555070Ssaidi@eecs.umich.edu{
5565070Ssaidi@eecs.umich.edu    if (!sectionNames.size())
5575070Ssaidi@eecs.umich.edu        getSections();
55811391Sbrandon.potter@amd.com
5595070Ssaidi@eecs.umich.edu    return sectionNames.find(sec) != sectionNames.end();
5605070Ssaidi@eecs.umich.edu}
5613917Ssaidi@eecs.umich.edu
5625070Ssaidi@eecs.umich.edu
56311389Sbrandon.potter@amd.comvoid
56411389Sbrandon.potter@amd.comElfObject::updateBias(Addr bias_addr)
56511389Sbrandon.potter@amd.com{
56611389Sbrandon.potter@amd.com    // Record the bias.
56711389Sbrandon.potter@amd.com    ldBias = bias_addr;
56811389Sbrandon.potter@amd.com
56911389Sbrandon.potter@amd.com    // Patch the entry point with bias_addr.
57011389Sbrandon.potter@amd.com    entry += bias_addr;
57111389Sbrandon.potter@amd.com
57211389Sbrandon.potter@amd.com    // Patch segments with the bias_addr.
57311389Sbrandon.potter@amd.com    text.baseAddr += bias_addr;
57411389Sbrandon.potter@amd.com    data.baseAddr += bias_addr;
57511389Sbrandon.potter@amd.com    bss.baseAddr  += bias_addr;
57611389Sbrandon.potter@amd.com    for (auto &segment : extraSegments)
57711389Sbrandon.potter@amd.com        segment.baseAddr += bias_addr;
57811389Sbrandon.potter@amd.com}
579