//===- 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::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() : OutputSectionBase(".got", llvm::ELF::SHT_PROGBITS, llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_WRITE) { 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 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, 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), 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 SymbolBody *Body = C.getFile()->getSymbolBody(SymIndex); uint32_t Type = RI.getType(IsMips64EL); if (Target->relocNeedsGot(Type, *Body)) { P->r_offset = GotSec.getEntryAddr(*Body); P->setSymbolAndType(Body->getDynamicSymbolTableIndex(), Target->getGotReloc(), IsMips64EL); } else { P->r_offset = RI.r_offset + C.getOutputSectionOff() + Out->getVA(); P->setSymbolAndType(Body->getDynamicSymbolTableIndex(), Type, IsMips64EL); if (IsRela) static_cast(P)->r_addend = static_cast(RI).r_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) : OutputSectionBase(".dynamic", llvm::ELF::SHT_DYNAMIC, llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_WRITE), HashSec(HashSec), DynSymSec(HashSec.getDynSymSec()), DynStrSec(DynSymSec.getStrTabSec()), RelaDynSec(RelaDynSec), 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() { 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 StringRef RPath = Config->RPath; if (!RPath.empty()) { ++NumEntries; // DT_RUNPATH DynStrSec.add(RPath); } const std::vector> &SharedFiles = SymTab.getSharedFiles(); for (const std::unique_ptr &File : SharedFiles) DynStrSec.add(File->getSoName()); NumEntries += SharedFiles.size(); ++NumEntries; // DT_NULL Header.sh_size = NumEntries * Header.sh_entsize; } template void DynamicSection::writeTo(uint8_t *Buf) { typedef typename std::conditional::type Elf_Dyn; auto *P = reinterpret_cast(Buf); if (RelaDynSec.hasRelocs()) { bool IsRela = RelaDynSec.isRela(); P->d_tag = IsRela ? DT_RELA : DT_REL; P->d_un.d_ptr = RelaDynSec.getVA(); ++P; P->d_tag = IsRela ? DT_RELASZ : DT_RELSZ; P->d_un.d_val = RelaDynSec.getSize(); ++P; P->d_tag = IsRela ? DT_RELAENT : DT_RELENT; P->d_un.d_val = IsRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel); ++P; } P->d_tag = DT_SYMTAB; P->d_un.d_ptr = DynSymSec.getVA(); ++P; P->d_tag = DT_SYMENT; P->d_un.d_ptr = sizeof(Elf_Sym); ++P; P->d_tag = DT_STRTAB; P->d_un.d_ptr = DynStrSec.getVA(); ++P; P->d_tag = DT_STRSZ; P->d_un.d_val = DynStrSec.data().size(); ++P; P->d_tag = DT_HASH; P->d_un.d_ptr = HashSec.getVA(); ++P; StringRef RPath = Config->RPath; if (!RPath.empty()) { P->d_tag = DT_RUNPATH; P->d_un.d_val = DynStrSec.getFileOff(RPath); ++P; } const std::vector> &SharedFiles = SymTab.getSharedFiles(); for (const std::unique_ptr &File : SharedFiles) { P->d_tag = DT_NEEDED; P->d_un.d_val = DynStrSec.getFileOff(File->getSoName()); ++P; } P->d_tag = DT_NULL; P->d_un.d_val = 0; ++P; } 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 ELFSymbolBody &S, const OutputSection &BssSec) { switch (S.kind()) { case SymbolBody::DefinedSyntheticKind: return cast>(S).Section.getVA() + S.Sym.st_value; case SymbolBody::DefinedAbsoluteKind: return 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: break; } llvm_unreachable("Lazy symbol reached writer"); } 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; } 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()); } bool lld::elf2::includeInSymtab(const SymbolBody &B) { if (B.isLazy()) return false; if (!B.isUsedInRegularObj()) return false; uint8_t V = B.getMostConstrainingVisibility(); if (V != STV_DEFAULT && V != STV_PROTECTED) return false; return true; } bool lld::elf2::includeInDynamicSymtab(const SymbolBody &B) { if (Config->ExportDynamic || Config->Shared) return true; return B.isUsedInDynamicReloc(); } bool lld::elf2::shouldKeepInSymtab(StringRef SymName) { 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)) 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. 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; const auto &EBody = *cast>(Body); const Elf_Sym &InputSym = EBody.Sym; auto *ESym = reinterpret_cast(Buf); Buf += sizeof(*ESym); ESym->st_name = StrTabSec.getFileOff(Name); const OutputSection *Out = nullptr; const InputSection *Section = nullptr; switch (EBody.kind()) { case SymbolBody::DefinedSyntheticKind: Out = &cast>(Body)->Section; break; case SymbolBody::DefinedRegularKind: Section = &cast>(EBody).Section; break; case SymbolBody::DefinedCommonKind: Out = &BssSec; break; case SymbolBody::UndefinedKind: case SymbolBody::DefinedAbsoluteKind: case SymbolBody::SharedKind: break; case SymbolBody::LazyKind: llvm_unreachable("Lazy symbol got to output symbol table!"); } ESym->setBindingAndType(InputSym.getBinding(), InputSym.getType()); ESym->st_size = InputSym.st_size; ESym->setVisibility(EBody.getMostConstrainingVisibility()); if (InputSym.isAbsolute()) { ESym->st_shndx = SHN_ABS; ESym->st_value = InputSym.st_value; } if (Section) Out = Section->getOutputSection(); ESym->st_value = getSymVA(EBody, BssSec); if (Out) ESym->st_shndx = Out->getSectionIndex(); } } 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 ELFSymbolBody &, const OutputSection &); template ELFFile::uintX_t getSymVA(const ELFSymbolBody &, const OutputSection &); template ELFFile::uintX_t getSymVA(const ELFSymbolBody &, const OutputSection &); template ELFFile::uintX_t getSymVA(const ELFSymbolBody &, 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 &); } }