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

Provided by KDAB

Privacy Policy
Update your C++ knowledge – Modern C++11/14/17 Training
Find out more

source code of lld/ELF/Arch/MipsArchTree.cpp