//===- OutputSections.cpp -------------------------------------------------===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "OutputSections.h" #include "Config.h" #include "SymbolTable.h" #include "Target.h" using namespace llvm; using namespace llvm::object; using namespace llvm::support::endian; using namespace llvm::ELF; using namespace lld; using namespace lld::elf2; template OutputSectionBase::OutputSectionBase(StringRef Name, uint32_t sh_type, uintX_t sh_flags) : Name(Name) { memset(&Header, 0, sizeof(HeaderT)); Header.sh_type = sh_type; Header.sh_flags = sh_flags; } template GotSection::GotSection(const OutputSection &BssSec) : OutputSectionBase(".got", llvm::ELF::SHT_PROGBITS, llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_WRITE), BssSec(BssSec) { this->Header.sh_addralign = this->getAddrSize(); } template void GotSection::addEntry(SymbolBody *Sym) { Sym->setGotIndex(Entries.size()); Entries.push_back(Sym); } template typename GotSection::uintX_t GotSection::getEntryAddr(const SymbolBody &B) const { return this->getVA() + B.getGotIndex() * this->getAddrSize(); } template void GotSection::writeTo(uint8_t *Buf) { for (const SymbolBody *B : Entries) { if (canBePreempted(B)) continue; // The dynamic linker will take care of it. uintX_t VA = getSymVA(*B, BssSec); write(Buf, VA); Buf += sizeof(uintX_t); } } template PltSection::PltSection(const GotSection &GotSec) : OutputSectionBase(".plt", llvm::ELF::SHT_PROGBITS, llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_EXECINSTR), GotSec(GotSec) { this->Header.sh_addralign = 16; } template void PltSection::writeTo(uint8_t *Buf) { uintptr_t Start = reinterpret_cast(Buf); for (const SymbolBody *E : Entries) { uint64_t GotEntryAddr = GotSec.getEntryAddr(*E); uintptr_t InstPos = reinterpret_cast(Buf); uint64_t PltEntryAddr = (InstPos - Start) + this->getVA(); Target->writePltEntry(Buf, GotEntryAddr, PltEntryAddr); Buf += 8; } } template void PltSection::addEntry(SymbolBody *Sym) { Sym->setPltIndex(Entries.size()); Entries.push_back(Sym); } template typename PltSection::uintX_t PltSection::getEntryAddr(const SymbolBody &B) const { return this->getVA() + B.getPltIndex() * EntrySize; } template RelocationSection::RelocationSection(SymbolTableSection &DynSymSec, const GotSection &GotSec, const OutputSection &BssSec, bool IsRela) : OutputSectionBase(IsRela ? ".rela.dyn" : ".rel.dyn", IsRela ? llvm::ELF::SHT_RELA : llvm::ELF::SHT_REL, llvm::ELF::SHF_ALLOC), DynSymSec(DynSymSec), GotSec(GotSec), BssSec(BssSec), IsRela(IsRela) { this->Header.sh_entsize = IsRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel); this->Header.sh_addralign = ELFT::Is64Bits ? 8 : 4; } template void RelocationSection::writeTo(uint8_t *Buf) { const unsigned EntrySize = IsRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel); bool IsMips64EL = Relocs[0].C.getFile()->getObj().isMips64EL(); for (const DynamicReloc &Rel : Relocs) { auto *P = reinterpret_cast(Buf); Buf += EntrySize; const InputSection &C = Rel.C; const Elf_Rel &RI = Rel.RI; OutputSection *Out = C.getOutputSection(); uint32_t SymIndex = RI.getSymbol(IsMips64EL); const ObjectFile &File = *C.getFile(); const SymbolBody *Body = File.getSymbolBody(SymIndex); const ELFFile &Obj = File.getObj(); uint32_t Type = RI.getType(IsMips64EL); bool CanBePreempted = canBePreempted(Body); uintX_t Addend = 0; if (!CanBePreempted) { if (IsRela) { if (Body) Addend += getSymVA(cast>(*Body), BssSec); else Addend += getLocalSymVA( Obj.getRelocationSymbol(&RI, File.getSymbolTable()), File); } P->setSymbolAndType(0, Target->getRelativeReloc(), IsMips64EL); } if (Body && Target->relocNeedsGot(Type, *Body)) { P->r_offset = GotSec.getEntryAddr(*Body); if (CanBePreempted) P->setSymbolAndType(Body->getDynamicSymbolTableIndex(), Target->getGotReloc(), IsMips64EL); } else { if (IsRela) Addend += static_cast(RI).r_addend; P->r_offset = RI.r_offset + C.getOutputSectionOff() + Out->getVA(); if (CanBePreempted) P->setSymbolAndType(Body->getDynamicSymbolTableIndex(), Type, IsMips64EL); } if (IsRela) static_cast(P)->r_addend = Addend; } } template void RelocationSection::finalize() { this->Header.sh_link = DynSymSec.getSectionIndex(); this->Header.sh_size = Relocs.size() * this->Header.sh_entsize; } template InterpSection::InterpSection() : OutputSectionBase(".interp", llvm::ELF::SHT_PROGBITS, llvm::ELF::SHF_ALLOC) { this->Header.sh_size = Config->DynamicLinker.size() + 1; this->Header.sh_addralign = 1; } template template void OutputSectionBase::writeHeaderTo( typename ELFFile>::Elf_Shdr *SHdr) { SHdr->sh_name = Header.sh_name; SHdr->sh_type = Header.sh_type; SHdr->sh_flags = Header.sh_flags; SHdr->sh_addr = Header.sh_addr; SHdr->sh_offset = Header.sh_offset; SHdr->sh_size = Header.sh_size; SHdr->sh_link = Header.sh_link; SHdr->sh_info = Header.sh_info; SHdr->sh_addralign = Header.sh_addralign; SHdr->sh_entsize = Header.sh_entsize; } template void InterpSection::writeTo(uint8_t *Buf) { memcpy(Buf, Config->DynamicLinker.data(), Config->DynamicLinker.size()); } template HashTableSection::HashTableSection(SymbolTableSection &DynSymSec) : OutputSectionBase(".hash", llvm::ELF::SHT_HASH, llvm::ELF::SHF_ALLOC), DynSymSec(DynSymSec) { this->Header.sh_entsize = sizeof(Elf_Word); this->Header.sh_addralign = sizeof(Elf_Word); } template void HashTableSection::addSymbol(SymbolBody *S) { StringRef Name = S->getName(); DynSymSec.addSymbol(Name); Hashes.push_back(hash(Name)); S->setDynamicSymbolTableIndex(Hashes.size()); } template DynamicSection::DynamicSection(SymbolTable &SymTab, HashTableSection &HashSec, RelocationSection &RelaDynSec, const OutputSection &BssSec) : OutputSectionBase(".dynamic", llvm::ELF::SHT_DYNAMIC, llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_WRITE), HashSec(HashSec), DynSymSec(HashSec.getDynSymSec()), DynStrSec(DynSymSec.getStrTabSec()), RelaDynSec(RelaDynSec), BssSec(BssSec), SymTab(SymTab) { typename Base::HeaderT &Header = this->Header; Header.sh_addralign = ELFT::Is64Bits ? 8 : 4; Header.sh_entsize = ELFT::Is64Bits ? 16 : 8; } template void DynamicSection::finalize() { if (this->Header.sh_size) return; // Already finalized. typename Base::HeaderT &Header = this->Header; Header.sh_link = DynStrSec.getSectionIndex(); unsigned NumEntries = 0; if (RelaDynSec.hasRelocs()) { ++NumEntries; // DT_RELA / DT_REL ++NumEntries; // DT_RELASZ / DT_RELSZ ++NumEntries; // DT_RELAENT / DT_RELENT } ++NumEntries; // DT_SYMTAB ++NumEntries; // DT_SYMENT ++NumEntries; // DT_STRTAB ++NumEntries; // DT_STRSZ ++NumEntries; // DT_HASH if (!Config->RPath.empty()) { ++NumEntries; // DT_RUNPATH / DT_RPATH DynStrSec.add(Config->RPath); } if (!Config->SoName.empty()) { ++NumEntries; // DT_SONAME DynStrSec.add(Config->SoName); } if (PreInitArraySec) NumEntries += 2; if (InitArraySec) NumEntries += 2; if (FiniArraySec) NumEntries += 2; const std::vector> &SharedFiles = SymTab.getSharedFiles(); for (const std::unique_ptr &File : SharedFiles) DynStrSec.add(File->getSoName()); NumEntries += SharedFiles.size(); if (Symbol *S = SymTab.getSymbols().lookup(Config->Init)) InitSym = dyn_cast>(S->Body); if (Symbol *S = SymTab.getSymbols().lookup(Config->Fini)) FiniSym = dyn_cast>(S->Body); if (InitSym) ++NumEntries; // DT_INIT if (FiniSym) ++NumEntries; // DT_FINI ++NumEntries; // DT_NULL Header.sh_size = NumEntries * Header.sh_entsize; } template void DynamicSection::writeTo(uint8_t *Buf) { auto *P = reinterpret_cast(Buf); auto WritePtr = [&](int32_t Tag, uint64_t Val) { P->d_tag = Tag; P->d_un.d_ptr = Val; ++P; }; auto WriteVal = [&](int32_t Tag, uint32_t Val) { P->d_tag = Tag; P->d_un.d_val = Val; ++P; }; if (RelaDynSec.hasRelocs()) { bool IsRela = RelaDynSec.isRela(); WritePtr(IsRela ? DT_RELA : DT_REL, RelaDynSec.getVA()); WriteVal(IsRela ? DT_RELASZ : DT_RELSZ, RelaDynSec.getSize()); WriteVal(IsRela ? DT_RELAENT : DT_RELENT, IsRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel)); } WritePtr(DT_SYMTAB, DynSymSec.getVA()); WritePtr(DT_SYMENT, sizeof(Elf_Sym)); WritePtr(DT_STRTAB, DynStrSec.getVA()); WriteVal(DT_STRSZ, DynStrSec.data().size()); WritePtr(DT_HASH, HashSec.getVA()); if (!Config->RPath.empty()) // If --enable-new-dtags is set lld emits DT_RUNPATH // instead of DT_RPATH. The two tags are functionally // equivalent except for the following: // - DT_RUNPATH is searched after LD_LIBRARY_PATH, while // DT_RPATH is searched before. // - DT_RUNPATH is used only to search for direct // dependencies of the object it's contained in, while // DT_RPATH is used for indirect dependencies as well. WriteVal(Config->EnableNewDtags ? DT_RUNPATH : DT_RPATH, DynStrSec.getFileOff(Config->RPath)); if (!Config->SoName.empty()) WriteVal(DT_SONAME, DynStrSec.getFileOff(Config->SoName)); auto WriteArray = [&](int32_t T1, int32_t T2, const OutputSection *Sec) { if (!Sec) return; WritePtr(T1, Sec->getVA()); WriteVal(T2, Sec->getSize()); }; WriteArray(DT_PREINIT_ARRAY, DT_PREINIT_ARRAYSZ, PreInitArraySec); WriteArray(DT_INIT_ARRAY, DT_INIT_ARRAYSZ, InitArraySec); WriteArray(DT_FINI_ARRAY, DT_FINI_ARRAYSZ, FiniArraySec); const std::vector> &SharedFiles = SymTab.getSharedFiles(); for (const std::unique_ptr &File : SharedFiles) WriteVal(DT_NEEDED, DynStrSec.getFileOff(File->getSoName())); if (InitSym) WritePtr(DT_INIT, getSymVA(*InitSym, BssSec)); if (FiniSym) WritePtr(DT_FINI, getSymVA(*FiniSym, BssSec)); WriteVal(DT_NULL, 0); } template OutputSection::OutputSection(const PltSection &PltSec, const GotSection &GotSec, const OutputSection &BssSec, StringRef Name, uint32_t sh_type, uintX_t sh_flags) : OutputSectionBase(Name, sh_type, sh_flags), PltSec(PltSec), GotSec(GotSec), BssSec(BssSec) {} template void OutputSection::addSection(InputSection *C) { Sections.push_back(C); C->setOutputSection(this); uint32_t Align = C->getAlign(); if (Align > this->Header.sh_addralign) this->Header.sh_addralign = Align; uintX_t Off = this->Header.sh_size; Off = RoundUpToAlignment(Off, Align); C->setOutputSectionOff(Off); Off += C->getSize(); this->Header.sh_size = Off; } template typename ELFFile::uintX_t lld::elf2::getSymVA(const SymbolBody &S, const OutputSection &BssSec) { switch (S.kind()) { case SymbolBody::DefinedSyntheticKind: { auto &D = cast>(S); return D.Section.getVA() + D.Sym.st_value; } case SymbolBody::DefinedAbsoluteKind: return cast>(S).Sym.st_value; case SymbolBody::DefinedRegularKind: { const auto &DR = cast>(S); const InputSection *SC = &DR.Section; OutputSection *OS = SC->getOutputSection(); return OS->getVA() + SC->getOutputSectionOff() + DR.Sym.st_value; } case SymbolBody::DefinedCommonKind: return BssSec.getVA() + cast>(S).OffsetInBSS; case SymbolBody::SharedKind: case SymbolBody::UndefinedKind: return 0; case SymbolBody::LazyKind: assert(S.isUsedInRegularObj() && "Lazy symbol reached writer"); return 0; } } template typename ELFFile::uintX_t lld::elf2::getLocalSymVA(const typename ELFFile::Elf_Sym *Sym, const ObjectFile &File) { uint32_t SecIndex = Sym->st_shndx; if (SecIndex == SHN_XINDEX) SecIndex = File.getObj().getExtendedSymbolTableIndex( Sym, File.getSymbolTable(), File.getSymbolTableShndx()); ArrayRef *> Sections = File.getSections(); InputSection *Section = Sections[SecIndex]; OutputSection *Out = Section->getOutputSection(); return Out->getVA() + Section->getOutputSectionOff() + Sym->st_value; } bool lld::elf2::canBePreempted(const SymbolBody *Body) { if (!Body) return false; if (Body->isShared() || Body->isUndefined()) return true; if (!Config->Shared) return false; return Body->getMostConstrainingVisibility() == STV_DEFAULT; } template void OutputSection::writeTo(uint8_t *Buf) { for (InputSection *C : Sections) C->writeTo(Buf, BssSec, PltSec, GotSec); } template StringTableSection::StringTableSection(bool Dynamic) : OutputSectionBase(Dynamic ? ".dynstr" : ".strtab", llvm::ELF::SHT_STRTAB, Dynamic ? (uintX_t)llvm::ELF::SHF_ALLOC : 0), Dynamic(Dynamic) { this->Header.sh_addralign = 1; } template void StringTableSection::writeTo(uint8_t *Buf) { StringRef Data = StrTabBuilder.data(); memcpy(Buf, Data.data(), Data.size()); } template bool lld::elf2::includeInSymtab(const SymbolBody &B) { if (!B.isUsedInRegularObj()) return false; // Don't include synthetic symbols like __init_array_start in every output. if (auto *U = dyn_cast>(&B)) if (&U->Sym == &DefinedAbsolute::IgnoreUndef) return false; return true; } bool lld::elf2::includeInDynamicSymtab(const SymbolBody &B) { uint8_t V = B.getMostConstrainingVisibility(); if (V != STV_DEFAULT && V != STV_PROTECTED) return false; if (Config->ExportDynamic || Config->Shared) return true; return B.isUsedInDynamicReloc(); } template bool lld::elf2::shouldKeepInSymtab(StringRef SymName, const typename ELFFile::Elf_Sym &Sym) { if (Sym.getType() == STT_SECTION) return false; if (Config->DiscardNone) return true; // ELF defines dynamic locals as symbols which name starts with ".L". return !(Config->DiscardLocals && SymName.startswith(".L")); } template SymbolTableSection::SymbolTableSection( SymbolTable &Table, StringTableSection &StrTabSec, const OutputSection &BssSec) : OutputSectionBase( StrTabSec.isDynamic() ? ".dynsym" : ".symtab", StrTabSec.isDynamic() ? llvm::ELF::SHT_DYNSYM : llvm::ELF::SHT_SYMTAB, StrTabSec.isDynamic() ? (uintX_t)llvm::ELF::SHF_ALLOC : 0), Table(Table), StrTabSec(StrTabSec), BssSec(BssSec) { typedef OutputSectionBase Base; typename Base::HeaderT &Header = this->Header; Header.sh_entsize = sizeof(Elf_Sym); Header.sh_addralign = ELFT::Is64Bits ? 8 : 4; } template void SymbolTableSection::writeTo(uint8_t *Buf) { Buf += sizeof(Elf_Sym); // All symbols with STB_LOCAL binding precede the weak and global symbols. // .dynsym only contains global symbols. if (!Config->DiscardAll && !StrTabSec.isDynamic()) writeLocalSymbols(Buf); writeGlobalSymbols(Buf); } template void SymbolTableSection::writeLocalSymbols(uint8_t *&Buf) { // Iterate over all input object files to copy their local symbols // to the output symbol table pointed by Buf. for (const std::unique_ptr &FileB : Table.getObjectFiles()) { auto &File = cast>(*FileB); Elf_Sym_Range Syms = File.getLocalSymbols(); for (const Elf_Sym &Sym : Syms) { ErrorOr SymName = Sym.getName(File.getStringTable()); if (SymName && !shouldKeepInSymtab(*SymName, Sym)) continue; auto *ESym = reinterpret_cast(Buf); Buf += sizeof(*ESym); ESym->st_name = (SymName) ? StrTabSec.getFileOff(*SymName) : 0; ESym->st_size = Sym.st_size; ESym->setBindingAndType(Sym.getBinding(), Sym.getType()); uint32_t SecIndex = Sym.st_shndx; uintX_t VA = Sym.st_value; if (SecIndex == SHN_ABS) { ESym->st_shndx = SHN_ABS; } else { if (SecIndex == SHN_XINDEX) SecIndex = File.getObj().getExtendedSymbolTableIndex( &Sym, File.getSymbolTable(), File.getSymbolTableShndx()); ArrayRef *> Sections = File.getSections(); const InputSection *Section = Sections[SecIndex]; const OutputSection *Out = Section->getOutputSection(); ESym->st_shndx = Out->getSectionIndex(); VA += Out->getVA() + Section->getOutputSectionOff(); } ESym->st_value = VA; } } } template void SymbolTableSection::writeGlobalSymbols(uint8_t *&Buf) { // Write the internal symbol table contents to the output symbol table // pointed by Buf. uint8_t *Start = Buf; for (const std::pair &P : Table.getSymbols()) { StringRef Name = P.first; Symbol *Sym = P.second; SymbolBody *Body = Sym->Body; if (!includeInSymtab(*Body)) continue; if (StrTabSec.isDynamic() && !includeInDynamicSymtab(*Body)) continue; auto *ESym = reinterpret_cast(Buf); Buf += sizeof(*ESym); ESym->st_name = StrTabSec.getFileOff(Name); const OutputSection *Out = nullptr; const InputSection *Section = nullptr; switch (Body->kind()) { case SymbolBody::DefinedSyntheticKind: Out = &cast>(Body)->Section; break; case SymbolBody::DefinedRegularKind: Section = &cast>(Body)->Section; break; case SymbolBody::DefinedCommonKind: Out = &BssSec; break; case SymbolBody::UndefinedKind: case SymbolBody::DefinedAbsoluteKind: case SymbolBody::SharedKind: case SymbolBody::LazyKind: break; } unsigned char Binding = Body->isWeak() ? STB_WEAK : STB_GLOBAL; unsigned char Type = STT_NOTYPE; uintX_t Size = 0; if (const auto *EBody = dyn_cast>(Body)) { const Elf_Sym &InputSym = EBody->Sym; Binding = InputSym.getBinding(); Type = InputSym.getType(); Size = InputSym.st_size; } unsigned char Visibility = Body->getMostConstrainingVisibility(); if (Visibility != STV_DEFAULT && Visibility != STV_PROTECTED) Binding = STB_LOCAL; ESym->setBindingAndType(Binding, Type); ESym->st_size = Size; ESym->setVisibility(Visibility); ESym->st_value = getSymVA(*Body, BssSec); if (Section) Out = Section->getOutputSection(); if (isa>(Body)) ESym->st_shndx = SHN_ABS; else if (Out) ESym->st_shndx = Out->getSectionIndex(); } if (!StrTabSec.isDynamic()) std::stable_sort( reinterpret_cast(Start), reinterpret_cast(Buf), [](const Elf_Sym &A, const Elf_Sym &B) -> bool { return A.getBinding() == STB_LOCAL && B.getBinding() != STB_LOCAL; }); } namespace lld { namespace elf2 { template class OutputSectionBase; template class OutputSectionBase; template void OutputSectionBase::writeHeaderTo( ELFFile>::Elf_Shdr *SHdr); template void OutputSectionBase::writeHeaderTo( ELFFile>::Elf_Shdr *SHdr); template void OutputSectionBase::writeHeaderTo( ELFFile>::Elf_Shdr *SHdr); template void OutputSectionBase::writeHeaderTo( ELFFile>::Elf_Shdr *SHdr); template class GotSection; template class GotSection; template class GotSection; template class GotSection; template class PltSection; template class PltSection; template class PltSection; template class PltSection; template class RelocationSection; template class RelocationSection; template class RelocationSection; template class RelocationSection; template class InterpSection; template class InterpSection; template class HashTableSection; template class HashTableSection; template class HashTableSection; template class HashTableSection; template class DynamicSection; template class DynamicSection; template class DynamicSection; template class DynamicSection; template class OutputSection; template class OutputSection; template class OutputSection; template class OutputSection; template class StringTableSection; template class StringTableSection; template class SymbolTableSection; template class SymbolTableSection; template class SymbolTableSection; template class SymbolTableSection; template ELFFile::uintX_t getSymVA(const SymbolBody &, const OutputSection &); template ELFFile::uintX_t getSymVA(const SymbolBody &, const OutputSection &); template ELFFile::uintX_t getSymVA(const SymbolBody &, const OutputSection &); template ELFFile::uintX_t getSymVA(const SymbolBody &, const OutputSection &); template ELFFile::uintX_t getLocalSymVA(const ELFFile::Elf_Sym *, const ObjectFile &); template ELFFile::uintX_t getLocalSymVA(const ELFFile::Elf_Sym *, const ObjectFile &); template ELFFile::uintX_t getLocalSymVA(const ELFFile::Elf_Sym *, const ObjectFile &); template ELFFile::uintX_t getLocalSymVA(const ELFFile::Elf_Sym *, const ObjectFile &); template bool includeInSymtab(const SymbolBody &); template bool includeInSymtab(const SymbolBody &); template bool includeInSymtab(const SymbolBody &); template bool includeInSymtab(const SymbolBody &); template bool shouldKeepInSymtab(StringRef, const ELFFile::Elf_Sym &); template bool shouldKeepInSymtab(StringRef, const ELFFile::Elf_Sym &); template bool shouldKeepInSymtab(StringRef, const ELFFile::Elf_Sym &); template bool shouldKeepInSymtab(StringRef, const ELFFile::Elf_Sym &); } }