blob: 26b54220ac0d6661e7d301cbb066d908e913298e [file] [log] [blame]
Peter Smithfb05cd92016-07-08 16:10:27 +00001//===- Thunks.cpp --------------------------------------------------------===//
2//
3// The LLVM Linker
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===---------------------------------------------------------------------===//
9//
10// This file contains both the Target independent and Target specific Thunk
11// classes
12//
13// A Thunk Object represents a single Thunk that will be written to an
14// InputSection when the InputSection contents are written. The InputSection
15// maintains a list of Thunks that it owns.
16//===---------------------------------------------------------------------===//
17
18#include "Thunks.h"
19#include "Error.h"
20#include "InputFiles.h"
21#include "InputSection.h"
22#include "OutputSections.h"
23#include "Symbols.h"
24#include "Target.h"
Rui Ueyama8b8d0052016-07-08 17:58:54 +000025#include "llvm/Support/Allocator.h"
Peter Smithfb05cd92016-07-08 16:10:27 +000026
27#include "llvm/Object/ELF.h"
28#include "llvm/Support/ELF.h"
29#include "llvm/Support/Endian.h"
30
31using namespace llvm;
32using namespace llvm::object;
33using namespace llvm::support::endian;
34using namespace llvm::ELF;
35
36namespace lld {
37namespace elf {
38
39template <class ELFT> Thunk<ELFT>::~Thunk() {}
40
41template <class ELFT>
42Thunk<ELFT>::Thunk(const SymbolBody &D, const InputSection<ELFT> &O)
43 : Destination(D), Owner(O), Offset(O.getThunkOff() + O.getThunksSize()) {}
44
45template <class ELFT> typename ELFT::uint Thunk<ELFT>::getVA() const {
46 return Owner.OutSec->getVA() + Owner.OutSecOff + Offset;
47}
48
49// ARM Target Thunks
50template <class ELFT> static uint64_t getARMThunkDestVA(const SymbolBody &S) {
51 return S.isInPlt() ? S.getPltVA<ELFT>() : S.getVA<ELFT>();
52}
53
54// Specific ARM Thunk implementations. The naming convention is:
55// Source State, TargetState, Target Requirement, ABS or PI, Range
56namespace {
57template <class ELFT>
58class ARMToThumbV7ABSLongThunk final : public Thunk<ELFT> {
59public:
60 uint32_t size() const override { return 12; }
61
62 void writeTo(uint8_t *Buf) const override {
63 const uint8_t ATData[] = {
64 0x00, 0xc0, 0x00, 0xe3, // movw ip,:lower16:S
65 0x00, 0xc0, 0x40, 0xe3, // movt ip,:upper16:S
66 0x1c, 0xff, 0x2f, 0xe1, // bx ip
67 };
68 uint64_t S = getARMThunkDestVA<ELFT>(this->Destination);
69 memcpy(Buf, ATData, sizeof(ATData));
70 Target->relocateOne(Buf, R_ARM_MOVW_ABS_NC, S);
71 Target->relocateOne(Buf + 4, R_ARM_MOVT_ABS, S);
72 }
73
74 ARMToThumbV7ABSLongThunk(const SymbolBody &Destination,
75 const InputSection<ELFT> &Owner)
76 : Thunk<ELFT>(Destination, Owner) {}
77};
78
79template <class ELFT> class ARMToThumbV7PILongThunk final : public Thunk<ELFT> {
80public:
81 uint32_t size() const override { return 16; }
82
83 void writeTo(uint8_t *Buf) const override {
84 const uint8_t ATData[] = {
85 0xf0, 0xcf, 0x0f, 0xe3, // P: movw ip,:lower16:S - (P + (L1-P) +8)
86 0x00, 0xc0, 0x40, 0xe3, // movt ip,:upper16:S - (P + (L1-P+4) +8)
87 0x0f, 0xc0, 0x8c, 0xe0, // L1: add ip, ip, pc
88 0x1c, 0xff, 0x2f, 0xe1, // bx r12
89 };
90 uint64_t S = getARMThunkDestVA<ELFT>(this->Destination);
91 uint64_t P = this->getVA();
92 memcpy(Buf, ATData, sizeof(ATData));
93 Target->relocateOne(Buf, R_ARM_MOVW_PREL_NC, S - P - 16);
94 Target->relocateOne(Buf + 4, R_ARM_MOVT_PREL, S - P - 12);
95 }
96
97 ARMToThumbV7PILongThunk(const SymbolBody &Destination,
98 const InputSection<ELFT> &Owner)
99 : Thunk<ELFT>(Destination, Owner) {}
100};
101
102template <class ELFT>
103class ThumbToARMV7ABSLongThunk final : public Thunk<ELFT> {
104public:
105 uint32_t size() const override { return 10; }
106
107 void writeTo(uint8_t *Buf) const override {
108 const uint8_t TAData[] = {
109 0x40, 0xf2, 0x00, 0x0c, // movw ip, :lower16:S
110 0xc0, 0xf2, 0x00, 0x0c, // movt ip, :upper16:S
111 0x60, 0x47, // bx ip
112 };
113 uint64_t S = getARMThunkDestVA<ELFT>(this->Destination);
114 memcpy(Buf, TAData, sizeof(TAData));
115 Target->relocateOne(Buf, R_ARM_THM_MOVW_ABS_NC, S);
116 Target->relocateOne(Buf + 4, R_ARM_THM_MOVT_ABS, S);
117 }
118
119 ThumbToARMV7ABSLongThunk(const SymbolBody &Destination,
120 const InputSection<ELFT> &Owner)
121 : Thunk<ELFT>(Destination, Owner) {}
122};
123
124template <class ELFT> class ThumbToARMV7PILongThunk final : public Thunk<ELFT> {
125public:
126 uint32_t size() const override { return 12; }
127
128 void writeTo(uint8_t *Buf) const override {
129 const uint8_t TAData[] = {
130 0x4f, 0xf6, 0xf4, 0x7c, // P: movw ip,:lower16:S - (P + (L1-P) + 4)
131 0xc0, 0xf2, 0x00, 0x0c, // movt ip,:upper16:S - (P + (L1-P+4) + 4)
132 0xfc, 0x44, // L1: add r12, pc
133 0x60, 0x47, // bx r12
134 };
135 uint64_t S = getARMThunkDestVA<ELFT>(this->Destination);
136 uint64_t P = this->getVA();
137 memcpy(Buf, TAData, sizeof(TAData));
138 Target->relocateOne(Buf, R_ARM_THM_MOVW_PREL_NC, S - P - 12);
139 Target->relocateOne(Buf + 4, R_ARM_THM_MOVT_PREL, S - P - 8);
140 }
141
142 ThumbToARMV7PILongThunk(const SymbolBody &Destination,
143 const InputSection<ELFT> &Owner)
144 : Thunk<ELFT>(Destination, Owner) {}
145};
146
147// Mips Thunks
148// Only the MIPS LA25 Thunk is supported, the implementation is delegated
149// to the MipsTargetInfo class in Target.cpp
150template <class ELFT> class MipsThunk : public Thunk<ELFT> {
151public:
152 MipsThunk(const SymbolBody &Destination, const InputSection<ELFT> &Owner);
153 uint32_t size() const override;
154 void writeTo(uint8_t *Buf) const override;
155};
156
157template <class ELFT>
158MipsThunk<ELFT>::MipsThunk(const SymbolBody &Destination,
159 const InputSection<ELFT> &Owner)
160 : Thunk<ELFT>(Destination, Owner) {}
161
162template <class ELFT> uint32_t MipsThunk<ELFT>::size() const { return 16; }
163
164template <class ELFT> void MipsThunk<ELFT>::writeTo(uint8_t *Buf) const {
165 const SymbolBody &D = this->Destination;
166 uint64_t S = D.getVA<ELFT>();
167 Target->writeThunk(Buf, S);
168}
169}
170
Rui Ueyama5e3d6042016-07-09 22:03:51 +0000171// Creates a thunk for Thumb-ARM interworking.
Peter Smithfb05cd92016-07-08 16:10:27 +0000172template <class ELFT>
Rui Ueyama5e3d6042016-07-09 22:03:51 +0000173static Thunk<ELFT> *createThunkArm(uint32_t Reloc, SymbolBody &S,
174 InputSection<ELFT> &IS) {
Peter Smithfb05cd92016-07-08 16:10:27 +0000175 bool NeedsPI = Config->Pic || Config->Pie || Config->Shared;
Rui Ueyama8b8d0052016-07-08 17:58:54 +0000176 BumpPtrAllocator &Alloc = IS.getFile()->Alloc;
177
Rui Ueyama5e3d6042016-07-09 22:03:51 +0000178 // ARM relocations need ARM to Thumb interworking Thunks.
179 // Thumb relocations need Thumb to ARM relocations.
180 // Use position independent Thunks if we require position independent code.
181 switch (Reloc) {
Peter Smithfb05cd92016-07-08 16:10:27 +0000182 case R_ARM_PC24:
183 case R_ARM_PLT32:
184 case R_ARM_JUMP24:
185 if (NeedsPI)
Rui Ueyama5e3d6042016-07-09 22:03:51 +0000186 return new (Alloc) ARMToThumbV7PILongThunk<ELFT>(S, IS);
187 return new (Alloc) ARMToThumbV7ABSLongThunk<ELFT>(S, IS);
Peter Smithfb05cd92016-07-08 16:10:27 +0000188 case R_ARM_THM_JUMP19:
189 case R_ARM_THM_JUMP24:
190 if (NeedsPI)
Rui Ueyama5e3d6042016-07-09 22:03:51 +0000191 return new (Alloc) ThumbToARMV7PILongThunk<ELFT>(S, IS);
192 return new (Alloc) ThumbToARMV7ABSLongThunk<ELFT>(S, IS);
Peter Smithfb05cd92016-07-08 16:10:27 +0000193 }
Rui Ueyama5e3d6042016-07-09 22:03:51 +0000194 fatal("unrecognized relocation type");
195}
196
197template <class ELFT>
198static void addThunkARM(uint32_t Reloc, SymbolBody &S, InputSection<ELFT> &IS) {
199 // Only one Thunk supported per symbol.
200 if (S.hasThunk<ELFT>())
201 return;
Rui Ueyama8b8d0052016-07-08 17:58:54 +0000202
Peter Smithfb05cd92016-07-08 16:10:27 +0000203 // ARM Thunks are added to the same InputSection as the relocation. This
204 // isn't strictly necessary but it makes it more likely that a limited range
205 // branch can reach the Thunk, and it makes Thunks to the PLT section easier
Rui Ueyama5e3d6042016-07-09 22:03:51 +0000206 Thunk<ELFT> *T = createThunkArm(Reloc, S, IS);
Rui Ueyama8b8d0052016-07-08 17:58:54 +0000207 IS.addThunk(T);
Rui Ueyama5e3d6042016-07-09 22:03:51 +0000208 if (auto *Sym = dyn_cast<DefinedRegular<ELFT>>(&S))
209 Sym->ThunkData = T;
210 else if (auto *Sym = dyn_cast<SharedSymbol<ELFT>>(&S))
211 Sym->ThunkData = T;
Peter Smithfb05cd92016-07-08 16:10:27 +0000212 else
Rui Ueyama5e3d6042016-07-09 22:03:51 +0000213 fatal("symbol not DefinedRegular or Shared");
Peter Smithfb05cd92016-07-08 16:10:27 +0000214}
215
216template <class ELFT>
Rui Ueyama8b8d0052016-07-08 17:58:54 +0000217static void addThunkMips(uint32_t RelocType, SymbolBody &S,
218 InputSection<ELFT> &IS) {
Rui Ueyama5e3d6042016-07-09 22:03:51 +0000219 // Only one Thunk supported per symbol.
Peter Smithfb05cd92016-07-08 16:10:27 +0000220 if (S.hasThunk<ELFT>())
Peter Smithfb05cd92016-07-08 16:10:27 +0000221 return;
Rui Ueyama8b8d0052016-07-08 17:58:54 +0000222
223 // Mips Thunks are added to the InputSection defining S.
Peter Smithfb05cd92016-07-08 16:10:27 +0000224 auto *R = cast<DefinedRegular<ELFT>>(&S);
225 auto *Sec = cast<InputSection<ELFT>>(R->Section);
Rui Ueyama8b8d0052016-07-08 17:58:54 +0000226 auto *T = new (IS.getFile()->Alloc) MipsThunk<ELFT>(S, *Sec);
Peter Smithfb05cd92016-07-08 16:10:27 +0000227 Sec->addThunk(T);
Rui Ueyama8b8d0052016-07-08 17:58:54 +0000228 R->ThunkData = T;
Peter Smithfb05cd92016-07-08 16:10:27 +0000229}
230
231template <class ELFT>
232void addThunk(uint32_t RelocType, SymbolBody &S, InputSection<ELFT> &IS) {
233 if (Config->EMachine == EM_ARM)
234 addThunkARM<ELFT>(RelocType, S, IS);
235 else if (Config->EMachine == EM_MIPS)
Rui Ueyama8b8d0052016-07-08 17:58:54 +0000236 addThunkMips<ELFT>(RelocType, S, IS);
Peter Smithfb05cd92016-07-08 16:10:27 +0000237 else
238 llvm_unreachable("add Thunk only supported for ARM and Mips");
239}
240
241template void addThunk<ELF32LE>(uint32_t, SymbolBody &,
242 InputSection<ELF32LE> &);
243template void addThunk<ELF32BE>(uint32_t, SymbolBody &,
244 InputSection<ELF32BE> &);
245template void addThunk<ELF64LE>(uint32_t, SymbolBody &,
246 InputSection<ELF64LE> &);
247template void addThunk<ELF64BE>(uint32_t, SymbolBody &,
248 InputSection<ELF64BE> &);
249
Rui Ueyamaec4220d2016-07-09 22:06:47 +0000250template class Thunk<ELF32LE>;
251template class Thunk<ELF32BE>;
252template class Thunk<ELF64LE>;
253template class Thunk<ELF64BE>;
Peter Smithfb05cd92016-07-08 16:10:27 +0000254
255} // namespace elf
256} // namespace lld