1 | //===- ELFObjectFile.cpp - ELF object file implementation -----------------===// |
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 | // Part of the ELFObjectFile class implementation. |
10 | // |
11 | //===----------------------------------------------------------------------===// |
12 | |
13 | #include "llvm/Object/ELFObjectFile.h" |
14 | #include "llvm/BinaryFormat/ELF.h" |
15 | #include "llvm/MC/MCInstrAnalysis.h" |
16 | #include "llvm/MC/TargetRegistry.h" |
17 | #include "llvm/Object/ELF.h" |
18 | #include "llvm/Object/ELFTypes.h" |
19 | #include "llvm/Object/Error.h" |
20 | #include "llvm/Support/ARMAttributeParser.h" |
21 | #include "llvm/Support/ARMBuildAttributes.h" |
22 | #include "llvm/Support/ErrorHandling.h" |
23 | #include "llvm/Support/HexagonAttributeParser.h" |
24 | #include "llvm/Support/MathExtras.h" |
25 | #include "llvm/Support/RISCVAttributeParser.h" |
26 | #include "llvm/Support/RISCVAttributes.h" |
27 | #include "llvm/TargetParser/RISCVISAInfo.h" |
28 | #include "llvm/TargetParser/SubtargetFeature.h" |
29 | #include "llvm/TargetParser/Triple.h" |
30 | #include <algorithm> |
31 | #include <cstddef> |
32 | #include <cstdint> |
33 | #include <memory> |
34 | #include <optional> |
35 | #include <string> |
36 | #include <utility> |
37 | |
38 | using namespace llvm; |
39 | using namespace object; |
40 | |
41 | const EnumEntry<unsigned> llvm::object::ElfSymbolTypes[NumElfSymbolTypes] = { |
42 | {"None" , "NOTYPE" , ELF::STT_NOTYPE}, |
43 | {"Object" , "OBJECT" , ELF::STT_OBJECT}, |
44 | {"Function" , "FUNC" , ELF::STT_FUNC}, |
45 | {"Section" , "SECTION" , ELF::STT_SECTION}, |
46 | {"File" , "FILE" , ELF::STT_FILE}, |
47 | {"Common" , "COMMON" , ELF::STT_COMMON}, |
48 | {"TLS" , "TLS" , ELF::STT_TLS}, |
49 | {"Unknown" , "<unknown>: 7" , 7}, |
50 | {"Unknown" , "<unknown>: 8" , 8}, |
51 | {"Unknown" , "<unknown>: 9" , 9}, |
52 | {"GNU_IFunc" , "IFUNC" , ELF::STT_GNU_IFUNC}, |
53 | {"OS Specific" , "<OS specific>: 11" , 11}, |
54 | {"OS Specific" , "<OS specific>: 12" , 12}, |
55 | {"Proc Specific" , "<processor specific>: 13" , 13}, |
56 | {"Proc Specific" , "<processor specific>: 14" , 14}, |
57 | {"Proc Specific" , "<processor specific>: 15" , 15} |
58 | }; |
59 | |
60 | ELFObjectFileBase::ELFObjectFileBase(unsigned int Type, MemoryBufferRef Source) |
61 | : ObjectFile(Type, Source) {} |
62 | |
63 | template <class ELFT> |
64 | static Expected<std::unique_ptr<ELFObjectFile<ELFT>>> |
65 | createPtr(MemoryBufferRef Object, bool InitContent) { |
66 | auto Ret = ELFObjectFile<ELFT>::create(Object, InitContent); |
67 | if (Error E = Ret.takeError()) |
68 | return std::move(E); |
69 | return std::make_unique<ELFObjectFile<ELFT>>(std::move(*Ret)); |
70 | } |
71 | |
72 | Expected<std::unique_ptr<ObjectFile>> |
73 | ObjectFile::createELFObjectFile(MemoryBufferRef Obj, bool InitContent) { |
74 | std::pair<unsigned char, unsigned char> Ident = |
75 | getElfArchType(Object: Obj.getBuffer()); |
76 | std::size_t MaxAlignment = |
77 | 1ULL << llvm::countr_zero( |
78 | Val: reinterpret_cast<uintptr_t>(Obj.getBufferStart())); |
79 | |
80 | if (MaxAlignment < 2) |
81 | return createError(Err: "Insufficient alignment" ); |
82 | |
83 | if (Ident.first == ELF::ELFCLASS32) { |
84 | if (Ident.second == ELF::ELFDATA2LSB) |
85 | return createPtr<ELF32LE>(Object: Obj, InitContent); |
86 | else if (Ident.second == ELF::ELFDATA2MSB) |
87 | return createPtr<ELF32BE>(Object: Obj, InitContent); |
88 | else |
89 | return createError(Err: "Invalid ELF data" ); |
90 | } else if (Ident.first == ELF::ELFCLASS64) { |
91 | if (Ident.second == ELF::ELFDATA2LSB) |
92 | return createPtr<ELF64LE>(Object: Obj, InitContent); |
93 | else if (Ident.second == ELF::ELFDATA2MSB) |
94 | return createPtr<ELF64BE>(Object: Obj, InitContent); |
95 | else |
96 | return createError(Err: "Invalid ELF data" ); |
97 | } |
98 | return createError(Err: "Invalid ELF class" ); |
99 | } |
100 | |
101 | SubtargetFeatures ELFObjectFileBase::getMIPSFeatures() const { |
102 | SubtargetFeatures Features; |
103 | unsigned PlatformFlags = getPlatformFlags(); |
104 | |
105 | switch (PlatformFlags & ELF::EF_MIPS_ARCH) { |
106 | case ELF::EF_MIPS_ARCH_1: |
107 | break; |
108 | case ELF::EF_MIPS_ARCH_2: |
109 | Features.AddFeature(String: "mips2" ); |
110 | break; |
111 | case ELF::EF_MIPS_ARCH_3: |
112 | Features.AddFeature(String: "mips3" ); |
113 | break; |
114 | case ELF::EF_MIPS_ARCH_4: |
115 | Features.AddFeature(String: "mips4" ); |
116 | break; |
117 | case ELF::EF_MIPS_ARCH_5: |
118 | Features.AddFeature(String: "mips5" ); |
119 | break; |
120 | case ELF::EF_MIPS_ARCH_32: |
121 | Features.AddFeature(String: "mips32" ); |
122 | break; |
123 | case ELF::EF_MIPS_ARCH_64: |
124 | Features.AddFeature(String: "mips64" ); |
125 | break; |
126 | case ELF::EF_MIPS_ARCH_32R2: |
127 | Features.AddFeature(String: "mips32r2" ); |
128 | break; |
129 | case ELF::EF_MIPS_ARCH_64R2: |
130 | Features.AddFeature(String: "mips64r2" ); |
131 | break; |
132 | case ELF::EF_MIPS_ARCH_32R6: |
133 | Features.AddFeature(String: "mips32r6" ); |
134 | break; |
135 | case ELF::EF_MIPS_ARCH_64R6: |
136 | Features.AddFeature(String: "mips64r6" ); |
137 | break; |
138 | default: |
139 | llvm_unreachable("Unknown EF_MIPS_ARCH value" ); |
140 | } |
141 | |
142 | switch (PlatformFlags & ELF::EF_MIPS_MACH) { |
143 | case ELF::EF_MIPS_MACH_NONE: |
144 | // No feature associated with this value. |
145 | break; |
146 | case ELF::EF_MIPS_MACH_OCTEON: |
147 | Features.AddFeature(String: "cnmips" ); |
148 | break; |
149 | default: |
150 | llvm_unreachable("Unknown EF_MIPS_ARCH value" ); |
151 | } |
152 | |
153 | if (PlatformFlags & ELF::EF_MIPS_ARCH_ASE_M16) |
154 | Features.AddFeature(String: "mips16" ); |
155 | if (PlatformFlags & ELF::EF_MIPS_MICROMIPS) |
156 | Features.AddFeature(String: "micromips" ); |
157 | |
158 | return Features; |
159 | } |
160 | |
161 | SubtargetFeatures ELFObjectFileBase::getARMFeatures() const { |
162 | SubtargetFeatures Features; |
163 | ARMAttributeParser Attributes; |
164 | if (Error E = getBuildAttributes(Attributes)) { |
165 | consumeError(Err: std::move(E)); |
166 | return SubtargetFeatures(); |
167 | } |
168 | |
169 | // both ARMv7-M and R have to support thumb hardware div |
170 | bool isV7 = false; |
171 | std::optional<unsigned> Attr = |
172 | Attributes.getAttributeValue(tag: ARMBuildAttrs::CPU_arch); |
173 | if (Attr) |
174 | isV7 = *Attr == ARMBuildAttrs::v7; |
175 | |
176 | Attr = Attributes.getAttributeValue(tag: ARMBuildAttrs::CPU_arch_profile); |
177 | if (Attr) { |
178 | switch (*Attr) { |
179 | case ARMBuildAttrs::ApplicationProfile: |
180 | Features.AddFeature(String: "aclass" ); |
181 | break; |
182 | case ARMBuildAttrs::RealTimeProfile: |
183 | Features.AddFeature(String: "rclass" ); |
184 | if (isV7) |
185 | Features.AddFeature(String: "hwdiv" ); |
186 | break; |
187 | case ARMBuildAttrs::MicroControllerProfile: |
188 | Features.AddFeature(String: "mclass" ); |
189 | if (isV7) |
190 | Features.AddFeature(String: "hwdiv" ); |
191 | break; |
192 | } |
193 | } |
194 | |
195 | Attr = Attributes.getAttributeValue(tag: ARMBuildAttrs::THUMB_ISA_use); |
196 | if (Attr) { |
197 | switch (*Attr) { |
198 | default: |
199 | break; |
200 | case ARMBuildAttrs::Not_Allowed: |
201 | Features.AddFeature(String: "thumb" , Enable: false); |
202 | Features.AddFeature(String: "thumb2" , Enable: false); |
203 | break; |
204 | case ARMBuildAttrs::AllowThumb32: |
205 | Features.AddFeature(String: "thumb2" ); |
206 | break; |
207 | } |
208 | } |
209 | |
210 | Attr = Attributes.getAttributeValue(tag: ARMBuildAttrs::FP_arch); |
211 | if (Attr) { |
212 | switch (*Attr) { |
213 | default: |
214 | break; |
215 | case ARMBuildAttrs::Not_Allowed: |
216 | Features.AddFeature(String: "vfp2sp" , Enable: false); |
217 | Features.AddFeature(String: "vfp3d16sp" , Enable: false); |
218 | Features.AddFeature(String: "vfp4d16sp" , Enable: false); |
219 | break; |
220 | case ARMBuildAttrs::AllowFPv2: |
221 | Features.AddFeature(String: "vfp2" ); |
222 | break; |
223 | case ARMBuildAttrs::AllowFPv3A: |
224 | case ARMBuildAttrs::AllowFPv3B: |
225 | Features.AddFeature(String: "vfp3" ); |
226 | break; |
227 | case ARMBuildAttrs::AllowFPv4A: |
228 | case ARMBuildAttrs::AllowFPv4B: |
229 | Features.AddFeature(String: "vfp4" ); |
230 | break; |
231 | } |
232 | } |
233 | |
234 | Attr = Attributes.getAttributeValue(tag: ARMBuildAttrs::Advanced_SIMD_arch); |
235 | if (Attr) { |
236 | switch (*Attr) { |
237 | default: |
238 | break; |
239 | case ARMBuildAttrs::Not_Allowed: |
240 | Features.AddFeature(String: "neon" , Enable: false); |
241 | Features.AddFeature(String: "fp16" , Enable: false); |
242 | break; |
243 | case ARMBuildAttrs::AllowNeon: |
244 | Features.AddFeature(String: "neon" ); |
245 | break; |
246 | case ARMBuildAttrs::AllowNeon2: |
247 | Features.AddFeature(String: "neon" ); |
248 | Features.AddFeature(String: "fp16" ); |
249 | break; |
250 | } |
251 | } |
252 | |
253 | Attr = Attributes.getAttributeValue(tag: ARMBuildAttrs::MVE_arch); |
254 | if (Attr) { |
255 | switch (*Attr) { |
256 | default: |
257 | break; |
258 | case ARMBuildAttrs::Not_Allowed: |
259 | Features.AddFeature(String: "mve" , Enable: false); |
260 | Features.AddFeature(String: "mve.fp" , Enable: false); |
261 | break; |
262 | case ARMBuildAttrs::AllowMVEInteger: |
263 | Features.AddFeature(String: "mve.fp" , Enable: false); |
264 | Features.AddFeature(String: "mve" ); |
265 | break; |
266 | case ARMBuildAttrs::AllowMVEIntegerAndFloat: |
267 | Features.AddFeature(String: "mve.fp" ); |
268 | break; |
269 | } |
270 | } |
271 | |
272 | Attr = Attributes.getAttributeValue(tag: ARMBuildAttrs::DIV_use); |
273 | if (Attr) { |
274 | switch (*Attr) { |
275 | default: |
276 | break; |
277 | case ARMBuildAttrs::DisallowDIV: |
278 | Features.AddFeature(String: "hwdiv" , Enable: false); |
279 | Features.AddFeature(String: "hwdiv-arm" , Enable: false); |
280 | break; |
281 | case ARMBuildAttrs::AllowDIVExt: |
282 | Features.AddFeature(String: "hwdiv" ); |
283 | Features.AddFeature(String: "hwdiv-arm" ); |
284 | break; |
285 | } |
286 | } |
287 | |
288 | return Features; |
289 | } |
290 | |
291 | static std::optional<std::string> hexagonAttrToFeatureString(unsigned Attr) { |
292 | switch (Attr) { |
293 | case 5: |
294 | return "v5" ; |
295 | case 55: |
296 | return "v55" ; |
297 | case 60: |
298 | return "v60" ; |
299 | case 62: |
300 | return "v62" ; |
301 | case 65: |
302 | return "v65" ; |
303 | case 67: |
304 | return "v67" ; |
305 | case 68: |
306 | return "v68" ; |
307 | case 69: |
308 | return "v69" ; |
309 | case 71: |
310 | return "v71" ; |
311 | case 73: |
312 | return "v73" ; |
313 | default: |
314 | return {}; |
315 | } |
316 | } |
317 | |
318 | SubtargetFeatures ELFObjectFileBase::getHexagonFeatures() const { |
319 | SubtargetFeatures Features; |
320 | HexagonAttributeParser Parser; |
321 | if (Error E = getBuildAttributes(Attributes&: Parser)) { |
322 | // Return no attributes if none can be read. |
323 | // This behavior is important for backwards compatibility. |
324 | consumeError(Err: std::move(E)); |
325 | return Features; |
326 | } |
327 | std::optional<unsigned> Attr; |
328 | |
329 | if ((Attr = Parser.getAttributeValue(tag: HexagonAttrs::ARCH))) { |
330 | if (std::optional<std::string> FeatureString = |
331 | hexagonAttrToFeatureString(Attr: *Attr)) |
332 | Features.AddFeature(String: *FeatureString); |
333 | } |
334 | |
335 | if ((Attr = Parser.getAttributeValue(tag: HexagonAttrs::HVXARCH))) { |
336 | std::optional<std::string> FeatureString = |
337 | hexagonAttrToFeatureString(Attr: *Attr); |
338 | // There is no corresponding hvx arch for v5 and v55. |
339 | if (FeatureString && *Attr >= 60) |
340 | Features.AddFeature(String: "hvx" + *FeatureString); |
341 | } |
342 | |
343 | if ((Attr = Parser.getAttributeValue(tag: HexagonAttrs::HVXIEEEFP))) |
344 | if (*Attr) |
345 | Features.AddFeature(String: "hvx-ieee-fp" ); |
346 | |
347 | if ((Attr = Parser.getAttributeValue(tag: HexagonAttrs::HVXQFLOAT))) |
348 | if (*Attr) |
349 | Features.AddFeature(String: "hvx-qfloat" ); |
350 | |
351 | if ((Attr = Parser.getAttributeValue(tag: HexagonAttrs::ZREG))) |
352 | if (*Attr) |
353 | Features.AddFeature(String: "zreg" ); |
354 | |
355 | if ((Attr = Parser.getAttributeValue(tag: HexagonAttrs::AUDIO))) |
356 | if (*Attr) |
357 | Features.AddFeature(String: "audio" ); |
358 | |
359 | if ((Attr = Parser.getAttributeValue(tag: HexagonAttrs::CABAC))) |
360 | if (*Attr) |
361 | Features.AddFeature(String: "cabac" ); |
362 | |
363 | return Features; |
364 | } |
365 | |
366 | Expected<SubtargetFeatures> ELFObjectFileBase::getRISCVFeatures() const { |
367 | SubtargetFeatures Features; |
368 | unsigned PlatformFlags = getPlatformFlags(); |
369 | |
370 | if (PlatformFlags & ELF::EF_RISCV_RVC) { |
371 | Features.AddFeature(String: "zca" ); |
372 | } |
373 | |
374 | RISCVAttributeParser Attributes; |
375 | if (Error E = getBuildAttributes(Attributes)) { |
376 | return std::move(E); |
377 | } |
378 | |
379 | std::optional<StringRef> Attr = |
380 | Attributes.getAttributeString(tag: RISCVAttrs::ARCH); |
381 | if (Attr) { |
382 | auto ParseResult = RISCVISAInfo::parseNormalizedArchString(Arch: *Attr); |
383 | if (!ParseResult) |
384 | return ParseResult.takeError(); |
385 | auto &ISAInfo = *ParseResult; |
386 | |
387 | if (ISAInfo->getXLen() == 32) |
388 | Features.AddFeature(String: "64bit" , Enable: false); |
389 | else if (ISAInfo->getXLen() == 64) |
390 | Features.AddFeature(String: "64bit" ); |
391 | else |
392 | llvm_unreachable("XLEN should be 32 or 64." ); |
393 | |
394 | Features.addFeaturesVector(OtherFeatures: ISAInfo->toFeatures()); |
395 | } |
396 | |
397 | return Features; |
398 | } |
399 | |
400 | SubtargetFeatures ELFObjectFileBase::getLoongArchFeatures() const { |
401 | SubtargetFeatures Features; |
402 | |
403 | switch (getPlatformFlags() & ELF::EF_LOONGARCH_ABI_MODIFIER_MASK) { |
404 | case ELF::EF_LOONGARCH_ABI_SOFT_FLOAT: |
405 | break; |
406 | case ELF::EF_LOONGARCH_ABI_DOUBLE_FLOAT: |
407 | Features.AddFeature(String: "d" ); |
408 | // D implies F according to LoongArch ISA spec. |
409 | [[fallthrough]]; |
410 | case ELF::EF_LOONGARCH_ABI_SINGLE_FLOAT: |
411 | Features.AddFeature(String: "f" ); |
412 | break; |
413 | } |
414 | |
415 | return Features; |
416 | } |
417 | |
418 | Expected<SubtargetFeatures> ELFObjectFileBase::getFeatures() const { |
419 | switch (getEMachine()) { |
420 | case ELF::EM_MIPS: |
421 | return getMIPSFeatures(); |
422 | case ELF::EM_ARM: |
423 | return getARMFeatures(); |
424 | case ELF::EM_RISCV: |
425 | return getRISCVFeatures(); |
426 | case ELF::EM_LOONGARCH: |
427 | return getLoongArchFeatures(); |
428 | case ELF::EM_HEXAGON: |
429 | return getHexagonFeatures(); |
430 | default: |
431 | return SubtargetFeatures(); |
432 | } |
433 | } |
434 | |
435 | std::optional<StringRef> ELFObjectFileBase::tryGetCPUName() const { |
436 | switch (getEMachine()) { |
437 | case ELF::EM_AMDGPU: |
438 | return getAMDGPUCPUName(); |
439 | case ELF::EM_CUDA: |
440 | return getNVPTXCPUName(); |
441 | case ELF::EM_PPC: |
442 | case ELF::EM_PPC64: |
443 | return StringRef("future" ); |
444 | default: |
445 | return std::nullopt; |
446 | } |
447 | } |
448 | |
449 | StringRef ELFObjectFileBase::getAMDGPUCPUName() const { |
450 | assert(getEMachine() == ELF::EM_AMDGPU); |
451 | unsigned CPU = getPlatformFlags() & ELF::EF_AMDGPU_MACH; |
452 | |
453 | switch (CPU) { |
454 | // Radeon HD 2000/3000 Series (R600). |
455 | case ELF::EF_AMDGPU_MACH_R600_R600: |
456 | return "r600" ; |
457 | case ELF::EF_AMDGPU_MACH_R600_R630: |
458 | return "r630" ; |
459 | case ELF::EF_AMDGPU_MACH_R600_RS880: |
460 | return "rs880" ; |
461 | case ELF::EF_AMDGPU_MACH_R600_RV670: |
462 | return "rv670" ; |
463 | |
464 | // Radeon HD 4000 Series (R700). |
465 | case ELF::EF_AMDGPU_MACH_R600_RV710: |
466 | return "rv710" ; |
467 | case ELF::EF_AMDGPU_MACH_R600_RV730: |
468 | return "rv730" ; |
469 | case ELF::EF_AMDGPU_MACH_R600_RV770: |
470 | return "rv770" ; |
471 | |
472 | // Radeon HD 5000 Series (Evergreen). |
473 | case ELF::EF_AMDGPU_MACH_R600_CEDAR: |
474 | return "cedar" ; |
475 | case ELF::EF_AMDGPU_MACH_R600_CYPRESS: |
476 | return "cypress" ; |
477 | case ELF::EF_AMDGPU_MACH_R600_JUNIPER: |
478 | return "juniper" ; |
479 | case ELF::EF_AMDGPU_MACH_R600_REDWOOD: |
480 | return "redwood" ; |
481 | case ELF::EF_AMDGPU_MACH_R600_SUMO: |
482 | return "sumo" ; |
483 | |
484 | // Radeon HD 6000 Series (Northern Islands). |
485 | case ELF::EF_AMDGPU_MACH_R600_BARTS: |
486 | return "barts" ; |
487 | case ELF::EF_AMDGPU_MACH_R600_CAICOS: |
488 | return "caicos" ; |
489 | case ELF::EF_AMDGPU_MACH_R600_CAYMAN: |
490 | return "cayman" ; |
491 | case ELF::EF_AMDGPU_MACH_R600_TURKS: |
492 | return "turks" ; |
493 | |
494 | // AMDGCN GFX6. |
495 | case ELF::EF_AMDGPU_MACH_AMDGCN_GFX600: |
496 | return "gfx600" ; |
497 | case ELF::EF_AMDGPU_MACH_AMDGCN_GFX601: |
498 | return "gfx601" ; |
499 | case ELF::EF_AMDGPU_MACH_AMDGCN_GFX602: |
500 | return "gfx602" ; |
501 | |
502 | // AMDGCN GFX7. |
503 | case ELF::EF_AMDGPU_MACH_AMDGCN_GFX700: |
504 | return "gfx700" ; |
505 | case ELF::EF_AMDGPU_MACH_AMDGCN_GFX701: |
506 | return "gfx701" ; |
507 | case ELF::EF_AMDGPU_MACH_AMDGCN_GFX702: |
508 | return "gfx702" ; |
509 | case ELF::EF_AMDGPU_MACH_AMDGCN_GFX703: |
510 | return "gfx703" ; |
511 | case ELF::EF_AMDGPU_MACH_AMDGCN_GFX704: |
512 | return "gfx704" ; |
513 | case ELF::EF_AMDGPU_MACH_AMDGCN_GFX705: |
514 | return "gfx705" ; |
515 | |
516 | // AMDGCN GFX8. |
517 | case ELF::EF_AMDGPU_MACH_AMDGCN_GFX801: |
518 | return "gfx801" ; |
519 | case ELF::EF_AMDGPU_MACH_AMDGCN_GFX802: |
520 | return "gfx802" ; |
521 | case ELF::EF_AMDGPU_MACH_AMDGCN_GFX803: |
522 | return "gfx803" ; |
523 | case ELF::EF_AMDGPU_MACH_AMDGCN_GFX805: |
524 | return "gfx805" ; |
525 | case ELF::EF_AMDGPU_MACH_AMDGCN_GFX810: |
526 | return "gfx810" ; |
527 | |
528 | // AMDGCN GFX9. |
529 | case ELF::EF_AMDGPU_MACH_AMDGCN_GFX900: |
530 | return "gfx900" ; |
531 | case ELF::EF_AMDGPU_MACH_AMDGCN_GFX902: |
532 | return "gfx902" ; |
533 | case ELF::EF_AMDGPU_MACH_AMDGCN_GFX904: |
534 | return "gfx904" ; |
535 | case ELF::EF_AMDGPU_MACH_AMDGCN_GFX906: |
536 | return "gfx906" ; |
537 | case ELF::EF_AMDGPU_MACH_AMDGCN_GFX908: |
538 | return "gfx908" ; |
539 | case ELF::EF_AMDGPU_MACH_AMDGCN_GFX909: |
540 | return "gfx909" ; |
541 | case ELF::EF_AMDGPU_MACH_AMDGCN_GFX90A: |
542 | return "gfx90a" ; |
543 | case ELF::EF_AMDGPU_MACH_AMDGCN_GFX90C: |
544 | return "gfx90c" ; |
545 | case ELF::EF_AMDGPU_MACH_AMDGCN_GFX940: |
546 | return "gfx940" ; |
547 | case ELF::EF_AMDGPU_MACH_AMDGCN_GFX941: |
548 | return "gfx941" ; |
549 | case ELF::EF_AMDGPU_MACH_AMDGCN_GFX942: |
550 | return "gfx942" ; |
551 | |
552 | // AMDGCN GFX10. |
553 | case ELF::EF_AMDGPU_MACH_AMDGCN_GFX1010: |
554 | return "gfx1010" ; |
555 | case ELF::EF_AMDGPU_MACH_AMDGCN_GFX1011: |
556 | return "gfx1011" ; |
557 | case ELF::EF_AMDGPU_MACH_AMDGCN_GFX1012: |
558 | return "gfx1012" ; |
559 | case ELF::EF_AMDGPU_MACH_AMDGCN_GFX1013: |
560 | return "gfx1013" ; |
561 | case ELF::EF_AMDGPU_MACH_AMDGCN_GFX1030: |
562 | return "gfx1030" ; |
563 | case ELF::EF_AMDGPU_MACH_AMDGCN_GFX1031: |
564 | return "gfx1031" ; |
565 | case ELF::EF_AMDGPU_MACH_AMDGCN_GFX1032: |
566 | return "gfx1032" ; |
567 | case ELF::EF_AMDGPU_MACH_AMDGCN_GFX1033: |
568 | return "gfx1033" ; |
569 | case ELF::EF_AMDGPU_MACH_AMDGCN_GFX1034: |
570 | return "gfx1034" ; |
571 | case ELF::EF_AMDGPU_MACH_AMDGCN_GFX1035: |
572 | return "gfx1035" ; |
573 | case ELF::EF_AMDGPU_MACH_AMDGCN_GFX1036: |
574 | return "gfx1036" ; |
575 | |
576 | // AMDGCN GFX11. |
577 | case ELF::EF_AMDGPU_MACH_AMDGCN_GFX1100: |
578 | return "gfx1100" ; |
579 | case ELF::EF_AMDGPU_MACH_AMDGCN_GFX1101: |
580 | return "gfx1101" ; |
581 | case ELF::EF_AMDGPU_MACH_AMDGCN_GFX1102: |
582 | return "gfx1102" ; |
583 | case ELF::EF_AMDGPU_MACH_AMDGCN_GFX1103: |
584 | return "gfx1103" ; |
585 | case ELF::EF_AMDGPU_MACH_AMDGCN_GFX1150: |
586 | return "gfx1150" ; |
587 | case ELF::EF_AMDGPU_MACH_AMDGCN_GFX1151: |
588 | return "gfx1151" ; |
589 | case ELF::EF_AMDGPU_MACH_AMDGCN_GFX1152: |
590 | return "gfx1152" ; |
591 | |
592 | // AMDGCN GFX12. |
593 | case ELF::EF_AMDGPU_MACH_AMDGCN_GFX1200: |
594 | return "gfx1200" ; |
595 | case ELF::EF_AMDGPU_MACH_AMDGCN_GFX1201: |
596 | return "gfx1201" ; |
597 | |
598 | // Generic AMDGCN targets |
599 | case ELF::EF_AMDGPU_MACH_AMDGCN_GFX9_GENERIC: |
600 | return "gfx9-generic" ; |
601 | case ELF::EF_AMDGPU_MACH_AMDGCN_GFX10_1_GENERIC: |
602 | return "gfx10-1-generic" ; |
603 | case ELF::EF_AMDGPU_MACH_AMDGCN_GFX10_3_GENERIC: |
604 | return "gfx10-3-generic" ; |
605 | case ELF::EF_AMDGPU_MACH_AMDGCN_GFX11_GENERIC: |
606 | return "gfx11-generic" ; |
607 | case ELF::EF_AMDGPU_MACH_AMDGCN_GFX12_GENERIC: |
608 | return "gfx12-generic" ; |
609 | default: |
610 | llvm_unreachable("Unknown EF_AMDGPU_MACH value" ); |
611 | } |
612 | } |
613 | |
614 | StringRef ELFObjectFileBase::getNVPTXCPUName() const { |
615 | assert(getEMachine() == ELF::EM_CUDA); |
616 | unsigned SM = getPlatformFlags() & ELF::EF_CUDA_SM; |
617 | |
618 | switch (SM) { |
619 | // Fermi architecture. |
620 | case ELF::EF_CUDA_SM20: |
621 | return "sm_20" ; |
622 | case ELF::EF_CUDA_SM21: |
623 | return "sm_21" ; |
624 | |
625 | // Kepler architecture. |
626 | case ELF::EF_CUDA_SM30: |
627 | return "sm_30" ; |
628 | case ELF::EF_CUDA_SM32: |
629 | return "sm_32" ; |
630 | case ELF::EF_CUDA_SM35: |
631 | return "sm_35" ; |
632 | case ELF::EF_CUDA_SM37: |
633 | return "sm_37" ; |
634 | |
635 | // Maxwell architecture. |
636 | case ELF::EF_CUDA_SM50: |
637 | return "sm_50" ; |
638 | case ELF::EF_CUDA_SM52: |
639 | return "sm_52" ; |
640 | case ELF::EF_CUDA_SM53: |
641 | return "sm_53" ; |
642 | |
643 | // Pascal architecture. |
644 | case ELF::EF_CUDA_SM60: |
645 | return "sm_60" ; |
646 | case ELF::EF_CUDA_SM61: |
647 | return "sm_61" ; |
648 | case ELF::EF_CUDA_SM62: |
649 | return "sm_62" ; |
650 | |
651 | // Volta architecture. |
652 | case ELF::EF_CUDA_SM70: |
653 | return "sm_70" ; |
654 | case ELF::EF_CUDA_SM72: |
655 | return "sm_72" ; |
656 | |
657 | // Turing architecture. |
658 | case ELF::EF_CUDA_SM75: |
659 | return "sm_75" ; |
660 | |
661 | // Ampere architecture. |
662 | case ELF::EF_CUDA_SM80: |
663 | return "sm_80" ; |
664 | case ELF::EF_CUDA_SM86: |
665 | return "sm_86" ; |
666 | case ELF::EF_CUDA_SM87: |
667 | return "sm_87" ; |
668 | |
669 | // Ada architecture. |
670 | case ELF::EF_CUDA_SM89: |
671 | return "sm_89" ; |
672 | |
673 | // Hopper architecture. |
674 | case ELF::EF_CUDA_SM90: |
675 | return getPlatformFlags() & ELF::EF_CUDA_ACCELERATORS ? "sm_90a" : "sm_90" ; |
676 | default: |
677 | llvm_unreachable("Unknown EF_CUDA_SM value" ); |
678 | } |
679 | } |
680 | |
681 | // FIXME Encode from a tablegen description or target parser. |
682 | void ELFObjectFileBase::setARMSubArch(Triple &TheTriple) const { |
683 | if (TheTriple.getSubArch() != Triple::NoSubArch) |
684 | return; |
685 | |
686 | ARMAttributeParser Attributes; |
687 | if (Error E = getBuildAttributes(Attributes)) { |
688 | // TODO Propagate Error. |
689 | consumeError(Err: std::move(E)); |
690 | return; |
691 | } |
692 | |
693 | std::string Triple; |
694 | // Default to ARM, but use the triple if it's been set. |
695 | if (TheTriple.isThumb()) |
696 | Triple = "thumb" ; |
697 | else |
698 | Triple = "arm" ; |
699 | |
700 | std::optional<unsigned> Attr = |
701 | Attributes.getAttributeValue(tag: ARMBuildAttrs::CPU_arch); |
702 | if (Attr) { |
703 | switch (*Attr) { |
704 | case ARMBuildAttrs::v4: |
705 | Triple += "v4" ; |
706 | break; |
707 | case ARMBuildAttrs::v4T: |
708 | Triple += "v4t" ; |
709 | break; |
710 | case ARMBuildAttrs::v5T: |
711 | Triple += "v5t" ; |
712 | break; |
713 | case ARMBuildAttrs::v5TE: |
714 | Triple += "v5te" ; |
715 | break; |
716 | case ARMBuildAttrs::v5TEJ: |
717 | Triple += "v5tej" ; |
718 | break; |
719 | case ARMBuildAttrs::v6: |
720 | Triple += "v6" ; |
721 | break; |
722 | case ARMBuildAttrs::v6KZ: |
723 | Triple += "v6kz" ; |
724 | break; |
725 | case ARMBuildAttrs::v6T2: |
726 | Triple += "v6t2" ; |
727 | break; |
728 | case ARMBuildAttrs::v6K: |
729 | Triple += "v6k" ; |
730 | break; |
731 | case ARMBuildAttrs::v7: { |
732 | std::optional<unsigned> ArchProfileAttr = |
733 | Attributes.getAttributeValue(tag: ARMBuildAttrs::CPU_arch_profile); |
734 | if (ArchProfileAttr && |
735 | *ArchProfileAttr == ARMBuildAttrs::MicroControllerProfile) |
736 | Triple += "v7m" ; |
737 | else |
738 | Triple += "v7" ; |
739 | break; |
740 | } |
741 | case ARMBuildAttrs::v6_M: |
742 | Triple += "v6m" ; |
743 | break; |
744 | case ARMBuildAttrs::v6S_M: |
745 | Triple += "v6sm" ; |
746 | break; |
747 | case ARMBuildAttrs::v7E_M: |
748 | Triple += "v7em" ; |
749 | break; |
750 | case ARMBuildAttrs::v8_A: |
751 | Triple += "v8a" ; |
752 | break; |
753 | case ARMBuildAttrs::v8_R: |
754 | Triple += "v8r" ; |
755 | break; |
756 | case ARMBuildAttrs::v8_M_Base: |
757 | Triple += "v8m.base" ; |
758 | break; |
759 | case ARMBuildAttrs::v8_M_Main: |
760 | Triple += "v8m.main" ; |
761 | break; |
762 | case ARMBuildAttrs::v8_1_M_Main: |
763 | Triple += "v8.1m.main" ; |
764 | break; |
765 | case ARMBuildAttrs::v9_A: |
766 | Triple += "v9a" ; |
767 | break; |
768 | } |
769 | } |
770 | if (!isLittleEndian()) |
771 | Triple += "eb" ; |
772 | |
773 | TheTriple.setArchName(Triple); |
774 | } |
775 | |
776 | std::vector<ELFPltEntry> ELFObjectFileBase::getPltEntries() const { |
777 | std::string Err; |
778 | const auto Triple = makeTriple(); |
779 | const auto *T = TargetRegistry::lookupTarget(Triple: Triple.str(), Error&: Err); |
780 | if (!T) |
781 | return {}; |
782 | uint32_t JumpSlotReloc = 0, GlobDatReloc = 0; |
783 | switch (Triple.getArch()) { |
784 | case Triple::x86: |
785 | JumpSlotReloc = ELF::R_386_JUMP_SLOT; |
786 | GlobDatReloc = ELF::R_386_GLOB_DAT; |
787 | break; |
788 | case Triple::x86_64: |
789 | JumpSlotReloc = ELF::R_X86_64_JUMP_SLOT; |
790 | GlobDatReloc = ELF::R_X86_64_GLOB_DAT; |
791 | break; |
792 | case Triple::aarch64: |
793 | case Triple::aarch64_be: |
794 | JumpSlotReloc = ELF::R_AARCH64_JUMP_SLOT; |
795 | break; |
796 | default: |
797 | return {}; |
798 | } |
799 | std::unique_ptr<const MCInstrInfo> MII(T->createMCInstrInfo()); |
800 | std::unique_ptr<const MCInstrAnalysis> MIA( |
801 | T->createMCInstrAnalysis(Info: MII.get())); |
802 | if (!MIA) |
803 | return {}; |
804 | std::vector<std::pair<uint64_t, uint64_t>> PltEntries; |
805 | std::optional<SectionRef> RelaPlt, RelaDyn; |
806 | uint64_t GotBaseVA = 0; |
807 | for (const SectionRef &Section : sections()) { |
808 | Expected<StringRef> NameOrErr = Section.getName(); |
809 | if (!NameOrErr) { |
810 | consumeError(Err: NameOrErr.takeError()); |
811 | continue; |
812 | } |
813 | StringRef Name = *NameOrErr; |
814 | |
815 | if (Name == ".rela.plt" || Name == ".rel.plt" ) { |
816 | RelaPlt = Section; |
817 | } else if (Name == ".rela.dyn" || Name == ".rel.dyn" ) { |
818 | RelaDyn = Section; |
819 | } else if (Name == ".got.plt" ) { |
820 | GotBaseVA = Section.getAddress(); |
821 | } else if (Name == ".plt" || Name == ".plt.got" ) { |
822 | Expected<StringRef> PltContents = Section.getContents(); |
823 | if (!PltContents) { |
824 | consumeError(Err: PltContents.takeError()); |
825 | return {}; |
826 | } |
827 | llvm::append_range( |
828 | C&: PltEntries, |
829 | R: MIA->findPltEntries(PltSectionVA: Section.getAddress(), |
830 | PltContents: arrayRefFromStringRef(Input: *PltContents), TargetTriple: Triple)); |
831 | } |
832 | } |
833 | |
834 | // Build a map from GOT entry virtual address to PLT entry virtual address. |
835 | DenseMap<uint64_t, uint64_t> GotToPlt; |
836 | for (auto [Plt, GotPlt] : PltEntries) { |
837 | uint64_t GotPltEntry = GotPlt; |
838 | // An x86-32 PIC PLT uses jmp DWORD PTR [ebx-offset]. Add |
839 | // _GLOBAL_OFFSET_TABLE_ (EBX) to get the .got.plt (or .got) entry address. |
840 | // See X86MCTargetDesc.cpp:findPltEntries for the 1 << 32 bit. |
841 | if (GotPltEntry & (uint64_t(1) << 32) && getEMachine() == ELF::EM_386) |
842 | GotPltEntry = static_cast<int32_t>(GotPltEntry) + GotBaseVA; |
843 | GotToPlt.insert(KV: std::make_pair(x&: GotPltEntry, y&: Plt)); |
844 | } |
845 | |
846 | // Find the relocations in the dynamic relocation table that point to |
847 | // locations in the GOT for which we know the corresponding PLT entry. |
848 | std::vector<ELFPltEntry> Result; |
849 | auto handleRels = [&](iterator_range<relocation_iterator> Rels, |
850 | uint32_t RelType, StringRef PltSec) { |
851 | for (const auto &R : Rels) { |
852 | if (R.getType() != RelType) |
853 | continue; |
854 | auto PltEntryIter = GotToPlt.find(Val: R.getOffset()); |
855 | if (PltEntryIter != GotToPlt.end()) { |
856 | symbol_iterator Sym = R.getSymbol(); |
857 | if (Sym == symbol_end()) |
858 | Result.push_back( |
859 | x: ELFPltEntry{.Section: PltSec, .Symbol: std::nullopt, .Address: PltEntryIter->second}); |
860 | else |
861 | Result.push_back(x: ELFPltEntry{.Section: PltSec, .Symbol: Sym->getRawDataRefImpl(), |
862 | .Address: PltEntryIter->second}); |
863 | } |
864 | } |
865 | }; |
866 | |
867 | if (RelaPlt) |
868 | handleRels(RelaPlt->relocations(), JumpSlotReloc, ".plt" ); |
869 | |
870 | // If a symbol needing a PLT entry also needs a GLOB_DAT relocation, GNU ld's |
871 | // x86 port places the PLT entry in the .plt.got section. |
872 | if (RelaDyn) |
873 | handleRels(RelaDyn->relocations(), GlobDatReloc, ".plt.got" ); |
874 | |
875 | return Result; |
876 | } |
877 | |
878 | template <class ELFT> |
879 | Expected<std::vector<BBAddrMap>> static readBBAddrMapImpl( |
880 | const ELFFile<ELFT> &EF, std::optional<unsigned> TextSectionIndex, |
881 | std::vector<PGOAnalysisMap> *PGOAnalyses) { |
882 | using Elf_Shdr = typename ELFT::Shdr; |
883 | bool IsRelocatable = EF.getHeader().e_type == ELF::ET_REL; |
884 | std::vector<BBAddrMap> BBAddrMaps; |
885 | if (PGOAnalyses) |
886 | PGOAnalyses->clear(); |
887 | |
888 | const auto &Sections = cantFail(EF.sections()); |
889 | auto IsMatch = [&](const Elf_Shdr &Sec) -> Expected<bool> { |
890 | if (Sec.sh_type != ELF::SHT_LLVM_BB_ADDR_MAP && |
891 | Sec.sh_type != ELF::SHT_LLVM_BB_ADDR_MAP_V0) |
892 | return false; |
893 | if (!TextSectionIndex) |
894 | return true; |
895 | Expected<const Elf_Shdr *> TextSecOrErr = EF.getSection(Sec.sh_link); |
896 | if (!TextSecOrErr) |
897 | return createError("unable to get the linked-to section for " + |
898 | describe(EF, Sec) + ": " + |
899 | toString(TextSecOrErr.takeError())); |
900 | assert(*TextSecOrErr >= Sections.begin() && |
901 | "Text section pointer outside of bounds" ); |
902 | if (*TextSectionIndex != |
903 | (unsigned)std::distance(Sections.begin(), *TextSecOrErr)) |
904 | return false; |
905 | return true; |
906 | }; |
907 | |
908 | Expected<MapVector<const Elf_Shdr *, const Elf_Shdr *>> SectionRelocMapOrErr = |
909 | EF.getSectionAndRelocations(IsMatch); |
910 | if (!SectionRelocMapOrErr) |
911 | return SectionRelocMapOrErr.takeError(); |
912 | |
913 | for (auto const &[Sec, RelocSec] : *SectionRelocMapOrErr) { |
914 | if (IsRelocatable && !RelocSec) |
915 | return createError("unable to get relocation section for " + |
916 | describe(EF, *Sec)); |
917 | Expected<std::vector<BBAddrMap>> BBAddrMapOrErr = |
918 | EF.decodeBBAddrMap(*Sec, RelocSec, PGOAnalyses); |
919 | if (!BBAddrMapOrErr) { |
920 | if (PGOAnalyses) |
921 | PGOAnalyses->clear(); |
922 | return createError("unable to read " + describe(EF, *Sec) + ": " + |
923 | toString(E: BBAddrMapOrErr.takeError())); |
924 | } |
925 | std::move(first: BBAddrMapOrErr->begin(), last: BBAddrMapOrErr->end(), |
926 | result: std::back_inserter(x&: BBAddrMaps)); |
927 | } |
928 | if (PGOAnalyses) |
929 | assert(PGOAnalyses->size() == BBAddrMaps.size() && |
930 | "The same number of BBAddrMaps and PGOAnalysisMaps should be " |
931 | "returned when PGO information is requested" ); |
932 | return BBAddrMaps; |
933 | } |
934 | |
935 | template <class ELFT> |
936 | static Expected<std::vector<VersionEntry>> |
937 | readDynsymVersionsImpl(const ELFFile<ELFT> &EF, |
938 | ELFObjectFileBase::elf_symbol_iterator_range Symbols) { |
939 | using Elf_Shdr = typename ELFT::Shdr; |
940 | const Elf_Shdr *VerSec = nullptr; |
941 | const Elf_Shdr *VerNeedSec = nullptr; |
942 | const Elf_Shdr *VerDefSec = nullptr; |
943 | // The user should ensure sections() can't fail here. |
944 | for (const Elf_Shdr &Sec : cantFail(EF.sections())) { |
945 | if (Sec.sh_type == ELF::SHT_GNU_versym) |
946 | VerSec = &Sec; |
947 | else if (Sec.sh_type == ELF::SHT_GNU_verdef) |
948 | VerDefSec = &Sec; |
949 | else if (Sec.sh_type == ELF::SHT_GNU_verneed) |
950 | VerNeedSec = &Sec; |
951 | } |
952 | if (!VerSec) |
953 | return std::vector<VersionEntry>(); |
954 | |
955 | Expected<SmallVector<std::optional<VersionEntry>, 0>> MapOrErr = |
956 | EF.loadVersionMap(VerNeedSec, VerDefSec); |
957 | if (!MapOrErr) |
958 | return MapOrErr.takeError(); |
959 | |
960 | std::vector<VersionEntry> Ret; |
961 | size_t I = 0; |
962 | for (const ELFSymbolRef &Sym : Symbols) { |
963 | ++I; |
964 | Expected<const typename ELFT::Versym *> VerEntryOrErr = |
965 | EF.template getEntry<typename ELFT::Versym>(*VerSec, I); |
966 | if (!VerEntryOrErr) |
967 | return createError("unable to read an entry with index " + Twine(I) + |
968 | " from " + describe(EF, *VerSec) + ": " + |
969 | toString(VerEntryOrErr.takeError())); |
970 | |
971 | Expected<uint32_t> FlagsOrErr = Sym.getFlags(); |
972 | if (!FlagsOrErr) |
973 | return createError(Err: "unable to read flags for symbol with index " + |
974 | Twine(I) + ": " + toString(E: FlagsOrErr.takeError())); |
975 | |
976 | bool IsDefault; |
977 | Expected<StringRef> VerOrErr = EF.getSymbolVersionByIndex( |
978 | (*VerEntryOrErr)->vs_index, IsDefault, *MapOrErr, |
979 | (*FlagsOrErr) & SymbolRef::SF_Undefined); |
980 | if (!VerOrErr) |
981 | return createError("unable to get a version for entry " + Twine(I) + |
982 | " of " + describe(EF, *VerSec) + ": " + |
983 | toString(E: VerOrErr.takeError())); |
984 | |
985 | Ret.push_back(x: {.Name: (*VerOrErr).str(), .IsVerDef: IsDefault}); |
986 | } |
987 | |
988 | return Ret; |
989 | } |
990 | |
991 | Expected<std::vector<VersionEntry>> |
992 | ELFObjectFileBase::readDynsymVersions() const { |
993 | elf_symbol_iterator_range Symbols = getDynamicSymbolIterators(); |
994 | if (const auto *Obj = dyn_cast<ELF32LEObjectFile>(Val: this)) |
995 | return readDynsymVersionsImpl(EF: Obj->getELFFile(), Symbols); |
996 | if (const auto *Obj = dyn_cast<ELF32BEObjectFile>(Val: this)) |
997 | return readDynsymVersionsImpl(EF: Obj->getELFFile(), Symbols); |
998 | if (const auto *Obj = dyn_cast<ELF64LEObjectFile>(Val: this)) |
999 | return readDynsymVersionsImpl(EF: Obj->getELFFile(), Symbols); |
1000 | return readDynsymVersionsImpl(EF: cast<ELF64BEObjectFile>(Val: this)->getELFFile(), |
1001 | Symbols); |
1002 | } |
1003 | |
1004 | Expected<std::vector<BBAddrMap>> ELFObjectFileBase::readBBAddrMap( |
1005 | std::optional<unsigned> TextSectionIndex, |
1006 | std::vector<PGOAnalysisMap> *PGOAnalyses) const { |
1007 | if (const auto *Obj = dyn_cast<ELF32LEObjectFile>(Val: this)) |
1008 | return readBBAddrMapImpl(EF: Obj->getELFFile(), TextSectionIndex, PGOAnalyses); |
1009 | if (const auto *Obj = dyn_cast<ELF64LEObjectFile>(Val: this)) |
1010 | return readBBAddrMapImpl(EF: Obj->getELFFile(), TextSectionIndex, PGOAnalyses); |
1011 | if (const auto *Obj = dyn_cast<ELF32BEObjectFile>(Val: this)) |
1012 | return readBBAddrMapImpl(EF: Obj->getELFFile(), TextSectionIndex, PGOAnalyses); |
1013 | return readBBAddrMapImpl(EF: cast<ELF64BEObjectFile>(Val: this)->getELFFile(), |
1014 | TextSectionIndex, PGOAnalyses); |
1015 | } |
1016 | |
1017 | StringRef ELFObjectFileBase::getCrelDecodeProblem(SectionRef Sec) const { |
1018 | auto Data = Sec.getRawDataRefImpl(); |
1019 | if (const auto *Obj = dyn_cast<ELF32LEObjectFile>(Val: this)) |
1020 | return Obj->getCrelDecodeProblem(Sec: Data); |
1021 | if (const auto *Obj = dyn_cast<ELF32BEObjectFile>(Val: this)) |
1022 | return Obj->getCrelDecodeProblem(Sec: Data); |
1023 | if (const auto *Obj = dyn_cast<ELF64LEObjectFile>(Val: this)) |
1024 | return Obj->getCrelDecodeProblem(Sec: Data); |
1025 | return cast<ELF64BEObjectFile>(Val: this)->getCrelDecodeProblem(Sec: Data); |
1026 | } |
1027 | |