//===- Writer.cpp ---------------------------------------------------------===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "Writer.h" #include "Config.h" #include "OutputSections.h" #include "SymbolTable.h" #include "Target.h" #include "llvm/Support/FileOutputBuffer.h" using namespace llvm; using namespace llvm::ELF; using namespace llvm::object; using namespace lld; using namespace lld::elf2; namespace { static uint32_t toPHDRFlags(uint64_t Flags) { uint32_t Ret = PF_R; if (Flags & SHF_WRITE) Ret |= PF_W; if (Flags & SHF_EXECINSTR) Ret |= PF_X; return Ret; } template struct ProgramHeader { typedef typename ELFFile::uintX_t uintX_t; typedef typename ELFFile::Elf_Phdr Elf_Phdr; ProgramHeader(uintX_t Type, uintX_t Flags, uintX_t FileOff, uintX_t VA) { std::memset(&Header, 0, sizeof(Elf_Phdr)); Header.p_type = Type; Header.p_flags = Flags; Header.p_align = Target->getPageSize(); Header.p_offset = FileOff; Header.p_vaddr = VA; Header.p_paddr = VA; } void setValuesFromSection(OutputSectionBase *Sec) { Header.p_flags = toPHDRFlags(Sec->getFlags()); Header.p_offset = Sec->getFileOff(); Header.p_vaddr = Sec->getVA(); Header.p_paddr = Header.p_vaddr; Header.p_filesz = Sec->getSize(); Header.p_memsz = Header.p_filesz; Header.p_align = Sec->getAlign(); } Elf_Phdr Header; bool Closed = false; }; // The writer writes a SymbolTable result to a file. template class Writer { public: typedef typename ELFFile::uintX_t uintX_t; typedef typename ELFFile::Elf_Shdr Elf_Shdr; typedef typename ELFFile::Elf_Ehdr Elf_Ehdr; typedef typename ELFFile::Elf_Phdr Elf_Phdr; typedef typename ELFFile::Elf_Sym Elf_Sym; typedef typename ELFFile::Elf_Sym_Range Elf_Sym_Range; typedef typename ELFFile::Elf_Rela Elf_Rela; Writer(SymbolTable &S) : Symtab(S) {} void run(); private: void copyLocalSymbols(); void createSections(); template void scanRelocs(const InputSection &C, iterator_range *> Rels); void scanRelocs(const InputSection &C); void assignAddresses(); void openFile(StringRef OutputPath); void writeHeader(); void writeSections(); bool needsInterpSection() const { return !Symtab.getSharedFiles().empty() && !Config->DynamicLinker.empty(); } bool isOutputDynamic() const { return !Symtab.getSharedFiles().empty() || Config->Shared; } bool needsDynamicSections() const { return isOutputDynamic(); } uintX_t getVAStart() const { return Config->Shared ? 0 : Target->getVAStart(); } std::unique_ptr Buffer; llvm::SpecificBumpPtrAllocator> CAlloc; std::vector *> OutputSections; unsigned getNumSections() const { return OutputSections.size() + 1; } llvm::BumpPtrAllocator PAlloc; SymbolTable &Symtab; std::vector *> PHDRs; ProgramHeader FileHeaderPHDR{PT_LOAD, PF_R, 0, 0}; ProgramHeader InterpPHDR{PT_INTERP, 0, 0, 0}; ProgramHeader DynamicPHDR{PT_DYNAMIC, 0, 0, 0}; uintX_t FileSize; uintX_t ProgramHeaderOff; uintX_t SectionHeaderOff; }; } // anonymous namespace template static void doWriteResult(SymbolTable *Symtab) { // Initialize output sections that are handled by Writer specially. // Don't reorder because the order of initialization matters. InterpSection Interp; Out::Interp = &Interp; StringTableSection StrTab(false); Out::StrTab = &StrTab; StringTableSection DynStrTab(true); Out::DynStrTab = &DynStrTab; OutputSection Bss(".bss", SHT_NOBITS, SHF_ALLOC | SHF_WRITE); Out::Bss = &Bss; GotSection Got; Out::Got = &Got; PltSection Plt; Out::Plt = &Plt; SymbolTableSection SymTab(*Symtab, *Out::StrTab); Out::SymTab = &SymTab; SymbolTableSection DynSymTab(*Symtab, *Out::DynStrTab); Out::DynSymTab = &DynSymTab; HashTableSection HashTab; Out::HashTab = &HashTab; RelocationSection RelaDyn(Symtab->shouldUseRela()); Out::RelaDyn = &RelaDyn; DynamicSection Dynamic(*Symtab); Out::Dynamic = &Dynamic; Writer(*Symtab).run(); } void lld::elf2::writeResult(SymbolTable *Symtab) { switch (Symtab->getFirstELF()->getELFKind()) { case ELF32LEKind: doWriteResult(Symtab); return; case ELF32BEKind: doWriteResult(Symtab); return; case ELF64LEKind: doWriteResult(Symtab); return; case ELF64BEKind: doWriteResult(Symtab); return; default: llvm_unreachable("Invalid kind"); } } // The main function of the writer. template void Writer::run() { if (!Config->DiscardAll) copyLocalSymbols(); createSections(); assignAddresses(); openFile(Config->OutputFile); writeHeader(); writeSections(); error(Buffer->commit()); } namespace { template struct SectionKey { typedef typename std::conditional::type uintX_t; StringRef Name; uint32_t Type; uintX_t Flags; }; } namespace llvm { template struct DenseMapInfo> { static SectionKey getEmptyKey() { return SectionKey{DenseMapInfo::getEmptyKey(), 0, 0}; } static SectionKey getTombstoneKey() { return SectionKey{DenseMapInfo::getTombstoneKey(), 0, 0}; } static unsigned getHashValue(const SectionKey &Val) { return hash_combine(Val.Name, Val.Type, Val.Flags); } static bool isEqual(const SectionKey &LHS, const SectionKey &RHS) { return DenseMapInfo::isEqual(LHS.Name, RHS.Name) && LHS.Type == RHS.Type && LHS.Flags == RHS.Flags; } }; } // The reason we have to do this early scan is as follows // * To mmap the output file, we need to know the size // * For that, we need to know how many dynamic relocs we will have. // It might be possible to avoid this by outputting the file with write: // * Write the allocated output sections, computing addresses. // * Apply relocations, recording which ones require a dynamic reloc. // * Write the dynamic relocations. // * Write the rest of the file. template template void Writer::scanRelocs( const InputSection &C, iterator_range *> Rels) { typedef Elf_Rel_Impl RelType; const ObjectFile &File = *C.getFile(); bool IsMips64EL = File.getObj().isMips64EL(); for (const RelType &RI : Rels) { uint32_t SymIndex = RI.getSymbol(IsMips64EL); SymbolBody *Body = File.getSymbolBody(SymIndex); uint32_t Type = RI.getType(IsMips64EL); if (Body) { if (Target->relocNeedsPlt(Type, *Body)) { if (Body->isInPlt()) continue; Out::Plt->addEntry(Body); } if (Target->relocNeedsGot(Type, *Body)) { if (Body->isInGot()) continue; Out::Got->addEntry(Body); } } if (canBePreempted(Body)) { Body->setUsedInDynamicReloc(); Out::RelaDyn->addReloc({C, RI}); } else if (Config->Shared && !Target->isRelRelative(Type)) { Out::RelaDyn->addReloc({C, RI}); } } } template void Writer::scanRelocs(const InputSection &C) { ObjectFile *File = C.getFile(); ELFFile &EObj = File->getObj(); if (!(C.getSectionHdr()->sh_flags & SHF_ALLOC)) return; for (const Elf_Shdr *RelSec : C.RelocSections) { if (RelSec->sh_type == SHT_RELA) scanRelocs(C, EObj.relas(RelSec)); else scanRelocs(C, EObj.rels(RelSec)); } } template static void reportUndefined(const SymbolTable &S, const SymbolBody &Sym) { typedef typename ELFFile::Elf_Sym Elf_Sym; typedef typename ELFFile::Elf_Sym_Range Elf_Sym_Range; if (Config->Shared && !Config->NoUndefined) return; const Elf_Sym &SymE = cast>(Sym).Sym; ELFFileBase *SymFile = nullptr; for (const std::unique_ptr &F : S.getObjectFiles()) { const auto &File = cast>(*F); Elf_Sym_Range Syms = File.getObj().symbols(File.getSymbolTable()); if (&SymE > Syms.begin() && &SymE < Syms.end()) SymFile = F.get(); } std::string Message = "undefined symbol: " + Sym.getName().str(); if (SymFile) Message += " in " + SymFile->getName().str(); if (Config->NoInhibitExec) warning(Message); else error(Message); } // Local symbols are not in the linker's symbol table. This function scans // each object file's symbol table to copy local symbols to the output. template void Writer::copyLocalSymbols() { for (const std::unique_ptr &FileB : Symtab.getObjectFiles()) { auto &File = cast>(*FileB); for (const Elf_Sym &Sym : File.getLocalSymbols()) { ErrorOr SymNameOrErr = Sym.getName(File.getStringTable()); error(SymNameOrErr); StringRef SymName = *SymNameOrErr; if (shouldKeepInSymtab(SymName, Sym)) Out::SymTab->addSymbol(SymName, true); } } } // Output section ordering is determined by this function. template static bool compareOutputSections(OutputSectionBase *A, OutputSectionBase *B) { typedef typename ELFFile::uintX_t uintX_t; uintX_t AFlags = A->getFlags(); uintX_t BFlags = B->getFlags(); // Allocatable sections go first to reduce the total PT_LOAD size and // so debug info doesn't change addresses in actual code. bool AIsAlloc = AFlags & SHF_ALLOC; bool BIsAlloc = BFlags & SHF_ALLOC; if (AIsAlloc != BIsAlloc) return AIsAlloc; // We don't have any special requirements for the relative order of // two non allocatable sections. if (!AIsAlloc) return false; // We want the read only sections first so that they go in the PT_LOAD // covering the program headers at the start of the file. bool AIsWritable = AFlags & SHF_WRITE; bool BIsWritable = BFlags & SHF_WRITE; if (AIsWritable != BIsWritable) return BIsWritable; // For a corresponding reason, put non exec sections first (the program // header PT_LOAD is not executable). bool AIsExec = AFlags & SHF_EXECINSTR; bool BIsExec = BFlags & SHF_EXECINSTR; if (AIsExec != BIsExec) return BIsExec; // If we got here we know that both A and B and in the same PT_LOAD. // The last requirement we have is to put nobits section last. The // reason is that the only thing the dynamic linker will see about // them is a p_memsz that is larger than p_filesz. Seeing that it // zeros the end of the PT_LOAD, so that has to correspond to the // nobits sections. return A->getType() != SHT_NOBITS && B->getType() == SHT_NOBITS; } // Until this function is called, common symbols do not belong to any section. // This function adds them to end of BSS section. template static void addCommonSymbols(std::vector *> &Syms) { typedef typename ELFFile::uintX_t uintX_t; typedef typename ELFFile::Elf_Sym Elf_Sym; // Sort the common symbols by alignment as an heuristic to pack them better. std::stable_sort( Syms.begin(), Syms.end(), [](const DefinedCommon *A, const DefinedCommon *B) { return A->MaxAlignment > B->MaxAlignment; }); uintX_t Off = Out::Bss->getSize(); for (DefinedCommon *C : Syms) { const Elf_Sym &Sym = C->Sym; uintX_t Align = C->MaxAlignment; Off = RoundUpToAlignment(Off, Align); C->OffsetInBSS = Off; Off += Sym.st_size; } Out::Bss->setSize(Off); } // Create output section objects and add them to OutputSections. template void Writer::createSections() { SmallDenseMap, OutputSection *> Map; OutputSections.push_back(Out::Bss); Map[{Out::Bss->getName(), Out::Bss->getType(), Out::Bss->getFlags()}] = Out::Bss; // Declare linker generated symbols. // This must be done before the relocation scan to make sure we can correctly // decide if a dynamic relocation is needed or not. // FIXME: Make this more declarative. for (StringRef Name : {"__preinit_array_start", "__preinit_array_end", "__init_array_start", "__init_array_end", "__fini_array_start", "__fini_array_end"}) Symtab.addIgnoredSym(Name); // __tls_get_addr is defined by the dynamic linker for dynamic ELFs. For // static linking the linker is required to optimize away any references to // __tls_get_addr, so it's not defined anywhere. Create a hidden definition // to avoid the undefined symbol error. if (!isOutputDynamic()) Symtab.addIgnoredSym("__tls_get_addr"); for (const std::unique_ptr &FileB : Symtab.getObjectFiles()) { auto &File = cast>(*FileB); for (InputSection *C : File.getSections()) { if (!C) continue; const Elf_Shdr *H = C->getSectionHdr(); SectionKey Key{C->getSectionName(), H->sh_type, H->sh_flags}; OutputSection *&Sec = Map[Key]; if (!Sec) { Sec = new (CAlloc.Allocate()) OutputSection(Key.Name, Key.Type, Key.Flags); OutputSections.push_back(Sec); } Sec->addSection(C); scanRelocs(*C); } } Out::Dynamic->PreInitArraySec = Map.lookup({".preinit_array", SHT_PREINIT_ARRAY, SHF_WRITE | SHF_ALLOC}); Out::Dynamic->InitArraySec = Map.lookup({".init_array", SHT_INIT_ARRAY, SHF_WRITE | SHF_ALLOC}); Out::Dynamic->FiniArraySec = Map.lookup({".fini_array", SHT_FINI_ARRAY, SHF_WRITE | SHF_ALLOC}); auto AddStartEnd = [&](StringRef Start, StringRef End, OutputSection *OS) { if (OS) { Symtab.addSyntheticSym(Start, *OS, 0); Symtab.addSyntheticSym(End, *OS, OS->getSize()); } }; AddStartEnd("__preinit_array_start", "__preinit_array_end", Out::Dynamic->PreInitArraySec); AddStartEnd("__init_array_start", "__init_array_end", Out::Dynamic->InitArraySec); AddStartEnd("__fini_array_start", "__fini_array_end", Out::Dynamic->FiniArraySec); // FIXME: Try to avoid the extra walk over all global symbols. std::vector *> CommonSymbols; for (auto &P : Symtab.getSymbols()) { StringRef Name = P.first; SymbolBody *Body = P.second->Body; if (auto *U = dyn_cast>(Body)) { if (!U->isWeak() && !U->canKeepUndefined()) reportUndefined(Symtab, *Body); } if (auto *C = dyn_cast>(Body)) CommonSymbols.push_back(C); if (!includeInSymtab(*Body)) continue; Out::SymTab->addSymbol(Name); if (needsDynamicSections() && includeInDynamicSymtab(*Body)) Out::HashTab->addSymbol(Body); } addCommonSymbols(CommonSymbols); OutputSections.push_back(Out::SymTab); if (needsDynamicSections()) { if (needsInterpSection()) OutputSections.push_back(Out::Interp); OutputSections.push_back(Out::DynSymTab); OutputSections.push_back(Out::HashTab); OutputSections.push_back(Out::Dynamic); OutputSections.push_back(Out::DynStrTab); if (Out::RelaDyn->hasRelocs()) OutputSections.push_back(Out::RelaDyn); } if (!Out::Got->empty()) OutputSections.push_back(Out::Got); if (!Out::Plt->empty()) OutputSections.push_back(Out::Plt); std::stable_sort(OutputSections.begin(), OutputSections.end(), compareOutputSections); // Always put StrTabSec last so that no section names are added to it after // it's finalized. OutputSections.push_back(Out::StrTab); for (unsigned I = 0, N = OutputSections.size(); I < N; ++I) OutputSections[I]->setSectionIndex(I + 1); // Fill the DynStrTab early. Out::Dynamic->finalize(); } template static bool needsPHDR(OutputSectionBase *Sec) { return Sec->getFlags() & SHF_ALLOC; } // Visits all sections to assign incremental, non-overlapping RVAs and // file offsets. template void Writer::assignAddresses() { assert(!OutputSections.empty() && "No output sections to layout!"); uintX_t VA = getVAStart(); uintX_t FileOff = 0; FileOff += sizeof(Elf_Ehdr); VA += sizeof(Elf_Ehdr); // Reserve space for PHDRs. ProgramHeaderOff = FileOff; FileOff = RoundUpToAlignment(FileOff, Target->getPageSize()); VA = RoundUpToAlignment(VA, Target->getPageSize()); if (needsInterpSection()) PHDRs.push_back(&InterpPHDR); // Create a PHDR for the file header. PHDRs.push_back(&FileHeaderPHDR); FileHeaderPHDR.Header.p_vaddr = getVAStart(); FileHeaderPHDR.Header.p_paddr = getVAStart(); FileHeaderPHDR.Header.p_align = Target->getPageSize(); for (OutputSectionBase *Sec : OutputSections) { Out::StrTab->add(Sec->getName()); Sec->finalize(); if (Sec->getSize()) { uintX_t Flags = toPHDRFlags(Sec->getFlags()); ProgramHeader *Last = PHDRs.back(); if (Last->Header.p_flags != Flags || !needsPHDR(Sec)) { // Flags changed. End current PHDR and potentially create a new one. if (!Last->Closed) { Last->Header.p_filesz = FileOff - Last->Header.p_offset; Last->Header.p_memsz = VA - Last->Header.p_vaddr; Last->Closed = true; } if (needsPHDR(Sec)) { VA = RoundUpToAlignment(VA, Target->getPageSize()); FileOff = RoundUpToAlignment(FileOff, Target->getPageSize()); PHDRs.push_back(new (PAlloc) ProgramHeader(PT_LOAD, Flags, FileOff, VA)); } } } uintX_t Align = Sec->getAlign(); uintX_t Size = Sec->getSize(); if (Sec->getFlags() & SHF_ALLOC) { VA = RoundUpToAlignment(VA, Align); Sec->setVA(VA); VA += Size; } FileOff = RoundUpToAlignment(FileOff, Align); Sec->setFileOffset(FileOff); if (Sec->getType() != SHT_NOBITS) FileOff += Size; } // Add a PHDR for the dynamic table. if (needsDynamicSections()) PHDRs.push_back(&DynamicPHDR); FileOff += OffsetToAlignment(FileOff, ELFT::Is64Bits ? 8 : 4); // Add space for section headers. SectionHeaderOff = FileOff; FileOff += getNumSections() * sizeof(Elf_Shdr); FileSize = FileOff; } template void Writer::writeHeader() { uint8_t *Buf = Buffer->getBufferStart(); auto *EHdr = reinterpret_cast(Buf); EHdr->e_ident[EI_MAG0] = 0x7F; EHdr->e_ident[EI_MAG1] = 0x45; EHdr->e_ident[EI_MAG2] = 0x4C; EHdr->e_ident[EI_MAG3] = 0x46; EHdr->e_ident[EI_CLASS] = ELFT::Is64Bits ? ELFCLASS64 : ELFCLASS32; EHdr->e_ident[EI_DATA] = ELFT::TargetEndianness == llvm::support::little ? ELFDATA2LSB : ELFDATA2MSB; EHdr->e_ident[EI_VERSION] = EV_CURRENT; auto &FirstObj = cast>(*Symtab.getFirstELF()); EHdr->e_ident[EI_OSABI] = FirstObj.getOSABI(); // FIXME: Generalize the segment construction similar to how we create // output sections. EHdr->e_type = Config->Shared ? ET_DYN : ET_EXEC; EHdr->e_machine = FirstObj.getEMachine(); EHdr->e_version = EV_CURRENT; SymbolBody *Entry = Symtab.getEntrySym(); EHdr->e_entry = Entry ? getSymVA(cast>(*Entry)) : 0; EHdr->e_phoff = ProgramHeaderOff; EHdr->e_shoff = SectionHeaderOff; EHdr->e_ehsize = sizeof(Elf_Ehdr); EHdr->e_phentsize = sizeof(Elf_Phdr); EHdr->e_phnum = PHDRs.size(); EHdr->e_shentsize = sizeof(Elf_Shdr); EHdr->e_shnum = getNumSections(); EHdr->e_shstrndx = Out::StrTab->getSectionIndex(); // If nothing was merged into the file header PT_LOAD, set the size correctly. if (FileHeaderPHDR.Header.p_filesz == Target->getPageSize()) { uint64_t Size = sizeof(Elf_Ehdr) + sizeof(Elf_Phdr) * PHDRs.size(); FileHeaderPHDR.Header.p_filesz = Size; FileHeaderPHDR.Header.p_memsz = Size; } if (needsInterpSection()) InterpPHDR.setValuesFromSection(Out::Interp); if (needsDynamicSections()) DynamicPHDR.setValuesFromSection(Out::Dynamic); auto PHdrs = reinterpret_cast(Buf + EHdr->e_phoff); for (ProgramHeader *PHDR : PHDRs) *PHdrs++ = PHDR->Header; auto SHdrs = reinterpret_cast(Buf + EHdr->e_shoff); // First entry is null. ++SHdrs; for (OutputSectionBase *Sec : OutputSections) { Sec->setNameOffset(Out::StrTab->getFileOff(Sec->getName())); Sec->template writeHeaderTo(SHdrs++); } } template void Writer::openFile(StringRef Path) { ErrorOr> BufferOrErr = FileOutputBuffer::create(Path, FileSize, FileOutputBuffer::F_executable); error(BufferOrErr, Twine("failed to open ") + Path); Buffer = std::move(*BufferOrErr); } // Write section contents to a mmap'ed file. template void Writer::writeSections() { uint8_t *Buf = Buffer->getBufferStart(); for (OutputSectionBase *Sec : OutputSections) Sec->writeTo(Buf + Sec->getFileOff()); }