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(objectFiles[0]); 52 53 // Verify that all input files have the same e_flags. 54 for (InputFile *f : makeArrayRef(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(objectFiles[0]) & EF_AMDGPU_MACH; 65 uint32_t retXnack = getEFlags(objectFiles[0]) & EF_AMDGPU_FEATURE_XNACK_V4; 66 uint32_t retSramEcc = 67 getEFlags(objectFiles[0]) & EF_AMDGPU_FEATURE_SRAMECC_V4; 68 69 // Verify that all input files have compatible e_flags (same mach, all 70 // features in the same category are either ANY, ANY and ON, or ANY and OFF). 71 for (InputFile *f : makeArrayRef(objectFiles).slice(1)) { 72 if (retMach != (getEFlags(f) & EF_AMDGPU_MACH)) { 73 error("incompatible mach: " + toString(f)); 74 return 0; 75 } 76 77 if (retXnack == EF_AMDGPU_FEATURE_XNACK_UNSUPPORTED_V4 || 78 (retXnack != EF_AMDGPU_FEATURE_XNACK_ANY_V4 && 79 (getEFlags(f) & EF_AMDGPU_FEATURE_XNACK_V4) 80 != EF_AMDGPU_FEATURE_XNACK_ANY_V4)) { 81 if (retXnack != (getEFlags(f) & EF_AMDGPU_FEATURE_XNACK_V4)) { 82 error("incompatible xnack: " + toString(f)); 83 return 0; 84 } 85 } else { 86 if (retXnack == EF_AMDGPU_FEATURE_XNACK_ANY_V4) 87 retXnack = getEFlags(f) & EF_AMDGPU_FEATURE_XNACK_V4; 88 } 89 90 if (retSramEcc == EF_AMDGPU_FEATURE_SRAMECC_UNSUPPORTED_V4 || 91 (retSramEcc != EF_AMDGPU_FEATURE_SRAMECC_ANY_V4 && 92 (getEFlags(f) & EF_AMDGPU_FEATURE_SRAMECC_V4) != 93 EF_AMDGPU_FEATURE_SRAMECC_ANY_V4)) { 94 if (retSramEcc != (getEFlags(f) & EF_AMDGPU_FEATURE_SRAMECC_V4)) { 95 error("incompatible sramecc: " + toString(f)); 96 return 0; 97 } 98 } else { 99 if (retSramEcc == EF_AMDGPU_FEATURE_SRAMECC_ANY_V4) 100 retSramEcc = getEFlags(f) & EF_AMDGPU_FEATURE_SRAMECC_V4; 101 } 102 } 103 104 return retMach | retXnack | retSramEcc; 105 } 106 107 uint32_t AMDGPU::calcEFlags() const { 108 assert(!objectFiles.empty()); 109 110 uint8_t abiVersion = cast<ObjFile<ELF64LE>>(objectFiles[0])->getObj() 111 .getHeader().e_ident[EI_ABIVERSION]; 112 switch (abiVersion) { 113 case ELFABIVERSION_AMDGPU_HSA_V2: 114 case ELFABIVERSION_AMDGPU_HSA_V3: 115 return calcEFlagsV3(); 116 case ELFABIVERSION_AMDGPU_HSA_V4: 117 case ELFABIVERSION_AMDGPU_HSA_V5: 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