brintos

brintos / llvm-project-archived public Read only

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