forked from OSchip/llvm-project
ELF: Add support for emitting dynamic relocations in the Android relocation packing format.
The Android relocation packing format is a more compact format for dynamic relocations in executables and DSOs that is based on delta encoding and SLEBs. An overview of the format can be found in the Android source code: https://android.googlesource.com/platform/bionic/+/refs/heads/master/tools/relocation_packer/src/delta_encoder.h This patch implements relocation packing using that format. This implementation uses a more intelligent algorithm for compressing relative relocations than Android's own relocation packer. As a result it can generally create smaller relocation sections than that packer. If I link Chromium for Android targeting ARM32 I get a .rel.dyn of size 174693 bytes, as compared to 371832 bytes with gold and the Android packer. Differential Revision: https://reviews.llvm.org/D39152 llvm-svn: 316775
This commit is contained in:
parent
1d053791a1
commit
5c54f15c55
|
@ -105,6 +105,7 @@ struct Configuration {
|
|||
std::vector<SymbolVersion> VersionScriptLocals;
|
||||
std::vector<uint8_t> BuildIdVector;
|
||||
bool AllowMultipleDefinition;
|
||||
bool AndroidPackDynRelocs = false;
|
||||
bool AsNeeded = false;
|
||||
bool Bsymbolic;
|
||||
bool BsymbolicFunctions;
|
||||
|
|
|
@ -775,6 +775,14 @@ void LinkerDriver::readConfigs(opt::InputArgList &Args) {
|
|||
|
||||
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<MemoryBufferRef> Buffer = readFile(Arg->getValue()))
|
||||
Config->SymbolOrderingFile = getLines(*Buffer);
|
||||
|
|
|
@ -222,6 +222,9 @@ def omagic: Flag<["--"], "omagic">, MetaVarName<"<magic>">,
|
|||
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<"<format>">,
|
||||
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">,
|
||||
|
|
|
@ -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 @@ unsigned MipsGotSection::getLocalEntriesNum() const {
|
|||
|
||||
void MipsGotSection::finalizeContents() { updateAllocSize(); }
|
||||
|
||||
void MipsGotSection::updateAllocSize() {
|
||||
bool MipsGotSection::updateAllocSize() {
|
||||
PageEntriesNum = 0;
|
||||
for (std::pair<const OutputSection *, size_t> &P : PageIndexMap) {
|
||||
// For each output section referenced by GOT page relocations calculate
|
||||
|
@ -831,6 +832,7 @@ void MipsGotSection::updateAllocSize() {
|
|||
}
|
||||
Size = (getLocalEntriesNum() + GlobalEntries.size() + TlsEntries.size()) *
|
||||
Config->Wordsize;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MipsGotSection::empty() const {
|
||||
|
@ -1063,10 +1065,11 @@ template <class ELFT> void DynamicSection<ELFT>::finalizeContents() {
|
|||
|
||||
this->Link = InX::DynStrTab->getParent()->SectionIndex;
|
||||
if (In<ELFT>::RelaDyn->getParent() && !In<ELFT>::RelaDyn->empty()) {
|
||||
bool IsRela = Config->IsRela;
|
||||
add({IsRela ? DT_RELA : DT_REL, In<ELFT>::RelaDyn});
|
||||
add({IsRela ? DT_RELASZ : DT_RELSZ, In<ELFT>::RelaDyn->getParent(),
|
||||
add({In<ELFT>::RelaDyn->DynamicTag, In<ELFT>::RelaDyn});
|
||||
add({In<ELFT>::RelaDyn->SizeDynamicTag, In<ELFT>::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 @@ uint32_t DynamicReloc::getSymIndex() const {
|
|||
return 0;
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
RelocationSection<ELFT>::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 <class ELFT>
|
||||
void RelocationSection<ELFT>::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 <class ELFT>
|
||||
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 <class ELFT>
|
||||
RelocationSection<ELFT>::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 <class ELFT, class RelTy>
|
||||
static bool compRelocations(const RelTy &A, const RelTy &B) {
|
||||
bool AIsRel = A.getType(Config->IsMips64EL) == Target->RelativeRel;
|
||||
|
@ -1230,18 +1269,8 @@ static bool compRelocations(const RelTy &A, const RelTy &B) {
|
|||
template <class ELFT> void RelocationSection<ELFT>::writeTo(uint8_t *Buf) {
|
||||
uint8_t *BufBegin = Buf;
|
||||
for (const DynamicReloc &Rel : Relocs) {
|
||||
auto *P = reinterpret_cast<Elf_Rela *>(Buf);
|
||||
encodeDynamicReloc<ELFT>(reinterpret_cast<Elf_Rela *>(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 @@ template <class ELFT> unsigned RelocationSection<ELFT>::getRelocOffset() {
|
|||
return this->Entsize * Relocs.size();
|
||||
}
|
||||
|
||||
template <class ELFT> void RelocationSection<ELFT>::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 <class ELFT>
|
||||
AndroidPackedRelocationSection<ELFT>::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 <class ELFT>
|
||||
bool AndroidPackedRelocationSection<ELFT>::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<Elf_Rela> Relatives, NonRelatives;
|
||||
|
||||
for (const DynamicReloc &Rel : Relocs) {
|
||||
Elf_Rela R;
|
||||
encodeDynamicReloc<ELFT>(&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<Elf_Rela> UngroupedRelatives;
|
||||
std::vector<std::vector<Elf_Rela>> RelativeGroups;
|
||||
for (auto I = Relatives.begin(), E = Relatives.end(); I != E;) {
|
||||
std::vector<Elf_Rela> 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<Elf_Rela> &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<ELF32BE>;
|
|||
template class elf::RelocationSection<ELF64LE>;
|
||||
template class elf::RelocationSection<ELF64BE>;
|
||||
|
||||
template class elf::AndroidPackedRelocationSection<ELF32LE>;
|
||||
template class elf::AndroidPackedRelocationSection<ELF32BE>;
|
||||
template class elf::AndroidPackedRelocationSection<ELF64LE>;
|
||||
template class elf::AndroidPackedRelocationSection<ELF64BE>;
|
||||
|
||||
template class elf::SymbolTableSection<ELF32LE>;
|
||||
template class elf::SymbolTableSection<ELF32BE>;
|
||||
template class elf::SymbolTableSection<ELF64LE>;
|
||||
|
|
|
@ -45,7 +45,7 @@ public:
|
|||
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 @@ public:
|
|||
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 @@ private:
|
|||
uint64_t Size = 0;
|
||||
};
|
||||
|
||||
template <class ELFT> 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<DynamicReloc> Relocs;
|
||||
size_t NumRelativeRelocs = 0;
|
||||
};
|
||||
|
||||
template <class ELFT>
|
||||
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<DynamicReloc> Relocs;
|
||||
};
|
||||
|
||||
template <class ELFT>
|
||||
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<char, 0> RelocData;
|
||||
};
|
||||
|
||||
struct SymbolTableEntry {
|
||||
|
@ -833,7 +861,7 @@ struct InX {
|
|||
};
|
||||
|
||||
template <class ELFT> struct In {
|
||||
static RelocationSection<ELFT> *RelaDyn;
|
||||
static RelocationBaseSection *RelaDyn;
|
||||
static RelocationSection<ELFT> *RelaPlt;
|
||||
static RelocationSection<ELFT> *RelaIplt;
|
||||
static VersionDefinitionSection<ELFT> *VerDef;
|
||||
|
@ -841,7 +869,7 @@ template <class ELFT> struct In {
|
|||
static VersionNeedSection<ELFT> *VerNeed;
|
||||
};
|
||||
|
||||
template <class ELFT> RelocationSection<ELFT> *In<ELFT>::RelaDyn;
|
||||
template <class ELFT> RelocationBaseSection *In<ELFT>::RelaDyn;
|
||||
template <class ELFT> RelocationSection<ELFT> *In<ELFT>::RelaPlt;
|
||||
template <class ELFT> RelocationSection<ELFT> *In<ELFT>::RelaIplt;
|
||||
template <class ELFT> VersionDefinitionSection<ELFT> *In<ELFT>::VerDef;
|
||||
|
|
|
@ -266,8 +266,13 @@ template <class ELFT> void Writer<ELFT>::createSyntheticSections() {
|
|||
|
||||
InX::DynStrTab = make<StringTableSection>(".dynstr", true);
|
||||
InX::Dynamic = make<DynamicSection<ELFT>>();
|
||||
if (Config->AndroidPackDynRelocs) {
|
||||
In<ELFT>::RelaDyn = make<AndroidPackedRelocationSection<ELFT>>(
|
||||
Config->IsRela ? ".rela.dyn" : ".rel.dyn");
|
||||
} else {
|
||||
In<ELFT>::RelaDyn = make<RelocationSection<ELFT>>(
|
||||
Config->IsRela ? ".rela.dyn" : ".rel.dyn", Config->ZCombreloc);
|
||||
}
|
||||
InX::ShStrTab = make<StringTableSection>(".shstrtab", false);
|
||||
|
||||
Out::ElfHeader = make<OutputSection>("", 0, SHF_ALLOC);
|
||||
|
@ -368,9 +373,15 @@ template <class ELFT> void Writer<ELFT>::createSyntheticSections() {
|
|||
Add(In<ELFT>::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<ELFT>::RelaIplt = make<RelocationSection<ELFT>>(
|
||||
(Config->EMachine == EM_ARM) ? ".rel.dyn" : In<ELFT>::RelaPlt->Name,
|
||||
(Config->EMachine == EM_ARM && !Config->AndroidPackDynRelocs)
|
||||
? ".rel.dyn"
|
||||
: In<ELFT>::RelaPlt->Name,
|
||||
false /*Sort*/);
|
||||
Add(In<ELFT>::RelaIplt);
|
||||
|
||||
|
@ -1359,14 +1370,18 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
|
|||
// 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;
|
||||
bool Changed;
|
||||
do {
|
||||
Script->assignAddresses();
|
||||
while (TC.createThunks(OutputSections)) {
|
||||
applySynthetic({InX::MipsGot},
|
||||
[](SyntheticSection *SS) { SS->updateAllocSize(); });
|
||||
Script->assignAddresses();
|
||||
}
|
||||
Changed = false;
|
||||
if (Target->NeedsThunks)
|
||||
Changed |= TC.createThunks(OutputSections);
|
||||
if (InX::MipsGot)
|
||||
InX::MipsGot->updateAllocSize();
|
||||
Changed |= In<ELFT>::RelaDyn->updateAllocSize();
|
||||
} while (Changed);
|
||||
}
|
||||
|
||||
// Fill other section headers. The dynamic table is finalized
|
||||
|
|
|
@ -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
|
|
@ -201,6 +201,8 @@ StringRef llvm::object::getELFSectionTypeName(uint32_t Machine, unsigned Type) {
|
|||
STRINGIFY_ENUM_CASE(ELF, SHT_PREINIT_ARRAY);
|
||||
STRINGIFY_ENUM_CASE(ELF, SHT_GROUP);
|
||||
STRINGIFY_ENUM_CASE(ELF, SHT_SYMTAB_SHNDX);
|
||||
STRINGIFY_ENUM_CASE(ELF, SHT_ANDROID_REL);
|
||||
STRINGIFY_ENUM_CASE(ELF, SHT_ANDROID_RELA);
|
||||
STRINGIFY_ENUM_CASE(ELF, SHT_LLVM_ODRTAB);
|
||||
STRINGIFY_ENUM_CASE(ELF, SHT_GNU_ATTRIBUTES);
|
||||
STRINGIFY_ENUM_CASE(ELF, SHT_GNU_HASH);
|
||||
|
|
|
@ -1513,6 +1513,10 @@ static const char *getTypeString(unsigned Arch, uint64_t Type) {
|
|||
}
|
||||
}
|
||||
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 @@ void ELFDumper<ELFT>::printValue(uint64_t Type, uint64_t Value) {
|
|||
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:
|
||||
|
|
Loading…
Reference in New Issue