//===- lib/ReaderWriter/ELF/ExecutableWriter.h ----------------------------===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #ifndef LLD_READER_WRITER_ELF_EXECUTABLE_WRITER_H #define LLD_READER_WRITER_ELF_EXECUTABLE_WRITER_H #include "lld/ReaderWriter/Writer.h" #include "DefaultLayout.h" #include "TargetLayout.h" #include "ExecutableAtoms.h" #include "lld/ReaderWriter/ELFTargetInfo.h" #include "llvm/ADT/StringSet.h" namespace lld { namespace elf { using namespace llvm; using namespace llvm::object; template class ExecutableWriter; //===----------------------------------------------------------------------===// // ExecutableWriter Class //===----------------------------------------------------------------------===// template class ExecutableWriter : public ELFWriter { public: typedef Elf_Shdr_Impl Elf_Shdr; typedef Elf_Sym_Impl Elf_Sym; typedef Elf_Dyn_Impl Elf_Dyn; ExecutableWriter(const ELFTargetInfo &ti); private: // build the sections that need to be created void buildChunks(const File &file); virtual error_code writeFile(const File &File, StringRef path); void buildAtomToAddressMap(); void buildStaticSymbolTable(const File &file); void buildDynamicSymbolTable(const File &file); void buildSectionHeaderTable(); void assignSectionsWithNoSegments(); void addDefaultAtoms(); void addFiles(InputFiles&); void finalizeDefaultAtomValues(); uint64_t addressOfAtom(const Atom *atom) { return _atomToAddressMap[atom]; } void createDefaultSections(); void createDefaultDynamicEntries() {} llvm::BumpPtrAllocator _alloc; const ELFTargetInfo &_targetInfo; TargetHandler &_targetHandler; typedef llvm::DenseMap AtomToAddress; AtomToAddress _atomToAddressMap; TargetLayout *_layout; LLD_UNIQUE_BUMP_PTR(Header) _Header; LLD_UNIQUE_BUMP_PTR(ProgramHeader) _programHeader; LLD_UNIQUE_BUMP_PTR(SymbolTable) _symtab; LLD_UNIQUE_BUMP_PTR(StringTable) _strtab; LLD_UNIQUE_BUMP_PTR(StringTable) _shstrtab; LLD_UNIQUE_BUMP_PTR(SectionHeader) _shdrtab; /// \name Dynamic sections. /// @{ LLD_UNIQUE_BUMP_PTR(DynamicTable) _dynamicTable; LLD_UNIQUE_BUMP_PTR(DynamicSymbolTable) _dynamicSymbolTable; LLD_UNIQUE_BUMP_PTR(StringTable) _dynamicStringTable; LLD_UNIQUE_BUMP_PTR(InterpSection) _interpSection; LLD_UNIQUE_BUMP_PTR(HashSection) _hashTable; llvm::StringSet<> _soNeeded; /// @} CRuntimeFile _runtimeFile; }; //===----------------------------------------------------------------------===// // ExecutableWriter //===----------------------------------------------------------------------===// template ExecutableWriter::ExecutableWriter(const ELFTargetInfo &ti) : _targetInfo(ti), _targetHandler(ti.getTargetHandler()), _runtimeFile(ti) { _layout = &_targetHandler.targetLayout(); } template void ExecutableWriter::buildChunks(const File &file) { for (const DefinedAtom *definedAtom : file.defined()) { _layout->addAtom(definedAtom); } for (const AbsoluteAtom *absoluteAtom : file.absolute()) _layout->addAtom(absoluteAtom); } template void ExecutableWriter::buildStaticSymbolTable(const File &file) { for (auto sec : _layout->sections()) if (auto section = dyn_cast>(sec)) for (const auto &atom : section->atoms()) _symtab->addSymbol(atom->_atom, section->ordinal(), atom->_virtualAddr); for (auto &atom : _layout->absoluteAtoms()) _symtab->addSymbol(atom->_atom, ELF::SHN_ABS, atom->_virtualAddr); for (const UndefinedAtom *a : file.undefined()) _symtab->addSymbol(a, ELF::SHN_UNDEF); } template void ExecutableWriter::buildDynamicSymbolTable(const File &file) { for (const auto sla : file.sharedLibrary()) { _dynamicSymbolTable->addSymbol(sla, ELF::SHN_UNDEF); _soNeeded.insert(sla->loadName()); } for (const auto &loadName : _soNeeded) { Elf_Dyn dyn; dyn.d_tag = DT_NEEDED; dyn.d_un.d_val = _dynamicStringTable->addString(loadName.getKey()); _dynamicTable->addEntry(dyn); } } template void ExecutableWriter::buildAtomToAddressMap() { for (auto sec : _layout->sections()) if (auto section = dyn_cast>(sec)) for (const auto &atom : section->atoms()) _atomToAddressMap[atom->_atom] = atom->_virtualAddr; // build the atomToAddressMap that contains absolute symbols too for (auto &atom : _layout->absoluteAtoms()) _atomToAddressMap[atom->_atom] = atom->_virtualAddr; } template void ExecutableWriter::buildSectionHeaderTable() { for (auto mergedSec : _layout->mergedSections()) { if (mergedSec->kind() != Chunk::K_ELFSection && mergedSec->kind() != Chunk::K_AtomSection) continue; if (mergedSec->hasSegment()) _shdrtab->appendSection(mergedSec); } } template void ExecutableWriter::assignSectionsWithNoSegments() { for (auto mergedSec : _layout->mergedSections()) { if (mergedSec->kind() != Chunk::K_ELFSection && mergedSec->kind() != Chunk::K_AtomSection) continue; if (!mergedSec->hasSegment()) _shdrtab->appendSection(mergedSec); } _layout->assignOffsetsForMiscSections(); for (auto sec : _layout->sections()) if (auto section = dyn_cast>(sec)) if (!DefaultLayout::hasOutputSegment(section)) _shdrtab->updateSection(section); } /// \brief Add absolute symbols by default. These are linker added /// absolute symbols template void ExecutableWriter::addDefaultAtoms() { _runtimeFile.addUndefinedAtom(_targetInfo.getEntry()); _runtimeFile.addAbsoluteAtom("__bss_start"); _runtimeFile.addAbsoluteAtom("__bss_end"); _runtimeFile.addAbsoluteAtom("_end"); _runtimeFile.addAbsoluteAtom("end"); _runtimeFile.addAbsoluteAtom("__preinit_array_start"); _runtimeFile.addAbsoluteAtom("__preinit_array_end"); _runtimeFile.addAbsoluteAtom("__init_array_start"); _runtimeFile.addAbsoluteAtom("__init_array_end"); _runtimeFile.addAbsoluteAtom("__rela_iplt_start"); _runtimeFile.addAbsoluteAtom("__rela_iplt_end"); _runtimeFile.addAbsoluteAtom("__fini_array_start"); _runtimeFile.addAbsoluteAtom("__fini_array_end"); } /// \brief Hook in lld to add CRuntime file template void ExecutableWriter::addFiles(InputFiles &inputFiles) { addDefaultAtoms(); inputFiles.prependFile(_runtimeFile); // Give a chance for the target to add atoms _targetHandler.addFiles(inputFiles); } /// Finalize the value of all the absolute symbols that we /// created template void ExecutableWriter::finalizeDefaultAtomValues() { auto bssStartAtomIter = _layout->findAbsoluteAtom("__bss_start"); auto bssEndAtomIter = _layout->findAbsoluteAtom("__bss_end"); auto underScoreEndAtomIter = _layout->findAbsoluteAtom("_end"); auto endAtomIter = _layout->findAbsoluteAtom("end"); auto startEnd = [&](StringRef sym, StringRef sec) -> void { // TODO: This looks like a good place to use Twine... std::string start("__"), end("__"); start += sym; start += "_start"; end += sym; end += "_end"; auto s = _layout->findAbsoluteAtom(start); auto e = _layout->findAbsoluteAtom(end); auto section = _layout->findOutputSection(sec); if (section) { (*s)->_virtualAddr = section->virtualAddr(); (*e)->_virtualAddr = section->virtualAddr() + section->memSize(); } else { (*s)->_virtualAddr = 0; (*e)->_virtualAddr = 0; } }; startEnd("preinit_array", ".preinit_array"); startEnd("init_array", ".init_array"); startEnd("rela_iplt", ".rela.plt"); startEnd("fini_array", ".fini_array"); assert(!(bssStartAtomIter == _layout->absoluteAtoms().end() || bssEndAtomIter == _layout->absoluteAtoms().end() || underScoreEndAtomIter == _layout->absoluteAtoms().end() || endAtomIter == _layout->absoluteAtoms().end()) && "Unable to find the absolute atoms that have been added by lld"); auto phe = _programHeader->findProgramHeader( llvm::ELF::PT_LOAD, llvm::ELF::PF_W, llvm::ELF::PF_X); assert(!(phe == _programHeader->end()) && "Can't find a data segment in the program header!"); (*bssStartAtomIter)->_virtualAddr = (*phe)->p_vaddr + (*phe)->p_filesz; (*bssEndAtomIter)->_virtualAddr = (*phe)->p_vaddr + (*phe)->p_memsz; (*underScoreEndAtomIter)->_virtualAddr = (*phe)->p_vaddr + (*phe)->p_memsz; (*endAtomIter)->_virtualAddr = (*phe)->p_vaddr + (*phe)->p_memsz; // Give a chance for the target to finalize its atom values _targetHandler.finalizeSymbolValues(); } template error_code ExecutableWriter::writeFile(const File &file, StringRef path) { buildChunks(file); // Call the preFlight callbacks to modify the sections and the atoms // contained in them, in anyway the targets may want _layout->doPreFlight(); // Create the default sections like the symbol table, string table, and the // section string table createDefaultSections(); if (_targetInfo.isDynamic()) { _dynamicTable->createDefaultEntries(); buildDynamicSymbolTable(file); } // Set the Layout _layout->assignSectionsToSegments(); _layout->assignFileOffsets(); _layout->assignVirtualAddress(); // Finalize the default value of symbols that the linker adds finalizeDefaultAtomValues(); // Build the Atom To Address map for applying relocations buildAtomToAddressMap(); // Create symbol table and section string table buildStaticSymbolTable(file); // Finalize the layout by calling the finalize() functions _layout->finalize(); // build Section Header table buildSectionHeaderTable(); // assign Offsets and virtual addresses // for sections with no segments assignSectionsWithNoSegments(); if (_targetInfo.isDynamic()) _dynamicTable->updateDynamicTable(_hashTable.get(), _dynamicSymbolTable.get()); uint64_t totalSize = _shdrtab->fileOffset() + _shdrtab->fileSize(); OwningPtr buffer; error_code ec = FileOutputBuffer::create(path, totalSize, buffer, FileOutputBuffer::F_executable); if (ec) return ec; _Header->e_ident(ELF::EI_CLASS, _targetInfo.is64Bits() ? ELF::ELFCLASS64 : ELF::ELFCLASS32); _Header->e_ident(ELF::EI_DATA, _targetInfo.isLittleEndian() ? ELF::ELFDATA2LSB : ELF::ELFDATA2MSB); _Header->e_type(_targetInfo.getOutputType()); _Header->e_machine(_targetInfo.getOutputMachine()); if (!_targetHandler.doesOverrideHeader()) { _Header->e_ident(ELF::EI_VERSION, 1); _Header->e_ident(ELF::EI_OSABI, 0); _Header->e_version(1); } else { // override the contents of the ELF Header _targetHandler.setHeaderInfo(_Header.get()); } _Header->e_phoff(_programHeader->fileOffset()); _Header->e_shoff(_shdrtab->fileOffset()); _Header->e_phentsize(_programHeader->entsize()); _Header->e_phnum(_programHeader->numHeaders()); _Header->e_shentsize(_shdrtab->entsize()); _Header->e_shnum(_shdrtab->numHeaders()); _Header->e_shstrndx(_shstrtab->ordinal()); uint64_t virtualAddr = 0; _layout->findAtomAddrByName(_targetInfo.getEntry(), virtualAddr); _Header->e_entry(virtualAddr); // HACK: We have to write out the header and program header here even though // they are a member of a segment because only sections are written in the // following loop. _Header->write(this, *buffer); _programHeader->write(this, *buffer); for (auto section : _layout->sections()) section->write(this, *buffer); return buffer->commit(); } template void ExecutableWriter::createDefaultSections() { _Header.reset(new (_alloc) Header(_targetInfo)); _programHeader.reset(new (_alloc) ProgramHeader(_targetInfo)); _layout->setHeader(_Header.get()); _layout->setProgramHeader(_programHeader.get()); _symtab.reset(new (_alloc) SymbolTable( _targetInfo, ".symtab", DefaultLayout::ORDER_SYMBOL_TABLE)); _strtab.reset(new (_alloc) StringTable( _targetInfo, ".strtab", DefaultLayout::ORDER_STRING_TABLE)); _shstrtab.reset(new (_alloc) StringTable( _targetInfo, ".shstrtab", DefaultLayout::ORDER_SECTION_STRINGS)); _shdrtab.reset(new (_alloc) SectionHeader( _targetInfo, DefaultLayout::ORDER_SECTION_HEADERS)); _layout->addSection(_symtab.get()); _layout->addSection(_strtab.get()); _layout->addSection(_shstrtab.get()); _shdrtab->setStringSection(_shstrtab.get()); _symtab->setStringSection(_strtab.get()); _layout->addSection(_shdrtab.get()); if (_targetInfo.isDynamic()) { _dynamicTable.reset(new (_alloc) DynamicTable( _targetInfo, ".dynamic", DefaultLayout::ORDER_DYNAMIC)); _dynamicStringTable.reset(new (_alloc) StringTable( _targetInfo, ".dynstr", DefaultLayout::ORDER_DYNAMIC_STRINGS, true)); _dynamicSymbolTable.reset(new (_alloc) DynamicSymbolTable( _targetInfo, ".dynsym", DefaultLayout::ORDER_DYNAMIC_SYMBOLS)); _interpSection.reset(new (_alloc) InterpSection( _targetInfo, ".interp", DefaultLayout::ORDER_INTERP, _targetInfo.getInterpreter())); _hashTable.reset(new (_alloc) HashSection( _targetInfo, ".hash", DefaultLayout::ORDER_HASH)); _layout->addSection(_dynamicTable.get()); _layout->addSection(_dynamicStringTable.get()); _layout->addSection(_dynamicSymbolTable.get()); _layout->addSection(_interpSection.get()); _layout->addSection(_hashTable.get()); _dynamicSymbolTable->setStringSection(_dynamicStringTable.get()); if (_layout->hasDynamicRelocationTable()) _layout->getDynamicRelocationTable()->setSymbolTable( _dynamicSymbolTable.get()); if (_layout->hasPLTRelocationTable()) _layout->getPLTRelocationTable()->setSymbolTable( _dynamicSymbolTable.get()); } // give a chance for the target to add sections _targetHandler.createDefaultSections(); } } // namespace elf } // namespace lld #endif // LLD_READER_WRITER_ELF_EXECUTABLE_WRITER_H