xref: /freebsd/contrib/llvm-project/llvm/lib/Target/X86/MCTargetDesc/X86WinCOFFObjectWriter.cpp (revision 700637cbb5e582861067a11aaca4d053546871d2)
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 
21 using namespace llvm;
22 
23 namespace {
24 
25 class X86WinCOFFObjectWriter : public MCWinCOFFObjectTargetWriter {
26 public:
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 
X86WinCOFFObjectWriter(bool Is64Bit)37 X86WinCOFFObjectWriter::X86WinCOFFObjectWriter(bool Is64Bit)
38     : MCWinCOFFObjectTargetWriter(Is64Bit ? COFF::IMAGE_FILE_MACHINE_AMD64
39                                           : COFF::IMAGE_FILE_MACHINE_I386) {}
40 
getRelocType(MCContext & Ctx,const MCValue & Target,const MCFixup & Fixup,bool IsCrossSection,const MCAsmBackend & MAB) const41 unsigned 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(Fixup.getLoc(), "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(Fixup.getLoc(), "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(Fixup.getLoc(), "unsupported relocation type");
120       return COFF::IMAGE_REL_I386_DIR32;
121     }
122   } else
123     llvm_unreachable("Unsupported COFF machine type.");
124 }
125 
126 std::unique_ptr<MCObjectTargetWriter>
createX86WinCOFFObjectWriter(bool Is64Bit)127 llvm::createX86WinCOFFObjectWriter(bool Is64Bit) {
128   return std::make_unique<X86WinCOFFObjectWriter>(Is64Bit);
129 }
130