1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
|
//===-- SparcAsmBackend.cpp - Sparc Assembler Backend ---------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "MCTargetDesc/SparcFixupKinds.h"
#include "MCTargetDesc/SparcMCTargetDesc.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/MC/MCAsmBackend.h"
#include "llvm/MC/MCELFObjectWriter.h"
#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCObjectWriter.h"
#include "llvm/MC/MCSubtargetInfo.h"
#include "llvm/MC/MCValue.h"
#include "llvm/MC/TargetRegistry.h"
#include "llvm/Support/EndianStream.h"
using namespace llvm;
static unsigned adjustFixupValue(unsigned Kind, uint64_t Value) {
switch (Kind) {
default:
assert(uint16_t(Kind) < FirstTargetFixupKind && "Unknown fixup kind!");
return Value;
case FK_Data_1:
case FK_Data_2:
case FK_Data_4:
case FK_Data_8:
return Value;
case Sparc::fixup_sparc_call30:
return (Value >> 2) & 0x3fffffff;
case ELF::R_SPARC_WDISP22:
return (Value >> 2) & 0x3fffff;
case ELF::R_SPARC_WDISP19:
return (Value >> 2) & 0x7ffff;
case ELF::R_SPARC_WDISP16: {
// A.3 Branch on Integer Register with Prediction (BPr)
// Inst{21-20} = d16hi;
// Inst{13-0} = d16lo;
unsigned d16hi = (Value >> 16) & 0x3;
unsigned d16lo = (Value >> 2) & 0x3fff;
return (d16hi << 20) | d16lo;
}
case ELF::R_SPARC_WDISP10: {
// FIXME this really should be an error reporting check.
assert((Value & 0x3) == 0);
// 7.17 Compare and Branch
// Inst{20-19} = d10hi;
// Inst{12-5} = d10lo;
unsigned d10hi = (Value >> 10) & 0x3;
unsigned d10lo = (Value >> 2) & 0xff;
return (d10hi << 19) | (d10lo << 5);
}
case ELF::R_SPARC_HIX22:
return (~Value >> 10) & 0x3fffff;
case ELF::R_SPARC_PC22:
case ELF::R_SPARC_HI22:
case ELF::R_SPARC_LM22:
return (Value >> 10) & 0x3fffff;
case Sparc::fixup_sparc_13:
return Value & 0x1fff;
case ELF::R_SPARC_5:
return Value & 0x1f;
case ELF::R_SPARC_LOX10:
return (Value & 0x3ff) | 0x1c00;
case ELF::R_SPARC_PC10:
case ELF::R_SPARC_LO10:
return Value & 0x3ff;
case ELF::R_SPARC_H44:
return (Value >> 22) & 0x3fffff;
case ELF::R_SPARC_M44:
return (Value >> 12) & 0x3ff;
case ELF::R_SPARC_L44:
return Value & 0xfff;
case ELF::R_SPARC_HH22:
return (Value >> 42) & 0x3fffff;
case ELF::R_SPARC_HM10:
return (Value >> 32) & 0x3ff;
}
}
/// getFixupKindNumBytes - The number of bytes the fixup may change.
static unsigned getFixupKindNumBytes(unsigned Kind) {
switch (Kind) {
default:
return 4;
case FK_Data_1:
return 1;
case FK_Data_2:
return 2;
case FK_Data_8:
return 8;
}
}
namespace {
class SparcAsmBackend : public MCAsmBackend {
protected:
bool Is64Bit;
bool IsV8Plus;
public:
SparcAsmBackend(const MCSubtargetInfo &STI)
: MCAsmBackend(STI.getTargetTriple().isLittleEndian()
? llvm::endianness::little
: llvm::endianness::big),
Is64Bit(STI.getTargetTriple().isArch64Bit()),
IsV8Plus(STI.hasFeature(Sparc::FeatureV8Plus)) {}
std::optional<MCFixupKind> getFixupKind(StringRef Name) const override;
MCFixupKindInfo getFixupKindInfo(MCFixupKind Kind) const override;
void applyFixup(const MCFragment &, const MCFixup &, const MCValue &Target,
uint8_t *Data, uint64_t Value, bool IsResolved) override;
bool writeNopData(raw_ostream &OS, uint64_t Count,
const MCSubtargetInfo *STI) const override {
// If the count is not 4-byte aligned, we must be writing data into the
// text section (otherwise we have unaligned instructions, and thus have
// far bigger problems), so just write zeros instead.
OS.write_zeros(Count % 4);
uint64_t NumNops = Count / 4;
for (uint64_t i = 0; i != NumNops; ++i)
support::endian::write<uint32_t>(OS, 0x01000000, Endian);
return true;
}
};
class ELFSparcAsmBackend : public SparcAsmBackend {
Triple::OSType OSType;
public:
ELFSparcAsmBackend(const MCSubtargetInfo &STI, Triple::OSType OSType)
: SparcAsmBackend(STI), OSType(OSType) {}
std::unique_ptr<MCObjectTargetWriter>
createObjectTargetWriter() const override {
uint8_t OSABI = MCELFObjectTargetWriter::getOSABI(OSType);
return createSparcELFObjectWriter(Is64Bit, IsV8Plus, OSABI);
}
};
} // end anonymous namespace
std::optional<MCFixupKind> SparcAsmBackend::getFixupKind(StringRef Name) const {
unsigned Type;
Type = llvm::StringSwitch<unsigned>(Name)
#define ELF_RELOC(X, Y) .Case(#X, Y)
#include "llvm/BinaryFormat/ELFRelocs/Sparc.def"
#undef ELF_RELOC
.Case("BFD_RELOC_NONE", ELF::R_SPARC_NONE)
.Case("BFD_RELOC_8", ELF::R_SPARC_8)
.Case("BFD_RELOC_16", ELF::R_SPARC_16)
.Case("BFD_RELOC_32", ELF::R_SPARC_32)
.Case("BFD_RELOC_64", ELF::R_SPARC_64)
.Default(-1u);
if (Type == -1u)
return std::nullopt;
return static_cast<MCFixupKind>(FirstLiteralRelocationKind + Type);
}
MCFixupKindInfo SparcAsmBackend::getFixupKindInfo(MCFixupKind Kind) const {
// clang-format off
const static MCFixupKindInfo InfosBE[Sparc::NumTargetFixupKinds] = {
// name offset bits flags
{"fixup_sparc_call30", 2, 30, 0},
{"fixup_sparc_13", 19, 13, 0},
};
const static MCFixupKindInfo InfosLE[Sparc::NumTargetFixupKinds] = {
// name offset bits flags
{"fixup_sparc_call30", 0, 30, 0},
{"fixup_sparc_13", 0, 13, 0},
};
// clang-format on
if (!mc::isRelocation(Kind)) {
if (Kind < FirstTargetFixupKind)
return MCAsmBackend::getFixupKindInfo(Kind);
assert(unsigned(Kind - FirstTargetFixupKind) < Sparc::NumTargetFixupKinds &&
"Invalid kind!");
if (Endian == llvm::endianness::little)
return InfosLE[Kind - FirstTargetFixupKind];
return InfosBE[Kind - FirstTargetFixupKind];
}
MCFixupKindInfo Info{};
switch (uint16_t(Kind)) {
case ELF::R_SPARC_PC10:
Info = {"", 22, 10, 0};
break;
case ELF::R_SPARC_PC22:
Info = {"", 10, 22, 0};
break;
case ELF::R_SPARC_WDISP10:
Info = {"", 0, 32, 0};
break;
case ELF::R_SPARC_WDISP16:
Info = {"", 0, 32, 0};
break;
case ELF::R_SPARC_WDISP19:
Info = {"", 13, 19, 0};
break;
case ELF::R_SPARC_WDISP22:
Info = {"", 10, 22, 0};
break;
case ELF::R_SPARC_HI22:
Info = {"", 10, 22, 0};
break;
case ELF::R_SPARC_LO10:
Info = {"", 22, 10, 0};
break;
case ELF::R_SPARC_HH22:
Info = {"", 10, 22, 0};
break;
case ELF::R_SPARC_HM10:
Info = {"", 22, 10, 0};
break;
case ELF::R_SPARC_LM22:
Info = {"", 10, 22, 0};
break;
case ELF::R_SPARC_HIX22:
Info = {"", 10, 22, 0};
break;
case ELF::R_SPARC_LOX10:
Info = {"", 19, 13, 0};
break;
}
if (Endian == llvm::endianness::little)
Info.TargetOffset = 32 - Info.TargetOffset - Info.TargetSize;
return Info;
}
void SparcAsmBackend::applyFixup(const MCFragment &F, const MCFixup &Fixup,
const MCValue &Target, uint8_t *Data,
uint64_t Value, bool IsResolved) {
maybeAddReloc(F, Fixup, Target, Value, IsResolved);
if (!IsResolved)
return;
Value = adjustFixupValue(Fixup.getKind(), Value);
unsigned NumBytes = getFixupKindNumBytes(Fixup.getKind());
// For each byte of the fragment that the fixup touches, mask in the
// bits from the fixup value.
for (unsigned i = 0; i != NumBytes; ++i) {
unsigned Idx = Endian == llvm::endianness::little ? i : (NumBytes - 1) - i;
Data[Idx] |= uint8_t((Value >> (i * 8)) & 0xff);
}
}
MCAsmBackend *llvm::createSparcAsmBackend(const Target &T,
const MCSubtargetInfo &STI,
const MCRegisterInfo &MRI,
const MCTargetOptions &Options) {
return new ELFSparcAsmBackend(STI, STI.getTargetTriple().getOS());
}
|