LLVM 22.0.0git
PPCAsmBackend.cpp
Go to the documentation of this file.
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
15#include "llvm/MC/MCAssembler.h"
16#include "llvm/MC/MCContext.h"
21#include "llvm/MC/MCSymbolELF.h"
23#include "llvm/MC/MCValue.h"
26using namespace llvm;
27
29 unsigned Kind, uint64_t Value) {
30 auto checkBrFixup = [&](unsigned Bits) {
31 int64_t SVal = int64_t(Value);
32 if ((Value & 3) != 0) {
33 Ctx.reportError(Fixup.getLoc(), "branch target not a multiple of four (" +
34 Twine(SVal) + ")");
35 return;
36 }
37
38 // Low two bits are not encoded.
39 if (!isIntN(Bits + 2, Value)) {
40 Ctx.reportError(Fixup.getLoc(), "branch target out of range (" +
41 Twine(SVal) + " not between " +
42 Twine(minIntN(Bits) * 4) + " and " +
43 Twine(maxIntN(Bits) * 4) + ")");
44 }
45 };
46
47 switch (Kind) {
48 default:
49 llvm_unreachable("Unknown fixup kind!");
50 case FK_Data_1:
51 case FK_Data_2:
52 case FK_Data_4:
53 case FK_Data_8:
55 return Value;
58 checkBrFixup(14);
59 return Value & 0xfffc;
63 checkBrFixup(24);
64 return Value & 0x3fffffc;
66 return Value & 0xffff;
69 return Value & 0xfffc;
72 return Value & 0xffffffff;
75 return Value & 0x3ffffffff;
76 }
77}
78
79static unsigned getFixupKindNumBytes(unsigned Kind) {
80 switch (Kind) {
81 default:
82 llvm_unreachable("Unknown fixup kind!");
83 case FK_Data_1:
84 return 1;
85 case FK_Data_2:
89 return 2;
90 case FK_Data_4:
96 return 4;
101 case FK_Data_8:
102 return 8;
104 return 0;
105 }
106}
107
108namespace {
109
110class PPCAsmBackend : public MCAsmBackend {
111protected:
112 Triple TT;
113public:
114 PPCAsmBackend(const Target &T, const Triple &TT)
115 : MCAsmBackend(TT.isLittleEndian() ? llvm::endianness::little
116 : llvm::endianness::big),
117 TT(TT) {}
118
119 MCFixupKindInfo getFixupKindInfo(MCFixupKind Kind) const override;
120
121 void applyFixup(const MCFragment &, const MCFixup &Fixup,
122 const MCValue &Target, uint8_t *Data, uint64_t Value,
123 bool IsResolved) override;
124
125 bool shouldForceRelocation(const MCFixup &Fixup, const MCValue &Target) {
126 // If there is a @ specifier, unless it is optimized out (e.g. constant @l),
127 // force a relocation.
128 if (Target.getSpecifier())
129 return true;
130 MCFixupKind Kind = Fixup.getKind();
131 switch ((unsigned)Kind) {
132 default:
133 return false;
137 // If the target symbol has a local entry point we must not attempt
138 // to resolve the fixup directly. Emit a relocation and leave
139 // resolution of the final target address to the linker.
140 if (const auto *A = Target.getAddSym()) {
141 if (getContext().isELF()) {
142 // The "other" values are stored in the last 6 bits of the second
143 // byte. The traditional defines for STO values assume the full byte
144 // and thus the shift to pack it.
145 unsigned Other = static_cast<const MCSymbolELF *>(A)->getOther() << 2;
146 if ((Other & ELF::STO_PPC64_LOCAL_MASK) != 0)
147 return true;
148 } else if (getContext().isXCOFF()) {
149 auto *S = static_cast<const MCSymbolXCOFF *>(A);
150 return !Target.isAbsolute() && S->isExternal() &&
151 S->getStorageClass() == XCOFF::C_WEAKEXT;
152 }
153 }
154 return false;
155 }
156 }
157
158 bool writeNopData(raw_ostream &OS, uint64_t Count,
159 const MCSubtargetInfo *STI) const override {
160 uint64_t NumNops = Count / 4;
161 for (uint64_t i = 0; i != NumNops; ++i)
162 support::endian::write<uint32_t>(OS, 0x60000000, Endian);
163
164 OS.write_zeros(Count % 4);
165
166 return true;
167 }
168};
169} // end anonymous namespace
170
171MCFixupKindInfo PPCAsmBackend::getFixupKindInfo(MCFixupKind Kind) const {
172 // clang-format off
173 const static MCFixupKindInfo InfosBE[PPC::NumTargetFixupKinds] = {
174 // name offset bits flags
175 {"fixup_ppc_br24", 6, 24, 0},
176 {"fixup_ppc_br24_notoc", 6, 24, 0},
177 {"fixup_ppc_brcond14", 16, 14, 0},
178 {"fixup_ppc_br24abs", 6, 24, 0},
179 {"fixup_ppc_brcond14abs", 16, 14, 0},
180 {"fixup_ppc_half16", 0, 16, 0},
181 {"fixup_ppc_half16ds", 0, 14, 0},
182 {"fixup_ppc_pcrel32", 0, 32, 0},
183 {"fixup_ppc_imm32", 0, 32, 0},
184 {"fixup_ppc_pcrel34", 0, 34, 0},
185 {"fixup_ppc_imm34", 0, 34, 0},
186 {"fixup_ppc_nofixup", 0, 0, 0}};
187 const static MCFixupKindInfo InfosLE[PPC::NumTargetFixupKinds] = {
188 // name offset bits flags
189 {"fixup_ppc_br24", 2, 24, 0},
190 {"fixup_ppc_br24_notoc", 2, 24, 0},
191 {"fixup_ppc_brcond14", 2, 14, 0},
192 {"fixup_ppc_br24abs", 2, 24, 0},
193 {"fixup_ppc_brcond14abs", 2, 14, 0},
194 {"fixup_ppc_half16", 0, 16, 0},
195 {"fixup_ppc_half16ds", 2, 14, 0},
196 {"fixup_ppc_pcrel32", 0, 32, 0},
197 {"fixup_ppc_imm32", 0, 32, 0},
198 {"fixup_ppc_pcrel34", 0, 34, 0},
199 {"fixup_ppc_imm34", 0, 34, 0},
200 {"fixup_ppc_nofixup", 0, 0, 0}};
201 // clang-format on
202
203 // Fixup kinds from .reloc directive are like R_PPC_NONE/R_PPC64_NONE. They
204 // do not require any extra processing.
205 if (mc::isRelocation(Kind))
206 return {};
207
208 if (Kind < FirstTargetFixupKind)
210
212 "Invalid kind!");
213 return (Endian == llvm::endianness::little
214 ? InfosLE
215 : InfosBE)[Kind - FirstTargetFixupKind];
216}
217
218void PPCAsmBackend::applyFixup(const MCFragment &F, const MCFixup &Fixup,
219 const MCValue &TargetVal, uint8_t *Data,
220 uint64_t Value, bool IsResolved) {
221 // In PPC64 ELFv1, .quad .TOC.@tocbase in the .opd section is expected to
222 // reference the null symbol.
223 auto Target = TargetVal;
224 if (Target.getSpecifier() == PPC::S_TOCBASE)
225 Target.setAddSym(nullptr);
226 if (IsResolved && shouldForceRelocation(Fixup, Target))
227 IsResolved = false;
228 if (!IsResolved)
229 Asm->getWriter().recordRelocation(F, Fixup, Target, Value);
230
231 MCFixupKind Kind = Fixup.getKind();
232 if (mc::isRelocation(Kind))
233 return;
235 if (!Value)
236 return; // Doesn't change encoding.
237
238 unsigned NumBytes = getFixupKindNumBytes(Kind);
239
240 // For each byte of the fragment that the fixup touches, mask in the bits
241 // from the fixup value. The Value has been "split up" into the appropriate
242 // bitfields above.
243 for (unsigned i = 0; i != NumBytes; ++i) {
244 unsigned Idx = Endian == llvm::endianness::little ? i : (NumBytes - 1 - i);
245 Data[i] |= uint8_t((Value >> (Idx * 8)) & 0xff);
246 }
247}
248
249// FIXME: This should be in a separate file.
250namespace {
251
252class ELFPPCAsmBackend : public PPCAsmBackend {
253public:
254 ELFPPCAsmBackend(const Target &T, const Triple &TT) : PPCAsmBackend(T, TT) {}
255
256 std::unique_ptr<MCObjectTargetWriter>
257 createObjectTargetWriter() const override {
258 uint8_t OSABI = MCELFObjectTargetWriter::getOSABI(TT.getOS());
259 bool Is64 = TT.isPPC64();
260 return createPPCELFObjectWriter(Is64, OSABI);
261 }
262
263 std::optional<MCFixupKind> getFixupKind(StringRef Name) const override;
264};
265
266class XCOFFPPCAsmBackend : public PPCAsmBackend {
267public:
268 XCOFFPPCAsmBackend(const Target &T, const Triple &TT)
269 : PPCAsmBackend(T, TT) {}
270
271 std::unique_ptr<MCObjectTargetWriter>
272 createObjectTargetWriter() const override {
273 return createPPCXCOFFObjectWriter(TT.isArch64Bit());
274 }
275};
276
277} // end anonymous namespace
278
279std::optional<MCFixupKind>
280ELFPPCAsmBackend::getFixupKind(StringRef Name) const {
281 if (TT.isOSBinFormatELF()) {
282 unsigned Type;
283 if (TT.isPPC64()) {
284 Type = llvm::StringSwitch<unsigned>(Name)
285#define ELF_RELOC(X, Y) .Case(#X, Y)
286#include "llvm/BinaryFormat/ELFRelocs/PowerPC64.def"
287#undef ELF_RELOC
288 .Case("BFD_RELOC_NONE", ELF::R_PPC64_NONE)
289 .Case("BFD_RELOC_16", ELF::R_PPC64_ADDR16)
290 .Case("BFD_RELOC_32", ELF::R_PPC64_ADDR32)
291 .Case("BFD_RELOC_64", ELF::R_PPC64_ADDR64)
292 .Default(-1u);
293 } else {
294 Type = llvm::StringSwitch<unsigned>(Name)
295#define ELF_RELOC(X, Y) .Case(#X, Y)
296#include "llvm/BinaryFormat/ELFRelocs/PowerPC.def"
297#undef ELF_RELOC
298 .Case("BFD_RELOC_NONE", ELF::R_PPC_NONE)
299 .Case("BFD_RELOC_16", ELF::R_PPC_ADDR16)
300 .Case("BFD_RELOC_32", ELF::R_PPC_ADDR32)
301 .Default(-1u);
302 }
303 if (Type != -1u)
304 return static_cast<MCFixupKind>(FirstLiteralRelocationKind + Type);
305 }
306 return std::nullopt;
307}
308
310 const MCSubtargetInfo &STI,
311 const MCRegisterInfo &MRI,
312 const MCTargetOptions &Options) {
313 const Triple &TT = STI.getTargetTriple();
314 if (TT.isOSBinFormatXCOFF())
315 return new XCOFFPPCAsmBackend(T, TT);
316
317 return new ELFPPCAsmBackend(T, TT);
318}
unsigned const MachineRegisterInfo * MRI
static unsigned getFixupKindNumBytes(unsigned Kind)
The number of bytes the fixup may change.
static uint64_t adjustFixupValue(const MCFixup &Fixup, const MCValue &Target, uint64_t Value, MCContext &Ctx, const Triple &TheTriple, bool IsResolved)
static bool shouldForceRelocation(const MCFixup &Fixup)
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static LVOptions Options
Definition LVOptions.cpp:25
#define F(x, y, z)
Definition MD5.cpp:54
#define T
static uint64_t adjustFixupValue(MCContext &Ctx, const MCFixup &Fixup, unsigned Kind, uint64_t Value)
static unsigned getFixupKindNumBytes(unsigned Kind)
PowerPC TLS Dynamic Call Fixup
Generic interface to target specific assembler backends.
virtual MCFixupKindInfo getFixupKindInfo(MCFixupKind Kind) const
Get information on a fixup kind.
Context object for machine code objects.
Definition MCContext.h:83
Encode information on a single operation to perform on a byte sequence (e.g., an encoded instruction)...
Definition MCFixup.h:61
MCRegisterInfo base class - We assume that the target defines a static array of MCRegisterDesc object...
Generic base class for all target subtargets.
const Triple & getTargetTriple() const
Target - Wrapper for Target specific information.
Triple - Helper class for working with autoconf configuration names.
Definition Triple.h:47
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition Twine.h:82
LLVM Value Representation.
Definition Value.h:75
raw_ostream & write_zeros(unsigned NumZeros)
write_zeros - Insert 'NumZeros' nulls.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
@ STO_PPC64_LOCAL_MASK
Definition ELF.h:424
@ fixup_ppc_brcond14abs
14-bit absolute relocation for conditional branches.
@ fixup_ppc_half16
A 16-bit fixup corresponding to lo16(_foo) or ha16(_foo) for instrs like 'li' or 'addis'.
@ NumTargetFixupKinds
@ fixup_ppc_br24_notoc
@ fixup_ppc_brcond14
14-bit PC relative relocation for conditional branches.
@ fixup_ppc_half16dq
A 16-bit fixup corresponding to lo16(_foo) with implied 3 zero bits for instrs like 'lxv'.
@ fixup_ppc_half16ds
A 14-bit fixup corresponding to lo16(_foo) with implied 2 zero bits for instrs like 'std'.
@ fixup_ppc_nofixup
Not a true fixup, but ties a symbol to a call to __tls_get_addr for the TLS general and local dynamic...
@ fixup_ppc_br24abs
24-bit absolute relocation for direct branches like 'ba' and 'bla'.
VE::Fixups getFixupKind(uint8_t S)
@ C_WEAKEXT
Definition XCOFF.h:200
bool isRelocation(MCFixupKind FixupKind)
Definition MCFixup.h:130
Context & getContext() const
Definition BasicBlock.h:99
void write(void *memory, value_type value, endianness endian)
Write a value to memory with a particular endianness.
Definition Endian.h:96
This is an optimization pass for GlobalISel generic memory operations.
FunctionAddr VTableAddr Value
Definition InstrProf.h:137
constexpr int64_t minIntN(int64_t N)
Gets the minimum value for a N-bit signed integer.
Definition MathExtras.h:223
MCAsmBackend * createPPCAsmBackend(const Target &T, const MCSubtargetInfo &STI, const MCRegisterInfo &MRI, const MCTargetOptions &Options)
uint16_t MCFixupKind
Extensible enumeration to represent the type of a fixup.
Definition MCFixup.h:22
std::unique_ptr< MCObjectTargetWriter > createPPCXCOFFObjectWriter(bool Is64Bit)
Construct a PPC XCOFF object writer.
FunctionAddr VTableAddr Count
Definition InstrProf.h:139
@ Other
Any other memory.
Definition ModRef.h:68
@ FirstTargetFixupKind
Definition MCFixup.h:44
@ FirstLiteralRelocationKind
Definition MCFixup.h:29
@ FK_Data_8
A eight-byte fixup.
Definition MCFixup.h:37
@ FK_Data_1
A one-byte fixup.
Definition MCFixup.h:34
@ FK_Data_4
A four-byte fixup.
Definition MCFixup.h:36
@ FK_Data_2
A two-byte fixup.
Definition MCFixup.h:35
FunctionAddr VTableAddr uintptr_t uintptr_t Data
Definition InstrProf.h:189
constexpr int64_t maxIntN(int64_t N)
Gets the maximum value for a N-bit signed integer.
Definition MathExtras.h:232
std::unique_ptr< MCObjectTargetWriter > createPPCELFObjectWriter(bool Is64Bit, uint8_t OSABI)
Construct an PPC ELF object writer.
constexpr bool isIntN(unsigned N, int64_t x)
Checks if an signed integer fits into the given (dynamic) bit width.
Definition MathExtras.h:248
endianness
Definition bit.h:71
Target independent information on a fixup kind.