xref: /llvm-project-15.0.7/lld/ELF/Arch/AMDGPU.cpp (revision 06cfb7a3)
1 //===- AMDGPU.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 #include "Symbols.h"
10 #include "Target.h"
11 #include "lld/Common/ErrorHandler.h"
12 #include "llvm/BinaryFormat/ELF.h"
13 #include "llvm/Support/Endian.h"
14 
15 using namespace llvm;
16 using namespace llvm::object;
17 using namespace llvm::support::endian;
18 using namespace llvm::ELF;
19 using namespace lld;
20 using namespace lld::elf;
21 
22 namespace {
23 class AMDGPU final : public TargetInfo {
24 private:
25   uint32_t calcEFlagsV3() const;
26   uint32_t calcEFlagsV4() const;
27 
28 public:
29   AMDGPU();
30   uint32_t calcEFlags() const override;
31   void relocate(uint8_t *loc, const Relocation &rel,
32                 uint64_t val) const override;
33   RelExpr getRelExpr(RelType type, const Symbol &s,
34                      const uint8_t *loc) const override;
35   RelType getDynRel(RelType type) const override;
36 };
37 } // namespace
38 
39 AMDGPU::AMDGPU() {
40   relativeRel = R_AMDGPU_RELATIVE64;
41   gotRel = R_AMDGPU_ABS64;
42   symbolicRel = R_AMDGPU_ABS64;
43 }
44 
45 static uint32_t getEFlags(InputFile *file) {
46   return cast<ObjFile<ELF64LE>>(file)->getObj().getHeader().e_flags;
47 }
48 
49 uint32_t AMDGPU::calcEFlagsV3() const {
50   uint32_t ret = getEFlags(objectFiles[0]);
51 
52   // Verify that all input files have the same e_flags.
53   for (InputFile *f : makeArrayRef(objectFiles).slice(1)) {
54     if (ret == getEFlags(f))
55       continue;
56     error("incompatible e_flags: " + toString(f));
57     return 0;
58   }
59   return ret;
60 }
61 
62 uint32_t AMDGPU::calcEFlagsV4() const {
63   uint32_t retMach = getEFlags(objectFiles[0]) & EF_AMDGPU_MACH;
64   uint32_t retXnack = getEFlags(objectFiles[0]) & EF_AMDGPU_FEATURE_XNACK_V4;
65   uint32_t retSramEcc =
66       getEFlags(objectFiles[0]) & EF_AMDGPU_FEATURE_SRAMECC_V4;
67 
68   // Verify that all input files have compatible e_flags (same mach, all
69   // features in the same category are either ANY, ANY and ON, or ANY and OFF).
70   for (InputFile *f : makeArrayRef(objectFiles).slice(1)) {
71     if (retMach != (getEFlags(f) & EF_AMDGPU_MACH)) {
72       error("incompatible mach: " + toString(f));
73       return 0;
74     }
75 
76     if (retXnack == EF_AMDGPU_FEATURE_XNACK_UNSUPPORTED_V4 ||
77         (retXnack != EF_AMDGPU_FEATURE_XNACK_ANY_V4 &&
78             (getEFlags(f) & EF_AMDGPU_FEATURE_XNACK_V4)
79                 != EF_AMDGPU_FEATURE_XNACK_ANY_V4)) {
80       if (retXnack != (getEFlags(f) & EF_AMDGPU_FEATURE_XNACK_V4)) {
81         error("incompatible xnack: " + toString(f));
82         return 0;
83       }
84     } else {
85       if (retXnack == EF_AMDGPU_FEATURE_XNACK_ANY_V4)
86         retXnack = getEFlags(f) & EF_AMDGPU_FEATURE_XNACK_V4;
87     }
88 
89     if (retSramEcc == EF_AMDGPU_FEATURE_SRAMECC_UNSUPPORTED_V4 ||
90         (retSramEcc != EF_AMDGPU_FEATURE_SRAMECC_ANY_V4 &&
91             (getEFlags(f) & EF_AMDGPU_FEATURE_SRAMECC_V4) !=
92                 EF_AMDGPU_FEATURE_SRAMECC_ANY_V4)) {
93       if (retSramEcc != (getEFlags(f) & EF_AMDGPU_FEATURE_SRAMECC_V4)) {
94         error("incompatible sramecc: " + toString(f));
95         return 0;
96       }
97     } else {
98       if (retSramEcc == EF_AMDGPU_FEATURE_SRAMECC_ANY_V4)
99         retSramEcc = getEFlags(f) & EF_AMDGPU_FEATURE_SRAMECC_V4;
100     }
101   }
102 
103   return retMach | retXnack | retSramEcc;
104 }
105 
106 uint32_t AMDGPU::calcEFlags() const {
107   assert(!objectFiles.empty());
108 
109   uint8_t abiVersion = cast<ObjFile<ELF64LE>>(objectFiles[0])->getObj()
110       .getHeader().e_ident[EI_ABIVERSION];
111   switch (abiVersion) {
112   case ELFABIVERSION_AMDGPU_HSA_V2:
113   case ELFABIVERSION_AMDGPU_HSA_V3:
114     return calcEFlagsV3();
115   case ELFABIVERSION_AMDGPU_HSA_V4:
116     return calcEFlagsV4();
117   default:
118     error("unknown abi version: " + Twine(abiVersion));
119     return 0;
120   }
121 }
122 
123 void AMDGPU::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const {
124   switch (rel.type) {
125   case R_AMDGPU_ABS32:
126   case R_AMDGPU_GOTPCREL:
127   case R_AMDGPU_GOTPCREL32_LO:
128   case R_AMDGPU_REL32:
129   case R_AMDGPU_REL32_LO:
130     write32le(loc, val);
131     break;
132   case R_AMDGPU_ABS64:
133   case R_AMDGPU_REL64:
134     write64le(loc, val);
135     break;
136   case R_AMDGPU_GOTPCREL32_HI:
137   case R_AMDGPU_REL32_HI:
138     write32le(loc, val >> 32);
139     break;
140   case R_AMDGPU_REL16: {
141     int64_t simm = (static_cast<int64_t>(val) - 4) / 4;
142     checkInt(loc, simm, 16, rel);
143     write16le(loc, simm);
144     break;
145   }
146   default:
147     llvm_unreachable("unknown relocation");
148   }
149 }
150 
151 RelExpr AMDGPU::getRelExpr(RelType type, const Symbol &s,
152                            const uint8_t *loc) const {
153   switch (type) {
154   case R_AMDGPU_ABS32:
155   case R_AMDGPU_ABS64:
156     return R_ABS;
157   case R_AMDGPU_REL32:
158   case R_AMDGPU_REL32_LO:
159   case R_AMDGPU_REL32_HI:
160   case R_AMDGPU_REL64:
161   case R_AMDGPU_REL16:
162     return R_PC;
163   case R_AMDGPU_GOTPCREL:
164   case R_AMDGPU_GOTPCREL32_LO:
165   case R_AMDGPU_GOTPCREL32_HI:
166     return R_GOT_PC;
167   default:
168     error(getErrorLocation(loc) + "unknown relocation (" + Twine(type) +
169           ") against symbol " + toString(s));
170     return R_NONE;
171   }
172 }
173 
174 RelType AMDGPU::getDynRel(RelType type) const {
175   if (type == R_AMDGPU_ABS64)
176     return type;
177   return R_AMDGPU_NONE;
178 }
179 
180 TargetInfo *elf::getAMDGPUTargetInfo() {
181   static AMDGPU target;
182   return &target;
183 }
184