summaryrefslogtreecommitdiffstats
path: root/lld/lib/ReaderWriter/ELF/DynamicFile.cpp
blob: 5339c7d66577ef415c7eeb43072bd2f007329fab (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
//===- lib/ReaderWriter/ELF/DynamicFile.cpp -------------------------------===//
//
//                             The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "DynamicFile.h"
#include "FileCommon.h"
#include "lld/ReaderWriter/ELFLinkingContext.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Object/ELF.h"
#include "llvm/Support/Path.h"

namespace lld {
namespace elf {

template <class ELFT>
DynamicFile<ELFT>::DynamicFile(std::unique_ptr<MemoryBuffer> mb,
                               ELFLinkingContext &ctx)
    : SharedLibraryFile(mb->getBufferIdentifier()), _mb(std::move(mb)),
      _ctx(ctx), _useShlibUndefines(ctx.useShlibUndefines()) {}

template <typename ELFT>
std::error_code DynamicFile<ELFT>::isCompatible(MemoryBufferRef mb,
                                                ELFLinkingContext &ctx) {
  return elf::isCompatible<ELFT>(mb, ctx);
}

template <class ELFT>
const SharedLibraryAtom *DynamicFile<ELFT>::exports(StringRef name,
                                                    bool dataSymbolOnly) const {
  assert(!dataSymbolOnly && "Invalid option for ELF exports!");
  // See if we have the symbol.
  auto sym = _nameToSym.find(name);
  if (sym == _nameToSym.end())
    return nullptr;
  // Have we already created a SharedLibraryAtom for it?
  if (sym->second._atom)
    return sym->second._atom;
  // Create a SharedLibraryAtom for this symbol.
  return sym->second._atom = new (_alloc)
             ELFDynamicAtom<ELFT>(*this, name, _soname, sym->second._symbol);
}

template <class ELFT> StringRef DynamicFile<ELFT>::getDSOName() const {
  return _soname;
}

template <class ELFT> bool DynamicFile<ELFT>::canParse(file_magic magic) {
  return magic == file_magic::elf_shared_object;
}

template <class ELFT> std::error_code DynamicFile<ELFT>::doParse() {
  typedef llvm::object::ELFFile<ELFT> ELFO;
  typedef typename ELFO::Elf_Shdr Elf_Shdr;
  typedef typename ELFO::Elf_Dyn Elf_Dyn;

  std::error_code ec;
  _objFile.reset(new ELFO(_mb->getBuffer(), ec));
  if (ec)
    return ec;

  ELFO &obj = *_objFile;

  const char *base = _mb->getBuffer().data();
  const Elf_Dyn *dynStart = nullptr;
  const Elf_Dyn *dynEnd = nullptr;

  const Elf_Shdr *dynSymSec = nullptr;
  for (const Elf_Shdr &sec : obj.sections()) {
    switch (sec.sh_type) {
    case llvm::ELF::SHT_DYNAMIC: {
      dynStart = reinterpret_cast<const Elf_Dyn *>(base + sec.sh_offset);
      uint64_t size = sec.sh_size;
      if (size % sizeof(Elf_Dyn))
        return llvm::object::object_error::parse_failed;
      dynEnd = dynStart + size / sizeof(Elf_Dyn);
      break;
    }
    case llvm::ELF::SHT_DYNSYM:
      dynSymSec = &sec;
      break;
    }
  }

  ErrorOr<StringRef> strTableOrErr = obj.getStringTableForSymtab(*dynSymSec);
  if (std::error_code ec = strTableOrErr.getError())
    return ec;
  StringRef stringTable = *strTableOrErr;

  for (const Elf_Dyn &dyn : llvm::make_range(dynStart, dynEnd)) {
    if (dyn.d_tag == llvm::ELF::DT_SONAME) {
      uint64_t offset = dyn.getVal();
      if (offset >= stringTable.size())
        return llvm::object::object_error::parse_failed;
      _soname = StringRef(stringTable.data() + offset);
      break;
    }
  }

  if (_soname.empty())
    _soname = llvm::sys::path::filename(path());

  // Create a map from names to dynamic symbol table entries.
  // TODO: This should use the object file's build in hash table instead if
  // it exists.
  for (auto i = obj.symbol_begin(dynSymSec), e = obj.symbol_end(dynSymSec);
       i != e; ++i) {
    auto name = i->getName(stringTable);
    if ((ec = name.getError()))
      return ec;

    // Dont add local symbols to dynamic entries. The first symbol in the
    // dynamic symbol table is a local symbol.
    if (i->getBinding() == llvm::ELF::STB_LOCAL)
      continue;

    // TODO: Add absolute symbols
    if (i->st_shndx == llvm::ELF::SHN_ABS)
      continue;

    if (i->st_shndx == llvm::ELF::SHN_UNDEF) {
      if (!_useShlibUndefines)
        continue;
      // Create an undefined atom.
      if (!name->empty()) {
        auto *newAtom = new (_alloc) ELFUndefinedAtom<ELFT>(*this, *name, &*i);
        _undefinedAtoms.push_back(newAtom);
      }
      continue;
    }
    _nameToSym[*name]._symbol = &*i;
  }
  return std::error_code();
}

template class DynamicFile<ELF32LE>;
template class DynamicFile<ELF32BE>;
template class DynamicFile<ELF64LE>;
template class DynamicFile<ELF64BE>;

} // end namespace elf
} // end namespace lld
OpenPOWER on IntegriCloud