Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/llvm/lib/Target/PowerPC/MCTargetDesc/PPCAsmBackend.cpp
35294 views
1
//===-- PPCAsmBackend.cpp - PPC Assembler Backend -------------------------===//
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/PPCFixupKinds.h"
10
#include "MCTargetDesc/PPCMCTargetDesc.h"
11
#include "llvm/BinaryFormat/ELF.h"
12
#include "llvm/BinaryFormat/MachO.h"
13
#include "llvm/MC/MCAsmBackend.h"
14
#include "llvm/MC/MCAssembler.h"
15
#include "llvm/MC/MCELFObjectWriter.h"
16
#include "llvm/MC/MCFixupKindInfo.h"
17
#include "llvm/MC/MCMachObjectWriter.h"
18
#include "llvm/MC/MCObjectWriter.h"
19
#include "llvm/MC/MCSectionMachO.h"
20
#include "llvm/MC/MCSubtargetInfo.h"
21
#include "llvm/MC/MCSymbolELF.h"
22
#include "llvm/MC/MCSymbolXCOFF.h"
23
#include "llvm/MC/MCValue.h"
24
#include "llvm/MC/TargetRegistry.h"
25
#include "llvm/Support/ErrorHandling.h"
26
using namespace llvm;
27
28
static uint64_t adjustFixupValue(unsigned Kind, uint64_t Value) {
29
switch (Kind) {
30
default:
31
llvm_unreachable("Unknown fixup kind!");
32
case FK_Data_1:
33
case FK_Data_2:
34
case FK_Data_4:
35
case FK_Data_8:
36
case PPC::fixup_ppc_nofixup:
37
return Value;
38
case PPC::fixup_ppc_brcond14:
39
case PPC::fixup_ppc_brcond14abs:
40
return Value & 0xfffc;
41
case PPC::fixup_ppc_br24:
42
case PPC::fixup_ppc_br24abs:
43
case PPC::fixup_ppc_br24_notoc:
44
return Value & 0x3fffffc;
45
case PPC::fixup_ppc_half16:
46
return Value & 0xffff;
47
case PPC::fixup_ppc_half16ds:
48
case PPC::fixup_ppc_half16dq:
49
return Value & 0xfffc;
50
case PPC::fixup_ppc_pcrel34:
51
case PPC::fixup_ppc_imm34:
52
return Value & 0x3ffffffff;
53
}
54
}
55
56
static unsigned getFixupKindNumBytes(unsigned Kind) {
57
switch (Kind) {
58
default:
59
llvm_unreachable("Unknown fixup kind!");
60
case FK_Data_1:
61
return 1;
62
case FK_Data_2:
63
case PPC::fixup_ppc_half16:
64
case PPC::fixup_ppc_half16ds:
65
case PPC::fixup_ppc_half16dq:
66
return 2;
67
case FK_Data_4:
68
case PPC::fixup_ppc_brcond14:
69
case PPC::fixup_ppc_brcond14abs:
70
case PPC::fixup_ppc_br24:
71
case PPC::fixup_ppc_br24abs:
72
case PPC::fixup_ppc_br24_notoc:
73
return 4;
74
case PPC::fixup_ppc_pcrel34:
75
case PPC::fixup_ppc_imm34:
76
case FK_Data_8:
77
return 8;
78
case PPC::fixup_ppc_nofixup:
79
return 0;
80
}
81
}
82
83
namespace {
84
85
class PPCAsmBackend : public MCAsmBackend {
86
protected:
87
Triple TT;
88
public:
89
PPCAsmBackend(const Target &T, const Triple &TT)
90
: MCAsmBackend(TT.isLittleEndian() ? llvm::endianness::little
91
: llvm::endianness::big),
92
TT(TT) {}
93
94
unsigned getNumFixupKinds() const override {
95
return PPC::NumTargetFixupKinds;
96
}
97
98
const MCFixupKindInfo &getFixupKindInfo(MCFixupKind Kind) const override {
99
const static MCFixupKindInfo InfosBE[PPC::NumTargetFixupKinds] = {
100
// name offset bits flags
101
{ "fixup_ppc_br24", 6, 24, MCFixupKindInfo::FKF_IsPCRel },
102
{ "fixup_ppc_br24_notoc", 6, 24, MCFixupKindInfo::FKF_IsPCRel },
103
{ "fixup_ppc_brcond14", 16, 14, MCFixupKindInfo::FKF_IsPCRel },
104
{ "fixup_ppc_br24abs", 6, 24, 0 },
105
{ "fixup_ppc_brcond14abs", 16, 14, 0 },
106
{ "fixup_ppc_half16", 0, 16, 0 },
107
{ "fixup_ppc_half16ds", 0, 14, 0 },
108
{ "fixup_ppc_pcrel34", 0, 34, MCFixupKindInfo::FKF_IsPCRel },
109
{ "fixup_ppc_imm34", 0, 34, 0 },
110
{ "fixup_ppc_nofixup", 0, 0, 0 }
111
};
112
const static MCFixupKindInfo InfosLE[PPC::NumTargetFixupKinds] = {
113
// name offset bits flags
114
{ "fixup_ppc_br24", 2, 24, MCFixupKindInfo::FKF_IsPCRel },
115
{ "fixup_ppc_br24_notoc", 2, 24, MCFixupKindInfo::FKF_IsPCRel },
116
{ "fixup_ppc_brcond14", 2, 14, MCFixupKindInfo::FKF_IsPCRel },
117
{ "fixup_ppc_br24abs", 2, 24, 0 },
118
{ "fixup_ppc_brcond14abs", 2, 14, 0 },
119
{ "fixup_ppc_half16", 0, 16, 0 },
120
{ "fixup_ppc_half16ds", 2, 14, 0 },
121
{ "fixup_ppc_pcrel34", 0, 34, MCFixupKindInfo::FKF_IsPCRel },
122
{ "fixup_ppc_imm34", 0, 34, 0 },
123
{ "fixup_ppc_nofixup", 0, 0, 0 }
124
};
125
126
// Fixup kinds from .reloc directive are like R_PPC_NONE/R_PPC64_NONE. They
127
// do not require any extra processing.
128
if (Kind >= FirstLiteralRelocationKind)
129
return MCAsmBackend::getFixupKindInfo(FK_NONE);
130
131
if (Kind < FirstTargetFixupKind)
132
return MCAsmBackend::getFixupKindInfo(Kind);
133
134
assert(unsigned(Kind - FirstTargetFixupKind) < getNumFixupKinds() &&
135
"Invalid kind!");
136
return (Endian == llvm::endianness::little
137
? InfosLE
138
: InfosBE)[Kind - FirstTargetFixupKind];
139
}
140
141
void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
142
const MCValue &Target, MutableArrayRef<char> Data,
143
uint64_t Value, bool IsResolved,
144
const MCSubtargetInfo *STI) const override {
145
MCFixupKind Kind = Fixup.getKind();
146
if (Kind >= FirstLiteralRelocationKind)
147
return;
148
Value = adjustFixupValue(Kind, Value);
149
if (!Value) return; // Doesn't change encoding.
150
151
unsigned Offset = Fixup.getOffset();
152
unsigned NumBytes = getFixupKindNumBytes(Kind);
153
154
// For each byte of the fragment that the fixup touches, mask in the bits
155
// from the fixup value. The Value has been "split up" into the appropriate
156
// bitfields above.
157
for (unsigned i = 0; i != NumBytes; ++i) {
158
unsigned Idx =
159
Endian == llvm::endianness::little ? i : (NumBytes - 1 - i);
160
Data[Offset + i] |= uint8_t((Value >> (Idx * 8)) & 0xff);
161
}
162
}
163
164
bool shouldForceRelocation(const MCAssembler &Asm, const MCFixup &Fixup,
165
const MCValue &Target,
166
const MCSubtargetInfo *STI) override {
167
MCFixupKind Kind = Fixup.getKind();
168
switch ((unsigned)Kind) {
169
default:
170
return Kind >= FirstLiteralRelocationKind;
171
case PPC::fixup_ppc_br24:
172
case PPC::fixup_ppc_br24abs:
173
case PPC::fixup_ppc_br24_notoc:
174
// If the target symbol has a local entry point we must not attempt
175
// to resolve the fixup directly. Emit a relocation and leave
176
// resolution of the final target address to the linker.
177
if (const MCSymbolRefExpr *A = Target.getSymA()) {
178
if (const auto *S = dyn_cast<MCSymbolELF>(&A->getSymbol())) {
179
// The "other" values are stored in the last 6 bits of the second
180
// byte. The traditional defines for STO values assume the full byte
181
// and thus the shift to pack it.
182
unsigned Other = S->getOther() << 2;
183
if ((Other & ELF::STO_PPC64_LOCAL_MASK) != 0)
184
return true;
185
} else if (const auto *S = dyn_cast<MCSymbolXCOFF>(&A->getSymbol())) {
186
return !Target.isAbsolute() && S->isExternal() &&
187
S->getStorageClass() == XCOFF::C_WEAKEXT;
188
}
189
}
190
return false;
191
}
192
}
193
194
void relaxInstruction(MCInst &Inst,
195
const MCSubtargetInfo &STI) const override {
196
// FIXME.
197
llvm_unreachable("relaxInstruction() unimplemented");
198
}
199
200
bool writeNopData(raw_ostream &OS, uint64_t Count,
201
const MCSubtargetInfo *STI) const override {
202
uint64_t NumNops = Count / 4;
203
for (uint64_t i = 0; i != NumNops; ++i)
204
support::endian::write<uint32_t>(OS, 0x60000000, Endian);
205
206
OS.write_zeros(Count % 4);
207
208
return true;
209
}
210
};
211
} // end anonymous namespace
212
213
214
// FIXME: This should be in a separate file.
215
namespace {
216
217
class ELFPPCAsmBackend : public PPCAsmBackend {
218
public:
219
ELFPPCAsmBackend(const Target &T, const Triple &TT) : PPCAsmBackend(T, TT) {}
220
221
std::unique_ptr<MCObjectTargetWriter>
222
createObjectTargetWriter() const override {
223
uint8_t OSABI = MCELFObjectTargetWriter::getOSABI(TT.getOS());
224
bool Is64 = TT.isPPC64();
225
return createPPCELFObjectWriter(Is64, OSABI);
226
}
227
228
std::optional<MCFixupKind> getFixupKind(StringRef Name) const override;
229
};
230
231
class XCOFFPPCAsmBackend : public PPCAsmBackend {
232
public:
233
XCOFFPPCAsmBackend(const Target &T, const Triple &TT)
234
: PPCAsmBackend(T, TT) {}
235
236
std::unique_ptr<MCObjectTargetWriter>
237
createObjectTargetWriter() const override {
238
return createPPCXCOFFObjectWriter(TT.isArch64Bit());
239
}
240
241
std::optional<MCFixupKind> getFixupKind(StringRef Name) const override;
242
};
243
244
} // end anonymous namespace
245
246
std::optional<MCFixupKind>
247
ELFPPCAsmBackend::getFixupKind(StringRef Name) const {
248
if (TT.isOSBinFormatELF()) {
249
unsigned Type;
250
if (TT.isPPC64()) {
251
Type = llvm::StringSwitch<unsigned>(Name)
252
#define ELF_RELOC(X, Y) .Case(#X, Y)
253
#include "llvm/BinaryFormat/ELFRelocs/PowerPC64.def"
254
#undef ELF_RELOC
255
.Case("BFD_RELOC_NONE", ELF::R_PPC64_NONE)
256
.Case("BFD_RELOC_16", ELF::R_PPC64_ADDR16)
257
.Case("BFD_RELOC_32", ELF::R_PPC64_ADDR32)
258
.Case("BFD_RELOC_64", ELF::R_PPC64_ADDR64)
259
.Default(-1u);
260
} else {
261
Type = llvm::StringSwitch<unsigned>(Name)
262
#define ELF_RELOC(X, Y) .Case(#X, Y)
263
#include "llvm/BinaryFormat/ELFRelocs/PowerPC.def"
264
#undef ELF_RELOC
265
.Case("BFD_RELOC_NONE", ELF::R_PPC_NONE)
266
.Case("BFD_RELOC_16", ELF::R_PPC_ADDR16)
267
.Case("BFD_RELOC_32", ELF::R_PPC_ADDR32)
268
.Default(-1u);
269
}
270
if (Type != -1u)
271
return static_cast<MCFixupKind>(FirstLiteralRelocationKind + Type);
272
}
273
return std::nullopt;
274
}
275
276
std::optional<MCFixupKind>
277
XCOFFPPCAsmBackend::getFixupKind(StringRef Name) const {
278
return StringSwitch<std::optional<MCFixupKind>>(Name)
279
.Case("R_REF", (MCFixupKind)PPC::fixup_ppc_nofixup)
280
.Default(std::nullopt);
281
}
282
283
MCAsmBackend *llvm::createPPCAsmBackend(const Target &T,
284
const MCSubtargetInfo &STI,
285
const MCRegisterInfo &MRI,
286
const MCTargetOptions &Options) {
287
const Triple &TT = STI.getTargetTriple();
288
if (TT.isOSBinFormatXCOFF())
289
return new XCOFFPPCAsmBackend(T, TT);
290
291
return new ELFPPCAsmBackend(T, TT);
292
}
293
294