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