From 0f440d832f98f665278f104149109adc9e7eab23 Mon Sep 17 00:00:00 2001 From: Jake Ehrlich Date: Thu, 28 Jun 2018 21:07:34 +0000 Subject: [PATCH] [llvm-readobj] Add experimental support for SHT_RELR sections This change adds experimental support for SHT_RELR sections, proposed here: https://groups.google.com/forum/#!topic/generic-abi/bX460iggiKg Definitions for the new ELF section type and dynamic array tags, as well as the encoding used in the new section are all under discussion and are subject to change. Use with caution! Author: rahulchaudhry Differential Revision: https://reviews.llvm.org/D47919 llvm-svn: 335922 --- llvm/include/llvm/BinaryFormat/DynamicTags.def | 12 ++ llvm/include/llvm/BinaryFormat/ELF.h | 12 ++ llvm/include/llvm/Object/ELF.h | 15 ++ llvm/include/llvm/Object/ELFTypes.h | 2 + llvm/lib/Object/ELF.cpp | 127 +++++++++++++++ llvm/lib/ObjectYAML/ELFYAML.cpp | 2 + .../tools/llvm-readobj/Inputs/elf-relr-relocs1.s | 5 + .../tools/llvm-readobj/Inputs/elf-relr-relocs2.s | 5 + llvm/test/tools/llvm-readobj/elf-relr-relocs.test | 172 +++++++++++++++++++++ llvm/tools/llvm-readobj/ELFDumper.cpp | 127 ++++++++++++--- llvm/tools/llvm-readobj/llvm-readobj.cpp | 4 + llvm/tools/llvm-readobj/llvm-readobj.h | 1 + llvm/tools/yaml2obj/yaml2elf.cpp | 6 +- 13 files changed, 471 insertions(+), 19 deletions(-) create mode 100644 llvm/test/tools/llvm-readobj/Inputs/elf-relr-relocs1.s create mode 100644 llvm/test/tools/llvm-readobj/Inputs/elf-relr-relocs2.s create mode 100644 llvm/test/tools/llvm-readobj/elf-relr-relocs.test diff --git a/llvm/include/llvm/BinaryFormat/DynamicTags.def b/llvm/include/llvm/BinaryFormat/DynamicTags.def index 40b2b2a..2e15cc30 100644 --- a/llvm/include/llvm/BinaryFormat/DynamicTags.def +++ b/llvm/include/llvm/BinaryFormat/DynamicTags.def @@ -65,6 +65,12 @@ DYNAMIC_TAG(PREINIT_ARRAYSZ, 33) // Size of the DT_PREINIT_ARRAY array. 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. @@ -77,6 +83,12 @@ DYNAMIC_TAG(ANDROID_RELSZ, 0x60000010) 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. diff --git a/llvm/include/llvm/BinaryFormat/ELF.h b/llvm/include/llvm/BinaryFormat/ELF.h index 3a8afbe..37940a4 100644 --- a/llvm/include/llvm/BinaryFormat/ELF.h +++ b/llvm/include/llvm/BinaryFormat/ELF.h @@ -796,6 +796,9 @@ enum : unsigned { 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 @@ -804,6 +807,9 @@ enum : unsigned { 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. @@ -1067,6 +1073,9 @@ struct Elf32_Rela { } }; +// 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). @@ -1100,6 +1109,9 @@ struct Elf64_Rela { } }; +// 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 diff --git a/llvm/include/llvm/Object/ELF.h b/llvm/include/llvm/Object/ELF.h index c0fcda3..1700dbe 100644 --- a/llvm/include/llvm/Object/ELF.h +++ b/llvm/include/llvm/Object/ELF.h @@ -32,6 +32,7 @@ namespace llvm { 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 @@ -60,6 +61,7 @@ public: 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; @@ -75,6 +77,7 @@ public: 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 { @@ -110,6 +113,7 @@ public: StringRef getRelocationTypeName(uint32_t Type) const; void getRelocationTypeName(uint32_t Type, SmallVectorImpl &Result) const; + uint32_t getRelrRelocationType() const; /// Get the symbol for a given relocation. Expected getRelocationSymbol(const Elf_Rel *Rel, @@ -143,6 +147,12 @@ public: return getSectionContentsAsArray(Sec); } + Expected relrs(const Elf_Shdr *Sec) const { + return getSectionContentsAsArray(Sec); + } + + Expected> decode_relrs(Elf_Relr_Range relrs) const; + Expected> android_relas(const Elf_Shdr *Sec) const; /// Iterate over program header table. @@ -398,6 +408,11 @@ void ELFFile::getRelocationTypeName(uint32_t Type, } template +uint32_t ELFFile::getRelrRelocationType() const { + return getELFRelrRelocationType(getHeader()->e_machine); +} + +template Expected ELFFile::getRelocationSymbol(const Elf_Rel *Rel, const Elf_Shdr *SymTab) const { diff --git a/llvm/include/llvm/Object/ELFTypes.h b/llvm/include/llvm/Object/ELFTypes.h index 78a1b98..fb38612 100644 --- a/llvm/include/llvm/Object/ELFTypes.h +++ b/llvm/include/llvm/Object/ELFTypes.h @@ -62,6 +62,7 @@ public: using Phdr = Elf_Phdr_Impl>; using Rel = Elf_Rel_Impl, false>; using Rela = Elf_Rel_Impl, true>; + using Relr = packed; using Verdef = Elf_Verdef_Impl>; using Verdaux = Elf_Verdaux_Impl>; using Verneed = Elf_Verneed_Impl>; @@ -79,6 +80,7 @@ public: using SymRange = ArrayRef; using RelRange = ArrayRef; using RelaRange = ArrayRef; + using RelrRange = ArrayRef; using PhdrRange = ArrayRef; using Half = packed; diff --git a/llvm/lib/Object/ELF.cpp b/llvm/lib/Object/ELF.cpp index 965c38a..3477da0 100644 --- a/llvm/lib/Object/ELF.cpp +++ b/llvm/lib/Object/ELF.cpp @@ -154,6 +154,52 @@ StringRef llvm::object::getELFRelocationTypeName(uint32_t Machine, #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: @@ -202,8 +248,10 @@ 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_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); @@ -219,6 +267,85 @@ StringRef llvm::object::getELFSectionTypeName(uint32_t Machine, unsigned Type) { template Expected> +ELFFile::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 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 +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. diff --git a/llvm/lib/ObjectYAML/ELFYAML.cpp b/llvm/lib/ObjectYAML/ELFYAML.cpp index 455ecfb..8964f5c 100644 --- a/llvm/lib/ObjectYAML/ELFYAML.cpp +++ b/llvm/lib/ObjectYAML/ELFYAML.cpp @@ -436,9 +436,11 @@ void ScalarEnumerationTraits::enumeration( 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); diff --git a/llvm/test/tools/llvm-readobj/Inputs/elf-relr-relocs1.s b/llvm/test/tools/llvm-readobj/Inputs/elf-relr-relocs1.s new file mode 100644 index 0000000..ec4e9ca --- /dev/null +++ b/llvm/test/tools/llvm-readobj/Inputs/elf-relr-relocs1.s @@ -0,0 +1,5 @@ +.quad 0x0000000000010d60 // Initial offset +.quad 0x0000000000000103 // Continuation bitmap +.quad 0x0000000000020000 // New offset +.quad 0x00000000000f0501 // Continuation bitmap +.quad 0x000a700550400009 // Continuation bitmap diff --git a/llvm/test/tools/llvm-readobj/Inputs/elf-relr-relocs2.s b/llvm/test/tools/llvm-readobj/Inputs/elf-relr-relocs2.s new file mode 100644 index 0000000..515d578 --- /dev/null +++ b/llvm/test/tools/llvm-readobj/Inputs/elf-relr-relocs2.s @@ -0,0 +1,5 @@ +.long 0x00010d60 // Initial offset +.long 0x00000103 // Continuation bitmap +.long 0x00020000 // New offset +.long 0x000f0501 // Continuation bitmap +.long 0x50400009 // Continuation bitmap diff --git a/llvm/test/tools/llvm-readobj/elf-relr-relocs.test b/llvm/test/tools/llvm-readobj/elf-relr-relocs.test new file mode 100644 index 0000000..230faff --- /dev/null +++ b/llvm/test/tools/llvm-readobj/elf-relr-relocs.test @@ -0,0 +1,172 @@ +# 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 +... diff --git a/llvm/tools/llvm-readobj/ELFDumper.cpp b/llvm/tools/llvm-readobj/ELFDumper.cpp index 05bcd1a..9a2be31 100644 --- a/llvm/tools/llvm-readobj/ELFDumper.cpp +++ b/llvm/tools/llvm-readobj/ELFDumper.cpp @@ -85,8 +85,10 @@ using namespace ELF; 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; \ @@ -206,6 +208,7 @@ private: const ELFO *Obj; DynRegionInfo DynRelRegion; DynRegionInfo DynRelaRegion; + DynRegionInfo DynRelrRegion; DynRegionInfo DynPLTRelRegion; DynRegionInfo DynSymRegion; DynRegionInfo DynamicTable; @@ -257,6 +260,7 @@ public: 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, @@ -271,6 +275,7 @@ public: 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; } @@ -392,6 +397,7 @@ private: } 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, @@ -1492,6 +1498,18 @@ void ELFDumper::parseDynamicTable( 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); @@ -1525,6 +1543,11 @@ typename ELFDumper::Elf_Rela_Range ELFDumper::dyn_relas() const { return DynRelaRegion.getAsArrayRef(); } +template +typename ELFDumper::Elf_Relr_Range ELFDumper::dyn_relrs() const { + return DynRelrRegion.getAsArrayRef(); +} + template void ELFDumper::printFileHeaders() { ELFDumperStyle->printFileHeaders(Obj); @@ -2582,7 +2605,6 @@ void GNUStyle::printRelocation(const ELFO *Obj, const Elf_Shdr *SymTab, 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; @@ -2598,6 +2620,7 @@ void GNUStyle::printRelocation(const ELFO *Obj, const Elf_Shdr *SymTab, 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)); } @@ -2629,24 +2652,36 @@ void GNUStyle::printRelocation(const ELFO *Obj, const Elf_Shdr *SymTab, OS << "\n"; } -static inline void printRelocHeader(raw_ostream &OS, bool Is64, bool IsRela) { - if (Is64) - OS << " Offset Info Type" +template void GNUStyle::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 void GNUStyle::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)); @@ -2659,13 +2694,20 @@ template void GNUStyle::printRelocations(const ELFO *Obj) { AndroidRelas = unwrapOrError(Obj->android_relas(&Sec)); Entries = AndroidRelas.size(); } + std::vector 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: @@ -2681,6 +2723,16 @@ template void GNUStyle::printRelocations(const ELFO *Obj) { 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) @@ -2762,6 +2814,9 @@ std::string getSectionTypeString(unsigned Arch, unsigned Type) { 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: @@ -3300,13 +3355,14 @@ template void GNUStyle::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(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); } @@ -3315,7 +3371,7 @@ void GNUStyle::printDynamicRelocations(const ELFO *Obj) { << format_hex(reinterpret_cast(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; @@ -3324,6 +3380,18 @@ void GNUStyle::printDynamicRelocations(const ELFO *Obj) { printDynamicRelocation(Obj, Rela, false); } } + if (DynRelrRegion.Size > 0) { + OS << "\n'RELR' relocation section at offset " + << format_hex(reinterpret_cast(DynRelrRegion.Addr) - + Obj->base(), + 1) << " contains " << DynRelrRegion.Size << " bytes:\n"; + printRelocHeader(ELF::SHT_REL); + Elf_Relr_Range Relrs = this->dumper()->dyn_relrs(); + std::vector 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(DynPLTRelRegion.Addr) - @@ -3331,11 +3399,11 @@ void GNUStyle::printDynamicRelocations(const ELFO *Obj) { 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()) printDynamicRelocation(Obj, Rela, true); } else { - printRelocHeader(OS, ELFT::Is64Bits, false); + printRelocHeader(ELF::SHT_REL); for (const Elf_Rel &Rel : DynPLTRelRegion.getAsArrayRef()) { Elf_Rela Rela; Rela.r_offset = Rel.r_offset; @@ -3956,9 +4024,12 @@ template void LLVMStyle::printRelocations(const ELFO *Obj) { 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)); @@ -3991,6 +4062,19 @@ void LLVMStyle::printRelocations(const Elf_Shdr *Sec, const ELFO *Obj) { 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 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))) @@ -4171,6 +4255,7 @@ template void LLVMStyle::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"); @@ -4187,6 +4272,12 @@ void LLVMStyle::printDynamicRelocations(const ELFO *Obj) { Rela.r_addend = 0; printDynamicRelocation(Obj, Rela); } + if (DynRelrRegion.Size > 0) { + Elf_Relr_Range Relrs = this->dumper()->dyn_relrs(); + std::vector 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()) printDynamicRelocation(Obj, Rela); diff --git a/llvm/tools/llvm-readobj/llvm-readobj.cpp b/llvm/tools/llvm-readobj/llvm-readobj.cpp index 22a8fcd..aa2cc76 100644 --- a/llvm/tools/llvm-readobj/llvm-readobj.cpp +++ b/llvm/tools/llvm-readobj/llvm-readobj.cpp @@ -164,6 +164,10 @@ namespace opts { cl::opt ExpandRelocs("expand-relocs", cl::desc("Expand each shown relocation to multiple lines")); + // -raw-relr + cl::opt RawRelr("raw-relr", + cl::desc("Do not decode relocations in SHT_RELR section, display raw contents")); + // -codeview cl::opt CodeView("codeview", cl::desc("Display CodeView debug information")); diff --git a/llvm/tools/llvm-readobj/llvm-readobj.h b/llvm/tools/llvm-readobj/llvm-readobj.h index 840ddba..374ffd0 100644 --- a/llvm/tools/llvm-readobj/llvm-readobj.h +++ b/llvm/tools/llvm-readobj/llvm-readobj.h @@ -60,6 +60,7 @@ namespace opts { extern llvm::cl::opt DynamicSymbols; extern llvm::cl::opt UnwindInfo; extern llvm::cl::opt ExpandRelocs; + extern llvm::cl::opt RawRelr; extern llvm::cl::opt CodeView; extern llvm::cl::opt CodeViewSubsectionBytes; extern llvm::cl::opt ARMAttributes; diff --git a/llvm/tools/yaml2obj/yaml2elf.cpp b/llvm/tools/yaml2obj/yaml2elf.cpp index 59da937..4dc5215 100644 --- a/llvm/tools/yaml2obj/yaml2elf.cpp +++ b/llvm/tools/yaml2obj/yaml2elf.cpp @@ -114,6 +114,7 @@ class ELFState { 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 }; @@ -459,7 +460,10 @@ ELFState::writeSectionContent(Elf_Shdr &SHeader, 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; } -- 2.7.4