1//===-- X86WinCOFFObjectWriter.cpp - X86 Win COFF Writer ------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "MCTargetDesc/X86FixupKinds.h"
10#include "MCTargetDesc/X86MCAsmInfo.h"
11#include "MCTargetDesc/X86MCTargetDesc.h"
12#include "llvm/BinaryFormat/COFF.h"
13#include "llvm/MC/MCContext.h"
14#include "llvm/MC/MCExpr.h"
15#include "llvm/MC/MCFixup.h"
16#include "llvm/MC/MCObjectWriter.h"
17#include "llvm/MC/MCValue.h"
18#include "llvm/MC/MCWinCOFFObjectWriter.h"
19#include "llvm/Support/ErrorHandling.h"
20
21using namespace llvm;
22
23namespace {
24
25class X86WinCOFFObjectWriter : public MCWinCOFFObjectTargetWriter {
26public:
27 X86WinCOFFObjectWriter(bool Is64Bit);
28 ~X86WinCOFFObjectWriter() override = default;
29
30 unsigned getRelocType(MCContext &Ctx, const MCValue &Target,
31 const MCFixup &Fixup, bool IsCrossSection,
32 const MCAsmBackend &MAB) const override;
33};
34
35} // end anonymous namespace
36
37X86WinCOFFObjectWriter::X86WinCOFFObjectWriter(bool Is64Bit)
38 : MCWinCOFFObjectTargetWriter(Is64Bit ? COFF::IMAGE_FILE_MACHINE_AMD64
39 : COFF::IMAGE_FILE_MACHINE_I386) {}
40
41unsigned X86WinCOFFObjectWriter::getRelocType(MCContext &Ctx,
42 const MCValue &Target,
43 const MCFixup &Fixup,
44 bool IsCrossSection,
45 const MCAsmBackend &MAB) const {
46 const bool Is64Bit = getMachine() == COFF::IMAGE_FILE_MACHINE_AMD64;
47 unsigned FixupKind = Fixup.getKind();
48 if (IsCrossSection) {
49 // IMAGE_REL_AMD64_REL64 does not exist. We treat FK_Data_8 as FK_PCRel_4 so
50 // that .quad a-b can lower to IMAGE_REL_AMD64_REL32. This allows generic
51 // instrumentation to not bother with the COFF limitation. A negative value
52 // needs attention.
53 if (FixupKind == FK_Data_4 || FixupKind == llvm::X86::reloc_signed_4byte ||
54 (FixupKind == FK_Data_8 && Is64Bit)) {
55 FixupKind = FK_PCRel_4;
56 } else {
57 Ctx.reportError(L: Fixup.getLoc(), Msg: "Cannot represent this expression");
58 return COFF::IMAGE_REL_AMD64_ADDR32;
59 }
60 }
61
62 auto Spec = Target.getSpecifier();
63 if (Is64Bit) {
64 switch (FixupKind) {
65 case FK_PCRel_4:
66 case X86::reloc_riprel_4byte:
67 case X86::reloc_riprel_4byte_movq_load:
68 case X86::reloc_riprel_4byte_movq_load_rex2:
69 case X86::reloc_riprel_4byte_relax:
70 case X86::reloc_riprel_4byte_relax_rex:
71 case X86::reloc_riprel_4byte_relax_rex2:
72 case X86::reloc_riprel_4byte_relax_evex:
73 case X86::reloc_branch_4byte_pcrel:
74 return COFF::IMAGE_REL_AMD64_REL32;
75 case FK_Data_4:
76 case X86::reloc_signed_4byte:
77 case X86::reloc_signed_4byte_relax:
78 if (Spec == MCSymbolRefExpr::VK_COFF_IMGREL32)
79 return COFF::IMAGE_REL_AMD64_ADDR32NB;
80 if (Spec == X86::S_COFF_SECREL)
81 return COFF::IMAGE_REL_AMD64_SECREL;
82 return COFF::IMAGE_REL_AMD64_ADDR32;
83 case FK_Data_8:
84 return COFF::IMAGE_REL_AMD64_ADDR64;
85 case FK_SecRel_2:
86 return COFF::IMAGE_REL_AMD64_SECTION;
87 case FK_SecRel_4:
88 return COFF::IMAGE_REL_AMD64_SECREL;
89 default:
90 Ctx.reportError(L: Fixup.getLoc(), Msg: "unsupported relocation type");
91 return COFF::IMAGE_REL_AMD64_ADDR32;
92 }
93 } else if (getMachine() == COFF::IMAGE_FILE_MACHINE_I386) {
94 switch (FixupKind) {
95 case FK_PCRel_4:
96 case X86::reloc_riprel_4byte:
97 case X86::reloc_riprel_4byte_movq_load:
98 return COFF::IMAGE_REL_I386_REL32;
99 case FK_Data_4:
100 case X86::reloc_signed_4byte:
101 case X86::reloc_signed_4byte_relax:
102 if (Spec == MCSymbolRefExpr::VK_COFF_IMGREL32)
103 return COFF::IMAGE_REL_I386_DIR32NB;
104 if (Spec == X86::S_COFF_SECREL)
105 return COFF::IMAGE_REL_I386_SECREL;
106 return COFF::IMAGE_REL_I386_DIR32;
107 case FK_SecRel_2:
108 return COFF::IMAGE_REL_I386_SECTION;
109 case FK_SecRel_4:
110 return COFF::IMAGE_REL_I386_SECREL;
111 default:
112 Ctx.reportError(L: Fixup.getLoc(), Msg: "unsupported relocation type");
113 return COFF::IMAGE_REL_I386_DIR32;
114 }
115 } else
116 llvm_unreachable("Unsupported COFF machine type.");
117}
118
119std::unique_ptr<MCObjectTargetWriter>
120llvm::createX86WinCOFFObjectWriter(bool Is64Bit) {
121 return std::make_unique<X86WinCOFFObjectWriter>(args&: Is64Bit);
122}
123