• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
20 namespace 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.
25 typedef llvm::object::ELFType<llvm::support::little, false> ELF32LE;
26 typedef llvm::object::Elf_Mips_ABIFlags<ELF32LE> ElfMipsAbiFlags;
27 
size()28 uint64_t MipsAbiFlags::size() {
29   return sizeof(ElfMipsAbiFlags);
30 }
31 
emit(const MipsAbiFlags & pInfo,MemoryRegion & pRegion)32 uint64_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 
fillBySection(const Input & pInput,const LDSection & pSection,MipsAbiFlags & mipsAbi)48 bool 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 
getIsaLevel(uint64_t flags)85 static 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 
getIsaRev(uint64_t flags)112 static 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 
getIsaExt(uint64_t flags)136 static 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 
is32BitElfFlags(uint64_t flags)164 static 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 
fillByElfFlags(const Input & pInput,uint64_t elfFlags,MipsAbiFlags & mipsAbi)183 bool 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 
isCompatible(const Input & pInput,const MipsAbiFlags & elf,const MipsAbiFlags & abi)208 bool 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 
isFpGreater(uint64_t fpA,uint64_t fpB)228 static 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 
getFpAbiName(uint64_t abi)241 static 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 
merge(const Input & pInput,MipsAbiFlags & oldFlags,const MipsAbiFlags & newFlags)264 bool 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