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_TLSGD:
158     checkIs32(Ctx, Loc, Type);
159     return ELF::R_X86_64_TLSGD;
160   case MCSymbolRefExpr::VK_GOTTPOFF:
161     checkIs32(Ctx, Loc, Type);
162     return ELF::R_X86_64_GOTTPOFF;
163   case MCSymbolRefExpr::VK_TLSLD:
164     checkIs32(Ctx, Loc, Type);
165     return ELF::R_X86_64_TLSLD;
166   case MCSymbolRefExpr::VK_PLT:
167     checkIs32(Ctx, Loc, Type);
168     return ELF::R_X86_64_PLT32;
169   case MCSymbolRefExpr::VK_GOTPCREL:
170     checkIs32(Ctx, Loc, Type);
171     return ELF::R_X86_64_GOTPCREL;
172   }
173 }
174 
175 enum X86_32RelType { RT32_32, RT32_16, RT32_8 };
176 
177 static X86_32RelType getType32(X86_64RelType T) {
178   switch (T) {
179   case RT64_64:
180     llvm_unreachable("Unimplemented");
181   case RT64_32:
182   case RT64_32S:
183     return RT32_32;
184   case RT64_16:
185     return RT32_16;
186   case RT64_8:
187     return RT32_8;
188   }
189   llvm_unreachable("unexpected relocation type!");
190 }
191 
192 static unsigned getRelocType32(MCSymbolRefExpr::VariantKind Modifier,
193                                X86_32RelType Type, bool IsPCRel) {
194   switch (Modifier) {
195   default:
196     llvm_unreachable("Unimplemented");
197   case MCSymbolRefExpr::VK_None:
198     switch (Type) {
199     case RT32_32:
200       return IsPCRel ? ELF::R_386_PC32 : ELF::R_386_32;
201     case RT32_16:
202       return IsPCRel ? ELF::R_386_PC16 : ELF::R_386_16;
203     case RT32_8:
204       return IsPCRel ? ELF::R_386_PC8 : ELF::R_386_8;
205     }
206   case MCSymbolRefExpr::VK_GOT:
207     assert(Type == RT32_32);
208     return IsPCRel ? ELF::R_386_GOTPC : ELF::R_386_GOT32;
209   case MCSymbolRefExpr::VK_GOTOFF:
210     assert(Type == RT32_32);
211     assert(!IsPCRel);
212     return ELF::R_386_GOTOFF;
213   case MCSymbolRefExpr::VK_TPOFF:
214     assert(Type == RT32_32);
215     assert(!IsPCRel);
216     return ELF::R_386_TLS_LE_32;
217   case MCSymbolRefExpr::VK_DTPOFF:
218     assert(Type == RT32_32);
219     assert(!IsPCRel);
220     return ELF::R_386_TLS_LDO_32;
221   case MCSymbolRefExpr::VK_TLSGD:
222     assert(Type == RT32_32);
223     assert(!IsPCRel);
224     return ELF::R_386_TLS_GD;
225   case MCSymbolRefExpr::VK_GOTTPOFF:
226     assert(Type == RT32_32);
227     assert(!IsPCRel);
228     return ELF::R_386_TLS_IE_32;
229   case MCSymbolRefExpr::VK_PLT:
230     assert(Type == RT32_32);
231     return ELF::R_386_PLT32;
232   case MCSymbolRefExpr::VK_INDNTPOFF:
233     assert(Type == RT32_32);
234     assert(!IsPCRel);
235     return ELF::R_386_TLS_IE;
236   case MCSymbolRefExpr::VK_NTPOFF:
237     assert(Type == RT32_32);
238     assert(!IsPCRel);
239     return ELF::R_386_TLS_LE;
240   case MCSymbolRefExpr::VK_GOTNTPOFF:
241     assert(Type == RT32_32);
242     assert(!IsPCRel);
243     return ELF::R_386_TLS_GOTIE;
244   case MCSymbolRefExpr::VK_TLSLDM:
245     assert(Type == RT32_32);
246     assert(!IsPCRel);
247     return ELF::R_386_TLS_LDM;
248   }
249 }
250 
251 unsigned X86ELFObjectWriter::getRelocType(MCContext &Ctx, const MCValue &Target,
252                                           const MCFixup &Fixup,
253                                           bool IsPCRel) const {
254   MCSymbolRefExpr::VariantKind Modifier = Target.getAccessVariant();
255   X86_64RelType Type = getType64(Fixup.getKind(), Modifier, IsPCRel);
256   if (getEMachine() == ELF::EM_X86_64)
257     return getRelocType64(Ctx, Fixup.getLoc(), Modifier, Type, IsPCRel);
258 
259   assert((getEMachine() == ELF::EM_386 || getEMachine() == ELF::EM_IAMCU) &&
260          "Unsupported ELF machine type.");
261   return getRelocType32(Modifier, getType32(Type), IsPCRel);
262 }
263 
264 MCObjectWriter *llvm::createX86ELFObjectWriter(raw_pwrite_stream &OS,
265                                                bool IsELF64, uint8_t OSABI,
266                                                uint16_t EMachine) {
267   MCELFObjectTargetWriter *MOTW =
268     new X86ELFObjectWriter(IsELF64, OSABI, EMachine);
269   return createELFObjectWriter(MOTW, OS,  /*IsLittleEndian=*/true);
270 }
271