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 : ArrayRef(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 : ArrayRef(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 ⌖ 189 } 190