Index: llvm/include/llvm/BinaryFormat/ELF.h =================================================================== --- llvm/include/llvm/BinaryFormat/ELF.h +++ llvm/include/llvm/BinaryFormat/ELF.h @@ -730,6 +730,10 @@ SHT_GROUP = 17, // Section group. SHT_SYMTAB_SHNDX = 18, // Indices for SHN_XINDEX entries. 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_ANDROID_REL = 0x60000001, + SHT_ANDROID_RELA = 0x60000002, SHT_LLVM_ODRTAB = 0x6fff4c00, // LLVM ODR table. SHT_GNU_ATTRIBUTES = 0x6ffffff5, // Object attributes. SHT_GNU_HASH = 0x6ffffff6, // GNU-style hash table. @@ -1166,6 +1170,13 @@ DT_LOPROC = 0x70000000, // Start of processor specific tags. DT_HIPROC = 0x7FFFFFFF, // End of processor specific tags. + // Android packed relocation section tags. + // https://android.googlesource.com/platform/bionic/+/6f12bfece5dcc01325e0abba56a46b1bcf991c69/tools/relocation_packer/src/elf_file.cc#31 + DT_ANDROID_REL = 0x6000000F, + DT_ANDROID_RELSZ = 0x60000010, + DT_ANDROID_RELA = 0x60000011, + DT_ANDROID_RELASZ = 0x60000012, + DT_GNU_HASH = 0x6FFFFEF5, // Reference to the GNU hash table. DT_TLSDESC_PLT = 0x6FFFFEF6, // Location of PLT entry for TLS descriptor resolver calls. @@ -1387,6 +1398,14 @@ GNU_ABI_TAG_NACL = 6, }; +// Android packed relocation group flags. +enum { + RELOCATION_GROUPED_BY_INFO_FLAG = 1, + RELOCATION_GROUPED_BY_OFFSET_DELTA_FLAG = 2, + RELOCATION_GROUPED_BY_ADDEND_FLAG = 4, + RELOCATION_GROUP_HAS_ADDEND_FLAG = 8, +}; + // Compressed section header for ELF32. struct Elf32_Chdr { Elf32_Word ch_type; Index: llvm/include/llvm/Object/ELF.h =================================================================== --- llvm/include/llvm/Object/ELF.h +++ llvm/include/llvm/Object/ELF.h @@ -142,6 +142,8 @@ return getSectionContentsAsArray(Sec); } + Expected> android_relas(const Elf_Shdr *Sec) const; + /// \brief Iterate over program header table. Expected program_headers() const { if (getHeader()->e_phnum && getHeader()->e_phentsize != sizeof(Elf_Phdr)) Index: llvm/lib/Object/ELF.cpp =================================================================== --- llvm/lib/Object/ELF.cpp +++ llvm/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; @@ -474,6 +475,90 @@ 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; Index: llvm/lib/ObjectYAML/ELFYAML.cpp =================================================================== --- llvm/lib/ObjectYAML/ELFYAML.cpp +++ llvm/lib/ObjectYAML/ELFYAML.cpp @@ -405,6 +405,8 @@ ECase(SHT_GROUP); ECase(SHT_SYMTAB_SHNDX); ECase(SHT_LOOS); + ECase(SHT_ANDROID_REL); + ECase(SHT_ANDROID_RELA); ECase(SHT_LLVM_ODRTAB); ECase(SHT_GNU_ATTRIBUTES); ECase(SHT_GNU_HASH); Index: llvm/test/tools/llvm-readobj/Inputs/elf-packed-relocs1.s =================================================================== --- /dev/null +++ llvm/test/tools/llvm-readobj/Inputs/elf-packed-relocs1.s @@ -0,0 +1,37 @@ +.ascii "APS2" +.sleb128 8 // Number of relocations +.sleb128 4096 // Initial offset + +.sleb128 2 // Number of relocations in group +.sleb128 1 // RELOCATION_GROUPED_BY_INFO_FLAG +.sleb128 8 // R_X86_RELATIVE + +.sleb128 256 // Reloc 1: r_offset delta +.sleb128 128 // Reloc 2: r_offset delta + +.sleb128 2 // Number of relocations in group +.sleb128 2 // RELOCATION_GROUPED_BY_OFFSET_DELTA_FLAG +.sleb128 8 // offset delta + +.sleb128 (1 << 32) | 1 // R_X86_64_64 (sym index 1) +.sleb128 (2 << 32) | 1 // R_X86_64_64 (sym index 2) + +.sleb128 2 // Number of relocations in group +.sleb128 8 // RELOCATION_GROUP_HAS_ADDEND_FLAG + +.sleb128 1 // offset delta +.sleb128 (1 << 32) | 1 // R_X86_64_64 (sym index 1) +.sleb128 8 // addend delta + +.sleb128 2 // offset delta +.sleb128 (2 << 32) | 1 // R_X86_64_64 (sym index 2) +.sleb128 4 // addend delta + +.sleb128 2 // Number of relocations in group +.sleb128 12 // RELOCATION_GROUP_HAS_ADDEND_FLAG | RELOCATION_GROUPED_BY_ADDEND_FLAG +.sleb128 -2 // addend delta + +.sleb128 4 // offset delta +.sleb128 (1 << 32) | 1 // R_X86_64_64 (sym index 1) +.sleb128 8 // offset delta +.sleb128 (2 << 32) | 1 // R_X86_64_64 (sym index 2) Index: llvm/test/tools/llvm-readobj/Inputs/elf-packed-relocs2.s =================================================================== --- /dev/null +++ llvm/test/tools/llvm-readobj/Inputs/elf-packed-relocs2.s @@ -0,0 +1,15 @@ +.ascii "APS2" +.sleb128 10 // Number of relocations +.sleb128 4096 // Initial offset + +.sleb128 2 // Number of relocations in group +.sleb128 2 // RELOCATION_GROUPED_BY_OFFSET_DELTA_FLAG +.sleb128 8 // offset delta + +.sleb128 (1 << 8) | 1 // R_386_32 (sym index 1) +.sleb128 (2 << 8) | 3 // R_386_GOT32 (sym index 2) + +.sleb128 8 // Number of relocations in group +.sleb128 3 // RELOCATION_GROUPED_BY_OFFSET_DELTA_FLAG | RELOCATION_GROUPED_BY_INFO_FLAG +.sleb128 -4 // offset delta +.sleb128 8 // R_386_RELATIVE Index: llvm/test/tools/llvm-readobj/elf-packed-relocs-empty.s =================================================================== --- /dev/null +++ llvm/test/tools/llvm-readobj/elf-packed-relocs-empty.s @@ -0,0 +1,11 @@ +// RUN: llvm-mc -filetype=obj -triple x86_64-pc-linux-gnu %s -o - | llvm-readobj -relocations - | FileCheck %s + +// CHECK: Relocations [ +// CHECK-NEXT: Section (3) .rela.dyn { +// CHECK-NEXT: } +// CHECK-NEXT: ] + +.section .rela.dyn, "a", @0x60000001 +.ascii "APS2" +.sleb128 0 +.sleb128 0 Index: llvm/test/tools/llvm-readobj/elf-packed-relocs-error1.s =================================================================== --- /dev/null +++ llvm/test/tools/llvm-readobj/elf-packed-relocs-error1.s @@ -0,0 +1,6 @@ +// RUN: llvm-mc -filetype=obj -triple x86_64-pc-linux-gnu %s -o - | not llvm-readobj -relocations - 2>&1 | FileCheck %s + +// CHECK: Error reading file: invalid packed relocation header + +.section .rela.dyn, "a", @0x60000001 +.ascii "APS9" Index: llvm/test/tools/llvm-readobj/elf-packed-relocs-error2.s =================================================================== --- /dev/null +++ llvm/test/tools/llvm-readobj/elf-packed-relocs-error2.s @@ -0,0 +1,6 @@ +// RUN: llvm-mc -filetype=obj -triple x86_64-pc-linux-gnu %s -o - | not llvm-readobj -relocations - 2>&1 | FileCheck %s + +// CHECK: Error reading file: malformed sleb128, extends past end + +.section .rela.dyn, "a", @0x60000001 +.ascii "APS2" Index: llvm/test/tools/llvm-readobj/elf-packed-relocs-error3.s =================================================================== --- /dev/null +++ llvm/test/tools/llvm-readobj/elf-packed-relocs-error3.s @@ -0,0 +1,8 @@ +// RUN: llvm-mc -filetype=obj -triple x86_64-pc-linux-gnu %s -o - | not llvm-readobj -relocations - 2>&1 | FileCheck %s + +// CHECK: Error reading file: malformed sleb128, extends past end + +.section .rela.dyn, "a", @0x60000001 +.ascii "APS2" +.sleb128 4 // Number of relocations +.sleb128 0 // Initial offset Index: llvm/test/tools/llvm-readobj/elf-packed-relocs-error4.s =================================================================== --- /dev/null +++ llvm/test/tools/llvm-readobj/elf-packed-relocs-error4.s @@ -0,0 +1,12 @@ +// RUN: llvm-mc -filetype=obj -triple x86_64-pc-linux-gnu %s -o - | not llvm-readobj -relocations - 2>&1 | FileCheck %s + +// CHECK: Error reading file: malformed sleb128, extends past end + +.section .rela.dyn, "a", @0x60000001 +.ascii "APS2" +.sleb128 4 // Number of relocations +.sleb128 0 // Initial offset + +.sleb128 2 // Number of relocations in group +.sleb128 2 // RELOCATION_GROUPED_BY_OFFSET_DELTA_FLAG +.sleb128 8 // offset delta Index: llvm/test/tools/llvm-readobj/elf-packed-relocs-error5.s =================================================================== --- /dev/null +++ llvm/test/tools/llvm-readobj/elf-packed-relocs-error5.s @@ -0,0 +1,12 @@ +// RUN: llvm-mc -filetype=obj -triple x86_64-pc-linux-gnu %s -o - | not llvm-readobj -relocations - 2>&1 | FileCheck %s + +// CHECK: Error reading file: relocation group unexpectedly large + +.section .rela.dyn, "a", @0x60000001 +.ascii "APS2" +.sleb128 4 // Number of relocations +.sleb128 0 // Initial offset + +.sleb128 5 // Number of relocations in group +.sleb128 2 // RELOCATION_GROUPED_BY_OFFSET_DELTA_FLAG +.sleb128 8 // offset delta Index: llvm/test/tools/llvm-readobj/elf-packed-relocs.test =================================================================== --- /dev/null +++ llvm/test/tools/llvm-readobj/elf-packed-relocs.test @@ -0,0 +1,94 @@ +# The binary blobs in this file were created like this: +# llvm-mc -filetype=obj -triple x86_64-pc-linux-gnu Inputs/elf-packed-relocs1.s -o - | obj2yaml | grep Content: + +# RUN: yaml2obj -docnum 1 %s | llvm-readobj -elf-output-style=LLVM -relocations - | FileCheck --check-prefix=LLVM1 %s +# LLVM1: Section (1) .rela.dyn { +# LLVM1-NEXT: 0x1100 R_X86_64_RELATIVE - 0x0 +# LLVM1-NEXT: 0x1180 R_X86_64_RELATIVE - 0x0 +# LLVM1-NEXT: 0x1188 R_X86_64_64 sym1 0x0 +# LLVM1-NEXT: 0x1190 R_X86_64_64 sym2 0x0 +# LLVM1-NEXT: 0x1191 R_X86_64_64 sym1 0x8 +# LLVM1-NEXT: 0x1193 R_X86_64_64 sym2 0xC +# LLVM1-NEXT: 0x1197 R_X86_64_64 sym1 0xA +# LLVM1-NEXT: 0x119F R_X86_64_64 sym2 0xA +# LLVM1-NEXT: } + +# RUN: yaml2obj -docnum 1 %s | llvm-readobj -elf-output-style=GNU -relocations - | FileCheck --check-prefix=GNU1 %s +# GNU1: 0000000000001100 0000000000000008 R_X86_64_RELATIVE 0 +# GNU1-NEXT: 0000000000001180 0000000000000008 R_X86_64_RELATIVE 0 +# GNU1-NEXT: 0000000000001188 0000000100000001 R_X86_64_64 0000000000000000 sym1 + 0 +# GNU1-NEXT: 0000000000001190 0000000200000001 R_X86_64_64 0000000000000000 sym2 + 0 +# GNU1-NEXT: 0000000000001191 0000000100000001 R_X86_64_64 0000000000000000 sym1 + 8 +# GNU1-NEXT: 0000000000001193 0000000200000001 R_X86_64_64 0000000000000000 sym2 + c +# GNU1-NEXT: 0000000000001197 0000000100000001 R_X86_64_64 0000000000000000 sym1 + a +# GNU1-NEXT: 000000000000119f 0000000200000001 R_X86_64_64 0000000000000000 sym2 + a + +# elf-packed-relocs1.s +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_DYN + Machine: EM_X86_64 + Entry: 0x0000000000001000 +Sections: + - Name: .rela.dyn + Type: SHT_ANDROID_RELA + Flags: [ SHF_ALLOC ] + Address: 0x00000000000001C8 + Link: .symtab + AddressAlign: 0x0000000000000001 + Content: 41505332088020020108800280010202088180808010818080802002080181808080100802818080802004020C7E048180808010088180808020 +Symbols: + Global: + - Name: sym1 + - Name: sym2 +... + +# RUN: yaml2obj -docnum 2 %s | llvm-readobj -elf-output-style=LLVM -relocations - | FileCheck --check-prefix=LLVM2 %s +# LLVM2: Section (1) .rel.dyn { +# LLVM2-NEXT: 0x1008 R_386_32 sym1 0x0 +# LLVM2-NEXT: 0x1010 R_386_GOT32 sym2 0x0 +# LLVM2-NEXT: 0x100C R_386_RELATIVE - 0x0 +# LLVM2-NEXT: 0x1008 R_386_RELATIVE - 0x0 +# LLVM2-NEXT: 0x1004 R_386_RELATIVE - 0x0 +# LLVM2-NEXT: 0x1000 R_386_RELATIVE - 0x0 +# LLVM2-NEXT: 0xFFC R_386_RELATIVE - 0x0 +# LLVM2-NEXT: 0xFF8 R_386_RELATIVE - 0x0 +# LLVM2-NEXT: 0xFF4 R_386_RELATIVE - 0x0 +# LLVM2-NEXT: 0xFF0 R_386_RELATIVE - 0x0 +# LLVM2-NEXT: } + +# RUN: yaml2obj -docnum 2 %s | llvm-readobj -elf-output-style=GNU -relocations - | FileCheck --check-prefix=GNU2 %s +# GNU2: 00001008 00000101 R_386_32 00000000 sym1 +# GNU2-NEXT: 00001010 00000203 R_386_GOT32 00000000 sym2 +# GNU2-NEXT: 0000100c 00000008 R_386_RELATIVE +# GNU2-NEXT: 00001008 00000008 R_386_RELATIVE +# GNU2-NEXT: 00001004 00000008 R_386_RELATIVE +# GNU2-NEXT: 00001000 00000008 R_386_RELATIVE +# GNU2-NEXT: 00000ffc 00000008 R_386_RELATIVE +# GNU2-NEXT: 00000ff8 00000008 R_386_RELATIVE +# GNU2-NEXT: 00000ff4 00000008 R_386_RELATIVE +# GNU2-NEXT: 00000ff0 00000008 R_386_RELATIVE + +# elf-packed-relocs2.s +--- !ELF +FileHeader: + Class: ELFCLASS32 + Data: ELFDATA2LSB + Type: ET_DYN + Machine: EM_386 + Entry: 0x0000000000001000 +Sections: + - Name: .rel.dyn + Type: SHT_ANDROID_REL + Flags: [ SHF_ALLOC ] + Address: 0x00000000000001C8 + Link: .symtab + AddressAlign: 0x0000000000000001 + Content: 415053320A80200202088102830408037C08 +Symbols: + Global: + - Name: sym1 + - Name: sym2 +... Index: llvm/tools/llvm-readobj/ELFDumper.cpp =================================================================== --- llvm/tools/llvm-readobj/ELFDumper.cpp +++ llvm/tools/llvm-readobj/ELFDumper.cpp @@ -2594,7 +2594,9 @@ 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_ANDROID_REL && + Sec.sh_type != ELF::SHT_ANDROID_RELA) continue; HasRelocSections = true; StringRef Name = unwrapOrError(Obj->getSectionName(&Sec)); @@ -2603,9 +2605,12 @@ 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)); + printRelocHeader(OS, ELFT::Is64Bits, + Sec.sh_type == ELF::SHT_RELA || + Sec.sh_type == ELF::SHT_ANDROID_RELA); const Elf_Shdr *SymTab = unwrapOrError(Obj->getSection(Sec.sh_link)); - if (Sec.sh_type == ELF::SHT_REL) { + switch (Sec.sh_type) { + case ELF::SHT_REL: for (const auto &R : unwrapOrError(Obj->rels(&Sec))) { Elf_Rela Rela; Rela.r_offset = R.r_offset; @@ -2613,9 +2618,16 @@ Rela.r_addend = 0; printRelocation(Obj, SymTab, Rela, false); } - } else { + break; + case ELF::SHT_RELA: for (const auto &R : unwrapOrError(Obj->relas(&Sec))) printRelocation(Obj, SymTab, R, true); + break; + case ELF::SHT_ANDROID_REL: + case ELF::SHT_ANDROID_RELA: + for (const auto &R : unwrapOrError(Obj->android_relas(&Sec))) + printRelocation(Obj, SymTab, R, Sec.sh_type == ELF::SHT_ANDROID_RELA); + break; } } if (!HasRelocSections) @@ -3653,7 +3665,9 @@ 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_ANDROID_REL && + Sec.sh_type != ELF::SHT_ANDROID_RELA) continue; StringRef Name = unwrapOrError(Obj->getSectionName(&Sec)); @@ -3686,6 +3700,11 @@ for (const Elf_Rela &R : unwrapOrError(Obj->relas(Sec))) 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))) + printRelocation(Obj, R, SymTab); + break; } }