summaryrefslogtreecommitdiffstats
path: root/lld/lib/ReaderWriter/ELF/Mips/MipsSectionChunks.h
blob: fce2a15e8c965d898f4712406d903e9cedb7b653 (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
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
//===- lib/ReaderWriter/ELF/Mips/MipsSectionChunks.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_MIPS_MIPS_SECTION_CHUNKS_H
#define LLD_READER_WRITER_ELF_MIPS_MIPS_SECTION_CHUNKS_H

namespace lld {
namespace elf {

template <typename ELFT> class MipsTargetLayout;
class MipsLinkingContext;

/// \brief Handle Mips GOT section
template <class ELFType> class MipsGOTSection : public AtomSection<ELFType> {
public:
  MipsGOTSection(const MipsLinkingContext &ctx)
      : AtomSection<ELFType>(ctx, ".got", DefinedAtom::typeGOT,
                             DefinedAtom::permRW_,
                             MipsTargetLayout<ELFType>::ORDER_GOT),
        _hasNonLocal(false), _localCount(0) {
    this->_flags |= SHF_MIPS_GPREL;
    this->_alignment = 4;
  }

  /// \brief Number of local GOT entries.
  std::size_t getLocalCount() const { return _localCount; }

  /// \brief Number of global GOT entries.
  std::size_t getGlobalCount() const { return _posMap.size(); }

  /// \brief Does the atom have a global GOT entry?
  bool hasGlobalGOTEntry(const Atom *a) const {
    return _posMap.count(a) || _tlsMap.count(a);
  }

  /// \brief Compare two atoms accordingly theirs positions in the GOT.
  bool compare(const Atom *a, const Atom *b) const {
    auto ia = _posMap.find(a);
    auto ib = _posMap.find(b);

    if (ia != _posMap.end() && ib != _posMap.end())
      return ia->second < ib->second;

    return ia == _posMap.end() && ib != _posMap.end();
  }

  const lld::AtomLayout *appendAtom(const Atom *atom) override {
    const DefinedAtom *da = dyn_cast<DefinedAtom>(atom);

    for (const auto &r : *da) {
      if (r->kindNamespace() != lld::Reference::KindNamespace::ELF)
        continue;
      assert(r->kindArch() == Reference::KindArch::Mips);
      switch (r->kindValue()) {
      case LLD_R_MIPS_GLOBAL_GOT:
        _hasNonLocal = true;
        _posMap[r->target()] = _posMap.size();
        return AtomSection<ELFType>::appendAtom(atom);
      case R_MIPS_TLS_TPREL32:
      case R_MIPS_TLS_DTPREL32:
      case R_MIPS_TLS_TPREL64:
      case R_MIPS_TLS_DTPREL64:
        _hasNonLocal = true;
        _tlsMap[r->target()] = _tlsMap.size();
        return AtomSection<ELFType>::appendAtom(atom);
      case R_MIPS_TLS_DTPMOD32:
      case R_MIPS_TLS_DTPMOD64:
        _hasNonLocal = true;
        break;
      }
    }

    if (!_hasNonLocal)
      ++_localCount;

    return AtomSection<ELFType>::appendAtom(atom);
  }

private:
  /// \brief True if the GOT contains non-local entries.
  bool _hasNonLocal;

  /// \brief Number of local GOT entries.
  std::size_t _localCount;

  /// \brief Map TLS Atoms to their GOT entry index.
  llvm::DenseMap<const Atom *, std::size_t> _tlsMap;

  /// \brief Map Atoms to their GOT entry index.
  llvm::DenseMap<const Atom *, std::size_t> _posMap;
};

/// \brief Handle Mips PLT section
template <class ELFType> class MipsPLTSection : public AtomSection<ELFType> {
public:
  MipsPLTSection(const MipsLinkingContext &ctx)
      : AtomSection<ELFType>(ctx, ".plt", DefinedAtom::typeGOT,
                             DefinedAtom::permR_X,
                             MipsTargetLayout<ELFType>::ORDER_PLT) {}

  const AtomLayout *findPLTLayout(const Atom *plt) const {
    auto it = _pltLayoutMap.find(plt);
    return it != _pltLayoutMap.end() ? it->second : nullptr;
  }

  const lld::AtomLayout *appendAtom(const Atom *atom) override {
    const auto *layout = AtomSection<ELFType>::appendAtom(atom);

    const DefinedAtom *da = cast<DefinedAtom>(atom);

    for (const auto &r : *da) {
      if (r->kindNamespace() != lld::Reference::KindNamespace::ELF)
        continue;
      assert(r->kindArch() == Reference::KindArch::Mips);
      if (r->kindValue() == LLD_R_MIPS_STO_PLT) {
        _pltLayoutMap[r->target()] = layout;
        break;
      }
    }

    return layout;
  }

private:
  /// \brief Map PLT Atoms to their layouts.
  std::unordered_map<const Atom *, const AtomLayout *> _pltLayoutMap;
};

template <class ELFT> class MipsRelocationTable : public RelocationTable<ELFT> {
  typedef llvm::object::Elf_Rel_Impl<ELFT, false> Elf_Rel;
  typedef llvm::object::Elf_Rel_Impl<ELFT, true> Elf_Rela;

  static const bool _isMips64EL =
      ELFT::Is64Bits && ELFT::TargetEndianness == llvm::support::little;

public:
  MipsRelocationTable(const ELFLinkingContext &ctx, StringRef str,
                      int32_t order)
      : RelocationTable<ELFT>(ctx, str, order) {}

protected:
  void writeRela(ELFWriter *writer, Elf_Rela &r, const DefinedAtom &atom,
                 const Reference &ref) override {
    uint32_t rType = ref.kindValue() | (ref.tag() << 8);
    r.setSymbolAndType(this->getSymbolIndex(ref.target()), rType, _isMips64EL);
    r.r_offset = writer->addressOfAtom(&atom) + ref.offsetInAtom();
    // The addend is used only by relative relocations
    if (this->_ctx.isRelativeReloc(ref))
      r.r_addend = writer->addressOfAtom(ref.target()) + ref.addend();
    else
      r.r_addend = 0;
  }

  void writeRel(ELFWriter *writer, Elf_Rel &r, const DefinedAtom &atom,
                const Reference &ref) override {
    uint32_t rType = ref.kindValue() | (ref.tag() << 8);
    r.setSymbolAndType(this->getSymbolIndex(ref.target()), rType, _isMips64EL);
    r.r_offset = writer->addressOfAtom(&atom) + ref.offsetInAtom();
  }
};

} // elf
} // lld

#endif
OpenPOWER on IntegriCloud