Index: lld/trunk/ELF/Config.h =================================================================== --- lld/trunk/ELF/Config.h +++ lld/trunk/ELF/Config.h @@ -105,6 +105,7 @@ std::vector VersionScriptLocals; std::vector BuildIdVector; bool AllowMultipleDefinition; + bool AndroidPackDynRelocs = false; bool AsNeeded = false; bool Bsymbolic; bool BsymbolicFunctions; Index: lld/trunk/ELF/Driver.cpp =================================================================== --- lld/trunk/ELF/Driver.cpp +++ lld/trunk/ELF/Driver.cpp @@ -775,6 +775,14 @@ std::tie(Config->BuildId, Config->BuildIdVector) = getBuildId(Args); + if (auto *Arg = Args.getLastArg(OPT_pack_dyn_relocs_eq)) { + StringRef S = Arg->getValue(); + if (S == "android") + Config->AndroidPackDynRelocs = true; + else if (S != "none") + error("unknown -pack-dyn-relocs format: " + S); + } + if (auto *Arg = Args.getLastArg(OPT_symbol_ordering_file)) if (Optional Buffer = readFile(Arg->getValue())) Config->SymbolOrderingFile = getLines(*Buffer); Index: lld/trunk/ELF/Options.td =================================================================== --- lld/trunk/ELF/Options.td +++ lld/trunk/ELF/Options.td @@ -222,6 +222,9 @@ defm orphan_handling: Eq<"orphan-handling">, HelpText<"Control how orphan sections are handled when linker script used">; +def pack_dyn_relocs_eq: J<"pack-dyn-relocs=">, MetaVarName<"">, + HelpText<"Pack dynamic relocations in the given format (none or android)">; + def pie: F<"pie">, HelpText<"Create a position independent executable">; def print_gc_sections: F<"print-gc-sections">, Index: lld/trunk/ELF/SyntheticSections.h =================================================================== --- lld/trunk/ELF/SyntheticSections.h +++ lld/trunk/ELF/SyntheticSections.h @@ -45,7 +45,7 @@ virtual void finalizeContents() {} // If the section has the SHF_ALLOC flag and the size may be changed if // thunks are added, update the section size. - virtual void updateAllocSize() {} + virtual bool updateAllocSize() { return false; } // If any additional finalization of contents are needed post thunk creation. virtual void postThunkContents() {} virtual bool empty() const { return false; } @@ -169,7 +169,7 @@ MipsGotSection(); void writeTo(uint8_t *Buf) override; size_t getSize() const override { return Size; } - void updateAllocSize() override; + bool updateAllocSize() override; void finalizeContents() override; bool empty() const override; void addEntry(SymbolBody &Sym, int64_t Addend, RelExpr Expr); @@ -374,24 +374,52 @@ uint64_t Size = 0; }; -template class RelocationSection final : public SyntheticSection { +class RelocationBaseSection : public SyntheticSection { +public: + RelocationBaseSection(StringRef Name, uint32_t Type, int32_t DynamicTag, + int32_t SizeDynamicTag); + void addReloc(const DynamicReloc &Reloc); + bool empty() const override { return Relocs.empty(); } + size_t getSize() const override { return Relocs.size() * this->Entsize; } + size_t getRelativeRelocCount() const { return NumRelativeRelocs; } + void finalizeContents() override; + int32_t DynamicTag, SizeDynamicTag; + +protected: + std::vector Relocs; + size_t NumRelativeRelocs = 0; +}; + +template +class RelocationSection final : public RelocationBaseSection { typedef typename ELFT::Rel Elf_Rel; typedef typename ELFT::Rela Elf_Rela; public: RelocationSection(StringRef Name, bool Sort); - void addReloc(const DynamicReloc &Reloc); unsigned getRelocOffset(); - void finalizeContents() override; void writeTo(uint8_t *Buf) override; - bool empty() const override { return Relocs.empty(); } - size_t getSize() const override { return Relocs.size() * this->Entsize; } - size_t getRelativeRelocCount() const { return NumRelativeRelocs; } private: bool Sort; - size_t NumRelativeRelocs = 0; - std::vector Relocs; +}; + +template +class AndroidPackedRelocationSection final : public RelocationBaseSection { + typedef typename ELFT::Rel Elf_Rel; + typedef typename ELFT::Rela Elf_Rela; + +public: + AndroidPackedRelocationSection(StringRef Name); + + bool updateAllocSize() override; + size_t getSize() const override { return RelocData.size(); } + void writeTo(uint8_t *Buf) override { + memcpy(Buf, RelocData.data(), RelocData.size()); + } + +private: + SmallVector RelocData; }; struct SymbolTableEntry { @@ -833,7 +861,7 @@ }; template struct In { - static RelocationSection *RelaDyn; + static RelocationBaseSection *RelaDyn; static RelocationSection *RelaPlt; static RelocationSection *RelaIplt; static VersionDefinitionSection *VerDef; @@ -841,7 +869,7 @@ static VersionNeedSection *VerNeed; }; -template RelocationSection *In::RelaDyn; +template RelocationBaseSection *In::RelaDyn; template RelocationSection *In::RelaPlt; template RelocationSection *In::RelaIplt; template VersionDefinitionSection *In::VerDef; Index: lld/trunk/ELF/SyntheticSections.cpp =================================================================== --- lld/trunk/ELF/SyntheticSections.cpp +++ lld/trunk/ELF/SyntheticSections.cpp @@ -33,6 +33,7 @@ #include "llvm/Object/Decompressor.h" #include "llvm/Object/ELFObjectFile.h" #include "llvm/Support/Endian.h" +#include "llvm/Support/LEB128.h" #include "llvm/Support/MD5.h" #include "llvm/Support/RandomNumberGenerator.h" #include "llvm/Support/SHA1.h" @@ -817,7 +818,7 @@ void MipsGotSection::finalizeContents() { updateAllocSize(); } -void MipsGotSection::updateAllocSize() { +bool MipsGotSection::updateAllocSize() { PageEntriesNum = 0; for (std::pair &P : PageIndexMap) { // For each output section referenced by GOT page relocations calculate @@ -831,6 +832,7 @@ } Size = (getLocalEntriesNum() + GlobalEntries.size() + TlsEntries.size()) * Config->Wordsize; + return false; } bool MipsGotSection::empty() const { @@ -1063,10 +1065,11 @@ this->Link = InX::DynStrTab->getParent()->SectionIndex; if (In::RelaDyn->getParent() && !In::RelaDyn->empty()) { - bool IsRela = Config->IsRela; - add({IsRela ? DT_RELA : DT_REL, In::RelaDyn}); - add({IsRela ? DT_RELASZ : DT_RELSZ, In::RelaDyn->getParent(), + add({In::RelaDyn->DynamicTag, In::RelaDyn}); + add({In::RelaDyn->SizeDynamicTag, In::RelaDyn->getParent(), Entry::SecSize}); + + bool IsRela = Config->IsRela; add({IsRela ? DT_RELAENT : DT_RELENT, uint64_t(IsRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel))}); @@ -1202,21 +1205,57 @@ return 0; } -template -RelocationSection::RelocationSection(StringRef Name, bool Sort) - : SyntheticSection(SHF_ALLOC, Config->IsRela ? SHT_RELA : SHT_REL, - Config->Wordsize, Name), - Sort(Sort) { - this->Entsize = Config->IsRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel); -} +RelocationBaseSection::RelocationBaseSection(StringRef Name, uint32_t Type, + int32_t DynamicTag, + int32_t SizeDynamicTag) + : SyntheticSection(SHF_ALLOC, Type, Config->Wordsize, Name), + DynamicTag(DynamicTag), SizeDynamicTag(SizeDynamicTag) {} -template -void RelocationSection::addReloc(const DynamicReloc &Reloc) { +void RelocationBaseSection::addReloc(const DynamicReloc &Reloc) { if (Reloc.Type == Target->RelativeRel) ++NumRelativeRelocs; Relocs.push_back(Reloc); } +void RelocationBaseSection::finalizeContents() { + // If all relocations are R_*_RELATIVE they don't refer to any + // dynamic symbol and we don't need a dynamic symbol table. If that + // is the case, just use 0 as the link. + this->Link = InX::DynSymTab ? InX::DynSymTab->getParent()->SectionIndex : 0; + + // Set required output section properties. + getParent()->Link = this->Link; +} + +template +static void encodeDynamicReloc(typename ELFT::Rela *P, + const DynamicReloc &Rel) { + if (Config->IsRela) + P->r_addend = Rel.getAddend(); + P->r_offset = Rel.getOffset(); + if (Config->EMachine == EM_MIPS && Rel.getInputSec() == InX::MipsGot) + // The MIPS GOT section contains dynamic relocations that correspond to TLS + // entries. These entries are placed after the global and local sections of + // the GOT. At the point when we create these relocations, the size of the + // global and local sections is unknown, so the offset that we store in the + // TLS entry's DynamicReloc is relative to the start of the TLS section of + // the GOT, rather than being relative to the start of the GOT. This line of + // code adds the size of the global and local sections to the virtual + // address computed by getOffset() in order to adjust it into the TLS + // section. + P->r_offset += InX::MipsGot->getTlsOffset(); + P->setSymbolAndType(Rel.getSymIndex(), Rel.Type, Config->IsMips64EL); +} + +template +RelocationSection::RelocationSection(StringRef Name, bool Sort) + : RelocationBaseSection(Name, Config->IsRela ? SHT_RELA : SHT_REL, + Config->IsRela ? DT_RELA : DT_REL, + Config->IsRela ? DT_RELASZ : DT_RELSZ), + Sort(Sort) { + this->Entsize = Config->IsRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel); +} + template static bool compRelocations(const RelTy &A, const RelTy &B) { bool AIsRel = A.getType(Config->IsMips64EL) == Target->RelativeRel; @@ -1230,18 +1269,8 @@ template void RelocationSection::writeTo(uint8_t *Buf) { uint8_t *BufBegin = Buf; for (const DynamicReloc &Rel : Relocs) { - auto *P = reinterpret_cast(Buf); + encodeDynamicReloc(reinterpret_cast(Buf), Rel); Buf += Config->IsRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel); - - if (Config->IsRela) - P->r_addend = Rel.getAddend(); - P->r_offset = Rel.getOffset(); - if (Config->EMachine == EM_MIPS && Rel.getInputSec() == InX::MipsGot) - // Dynamic relocation against MIPS GOT section make deal TLS entries - // allocated in the end of the GOT. We need to adjust the offset to take - // in account 'local' and 'global' GOT entries. - P->r_offset += InX::MipsGot->getTlsOffset(); - P->setSymbolAndType(Rel.getSymIndex(), Rel.Type, Config->IsMips64EL); } if (Sort) { @@ -1259,14 +1288,193 @@ return this->Entsize * Relocs.size(); } -template void RelocationSection::finalizeContents() { - // If all relocations are *RELATIVE they don't refer to any - // dynamic symbol and we don't need a dynamic symbol table. If that - // is the case, just use 0 as the link. - this->Link = InX::DynSymTab ? InX::DynSymTab->getParent()->SectionIndex : 0; +template +AndroidPackedRelocationSection::AndroidPackedRelocationSection( + StringRef Name) + : RelocationBaseSection( + Name, Config->IsRela ? SHT_ANDROID_RELA : SHT_ANDROID_REL, + Config->IsRela ? DT_ANDROID_RELA : DT_ANDROID_REL, + Config->IsRela ? DT_ANDROID_RELASZ : DT_ANDROID_RELSZ) { + this->Entsize = 1; +} - // Set required output section properties. - getParent()->Link = this->Link; +template +bool AndroidPackedRelocationSection::updateAllocSize() { + // This function computes the contents of an Android-format packed relocation + // section. + // + // This format compresses relocations by using relocation groups to factor out + // fields that are common between relocations and storing deltas from previous + // relocations in SLEB128 format (which has a short representation for small + // numbers). A good example of a relocation type with common fields is + // R_*_RELATIVE, which is normally used to represent function pointers in + // vtables. In the REL format, each relative relocation has the same r_info + // field, and is only different from other relative relocations in terms of + // the r_offset field. By sorting relocations by offset, grouping them by + // r_info and representing each relocation with only the delta from the + // previous offset, each 8-byte relocation can be compressed to as little as 1 + // byte (or less with run-length encoding). This relocation packer was able to + // reduce the size of the relocation section in an Android Chromium DSO from + // 2,911,184 bytes to 174,693 bytes, or 6% of the original size. + // + // A relocation section consists of a header containing the literal bytes + // 'APS2' followed by a sequence of SLEB128-encoded integers. The first two + // elements are the total number of relocations in the section and an initial + // r_offset value. The remaining elements define a sequence of relocation + // groups. Each relocation group starts with a header consisting of the + // following elements: + // + // - the number of relocations in the relocation group + // - flags for the relocation group + // - (if RELOCATION_GROUPED_BY_OFFSET_DELTA_FLAG is set) the r_offset delta + // for each relocation in the group. + // - (if RELOCATION_GROUPED_BY_INFO_FLAG is set) the value of the r_info + // field for each relocation in the group. + // - (if RELOCATION_GROUP_HAS_ADDEND_FLAG and + // RELOCATION_GROUPED_BY_ADDEND_FLAG are set) the r_addend delta for + // each relocation in the group. + // + // Following the relocation group header are descriptions of each of the + // relocations in the group. They consist of the following elements: + // + // - (if RELOCATION_GROUPED_BY_OFFSET_DELTA_FLAG is not set) the r_offset + // delta for this relocation. + // - (if RELOCATION_GROUPED_BY_INFO_FLAG is not set) the value of the r_info + // field for this relocation. + // - (if RELOCATION_GROUP_HAS_ADDEND_FLAG is set and + // RELOCATION_GROUPED_BY_ADDEND_FLAG is not set) the r_addend delta for + // this relocation. + + size_t OldSize = RelocData.size(); + + RelocData = {'A', 'P', 'S', '2'}; + raw_svector_ostream OS(RelocData); + + // The format header includes the number of relocations and the initial + // offset (we set this to zero because the first relocation group will + // perform the initial adjustment). + encodeSLEB128(Relocs.size(), OS); + encodeSLEB128(0, OS); + + std::vector Relatives, NonRelatives; + + for (const DynamicReloc &Rel : Relocs) { + Elf_Rela R; + encodeDynamicReloc(&R, Rel); + + if (R.getType(Config->IsMips64EL) == Target->RelativeRel) + Relatives.push_back(R); + else + NonRelatives.push_back(R); + } + + std::sort(Relatives.begin(), Relatives.end(), + [](const Elf_Rel &A, const Elf_Rel &B) { + return A.r_offset < B.r_offset; + }); + + // Try to find groups of relative relocations which are spaced one word + // apart from one another. These generally correspond to vtable entries. The + // format allows these groups to be encoded using a sort of run-length + // encoding, but each group will cost 7 bytes in addition to the offset from + // the previous group, so it is only profitable to do this for groups of + // size 8 or larger. + std::vector UngroupedRelatives; + std::vector> RelativeGroups; + for (auto I = Relatives.begin(), E = Relatives.end(); I != E;) { + std::vector Group; + do { + Group.push_back(*I++); + } while (I != E && (I - 1)->r_offset + Config->Wordsize == I->r_offset); + + if (Group.size() < 8) + UngroupedRelatives.insert(UngroupedRelatives.end(), Group.begin(), + Group.end()); + else + RelativeGroups.emplace_back(std::move(Group)); + } + + unsigned HasAddendIfRela = + Config->IsRela ? RELOCATION_GROUP_HAS_ADDEND_FLAG : 0; + + uint64_t Offset = 0; + uint64_t Addend = 0; + + // Emit the run-length encoding for the groups of adjacent relative + // relocations. Each group is represented using two groups in the packed + // format. The first is used to set the current offset to the start of the + // group (and also encodes the first relocation), and the second encodes the + // remaining relocations. + for (std::vector &G : RelativeGroups) { + // The first relocation in the group. + encodeSLEB128(1, OS); + encodeSLEB128(RELOCATION_GROUPED_BY_OFFSET_DELTA_FLAG | + RELOCATION_GROUPED_BY_INFO_FLAG | HasAddendIfRela, + OS); + encodeSLEB128(G[0].r_offset - Offset, OS); + encodeSLEB128(Target->RelativeRel, OS); + if (Config->IsRela) { + encodeSLEB128(G[0].r_addend - Addend, OS); + Addend = G[0].r_addend; + } + + // The remaining relocations. + encodeSLEB128(G.size() - 1, OS); + encodeSLEB128(RELOCATION_GROUPED_BY_OFFSET_DELTA_FLAG | + RELOCATION_GROUPED_BY_INFO_FLAG | HasAddendIfRela, + OS); + encodeSLEB128(Config->Wordsize, OS); + encodeSLEB128(Target->RelativeRel, OS); + if (Config->IsRela) { + for (auto I = G.begin() + 1, E = G.end(); I != E; ++I) { + encodeSLEB128(I->r_addend - Addend, OS); + Addend = I->r_addend; + } + } + + Offset = G.back().r_offset; + } + + // Now the ungrouped relatives. + if (!UngroupedRelatives.empty()) { + encodeSLEB128(UngroupedRelatives.size(), OS); + encodeSLEB128(RELOCATION_GROUPED_BY_INFO_FLAG | HasAddendIfRela, OS); + encodeSLEB128(Target->RelativeRel, OS); + for (Elf_Rela &R : UngroupedRelatives) { + encodeSLEB128(R.r_offset - Offset, OS); + Offset = R.r_offset; + if (Config->IsRela) { + encodeSLEB128(R.r_addend - Addend, OS); + Addend = R.r_addend; + } + } + } + + // Finally the non-relative relocations. + std::sort(NonRelatives.begin(), NonRelatives.end(), + [](const Elf_Rela &A, const Elf_Rela &B) { + return A.r_offset < B.r_offset; + }); + if (!NonRelatives.empty()) { + encodeSLEB128(NonRelatives.size(), OS); + encodeSLEB128(HasAddendIfRela, OS); + for (Elf_Rela &R : NonRelatives) { + encodeSLEB128(R.r_offset - Offset, OS); + Offset = R.r_offset; + encodeSLEB128(R.r_info, OS); + if (Config->IsRela) { + encodeSLEB128(R.r_addend - Addend, OS); + Addend = R.r_addend; + } + } + } + + // Returns whether the section size changed. We need to keep recomputing both + // section layout and the contents of this section until the size converges + // because changing this section's size can affect section layout, which in + // turn can affect the sizes of the LEB-encoded integers stored in this + // section. + return RelocData.size() != OldSize; } SymbolTableBaseSection::SymbolTableBaseSection(StringTableSection &StrTabSec) @@ -2471,6 +2679,11 @@ template class elf::RelocationSection; template class elf::RelocationSection; +template class elf::AndroidPackedRelocationSection; +template class elf::AndroidPackedRelocationSection; +template class elf::AndroidPackedRelocationSection; +template class elf::AndroidPackedRelocationSection; + template class elf::SymbolTableSection; template class elf::SymbolTableSection; template class elf::SymbolTableSection; Index: lld/trunk/ELF/Writer.cpp =================================================================== --- lld/trunk/ELF/Writer.cpp +++ lld/trunk/ELF/Writer.cpp @@ -266,8 +266,13 @@ InX::DynStrTab = make(".dynstr", true); InX::Dynamic = make>(); - In::RelaDyn = make>( - Config->IsRela ? ".rela.dyn" : ".rel.dyn", Config->ZCombreloc); + if (Config->AndroidPackDynRelocs) { + In::RelaDyn = make>( + Config->IsRela ? ".rela.dyn" : ".rel.dyn"); + } else { + In::RelaDyn = make>( + Config->IsRela ? ".rela.dyn" : ".rel.dyn", Config->ZCombreloc); + } InX::ShStrTab = make(".shstrtab", false); Out::ElfHeader = make("", 0, SHF_ALLOC); @@ -368,9 +373,15 @@ Add(In::RelaPlt); // The RelaIplt immediately follows .rel.plt (.rel.dyn for ARM) to ensure - // that the IRelative relocations are processed last by the dynamic loader + // that the IRelative relocations are processed last by the dynamic loader. + // We cannot place the iplt section in .rel.dyn when Android relocation + // packing is enabled because that would cause a section type mismatch. + // However, because the Android dynamic loader reads .rel.plt after .rel.dyn, + // we can get the desired behaviour by placing the iplt section in .rel.plt. In::RelaIplt = make>( - (Config->EMachine == EM_ARM) ? ".rel.dyn" : In::RelaPlt->Name, + (Config->EMachine == EM_ARM && !Config->AndroidPackDynRelocs) + ? ".rel.dyn" + : In::RelaPlt->Name, false /*Sort*/); Add(In::RelaIplt); @@ -1359,14 +1370,18 @@ // Some architectures use small displacements for jump instructions. // It is linker's responsibility to create thunks containing long // jump instructions if jump targets are too far. Create thunks. - if (Target->NeedsThunks) { + if (Target->NeedsThunks || Config->AndroidPackDynRelocs) { ThunkCreator TC; - Script->assignAddresses(); - while (TC.createThunks(OutputSections)) { - applySynthetic({InX::MipsGot}, - [](SyntheticSection *SS) { SS->updateAllocSize(); }); + bool Changed; + do { Script->assignAddresses(); - } + Changed = false; + if (Target->NeedsThunks) + Changed |= TC.createThunks(OutputSections); + if (InX::MipsGot) + InX::MipsGot->updateAllocSize(); + Changed |= In::RelaDyn->updateAllocSize(); + } while (Changed); } // Fill other section headers. The dynamic table is finalized Index: lld/trunk/test/ELF/pack-dyn-relocs.s =================================================================== --- lld/trunk/test/ELF/pack-dyn-relocs.s +++ lld/trunk/test/ELF/pack-dyn-relocs.s @@ -0,0 +1,210 @@ +// REQUIRES: arm, aarch64 + +// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %p/Inputs/arm-shared.s -o %t.a32.so.o +// RUN: ld.lld -shared %t.a32.so.o -o %t.a32.so +// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t.a32 +// RUN: ld.lld -pie --pack-dyn-relocs=none %t.a32 %t.a32.so -o %t2.a32 +// RUN: llvm-readobj -relocations %t2.a32 | FileCheck --check-prefix=UNPACKED32 %s +// RUN: ld.lld -pie --pack-dyn-relocs=android %t.a32 %t.a32.so -o %t3.a32 +// RUN: llvm-readobj -s -dynamic-table %t3.a32 | FileCheck --check-prefix=PACKED32-HEADERS %s +// RUN: llvm-readobj -relocations %t3.a32 | FileCheck --check-prefix=PACKED32 %s + +// Unpacked should have the relative relocations in their natural order. +// UNPACKED32: 0x1000 R_ARM_RELATIVE - 0x0 +// UNPACKED32-NEXT: 0x1004 R_ARM_RELATIVE - 0x0 +// UNPACKED32-NEXT: 0x1008 R_ARM_RELATIVE - 0x0 +// UNPACKED32-NEXT: 0x100C R_ARM_RELATIVE - 0x0 +// UNPACKED32-NEXT: 0x1010 R_ARM_RELATIVE - 0x0 +// UNPACKED32-NEXT: 0x1014 R_ARM_RELATIVE - 0x0 +// UNPACKED32-NEXT: 0x1018 R_ARM_RELATIVE - 0x0 +// UNPACKED32-NEXT: 0x101C R_ARM_RELATIVE - 0x0 + +// UNPACKED32-NEXT: 0x1024 R_ARM_RELATIVE - 0x0 +// UNPACKED32-NEXT: 0x1028 R_ARM_RELATIVE - 0x0 +// UNPACKED32-NEXT: 0x102C R_ARM_RELATIVE - 0x0 +// UNPACKED32-NEXT: 0x1030 R_ARM_RELATIVE - 0x0 +// UNPACKED32-NEXT: 0x1034 R_ARM_RELATIVE - 0x0 +// UNPACKED32-NEXT: 0x1038 R_ARM_RELATIVE - 0x0 +// UNPACKED32-NEXT: 0x103C R_ARM_RELATIVE - 0x0 + +// UNPACKED32-NEXT: 0x1044 R_ARM_RELATIVE - 0x0 +// UNPACKED32-NEXT: 0x1048 R_ARM_RELATIVE - 0x0 +// UNPACKED32-NEXT: 0x104C R_ARM_RELATIVE - 0x0 +// UNPACKED32-NEXT: 0x1050 R_ARM_RELATIVE - 0x0 +// UNPACKED32-NEXT: 0x1054 R_ARM_RELATIVE - 0x0 +// UNPACKED32-NEXT: 0x1058 R_ARM_RELATIVE - 0x0 +// UNPACKED32-NEXT: 0x105C R_ARM_RELATIVE - 0x0 +// UNPACKED32-NEXT: 0x1060 R_ARM_RELATIVE - 0x0 +// UNPACKED32-NEXT: 0x1064 R_ARM_RELATIVE - 0x0 + +// UNPACKED32-NEXT: 0x1020 R_ARM_ABS32 bar2 0x0 +// UNPACKED32-NEXT: 0x1040 R_ARM_ABS32 zed2 0x0 + +// PACKED32-HEADERS: Index: 1 +// PACKED32-HEADERS-NEXT: Name: .dynsym + +// PACKED32-HEADERS: Name: .rel.dyn +// PACKED32-HEADERS-NEXT: Type: SHT_ANDROID_REL +// PACKED32-HEADERS-NEXT: Flags [ (0x2) +// PACKED32-HEADERS-NEXT: SHF_ALLOC (0x2) +// PACKED32-HEADERS-NEXT: ] +// PACKED32-HEADERS-NEXT: Address: [[ADDR:.*]] +// PACKED32-HEADERS-NEXT: Offset: [[ADDR]] +// PACKED32-HEADERS-NEXT: Size: [[SIZE:.*]] +// PACKED32-HEADERS-NEXT: Link: 1 +// PACKED32-HEADERS-NEXT: Info: 0 +// PACKED32-HEADERS-NEXT: AddressAlignment: 4 +// PACKED32-HEADERS-NEXT: EntrySize: 1 + +// PACKED32-HEADERS: 0x6000000F ANDROID_REL [[ADDR]] +// PACKED32-HEADERS: 0x60000010 ANDROID_RELSZ [[SIZE]] + +// Packed should have the larger groups of relative relocations first, +// i.e. the 8 and 9 followed by the 7. +// PACKED32: 0x1000 R_ARM_RELATIVE - 0x0 +// PACKED32-NEXT: 0x1004 R_ARM_RELATIVE - 0x0 +// PACKED32-NEXT: 0x1008 R_ARM_RELATIVE - 0x0 +// PACKED32-NEXT: 0x100C R_ARM_RELATIVE - 0x0 +// PACKED32-NEXT: 0x1010 R_ARM_RELATIVE - 0x0 +// PACKED32-NEXT: 0x1014 R_ARM_RELATIVE - 0x0 +// PACKED32-NEXT: 0x1018 R_ARM_RELATIVE - 0x0 +// PACKED32-NEXT: 0x101C R_ARM_RELATIVE - 0x0 + +// PACKED32-NEXT: 0x1044 R_ARM_RELATIVE - 0x0 +// PACKED32-NEXT: 0x1048 R_ARM_RELATIVE - 0x0 +// PACKED32-NEXT: 0x104C R_ARM_RELATIVE - 0x0 +// PACKED32-NEXT: 0x1050 R_ARM_RELATIVE - 0x0 +// PACKED32-NEXT: 0x1054 R_ARM_RELATIVE - 0x0 +// PACKED32-NEXT: 0x1058 R_ARM_RELATIVE - 0x0 +// PACKED32-NEXT: 0x105C R_ARM_RELATIVE - 0x0 +// PACKED32-NEXT: 0x1060 R_ARM_RELATIVE - 0x0 +// PACKED32-NEXT: 0x1064 R_ARM_RELATIVE - 0x0 + +// PACKED32-NEXT: 0x1024 R_ARM_RELATIVE - 0x0 +// PACKED32-NEXT: 0x1028 R_ARM_RELATIVE - 0x0 +// PACKED32-NEXT: 0x102C R_ARM_RELATIVE - 0x0 +// PACKED32-NEXT: 0x1030 R_ARM_RELATIVE - 0x0 +// PACKED32-NEXT: 0x1034 R_ARM_RELATIVE - 0x0 +// PACKED32-NEXT: 0x1038 R_ARM_RELATIVE - 0x0 +// PACKED32-NEXT: 0x103C R_ARM_RELATIVE - 0x0 + +// PACKED32-NEXT: 0x1020 R_ARM_ABS32 bar2 0x0 +// PACKED32-NEXT: 0x1040 R_ARM_ABS32 zed2 0x0 + +// RUN: llvm-mc -filetype=obj -triple=aarch64-unknown-linux %p/Inputs/shared2.s -o %t.a64.so.o +// RUN: ld.lld -shared %t.a64.so.o -o %t.a64.so +// RUN: llvm-mc -filetype=obj -triple=aarch64-unknown-linux %s -o %t.a64 +// RUN: ld.lld -pie --pack-dyn-relocs=none %t.a64 %t.a64.so -o %t2.a64 +// RUN: llvm-readobj -relocations %t2.a64 | FileCheck --check-prefix=UNPACKED64 %s +// RUN: ld.lld -pie --pack-dyn-relocs=android %t.a64 %t.a64.so -o %t3.a64 +// RUN: llvm-readobj -s -dynamic-table %t3.a64 | FileCheck --check-prefix=PACKED64-HEADERS %s +// RUN: llvm-readobj -relocations %t3.a64 | FileCheck --check-prefix=PACKED64 %s + +// UNPACKED64: 0x10000 R_AARCH64_RELATIVE - 0x1 +// UNPACKED64-NEXT: 0x10008 R_AARCH64_RELATIVE - 0x2 +// UNPACKED64-NEXT: 0x10010 R_AARCH64_RELATIVE - 0x3 +// UNPACKED64-NEXT: 0x10018 R_AARCH64_RELATIVE - 0x4 +// UNPACKED64-NEXT: 0x10020 R_AARCH64_RELATIVE - 0x5 +// UNPACKED64-NEXT: 0x10028 R_AARCH64_RELATIVE - 0x6 +// UNPACKED64-NEXT: 0x10030 R_AARCH64_RELATIVE - 0x7 +// UNPACKED64-NEXT: 0x10038 R_AARCH64_RELATIVE - 0x8 + +// UNPACKED64-NEXT: 0x10048 R_AARCH64_RELATIVE - 0x1 +// UNPACKED64-NEXT: 0x10050 R_AARCH64_RELATIVE - 0x2 +// UNPACKED64-NEXT: 0x10058 R_AARCH64_RELATIVE - 0x3 +// UNPACKED64-NEXT: 0x10060 R_AARCH64_RELATIVE - 0x4 +// UNPACKED64-NEXT: 0x10068 R_AARCH64_RELATIVE - 0x5 +// UNPACKED64-NEXT: 0x10070 R_AARCH64_RELATIVE - 0x6 +// UNPACKED64-NEXT: 0x10078 R_AARCH64_RELATIVE - 0x7 + +// UNPACKED64-NEXT: 0x10088 R_AARCH64_RELATIVE - 0x1 +// UNPACKED64-NEXT: 0x10090 R_AARCH64_RELATIVE - 0x2 +// UNPACKED64-NEXT: 0x10098 R_AARCH64_RELATIVE - 0x3 +// UNPACKED64-NEXT: 0x100A0 R_AARCH64_RELATIVE - 0x4 +// UNPACKED64-NEXT: 0x100A8 R_AARCH64_RELATIVE - 0x5 +// UNPACKED64-NEXT: 0x100B0 R_AARCH64_RELATIVE - 0x6 +// UNPACKED64-NEXT: 0x100B8 R_AARCH64_RELATIVE - 0x7 +// UNPACKED64-NEXT: 0x100C0 R_AARCH64_RELATIVE - 0x8 +// UNPACKED64-NEXT: 0x100C8 R_AARCH64_RELATIVE - 0x9 + +// UNPACKED64-NEXT: 0x10040 R_AARCH64_ABS64 bar2 0x1 +// UNPACKED64-NEXT: 0x10080 R_AARCH64_ABS64 zed2 0x0 + +// PACKED64: 0x10000 R_AARCH64_RELATIVE - 0x1 +// PACKED64-NEXT: 0x10008 R_AARCH64_RELATIVE - 0x2 +// PACKED64-NEXT: 0x10010 R_AARCH64_RELATIVE - 0x3 +// PACKED64-NEXT: 0x10018 R_AARCH64_RELATIVE - 0x4 +// PACKED64-NEXT: 0x10020 R_AARCH64_RELATIVE - 0x5 +// PACKED64-NEXT: 0x10028 R_AARCH64_RELATIVE - 0x6 +// PACKED64-NEXT: 0x10030 R_AARCH64_RELATIVE - 0x7 +// PACKED64-NEXT: 0x10038 R_AARCH64_RELATIVE - 0x8 + +// PACKED64-NEXT: 0x10088 R_AARCH64_RELATIVE - 0x1 +// PACKED64-NEXT: 0x10090 R_AARCH64_RELATIVE - 0x2 +// PACKED64-NEXT: 0x10098 R_AARCH64_RELATIVE - 0x3 +// PACKED64-NEXT: 0x100A0 R_AARCH64_RELATIVE - 0x4 +// PACKED64-NEXT: 0x100A8 R_AARCH64_RELATIVE - 0x5 +// PACKED64-NEXT: 0x100B0 R_AARCH64_RELATIVE - 0x6 +// PACKED64-NEXT: 0x100B8 R_AARCH64_RELATIVE - 0x7 +// PACKED64-NEXT: 0x100C0 R_AARCH64_RELATIVE - 0x8 +// PACKED64-NEXT: 0x100C8 R_AARCH64_RELATIVE - 0x9 + +// PACKED64-NEXT: 0x10048 R_AARCH64_RELATIVE - 0x1 +// PACKED64-NEXT: 0x10050 R_AARCH64_RELATIVE - 0x2 +// PACKED64-NEXT: 0x10058 R_AARCH64_RELATIVE - 0x3 +// PACKED64-NEXT: 0x10060 R_AARCH64_RELATIVE - 0x4 +// PACKED64-NEXT: 0x10068 R_AARCH64_RELATIVE - 0x5 +// PACKED64-NEXT: 0x10070 R_AARCH64_RELATIVE - 0x6 +// PACKED64-NEXT: 0x10078 R_AARCH64_RELATIVE - 0x7 + +// PACKED64-NEXT: 0x10040 R_AARCH64_ABS64 bar2 0x1 +// PACKED64-NEXT: 0x10080 R_AARCH64_ABS64 zed2 0x0 + +// PACKED64-HEADERS: Index: 1 +// PACKED64-HEADERS-NEXT: Name: .dynsym + +// PACKED64-HEADERS: Name: .rela.dyn +// PACKED64-HEADERS-NEXT: Type: SHT_ANDROID_RELA +// PACKED64-HEADERS-NEXT: Flags [ (0x2) +// PACKED64-HEADERS-NEXT: SHF_ALLOC (0x2) +// PACKED64-HEADERS-NEXT: ] +// PACKED64-HEADERS-NEXT: Address: [[ADDR:.*]] +// PACKED64-HEADERS-NEXT: Offset: [[ADDR]] +// PACKED64-HEADERS-NEXT: Size: [[SIZE:.*]] +// PACKED64-HEADERS-NEXT: Link: 1 +// PACKED64-HEADERS-NEXT: Info: 0 +// PACKED64-HEADERS-NEXT: AddressAlignment: 8 +// PACKED64-HEADERS-NEXT: EntrySize: 1 + +// PACKED64-HEADERS: 0x0000000060000011 ANDROID_RELA [[ADDR]] +// PACKED64-HEADERS: 0x0000000060000012 ANDROID_RELASZ [[SIZE]] + +.data +.dc.a __ehdr_start + 1 +.dc.a __ehdr_start + 2 +.dc.a __ehdr_start + 3 +.dc.a __ehdr_start + 4 +.dc.a __ehdr_start + 5 +.dc.a __ehdr_start + 6 +.dc.a __ehdr_start + 7 +.dc.a __ehdr_start + 8 +.dc.a bar2 + 1 + +.dc.a __ehdr_start + 1 +.dc.a __ehdr_start + 2 +.dc.a __ehdr_start + 3 +.dc.a __ehdr_start + 4 +.dc.a __ehdr_start + 5 +.dc.a __ehdr_start + 6 +.dc.a __ehdr_start + 7 +.dc.a zed2 + +.dc.a __ehdr_start + 1 +.dc.a __ehdr_start + 2 +.dc.a __ehdr_start + 3 +.dc.a __ehdr_start + 4 +.dc.a __ehdr_start + 5 +.dc.a __ehdr_start + 6 +.dc.a __ehdr_start + 7 +.dc.a __ehdr_start + 8 +.dc.a __ehdr_start + 9 Index: llvm/trunk/lib/Object/ELF.cpp =================================================================== --- llvm/trunk/lib/Object/ELF.cpp +++ llvm/trunk/lib/Object/ELF.cpp @@ -201,6 +201,8 @@ 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); Index: llvm/trunk/tools/llvm-readobj/ELFDumper.cpp =================================================================== --- llvm/trunk/tools/llvm-readobj/ELFDumper.cpp +++ llvm/trunk/tools/llvm-readobj/ELFDumper.cpp @@ -1513,6 +1513,10 @@ } } switch (Type) { + LLVM_READOBJ_TYPE_CASE(ANDROID_REL); + LLVM_READOBJ_TYPE_CASE(ANDROID_RELSZ); + LLVM_READOBJ_TYPE_CASE(ANDROID_RELA); + LLVM_READOBJ_TYPE_CASE(ANDROID_RELASZ); LLVM_READOBJ_TYPE_CASE(BIND_NOW); LLVM_READOBJ_TYPE_CASE(DEBUG); LLVM_READOBJ_TYPE_CASE(FINI); @@ -1715,6 +1719,8 @@ case DT_INIT_ARRAYSZ: case DT_FINI_ARRAYSZ: case DT_PREINIT_ARRAYSZ: + case DT_ANDROID_RELSZ: + case DT_ANDROID_RELASZ: OS << Value << " (bytes)"; break; case DT_NEEDED: