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 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 return calcEFlagsV4(); 118 default: 119 error("unknown abi version: " + Twine(abiVersion)); 120 return 0; 121 } 122 } 123 124 void AMDGPU::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const { 125 switch (rel.type) { 126 case R_AMDGPU_ABS32: 127 case R_AMDGPU_GOTPCREL: 128 case R_AMDGPU_GOTPCREL32_LO: 129 case R_AMDGPU_REL32: 130 case R_AMDGPU_REL32_LO: 131 write32le(loc, val); 132 break; 133 case R_AMDGPU_ABS64: 134 case R_AMDGPU_REL64: 135 write64le(loc, val); 136 break; 137 case R_AMDGPU_GOTPCREL32_HI: 138 case R_AMDGPU_REL32_HI: 139 write32le(loc, val >> 32); 140 break; 141 case R_AMDGPU_REL16: { 142 int64_t simm = (static_cast<int64_t>(val) - 4) / 4; 143 checkInt(loc, simm, 16, rel); 144 write16le(loc, simm); 145 break; 146 } 147 default: 148 llvm_unreachable("unknown relocation"); 149 } 150 } 151 152 RelExpr AMDGPU::getRelExpr(RelType type, const Symbol &s, 153 const uint8_t *loc) const { 154 switch (type) { 155 case R_AMDGPU_ABS32: 156 case R_AMDGPU_ABS64: 157 return R_ABS; 158 case R_AMDGPU_REL32: 159 case R_AMDGPU_REL32_LO: 160 case R_AMDGPU_REL32_HI: 161 case R_AMDGPU_REL64: 162 case R_AMDGPU_REL16: 163 return R_PC; 164 case R_AMDGPU_GOTPCREL: 165 case R_AMDGPU_GOTPCREL32_LO: 166 case R_AMDGPU_GOTPCREL32_HI: 167 return R_GOT_PC; 168 default: 169 error(getErrorLocation(loc) + "unknown relocation (" + Twine(type) + 170 ") against symbol " + toString(s)); 171 return R_NONE; 172 } 173 } 174 175 RelType AMDGPU::getDynRel(RelType type) const { 176 if (type == R_AMDGPU_ABS64) 177 return type; 178 return R_AMDGPU_NONE; 179 } 180 181 TargetInfo *elf::getAMDGPUTargetInfo() { 182 static AMDGPU target; 183 return ⌖ 184 } 185