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 | |
20 | using namespace llvm; |
21 | using namespace llvm::object; |
22 | using namespace llvm::ELF; |
23 | |
24 | using namespace lld; |
25 | using namespace lld::elf; |
26 | |
27 | namespace { |
28 | struct ArchTreeEdge { |
29 | uint32_t child; |
30 | uint32_t parent; |
31 | }; |
32 | |
33 | struct FileFlags { |
34 | InputFile *file; |
35 | uint32_t flags; |
36 | }; |
37 | } // namespace |
38 | |
39 | static 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 | |
58 | static StringRef getNanName(bool isNan2008) { |
59 | return isNan2008 ? "2008" : "legacy" ; |
60 | } |
61 | |
62 | static StringRef getFpName(bool isFp64) { return isFp64 ? "64" : "32" ; } |
63 | |
64 | static 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 | |
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(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 | |
126 | static 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 | |
166 | static 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 | |
183 | static 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 | |
228 | static 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 | |
257 | static 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. |
274 | static 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 | |
294 | template <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 | |
310 | static 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 | |
327 | static 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 | |
350 | uint8_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 | |
361 | template <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 | |
367 | bool 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 | |
382 | bool elf::isMicroMips(Ctx &ctx) { return ctx.arg.eflags & EF_MIPS_MICROMIPS; } |
383 | |
384 | bool 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 | |
389 | template uint32_t elf::calcMipsEFlags<ELF32LE>(Ctx &); |
390 | template uint32_t elf::calcMipsEFlags<ELF32BE>(Ctx &); |
391 | template uint32_t elf::calcMipsEFlags<ELF64LE>(Ctx &); |
392 | template uint32_t elf::calcMipsEFlags<ELF64BE>(Ctx &); |
393 | |