Please use GitHub pull requests for new patches. Phabricator shutdown timeline
Changeset View
Changeset View
Standalone View
Standalone View
lld/ELF/SyntheticSections.cpp
Show First 20 Lines • Show All 349 Lines • ▼ Show 20 Lines | bool EhFrameSection::isFdeLive(EhSectionPiece &Fde, ArrayRef<RelTy> Rels) { | ||||
// corresponding FDEs, which results in creating bad .eh_frame sections. | // corresponding FDEs, which results in creating bad .eh_frame sections. | ||||
// To deal with that, we ignore such FDEs. | // To deal with that, we ignore such FDEs. | ||||
if (FirstRelI == (unsigned)-1) | if (FirstRelI == (unsigned)-1) | ||||
return false; | return false; | ||||
const RelTy &Rel = Rels[FirstRelI]; | const RelTy &Rel = Rels[FirstRelI]; | ||||
Symbol &B = Sec->template getFile<ELFT>()->getRelocTargetSym(Rel); | Symbol &B = Sec->template getFile<ELFT>()->getRelocTargetSym(Rel); | ||||
// FDEs for garbage-collected or merged-by-ICF sections are dead. | // FDEs for garbage-collected or merged-by-ICF sections, or sections in | ||||
// another partition, are dead. | |||||
if (auto *D = dyn_cast<Defined>(&B)) | if (auto *D = dyn_cast<Defined>(&B)) | ||||
if (SectionBase *Sec = D->Section) | if (SectionBase *Sec = D->Section) | ||||
return Sec->isLive(); | return Sec->Partition == Partition; | ||||
return false; | return false; | ||||
} | } | ||||
// .eh_frame is a sequence of CIE or FDE records. In general, there | // .eh_frame is a sequence of CIE or FDE records. In general, there | ||||
// is one CIE record per input object file which is followed by | // is one CIE record per input object file which is followed by | ||||
// a list of FDEs. This function searches an existing CIE or create a new | // a list of FDEs. This function searches an existing CIE or create a new | ||||
// one and associates FDEs to the CIE. | // one and associates FDEs to the CIE. | ||||
template <class ELFT, class RelTy> | template <class ELFT, class RelTy> | ||||
▲ Show 20 Lines • Show All 78 Lines • ▼ Show 20 Lines | |||||
// Returns data for .eh_frame_hdr. .eh_frame_hdr is a binary search table | // Returns data for .eh_frame_hdr. .eh_frame_hdr is a binary search table | ||||
// to get an FDE from an address to which FDE is applied. This function | // to get an FDE from an address to which FDE is applied. This function | ||||
// returns a list of such pairs. | // returns a list of such pairs. | ||||
std::vector<EhFrameSection::FdeData> EhFrameSection::getFdeData() const { | std::vector<EhFrameSection::FdeData> EhFrameSection::getFdeData() const { | ||||
uint8_t *Buf = Out::BufferStart + getParent()->Offset + OutSecOff; | uint8_t *Buf = Out::BufferStart + getParent()->Offset + OutSecOff; | ||||
std::vector<FdeData> Ret; | std::vector<FdeData> Ret; | ||||
uint64_t VA = In.EhFrameHdr->getVA(); | uint64_t VA = getPartition().EhFrameHdr->getVA(); | ||||
for (CieRecord *Rec : CieRecords) { | for (CieRecord *Rec : CieRecords) { | ||||
uint8_t Enc = getFdeEncoding(Rec->Cie); | uint8_t Enc = getFdeEncoding(Rec->Cie); | ||||
for (EhSectionPiece *Fde : Rec->Fdes) { | for (EhSectionPiece *Fde : Rec->Fdes) { | ||||
uint64_t Pc = getFdePc(Buf, Fde->OutputOff, Enc); | uint64_t Pc = getFdePc(Buf, Fde->OutputOff, Enc); | ||||
uint64_t FdeVA = getParent()->Addr + Fde->OutputOff; | uint64_t FdeVA = getParent()->Addr + Fde->OutputOff; | ||||
if (!isInt<32>(Pc - VA)) | if (!isInt<32>(Pc - VA)) | ||||
fatal(toString(Fde->Sec) + ": PC offset is too large: 0x" + | fatal(toString(Fde->Sec) + ": PC offset is too large: 0x" + | ||||
Twine::utohexstr(Pc - VA)); | Twine::utohexstr(Pc - VA)); | ||||
▲ Show 20 Lines • Show All 67 Lines • ▼ Show 20 Lines | void EhFrameSection::writeTo(uint8_t *Buf) { | ||||
} | } | ||||
// Apply relocations. .eh_frame section contents are not contiguous | // Apply relocations. .eh_frame section contents are not contiguous | ||||
// in the output buffer, but relocateAlloc() still works because | // in the output buffer, but relocateAlloc() still works because | ||||
// getOffset() takes care of discontiguous section pieces. | // getOffset() takes care of discontiguous section pieces. | ||||
for (EhInputSection *S : Sections) | for (EhInputSection *S : Sections) | ||||
S->relocateAlloc(Buf, nullptr); | S->relocateAlloc(Buf, nullptr); | ||||
if (In.EhFrameHdr && In.EhFrameHdr->getParent()) | if (getPartition().EhFrameHdr && getPartition().EhFrameHdr->getParent()) | ||||
In.EhFrameHdr->write(); | getPartition().EhFrameHdr->write(); | ||||
} | } | ||||
GotSection::GotSection() | GotSection::GotSection() | ||||
: SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS, Config->Wordsize, | : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS, Config->Wordsize, | ||||
".got") { | ".got") { | ||||
// PPC64 saves the ElfSym::GlobalOffsetTable .TOC. as the first entry in the | // PPC64 saves the ElfSym::GlobalOffsetTable .TOC. as the first entry in the | ||||
// .got. If there are no references to .TOC. in the symbol table, | // .got. If there are no references to .TOC. in the symbol table, | ||||
// ElfSym::GlobalOffsetTable will not be defined and we won't need to save | // ElfSym::GlobalOffsetTable will not be defined and we won't need to save | ||||
▲ Show 20 Lines • Show All 334 Lines • ▼ Show 20 Lines | void MipsGotSection::build() { | ||||
// Create dynamic relocations. | // Create dynamic relocations. | ||||
for (FileGot &Got : Gots) { | for (FileGot &Got : Gots) { | ||||
// Create dynamic relocations for TLS entries. | // Create dynamic relocations for TLS entries. | ||||
for (std::pair<Symbol *, size_t> &P : Got.Tls) { | for (std::pair<Symbol *, size_t> &P : Got.Tls) { | ||||
Symbol *S = P.first; | Symbol *S = P.first; | ||||
uint64_t Offset = P.second * Config->Wordsize; | uint64_t Offset = P.second * Config->Wordsize; | ||||
if (S->IsPreemptible) | if (S->IsPreemptible) | ||||
In.RelaDyn->addReloc(Target->TlsGotRel, this, Offset, S); | Main->RelaDyn->addReloc(Target->TlsGotRel, this, Offset, S); | ||||
} | } | ||||
for (std::pair<Symbol *, size_t> &P : Got.DynTlsSymbols) { | for (std::pair<Symbol *, size_t> &P : Got.DynTlsSymbols) { | ||||
Symbol *S = P.first; | Symbol *S = P.first; | ||||
uint64_t Offset = P.second * Config->Wordsize; | uint64_t Offset = P.second * Config->Wordsize; | ||||
if (S == nullptr) { | if (S == nullptr) { | ||||
if (!Config->Pic) | if (!Config->Pic) | ||||
continue; | continue; | ||||
In.RelaDyn->addReloc(Target->TlsModuleIndexRel, this, Offset, S); | Main->RelaDyn->addReloc(Target->TlsModuleIndexRel, this, Offset, S); | ||||
} else { | } else { | ||||
// When building a shared library we still need a dynamic relocation | // When building a shared library we still need a dynamic relocation | ||||
// for the module index. Therefore only checking for | // for the module index. Therefore only checking for | ||||
// S->IsPreemptible is not sufficient (this happens e.g. for | // S->IsPreemptible is not sufficient (this happens e.g. for | ||||
// thread-locals that have been marked as local through a linker script) | // thread-locals that have been marked as local through a linker script) | ||||
if (!S->IsPreemptible && !Config->Pic) | if (!S->IsPreemptible && !Config->Pic) | ||||
continue; | continue; | ||||
In.RelaDyn->addReloc(Target->TlsModuleIndexRel, this, Offset, S); | Main->RelaDyn->addReloc(Target->TlsModuleIndexRel, this, Offset, S); | ||||
// However, we can skip writing the TLS offset reloc for non-preemptible | // However, we can skip writing the TLS offset reloc for non-preemptible | ||||
// symbols since it is known even in shared libraries | // symbols since it is known even in shared libraries | ||||
if (!S->IsPreemptible) | if (!S->IsPreemptible) | ||||
continue; | continue; | ||||
Offset += Config->Wordsize; | Offset += Config->Wordsize; | ||||
In.RelaDyn->addReloc(Target->TlsOffsetRel, this, Offset, S); | Main->RelaDyn->addReloc(Target->TlsOffsetRel, this, Offset, S); | ||||
} | } | ||||
} | } | ||||
// Do not create dynamic relocations for non-TLS | // Do not create dynamic relocations for non-TLS | ||||
// entries in the primary GOT. | // entries in the primary GOT. | ||||
if (&Got == PrimGot) | if (&Got == PrimGot) | ||||
continue; | continue; | ||||
// Dynamic relocations for "global" entries. | // Dynamic relocations for "global" entries. | ||||
for (const std::pair<Symbol *, size_t> &P : Got.Global) { | for (const std::pair<Symbol *, size_t> &P : Got.Global) { | ||||
uint64_t Offset = P.second * Config->Wordsize; | uint64_t Offset = P.second * Config->Wordsize; | ||||
In.RelaDyn->addReloc(Target->RelativeRel, this, Offset, P.first); | Main->RelaDyn->addReloc(Target->RelativeRel, this, Offset, P.first); | ||||
} | } | ||||
if (!Config->Pic) | if (!Config->Pic) | ||||
continue; | continue; | ||||
// Dynamic relocations for "local" entries in case of PIC. | // Dynamic relocations for "local" entries in case of PIC. | ||||
for (const std::pair<const OutputSection *, FileGot::PageBlock> &L : | for (const std::pair<const OutputSection *, FileGot::PageBlock> &L : | ||||
Got.PagesMap) { | Got.PagesMap) { | ||||
size_t PageCount = L.second.Count; | size_t PageCount = L.second.Count; | ||||
for (size_t PI = 0; PI < PageCount; ++PI) { | for (size_t PI = 0; PI < PageCount; ++PI) { | ||||
uint64_t Offset = (L.second.FirstIndex + PI) * Config->Wordsize; | uint64_t Offset = (L.second.FirstIndex + PI) * Config->Wordsize; | ||||
In.RelaDyn->addReloc({Target->RelativeRel, this, Offset, L.first, | Main->RelaDyn->addReloc({Target->RelativeRel, this, Offset, L.first, | ||||
int64_t(PI * 0x10000)}); | int64_t(PI * 0x10000)}); | ||||
} | } | ||||
} | } | ||||
for (const std::pair<GotEntry, size_t> &P : Got.Local16) { | for (const std::pair<GotEntry, size_t> &P : Got.Local16) { | ||||
uint64_t Offset = P.second * Config->Wordsize; | uint64_t Offset = P.second * Config->Wordsize; | ||||
In.RelaDyn->addReloc({Target->RelativeRel, this, Offset, true, | Main->RelaDyn->addReloc({Target->RelativeRel, this, Offset, true, | ||||
P.first.first, P.first.second}); | P.first.first, P.first.second}); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
bool MipsGotSection::isNeeded() const { | bool MipsGotSection::isNeeded() const { | ||||
// We add the .got section to the result for dynamic MIPS target because | // We add the .got section to the result for dynamic MIPS target because | ||||
// its address and properties are mentioned in the .dynamic section. | // its address and properties are mentioned in the .dynamic section. | ||||
return !Config->Relocatable; | return !Config->Relocatable; | ||||
▲ Show 20 Lines • Show All 237 Lines • ▼ Show 20 Lines | static uint64_t addPltRelSz() { | ||||
if (In.RelaIplt->getParent() == In.RelaPlt->getParent() && | if (In.RelaIplt->getParent() == In.RelaPlt->getParent() && | ||||
In.RelaIplt->Name == In.RelaPlt->Name) | In.RelaIplt->Name == In.RelaPlt->Name) | ||||
Size += In.RelaIplt->getSize(); | Size += In.RelaIplt->getSize(); | ||||
return Size; | return Size; | ||||
} | } | ||||
// Add remaining entries to complete .dynamic contents. | // Add remaining entries to complete .dynamic contents. | ||||
template <class ELFT> void DynamicSection<ELFT>::finalizeContents() { | template <class ELFT> void DynamicSection<ELFT>::finalizeContents() { | ||||
elf::Partition &Part = getPartition(); | |||||
bool IsMain = Part.Name.empty(); | |||||
for (StringRef S : Config->FilterList) | for (StringRef S : Config->FilterList) | ||||
addInt(DT_FILTER, In.DynStrTab->addString(S)); | addInt(DT_FILTER, Part.DynStrTab->addString(S)); | ||||
for (StringRef S : Config->AuxiliaryList) | for (StringRef S : Config->AuxiliaryList) | ||||
addInt(DT_AUXILIARY, In.DynStrTab->addString(S)); | addInt(DT_AUXILIARY, Part.DynStrTab->addString(S)); | ||||
if (!Config->Rpath.empty()) | if (!Config->Rpath.empty()) | ||||
addInt(Config->EnableNewDtags ? DT_RUNPATH : DT_RPATH, | addInt(Config->EnableNewDtags ? DT_RUNPATH : DT_RPATH, | ||||
In.DynStrTab->addString(Config->Rpath)); | Part.DynStrTab->addString(Config->Rpath)); | ||||
for (SharedFile *File : SharedFiles) | for (SharedFile *File : SharedFiles) | ||||
if (File->IsNeeded) | if (File->IsNeeded) | ||||
addInt(DT_NEEDED, In.DynStrTab->addString(File->SoName)); | addInt(DT_NEEDED, Part.DynStrTab->addString(File->SoName)); | ||||
if (IsMain) { | |||||
if (!Config->SoName.empty()) | |||||
addInt(DT_SONAME, Part.DynStrTab->addString(Config->SoName)); | |||||
} else { | |||||
if (!Config->SoName.empty()) | if (!Config->SoName.empty()) | ||||
addInt(DT_SONAME, In.DynStrTab->addString(Config->SoName)); | addInt(DT_NEEDED, Part.DynStrTab->addString(Config->SoName)); | ||||
addInt(DT_SONAME, Part.DynStrTab->addString(Part.Name)); | |||||
} | |||||
// Set DT_FLAGS and DT_FLAGS_1. | // Set DT_FLAGS and DT_FLAGS_1. | ||||
uint32_t DtFlags = 0; | uint32_t DtFlags = 0; | ||||
uint32_t DtFlags1 = 0; | uint32_t DtFlags1 = 0; | ||||
if (Config->Bsymbolic) | if (Config->Bsymbolic) | ||||
DtFlags |= DF_SYMBOLIC; | DtFlags |= DF_SYMBOLIC; | ||||
if (Config->ZGlobal) | if (Config->ZGlobal) | ||||
DtFlags1 |= DF_1_GLOBAL; | DtFlags1 |= DF_1_GLOBAL; | ||||
Show All 31 Lines | template <class ELFT> void DynamicSection<ELFT>::finalizeContents() { | ||||
// | // | ||||
// DT_DEBUG is the only .dynamic entry that needs to be written to. Some | // DT_DEBUG is the only .dynamic entry that needs to be written to. Some | ||||
// systems (currently only Fuchsia OS) provide other means to give the | // systems (currently only Fuchsia OS) provide other means to give the | ||||
// debugger this information. Such systems may choose make .dynamic read-only. | // debugger this information. Such systems may choose make .dynamic read-only. | ||||
// If the target is such a system (used -z rodynamic) don't write DT_DEBUG. | // If the target is such a system (used -z rodynamic) don't write DT_DEBUG. | ||||
if (!Config->Shared && !Config->Relocatable && !Config->ZRodynamic) | if (!Config->Shared && !Config->Relocatable && !Config->ZRodynamic) | ||||
addInt(DT_DEBUG, 0); | addInt(DT_DEBUG, 0); | ||||
if (OutputSection *Sec = In.DynStrTab->getParent()) | if (OutputSection *Sec = Part.DynStrTab->getParent()) | ||||
this->Link = Sec->SectionIndex; | this->Link = Sec->SectionIndex; | ||||
if (In.RelaDyn->isNeeded()) { | if (Part.RelaDyn->isNeeded()) { | ||||
addInSec(In.RelaDyn->DynamicTag, In.RelaDyn); | addInSec(Part.RelaDyn->DynamicTag, Part.RelaDyn); | ||||
addSize(In.RelaDyn->SizeDynamicTag, In.RelaDyn->getParent()); | addSize(Part.RelaDyn->SizeDynamicTag, Part.RelaDyn->getParent()); | ||||
bool IsRela = Config->IsRela; | bool IsRela = Config->IsRela; | ||||
addInt(IsRela ? DT_RELAENT : DT_RELENT, | addInt(IsRela ? DT_RELAENT : DT_RELENT, | ||||
IsRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel)); | IsRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel)); | ||||
// MIPS dynamic loader does not support RELCOUNT tag. | // MIPS dynamic loader does not support RELCOUNT tag. | ||||
// The problem is in the tight relation between dynamic | // The problem is in the tight relation between dynamic | ||||
// relocations and GOT. So do not emit this tag on MIPS. | // relocations and GOT. So do not emit this tag on MIPS. | ||||
if (Config->EMachine != EM_MIPS) { | if (Config->EMachine != EM_MIPS) { | ||||
size_t NumRelativeRels = In.RelaDyn->getRelativeRelocCount(); | size_t NumRelativeRels = Part.RelaDyn->getRelativeRelocCount(); | ||||
if (Config->ZCombreloc && NumRelativeRels) | if (Config->ZCombreloc && NumRelativeRels) | ||||
addInt(IsRela ? DT_RELACOUNT : DT_RELCOUNT, NumRelativeRels); | addInt(IsRela ? DT_RELACOUNT : DT_RELCOUNT, NumRelativeRels); | ||||
} | } | ||||
} | } | ||||
if (In.RelrDyn && !In.RelrDyn->Relocs.empty()) { | if (Part.RelrDyn && !Part.RelrDyn->Relocs.empty()) { | ||||
addInSec(Config->UseAndroidRelrTags ? DT_ANDROID_RELR : DT_RELR, | addInSec(Config->UseAndroidRelrTags ? DT_ANDROID_RELR : DT_RELR, | ||||
In.RelrDyn); | Part.RelrDyn); | ||||
addSize(Config->UseAndroidRelrTags ? DT_ANDROID_RELRSZ : DT_RELRSZ, | addSize(Config->UseAndroidRelrTags ? DT_ANDROID_RELRSZ : DT_RELRSZ, | ||||
In.RelrDyn->getParent()); | Part.RelrDyn->getParent()); | ||||
addInt(Config->UseAndroidRelrTags ? DT_ANDROID_RELRENT : DT_RELRENT, | addInt(Config->UseAndroidRelrTags ? DT_ANDROID_RELRENT : DT_RELRENT, | ||||
sizeof(Elf_Relr)); | sizeof(Elf_Relr)); | ||||
} | } | ||||
// .rel[a].plt section usually consists of two parts, containing plt and | // .rel[a].plt section usually consists of two parts, containing plt and | ||||
// iplt relocations. It is possible to have only iplt relocations in the | // iplt relocations. It is possible to have only iplt relocations in the | ||||
// output. In that case RelaPlt is empty and have zero offset, the same offset | // output. In that case RelaPlt is empty and have zero offset, the same offset | ||||
// as RelaIplt have. And we still want to emit proper dynamic tags for that | // as RelaIplt have. And we still want to emit proper dynamic tags for that | ||||
// case, so here we always use RelaPlt as marker for the begining of | // case, so here we always use RelaPlt as marker for the begining of | ||||
// .rel[a].plt section. | // .rel[a].plt section. | ||||
if (In.RelaPlt->getParent()->isLive()) { | if (IsMain && In.RelaPlt->getParent()->isLive()) { | ||||
addInSec(DT_JMPREL, In.RelaPlt); | addInSec(DT_JMPREL, In.RelaPlt); | ||||
Entries.push_back({DT_PLTRELSZ, addPltRelSz}); | Entries.push_back({DT_PLTRELSZ, addPltRelSz}); | ||||
switch (Config->EMachine) { | switch (Config->EMachine) { | ||||
case EM_MIPS: | case EM_MIPS: | ||||
addInSec(DT_MIPS_PLTGOT, In.GotPlt); | addInSec(DT_MIPS_PLTGOT, In.GotPlt); | ||||
break; | break; | ||||
case EM_SPARCV9: | case EM_SPARCV9: | ||||
addInSec(DT_PLTGOT, In.Plt); | addInSec(DT_PLTGOT, In.Plt); | ||||
break; | break; | ||||
default: | default: | ||||
addInSec(DT_PLTGOT, In.GotPlt); | addInSec(DT_PLTGOT, In.GotPlt); | ||||
break; | break; | ||||
} | } | ||||
addInt(DT_PLTREL, Config->IsRela ? DT_RELA : DT_REL); | addInt(DT_PLTREL, Config->IsRela ? DT_RELA : DT_REL); | ||||
} | } | ||||
addInSec(DT_SYMTAB, In.DynSymTab); | addInSec(DT_SYMTAB, Part.DynSymTab); | ||||
addInt(DT_SYMENT, sizeof(Elf_Sym)); | addInt(DT_SYMENT, sizeof(Elf_Sym)); | ||||
addInSec(DT_STRTAB, In.DynStrTab); | addInSec(DT_STRTAB, Part.DynStrTab); | ||||
addInt(DT_STRSZ, In.DynStrTab->getSize()); | addInt(DT_STRSZ, Part.DynStrTab->getSize()); | ||||
if (!Config->ZText) | if (!Config->ZText) | ||||
addInt(DT_TEXTREL, 0); | addInt(DT_TEXTREL, 0); | ||||
if (In.GnuHashTab) | if (Part.GnuHashTab) | ||||
addInSec(DT_GNU_HASH, In.GnuHashTab); | addInSec(DT_GNU_HASH, Part.GnuHashTab); | ||||
if (In.HashTab) | if (Part.HashTab) | ||||
addInSec(DT_HASH, In.HashTab); | addInSec(DT_HASH, Part.HashTab); | ||||
if (IsMain) { | |||||
if (Out::PreinitArray) { | if (Out::PreinitArray) { | ||||
addOutSec(DT_PREINIT_ARRAY, Out::PreinitArray); | addOutSec(DT_PREINIT_ARRAY, Out::PreinitArray); | ||||
addSize(DT_PREINIT_ARRAYSZ, Out::PreinitArray); | addSize(DT_PREINIT_ARRAYSZ, Out::PreinitArray); | ||||
} | } | ||||
if (Out::InitArray) { | if (Out::InitArray) { | ||||
addOutSec(DT_INIT_ARRAY, Out::InitArray); | addOutSec(DT_INIT_ARRAY, Out::InitArray); | ||||
addSize(DT_INIT_ARRAYSZ, Out::InitArray); | addSize(DT_INIT_ARRAYSZ, Out::InitArray); | ||||
} | } | ||||
if (Out::FiniArray) { | if (Out::FiniArray) { | ||||
addOutSec(DT_FINI_ARRAY, Out::FiniArray); | addOutSec(DT_FINI_ARRAY, Out::FiniArray); | ||||
addSize(DT_FINI_ARRAYSZ, Out::FiniArray); | addSize(DT_FINI_ARRAYSZ, Out::FiniArray); | ||||
} | } | ||||
if (Symbol *B = Symtab->find(Config->Init)) | if (Symbol *B = Symtab->find(Config->Init)) | ||||
if (B->isDefined()) | if (B->isDefined()) | ||||
addSym(DT_INIT, B); | addSym(DT_INIT, B); | ||||
if (Symbol *B = Symtab->find(Config->Fini)) | if (Symbol *B = Symtab->find(Config->Fini)) | ||||
if (B->isDefined()) | if (B->isDefined()) | ||||
addSym(DT_FINI, B); | addSym(DT_FINI, B); | ||||
} | |||||
bool HasVerNeed = SharedFile::VernauxNum != 0; | bool HasVerNeed = SharedFile::VernauxNum != 0; | ||||
if (HasVerNeed || In.VerDef) | if (HasVerNeed || Part.VerDef) | ||||
addInSec(DT_VERSYM, In.VerSym); | addInSec(DT_VERSYM, Part.VerSym); | ||||
if (In.VerDef) { | if (Part.VerDef) { | ||||
addInSec(DT_VERDEF, In.VerDef); | addInSec(DT_VERDEF, Part.VerDef); | ||||
addInt(DT_VERDEFNUM, getVerDefNum()); | addInt(DT_VERDEFNUM, getVerDefNum()); | ||||
} | } | ||||
if (HasVerNeed) { | if (HasVerNeed) { | ||||
addInSec(DT_VERNEED, In.VerNeed); | addInSec(DT_VERNEED, Part.VerNeed); | ||||
unsigned NeedNum = 0; | unsigned NeedNum = 0; | ||||
for (SharedFile *F : SharedFiles) | for (SharedFile *F : SharedFiles) | ||||
if (!F->Vernauxs.empty()) | if (!F->Vernauxs.empty()) | ||||
++NeedNum; | ++NeedNum; | ||||
addInt(DT_VERNEEDNUM, NeedNum); | addInt(DT_VERNEEDNUM, NeedNum); | ||||
} | } | ||||
if (Config->EMachine == EM_MIPS) { | if (Config->EMachine == EM_MIPS) { | ||||
addInt(DT_MIPS_RLD_VERSION, 1); | addInt(DT_MIPS_RLD_VERSION, 1); | ||||
addInt(DT_MIPS_FLAGS, RHF_NOTPOT); | addInt(DT_MIPS_FLAGS, RHF_NOTPOT); | ||||
addInt(DT_MIPS_BASE_ADDRESS, Target->getImageBase()); | addInt(DT_MIPS_BASE_ADDRESS, Target->getImageBase()); | ||||
addInt(DT_MIPS_SYMTABNO, In.DynSymTab->getNumSymbols()); | addInt(DT_MIPS_SYMTABNO, Part.DynSymTab->getNumSymbols()); | ||||
add(DT_MIPS_LOCAL_GOTNO, [] { return In.MipsGot->getLocalEntriesNum(); }); | add(DT_MIPS_LOCAL_GOTNO, [] { return In.MipsGot->getLocalEntriesNum(); }); | ||||
if (const Symbol *B = In.MipsGot->getFirstGlobalEntry()) | if (const Symbol *B = In.MipsGot->getFirstGlobalEntry()) | ||||
addInt(DT_MIPS_GOTSYM, B->DynsymIndex); | addInt(DT_MIPS_GOTSYM, B->DynsymIndex); | ||||
else | else | ||||
addInt(DT_MIPS_GOTSYM, In.DynSymTab->getNumSymbols()); | addInt(DT_MIPS_GOTSYM, Part.DynSymTab->getNumSymbols()); | ||||
addInSec(DT_PLTGOT, In.MipsGot); | addInSec(DT_PLTGOT, In.MipsGot); | ||||
if (In.MipsRldMap) { | if (In.MipsRldMap) { | ||||
if (!Config->Pie) | if (!Config->Pie) | ||||
addInSec(DT_MIPS_RLD_MAP, In.MipsRldMap); | addInSec(DT_MIPS_RLD_MAP, In.MipsRldMap); | ||||
// Store the offset to the .rld_map section | // Store the offset to the .rld_map section | ||||
// relative to the address of the tag. | // relative to the address of the tag. | ||||
addInSecRelative(DT_MIPS_RLD_MAP_REL, In.MipsRldMap); | addInSecRelative(DT_MIPS_RLD_MAP_REL, In.MipsRldMap); | ||||
} | } | ||||
Show All 33 Lines | int64_t DynamicReloc::computeAddend() const { | ||||
if (UseSymVA) | if (UseSymVA) | ||||
return Sym->getVA(Addend); | return Sym->getVA(Addend); | ||||
if (!OutputSec) | if (!OutputSec) | ||||
return Addend; | return Addend; | ||||
// See the comment in the DynamicReloc ctor. | // See the comment in the DynamicReloc ctor. | ||||
return getMipsPageAddr(OutputSec->Addr) + Addend; | return getMipsPageAddr(OutputSec->Addr) + Addend; | ||||
} | } | ||||
uint32_t DynamicReloc::getSymIndex() const { | uint32_t DynamicReloc::getSymIndex(SymbolTableBaseSection *SymTab) const { | ||||
if (Sym && !UseSymVA) | if (Sym && !UseSymVA) | ||||
return Sym->DynsymIndex; | return SymTab->getSymbolIndex(Sym); | ||||
return 0; | return 0; | ||||
} | } | ||||
RelocationBaseSection::RelocationBaseSection(StringRef Name, uint32_t Type, | RelocationBaseSection::RelocationBaseSection(StringRef Name, uint32_t Type, | ||||
int32_t DynamicTag, | int32_t DynamicTag, | ||||
int32_t SizeDynamicTag) | int32_t SizeDynamicTag) | ||||
: SyntheticSection(SHF_ALLOC, Type, Config->Wordsize, Name), | : SyntheticSection(SHF_ALLOC, Type, Config->Wordsize, Name), | ||||
DynamicTag(DynamicTag), SizeDynamicTag(SizeDynamicTag) {} | DynamicTag(DynamicTag), SizeDynamicTag(SizeDynamicTag) {} | ||||
Show All 17 Lines | |||||
void RelocationBaseSection::addReloc(const DynamicReloc &Reloc) { | void RelocationBaseSection::addReloc(const DynamicReloc &Reloc) { | ||||
if (Reloc.Type == Target->RelativeRel) | if (Reloc.Type == Target->RelativeRel) | ||||
++NumRelativeRelocs; | ++NumRelativeRelocs; | ||||
Relocs.push_back(Reloc); | Relocs.push_back(Reloc); | ||||
} | } | ||||
void RelocationBaseSection::finalizeContents() { | void RelocationBaseSection::finalizeContents() { | ||||
SymbolTableBaseSection *SymTab = getPartition().DynSymTab; | |||||
// When linking glibc statically, .rel{,a}.plt contains R_*_IRELATIVE | // When linking glibc statically, .rel{,a}.plt contains R_*_IRELATIVE | ||||
// relocations due to IFUNC (e.g. strcpy). sh_link will be set to 0 in that | // relocations due to IFUNC (e.g. strcpy). sh_link will be set to 0 in that | ||||
// case. | // case. | ||||
if (In.DynSymTab && In.DynSymTab->getParent()) | if (SymTab && SymTab->getParent()) | ||||
getParent()->Link = In.DynSymTab->getParent()->SectionIndex; | getParent()->Link = SymTab->getParent()->SectionIndex; | ||||
else | else | ||||
getParent()->Link = 0; | getParent()->Link = 0; | ||||
if (In.RelaPlt == this) | if (In.RelaPlt == this) | ||||
getParent()->Info = In.GotPlt->getParent()->SectionIndex; | getParent()->Info = In.GotPlt->getParent()->SectionIndex; | ||||
if (In.RelaIplt == this) | if (In.RelaIplt == this) | ||||
getParent()->Info = In.IgotPlt->getParent()->SectionIndex; | getParent()->Info = In.IgotPlt->getParent()->SectionIndex; | ||||
} | } | ||||
RelrBaseSection::RelrBaseSection() | RelrBaseSection::RelrBaseSection() | ||||
: SyntheticSection(SHF_ALLOC, | : SyntheticSection(SHF_ALLOC, | ||||
Config->UseAndroidRelrTags ? SHT_ANDROID_RELR : SHT_RELR, | Config->UseAndroidRelrTags ? SHT_ANDROID_RELR : SHT_RELR, | ||||
Config->Wordsize, ".relr.dyn") {} | Config->Wordsize, ".relr.dyn") {} | ||||
template <class ELFT> | template <class ELFT> | ||||
static void encodeDynamicReloc(typename ELFT::Rela *P, | static void encodeDynamicReloc(SymbolTableBaseSection *SymTab, | ||||
typename ELFT::Rela *P, | |||||
const DynamicReloc &Rel) { | const DynamicReloc &Rel) { | ||||
if (Config->IsRela) | if (Config->IsRela) | ||||
P->r_addend = Rel.computeAddend(); | P->r_addend = Rel.computeAddend(); | ||||
P->r_offset = Rel.getOffset(); | P->r_offset = Rel.getOffset(); | ||||
P->setSymbolAndType(Rel.getSymIndex(), Rel.Type, Config->IsMips64EL); | P->setSymbolAndType(Rel.getSymIndex(SymTab), Rel.Type, Config->IsMips64EL); | ||||
} | } | ||||
template <class ELFT> | template <class ELFT> | ||||
RelocationSection<ELFT>::RelocationSection(StringRef Name, bool Sort) | RelocationSection<ELFT>::RelocationSection(StringRef Name, bool Sort) | ||||
: RelocationBaseSection(Name, Config->IsRela ? SHT_RELA : SHT_REL, | : RelocationBaseSection(Name, Config->IsRela ? SHT_RELA : SHT_REL, | ||||
Config->IsRela ? DT_RELA : DT_REL, | Config->IsRela ? DT_RELA : DT_REL, | ||||
Config->IsRela ? DT_RELASZ : DT_RELSZ), | Config->IsRela ? DT_RELASZ : DT_RELSZ), | ||||
Sort(Sort) { | Sort(Sort) { | ||||
this->Entsize = Config->IsRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel); | this->Entsize = Config->IsRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel); | ||||
} | } | ||||
template <class ELFT> void RelocationSection<ELFT>::writeTo(uint8_t *Buf) { | template <class ELFT> void RelocationSection<ELFT>::writeTo(uint8_t *Buf) { | ||||
SymbolTableBaseSection *SymTab = getPartition().DynSymTab; | |||||
// Sort by (!IsRelative,SymIndex,r_offset). DT_REL[A]COUNT requires us to | // Sort by (!IsRelative,SymIndex,r_offset). DT_REL[A]COUNT requires us to | ||||
// place R_*_RELATIVE first. SymIndex is to improve locality, while r_offset | // place R_*_RELATIVE first. SymIndex is to improve locality, while r_offset | ||||
// is to make results easier to read. | // is to make results easier to read. | ||||
if (Sort) | if (Sort) | ||||
llvm::stable_sort(Relocs, [](const DynamicReloc &A, const DynamicReloc &B) { | llvm::stable_sort( | ||||
return std::make_tuple(A.Type != Target->RelativeRel, A.getSymIndex(), | Relocs, [&](const DynamicReloc &A, const DynamicReloc &B) { | ||||
A.getOffset()) < | return std::make_tuple(A.Type != Target->RelativeRel, | ||||
std::make_tuple(B.Type != Target->RelativeRel, B.getSymIndex(), | A.getSymIndex(SymTab), A.getOffset()) < | ||||
B.getOffset()); | std::make_tuple(B.Type != Target->RelativeRel, | ||||
B.getSymIndex(SymTab), B.getOffset()); | |||||
}); | }); | ||||
for (const DynamicReloc &Rel : Relocs) { | for (const DynamicReloc &Rel : Relocs) { | ||||
encodeDynamicReloc<ELFT>(reinterpret_cast<Elf_Rela *>(Buf), Rel); | encodeDynamicReloc<ELFT>(SymTab, reinterpret_cast<Elf_Rela *>(Buf), Rel); | ||||
Buf += Config->IsRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel); | Buf += Config->IsRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel); | ||||
} | } | ||||
} | } | ||||
template <class ELFT> | template <class ELFT> | ||||
AndroidPackedRelocationSection<ELFT>::AndroidPackedRelocationSection( | AndroidPackedRelocationSection<ELFT>::AndroidPackedRelocationSection( | ||||
StringRef Name) | StringRef Name) | ||||
: RelocationBaseSection( | : RelocationBaseSection( | ||||
▲ Show 20 Lines • Show All 61 Lines • ▼ Show 20 Lines | bool AndroidPackedRelocationSection<ELFT>::updateAllocSize() { | ||||
// perform the initial adjustment). | // perform the initial adjustment). | ||||
Add(Relocs.size()); | Add(Relocs.size()); | ||||
Add(0); | Add(0); | ||||
std::vector<Elf_Rela> Relatives, NonRelatives; | std::vector<Elf_Rela> Relatives, NonRelatives; | ||||
for (const DynamicReloc &Rel : Relocs) { | for (const DynamicReloc &Rel : Relocs) { | ||||
Elf_Rela R; | Elf_Rela R; | ||||
encodeDynamicReloc<ELFT>(&R, Rel); | encodeDynamicReloc<ELFT>(getPartition().DynSymTab, &R, Rel); | ||||
if (R.getType(Config->IsMips64EL) == Target->RelativeRel) | if (R.getType(Config->IsMips64EL) == Target->RelativeRel) | ||||
Relatives.push_back(R); | Relatives.push_back(R); | ||||
else | else | ||||
NonRelatives.push_back(R); | NonRelatives.push_back(R); | ||||
} | } | ||||
llvm::sort(Relatives, [](const Elf_Rel &A, const Elf_Rel &B) { | llvm::sort(Relatives, [](const Elf_Rel &A, const Elf_Rel &B) { | ||||
▲ Show 20 Lines • Show All 231 Lines • ▼ Show 20 Lines | void SymbolTableBaseSection::finalizeContents() { | ||||
// If it is a .dynsym, there should be no local symbols, but we need | // If it is a .dynsym, there should be no local symbols, but we need | ||||
// to do a few things for the dynamic linker. | // to do a few things for the dynamic linker. | ||||
// Section's Info field has the index of the first non-local symbol. | // Section's Info field has the index of the first non-local symbol. | ||||
// Because the first symbol entry is a null entry, 1 is the first. | // Because the first symbol entry is a null entry, 1 is the first. | ||||
getParent()->Info = 1; | getParent()->Info = 1; | ||||
if (In.GnuHashTab) { | if (getPartition().GnuHashTab) { | ||||
// NB: It also sorts Symbols to meet the GNU hash table requirements. | // NB: It also sorts Symbols to meet the GNU hash table requirements. | ||||
In.GnuHashTab->addSymbols(Symbols); | getPartition().GnuHashTab->addSymbols(Symbols); | ||||
} else if (Config->EMachine == EM_MIPS) { | } else if (Config->EMachine == EM_MIPS) { | ||||
llvm::stable_sort(Symbols, sortMipsSymbols); | llvm::stable_sort(Symbols, sortMipsSymbols); | ||||
} | } | ||||
// Only the main partition's dynsym indexes are stored in the symbols | |||||
// themselves. All other partitions use a lookup table. | |||||
if (this == Main->DynSymTab) { | |||||
size_t I = 0; | size_t I = 0; | ||||
for (const SymbolTableEntry &S : Symbols) | for (const SymbolTableEntry &S : Symbols) | ||||
S.Sym->DynsymIndex = ++I; | S.Sym->DynsymIndex = ++I; | ||||
} | } | ||||
} | |||||
// The ELF spec requires that all local symbols precede global symbols, so we | // The ELF spec requires that all local symbols precede global symbols, so we | ||||
// sort symbol entries in this function. (For .dynsym, we don't do that because | // sort symbol entries in this function. (For .dynsym, we don't do that because | ||||
// symbols for dynamic linking are inherently all globals.) | // symbols for dynamic linking are inherently all globals.) | ||||
// | // | ||||
// Aside from above, we put local symbols in groups starting with the STT_FILE | // Aside from above, we put local symbols in groups starting with the STT_FILE | ||||
// symbol. That is convenient for purpose of identifying where are local symbols | // symbol. That is convenient for purpose of identifying where are local symbols | ||||
// coming from. | // coming from. | ||||
Show All 25 Lines | void SymbolTableBaseSection::addSymbol(Symbol *B) { | ||||
// Adding a local symbol to a .dynsym is a bug. | // Adding a local symbol to a .dynsym is a bug. | ||||
assert(this->Type != SHT_DYNSYM || !B->isLocal()); | assert(this->Type != SHT_DYNSYM || !B->isLocal()); | ||||
bool HashIt = B->isLocal(); | bool HashIt = B->isLocal(); | ||||
Symbols.push_back({B, StrTabSec.addString(B->getName(), HashIt)}); | Symbols.push_back({B, StrTabSec.addString(B->getName(), HashIt)}); | ||||
} | } | ||||
size_t SymbolTableBaseSection::getSymbolIndex(Symbol *Sym) { | size_t SymbolTableBaseSection::getSymbolIndex(Symbol *Sym) { | ||||
// Initializes symbol lookup tables lazily. This is used only | if (this == Main->DynSymTab) | ||||
// for -r or -emit-relocs. | return Sym->DynsymIndex; | ||||
// Initializes symbol lookup tables lazily. This is used only for -r, | |||||
// -emit-relocs and dynsyms in partitions other than the main one. | |||||
llvm::call_once(OnceFlag, [&] { | llvm::call_once(OnceFlag, [&] { | ||||
SymbolIndexMap.reserve(Symbols.size()); | SymbolIndexMap.reserve(Symbols.size()); | ||||
size_t I = 0; | size_t I = 0; | ||||
for (const SymbolTableEntry &E : Symbols) { | for (const SymbolTableEntry &E : Symbols) { | ||||
if (E.Sym->Type == STT_SECTION) | if (E.Sym->Type == STT_SECTION) | ||||
SectionIndexMap[E.Sym->getOutputSection()] = ++I; | SectionIndexMap[E.Sym->getOutputSection()] = ++I; | ||||
else | else | ||||
SymbolIndexMap[E.Sym] = ++I; | SymbolIndexMap[E.Sym] = ++I; | ||||
Show All 36 Lines | template <class ELFT> void SymbolTableSection<ELFT>::writeTo(uint8_t *Buf) { | ||||
// The first entry is a null entry as per the ELF spec. | // The first entry is a null entry as per the ELF spec. | ||||
memset(Buf, 0, sizeof(Elf_Sym)); | memset(Buf, 0, sizeof(Elf_Sym)); | ||||
Buf += sizeof(Elf_Sym); | Buf += sizeof(Elf_Sym); | ||||
auto *ESym = reinterpret_cast<Elf_Sym *>(Buf); | auto *ESym = reinterpret_cast<Elf_Sym *>(Buf); | ||||
for (SymbolTableEntry &Ent : Symbols) { | for (SymbolTableEntry &Ent : Symbols) { | ||||
Symbol *Sym = Ent.Sym; | Symbol *Sym = Ent.Sym; | ||||
bool IsDefinedHere = Type == SHT_SYMTAB || Sym->Partition == Partition; | |||||
// Set st_info and st_other. | // Set st_info and st_other. | ||||
ESym->st_other = 0; | ESym->st_other = 0; | ||||
if (Sym->isLocal()) { | if (Sym->isLocal()) { | ||||
ESym->setBindingAndType(STB_LOCAL, Sym->Type); | ESym->setBindingAndType(STB_LOCAL, Sym->Type); | ||||
} else { | } else { | ||||
ESym->setBindingAndType(Sym->computeBinding(), Sym->Type); | ESym->setBindingAndType(Sym->computeBinding(), Sym->Type); | ||||
ESym->setVisibility(Sym->Visibility); | ESym->setVisibility(Sym->Visibility); | ||||
} | } | ||||
// The 3 most significant bits of st_other are used by OpenPOWER ABI. | // The 3 most significant bits of st_other are used by OpenPOWER ABI. | ||||
// See getPPC64GlobalEntryToLocalEntryOffset() for more details. | // See getPPC64GlobalEntryToLocalEntryOffset() for more details. | ||||
if (Config->EMachine == EM_PPC64) | if (Config->EMachine == EM_PPC64) | ||||
ESym->st_other |= Sym->StOther & 0xe0; | ESym->st_other |= Sym->StOther & 0xe0; | ||||
ESym->st_name = Ent.StrTabOffset; | ESym->st_name = Ent.StrTabOffset; | ||||
if (IsDefinedHere) | |||||
ESym->st_shndx = getSymSectionIndex(Ent.Sym); | ESym->st_shndx = getSymSectionIndex(Ent.Sym); | ||||
else | |||||
ESym->st_shndx = 0; | |||||
// Copy symbol size if it is a defined symbol. st_size is not significant | // Copy symbol size if it is a defined symbol. st_size is not significant | ||||
// for undefined symbols, so whether copying it or not is up to us if that's | // for undefined symbols, so whether copying it or not is up to us if that's | ||||
// the case. We'll leave it as zero because by not setting a value, we can | // the case. We'll leave it as zero because by not setting a value, we can | ||||
// get the exact same outputs for two sets of input files that differ only | // get the exact same outputs for two sets of input files that differ only | ||||
// in undefined symbol size in DSOs. | // in undefined symbol size in DSOs. | ||||
if (ESym->st_shndx == SHN_UNDEF) | if (ESym->st_shndx == SHN_UNDEF || !IsDefinedHere) | ||||
ESym->st_size = 0; | ESym->st_size = 0; | ||||
else | else | ||||
ESym->st_size = Sym->getSize(); | ESym->st_size = Sym->getSize(); | ||||
// st_value is usually an address of a symbol, but that has a | // st_value is usually an address of a symbol, but that has a | ||||
// special meaining for uninstantiated common symbols (this can | // special meaining for uninstantiated common symbols (this can | ||||
// occur if -r is given). | // occur if -r is given). | ||||
if (BssSection *CommonSec = getCommonSec(Ent.Sym)) | if (BssSection *CommonSec = getCommonSec(Ent.Sym)) | ||||
ESym->st_value = CommonSec->Alignment; | ESym->st_value = CommonSec->Alignment; | ||||
else | else if (IsDefinedHere) | ||||
ESym->st_value = Sym->getVA(); | ESym->st_value = Sym->getVA(); | ||||
else | |||||
ESym->st_value = 0; | |||||
++ESym; | ++ESym; | ||||
} | } | ||||
// On MIPS we need to mark symbol which has a PLT entry and requires | // On MIPS we need to mark symbol which has a PLT entry and requires | ||||
// pointer equality by STO_MIPS_PLT flag. That is necessary to help | // pointer equality by STO_MIPS_PLT flag. That is necessary to help | ||||
// dynamic linker distinguish such symbols and MIPS lazy-binding stubs. | // dynamic linker distinguish such symbols and MIPS lazy-binding stubs. | ||||
// https://sourceware.org/ml/binutils/2008-07/txt00000.txt | // https://sourceware.org/ml/binutils/2008-07/txt00000.txt | ||||
▲ Show 20 Lines • Show All 97 Lines • ▼ Show 20 Lines | |||||
// DSOs very quickly. If you are sure that your dynamic linker knows | // DSOs very quickly. If you are sure that your dynamic linker knows | ||||
// about .gnu.hash, you want to specify -hash-style=gnu. Otherwise, a | // about .gnu.hash, you want to specify -hash-style=gnu. Otherwise, a | ||||
// safe bet is to specify -hash-style=both for backward compatibilty. | // safe bet is to specify -hash-style=both for backward compatibilty. | ||||
GnuHashTableSection::GnuHashTableSection() | GnuHashTableSection::GnuHashTableSection() | ||||
: SyntheticSection(SHF_ALLOC, SHT_GNU_HASH, Config->Wordsize, ".gnu.hash") { | : SyntheticSection(SHF_ALLOC, SHT_GNU_HASH, Config->Wordsize, ".gnu.hash") { | ||||
} | } | ||||
void GnuHashTableSection::finalizeContents() { | void GnuHashTableSection::finalizeContents() { | ||||
if (OutputSection *Sec = In.DynSymTab->getParent()) | if (OutputSection *Sec = getPartition().DynSymTab->getParent()) | ||||
getParent()->Link = Sec->SectionIndex; | getParent()->Link = Sec->SectionIndex; | ||||
// Computes bloom filter size in word size. We want to allocate 12 | // Computes bloom filter size in word size. We want to allocate 12 | ||||
// bits for each symbol. It must be a power of two. | // bits for each symbol. It must be a power of two. | ||||
if (Symbols.empty()) { | if (Symbols.empty()) { | ||||
MaskWords = 1; | MaskWords = 1; | ||||
} else { | } else { | ||||
uint64_t NumBits = Symbols.size() * 12; | uint64_t NumBits = Symbols.size() * 12; | ||||
Show All 9 Lines | |||||
void GnuHashTableSection::writeTo(uint8_t *Buf) { | void GnuHashTableSection::writeTo(uint8_t *Buf) { | ||||
// The output buffer is not guaranteed to be zero-cleared because we pre- | // The output buffer is not guaranteed to be zero-cleared because we pre- | ||||
// fill executable sections with trap instructions. This is a precaution | // fill executable sections with trap instructions. This is a precaution | ||||
// for that case, which happens only when -no-rosegment is given. | // for that case, which happens only when -no-rosegment is given. | ||||
memset(Buf, 0, Size); | memset(Buf, 0, Size); | ||||
// Write a header. | // Write a header. | ||||
write32(Buf, NBuckets); | write32(Buf, NBuckets); | ||||
write32(Buf + 4, In.DynSymTab->getNumSymbols() - Symbols.size()); | write32(Buf + 4, getPartition().DynSymTab->getNumSymbols() - Symbols.size()); | ||||
write32(Buf + 8, MaskWords); | write32(Buf + 8, MaskWords); | ||||
write32(Buf + 12, Shift2); | write32(Buf + 12, Shift2); | ||||
Buf += 16; | Buf += 16; | ||||
// Write a bloom filter and a hash table. | // Write a bloom filter and a hash table. | ||||
writeBloomFilter(Buf); | writeBloomFilter(Buf); | ||||
Buf += Config->Wordsize * MaskWords; | Buf += Config->Wordsize * MaskWords; | ||||
writeHashTable(Buf); | writeHashTable(Buf); | ||||
Show All 31 Lines | for (auto I = Symbols.begin(), E = Symbols.end(); I != E; ++I) { | ||||
bool IsLastInChain = (I + 1) == E || I->BucketIdx != (I + 1)->BucketIdx; | bool IsLastInChain = (I + 1) == E || I->BucketIdx != (I + 1)->BucketIdx; | ||||
Hash = IsLastInChain ? Hash | 1 : Hash & ~1; | Hash = IsLastInChain ? Hash | 1 : Hash & ~1; | ||||
write32(Values++, Hash); | write32(Values++, Hash); | ||||
if (I->BucketIdx == OldBucket) | if (I->BucketIdx == OldBucket) | ||||
continue; | continue; | ||||
// Write a hash bucket. Hash buckets contain indices in the following hash | // Write a hash bucket. Hash buckets contain indices in the following hash | ||||
// value table. | // value table. | ||||
write32(Buckets + I->BucketIdx, I->Sym->DynsymIndex); | write32(Buckets + I->BucketIdx, | ||||
getPartition().DynSymTab->getSymbolIndex(I->Sym)); | |||||
OldBucket = I->BucketIdx; | OldBucket = I->BucketIdx; | ||||
} | } | ||||
} | } | ||||
static uint32_t hashGnu(StringRef Name) { | static uint32_t hashGnu(StringRef Name) { | ||||
uint32_t H = 5381; | uint32_t H = 5381; | ||||
for (uint8_t C : Name) | for (uint8_t C : Name) | ||||
H = (H << 5) + H + C; | H = (H << 5) + H + C; | ||||
return H; | return H; | ||||
} | } | ||||
// Add symbols to this symbol hash table. Note that this function | // Add symbols to this symbol hash table. Note that this function | ||||
// destructively sort a given vector -- which is needed because | // destructively sort a given vector -- which is needed because | ||||
// GNU-style hash table places some sorting requirements. | // GNU-style hash table places some sorting requirements. | ||||
void GnuHashTableSection::addSymbols(std::vector<SymbolTableEntry> &V) { | void GnuHashTableSection::addSymbols(std::vector<SymbolTableEntry> &V) { | ||||
// We cannot use 'auto' for Mid because GCC 6.1 cannot deduce | // We cannot use 'auto' for Mid because GCC 6.1 cannot deduce | ||||
// its type correctly. | // its type correctly. | ||||
std::vector<SymbolTableEntry>::iterator Mid = | std::vector<SymbolTableEntry>::iterator Mid = | ||||
std::stable_partition(V.begin(), V.end(), [](const SymbolTableEntry &S) { | std::stable_partition(V.begin(), V.end(), [&](const SymbolTableEntry &S) { | ||||
return !S.Sym->isDefined(); | return !S.Sym->isDefined() || S.Sym->Partition != Partition; | ||||
}); | }); | ||||
// We chose load factor 4 for the on-disk hash table. For each hash | // We chose load factor 4 for the on-disk hash table. For each hash | ||||
// collision, the dynamic linker will compare a uint32_t hash value. | // collision, the dynamic linker will compare a uint32_t hash value. | ||||
// Since the integer comparison is quite fast, we believe we can | // Since the integer comparison is quite fast, we believe we can | ||||
// make the load factor even larger. 4 is just a conservative choice. | // make the load factor even larger. 4 is just a conservative choice. | ||||
// | // | ||||
// Note that we don't want to create a zero-sized hash table because | // Note that we don't want to create a zero-sized hash table because | ||||
Show All 22 Lines | |||||
} | } | ||||
HashTableSection::HashTableSection() | HashTableSection::HashTableSection() | ||||
: SyntheticSection(SHF_ALLOC, SHT_HASH, 4, ".hash") { | : SyntheticSection(SHF_ALLOC, SHT_HASH, 4, ".hash") { | ||||
this->Entsize = 4; | this->Entsize = 4; | ||||
} | } | ||||
void HashTableSection::finalizeContents() { | void HashTableSection::finalizeContents() { | ||||
if (OutputSection *Sec = In.DynSymTab->getParent()) | SymbolTableBaseSection *SymTab = getPartition().DynSymTab; | ||||
if (OutputSection *Sec = SymTab->getParent()) | |||||
getParent()->Link = Sec->SectionIndex; | getParent()->Link = Sec->SectionIndex; | ||||
unsigned NumEntries = 2; // nbucket and nchain. | unsigned NumEntries = 2; // nbucket and nchain. | ||||
NumEntries += In.DynSymTab->getNumSymbols(); // The chain entries. | NumEntries += SymTab->getNumSymbols(); // The chain entries. | ||||
// Create as many buckets as there are symbols. | // Create as many buckets as there are symbols. | ||||
NumEntries += In.DynSymTab->getNumSymbols(); | NumEntries += SymTab->getNumSymbols(); | ||||
this->Size = NumEntries * 4; | this->Size = NumEntries * 4; | ||||
} | } | ||||
void HashTableSection::writeTo(uint8_t *Buf) { | void HashTableSection::writeTo(uint8_t *Buf) { | ||||
SymbolTableBaseSection *SymTab = getPartition().DynSymTab; | |||||
// See comment in GnuHashTableSection::writeTo. | // See comment in GnuHashTableSection::writeTo. | ||||
memset(Buf, 0, Size); | memset(Buf, 0, Size); | ||||
unsigned NumSymbols = In.DynSymTab->getNumSymbols(); | unsigned NumSymbols = SymTab->getNumSymbols(); | ||||
uint32_t *P = reinterpret_cast<uint32_t *>(Buf); | uint32_t *P = reinterpret_cast<uint32_t *>(Buf); | ||||
write32(P++, NumSymbols); // nbucket | write32(P++, NumSymbols); // nbucket | ||||
write32(P++, NumSymbols); // nchain | write32(P++, NumSymbols); // nchain | ||||
uint32_t *Buckets = P; | uint32_t *Buckets = P; | ||||
uint32_t *Chains = P + NumSymbols; | uint32_t *Chains = P + NumSymbols; | ||||
for (const SymbolTableEntry &S : In.DynSymTab->getSymbols()) { | for (const SymbolTableEntry &S : SymTab->getSymbols()) { | ||||
Symbol *Sym = S.Sym; | Symbol *Sym = S.Sym; | ||||
StringRef Name = Sym->getName(); | StringRef Name = Sym->getName(); | ||||
unsigned I = Sym->DynsymIndex; | unsigned I = Sym->DynsymIndex; | ||||
uint32_t Hash = hashSysV(Name) % NumSymbols; | uint32_t Hash = hashSysV(Name) % NumSymbols; | ||||
Chains[I] = Buckets[Hash]; | Chains[I] = Buckets[Hash]; | ||||
write32(Buckets + Hash, I); | write32(Buckets + Hash, I); | ||||
} | } | ||||
} | } | ||||
▲ Show 20 Lines • Show All 361 Lines • ▼ Show 20 Lines | |||||
// .eh_frame_hdr contains a binary search table of pointers to FDEs. | // .eh_frame_hdr contains a binary search table of pointers to FDEs. | ||||
// Each entry of the search table consists of two values, | // Each entry of the search table consists of two values, | ||||
// the starting PC from where FDEs covers, and the FDE's address. | // the starting PC from where FDEs covers, and the FDE's address. | ||||
// It is sorted by PC. | // It is sorted by PC. | ||||
void EhFrameHeader::write() { | void EhFrameHeader::write() { | ||||
uint8_t *Buf = Out::BufferStart + getParent()->Offset + OutSecOff; | uint8_t *Buf = Out::BufferStart + getParent()->Offset + OutSecOff; | ||||
using FdeData = EhFrameSection::FdeData; | using FdeData = EhFrameSection::FdeData; | ||||
std::vector<FdeData> Fdes = In.EhFrame->getFdeData(); | std::vector<FdeData> Fdes = getPartition().EhFrame->getFdeData(); | ||||
Buf[0] = 1; | Buf[0] = 1; | ||||
Buf[1] = DW_EH_PE_pcrel | DW_EH_PE_sdata4; | Buf[1] = DW_EH_PE_pcrel | DW_EH_PE_sdata4; | ||||
Buf[2] = DW_EH_PE_udata4; | Buf[2] = DW_EH_PE_udata4; | ||||
Buf[3] = DW_EH_PE_datarel | DW_EH_PE_sdata4; | Buf[3] = DW_EH_PE_datarel | DW_EH_PE_sdata4; | ||||
write32(Buf + 4, In.EhFrame->getParent()->Addr - this->getVA() - 4); | write32(Buf + 4, | ||||
getPartition().EhFrame->getParent()->Addr - this->getVA() - 4); | |||||
write32(Buf + 8, Fdes.size()); | write32(Buf + 8, Fdes.size()); | ||||
Buf += 12; | Buf += 12; | ||||
for (FdeData &Fde : Fdes) { | for (FdeData &Fde : Fdes) { | ||||
write32(Buf, Fde.PcRel); | write32(Buf, Fde.PcRel); | ||||
write32(Buf + 4, Fde.FdeVARel); | write32(Buf + 4, Fde.FdeVARel); | ||||
Buf += 8; | Buf += 8; | ||||
} | } | ||||
} | } | ||||
size_t EhFrameHeader::getSize() const { | size_t EhFrameHeader::getSize() const { | ||||
// .eh_frame_hdr has a 12 bytes header followed by an array of FDEs. | // .eh_frame_hdr has a 12 bytes header followed by an array of FDEs. | ||||
return 12 + In.EhFrame->NumFdes * 8; | return 12 + getPartition().EhFrame->NumFdes * 8; | ||||
} | } | ||||
bool EhFrameHeader::isNeeded() const { return In.EhFrame->isNeeded(); } | bool EhFrameHeader::isNeeded() const { | ||||
return isLive() && getPartition().EhFrame->isNeeded(); | |||||
} | |||||
VersionDefinitionSection::VersionDefinitionSection() | VersionDefinitionSection::VersionDefinitionSection() | ||||
: SyntheticSection(SHF_ALLOC, SHT_GNU_verdef, sizeof(uint32_t), | : SyntheticSection(SHF_ALLOC, SHT_GNU_verdef, sizeof(uint32_t), | ||||
".gnu.version_d") {} | ".gnu.version_d") {} | ||||
static StringRef getFileDefName() { | StringRef VersionDefinitionSection::getFileDefName() { | ||||
if (!getPartition().Name.empty()) | |||||
return getPartition().Name; | |||||
if (!Config->SoName.empty()) | if (!Config->SoName.empty()) | ||||
return Config->SoName; | return Config->SoName; | ||||
return Config->OutputFile; | return Config->OutputFile; | ||||
} | } | ||||
void VersionDefinitionSection::finalizeContents() { | void VersionDefinitionSection::finalizeContents() { | ||||
FileDefNameOff = In.DynStrTab->addString(getFileDefName()); | FileDefNameOff = getPartition().DynStrTab->addString(getFileDefName()); | ||||
for (VersionDefinition &V : Config->VersionDefinitions) | for (VersionDefinition &V : Config->VersionDefinitions) | ||||
V.NameOff = In.DynStrTab->addString(V.Name); | VerDefNameOffs.push_back(getPartition().DynStrTab->addString(V.Name)); | ||||
if (OutputSection *Sec = In.DynStrTab->getParent()) | if (OutputSection *Sec = getPartition().DynStrTab->getParent()) | ||||
getParent()->Link = Sec->SectionIndex; | getParent()->Link = Sec->SectionIndex; | ||||
// sh_info should be set to the number of definitions. This fact is missed in | // sh_info should be set to the number of definitions. This fact is missed in | ||||
// documentation, but confirmed by binutils community: | // documentation, but confirmed by binutils community: | ||||
// https://sourceware.org/ml/binutils/2014-11/msg00355.html | // https://sourceware.org/ml/binutils/2014-11/msg00355.html | ||||
getParent()->Info = getVerDefNum(); | getParent()->Info = getVerDefNum(); | ||||
} | } | ||||
Show All 13 Lines | void VersionDefinitionSection::writeOne(uint8_t *Buf, uint32_t Index, | ||||
// Write a veraux. | // Write a veraux. | ||||
write32(Buf + 20, NameOff); // vda_name | write32(Buf + 20, NameOff); // vda_name | ||||
write32(Buf + 24, 0); // vda_next | write32(Buf + 24, 0); // vda_next | ||||
} | } | ||||
void VersionDefinitionSection::writeTo(uint8_t *Buf) { | void VersionDefinitionSection::writeTo(uint8_t *Buf) { | ||||
writeOne(Buf, 1, getFileDefName(), FileDefNameOff); | writeOne(Buf, 1, getFileDefName(), FileDefNameOff); | ||||
auto NameOffIt = VerDefNameOffs.begin(); | |||||
for (VersionDefinition &V : Config->VersionDefinitions) { | for (VersionDefinition &V : Config->VersionDefinitions) { | ||||
Buf += EntrySize; | Buf += EntrySize; | ||||
writeOne(Buf, V.Id, V.Name, V.NameOff); | writeOne(Buf, V.Id, V.Name, *NameOffIt++); | ||||
} | } | ||||
// Need to terminate the last version definition. | // Need to terminate the last version definition. | ||||
write32(Buf + 16, 0); // vd_next | write32(Buf + 16, 0); // vd_next | ||||
} | } | ||||
size_t VersionDefinitionSection::getSize() const { | size_t VersionDefinitionSection::getSize() const { | ||||
return EntrySize * getVerDefNum(); | return EntrySize * getVerDefNum(); | ||||
} | } | ||||
// .gnu.version is a table where each entry is 2 byte long. | // .gnu.version is a table where each entry is 2 byte long. | ||||
VersionTableSection::VersionTableSection() | VersionTableSection::VersionTableSection() | ||||
: SyntheticSection(SHF_ALLOC, SHT_GNU_versym, sizeof(uint16_t), | : SyntheticSection(SHF_ALLOC, SHT_GNU_versym, sizeof(uint16_t), | ||||
".gnu.version") { | ".gnu.version") { | ||||
this->Entsize = 2; | this->Entsize = 2; | ||||
} | } | ||||
void VersionTableSection::finalizeContents() { | void VersionTableSection::finalizeContents() { | ||||
// At the moment of june 2016 GNU docs does not mention that sh_link field | // At the moment of june 2016 GNU docs does not mention that sh_link field | ||||
// should be set, but Sun docs do. Also readelf relies on this field. | // should be set, but Sun docs do. Also readelf relies on this field. | ||||
getParent()->Link = In.DynSymTab->getParent()->SectionIndex; | getParent()->Link = getPartition().DynSymTab->getParent()->SectionIndex; | ||||
} | } | ||||
size_t VersionTableSection::getSize() const { | size_t VersionTableSection::getSize() const { | ||||
return (In.DynSymTab->getSymbols().size() + 1) * 2; | return (getPartition().DynSymTab->getSymbols().size() + 1) * 2; | ||||
} | } | ||||
void VersionTableSection::writeTo(uint8_t *Buf) { | void VersionTableSection::writeTo(uint8_t *Buf) { | ||||
Buf += 2; | Buf += 2; | ||||
for (const SymbolTableEntry &S : In.DynSymTab->getSymbols()) { | for (const SymbolTableEntry &S : getPartition().DynSymTab->getSymbols()) { | ||||
write16(Buf, S.Sym->VersionId); | write16(Buf, S.Sym->VersionId); | ||||
Buf += 2; | Buf += 2; | ||||
} | } | ||||
} | } | ||||
bool VersionTableSection::isNeeded() const { | bool VersionTableSection::isNeeded() const { | ||||
return In.VerDef || In.VerNeed->isNeeded(); | return getPartition().VerDef || getPartition().VerNeed->isNeeded(); | ||||
} | } | ||||
void elf::addVerneed(Symbol *SS) { | void elf::addVerneed(Symbol *SS) { | ||||
auto &File = cast<SharedFile>(*SS->File); | auto &File = cast<SharedFile>(*SS->File); | ||||
if (SS->VerdefIndex == VER_NDX_GLOBAL) { | if (SS->VerdefIndex == VER_NDX_GLOBAL) { | ||||
SS->VersionId = VER_NDX_GLOBAL; | SS->VersionId = VER_NDX_GLOBAL; | ||||
return; | return; | ||||
} | } | ||||
Show All 17 Lines | : SyntheticSection(SHF_ALLOC, SHT_GNU_verneed, sizeof(uint32_t), | ||||
".gnu.version_r") {} | ".gnu.version_r") {} | ||||
template <class ELFT> void VersionNeedSection<ELFT>::finalizeContents() { | template <class ELFT> void VersionNeedSection<ELFT>::finalizeContents() { | ||||
for (SharedFile *F : SharedFiles) { | for (SharedFile *F : SharedFiles) { | ||||
if (F->Vernauxs.empty()) | if (F->Vernauxs.empty()) | ||||
continue; | continue; | ||||
Verneeds.emplace_back(); | Verneeds.emplace_back(); | ||||
Verneed &VN = Verneeds.back(); | Verneed &VN = Verneeds.back(); | ||||
VN.NameStrTab = In.DynStrTab->addString(F->SoName); | VN.NameStrTab = getPartition().DynStrTab->addString(F->SoName); | ||||
for (unsigned I = 0; I != F->Vernauxs.size(); ++I) { | for (unsigned I = 0; I != F->Vernauxs.size(); ++I) { | ||||
if (F->Vernauxs[I] == 0) | if (F->Vernauxs[I] == 0) | ||||
continue; | continue; | ||||
auto *Verdef = | auto *Verdef = | ||||
reinterpret_cast<const typename ELFT::Verdef *>(F->Verdefs[I]); | reinterpret_cast<const typename ELFT::Verdef *>(F->Verdefs[I]); | ||||
VN.Vernauxs.push_back( | VN.Vernauxs.push_back( | ||||
{Verdef->vd_hash, F->Vernauxs[I], | {Verdef->vd_hash, F->Vernauxs[I], | ||||
In.DynStrTab->addString(F->getStringTable().data() + | getPartition().DynStrTab->addString(F->getStringTable().data() + | ||||
Verdef->getAux()->vda_name)}); | Verdef->getAux()->vda_name)}); | ||||
} | } | ||||
} | } | ||||
if (OutputSection *Sec = In.DynStrTab->getParent()) | if (OutputSection *Sec = getPartition().DynStrTab->getParent()) | ||||
getParent()->Link = Sec->SectionIndex; | getParent()->Link = Sec->SectionIndex; | ||||
getParent()->Info = Verneeds.size(); | getParent()->Info = Verneeds.size(); | ||||
} | } | ||||
template <class ELFT> void VersionNeedSection<ELFT>::writeTo(uint8_t *Buf) { | template <class ELFT> void VersionNeedSection<ELFT>::writeTo(uint8_t *Buf) { | ||||
// The Elf_Verneeds need to appear first, followed by the Elf_Vernauxs. | // The Elf_Verneeds need to appear first, followed by the Elf_Vernauxs. | ||||
auto *Verneed = reinterpret_cast<Elf_Verneed *>(Buf); | auto *Verneed = reinterpret_cast<Elf_Verneed *>(Buf); | ||||
auto *Vernaux = reinterpret_cast<Elf_Vernaux *>(Verneed + Verneeds.size()); | auto *Vernaux = reinterpret_cast<Elf_Vernaux *>(Verneed + Verneeds.size()); | ||||
▲ Show 20 Lines • Show All 466 Lines • ▼ Show 20 Lines | bool PPC64LongBranchTargetSection::isNeeded() const { | ||||
// is too early to determine if this section will be empty or not. We need | // is too early to determine if this section will be empty or not. We need | ||||
// Finalized to keep the section alive until after thunk creation. Finalized | // Finalized to keep the section alive until after thunk creation. Finalized | ||||
// only gets set to true once `finalizeSections()` is called after thunk | // only gets set to true once `finalizeSections()` is called after thunk | ||||
// creation. Becuase of this, if we don't create any long-branch thunks we end | // creation. Becuase of this, if we don't create any long-branch thunks we end | ||||
// up with an empty .branch_lt section in the binary. | // up with an empty .branch_lt section in the binary. | ||||
return !Finalized || !Entries.empty(); | return !Finalized || !Entries.empty(); | ||||
} | } | ||||
static uint8_t getAbiVersion() { | |||||
// MIPS non-PIC executable gets ABI version 1. | |||||
if (Config->EMachine == EM_MIPS) { | |||||
if (!Config->Pic && !Config->Relocatable && | |||||
(Config->EFlags & (EF_MIPS_PIC | EF_MIPS_CPIC)) == EF_MIPS_CPIC) | |||||
return 1; | |||||
return 0; | |||||
} | |||||
if (Config->EMachine == EM_AMDGPU) { | |||||
uint8_t Ver = ObjectFiles[0]->ABIVersion; | |||||
for (InputFile *File : makeArrayRef(ObjectFiles).slice(1)) | |||||
if (File->ABIVersion != Ver) | |||||
error("incompatible ABI version: " + toString(File)); | |||||
return Ver; | |||||
} | |||||
return 0; | |||||
} | |||||
template <typename ELFT> void elf::writeEhdr(uint8_t *Buf, Partition &Part) { | |||||
// For executable segments, the trap instructions are written before writing | |||||
// the header. Setting Elf header bytes to zero ensures that any unused bytes | |||||
// in header are zero-cleared, instead of having trap instructions. | |||||
memset(Buf, 0, sizeof(typename ELFT::Ehdr)); | |||||
memcpy(Buf, "\177ELF", 4); | |||||
auto *EHdr = reinterpret_cast<typename ELFT::Ehdr *>(Buf); | |||||
EHdr->e_ident[EI_CLASS] = Config->Is64 ? ELFCLASS64 : ELFCLASS32; | |||||
EHdr->e_ident[EI_DATA] = Config->IsLE ? ELFDATA2LSB : ELFDATA2MSB; | |||||
EHdr->e_ident[EI_VERSION] = EV_CURRENT; | |||||
EHdr->e_ident[EI_OSABI] = Config->OSABI; | |||||
EHdr->e_ident[EI_ABIVERSION] = getAbiVersion(); | |||||
EHdr->e_machine = Config->EMachine; | |||||
EHdr->e_version = EV_CURRENT; | |||||
EHdr->e_flags = Config->EFlags; | |||||
EHdr->e_ehsize = sizeof(typename ELFT::Ehdr); | |||||
EHdr->e_phnum = Part.Phdrs.size(); | |||||
EHdr->e_shentsize = sizeof(typename ELFT::Shdr); | |||||
if (!Config->Relocatable) { | |||||
EHdr->e_phoff = sizeof(typename ELFT::Ehdr); | |||||
EHdr->e_phentsize = sizeof(typename ELFT::Phdr); | |||||
} | |||||
} | |||||
template <typename ELFT> void elf::writePhdrs(uint8_t *Buf, Partition &Part) { | |||||
// Write the program header table. | |||||
auto *HBuf = reinterpret_cast<typename ELFT::Phdr *>(Buf); | |||||
for (PhdrEntry *P : Part.Phdrs) { | |||||
HBuf->p_type = P->p_type; | |||||
HBuf->p_flags = P->p_flags; | |||||
HBuf->p_offset = P->p_offset; | |||||
HBuf->p_vaddr = P->p_vaddr; | |||||
HBuf->p_paddr = P->p_paddr; | |||||
HBuf->p_filesz = P->p_filesz; | |||||
HBuf->p_memsz = P->p_memsz; | |||||
HBuf->p_align = P->p_align; | |||||
++HBuf; | |||||
} | |||||
} | |||||
template <typename ELFT> | |||||
PartitionElfHeaderSection<ELFT>::PartitionElfHeaderSection() | |||||
: SyntheticSection(SHF_ALLOC, SHT_LLVM_PART_EHDR, 1, "") {} | |||||
template <typename ELFT> | |||||
size_t PartitionElfHeaderSection<ELFT>::getSize() const { | |||||
return sizeof(typename ELFT::Ehdr); | |||||
} | |||||
template <typename ELFT> | |||||
void PartitionElfHeaderSection<ELFT>::writeTo(uint8_t *Buf) { | |||||
writeEhdr<ELFT>(Buf, getPartition()); | |||||
// Loadable partitions are always ET_DYN. | |||||
auto *EHdr = reinterpret_cast<typename ELFT::Ehdr *>(Buf); | |||||
EHdr->e_type = ET_DYN; | |||||
} | |||||
template <typename ELFT> | |||||
PartitionProgramHeadersSection<ELFT>::PartitionProgramHeadersSection() | |||||
: SyntheticSection(SHF_ALLOC, SHT_LLVM_PART_PHDR, 1, ".phdrs") {} | |||||
template <typename ELFT> | |||||
size_t PartitionProgramHeadersSection<ELFT>::getSize() const { | |||||
return sizeof(typename ELFT::Phdr) * getPartition().Phdrs.size(); | |||||
} | |||||
template <typename ELFT> | |||||
void PartitionProgramHeadersSection<ELFT>::writeTo(uint8_t *Buf) { | |||||
writePhdrs<ELFT>(Buf, getPartition()); | |||||
} | |||||
PartitionIndexSection::PartitionIndexSection() | |||||
: SyntheticSection(SHF_ALLOC, SHT_PROGBITS, 4, ".rodata") {} | |||||
size_t PartitionIndexSection::getSize() const { | |||||
return 12 * (Partitions.size() - 1); | |||||
} | |||||
void PartitionIndexSection::finalizeContents() { | |||||
for (size_t I = 1; I != Partitions.size(); ++I) | |||||
Partitions[I].NameStrTab = Main->DynStrTab->addString(Partitions[I].Name); | |||||
} | |||||
void PartitionIndexSection::writeTo(uint8_t *Buf) { | |||||
uint64_t VA = getVA(); | |||||
for (size_t I = 1; I != Partitions.size(); ++I) { | |||||
write32(Buf, Main->DynStrTab->getVA() + Partitions[I].NameStrTab - VA); | |||||
write32(Buf + 4, Partitions[I].ElfHeader->getVA() - (VA + 4)); | |||||
SyntheticSection *Next = | |||||
I == Partitions.size() - 1 ? In.PartEnd : Partitions[I + 1].ElfHeader; | |||||
write32(Buf + 8, Next->getVA() - Partitions[I].ElfHeader->getVA()); | |||||
VA += 12; | |||||
Buf += 12; | |||||
} | |||||
} | |||||
InStruct elf::In; | InStruct elf::In; | ||||
std::vector<Partition> elf::Partitions; | std::vector<Partition> elf::Partitions; | ||||
Partition *elf::Main; | |||||
template GdbIndexSection *GdbIndexSection::create<ELF32LE>(); | template GdbIndexSection *GdbIndexSection::create<ELF32LE>(); | ||||
template GdbIndexSection *GdbIndexSection::create<ELF32BE>(); | template GdbIndexSection *GdbIndexSection::create<ELF32BE>(); | ||||
template GdbIndexSection *GdbIndexSection::create<ELF64LE>(); | template GdbIndexSection *GdbIndexSection::create<ELF64LE>(); | ||||
template GdbIndexSection *GdbIndexSection::create<ELF64BE>(); | template GdbIndexSection *GdbIndexSection::create<ELF64BE>(); | ||||
template void elf::splitSections<ELF32LE>(); | template void elf::splitSections<ELF32LE>(); | ||||
template void elf::splitSections<ELF32BE>(); | template void elf::splitSections<ELF32BE>(); | ||||
▲ Show 20 Lines • Show All 49 Lines • ▼ Show 20 Lines | |||||
template class elf::SymbolTableSection<ELF32BE>; | template class elf::SymbolTableSection<ELF32BE>; | ||||
template class elf::SymbolTableSection<ELF64LE>; | template class elf::SymbolTableSection<ELF64LE>; | ||||
template class elf::SymbolTableSection<ELF64BE>; | template class elf::SymbolTableSection<ELF64BE>; | ||||
template class elf::VersionNeedSection<ELF32LE>; | template class elf::VersionNeedSection<ELF32LE>; | ||||
template class elf::VersionNeedSection<ELF32BE>; | template class elf::VersionNeedSection<ELF32BE>; | ||||
template class elf::VersionNeedSection<ELF64LE>; | template class elf::VersionNeedSection<ELF64LE>; | ||||
template class elf::VersionNeedSection<ELF64BE>; | template class elf::VersionNeedSection<ELF64BE>; | ||||
template void elf::writeEhdr<ELF32LE>(uint8_t *Buf, Partition &Part); | |||||
template void elf::writeEhdr<ELF32BE>(uint8_t *Buf, Partition &Part); | |||||
template void elf::writeEhdr<ELF64LE>(uint8_t *Buf, Partition &Part); | |||||
template void elf::writeEhdr<ELF64BE>(uint8_t *Buf, Partition &Part); | |||||
template void elf::writePhdrs<ELF32LE>(uint8_t *Buf, Partition &Part); | |||||
template void elf::writePhdrs<ELF32BE>(uint8_t *Buf, Partition &Part); | |||||
template void elf::writePhdrs<ELF64LE>(uint8_t *Buf, Partition &Part); | |||||
template void elf::writePhdrs<ELF64BE>(uint8_t *Buf, Partition &Part); | |||||
template class elf::PartitionElfHeaderSection<ELF32LE>; | |||||
template class elf::PartitionElfHeaderSection<ELF32BE>; | |||||
template class elf::PartitionElfHeaderSection<ELF64LE>; | |||||
template class elf::PartitionElfHeaderSection<ELF64BE>; | |||||
template class elf::PartitionProgramHeadersSection<ELF32LE>; | |||||
template class elf::PartitionProgramHeadersSection<ELF32BE>; | |||||
template class elf::PartitionProgramHeadersSection<ELF64LE>; | |||||
template class elf::PartitionProgramHeadersSection<ELF64BE>; |