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

Generated on Sun Jul 30 2023 01:56:51 for gem5 by doxygen 1.8.17