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 
40 AMDGPU::AMDGPU() {
41   relativeRel = R_AMDGPU_RELATIVE64;
42   gotRel = R_AMDGPU_ABS64;
43   symbolicRel = R_AMDGPU_ABS64;
44 }
45 
46 static uint32_t getEFlags(InputFile *file) {
47   return cast<ObjFile<ELF64LE>>(file)->getObj().getHeader().e_flags;
48 }
49 
50 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 : makeArrayRef(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 
63 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 : makeArrayRef(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 
108 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 
129 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 
157 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 
180 RelType AMDGPU::getDynRel(RelType type) const {
181   if (type == R_AMDGPU_ABS64)
182     return type;
183   return R_AMDGPU_NONE;
184 }
185 
186 TargetInfo *elf::getAMDGPUTargetInfo() {
187   static AMDGPU target;
188   return &target;
189 }
190