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
29public:
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
41AMDGPU::AMDGPU() {
42  relativeRel = R_AMDGPU_RELATIVE64;
43  gotRel = R_AMDGPU_ABS64;
44  symbolicRel = R_AMDGPU_ABS64;
45}
46
47static uint32_t getEFlags(InputFile *file) {
48  return cast<ObjFile<ELF64LE>>(file)->getObj().getHeader().e_flags;
49}
50
51uint32_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
64uint32_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
109uint32_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
130void 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
158RelExpr 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
181RelType AMDGPU::getDynRel(RelType type) const {
182  if (type == R_AMDGPU_ABS64)
183    return type;
184  return R_AMDGPU_NONE;
185}
186
187int64_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
201TargetInfo *elf::getAMDGPUTargetInfo() {
202  static AMDGPU target;
203  return &target;
204}
205