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/Object/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 noneRel = R_AMDGPU_NONE; 44 symbolicRel = R_AMDGPU_ABS64; 45 } 46 47 static uint32_t getEFlags(InputFile *file) { 48 return cast<ObjFile<ELF64LE>>(file)->getObj().getHeader().e_flags; 49 } 50 51 uint32_t AMDGPU::calcEFlagsV3() const { 52 uint32_t ret = getEFlags(objectFiles[0]); 53 54 // Verify that all input files have the same e_flags. 55 for (InputFile *f : makeArrayRef(objectFiles).slice(1)) { 56 if (ret == getEFlags(f)) 57 continue; 58 error("incompatible e_flags: " + toString(f)); 59 return 0; 60 } 61 return ret; 62 } 63 64 uint32_t AMDGPU::calcEFlagsV4() const { 65 uint32_t retMach = getEFlags(objectFiles[0]) & EF_AMDGPU_MACH; 66 uint32_t retXnack = getEFlags(objectFiles[0]) & EF_AMDGPU_FEATURE_XNACK_V4; 67 uint32_t retSramEcc = 68 getEFlags(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 : makeArrayRef(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 assert(!objectFiles.empty()); 110 111 uint8_t abiVersion = cast<ObjFile<ELF64LE>>(objectFiles[0])->getObj() 112 .getHeader().e_ident[EI_ABIVERSION]; 113 switch (abiVersion) { 114 case ELFABIVERSION_AMDGPU_HSA_V2: 115 case ELFABIVERSION_AMDGPU_HSA_V3: 116 return calcEFlagsV3(); 117 case ELFABIVERSION_AMDGPU_HSA_V4: 118 return calcEFlagsV4(); 119 default: 120 error("unknown abi version: " + Twine(abiVersion)); 121 return 0; 122 } 123 } 124 125 void AMDGPU::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const { 126 switch (rel.type) { 127 case R_AMDGPU_ABS32: 128 case R_AMDGPU_GOTPCREL: 129 case R_AMDGPU_GOTPCREL32_LO: 130 case R_AMDGPU_REL32: 131 case R_AMDGPU_REL32_LO: 132 write32le(loc, val); 133 break; 134 case R_AMDGPU_ABS64: 135 case R_AMDGPU_REL64: 136 write64le(loc, val); 137 break; 138 case R_AMDGPU_GOTPCREL32_HI: 139 case R_AMDGPU_REL32_HI: 140 write32le(loc, val >> 32); 141 break; 142 case R_AMDGPU_REL16: { 143 int64_t simm = (static_cast<int64_t>(val) - 4) / 4; 144 checkInt(loc, simm, 16, rel); 145 write16le(loc, simm); 146 break; 147 } 148 default: 149 llvm_unreachable("unknown relocation"); 150 } 151 } 152 153 RelExpr AMDGPU::getRelExpr(RelType type, const Symbol &s, 154 const uint8_t *loc) const { 155 switch (type) { 156 case R_AMDGPU_ABS32: 157 case R_AMDGPU_ABS64: 158 return R_ABS; 159 case R_AMDGPU_REL32: 160 case R_AMDGPU_REL32_LO: 161 case R_AMDGPU_REL32_HI: 162 case R_AMDGPU_REL64: 163 case R_AMDGPU_REL16: 164 return R_PC; 165 case R_AMDGPU_GOTPCREL: 166 case R_AMDGPU_GOTPCREL32_LO: 167 case R_AMDGPU_GOTPCREL32_HI: 168 return R_GOT_PC; 169 default: 170 error(getErrorLocation(loc) + "unknown relocation (" + Twine(type) + 171 ") against symbol " + toString(s)); 172 return R_NONE; 173 } 174 } 175 176 RelType AMDGPU::getDynRel(RelType type) const { 177 if (type == R_AMDGPU_ABS64) 178 return type; 179 return R_AMDGPU_NONE; 180 } 181 182 TargetInfo *elf::getAMDGPUTargetInfo() { 183 static AMDGPU target; 184 return ⌖ 185 } 186