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