DYNAMIC_TAG(SYMTAB_SHNDX, 34) // Address of the SHT_SYMTAB_SHNDX section.
+// Experimental support for SHT_RELR sections. For details, see proposal
+// at https://groups.google.com/forum/#!topic/generic-abi/bX460iggiKg
+DYNAMIC_TAG(RELRSZ, 35) // Size of Relr relocation table.
+DYNAMIC_TAG(RELR, 36) // Address of relocation table (Relr entries).
+DYNAMIC_TAG(RELRENT, 37) // Size of a Relr relocation entry.
+
DYNAMIC_TAG_MARKER(LOOS, 0x60000000) // Start of environment specific tags.
DYNAMIC_TAG_MARKER(HIOS, 0x6FFFFFFF) // End of environment specific tags.
DYNAMIC_TAG_MARKER(LOPROC, 0x70000000) // Start of processor specific tags.
DYNAMIC_TAG(ANDROID_RELA, 0x60000011)
DYNAMIC_TAG(ANDROID_RELASZ, 0x60000012)
+// Android's experimental support for SHT_RELR sections.
+// https://android.googlesource.com/platform/bionic/+/b7feec74547f84559a1467aca02708ff61346d2a/libc/include/elf.h#253
+DYNAMIC_TAG(ANDROID_RELR, 0x6FFFE000) // Address of relocation table (Relr entries).
+DYNAMIC_TAG(ANDROID_RELRSZ, 0x6FFFE001) // Size of Relr relocation table.
+DYNAMIC_TAG(ANDROID_RELRENT, 0x6FFFE003) // Size of a Relr relocation entry.
+
DYNAMIC_TAG(GNU_HASH, 0x6FFFFEF5) // Reference to the GNU hash table.
DYNAMIC_TAG(TLSDESC_PLT, 0x6FFFFEF6) // Location of PLT entry for TLS
// descriptor resolver calls.
SHT_PREINIT_ARRAY = 16, // Pointers to pre-init functions.
SHT_GROUP = 17, // Section group.
SHT_SYMTAB_SHNDX = 18, // Indices for SHN_XINDEX entries.
+ // Experimental support for SHT_RELR sections. For details, see proposal
+ // at https://groups.google.com/forum/#!topic/generic-abi/bX460iggiKg
+ SHT_RELR = 19, // Relocation entries; only offsets.
SHT_LOOS = 0x60000000, // Lowest operating system-specific type.
// Android packed relocation section types.
// https://android.googlesource.com/platform/bionic/+/6f12bfece5dcc01325e0abba56a46b1bcf991c69/tools/relocation_packer/src/elf_file.cc#37
SHT_LLVM_ODRTAB = 0x6fff4c00, // LLVM ODR table.
SHT_LLVM_LINKER_OPTIONS = 0x6fff4c01, // LLVM Linker Options.
SHT_LLVM_CALL_GRAPH_PROFILE = 0x6fff4c02, // LLVM Call Graph Profile.
+ // Android's experimental support for SHT_RELR sections.
+ // https://android.googlesource.com/platform/bionic/+/b7feec74547f84559a1467aca02708ff61346d2a/libc/include/elf.h#512
+ SHT_ANDROID_RELR = 0x6fffff00, // Relocation entries; only offsets.
SHT_GNU_ATTRIBUTES = 0x6ffffff5, // Object attributes.
SHT_GNU_HASH = 0x6ffffff6, // GNU-style hash table.
SHT_GNU_verdef = 0x6ffffffd, // GNU version definitions.
}
};
+// Relocation entry without explicit addend or info (relative relocations only).
+typedef Elf32_Word Elf32_Relr; // offset/bitmap for relative relocations
+
// Relocation entry, without explicit addend.
struct Elf64_Rel {
Elf64_Addr r_offset; // Location (file byte offset, or program virtual addr).
}
};
+// Relocation entry without explicit addend or info (relative relocations only).
+typedef Elf64_Xword Elf64_Relr; // offset/bitmap for relative relocations
+
// Program header for ELF32.
struct Elf32_Phdr {
Elf32_Word p_type; // Type of segment
namespace object {
StringRef getELFRelocationTypeName(uint32_t Machine, uint32_t Type);
+uint32_t getELFRelrRelocationType(uint32_t Machine);
StringRef getELFSectionTypeName(uint32_t Machine, uint32_t Type);
// Subclasses of ELFFile may need this for template instantiation
using Elf_Phdr = typename ELFT::Phdr;
using Elf_Rel = typename ELFT::Rel;
using Elf_Rela = typename ELFT::Rela;
+ using Elf_Relr = typename ELFT::Relr;
using Elf_Verdef = typename ELFT::Verdef;
using Elf_Verdaux = typename ELFT::Verdaux;
using Elf_Verneed = typename ELFT::Verneed;
using Elf_Sym_Range = typename ELFT::SymRange;
using Elf_Rel_Range = typename ELFT::RelRange;
using Elf_Rela_Range = typename ELFT::RelaRange;
+ using Elf_Relr_Range = typename ELFT::RelrRange;
using Elf_Phdr_Range = typename ELFT::PhdrRange;
const uint8_t *base() const {
StringRef getRelocationTypeName(uint32_t Type) const;
void getRelocationTypeName(uint32_t Type,
SmallVectorImpl<char> &Result) const;
+ uint32_t getRelrRelocationType() const;
/// Get the symbol for a given relocation.
Expected<const Elf_Sym *> getRelocationSymbol(const Elf_Rel *Rel,
return getSectionContentsAsArray<Elf_Rel>(Sec);
}
+ Expected<Elf_Relr_Range> relrs(const Elf_Shdr *Sec) const {
+ return getSectionContentsAsArray<Elf_Relr>(Sec);
+ }
+
+ Expected<std::vector<Elf_Rela>> decode_relrs(Elf_Relr_Range relrs) const;
+
Expected<std::vector<Elf_Rela>> android_relas(const Elf_Shdr *Sec) const;
/// Iterate over program header table.
}
template <class ELFT>
+uint32_t ELFFile<ELFT>::getRelrRelocationType() const {
+ return getELFRelrRelocationType(getHeader()->e_machine);
+}
+
+template <class ELFT>
Expected<const typename ELFT::Sym *>
ELFFile<ELFT>::getRelocationSymbol(const Elf_Rel *Rel,
const Elf_Shdr *SymTab) const {
using Phdr = Elf_Phdr_Impl<ELFType<E, Is64>>;
using Rel = Elf_Rel_Impl<ELFType<E, Is64>, false>;
using Rela = Elf_Rel_Impl<ELFType<E, Is64>, true>;
+ using Relr = packed<uint>;
using Verdef = Elf_Verdef_Impl<ELFType<E, Is64>>;
using Verdaux = Elf_Verdaux_Impl<ELFType<E, Is64>>;
using Verneed = Elf_Verneed_Impl<ELFType<E, Is64>>;
using SymRange = ArrayRef<Sym>;
using RelRange = ArrayRef<Rel>;
using RelaRange = ArrayRef<Rela>;
+ using RelrRange = ArrayRef<Relr>;
using PhdrRange = ArrayRef<Phdr>;
using Half = packed<uint16_t>;
#undef ELF_RELOC
+uint32_t llvm::object::getELFRelrRelocationType(uint32_t Machine) {
+ switch (Machine) {
+ case ELF::EM_X86_64:
+ return ELF::R_X86_64_RELATIVE;
+ case ELF::EM_386:
+ case ELF::EM_IAMCU:
+ return ELF::R_386_RELATIVE;
+ case ELF::EM_MIPS:
+ break;
+ case ELF::EM_AARCH64:
+ return ELF::R_AARCH64_RELATIVE;
+ case ELF::EM_ARM:
+ return ELF::R_ARM_RELATIVE;
+ case ELF::EM_ARC_COMPACT:
+ case ELF::EM_ARC_COMPACT2:
+ return ELF::R_ARC_RELATIVE;
+ case ELF::EM_AVR:
+ break;
+ case ELF::EM_HEXAGON:
+ return ELF::R_HEX_RELATIVE;
+ case ELF::EM_LANAI:
+ break;
+ case ELF::EM_PPC:
+ break;
+ case ELF::EM_PPC64:
+ return ELF::R_PPC64_RELATIVE;
+ case ELF::EM_RISCV:
+ return ELF::R_RISCV_RELATIVE;
+ case ELF::EM_S390:
+ return ELF::R_390_RELATIVE;
+ case ELF::EM_SPARC:
+ case ELF::EM_SPARC32PLUS:
+ case ELF::EM_SPARCV9:
+ return ELF::R_SPARC_RELATIVE;
+ case ELF::EM_WEBASSEMBLY:
+ break;
+ case ELF::EM_AMDGPU:
+ break;
+ case ELF::EM_BPF:
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
StringRef llvm::object::getELFSectionTypeName(uint32_t Machine, unsigned Type) {
switch (Machine) {
case ELF::EM_ARM:
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_RELR);
STRINGIFY_ENUM_CASE(ELF, SHT_ANDROID_REL);
STRINGIFY_ENUM_CASE(ELF, SHT_ANDROID_RELA);
+ STRINGIFY_ENUM_CASE(ELF, SHT_ANDROID_RELR);
STRINGIFY_ENUM_CASE(ELF, SHT_LLVM_ODRTAB);
STRINGIFY_ENUM_CASE(ELF, SHT_LLVM_LINKER_OPTIONS);
STRINGIFY_ENUM_CASE(ELF, SHT_LLVM_CALL_GRAPH_PROFILE);
template <class ELFT>
Expected<std::vector<typename ELFT::Rela>>
+ELFFile<ELFT>::decode_relrs(Elf_Relr_Range relrs) const {
+ // This function decodes the contents of an SHT_RELR packed relocation
+ // section.
+ //
+ // Proposal for adding SHT_RELR sections to generic-abi is here:
+ // https://groups.google.com/forum/#!topic/generic-abi/bX460iggiKg
+ //
+ // The encoded sequence of Elf64_Relr entries in a SHT_RELR section looks
+ // like [ AAAAAAAA BBBBBBB1 BBBBBBB1 ... AAAAAAAA BBBBBB1 ... ]
+ //
+ // i.e. start with an address, followed by any number of bitmaps. The address
+ // entry encodes 1 relocation. The subsequent bitmap entries encode up to 63
+ // relocations each, at subsequent offsets following the last address entry.
+ //
+ // The bitmap entries must have 1 in the least significant bit. The assumption
+ // here is that an address cannot have 1 in lsb. Odd addresses are not
+ // supported.
+ //
+ // Excluding the least significant bit in the bitmap, each non-zero bit in
+ // the bitmap represents a relocation to be applied to a corresponding machine
+ // word that follows the base address word. The second least significant bit
+ // represents the machine word immediately following the initial address, and
+ // each bit that follows represents the next word, in linear order. As such,
+ // a single bitmap can encode up to 31 relocations in a 32-bit object, and
+ // 63 relocations in a 64-bit object.
+ //
+ // This encoding has a couple of interesting properties:
+ // 1. Looking at any entry, it is clear whether it's an address or a bitmap:
+ // even means address, odd means bitmap.
+ // 2. Just a simple list of addresses is a valid encoding.
+
+ Elf_Rela Rela;
+ Rela.r_info = 0;
+ Rela.r_addend = 0;
+ Rela.setType(getRelrRelocationType(), false);
+ std::vector<Elf_Rela> Relocs;
+
+ // Word type: uint32_t for Elf32, and uint64_t for Elf64.
+ typedef typename ELFT::uint Word;
+
+ // Word size in number of bytes.
+ const size_t WordSize = sizeof(Word);
+
+ // Number of bits used for the relocation offsets bitmap.
+ // These many relative relocations can be encoded in a single entry.
+ const size_t NBits = 8*WordSize - 1;
+
+ Word Base = 0;
+ for (const Elf_Relr &R : relrs) {
+ Word Entry = R;
+ if ((Entry&1) == 0) {
+ // Even entry: encodes the offset for next relocation.
+ Rela.r_offset = Entry;
+ Relocs.push_back(Rela);
+ // Set base offset for subsequent bitmap entries.
+ Base = Entry + WordSize;
+ continue;
+ }
+
+ // Odd entry: encodes bitmap for relocations starting at base.
+ Word Offset = Base;
+ while (Entry != 0) {
+ Entry >>= 1;
+ if ((Entry&1) != 0) {
+ Rela.r_offset = Offset;
+ Relocs.push_back(Rela);
+ }
+ Offset += WordSize;
+ }
+
+ // Advance base offset by NBits words.
+ Base += NBits * WordSize;
+ }
+
+ return Relocs;
+}
+
+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.
ECase(SHT_PREINIT_ARRAY);
ECase(SHT_GROUP);
ECase(SHT_SYMTAB_SHNDX);
+ ECase(SHT_RELR);
ECase(SHT_LOOS);
ECase(SHT_ANDROID_REL);
ECase(SHT_ANDROID_RELA);
+ ECase(SHT_ANDROID_RELR);
ECase(SHT_LLVM_ODRTAB);
ECase(SHT_LLVM_LINKER_OPTIONS);
ECase(SHT_LLVM_CALL_GRAPH_PROFILE);
--- /dev/null
+.quad 0x0000000000010d60 // Initial offset
+.quad 0x0000000000000103 // Continuation bitmap
+.quad 0x0000000000020000 // New offset
+.quad 0x00000000000f0501 // Continuation bitmap
+.quad 0x000a700550400009 // Continuation bitmap
--- /dev/null
+.long 0x00010d60 // Initial offset
+.long 0x00000103 // Continuation bitmap
+.long 0x00020000 // New offset
+.long 0x000f0501 // Continuation bitmap
+.long 0x50400009 // Continuation bitmap
--- /dev/null
+# The binary blobs in this file were created like this:
+# llvm-mc -filetype=obj -triple x86_64-pc-linux-gnu Inputs/elf-relr-relocs1.s -o - | obj2yaml | grep Content:
+
+# RUN: yaml2obj -docnum 1 %s \
+# RUN: | llvm-readobj -elf-output-style=LLVM -relocations -raw-relr - \
+# RUN: | FileCheck --check-prefix=RAW-LLVM1 %s
+# RAW-LLVM1: Section (1) .relr.dyn {
+# RAW-LLVM1-NEXT: 0x10D60
+# RAW-LLVM1-NEXT: 0x103
+# RAW-LLVM1-NEXT: 0x20000
+# RAW-LLVM1-NEXT: 0xF0501
+# RAW-LLVM1-NEXT: 0xA700550400009
+# RAW-LLVM1-NEXT: }
+
+# RUN: yaml2obj -docnum 1 %s \
+# RUN: | llvm-readobj -elf-output-style=LLVM -relocations - \
+# RUN: | FileCheck --check-prefix=LLVM1 %s
+# LLVM1: Section (1) .relr.dyn {
+# LLVM1-NEXT: 0x10D60 R_X86_64_RELATIVE - 0x0
+# LLVM1-NEXT: 0x10D68 R_X86_64_RELATIVE - 0x0
+# LLVM1-NEXT: 0x10DA0 R_X86_64_RELATIVE - 0x0
+# LLVM1-NEXT: 0x20000 R_X86_64_RELATIVE - 0x0
+# LLVM1-NEXT: 0x20040 R_X86_64_RELATIVE - 0x0
+# LLVM1-NEXT: 0x20050 R_X86_64_RELATIVE - 0x0
+# LLVM1-NEXT: 0x20080 R_X86_64_RELATIVE - 0x0
+# LLVM1-NEXT: 0x20088 R_X86_64_RELATIVE - 0x0
+# LLVM1-NEXT: 0x20090 R_X86_64_RELATIVE - 0x0
+# LLVM1-NEXT: 0x20098 R_X86_64_RELATIVE - 0x0
+# LLVM1-NEXT: 0x20210 R_X86_64_RELATIVE - 0x0
+# LLVM1-NEXT: 0x202A8 R_X86_64_RELATIVE - 0x0
+# LLVM1-NEXT: 0x202D8 R_X86_64_RELATIVE - 0x0
+# LLVM1-NEXT: 0x202E8 R_X86_64_RELATIVE - 0x0
+# LLVM1-NEXT: 0x202F8 R_X86_64_RELATIVE - 0x0
+# LLVM1-NEXT: 0x20308 R_X86_64_RELATIVE - 0x0
+# LLVM1-NEXT: 0x20358 R_X86_64_RELATIVE - 0x0
+# LLVM1-NEXT: 0x20360 R_X86_64_RELATIVE - 0x0
+# LLVM1-NEXT: 0x20368 R_X86_64_RELATIVE - 0x0
+# LLVM1-NEXT: 0x20380 R_X86_64_RELATIVE - 0x0
+# LLVM1-NEXT: 0x20390 R_X86_64_RELATIVE - 0x0
+# LLVM1-NEXT: }
+
+# RUN: yaml2obj -docnum 1 %s \
+# RUN: | llvm-readobj -elf-output-style=GNU -relocations -raw-relr - \
+# RUN: | FileCheck --check-prefix=RAW-GNU1 %s
+# RAW-GNU1: Relocation section '.relr.dyn' at offset 0x180 contains 5 entries:
+# RAW-GNU1: 0000000000010d60
+# RAW-GNU1-NEXT: 0000000000000103
+# RAW-GNU1-NEXT: 0000000000020000
+# RAW-GNU1-NEXT: 00000000000f0501
+# RAW-GNU1-NEXT: 000a700550400009
+
+# RUN: yaml2obj -docnum 1 %s \
+# RUN: | llvm-readobj -elf-output-style=GNU -relocations - \
+# RUN: | FileCheck --check-prefix=GNU1 %s
+# GNU1: Relocation section '.relr.dyn' at offset 0x180 contains 21 entries:
+# GNU1: 0000000000010d60 0000000000000008 R_X86_64_RELATIVE
+# GNU1-NEXT: 0000000000010d68 0000000000000008 R_X86_64_RELATIVE
+# GNU1-NEXT: 0000000000010da0 0000000000000008 R_X86_64_RELATIVE
+# GNU1-NEXT: 0000000000020000 0000000000000008 R_X86_64_RELATIVE
+# GNU1-NEXT: 0000000000020040 0000000000000008 R_X86_64_RELATIVE
+# GNU1-NEXT: 0000000000020050 0000000000000008 R_X86_64_RELATIVE
+# GNU1-NEXT: 0000000000020080 0000000000000008 R_X86_64_RELATIVE
+# GNU1-NEXT: 0000000000020088 0000000000000008 R_X86_64_RELATIVE
+# GNU1-NEXT: 0000000000020090 0000000000000008 R_X86_64_RELATIVE
+# GNU1-NEXT: 0000000000020098 0000000000000008 R_X86_64_RELATIVE
+# GNU1-NEXT: 0000000000020210 0000000000000008 R_X86_64_RELATIVE
+# GNU1-NEXT: 00000000000202a8 0000000000000008 R_X86_64_RELATIVE
+# GNU1-NEXT: 00000000000202d8 0000000000000008 R_X86_64_RELATIVE
+# GNU1-NEXT: 00000000000202e8 0000000000000008 R_X86_64_RELATIVE
+# GNU1-NEXT: 00000000000202f8 0000000000000008 R_X86_64_RELATIVE
+# GNU1-NEXT: 0000000000020308 0000000000000008 R_X86_64_RELATIVE
+# GNU1-NEXT: 0000000000020358 0000000000000008 R_X86_64_RELATIVE
+# GNU1-NEXT: 0000000000020360 0000000000000008 R_X86_64_RELATIVE
+# GNU1-NEXT: 0000000000020368 0000000000000008 R_X86_64_RELATIVE
+# GNU1-NEXT: 0000000000020380 0000000000000008 R_X86_64_RELATIVE
+# GNU1-NEXT: 0000000000020390 0000000000000008 R_X86_64_RELATIVE
+
+# elf-relr-relocs1.s
+--- !ELF
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_DYN
+ Machine: EM_X86_64
+ Entry: 0x0000000000001000
+Sections:
+ - Name: .relr.dyn
+ Type: SHT_RELR
+ Flags: [ SHF_ALLOC ]
+ Address: 0x00000000000001C8
+ Link: .symtab
+ AddressAlign: 0x0000000000000001
+ Content: 600D0100000000000301000000000000000002000000000001050F00000000000900405005700A00
+...
+
+# RUN: yaml2obj -docnum 2 %s \
+# RUN: | llvm-readobj -elf-output-style=LLVM -relocations -raw-relr - \
+# RUN: | FileCheck --check-prefix=RAW-LLVM2 %s
+# RAW-LLVM2: Section (1) .relr.dyn {
+# RAW-LLVM2-NEXT: 0x10D60
+# RAW-LLVM2-NEXT: 0x103
+# RAW-LLVM2-NEXT: 0x20000
+# RAW-LLVM2-NEXT: 0xF0501
+# RAW-LLVM2-NEXT: 0x50400009
+# RAW-LLVM2-NEXT: }
+
+# RUN: yaml2obj -docnum 2 %s \
+# RUN: | llvm-readobj -elf-output-style=LLVM -relocations - \
+# RUN: | FileCheck --check-prefix=LLVM2 %s
+# LLVM2: Section (1) .relr.dyn {
+# LLVM2-NEXT: 0x10D60 R_386_RELATIVE - 0x0
+# LLVM2-NEXT: 0x10D64 R_386_RELATIVE - 0x0
+# LLVM2-NEXT: 0x10D80 R_386_RELATIVE - 0x0
+# LLVM2-NEXT: 0x20000 R_386_RELATIVE - 0x0
+# LLVM2-NEXT: 0x20020 R_386_RELATIVE - 0x0
+# LLVM2-NEXT: 0x20028 R_386_RELATIVE - 0x0
+# LLVM2-NEXT: 0x20040 R_386_RELATIVE - 0x0
+# LLVM2-NEXT: 0x20044 R_386_RELATIVE - 0x0
+# LLVM2-NEXT: 0x20048 R_386_RELATIVE - 0x0
+# LLVM2-NEXT: 0x2004C R_386_RELATIVE - 0x0
+# LLVM2-NEXT: 0x20088 R_386_RELATIVE - 0x0
+# LLVM2-NEXT: 0x200D4 R_386_RELATIVE - 0x0
+# LLVM2-NEXT: 0x200EC R_386_RELATIVE - 0x0
+# LLVM2-NEXT: 0x200F4 R_386_RELATIVE - 0x0
+# LLVM2-NEXT: }
+
+# RUN: yaml2obj -docnum 2 %s \
+# RUN: | llvm-readobj -elf-output-style=GNU -relocations -raw-relr - \
+# RUN: | FileCheck --check-prefix=RAW-GNU2 %s
+# RAW-GNU2: Relocation section '.relr.dyn' at offset 0xfc contains 5 entries:
+# RAW-GNU2: 00010d60
+# RAW-GNU2-NEXT: 00000103
+# RAW-GNU2-NEXT: 00020000
+# RAW-GNU2-NEXT: 000f0501
+# RAW-GNU2-NEXT: 50400009
+
+# RUN: yaml2obj -docnum 2 %s \
+# RUN: | llvm-readobj -elf-output-style=GNU -relocations - \
+# RUN: | FileCheck --check-prefix=GNU2 %s
+# GNU2: Relocation section '.relr.dyn' at offset 0xfc contains 14 entries:
+# GNU2: 00010d60 00000008 R_386_RELATIVE
+# GNU2-NEXT: 00010d64 00000008 R_386_RELATIVE
+# GNU2-NEXT: 00010d80 00000008 R_386_RELATIVE
+# GNU2-NEXT: 00020000 00000008 R_386_RELATIVE
+# GNU2-NEXT: 00020020 00000008 R_386_RELATIVE
+# GNU2-NEXT: 00020028 00000008 R_386_RELATIVE
+# GNU2-NEXT: 00020040 00000008 R_386_RELATIVE
+# GNU2-NEXT: 00020044 00000008 R_386_RELATIVE
+# GNU2-NEXT: 00020048 00000008 R_386_RELATIVE
+# GNU2-NEXT: 0002004c 00000008 R_386_RELATIVE
+# GNU2-NEXT: 00020088 00000008 R_386_RELATIVE
+# GNU2-NEXT: 000200d4 00000008 R_386_RELATIVE
+# GNU2-NEXT: 000200ec 00000008 R_386_RELATIVE
+# GNU2-NEXT: 000200f4 00000008 R_386_RELATIVE
+
+# elf-relr-relocs2.s
+--- !ELF
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_DYN
+ Machine: EM_386
+ Entry: 0x00001000
+Sections:
+ - Name: .relr.dyn
+ Type: SHT_RELR
+ Flags: [ SHF_ALLOC ]
+ Address: 0x000001C8
+ Link: .symtab
+ AddressAlign: 0x00000001
+ Content: 600D0100030100000000020001050F0009004050
+...
using Elf_Dyn_Range = typename ELFT::DynRange; \
using Elf_Rel = typename ELFT::Rel; \
using Elf_Rela = typename ELFT::Rela; \
+ using Elf_Relr = typename ELFT::Relr; \
using Elf_Rel_Range = typename ELFT::RelRange; \
using Elf_Rela_Range = typename ELFT::RelaRange; \
+ using Elf_Relr_Range = typename ELFT::RelrRange; \
using Elf_Phdr = typename ELFT::Phdr; \
using Elf_Half = typename ELFT::Half; \
using Elf_Ehdr = typename ELFT::Ehdr; \
const ELFO *Obj;
DynRegionInfo DynRelRegion;
DynRegionInfo DynRelaRegion;
+ DynRegionInfo DynRelrRegion;
DynRegionInfo DynPLTRelRegion;
DynRegionInfo DynSymRegion;
DynRegionInfo DynamicTable;
Elf_Rel_Range dyn_rels() const;
Elf_Rela_Range dyn_relas() const;
+ Elf_Relr_Range dyn_relrs() const;
std::string getFullSymbolName(const Elf_Sym *Symbol, StringRef StrTable,
bool IsDynamic) const;
void getSectionNameIndex(const Elf_Sym *Symbol, const Elf_Sym *FirstSym,
StringRef getDynamicStringTable() const { return DynamicStringTable; }
const DynRegionInfo &getDynRelRegion() const { return DynRelRegion; }
const DynRegionInfo &getDynRelaRegion() const { return DynRelaRegion; }
+ const DynRegionInfo &getDynRelrRegion() const { return DynRelrRegion; }
const DynRegionInfo &getDynPLTRelRegion() const { return DynPLTRelRegion; }
const Elf_Hash *getHashTable() const { return HashTable; }
const Elf_GnuHash *getGnuHashTable() const { return GnuHashTable; }
}
void printHashedSymbol(const ELFO *Obj, const Elf_Sym *FirstSym, uint32_t Sym,
StringRef StrTable, uint32_t Bucket);
+ void printRelocHeader(unsigned SType);
void printRelocation(const ELFO *Obj, const Elf_Shdr *SymTab,
const Elf_Rela &R, bool IsRela);
void printSymbol(const ELFO *Obj, const Elf_Sym *Symbol, const Elf_Sym *First,
case ELF::DT_RELENT:
DynRelRegion.EntSize = Dyn.getVal();
break;
+ case ELF::DT_RELR:
+ case ELF::DT_ANDROID_RELR:
+ DynRelrRegion.Addr = toMappedAddr(Dyn.getPtr());
+ break;
+ case ELF::DT_RELRSZ:
+ case ELF::DT_ANDROID_RELRSZ:
+ DynRelrRegion.Size = Dyn.getVal();
+ break;
+ case ELF::DT_RELRENT:
+ case ELF::DT_ANDROID_RELRENT:
+ DynRelrRegion.EntSize = Dyn.getVal();
+ break;
case ELF::DT_PLTREL:
if (Dyn.getVal() == DT_REL)
DynPLTRelRegion.EntSize = sizeof(Elf_Rel);
return DynRelaRegion.getAsArrayRef<Elf_Rela>();
}
+template <typename ELFT>
+typename ELFDumper<ELFT>::Elf_Relr_Range ELFDumper<ELFT>::dyn_relrs() const {
+ return DynRelrRegion.getAsArrayRef<Elf_Relr>();
+}
+
template<class ELFT>
void ELFDumper<ELFT>::printFileHeaders() {
ELFDumperStyle->printFileHeaders(Obj);
const Elf_Rela &R, bool IsRela) {
std::string Offset, Info, Addend, Value;
SmallString<32> RelocName;
- StringRef StrTable = unwrapOrError(Obj->getStringTableForSymtab(*SymTab));
StringRef TargetName;
const Elf_Sym *Sym = nullptr;
unsigned Width = ELFT::Is64Bits ? 16 : 8;
Obj->getSection(Sym, SymTab, this->dumper()->getShndxTable()));
TargetName = unwrapOrError(Obj->getSectionName(Sec));
} else if (Sym) {
+ StringRef StrTable = unwrapOrError(Obj->getStringTableForSymtab(*SymTab));
TargetName = unwrapOrError(Sym->getName(StrTable));
}
OS << "\n";
}
-static inline void printRelocHeader(raw_ostream &OS, bool Is64, bool IsRela) {
- if (Is64)
- OS << " Offset Info Type"
+template <class ELFT> void GNUStyle<ELFT>::printRelocHeader(unsigned SType) {
+ bool IsRela = SType == ELF::SHT_RELA || SType == ELF::SHT_ANDROID_RELA;
+ bool IsRelr = SType == ELF::SHT_RELR || SType == ELF::SHT_ANDROID_RELR;
+ if (ELFT::Is64Bits)
+ OS << " ";
+ else
+ OS << " ";
+ if (IsRelr && opts::RawRelr)
+ OS << "Data ";
+ else
+ OS << "Offset";
+ if (ELFT::Is64Bits)
+ OS << " Info Type"
<< " Symbol's Value Symbol's Name";
else
- OS << " Offset Info Type Sym. Value "
- << "Symbol's Name";
+ OS << " Info Type Sym. Value Symbol's Name";
if (IsRela)
- OS << (IsRela ? " + Addend" : "");
+ OS << " + Addend";
OS << "\n";
}
template <class ELFT> void GNUStyle<ELFT>::printRelocations(const ELFO *Obj) {
bool HasRelocSections = false;
for (const Elf_Shdr &Sec : unwrapOrError(Obj->sections())) {
- if (Sec.sh_type != ELF::SHT_REL && Sec.sh_type != ELF::SHT_RELA &&
+ if (Sec.sh_type != ELF::SHT_REL &&
+ Sec.sh_type != ELF::SHT_RELA &&
+ Sec.sh_type != ELF::SHT_RELR &&
Sec.sh_type != ELF::SHT_ANDROID_REL &&
- Sec.sh_type != ELF::SHT_ANDROID_RELA)
+ Sec.sh_type != ELF::SHT_ANDROID_RELA &&
+ Sec.sh_type != ELF::SHT_ANDROID_RELR)
continue;
HasRelocSections = true;
StringRef Name = unwrapOrError(Obj->getSectionName(&Sec));
AndroidRelas = unwrapOrError(Obj->android_relas(&Sec));
Entries = AndroidRelas.size();
}
+ std::vector<Elf_Rela> RelrRelas;
+ if (!opts::RawRelr && (Sec.sh_type == ELF::SHT_RELR ||
+ Sec.sh_type == ELF::SHT_ANDROID_RELR)) {
+ // .relr.dyn relative relocation section needs to be unpacked first
+ // to get the actual number of entries.
+ Elf_Relr_Range Relrs = unwrapOrError(Obj->relrs(&Sec));
+ RelrRelas = unwrapOrError(Obj->decode_relrs(Relrs));
+ Entries = RelrRelas.size();
+ }
uintX_t Offset = Sec.sh_offset;
OS << "\nRelocation section '" << Name << "' at offset 0x"
<< to_hexString(Offset, false) << " contains " << Entries
<< " entries:\n";
- printRelocHeader(OS, ELFT::Is64Bits,
- Sec.sh_type == ELF::SHT_RELA ||
- Sec.sh_type == ELF::SHT_ANDROID_RELA);
+ printRelocHeader(Sec.sh_type);
const Elf_Shdr *SymTab = unwrapOrError(Obj->getSection(Sec.sh_link));
switch (Sec.sh_type) {
case ELF::SHT_REL:
for (const auto &R : unwrapOrError(Obj->relas(&Sec)))
printRelocation(Obj, SymTab, R, true);
break;
+ case ELF::SHT_RELR:
+ case ELF::SHT_ANDROID_RELR:
+ if (opts::RawRelr)
+ for (const auto &R : unwrapOrError(Obj->relrs(&Sec)))
+ OS << to_string(format_hex_no_prefix(R, ELFT::Is64Bits ? 16 : 8))
+ << "\n";
+ else
+ for (const auto &R : RelrRelas)
+ printRelocation(Obj, SymTab, R, false);
+ break;
case ELF::SHT_ANDROID_REL:
case ELF::SHT_ANDROID_RELA:
for (const auto &R : AndroidRelas)
return "GROUP";
case SHT_SYMTAB_SHNDX:
return "SYMTAB SECTION INDICES";
+ case SHT_RELR:
+ case SHT_ANDROID_RELR:
+ return "RELR";
case SHT_LLVM_ODRTAB:
return "LLVM_ODRTAB";
case SHT_LLVM_LINKER_OPTIONS:
void GNUStyle<ELFT>::printDynamicRelocations(const ELFO *Obj) {
const DynRegionInfo &DynRelRegion = this->dumper()->getDynRelRegion();
const DynRegionInfo &DynRelaRegion = this->dumper()->getDynRelaRegion();
+ const DynRegionInfo &DynRelrRegion = this->dumper()->getDynRelrRegion();
const DynRegionInfo &DynPLTRelRegion = this->dumper()->getDynPLTRelRegion();
if (DynRelaRegion.Size > 0) {
OS << "\n'RELA' relocation section at offset "
<< format_hex(reinterpret_cast<const uint8_t *>(DynRelaRegion.Addr) -
Obj->base(),
1) << " contains " << DynRelaRegion.Size << " bytes:\n";
- printRelocHeader(OS, ELFT::Is64Bits, true);
+ printRelocHeader(ELF::SHT_RELA);
for (const Elf_Rela &Rela : this->dumper()->dyn_relas())
printDynamicRelocation(Obj, Rela, true);
}
<< format_hex(reinterpret_cast<const uint8_t *>(DynRelRegion.Addr) -
Obj->base(),
1) << " contains " << DynRelRegion.Size << " bytes:\n";
- printRelocHeader(OS, ELFT::Is64Bits, false);
+ printRelocHeader(ELF::SHT_REL);
for (const Elf_Rel &Rel : this->dumper()->dyn_rels()) {
Elf_Rela Rela;
Rela.r_offset = Rel.r_offset;
printDynamicRelocation(Obj, Rela, false);
}
}
+ if (DynRelrRegion.Size > 0) {
+ OS << "\n'RELR' relocation section at offset "
+ << format_hex(reinterpret_cast<const uint8_t *>(DynRelrRegion.Addr) -
+ Obj->base(),
+ 1) << " contains " << DynRelrRegion.Size << " bytes:\n";
+ printRelocHeader(ELF::SHT_REL);
+ Elf_Relr_Range Relrs = this->dumper()->dyn_relrs();
+ std::vector<Elf_Rela> RelrRelas = unwrapOrError(Obj->decode_relrs(Relrs));
+ for (const Elf_Rela &Rela : RelrRelas) {
+ printDynamicRelocation(Obj, Rela, false);
+ }
+ }
if (DynPLTRelRegion.Size) {
OS << "\n'PLT' relocation section at offset "
<< format_hex(reinterpret_cast<const uint8_t *>(DynPLTRelRegion.Addr) -
1) << " contains " << DynPLTRelRegion.Size << " bytes:\n";
}
if (DynPLTRelRegion.EntSize == sizeof(Elf_Rela)) {
- printRelocHeader(OS, ELFT::Is64Bits, true);
+ printRelocHeader(ELF::SHT_RELA);
for (const Elf_Rela &Rela : DynPLTRelRegion.getAsArrayRef<Elf_Rela>())
printDynamicRelocation(Obj, Rela, true);
} else {
- printRelocHeader(OS, ELFT::Is64Bits, false);
+ printRelocHeader(ELF::SHT_REL);
for (const Elf_Rel &Rel : DynPLTRelRegion.getAsArrayRef<Elf_Rel>()) {
Elf_Rela Rela;
Rela.r_offset = Rel.r_offset;
for (const Elf_Shdr &Sec : unwrapOrError(Obj->sections())) {
++SectionNumber;
- if (Sec.sh_type != ELF::SHT_REL && Sec.sh_type != ELF::SHT_RELA &&
+ if (Sec.sh_type != ELF::SHT_REL &&
+ Sec.sh_type != ELF::SHT_RELA &&
+ Sec.sh_type != ELF::SHT_RELR &&
Sec.sh_type != ELF::SHT_ANDROID_REL &&
- Sec.sh_type != ELF::SHT_ANDROID_RELA)
+ Sec.sh_type != ELF::SHT_ANDROID_RELA &&
+ Sec.sh_type != ELF::SHT_ANDROID_RELR)
continue;
StringRef Name = unwrapOrError(Obj->getSectionName(&Sec));
for (const Elf_Rela &R : unwrapOrError(Obj->relas(Sec)))
printRelocation(Obj, R, SymTab);
break;
+ case ELF::SHT_RELR:
+ case ELF::SHT_ANDROID_RELR: {
+ Elf_Relr_Range Relrs = unwrapOrError(Obj->relrs(Sec));
+ if (opts::RawRelr) {
+ for (const Elf_Relr &R : Relrs)
+ W.startLine() << W.hex(R) << "\n";
+ } else {
+ std::vector<Elf_Rela> RelrRelas = unwrapOrError(Obj->decode_relrs(Relrs));
+ for (const Elf_Rela &R : RelrRelas)
+ printRelocation(Obj, R, SymTab);
+ }
+ break;
+ }
case ELF::SHT_ANDROID_REL:
case ELF::SHT_ANDROID_RELA:
for (const Elf_Rela &R : unwrapOrError(Obj->android_relas(Sec)))
void LLVMStyle<ELFT>::printDynamicRelocations(const ELFO *Obj) {
const DynRegionInfo &DynRelRegion = this->dumper()->getDynRelRegion();
const DynRegionInfo &DynRelaRegion = this->dumper()->getDynRelaRegion();
+ const DynRegionInfo &DynRelrRegion = this->dumper()->getDynRelrRegion();
const DynRegionInfo &DynPLTRelRegion = this->dumper()->getDynPLTRelRegion();
if (DynRelRegion.Size && DynRelaRegion.Size)
report_fatal_error("There are both REL and RELA dynamic relocations");
Rela.r_addend = 0;
printDynamicRelocation(Obj, Rela);
}
+ if (DynRelrRegion.Size > 0) {
+ Elf_Relr_Range Relrs = this->dumper()->dyn_relrs();
+ std::vector<Elf_Rela> RelrRelas = unwrapOrError(Obj->decode_relrs(Relrs));
+ for (const Elf_Rela &Rela : RelrRelas)
+ printDynamicRelocation(Obj, Rela);
+ }
if (DynPLTRelRegion.EntSize == sizeof(Elf_Rela))
for (const Elf_Rela &Rela : DynPLTRelRegion.getAsArrayRef<Elf_Rela>())
printDynamicRelocation(Obj, Rela);
cl::opt<bool> ExpandRelocs("expand-relocs",
cl::desc("Expand each shown relocation to multiple lines"));
+ // -raw-relr
+ cl::opt<bool> RawRelr("raw-relr",
+ cl::desc("Do not decode relocations in SHT_RELR section, display raw contents"));
+
// -codeview
cl::opt<bool> CodeView("codeview",
cl::desc("Display CodeView debug information"));
extern llvm::cl::opt<bool> DynamicSymbols;
extern llvm::cl::opt<bool> UnwindInfo;
extern llvm::cl::opt<bool> ExpandRelocs;
+ extern llvm::cl::opt<bool> RawRelr;
extern llvm::cl::opt<bool> CodeView;
extern llvm::cl::opt<bool> CodeViewSubsectionBytes;
extern llvm::cl::opt<bool> ARMAttributes;
typedef typename ELFT::Sym Elf_Sym;
typedef typename ELFT::Rel Elf_Rel;
typedef typename ELFT::Rela Elf_Rela;
+ typedef typename ELFT::Relr Elf_Relr;
enum class SymtabType { Static, Dynamic };
Section.Content.writeAsBinary(OS);
for (auto i = Section.Content.binary_size(); i < Section.Size; ++i)
OS.write(0);
- SHeader.sh_entsize = 0;
+ if (Section.Type == llvm::ELF::SHT_RELR)
+ SHeader.sh_entsize = sizeof(Elf_Relr);
+ else
+ SHeader.sh_entsize = 0;
SHeader.sh_size = Section.Size;
}