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