//===- lib/ReaderWriter/ELF/OutputELFWriter.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_OUTPUT_WRITER_H #define LLD_READER_WRITER_ELF_OUTPUT_WRITER_H #include "DefaultLayout.h" #include "ELFFile.h" #include "TargetLayout.h" #include "lld/Core/Instrumentation.h" #include "lld/Core/Parallel.h" #include "lld/ReaderWriter/ELFLinkingContext.h" #include "lld/ReaderWriter/Writer.h" #include "llvm/ADT/StringSet.h" namespace lld { namespace elf { using namespace llvm; using namespace llvm::object; template class OutputELFWriter; template class TargetLayout; //===----------------------------------------------------------------------===// // OutputELFWriter Class //===----------------------------------------------------------------------===// /// \brief This acts as the base class for all the ELF writers that are output /// for emitting an ELF output file. This class also acts as a common class for /// creating static and dynamic executables. All the function in this class /// can be overridden and an appropriate writer be created template class OutputELFWriter : public ELFWriter { public: typedef Elf_Shdr_Impl Elf_Shdr; typedef Elf_Sym_Impl Elf_Sym; typedef Elf_Dyn_Impl Elf_Dyn; OutputELFWriter(const ELFLinkingContext &context, TargetLayout &layout); protected: // build the sections that need to be created virtual void createDefaultSections(); // Build all the output sections void buildChunks(const File &file) override; // Build the output file virtual error_code buildOutput(const File &file); // Setup the ELF header. virtual error_code setELFHeader(); // Write the file to the path specified error_code writeFile(const File &File, StringRef path) override; // Write to the output file. virtual error_code writeOutput(const File &file, StringRef path); // Get the size of the output file that the linker would emit. virtual uint64_t outputFileSize() const; // Build the atom to address map, this has to be called // before applying relocations virtual void buildAtomToAddressMap(const File &file); // Build the symbol table for static linking virtual void buildStaticSymbolTable(const File &file); // Build the dynamic symbol table for dynamic linking virtual void buildDynamicSymbolTable(const File &file); // Build the section header table virtual void buildSectionHeaderTable(); // Assign sections that have no segments such as the symbol table, // section header table, string table etc virtual void assignSectionsWithNoSegments(); // Add default atoms that need to be present in the output file virtual void addDefaultAtoms() = 0; // Add any runtime files and their atoms to the output bool createImplicitFiles(std::vector> &) override; // Finalize the default atom values virtual void finalizeDefaultAtomValues() = 0; // This is called by the write section to apply relocations uint64_t addressOfAtom(const Atom *atom) override { auto addr = _atomToAddressMap.find(atom); return addr == _atomToAddressMap.end() ? 0 : addr->second; } // This is a hook for creating default dynamic entries virtual void createDefaultDynamicEntries() {} /// \brief create dynamic table. virtual LLD_UNIQUE_BUMP_PTR(DynamicTable) createDynamicTable(); /// \brief create dynamic symbol table. virtual LLD_UNIQUE_BUMP_PTR(DynamicSymbolTable) createDynamicSymbolTable(); llvm::BumpPtrAllocator _alloc; const ELFLinkingContext &_context; TargetHandler &_targetHandler; typedef llvm::DenseMap AtomToAddress; AtomToAddress _atomToAddressMap; TargetLayout &_layout; LLD_UNIQUE_BUMP_PTR(ELFHeader) _elfHeader; 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; LLD_UNIQUE_BUMP_PTR(EHFrameHeader) _ehFrameHeader; /// \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(HashSection) _hashTable; llvm::StringSet<> _soNeeded; /// @} }; //===----------------------------------------------------------------------===// // OutputELFWriter //===----------------------------------------------------------------------===// template OutputELFWriter::OutputELFWriter(const ELFLinkingContext &context, TargetLayout &layout) : _context(context), _targetHandler(context.getTargetHandler()), _layout(layout) {} template void OutputELFWriter::buildChunks(const File &file) { ScopedTask task(getDefaultDomain(), "buildChunks"); for (const DefinedAtom *definedAtom : file.defined()) { _layout.addAtom(definedAtom); } for (const AbsoluteAtom *absoluteAtom : file.absolute()) _layout.addAtom(absoluteAtom); } template void OutputELFWriter::buildStaticSymbolTable(const File &file) { ScopedTask task(getDefaultDomain(), "buildStaticSymbolTable"); 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 OutputELFWriter::buildDynamicSymbolTable(const File &file) { ScopedTask task(getDefaultDomain(), "buildDynamicSymbolTable"); for (auto sec : this->_layout.sections()) if (auto section = dyn_cast>(sec)) for (const auto &atom : section->atoms()) { const DefinedAtom *da = dyn_cast(atom->_atom); if (da && da->dynamicExport() == DefinedAtom::dynamicExportAlways) _dynamicSymbolTable->addSymbol(atom->_atom, section->ordinal(), atom->_virtualAddr, atom); } 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); } const auto &rpathList = _context.getRpathList(); if (!rpathList.empty()) { auto rpath = new (_alloc) std::string(join(rpathList.begin(), rpathList.end(), ":")); Elf_Dyn dyn; dyn.d_tag = DT_RPATH; dyn.d_un.d_val = _dynamicStringTable->addString(*rpath); _dynamicTable->addEntry(dyn); } StringRef soname = _context.sharedObjectName(); if (!soname.empty() && _context.getOutputELFType() == llvm::ELF::ET_DYN) { Elf_Dyn dyn; dyn.d_tag = DT_SONAME; dyn.d_un.d_val = _dynamicStringTable->addString(soname); _dynamicTable->addEntry(dyn); } // The dynamic symbol table need to be sorted earlier because the hash // table needs to be built using the dynamic symbol table. It would be // late to sort the symbols due to that in finalize. In the dynamic symbol // table finalize, we call the symbol table finalize and we don't want to // sort again _dynamicSymbolTable->sortSymbols(); // Add the dynamic symbols into the hash table _dynamicSymbolTable->addSymbolsToHashTable(); } template void OutputELFWriter::buildAtomToAddressMap(const File &file) { ScopedTask task(getDefaultDomain(), "buildAtomToAddressMap"); int64_t totalAbsAtoms = _layout.absoluteAtoms().size(); int64_t totalUndefinedAtoms = file.undefined().size(); int64_t totalDefinedAtoms = 0; for (auto sec : _layout.sections()) if (auto section = dyn_cast >(sec)) { totalDefinedAtoms += section->atoms().size(); 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; // Set the total number of atoms in the symbol table, so that appropriate // resizing of the string table can be done _symtab->setNumEntries(totalDefinedAtoms + totalAbsAtoms + totalUndefinedAtoms); } template void OutputELFWriter::buildSectionHeaderTable() { ScopedTask task(getDefaultDomain(), "buildSectionHeaderTable"); for (auto mergedSec : _layout.mergedSections()) { if (mergedSec->kind() != Chunk::Kind::ELFSection && mergedSec->kind() != Chunk::Kind::AtomSection) continue; if (mergedSec->hasSegment()) _shdrtab->appendSection(mergedSec); } } template void OutputELFWriter::assignSectionsWithNoSegments() { ScopedTask task(getDefaultDomain(), "assignSectionsWithNoSegments"); for (auto mergedSec : _layout.mergedSections()) { if (mergedSec->kind() != Chunk::Kind::ELFSection && mergedSec->kind() != Chunk::Kind::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); } template bool OutputELFWriter::createImplicitFiles( std::vector> &) { return true; } template void OutputELFWriter::createDefaultSections() { _elfHeader.reset(new (_alloc) ELFHeader(_context)); _programHeader.reset(new (_alloc) ProgramHeader(_context)); _layout.setHeader(_elfHeader.get()); _layout.setProgramHeader(_programHeader.get()); _symtab.reset(new (_alloc) SymbolTable( _context, ".symtab", DefaultLayout::ORDER_SYMBOL_TABLE)); _strtab.reset(new (_alloc) StringTable( _context, ".strtab", DefaultLayout::ORDER_STRING_TABLE)); _shstrtab.reset(new (_alloc) StringTable( _context, ".shstrtab", DefaultLayout::ORDER_SECTION_STRINGS)); _shdrtab.reset(new (_alloc) SectionHeader( _context, 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()); for (auto sec : _layout.sections()) { if (sec->name() != ".eh_frame") continue; _ehFrameHeader.reset(new (_alloc) EHFrameHeader( _context, ".eh_frame_hdr", _layout, DefaultLayout::ORDER_EH_FRAMEHDR)); _layout.addSection(_ehFrameHeader.get()); break; } if (_context.isDynamic()) { _dynamicTable = std::move(createDynamicTable()); _dynamicStringTable.reset(new (_alloc) StringTable( _context, ".dynstr", DefaultLayout::ORDER_DYNAMIC_STRINGS, true)); _dynamicSymbolTable = std::move(createDynamicSymbolTable()); _hashTable.reset(new (_alloc) HashSection( _context, ".hash", DefaultLayout::ORDER_HASH)); // Set the hash table in the dynamic symbol table so that the entries in the // hash table can be created _dynamicSymbolTable->setHashTable(_hashTable.get()); _hashTable->setSymbolTable(_dynamicSymbolTable.get()); _layout.addSection(_dynamicTable.get()); _layout.addSection(_dynamicStringTable.get()); _layout.addSection(_dynamicSymbolTable.get()); _layout.addSection(_hashTable.get()); _dynamicSymbolTable->setStringSection(_dynamicStringTable.get()); _dynamicTable->setSymbolTable(_dynamicSymbolTable.get()); _dynamicTable->setHashTable(_hashTable.get()); if (_layout.hasDynamicRelocationTable()) _layout.getDynamicRelocationTable()->setSymbolTable( _dynamicSymbolTable.get()); if (_layout.hasPLTRelocationTable()) _layout.getPLTRelocationTable()->setSymbolTable( _dynamicSymbolTable.get()); } } /// \brief create dynamic table template LLD_UNIQUE_BUMP_PTR(DynamicTable) OutputELFWriter::createDynamicTable() { return LLD_UNIQUE_BUMP_PTR( DynamicTable)(new (_alloc) DynamicTable( this->_context, _layout, ".dynamic", DefaultLayout::ORDER_DYNAMIC)); } /// \brief create dynamic symbol table template LLD_UNIQUE_BUMP_PTR(DynamicSymbolTable) OutputELFWriter::createDynamicSymbolTable() { return LLD_UNIQUE_BUMP_PTR( DynamicSymbolTable)(new (_alloc) DynamicSymbolTable( this->_context, _layout, ".dynsym", DefaultLayout::ORDER_DYNAMIC_SYMBOLS)); } template error_code OutputELFWriter::buildOutput(const File &file) { ScopedTask buildTask(getDefaultDomain(), "ELF Writer buildOutput"); buildChunks(file); // Create the default sections like the symbol table, string table, and the // section string table createDefaultSections(); // Set the Layout _layout.assignSectionsToSegments(); // Create the dynamic table entries if (_context.isDynamic()) { _dynamicTable->createDefaultEntries(); buildDynamicSymbolTable(file); } // Call the preFlight callbacks to modify the sections and the atoms // contained in them, in anyway the targets may want _layout.doPreFlight(); _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(file); // 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 (_context.isDynamic()) _dynamicTable->updateDynamicTable(); return error_code::success(); } template error_code OutputELFWriter::setELFHeader() { _elfHeader->e_ident(ELF::EI_CLASS, _context.is64Bits() ? ELF::ELFCLASS64 : ELF::ELFCLASS32); _elfHeader->e_ident(ELF::EI_DATA, _context.isLittleEndian() ? ELF::ELFDATA2LSB : ELF::ELFDATA2MSB); _elfHeader->e_type(_context.getOutputELFType()); _elfHeader->e_machine(_context.getOutputMachine()); _elfHeader->e_ident(ELF::EI_VERSION, 1); _elfHeader->e_ident(ELF::EI_OSABI, 0); _elfHeader->e_version(1); _elfHeader->e_phoff(_programHeader->fileOffset()); _elfHeader->e_shoff(_shdrtab->fileOffset()); _elfHeader->e_phentsize(_programHeader->entsize()); _elfHeader->e_phnum(_programHeader->numHeaders()); _elfHeader->e_shentsize(_shdrtab->entsize()); _elfHeader->e_shnum(_shdrtab->numHeaders()); _elfHeader->e_shstrndx(_shstrtab->ordinal()); uint64_t virtualAddr = 0; _layout.findAtomAddrByName(_context.entrySymbolName(), virtualAddr); _elfHeader->e_entry(virtualAddr); return error_code::success(); } template uint64_t OutputELFWriter::outputFileSize() const { return _shdrtab->fileOffset() + _shdrtab->fileSize(); } template error_code OutputELFWriter::writeOutput(const File &file, StringRef path) { std::unique_ptr buffer; ScopedTask createOutputTask(getDefaultDomain(), "ELF Writer Create Output"); error_code ec = FileOutputBuffer::create(path, outputFileSize(), buffer, FileOutputBuffer::F_executable); createOutputTask.end(); if (ec) return ec; ScopedTask writeTask(getDefaultDomain(), "ELF Writer write to memory"); // 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. _elfHeader->write(this, _layout, *buffer); _programHeader->write(this, _layout, *buffer); for (auto section : _layout.sections()) section->write(this, _layout, *buffer); writeTask.end(); ScopedTask commitTask(getDefaultDomain(), "ELF Writer commit to disk"); return buffer->commit(); } template error_code OutputELFWriter::writeFile(const File &file, StringRef path) { error_code ec = buildOutput(file); if (ec) return ec; ec = setELFHeader(); if (ec) return ec; return writeOutput(file, path); } } // namespace elf } // namespace lld #endif // LLD_READER_WRITER_ELF_OUTPUT_WRITER_H