1 | //= AArch64WinCOFFObjectWriter.cpp - AArch64 Windows COFF Object Writer C++ =// |
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 "AArch64MCTargetDesc.h" |
10 | #include "MCTargetDesc/AArch64FixupKinds.h" |
11 | #include "MCTargetDesc/AArch64MCExpr.h" |
12 | #include "llvm/ADT/Twine.h" |
13 | #include "llvm/BinaryFormat/COFF.h" |
14 | #include "llvm/MC/MCAsmBackend.h" |
15 | #include "llvm/MC/MCContext.h" |
16 | #include "llvm/MC/MCExpr.h" |
17 | #include "llvm/MC/MCFixup.h" |
18 | #include "llvm/MC/MCFixupKindInfo.h" |
19 | #include "llvm/MC/MCObjectWriter.h" |
20 | #include "llvm/MC/MCValue.h" |
21 | #include "llvm/MC/MCWinCOFFObjectWriter.h" |
22 | #include "llvm/Support/Casting.h" |
23 | #include "llvm/Support/ErrorHandling.h" |
24 | #include "llvm/Support/raw_ostream.h" |
25 | #include <cassert> |
26 | |
27 | using namespace llvm; |
28 | |
29 | namespace { |
30 | |
31 | class AArch64WinCOFFObjectWriter : public MCWinCOFFObjectTargetWriter { |
32 | public: |
33 | AArch64WinCOFFObjectWriter(const Triple &TheTriple) |
34 | : MCWinCOFFObjectTargetWriter(TheTriple.isWindowsArm64EC() |
35 | ? COFF::IMAGE_FILE_MACHINE_ARM64EC |
36 | : COFF::IMAGE_FILE_MACHINE_ARM64) {} |
37 | |
38 | ~AArch64WinCOFFObjectWriter() override = default; |
39 | |
40 | unsigned getRelocType(MCContext &Ctx, const MCValue &Target, |
41 | const MCFixup &Fixup, bool IsCrossSection, |
42 | const MCAsmBackend &MAB) const override; |
43 | |
44 | bool recordRelocation(const MCFixup &) const override; |
45 | }; |
46 | |
47 | } // end anonymous namespace |
48 | |
49 | unsigned AArch64WinCOFFObjectWriter::getRelocType( |
50 | MCContext &Ctx, const MCValue &Target, const MCFixup &Fixup, |
51 | bool IsCrossSection, const MCAsmBackend &MAB) const { |
52 | unsigned FixupKind = Fixup.getKind(); |
53 | if (IsCrossSection) { |
54 | // IMAGE_REL_ARM64_REL64 does not exist. We treat FK_Data_8 as FK_PCRel_4 so |
55 | // that .xword a-b can lower to IMAGE_REL_ARM64_REL32. This allows generic |
56 | // instrumentation to not bother with the COFF limitation. A negative value |
57 | // needs attention. |
58 | if (FixupKind != FK_Data_4 && FixupKind != FK_Data_8) { |
59 | Ctx.reportError(L: Fixup.getLoc(), Msg: "Cannot represent this expression" ); |
60 | return COFF::IMAGE_REL_ARM64_ADDR32; |
61 | } |
62 | FixupKind = FK_PCRel_4; |
63 | } |
64 | |
65 | auto Modifier = Target.isAbsolute() ? MCSymbolRefExpr::VK_None |
66 | : Target.getSymA()->getKind(); |
67 | const MCExpr *Expr = Fixup.getValue(); |
68 | |
69 | if (const AArch64MCExpr *A64E = dyn_cast<AArch64MCExpr>(Val: Expr)) { |
70 | AArch64MCExpr::VariantKind RefKind = A64E->getKind(); |
71 | switch (AArch64MCExpr::getSymbolLoc(Kind: RefKind)) { |
72 | case AArch64MCExpr::VK_ABS: |
73 | case AArch64MCExpr::VK_SECREL: |
74 | // Supported |
75 | break; |
76 | default: |
77 | Ctx.reportError(L: Fixup.getLoc(), Msg: "relocation variant " + |
78 | A64E->getVariantKindName() + |
79 | " unsupported on COFF targets" ); |
80 | return COFF::IMAGE_REL_ARM64_ABSOLUTE; // Dummy return value |
81 | } |
82 | } |
83 | |
84 | switch (FixupKind) { |
85 | default: { |
86 | if (const AArch64MCExpr *A64E = dyn_cast<AArch64MCExpr>(Val: Expr)) { |
87 | Ctx.reportError(L: Fixup.getLoc(), Msg: "relocation type " + |
88 | A64E->getVariantKindName() + |
89 | " unsupported on COFF targets" ); |
90 | } else { |
91 | const MCFixupKindInfo &Info = MAB.getFixupKindInfo(Kind: Fixup.getKind()); |
92 | Ctx.reportError(L: Fixup.getLoc(), Msg: Twine("relocation type " ) + Info.Name + |
93 | " unsupported on COFF targets" ); |
94 | } |
95 | return COFF::IMAGE_REL_ARM64_ABSOLUTE; // Dummy return value |
96 | } |
97 | |
98 | case FK_PCRel_4: |
99 | return COFF::IMAGE_REL_ARM64_REL32; |
100 | |
101 | case FK_Data_4: |
102 | switch (Modifier) { |
103 | default: |
104 | return COFF::IMAGE_REL_ARM64_ADDR32; |
105 | case MCSymbolRefExpr::VK_COFF_IMGREL32: |
106 | return COFF::IMAGE_REL_ARM64_ADDR32NB; |
107 | case MCSymbolRefExpr::VK_SECREL: |
108 | return COFF::IMAGE_REL_ARM64_SECREL; |
109 | } |
110 | |
111 | case FK_Data_8: |
112 | return COFF::IMAGE_REL_ARM64_ADDR64; |
113 | |
114 | case FK_SecRel_2: |
115 | return COFF::IMAGE_REL_ARM64_SECTION; |
116 | |
117 | case FK_SecRel_4: |
118 | return COFF::IMAGE_REL_ARM64_SECREL; |
119 | |
120 | case AArch64::fixup_aarch64_add_imm12: |
121 | if (const AArch64MCExpr *A64E = dyn_cast<AArch64MCExpr>(Val: Expr)) { |
122 | AArch64MCExpr::VariantKind RefKind = A64E->getKind(); |
123 | if (RefKind == AArch64MCExpr::VK_SECREL_LO12) |
124 | return COFF::IMAGE_REL_ARM64_SECREL_LOW12A; |
125 | if (RefKind == AArch64MCExpr::VK_SECREL_HI12) |
126 | return COFF::IMAGE_REL_ARM64_SECREL_HIGH12A; |
127 | } |
128 | return COFF::IMAGE_REL_ARM64_PAGEOFFSET_12A; |
129 | |
130 | case AArch64::fixup_aarch64_ldst_imm12_scale1: |
131 | case AArch64::fixup_aarch64_ldst_imm12_scale2: |
132 | case AArch64::fixup_aarch64_ldst_imm12_scale4: |
133 | case AArch64::fixup_aarch64_ldst_imm12_scale8: |
134 | case AArch64::fixup_aarch64_ldst_imm12_scale16: |
135 | if (const AArch64MCExpr *A64E = dyn_cast<AArch64MCExpr>(Val: Expr)) { |
136 | AArch64MCExpr::VariantKind RefKind = A64E->getKind(); |
137 | if (RefKind == AArch64MCExpr::VK_SECREL_LO12) |
138 | return COFF::IMAGE_REL_ARM64_SECREL_LOW12L; |
139 | } |
140 | return COFF::IMAGE_REL_ARM64_PAGEOFFSET_12L; |
141 | |
142 | case AArch64::fixup_aarch64_pcrel_adr_imm21: |
143 | return COFF::IMAGE_REL_ARM64_REL21; |
144 | |
145 | case AArch64::fixup_aarch64_pcrel_adrp_imm21: |
146 | return COFF::IMAGE_REL_ARM64_PAGEBASE_REL21; |
147 | |
148 | case AArch64::fixup_aarch64_pcrel_branch14: |
149 | return COFF::IMAGE_REL_ARM64_BRANCH14; |
150 | |
151 | case AArch64::fixup_aarch64_pcrel_branch19: |
152 | return COFF::IMAGE_REL_ARM64_BRANCH19; |
153 | |
154 | case AArch64::fixup_aarch64_pcrel_branch26: |
155 | case AArch64::fixup_aarch64_pcrel_call26: |
156 | return COFF::IMAGE_REL_ARM64_BRANCH26; |
157 | } |
158 | } |
159 | |
160 | bool AArch64WinCOFFObjectWriter::recordRelocation(const MCFixup &Fixup) const { |
161 | return true; |
162 | } |
163 | |
164 | std::unique_ptr<MCObjectTargetWriter> |
165 | llvm::createAArch64WinCOFFObjectWriter(const Triple &TheTriple) { |
166 | return std::make_unique<AArch64WinCOFFObjectWriter>(args: TheTriple); |
167 | } |
168 | |