gem5  v20.1.0.0
elf_object.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2011-2013, 2019 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 
42 
43 #include <fcntl.h>
44 #include <sys/mman.h>
45 #include <sys/stat.h>
46 #include <sys/types.h>
47 #include <unistd.h>
48 
49 #include <cassert>
50 #include <string>
51 
52 #include "base/bitfield.hh"
53 #include "base/loader/symtab.hh"
54 #include "base/logging.hh"
55 #include "base/trace.hh"
56 #include "debug/Loader.hh"
57 #include "gelf.h"
58 #include "sim/byteswap.hh"
59 
60 namespace Loader
61 {
62 
63 ObjectFile *
65 {
66  // check that header matches library version
67  if (elf_version(EV_CURRENT) == EV_NONE)
68  panic("wrong elf version number!");
69 
70  ObjectFile *object = nullptr;
71 
72  // get a pointer to elf structure
73  // Check that we actually have a elf file
74  Elf *elf =
75  elf_memory((char *)const_cast<uint8_t *>(ifd->data()), ifd->len());
76  assert(elf);
77 
78  GElf_Ehdr ehdr;
79  if (gelf_getehdr(elf, &ehdr) == 0)
80  DPRINTFR(Loader, "Not ELF\n");
81  else
82  object = new ElfObject(ifd);
83 
84  elf_end(elf);
85 
86  return object;
87 }
88 
89 namespace
90 {
91 
92 ElfObjectFormat elfObjectFormat;
93 std::string interpDir;
94 
95 } // anonymous namespace
96 
97 void
98 setInterpDir(const std::string &dirname)
99 {
100  fatal_if(!interpDir.empty(),
101  "Error: setInterpDir has already been called once\n");
102  interpDir = dirname;
103 }
104 
106 {
107  // get a pointer to elf structure
108  elf = elf_memory((char *)const_cast<uint8_t *>(imageData->data()),
109  imageData->len());
110  assert(elf);
111  gelf_getehdr(elf, &ehdr);
112 
113  determineArch();
114  determineOpSys();
115 
116  entry = ehdr.e_entry;
117  _programHeaderCount = ehdr.e_phnum;
118  _programHeaderSize = ehdr.e_phentsize;
119 
120  // Go through all the segments in the program and record them.
121  for (int i = 0; i < ehdr.e_phnum; ++i) {
122  GElf_Phdr phdr;
123  if (gelf_getphdr(elf, i, &phdr) == 0) {
124  panic("gelf_getphdr failed for segment %d.", i);
125  }
126 
127  if (phdr.p_type == PT_LOAD)
128  handleLoadableSegment(phdr, i);
129  if (phdr.p_type == PT_INTERP) {
130  // Make sure the interpreter is an valid ELF file.
131  auto interp_path = getInterpPath(phdr);
132  ObjectFile *obj = createObjectFile(interp_path);
133  interpreter = dynamic_cast<ElfObject *>(obj);
134  assert(interpreter != nullptr);
135  _symtab.insert(obj->symtab());
136  }
137  }
138 
139  // should have found at least one loadable segment
140  warn_if(image.segments().empty(),
141  "No loadable segments in '%s'. ELF file corrupted?\n",
142  imageData->filename());
143 
144  for (auto M5_VAR_USED &seg: image.segments())
145  DPRINTFR(Loader, "%s\n", seg);
146 
147  // We will actually read the sections when we need to load them
148 
149  // check that header matches library version
150  if (elf_version(EV_CURRENT) == EV_NONE)
151  panic("wrong elf version number!");
152 
153  // Get the first section
154  int sec_idx = 1; // there is a 0 but it is nothing, go figure
155  Elf_Scn *section = elf_getscn(elf, sec_idx);
156 
157  // While there are no more sections
158  while (section) {
159  GElf_Shdr shdr;
160  gelf_getshdr(section, &shdr);
161 
162  if (shdr.sh_type == SHT_SYMTAB) {
163  Elf_Data *data = elf_getdata(section, nullptr);
164  int count = shdr.sh_size / shdr.sh_entsize;
165  DPRINTF(Loader, "Found Symbol Table, %d symbols present.", count);
166 
167  // Loop through all the symbols.
168  for (int i = 0; i < count; ++i) {
169  GElf_Sym sym;
170  gelf_getsym(data, i, &sym);
171 
172  char *sym_name = elf_strptr(elf, shdr.sh_link, sym.st_name);
173  if (!sym_name || sym_name[0] == '$')
174  continue;
175 
176  Loader::Symbol symbol;
177  symbol.address = sym.st_value;
178  symbol.name = sym_name;
179 
180  switch (GELF_ST_BIND(sym.st_info)) {
181  case STB_GLOBAL:
183  break;
184  case STB_LOCAL:
186  break;
187  case STB_WEAK:
189  break;
190  default:
191  continue;
192  }
193 
194  if (_symtab.insert(symbol)) {
195  DPRINTF(Loader, "Symbol: %-40s value %#x.\n",
196  symbol.name, symbol.address);
197  }
198  }
199  }
200  ++sec_idx;
201  section = elf_getscn(elf, sec_idx);
202  }
203 }
204 
205 std::string
206 ElfObject::getInterpPath(const GElf_Phdr &phdr) const
207 {
208  // This is the interpreter path as specified in the elf file
209  const std::string elf_path = (char *)imageData->data() + phdr.p_offset;
210  if (!interpDir.empty())
211  return interpDir + elf_path;
212  else
213  return elf_path;
214 }
215 
216 void
218 {
219  auto &emach = ehdr.e_machine;
220  auto &eclass = ehdr.e_ident[EI_CLASS];
221  auto &edata = ehdr.e_ident[EI_DATA];
222 
223  // Detect the architecture
224  if (emach == EM_SPARC64 || (emach == EM_SPARC && eclass == ELFCLASS64) ||
225  emach == EM_SPARCV9) {
226  arch = SPARC64;
227  } else if (emach == EM_SPARC32PLUS ||
228  (emach == EM_SPARC && eclass == ELFCLASS32)) {
229  arch = SPARC32;
230  } else if (emach == EM_MIPS && eclass == ELFCLASS32) {
231  arch = Mips;
232  if (edata != ELFDATA2LSB) {
233  fatal("The binary you're trying to load is compiled for big "
234  "endian MIPS. gem5\nonly supports little endian MIPS. "
235  "Please recompile your binary.\n");
236  }
237  } else if (emach == EM_X86_64 && eclass == ELFCLASS64) {
238  arch = X86_64;
239  } else if (emach == EM_386 && eclass == ELFCLASS32) {
240  arch = I386;
241  } else if (emach == EM_ARM && eclass == ELFCLASS32) {
242  arch = bits(ehdr.e_entry, 0) ? Thumb : Arm;
243  } else if (emach == EM_AARCH64 && eclass == ELFCLASS64) {
244  arch = Arm64;
245  } else if (emach == EM_RISCV) {
246  arch = (eclass == ELFCLASS64) ? Riscv64 : Riscv32;
247  } else if (emach == EM_PPC && eclass == ELFCLASS32) {
248  arch = Power;
249  if (edata != ELFDATA2MSB) {
250  fatal("The binary you're trying to load is compiled for "
251  "little endian Power.\ngem5 only supports big "
252  "endian Power. Please recompile your binary.\n");
253  }
254  } else if (emach == EM_PPC64) {
255  fatal("The binary you're trying to load is compiled for 64-bit "
256  "Power. M5\n only supports 32-bit Power. Please "
257  "recompile your binary.\n");
258  } else {
259  warn("Unknown architecture: %d\n", emach);
260  }
261 }
262 
263 void
265 {
266  // Detect the operating system
267  switch (ehdr.e_ident[EI_OSABI]) {
268  case ELFOSABI_LINUX:
269  opSys = Linux;
270  return;
271  case ELFOSABI_SOLARIS:
272  opSys = Solaris;
273  return;
274  case ELFOSABI_TRU64:
275  opSys = Tru64;
276  return;
277  case ELFOSABI_ARM:
279  return;
280  case ELFOSABI_FREEBSD:
281  opSys = FreeBSD;
282  return;
283  default:
285  }
286 
287  Elf_Scn *section = elf_getscn(elf, 1);
288  for (int sec_idx = 1; section; section = elf_getscn(elf, ++sec_idx)) {
289  GElf_Shdr shdr;
290  gelf_getshdr(section, &shdr);
291 
292  char *e_str = elf_strptr(elf, ehdr.e_shstrndx, shdr.sh_name);
293  if (shdr.sh_type == SHT_NOTE && !strcmp(".note.ABI-tag", e_str)) {
294  // we have found a ABI note section
295  // Check the 5th 32bit word for OS 0 == linux, 1 == hurd,
296  // 2 == solaris, 3 == freebsd
297  Elf_Data *raw_data = elf_rawdata(section, nullptr);
298  assert(raw_data && raw_data->d_buf);
299 
300  uint32_t raw_abi = ((uint32_t *)raw_data->d_buf)[4];
301  bool is_le = ehdr.e_ident[EI_DATA] == ELFDATA2LSB;
302  uint32_t os_abi = is_le ? htole(raw_abi) : htobe(raw_abi);
303 
304  switch (os_abi) {
305  case 0:
306  opSys = Linux;
307  return;
308  case 1:
309  fatal("gem5 does not support the HURD ABI.\n");
310  case 2:
311  opSys = Solaris;
312  return;
313  case 3:
314  opSys = FreeBSD;
315  return;
316  }
317  }
318 
319  if (!strcmp(".SUNW_version", e_str) || !strcmp(".stab.index", e_str)) {
320  opSys = Solaris;
321  return;
322  }
323  }
324 }
325 
326 void
327 ElfObject::handleLoadableSegment(GElf_Phdr phdr, int seg_num)
328 {
329  auto name = std::to_string(seg_num);
330 
331  image.addSegment({ name, phdr.p_paddr, imageData,
332  phdr.p_offset, phdr.p_filesz });
333  Addr uninitialized = phdr.p_memsz - phdr.p_filesz;
334  if (uninitialized) {
335  // There may be parts of a segment which aren't included in the
336  // file. In those cases, we need to create a new segment with no
337  // data to take up the extra space. This should be zeroed when
338  // loaded into memory.
339  image.addSegment({ name + "(uninitialized)",
340  phdr.p_paddr + phdr.p_filesz, uninitialized });
341  }
342 
343  const Addr file_start = phdr.p_offset;
344  const Addr file_end = file_start + phdr.p_filesz;
345 
346  // If there is a program header table, figure out the virtual
347  // address of the header table in the final memory image. We use
348  // the program headers themselves to translate from a file offset
349  // to the address in the image.
350  if (file_start <= ehdr.e_phoff && file_end > ehdr.e_phoff)
351  _programHeaderTable = phdr.p_vaddr + (ehdr.e_phoff - file_start);
352 }
353 
355 {
356  elf_end(elf);
357 }
358 
359 void
361 {
362  assert(!sectionNames.size());
363 
364  // check that header matches library version
365  if (elf_version(EV_CURRENT) == EV_NONE)
366  panic("wrong elf version number!");
367 
368  // get a pointer to elf structure
369  Elf *elf =
370  elf_memory((char *)const_cast<uint8_t *>(imageData->data()),
371  imageData->len());
372  assert(elf != NULL);
373 
374  // Check that we actually have a elf file
375  GElf_Ehdr ehdr;
376  if (gelf_getehdr(elf, &ehdr) ==0) {
377  panic("Not ELF, shouldn't be here");
378  }
379 
380  // Get the first section
381  int sec_idx = 1; // there is a 0 but it is nothing, go figure
382  Elf_Scn *section = elf_getscn(elf, sec_idx);
383 
384  // While there are no more sections
385  while (section) {
386  GElf_Shdr shdr;
387  gelf_getshdr(section, &shdr);
388  sectionNames.insert(elf_strptr(elf, ehdr.e_shstrndx, shdr.sh_name));
389  section = elf_getscn(elf, ++sec_idx);
390  } // while sections
391 
392  elf_end(elf);
393 }
394 
395 bool
396 ElfObject::sectionExists(std::string sec)
397 {
398  if (!sectionNames.size())
399  getSections();
400 
401  return sectionNames.find(sec) != sectionNames.end();
402 }
403 
404 
405 void
407 {
408  // Record the bias.
409  ldBias = bias_addr;
410 
411  // Patch the entry point with bias_addr.
412  entry += bias_addr;
413 
414  // Patch segments with the bias_addr.
415  image.offset(bias_addr);
416 }
417 
418 } // namespace Loader
fatal
#define fatal(...)
This implements a cprintf based fatal() function.
Definition: logging.hh:183
Loader::Symbol::address
Addr address
Definition: symtab.hh:56
Loader::Linux
@ Linux
Definition: object_file.hh:62
Loader::ElfObject::elf
Elf * elf
Definition: elf_object.hh:62
Loader::ElfObject::updateBias
void updateBias(Addr bias_addr) override
Definition: elf_object.cc:406
Loader::MemoryImage::offset
MemoryImage & offset(Addr by)
Definition: memory_image.hh:121
Loader::SPARC32
@ SPARC32
Definition: object_file.hh:47
warn
#define warn(...)
Definition: logging.hh:239
Loader::Symbol::Binding::Local
@ Local
Loader::ElfObject::_programHeaderTable
Addr _programHeaderTable
Definition: elf_object.hh:71
data
const char data[]
Definition: circlebuf.test.cc:42
Loader::ElfObject::sectionNames
std::set< std::string > sectionNames
Definition: elf_object.hh:74
Loader::Riscv32
@ Riscv32
Definition: object_file.hh:56
Loader::Thumb
@ Thumb
Definition: object_file.hh:53
Loader::ElfObject::getSections
void getSections()
Definition: elf_object.cc:360
ArmISA::i
Bitfield< 7 > i
Definition: miscregs_types.hh:63
Loader::ObjectFile::arch
Arch arch
Definition: object_file.hh:73
Loader::Arm
@ Arm
Definition: object_file.hh:52
Loader::ElfObject::ehdr
GElf_Ehdr ehdr
Definition: elf_object.hh:63
Loader::ElfObject::getInterpPath
std::string getInterpPath(const GElf_Phdr &phdr) const
Definition: elf_object.cc:206
htole
T htole(T value)
Definition: byteswap.hh:140
sc_dt::to_string
const std::string to_string(sc_enc enc)
Definition: sc_fxdefs.cc:91
Loader::ElfObject::_programHeaderCount
uint16_t _programHeaderCount
Definition: elf_object.hh:73
Loader::Power
@ Power
Definition: object_file.hh:54
Loader::createObjectFile
ObjectFile * createObjectFile(const std::string &fname, bool raw)
Definition: object_file.cc:61
X86ISA::count
count
Definition: misc.hh:703
Loader::ElfObject::ldBias
Addr ldBias
Definition: elf_object.hh:81
Loader::Solaris
@ Solaris
Definition: object_file.hh:63
Loader::SPARC64
@ SPARC64
Definition: object_file.hh:46
Loader::ElfObject::handleLoadableSegment
void handleLoadableSegment(GElf_Phdr phdr, int seg_num)
Definition: elf_object.cc:327
Loader::ElfObject
Definition: elf_object.hh:59
Loader::ImageFileDataPtr
std::shared_ptr< ImageFileData > ImageFileDataPtr
Definition: image_file_data.hh:55
Loader::Symbol::Binding::Global
@ Global
Loader::Riscv64
@ Riscv64
Definition: object_file.hh:55
Loader::setInterpDir
void setInterpDir(const std::string &dirname)
This is the interface for setting up a base path for the elf interpreter.
Definition: elf_object.cc:98
Loader::ElfObjectFormat
Definition: elf_object.hh:53
Loader::ElfObject::~ElfObject
~ElfObject()
Definition: elf_object.cc:354
Loader::ElfObject::sectionExists
bool sectionExists(std::string sec)
Definition: elf_object.cc:396
Loader
Definition: process.hh:39
Loader::ObjectFile
Definition: object_file.hh:70
elf_object.hh
Loader::ElfObject::ElfObject
ElfObject(ImageFileDataPtr ifd)
Definition: elf_object.cc:105
Loader::ObjectFile::symtab
const SymbolTable & symtab() const
Definition: object_file.hh:102
bitfield.hh
DPRINTF
#define DPRINTF(x,...)
Definition: trace.hh:234
Loader::ElfObject::determineOpSys
void determineOpSys()
Definition: elf_object.cc:264
Loader::ObjectFile::opSys
OpSys opSys
Definition: object_file.hh:74
Loader::UnknownOpSys
@ UnknownOpSys
Definition: object_file.hh:60
DPRINTFR
#define DPRINTFR(...)
Definition: trace.hh:236
Loader::I386
@ I386
Definition: object_file.hh:50
Loader::ElfObjectFormat::load
ObjectFile * load(ImageFileDataPtr data) override
Definition: elf_object.cc:64
Loader::ImageFile::imageData
ImageFileDataPtr imageData
Definition: image_file.hh:44
Addr
uint64_t Addr
Address type This will probably be moved somewhere else in the near future.
Definition: types.hh:142
Loader::ElfObject::interpreter
ElfObject * interpreter
Definition: elf_object.hh:76
name
const std::string & name()
Definition: trace.cc:50
Loader::ElfObject::image
MemoryImage image
Definition: elf_object.hh:101
Loader::Mips
@ Mips
Definition: object_file.hh:48
Loader::ElfObject::_programHeaderSize
uint16_t _programHeaderSize
Definition: elf_object.hh:72
warn_if
#define warn_if(cond,...)
Conditional warning macro that checks the supplied condition and only prints a warning if the conditi...
Definition: logging.hh:263
Loader::FreeBSD
@ FreeBSD
Definition: object_file.hh:65
Loader::ObjectFile::_symtab
SymbolTable _symtab
Definition: object_file.hh:76
Loader::Symbol::name
std::string name
Definition: symtab.hh:55
Loader::X86_64
@ X86_64
Definition: object_file.hh:49
Loader::Tru64
@ Tru64
Definition: object_file.hh:61
Loader::Symbol
Definition: symtab.hh:46
Loader::MemoryImage::segments
const std::vector< Segment > & segments() const
Definition: memory_image.hh:100
htobe
T htobe(T value)
Definition: byteswap.hh:142
Loader::LinuxArmOABI
@ LinuxArmOABI
Definition: object_file.hh:64
logging.hh
Loader::Arm64
@ Arm64
Definition: object_file.hh:51
trace.hh
Loader::SymbolTable::insert
bool insert(const Symbol &symbol)
Definition: symtab.cc:58
symtab.hh
Loader::ObjectFile::entry
Addr entry
Definition: object_file.hh:105
fatal_if
#define fatal_if(cond,...)
Conditional fatal macro that checks the supplied condition and only causes a fatal error if the condi...
Definition: logging.hh:219
Loader::ElfObject::determineArch
void determineArch()
Definition: elf_object.cc:217
X86ISA::seg
Bitfield< 2, 0 > seg
Definition: types.hh:82
Loader::Symbol::binding
Binding binding
Definition: symtab.hh:54
Loader::Symbol::Binding::Weak
@ Weak
byteswap.hh
panic
#define panic(...)
This implements a cprintf based panic() function.
Definition: logging.hh:171
Loader::MemoryImage::addSegment
void addSegment(const Segment &seg)
Definition: memory_image.hh:106
bits
T bits(T val, int first, int last)
Extract the bitfield from position 'first' to 'last' (inclusive) from 'val' and right justify it.
Definition: bitfield.hh:75

Generated on Wed Sep 30 2020 14:02:07 for gem5 by doxygen 1.8.17