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
21using namespace llvm;
22using namespace llvm::object;
23using namespace llvm::ELF;
24
25using namespace lld;
26using namespace lld::elf;
27
28namespace {
29struct ArchTreeEdge {
30  uint32_t child;
31  uint32_t parent;
32};
33
34struct FileFlags {
35  InputFile *file;
36  uint32_t flags;
37};
38} // namespace
39
40static 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
59static StringRef getNanName(bool isNan2008) {
60  return isNan2008 ? "2008" : "legacy";
61}
62
63static StringRef getFpName(bool isFp64) { return isFp64 ? "64" : "32"; }
64
65static 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
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(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
128static 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
168static 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
185static 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
230static 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
259static 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.
276static 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
296template <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
312static 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
329static 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
352uint8_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
363template <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
369bool 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
384bool elf::isMicroMips() { return config->eflags & EF_MIPS_MICROMIPS; }
385
386bool 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
391template uint32_t elf::calcMipsEFlags<ELF32LE>();
392template uint32_t elf::calcMipsEFlags<ELF32BE>();
393template uint32_t elf::calcMipsEFlags<ELF64LE>();
394template uint32_t elf::calcMipsEFlags<ELF64BE>();
395