diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2017-12-18 20:10:56 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2017-12-18 20:10:56 +0000 |
commit | 044eb2f6afba375a914ac9d8024f8f5142bb912e (patch) | |
tree | 1475247dc9f9fe5be155ebd4c9069c75aadf8c20 /lib/Object/ELF.cpp | |
parent | eb70dddbd77e120e5d490bd8fbe7ff3f8fa81c6b (diff) |
Notes
Diffstat (limited to 'lib/Object/ELF.cpp')
-rw-r--r-- | lib/Object/ELF.cpp | 100 |
1 files changed, 100 insertions, 0 deletions
diff --git a/lib/Object/ELF.cpp b/lib/Object/ELF.cpp index 448fb1bd6b56..c72a1258c1ee 100644 --- a/lib/Object/ELF.cpp +++ b/lib/Object/ELF.cpp @@ -9,6 +9,7 @@ #include "llvm/Object/ELF.h" #include "llvm/BinaryFormat/ELF.h" +#include "llvm/Support/LEB128.h" using namespace llvm; using namespace object; @@ -58,6 +59,14 @@ StringRef llvm::object::getELFRelocationTypeName(uint32_t Machine, 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" @@ -192,6 +201,8 @@ StringRef llvm::object::getELFSectionTypeName(uint32_t Machine, unsigned Type) { 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); @@ -202,3 +213,92 @@ StringRef llvm::object::getELFSectionTypeName(uint32_t Machine, unsigned Type) { return "Unknown"; } } + +template <class ELFT> +Expected<std::vector<typename ELFT::Rela>> +ELFFile<ELFT>::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<ArrayRef<uint8_t>> 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<Elf_Rela> 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<ELF32LE>; +template class llvm::object::ELFFile<ELF32BE>; +template class llvm::object::ELFFile<ELF64LE>; +template class llvm::object::ELFFile<ELF64BE>; |