summaryrefslogtreecommitdiffstats
path: root/lld/lib/ReaderWriter/ELF/Mips/MipsSectionChunks.h
blob: 56cb8148f2e07329cc9ade31ce07e5157f656e2c (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
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
//===- 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

#include "MipsReginfo.h"
#include "SectionChunks.h"

namespace lld {
namespace elf {

template <typename ELFT> class MipsTargetLayout;
class MipsLinkingContext;

/// \brief Handle Mips .reginfo section
template <class ELFT> class MipsReginfoSection : public Section<ELFT> {
public:
  MipsReginfoSection(const ELFLinkingContext &ctx,
                     MipsTargetLayout<ELFT> &targetLayout,
                     const MipsReginfo &reginfo)
      : Section<ELFT>(ctx, ".reginfo", "MipsReginfo"),
        _targetLayout(targetLayout) {
    this->setOrder(MipsTargetLayout<ELFT>::ORDER_RO_NOTE);
    this->_entSize = sizeof(Elf_RegInfo);
    this->_fsize = sizeof(Elf_RegInfo);
    this->_msize = sizeof(Elf_RegInfo);
    this->_alignment = 4;
    this->_type = SHT_MIPS_REGINFO;
    this->_flags = SHF_ALLOC;

    std::memset(&_reginfo, 0, sizeof(_reginfo));
    _reginfo.ri_gprmask = reginfo._gpRegMask;
    _reginfo.ri_cprmask[0] = reginfo._cpRegMask[0];
    _reginfo.ri_cprmask[1] = reginfo._cpRegMask[1];
    _reginfo.ri_cprmask[2] = reginfo._cpRegMask[2];
    _reginfo.ri_cprmask[3] = reginfo._cpRegMask[3];
  }

  void write(ELFWriter *writer, TargetLayout<ELFT> &layout,
             llvm::FileOutputBuffer &buffer) override {
    uint8_t *dest = buffer.getBufferStart() + this->fileOffset();
    std::memcpy(dest, &_reginfo, this->_fsize);
  }

  void finalize() override {
    _reginfo.ri_gp_value = _targetLayout.getGPAddr();

    if (this->_outputSection)
      this->_outputSection->setType(this->_type);
  }

private:
  typedef llvm::object::Elf_RegInfo<ELFT> Elf_RegInfo;

  Elf_RegInfo _reginfo;
  MipsTargetLayout<ELFT> &_targetLayout;
};

/// \brief Handle .MIPS.options section
template <class ELFT> class MipsOptionsSection : public Section<ELFT> {
public:
  typedef typename std::vector<MipsReginfo>::const_iterator mask_const_iterator;

  MipsOptionsSection(const ELFLinkingContext &ctx,
                     MipsTargetLayout<ELFT> &targetLayout,
                     const MipsReginfo &reginfo)
      : Section<ELFT>(ctx, ".MIPS.options", "MipsOptions"),
        _targetLayout(targetLayout) {
    this->setOrder(MipsTargetLayout<ELFT>::ORDER_RO_NOTE);
    this->_entSize = 1;
    this->_alignment = 8;
    this->_fsize = llvm::RoundUpToAlignment(
        sizeof(Elf_Mips_Options) + sizeof(Elf_RegInfo), this->_alignment);
    this->_msize = this->_fsize;
    this->_type = SHT_MIPS_OPTIONS;
    this->_flags = SHF_ALLOC | SHF_MIPS_NOSTRIP;

    _header.kind = ODK_REGINFO;
    _header.size = this->_fsize;
    _header.section = 0;
    _header.info = 0;

    std::memset(&_reginfo, 0, sizeof(_reginfo));
    _reginfo.ri_gprmask = reginfo._gpRegMask;
    _reginfo.ri_cprmask[0] = reginfo._cpRegMask[0];
    _reginfo.ri_cprmask[1] = reginfo._cpRegMask[1];
    _reginfo.ri_cprmask[2] = reginfo._cpRegMask[2];
    _reginfo.ri_cprmask[3] = reginfo._cpRegMask[3];
  }

  void write(ELFWriter *writer, TargetLayout<ELFT> &layout,
             llvm::FileOutputBuffer &buffer) override {
    uint8_t *dest = buffer.getBufferStart() + this->fileOffset();
    std::memset(dest, 0, this->_fsize);
    std::memcpy(dest, &_header, sizeof(_header));
    std::memcpy(dest + sizeof(_header), &_reginfo, sizeof(_reginfo));
  }

  void finalize() override {
    _reginfo.ri_gp_value = _targetLayout.getGPAddr();

    if (this->_outputSection)
      this->_outputSection->setType(this->_type);
  }

private:
  typedef llvm::object::Elf_Mips_Options<ELFT> Elf_Mips_Options;
  typedef llvm::object::Elf_RegInfo<ELFT> Elf_RegInfo;

  Elf_Mips_Options _header;
  Elf_RegInfo _reginfo;
  MipsTargetLayout<ELFT> &_targetLayout;
};

/// \brief Handle Mips GOT section
template <class ELFT> class MipsGOTSection : public AtomSection<ELFT> {
public:
  MipsGOTSection(const MipsLinkingContext &ctx)
      : AtomSection<ELFT>(ctx, ".got", DefinedAtom::typeGOT,
                          DefinedAtom::permRW_,
                          MipsTargetLayout<ELFT>::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<ELFT>::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<ELFT>::appendAtom(atom);
      case R_MIPS_TLS_DTPMOD32:
      case R_MIPS_TLS_DTPMOD64:
        _hasNonLocal = true;
        break;
      }
    }

    if (!_hasNonLocal)
      ++_localCount;

    return AtomSection<ELFT>::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 ELFT> class MipsPLTSection : public AtomSection<ELFT> {
public:
  MipsPLTSection(const MipsLinkingContext &ctx)
      : AtomSection<ELFT>(ctx, ".plt", DefinedAtom::typeGOT,
                          DefinedAtom::permR_X,
                          MipsTargetLayout<ELFT>::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<ELFT>::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