diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2019-10-23 17:52:45 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2019-10-23 17:52:45 +0000 |
commit | d2bd9e70b16db88a7808ee2280b0a107afbfdd3b (patch) | |
tree | 12612d2c593445b297ac656911c9db7cf9065bdd /ELF/SyntheticSections.cpp | |
parent | f1e1c239e31b467e17f1648b1f524fc9ab5b431a (diff) |
Notes
Diffstat (limited to 'ELF/SyntheticSections.cpp')
-rw-r--r-- | ELF/SyntheticSections.cpp | 485 |
1 files changed, 271 insertions, 214 deletions
diff --git a/ELF/SyntheticSections.cpp b/ELF/SyntheticSections.cpp index f6d0f190d84d..ff35bb7bd10c 100644 --- a/ELF/SyntheticSections.cpp +++ b/ELF/SyntheticSections.cpp @@ -45,13 +45,12 @@ using namespace llvm::ELF; using namespace llvm::object; using namespace llvm::support; -using namespace lld; -using namespace lld::elf; - using llvm::support::endian::read32le; using llvm::support::endian::write32le; using llvm::support::endian::write64le; +namespace lld { +namespace elf { constexpr size_t MergeNoTailSection::numShards; static uint64_t readUint(uint8_t *buf) { @@ -82,7 +81,7 @@ static ArrayRef<uint8_t> getVersion() { // With this feature, you can identify LLD-generated binaries easily // by "readelf --string-dump .comment <file>". // The returned object is a mergeable string section. -MergeInputSection *elf::createCommentSection() { +MergeInputSection *createCommentSection() { return make<MergeInputSection>(SHF_MERGE | SHF_STRINGS, SHT_PROGBITS, 1, getVersion(), ".comment"); } @@ -138,7 +137,7 @@ MipsAbiFlagsSection<ELFT> *MipsAbiFlagsSection<ELFT>::create() { flags.ases |= s->ases; flags.flags1 |= s->flags1; flags.flags2 |= s->flags2; - flags.fp_abi = elf::getMipsFpAbiFlag(flags.fp_abi, s->fp_abi, filename); + flags.fp_abi = getMipsFpAbiFlag(flags.fp_abi, s->fp_abi, filename); }; if (create) @@ -252,19 +251,17 @@ MipsReginfoSection<ELFT> *MipsReginfoSection<ELFT>::create() { return make<MipsReginfoSection<ELFT>>(reginfo); } -InputSection *elf::createInterpSection() { +InputSection *createInterpSection() { // StringSaver guarantees that the returned string ends with '\0'. StringRef s = saver.save(config->dynamicLinker); ArrayRef<uint8_t> contents = {(const uint8_t *)s.data(), s.size() + 1}; - auto *sec = make<InputSection>(nullptr, SHF_ALLOC, SHT_PROGBITS, 1, contents, - ".interp"); - sec->markLive(); - return sec; + return make<InputSection>(nullptr, SHF_ALLOC, SHT_PROGBITS, 1, contents, + ".interp"); } -Defined *elf::addSyntheticLocal(StringRef name, uint8_t type, uint64_t value, - uint64_t size, InputSectionBase §ion) { +Defined *addSyntheticLocal(StringRef name, uint8_t type, uint64_t value, + uint64_t size, InputSectionBase §ion) { auto *s = make<Defined>(section.file, name, STB_LOCAL, STV_DEFAULT, type, value, size, §ion); if (in.symTab) @@ -402,7 +399,7 @@ bool EhFrameSection::isFdeLive(EhSectionPiece &fde, ArrayRef<RelTy> rels) { // a list of FDEs. This function searches an existing CIE or create a new // one and associates FDEs to the CIE. template <class ELFT, class RelTy> -void EhFrameSection::addSectionAux(EhInputSection *sec, ArrayRef<RelTy> rels) { +void EhFrameSection::addRecords(EhInputSection *sec, ArrayRef<RelTy> rels) { offsetToCie.clear(); for (EhSectionPiece &piece : sec->pieces) { // The empty record is the end marker. @@ -428,8 +425,17 @@ void EhFrameSection::addSectionAux(EhInputSection *sec, ArrayRef<RelTy> rels) { } } -template <class ELFT> void EhFrameSection::addSection(InputSectionBase *c) { - auto *sec = cast<EhInputSection>(c); +template <class ELFT> +void EhFrameSection::addSectionAux(EhInputSection *sec) { + if (!sec->isLive()) + return; + if (sec->areRelocsRela) + addRecords<ELFT>(sec, sec->template relas<ELFT>()); + else + addRecords<ELFT>(sec, sec->template rels<ELFT>()); +} + +void EhFrameSection::addSection(EhInputSection *sec) { sec->parent = this; alignment = std::max(alignment, sec->alignment); @@ -437,14 +443,6 @@ template <class ELFT> void EhFrameSection::addSection(InputSectionBase *c) { for (auto *ds : sec->dependentSections) dependentSections.push_back(ds); - - if (sec->pieces.empty()) - return; - - if (sec->areRelocsRela) - addSectionAux<ELFT>(sec, sec->template relas<ELFT>()); - else - addSectionAux<ELFT>(sec, sec->template rels<ELFT>()); } static void writeCieFde(uint8_t *buf, ArrayRef<uint8_t> d) { @@ -461,6 +459,28 @@ static void writeCieFde(uint8_t *buf, ArrayRef<uint8_t> d) { void EhFrameSection::finalizeContents() { assert(!this->size); // Not finalized. + + switch (config->ekind) { + case ELFNoneKind: + llvm_unreachable("invalid ekind"); + case ELF32LEKind: + for (EhInputSection *sec : sections) + addSectionAux<ELF32LE>(sec); + break; + case ELF32BEKind: + for (EhInputSection *sec : sections) + addSectionAux<ELF32BE>(sec); + break; + case ELF64LEKind: + for (EhInputSection *sec : sections) + addSectionAux<ELF64LE>(sec); + break; + case ELF64BEKind: + for (EhInputSection *sec : sections) + addSectionAux<ELF64BE>(sec); + break; + } + size_t off = 0; for (CieRecord *rec : cieRecords) { rec->cie->outputOff = off; @@ -1162,10 +1182,12 @@ void StringTableSection::writeTo(uint8_t *buf) { } } -// Returns the number of version definition entries. Because the first entry -// is for the version definition itself, it is the number of versioned symbols -// plus one. Note that we don't support multiple versions yet. -static unsigned getVerDefNum() { return config->versionDefinitions.size() + 1; } +// Returns the number of entries in .gnu.version_d: the number of +// non-VER_NDX_LOCAL-non-VER_NDX_GLOBAL definitions, plus 1. +// Note that we don't support vd_cnt > 1 yet. +static unsigned getVerDefNum() { + return namedVersionDefs().size() + 1; +} template <class ELFT> DynamicSection<ELFT>::DynamicSection() @@ -1218,6 +1240,25 @@ void DynamicSection<ELFT>::addSym(int32_t tag, Symbol *sym) { entries.push_back({tag, [=] { return sym->getVA(); }}); } +// The output section .rela.dyn may include these synthetic sections: +// +// - part.relaDyn +// - in.relaIplt: this is included if in.relaIplt is named .rela.dyn +// - in.relaPlt: this is included if a linker script places .rela.plt inside +// .rela.dyn +// +// DT_RELASZ is the total size of the included sections. +static std::function<uint64_t()> addRelaSz(RelocationBaseSection *relaDyn) { + return [=]() { + size_t size = relaDyn->getSize(); + if (in.relaIplt->getParent() == relaDyn->getParent()) + size += in.relaIplt->getSize(); + if (in.relaPlt->getParent() == relaDyn->getParent()) + size += in.relaPlt->getSize(); + return size; + }; +} + // A Linker script may assign the RELA relocation sections to the same // output section. When this occurs we cannot just use the OutputSection // Size. Moreover the [DT_JMPREL, DT_JMPREL + DT_PLTRELSZ) is permitted to @@ -1232,7 +1273,7 @@ static uint64_t addPltRelSz() { // Add remaining entries to complete .dynamic contents. template <class ELFT> void DynamicSection<ELFT>::finalizeContents() { - elf::Partition &part = getPartition(); + Partition &part = getPartition(); bool isMain = part.name.empty(); for (StringRef s : config->filterList) @@ -1306,9 +1347,11 @@ template <class ELFT> void DynamicSection<ELFT>::finalizeContents() { if (OutputSection *sec = part.dynStrTab->getParent()) this->link = sec->sectionIndex; - if (part.relaDyn->isNeeded()) { + if (part.relaDyn->isNeeded() || + (in.relaIplt->isNeeded() && + part.relaDyn->getParent() == in.relaIplt->getParent())) { addInSec(part.relaDyn->dynamicTag, part.relaDyn); - addSize(part.relaDyn->sizeDynamicTag, part.relaDyn->getParent()); + entries.push_back({part.relaDyn->sizeDynamicTag, addRelaSz(part.relaDyn)}); bool isRela = config->isRela; addInt(isRela ? DT_RELAENT : DT_RELENT, @@ -1679,6 +1722,56 @@ bool AndroidPackedRelocationSection<ELFT>::updateAllocSize() { relativeGroups.emplace_back(std::move(group)); } + // For non-relative relocations, we would like to: + // 1. Have relocations with the same symbol offset to be consecutive, so + // that the runtime linker can speed-up symbol lookup by implementing an + // 1-entry cache. + // 2. Group relocations by r_info to reduce the size of the relocation + // section. + // Since the symbol offset is the high bits in r_info, sorting by r_info + // allows us to do both. + // + // For Rela, we also want to sort by r_addend when r_info is the same. This + // enables us to group by r_addend as well. + llvm::stable_sort(nonRelatives, [](const Elf_Rela &a, const Elf_Rela &b) { + if (a.r_info != b.r_info) + return a.r_info < b.r_info; + if (config->isRela) + return a.r_addend < b.r_addend; + return false; + }); + + // Group relocations with the same r_info. Note that each group emits a group + // header and that may make the relocation section larger. It is hard to + // estimate the size of a group header as the encoded size of that varies + // based on r_info. However, we can approximate this trade-off by the number + // of values encoded. Each group header contains 3 values, and each relocation + // in a group encodes one less value, as compared to when it is not grouped. + // Therefore, we only group relocations if there are 3 or more of them with + // the same r_info. + // + // For Rela, the addend for most non-relative relocations is zero, and thus we + // can usually get a smaller relocation section if we group relocations with 0 + // addend as well. + std::vector<Elf_Rela> ungroupedNonRelatives; + std::vector<std::vector<Elf_Rela>> nonRelativeGroups; + for (auto i = nonRelatives.begin(), e = nonRelatives.end(); i != e;) { + auto j = i + 1; + while (j != e && i->r_info == j->r_info && + (!config->isRela || i->r_addend == j->r_addend)) + ++j; + if (j - i < 3 || (config->isRela && i->r_addend != 0)) + ungroupedNonRelatives.insert(ungroupedNonRelatives.end(), i, j); + else + nonRelativeGroups.emplace_back(i, j); + i = j; + } + + // Sort ungrouped relocations by offset to minimize the encoded length. + llvm::sort(ungroupedNonRelatives, [](const Elf_Rela &a, const Elf_Rela &b) { + return a.r_offset < b.r_offset; + }); + unsigned hasAddendIfRela = config->isRela ? RELOCATION_GROUP_HAS_ADDEND_FLAG : 0; @@ -1733,14 +1826,23 @@ bool AndroidPackedRelocationSection<ELFT>::updateAllocSize() { } } - // Finally the non-relative relocations. - llvm::sort(nonRelatives, [](const Elf_Rela &a, const Elf_Rela &b) { - return a.r_offset < b.r_offset; - }); - if (!nonRelatives.empty()) { - add(nonRelatives.size()); + // Grouped non-relatives. + for (ArrayRef<Elf_Rela> g : nonRelativeGroups) { + add(g.size()); + add(RELOCATION_GROUPED_BY_INFO_FLAG); + add(g[0].r_info); + for (const Elf_Rela &r : g) { + add(r.r_offset - offset); + offset = r.r_offset; + } + addend = 0; + } + + // Finally the ungrouped non-relative relocations. + if (!ungroupedNonRelatives.empty()) { + add(ungroupedNonRelatives.size()); add(hasAddendIfRela); - for (Elf_Rela &r : nonRelatives) { + for (Elf_Rela &r : ungroupedNonRelatives) { add(r.r_offset - offset); offset = r.r_offset; add(r.r_info); @@ -1852,6 +1954,14 @@ template <class ELFT> bool RelrSection<ELFT>::updateAllocSize() { } } + // Don't allow the section to shrink; otherwise the size of the section can + // oscillate infinitely. Trailing 1s do not decode to more relocations. + if (relrRelocs.size() < oldSize) { + log(".relr.dyn needs " + Twine(oldSize - relrRelocs.size()) + + " padding word(s)"); + relrRelocs.resize(oldSize, Elf_Relr(1)); + } + return relrRelocs.size() != oldSize; } @@ -2452,6 +2562,10 @@ readAddressAreas(DWARFContext &dwarf, InputSection *sec) { uint32_t cuIdx = 0; for (std::unique_ptr<DWARFUnit> &cu : dwarf.compile_units()) { + if (Error e = cu->tryExtractDIEsIfNeeded(false)) { + error(toString(sec) + ": " + toString(std::move(e))); + return {}; + } Expected<DWARFAddressRangesVector> ranges = cu->collectAddressRanges(); if (!ranges) { error(toString(sec) + ": " + toString(ranges.takeError())); @@ -2481,9 +2595,9 @@ readAddressAreas(DWARFContext &dwarf, InputSection *sec) { template <class ELFT> static std::vector<GdbIndexSection::NameAttrEntry> readPubNamesAndTypes(const LLDDwarfObj<ELFT> &obj, - const std::vector<GdbIndexSection::CuEntry> &cUs) { - const DWARFSection &pubNames = obj.getGnuPubNamesSection(); - const DWARFSection &pubTypes = obj.getGnuPubTypesSection(); + const std::vector<GdbIndexSection::CuEntry> &cus) { + const DWARFSection &pubNames = obj.getGnuPubnamesSection(); + const DWARFSection &pubTypes = obj.getGnuPubtypesSection(); std::vector<GdbIndexSection::NameAttrEntry> ret; for (const DWARFSection *pub : {&pubNames, &pubTypes}) { @@ -2493,12 +2607,11 @@ readPubNamesAndTypes(const LLDDwarfObj<ELFT> &obj, // don't know how many compilation units precede this object to compute // cuIndex, we compute (kind << 24 | cuIndexInThisObject) instead, and add // the number of preceding compilation units later. - uint32_t i = - lower_bound(cUs, set.Offset, - [](GdbIndexSection::CuEntry cu, uint32_t offset) { - return cu.cuOffset < offset; - }) - - cUs.begin(); + uint32_t i = llvm::partition_point(cus, + [&](GdbIndexSection::CuEntry cu) { + return cu.cuOffset < set.Offset; + }) - + cus.begin(); for (const DWARFDebugPubTable::Entry &ent : set.Entries) ret.push_back({{ent.Name, computeGdbHash(ent.Name)}, (ent.Descriptor.toBits() << 24) | i}); @@ -2603,7 +2716,7 @@ template <class ELFT> GdbIndexSection *GdbIndexSection::create() { parallelForEachN(0, sections.size(), [&](size_t i) { ObjFile<ELFT> *file = sections[i]->getFile<ELFT>(); - DWARFContext dwarf(make_unique<LLDDwarfObj<ELFT>>(file)); + DWARFContext dwarf(std::make_unique<LLDDwarfObj<ELFT>>(file)); chunks[i].sec = sections[i]; chunks[i].compilationUnits = readCuList(dwarf); @@ -2750,7 +2863,7 @@ StringRef VersionDefinitionSection::getFileDefName() { void VersionDefinitionSection::finalizeContents() { fileDefNameOff = getPartition().dynStrTab->addString(getFileDefName()); - for (VersionDefinition &v : config->versionDefinitions) + for (const VersionDefinition &v : namedVersionDefs()) verDefNameOffs.push_back(getPartition().dynStrTab->addString(v.name)); if (OutputSection *sec = getPartition().dynStrTab->getParent()) @@ -2784,7 +2897,7 @@ void VersionDefinitionSection::writeTo(uint8_t *buf) { writeOne(buf, 1, getFileDefName(), fileDefNameOff); auto nameOffIt = verDefNameOffs.begin(); - for (VersionDefinition &v : config->versionDefinitions) { + for (const VersionDefinition &v : namedVersionDefs()) { buf += EntrySize; writeOne(buf, v.id, v.name, *nameOffIt++); } @@ -2826,7 +2939,7 @@ bool VersionTableSection::isNeeded() const { return getPartition().verDef || getPartition().verNeed->isNeeded(); } -void elf::addVerneed(Symbol *ss) { +void addVerneed(Symbol *ss) { auto &file = cast<SharedFile>(*ss->file); if (ss->verdefIndex == VER_NDX_GLOBAL) { ss->versionId = VER_NDX_GLOBAL; @@ -3009,17 +3122,16 @@ void MergeNoTailSection::finalizeContents() { }); } -static MergeSyntheticSection *createMergeSynthetic(StringRef name, - uint32_t type, - uint64_t flags, - uint32_t alignment) { +MergeSyntheticSection *createMergeSynthetic(StringRef name, uint32_t type, + uint64_t flags, + uint32_t alignment) { bool shouldTailMerge = (flags & SHF_STRINGS) && config->optimize >= 2; if (shouldTailMerge) return make<MergeTailSection>(name, type, flags, alignment); return make<MergeNoTailSection>(name, type, flags, alignment); } -template <class ELFT> void elf::splitSections() { +template <class ELFT> void splitSections() { // splitIntoPieces needs to be called on each MergeInputSection // before calling finalizeContents(). parallelForEach(inputSections, [](InputSectionBase *sec) { @@ -3030,63 +3142,6 @@ template <class ELFT> void elf::splitSections() { }); } -// This function scans over the inputsections to create mergeable -// synthetic sections. -// -// It removes MergeInputSections from the input section array and adds -// new synthetic sections at the location of the first input section -// that it replaces. It then finalizes each synthetic section in order -// to compute an output offset for each piece of each input section. -void elf::mergeSections() { - std::vector<MergeSyntheticSection *> mergeSections; - for (InputSectionBase *&s : inputSections) { - MergeInputSection *ms = dyn_cast<MergeInputSection>(s); - if (!ms) - continue; - - // We do not want to handle sections that are not alive, so just remove - // them instead of trying to merge. - if (!ms->isLive()) { - s = nullptr; - continue; - } - - StringRef outsecName = getOutputSectionName(ms); - - auto i = llvm::find_if(mergeSections, [=](MergeSyntheticSection *sec) { - // While we could create a single synthetic section for two different - // values of Entsize, it is better to take Entsize into consideration. - // - // With a single synthetic section no two pieces with different Entsize - // could be equal, so we may as well have two sections. - // - // Using Entsize in here also allows us to propagate it to the synthetic - // section. - // - // SHF_STRINGS section with different alignments should not be merged. - return sec->name == outsecName && sec->flags == ms->flags && - sec->entsize == ms->entsize && - (sec->alignment == ms->alignment || !(sec->flags & SHF_STRINGS)); - }); - if (i == mergeSections.end()) { - MergeSyntheticSection *syn = - createMergeSynthetic(outsecName, ms->type, ms->flags, ms->alignment); - mergeSections.push_back(syn); - i = std::prev(mergeSections.end()); - s = syn; - syn->entsize = ms->entsize; - } else { - s = nullptr; - } - (*i)->addSection(ms); - } - for (auto *ms : mergeSections) - ms->finalizeContents(); - - std::vector<InputSectionBase *> &v = inputSections; - v.erase(std::remove(v.begin(), v.end(), nullptr), v.end()); -} - MipsRldMapSection::MipsRldMapSection() : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS, config->wordsize, ".rld_map") {} @@ -3102,17 +3157,23 @@ static InputSection *findExidxSection(InputSection *isec) { return nullptr; } +static bool isValidExidxSectionDep(InputSection *isec) { + return (isec->flags & SHF_ALLOC) && (isec->flags & SHF_EXECINSTR) && + isec->getSize() > 0; +} + bool ARMExidxSyntheticSection::addSection(InputSection *isec) { if (isec->type == SHT_ARM_EXIDX) { - exidxSections.push_back(isec); - return true; + if (InputSection* dep = isec->getLinkOrderDep()) + if (isValidExidxSectionDep(dep)) { + exidxSections.push_back(isec); + return true; + } + return false; } - if ((isec->flags & SHF_ALLOC) && (isec->flags & SHF_EXECINSTR) && - isec->getSize() > 0) { + if (isValidExidxSectionDep(isec)) { executableSections.push_back(isec); - if (empty && findExidxSection(isec)) - empty = false; return false; } @@ -3177,11 +3238,20 @@ static bool isDuplicateArmExidxSec(InputSection *prev, InputSection *cur) { // The .ARM.exidx table must be sorted in ascending order of the address of the // functions the table describes. Optionally duplicate adjacent table entries -// can be removed. At the end of the function the ExecutableSections must be +// can be removed. At the end of the function the executableSections must be // sorted in ascending order of address, Sentinel is set to the InputSection // with the highest address and any InputSections that have mergeable // .ARM.exidx table entries are removed from it. void ARMExidxSyntheticSection::finalizeContents() { + // The executableSections and exidxSections that we use to derive the final + // contents of this SyntheticSection are populated before + // processSectionCommands() and ICF. A /DISCARD/ entry in SECTIONS command or + // ICF may remove executable InputSections and their dependent .ARM.exidx + // section that we recorded earlier. + auto isDiscarded = [](const InputSection *isec) { return !isec->isLive(); }; + llvm::erase_if(executableSections, isDiscarded); + llvm::erase_if(exidxSections, isDiscarded); + // Sort the executable sections that may or may not have associated // .ARM.exidx sections by order of ascending address. This requires the // relative positions of InputSections to be known. @@ -3270,6 +3340,12 @@ void ARMExidxSyntheticSection::writeTo(uint8_t *buf) { assert(size == offset + 8); } +bool ARMExidxSyntheticSection::isNeeded() const { + return llvm::find_if(exidxSections, [](InputSection *isec) { + return isec->isLive(); + }) != exidxSections.end(); +} + bool ARMExidxSyntheticSection::classof(const SectionBase *d) { return d->kind() == InputSectionBase::Synthetic && d->type == SHT_ARM_EXIDX; } @@ -3389,23 +3465,6 @@ bool PPC64LongBranchTargetSection::isNeeded() const { return !finalized || !entries.empty(); } -RISCVSdataSection::RISCVSdataSection() - : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS, 1, ".sdata") {} - -bool RISCVSdataSection::isNeeded() const { - if (!ElfSym::riscvGlobalPointer) - return false; - - // __global_pointer$ is defined relative to .sdata . If the section does not - // exist, create a dummy one. - for (BaseCommand *base : getParent()->sectionCommands) - if (auto *isd = dyn_cast<InputSectionDescription>(base)) - for (InputSection *isec : isd->sections) - if (isec != this) - return false; - return true; -} - static uint8_t getAbiVersion() { // MIPS non-PIC executable gets ABI version 1. if (config->emachine == EM_MIPS) { @@ -3426,7 +3485,7 @@ static uint8_t getAbiVersion() { return 0; } -template <typename ELFT> void elf::writeEhdr(uint8_t *buf, Partition &part) { +template <typename ELFT> void 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. @@ -3452,7 +3511,7 @@ template <typename ELFT> void elf::writeEhdr(uint8_t *buf, Partition &part) { } } -template <typename ELFT> void elf::writePhdrs(uint8_t *buf, Partition &part) { +template <typename ELFT> void writePhdrs(uint8_t *buf, Partition &part) { // Write the program header table. auto *hBuf = reinterpret_cast<typename ELFT::Phdr *>(buf); for (PhdrEntry *p : part.phdrs) { @@ -3527,92 +3586,90 @@ void PartitionIndexSection::writeTo(uint8_t *buf) { } } -InStruct elf::in; +InStruct in; -std::vector<Partition> elf::partitions; -Partition *elf::mainPart; +std::vector<Partition> partitions; +Partition *mainPart; template GdbIndexSection *GdbIndexSection::create<ELF32LE>(); template GdbIndexSection *GdbIndexSection::create<ELF32BE>(); template GdbIndexSection *GdbIndexSection::create<ELF64LE>(); template GdbIndexSection *GdbIndexSection::create<ELF64BE>(); -template void elf::splitSections<ELF32LE>(); -template void elf::splitSections<ELF32BE>(); -template void elf::splitSections<ELF64LE>(); -template void elf::splitSections<ELF64BE>(); - -template void EhFrameSection::addSection<ELF32LE>(InputSectionBase *); -template void EhFrameSection::addSection<ELF32BE>(InputSectionBase *); -template void EhFrameSection::addSection<ELF64LE>(InputSectionBase *); -template void EhFrameSection::addSection<ELF64BE>(InputSectionBase *); +template void splitSections<ELF32LE>(); +template void splitSections<ELF32BE>(); +template void splitSections<ELF64LE>(); +template void splitSections<ELF64BE>(); template void PltSection::addEntry<ELF32LE>(Symbol &Sym); template void PltSection::addEntry<ELF32BE>(Symbol &Sym); template void PltSection::addEntry<ELF64LE>(Symbol &Sym); template void PltSection::addEntry<ELF64BE>(Symbol &Sym); -template class elf::MipsAbiFlagsSection<ELF32LE>; -template class elf::MipsAbiFlagsSection<ELF32BE>; -template class elf::MipsAbiFlagsSection<ELF64LE>; -template class elf::MipsAbiFlagsSection<ELF64BE>; - -template class elf::MipsOptionsSection<ELF32LE>; -template class elf::MipsOptionsSection<ELF32BE>; -template class elf::MipsOptionsSection<ELF64LE>; -template class elf::MipsOptionsSection<ELF64BE>; - -template class elf::MipsReginfoSection<ELF32LE>; -template class elf::MipsReginfoSection<ELF32BE>; -template class elf::MipsReginfoSection<ELF64LE>; -template class elf::MipsReginfoSection<ELF64BE>; - -template class elf::DynamicSection<ELF32LE>; -template class elf::DynamicSection<ELF32BE>; -template class elf::DynamicSection<ELF64LE>; -template class elf::DynamicSection<ELF64BE>; - -template class elf::RelocationSection<ELF32LE>; -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::RelrSection<ELF32LE>; -template class elf::RelrSection<ELF32BE>; -template class elf::RelrSection<ELF64LE>; -template class elf::RelrSection<ELF64BE>; - -template class elf::SymbolTableSection<ELF32LE>; -template class elf::SymbolTableSection<ELF32BE>; -template class elf::SymbolTableSection<ELF64LE>; -template class elf::SymbolTableSection<ELF64BE>; - -template class elf::VersionNeedSection<ELF32LE>; -template class elf::VersionNeedSection<ELF32BE>; -template class elf::VersionNeedSection<ELF64LE>; -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>; +template class MipsAbiFlagsSection<ELF32LE>; +template class MipsAbiFlagsSection<ELF32BE>; +template class MipsAbiFlagsSection<ELF64LE>; +template class MipsAbiFlagsSection<ELF64BE>; + +template class MipsOptionsSection<ELF32LE>; +template class MipsOptionsSection<ELF32BE>; +template class MipsOptionsSection<ELF64LE>; +template class MipsOptionsSection<ELF64BE>; + +template class MipsReginfoSection<ELF32LE>; +template class MipsReginfoSection<ELF32BE>; +template class MipsReginfoSection<ELF64LE>; +template class MipsReginfoSection<ELF64BE>; + +template class DynamicSection<ELF32LE>; +template class DynamicSection<ELF32BE>; +template class DynamicSection<ELF64LE>; +template class DynamicSection<ELF64BE>; + +template class RelocationSection<ELF32LE>; +template class RelocationSection<ELF32BE>; +template class RelocationSection<ELF64LE>; +template class RelocationSection<ELF64BE>; + +template class AndroidPackedRelocationSection<ELF32LE>; +template class AndroidPackedRelocationSection<ELF32BE>; +template class AndroidPackedRelocationSection<ELF64LE>; +template class AndroidPackedRelocationSection<ELF64BE>; + +template class RelrSection<ELF32LE>; +template class RelrSection<ELF32BE>; +template class RelrSection<ELF64LE>; +template class RelrSection<ELF64BE>; + +template class SymbolTableSection<ELF32LE>; +template class SymbolTableSection<ELF32BE>; +template class SymbolTableSection<ELF64LE>; +template class SymbolTableSection<ELF64BE>; + +template class VersionNeedSection<ELF32LE>; +template class VersionNeedSection<ELF32BE>; +template class VersionNeedSection<ELF64LE>; +template class VersionNeedSection<ELF64BE>; + +template void writeEhdr<ELF32LE>(uint8_t *Buf, Partition &Part); +template void writeEhdr<ELF32BE>(uint8_t *Buf, Partition &Part); +template void writeEhdr<ELF64LE>(uint8_t *Buf, Partition &Part); +template void writeEhdr<ELF64BE>(uint8_t *Buf, Partition &Part); + +template void writePhdrs<ELF32LE>(uint8_t *Buf, Partition &Part); +template void writePhdrs<ELF32BE>(uint8_t *Buf, Partition &Part); +template void writePhdrs<ELF64LE>(uint8_t *Buf, Partition &Part); +template void writePhdrs<ELF64BE>(uint8_t *Buf, Partition &Part); + +template class PartitionElfHeaderSection<ELF32LE>; +template class PartitionElfHeaderSection<ELF32BE>; +template class PartitionElfHeaderSection<ELF64LE>; +template class PartitionElfHeaderSection<ELF64BE>; + +template class PartitionProgramHeadersSection<ELF32LE>; +template class PartitionProgramHeadersSection<ELF32BE>; +template class PartitionProgramHeadersSection<ELF64LE>; +template class PartitionProgramHeadersSection<ELF64BE>; + +} // namespace elf +} // namespace lld |