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(msg: toString(f: 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(msg: toString(f: f.file) + ": ABI '" + getAbiName(flags: abi2) + |
79 | "' is incompatible with target ABI '" + getAbiName(flags: abi) + "'" ); |
80 | |
81 | bool nan2 = f.flags & EF_MIPS_NAN2008; |
82 | if (nan != nan2) |
83 | error(msg: toString(f: 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 | error(msg: toString(f: 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(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(msg: toString(f: f.file) + |
109 | ": linking non-abicalls code with abicalls code " + |
110 | toString(f: files[0].file)); |
111 | if (!isPic && isPic2) |
112 | warn(msg: toString(f: f.file) + |
113 | ": linking abicalls code with non-abicalls code " + |
114 | toString(f: 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(N: 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 | {.child: EF_MIPS_ARCH_64R2 | EF_MIPS_MACH_OCTEON3, .parent: EF_MIPS_ARCH_64R2}, |
132 | {.child: EF_MIPS_ARCH_64R2 | EF_MIPS_MACH_OCTEON2, .parent: EF_MIPS_ARCH_64R2}, |
133 | {.child: EF_MIPS_ARCH_64R2 | EF_MIPS_MACH_OCTEON, .parent: EF_MIPS_ARCH_64R2}, |
134 | {.child: EF_MIPS_ARCH_64R2 | EF_MIPS_MACH_LS3A, .parent: EF_MIPS_ARCH_64R2}, |
135 | // MIPS64 extensions. |
136 | {.child: EF_MIPS_ARCH_64 | EF_MIPS_MACH_SB1, .parent: EF_MIPS_ARCH_64}, |
137 | {.child: EF_MIPS_ARCH_64 | EF_MIPS_MACH_XLR, .parent: EF_MIPS_ARCH_64}, |
138 | {.child: EF_MIPS_ARCH_64R2, .parent: EF_MIPS_ARCH_64}, |
139 | // MIPS V extensions. |
140 | {.child: EF_MIPS_ARCH_64, .parent: EF_MIPS_ARCH_5}, |
141 | // R5000 extensions. |
142 | {.child: EF_MIPS_ARCH_4 | EF_MIPS_MACH_5500, .parent: EF_MIPS_ARCH_4 | EF_MIPS_MACH_5400}, |
143 | // MIPS IV extensions. |
144 | {.child: EF_MIPS_ARCH_4 | EF_MIPS_MACH_5400, .parent: EF_MIPS_ARCH_4}, |
145 | {.child: EF_MIPS_ARCH_4 | EF_MIPS_MACH_9000, .parent: EF_MIPS_ARCH_4}, |
146 | {.child: EF_MIPS_ARCH_5, .parent: EF_MIPS_ARCH_4}, |
147 | // VR4100 extensions. |
148 | {.child: EF_MIPS_ARCH_3 | EF_MIPS_MACH_4111, .parent: EF_MIPS_ARCH_3 | EF_MIPS_MACH_4100}, |
149 | {.child: EF_MIPS_ARCH_3 | EF_MIPS_MACH_4120, .parent: EF_MIPS_ARCH_3 | EF_MIPS_MACH_4100}, |
150 | // MIPS III extensions. |
151 | {.child: EF_MIPS_ARCH_3 | EF_MIPS_MACH_4010, .parent: EF_MIPS_ARCH_3}, |
152 | {.child: EF_MIPS_ARCH_3 | EF_MIPS_MACH_4100, .parent: EF_MIPS_ARCH_3}, |
153 | {.child: EF_MIPS_ARCH_3 | EF_MIPS_MACH_4650, .parent: EF_MIPS_ARCH_3}, |
154 | {.child: EF_MIPS_ARCH_3 | EF_MIPS_MACH_5900, .parent: EF_MIPS_ARCH_3}, |
155 | {.child: EF_MIPS_ARCH_3 | EF_MIPS_MACH_LS2E, .parent: EF_MIPS_ARCH_3}, |
156 | {.child: EF_MIPS_ARCH_3 | EF_MIPS_MACH_LS2F, .parent: EF_MIPS_ARCH_3}, |
157 | {.child: EF_MIPS_ARCH_4, .parent: EF_MIPS_ARCH_3}, |
158 | // MIPS32 extensions. |
159 | {.child: EF_MIPS_ARCH_32R2, .parent: EF_MIPS_ARCH_32}, |
160 | // MIPS II extensions. |
161 | {.child: EF_MIPS_ARCH_3, .parent: EF_MIPS_ARCH_2}, |
162 | {.child: EF_MIPS_ARCH_32, .parent: EF_MIPS_ARCH_2}, |
163 | // MIPS I extensions. |
164 | {.child: EF_MIPS_ARCH_1 | EF_MIPS_MACH_3900, .parent: EF_MIPS_ARCH_1}, |
165 | {.child: EF_MIPS_ARCH_2, .parent: 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(newFlags: EF_MIPS_ARCH_64, res)) |
172 | return true; |
173 | if (newFlags == EF_MIPS_ARCH_32R2 && isArchMatched(newFlags: 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(N: 1)) { |
280 | uint32_t newFlags = f.flags & (EF_MIPS_ARCH | EF_MIPS_MACH); |
281 | |
282 | // Check ISA compatibility. |
283 | if (isArchMatched(newFlags, res: ret)) |
284 | continue; |
285 | if (!isArchMatched(newFlags: ret, res: newFlags)) { |
286 | error(msg: "incompatible target ISA:\n>>> " + toString(f: files[0].file) + ": " + |
287 | getFullArchName(flags: ret) + "\n>>> " + toString(f: f.file) + ": " + |
288 | getFullArchName(flags: 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(files: v); |
309 | return getMiscFlags(files: v) | getPicFlags(files: v) | getArchFlags(files: 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(fpA: newFlag, fpB: oldFlag) >= 0) |
355 | return newFlag; |
356 | if (compareMipsFpAbi(fpA: oldFlag, fpB: newFlag) < 0) |
357 | error(msg: fileName + ": floating point ABI '" + getMipsFpAbiName(fpAbi: newFlag) + |
358 | "' is incompatible with target floating point ABI '" + |
359 | getMipsFpAbiName(fpAbi: oldFlag) + "'" ); |
360 | return oldFlag; |
361 | } |
362 | |
363 | template <class ELFT> static bool isN32Abi(const InputFile *f) { |
364 | if (auto *ef = dyn_cast<ELFFileBase>(Val: 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 | |