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 bool PCRel = Fixup.isPCRel();
49 if (IsCrossSection) {
50 // IMAGE_REL_AMD64_REL64 does not exist. We treat FK_Data_8 as FK_PCRel_4 so
51 // that .quad a-b can lower to IMAGE_REL_AMD64_REL32. This allows generic
52 // instrumentation to not bother with the COFF limitation. A negative value
53 // needs attention.
54 if (!PCRel &&
55 (FixupKind == FK_Data_4 || FixupKind == llvm::X86::reloc_signed_4byte ||
56 (FixupKind == FK_Data_8 && Is64Bit))) {
57 FixupKind = FK_Data_4;
58 PCRel = true;
59 } else {
60 Ctx.reportError(L: Fixup.getLoc(), Msg: "Cannot represent this expression");
61 return COFF::IMAGE_REL_AMD64_ADDR32;
62 }
63 }
64
65 auto Spec = Target.getSpecifier();
66 if (Is64Bit) {
67 switch (FixupKind) {
68 case X86::reloc_riprel_4byte:
69 case X86::reloc_riprel_4byte_movq_load:
70 case X86::reloc_riprel_4byte_movq_load_rex2:
71 case X86::reloc_riprel_4byte_relax:
72 case X86::reloc_riprel_4byte_relax_rex:
73 case X86::reloc_riprel_4byte_relax_rex2:
74 case X86::reloc_riprel_4byte_relax_evex:
75 case X86::reloc_branch_4byte_pcrel:
76 return COFF::IMAGE_REL_AMD64_REL32;
77 case FK_Data_4:
78 if (PCRel)
79 return COFF::IMAGE_REL_AMD64_REL32;
80 [[fallthrough]];
81 case X86::reloc_signed_4byte:
82 case X86::reloc_signed_4byte_relax:
83 if (Spec == MCSymbolRefExpr::VK_COFF_IMGREL32)
84 return COFF::IMAGE_REL_AMD64_ADDR32NB;
85 if (Spec == X86::S_COFF_SECREL)
86 return COFF::IMAGE_REL_AMD64_SECREL;
87 return COFF::IMAGE_REL_AMD64_ADDR32;
88 case FK_Data_8:
89 return COFF::IMAGE_REL_AMD64_ADDR64;
90 case FK_SecRel_2:
91 return COFF::IMAGE_REL_AMD64_SECTION;
92 case FK_SecRel_4:
93 return COFF::IMAGE_REL_AMD64_SECREL;
94 default:
95 Ctx.reportError(L: Fixup.getLoc(), Msg: "unsupported relocation type");
96 return COFF::IMAGE_REL_AMD64_ADDR32;
97 }
98 } else if (getMachine() == COFF::IMAGE_FILE_MACHINE_I386) {
99 switch (FixupKind) {
100 case X86::reloc_riprel_4byte:
101 case X86::reloc_riprel_4byte_movq_load:
102 return COFF::IMAGE_REL_I386_REL32;
103 case FK_Data_4:
104 if (PCRel)
105 return COFF::IMAGE_REL_I386_REL32;
106 [[fallthrough]];
107 case X86::reloc_signed_4byte:
108 case X86::reloc_signed_4byte_relax:
109 if (Spec == MCSymbolRefExpr::VK_COFF_IMGREL32)
110 return COFF::IMAGE_REL_I386_DIR32NB;
111 if (Spec == X86::S_COFF_SECREL)
112 return COFF::IMAGE_REL_I386_SECREL;
113 return COFF::IMAGE_REL_I386_DIR32;
114 case FK_SecRel_2:
115 return COFF::IMAGE_REL_I386_SECTION;
116 case FK_SecRel_4:
117 return COFF::IMAGE_REL_I386_SECREL;
118 default:
119 Ctx.reportError(L: Fixup.getLoc(), Msg: "unsupported relocation type");
120 return COFF::IMAGE_REL_I386_DIR32;
121 }
122 } else
123 llvm_unreachable("Unsupported COFF machine type.");
124}
125
126std::unique_ptr<MCObjectTargetWriter>
127llvm::createX86WinCOFFObjectWriter(bool Is64Bit) {
128 return std::make_unique<X86WinCOFFObjectWriter>(args&: Is64Bit);
129}
130