10b57cec5SDimitry Andric //===- AMDGPU.cpp ---------------------------------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric
90b57cec5SDimitry Andric #include "InputFiles.h"
100b57cec5SDimitry Andric #include "Symbols.h"
110b57cec5SDimitry Andric #include "Target.h"
120b57cec5SDimitry Andric #include "lld/Common/ErrorHandler.h"
1381ad6265SDimitry Andric #include "llvm/BinaryFormat/ELF.h"
140b57cec5SDimitry Andric #include "llvm/Support/Endian.h"
150b57cec5SDimitry Andric
160b57cec5SDimitry Andric using namespace llvm;
170b57cec5SDimitry Andric using namespace llvm::object;
180b57cec5SDimitry Andric using namespace llvm::support::endian;
190b57cec5SDimitry Andric using namespace llvm::ELF;
205ffd83dbSDimitry Andric using namespace lld;
215ffd83dbSDimitry Andric using namespace lld::elf;
220b57cec5SDimitry Andric
230b57cec5SDimitry Andric namespace {
240b57cec5SDimitry Andric class AMDGPU final : public TargetInfo {
25fe6060f1SDimitry Andric private:
26fe6060f1SDimitry Andric uint32_t calcEFlagsV3() const;
27fe6060f1SDimitry Andric uint32_t calcEFlagsV4() const;
28*0fca6ea1SDimitry Andric uint32_t calcEFlagsV6() const;
29fe6060f1SDimitry Andric
300b57cec5SDimitry Andric public:
310b57cec5SDimitry Andric AMDGPU();
320b57cec5SDimitry Andric uint32_t calcEFlags() const override;
335ffd83dbSDimitry Andric void relocate(uint8_t *loc, const Relocation &rel,
345ffd83dbSDimitry Andric uint64_t val) const override;
350b57cec5SDimitry Andric RelExpr getRelExpr(RelType type, const Symbol &s,
360b57cec5SDimitry Andric const uint8_t *loc) const override;
370b57cec5SDimitry Andric RelType getDynRel(RelType type) const override;
385f757f3fSDimitry Andric int64_t getImplicitAddend(const uint8_t *buf, RelType type) const override;
390b57cec5SDimitry Andric };
400b57cec5SDimitry Andric } // namespace
410b57cec5SDimitry Andric
AMDGPU()420b57cec5SDimitry Andric AMDGPU::AMDGPU() {
430b57cec5SDimitry Andric relativeRel = R_AMDGPU_RELATIVE64;
440b57cec5SDimitry Andric gotRel = R_AMDGPU_ABS64;
450b57cec5SDimitry Andric symbolicRel = R_AMDGPU_ABS64;
460b57cec5SDimitry Andric }
470b57cec5SDimitry Andric
getEFlags(InputFile * file)480b57cec5SDimitry Andric static uint32_t getEFlags(InputFile *file) {
49e8d8bef9SDimitry Andric return cast<ObjFile<ELF64LE>>(file)->getObj().getHeader().e_flags;
500b57cec5SDimitry Andric }
510b57cec5SDimitry Andric
calcEFlagsV3() const52fe6060f1SDimitry Andric uint32_t AMDGPU::calcEFlagsV3() const {
53bdd1243dSDimitry Andric uint32_t ret = getEFlags(ctx.objectFiles[0]);
540b57cec5SDimitry Andric
550b57cec5SDimitry Andric // Verify that all input files have the same e_flags.
56bdd1243dSDimitry Andric for (InputFile *f : ArrayRef(ctx.objectFiles).slice(1)) {
570b57cec5SDimitry Andric if (ret == getEFlags(f))
580b57cec5SDimitry Andric continue;
590b57cec5SDimitry Andric error("incompatible e_flags: " + toString(f));
600b57cec5SDimitry Andric return 0;
610b57cec5SDimitry Andric }
620b57cec5SDimitry Andric return ret;
630b57cec5SDimitry Andric }
640b57cec5SDimitry Andric
calcEFlagsV4() const65fe6060f1SDimitry Andric uint32_t AMDGPU::calcEFlagsV4() const {
66bdd1243dSDimitry Andric uint32_t retMach = getEFlags(ctx.objectFiles[0]) & EF_AMDGPU_MACH;
6781ad6265SDimitry Andric uint32_t retXnack =
68bdd1243dSDimitry Andric getEFlags(ctx.objectFiles[0]) & EF_AMDGPU_FEATURE_XNACK_V4;
69fe6060f1SDimitry Andric uint32_t retSramEcc =
70bdd1243dSDimitry Andric getEFlags(ctx.objectFiles[0]) & EF_AMDGPU_FEATURE_SRAMECC_V4;
71fe6060f1SDimitry Andric
72fe6060f1SDimitry Andric // Verify that all input files have compatible e_flags (same mach, all
73fe6060f1SDimitry Andric // features in the same category are either ANY, ANY and ON, or ANY and OFF).
74bdd1243dSDimitry Andric for (InputFile *f : ArrayRef(ctx.objectFiles).slice(1)) {
75fe6060f1SDimitry Andric if (retMach != (getEFlags(f) & EF_AMDGPU_MACH)) {
76fe6060f1SDimitry Andric error("incompatible mach: " + toString(f));
77fe6060f1SDimitry Andric return 0;
78fe6060f1SDimitry Andric }
79fe6060f1SDimitry Andric
80fe6060f1SDimitry Andric if (retXnack == EF_AMDGPU_FEATURE_XNACK_UNSUPPORTED_V4 ||
81fe6060f1SDimitry Andric (retXnack != EF_AMDGPU_FEATURE_XNACK_ANY_V4 &&
82fe6060f1SDimitry Andric (getEFlags(f) & EF_AMDGPU_FEATURE_XNACK_V4)
83fe6060f1SDimitry Andric != EF_AMDGPU_FEATURE_XNACK_ANY_V4)) {
84fe6060f1SDimitry Andric if (retXnack != (getEFlags(f) & EF_AMDGPU_FEATURE_XNACK_V4)) {
85fe6060f1SDimitry Andric error("incompatible xnack: " + toString(f));
86fe6060f1SDimitry Andric return 0;
87fe6060f1SDimitry Andric }
88fe6060f1SDimitry Andric } else {
89fe6060f1SDimitry Andric if (retXnack == EF_AMDGPU_FEATURE_XNACK_ANY_V4)
90fe6060f1SDimitry Andric retXnack = getEFlags(f) & EF_AMDGPU_FEATURE_XNACK_V4;
91fe6060f1SDimitry Andric }
92fe6060f1SDimitry Andric
93fe6060f1SDimitry Andric if (retSramEcc == EF_AMDGPU_FEATURE_SRAMECC_UNSUPPORTED_V4 ||
94fe6060f1SDimitry Andric (retSramEcc != EF_AMDGPU_FEATURE_SRAMECC_ANY_V4 &&
95fe6060f1SDimitry Andric (getEFlags(f) & EF_AMDGPU_FEATURE_SRAMECC_V4) !=
96fe6060f1SDimitry Andric EF_AMDGPU_FEATURE_SRAMECC_ANY_V4)) {
97fe6060f1SDimitry Andric if (retSramEcc != (getEFlags(f) & EF_AMDGPU_FEATURE_SRAMECC_V4)) {
98fe6060f1SDimitry Andric error("incompatible sramecc: " + toString(f));
99fe6060f1SDimitry Andric return 0;
100fe6060f1SDimitry Andric }
101fe6060f1SDimitry Andric } else {
102fe6060f1SDimitry Andric if (retSramEcc == EF_AMDGPU_FEATURE_SRAMECC_ANY_V4)
103fe6060f1SDimitry Andric retSramEcc = getEFlags(f) & EF_AMDGPU_FEATURE_SRAMECC_V4;
104fe6060f1SDimitry Andric }
105fe6060f1SDimitry Andric }
106fe6060f1SDimitry Andric
107fe6060f1SDimitry Andric return retMach | retXnack | retSramEcc;
108fe6060f1SDimitry Andric }
109fe6060f1SDimitry Andric
calcEFlagsV6() const110*0fca6ea1SDimitry Andric uint32_t AMDGPU::calcEFlagsV6() const {
111*0fca6ea1SDimitry Andric uint32_t flags = calcEFlagsV4();
112*0fca6ea1SDimitry Andric
113*0fca6ea1SDimitry Andric uint32_t genericVersion =
114*0fca6ea1SDimitry Andric getEFlags(ctx.objectFiles[0]) & EF_AMDGPU_GENERIC_VERSION;
115*0fca6ea1SDimitry Andric
116*0fca6ea1SDimitry Andric // Verify that all input files have compatible generic version.
117*0fca6ea1SDimitry Andric for (InputFile *f : ArrayRef(ctx.objectFiles).slice(1)) {
118*0fca6ea1SDimitry Andric if (genericVersion != (getEFlags(f) & EF_AMDGPU_GENERIC_VERSION)) {
119*0fca6ea1SDimitry Andric error("incompatible generic version: " + toString(f));
120*0fca6ea1SDimitry Andric return 0;
121*0fca6ea1SDimitry Andric }
122*0fca6ea1SDimitry Andric }
123*0fca6ea1SDimitry Andric
124*0fca6ea1SDimitry Andric flags |= genericVersion;
125*0fca6ea1SDimitry Andric return flags;
126*0fca6ea1SDimitry Andric }
127*0fca6ea1SDimitry Andric
calcEFlags() const128fe6060f1SDimitry Andric uint32_t AMDGPU::calcEFlags() const {
129bdd1243dSDimitry Andric if (ctx.objectFiles.empty())
13081ad6265SDimitry Andric return 0;
131fe6060f1SDimitry Andric
132bdd1243dSDimitry Andric uint8_t abiVersion = cast<ObjFile<ELF64LE>>(ctx.objectFiles[0])
13381ad6265SDimitry Andric ->getObj()
13481ad6265SDimitry Andric .getHeader()
13581ad6265SDimitry Andric .e_ident[EI_ABIVERSION];
136fe6060f1SDimitry Andric switch (abiVersion) {
137fe6060f1SDimitry Andric case ELFABIVERSION_AMDGPU_HSA_V2:
138fe6060f1SDimitry Andric case ELFABIVERSION_AMDGPU_HSA_V3:
139fe6060f1SDimitry Andric return calcEFlagsV3();
140fe6060f1SDimitry Andric case ELFABIVERSION_AMDGPU_HSA_V4:
14181ad6265SDimitry Andric case ELFABIVERSION_AMDGPU_HSA_V5:
142fe6060f1SDimitry Andric return calcEFlagsV4();
143*0fca6ea1SDimitry Andric case ELFABIVERSION_AMDGPU_HSA_V6:
144*0fca6ea1SDimitry Andric return calcEFlagsV6();
145fe6060f1SDimitry Andric default:
146fe6060f1SDimitry Andric error("unknown abi version: " + Twine(abiVersion));
147fe6060f1SDimitry Andric return 0;
148fe6060f1SDimitry Andric }
149fe6060f1SDimitry Andric }
150fe6060f1SDimitry Andric
relocate(uint8_t * loc,const Relocation & rel,uint64_t val) const1515ffd83dbSDimitry Andric void AMDGPU::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const {
1525ffd83dbSDimitry Andric switch (rel.type) {
1530b57cec5SDimitry Andric case R_AMDGPU_ABS32:
1540b57cec5SDimitry Andric case R_AMDGPU_GOTPCREL:
1550b57cec5SDimitry Andric case R_AMDGPU_GOTPCREL32_LO:
1560b57cec5SDimitry Andric case R_AMDGPU_REL32:
1570b57cec5SDimitry Andric case R_AMDGPU_REL32_LO:
1580b57cec5SDimitry Andric write32le(loc, val);
1590b57cec5SDimitry Andric break;
1600b57cec5SDimitry Andric case R_AMDGPU_ABS64:
1610b57cec5SDimitry Andric case R_AMDGPU_REL64:
1620b57cec5SDimitry Andric write64le(loc, val);
1630b57cec5SDimitry Andric break;
1640b57cec5SDimitry Andric case R_AMDGPU_GOTPCREL32_HI:
1650b57cec5SDimitry Andric case R_AMDGPU_REL32_HI:
1660b57cec5SDimitry Andric write32le(loc, val >> 32);
1670b57cec5SDimitry Andric break;
168fe6060f1SDimitry Andric case R_AMDGPU_REL16: {
169fe6060f1SDimitry Andric int64_t simm = (static_cast<int64_t>(val) - 4) / 4;
170fe6060f1SDimitry Andric checkInt(loc, simm, 16, rel);
171fe6060f1SDimitry Andric write16le(loc, simm);
172fe6060f1SDimitry Andric break;
173fe6060f1SDimitry Andric }
1740b57cec5SDimitry Andric default:
1750b57cec5SDimitry Andric llvm_unreachable("unknown relocation");
1760b57cec5SDimitry Andric }
1770b57cec5SDimitry Andric }
1780b57cec5SDimitry Andric
getRelExpr(RelType type,const Symbol & s,const uint8_t * loc) const1790b57cec5SDimitry Andric RelExpr AMDGPU::getRelExpr(RelType type, const Symbol &s,
1800b57cec5SDimitry Andric const uint8_t *loc) const {
1810b57cec5SDimitry Andric switch (type) {
1820b57cec5SDimitry Andric case R_AMDGPU_ABS32:
1830b57cec5SDimitry Andric case R_AMDGPU_ABS64:
1840b57cec5SDimitry Andric return R_ABS;
1850b57cec5SDimitry Andric case R_AMDGPU_REL32:
1860b57cec5SDimitry Andric case R_AMDGPU_REL32_LO:
1870b57cec5SDimitry Andric case R_AMDGPU_REL32_HI:
1880b57cec5SDimitry Andric case R_AMDGPU_REL64:
189fe6060f1SDimitry Andric case R_AMDGPU_REL16:
1900b57cec5SDimitry Andric return R_PC;
1910b57cec5SDimitry Andric case R_AMDGPU_GOTPCREL:
1920b57cec5SDimitry Andric case R_AMDGPU_GOTPCREL32_LO:
1930b57cec5SDimitry Andric case R_AMDGPU_GOTPCREL32_HI:
1940b57cec5SDimitry Andric return R_GOT_PC;
1950b57cec5SDimitry Andric default:
1960b57cec5SDimitry Andric error(getErrorLocation(loc) + "unknown relocation (" + Twine(type) +
1970b57cec5SDimitry Andric ") against symbol " + toString(s));
1980b57cec5SDimitry Andric return R_NONE;
1990b57cec5SDimitry Andric }
2000b57cec5SDimitry Andric }
2010b57cec5SDimitry Andric
getDynRel(RelType type) const2020b57cec5SDimitry Andric RelType AMDGPU::getDynRel(RelType type) const {
2030b57cec5SDimitry Andric if (type == R_AMDGPU_ABS64)
2040b57cec5SDimitry Andric return type;
2050b57cec5SDimitry Andric return R_AMDGPU_NONE;
2060b57cec5SDimitry Andric }
2070b57cec5SDimitry Andric
getImplicitAddend(const uint8_t * buf,RelType type) const2085f757f3fSDimitry Andric int64_t AMDGPU::getImplicitAddend(const uint8_t *buf, RelType type) const {
2095f757f3fSDimitry Andric switch (type) {
2105f757f3fSDimitry Andric case R_AMDGPU_NONE:
2115f757f3fSDimitry Andric return 0;
2125f757f3fSDimitry Andric case R_AMDGPU_ABS64:
2135f757f3fSDimitry Andric case R_AMDGPU_RELATIVE64:
2145f757f3fSDimitry Andric return read64(buf);
2155f757f3fSDimitry Andric default:
2165f757f3fSDimitry Andric internalLinkerError(getErrorLocation(buf),
2175f757f3fSDimitry Andric "cannot read addend for relocation " + toString(type));
2185f757f3fSDimitry Andric return 0;
2195f757f3fSDimitry Andric }
2205f757f3fSDimitry Andric }
2215f757f3fSDimitry Andric
getAMDGPUTargetInfo()2225ffd83dbSDimitry Andric TargetInfo *elf::getAMDGPUTargetInfo() {
2230b57cec5SDimitry Andric static AMDGPU target;
2240b57cec5SDimitry Andric return ⌖
2250b57cec5SDimitry Andric }
226