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