blob: 7f4d9a28d0c37c7064addb9399310d434b868846 [file] [log] [blame]
Rafael Espindola38a400d2011-12-22 01:57:09 +00001//===-- PPCELFObjectWriter.cpp - PPC ELF Writer ---------------------------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
Rafael Espindola38a400d2011-12-22 01:57:09 +000010#include "MCTargetDesc/PPCMCTargetDesc.h"
Chandler Carruthed0881b2012-12-03 16:50:05 +000011#include "MCTargetDesc/PPCFixupKinds.h"
Bill Schmidta4f89842012-12-14 20:28:38 +000012#include "llvm/ADT/STLExtras.h"
Rafael Espindola38a400d2011-12-22 01:57:09 +000013#include "llvm/MC/MCELFObjectWriter.h"
Adhemerval Zanellaf2aceda2012-10-25 12:27:42 +000014#include "llvm/MC/MCExpr.h"
15#include "llvm/MC/MCValue.h"
Chandler Carruthed0881b2012-12-03 16:50:05 +000016#include "llvm/Support/ErrorHandling.h"
Rafael Espindola38a400d2011-12-22 01:57:09 +000017
18using namespace llvm;
19
20namespace {
21 class PPCELFObjectWriter : public MCELFObjectTargetWriter {
22 public:
23 PPCELFObjectWriter(bool Is64Bit, uint8_t OSABI);
24
25 virtual ~PPCELFObjectWriter();
26 protected:
Adhemerval Zanellaf2aceda2012-10-25 12:27:42 +000027 virtual unsigned getRelocTypeInner(const MCValue &Target,
28 const MCFixup &Fixup,
29 bool IsPCRel) const;
Rafael Espindola38a400d2011-12-22 01:57:09 +000030 virtual unsigned GetRelocType(const MCValue &Target, const MCFixup &Fixup,
31 bool IsPCRel, bool IsRelocWithSymbol,
32 int64_t Addend) const;
Adhemerval Zanellaf2aceda2012-10-25 12:27:42 +000033 virtual const MCSymbol *undefinedExplicitRelSym(const MCValue &Target,
34 const MCFixup &Fixup,
35 bool IsPCRel) const;
Rafael Espindola38a400d2011-12-22 01:57:09 +000036 virtual void adjustFixupOffset(const MCFixup &Fixup, uint64_t &RelocOffset);
Bill Schmidta4f89842012-12-14 20:28:38 +000037
38 virtual void sortRelocs(const MCAssembler &Asm,
39 std::vector<ELFRelocationEntry> &Relocs);
40 };
41
42 class PPCELFRelocationEntry : public ELFRelocationEntry {
43 public:
44 PPCELFRelocationEntry(const ELFRelocationEntry &RE);
45 bool operator<(const PPCELFRelocationEntry &RE) const {
46 return (RE.r_offset < r_offset ||
47 (RE.r_offset == r_offset && RE.Type > Type));
48 }
Rafael Espindola38a400d2011-12-22 01:57:09 +000049 };
50}
51
Bill Schmidta4f89842012-12-14 20:28:38 +000052PPCELFRelocationEntry::PPCELFRelocationEntry(const ELFRelocationEntry &RE)
53 : ELFRelocationEntry(RE.r_offset, RE.Index, RE.Type, RE.Symbol,
54 RE.r_addend, *RE.Fixup) {}
55
Rafael Espindola38a400d2011-12-22 01:57:09 +000056PPCELFObjectWriter::PPCELFObjectWriter(bool Is64Bit, uint8_t OSABI)
57 : MCELFObjectTargetWriter(Is64Bit, OSABI,
58 Is64Bit ? ELF::EM_PPC64 : ELF::EM_PPC,
Rafael Espindola25009622011-12-22 18:38:06 +000059 /*HasRelocationAddend*/ true) {}
Rafael Espindola38a400d2011-12-22 01:57:09 +000060
61PPCELFObjectWriter::~PPCELFObjectWriter() {
62}
63
Adhemerval Zanellaf2aceda2012-10-25 12:27:42 +000064unsigned PPCELFObjectWriter::getRelocTypeInner(const MCValue &Target,
65 const MCFixup &Fixup,
66 bool IsPCRel) const
67{
68 MCSymbolRefExpr::VariantKind Modifier = Target.isAbsolute() ?
69 MCSymbolRefExpr::VK_None : Target.getSymA()->getKind();
70
Rafael Espindola38a400d2011-12-22 01:57:09 +000071 // determine the type of the relocation
72 unsigned Type;
73 if (IsPCRel) {
74 switch ((unsigned)Fixup.getKind()) {
75 default:
76 llvm_unreachable("Unimplemented");
77 case PPC::fixup_ppc_br24:
78 Type = ELF::R_PPC_REL24;
79 break;
80 case FK_PCRel_4:
81 Type = ELF::R_PPC_REL32;
82 break;
83 }
84 } else {
85 switch ((unsigned)Fixup.getKind()) {
86 default: llvm_unreachable("invalid fixup kind!");
87 case PPC::fixup_ppc_br24:
88 Type = ELF::R_PPC_ADDR24;
89 break;
90 case PPC::fixup_ppc_brcond14:
Adhemerval Zanellaf2aceda2012-10-25 12:27:42 +000091 Type = ELF::R_PPC_ADDR14; // XXX: or BRNTAKEN?_
Rafael Espindola38a400d2011-12-22 01:57:09 +000092 break;
93 case PPC::fixup_ppc_ha16:
Ulrich Weigand85578502012-11-13 19:24:36 +000094 switch (Modifier) {
95 default: llvm_unreachable("Unsupported Modifier");
96 case MCSymbolRefExpr::VK_PPC_TPREL16_HA:
97 Type = ELF::R_PPC_TPREL16_HA;
98 break;
Bill Schmidt24b8dd62012-12-12 19:29:35 +000099 case MCSymbolRefExpr::VK_PPC_DTPREL16_HA:
100 Type = ELF::R_PPC64_DTPREL16_HA;
101 break;
Ulrich Weigand85578502012-11-13 19:24:36 +0000102 case MCSymbolRefExpr::VK_None:
103 Type = ELF::R_PPC_ADDR16_HA;
104 break;
Bill Schmidt34627e32012-11-27 17:35:46 +0000105 case MCSymbolRefExpr::VK_PPC_TOC16_HA:
106 Type = ELF::R_PPC64_TOC16_HA;
107 break;
Bill Schmidt9f0b4ec2012-12-14 17:02:38 +0000108 case MCSymbolRefExpr::VK_PPC_GOT_TPREL16_HA:
109 Type = ELF::R_PPC64_GOT_TPREL16_HA;
110 break;
Bill Schmidtc56f1d32012-12-11 20:30:11 +0000111 case MCSymbolRefExpr::VK_PPC_GOT_TLSGD16_HA:
112 Type = ELF::R_PPC64_GOT_TLSGD16_HA;
113 break;
Bill Schmidt24b8dd62012-12-12 19:29:35 +0000114 case MCSymbolRefExpr::VK_PPC_GOT_TLSLD16_HA:
115 Type = ELF::R_PPC64_GOT_TLSLD16_HA;
116 break;
Ulrich Weigand85578502012-11-13 19:24:36 +0000117 }
Rafael Espindola38a400d2011-12-22 01:57:09 +0000118 break;
119 case PPC::fixup_ppc_lo16:
Ulrich Weigand85578502012-11-13 19:24:36 +0000120 switch (Modifier) {
121 default: llvm_unreachable("Unsupported Modifier");
122 case MCSymbolRefExpr::VK_PPC_TPREL16_LO:
123 Type = ELF::R_PPC_TPREL16_LO;
124 break;
Bill Schmidt24b8dd62012-12-12 19:29:35 +0000125 case MCSymbolRefExpr::VK_PPC_DTPREL16_LO:
126 Type = ELF::R_PPC64_DTPREL16_LO;
127 break;
Ulrich Weigand85578502012-11-13 19:24:36 +0000128 case MCSymbolRefExpr::VK_None:
129 Type = ELF::R_PPC_ADDR16_LO;
130 break;
Bill Schmidt34627e32012-11-27 17:35:46 +0000131 case MCSymbolRefExpr::VK_PPC_TOC16_LO:
132 Type = ELF::R_PPC64_TOC16_LO;
133 break;
Bill Schmidtc56f1d32012-12-11 20:30:11 +0000134 case MCSymbolRefExpr::VK_PPC_GOT_TLSGD16_LO:
135 Type = ELF::R_PPC64_GOT_TLSGD16_LO;
136 break;
Bill Schmidt24b8dd62012-12-12 19:29:35 +0000137 case MCSymbolRefExpr::VK_PPC_GOT_TLSLD16_LO:
138 Type = ELF::R_PPC64_GOT_TLSLD16_LO;
139 break;
Ulrich Weigand85578502012-11-13 19:24:36 +0000140 }
Rafael Espindola38a400d2011-12-22 01:57:09 +0000141 break;
142 case PPC::fixup_ppc_lo14:
143 Type = ELF::R_PPC_ADDR14;
144 break;
Adhemerval Zanellaf2aceda2012-10-25 12:27:42 +0000145 case PPC::fixup_ppc_toc:
146 Type = ELF::R_PPC64_TOC;
147 break;
148 case PPC::fixup_ppc_toc16:
149 Type = ELF::R_PPC64_TOC16;
150 break;
151 case PPC::fixup_ppc_toc16_ds:
Bill Schmidt34627e32012-11-27 17:35:46 +0000152 switch (Modifier) {
153 default: llvm_unreachable("Unsupported Modifier");
154 case MCSymbolRefExpr::VK_PPC_TOC_ENTRY:
155 Type = ELF::R_PPC64_TOC16_DS;
156 break;
157 case MCSymbolRefExpr::VK_PPC_TOC16_LO:
158 Type = ELF::R_PPC64_TOC16_LO_DS;
159 break;
Bill Schmidt9f0b4ec2012-12-14 17:02:38 +0000160 case MCSymbolRefExpr::VK_PPC_GOT_TPREL16_LO:
161 Type = ELF::R_PPC64_GOT_TPREL16_LO_DS;
Bill Schmidtca4a0c92012-12-04 16:18:08 +0000162 break;
Bill Schmidt34627e32012-11-27 17:35:46 +0000163 }
Adhemerval Zanellaf2aceda2012-10-25 12:27:42 +0000164 break;
Bill Schmidtca4a0c92012-12-04 16:18:08 +0000165 case PPC::fixup_ppc_tlsreg:
166 Type = ELF::R_PPC64_TLS;
167 break;
Bill Schmidt24b8dd62012-12-12 19:29:35 +0000168 case PPC::fixup_ppc_nofixup:
169 switch (Modifier) {
170 default: llvm_unreachable("Unsupported Modifier");
171 case MCSymbolRefExpr::VK_PPC_TLSGD:
172 Type = ELF::R_PPC64_TLSGD;
173 break;
174 case MCSymbolRefExpr::VK_PPC_TLSLD:
175 Type = ELF::R_PPC64_TLSLD;
176 break;
177 }
Bill Schmidtc56f1d32012-12-11 20:30:11 +0000178 break;
Adhemerval Zanellaf2aceda2012-10-25 12:27:42 +0000179 case FK_Data_8:
180 switch (Modifier) {
181 default: llvm_unreachable("Unsupported Modifier");
182 case MCSymbolRefExpr::VK_PPC_TOC:
183 Type = ELF::R_PPC64_TOC;
184 break;
185 case MCSymbolRefExpr::VK_None:
186 Type = ELF::R_PPC64_ADDR64;
187 break;
188 }
189 break;
Rafael Espindola38a400d2011-12-22 01:57:09 +0000190 case FK_Data_4:
191 Type = ELF::R_PPC_ADDR32;
192 break;
193 case FK_Data_2:
194 Type = ELF::R_PPC_ADDR16;
195 break;
196 }
197 }
198 return Type;
199}
200
Adhemerval Zanellaf2aceda2012-10-25 12:27:42 +0000201unsigned PPCELFObjectWriter::GetRelocType(const MCValue &Target,
202 const MCFixup &Fixup,
203 bool IsPCRel,
204 bool IsRelocWithSymbol,
205 int64_t Addend) const {
206 return getRelocTypeInner(Target, Fixup, IsPCRel);
207}
208
209const MCSymbol *PPCELFObjectWriter::undefinedExplicitRelSym(const MCValue &Target,
210 const MCFixup &Fixup,
211 bool IsPCRel) const {
212 assert(Target.getSymA() && "SymA cannot be 0");
213 const MCSymbol &Symbol = Target.getSymA()->getSymbol().AliasedSymbol();
214
215 unsigned RelocType = getRelocTypeInner(Target, Fixup, IsPCRel);
216
217 // The .odp creation emits a relocation against the symbol ".TOC." which
218 // create a R_PPC64_TOC relocation. However the relocation symbol name
219 // in final object creation should be NULL, since the symbol does not
220 // really exist, it is just the reference to TOC base for the current
221 // object file.
222 bool EmitThisSym = RelocType != ELF::R_PPC64_TOC;
223
224 if (EmitThisSym && !Symbol.isTemporary())
225 return &Symbol;
226 return NULL;
227}
228
Rafael Espindola38a400d2011-12-22 01:57:09 +0000229void PPCELFObjectWriter::
230adjustFixupOffset(const MCFixup &Fixup, uint64_t &RelocOffset) {
231 switch ((unsigned)Fixup.getKind()) {
232 case PPC::fixup_ppc_ha16:
233 case PPC::fixup_ppc_lo16:
Adhemerval Zanella1be10dc2012-10-25 14:29:13 +0000234 case PPC::fixup_ppc_toc16:
235 case PPC::fixup_ppc_toc16_ds:
Rafael Espindola38a400d2011-12-22 01:57:09 +0000236 RelocOffset += 2;
237 break;
238 default:
239 break;
240 }
241}
242
Bill Schmidta4f89842012-12-14 20:28:38 +0000243// The standard sorter only sorts on the r_offset field, but PowerPC can
244// have multiple relocations at the same offset. Sort secondarily on the
245// relocation type to avoid nondeterminism.
246void PPCELFObjectWriter::sortRelocs(const MCAssembler &Asm,
247 std::vector<ELFRelocationEntry> &Relocs) {
248
249 // Copy to a temporary vector of relocation entries having a different
250 // sort function.
251 std::vector<PPCELFRelocationEntry> TmpRelocs;
252
253 for (std::vector<ELFRelocationEntry>::iterator R = Relocs.begin();
254 R != Relocs.end(); ++R) {
255 TmpRelocs.push_back(PPCELFRelocationEntry(*R));
256 }
257
258 // Sort in place by ascending r_offset and descending r_type.
259 array_pod_sort(TmpRelocs.begin(), TmpRelocs.end());
260
261 // Copy back to the original vector.
262 unsigned I = 0;
263 for (std::vector<PPCELFRelocationEntry>::iterator R = TmpRelocs.begin();
264 R != TmpRelocs.end(); ++R, ++I) {
265 Relocs[I] = ELFRelocationEntry(R->r_offset, R->Index, R->Type,
266 R->Symbol, R->r_addend, *R->Fixup);
267 }
268}
269
270
Rafael Espindola38a400d2011-12-22 01:57:09 +0000271MCObjectWriter *llvm::createPPCELFObjectWriter(raw_ostream &OS,
272 bool Is64Bit,
273 uint8_t OSABI) {
274 MCELFObjectTargetWriter *MOTW = new PPCELFObjectWriter(Is64Bit, OSABI);
Rafael Espindola25009622011-12-22 18:38:06 +0000275 return createELFObjectWriter(MOTW, OS, /*IsLittleEndian=*/false);
Rafael Espindola38a400d2011-12-22 01:57:09 +0000276}