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