MipsAbiFlags.cpp revision cfcb22478ca64c308df58f9abe6fa2dedb213c16
1//===- MipsAbiFlags.cpp ---------------------------------------------------===//
2//
3//                     The MCLinker Project
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9#include "MipsAbiFlags.h"
10
11#include "mcld/Fragment/RegionFragment.h"
12#include "mcld/LD/LDSection.h"
13#include "mcld/LD/SectionData.h"
14#include "mcld/MC/Input.h"
15#include "mcld/Support/MsgHandling.h"
16
17#include <llvm/Support/Casting.h>
18#include <llvm/Support/MipsABIFlags.h>
19
20namespace mcld {
21
22// SHT_MIPS_ABIFLAGS has the same format for both 32/64-bit targets.
23// We do not support linking of big-endian code now so 32-bit LE
24// combination is Okay.
25typedef llvm::object::ELFType<llvm::support::little, false> ELF32LE;
26typedef llvm::object::Elf_Mips_ABIFlags<ELF32LE> ElfMipsAbiFlags;
27
28uint64_t MipsAbiFlags::size() {
29  return sizeof(ElfMipsAbiFlags);
30}
31
32uint64_t MipsAbiFlags::emit(const MipsAbiFlags& pInfo, MemoryRegion& pRegion) {
33  auto* buf = reinterpret_cast<ElfMipsAbiFlags*>(pRegion.begin());
34  buf->version = 0;
35  buf->isa_level = pInfo.m_IsaLevel;
36  buf->isa_rev = pInfo.m_IsaRev;
37  buf->gpr_size = pInfo.m_GprSize;
38  buf->cpr1_size = pInfo.m_Cpr1Size;
39  buf->cpr2_size = pInfo.m_Cpr2Size;
40  buf->fp_abi = pInfo.m_FpAbi;
41  buf->isa_ext = pInfo.m_IsaExt;
42  buf->ases = pInfo.m_Ases;
43  buf->flags1 = pInfo.m_Flags1;
44  buf->flags2 = 0;
45  return size();
46}
47
48bool MipsAbiFlags::fillBySection(const Input& pInput, const LDSection& pSection,
49                                 MipsAbiFlags& mipsAbi) {
50  assert(pSection.type() == llvm::ELF::SHT_MIPS_ABIFLAGS &&
51         "Unexpected section type");
52
53  if (pSection.size() != size()) {
54    error(diag::error_Mips_abiflags_invalid_size) << pInput.name();
55    return false;
56  }
57
58  const SectionData* secData = pSection.getSectionData();
59  if (secData->size() != 2 || !llvm::isa<RegionFragment>(secData->front())) {
60    error(diag::error_Mips_abiflags_invalid_size) << pInput.name();
61    return false;
62  }
63
64  const auto& frag = llvm::cast<RegionFragment>(secData->front());
65  auto* data =
66      reinterpret_cast<const ElfMipsAbiFlags*>(frag.getRegion().data());
67  if (data->version != 0) {
68    error(diag::error_Mips_abiflags_invalid_version) << int(data->version)
69                                                     << pInput.name();
70    return false;
71  }
72
73  mipsAbi.m_IsaLevel = data->isa_level;
74  mipsAbi.m_IsaRev = data->isa_rev;
75  mipsAbi.m_GprSize = data->gpr_size;
76  mipsAbi.m_Cpr1Size = data->cpr1_size;
77  mipsAbi.m_Cpr2Size = data->cpr2_size;
78  mipsAbi.m_FpAbi = data->fp_abi;
79  mipsAbi.m_IsaExt = data->isa_ext;
80  mipsAbi.m_Ases = data->ases;
81  mipsAbi.m_Flags1 = data->flags1;
82  return true;
83}
84
85static unsigned getIsaLevel(uint64_t flags) {
86  switch (flags & llvm::ELF::EF_MIPS_ARCH) {
87    case llvm::ELF::EF_MIPS_ARCH_1:
88      return 1;
89    case llvm::ELF::EF_MIPS_ARCH_2:
90      return 2;
91    case llvm::ELF::EF_MIPS_ARCH_3:
92      return 3;
93    case llvm::ELF::EF_MIPS_ARCH_4:
94      return 4;
95    case llvm::ELF::EF_MIPS_ARCH_5:
96      return 5;
97    case llvm::ELF::EF_MIPS_ARCH_32:
98    case llvm::ELF::EF_MIPS_ARCH_32R2:
99    case llvm::ELF::EF_MIPS_ARCH_32R6:
100      return 32;
101    case llvm::ELF::EF_MIPS_ARCH_64:
102    case llvm::ELF::EF_MIPS_ARCH_64R2:
103    case llvm::ELF::EF_MIPS_ARCH_64R6:
104      return 64;
105    default:
106      // We check ELF flags and show error in case
107      // of unknown value in other place.
108      llvm_unreachable("Unknown MIPS architecture flag");
109  }
110}
111
112static unsigned getIsaRev(uint64_t flags) {
113  switch (flags & llvm::ELF::EF_MIPS_ARCH) {
114    case llvm::ELF::EF_MIPS_ARCH_1:
115    case llvm::ELF::EF_MIPS_ARCH_2:
116    case llvm::ELF::EF_MIPS_ARCH_3:
117    case llvm::ELF::EF_MIPS_ARCH_4:
118    case llvm::ELF::EF_MIPS_ARCH_5:
119      return 0;
120    case llvm::ELF::EF_MIPS_ARCH_32:
121    case llvm::ELF::EF_MIPS_ARCH_64:
122      return 1;
123    case llvm::ELF::EF_MIPS_ARCH_32R2:
124    case llvm::ELF::EF_MIPS_ARCH_64R2:
125      return 2;
126    case llvm::ELF::EF_MIPS_ARCH_32R6:
127    case llvm::ELF::EF_MIPS_ARCH_64R6:
128      return 6;
129    default:
130      // We check ELF flags and show error in case
131      // of unknown value in other place.
132      llvm_unreachable("Unknown MIPS architecture flag");
133  }
134}
135
136static unsigned getIsaExt(uint64_t flags) {
137  switch (flags & llvm::ELF::EF_MIPS_MACH) {
138    case 0:
139      return llvm::Mips::AFL_EXT_NONE;
140    case llvm::ELF::EF_MIPS_MACH_3900: return llvm::Mips::AFL_EXT_3900;
141    case llvm::ELF::EF_MIPS_MACH_4010: return llvm::Mips::AFL_EXT_4010;
142    case llvm::ELF::EF_MIPS_MACH_4100: return llvm::Mips::AFL_EXT_4010;
143    case llvm::ELF::EF_MIPS_MACH_4111: return llvm::Mips::AFL_EXT_4111;
144    case llvm::ELF::EF_MIPS_MACH_4120: return llvm::Mips::AFL_EXT_4120;
145    case llvm::ELF::EF_MIPS_MACH_4650: return llvm::Mips::AFL_EXT_4650;
146    case llvm::ELF::EF_MIPS_MACH_5400: return llvm::Mips::AFL_EXT_5400;
147    case llvm::ELF::EF_MIPS_MACH_5500: return llvm::Mips::AFL_EXT_5500;
148    case llvm::ELF::EF_MIPS_MACH_5900: return llvm::Mips::AFL_EXT_5900;
149    case llvm::ELF::EF_MIPS_MACH_SB1: return llvm::Mips::AFL_EXT_SB1;
150    case llvm::ELF::EF_MIPS_MACH_LS2E: return llvm::Mips::AFL_EXT_LOONGSON_2E;
151    case llvm::ELF::EF_MIPS_MACH_LS2F: return llvm::Mips::AFL_EXT_LOONGSON_2F;
152    case llvm::ELF::EF_MIPS_MACH_LS3A: return llvm::Mips::AFL_EXT_LOONGSON_3A;
153    case llvm::ELF::EF_MIPS_MACH_OCTEON3: return llvm::Mips::AFL_EXT_OCTEON3;
154    case llvm::ELF::EF_MIPS_MACH_OCTEON2: return llvm::Mips::AFL_EXT_OCTEON2;
155    case llvm::ELF::EF_MIPS_MACH_OCTEON: return llvm::Mips::AFL_EXT_OCTEON;
156    case llvm::ELF::EF_MIPS_MACH_XLR: return llvm::Mips::AFL_EXT_XLR;
157    default:
158      // We check ELF flags and show error in case
159      // of unknown value in other place.
160      llvm_unreachable("Unknown MIPS extension flag");
161  }
162}
163
164static bool is32BitElfFlags(uint64_t flags) {
165  if (flags & llvm::ELF::EF_MIPS_32BITMODE)
166    return true;
167
168  uint64_t arch = flags & llvm::ELF::EF_MIPS_ARCH;
169  if (arch == llvm::ELF::EF_MIPS_ARCH_1 ||
170      arch == llvm::ELF::EF_MIPS_ARCH_2 ||
171      arch == llvm::ELF::EF_MIPS_ARCH_32 ||
172      arch == llvm::ELF::EF_MIPS_ARCH_32R2 ||
173      arch == llvm::ELF::EF_MIPS_ARCH_32R6)
174    return true;
175
176  uint64_t abi = flags & llvm::ELF::EF_MIPS_ABI;
177  if (abi == llvm::ELF::EF_MIPS_ABI_O32 || abi == llvm::ELF::EF_MIPS_ABI_EABI32)
178    return true;
179
180  return false;
181}
182
183bool MipsAbiFlags::fillByElfFlags(const Input& pInput, uint64_t elfFlags,
184                                  MipsAbiFlags& mipsAbi) {
185  mipsAbi.m_IsaLevel = getIsaLevel(elfFlags);
186  mipsAbi.m_IsaRev = getIsaRev(elfFlags);
187  mipsAbi.m_IsaExt = getIsaExt(elfFlags);
188
189  mipsAbi.m_GprSize = is32BitElfFlags(elfFlags) ?
190                      llvm::Mips::AFL_REG_32 : llvm::Mips::AFL_REG_64;
191
192  mipsAbi.m_Cpr1Size = llvm::Mips::AFL_REG_NONE;
193  mipsAbi.m_Cpr2Size = llvm::Mips::AFL_REG_NONE;
194  mipsAbi.m_FpAbi = llvm::Mips::Val_GNU_MIPS_ABI_FP_ANY;
195
196  mipsAbi.m_Ases = 0;
197  if (elfFlags & llvm::ELF::EF_MIPS_MICROMIPS)
198    mipsAbi.m_Ases |= llvm::Mips::AFL_ASE_MICROMIPS;
199  if (elfFlags & llvm::ELF::EF_MIPS_ARCH_ASE_M16)
200    mipsAbi.m_Ases |= llvm::Mips::AFL_ASE_MIPS16;
201  if (elfFlags & llvm::ELF::EF_MIPS_ARCH_ASE_MDMX)
202    mipsAbi.m_Ases |= llvm::Mips::AFL_ASE_MDMX;
203
204  mipsAbi.m_Flags1 = 0;
205  return true;
206}
207
208bool MipsAbiFlags::isCompatible(const Input& pInput, const MipsAbiFlags& elf,
209                                const MipsAbiFlags& abi) {
210  unsigned isaRev = abi.m_IsaRev;
211  if (isaRev == 3 || isaRev == 5)
212    isaRev = 2;
213  if (abi.m_IsaLevel != elf.m_IsaLevel || isaRev != elf.m_IsaRev) {
214    warning(diag::warn_Mips_isa_incompatible) << pInput.name();
215    return false;
216  }
217  if (abi.m_IsaExt != elf.m_IsaExt) {
218    warning(diag::warn_Mips_isa_ext_incompatible) << pInput.name();
219    return false;
220  }
221  if ((abi.m_Ases & elf.m_Ases) != elf.m_Ases) {
222    warning(diag::warn_Mips_ases_incompatible) << pInput.name();
223    return false;
224  }
225  return true;
226}
227
228static bool isFpGreater(uint64_t fpA, uint64_t fpB) {
229  if (fpB == llvm::Mips::Val_GNU_MIPS_ABI_FP_ANY)
230    return true;
231  if (fpB == llvm::Mips::Val_GNU_MIPS_ABI_FP_64A &&
232      fpA == llvm::Mips::Val_GNU_MIPS_ABI_FP_64)
233    return true;
234  if (fpB != llvm::Mips::Val_GNU_MIPS_ABI_FP_XX)
235    return false;
236  return fpA == llvm::Mips::Val_GNU_MIPS_ABI_FP_DOUBLE ||
237         fpA == llvm::Mips::Val_GNU_MIPS_ABI_FP_64 ||
238         fpA == llvm::Mips::Val_GNU_MIPS_ABI_FP_64A;
239}
240
241static llvm::StringRef getFpAbiName(uint64_t abi) {
242  switch (abi) {
243    case llvm::Mips::Val_GNU_MIPS_ABI_FP_ANY:
244      return "<any>";
245    case llvm::Mips::Val_GNU_MIPS_ABI_FP_DOUBLE:
246      return "-mdouble-float";
247    case llvm::Mips::Val_GNU_MIPS_ABI_FP_SINGLE:
248      return "-msingle-float";
249    case llvm::Mips::Val_GNU_MIPS_ABI_FP_SOFT:
250      return "-msoft-float";
251    case llvm::Mips::Val_GNU_MIPS_ABI_FP_OLD_64:
252      return "-mips32r2 -mfp64 (old)";
253    case llvm::Mips::Val_GNU_MIPS_ABI_FP_XX:
254      return "-mfpxx";
255    case llvm::Mips::Val_GNU_MIPS_ABI_FP_64:
256      return "-mgp32 -mfp64";
257    case llvm::Mips::Val_GNU_MIPS_ABI_FP_64A:
258      return "-mgp32 -mfp64 -mno-odd-spreg";
259    default:
260      return "<unknown>";
261  }
262}
263
264bool MipsAbiFlags::merge(const Input& pInput, MipsAbiFlags& oldFlags,
265                         const MipsAbiFlags& newFlags) {
266  if (oldFlags.m_IsaLevel == 0) {
267    oldFlags = newFlags;
268    return true;
269  }
270
271  if (newFlags.m_IsaLevel > oldFlags.m_IsaLevel)
272    oldFlags.m_IsaLevel = newFlags.m_IsaLevel;
273
274  oldFlags.m_IsaRev = std::max(oldFlags.m_IsaRev, newFlags.m_IsaRev);
275  oldFlags.m_GprSize = std::max(oldFlags.m_GprSize, newFlags.m_GprSize);
276  oldFlags.m_Cpr1Size = std::max(oldFlags.m_Cpr1Size, newFlags.m_Cpr1Size);
277  oldFlags.m_Cpr2Size = std::max(oldFlags.m_Cpr2Size, newFlags.m_Cpr2Size);
278  oldFlags.m_Ases |= newFlags.m_Ases;
279  oldFlags.m_Flags1 |= newFlags.m_Flags1;
280
281  if (oldFlags.m_FpAbi == newFlags.m_FpAbi)
282    return true;
283
284  if (isFpGreater(newFlags.m_FpAbi, oldFlags.m_FpAbi)) {
285    oldFlags.m_FpAbi = newFlags.m_FpAbi;
286    return true;
287  }
288
289  if (isFpGreater(oldFlags.m_FpAbi, newFlags.m_FpAbi))
290    return true;
291
292  llvm::StringRef oldAbiName = getFpAbiName(oldFlags.m_FpAbi);
293  llvm::StringRef newAbiName = getFpAbiName(newFlags.m_FpAbi);
294  warning(diag::warn_Mips_fp_abi_incompatible) << oldAbiName << newAbiName
295                                               << pInput.name();
296  return false;
297}
298}  // namespace mcld
299