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