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