1234285Sdim//===-- X86ELFObjectWriter.cpp - X86 ELF Writer ---------------------------===//
2234285Sdim//
3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4353358Sdim// See https://llvm.org/LICENSE.txt for license information.
5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6234285Sdim//
7234285Sdim//===----------------------------------------------------------------------===//
8234285Sdim
9234285Sdim#include "MCTargetDesc/X86FixupKinds.h"
10234285Sdim#include "MCTargetDesc/X86MCTargetDesc.h"
11321369Sdim#include "llvm/BinaryFormat/ELF.h"
12309124Sdim#include "llvm/MC/MCAsmInfo.h"
13309124Sdim#include "llvm/MC/MCContext.h"
14234285Sdim#include "llvm/MC/MCELFObjectWriter.h"
15234285Sdim#include "llvm/MC/MCExpr.h"
16321369Sdim#include "llvm/MC/MCFixup.h"
17327952Sdim#include "llvm/MC/MCObjectWriter.h"
18234285Sdim#include "llvm/MC/MCValue.h"
19234285Sdim#include "llvm/Support/ErrorHandling.h"
20321369Sdim#include <cassert>
21321369Sdim#include <cstdint>
22234285Sdim
23234285Sdimusing namespace llvm;
24234285Sdim
25234285Sdimnamespace {
26234285Sdim
27321369Sdimclass X86ELFObjectWriter : public MCELFObjectTargetWriter {
28321369Sdimpublic:
29321369Sdim  X86ELFObjectWriter(bool IsELF64, uint8_t OSABI, uint16_t EMachine);
30321369Sdim  ~X86ELFObjectWriter() override = default;
31288943Sdim
32321369Sdimprotected:
33321369Sdim  unsigned getRelocType(MCContext &Ctx, const MCValue &Target,
34321369Sdim                        const MCFixup &Fixup, bool IsPCRel) const override;
35321369Sdim};
36234285Sdim
37321369Sdim} // end anonymous namespace
38321369Sdim
39243830SdimX86ELFObjectWriter::X86ELFObjectWriter(bool IsELF64, uint8_t OSABI,
40243830Sdim                                       uint16_t EMachine)
41296417Sdim    : MCELFObjectTargetWriter(IsELF64, OSABI, EMachine,
42296417Sdim                              // Only i386 and IAMCU use Rel instead of RelA.
43296417Sdim                              /*HasRelocationAddend*/
44296417Sdim                              (EMachine != ELF::EM_386) &&
45296417Sdim                                  (EMachine != ELF::EM_IAMCU)) {}
46234285Sdim
47353358Sdimenum X86_64RelType { RT64_NONE, RT64_64, RT64_32, RT64_32S, RT64_16, RT64_8 };
48234285Sdim
49360784Sdimstatic X86_64RelType getType64(MCFixupKind Kind,
50288943Sdim                               MCSymbolRefExpr::VariantKind &Modifier,
51288943Sdim                               bool &IsPCRel) {
52360784Sdim  switch (unsigned(Kind)) {
53288943Sdim  default:
54288943Sdim    llvm_unreachable("Unimplemented");
55353358Sdim  case FK_NONE:
56353358Sdim    return RT64_NONE;
57288943Sdim  case X86::reloc_global_offset_table8:
58288943Sdim    Modifier = MCSymbolRefExpr::VK_GOT;
59288943Sdim    IsPCRel = true;
60288943Sdim    return RT64_64;
61288943Sdim  case FK_Data_8:
62288943Sdim    return RT64_64;
63288943Sdim  case X86::reloc_signed_4byte:
64309124Sdim  case X86::reloc_signed_4byte_relax:
65288943Sdim    if (Modifier == MCSymbolRefExpr::VK_None && !IsPCRel)
66288943Sdim      return RT64_32S;
67288943Sdim    return RT64_32;
68288943Sdim  case X86::reloc_global_offset_table:
69288943Sdim    Modifier = MCSymbolRefExpr::VK_GOT;
70288943Sdim    IsPCRel = true;
71288943Sdim    return RT64_32;
72288943Sdim  case FK_Data_4:
73288943Sdim  case FK_PCRel_4:
74288943Sdim  case X86::reloc_riprel_4byte:
75309124Sdim  case X86::reloc_riprel_4byte_relax:
76309124Sdim  case X86::reloc_riprel_4byte_relax_rex:
77288943Sdim  case X86::reloc_riprel_4byte_movq_load:
78288943Sdim    return RT64_32;
79341825Sdim  case X86::reloc_branch_4byte_pcrel:
80341825Sdim    Modifier = MCSymbolRefExpr::VK_PLT;
81341825Sdim    return RT64_32;
82288943Sdim  case FK_PCRel_2:
83288943Sdim  case FK_Data_2:
84288943Sdim    return RT64_16;
85288943Sdim  case FK_PCRel_1:
86288943Sdim  case FK_Data_1:
87288943Sdim    return RT64_8;
88288943Sdim  }
89288943Sdim}
90234285Sdim
91309124Sdimstatic void checkIs32(MCContext &Ctx, SMLoc Loc, X86_64RelType Type) {
92309124Sdim  if (Type != RT64_32)
93309124Sdim    Ctx.reportError(Loc,
94309124Sdim                    "32 bit reloc applied to a field with a different size");
95309124Sdim}
96309124Sdim
97309124Sdimstatic unsigned getRelocType64(MCContext &Ctx, SMLoc Loc,
98309124Sdim                               MCSymbolRefExpr::VariantKind Modifier,
99309124Sdim                               X86_64RelType Type, bool IsPCRel,
100360784Sdim                               MCFixupKind Kind) {
101288943Sdim  switch (Modifier) {
102288943Sdim  default:
103288943Sdim    llvm_unreachable("Unimplemented");
104288943Sdim  case MCSymbolRefExpr::VK_None:
105321369Sdim  case MCSymbolRefExpr::VK_X86_ABS8:
106288943Sdim    switch (Type) {
107353358Sdim    case RT64_NONE:
108353358Sdim      if (Modifier == MCSymbolRefExpr::VK_None)
109353358Sdim        return ELF::R_X86_64_NONE;
110353358Sdim      llvm_unreachable("Unimplemented");
111288943Sdim    case RT64_64:
112288943Sdim      return IsPCRel ? ELF::R_X86_64_PC64 : ELF::R_X86_64_64;
113288943Sdim    case RT64_32:
114288943Sdim      return IsPCRel ? ELF::R_X86_64_PC32 : ELF::R_X86_64_32;
115288943Sdim    case RT64_32S:
116288943Sdim      return ELF::R_X86_64_32S;
117288943Sdim    case RT64_16:
118288943Sdim      return IsPCRel ? ELF::R_X86_64_PC16 : ELF::R_X86_64_16;
119288943Sdim    case RT64_8:
120288943Sdim      return IsPCRel ? ELF::R_X86_64_PC8 : ELF::R_X86_64_8;
121234285Sdim    }
122353358Sdim    llvm_unreachable("unexpected relocation type!");
123288943Sdim  case MCSymbolRefExpr::VK_GOT:
124288943Sdim    switch (Type) {
125288943Sdim    case RT64_64:
126288943Sdim      return IsPCRel ? ELF::R_X86_64_GOTPC64 : ELF::R_X86_64_GOT64;
127288943Sdim    case RT64_32:
128288943Sdim      return IsPCRel ? ELF::R_X86_64_GOTPC32 : ELF::R_X86_64_GOT32;
129288943Sdim    case RT64_32S:
130288943Sdim    case RT64_16:
131288943Sdim    case RT64_8:
132353358Sdim    case RT64_NONE:
133288943Sdim      llvm_unreachable("Unimplemented");
134288943Sdim    }
135353358Sdim    llvm_unreachable("unexpected relocation type!");
136288943Sdim  case MCSymbolRefExpr::VK_GOTOFF:
137288943Sdim    assert(Type == RT64_64);
138288943Sdim    assert(!IsPCRel);
139288943Sdim    return ELF::R_X86_64_GOTOFF64;
140288943Sdim  case MCSymbolRefExpr::VK_TPOFF:
141288943Sdim    assert(!IsPCRel);
142288943Sdim    switch (Type) {
143288943Sdim    case RT64_64:
144288943Sdim      return ELF::R_X86_64_TPOFF64;
145288943Sdim    case RT64_32:
146288943Sdim      return ELF::R_X86_64_TPOFF32;
147288943Sdim    case RT64_32S:
148288943Sdim    case RT64_16:
149288943Sdim    case RT64_8:
150353358Sdim    case RT64_NONE:
151288943Sdim      llvm_unreachable("Unimplemented");
152288943Sdim    }
153353358Sdim    llvm_unreachable("unexpected relocation type!");
154288943Sdim  case MCSymbolRefExpr::VK_DTPOFF:
155288943Sdim    assert(!IsPCRel);
156288943Sdim    switch (Type) {
157288943Sdim    case RT64_64:
158288943Sdim      return ELF::R_X86_64_DTPOFF64;
159288943Sdim    case RT64_32:
160288943Sdim      return ELF::R_X86_64_DTPOFF32;
161288943Sdim    case RT64_32S:
162288943Sdim    case RT64_16:
163288943Sdim    case RT64_8:
164353358Sdim    case RT64_NONE:
165288943Sdim      llvm_unreachable("Unimplemented");
166288943Sdim    }
167353358Sdim    llvm_unreachable("unexpected relocation type!");
168288943Sdim  case MCSymbolRefExpr::VK_SIZE:
169288943Sdim    assert(!IsPCRel);
170288943Sdim    switch (Type) {
171288943Sdim    case RT64_64:
172288943Sdim      return ELF::R_X86_64_SIZE64;
173288943Sdim    case RT64_32:
174288943Sdim      return ELF::R_X86_64_SIZE32;
175288943Sdim    case RT64_32S:
176288943Sdim    case RT64_16:
177288943Sdim    case RT64_8:
178353358Sdim    case RT64_NONE:
179288943Sdim      llvm_unreachable("Unimplemented");
180288943Sdim    }
181353358Sdim    llvm_unreachable("unexpected relocation type!");
182309124Sdim  case MCSymbolRefExpr::VK_TLSCALL:
183309124Sdim    return ELF::R_X86_64_TLSDESC_CALL;
184309124Sdim  case MCSymbolRefExpr::VK_TLSDESC:
185309124Sdim    return ELF::R_X86_64_GOTPC32_TLSDESC;
186288943Sdim  case MCSymbolRefExpr::VK_TLSGD:
187309124Sdim    checkIs32(Ctx, Loc, Type);
188288943Sdim    return ELF::R_X86_64_TLSGD;
189288943Sdim  case MCSymbolRefExpr::VK_GOTTPOFF:
190309124Sdim    checkIs32(Ctx, Loc, Type);
191288943Sdim    return ELF::R_X86_64_GOTTPOFF;
192288943Sdim  case MCSymbolRefExpr::VK_TLSLD:
193309124Sdim    checkIs32(Ctx, Loc, Type);
194288943Sdim    return ELF::R_X86_64_TLSLD;
195288943Sdim  case MCSymbolRefExpr::VK_PLT:
196309124Sdim    checkIs32(Ctx, Loc, Type);
197288943Sdim    return ELF::R_X86_64_PLT32;
198288943Sdim  case MCSymbolRefExpr::VK_GOTPCREL:
199309124Sdim    checkIs32(Ctx, Loc, Type);
200309124Sdim    // Older versions of ld.bfd/ld.gold/lld
201309124Sdim    // do not support GOTPCRELX/REX_GOTPCRELX,
202309124Sdim    // and we want to keep back-compatibility.
203309124Sdim    if (!Ctx.getAsmInfo()->canRelaxRelocations())
204309124Sdim      return ELF::R_X86_64_GOTPCREL;
205360784Sdim    switch (unsigned(Kind)) {
206309124Sdim    default:
207309124Sdim      return ELF::R_X86_64_GOTPCREL;
208309124Sdim    case X86::reloc_riprel_4byte_relax:
209309124Sdim      return ELF::R_X86_64_GOTPCRELX;
210309124Sdim    case X86::reloc_riprel_4byte_relax_rex:
211309124Sdim    case X86::reloc_riprel_4byte_movq_load:
212309124Sdim      return ELF::R_X86_64_REX_GOTPCRELX;
213309124Sdim    }
214353358Sdim    llvm_unreachable("unexpected relocation type!");
215288943Sdim  }
216288943Sdim}
217234285Sdim
218353358Sdimenum X86_32RelType { RT32_NONE, RT32_32, RT32_16, RT32_8 };
219234285Sdim
220288943Sdimstatic X86_32RelType getType32(X86_64RelType T) {
221288943Sdim  switch (T) {
222353358Sdim  case RT64_NONE:
223353358Sdim    return RT32_NONE;
224288943Sdim  case RT64_64:
225288943Sdim    llvm_unreachable("Unimplemented");
226288943Sdim  case RT64_32:
227288943Sdim  case RT64_32S:
228288943Sdim    return RT32_32;
229288943Sdim  case RT64_16:
230288943Sdim    return RT32_16;
231288943Sdim  case RT64_8:
232288943Sdim    return RT32_8;
233288943Sdim  }
234288943Sdim  llvm_unreachable("unexpected relocation type!");
235288943Sdim}
236276479Sdim
237309124Sdimstatic unsigned getRelocType32(MCContext &Ctx,
238309124Sdim                               MCSymbolRefExpr::VariantKind Modifier,
239309124Sdim                               X86_32RelType Type, bool IsPCRel,
240360784Sdim                               MCFixupKind Kind) {
241288943Sdim  switch (Modifier) {
242288943Sdim  default:
243288943Sdim    llvm_unreachable("Unimplemented");
244288943Sdim  case MCSymbolRefExpr::VK_None:
245321369Sdim  case MCSymbolRefExpr::VK_X86_ABS8:
246288943Sdim    switch (Type) {
247353358Sdim    case RT32_NONE:
248353358Sdim      if (Modifier == MCSymbolRefExpr::VK_None)
249353358Sdim        return ELF::R_386_NONE;
250353358Sdim      llvm_unreachable("Unimplemented");
251288943Sdim    case RT32_32:
252288943Sdim      return IsPCRel ? ELF::R_386_PC32 : ELF::R_386_32;
253288943Sdim    case RT32_16:
254288943Sdim      return IsPCRel ? ELF::R_386_PC16 : ELF::R_386_16;
255288943Sdim    case RT32_8:
256288943Sdim      return IsPCRel ? ELF::R_386_PC8 : ELF::R_386_8;
257288943Sdim    }
258353358Sdim    llvm_unreachable("unexpected relocation type!");
259288943Sdim  case MCSymbolRefExpr::VK_GOT:
260288943Sdim    assert(Type == RT32_32);
261309124Sdim    if (IsPCRel)
262309124Sdim      return ELF::R_386_GOTPC;
263309124Sdim    // Older versions of ld.bfd/ld.gold/lld do not support R_386_GOT32X and we
264309124Sdim    // want to maintain compatibility.
265309124Sdim    if (!Ctx.getAsmInfo()->canRelaxRelocations())
266309124Sdim      return ELF::R_386_GOT32;
267309124Sdim
268360784Sdim    return Kind == MCFixupKind(X86::reloc_signed_4byte_relax)
269360784Sdim               ? ELF::R_386_GOT32X
270360784Sdim               : ELF::R_386_GOT32;
271288943Sdim  case MCSymbolRefExpr::VK_GOTOFF:
272288943Sdim    assert(Type == RT32_32);
273288943Sdim    assert(!IsPCRel);
274288943Sdim    return ELF::R_386_GOTOFF;
275353358Sdim  case MCSymbolRefExpr::VK_TLSCALL:
276353358Sdim    return ELF::R_386_TLS_DESC_CALL;
277353358Sdim  case MCSymbolRefExpr::VK_TLSDESC:
278353358Sdim    return ELF::R_386_TLS_GOTDESC;
279288943Sdim  case MCSymbolRefExpr::VK_TPOFF:
280288943Sdim    assert(Type == RT32_32);
281288943Sdim    assert(!IsPCRel);
282288943Sdim    return ELF::R_386_TLS_LE_32;
283288943Sdim  case MCSymbolRefExpr::VK_DTPOFF:
284288943Sdim    assert(Type == RT32_32);
285288943Sdim    assert(!IsPCRel);
286288943Sdim    return ELF::R_386_TLS_LDO_32;
287288943Sdim  case MCSymbolRefExpr::VK_TLSGD:
288288943Sdim    assert(Type == RT32_32);
289288943Sdim    assert(!IsPCRel);
290288943Sdim    return ELF::R_386_TLS_GD;
291288943Sdim  case MCSymbolRefExpr::VK_GOTTPOFF:
292288943Sdim    assert(Type == RT32_32);
293288943Sdim    assert(!IsPCRel);
294288943Sdim    return ELF::R_386_TLS_IE_32;
295288943Sdim  case MCSymbolRefExpr::VK_PLT:
296288943Sdim    assert(Type == RT32_32);
297288943Sdim    return ELF::R_386_PLT32;
298288943Sdim  case MCSymbolRefExpr::VK_INDNTPOFF:
299288943Sdim    assert(Type == RT32_32);
300288943Sdim    assert(!IsPCRel);
301288943Sdim    return ELF::R_386_TLS_IE;
302288943Sdim  case MCSymbolRefExpr::VK_NTPOFF:
303288943Sdim    assert(Type == RT32_32);
304288943Sdim    assert(!IsPCRel);
305288943Sdim    return ELF::R_386_TLS_LE;
306288943Sdim  case MCSymbolRefExpr::VK_GOTNTPOFF:
307288943Sdim    assert(Type == RT32_32);
308288943Sdim    assert(!IsPCRel);
309288943Sdim    return ELF::R_386_TLS_GOTIE;
310288943Sdim  case MCSymbolRefExpr::VK_TLSLDM:
311288943Sdim    assert(Type == RT32_32);
312288943Sdim    assert(!IsPCRel);
313288943Sdim    return ELF::R_386_TLS_LDM;
314288943Sdim  }
315288943Sdim}
316276479Sdim
317309124Sdimunsigned X86ELFObjectWriter::getRelocType(MCContext &Ctx, const MCValue &Target,
318288943Sdim                                          const MCFixup &Fixup,
319288943Sdim                                          bool IsPCRel) const {
320288943Sdim  MCSymbolRefExpr::VariantKind Modifier = Target.getAccessVariant();
321360784Sdim  MCFixupKind Kind = Fixup.getKind();
322309124Sdim  X86_64RelType Type = getType64(Kind, Modifier, IsPCRel);
323288943Sdim  if (getEMachine() == ELF::EM_X86_64)
324309124Sdim    return getRelocType64(Ctx, Fixup.getLoc(), Modifier, Type, IsPCRel, Kind);
325234285Sdim
326296417Sdim  assert((getEMachine() == ELF::EM_386 || getEMachine() == ELF::EM_IAMCU) &&
327296417Sdim         "Unsupported ELF machine type.");
328309124Sdim  return getRelocType32(Ctx, Modifier, getType32(Type), IsPCRel, Kind);
329234285Sdim}
330234285Sdim
331341825Sdimstd::unique_ptr<MCObjectTargetWriter>
332341825Sdimllvm::createX86ELFObjectWriter(bool IsELF64, uint8_t OSABI, uint16_t EMachine) {
333360784Sdim  return std::make_unique<X86ELFObjectWriter>(IsELF64, OSABI, EMachine);
334234285Sdim}
335