summaryrefslogtreecommitdiffstats
path: root/lld/lib/ReaderWriter/ELF/DynamicFile.h
blob: 8a30d9fd31a596f153ad49a1947c49c09571a3c5 (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
//===- lib/ReaderWriter/ELF/DynamicFile.h ---------------------------------===//
//
//                             The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#ifndef LLD_READER_WRITER_ELF_DYNAMIC_FILE_H
#define LLD_READER_WRITER_ELF_DYNAMIC_FILE_H

#include "Atoms.h"
#include "lld/Core/SharedLibraryFile.h"
#include "lld/ReaderWriter/ELFLinkingContext.h"
#include "llvm/Object/ELF.h"
#include "llvm/Support/Path.h"
#include <unordered_map>

namespace lld {
namespace elf {
template <class ELFT> class DynamicFile : public SharedLibraryFile {
public:
  static ErrorOr<std::unique_ptr<DynamicFile>>
  create(std::unique_ptr<llvm::MemoryBuffer> mb, ELFLinkingContext &ctx);

  const SharedLibraryAtom *exports(StringRef name,
                                   bool dataSymbolOnly) const override {
    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);
  }

  StringRef getDSOName() const override { return _soname; }

protected:
  std::error_code doParse() override {
    std::error_code ec;
    _objFile.reset(
        new llvm::object::ELFFile<ELFT>(_mb->getBuffer(), ec));
    if (ec)
      return ec;

    llvm::object::ELFFile<ELFT> &obj = *_objFile;

    _soname = obj.getLoadName();
    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.begin_dynamic_symbols(), e = obj.end_dynamic_symbols();
         i != e; ++i) {
      auto name = obj.getSymbolName(i);
      if ((ec = name.getError()))
        return ec;

      // 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._atoms.push_back(newAtom);
        }
        continue;
      }
      _nameToSym[*name]._symbol = &*i;
    }
    return std::error_code();
  }

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

  mutable llvm::BumpPtrAllocator _alloc;
  std::unique_ptr<llvm::object::ELFFile<ELFT>> _objFile;
  /// \brief DT_SONAME
  StringRef _soname;

  struct SymAtomPair {
    SymAtomPair() : _symbol(nullptr), _atom(nullptr) {}
    const typename llvm::object::ELFFile<ELFT>::Elf_Sym *_symbol;
    const SharedLibraryAtom *_atom;
  };

  std::unique_ptr<MemoryBuffer> _mb;
  ELFLinkingContext &_ctx;
  bool _useShlibUndefines;
  mutable std::unordered_map<StringRef, SymAtomPair> _nameToSym;
};

template <class ELFT>
ErrorOr<std::unique_ptr<DynamicFile<ELFT>>>
DynamicFile<ELFT>::create(std::unique_ptr<llvm::MemoryBuffer> mb,
                          ELFLinkingContext &ctx) {
  return std::unique_ptr<DynamicFile>(new DynamicFile(std::move(mb), ctx));
}

} // end namespace elf
} // end namespace lld

#endif
OpenPOWER on IntegriCloud