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 "SyntheticSections.h"
16 #include "Writer.h"
17 
18 #include "lld/Common/ErrorHandler.h"
19 #include "llvm/BinaryFormat/ELF.h"
20 #include "llvm/Object/ELF.h"
21 #include "llvm/Support/MipsABIFlags.h"
22 
23 using namespace llvm;
24 using namespace llvm::object;
25 using namespace llvm::ELF;
26 
27 using namespace lld;
28 using namespace lld::elf;
29 
30 namespace {
31 struct ArchTreeEdge {
32   uint32_t child;
33   uint32_t parent;
34 };
35 
36 struct FileFlags {
37   InputFile *file;
38   uint32_t flags;
39 };
40 } // namespace
41 
getAbiName(uint32_t flags)42 static StringRef getAbiName(uint32_t flags) {
43   switch (flags) {
44   case 0:
45     return "n64";
46   case EF_MIPS_ABI2:
47     return "n32";
48   case EF_MIPS_ABI_O32:
49     return "o32";
50   case EF_MIPS_ABI_O64:
51     return "o64";
52   case EF_MIPS_ABI_EABI32:
53     return "eabi32";
54   case EF_MIPS_ABI_EABI64:
55     return "eabi64";
56   case EF_MIPS_ABI_CHERIABI:
57     return "purecap";
58   default:
59     return "unknown";
60   }
61 }
62 
getNanName(bool isNan2008)63 static StringRef getNanName(bool isNan2008) {
64   return isNan2008 ? "2008" : "legacy";
65 }
66 
getFpName(bool isFp64)67 static StringRef getFpName(bool isFp64) { return isFp64 ? "64" : "32"; }
68 
checkFlags(ArrayRef<FileFlags> files)69 static void checkFlags(ArrayRef<FileFlags> files) {
70   assert(!files.empty() && "expected non-empty file list");
71 
72   uint32_t abi = files[0].flags & (EF_MIPS_ABI | EF_MIPS_ABI2);
73   bool nan = files[0].flags & EF_MIPS_NAN2008;
74   bool fp = files[0].flags & EF_MIPS_FP64;
75 
76   for (const FileFlags &f : files) {
77     if (config->is64 && f.flags & EF_MIPS_MICROMIPS)
78       error(toString(f.file) + ": microMIPS 64-bit is not supported");
79 
80     uint32_t abi2 = f.flags & (EF_MIPS_ABI | EF_MIPS_ABI2);
81     if (abi != abi2)
82       error(toString(f.file) + ": ABI '" + getAbiName(abi2) +
83             "' is incompatible with target ABI '" + getAbiName(abi) + "'");
84 
85     bool nan2 = f.flags & EF_MIPS_NAN2008;
86     if (nan != nan2)
87       error(toString(f.file) + ": -mnan=" + getNanName(nan2) +
88             " is incompatible with target -mnan=" + getNanName(nan));
89 
90     bool fp2 = f.flags & EF_MIPS_FP64;
91     if (fp != fp2)
92       error(toString(f.file) + ": -mfp" + getFpName(fp2) +
93             " is incompatible with target -mfp" + getFpName(fp));
94   }
95 }
96 
getMiscFlags(ArrayRef<FileFlags> files)97 static uint32_t getMiscFlags(ArrayRef<FileFlags> files) {
98   uint32_t ret = 0;
99   for (const FileFlags &f : files)
100     ret |= f.flags &
101            (EF_MIPS_ABI | EF_MIPS_ABI2 | EF_MIPS_ARCH_ASE | EF_MIPS_NOREORDER |
102             EF_MIPS_MICROMIPS | EF_MIPS_NAN2008 | EF_MIPS_32BITMODE);
103   return ret;
104 }
105 
getPicFlags(ArrayRef<FileFlags> files)106 static uint32_t getPicFlags(ArrayRef<FileFlags> files) {
107   // Check PIC/non-PIC compatibility.
108   bool isPic = files[0].flags & (EF_MIPS_PIC | EF_MIPS_CPIC);
109   for (const FileFlags &f : files.slice(1)) {
110     bool isPic2 = f.flags & (EF_MIPS_PIC | EF_MIPS_CPIC);
111     if (isPic && !isPic2)
112       warn(toString(f.file) +
113            ": linking non-abicalls code with abicalls code " +
114            toString(files[0].file));
115     if (!isPic && isPic2)
116       warn(toString(f.file) +
117            ": linking abicalls code with non-abicalls code " +
118            toString(files[0].file));
119   }
120 
121   // Compute the result PIC/non-PIC flag.
122   uint32_t ret = files[0].flags & (EF_MIPS_PIC | EF_MIPS_CPIC);
123   for (const FileFlags &f : files.slice(1))
124     ret &= f.flags & (EF_MIPS_PIC | EF_MIPS_CPIC);
125 
126   // PIC code is inherently CPIC and may not set CPIC flag explicitly.
127   if (ret & EF_MIPS_PIC)
128     ret |= EF_MIPS_CPIC;
129   return ret;
130 }
131 
132 static ArchTreeEdge archTree[] = {
133     // MIPS32R6 and MIPS64R6 are not compatible with other extensions
134     // MIPS64R2 extensions.
135     {EF_MIPS_ARCH_64R2 | EF_MIPS_MACH_OCTEON3, EF_MIPS_ARCH_64R2},
136     {EF_MIPS_ARCH_64R2 | EF_MIPS_MACH_OCTEON2, EF_MIPS_ARCH_64R2},
137     {EF_MIPS_ARCH_64R2 | EF_MIPS_MACH_OCTEON, EF_MIPS_ARCH_64R2},
138     {EF_MIPS_ARCH_64R2 | EF_MIPS_MACH_LS3A, EF_MIPS_ARCH_64R2},
139     // MIPS64 extensions.
140     {EF_MIPS_ARCH_64 | EF_MIPS_MACH_SB1, EF_MIPS_ARCH_64},
141     {EF_MIPS_ARCH_64 | EF_MIPS_MACH_XLR, EF_MIPS_ARCH_64},
142     {EF_MIPS_ARCH_64R2, EF_MIPS_ARCH_64},
143     // MIPS V extensions.
144     {EF_MIPS_ARCH_64, EF_MIPS_ARCH_5},
145     // R5000 extensions.
146     {EF_MIPS_ARCH_4 | EF_MIPS_MACH_5500, EF_MIPS_ARCH_4 | EF_MIPS_MACH_5400},
147     // MIPS IV extensions.
148     {EF_MIPS_ARCH_4 | EF_MIPS_MACH_5400, EF_MIPS_ARCH_4},
149     {EF_MIPS_ARCH_4 | EF_MIPS_MACH_9000, EF_MIPS_ARCH_4},
150     // CHERI is a superset of BERI
151     {EF_MIPS_ARCH_4 | EF_MIPS_MACH_CHERI128, EF_MIPS_ARCH_4 | EF_MIPS_MACH_BERI},
152     {EF_MIPS_ARCH_4 | EF_MIPS_MACH_CHERI256, EF_MIPS_ARCH_4 | EF_MIPS_MACH_BERI},
153     // BERI is a superset of MIPS4
154     {EF_MIPS_ARCH_4 | EF_MIPS_MACH_BERI, EF_MIPS_ARCH_4},
155     {EF_MIPS_ARCH_5, EF_MIPS_ARCH_4},
156     // VR4100 extensions.
157     {EF_MIPS_ARCH_3 | EF_MIPS_MACH_4111, EF_MIPS_ARCH_3 | EF_MIPS_MACH_4100},
158     {EF_MIPS_ARCH_3 | EF_MIPS_MACH_4120, EF_MIPS_ARCH_3 | EF_MIPS_MACH_4100},
159     // MIPS III extensions.
160     {EF_MIPS_ARCH_3 | EF_MIPS_MACH_4010, EF_MIPS_ARCH_3},
161     {EF_MIPS_ARCH_3 | EF_MIPS_MACH_4100, EF_MIPS_ARCH_3},
162     {EF_MIPS_ARCH_3 | EF_MIPS_MACH_4650, EF_MIPS_ARCH_3},
163     {EF_MIPS_ARCH_3 | EF_MIPS_MACH_5900, EF_MIPS_ARCH_3},
164     {EF_MIPS_ARCH_3 | EF_MIPS_MACH_LS2E, EF_MIPS_ARCH_3},
165     {EF_MIPS_ARCH_3 | EF_MIPS_MACH_LS2F, EF_MIPS_ARCH_3},
166     {EF_MIPS_ARCH_4, EF_MIPS_ARCH_3},
167     // MIPS32 extensions.
168     {EF_MIPS_ARCH_32R2, EF_MIPS_ARCH_32},
169     // MIPS II extensions.
170     {EF_MIPS_ARCH_3, EF_MIPS_ARCH_2},
171     {EF_MIPS_ARCH_32, EF_MIPS_ARCH_2},
172     // MIPS I extensions.
173     {EF_MIPS_ARCH_1 | EF_MIPS_MACH_3900, EF_MIPS_ARCH_1},
174     {EF_MIPS_ARCH_2, EF_MIPS_ARCH_1},
175 };
176 
isArchMatched(uint32_t newFlags,uint32_t res)177 static bool isArchMatched(uint32_t newFlags, uint32_t res) {
178   // llvm::errs() << __func__ << ": new=" << utohexstr(newFlags) << " res=" << utohexstr(Res) << "\n";
179   if (newFlags == res)
180     return true;
181   if (newFlags == EF_MIPS_ARCH_32 && isArchMatched(EF_MIPS_ARCH_64, res))
182     return true;
183   if (newFlags == EF_MIPS_ARCH_32R2 && isArchMatched(EF_MIPS_ARCH_64R2, res))
184     return true;
185 
186   // check for cheri128 vs cheri256 and upgrade non-cheri to cheri
187   uint32_t newMach = (newFlags & EF_MIPS_MACH);
188   uint32_t resMach = (res & EF_MIPS_MACH);
189   if (resMach == EF_MIPS_MACH_CHERI128) {
190     if (newMach != 0 && newMach != EF_MIPS_MACH_CHERI128 && newMach != EF_MIPS_MACH_BERI)
191       return false;
192     return isArchMatched(newFlags & ~EF_MIPS_MACH, res & ~EF_MIPS_MACH);
193   }
194   if (resMach == EF_MIPS_MACH_CHERI256) {
195     if (newMach != 0 && newMach != EF_MIPS_MACH_CHERI256 && newMach != EF_MIPS_MACH_BERI)
196       return false;
197     return isArchMatched(newFlags & ~EF_MIPS_MACH, res & ~EF_MIPS_MACH);
198   }
199 
200   for (const auto &edge : archTree) {
201     if (res == edge.child) {
202       res = edge.parent;
203       if (res == newFlags)
204         return true;
205     }
206   }
207   return false;
208 }
209 
getMachName(uint32_t flags)210 static StringRef getMachName(uint32_t flags) {
211   switch (flags & EF_MIPS_MACH) {
212   case EF_MIPS_MACH_NONE:
213     return "";
214   case EF_MIPS_MACH_3900:
215     return "r3900";
216   case EF_MIPS_MACH_4010:
217     return "r4010";
218   case EF_MIPS_MACH_4100:
219     return "r4100";
220   case EF_MIPS_MACH_4650:
221     return "r4650";
222   case EF_MIPS_MACH_4120:
223     return "r4120";
224   case EF_MIPS_MACH_4111:
225     return "r4111";
226   case EF_MIPS_MACH_5400:
227     return "vr5400";
228   case EF_MIPS_MACH_5900:
229     return "vr5900";
230   case EF_MIPS_MACH_5500:
231     return "vr5500";
232   case EF_MIPS_MACH_9000:
233     return "rm9000";
234   case EF_MIPS_MACH_LS2E:
235     return "loongson2e";
236   case EF_MIPS_MACH_LS2F:
237     return "loongson2f";
238   case EF_MIPS_MACH_LS3A:
239     return "loongson3a";
240   case EF_MIPS_MACH_OCTEON:
241     return "octeon";
242   case EF_MIPS_MACH_OCTEON2:
243     return "octeon2";
244   case EF_MIPS_MACH_OCTEON3:
245     return "octeon3";
246   case EF_MIPS_MACH_SB1:
247     return "sb1";
248   case EF_MIPS_MACH_XLR:
249     return "xlr";
250   case EF_MIPS_MACH_BERI:
251     return "beri";
252   case EF_MIPS_MACH_CHERI128:
253     return "cheri128";
254   case EF_MIPS_MACH_CHERI256:
255     return "cheri256";
256   default:
257     return "unknown machine";
258   }
259 }
260 
getArchName(uint32_t flags)261 static StringRef getArchName(uint32_t flags) {
262   switch (flags & EF_MIPS_ARCH) {
263   case EF_MIPS_ARCH_1:
264     return "mips1";
265   case EF_MIPS_ARCH_2:
266     return "mips2";
267   case EF_MIPS_ARCH_3:
268     return "mips3";
269   case EF_MIPS_ARCH_4:
270     return "mips4";
271   case EF_MIPS_ARCH_5:
272     return "mips5";
273   case EF_MIPS_ARCH_32:
274     return "mips32";
275   case EF_MIPS_ARCH_64:
276     return "mips64";
277   case EF_MIPS_ARCH_32R2:
278     return "mips32r2";
279   case EF_MIPS_ARCH_64R2:
280     return "mips64r2";
281   case EF_MIPS_ARCH_32R6:
282     return "mips32r6";
283   case EF_MIPS_ARCH_64R6:
284     return "mips64r6";
285   default:
286     return "unknown arch";
287   }
288 }
289 
getFullArchName(uint32_t flags)290 static std::string getFullArchName(uint32_t flags) {
291   StringRef arch = getArchName(flags);
292   StringRef mach = getMachName(flags);
293   if (mach.empty())
294     return arch.str();
295   return (arch + " (" + mach + ")").str();
296 }
297 
isBeriOrCheri(uint32_t flags)298 static inline bool isBeriOrCheri(uint32_t flags) {
299   uint32_t mach = flags & EF_MIPS_MACH;
300   return mach == EF_MIPS_MACH_BERI || mach == EF_MIPS_MACH_CHERI128 ||
301          mach == EF_MIPS_MACH_CHERI256;
302 }
303 
304 // There are (arguably too) many MIPS ISAs out there. Their relationships
305 // can be represented as a forest. If all input files have ISAs which
306 // reachable by repeated proceeding from the single child to the parent,
307 // these input files are compatible. In that case we need to return "highest"
308 // ISA. If there are incompatible input files, we show an error.
309 // For example, mips1 is a "parent" of mips2 and such files are compatible.
310 // Output file gets EF_MIPS_ARCH_2 flag. From the other side mips3 and mips32
311 // are incompatible because nor mips3 is a parent for misp32, nor mips32
312 // is a parent for mips3.
getArchFlags(ArrayRef<FileFlags> files)313 static uint32_t getArchFlags(ArrayRef<FileFlags> files) {
314   uint32_t ret = files[0].flags & (EF_MIPS_ARCH | EF_MIPS_MACH);
315 
316   for (const FileFlags &f : files.slice(1)) {
317     uint32_t newFlags = f.flags & (EF_MIPS_ARCH | EF_MIPS_MACH);
318 
319     // Warn about linking BERI/CHERI and non BERI/CHERI
320     // This is required because the default -mcpu=mips4 instruction scheduling
321     // results in lots of pipeline bubbles that prevent MIPS performance from
322     // being comparable to CHERI performance.
323     if (isBeriOrCheri(ret) != isBeriOrCheri(newFlags)) {
324       warn("linking files compiled for BERI/CHERI and non-BERI/CHERI can "
325            "result in surprising performance:\n>>> " +
326            toString(files[0].file) + ": " + getFullArchName(ret) + "\n>>> " +
327            toString(f.file) + ": " + getFullArchName(newFlags));
328     }
329 
330     // Check ISA compatibility.
331     if (isArchMatched(newFlags, ret))
332       continue;
333     if (!isArchMatched(ret, newFlags)) {
334       error("incompatible target ISA:\n>>> " + toString(files[0].file) + ": " +
335             getFullArchName(ret) + "\n>>> " + toString(f.file) + ": " +
336             getFullArchName(newFlags));
337       return 0;
338     }
339     ret = newFlags;
340   }
341   return ret;
342 }
343 
calcMipsEFlags()344 template <class ELFT> uint32_t elf::calcMipsEFlags() {
345   std::vector<FileFlags> v;
346   for (InputFile *f : objectFiles)
347     v.push_back({f, cast<ObjFile<ELFT>>(f)->getObj().getHeader()->e_flags});
348   if (v.empty()) {
349     // If we don't have any input files, we'll have to rely on the information
350     // we can derive from emulation information, since this at least gets us
351     // ABI.
352     if (config->emulation.empty() || config->is64)
353       return 0;
354     return config->mipsN32Abi ? EF_MIPS_ABI2 : EF_MIPS_ABI_O32;
355   }
356   checkFlags(v);
357   return getMiscFlags(v) | getPicFlags(v) | getArchFlags(v);
358 }
359 
compareMipsFpAbi(uint8_t fpA,uint8_t fpB)360 static int compareMipsFpAbi(uint8_t fpA, uint8_t fpB) {
361   if (fpA == fpB)
362     return 0;
363   if (fpB == Mips::Val_GNU_MIPS_ABI_FP_ANY)
364     return 1;
365   if (fpB == Mips::Val_GNU_MIPS_ABI_FP_64A &&
366       fpA == Mips::Val_GNU_MIPS_ABI_FP_64)
367     return 1;
368   if (fpB != Mips::Val_GNU_MIPS_ABI_FP_XX)
369     return -1;
370   if (fpA == Mips::Val_GNU_MIPS_ABI_FP_DOUBLE ||
371       fpA == Mips::Val_GNU_MIPS_ABI_FP_64 ||
372       fpA == Mips::Val_GNU_MIPS_ABI_FP_64A)
373     return 1;
374   return -1;
375 }
376 
getMipsFpAbiName(uint8_t fpAbi)377 static StringRef getMipsFpAbiName(uint8_t fpAbi) {
378   switch (fpAbi) {
379   case Mips::Val_GNU_MIPS_ABI_FP_ANY:
380     return "any";
381   case Mips::Val_GNU_MIPS_ABI_FP_DOUBLE:
382     return "-mdouble-float";
383   case Mips::Val_GNU_MIPS_ABI_FP_SINGLE:
384     return "-msingle-float";
385   case Mips::Val_GNU_MIPS_ABI_FP_SOFT:
386     return "-msoft-float";
387   case Mips::Val_GNU_MIPS_ABI_FP_OLD_64:
388     return "-mgp32 -mfp64 (old)";
389   case Mips::Val_GNU_MIPS_ABI_FP_XX:
390     return "-mfpxx";
391   case Mips::Val_GNU_MIPS_ABI_FP_64:
392     return "-mgp32 -mfp64";
393   case Mips::Val_GNU_MIPS_ABI_FP_64A:
394     return "-mgp32 -mfp64 -mno-odd-spreg";
395   default:
396     return "unknown";
397   }
398 }
399 
getMipsFpAbiFlag(uint8_t oldFlag,StringRef oldFile,uint8_t newFlag,StringRef newFile)400 uint8_t elf::getMipsFpAbiFlag(uint8_t oldFlag, StringRef oldFile,
401                               uint8_t newFlag, StringRef newFile) {
402   if (compareMipsFpAbi(newFlag, oldFlag) >= 0)
403     return newFlag;
404   if (compareMipsFpAbi(oldFlag, newFlag) < 0)
405     error(newFile + ": floating point ABI '" + getMipsFpAbiName(newFlag) +
406           "' is incompatible with target floating point ABI '" +
407           getMipsFpAbiName(oldFlag) + "'");
408   return oldFlag;
409 }
410 
getMipsIsaExtName(Mips::AFL_EXT ext)411 static std::string getMipsIsaExtName(Mips::AFL_EXT ext) {
412   switch (ext) {
413     // duplicated from ELFYAML.cpp
414 #define ECase(X)                                                               \
415   case Mips::AFL_##X:                                                          \
416     return #X
417     ECase(EXT_NONE);
418     ECase(EXT_XLR);
419     ECase(EXT_OCTEON2);
420     ECase(EXT_OCTEONP);
421     ECase(EXT_LOONGSON_3A);
422     ECase(EXT_OCTEON);
423     ECase(EXT_5900);
424     ECase(EXT_4650);
425     ECase(EXT_4010);
426     ECase(EXT_4100);
427     ECase(EXT_3900);
428     ECase(EXT_10000);
429     ECase(EXT_SB1);
430     ECase(EXT_4111);
431     ECase(EXT_4120);
432     ECase(EXT_5400);
433     ECase(EXT_5500);
434     ECase(EXT_LOONGSON_2E);
435     ECase(EXT_LOONGSON_2F);
436     ECase(EXT_OCTEON3);
437     ECase(EXT_CHERI);
438     ECase(EXT_CHERI_ABI_LEGACY);
439     ECase(EXT_CHERI_ABI_PLT);
440     ECase(EXT_CHERI_ABI_PCREL);
441     ECase(EXT_CHERI_ABI_FNDESC);
442   default:
443     return ("<unknown isa_ext (" + Twine(ext) + ")>").str();
444 #undef ECase
445   }
446 }
447 
getMipsIsaExt(uint64_t oldExt,StringRef oldFile,uint64_t newExt,StringRef newFile)448 uint8_t elf::getMipsIsaExt(uint64_t oldExt, StringRef oldFile, uint64_t newExt,
449                            StringRef newFile) {
450   if (oldExt == newExt)
451     return newExt;
452 
453   // ISA_EXT is different, now check if we want to allow this
454   // No ext -> any ext is always fine (XXXAR: well at least for now it is)
455   // TODO: require isa_ext to be set for CHERI purecap programs in the future
456   if (oldExt == Mips::AFL_EXT_NONE)
457     return newExt;
458   if (newExt == Mips::AFL_EXT_NONE)
459     return oldExt;
460   Mips::AFL_EXT cheriABIs[] = {
461       Mips::AFL_EXT_CHERI_ABI_LEGACY,
462       Mips::AFL_EXT_CHERI_ABI_PLT,
463       Mips::AFL_EXT_CHERI_ABI_PCREL,
464       Mips::AFL_EXT_CHERI_ABI_FNDESC,
465   };
466   if (llvm::is_contained(cheriABIs, oldExt) ||
467       llvm::is_contained(cheriABIs, newExt)) {
468     // incompatible cheri purecap ABIs:
469     error("incompatible pure-capability ABIs:\n>>> " + oldFile + " uses " +
470           getMipsIsaExtName((Mips::AFL_EXT)oldExt) + "\n>>> " + newFile +
471           " uses " + getMipsIsaExtName((Mips::AFL_EXT)newExt));
472     // return NewExt to get sensible error messages with multiple mismatches
473     return newExt;
474   }
475   // non-cheri isa_ext -> just return the maximum
476   return std::max(oldExt, newExt);
477 }
478 
cheriFlagsToAFL_EXT(uint64_t cheriFlags)479 static Mips::AFL_EXT cheriFlagsToAFL_EXT(uint64_t cheriFlags) {
480   assert(cheriFlags < DF_MIPS_CHERI_ABI_MASK);
481   switch (cheriFlags) {
482   case DF_MIPS_CHERI_ABI_LEGACY:
483     return Mips::AFL_EXT::AFL_EXT_CHERI_ABI_LEGACY;
484   case DF_MIPS_CHERI_ABI_PCREL:
485     return Mips::AFL_EXT::AFL_EXT_CHERI_ABI_PCREL;
486   case DF_MIPS_CHERI_ABI_PLT:
487     return Mips::AFL_EXT::AFL_EXT_CHERI_ABI_PLT;
488   case DF_MIPS_CHERI_ABI_FNDESC:
489     return Mips::AFL_EXT::AFL_EXT_CHERI_ABI_FNDESC;
490   default:
491     llvm_unreachable("Invalid ABI");
492   }
493   return Mips::AFL_EXT::AFL_EXT_NONE;
494 }
495 
checkMipsShlibCompatible(InputFile * f,uint64_t inputCheriFlags,uint64_t targetCheriFlags)496 void elf::checkMipsShlibCompatible(InputFile *f, uint64_t inputCheriFlags,
497                                    uint64_t targetCheriFlags) {
498   const uint32_t targetABI = config->eflags & (EF_MIPS_ABI | EF_MIPS_ABI2);
499   assert(f->emachine == config->emachine);
500   uint32_t abi = f->eflags & (EF_MIPS_ABI | EF_MIPS_ABI2);
501   // Mips can't link against cheriabi and the other way around
502   if ((config->isCheriAbi && abi != EF_MIPS_ABI_CHERIABI) ||
503       (!config->isCheriAbi && abi == EF_MIPS_ABI_CHERIABI)) {
504     // assert(errorCount() && "Should have already caused an errors");
505     // llvm_unreachable("Should have been checked earlier!");
506     if (!errorCount())
507       error(toString(f) + ": ABI '" + getAbiName(abi) +
508             "' is incompatible with target ABI: " + getAbiName(targetABI));
509   } else {
510     uint64_t inputCheriAbi = inputCheriFlags & DF_MIPS_CHERI_ABI_MASK;
511     uint64_t targetCheriAbi = targetCheriFlags & DF_MIPS_CHERI_ABI_MASK;
512     if (inputCheriAbi != targetCheriAbi) {
513       std::string msg = "target pure-capability ABI " +
514                         getMipsIsaExtName(cheriFlagsToAFL_EXT(targetCheriAbi)) +
515                         " is incompatible with linked shared library\n>>> " +
516                         toString(f) + " uses " +
517                         getMipsIsaExtName(cheriFlagsToAFL_EXT(inputCheriAbi));
518       // mixing legacy/non-legacy is an error, anything a warning
519       if (inputCheriAbi == DF_MIPS_CHERI_ABI_LEGACY ||
520           targetCheriAbi == DF_MIPS_CHERI_ABI_LEGACY)
521         error(msg);
522       else
523         warn(msg);
524     }
525   }
526 }
527 
isN32Abi(const InputFile * f)528 template <class ELFT> static bool isN32Abi(const InputFile *f) {
529   if (auto *ef = dyn_cast<ELFFileBase>(f))
530     return ef->template getObj<ELFT>().getHeader()->e_flags & EF_MIPS_ABI2;
531   return false;
532 }
533 
isMipsN32Abi(const InputFile * f)534 bool elf::isMipsN32Abi(const InputFile *f) {
535   switch (config->ekind) {
536   case ELF32LEKind:
537     return isN32Abi<ELF32LE>(f);
538   case ELF32BEKind:
539     return isN32Abi<ELF32BE>(f);
540   case ELF64LEKind:
541     return isN32Abi<ELF64LE>(f);
542   case ELF64BEKind:
543     return isN32Abi<ELF64BE>(f);
544   default:
545     llvm_unreachable("unknown Config->EKind");
546   }
547 }
548 
isMicroMips()549 bool elf::isMicroMips() { return config->eflags & EF_MIPS_MICROMIPS; }
550 
isMipsR6()551 bool elf::isMipsR6() {
552   uint32_t arch = config->eflags & EF_MIPS_ARCH;
553   return arch == EF_MIPS_ARCH_32R6 || arch == EF_MIPS_ARCH_64R6;
554 }
555 
556 template uint32_t elf::calcMipsEFlags<ELF32LE>();
557 template uint32_t elf::calcMipsEFlags<ELF32BE>();
558 template uint32_t elf::calcMipsEFlags<ELF64LE>();
559 template uint32_t elf::calcMipsEFlags<ELF64BE>();
560