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 "Symbols.h" 10 #include "Target.h" 11 #include "lld/Common/ErrorHandler.h" 12 #include "llvm/BinaryFormat/ELF.h" 13 #include "llvm/Support/Endian.h" 14 15 using namespace llvm; 16 using namespace llvm::object; 17 using namespace llvm::support::endian; 18 using namespace llvm::ELF; 19 using namespace lld; 20 using namespace lld::elf; 21 22 namespace { 23 class AMDGPU final : public TargetInfo { 24 private: 25 uint32_t calcEFlagsV3() const; 26 uint32_t calcEFlagsV4() const; 27 28 public: 29 AMDGPU(); 30 uint32_t calcEFlags() const override; 31 void relocate(uint8_t *loc, const Relocation &rel, 32 uint64_t val) const override; 33 RelExpr getRelExpr(RelType type, const Symbol &s, 34 const uint8_t *loc) const override; 35 RelType getDynRel(RelType type) const override; 36 }; 37 } // namespace 38 39 AMDGPU::AMDGPU() { 40 relativeRel = R_AMDGPU_RELATIVE64; 41 gotRel = R_AMDGPU_ABS64; 42 symbolicRel = R_AMDGPU_ABS64; 43 } 44 45 static uint32_t getEFlags(InputFile *file) { 46 return cast<ObjFile<ELF64LE>>(file)->getObj().getHeader().e_flags; 47 } 48 49 uint32_t AMDGPU::calcEFlagsV3() const { 50 uint32_t ret = getEFlags(objectFiles[0]); 51 52 // Verify that all input files have the same e_flags. 53 for (InputFile *f : makeArrayRef(objectFiles).slice(1)) { 54 if (ret == getEFlags(f)) 55 continue; 56 error("incompatible e_flags: " + toString(f)); 57 return 0; 58 } 59 return ret; 60 } 61 62 uint32_t AMDGPU::calcEFlagsV4() const { 63 uint32_t retMach = getEFlags(objectFiles[0]) & EF_AMDGPU_MACH; 64 uint32_t retXnack = getEFlags(objectFiles[0]) & EF_AMDGPU_FEATURE_XNACK_V4; 65 uint32_t retSramEcc = 66 getEFlags(objectFiles[0]) & EF_AMDGPU_FEATURE_SRAMECC_V4; 67 68 // Verify that all input files have compatible e_flags (same mach, all 69 // features in the same category are either ANY, ANY and ON, or ANY and OFF). 70 for (InputFile *f : makeArrayRef(objectFiles).slice(1)) { 71 if (retMach != (getEFlags(f) & EF_AMDGPU_MACH)) { 72 error("incompatible mach: " + toString(f)); 73 return 0; 74 } 75 76 if (retXnack == EF_AMDGPU_FEATURE_XNACK_UNSUPPORTED_V4 || 77 (retXnack != EF_AMDGPU_FEATURE_XNACK_ANY_V4 && 78 (getEFlags(f) & EF_AMDGPU_FEATURE_XNACK_V4) 79 != EF_AMDGPU_FEATURE_XNACK_ANY_V4)) { 80 if (retXnack != (getEFlags(f) & EF_AMDGPU_FEATURE_XNACK_V4)) { 81 error("incompatible xnack: " + toString(f)); 82 return 0; 83 } 84 } else { 85 if (retXnack == EF_AMDGPU_FEATURE_XNACK_ANY_V4) 86 retXnack = getEFlags(f) & EF_AMDGPU_FEATURE_XNACK_V4; 87 } 88 89 if (retSramEcc == EF_AMDGPU_FEATURE_SRAMECC_UNSUPPORTED_V4 || 90 (retSramEcc != EF_AMDGPU_FEATURE_SRAMECC_ANY_V4 && 91 (getEFlags(f) & EF_AMDGPU_FEATURE_SRAMECC_V4) != 92 EF_AMDGPU_FEATURE_SRAMECC_ANY_V4)) { 93 if (retSramEcc != (getEFlags(f) & EF_AMDGPU_FEATURE_SRAMECC_V4)) { 94 error("incompatible sramecc: " + toString(f)); 95 return 0; 96 } 97 } else { 98 if (retSramEcc == EF_AMDGPU_FEATURE_SRAMECC_ANY_V4) 99 retSramEcc = getEFlags(f) & EF_AMDGPU_FEATURE_SRAMECC_V4; 100 } 101 } 102 103 return retMach | retXnack | retSramEcc; 104 } 105 106 uint32_t AMDGPU::calcEFlags() const { 107 assert(!objectFiles.empty()); 108 109 uint8_t abiVersion = cast<ObjFile<ELF64LE>>(objectFiles[0])->getObj() 110 .getHeader().e_ident[EI_ABIVERSION]; 111 switch (abiVersion) { 112 case ELFABIVERSION_AMDGPU_HSA_V2: 113 case ELFABIVERSION_AMDGPU_HSA_V3: 114 return calcEFlagsV3(); 115 case ELFABIVERSION_AMDGPU_HSA_V4: 116 return calcEFlagsV4(); 117 default: 118 error("unknown abi version: " + Twine(abiVersion)); 119 return 0; 120 } 121 } 122 123 void AMDGPU::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const { 124 switch (rel.type) { 125 case R_AMDGPU_ABS32: 126 case R_AMDGPU_GOTPCREL: 127 case R_AMDGPU_GOTPCREL32_LO: 128 case R_AMDGPU_REL32: 129 case R_AMDGPU_REL32_LO: 130 write32le(loc, val); 131 break; 132 case R_AMDGPU_ABS64: 133 case R_AMDGPU_REL64: 134 write64le(loc, val); 135 break; 136 case R_AMDGPU_GOTPCREL32_HI: 137 case R_AMDGPU_REL32_HI: 138 write32le(loc, val >> 32); 139 break; 140 case R_AMDGPU_REL16: { 141 int64_t simm = (static_cast<int64_t>(val) - 4) / 4; 142 checkInt(loc, simm, 16, rel); 143 write16le(loc, simm); 144 break; 145 } 146 default: 147 llvm_unreachable("unknown relocation"); 148 } 149 } 150 151 RelExpr AMDGPU::getRelExpr(RelType type, const Symbol &s, 152 const uint8_t *loc) const { 153 switch (type) { 154 case R_AMDGPU_ABS32: 155 case R_AMDGPU_ABS64: 156 return R_ABS; 157 case R_AMDGPU_REL32: 158 case R_AMDGPU_REL32_LO: 159 case R_AMDGPU_REL32_HI: 160 case R_AMDGPU_REL64: 161 case R_AMDGPU_REL16: 162 return R_PC; 163 case R_AMDGPU_GOTPCREL: 164 case R_AMDGPU_GOTPCREL32_LO: 165 case R_AMDGPU_GOTPCREL32_HI: 166 return R_GOT_PC; 167 default: 168 error(getErrorLocation(loc) + "unknown relocation (" + Twine(type) + 169 ") against symbol " + toString(s)); 170 return R_NONE; 171 } 172 } 173 174 RelType AMDGPU::getDynRel(RelType type) const { 175 if (type == R_AMDGPU_ABS64) 176 return type; 177 return R_AMDGPU_NONE; 178 } 179 180 TargetInfo *elf::getAMDGPUTargetInfo() { 181 static AMDGPU target; 182 return ⌖ 183 } 184