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

Generated on Tue Sep 21 2021 12:24:57 for gem5 by doxygen 1.8.17