1ece8a530Spatrick //===- AMDGPU.cpp ---------------------------------------------------------===//
2ece8a530Spatrick //
3ece8a530Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4ece8a530Spatrick // See https://llvm.org/LICENSE.txt for license information.
5ece8a530Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6ece8a530Spatrick //
7ece8a530Spatrick //===----------------------------------------------------------------------===//
8ece8a530Spatrick
9ece8a530Spatrick #include "InputFiles.h"
10ece8a530Spatrick #include "Symbols.h"
11ece8a530Spatrick #include "Target.h"
12ece8a530Spatrick #include "lld/Common/ErrorHandler.h"
13*dfe94b16Srobert #include "llvm/BinaryFormat/ELF.h"
14ece8a530Spatrick #include "llvm/Support/Endian.h"
15ece8a530Spatrick
16ece8a530Spatrick using namespace llvm;
17ece8a530Spatrick using namespace llvm::object;
18ece8a530Spatrick using namespace llvm::support::endian;
19ece8a530Spatrick using namespace llvm::ELF;
20bb684c34Spatrick using namespace lld;
21bb684c34Spatrick using namespace lld::elf;
22ece8a530Spatrick
23ece8a530Spatrick namespace {
24ece8a530Spatrick class AMDGPU final : public TargetInfo {
251cf9926bSpatrick private:
261cf9926bSpatrick uint32_t calcEFlagsV3() const;
271cf9926bSpatrick uint32_t calcEFlagsV4() const;
281cf9926bSpatrick
29ece8a530Spatrick public:
30ece8a530Spatrick AMDGPU();
31ece8a530Spatrick uint32_t calcEFlags() const override;
32bb684c34Spatrick void relocate(uint8_t *loc, const Relocation &rel,
33bb684c34Spatrick uint64_t val) const override;
34ece8a530Spatrick RelExpr getRelExpr(RelType type, const Symbol &s,
35ece8a530Spatrick const uint8_t *loc) const override;
36ece8a530Spatrick RelType getDynRel(RelType type) const override;
37ece8a530Spatrick };
38ece8a530Spatrick } // namespace
39ece8a530Spatrick
AMDGPU()40ece8a530Spatrick AMDGPU::AMDGPU() {
41ece8a530Spatrick relativeRel = R_AMDGPU_RELATIVE64;
42ece8a530Spatrick gotRel = R_AMDGPU_ABS64;
43ece8a530Spatrick symbolicRel = R_AMDGPU_ABS64;
44ece8a530Spatrick }
45ece8a530Spatrick
getEFlags(InputFile * file)46ece8a530Spatrick static uint32_t getEFlags(InputFile *file) {
471cf9926bSpatrick return cast<ObjFile<ELF64LE>>(file)->getObj().getHeader().e_flags;
48ece8a530Spatrick }
49ece8a530Spatrick
calcEFlagsV3() const501cf9926bSpatrick uint32_t AMDGPU::calcEFlagsV3() const {
51*dfe94b16Srobert uint32_t ret = getEFlags(ctx.objectFiles[0]);
52ece8a530Spatrick
53ece8a530Spatrick // Verify that all input files have the same e_flags.
54*dfe94b16Srobert for (InputFile *f : ArrayRef(ctx.objectFiles).slice(1)) {
55ece8a530Spatrick if (ret == getEFlags(f))
56ece8a530Spatrick continue;
57ece8a530Spatrick error("incompatible e_flags: " + toString(f));
58ece8a530Spatrick return 0;
59ece8a530Spatrick }
60ece8a530Spatrick return ret;
61ece8a530Spatrick }
62ece8a530Spatrick
calcEFlagsV4() const631cf9926bSpatrick uint32_t AMDGPU::calcEFlagsV4() const {
64*dfe94b16Srobert uint32_t retMach = getEFlags(ctx.objectFiles[0]) & EF_AMDGPU_MACH;
65*dfe94b16Srobert uint32_t retXnack =
66*dfe94b16Srobert getEFlags(ctx.objectFiles[0]) & EF_AMDGPU_FEATURE_XNACK_V4;
671cf9926bSpatrick uint32_t retSramEcc =
68*dfe94b16Srobert getEFlags(ctx.objectFiles[0]) & EF_AMDGPU_FEATURE_SRAMECC_V4;
691cf9926bSpatrick
701cf9926bSpatrick // Verify that all input files have compatible e_flags (same mach, all
711cf9926bSpatrick // features in the same category are either ANY, ANY and ON, or ANY and OFF).
72*dfe94b16Srobert for (InputFile *f : ArrayRef(ctx.objectFiles).slice(1)) {
731cf9926bSpatrick if (retMach != (getEFlags(f) & EF_AMDGPU_MACH)) {
741cf9926bSpatrick error("incompatible mach: " + toString(f));
751cf9926bSpatrick return 0;
761cf9926bSpatrick }
771cf9926bSpatrick
781cf9926bSpatrick if (retXnack == EF_AMDGPU_FEATURE_XNACK_UNSUPPORTED_V4 ||
791cf9926bSpatrick (retXnack != EF_AMDGPU_FEATURE_XNACK_ANY_V4 &&
801cf9926bSpatrick (getEFlags(f) & EF_AMDGPU_FEATURE_XNACK_V4)
811cf9926bSpatrick != EF_AMDGPU_FEATURE_XNACK_ANY_V4)) {
821cf9926bSpatrick if (retXnack != (getEFlags(f) & EF_AMDGPU_FEATURE_XNACK_V4)) {
831cf9926bSpatrick error("incompatible xnack: " + toString(f));
841cf9926bSpatrick return 0;
851cf9926bSpatrick }
861cf9926bSpatrick } else {
871cf9926bSpatrick if (retXnack == EF_AMDGPU_FEATURE_XNACK_ANY_V4)
881cf9926bSpatrick retXnack = getEFlags(f) & EF_AMDGPU_FEATURE_XNACK_V4;
891cf9926bSpatrick }
901cf9926bSpatrick
911cf9926bSpatrick if (retSramEcc == EF_AMDGPU_FEATURE_SRAMECC_UNSUPPORTED_V4 ||
921cf9926bSpatrick (retSramEcc != EF_AMDGPU_FEATURE_SRAMECC_ANY_V4 &&
931cf9926bSpatrick (getEFlags(f) & EF_AMDGPU_FEATURE_SRAMECC_V4) !=
941cf9926bSpatrick EF_AMDGPU_FEATURE_SRAMECC_ANY_V4)) {
951cf9926bSpatrick if (retSramEcc != (getEFlags(f) & EF_AMDGPU_FEATURE_SRAMECC_V4)) {
961cf9926bSpatrick error("incompatible sramecc: " + toString(f));
971cf9926bSpatrick return 0;
981cf9926bSpatrick }
991cf9926bSpatrick } else {
1001cf9926bSpatrick if (retSramEcc == EF_AMDGPU_FEATURE_SRAMECC_ANY_V4)
1011cf9926bSpatrick retSramEcc = getEFlags(f) & EF_AMDGPU_FEATURE_SRAMECC_V4;
1021cf9926bSpatrick }
1031cf9926bSpatrick }
1041cf9926bSpatrick
1051cf9926bSpatrick return retMach | retXnack | retSramEcc;
1061cf9926bSpatrick }
1071cf9926bSpatrick
calcEFlags() const1081cf9926bSpatrick uint32_t AMDGPU::calcEFlags() const {
109*dfe94b16Srobert if (ctx.objectFiles.empty())
110*dfe94b16Srobert return 0;
1111cf9926bSpatrick
112*dfe94b16Srobert uint8_t abiVersion = cast<ObjFile<ELF64LE>>(ctx.objectFiles[0])
113*dfe94b16Srobert ->getObj()
114*dfe94b16Srobert .getHeader()
115*dfe94b16Srobert .e_ident[EI_ABIVERSION];
1161cf9926bSpatrick switch (abiVersion) {
1171cf9926bSpatrick case ELFABIVERSION_AMDGPU_HSA_V2:
1181cf9926bSpatrick case ELFABIVERSION_AMDGPU_HSA_V3:
1191cf9926bSpatrick return calcEFlagsV3();
1201cf9926bSpatrick case ELFABIVERSION_AMDGPU_HSA_V4:
121*dfe94b16Srobert case ELFABIVERSION_AMDGPU_HSA_V5:
1221cf9926bSpatrick return calcEFlagsV4();
1231cf9926bSpatrick default:
1241cf9926bSpatrick error("unknown abi version: " + Twine(abiVersion));
1251cf9926bSpatrick return 0;
1261cf9926bSpatrick }
1271cf9926bSpatrick }
1281cf9926bSpatrick
relocate(uint8_t * loc,const Relocation & rel,uint64_t val) const129bb684c34Spatrick void AMDGPU::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const {
130bb684c34Spatrick switch (rel.type) {
131ece8a530Spatrick case R_AMDGPU_ABS32:
132ece8a530Spatrick case R_AMDGPU_GOTPCREL:
133ece8a530Spatrick case R_AMDGPU_GOTPCREL32_LO:
134ece8a530Spatrick case R_AMDGPU_REL32:
135ece8a530Spatrick case R_AMDGPU_REL32_LO:
136ece8a530Spatrick write32le(loc, val);
137ece8a530Spatrick break;
138ece8a530Spatrick case R_AMDGPU_ABS64:
139ece8a530Spatrick case R_AMDGPU_REL64:
140ece8a530Spatrick write64le(loc, val);
141ece8a530Spatrick break;
142ece8a530Spatrick case R_AMDGPU_GOTPCREL32_HI:
143ece8a530Spatrick case R_AMDGPU_REL32_HI:
144ece8a530Spatrick write32le(loc, val >> 32);
145ece8a530Spatrick break;
1461cf9926bSpatrick case R_AMDGPU_REL16: {
1471cf9926bSpatrick int64_t simm = (static_cast<int64_t>(val) - 4) / 4;
1481cf9926bSpatrick checkInt(loc, simm, 16, rel);
1491cf9926bSpatrick write16le(loc, simm);
1501cf9926bSpatrick break;
1511cf9926bSpatrick }
152ece8a530Spatrick default:
153ece8a530Spatrick llvm_unreachable("unknown relocation");
154ece8a530Spatrick }
155ece8a530Spatrick }
156ece8a530Spatrick
getRelExpr(RelType type,const Symbol & s,const uint8_t * loc) const157ece8a530Spatrick RelExpr AMDGPU::getRelExpr(RelType type, const Symbol &s,
158ece8a530Spatrick const uint8_t *loc) const {
159ece8a530Spatrick switch (type) {
160ece8a530Spatrick case R_AMDGPU_ABS32:
161ece8a530Spatrick case R_AMDGPU_ABS64:
162ece8a530Spatrick return R_ABS;
163ece8a530Spatrick case R_AMDGPU_REL32:
164ece8a530Spatrick case R_AMDGPU_REL32_LO:
165ece8a530Spatrick case R_AMDGPU_REL32_HI:
166ece8a530Spatrick case R_AMDGPU_REL64:
1671cf9926bSpatrick case R_AMDGPU_REL16:
168ece8a530Spatrick return R_PC;
169ece8a530Spatrick case R_AMDGPU_GOTPCREL:
170ece8a530Spatrick case R_AMDGPU_GOTPCREL32_LO:
171ece8a530Spatrick case R_AMDGPU_GOTPCREL32_HI:
172ece8a530Spatrick return R_GOT_PC;
173ece8a530Spatrick default:
174ece8a530Spatrick error(getErrorLocation(loc) + "unknown relocation (" + Twine(type) +
175ece8a530Spatrick ") against symbol " + toString(s));
176ece8a530Spatrick return R_NONE;
177ece8a530Spatrick }
178ece8a530Spatrick }
179ece8a530Spatrick
getDynRel(RelType type) const180ece8a530Spatrick RelType AMDGPU::getDynRel(RelType type) const {
181ece8a530Spatrick if (type == R_AMDGPU_ABS64)
182ece8a530Spatrick return type;
183ece8a530Spatrick return R_AMDGPU_NONE;
184ece8a530Spatrick }
185ece8a530Spatrick
getAMDGPUTargetInfo()186bb684c34Spatrick TargetInfo *elf::getAMDGPUTargetInfo() {
187ece8a530Spatrick static AMDGPU target;
188ece8a530Spatrick return ⌖
189ece8a530Spatrick }
190