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