blob: 8958f35e85f298f66a4974fef9e427d98686ceda [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"
16#include "llvm/MC/MCValue.h"
17#include "llvm/Support/ELF.h"
18#include "llvm/Support/ErrorHandling.h"
19
20using namespace llvm;
21
22namespace {
23 class X86ELFObjectWriter : public MCELFObjectTargetWriter {
24 public:
Michael Liao83a77c32012-10-30 17:33:39 +000025 X86ELFObjectWriter(bool IsELF64, uint8_t OSABI, uint16_t EMachine);
Rafael Espindolab264d332011-12-21 17:30:17 +000026
Alexander Kornienkof817c1c2015-04-11 02:11:45 +000027 ~X86ELFObjectWriter() override;
28
Rafael Espindolab264d332011-12-21 17:30:17 +000029 protected:
Rafael Espindola8340f942016-01-13 22:56:57 +000030 unsigned getRelocType(MCContext &Ctx, const MCValue &Target,
31 const MCFixup &Fixup, bool IsPCRel) const override;
Rafael Espindolab264d332011-12-21 17:30:17 +000032 };
Alexander Kornienkof00654e2015-06-23 09:49:53 +000033}
Rafael Espindolab264d332011-12-21 17:30:17 +000034
Michael Liao83a77c32012-10-30 17:33:39 +000035X86ELFObjectWriter::X86ELFObjectWriter(bool IsELF64, uint8_t OSABI,
36 uint16_t EMachine)
Michael Kupersteina3b79dd2015-11-04 11:21:50 +000037 : MCELFObjectTargetWriter(IsELF64, OSABI, EMachine,
38 // Only i386 and IAMCU use Rel instead of RelA.
39 /*HasRelocationAddend*/
40 (EMachine != ELF::EM_386) &&
41 (EMachine != ELF::EM_IAMCU)) {}
Rafael Espindolab264d332011-12-21 17:30:17 +000042
43X86ELFObjectWriter::~X86ELFObjectWriter()
44{}
45
Rafael Espindolabdfbde52015-03-20 19:48:54 +000046enum X86_64RelType { RT64_64, RT64_32, RT64_32S, RT64_16, RT64_8 };
47
48static X86_64RelType getType64(unsigned Kind,
49 MCSymbolRefExpr::VariantKind &Modifier,
50 bool &IsPCRel) {
51 switch (Kind) {
52 default:
53 llvm_unreachable("Unimplemented");
54 case X86::reloc_global_offset_table8:
55 Modifier = MCSymbolRefExpr::VK_GOT;
56 IsPCRel = true;
57 return RT64_64;
58 case FK_Data_8:
59 return RT64_64;
60 case X86::reloc_signed_4byte:
Rafael Espindolaa29971f2016-07-06 21:19:11 +000061 case X86::reloc_signed_4byte_relax:
Rafael Espindolabdfbde52015-03-20 19:48:54 +000062 if (Modifier == MCSymbolRefExpr::VK_None && !IsPCRel)
63 return RT64_32S;
64 return RT64_32;
65 case X86::reloc_global_offset_table:
66 Modifier = MCSymbolRefExpr::VK_GOT;
67 IsPCRel = true;
68 return RT64_32;
69 case FK_Data_4:
70 case FK_PCRel_4:
71 case X86::reloc_riprel_4byte:
Rafael Espindola52bd3302016-05-28 15:51:38 +000072 case X86::reloc_riprel_4byte_relax:
73 case X86::reloc_riprel_4byte_relax_rex:
Rafael Espindolabdfbde52015-03-20 19:48:54 +000074 case X86::reloc_riprel_4byte_movq_load:
75 return RT64_32;
Rafael Espindolaf3d49b32015-06-06 02:29:56 +000076 case FK_PCRel_2:
Rafael Espindolabdfbde52015-03-20 19:48:54 +000077 case FK_Data_2:
78 return RT64_16;
79 case FK_PCRel_1:
80 case FK_Data_1:
81 return RT64_8;
82 }
83}
84
Rafael Espindola8340f942016-01-13 22:56:57 +000085static void checkIs32(MCContext &Ctx, SMLoc Loc, X86_64RelType Type) {
86 if (Type != RT64_32)
87 Ctx.reportError(Loc,
88 "32 bit reloc applied to a field with a different size");
89}
90
Davide Italianof59b0da2016-04-24 01:03:57 +000091static unsigned getRelocType64(MCContext &Ctx, SMLoc Loc,
Rafael Espindola8340f942016-01-13 22:56:57 +000092 MCSymbolRefExpr::VariantKind Modifier,
Davide Italianof59b0da2016-04-24 01:03:57 +000093 X86_64RelType Type, bool IsPCRel,
94 unsigned Kind) {
Rafael Espindolabdfbde52015-03-20 19:48:54 +000095 switch (Modifier) {
96 default:
97 llvm_unreachable("Unimplemented");
98 case MCSymbolRefExpr::VK_None:
Peter Collingbourned763c4c2017-01-31 18:28:44 +000099 case MCSymbolRefExpr::VK_X86_ABS8:
Rafael Espindolabdfbde52015-03-20 19:48:54 +0000100 switch (Type) {
101 case RT64_64:
102 return IsPCRel ? ELF::R_X86_64_PC64 : ELF::R_X86_64_64;
103 case RT64_32:
104 return IsPCRel ? ELF::R_X86_64_PC32 : ELF::R_X86_64_32;
105 case RT64_32S:
106 return ELF::R_X86_64_32S;
107 case RT64_16:
108 return IsPCRel ? ELF::R_X86_64_PC16 : ELF::R_X86_64_16;
109 case RT64_8:
110 return IsPCRel ? ELF::R_X86_64_PC8 : ELF::R_X86_64_8;
111 }
112 case MCSymbolRefExpr::VK_GOT:
113 switch (Type) {
114 case RT64_64:
115 return IsPCRel ? ELF::R_X86_64_GOTPC64 : ELF::R_X86_64_GOT64;
116 case RT64_32:
117 return IsPCRel ? ELF::R_X86_64_GOTPC32 : ELF::R_X86_64_GOT32;
118 case RT64_32S:
119 case RT64_16:
120 case RT64_8:
121 llvm_unreachable("Unimplemented");
122 }
123 case MCSymbolRefExpr::VK_GOTOFF:
124 assert(Type == RT64_64);
125 assert(!IsPCRel);
126 return ELF::R_X86_64_GOTOFF64;
127 case MCSymbolRefExpr::VK_TPOFF:
128 assert(!IsPCRel);
129 switch (Type) {
130 case RT64_64:
131 return ELF::R_X86_64_TPOFF64;
132 case RT64_32:
133 return ELF::R_X86_64_TPOFF32;
134 case RT64_32S:
135 case RT64_16:
136 case RT64_8:
137 llvm_unreachable("Unimplemented");
138 }
139 case MCSymbolRefExpr::VK_DTPOFF:
140 assert(!IsPCRel);
141 switch (Type) {
142 case RT64_64:
143 return ELF::R_X86_64_DTPOFF64;
144 case RT64_32:
145 return ELF::R_X86_64_DTPOFF32;
146 case RT64_32S:
147 case RT64_16:
148 case RT64_8:
149 llvm_unreachable("Unimplemented");
150 }
151 case MCSymbolRefExpr::VK_SIZE:
152 assert(!IsPCRel);
153 switch (Type) {
154 case RT64_64:
155 return ELF::R_X86_64_SIZE64;
156 case RT64_32:
157 return ELF::R_X86_64_SIZE32;
158 case RT64_32S:
159 case RT64_16:
160 case RT64_8:
161 llvm_unreachable("Unimplemented");
162 }
Davide Italiano7aa47092016-04-09 20:32:33 +0000163 case MCSymbolRefExpr::VK_TLSCALL:
164 return ELF::R_X86_64_TLSDESC_CALL;
165 case MCSymbolRefExpr::VK_TLSDESC:
166 return ELF::R_X86_64_GOTPC32_TLSDESC;
Rafael Espindolabdfbde52015-03-20 19:48:54 +0000167 case MCSymbolRefExpr::VK_TLSGD:
Rafael Espindola8340f942016-01-13 22:56:57 +0000168 checkIs32(Ctx, Loc, Type);
Rafael Espindolabdfbde52015-03-20 19:48:54 +0000169 return ELF::R_X86_64_TLSGD;
170 case MCSymbolRefExpr::VK_GOTTPOFF:
Rafael Espindola8340f942016-01-13 22:56:57 +0000171 checkIs32(Ctx, Loc, Type);
Rafael Espindolabdfbde52015-03-20 19:48:54 +0000172 return ELF::R_X86_64_GOTTPOFF;
173 case MCSymbolRefExpr::VK_TLSLD:
Rafael Espindola8340f942016-01-13 22:56:57 +0000174 checkIs32(Ctx, Loc, Type);
Rafael Espindolabdfbde52015-03-20 19:48:54 +0000175 return ELF::R_X86_64_TLSLD;
176 case MCSymbolRefExpr::VK_PLT:
Rafael Espindola8340f942016-01-13 22:56:57 +0000177 checkIs32(Ctx, Loc, Type);
Rafael Espindolabdfbde52015-03-20 19:48:54 +0000178 return ELF::R_X86_64_PLT32;
179 case MCSymbolRefExpr::VK_GOTPCREL:
Rafael Espindola8340f942016-01-13 22:56:57 +0000180 checkIs32(Ctx, Loc, Type);
Davide Italianof59b0da2016-04-24 01:03:57 +0000181 // Older versions of ld.bfd/ld.gold/lld
182 // do not support GOTPCRELX/REX_GOTPCRELX,
183 // and we want to keep back-compatibility.
184 if (!Ctx.getAsmInfo()->canRelaxRelocations())
185 return ELF::R_X86_64_GOTPCREL;
186 switch (Kind) {
187 default:
188 return ELF::R_X86_64_GOTPCREL;
Rafael Espindola52bd3302016-05-28 15:51:38 +0000189 case X86::reloc_riprel_4byte_relax:
Davide Italianof59b0da2016-04-24 01:03:57 +0000190 return ELF::R_X86_64_GOTPCRELX;
Rafael Espindola52bd3302016-05-28 15:51:38 +0000191 case X86::reloc_riprel_4byte_relax_rex:
Davide Italianof59b0da2016-04-24 01:03:57 +0000192 case X86::reloc_riprel_4byte_movq_load:
193 return ELF::R_X86_64_REX_GOTPCRELX;
194 }
Rafael Espindolabdfbde52015-03-20 19:48:54 +0000195 }
196}
197
198enum X86_32RelType { RT32_32, RT32_16, RT32_8 };
199
200static X86_32RelType getType32(X86_64RelType T) {
201 switch (T) {
David Majnemerabd9f5b2015-03-22 21:27:10 +0000202 case RT64_64:
Rafael Espindolabdfbde52015-03-20 19:48:54 +0000203 llvm_unreachable("Unimplemented");
204 case RT64_32:
205 case RT64_32S:
206 return RT32_32;
207 case RT64_16:
208 return RT32_16;
209 case RT64_8:
210 return RT32_8;
211 }
David Majnemerabd9f5b2015-03-22 21:27:10 +0000212 llvm_unreachable("unexpected relocation type!");
Rafael Espindolabdfbde52015-03-20 19:48:54 +0000213}
214
Rafael Espindolaa29971f2016-07-06 21:19:11 +0000215static unsigned getRelocType32(MCContext &Ctx,
216 MCSymbolRefExpr::VariantKind Modifier,
217 X86_32RelType Type, bool IsPCRel,
218 unsigned Kind) {
Rafael Espindolabdfbde52015-03-20 19:48:54 +0000219 switch (Modifier) {
220 default:
221 llvm_unreachable("Unimplemented");
222 case MCSymbolRefExpr::VK_None:
Peter Collingbourned763c4c2017-01-31 18:28:44 +0000223 case MCSymbolRefExpr::VK_X86_ABS8:
Rafael Espindolabdfbde52015-03-20 19:48:54 +0000224 switch (Type) {
225 case RT32_32:
226 return IsPCRel ? ELF::R_386_PC32 : ELF::R_386_32;
227 case RT32_16:
228 return IsPCRel ? ELF::R_386_PC16 : ELF::R_386_16;
229 case RT32_8:
230 return IsPCRel ? ELF::R_386_PC8 : ELF::R_386_8;
231 }
232 case MCSymbolRefExpr::VK_GOT:
233 assert(Type == RT32_32);
Rafael Espindolaa29971f2016-07-06 21:19:11 +0000234 if (IsPCRel)
235 return ELF::R_386_GOTPC;
236 // Older versions of ld.bfd/ld.gold/lld do not support R_386_GOT32X and we
237 // want to maintain compatibility.
238 if (!Ctx.getAsmInfo()->canRelaxRelocations())
239 return ELF::R_386_GOT32;
240
241 return Kind == X86::reloc_signed_4byte_relax ? ELF::R_386_GOT32X
242 : ELF::R_386_GOT32;
Rafael Espindolabdfbde52015-03-20 19:48:54 +0000243 case MCSymbolRefExpr::VK_GOTOFF:
244 assert(Type == RT32_32);
245 assert(!IsPCRel);
246 return ELF::R_386_GOTOFF;
247 case MCSymbolRefExpr::VK_TPOFF:
248 assert(Type == RT32_32);
249 assert(!IsPCRel);
250 return ELF::R_386_TLS_LE_32;
251 case MCSymbolRefExpr::VK_DTPOFF:
252 assert(Type == RT32_32);
253 assert(!IsPCRel);
254 return ELF::R_386_TLS_LDO_32;
255 case MCSymbolRefExpr::VK_TLSGD:
256 assert(Type == RT32_32);
257 assert(!IsPCRel);
258 return ELF::R_386_TLS_GD;
259 case MCSymbolRefExpr::VK_GOTTPOFF:
260 assert(Type == RT32_32);
261 assert(!IsPCRel);
262 return ELF::R_386_TLS_IE_32;
263 case MCSymbolRefExpr::VK_PLT:
264 assert(Type == RT32_32);
265 return ELF::R_386_PLT32;
266 case MCSymbolRefExpr::VK_INDNTPOFF:
267 assert(Type == RT32_32);
268 assert(!IsPCRel);
269 return ELF::R_386_TLS_IE;
270 case MCSymbolRefExpr::VK_NTPOFF:
271 assert(Type == RT32_32);
272 assert(!IsPCRel);
273 return ELF::R_386_TLS_LE;
274 case MCSymbolRefExpr::VK_GOTNTPOFF:
275 assert(Type == RT32_32);
276 assert(!IsPCRel);
277 return ELF::R_386_TLS_GOTIE;
278 case MCSymbolRefExpr::VK_TLSLDM:
279 assert(Type == RT32_32);
280 assert(!IsPCRel);
281 return ELF::R_386_TLS_LDM;
282 }
283}
284
Rafael Espindola8340f942016-01-13 22:56:57 +0000285unsigned X86ELFObjectWriter::getRelocType(MCContext &Ctx, const MCValue &Target,
Rafael Espindolab264d332011-12-21 17:30:17 +0000286 const MCFixup &Fixup,
Rafael Espindolac03f44c2014-03-27 20:49:35 +0000287 bool IsPCRel) const {
Rafael Espindola3d082fa2014-05-03 19:57:04 +0000288 MCSymbolRefExpr::VariantKind Modifier = Target.getAccessVariant();
Rafael Espindolaa29971f2016-07-06 21:19:11 +0000289 unsigned Kind = Fixup.getKind();
290 X86_64RelType Type = getType64(Kind, Modifier, IsPCRel);
Rafael Espindolabdfbde52015-03-20 19:48:54 +0000291 if (getEMachine() == ELF::EM_X86_64)
Rafael Espindolaa29971f2016-07-06 21:19:11 +0000292 return getRelocType64(Ctx, Fixup.getLoc(), Modifier, Type, IsPCRel, Kind);
Rafael Espindolab264d332011-12-21 17:30:17 +0000293
Michael Kupersteina3b79dd2015-11-04 11:21:50 +0000294 assert((getEMachine() == ELF::EM_386 || getEMachine() == ELF::EM_IAMCU) &&
295 "Unsupported ELF machine type.");
Rafael Espindolaa29971f2016-07-06 21:19:11 +0000296 return getRelocType32(Ctx, Modifier, getType32(Type), IsPCRel, Kind);
Rafael Espindolab264d332011-12-21 17:30:17 +0000297}
298
Rafael Espindola5560a4c2015-04-14 22:14:34 +0000299MCObjectWriter *llvm::createX86ELFObjectWriter(raw_pwrite_stream &OS,
300 bool IsELF64, uint8_t OSABI,
Michael Liao83a77c32012-10-30 17:33:39 +0000301 uint16_t EMachine) {
Rafael Espindolab264d332011-12-21 17:30:17 +0000302 MCELFObjectTargetWriter *MOTW =
Michael Liao83a77c32012-10-30 17:33:39 +0000303 new X86ELFObjectWriter(IsELF64, OSABI, EMachine);
Rafael Espindolab264d332011-12-21 17:30:17 +0000304 return createELFObjectWriter(MOTW, OS, /*IsLittleEndian=*/true);
305}