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 
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 
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 FK_PCRel_2:
79   case FK_Data_2:
80     return RT64_16;
81   case FK_PCRel_1:
82   case FK_Data_1:
83     return RT64_8;
84   }
85 }
86 
87 static void checkIs32(MCContext &Ctx, SMLoc Loc, X86_64RelType Type) {
88   if (Type != RT64_32)
89     Ctx.reportError(Loc,
90                     "32 bit reloc applied to a field with a different size");
91 }
92 
93 static unsigned getRelocType64(MCContext &Ctx, SMLoc Loc,
94                                MCSymbolRefExpr::VariantKind Modifier,
95                                X86_64RelType Type, bool IsPCRel,
96                                unsigned Kind) {
97   switch (Modifier) {
98   default:
99     llvm_unreachable("Unimplemented");
100   case MCSymbolRefExpr::VK_None:
101   case MCSymbolRefExpr::VK_X86_ABS8:
102     switch (Type) {
103     case RT64_64:
104       return IsPCRel ? ELF::R_X86_64_PC64 : ELF::R_X86_64_64;
105     case RT64_32:
106       return IsPCRel ? ELF::R_X86_64_PC32 : ELF::R_X86_64_32;
107     case RT64_32S:
108       return ELF::R_X86_64_32S;
109     case RT64_16:
110       return IsPCRel ? ELF::R_X86_64_PC16 : ELF::R_X86_64_16;
111     case RT64_8:
112       return IsPCRel ? ELF::R_X86_64_PC8 : ELF::R_X86_64_8;
113     }
114   case MCSymbolRefExpr::VK_GOT:
115     switch (Type) {
116     case RT64_64:
117       return IsPCRel ? ELF::R_X86_64_GOTPC64 : ELF::R_X86_64_GOT64;
118     case RT64_32:
119       return IsPCRel ? ELF::R_X86_64_GOTPC32 : ELF::R_X86_64_GOT32;
120     case RT64_32S:
121     case RT64_16:
122     case RT64_8:
123       llvm_unreachable("Unimplemented");
124     }
125   case MCSymbolRefExpr::VK_GOTOFF:
126     assert(Type == RT64_64);
127     assert(!IsPCRel);
128     return ELF::R_X86_64_GOTOFF64;
129   case MCSymbolRefExpr::VK_TPOFF:
130     assert(!IsPCRel);
131     switch (Type) {
132     case RT64_64:
133       return ELF::R_X86_64_TPOFF64;
134     case RT64_32:
135       return ELF::R_X86_64_TPOFF32;
136     case RT64_32S:
137     case RT64_16:
138     case RT64_8:
139       llvm_unreachable("Unimplemented");
140     }
141   case MCSymbolRefExpr::VK_DTPOFF:
142     assert(!IsPCRel);
143     switch (Type) {
144     case RT64_64:
145       return ELF::R_X86_64_DTPOFF64;
146     case RT64_32:
147       return ELF::R_X86_64_DTPOFF32;
148     case RT64_32S:
149     case RT64_16:
150     case RT64_8:
151       llvm_unreachable("Unimplemented");
152     }
153   case MCSymbolRefExpr::VK_SIZE:
154     assert(!IsPCRel);
155     switch (Type) {
156     case RT64_64:
157       return ELF::R_X86_64_SIZE64;
158     case RT64_32:
159       return ELF::R_X86_64_SIZE32;
160     case RT64_32S:
161     case RT64_16:
162     case RT64_8:
163       llvm_unreachable("Unimplemented");
164     }
165   case MCSymbolRefExpr::VK_TLSCALL:
166     return ELF::R_X86_64_TLSDESC_CALL;
167   case MCSymbolRefExpr::VK_TLSDESC:
168     return ELF::R_X86_64_GOTPC32_TLSDESC;
169   case MCSymbolRefExpr::VK_TLSGD:
170     checkIs32(Ctx, Loc, Type);
171     return ELF::R_X86_64_TLSGD;
172   case MCSymbolRefExpr::VK_GOTTPOFF:
173     checkIs32(Ctx, Loc, Type);
174     return ELF::R_X86_64_GOTTPOFF;
175   case MCSymbolRefExpr::VK_TLSLD:
176     checkIs32(Ctx, Loc, Type);
177     return ELF::R_X86_64_TLSLD;
178   case MCSymbolRefExpr::VK_PLT:
179     checkIs32(Ctx, Loc, Type);
180     return ELF::R_X86_64_PLT32;
181   case MCSymbolRefExpr::VK_GOTPCREL:
182     checkIs32(Ctx, Loc, Type);
183     // Older versions of ld.bfd/ld.gold/lld
184     // do not support GOTPCRELX/REX_GOTPCRELX,
185     // and we want to keep back-compatibility.
186     if (!Ctx.getAsmInfo()->canRelaxRelocations())
187       return ELF::R_X86_64_GOTPCREL;
188     switch (Kind) {
189     default:
190       return ELF::R_X86_64_GOTPCREL;
191     case X86::reloc_riprel_4byte_relax:
192       return ELF::R_X86_64_GOTPCRELX;
193     case X86::reloc_riprel_4byte_relax_rex:
194     case X86::reloc_riprel_4byte_movq_load:
195       return ELF::R_X86_64_REX_GOTPCRELX;
196     }
197   }
198 }
199 
200 enum X86_32RelType { RT32_32, RT32_16, RT32_8 };
201 
202 static X86_32RelType getType32(X86_64RelType T) {
203   switch (T) {
204   case RT64_64:
205     llvm_unreachable("Unimplemented");
206   case RT64_32:
207   case RT64_32S:
208     return RT32_32;
209   case RT64_16:
210     return RT32_16;
211   case RT64_8:
212     return RT32_8;
213   }
214   llvm_unreachable("unexpected relocation type!");
215 }
216 
217 static unsigned getRelocType32(MCContext &Ctx,
218                                MCSymbolRefExpr::VariantKind Modifier,
219                                X86_32RelType Type, bool IsPCRel,
220                                unsigned Kind) {
221   switch (Modifier) {
222   default:
223     llvm_unreachable("Unimplemented");
224   case MCSymbolRefExpr::VK_None:
225   case MCSymbolRefExpr::VK_X86_ABS8:
226     switch (Type) {
227     case RT32_32:
228       return IsPCRel ? ELF::R_386_PC32 : ELF::R_386_32;
229     case RT32_16:
230       return IsPCRel ? ELF::R_386_PC16 : ELF::R_386_16;
231     case RT32_8:
232       return IsPCRel ? ELF::R_386_PC8 : ELF::R_386_8;
233     }
234   case MCSymbolRefExpr::VK_GOT:
235     assert(Type == RT32_32);
236     if (IsPCRel)
237       return ELF::R_386_GOTPC;
238     // Older versions of ld.bfd/ld.gold/lld do not support R_386_GOT32X and we
239     // want to maintain compatibility.
240     if (!Ctx.getAsmInfo()->canRelaxRelocations())
241       return ELF::R_386_GOT32;
242 
243     return Kind == X86::reloc_signed_4byte_relax ? ELF::R_386_GOT32X
244                                                  : ELF::R_386_GOT32;
245   case MCSymbolRefExpr::VK_GOTOFF:
246     assert(Type == RT32_32);
247     assert(!IsPCRel);
248     return ELF::R_386_GOTOFF;
249   case MCSymbolRefExpr::VK_TPOFF:
250     assert(Type == RT32_32);
251     assert(!IsPCRel);
252     return ELF::R_386_TLS_LE_32;
253   case MCSymbolRefExpr::VK_DTPOFF:
254     assert(Type == RT32_32);
255     assert(!IsPCRel);
256     return ELF::R_386_TLS_LDO_32;
257   case MCSymbolRefExpr::VK_TLSGD:
258     assert(Type == RT32_32);
259     assert(!IsPCRel);
260     return ELF::R_386_TLS_GD;
261   case MCSymbolRefExpr::VK_GOTTPOFF:
262     assert(Type == RT32_32);
263     assert(!IsPCRel);
264     return ELF::R_386_TLS_IE_32;
265   case MCSymbolRefExpr::VK_PLT:
266     assert(Type == RT32_32);
267     return ELF::R_386_PLT32;
268   case MCSymbolRefExpr::VK_INDNTPOFF:
269     assert(Type == RT32_32);
270     assert(!IsPCRel);
271     return ELF::R_386_TLS_IE;
272   case MCSymbolRefExpr::VK_NTPOFF:
273     assert(Type == RT32_32);
274     assert(!IsPCRel);
275     return ELF::R_386_TLS_LE;
276   case MCSymbolRefExpr::VK_GOTNTPOFF:
277     assert(Type == RT32_32);
278     assert(!IsPCRel);
279     return ELF::R_386_TLS_GOTIE;
280   case MCSymbolRefExpr::VK_TLSLDM:
281     assert(Type == RT32_32);
282     assert(!IsPCRel);
283     return ELF::R_386_TLS_LDM;
284   }
285 }
286 
287 unsigned X86ELFObjectWriter::getRelocType(MCContext &Ctx, const MCValue &Target,
288                                           const MCFixup &Fixup,
289                                           bool IsPCRel) const {
290   MCSymbolRefExpr::VariantKind Modifier = Target.getAccessVariant();
291   unsigned Kind = Fixup.getKind();
292   X86_64RelType Type = getType64(Kind, Modifier, IsPCRel);
293   if (getEMachine() == ELF::EM_X86_64)
294     return getRelocType64(Ctx, Fixup.getLoc(), Modifier, Type, IsPCRel, Kind);
295 
296   assert((getEMachine() == ELF::EM_386 || getEMachine() == ELF::EM_IAMCU) &&
297          "Unsupported ELF machine type.");
298   return getRelocType32(Ctx, Modifier, getType32(Type), IsPCRel, Kind);
299 }
300 
301 std::unique_ptr<MCObjectWriter>
302 llvm::createX86ELFObjectWriter(raw_pwrite_stream &OS, bool IsELF64,
303                                uint8_t OSABI, uint16_t EMachine) {
304   auto MOTW = llvm::make_unique<X86ELFObjectWriter>(IsELF64, OSABI, EMachine);
305   return createELFObjectWriter(std::move(MOTW), OS, /*IsLittleEndian=*/true);
306 }
307