//===- 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" 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 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 PltSection::writeTo(uint8_t *Buf) { uintptr_t Start = reinterpret_cast(Buf); ArrayRef Jmp = {0xff, 0x25}; // jmpq *val(%rip) for (const SymbolBody *E : Entries) { uintptr_t InstPos = reinterpret_cast(Buf); memcpy(Buf, Jmp.data(), Jmp.size()); Buf += Jmp.size(); uintptr_t OffsetInPLT = (InstPos + 6) - Start; uintptr_t Delta = GotSec.getEntryAddr(*E) - (this->getVA() + OffsetInPLT); assert(isInt<32>(Delta)); support::endian::write32le(Buf, Delta); Buf += 4; *Buf = 0x90; // nop ++Buf; *Buf = 0x90; // nop ++Buf; } } 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; } bool lld::elf2::relocNeedsPLT(uint32_t Type) { switch (Type) { default: return false; case R_X86_64_PLT32: return true; } } bool lld::elf2::relocNeedsGOT(uint32_t Type) { if (relocNeedsPLT(Type)) return true; switch (Type) { default: return false; case R_X86_64_GOTPCREL: return true; } } template void RelocationSection::writeTo(uint8_t *Buf) { auto *P = reinterpret_cast(Buf); bool IsMips64EL = Relocs[0].C.getFile()->getObj()->isMips64EL(); for (const DynamicReloc &Rel : Relocs) { 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 (relocNeedsGOT(Type)) { P->r_offset = GotSec.getEntryAddr(*Body); P->setSymbolAndType(Body->getDynamicSymbolTableIndex(), R_X86_64_GLOB_DAT, IsMips64EL); } else { P->r_offset = RI.r_offset + C.getOutputSectionOff() + Out->getVA(); P->setSymbolAndType(Body->getDynamicSymbolTableIndex(), Type, IsMips64EL); if (IsRela) P->r_addend = static_cast(RI).r_addend; } ++P; } } 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 void HashTableSection::addSymbol(SymbolBody *S) { StringRef Name = S->getName(); DynSymSec.addSymbol(Name); Hashes.push_back(hash(Name)); S->setDynamicSymbolTableIndex(Hashes.size()); } 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 / DTRELSZ } ++NumEntries; // DT_SYMTAB ++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->getName()); 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 = DT_SYMTAB; P->d_un.d_ptr = DynSymSec.getVA(); ++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->getName()); ++P; } P->d_tag = DT_NULL; P->d_un.d_val = 0; ++P; } template void OutputSection::addChunk(InputSection *C) { Chunks.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 DefinedRegular *DR) { const InputSection *SC = &DR->Section; OutputSection *OS = SC->getOutputSection(); return OS->getVA() + SC->getOutputSectionOff() + DR->Sym.st_value; } 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 *> Chunks = File.getChunks(); InputSection *Section = Chunks[SecIndex]; OutputSection *Out = Section->getOutputSection(); return Out->getVA() + Section->getOutputSectionOff() + Sym->st_value; } template void OutputSection::writeTo(uint8_t *Buf) { for (InputSection *C : Chunks) C->writeTo(Buf, PltSec, GotSec); } 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; } template void SymbolTableSection::writeTo(uint8_t *Buf) { const OutputSection *Out = nullptr; const InputSection *Section = nullptr; 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()) { for (const std::unique_ptr &FileB : Table.getObjectFiles()) { auto &File = cast>(*FileB); Elf_Sym_Range Syms = File.getLocalSymbols(); for (const Elf_Sym &Sym : Syms) { auto *ESym = reinterpret_cast(Buf); uint32_t SecIndex = Sym.st_shndx; ErrorOr SymName = Sym.getName(File.getStringTable()); if (Config->DiscardLocals && SymName->startswith(".L")) continue; ESym->st_name = (SymName) ? StrTabSec.getFileOff(*SymName) : 0; ESym->st_size = Sym.st_size; ESym->setBindingAndType(Sym.getBinding(), Sym.getType()); if (SecIndex == SHN_XINDEX) SecIndex = File.getObj()->getExtendedSymbolTableIndex( &Sym, File.getSymbolTable(), File.getSymbolTableShndx()); ArrayRef *> Chunks = File.getChunks(); Section = Chunks[SecIndex]; assert(Section != nullptr); Out = Section->getOutputSection(); assert(Out != nullptr); ESym->st_shndx = Out->getSectionIndex(); ESym->st_value = Out->getVA() + Section->getOutputSectionOff() + Sym.st_value; Buf += sizeof(Elf_Sym); } } } for (auto &P : Table.getSymbols()) { StringRef Name = P.first; Symbol *Sym = P.second; SymbolBody *Body = Sym->Body; if (!includeInSymtab(*Body)) continue; const Elf_Sym &InputSym = cast>(Body)->Sym; auto *ESym = reinterpret_cast(Buf); ESym->st_name = StrTabSec.getFileOff(Name); Out = nullptr; Section = nullptr; switch (Body->kind()) { case SymbolBody::DefinedRegularKind: Section = &cast>(Body)->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(Body->getMostConstrainingVisibility()); if (InputSym.isAbsolute()) { ESym->st_shndx = SHN_ABS; ESym->st_value = InputSym.st_value; } if (Section) Out = Section->getOutputSection(); if (Out) { ESym->st_shndx = Out->getSectionIndex(); uintX_t VA = Out->getVA(); if (Section) VA += Section->getOutputSectionOff(); if (auto *C = dyn_cast>(Body)) VA += C->OffsetInBSS; else VA += InputSym.st_value; ESym->st_value = VA; } Buf += sizeof(Elf_Sym); } } 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 typename ELFFile::uintX_t getSymVA(const DefinedRegular *DR); template typename ELFFile::uintX_t getSymVA(const DefinedRegular *DR); template typename ELFFile::uintX_t getSymVA(const DefinedRegular *DR); template typename ELFFile::uintX_t getSymVA(const DefinedRegular *DR); template typename ELFFile::uintX_t lld::elf2::getLocalSymVA(const typename ELFFile::Elf_Sym *Sym, const ObjectFile &File); template typename ELFFile::uintX_t lld::elf2::getLocalSymVA(const typename ELFFile::Elf_Sym *Sym, const ObjectFile &File); template typename ELFFile::uintX_t lld::elf2::getLocalSymVA(const typename ELFFile::Elf_Sym *Sym, const ObjectFile &File); template typename ELFFile::uintX_t lld::elf2::getLocalSymVA(const typename ELFFile::Elf_Sym *Sym, const ObjectFile &File); } }