Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/lld/ELF/Arch/MipsArchTree.cpp
34878 views
1
//===- MipsArchTree.cpp --------------------------------------------------===//
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
// This file contains a helper function for the Writer.
10
//
11
//===---------------------------------------------------------------------===//
12
13
#include "InputFiles.h"
14
#include "SymbolTable.h"
15
#include "Writer.h"
16
17
#include "lld/Common/ErrorHandler.h"
18
#include "llvm/BinaryFormat/ELF.h"
19
#include "llvm/Support/MipsABIFlags.h"
20
21
using namespace llvm;
22
using namespace llvm::object;
23
using namespace llvm::ELF;
24
25
using namespace lld;
26
using namespace lld::elf;
27
28
namespace {
29
struct ArchTreeEdge {
30
uint32_t child;
31
uint32_t parent;
32
};
33
34
struct FileFlags {
35
InputFile *file;
36
uint32_t flags;
37
};
38
} // namespace
39
40
static StringRef getAbiName(uint32_t flags) {
41
switch (flags) {
42
case 0:
43
return "n64";
44
case EF_MIPS_ABI2:
45
return "n32";
46
case EF_MIPS_ABI_O32:
47
return "o32";
48
case EF_MIPS_ABI_O64:
49
return "o64";
50
case EF_MIPS_ABI_EABI32:
51
return "eabi32";
52
case EF_MIPS_ABI_EABI64:
53
return "eabi64";
54
default:
55
return "unknown";
56
}
57
}
58
59
static StringRef getNanName(bool isNan2008) {
60
return isNan2008 ? "2008" : "legacy";
61
}
62
63
static StringRef getFpName(bool isFp64) { return isFp64 ? "64" : "32"; }
64
65
static void checkFlags(ArrayRef<FileFlags> files) {
66
assert(!files.empty() && "expected non-empty file list");
67
68
uint32_t abi = files[0].flags & (EF_MIPS_ABI | EF_MIPS_ABI2);
69
bool nan = files[0].flags & EF_MIPS_NAN2008;
70
bool fp = files[0].flags & EF_MIPS_FP64;
71
72
for (const FileFlags &f : files) {
73
if (config->is64 && f.flags & EF_MIPS_MICROMIPS)
74
error(toString(f.file) + ": microMIPS 64-bit is not supported");
75
76
uint32_t abi2 = f.flags & (EF_MIPS_ABI | EF_MIPS_ABI2);
77
if (abi != abi2)
78
error(toString(f.file) + ": ABI '" + getAbiName(abi2) +
79
"' is incompatible with target ABI '" + getAbiName(abi) + "'");
80
81
bool nan2 = f.flags & EF_MIPS_NAN2008;
82
if (nan != nan2)
83
error(toString(f.file) + ": -mnan=" + getNanName(nan2) +
84
" is incompatible with target -mnan=" + getNanName(nan));
85
86
bool fp2 = f.flags & EF_MIPS_FP64;
87
if (fp != fp2)
88
error(toString(f.file) + ": -mfp" + getFpName(fp2) +
89
" is incompatible with target -mfp" + getFpName(fp));
90
}
91
}
92
93
static uint32_t getMiscFlags(ArrayRef<FileFlags> files) {
94
uint32_t ret = 0;
95
for (const FileFlags &f : files)
96
ret |= f.flags &
97
(EF_MIPS_ABI | EF_MIPS_ABI2 | EF_MIPS_ARCH_ASE | EF_MIPS_NOREORDER |
98
EF_MIPS_MICROMIPS | EF_MIPS_NAN2008 | EF_MIPS_32BITMODE);
99
return ret;
100
}
101
102
static uint32_t getPicFlags(ArrayRef<FileFlags> files) {
103
// Check PIC/non-PIC compatibility.
104
bool isPic = files[0].flags & (EF_MIPS_PIC | EF_MIPS_CPIC);
105
for (const FileFlags &f : files.slice(1)) {
106
bool isPic2 = f.flags & (EF_MIPS_PIC | EF_MIPS_CPIC);
107
if (isPic && !isPic2)
108
warn(toString(f.file) +
109
": linking non-abicalls code with abicalls code " +
110
toString(files[0].file));
111
if (!isPic && isPic2)
112
warn(toString(f.file) +
113
": linking abicalls code with non-abicalls code " +
114
toString(files[0].file));
115
}
116
117
// Compute the result PIC/non-PIC flag.
118
uint32_t ret = files[0].flags & (EF_MIPS_PIC | EF_MIPS_CPIC);
119
for (const FileFlags &f : files.slice(1))
120
ret &= f.flags & (EF_MIPS_PIC | EF_MIPS_CPIC);
121
122
// PIC code is inherently CPIC and may not set CPIC flag explicitly.
123
if (ret & EF_MIPS_PIC)
124
ret |= EF_MIPS_CPIC;
125
return ret;
126
}
127
128
static ArchTreeEdge archTree[] = {
129
// MIPS32R6 and MIPS64R6 are not compatible with other extensions
130
// MIPS64R2 extensions.
131
{EF_MIPS_ARCH_64R2 | EF_MIPS_MACH_OCTEON3, EF_MIPS_ARCH_64R2},
132
{EF_MIPS_ARCH_64R2 | EF_MIPS_MACH_OCTEON2, EF_MIPS_ARCH_64R2},
133
{EF_MIPS_ARCH_64R2 | EF_MIPS_MACH_OCTEON, EF_MIPS_ARCH_64R2},
134
{EF_MIPS_ARCH_64R2 | EF_MIPS_MACH_LS3A, EF_MIPS_ARCH_64R2},
135
// MIPS64 extensions.
136
{EF_MIPS_ARCH_64 | EF_MIPS_MACH_SB1, EF_MIPS_ARCH_64},
137
{EF_MIPS_ARCH_64 | EF_MIPS_MACH_XLR, EF_MIPS_ARCH_64},
138
{EF_MIPS_ARCH_64R2, EF_MIPS_ARCH_64},
139
// MIPS V extensions.
140
{EF_MIPS_ARCH_64, EF_MIPS_ARCH_5},
141
// R5000 extensions.
142
{EF_MIPS_ARCH_4 | EF_MIPS_MACH_5500, EF_MIPS_ARCH_4 | EF_MIPS_MACH_5400},
143
// MIPS IV extensions.
144
{EF_MIPS_ARCH_4 | EF_MIPS_MACH_5400, EF_MIPS_ARCH_4},
145
{EF_MIPS_ARCH_4 | EF_MIPS_MACH_9000, EF_MIPS_ARCH_4},
146
{EF_MIPS_ARCH_5, EF_MIPS_ARCH_4},
147
// VR4100 extensions.
148
{EF_MIPS_ARCH_3 | EF_MIPS_MACH_4111, EF_MIPS_ARCH_3 | EF_MIPS_MACH_4100},
149
{EF_MIPS_ARCH_3 | EF_MIPS_MACH_4120, EF_MIPS_ARCH_3 | EF_MIPS_MACH_4100},
150
// MIPS III extensions.
151
{EF_MIPS_ARCH_3 | EF_MIPS_MACH_4010, EF_MIPS_ARCH_3},
152
{EF_MIPS_ARCH_3 | EF_MIPS_MACH_4100, EF_MIPS_ARCH_3},
153
{EF_MIPS_ARCH_3 | EF_MIPS_MACH_4650, EF_MIPS_ARCH_3},
154
{EF_MIPS_ARCH_3 | EF_MIPS_MACH_5900, EF_MIPS_ARCH_3},
155
{EF_MIPS_ARCH_3 | EF_MIPS_MACH_LS2E, EF_MIPS_ARCH_3},
156
{EF_MIPS_ARCH_3 | EF_MIPS_MACH_LS2F, EF_MIPS_ARCH_3},
157
{EF_MIPS_ARCH_4, EF_MIPS_ARCH_3},
158
// MIPS32 extensions.
159
{EF_MIPS_ARCH_32R2, EF_MIPS_ARCH_32},
160
// MIPS II extensions.
161
{EF_MIPS_ARCH_3, EF_MIPS_ARCH_2},
162
{EF_MIPS_ARCH_32, EF_MIPS_ARCH_2},
163
// MIPS I extensions.
164
{EF_MIPS_ARCH_1 | EF_MIPS_MACH_3900, EF_MIPS_ARCH_1},
165
{EF_MIPS_ARCH_2, EF_MIPS_ARCH_1},
166
};
167
168
static bool isArchMatched(uint32_t newFlags, uint32_t res) {
169
if (newFlags == res)
170
return true;
171
if (newFlags == EF_MIPS_ARCH_32 && isArchMatched(EF_MIPS_ARCH_64, res))
172
return true;
173
if (newFlags == EF_MIPS_ARCH_32R2 && isArchMatched(EF_MIPS_ARCH_64R2, res))
174
return true;
175
for (const auto &edge : archTree) {
176
if (res == edge.child) {
177
res = edge.parent;
178
if (res == newFlags)
179
return true;
180
}
181
}
182
return false;
183
}
184
185
static StringRef getMachName(uint32_t flags) {
186
switch (flags & EF_MIPS_MACH) {
187
case EF_MIPS_MACH_NONE:
188
return "";
189
case EF_MIPS_MACH_3900:
190
return "r3900";
191
case EF_MIPS_MACH_4010:
192
return "r4010";
193
case EF_MIPS_MACH_4100:
194
return "r4100";
195
case EF_MIPS_MACH_4650:
196
return "r4650";
197
case EF_MIPS_MACH_4120:
198
return "r4120";
199
case EF_MIPS_MACH_4111:
200
return "r4111";
201
case EF_MIPS_MACH_5400:
202
return "vr5400";
203
case EF_MIPS_MACH_5900:
204
return "vr5900";
205
case EF_MIPS_MACH_5500:
206
return "vr5500";
207
case EF_MIPS_MACH_9000:
208
return "rm9000";
209
case EF_MIPS_MACH_LS2E:
210
return "loongson2e";
211
case EF_MIPS_MACH_LS2F:
212
return "loongson2f";
213
case EF_MIPS_MACH_LS3A:
214
return "loongson3a";
215
case EF_MIPS_MACH_OCTEON:
216
return "octeon";
217
case EF_MIPS_MACH_OCTEON2:
218
return "octeon2";
219
case EF_MIPS_MACH_OCTEON3:
220
return "octeon3";
221
case EF_MIPS_MACH_SB1:
222
return "sb1";
223
case EF_MIPS_MACH_XLR:
224
return "xlr";
225
default:
226
return "unknown machine";
227
}
228
}
229
230
static StringRef getArchName(uint32_t flags) {
231
switch (flags & EF_MIPS_ARCH) {
232
case EF_MIPS_ARCH_1:
233
return "mips1";
234
case EF_MIPS_ARCH_2:
235
return "mips2";
236
case EF_MIPS_ARCH_3:
237
return "mips3";
238
case EF_MIPS_ARCH_4:
239
return "mips4";
240
case EF_MIPS_ARCH_5:
241
return "mips5";
242
case EF_MIPS_ARCH_32:
243
return "mips32";
244
case EF_MIPS_ARCH_64:
245
return "mips64";
246
case EF_MIPS_ARCH_32R2:
247
return "mips32r2";
248
case EF_MIPS_ARCH_64R2:
249
return "mips64r2";
250
case EF_MIPS_ARCH_32R6:
251
return "mips32r6";
252
case EF_MIPS_ARCH_64R6:
253
return "mips64r6";
254
default:
255
return "unknown arch";
256
}
257
}
258
259
static std::string getFullArchName(uint32_t flags) {
260
StringRef arch = getArchName(flags);
261
StringRef mach = getMachName(flags);
262
if (mach.empty())
263
return arch.str();
264
return (arch + " (" + mach + ")").str();
265
}
266
267
// There are (arguably too) many MIPS ISAs out there. Their relationships
268
// can be represented as a forest. If all input files have ISAs which
269
// reachable by repeated proceeding from the single child to the parent,
270
// these input files are compatible. In that case we need to return "highest"
271
// ISA. If there are incompatible input files, we show an error.
272
// For example, mips1 is a "parent" of mips2 and such files are compatible.
273
// Output file gets EF_MIPS_ARCH_2 flag. From the other side mips3 and mips32
274
// are incompatible because nor mips3 is a parent for misp32, nor mips32
275
// is a parent for mips3.
276
static uint32_t getArchFlags(ArrayRef<FileFlags> files) {
277
uint32_t ret = files[0].flags & (EF_MIPS_ARCH | EF_MIPS_MACH);
278
279
for (const FileFlags &f : files.slice(1)) {
280
uint32_t newFlags = f.flags & (EF_MIPS_ARCH | EF_MIPS_MACH);
281
282
// Check ISA compatibility.
283
if (isArchMatched(newFlags, ret))
284
continue;
285
if (!isArchMatched(ret, newFlags)) {
286
error("incompatible target ISA:\n>>> " + toString(files[0].file) + ": " +
287
getFullArchName(ret) + "\n>>> " + toString(f.file) + ": " +
288
getFullArchName(newFlags));
289
return 0;
290
}
291
ret = newFlags;
292
}
293
return ret;
294
}
295
296
template <class ELFT> uint32_t elf::calcMipsEFlags() {
297
std::vector<FileFlags> v;
298
for (InputFile *f : ctx.objectFiles)
299
v.push_back({f, cast<ObjFile<ELFT>>(f)->getObj().getHeader().e_flags});
300
if (v.empty()) {
301
// If we don't have any input files, we'll have to rely on the information
302
// we can derive from emulation information, since this at least gets us
303
// ABI.
304
if (config->emulation.empty() || config->is64)
305
return 0;
306
return config->mipsN32Abi ? EF_MIPS_ABI2 : EF_MIPS_ABI_O32;
307
}
308
checkFlags(v);
309
return getMiscFlags(v) | getPicFlags(v) | getArchFlags(v);
310
}
311
312
static int compareMipsFpAbi(uint8_t fpA, uint8_t fpB) {
313
if (fpA == fpB)
314
return 0;
315
if (fpB == Mips::Val_GNU_MIPS_ABI_FP_ANY)
316
return 1;
317
if (fpB == Mips::Val_GNU_MIPS_ABI_FP_64A &&
318
fpA == Mips::Val_GNU_MIPS_ABI_FP_64)
319
return 1;
320
if (fpB != Mips::Val_GNU_MIPS_ABI_FP_XX)
321
return -1;
322
if (fpA == Mips::Val_GNU_MIPS_ABI_FP_DOUBLE ||
323
fpA == Mips::Val_GNU_MIPS_ABI_FP_64 ||
324
fpA == Mips::Val_GNU_MIPS_ABI_FP_64A)
325
return 1;
326
return -1;
327
}
328
329
static StringRef getMipsFpAbiName(uint8_t fpAbi) {
330
switch (fpAbi) {
331
case Mips::Val_GNU_MIPS_ABI_FP_ANY:
332
return "any";
333
case Mips::Val_GNU_MIPS_ABI_FP_DOUBLE:
334
return "-mdouble-float";
335
case Mips::Val_GNU_MIPS_ABI_FP_SINGLE:
336
return "-msingle-float";
337
case Mips::Val_GNU_MIPS_ABI_FP_SOFT:
338
return "-msoft-float";
339
case Mips::Val_GNU_MIPS_ABI_FP_OLD_64:
340
return "-mgp32 -mfp64 (old)";
341
case Mips::Val_GNU_MIPS_ABI_FP_XX:
342
return "-mfpxx";
343
case Mips::Val_GNU_MIPS_ABI_FP_64:
344
return "-mgp32 -mfp64";
345
case Mips::Val_GNU_MIPS_ABI_FP_64A:
346
return "-mgp32 -mfp64 -mno-odd-spreg";
347
default:
348
return "unknown";
349
}
350
}
351
352
uint8_t elf::getMipsFpAbiFlag(uint8_t oldFlag, uint8_t newFlag,
353
StringRef fileName) {
354
if (compareMipsFpAbi(newFlag, oldFlag) >= 0)
355
return newFlag;
356
if (compareMipsFpAbi(oldFlag, newFlag) < 0)
357
error(fileName + ": floating point ABI '" + getMipsFpAbiName(newFlag) +
358
"' is incompatible with target floating point ABI '" +
359
getMipsFpAbiName(oldFlag) + "'");
360
return oldFlag;
361
}
362
363
template <class ELFT> static bool isN32Abi(const InputFile *f) {
364
if (auto *ef = dyn_cast<ELFFileBase>(f))
365
return ef->template getObj<ELFT>().getHeader().e_flags & EF_MIPS_ABI2;
366
return false;
367
}
368
369
bool elf::isMipsN32Abi(const InputFile *f) {
370
switch (config->ekind) {
371
case ELF32LEKind:
372
return isN32Abi<ELF32LE>(f);
373
case ELF32BEKind:
374
return isN32Abi<ELF32BE>(f);
375
case ELF64LEKind:
376
return isN32Abi<ELF64LE>(f);
377
case ELF64BEKind:
378
return isN32Abi<ELF64BE>(f);
379
default:
380
llvm_unreachable("unknown Config->EKind");
381
}
382
}
383
384
bool elf::isMicroMips() { return config->eflags & EF_MIPS_MICROMIPS; }
385
386
bool elf::isMipsR6() {
387
uint32_t arch = config->eflags & EF_MIPS_ARCH;
388
return arch == EF_MIPS_ARCH_32R6 || arch == EF_MIPS_ARCH_64R6;
389
}
390
391
template uint32_t elf::calcMipsEFlags<ELF32LE>();
392
template uint32_t elf::calcMipsEFlags<ELF32BE>();
393
template uint32_t elf::calcMipsEFlags<ELF64LE>();
394
template uint32_t elf::calcMipsEFlags<ELF64BE>();
395
396