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

#include "ELFReader.h"
#include "MipsELFFile.h"
#include "MipsELFWriters.h"
#include "MipsTargetHandler.h"

namespace lld {
namespace elf {

template <class ELFT>
MipsTargetHandler<ELFT>::MipsTargetHandler(MipsLinkingContext &ctx)
    : _ctx(ctx), _targetLayout(new MipsTargetLayout<ELFT>(ctx, _abiInfoHandler)),
      _relocationHandler(
          createMipsRelocationHandler<ELFT>(ctx, *_targetLayout)) {}

template <class ELFT>
std::unique_ptr<Reader> MipsTargetHandler<ELFT>::getObjReader() {
  return llvm::make_unique<ELFReader<MipsELFFile<ELFT>>>(_ctx);
}

template <class ELFT>
std::unique_ptr<Reader> MipsTargetHandler<ELFT>::getDSOReader() {
  return llvm::make_unique<ELFReader<DynamicFile<ELFT>>>(_ctx);
}

template <class ELFT>
const TargetRelocationHandler &
MipsTargetHandler<ELFT>::getRelocationHandler() const {
  return *_relocationHandler;
}

template <class ELFT>
std::unique_ptr<Writer> MipsTargetHandler<ELFT>::getWriter() {
  switch (_ctx.getOutputELFType()) {
  case llvm::ELF::ET_EXEC:
    return llvm::make_unique<MipsExecutableWriter<ELFT>>(_ctx, *_targetLayout,
                                                         _abiInfoHandler);
  case llvm::ELF::ET_DYN:
    return llvm::make_unique<MipsDynamicLibraryWriter<ELFT>>(
        _ctx, *_targetLayout, _abiInfoHandler);
  case llvm::ELF::ET_REL:
    llvm_unreachable("TODO: support -r mode");
  default:
    llvm_unreachable("unsupported output type");
  }
}

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

template <class ELFT>
MipsSymbolTable<ELFT>::MipsSymbolTable(const ELFLinkingContext &ctx)
    : SymbolTable<ELFT>(ctx, ".symtab",
                        TargetLayout<ELFT>::ORDER_SYMBOL_TABLE) {}

template <class ELFT>
void MipsSymbolTable<ELFT>::addDefinedAtom(Elf_Sym &sym, const DefinedAtom *da,
                                           int64_t addr) {
  SymbolTable<ELFT>::addDefinedAtom(sym, da, addr);

  switch (da->codeModel()) {
  case DefinedAtom::codeMipsMicro:
    sym.st_other |= llvm::ELF::STO_MIPS_MICROMIPS;
    break;
  case DefinedAtom::codeMipsMicroPIC:
    sym.st_other |= llvm::ELF::STO_MIPS_MICROMIPS | llvm::ELF::STO_MIPS_PIC;
    break;
  default:
    break;
  }
}

template <class ELFT> void MipsSymbolTable<ELFT>::finalize(bool sort) {
  SymbolTable<ELFT>::finalize(sort);

  for (auto &ste : this->_symbolTable) {
    if (!ste._atom)
      continue;
    if (const auto *da = dyn_cast<DefinedAtom>(ste._atom)) {
      if (da->codeModel() == DefinedAtom::codeMipsMicro ||
          da->codeModel() == DefinedAtom::codeMipsMicroPIC) {
        // Adjust dynamic microMIPS symbol value. That allows a dynamic
        // linker to recognize and handle this symbol correctly.
        ste._symbol.st_value = ste._symbol.st_value | 1;
      }
    }
  }
}

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

template <class ELFT>
MipsDynamicSymbolTable<ELFT>::MipsDynamicSymbolTable(
    const ELFLinkingContext &ctx, MipsTargetLayout<ELFT> &layout)
    : DynamicSymbolTable<ELFT>(ctx, layout, ".dynsym",
                               TargetLayout<ELFT>::ORDER_DYNAMIC_SYMBOLS),
      _targetLayout(layout) {}

template <class ELFT> void MipsDynamicSymbolTable<ELFT>::sortSymbols() {
  typedef typename DynamicSymbolTable<ELFT>::SymbolEntry SymbolEntry;
  std::stable_sort(this->_symbolTable.begin(), this->_symbolTable.end(),
                   [this](const SymbolEntry &A, const SymbolEntry &B) {
                     if (A._symbol.getBinding() != STB_GLOBAL &&
                         B._symbol.getBinding() != STB_GLOBAL)
                       return A._symbol.getBinding() < B._symbol.getBinding();

                     return _targetLayout.getGOTSection().compare(A._atom,
                                                                  B._atom);
                   });
}

template <class ELFT> void MipsDynamicSymbolTable<ELFT>::finalize() {
  DynamicSymbolTable<ELFT>::finalize();

  const auto &pltSection = _targetLayout.getPLTSection();

  for (auto &ste : this->_symbolTable) {
    const Atom *a = ste._atom;
    if (!a)
      continue;
    if (auto *layout = pltSection.findPLTLayout(a)) {
      a = layout->_atom;
      // Under some conditions a dynamic symbol table record should hold
      // a symbol value of the corresponding PLT entry. For details look
      // at the PLT entry creation code in the class MipsRelocationPass.
      // Let's update atomLayout fields for such symbols.
      assert(!ste._atomLayout);
      ste._symbol.st_value = layout->_virtualAddr;
      ste._symbol.st_other |= ELF::STO_MIPS_PLT;
    }

    if (const auto *da = dyn_cast<DefinedAtom>(a)) {
      if (da->codeModel() == DefinedAtom::codeMipsMicro ||
          da->codeModel() == DefinedAtom::codeMipsMicroPIC) {
        // Adjust dynamic microMIPS symbol value. That allows a dynamic
        // linker to recognize and handle this symbol correctly.
        ste._symbol.st_value = ste._symbol.st_value | 1;
      }
    }
  }
}

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

}
}
OpenPOWER on IntegriCloud