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
16using namespace llvm;
17using namespace llvm::object;
18using namespace llvm::support::endian;
19using namespace llvm::ELF;
20using namespace lld;
21using namespace lld::elf;
22
23namespace {
24class AMDGPU final : public TargetInfo {
25private:
26 uint32_t calcEFlagsV3() const;
27 uint32_t calcEFlagsV4() const;
28 uint32_t calcEFlagsV6() const;
29
30public:
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
42AMDGPU::AMDGPU() {
43 relativeRel = R_AMDGPU_RELATIVE64;
44 gotRel = R_AMDGPU_ABS64;
45 symbolicRel = R_AMDGPU_ABS64;
46}
47
48static uint32_t getEFlags(InputFile *file) {
49 return cast<ObjFile<ELF64LE>>(Val: file)->getObj().getHeader().e_flags;
50}
51
52uint32_t AMDGPU::calcEFlagsV3() const {
53 uint32_t ret = getEFlags(file: ctx.objectFiles[0]);
54
55 // Verify that all input files have the same e_flags.
56 for (InputFile *f : ArrayRef(ctx.objectFiles).slice(N: 1)) {
57 if (ret == getEFlags(file: f))
58 continue;
59 error(msg: "incompatible e_flags: " + toString(f));
60 return 0;
61 }
62 return ret;
63}
64
65uint32_t AMDGPU::calcEFlagsV4() const {
66 uint32_t retMach = getEFlags(file: ctx.objectFiles[0]) & EF_AMDGPU_MACH;
67 uint32_t retXnack =
68 getEFlags(file: ctx.objectFiles[0]) & EF_AMDGPU_FEATURE_XNACK_V4;
69 uint32_t retSramEcc =
70 getEFlags(file: 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(N: 1)) {
75 if (retMach != (getEFlags(file: f) & EF_AMDGPU_MACH)) {
76 error(msg: "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(file: f) & EF_AMDGPU_FEATURE_XNACK_V4)
83 != EF_AMDGPU_FEATURE_XNACK_ANY_V4)) {
84 if (retXnack != (getEFlags(file: f) & EF_AMDGPU_FEATURE_XNACK_V4)) {
85 error(msg: "incompatible xnack: " + toString(f));
86 return 0;
87 }
88 } else {
89 if (retXnack == EF_AMDGPU_FEATURE_XNACK_ANY_V4)
90 retXnack = getEFlags(file: 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(file: f) & EF_AMDGPU_FEATURE_SRAMECC_V4) !=
96 EF_AMDGPU_FEATURE_SRAMECC_ANY_V4)) {
97 if (retSramEcc != (getEFlags(file: f) & EF_AMDGPU_FEATURE_SRAMECC_V4)) {
98 error(msg: "incompatible sramecc: " + toString(f));
99 return 0;
100 }
101 } else {
102 if (retSramEcc == EF_AMDGPU_FEATURE_SRAMECC_ANY_V4)
103 retSramEcc = getEFlags(file: f) & EF_AMDGPU_FEATURE_SRAMECC_V4;
104 }
105 }
106
107 return retMach | retXnack | retSramEcc;
108}
109
110uint32_t AMDGPU::calcEFlagsV6() const {
111 uint32_t flags = calcEFlagsV4();
112
113 uint32_t genericVersion =
114 getEFlags(file: 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(N: 1)) {
118 if (genericVersion != (getEFlags(file: f) & EF_AMDGPU_GENERIC_VERSION)) {
119 error(msg: "incompatible generic version: " + toString(f));
120 return 0;
121 }
122 }
123
124 flags |= genericVersion;
125 return flags;
126}
127
128uint32_t AMDGPU::calcEFlags() const {
129 if (ctx.objectFiles.empty())
130 return 0;
131
132 uint8_t abiVersion = cast<ObjFile<ELF64LE>>(Val: 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(msg: "unknown abi version: " + Twine(abiVersion));
147 return 0;
148 }
149}
150
151void 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(P: loc, V: val);
159 break;
160 case R_AMDGPU_ABS64:
161 case R_AMDGPU_REL64:
162 write64le(P: loc, V: val);
163 break;
164 case R_AMDGPU_GOTPCREL32_HI:
165 case R_AMDGPU_REL32_HI:
166 write32le(P: loc, V: val >> 32);
167 break;
168 case R_AMDGPU_REL16: {
169 int64_t simm = (static_cast<int64_t>(val) - 4) / 4;
170 checkInt(loc, v: simm, n: 16, rel);
171 write16le(P: loc, V: simm);
172 break;
173 }
174 default:
175 llvm_unreachable("unknown relocation");
176 }
177}
178
179RelExpr 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(msg: getErrorLocation(loc) + "unknown relocation (" + Twine(type) +
197 ") against symbol " + toString(s));
198 return R_NONE;
199 }
200}
201
202RelType AMDGPU::getDynRel(RelType type) const {
203 if (type == R_AMDGPU_ABS64)
204 return type;
205 return R_AMDGPU_NONE;
206}
207
208int64_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(p: buf);
215 default:
216 internalLinkerError(loc: getErrorLocation(loc: buf),
217 msg: "cannot read addend for relocation " + toString(type));
218 return 0;
219 }
220}
221
222TargetInfo *elf::getAMDGPUTargetInfo() {
223 static AMDGPU target;
224 return &target;
225}
226