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