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 int64_t getImplicitAddend(const uint8_t *buf, RelType type) const override; 38 }; 39 } // namespace 40 41 AMDGPU::AMDGPU() { 42 relativeRel = R_AMDGPU_RELATIVE64; 43 gotRel = R_AMDGPU_ABS64; 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(ctx.objectFiles[0]); 53 54 // Verify that all input files have the same e_flags. 55 for (InputFile *f : ArrayRef(ctx.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(ctx.objectFiles[0]) & EF_AMDGPU_MACH; 66 uint32_t retXnack = 67 getEFlags(ctx.objectFiles[0]) & EF_AMDGPU_FEATURE_XNACK_V4; 68 uint32_t retSramEcc = 69 getEFlags(ctx.objectFiles[0]) & EF_AMDGPU_FEATURE_SRAMECC_V4; 70 71 // Verify that all input files have compatible e_flags (same mach, all 72 // features in the same category are either ANY, ANY and ON, or ANY and OFF). 73 for (InputFile *f : ArrayRef(ctx.objectFiles).slice(1)) { 74 if (retMach != (getEFlags(f) & EF_AMDGPU_MACH)) { 75 error("incompatible mach: " + toString(f)); 76 return 0; 77 } 78 79 if (retXnack == EF_AMDGPU_FEATURE_XNACK_UNSUPPORTED_V4 || 80 (retXnack != EF_AMDGPU_FEATURE_XNACK_ANY_V4 && 81 (getEFlags(f) & EF_AMDGPU_FEATURE_XNACK_V4) 82 != EF_AMDGPU_FEATURE_XNACK_ANY_V4)) { 83 if (retXnack != (getEFlags(f) & EF_AMDGPU_FEATURE_XNACK_V4)) { 84 error("incompatible xnack: " + toString(f)); 85 return 0; 86 } 87 } else { 88 if (retXnack == EF_AMDGPU_FEATURE_XNACK_ANY_V4) 89 retXnack = getEFlags(f) & EF_AMDGPU_FEATURE_XNACK_V4; 90 } 91 92 if (retSramEcc == EF_AMDGPU_FEATURE_SRAMECC_UNSUPPORTED_V4 || 93 (retSramEcc != EF_AMDGPU_FEATURE_SRAMECC_ANY_V4 && 94 (getEFlags(f) & EF_AMDGPU_FEATURE_SRAMECC_V4) != 95 EF_AMDGPU_FEATURE_SRAMECC_ANY_V4)) { 96 if (retSramEcc != (getEFlags(f) & EF_AMDGPU_FEATURE_SRAMECC_V4)) { 97 error("incompatible sramecc: " + toString(f)); 98 return 0; 99 } 100 } else { 101 if (retSramEcc == EF_AMDGPU_FEATURE_SRAMECC_ANY_V4) 102 retSramEcc = getEFlags(f) & EF_AMDGPU_FEATURE_SRAMECC_V4; 103 } 104 } 105 106 return retMach | retXnack | retSramEcc; 107 } 108 109 uint32_t AMDGPU::calcEFlags() const { 110 if (ctx.objectFiles.empty()) 111 return 0; 112 113 uint8_t abiVersion = cast<ObjFile<ELF64LE>>(ctx.objectFiles[0]) 114 ->getObj() 115 .getHeader() 116 .e_ident[EI_ABIVERSION]; 117 switch (abiVersion) { 118 case ELFABIVERSION_AMDGPU_HSA_V2: 119 case ELFABIVERSION_AMDGPU_HSA_V3: 120 return calcEFlagsV3(); 121 case ELFABIVERSION_AMDGPU_HSA_V4: 122 case ELFABIVERSION_AMDGPU_HSA_V5: 123 return calcEFlagsV4(); 124 default: 125 error("unknown abi version: " + Twine(abiVersion)); 126 return 0; 127 } 128 } 129 130 void AMDGPU::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const { 131 switch (rel.type) { 132 case R_AMDGPU_ABS32: 133 case R_AMDGPU_GOTPCREL: 134 case R_AMDGPU_GOTPCREL32_LO: 135 case R_AMDGPU_REL32: 136 case R_AMDGPU_REL32_LO: 137 write32le(loc, val); 138 break; 139 case R_AMDGPU_ABS64: 140 case R_AMDGPU_REL64: 141 write64le(loc, val); 142 break; 143 case R_AMDGPU_GOTPCREL32_HI: 144 case R_AMDGPU_REL32_HI: 145 write32le(loc, val >> 32); 146 break; 147 case R_AMDGPU_REL16: { 148 int64_t simm = (static_cast<int64_t>(val) - 4) / 4; 149 checkInt(loc, simm, 16, rel); 150 write16le(loc, simm); 151 break; 152 } 153 default: 154 llvm_unreachable("unknown relocation"); 155 } 156 } 157 158 RelExpr AMDGPU::getRelExpr(RelType type, const Symbol &s, 159 const uint8_t *loc) const { 160 switch (type) { 161 case R_AMDGPU_ABS32: 162 case R_AMDGPU_ABS64: 163 return R_ABS; 164 case R_AMDGPU_REL32: 165 case R_AMDGPU_REL32_LO: 166 case R_AMDGPU_REL32_HI: 167 case R_AMDGPU_REL64: 168 case R_AMDGPU_REL16: 169 return R_PC; 170 case R_AMDGPU_GOTPCREL: 171 case R_AMDGPU_GOTPCREL32_LO: 172 case R_AMDGPU_GOTPCREL32_HI: 173 return R_GOT_PC; 174 default: 175 error(getErrorLocation(loc) + "unknown relocation (" + Twine(type) + 176 ") against symbol " + toString(s)); 177 return R_NONE; 178 } 179 } 180 181 RelType AMDGPU::getDynRel(RelType type) const { 182 if (type == R_AMDGPU_ABS64) 183 return type; 184 return R_AMDGPU_NONE; 185 } 186 187 int64_t AMDGPU::getImplicitAddend(const uint8_t *buf, RelType type) const { 188 switch (type) { 189 case R_AMDGPU_NONE: 190 return 0; 191 case R_AMDGPU_ABS64: 192 case R_AMDGPU_RELATIVE64: 193 return read64(buf); 194 default: 195 internalLinkerError(getErrorLocation(buf), 196 "cannot read addend for relocation " + toString(type)); 197 return 0; 198 } 199 } 200 201 TargetInfo *elf::getAMDGPUTargetInfo() { 202 static AMDGPU target; 203 return ⌖ 204 } 205