1 //===-- Utils/ELF.cpp - Common ELF functionality --------------------------===// 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 // Common ELF functionality for target plugins. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #include "Utils/ELF.h" 14 15 #include "llvm/BinaryFormat/Magic.h" 16 #include "llvm/Object/Binary.h" 17 #include "llvm/Object/ELFObjectFile.h" 18 #include "llvm/Object/ELFTypes.h" 19 #include "llvm/Object/ObjectFile.h" 20 #include "llvm/Support/MemoryBuffer.h" 21 22 using namespace llvm; 23 using namespace llvm::ELF; 24 using namespace llvm::object; 25 26 bool utils::elf::isELF(StringRef Buffer) { 27 switch (identify_magic(Buffer)) { 28 case file_magic::elf: 29 case file_magic::elf_relocatable: 30 case file_magic::elf_executable: 31 case file_magic::elf_shared_object: 32 case file_magic::elf_core: 33 return true; 34 default: 35 return false; 36 } 37 } 38 39 uint16_t utils::elf::getTargetMachine() { 40 #if defined(__x86_64__) 41 return EM_X86_64; 42 #elif defined(__s390x__) 43 return EM_S390; 44 #elif defined(__aarch64__) 45 return EM_AARCH64; 46 #elif defined(__powerpc64__) 47 return EM_PPC64; 48 #elif defined(__riscv) 49 return EM_RISCV; 50 #elif defined(__loongarch__) 51 return EM_LOONGARCH; 52 #else 53 #warning "Unknown ELF compilation target architecture" 54 return EM_NONE; 55 #endif 56 } 57 58 template <class ELFT> 59 static Expected<bool> 60 checkMachineImpl(const object::ELFObjectFile<ELFT> &ELFObj, uint16_t EMachine) { 61 const auto Header = ELFObj.getELFFile().getHeader(); 62 if (Header.e_type != ET_EXEC && Header.e_type != ET_DYN) 63 return createError("Only executable ELF files are supported"); 64 65 if (Header.e_machine == EM_AMDGPU) { 66 if (Header.e_ident[EI_OSABI] != ELFOSABI_AMDGPU_HSA) 67 return createError("Invalid AMD OS/ABI, must be AMDGPU_HSA"); 68 if (Header.e_ident[EI_ABIVERSION] != ELFABIVERSION_AMDGPU_HSA_V4 && 69 Header.e_ident[EI_ABIVERSION] != ELFABIVERSION_AMDGPU_HSA_V5 && 70 Header.e_ident[EI_ABIVERSION] != ELFABIVERSION_AMDGPU_HSA_V6) 71 return createError("Invalid AMD ABI version, must be version 4 or above"); 72 if ((Header.e_flags & EF_AMDGPU_MACH) < EF_AMDGPU_MACH_AMDGCN_GFX700 || 73 (Header.e_flags & EF_AMDGPU_MACH) > 74 EF_AMDGPU_MACH_AMDGCN_GFX9_4_GENERIC) 75 return createError("Unsupported AMDGPU architecture"); 76 } else if (Header.e_machine == EM_CUDA) { 77 if (~Header.e_flags & EF_CUDA_64BIT_ADDRESS) 78 return createError("Invalid CUDA addressing mode"); 79 if ((Header.e_flags & EF_CUDA_SM) < EF_CUDA_SM35 || 80 (Header.e_flags & EF_CUDA_SM) > EF_CUDA_SM90) 81 return createError("Unsupported NVPTX architecture"); 82 } 83 84 return Header.e_machine == EMachine; 85 } 86 87 Expected<bool> utils::elf::checkMachine(StringRef Object, uint16_t EMachine) { 88 assert(isELF(Object) && "Input is not an ELF!"); 89 90 Expected<std::unique_ptr<ObjectFile>> ElfOrErr = 91 ObjectFile::createELFObjectFile( 92 MemoryBufferRef(Object, /*Identifier=*/""), 93 /*InitContent=*/false); 94 if (!ElfOrErr) 95 return ElfOrErr.takeError(); 96 97 if (const ELF64LEObjectFile *ELFObj = 98 dyn_cast<ELF64LEObjectFile>(&**ElfOrErr)) 99 return checkMachineImpl(*ELFObj, EMachine); 100 if (const ELF64BEObjectFile *ELFObj = 101 dyn_cast<ELF64BEObjectFile>(&**ElfOrErr)) 102 return checkMachineImpl(*ELFObj, EMachine); 103 return createError("Only 64-bit ELF files are supported"); 104 } 105 106 template <class ELFT> 107 static Expected<const typename ELFT::Sym *> 108 getSymbolFromGnuHashTable(StringRef Name, const typename ELFT::GnuHash &HashTab, 109 ArrayRef<typename ELFT::Sym> SymTab, 110 StringRef StrTab) { 111 const uint32_t NameHash = hashGnu(Name); 112 const typename ELFT::Word NBucket = HashTab.nbuckets; 113 const typename ELFT::Word SymOffset = HashTab.symndx; 114 ArrayRef<typename ELFT::Off> Filter = HashTab.filter(); 115 ArrayRef<typename ELFT::Word> Bucket = HashTab.buckets(); 116 ArrayRef<typename ELFT::Word> Chain = HashTab.values(SymTab.size()); 117 118 // Check the bloom filter and exit early if the symbol is not present. 119 uint64_t ElfClassBits = ELFT::Is64Bits ? 64 : 32; 120 typename ELFT::Off Word = 121 Filter[(NameHash / ElfClassBits) % HashTab.maskwords]; 122 uint64_t Mask = (0x1ull << (NameHash % ElfClassBits)) | 123 (0x1ull << ((NameHash >> HashTab.shift2) % ElfClassBits)); 124 if ((Word & Mask) != Mask) 125 return nullptr; 126 127 // The symbol may or may not be present, check the hash values. 128 for (typename ELFT::Word I = Bucket[NameHash % NBucket]; 129 I >= SymOffset && I < SymTab.size(); I = I + 1) { 130 const uint32_t ChainHash = Chain[I - SymOffset]; 131 132 if ((NameHash | 0x1) != (ChainHash | 0x1)) 133 continue; 134 135 if (SymTab[I].st_name >= StrTab.size()) 136 return createError("symbol [index " + Twine(I) + 137 "] has invalid st_name: " + Twine(SymTab[I].st_name)); 138 if (StrTab.drop_front(SymTab[I].st_name).data() == Name) 139 return &SymTab[I]; 140 141 if (ChainHash & 0x1) 142 return nullptr; 143 } 144 return nullptr; 145 } 146 147 template <class ELFT> 148 static Expected<const typename ELFT::Sym *> 149 getSymbolFromSysVHashTable(StringRef Name, const typename ELFT::Hash &HashTab, 150 ArrayRef<typename ELFT::Sym> SymTab, 151 StringRef StrTab) { 152 const uint32_t Hash = hashSysV(Name); 153 const typename ELFT::Word NBucket = HashTab.nbucket; 154 ArrayRef<typename ELFT::Word> Bucket = HashTab.buckets(); 155 ArrayRef<typename ELFT::Word> Chain = HashTab.chains(); 156 for (typename ELFT::Word I = Bucket[Hash % NBucket]; I != ELF::STN_UNDEF; 157 I = Chain[I]) { 158 if (I >= SymTab.size()) 159 return createError( 160 "symbol [index " + Twine(I) + 161 "] is greater than the number of symbols: " + Twine(SymTab.size())); 162 if (SymTab[I].st_name >= StrTab.size()) 163 return createError("symbol [index " + Twine(I) + 164 "] has invalid st_name: " + Twine(SymTab[I].st_name)); 165 166 if (StrTab.drop_front(SymTab[I].st_name).data() == Name) 167 return &SymTab[I]; 168 } 169 return nullptr; 170 } 171 172 template <class ELFT> 173 static Expected<std::optional<ELFSymbolRef>> 174 getHashTableSymbol(const ELFObjectFile<ELFT> &ELFObj, 175 const typename ELFT::Shdr &Sec, StringRef Name) { 176 const ELFFile<ELFT> &Elf = ELFObj.getELFFile(); 177 if (Sec.sh_type != ELF::SHT_HASH && Sec.sh_type != ELF::SHT_GNU_HASH) 178 return createError( 179 "invalid sh_type for hash table, expected SHT_HASH or SHT_GNU_HASH"); 180 Expected<typename ELFT::ShdrRange> SectionsOrError = Elf.sections(); 181 if (!SectionsOrError) 182 return SectionsOrError.takeError(); 183 184 auto SymTabOrErr = getSection<ELFT>(*SectionsOrError, Sec.sh_link); 185 if (!SymTabOrErr) 186 return SymTabOrErr.takeError(); 187 188 auto StrTabOrErr = 189 Elf.getStringTableForSymtab(**SymTabOrErr, *SectionsOrError); 190 if (!StrTabOrErr) 191 return StrTabOrErr.takeError(); 192 StringRef StrTab = *StrTabOrErr; 193 194 auto SymsOrErr = Elf.symbols(*SymTabOrErr); 195 if (!SymsOrErr) 196 return SymsOrErr.takeError(); 197 ArrayRef<typename ELFT::Sym> SymTab = *SymsOrErr; 198 199 // If this is a GNU hash table we verify its size and search the symbol 200 // table using the GNU hash table format. 201 if (Sec.sh_type == ELF::SHT_GNU_HASH) { 202 const typename ELFT::GnuHash *HashTab = 203 reinterpret_cast<const typename ELFT::GnuHash *>(Elf.base() + 204 Sec.sh_offset); 205 if (Sec.sh_offset + Sec.sh_size >= Elf.getBufSize()) 206 return createError("section has invalid sh_offset: " + 207 Twine(Sec.sh_offset)); 208 if (Sec.sh_size < sizeof(typename ELFT::GnuHash) || 209 Sec.sh_size < 210 sizeof(typename ELFT::GnuHash) + 211 sizeof(typename ELFT::Word) * HashTab->maskwords + 212 sizeof(typename ELFT::Word) * HashTab->nbuckets + 213 sizeof(typename ELFT::Word) * (SymTab.size() - HashTab->symndx)) 214 return createError("section has invalid sh_size: " + Twine(Sec.sh_size)); 215 auto Sym = getSymbolFromGnuHashTable<ELFT>(Name, *HashTab, SymTab, StrTab); 216 if (!Sym) 217 return Sym.takeError(); 218 if (!*Sym) 219 return std::nullopt; 220 return ELFObj.toSymbolRef(*SymTabOrErr, *Sym - &SymTab[0]); 221 } 222 223 // If this is a Sys-V hash table we verify its size and search the symbol 224 // table using the Sys-V hash table format. 225 if (Sec.sh_type == ELF::SHT_HASH) { 226 const typename ELFT::Hash *HashTab = 227 reinterpret_cast<const typename ELFT::Hash *>(Elf.base() + 228 Sec.sh_offset); 229 if (Sec.sh_offset + Sec.sh_size >= Elf.getBufSize()) 230 return createError("section has invalid sh_offset: " + 231 Twine(Sec.sh_offset)); 232 if (Sec.sh_size < sizeof(typename ELFT::Hash) || 233 Sec.sh_size < sizeof(typename ELFT::Hash) + 234 sizeof(typename ELFT::Word) * HashTab->nbucket + 235 sizeof(typename ELFT::Word) * HashTab->nchain) 236 return createError("section has invalid sh_size: " + Twine(Sec.sh_size)); 237 238 auto Sym = getSymbolFromSysVHashTable<ELFT>(Name, *HashTab, SymTab, StrTab); 239 if (!Sym) 240 return Sym.takeError(); 241 if (!*Sym) 242 return std::nullopt; 243 return ELFObj.toSymbolRef(*SymTabOrErr, *Sym - &SymTab[0]); 244 } 245 246 return std::nullopt; 247 } 248 249 template <class ELFT> 250 static Expected<std::optional<ELFSymbolRef>> 251 getSymTableSymbol(const ELFObjectFile<ELFT> &ELFObj, 252 const typename ELFT::Shdr &Sec, StringRef Name) { 253 const ELFFile<ELFT> &Elf = ELFObj.getELFFile(); 254 if (Sec.sh_type != ELF::SHT_SYMTAB && Sec.sh_type != ELF::SHT_DYNSYM) 255 return createError( 256 "invalid sh_type for hash table, expected SHT_SYMTAB or SHT_DYNSYM"); 257 Expected<typename ELFT::ShdrRange> SectionsOrError = Elf.sections(); 258 if (!SectionsOrError) 259 return SectionsOrError.takeError(); 260 261 auto StrTabOrErr = Elf.getStringTableForSymtab(Sec, *SectionsOrError); 262 if (!StrTabOrErr) 263 return StrTabOrErr.takeError(); 264 StringRef StrTab = *StrTabOrErr; 265 266 auto SymsOrErr = Elf.symbols(&Sec); 267 if (!SymsOrErr) 268 return SymsOrErr.takeError(); 269 ArrayRef<typename ELFT::Sym> SymTab = *SymsOrErr; 270 271 for (const typename ELFT::Sym &Sym : SymTab) 272 if (StrTab.drop_front(Sym.st_name).data() == Name) 273 return ELFObj.toSymbolRef(&Sec, &Sym - &SymTab[0]); 274 275 return std::nullopt; 276 } 277 278 template <class ELFT> 279 static Expected<std::optional<ELFSymbolRef>> 280 getSymbolImpl(const ELFObjectFile<ELFT> &ELFObj, StringRef Name) { 281 // First try to look up the symbol via the hash table. 282 for (ELFSectionRef Sec : ELFObj.sections()) { 283 if (Sec.getType() != SHT_HASH && Sec.getType() != SHT_GNU_HASH) 284 continue; 285 286 auto HashTabOrErr = ELFObj.getELFFile().getSection(Sec.getIndex()); 287 if (!HashTabOrErr) 288 return HashTabOrErr.takeError(); 289 return getHashTableSymbol<ELFT>(ELFObj, **HashTabOrErr, Name); 290 } 291 292 // If this is an executable file check the entire standard symbol table. 293 for (ELFSectionRef Sec : ELFObj.sections()) { 294 if (Sec.getType() != SHT_SYMTAB) 295 continue; 296 297 auto SymTabOrErr = ELFObj.getELFFile().getSection(Sec.getIndex()); 298 if (!SymTabOrErr) 299 return SymTabOrErr.takeError(); 300 return getSymTableSymbol<ELFT>(ELFObj, **SymTabOrErr, Name); 301 } 302 303 return std::nullopt; 304 } 305 306 Expected<std::optional<ELFSymbolRef>> 307 utils::elf::getSymbol(const ObjectFile &Obj, StringRef Name) { 308 if (const ELF64LEObjectFile *ELFObj = dyn_cast<ELF64LEObjectFile>(&Obj)) 309 return getSymbolImpl(*ELFObj, Name); 310 if (const ELF64BEObjectFile *ELFObj = dyn_cast<ELF64BEObjectFile>(&Obj)) 311 return getSymbolImpl(*ELFObj, Name); 312 return createError("Only 64-bit ELF files are supported"); 313 } 314 315 template <class ELFT> 316 static Expected<const void *> 317 getSymbolAddressImpl(const ELFObjectFile<ELFT> &ELFObj, 318 const ELFSymbolRef &SymRef) { 319 const ELFFile<ELFT> &ELFFile = ELFObj.getELFFile(); 320 321 auto SymOrErr = ELFObj.getSymbol(SymRef.getRawDataRefImpl()); 322 if (!SymOrErr) 323 return SymOrErr.takeError(); 324 const auto &Symbol = **SymOrErr; 325 326 auto SecOrErr = ELFFile.getSection(Symbol.st_shndx); 327 if (!SecOrErr) 328 return SecOrErr.takeError(); 329 const auto &Section = *SecOrErr; 330 331 // A section with SHT_NOBITS occupies no space in the file and has no 332 // offset. 333 if (Section->sh_type == ELF::SHT_NOBITS) 334 return createError( 335 "invalid sh_type for symbol lookup, cannot be SHT_NOBITS"); 336 337 uint64_t Offset = Section->sh_offset - Section->sh_addr + Symbol.st_value; 338 if (Offset > ELFFile.getBufSize()) 339 return createError("invalid offset [" + Twine(Offset) + 340 "] into ELF file of size [" + 341 Twine(ELFFile.getBufSize()) + "]"); 342 343 return ELFFile.base() + Offset; 344 } 345 346 Expected<const void *> 347 utils::elf::getSymbolAddress(const ELFSymbolRef &SymRef) { 348 const ObjectFile *Obj = SymRef.getObject(); 349 if (const ELF64LEObjectFile *ELFObj = dyn_cast<ELF64LEObjectFile>(Obj)) 350 return getSymbolAddressImpl(*ELFObj, SymRef); 351 if (const ELF64BEObjectFile *ELFObj = dyn_cast<ELF64BEObjectFile>(Obj)) 352 return getSymbolAddressImpl(*ELFObj, SymRef); 353 return createError("Only 64-bit ELF files are supported"); 354 } 355