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;
28fe6060f1SDimitry Andric 
290b57cec5SDimitry Andric public:
300b57cec5SDimitry Andric   AMDGPU();
310b57cec5SDimitry Andric   uint32_t calcEFlags() const override;
325ffd83dbSDimitry Andric   void relocate(uint8_t *loc, const Relocation &rel,
335ffd83dbSDimitry Andric                 uint64_t val) const override;
340b57cec5SDimitry Andric   RelExpr getRelExpr(RelType type, const Symbol &s,
350b57cec5SDimitry Andric                      const uint8_t *loc) const override;
360b57cec5SDimitry Andric   RelType getDynRel(RelType type) const override;
375f757f3fSDimitry Andric   int64_t getImplicitAddend(const uint8_t *buf, RelType type) const override;
380b57cec5SDimitry Andric };
390b57cec5SDimitry Andric } // namespace
400b57cec5SDimitry Andric 
AMDGPU()410b57cec5SDimitry Andric AMDGPU::AMDGPU() {
420b57cec5SDimitry Andric   relativeRel = R_AMDGPU_RELATIVE64;
430b57cec5SDimitry Andric   gotRel = R_AMDGPU_ABS64;
440b57cec5SDimitry Andric   symbolicRel = R_AMDGPU_ABS64;
450b57cec5SDimitry Andric }
460b57cec5SDimitry Andric 
getEFlags(InputFile * file)470b57cec5SDimitry Andric static uint32_t getEFlags(InputFile *file) {
48e8d8bef9SDimitry Andric   return cast<ObjFile<ELF64LE>>(file)->getObj().getHeader().e_flags;
490b57cec5SDimitry Andric }
500b57cec5SDimitry Andric 
calcEFlagsV3() const51fe6060f1SDimitry Andric uint32_t AMDGPU::calcEFlagsV3() const {
52bdd1243dSDimitry Andric   uint32_t ret = getEFlags(ctx.objectFiles[0]);
530b57cec5SDimitry Andric 
540b57cec5SDimitry Andric   // Verify that all input files have the same e_flags.
55bdd1243dSDimitry Andric   for (InputFile *f : ArrayRef(ctx.objectFiles).slice(1)) {
560b57cec5SDimitry Andric     if (ret == getEFlags(f))
570b57cec5SDimitry Andric       continue;
580b57cec5SDimitry Andric     error("incompatible e_flags: " + toString(f));
590b57cec5SDimitry Andric     return 0;
600b57cec5SDimitry Andric   }
610b57cec5SDimitry Andric   return ret;
620b57cec5SDimitry Andric }
630b57cec5SDimitry Andric 
calcEFlagsV4() const64fe6060f1SDimitry Andric uint32_t AMDGPU::calcEFlagsV4() const {
65bdd1243dSDimitry Andric   uint32_t retMach = getEFlags(ctx.objectFiles[0]) & EF_AMDGPU_MACH;
6681ad6265SDimitry Andric   uint32_t retXnack =
67bdd1243dSDimitry Andric       getEFlags(ctx.objectFiles[0]) & EF_AMDGPU_FEATURE_XNACK_V4;
68fe6060f1SDimitry Andric   uint32_t retSramEcc =
69bdd1243dSDimitry Andric       getEFlags(ctx.objectFiles[0]) & EF_AMDGPU_FEATURE_SRAMECC_V4;
70fe6060f1SDimitry Andric 
71fe6060f1SDimitry Andric   // Verify that all input files have compatible e_flags (same mach, all
72fe6060f1SDimitry Andric   // features in the same category are either ANY, ANY and ON, or ANY and OFF).
73bdd1243dSDimitry Andric   for (InputFile *f : ArrayRef(ctx.objectFiles).slice(1)) {
74fe6060f1SDimitry Andric     if (retMach != (getEFlags(f) & EF_AMDGPU_MACH)) {
75fe6060f1SDimitry Andric       error("incompatible mach: " + toString(f));
76fe6060f1SDimitry Andric       return 0;
77fe6060f1SDimitry Andric     }
78fe6060f1SDimitry Andric 
79fe6060f1SDimitry Andric     if (retXnack == EF_AMDGPU_FEATURE_XNACK_UNSUPPORTED_V4 ||
80fe6060f1SDimitry Andric         (retXnack != EF_AMDGPU_FEATURE_XNACK_ANY_V4 &&
81fe6060f1SDimitry Andric             (getEFlags(f) & EF_AMDGPU_FEATURE_XNACK_V4)
82fe6060f1SDimitry Andric                 != EF_AMDGPU_FEATURE_XNACK_ANY_V4)) {
83fe6060f1SDimitry Andric       if (retXnack != (getEFlags(f) & EF_AMDGPU_FEATURE_XNACK_V4)) {
84fe6060f1SDimitry Andric         error("incompatible xnack: " + toString(f));
85fe6060f1SDimitry Andric         return 0;
86fe6060f1SDimitry Andric       }
87fe6060f1SDimitry Andric     } else {
88fe6060f1SDimitry Andric       if (retXnack == EF_AMDGPU_FEATURE_XNACK_ANY_V4)
89fe6060f1SDimitry Andric         retXnack = getEFlags(f) & EF_AMDGPU_FEATURE_XNACK_V4;
90fe6060f1SDimitry Andric     }
91fe6060f1SDimitry Andric 
92fe6060f1SDimitry Andric     if (retSramEcc == EF_AMDGPU_FEATURE_SRAMECC_UNSUPPORTED_V4 ||
93fe6060f1SDimitry Andric         (retSramEcc != EF_AMDGPU_FEATURE_SRAMECC_ANY_V4 &&
94fe6060f1SDimitry Andric             (getEFlags(f) & EF_AMDGPU_FEATURE_SRAMECC_V4) !=
95fe6060f1SDimitry Andric                 EF_AMDGPU_FEATURE_SRAMECC_ANY_V4)) {
96fe6060f1SDimitry Andric       if (retSramEcc != (getEFlags(f) & EF_AMDGPU_FEATURE_SRAMECC_V4)) {
97fe6060f1SDimitry Andric         error("incompatible sramecc: " + toString(f));
98fe6060f1SDimitry Andric         return 0;
99fe6060f1SDimitry Andric       }
100fe6060f1SDimitry Andric     } else {
101fe6060f1SDimitry Andric       if (retSramEcc == EF_AMDGPU_FEATURE_SRAMECC_ANY_V4)
102fe6060f1SDimitry Andric         retSramEcc = getEFlags(f) & EF_AMDGPU_FEATURE_SRAMECC_V4;
103fe6060f1SDimitry Andric     }
104fe6060f1SDimitry Andric   }
105fe6060f1SDimitry Andric 
106fe6060f1SDimitry Andric   return retMach | retXnack | retSramEcc;
107fe6060f1SDimitry Andric }
108fe6060f1SDimitry Andric 
calcEFlags() const109fe6060f1SDimitry Andric uint32_t AMDGPU::calcEFlags() const {
110bdd1243dSDimitry Andric   if (ctx.objectFiles.empty())
11181ad6265SDimitry Andric     return 0;
112fe6060f1SDimitry Andric 
113bdd1243dSDimitry Andric   uint8_t abiVersion = cast<ObjFile<ELF64LE>>(ctx.objectFiles[0])
11481ad6265SDimitry Andric                            ->getObj()
11581ad6265SDimitry Andric                            .getHeader()
11681ad6265SDimitry Andric                            .e_ident[EI_ABIVERSION];
117fe6060f1SDimitry Andric   switch (abiVersion) {
118fe6060f1SDimitry Andric   case ELFABIVERSION_AMDGPU_HSA_V2:
119fe6060f1SDimitry Andric   case ELFABIVERSION_AMDGPU_HSA_V3:
120fe6060f1SDimitry Andric     return calcEFlagsV3();
121fe6060f1SDimitry Andric   case ELFABIVERSION_AMDGPU_HSA_V4:
12281ad6265SDimitry Andric   case ELFABIVERSION_AMDGPU_HSA_V5:
123fe6060f1SDimitry Andric     return calcEFlagsV4();
124fe6060f1SDimitry Andric   default:
125fe6060f1SDimitry Andric     error("unknown abi version: " + Twine(abiVersion));
126fe6060f1SDimitry Andric     return 0;
127fe6060f1SDimitry Andric   }
128fe6060f1SDimitry Andric }
129fe6060f1SDimitry Andric 
relocate(uint8_t * loc,const Relocation & rel,uint64_t val) const1305ffd83dbSDimitry Andric void AMDGPU::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const {
1315ffd83dbSDimitry Andric   switch (rel.type) {
1320b57cec5SDimitry Andric   case R_AMDGPU_ABS32:
1330b57cec5SDimitry Andric   case R_AMDGPU_GOTPCREL:
1340b57cec5SDimitry Andric   case R_AMDGPU_GOTPCREL32_LO:
1350b57cec5SDimitry Andric   case R_AMDGPU_REL32:
1360b57cec5SDimitry Andric   case R_AMDGPU_REL32_LO:
1370b57cec5SDimitry Andric     write32le(loc, val);
1380b57cec5SDimitry Andric     break;
1390b57cec5SDimitry Andric   case R_AMDGPU_ABS64:
1400b57cec5SDimitry Andric   case R_AMDGPU_REL64:
1410b57cec5SDimitry Andric     write64le(loc, val);
1420b57cec5SDimitry Andric     break;
1430b57cec5SDimitry Andric   case R_AMDGPU_GOTPCREL32_HI:
1440b57cec5SDimitry Andric   case R_AMDGPU_REL32_HI:
1450b57cec5SDimitry Andric     write32le(loc, val >> 32);
1460b57cec5SDimitry Andric     break;
147fe6060f1SDimitry Andric   case R_AMDGPU_REL16: {
148fe6060f1SDimitry Andric     int64_t simm = (static_cast<int64_t>(val) - 4) / 4;
149fe6060f1SDimitry Andric     checkInt(loc, simm, 16, rel);
150fe6060f1SDimitry Andric     write16le(loc, simm);
151fe6060f1SDimitry Andric     break;
152fe6060f1SDimitry Andric   }
1530b57cec5SDimitry Andric   default:
1540b57cec5SDimitry Andric     llvm_unreachable("unknown relocation");
1550b57cec5SDimitry Andric   }
1560b57cec5SDimitry Andric }
1570b57cec5SDimitry Andric 
getRelExpr(RelType type,const Symbol & s,const uint8_t * loc) const1580b57cec5SDimitry Andric RelExpr AMDGPU::getRelExpr(RelType type, const Symbol &s,
1590b57cec5SDimitry Andric                            const uint8_t *loc) const {
1600b57cec5SDimitry Andric   switch (type) {
1610b57cec5SDimitry Andric   case R_AMDGPU_ABS32:
1620b57cec5SDimitry Andric   case R_AMDGPU_ABS64:
1630b57cec5SDimitry Andric     return R_ABS;
1640b57cec5SDimitry Andric   case R_AMDGPU_REL32:
1650b57cec5SDimitry Andric   case R_AMDGPU_REL32_LO:
1660b57cec5SDimitry Andric   case R_AMDGPU_REL32_HI:
1670b57cec5SDimitry Andric   case R_AMDGPU_REL64:
168fe6060f1SDimitry Andric   case R_AMDGPU_REL16:
1690b57cec5SDimitry Andric     return R_PC;
1700b57cec5SDimitry Andric   case R_AMDGPU_GOTPCREL:
1710b57cec5SDimitry Andric   case R_AMDGPU_GOTPCREL32_LO:
1720b57cec5SDimitry Andric   case R_AMDGPU_GOTPCREL32_HI:
1730b57cec5SDimitry Andric     return R_GOT_PC;
1740b57cec5SDimitry Andric   default:
1750b57cec5SDimitry Andric     error(getErrorLocation(loc) + "unknown relocation (" + Twine(type) +
1760b57cec5SDimitry Andric           ") against symbol " + toString(s));
1770b57cec5SDimitry Andric     return R_NONE;
1780b57cec5SDimitry Andric   }
1790b57cec5SDimitry Andric }
1800b57cec5SDimitry Andric 
getDynRel(RelType type) const1810b57cec5SDimitry Andric RelType AMDGPU::getDynRel(RelType type) const {
1820b57cec5SDimitry Andric   if (type == R_AMDGPU_ABS64)
1830b57cec5SDimitry Andric     return type;
1840b57cec5SDimitry Andric   return R_AMDGPU_NONE;
1850b57cec5SDimitry Andric }
1860b57cec5SDimitry Andric 
getImplicitAddend(const uint8_t * buf,RelType type) const1875f757f3fSDimitry Andric int64_t AMDGPU::getImplicitAddend(const uint8_t *buf, RelType type) const {
1885f757f3fSDimitry Andric   switch (type) {
1895f757f3fSDimitry Andric   case R_AMDGPU_NONE:
1905f757f3fSDimitry Andric     return 0;
1915f757f3fSDimitry Andric   case R_AMDGPU_ABS64:
1925f757f3fSDimitry Andric   case R_AMDGPU_RELATIVE64:
1935f757f3fSDimitry Andric     return read64(buf);
1945f757f3fSDimitry Andric   default:
1955f757f3fSDimitry Andric     internalLinkerError(getErrorLocation(buf),
1965f757f3fSDimitry Andric                         "cannot read addend for relocation " + toString(type));
1975f757f3fSDimitry Andric     return 0;
1985f757f3fSDimitry Andric   }
1995f757f3fSDimitry Andric }
2005f757f3fSDimitry Andric 
getAMDGPUTargetInfo()2015ffd83dbSDimitry Andric TargetInfo *elf::getAMDGPUTargetInfo() {
2020b57cec5SDimitry Andric   static AMDGPU target;
2030b57cec5SDimitry Andric   return &target;
2040b57cec5SDimitry Andric }
205