elf_object.cc revision 11392:5967db4cff04
1/*
2 * Copyright (c) 2011-2013 ARM Limited
3 * All rights reserved
4 *
5 * The license below extends only to copyright in the software and shall
6 * not be construed as granting a license to any other intellectual
7 * property including but not limited to intellectual property relating
8 * to a hardware implementation of the functionality of the software
9 * licensed hereunder.  You may use the software subject to the license
10 * terms below provided that you ensure that this notice is replicated
11 * unmodified and in its entirety in all distributions of the software,
12 * modified or unmodified, in source code or in binary form.
13 *
14 * Copyright (c) 2003-2005 The Regents of The University of Michigan
15 * All rights reserved.
16 *
17 * Redistribution and use in source and binary forms, with or without
18 * modification, are permitted provided that the following conditions are
19 * met: redistributions of source code must retain the above copyright
20 * notice, this list of conditions and the following disclaimer;
21 * redistributions in binary form must reproduce the above copyright
22 * notice, this list of conditions and the following disclaimer in the
23 * documentation and/or other materials provided with the distribution;
24 * neither the name of the copyright holders nor the names of its
25 * contributors may be used to endorse or promote products derived from
26 * this software without specific prior written permission.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
31 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
32 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
33 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
34 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
35 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
36 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
37 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
38 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39 *
40 * Authors: Steve Reinhardt
41 *          Ali Saidi
42 */
43
44#include "base/loader/elf_object.hh"
45
46#include <fcntl.h>
47#include <sys/mman.h>
48#include <sys/stat.h>
49#include <sys/types.h>
50#include <unistd.h>
51
52#include <cassert>
53#include <string>
54
55#include "base/bitfield.hh"
56#include "base/loader/symtab.hh"
57#include "base/misc.hh"
58#include "base/trace.hh"
59#include "debug/Loader.hh"
60#include "gelf.h"
61#include "sim/byteswap.hh"
62
63ObjectFile *
64ElfObject::tryFile(const std::string &fname, size_t len, uint8_t *data,
65                   bool skip_interp_check)
66{
67    // check that header matches library version
68    if (elf_version(EV_CURRENT) == EV_NONE)
69        panic("wrong elf version number!");
70
71    // get a pointer to elf structure
72    // Check that we actually have a elf file
73    Elf *elf = elf_memory((char*)data, len);
74    assert(elf);
75
76    GElf_Ehdr ehdr;
77    if (gelf_getehdr(elf, &ehdr) == 0) {
78        DPRINTFR(Loader, "Not ELF\n");
79        elf_end(elf);
80        return NULL;
81    }
82
83    // Detect the architecture
84    Arch arch = UnknownArch;
85    if (ehdr.e_machine == EM_SPARC64 ||
86        (ehdr.e_machine == EM_SPARC &&
87         ehdr.e_ident[EI_CLASS] == ELFCLASS64) ||
88        ehdr.e_machine == EM_SPARCV9) {
89        arch = SPARC64;
90    } else if (ehdr.e_machine == EM_SPARC32PLUS ||
91               (ehdr.e_machine == EM_SPARC &&
92                ehdr.e_ident[EI_CLASS] == ELFCLASS32)) {
93        arch = SPARC32;
94    } else if (ehdr.e_machine == EM_MIPS &&
95               ehdr.e_ident[EI_CLASS] == ELFCLASS32) {
96        arch = Mips;
97        if (ehdr.e_ident[EI_DATA] != ELFDATA2LSB) {
98            fatal("The binary you're trying to load is compiled for big "
99                  "endian MIPS. gem5\nonly supports little endian MIPS. "
100                  "Please recompile your binary.\n");
101        }
102    } else if (ehdr.e_machine == EM_X86_64 &&
103               ehdr.e_ident[EI_CLASS] == ELFCLASS64) {
104        arch = X86_64;
105    } else if (ehdr.e_machine == EM_386 &&
106               ehdr.e_ident[EI_CLASS] == ELFCLASS32) {
107        arch = I386;
108    } else if (ehdr.e_machine == EM_ARM &&
109               ehdr.e_ident[EI_CLASS] == ELFCLASS32) {
110        arch = bits(ehdr.e_entry, 0) ? Thumb : Arm;
111    } else if (ehdr.e_machine == EM_AARCH64 &&
112               ehdr.e_ident[EI_CLASS] == ELFCLASS64) {
113        arch = Arm64;
114    } else if (ehdr.e_machine == EM_PPC &&
115               ehdr.e_ident[EI_CLASS] == ELFCLASS32) {
116        arch = Power;
117        if (ehdr.e_ident[EI_DATA] != ELFDATA2MSB) {
118            fatal("The binary you're trying to load is compiled for "
119                  "little endian Power.\ngem5 only supports big "
120                  "endian Power. Please recompile your binary.\n");
121        }
122    } else if (ehdr.e_machine == EM_PPC64) {
123        fatal("The binary you're trying to load is compiled for 64-bit "
124              "Power. M5\n only supports 32-bit Power. Please "
125              "recompile your binary.\n");
126    } else if (ehdr.e_ident[EI_CLASS] == ELFCLASS64) {
127        // Since we don't know how to check for alpha right now, we'll
128        // just assume if it wasn't something else and it's 64 bit, that's
129        // what it must be.
130        arch = Alpha;
131    } else {
132        warn("Unknown architecture: %d\n", ehdr.e_machine);
133        arch = UnknownArch;
134    }
135
136    // Detect the operating system
137    OpSys op_sys;
138    switch (ehdr.e_ident[EI_OSABI]) {
139      case ELFOSABI_LINUX:
140        op_sys = Linux;
141        break;
142      case ELFOSABI_SOLARIS:
143        op_sys = Solaris;
144        break;
145      case ELFOSABI_TRU64:
146        op_sys = Tru64;
147        break;
148      case ELFOSABI_ARM:
149        op_sys = LinuxArmOABI;
150        break;
151      case ELFOSABI_FREEBSD:
152        op_sys = FreeBSD;
153        break;
154      default:
155        op_sys = UnknownOpSys;
156    }
157
158    // Take a look at the .note.ABI section.
159    // It can let us know what's what.
160    if (op_sys == UnknownOpSys) {
161        int sec_idx = 1;
162
163        // Get the first section
164        Elf_Scn *section = elf_getscn(elf, sec_idx);
165
166        // While there are no more sections
167        while (section && op_sys == UnknownOpSys) {
168            GElf_Shdr shdr;
169            gelf_getshdr(section, &shdr);
170
171            char *e_str = elf_strptr(elf, ehdr.e_shstrndx, shdr.sh_name);
172            if (shdr.sh_type == SHT_NOTE &&
173                !strcmp(".note.ABI-tag", e_str)) {
174                // we have found a ABI note section
175                // Check the 5th 32bit word for OS  0 == linux, 1 == hurd,
176                // 2 == solaris, 3 == freebsd
177                Elf_Data *raw_data = elf_rawdata(section, NULL);
178                assert(raw_data && raw_data->d_buf);
179
180                uint32_t raw_abi = ((uint32_t*)raw_data->d_buf)[4];
181                bool is_le = ehdr.e_ident[EI_DATA] == ELFDATA2LSB;
182                uint32_t os_abi = is_le ? htole(raw_abi) : htobe(raw_abi);
183
184                switch (os_abi) {
185                  case 0:
186                    op_sys = Linux;
187                    break;
188                  case 1:
189                    fatal("gem5 does not support the HURD ABI.\n");
190                  case 2:
191                    op_sys = Solaris;
192                    break;
193                  case 3:
194                    op_sys = FreeBSD;
195                    break;
196                }
197            } // if section found
198
199            if (!strcmp(".SUNW_version", e_str) ||
200                !strcmp(".stab.index", e_str))
201                op_sys = Solaris;
202
203            section = elf_getscn(elf, ++sec_idx);
204        } // while sections
205    }
206
207    ElfObject * result = new ElfObject(fname, len, data, arch, op_sys);
208
209    // The number of headers in the file
210    result->_programHeaderCount = ehdr.e_phnum;
211    // Record the size of each entry
212    result->_programHeaderSize = ehdr.e_phentsize;
213    result->_programHeaderTable = 0;
214    if (result->_programHeaderCount) { // If there is a program header table
215        // Figure out the virtual address of the header table in the
216        // final memory image. We use the program headers themselves
217        // to translate from a file offset to the address in the image.
218        GElf_Phdr phdr;
219        uint64_t e_phoff = ehdr.e_phoff;
220
221        for (int i = 0; i < result->_programHeaderCount; i++) {
222            gelf_getphdr(elf, i, &phdr);
223            // Check if we've found the segment with the headers in it
224            if (phdr.p_offset <= e_phoff &&
225                phdr.p_offset + phdr.p_filesz > e_phoff) {
226                result->_programHeaderTable =
227                    phdr.p_paddr + (e_phoff - phdr.p_offset);
228                break;
229            }
230        }
231    }
232
233    if (!skip_interp_check) {
234        for (int i = 0; i < ehdr.e_phnum; i++) {
235            GElf_Phdr phdr;
236            M5_VAR_USED void *check_p = gelf_getphdr(elf, i, &phdr);
237            assert(check_p != nullptr);
238
239           if (phdr.p_type != PT_INTERP)
240                continue;
241
242            char *interp_path = (char*)data + phdr.p_offset;
243            int fd = open(interp_path, O_RDONLY);
244            if (fd == -1)
245                fatal("Unable to open dynamic executable's interpreter.\n");
246
247            struct stat sb;
248            M5_VAR_USED int check_i = fstat(fd, &sb);
249            assert(check_i == 0);
250
251            void *mm = mmap(nullptr, sb.st_size, PROT_READ,
252                            MAP_PRIVATE, fd, 0);
253            assert(mm != MAP_FAILED);
254            close(fd);
255
256            uint8_t *interp_image = (uint8_t*)mm;
257            ObjectFile *obj = tryFile(interp_path, sb.st_size,
258                                      interp_image, true);
259            assert(obj != nullptr);
260            result->interpreter = dynamic_cast<ElfObject*>(obj);
261            assert(result->interpreter != nullptr);
262            break;
263        }
264    }
265
266    elf_end(elf);
267    return result;
268}
269
270ElfObject::ElfObject(const std::string &_filename, size_t _len,
271                     uint8_t *_data, Arch _arch, OpSys _op_sys)
272    : ObjectFile(_filename, _len, _data, _arch, _op_sys),
273      _programHeaderTable(0), _programHeaderSize(0), _programHeaderCount(0),
274      interpreter(nullptr), ldBias(0), relocate(true),
275      ldMin(std::numeric_limits<Addr>::max()),
276      ldMax(std::numeric_limits<Addr>::min())
277{
278    // check that header matches library version
279    if (elf_version(EV_CURRENT) == EV_NONE)
280        panic("wrong elf version number!");
281
282    // get a pointer to elf structure
283    Elf *elf = elf_memory((char*)fileData,len);
284    assert(elf);
285
286    // Check that we actually have a elf file
287    GElf_Ehdr ehdr;
288    if (gelf_getehdr(elf, &ehdr) ==0) {
289        panic("Not ELF, shouldn't be here");
290    }
291
292    entry = ehdr.e_entry;
293
294    // initialize segment sizes to 0 in case they're not present
295    text.size = data.size = bss.size = 0;
296    text.baseAddr = data.baseAddr = bss.baseAddr = 0;
297
298    int sec_idx = 1;
299
300    // The first address of some important sections.
301    Addr text_sec_start = 0;
302    Addr data_sec_start = 0;
303    Addr bss_sec_start = 0;
304
305    // Get the first section
306    Elf_Scn *section = elf_getscn(elf, sec_idx);
307
308    // Find the beginning of the most interesting sections.
309    while (section) {
310        GElf_Shdr shdr;
311        gelf_getshdr(section, &shdr);
312        char *sec_name = elf_strptr(elf, ehdr.e_shstrndx, shdr.sh_name);
313
314        if (sec_name) {
315            if (!strcmp(".text", sec_name)) {
316                text_sec_start = shdr.sh_addr;
317            } else if (!strcmp(".data", sec_name)) {
318                data_sec_start = shdr.sh_addr;
319            } else if (!strcmp(".bss", sec_name)) {
320                bss_sec_start = shdr.sh_addr;
321            }
322        } else {
323            Elf_Error errorNum = (Elf_Error)elf_errno();
324            if (errorNum != ELF_E_NONE) {
325                const char *errorMessage = elf_errmsg(errorNum);
326                fatal("Error from libelf: %s.\n", errorMessage);
327            }
328        }
329
330        section = elf_getscn(elf, ++sec_idx);
331    }
332
333    // Go through all the segments in the program, record them, and scrape
334    // out information about the text, data, and bss areas needed by other
335    // code.
336    for (int i = 0; i < ehdr.e_phnum; ++i) {
337        GElf_Phdr phdr;
338        if (gelf_getphdr(elf, i, &phdr) == 0) {
339            panic("gelf_getphdr failed for segment %d.", i);
340        }
341
342        // for now we don't care about non-loadable segments
343        if (!(phdr.p_type & PT_LOAD))
344            continue;
345
346        ldMin = std::min(ldMin, phdr.p_vaddr);
347        ldMax = std::max(ldMax, phdr.p_vaddr + phdr.p_memsz);
348
349        // Check to see if this segment contains the bss section.
350        if (phdr.p_paddr <= bss_sec_start &&
351            phdr.p_paddr + phdr.p_memsz > bss_sec_start &&
352            phdr.p_memsz - phdr.p_filesz > 0) {
353            bss.baseAddr = phdr.p_paddr + phdr.p_filesz;
354            bss.size = phdr.p_memsz - phdr.p_filesz;
355            bss.fileImage = NULL;
356        }
357
358        // Check to see if this is the text or data segment
359        if (phdr.p_vaddr <= text_sec_start &&
360            phdr.p_vaddr + phdr.p_filesz > text_sec_start) {
361
362            // If this value is nonzero, we need to flip the relocate flag.
363            if (phdr.p_vaddr != 0)
364                relocate = false;
365
366            text.baseAddr = phdr.p_paddr;
367            text.size = phdr.p_filesz;
368            text.fileImage = fileData + phdr.p_offset;
369        } else if (phdr.p_vaddr <= data_sec_start &&
370                   phdr.p_vaddr + phdr.p_filesz > data_sec_start) {
371            data.baseAddr = phdr.p_paddr;
372            data.size = phdr.p_filesz;
373            data.fileImage = fileData + phdr.p_offset;
374        } else {
375            // If it's none of the above but is loadable,
376            // load the filesize worth of data
377            Segment extra;
378            extra.baseAddr = phdr.p_paddr;
379            extra.size = phdr.p_filesz;
380            extra.fileImage = fileData + phdr.p_offset;
381            extraSegments.push_back(extra);
382        }
383    }
384
385    // should have found at least one loadable segment
386    assert(text.size != 0);
387
388    DPRINTFR(Loader, "text: 0x%x %d\ndata: 0x%x %d\nbss: 0x%x %d\n",
389             text.baseAddr, text.size, data.baseAddr, data.size,
390             bss.baseAddr, bss.size);
391
392    elf_end(elf);
393
394    // We will actually read the sections when we need to load them
395}
396
397
398bool
399ElfObject::loadSomeSymbols(SymbolTable *symtab, int binding, Addr mask,
400                           Addr base, Addr offset)
401{
402    if (!symtab)
403        return false;
404
405    // check that header matches library version
406    if (elf_version(EV_CURRENT) == EV_NONE)
407        panic("wrong elf version number!");
408
409    // get a pointer to elf structure
410    Elf *elf = elf_memory((char*)fileData,len);
411    assert(elf != NULL);
412
413    // Get the first section
414    int sec_idx = 1; // there is a 0 but it is nothing, go figure
415    Elf_Scn *section = elf_getscn(elf, sec_idx);
416
417    // While there are no more sections
418    bool found = false;
419    while (section != NULL) {
420        GElf_Shdr shdr;
421        gelf_getshdr(section, &shdr);
422
423        if (shdr.sh_type == SHT_SYMTAB) {
424            found = true;
425            Elf_Data *data = elf_getdata(section, NULL);
426            int count = shdr.sh_size / shdr.sh_entsize;
427            DPRINTF(Loader, "Found Symbol Table, %d symbols present\n", count);
428
429            // loop through all the symbols, only loading global ones
430            for (int i = 0; i < count; ++i) {
431                GElf_Sym sym;
432                gelf_getsym(data, i, &sym);
433                if (GELF_ST_BIND(sym.st_info) == binding) {
434                    char *sym_name = elf_strptr(elf, shdr.sh_link, sym.st_name);
435                    if (sym_name && sym_name[0] != '$') {
436                        Addr value = sym.st_value - base + offset;
437                        if (symtab->insert(value & mask, sym_name)) {
438                            DPRINTF(Loader, "Symbol: %-40s value %#x\n",
439                                    sym_name, value);
440                        }
441                    }
442                }
443            }
444        }
445        ++sec_idx;
446        section = elf_getscn(elf, sec_idx);
447    }
448
449    elf_end(elf);
450
451    return found;
452}
453
454bool
455ElfObject::loadAllSymbols(SymbolTable *symtab, Addr base, Addr offset,
456                          Addr addr_mask)
457{
458    return (loadGlobalSymbols(symtab, base, offset, addr_mask) &&
459            loadLocalSymbols(symtab, base, offset, addr_mask) &&
460            loadWeakSymbols(symtab, base, offset, addr_mask));
461}
462
463bool
464ElfObject::loadGlobalSymbols(SymbolTable *symtab, Addr base, Addr offset,
465                             Addr addr_mask)
466{
467    if (interpreter) {
468        interpreter->loadSomeSymbols(symtab, STB_GLOBAL, addr_mask,
469                                     base, offset);
470    }
471    return loadSomeSymbols(symtab, STB_GLOBAL, addr_mask, base, offset);
472}
473
474bool
475ElfObject::loadLocalSymbols(SymbolTable *symtab, Addr base, Addr offset,
476                            Addr addr_mask)
477{
478    if (interpreter) {
479        interpreter->loadSomeSymbols(symtab, STB_LOCAL, addr_mask,
480                                     base, offset);
481    }
482    return loadSomeSymbols(symtab, STB_LOCAL, addr_mask, base, offset);
483}
484
485bool
486ElfObject::loadWeakSymbols(SymbolTable *symtab, Addr base, Addr offset,
487                           Addr addr_mask)
488{
489    if (interpreter) {
490        interpreter->loadSomeSymbols(symtab, STB_WEAK, addr_mask,
491                                     base, offset);
492    }
493    return loadSomeSymbols(symtab, STB_WEAK, addr_mask, base, offset);
494}
495
496bool
497ElfObject::loadSections(PortProxy& mem_proxy, Addr addr_mask, Addr offset)
498{
499    if (!ObjectFile::loadSections(mem_proxy, addr_mask, offset))
500        return false;
501
502    for (auto seg : extraSegments) {
503        if (!loadSection(&seg, mem_proxy, addr_mask, offset)) {
504            return false;
505        }
506    }
507
508    if (interpreter)
509        interpreter->loadSections(mem_proxy, addr_mask, offset);
510
511    return true;
512}
513
514void
515ElfObject::getSections()
516{
517    assert(!sectionNames.size());
518
519    // check that header matches library version
520    if (elf_version(EV_CURRENT) == EV_NONE)
521        panic("wrong elf version number!");
522
523    // get a pointer to elf structure
524    Elf *elf = elf_memory((char*)fileData,len);
525    assert(elf != NULL);
526
527    // Check that we actually have a elf file
528    GElf_Ehdr ehdr;
529    if (gelf_getehdr(elf, &ehdr) ==0) {
530        panic("Not ELF, shouldn't be here");
531    }
532
533    // Get the first section
534    int sec_idx = 1; // there is a 0 but it is nothing, go figure
535    Elf_Scn *section = elf_getscn(elf, sec_idx);
536
537    // While there are no more sections
538    while (section) {
539        GElf_Shdr shdr;
540        gelf_getshdr(section, &shdr);
541        sectionNames.insert(elf_strptr(elf, ehdr.e_shstrndx, shdr.sh_name));
542        section = elf_getscn(elf, ++sec_idx);
543    } // while sections
544}
545
546bool
547ElfObject::sectionExists(std::string sec)
548{
549    if (!sectionNames.size())
550        getSections();
551
552    return sectionNames.find(sec) != sectionNames.end();
553}
554
555
556void
557ElfObject::updateBias(Addr bias_addr)
558{
559    // Record the bias.
560    ldBias = bias_addr;
561
562    // Patch the entry point with bias_addr.
563    entry += bias_addr;
564
565    // Patch segments with the bias_addr.
566    text.baseAddr += bias_addr;
567    data.baseAddr += bias_addr;
568    bss.baseAddr  += bias_addr;
569    for (auto &segment : extraSegments)
570        segment.baseAddr += bias_addr;
571}
572