xref: /freebsd/contrib/llvm-project/lld/ELF/Arch/PPC.cpp (revision 0b57cec536236d46e3dba9bd041533462f33dbb7)
1*0b57cec5SDimitry Andric //===- PPC.cpp ------------------------------------------------------------===//
2*0b57cec5SDimitry Andric //
3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*0b57cec5SDimitry Andric //
7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
8*0b57cec5SDimitry Andric 
9*0b57cec5SDimitry Andric #include "OutputSections.h"
10*0b57cec5SDimitry Andric #include "Symbols.h"
11*0b57cec5SDimitry Andric #include "SyntheticSections.h"
12*0b57cec5SDimitry Andric #include "Target.h"
13*0b57cec5SDimitry Andric #include "lld/Common/ErrorHandler.h"
14*0b57cec5SDimitry Andric #include "llvm/Support/Endian.h"
15*0b57cec5SDimitry Andric 
16*0b57cec5SDimitry Andric using namespace llvm;
17*0b57cec5SDimitry Andric using namespace llvm::support::endian;
18*0b57cec5SDimitry Andric using namespace llvm::ELF;
19*0b57cec5SDimitry Andric using namespace lld;
20*0b57cec5SDimitry Andric using namespace lld::elf;
21*0b57cec5SDimitry Andric 
22*0b57cec5SDimitry Andric namespace {
23*0b57cec5SDimitry Andric class PPC final : public TargetInfo {
24*0b57cec5SDimitry Andric public:
25*0b57cec5SDimitry Andric   PPC();
26*0b57cec5SDimitry Andric   RelExpr getRelExpr(RelType type, const Symbol &s,
27*0b57cec5SDimitry Andric                      const uint8_t *loc) const override;
28*0b57cec5SDimitry Andric   RelType getDynRel(RelType type) const override;
29*0b57cec5SDimitry Andric   void writeGotHeader(uint8_t *buf) const override;
30*0b57cec5SDimitry Andric   void writePltHeader(uint8_t *buf) const override {
31*0b57cec5SDimitry Andric     llvm_unreachable("should call writePPC32GlinkSection() instead");
32*0b57cec5SDimitry Andric   }
33*0b57cec5SDimitry Andric   void writePlt(uint8_t *buf, uint64_t gotPltEntryAddr, uint64_t pltEntryAddr,
34*0b57cec5SDimitry Andric     int32_t index, unsigned relOff) const override {
35*0b57cec5SDimitry Andric     llvm_unreachable("should call writePPC32GlinkSection() instead");
36*0b57cec5SDimitry Andric   }
37*0b57cec5SDimitry Andric   void writeGotPlt(uint8_t *buf, const Symbol &s) const override;
38*0b57cec5SDimitry Andric   bool needsThunk(RelExpr expr, RelType relocType, const InputFile *file,
39*0b57cec5SDimitry Andric                   uint64_t branchAddr, const Symbol &s) const override;
40*0b57cec5SDimitry Andric   uint32_t getThunkSectionSpacing() const override;
41*0b57cec5SDimitry Andric   bool inBranchRange(RelType type, uint64_t src, uint64_t dst) const override;
42*0b57cec5SDimitry Andric   void relocateOne(uint8_t *loc, RelType type, uint64_t val) const override;
43*0b57cec5SDimitry Andric   RelExpr adjustRelaxExpr(RelType type, const uint8_t *data,
44*0b57cec5SDimitry Andric                           RelExpr expr) const override;
45*0b57cec5SDimitry Andric   int getTlsGdRelaxSkip(RelType type) const override;
46*0b57cec5SDimitry Andric   void relaxTlsGdToIe(uint8_t *loc, RelType type, uint64_t val) const override;
47*0b57cec5SDimitry Andric   void relaxTlsGdToLe(uint8_t *loc, RelType type, uint64_t val) const override;
48*0b57cec5SDimitry Andric   void relaxTlsLdToLe(uint8_t *loc, RelType type, uint64_t val) const override;
49*0b57cec5SDimitry Andric   void relaxTlsIeToLe(uint8_t *loc, RelType type, uint64_t val) const override;
50*0b57cec5SDimitry Andric };
51*0b57cec5SDimitry Andric } // namespace
52*0b57cec5SDimitry Andric 
53*0b57cec5SDimitry Andric static uint16_t lo(uint32_t v) { return v; }
54*0b57cec5SDimitry Andric static uint16_t ha(uint32_t v) { return (v + 0x8000) >> 16; }
55*0b57cec5SDimitry Andric 
56*0b57cec5SDimitry Andric static uint32_t readFromHalf16(const uint8_t *loc) {
57*0b57cec5SDimitry Andric   return read32(config->isLE ? loc : loc - 2);
58*0b57cec5SDimitry Andric }
59*0b57cec5SDimitry Andric 
60*0b57cec5SDimitry Andric static void writeFromHalf16(uint8_t *loc, uint32_t insn) {
61*0b57cec5SDimitry Andric   write32(config->isLE ? loc : loc - 2, insn);
62*0b57cec5SDimitry Andric }
63*0b57cec5SDimitry Andric 
64*0b57cec5SDimitry Andric void elf::writePPC32GlinkSection(uint8_t *buf, size_t numEntries) {
65*0b57cec5SDimitry Andric   // On PPC Secure PLT ABI, bl foo@plt jumps to a call stub, which loads an
66*0b57cec5SDimitry Andric   // absolute address from a specific .plt slot (usually called .got.plt on
67*0b57cec5SDimitry Andric   // other targets) and jumps there.
68*0b57cec5SDimitry Andric   //
69*0b57cec5SDimitry Andric   // a) With immediate binding (BIND_NOW), the .plt entry is resolved at load
70*0b57cec5SDimitry Andric   // time. The .glink section is not used.
71*0b57cec5SDimitry Andric   // b) With lazy binding, the .plt entry points to a `b PLTresolve`
72*0b57cec5SDimitry Andric   // instruction in .glink, filled in by PPC::writeGotPlt().
73*0b57cec5SDimitry Andric 
74*0b57cec5SDimitry Andric   // Write N `b PLTresolve` first.
75*0b57cec5SDimitry Andric   for (size_t i = 0; i != numEntries; ++i)
76*0b57cec5SDimitry Andric     write32(buf + 4 * i, 0x48000000 | 4 * (numEntries - i));
77*0b57cec5SDimitry Andric   buf += 4 * numEntries;
78*0b57cec5SDimitry Andric 
79*0b57cec5SDimitry Andric   // Then write PLTresolve(), which has two forms: PIC and non-PIC. PLTresolve()
80*0b57cec5SDimitry Andric   // computes the PLT index (by computing the distance from the landing b to
81*0b57cec5SDimitry Andric   // itself) and calls _dl_runtime_resolve() (in glibc).
82*0b57cec5SDimitry Andric   uint32_t got = in.got->getVA();
83*0b57cec5SDimitry Andric   uint32_t glink = in.plt->getVA(); // VA of .glink
84*0b57cec5SDimitry Andric   const uint8_t *end = buf + 64;
85*0b57cec5SDimitry Andric   if (config->isPic) {
86*0b57cec5SDimitry Andric     uint32_t afterBcl = in.plt->getSize() - target->pltHeaderSize + 12;
87*0b57cec5SDimitry Andric     uint32_t gotBcl = got + 4 - (glink + afterBcl);
88*0b57cec5SDimitry Andric     write32(buf + 0, 0x3d6b0000 | ha(afterBcl));  // addis r11,r11,1f-glink@ha
89*0b57cec5SDimitry Andric     write32(buf + 4, 0x7c0802a6);                 // mflr r0
90*0b57cec5SDimitry Andric     write32(buf + 8, 0x429f0005);                 // bcl 20,30,.+4
91*0b57cec5SDimitry Andric     write32(buf + 12, 0x396b0000 | lo(afterBcl)); // 1: addi r11,r11,1b-.glink@l
92*0b57cec5SDimitry Andric     write32(buf + 16, 0x7d8802a6);                // mflr r12
93*0b57cec5SDimitry Andric     write32(buf + 20, 0x7c0803a6);                // mtlr r0
94*0b57cec5SDimitry Andric     write32(buf + 24, 0x7d6c5850);                // sub r11,r11,r12
95*0b57cec5SDimitry Andric     write32(buf + 28, 0x3d8c0000 | ha(gotBcl));   // addis 12,12,GOT+4-1b@ha
96*0b57cec5SDimitry Andric     if (ha(gotBcl) == ha(gotBcl + 4)) {
97*0b57cec5SDimitry Andric       write32(buf + 32, 0x800c0000 | lo(gotBcl)); // lwz r0,r12,GOT+4-1b@l(r12)
98*0b57cec5SDimitry Andric       write32(buf + 36,
99*0b57cec5SDimitry Andric               0x818c0000 | lo(gotBcl + 4));       // lwz r12,r12,GOT+8-1b@l(r12)
100*0b57cec5SDimitry Andric     } else {
101*0b57cec5SDimitry Andric       write32(buf + 32, 0x840c0000 | lo(gotBcl)); // lwzu r0,r12,GOT+4-1b@l(r12)
102*0b57cec5SDimitry Andric       write32(buf + 36, 0x818c0000 | 4);          // lwz r12,r12,4(r12)
103*0b57cec5SDimitry Andric     }
104*0b57cec5SDimitry Andric     write32(buf + 40, 0x7c0903a6);                // mtctr 0
105*0b57cec5SDimitry Andric     write32(buf + 44, 0x7c0b5a14);                // add r0,11,11
106*0b57cec5SDimitry Andric     write32(buf + 48, 0x7d605a14);                // add r11,0,11
107*0b57cec5SDimitry Andric     write32(buf + 52, 0x4e800420);                // bctr
108*0b57cec5SDimitry Andric     buf += 56;
109*0b57cec5SDimitry Andric   } else {
110*0b57cec5SDimitry Andric     write32(buf + 0, 0x3d800000 | ha(got + 4));   // lis     r12,GOT+4@ha
111*0b57cec5SDimitry Andric     write32(buf + 4, 0x3d6b0000 | ha(-glink));    // addis   r11,r11,-Glink@ha
112*0b57cec5SDimitry Andric     if (ha(got + 4) == ha(got + 8))
113*0b57cec5SDimitry Andric       write32(buf + 8, 0x800c0000 | lo(got + 4)); // lwz r0,GOT+4@l(r12)
114*0b57cec5SDimitry Andric     else
115*0b57cec5SDimitry Andric       write32(buf + 8, 0x840c0000 | lo(got + 4)); // lwzu r0,GOT+4@l(r12)
116*0b57cec5SDimitry Andric     write32(buf + 12, 0x396b0000 | lo(-glink));   // addi    r11,r11,-Glink@l
117*0b57cec5SDimitry Andric     write32(buf + 16, 0x7c0903a6);                // mtctr   r0
118*0b57cec5SDimitry Andric     write32(buf + 20, 0x7c0b5a14);                // add     r0,r11,r11
119*0b57cec5SDimitry Andric     if (ha(got + 4) == ha(got + 8))
120*0b57cec5SDimitry Andric       write32(buf + 24, 0x818c0000 | lo(got + 8)); // lwz r12,GOT+8@ha(r12)
121*0b57cec5SDimitry Andric     else
122*0b57cec5SDimitry Andric       write32(buf + 24, 0x818c0000 | 4);          // lwz r12,4(r12)
123*0b57cec5SDimitry Andric     write32(buf + 28, 0x7d605a14);                // add     r11,r0,r11
124*0b57cec5SDimitry Andric     write32(buf + 32, 0x4e800420);                // bctr
125*0b57cec5SDimitry Andric     buf += 36;
126*0b57cec5SDimitry Andric   }
127*0b57cec5SDimitry Andric 
128*0b57cec5SDimitry Andric   // Pad with nop. They should not be executed.
129*0b57cec5SDimitry Andric   for (; buf < end; buf += 4)
130*0b57cec5SDimitry Andric     write32(buf, 0x60000000);
131*0b57cec5SDimitry Andric }
132*0b57cec5SDimitry Andric 
133*0b57cec5SDimitry Andric PPC::PPC() {
134*0b57cec5SDimitry Andric   gotRel = R_PPC_GLOB_DAT;
135*0b57cec5SDimitry Andric   noneRel = R_PPC_NONE;
136*0b57cec5SDimitry Andric   pltRel = R_PPC_JMP_SLOT;
137*0b57cec5SDimitry Andric   relativeRel = R_PPC_RELATIVE;
138*0b57cec5SDimitry Andric   iRelativeRel = R_PPC_IRELATIVE;
139*0b57cec5SDimitry Andric   symbolicRel = R_PPC_ADDR32;
140*0b57cec5SDimitry Andric   gotBaseSymInGotPlt = false;
141*0b57cec5SDimitry Andric   gotHeaderEntriesNum = 3;
142*0b57cec5SDimitry Andric   gotPltHeaderEntriesNum = 0;
143*0b57cec5SDimitry Andric   pltHeaderSize = 64; // size of PLTresolve in .glink
144*0b57cec5SDimitry Andric   pltEntrySize = 4;
145*0b57cec5SDimitry Andric 
146*0b57cec5SDimitry Andric   needsThunks = true;
147*0b57cec5SDimitry Andric 
148*0b57cec5SDimitry Andric   tlsModuleIndexRel = R_PPC_DTPMOD32;
149*0b57cec5SDimitry Andric   tlsOffsetRel = R_PPC_DTPREL32;
150*0b57cec5SDimitry Andric   tlsGotRel = R_PPC_TPREL32;
151*0b57cec5SDimitry Andric 
152*0b57cec5SDimitry Andric   defaultMaxPageSize = 65536;
153*0b57cec5SDimitry Andric   defaultImageBase = 0x10000000;
154*0b57cec5SDimitry Andric 
155*0b57cec5SDimitry Andric   write32(trapInstr.data(), 0x7fe00008);
156*0b57cec5SDimitry Andric }
157*0b57cec5SDimitry Andric 
158*0b57cec5SDimitry Andric void PPC::writeGotHeader(uint8_t *buf) const {
159*0b57cec5SDimitry Andric   // _GLOBAL_OFFSET_TABLE_[0] = _DYNAMIC
160*0b57cec5SDimitry Andric   // glibc stores _dl_runtime_resolve in _GLOBAL_OFFSET_TABLE_[1],
161*0b57cec5SDimitry Andric   // link_map in _GLOBAL_OFFSET_TABLE_[2].
162*0b57cec5SDimitry Andric   write32(buf, mainPart->dynamic->getVA());
163*0b57cec5SDimitry Andric }
164*0b57cec5SDimitry Andric 
165*0b57cec5SDimitry Andric void PPC::writeGotPlt(uint8_t *buf, const Symbol &s) const {
166*0b57cec5SDimitry Andric   // Address of the symbol resolver stub in .glink .
167*0b57cec5SDimitry Andric   write32(buf, in.plt->getVA() + 4 * s.pltIndex);
168*0b57cec5SDimitry Andric }
169*0b57cec5SDimitry Andric 
170*0b57cec5SDimitry Andric bool PPC::needsThunk(RelExpr expr, RelType type, const InputFile *file,
171*0b57cec5SDimitry Andric                      uint64_t branchAddr, const Symbol &s) const {
172*0b57cec5SDimitry Andric   if (type != R_PPC_REL24 && type != R_PPC_PLTREL24)
173*0b57cec5SDimitry Andric     return false;
174*0b57cec5SDimitry Andric   if (s.isInPlt())
175*0b57cec5SDimitry Andric     return true;
176*0b57cec5SDimitry Andric   if (s.isUndefWeak())
177*0b57cec5SDimitry Andric     return false;
178*0b57cec5SDimitry Andric   return !(expr == R_PC && PPC::inBranchRange(type, branchAddr, s.getVA()));
179*0b57cec5SDimitry Andric }
180*0b57cec5SDimitry Andric 
181*0b57cec5SDimitry Andric uint32_t PPC::getThunkSectionSpacing() const { return 0x2000000; }
182*0b57cec5SDimitry Andric 
183*0b57cec5SDimitry Andric bool PPC::inBranchRange(RelType type, uint64_t src, uint64_t dst) const {
184*0b57cec5SDimitry Andric   uint64_t offset = dst - src;
185*0b57cec5SDimitry Andric   if (type == R_PPC_REL24 || type == R_PPC_PLTREL24)
186*0b57cec5SDimitry Andric     return isInt<26>(offset);
187*0b57cec5SDimitry Andric   llvm_unreachable("unsupported relocation type used in branch");
188*0b57cec5SDimitry Andric }
189*0b57cec5SDimitry Andric 
190*0b57cec5SDimitry Andric RelExpr PPC::getRelExpr(RelType type, const Symbol &s,
191*0b57cec5SDimitry Andric                         const uint8_t *loc) const {
192*0b57cec5SDimitry Andric   switch (type) {
193*0b57cec5SDimitry Andric   case R_PPC_NONE:
194*0b57cec5SDimitry Andric     return R_NONE;
195*0b57cec5SDimitry Andric   case R_PPC_ADDR16_HA:
196*0b57cec5SDimitry Andric   case R_PPC_ADDR16_HI:
197*0b57cec5SDimitry Andric   case R_PPC_ADDR16_LO:
198*0b57cec5SDimitry Andric   case R_PPC_ADDR32:
199*0b57cec5SDimitry Andric     return R_ABS;
200*0b57cec5SDimitry Andric   case R_PPC_DTPREL16:
201*0b57cec5SDimitry Andric   case R_PPC_DTPREL16_HA:
202*0b57cec5SDimitry Andric   case R_PPC_DTPREL16_HI:
203*0b57cec5SDimitry Andric   case R_PPC_DTPREL16_LO:
204*0b57cec5SDimitry Andric   case R_PPC_DTPREL32:
205*0b57cec5SDimitry Andric     return R_DTPREL;
206*0b57cec5SDimitry Andric   case R_PPC_REL14:
207*0b57cec5SDimitry Andric   case R_PPC_REL32:
208*0b57cec5SDimitry Andric   case R_PPC_LOCAL24PC:
209*0b57cec5SDimitry Andric   case R_PPC_REL16_LO:
210*0b57cec5SDimitry Andric   case R_PPC_REL16_HI:
211*0b57cec5SDimitry Andric   case R_PPC_REL16_HA:
212*0b57cec5SDimitry Andric     return R_PC;
213*0b57cec5SDimitry Andric   case R_PPC_GOT16:
214*0b57cec5SDimitry Andric     return R_GOT_OFF;
215*0b57cec5SDimitry Andric   case R_PPC_REL24:
216*0b57cec5SDimitry Andric     return R_PLT_PC;
217*0b57cec5SDimitry Andric   case R_PPC_PLTREL24:
218*0b57cec5SDimitry Andric     return R_PPC32_PLTREL;
219*0b57cec5SDimitry Andric   case R_PPC_GOT_TLSGD16:
220*0b57cec5SDimitry Andric     return R_TLSGD_GOT;
221*0b57cec5SDimitry Andric   case R_PPC_GOT_TLSLD16:
222*0b57cec5SDimitry Andric     return R_TLSLD_GOT;
223*0b57cec5SDimitry Andric   case R_PPC_GOT_TPREL16:
224*0b57cec5SDimitry Andric     return R_GOT_OFF;
225*0b57cec5SDimitry Andric   case R_PPC_TLS:
226*0b57cec5SDimitry Andric     return R_TLSIE_HINT;
227*0b57cec5SDimitry Andric   case R_PPC_TLSGD:
228*0b57cec5SDimitry Andric     return R_TLSDESC_CALL;
229*0b57cec5SDimitry Andric   case R_PPC_TLSLD:
230*0b57cec5SDimitry Andric     return R_TLSLD_HINT;
231*0b57cec5SDimitry Andric   case R_PPC_TPREL16:
232*0b57cec5SDimitry Andric   case R_PPC_TPREL16_HA:
233*0b57cec5SDimitry Andric   case R_PPC_TPREL16_LO:
234*0b57cec5SDimitry Andric   case R_PPC_TPREL16_HI:
235*0b57cec5SDimitry Andric     return R_TLS;
236*0b57cec5SDimitry Andric   default:
237*0b57cec5SDimitry Andric     error(getErrorLocation(loc) + "unknown relocation (" + Twine(type) +
238*0b57cec5SDimitry Andric           ") against symbol " + toString(s));
239*0b57cec5SDimitry Andric     return R_NONE;
240*0b57cec5SDimitry Andric   }
241*0b57cec5SDimitry Andric }
242*0b57cec5SDimitry Andric 
243*0b57cec5SDimitry Andric RelType PPC::getDynRel(RelType type) const {
244*0b57cec5SDimitry Andric   if (type == R_PPC_ADDR32)
245*0b57cec5SDimitry Andric     return type;
246*0b57cec5SDimitry Andric   return R_PPC_NONE;
247*0b57cec5SDimitry Andric }
248*0b57cec5SDimitry Andric 
249*0b57cec5SDimitry Andric static std::pair<RelType, uint64_t> fromDTPREL(RelType type, uint64_t val) {
250*0b57cec5SDimitry Andric   uint64_t dtpBiasedVal = val - 0x8000;
251*0b57cec5SDimitry Andric   switch (type) {
252*0b57cec5SDimitry Andric   case R_PPC_DTPREL16:
253*0b57cec5SDimitry Andric     return {R_PPC64_ADDR16, dtpBiasedVal};
254*0b57cec5SDimitry Andric   case R_PPC_DTPREL16_HA:
255*0b57cec5SDimitry Andric     return {R_PPC_ADDR16_HA, dtpBiasedVal};
256*0b57cec5SDimitry Andric   case R_PPC_DTPREL16_HI:
257*0b57cec5SDimitry Andric     return {R_PPC_ADDR16_HI, dtpBiasedVal};
258*0b57cec5SDimitry Andric   case R_PPC_DTPREL16_LO:
259*0b57cec5SDimitry Andric     return {R_PPC_ADDR16_LO, dtpBiasedVal};
260*0b57cec5SDimitry Andric   case R_PPC_DTPREL32:
261*0b57cec5SDimitry Andric     return {R_PPC_ADDR32, dtpBiasedVal};
262*0b57cec5SDimitry Andric   default:
263*0b57cec5SDimitry Andric     return {type, val};
264*0b57cec5SDimitry Andric   }
265*0b57cec5SDimitry Andric }
266*0b57cec5SDimitry Andric 
267*0b57cec5SDimitry Andric void PPC::relocateOne(uint8_t *loc, RelType type, uint64_t val) const {
268*0b57cec5SDimitry Andric   RelType newType;
269*0b57cec5SDimitry Andric   std::tie(newType, val) = fromDTPREL(type, val);
270*0b57cec5SDimitry Andric   switch (newType) {
271*0b57cec5SDimitry Andric   case R_PPC_ADDR16:
272*0b57cec5SDimitry Andric     checkIntUInt(loc, val, 16, type);
273*0b57cec5SDimitry Andric     write16(loc, val);
274*0b57cec5SDimitry Andric     break;
275*0b57cec5SDimitry Andric   case R_PPC_GOT16:
276*0b57cec5SDimitry Andric   case R_PPC_GOT_TLSGD16:
277*0b57cec5SDimitry Andric   case R_PPC_GOT_TLSLD16:
278*0b57cec5SDimitry Andric   case R_PPC_GOT_TPREL16:
279*0b57cec5SDimitry Andric   case R_PPC_TPREL16:
280*0b57cec5SDimitry Andric     checkInt(loc, val, 16, type);
281*0b57cec5SDimitry Andric     write16(loc, val);
282*0b57cec5SDimitry Andric     break;
283*0b57cec5SDimitry Andric   case R_PPC_ADDR16_HA:
284*0b57cec5SDimitry Andric   case R_PPC_DTPREL16_HA:
285*0b57cec5SDimitry Andric   case R_PPC_GOT_TLSGD16_HA:
286*0b57cec5SDimitry Andric   case R_PPC_GOT_TLSLD16_HA:
287*0b57cec5SDimitry Andric   case R_PPC_GOT_TPREL16_HA:
288*0b57cec5SDimitry Andric   case R_PPC_REL16_HA:
289*0b57cec5SDimitry Andric   case R_PPC_TPREL16_HA:
290*0b57cec5SDimitry Andric     write16(loc, ha(val));
291*0b57cec5SDimitry Andric     break;
292*0b57cec5SDimitry Andric   case R_PPC_ADDR16_HI:
293*0b57cec5SDimitry Andric   case R_PPC_DTPREL16_HI:
294*0b57cec5SDimitry Andric   case R_PPC_GOT_TLSGD16_HI:
295*0b57cec5SDimitry Andric   case R_PPC_GOT_TLSLD16_HI:
296*0b57cec5SDimitry Andric   case R_PPC_GOT_TPREL16_HI:
297*0b57cec5SDimitry Andric   case R_PPC_REL16_HI:
298*0b57cec5SDimitry Andric   case R_PPC_TPREL16_HI:
299*0b57cec5SDimitry Andric     write16(loc, val >> 16);
300*0b57cec5SDimitry Andric     break;
301*0b57cec5SDimitry Andric   case R_PPC_ADDR16_LO:
302*0b57cec5SDimitry Andric   case R_PPC_DTPREL16_LO:
303*0b57cec5SDimitry Andric   case R_PPC_GOT_TLSGD16_LO:
304*0b57cec5SDimitry Andric   case R_PPC_GOT_TLSLD16_LO:
305*0b57cec5SDimitry Andric   case R_PPC_GOT_TPREL16_LO:
306*0b57cec5SDimitry Andric   case R_PPC_REL16_LO:
307*0b57cec5SDimitry Andric   case R_PPC_TPREL16_LO:
308*0b57cec5SDimitry Andric     write16(loc, val);
309*0b57cec5SDimitry Andric     break;
310*0b57cec5SDimitry Andric   case R_PPC_ADDR32:
311*0b57cec5SDimitry Andric   case R_PPC_REL32:
312*0b57cec5SDimitry Andric     write32(loc, val);
313*0b57cec5SDimitry Andric     break;
314*0b57cec5SDimitry Andric   case R_PPC_REL14: {
315*0b57cec5SDimitry Andric     uint32_t mask = 0x0000FFFC;
316*0b57cec5SDimitry Andric     checkInt(loc, val, 16, type);
317*0b57cec5SDimitry Andric     checkAlignment(loc, val, 4, type);
318*0b57cec5SDimitry Andric     write32(loc, (read32(loc) & ~mask) | (val & mask));
319*0b57cec5SDimitry Andric     break;
320*0b57cec5SDimitry Andric   }
321*0b57cec5SDimitry Andric   case R_PPC_REL24:
322*0b57cec5SDimitry Andric   case R_PPC_LOCAL24PC:
323*0b57cec5SDimitry Andric   case R_PPC_PLTREL24: {
324*0b57cec5SDimitry Andric     uint32_t mask = 0x03FFFFFC;
325*0b57cec5SDimitry Andric     checkInt(loc, val, 26, type);
326*0b57cec5SDimitry Andric     checkAlignment(loc, val, 4, type);
327*0b57cec5SDimitry Andric     write32(loc, (read32(loc) & ~mask) | (val & mask));
328*0b57cec5SDimitry Andric     break;
329*0b57cec5SDimitry Andric   }
330*0b57cec5SDimitry Andric   default:
331*0b57cec5SDimitry Andric     llvm_unreachable("unknown relocation");
332*0b57cec5SDimitry Andric   }
333*0b57cec5SDimitry Andric }
334*0b57cec5SDimitry Andric 
335*0b57cec5SDimitry Andric RelExpr PPC::adjustRelaxExpr(RelType type, const uint8_t *data,
336*0b57cec5SDimitry Andric                              RelExpr expr) const {
337*0b57cec5SDimitry Andric   if (expr == R_RELAX_TLS_GD_TO_IE)
338*0b57cec5SDimitry Andric     return R_RELAX_TLS_GD_TO_IE_GOT_OFF;
339*0b57cec5SDimitry Andric   if (expr == R_RELAX_TLS_LD_TO_LE)
340*0b57cec5SDimitry Andric     return R_RELAX_TLS_LD_TO_LE_ABS;
341*0b57cec5SDimitry Andric   return expr;
342*0b57cec5SDimitry Andric }
343*0b57cec5SDimitry Andric 
344*0b57cec5SDimitry Andric int PPC::getTlsGdRelaxSkip(RelType type) const {
345*0b57cec5SDimitry Andric   // A __tls_get_addr call instruction is marked with 2 relocations:
346*0b57cec5SDimitry Andric   //
347*0b57cec5SDimitry Andric   //   R_PPC_TLSGD / R_PPC_TLSLD: marker relocation
348*0b57cec5SDimitry Andric   //   R_PPC_REL24: __tls_get_addr
349*0b57cec5SDimitry Andric   //
350*0b57cec5SDimitry Andric   // After the relaxation we no longer call __tls_get_addr and should skip both
351*0b57cec5SDimitry Andric   // relocations to not create a false dependence on __tls_get_addr being
352*0b57cec5SDimitry Andric   // defined.
353*0b57cec5SDimitry Andric   if (type == R_PPC_TLSGD || type == R_PPC_TLSLD)
354*0b57cec5SDimitry Andric     return 2;
355*0b57cec5SDimitry Andric   return 1;
356*0b57cec5SDimitry Andric }
357*0b57cec5SDimitry Andric 
358*0b57cec5SDimitry Andric void PPC::relaxTlsGdToIe(uint8_t *loc, RelType type, uint64_t val) const {
359*0b57cec5SDimitry Andric   switch (type) {
360*0b57cec5SDimitry Andric   case R_PPC_GOT_TLSGD16: {
361*0b57cec5SDimitry Andric     // addi rT, rA, x@got@tlsgd --> lwz rT, x@got@tprel(rA)
362*0b57cec5SDimitry Andric     uint32_t insn = readFromHalf16(loc);
363*0b57cec5SDimitry Andric     writeFromHalf16(loc, 0x80000000 | (insn & 0x03ff0000));
364*0b57cec5SDimitry Andric     relocateOne(loc, R_PPC_GOT_TPREL16, val);
365*0b57cec5SDimitry Andric     break;
366*0b57cec5SDimitry Andric   }
367*0b57cec5SDimitry Andric   case R_PPC_TLSGD:
368*0b57cec5SDimitry Andric     // bl __tls_get_addr(x@tldgd) --> add r3, r3, r2
369*0b57cec5SDimitry Andric     write32(loc, 0x7c631214);
370*0b57cec5SDimitry Andric     break;
371*0b57cec5SDimitry Andric   default:
372*0b57cec5SDimitry Andric     llvm_unreachable("unsupported relocation for TLS GD to IE relaxation");
373*0b57cec5SDimitry Andric   }
374*0b57cec5SDimitry Andric }
375*0b57cec5SDimitry Andric 
376*0b57cec5SDimitry Andric void PPC::relaxTlsGdToLe(uint8_t *loc, RelType type, uint64_t val) const {
377*0b57cec5SDimitry Andric   switch (type) {
378*0b57cec5SDimitry Andric   case R_PPC_GOT_TLSGD16:
379*0b57cec5SDimitry Andric     // addi r3, r31, x@got@tlsgd --> addis r3, r2, x@tprel@ha
380*0b57cec5SDimitry Andric     writeFromHalf16(loc, 0x3c620000 | ha(val));
381*0b57cec5SDimitry Andric     break;
382*0b57cec5SDimitry Andric   case R_PPC_TLSGD:
383*0b57cec5SDimitry Andric     // bl __tls_get_addr(x@tldgd) --> add r3, r3, x@tprel@l
384*0b57cec5SDimitry Andric     write32(loc, 0x38630000 | lo(val));
385*0b57cec5SDimitry Andric     break;
386*0b57cec5SDimitry Andric   default:
387*0b57cec5SDimitry Andric     llvm_unreachable("unsupported relocation for TLS GD to LE relaxation");
388*0b57cec5SDimitry Andric   }
389*0b57cec5SDimitry Andric }
390*0b57cec5SDimitry Andric 
391*0b57cec5SDimitry Andric void PPC::relaxTlsLdToLe(uint8_t *loc, RelType type, uint64_t val) const {
392*0b57cec5SDimitry Andric   switch (type) {
393*0b57cec5SDimitry Andric   case R_PPC_GOT_TLSLD16:
394*0b57cec5SDimitry Andric     // addi r3, rA, x@got@tlsgd --> addis r3, r2, 0
395*0b57cec5SDimitry Andric     writeFromHalf16(loc, 0x3c620000);
396*0b57cec5SDimitry Andric     break;
397*0b57cec5SDimitry Andric   case R_PPC_TLSLD:
398*0b57cec5SDimitry Andric     // r3+x@dtprel computes r3+x-0x8000, while we want it to compute r3+x@tprel
399*0b57cec5SDimitry Andric     // = r3+x-0x7000, so add 4096 to r3.
400*0b57cec5SDimitry Andric     // bl __tls_get_addr(x@tlsld) --> addi r3, r3, 4096
401*0b57cec5SDimitry Andric     write32(loc, 0x38631000);
402*0b57cec5SDimitry Andric     break;
403*0b57cec5SDimitry Andric   case R_PPC_DTPREL16:
404*0b57cec5SDimitry Andric   case R_PPC_DTPREL16_HA:
405*0b57cec5SDimitry Andric   case R_PPC_DTPREL16_HI:
406*0b57cec5SDimitry Andric   case R_PPC_DTPREL16_LO:
407*0b57cec5SDimitry Andric     relocateOne(loc, type, val);
408*0b57cec5SDimitry Andric     break;
409*0b57cec5SDimitry Andric   default:
410*0b57cec5SDimitry Andric     llvm_unreachable("unsupported relocation for TLS LD to LE relaxation");
411*0b57cec5SDimitry Andric   }
412*0b57cec5SDimitry Andric }
413*0b57cec5SDimitry Andric 
414*0b57cec5SDimitry Andric void PPC::relaxTlsIeToLe(uint8_t *loc, RelType type, uint64_t val) const {
415*0b57cec5SDimitry Andric   switch (type) {
416*0b57cec5SDimitry Andric   case R_PPC_GOT_TPREL16: {
417*0b57cec5SDimitry Andric     // lwz rT, x@got@tprel(rA) --> addis rT, r2, x@tprel@ha
418*0b57cec5SDimitry Andric     uint32_t rt = readFromHalf16(loc) & 0x03e00000;
419*0b57cec5SDimitry Andric     writeFromHalf16(loc, 0x3c020000 | rt | ha(val));
420*0b57cec5SDimitry Andric     break;
421*0b57cec5SDimitry Andric   }
422*0b57cec5SDimitry Andric   case R_PPC_TLS: {
423*0b57cec5SDimitry Andric     uint32_t insn = read32(loc);
424*0b57cec5SDimitry Andric     if (insn >> 26 != 31)
425*0b57cec5SDimitry Andric       error("unrecognized instruction for IE to LE R_PPC_TLS");
426*0b57cec5SDimitry Andric     // addi rT, rT, x@tls --> addi rT, rT, x@tprel@l
427*0b57cec5SDimitry Andric     uint32_t dFormOp = getPPCDFormOp((read32(loc) & 0x000007fe) >> 1);
428*0b57cec5SDimitry Andric     if (dFormOp == 0)
429*0b57cec5SDimitry Andric       error("unrecognized instruction for IE to LE R_PPC_TLS");
430*0b57cec5SDimitry Andric     write32(loc, (dFormOp << 26) | (insn & 0x03ff0000) | lo(val));
431*0b57cec5SDimitry Andric     break;
432*0b57cec5SDimitry Andric   }
433*0b57cec5SDimitry Andric   default:
434*0b57cec5SDimitry Andric     llvm_unreachable("unsupported relocation for TLS IE to LE relaxation");
435*0b57cec5SDimitry Andric   }
436*0b57cec5SDimitry Andric }
437*0b57cec5SDimitry Andric 
438*0b57cec5SDimitry Andric TargetInfo *elf::getPPCTargetInfo() {
439*0b57cec5SDimitry Andric   static PPC target;
440*0b57cec5SDimitry Andric   return &target;
441*0b57cec5SDimitry Andric }
442