//===- ELF.cpp - ELF object file implementation ---------------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "llvm/Object/ELF.h" #include "llvm/BinaryFormat/ELF.h" #include "llvm/Support/LEB128.h" using namespace llvm; using namespace object; #define STRINGIFY_ENUM_CASE(ns, name) \ case ns::name: \ return #name; #define ELF_RELOC(name, value) STRINGIFY_ENUM_CASE(ELF, name) StringRef llvm::object::getELFRelocationTypeName(uint32_t Machine, uint32_t Type) { switch (Machine) { case ELF::EM_X86_64: switch (Type) { #include "llvm/BinaryFormat/ELFRelocs/x86_64.def" default: break; } break; case ELF::EM_386: case ELF::EM_IAMCU: switch (Type) { #include "llvm/BinaryFormat/ELFRelocs/i386.def" default: break; } break; case ELF::EM_MIPS: switch (Type) { #include "llvm/BinaryFormat/ELFRelocs/Mips.def" default: break; } break; case ELF::EM_AARCH64: switch (Type) { #include "llvm/BinaryFormat/ELFRelocs/AArch64.def" default: break; } break; case ELF::EM_ARM: switch (Type) { #include "llvm/BinaryFormat/ELFRelocs/ARM.def" default: break; } break; case ELF::EM_ARC_COMPACT: case ELF::EM_ARC_COMPACT2: switch (Type) { #include "llvm/BinaryFormat/ELFRelocs/ARC.def" default: break; } break; case ELF::EM_AVR: switch (Type) { #include "llvm/BinaryFormat/ELFRelocs/AVR.def" default: break; } break; case ELF::EM_HEXAGON: switch (Type) { #include "llvm/BinaryFormat/ELFRelocs/Hexagon.def" default: break; } break; case ELF::EM_LANAI: switch (Type) { #include "llvm/BinaryFormat/ELFRelocs/Lanai.def" default: break; } break; case ELF::EM_PPC: switch (Type) { #include "llvm/BinaryFormat/ELFRelocs/PowerPC.def" default: break; } break; case ELF::EM_PPC64: switch (Type) { #include "llvm/BinaryFormat/ELFRelocs/PowerPC64.def" default: break; } break; case ELF::EM_RISCV: switch (Type) { #include "llvm/BinaryFormat/ELFRelocs/RISCV.def" default: break; } break; case ELF::EM_S390: switch (Type) { #include "llvm/BinaryFormat/ELFRelocs/SystemZ.def" default: break; } break; case ELF::EM_SPARC: case ELF::EM_SPARC32PLUS: case ELF::EM_SPARCV9: switch (Type) { #include "llvm/BinaryFormat/ELFRelocs/Sparc.def" default: break; } break; case ELF::EM_WEBASSEMBLY: switch (Type) { #include "llvm/BinaryFormat/ELFRelocs/WebAssembly.def" default: break; } break; case ELF::EM_AMDGPU: switch (Type) { #include "llvm/BinaryFormat/ELFRelocs/AMDGPU.def" default: break; } case ELF::EM_BPF: switch (Type) { #include "llvm/BinaryFormat/ELFRelocs/BPF.def" default: break; } break; default: break; } return "Unknown"; } #undef ELF_RELOC StringRef llvm::object::getELFSectionTypeName(uint32_t Machine, unsigned Type) { switch (Machine) { case ELF::EM_ARM: switch (Type) { STRINGIFY_ENUM_CASE(ELF, SHT_ARM_EXIDX); STRINGIFY_ENUM_CASE(ELF, SHT_ARM_PREEMPTMAP); STRINGIFY_ENUM_CASE(ELF, SHT_ARM_ATTRIBUTES); STRINGIFY_ENUM_CASE(ELF, SHT_ARM_DEBUGOVERLAY); STRINGIFY_ENUM_CASE(ELF, SHT_ARM_OVERLAYSECTION); } break; case ELF::EM_HEXAGON: switch (Type) { STRINGIFY_ENUM_CASE(ELF, SHT_HEX_ORDERED); } break; case ELF::EM_X86_64: switch (Type) { STRINGIFY_ENUM_CASE(ELF, SHT_X86_64_UNWIND); } break; case ELF::EM_MIPS: case ELF::EM_MIPS_RS3_LE: switch (Type) { STRINGIFY_ENUM_CASE(ELF, SHT_MIPS_REGINFO); STRINGIFY_ENUM_CASE(ELF, SHT_MIPS_OPTIONS); STRINGIFY_ENUM_CASE(ELF, SHT_MIPS_ABIFLAGS); STRINGIFY_ENUM_CASE(ELF, SHT_MIPS_DWARF); } break; default: break; } switch (Type) { STRINGIFY_ENUM_CASE(ELF, SHT_NULL); STRINGIFY_ENUM_CASE(ELF, SHT_PROGBITS); STRINGIFY_ENUM_CASE(ELF, SHT_SYMTAB); STRINGIFY_ENUM_CASE(ELF, SHT_STRTAB); STRINGIFY_ENUM_CASE(ELF, SHT_RELA); STRINGIFY_ENUM_CASE(ELF, SHT_HASH); STRINGIFY_ENUM_CASE(ELF, SHT_DYNAMIC); STRINGIFY_ENUM_CASE(ELF, SHT_NOTE); STRINGIFY_ENUM_CASE(ELF, SHT_NOBITS); STRINGIFY_ENUM_CASE(ELF, SHT_REL); STRINGIFY_ENUM_CASE(ELF, SHT_SHLIB); STRINGIFY_ENUM_CASE(ELF, SHT_DYNSYM); STRINGIFY_ENUM_CASE(ELF, SHT_INIT_ARRAY); STRINGIFY_ENUM_CASE(ELF, SHT_FINI_ARRAY); STRINGIFY_ENUM_CASE(ELF, SHT_PREINIT_ARRAY); STRINGIFY_ENUM_CASE(ELF, SHT_GROUP); STRINGIFY_ENUM_CASE(ELF, SHT_SYMTAB_SHNDX); STRINGIFY_ENUM_CASE(ELF, SHT_ANDROID_REL); STRINGIFY_ENUM_CASE(ELF, SHT_ANDROID_RELA); STRINGIFY_ENUM_CASE(ELF, SHT_LLVM_ODRTAB); STRINGIFY_ENUM_CASE(ELF, SHT_GNU_ATTRIBUTES); STRINGIFY_ENUM_CASE(ELF, SHT_GNU_HASH); STRINGIFY_ENUM_CASE(ELF, SHT_GNU_verdef); STRINGIFY_ENUM_CASE(ELF, SHT_GNU_verneed); STRINGIFY_ENUM_CASE(ELF, SHT_GNU_versym); default: return "Unknown"; } } template Expected ELFFile::getSectionIndex(const Elf_Sym *Sym, Elf_Sym_Range Syms, ArrayRef ShndxTable) const { uint32_t Index = Sym->st_shndx; if (Index == ELF::SHN_XINDEX) { auto ErrorOrIndex = getExtendedSymbolTableIndex( Sym, Syms.begin(), ShndxTable); if (!ErrorOrIndex) return ErrorOrIndex.takeError(); return *ErrorOrIndex; } if (Index == ELF::SHN_UNDEF || Index >= ELF::SHN_LORESERVE) return 0; return Index; } template Expected ELFFile::getSection(const Elf_Sym *Sym, const Elf_Shdr *SymTab, ArrayRef ShndxTable) const { auto SymsOrErr = symbols(SymTab); if (!SymsOrErr) return SymsOrErr.takeError(); return getSection(Sym, *SymsOrErr, ShndxTable); } template Expected ELFFile::getSection(const Elf_Sym *Sym, Elf_Sym_Range Symbols, ArrayRef ShndxTable) const { auto IndexOrErr = getSectionIndex(Sym, Symbols, ShndxTable); if (!IndexOrErr) return IndexOrErr.takeError(); uint32_t Index = *IndexOrErr; if (Index == 0) return nullptr; return getSection(Index); } template Expected ELFFile::getSymbol(const Elf_Shdr *Sec, uint32_t Index) const { auto SymtabOrErr = symbols(Sec); if (!SymtabOrErr) return SymtabOrErr.takeError(); return object::getSymbol(*SymtabOrErr, Index); } template Expected> ELFFile::getSectionContents(const Elf_Shdr *Sec) const { return getSectionContentsAsArray(Sec); } template StringRef ELFFile::getRelocationTypeName(uint32_t Type) const { return getELFRelocationTypeName(getHeader()->e_machine, Type); } template void ELFFile::getRelocationTypeName(uint32_t Type, SmallVectorImpl &Result) const { if (!isMipsELF64()) { StringRef Name = getRelocationTypeName(Type); Result.append(Name.begin(), Name.end()); } else { // The Mips N64 ABI allows up to three operations to be specified per // relocation record. Unfortunately there's no easy way to test for the // presence of N64 ELFs as they have no special flag that identifies them // as being N64. We can safely assume at the moment that all Mips // ELFCLASS64 ELFs are N64. New Mips64 ABIs should provide enough // information to disambiguate between old vs new ABIs. uint8_t Type1 = (Type >> 0) & 0xFF; uint8_t Type2 = (Type >> 8) & 0xFF; uint8_t Type3 = (Type >> 16) & 0xFF; // Concat all three relocation type names. StringRef Name = getRelocationTypeName(Type1); Result.append(Name.begin(), Name.end()); Name = getRelocationTypeName(Type2); Result.append(1, '/'); Result.append(Name.begin(), Name.end()); Name = getRelocationTypeName(Type3); Result.append(1, '/'); Result.append(Name.begin(), Name.end()); } } template Expected ELFFile::getRelocationSymbol(const Elf_Rel *Rel, const Elf_Shdr *SymTab) const { uint32_t Index = Rel->getSymbol(isMips64EL()); if (Index == 0) return nullptr; return getEntry(SymTab, Index); } template Expected ELFFile::getSectionStringTable(Elf_Shdr_Range Sections) const { uint32_t Index = getHeader()->e_shstrndx; if (Index == ELF::SHN_XINDEX) Index = Sections[0].sh_link; if (!Index) // no section string table. return ""; if (Index >= Sections.size()) return createError("invalid section index"); return getStringTable(&Sections[Index]); } template ELFFile::ELFFile(StringRef Object) : Buf(Object) {} template Expected> ELFFile::create(StringRef Object) { if (sizeof(Elf_Ehdr) > Object.size()) return createError("Invalid buffer"); return ELFFile(Object); } template Expected ELFFile::sections() const { const uintX_t SectionTableOffset = getHeader()->e_shoff; if (SectionTableOffset == 0) return ArrayRef(); if (getHeader()->e_shentsize != sizeof(Elf_Shdr)) return createError( "invalid section header entry size (e_shentsize) in ELF header"); const uint64_t FileSize = Buf.size(); if (SectionTableOffset + sizeof(Elf_Shdr) > FileSize) return createError("section header table goes past the end of the file"); // Invalid address alignment of section headers if (SectionTableOffset & (alignof(Elf_Shdr) - 1)) return createError("invalid alignment of section headers"); const Elf_Shdr *First = reinterpret_cast(base() + SectionTableOffset); uintX_t NumSections = getHeader()->e_shnum; if (NumSections == 0) NumSections = First->sh_size; if (NumSections > UINT64_MAX / sizeof(Elf_Shdr)) return createError("section table goes past the end of file"); const uint64_t SectionTableSize = NumSections * sizeof(Elf_Shdr); // Section table goes past end of file! if (SectionTableOffset + SectionTableSize > FileSize) return createError("section table goes past the end of file"); return makeArrayRef(First, NumSections); } template Expected ELFFile::getSection(uint32_t Index) const { auto TableOrErr = sections(); if (!TableOrErr) return TableOrErr.takeError(); return object::getSection(*TableOrErr, Index); } template Expected ELFFile::getStringTable(const Elf_Shdr *Section) const { if (Section->sh_type != ELF::SHT_STRTAB) return createError("invalid sh_type for string table, expected SHT_STRTAB"); auto V = getSectionContentsAsArray(Section); if (!V) return V.takeError(); ArrayRef Data = *V; if (Data.empty()) return createError("empty string table"); if (Data.back() != '\0') return createError("string table non-null terminated"); return StringRef(Data.begin(), Data.size()); } template Expected> ELFFile::getSHNDXTable(const Elf_Shdr &Section) const { auto SectionsOrErr = sections(); if (!SectionsOrErr) return SectionsOrErr.takeError(); return getSHNDXTable(Section, *SectionsOrErr); } template Expected> ELFFile::getSHNDXTable(const Elf_Shdr &Section, Elf_Shdr_Range Sections) const { assert(Section.sh_type == ELF::SHT_SYMTAB_SHNDX); auto VOrErr = getSectionContentsAsArray(&Section); if (!VOrErr) return VOrErr.takeError(); ArrayRef V = *VOrErr; auto SymTableOrErr = object::getSection(Sections, Section.sh_link); if (!SymTableOrErr) return SymTableOrErr.takeError(); const Elf_Shdr &SymTable = **SymTableOrErr; if (SymTable.sh_type != ELF::SHT_SYMTAB && SymTable.sh_type != ELF::SHT_DYNSYM) return createError("invalid sh_type"); if (V.size() != (SymTable.sh_size / sizeof(Elf_Sym))) return createError("invalid section contents size"); return V; } template Expected ELFFile::getStringTableForSymtab(const Elf_Shdr &Sec) const { auto SectionsOrErr = sections(); if (!SectionsOrErr) return SectionsOrErr.takeError(); return getStringTableForSymtab(Sec, *SectionsOrErr); } template Expected ELFFile::getStringTableForSymtab(const Elf_Shdr &Sec, Elf_Shdr_Range Sections) const { if (Sec.sh_type != ELF::SHT_SYMTAB && Sec.sh_type != ELF::SHT_DYNSYM) return createError( "invalid sh_type for symbol table, expected SHT_SYMTAB or SHT_DYNSYM"); auto SectionOrErr = object::getSection(Sections, Sec.sh_link); if (!SectionOrErr) return SectionOrErr.takeError(); return getStringTable(*SectionOrErr); } template Expected ELFFile::getSectionName(const Elf_Shdr *Section) const { auto SectionsOrErr = sections(); if (!SectionsOrErr) return SectionsOrErr.takeError(); auto Table = getSectionStringTable(*SectionsOrErr); if (!Table) return Table.takeError(); return getSectionName(Section, *Table); } template Expected ELFFile::getSectionName(const Elf_Shdr *Section, StringRef DotShstrtab) const { uint32_t Offset = Section->sh_name; if (Offset == 0) return StringRef(); if (Offset >= DotShstrtab.size()) return createError("invalid string offset"); return StringRef(DotShstrtab.data() + Offset); } template Expected> ELFFile::android_relas(const Elf_Shdr *Sec) const { // This function reads relocations in Android's packed relocation format, // which is based on SLEB128 and delta encoding. Expected> ContentsOrErr = getSectionContents(Sec); if (!ContentsOrErr) return ContentsOrErr.takeError(); const uint8_t *Cur = ContentsOrErr->begin(); const uint8_t *End = ContentsOrErr->end(); if (ContentsOrErr->size() < 4 || Cur[0] != 'A' || Cur[1] != 'P' || Cur[2] != 'S' || Cur[3] != '2') return createError("invalid packed relocation header"); Cur += 4; const char *ErrStr = nullptr; auto ReadSLEB = [&]() -> int64_t { if (ErrStr) return 0; unsigned Len; int64_t Result = decodeSLEB128(Cur, &Len, End, &ErrStr); Cur += Len; return Result; }; uint64_t NumRelocs = ReadSLEB(); uint64_t Offset = ReadSLEB(); uint64_t Addend = 0; if (ErrStr) return createError(ErrStr); std::vector Relocs; Relocs.reserve(NumRelocs); while (NumRelocs) { uint64_t NumRelocsInGroup = ReadSLEB(); if (NumRelocsInGroup > NumRelocs) return createError("relocation group unexpectedly large"); NumRelocs -= NumRelocsInGroup; uint64_t GroupFlags = ReadSLEB(); bool GroupedByInfo = GroupFlags & ELF::RELOCATION_GROUPED_BY_INFO_FLAG; bool GroupedByOffsetDelta = GroupFlags & ELF::RELOCATION_GROUPED_BY_OFFSET_DELTA_FLAG; bool GroupedByAddend = GroupFlags & ELF::RELOCATION_GROUPED_BY_ADDEND_FLAG; bool GroupHasAddend = GroupFlags & ELF::RELOCATION_GROUP_HAS_ADDEND_FLAG; uint64_t GroupOffsetDelta; if (GroupedByOffsetDelta) GroupOffsetDelta = ReadSLEB(); uint64_t GroupRInfo; if (GroupedByInfo) GroupRInfo = ReadSLEB(); if (GroupedByAddend && GroupHasAddend) Addend += ReadSLEB(); for (uint64_t I = 0; I != NumRelocsInGroup; ++I) { Elf_Rela R; Offset += GroupedByOffsetDelta ? GroupOffsetDelta : ReadSLEB(); R.r_offset = Offset; R.r_info = GroupedByInfo ? GroupRInfo : ReadSLEB(); if (GroupHasAddend) { if (!GroupedByAddend) Addend += ReadSLEB(); R.r_addend = Addend; } else { R.r_addend = 0; } Relocs.push_back(R); if (ErrStr) return createError(ErrStr); } if (ErrStr) return createError(ErrStr); } return Relocs; } template class llvm::object::ELFFile; template class llvm::object::ELFFile; template class llvm::object::ELFFile; template class llvm::object::ELFFile;