blob: 0b73df3a2ff8c251dab8a16fbc298942cb9116e7 [file] [log] [blame]
Rafael Espindolab264d332011-12-21 17:30:17 +00001//===-- X86ELFObjectWriter.cpp - X86 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
10#include "MCTargetDesc/X86FixupKinds.h"
11#include "MCTargetDesc/X86MCTargetDesc.h"
Davide Italianof59b0da2016-04-24 01:03:57 +000012#include "llvm/MC/MCAsmInfo.h"
Rafael Espindola8340f942016-01-13 22:56:57 +000013#include "llvm/MC/MCContext.h"
Rafael Espindolab264d332011-12-21 17:30:17 +000014#include "llvm/MC/MCELFObjectWriter.h"
15#include "llvm/MC/MCExpr.h"
Eugene Zelenkofbd13c52017-02-02 22:55:55 +000016#include "llvm/MC/MCFixup.h"
Rafael Espindolab264d332011-12-21 17:30:17 +000017#include "llvm/MC/MCValue.h"
18#include "llvm/Support/ELF.h"
19#include "llvm/Support/ErrorHandling.h"
Eugene Zelenkofbd13c52017-02-02 22:55:55 +000020#include <cassert>
21#include <cstdint>
Rafael Espindolab264d332011-12-21 17:30:17 +000022
23using namespace llvm;
24
25namespace {
Rafael Espindolab264d332011-12-21 17:30:17 +000026
Eugene Zelenkofbd13c52017-02-02 22:55:55 +000027class X86ELFObjectWriter : public MCELFObjectTargetWriter {
28public:
29 X86ELFObjectWriter(bool IsELF64, uint8_t OSABI, uint16_t EMachine);
30 ~X86ELFObjectWriter() override = default;
Alexander Kornienkof817c1c2015-04-11 02:11:45 +000031
Eugene Zelenkofbd13c52017-02-02 22:55:55 +000032protected:
33 unsigned getRelocType(MCContext &Ctx, const MCValue &Target,
34 const MCFixup &Fixup, bool IsPCRel) const override;
35};
36
37} // end anonymous namespace
Rafael Espindolab264d332011-12-21 17:30:17 +000038
Michael Liao83a77c32012-10-30 17:33:39 +000039X86ELFObjectWriter::X86ELFObjectWriter(bool IsELF64, uint8_t OSABI,
40 uint16_t EMachine)
Michael Kupersteina3b79dd2015-11-04 11:21:50 +000041 : MCELFObjectTargetWriter(IsELF64, OSABI, EMachine,
42 // Only i386 and IAMCU use Rel instead of RelA.
43 /*HasRelocationAddend*/
44 (EMachine != ELF::EM_386) &&
45 (EMachine != ELF::EM_IAMCU)) {}
Rafael Espindolab264d332011-12-21 17:30:17 +000046
Rafael Espindolabdfbde52015-03-20 19:48:54 +000047enum X86_64RelType { RT64_64, RT64_32, RT64_32S, RT64_16, RT64_8 };
48
49static X86_64RelType getType64(unsigned Kind,
50 MCSymbolRefExpr::VariantKind &Modifier,
51 bool &IsPCRel) {
52 switch (Kind) {
53 default:
54 llvm_unreachable("Unimplemented");
55 case X86::reloc_global_offset_table8:
56 Modifier = MCSymbolRefExpr::VK_GOT;
57 IsPCRel = true;
58 return RT64_64;
59 case FK_Data_8:
60 return RT64_64;
61 case X86::reloc_signed_4byte:
Rafael Espindolaa29971f2016-07-06 21:19:11 +000062 case X86::reloc_signed_4byte_relax:
Rafael Espindolabdfbde52015-03-20 19:48:54 +000063 if (Modifier == MCSymbolRefExpr::VK_None && !IsPCRel)
64 return RT64_32S;
65 return RT64_32;
66 case X86::reloc_global_offset_table:
67 Modifier = MCSymbolRefExpr::VK_GOT;
68 IsPCRel = true;
69 return RT64_32;
70 case FK_Data_4:
71 case FK_PCRel_4:
72 case X86::reloc_riprel_4byte:
Rafael Espindola52bd3302016-05-28 15:51:38 +000073 case X86::reloc_riprel_4byte_relax:
74 case X86::reloc_riprel_4byte_relax_rex:
Rafael Espindolabdfbde52015-03-20 19:48:54 +000075 case X86::reloc_riprel_4byte_movq_load:
76 return RT64_32;
Rafael Espindolaf3d49b32015-06-06 02:29:56 +000077 case FK_PCRel_2:
Rafael Espindolabdfbde52015-03-20 19:48:54 +000078 case FK_Data_2:
79 return RT64_16;
80 case FK_PCRel_1:
81 case FK_Data_1:
82 return RT64_8;
83 }
84}
85
Rafael Espindola8340f942016-01-13 22:56:57 +000086static void checkIs32(MCContext &Ctx, SMLoc Loc, X86_64RelType Type) {
87 if (Type != RT64_32)
88 Ctx.reportError(Loc,
89 "32 bit reloc applied to a field with a different size");
90}
91
Davide Italianof59b0da2016-04-24 01:03:57 +000092static unsigned getRelocType64(MCContext &Ctx, SMLoc Loc,
Rafael Espindola8340f942016-01-13 22:56:57 +000093 MCSymbolRefExpr::VariantKind Modifier,
Davide Italianof59b0da2016-04-24 01:03:57 +000094 X86_64RelType Type, bool IsPCRel,
95 unsigned Kind) {
Rafael Espindolabdfbde52015-03-20 19:48:54 +000096 switch (Modifier) {
97 default:
98 llvm_unreachable("Unimplemented");
99 case MCSymbolRefExpr::VK_None:
Peter Collingbourned763c4c2017-01-31 18:28:44 +0000100 case MCSymbolRefExpr::VK_X86_ABS8:
Rafael Espindolabdfbde52015-03-20 19:48:54 +0000101 switch (Type) {
102 case RT64_64:
103 return IsPCRel ? ELF::R_X86_64_PC64 : ELF::R_X86_64_64;
104 case RT64_32:
105 return IsPCRel ? ELF::R_X86_64_PC32 : ELF::R_X86_64_32;
106 case RT64_32S:
107 return ELF::R_X86_64_32S;
108 case RT64_16:
109 return IsPCRel ? ELF::R_X86_64_PC16 : ELF::R_X86_64_16;
110 case RT64_8:
111 return IsPCRel ? ELF::R_X86_64_PC8 : ELF::R_X86_64_8;
112 }
113 case MCSymbolRefExpr::VK_GOT:
114 switch (Type) {
115 case RT64_64:
116 return IsPCRel ? ELF::R_X86_64_GOTPC64 : ELF::R_X86_64_GOT64;
117 case RT64_32:
118 return IsPCRel ? ELF::R_X86_64_GOTPC32 : ELF::R_X86_64_GOT32;
119 case RT64_32S:
120 case RT64_16:
121 case RT64_8:
122 llvm_unreachable("Unimplemented");
123 }
124 case MCSymbolRefExpr::VK_GOTOFF:
125 assert(Type == RT64_64);
126 assert(!IsPCRel);
127 return ELF::R_X86_64_GOTOFF64;
128 case MCSymbolRefExpr::VK_TPOFF:
129 assert(!IsPCRel);
130 switch (Type) {
131 case RT64_64:
132 return ELF::R_X86_64_TPOFF64;
133 case RT64_32:
134 return ELF::R_X86_64_TPOFF32;
135 case RT64_32S:
136 case RT64_16:
137 case RT64_8:
138 llvm_unreachable("Unimplemented");
139 }
140 case MCSymbolRefExpr::VK_DTPOFF:
141 assert(!IsPCRel);
142 switch (Type) {
143 case RT64_64:
144 return ELF::R_X86_64_DTPOFF64;
145 case RT64_32:
146 return ELF::R_X86_64_DTPOFF32;
147 case RT64_32S:
148 case RT64_16:
149 case RT64_8:
150 llvm_unreachable("Unimplemented");
151 }
152 case MCSymbolRefExpr::VK_SIZE:
153 assert(!IsPCRel);
154 switch (Type) {
155 case RT64_64:
156 return ELF::R_X86_64_SIZE64;
157 case RT64_32:
158 return ELF::R_X86_64_SIZE32;
159 case RT64_32S:
160 case RT64_16:
161 case RT64_8:
162 llvm_unreachable("Unimplemented");
163 }
Davide Italiano7aa47092016-04-09 20:32:33 +0000164 case MCSymbolRefExpr::VK_TLSCALL:
165 return ELF::R_X86_64_TLSDESC_CALL;
166 case MCSymbolRefExpr::VK_TLSDESC:
167 return ELF::R_X86_64_GOTPC32_TLSDESC;
Rafael Espindolabdfbde52015-03-20 19:48:54 +0000168 case MCSymbolRefExpr::VK_TLSGD:
Rafael Espindola8340f942016-01-13 22:56:57 +0000169 checkIs32(Ctx, Loc, Type);
Rafael Espindolabdfbde52015-03-20 19:48:54 +0000170 return ELF::R_X86_64_TLSGD;
171 case MCSymbolRefExpr::VK_GOTTPOFF:
Rafael Espindola8340f942016-01-13 22:56:57 +0000172 checkIs32(Ctx, Loc, Type);
Rafael Espindolabdfbde52015-03-20 19:48:54 +0000173 return ELF::R_X86_64_GOTTPOFF;
174 case MCSymbolRefExpr::VK_TLSLD:
Rafael Espindola8340f942016-01-13 22:56:57 +0000175 checkIs32(Ctx, Loc, Type);
Rafael Espindolabdfbde52015-03-20 19:48:54 +0000176 return ELF::R_X86_64_TLSLD;
177 case MCSymbolRefExpr::VK_PLT:
Rafael Espindola8340f942016-01-13 22:56:57 +0000178 checkIs32(Ctx, Loc, Type);
Rafael Espindolabdfbde52015-03-20 19:48:54 +0000179 return ELF::R_X86_64_PLT32;
180 case MCSymbolRefExpr::VK_GOTPCREL:
Rafael Espindola8340f942016-01-13 22:56:57 +0000181 checkIs32(Ctx, Loc, Type);
Davide Italianof59b0da2016-04-24 01:03:57 +0000182 // Older versions of ld.bfd/ld.gold/lld
183 // do not support GOTPCRELX/REX_GOTPCRELX,
184 // and we want to keep back-compatibility.
185 if (!Ctx.getAsmInfo()->canRelaxRelocations())
186 return ELF::R_X86_64_GOTPCREL;
187 switch (Kind) {
188 default:
189 return ELF::R_X86_64_GOTPCREL;
Rafael Espindola52bd3302016-05-28 15:51:38 +0000190 case X86::reloc_riprel_4byte_relax:
Davide Italianof59b0da2016-04-24 01:03:57 +0000191 return ELF::R_X86_64_GOTPCRELX;
Rafael Espindola52bd3302016-05-28 15:51:38 +0000192 case X86::reloc_riprel_4byte_relax_rex:
Davide Italianof59b0da2016-04-24 01:03:57 +0000193 case X86::reloc_riprel_4byte_movq_load:
194 return ELF::R_X86_64_REX_GOTPCRELX;
195 }
Rafael Espindolabdfbde52015-03-20 19:48:54 +0000196 }
197}
198
199enum X86_32RelType { RT32_32, RT32_16, RT32_8 };
200
201static X86_32RelType getType32(X86_64RelType T) {
202 switch (T) {
David Majnemerabd9f5b2015-03-22 21:27:10 +0000203 case RT64_64:
Rafael Espindolabdfbde52015-03-20 19:48:54 +0000204 llvm_unreachable("Unimplemented");
205 case RT64_32:
206 case RT64_32S:
207 return RT32_32;
208 case RT64_16:
209 return RT32_16;
210 case RT64_8:
211 return RT32_8;
212 }
David Majnemerabd9f5b2015-03-22 21:27:10 +0000213 llvm_unreachable("unexpected relocation type!");
Rafael Espindolabdfbde52015-03-20 19:48:54 +0000214}
215
Rafael Espindolaa29971f2016-07-06 21:19:11 +0000216static unsigned getRelocType32(MCContext &Ctx,
217 MCSymbolRefExpr::VariantKind Modifier,
218 X86_32RelType Type, bool IsPCRel,
219 unsigned Kind) {
Rafael Espindolabdfbde52015-03-20 19:48:54 +0000220 switch (Modifier) {
221 default:
222 llvm_unreachable("Unimplemented");
223 case MCSymbolRefExpr::VK_None:
Peter Collingbourned763c4c2017-01-31 18:28:44 +0000224 case MCSymbolRefExpr::VK_X86_ABS8:
Rafael Espindolabdfbde52015-03-20 19:48:54 +0000225 switch (Type) {
226 case RT32_32:
227 return IsPCRel ? ELF::R_386_PC32 : ELF::R_386_32;
228 case RT32_16:
229 return IsPCRel ? ELF::R_386_PC16 : ELF::R_386_16;
230 case RT32_8:
231 return IsPCRel ? ELF::R_386_PC8 : ELF::R_386_8;
232 }
233 case MCSymbolRefExpr::VK_GOT:
234 assert(Type == RT32_32);
Rafael Espindolaa29971f2016-07-06 21:19:11 +0000235 if (IsPCRel)
236 return ELF::R_386_GOTPC;
237 // Older versions of ld.bfd/ld.gold/lld do not support R_386_GOT32X and we
238 // want to maintain compatibility.
239 if (!Ctx.getAsmInfo()->canRelaxRelocations())
240 return ELF::R_386_GOT32;
241
242 return Kind == X86::reloc_signed_4byte_relax ? ELF::R_386_GOT32X
243 : ELF::R_386_GOT32;
Rafael Espindolabdfbde52015-03-20 19:48:54 +0000244 case MCSymbolRefExpr::VK_GOTOFF:
245 assert(Type == RT32_32);
246 assert(!IsPCRel);
247 return ELF::R_386_GOTOFF;
248 case MCSymbolRefExpr::VK_TPOFF:
249 assert(Type == RT32_32);
250 assert(!IsPCRel);
251 return ELF::R_386_TLS_LE_32;
252 case MCSymbolRefExpr::VK_DTPOFF:
253 assert(Type == RT32_32);
254 assert(!IsPCRel);
255 return ELF::R_386_TLS_LDO_32;
256 case MCSymbolRefExpr::VK_TLSGD:
257 assert(Type == RT32_32);
258 assert(!IsPCRel);
259 return ELF::R_386_TLS_GD;
260 case MCSymbolRefExpr::VK_GOTTPOFF:
261 assert(Type == RT32_32);
262 assert(!IsPCRel);
263 return ELF::R_386_TLS_IE_32;
264 case MCSymbolRefExpr::VK_PLT:
265 assert(Type == RT32_32);
266 return ELF::R_386_PLT32;
267 case MCSymbolRefExpr::VK_INDNTPOFF:
268 assert(Type == RT32_32);
269 assert(!IsPCRel);
270 return ELF::R_386_TLS_IE;
271 case MCSymbolRefExpr::VK_NTPOFF:
272 assert(Type == RT32_32);
273 assert(!IsPCRel);
274 return ELF::R_386_TLS_LE;
275 case MCSymbolRefExpr::VK_GOTNTPOFF:
276 assert(Type == RT32_32);
277 assert(!IsPCRel);
278 return ELF::R_386_TLS_GOTIE;
279 case MCSymbolRefExpr::VK_TLSLDM:
280 assert(Type == RT32_32);
281 assert(!IsPCRel);
282 return ELF::R_386_TLS_LDM;
283 }
284}
285
Rafael Espindola8340f942016-01-13 22:56:57 +0000286unsigned X86ELFObjectWriter::getRelocType(MCContext &Ctx, const MCValue &Target,
Rafael Espindolab264d332011-12-21 17:30:17 +0000287 const MCFixup &Fixup,
Rafael Espindolac03f44c2014-03-27 20:49:35 +0000288 bool IsPCRel) const {
Rafael Espindola3d082fa2014-05-03 19:57:04 +0000289 MCSymbolRefExpr::VariantKind Modifier = Target.getAccessVariant();
Rafael Espindolaa29971f2016-07-06 21:19:11 +0000290 unsigned Kind = Fixup.getKind();
291 X86_64RelType Type = getType64(Kind, Modifier, IsPCRel);
Rafael Espindolabdfbde52015-03-20 19:48:54 +0000292 if (getEMachine() == ELF::EM_X86_64)
Rafael Espindolaa29971f2016-07-06 21:19:11 +0000293 return getRelocType64(Ctx, Fixup.getLoc(), Modifier, Type, IsPCRel, Kind);
Rafael Espindolab264d332011-12-21 17:30:17 +0000294
Michael Kupersteina3b79dd2015-11-04 11:21:50 +0000295 assert((getEMachine() == ELF::EM_386 || getEMachine() == ELF::EM_IAMCU) &&
296 "Unsupported ELF machine type.");
Rafael Espindolaa29971f2016-07-06 21:19:11 +0000297 return getRelocType32(Ctx, Modifier, getType32(Type), IsPCRel, Kind);
Rafael Espindolab264d332011-12-21 17:30:17 +0000298}
299
Rafael Espindola5560a4c2015-04-14 22:14:34 +0000300MCObjectWriter *llvm::createX86ELFObjectWriter(raw_pwrite_stream &OS,
301 bool IsELF64, uint8_t OSABI,
Michael Liao83a77c32012-10-30 17:33:39 +0000302 uint16_t EMachine) {
Rafael Espindolab264d332011-12-21 17:30:17 +0000303 MCELFObjectTargetWriter *MOTW =
Michael Liao83a77c32012-10-30 17:33:39 +0000304 new X86ELFObjectWriter(IsELF64, OSABI, EMachine);
Rafael Espindolab264d332011-12-21 17:30:17 +0000305 return createELFObjectWriter(MOTW, OS, /*IsLittleEndian=*/true);
306}