1 //===-- 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"
12 #include "llvm/BinaryFormat/ELF.h"
13 #include "llvm/MC/MCAsmInfo.h"
14 #include "llvm/MC/MCContext.h"
15 #include "llvm/MC/MCELFObjectWriter.h"
16 #include "llvm/MC/MCExpr.h"
17 #include "llvm/MC/MCFixup.h"
18 #include "llvm/MC/MCObjectWriter.h"
19 #include "llvm/MC/MCValue.h"
20 #include "llvm/Support/ErrorHandling.h"
21 #include <cassert>
22 #include <cstdint>
23
24 using namespace llvm;
25
26 namespace {
27
28 class X86ELFObjectWriter : public MCELFObjectTargetWriter {
29 public:
30 X86ELFObjectWriter(bool IsELF64, uint8_t OSABI, uint16_t EMachine);
31 ~X86ELFObjectWriter() override = default;
32
33 protected:
34 unsigned getRelocType(MCContext &Ctx, const MCValue &Target,
35 const MCFixup &Fixup, bool IsPCRel) const override;
36 };
37
38 } // end anonymous namespace
39
X86ELFObjectWriter(bool IsELF64,uint8_t OSABI,uint16_t EMachine)40 X86ELFObjectWriter::X86ELFObjectWriter(bool IsELF64, uint8_t OSABI,
41 uint16_t EMachine)
42 : MCELFObjectTargetWriter(IsELF64, OSABI, EMachine,
43 // Only i386 and IAMCU use Rel instead of RelA.
44 /*HasRelocationAddend*/
45 (EMachine != ELF::EM_386) &&
46 (EMachine != ELF::EM_IAMCU)) {}
47
48 enum X86_64RelType { RT64_64, RT64_32, RT64_32S, RT64_16, RT64_8 };
49
getType64(unsigned Kind,MCSymbolRefExpr::VariantKind & Modifier,bool & IsPCRel)50 static X86_64RelType getType64(unsigned Kind,
51 MCSymbolRefExpr::VariantKind &Modifier,
52 bool &IsPCRel) {
53 switch (Kind) {
54 default:
55 llvm_unreachable("Unimplemented");
56 case X86::reloc_global_offset_table8:
57 Modifier = MCSymbolRefExpr::VK_GOT;
58 IsPCRel = true;
59 return RT64_64;
60 case FK_Data_8:
61 return RT64_64;
62 case X86::reloc_signed_4byte:
63 case X86::reloc_signed_4byte_relax:
64 if (Modifier == MCSymbolRefExpr::VK_None && !IsPCRel)
65 return RT64_32S;
66 return RT64_32;
67 case X86::reloc_global_offset_table:
68 Modifier = MCSymbolRefExpr::VK_GOT;
69 IsPCRel = true;
70 return RT64_32;
71 case FK_Data_4:
72 case FK_PCRel_4:
73 case X86::reloc_riprel_4byte:
74 case X86::reloc_riprel_4byte_relax:
75 case X86::reloc_riprel_4byte_relax_rex:
76 case X86::reloc_riprel_4byte_movq_load:
77 return RT64_32;
78 case X86::reloc_branch_4byte_pcrel:
79 Modifier = MCSymbolRefExpr::VK_PLT;
80 return RT64_32;
81 case FK_PCRel_2:
82 case FK_Data_2:
83 return RT64_16;
84 case FK_PCRel_1:
85 case FK_Data_1:
86 return RT64_8;
87 }
88 }
89
checkIs32(MCContext & Ctx,SMLoc Loc,X86_64RelType Type)90 static void checkIs32(MCContext &Ctx, SMLoc Loc, X86_64RelType Type) {
91 if (Type != RT64_32)
92 Ctx.reportError(Loc,
93 "32 bit reloc applied to a field with a different size");
94 }
95
getRelocType64(MCContext & Ctx,SMLoc Loc,MCSymbolRefExpr::VariantKind Modifier,X86_64RelType Type,bool IsPCRel,unsigned Kind)96 static unsigned getRelocType64(MCContext &Ctx, SMLoc Loc,
97 MCSymbolRefExpr::VariantKind Modifier,
98 X86_64RelType Type, bool IsPCRel,
99 unsigned Kind) {
100 switch (Modifier) {
101 default:
102 llvm_unreachable("Unimplemented");
103 case MCSymbolRefExpr::VK_None:
104 case MCSymbolRefExpr::VK_X86_ABS8:
105 switch (Type) {
106 case RT64_64:
107 return IsPCRel ? ELF::R_X86_64_PC64 : ELF::R_X86_64_64;
108 case RT64_32:
109 return IsPCRel ? ELF::R_X86_64_PC32 : ELF::R_X86_64_32;
110 case RT64_32S:
111 return ELF::R_X86_64_32S;
112 case RT64_16:
113 return IsPCRel ? ELF::R_X86_64_PC16 : ELF::R_X86_64_16;
114 case RT64_8:
115 return IsPCRel ? ELF::R_X86_64_PC8 : ELF::R_X86_64_8;
116 }
117 case MCSymbolRefExpr::VK_GOT:
118 switch (Type) {
119 case RT64_64:
120 return IsPCRel ? ELF::R_X86_64_GOTPC64 : ELF::R_X86_64_GOT64;
121 case RT64_32:
122 return IsPCRel ? ELF::R_X86_64_GOTPC32 : ELF::R_X86_64_GOT32;
123 case RT64_32S:
124 case RT64_16:
125 case RT64_8:
126 llvm_unreachable("Unimplemented");
127 }
128 case MCSymbolRefExpr::VK_GOTOFF:
129 assert(Type == RT64_64);
130 assert(!IsPCRel);
131 return ELF::R_X86_64_GOTOFF64;
132 case MCSymbolRefExpr::VK_TPOFF:
133 assert(!IsPCRel);
134 switch (Type) {
135 case RT64_64:
136 return ELF::R_X86_64_TPOFF64;
137 case RT64_32:
138 return ELF::R_X86_64_TPOFF32;
139 case RT64_32S:
140 case RT64_16:
141 case RT64_8:
142 llvm_unreachable("Unimplemented");
143 }
144 case MCSymbolRefExpr::VK_DTPOFF:
145 assert(!IsPCRel);
146 switch (Type) {
147 case RT64_64:
148 return ELF::R_X86_64_DTPOFF64;
149 case RT64_32:
150 return ELF::R_X86_64_DTPOFF32;
151 case RT64_32S:
152 case RT64_16:
153 case RT64_8:
154 llvm_unreachable("Unimplemented");
155 }
156 case MCSymbolRefExpr::VK_SIZE:
157 assert(!IsPCRel);
158 switch (Type) {
159 case RT64_64:
160 return ELF::R_X86_64_SIZE64;
161 case RT64_32:
162 return ELF::R_X86_64_SIZE32;
163 case RT64_32S:
164 case RT64_16:
165 case RT64_8:
166 llvm_unreachable("Unimplemented");
167 }
168 case MCSymbolRefExpr::VK_TLSCALL:
169 return ELF::R_X86_64_TLSDESC_CALL;
170 case MCSymbolRefExpr::VK_TLSDESC:
171 return ELF::R_X86_64_GOTPC32_TLSDESC;
172 case MCSymbolRefExpr::VK_TLSGD:
173 checkIs32(Ctx, Loc, Type);
174 return ELF::R_X86_64_TLSGD;
175 case MCSymbolRefExpr::VK_GOTTPOFF:
176 checkIs32(Ctx, Loc, Type);
177 return ELF::R_X86_64_GOTTPOFF;
178 case MCSymbolRefExpr::VK_TLSLD:
179 checkIs32(Ctx, Loc, Type);
180 return ELF::R_X86_64_TLSLD;
181 case MCSymbolRefExpr::VK_PLT:
182 checkIs32(Ctx, Loc, Type);
183 return ELF::R_X86_64_PLT32;
184 case MCSymbolRefExpr::VK_GOTPCREL:
185 checkIs32(Ctx, Loc, Type);
186 // Older versions of ld.bfd/ld.gold/lld
187 // do not support GOTPCRELX/REX_GOTPCRELX,
188 // and we want to keep back-compatibility.
189 if (!Ctx.getAsmInfo()->canRelaxRelocations())
190 return ELF::R_X86_64_GOTPCREL;
191 switch (Kind) {
192 default:
193 return ELF::R_X86_64_GOTPCREL;
194 case X86::reloc_riprel_4byte_relax:
195 return ELF::R_X86_64_GOTPCRELX;
196 case X86::reloc_riprel_4byte_relax_rex:
197 case X86::reloc_riprel_4byte_movq_load:
198 return ELF::R_X86_64_REX_GOTPCRELX;
199 }
200 }
201 }
202
203 enum X86_32RelType { RT32_32, RT32_16, RT32_8 };
204
getType32(X86_64RelType T)205 static X86_32RelType getType32(X86_64RelType T) {
206 switch (T) {
207 case RT64_64:
208 llvm_unreachable("Unimplemented");
209 case RT64_32:
210 case RT64_32S:
211 return RT32_32;
212 case RT64_16:
213 return RT32_16;
214 case RT64_8:
215 return RT32_8;
216 }
217 llvm_unreachable("unexpected relocation type!");
218 }
219
getRelocType32(MCContext & Ctx,MCSymbolRefExpr::VariantKind Modifier,X86_32RelType Type,bool IsPCRel,unsigned Kind)220 static unsigned getRelocType32(MCContext &Ctx,
221 MCSymbolRefExpr::VariantKind Modifier,
222 X86_32RelType Type, bool IsPCRel,
223 unsigned Kind) {
224 switch (Modifier) {
225 default:
226 llvm_unreachable("Unimplemented");
227 case MCSymbolRefExpr::VK_None:
228 case MCSymbolRefExpr::VK_X86_ABS8:
229 switch (Type) {
230 case RT32_32:
231 return IsPCRel ? ELF::R_386_PC32 : ELF::R_386_32;
232 case RT32_16:
233 return IsPCRel ? ELF::R_386_PC16 : ELF::R_386_16;
234 case RT32_8:
235 return IsPCRel ? ELF::R_386_PC8 : ELF::R_386_8;
236 }
237 case MCSymbolRefExpr::VK_GOT:
238 assert(Type == RT32_32);
239 if (IsPCRel)
240 return ELF::R_386_GOTPC;
241 // Older versions of ld.bfd/ld.gold/lld do not support R_386_GOT32X and we
242 // want to maintain compatibility.
243 if (!Ctx.getAsmInfo()->canRelaxRelocations())
244 return ELF::R_386_GOT32;
245
246 return Kind == X86::reloc_signed_4byte_relax ? ELF::R_386_GOT32X
247 : ELF::R_386_GOT32;
248 case MCSymbolRefExpr::VK_GOTOFF:
249 assert(Type == RT32_32);
250 assert(!IsPCRel);
251 return ELF::R_386_GOTOFF;
252 case MCSymbolRefExpr::VK_TPOFF:
253 assert(Type == RT32_32);
254 assert(!IsPCRel);
255 return ELF::R_386_TLS_LE_32;
256 case MCSymbolRefExpr::VK_DTPOFF:
257 assert(Type == RT32_32);
258 assert(!IsPCRel);
259 return ELF::R_386_TLS_LDO_32;
260 case MCSymbolRefExpr::VK_TLSGD:
261 assert(Type == RT32_32);
262 assert(!IsPCRel);
263 return ELF::R_386_TLS_GD;
264 case MCSymbolRefExpr::VK_GOTTPOFF:
265 assert(Type == RT32_32);
266 assert(!IsPCRel);
267 return ELF::R_386_TLS_IE_32;
268 case MCSymbolRefExpr::VK_PLT:
269 assert(Type == RT32_32);
270 return ELF::R_386_PLT32;
271 case MCSymbolRefExpr::VK_INDNTPOFF:
272 assert(Type == RT32_32);
273 assert(!IsPCRel);
274 return ELF::R_386_TLS_IE;
275 case MCSymbolRefExpr::VK_NTPOFF:
276 assert(Type == RT32_32);
277 assert(!IsPCRel);
278 return ELF::R_386_TLS_LE;
279 case MCSymbolRefExpr::VK_GOTNTPOFF:
280 assert(Type == RT32_32);
281 assert(!IsPCRel);
282 return ELF::R_386_TLS_GOTIE;
283 case MCSymbolRefExpr::VK_TLSLDM:
284 assert(Type == RT32_32);
285 assert(!IsPCRel);
286 return ELF::R_386_TLS_LDM;
287 }
288 }
289
getRelocType(MCContext & Ctx,const MCValue & Target,const MCFixup & Fixup,bool IsPCRel) const290 unsigned X86ELFObjectWriter::getRelocType(MCContext &Ctx, const MCValue &Target,
291 const MCFixup &Fixup,
292 bool IsPCRel) const {
293 MCSymbolRefExpr::VariantKind Modifier = Target.getAccessVariant();
294 unsigned Kind = Fixup.getKind();
295 X86_64RelType Type = getType64(Kind, Modifier, IsPCRel);
296 if (getEMachine() == ELF::EM_X86_64)
297 return getRelocType64(Ctx, Fixup.getLoc(), Modifier, Type, IsPCRel, Kind);
298
299 assert((getEMachine() == ELF::EM_386 || getEMachine() == ELF::EM_IAMCU) &&
300 "Unsupported ELF machine type.");
301 return getRelocType32(Ctx, Modifier, getType32(Type), IsPCRel, Kind);
302 }
303
304 std::unique_ptr<MCObjectTargetWriter>
createX86ELFObjectWriter(bool IsELF64,uint8_t OSABI,uint16_t EMachine)305 llvm::createX86ELFObjectWriter(bool IsELF64, uint8_t OSABI, uint16_t EMachine) {
306 return llvm::make_unique<X86ELFObjectWriter>(IsELF64, OSABI, EMachine);
307 }
308