blob: b5d3b4d3324efa8aaa968d2af300699a8a155a9c [file] [log] [blame]
//===- lib/ReaderWriter/ELF/WriterELF.cpp ---------------------------------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "lld/ReaderWriter/Writer.h"
#include "DefaultLayout.h"
#include "TargetLayout.h"
#include "ExecutableAtoms.h"
#include "lld/ReaderWriter/ELFTargetInfo.h"
using namespace llvm;
using namespace llvm::object;
namespace lld {
namespace elf {
template<class ELFT>
class ExecutableWriter;
//===----------------------------------------------------------------------===//
// ExecutableWriter Class
//===----------------------------------------------------------------------===//
template<class ELFT>
class ExecutableWriter : public ELFWriter {
public:
typedef Elf_Shdr_Impl<ELFT> Elf_Shdr;
typedef Elf_Sym_Impl<ELFT> Elf_Sym;
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();
llvm::BumpPtrAllocator _alloc;
const ELFTargetInfo &_targetInfo;
TargetHandler<ELFT> &_targetHandler;
typedef llvm::DenseMap<const Atom *, uint64_t> AtomToAddress;
AtomToAddress _atomToAddressMap;
TargetLayout<ELFT> *_layout;
LLD_UNIQUE_BUMP_PTR(Header<ELFT>) _Header;
LLD_UNIQUE_BUMP_PTR(ProgramHeader<ELFT>) _programHeader;
LLD_UNIQUE_BUMP_PTR(SymbolTable<ELFT>) _symtab;
LLD_UNIQUE_BUMP_PTR(StringTable<ELFT>) _strtab;
LLD_UNIQUE_BUMP_PTR(StringTable<ELFT>) _shstrtab;
LLD_UNIQUE_BUMP_PTR(SectionHeader<ELFT>) _shdrtab;
/// \name Dynamic sections.
/// @{
LLD_UNIQUE_BUMP_PTR(DynamicTable<ELFT>) _dynamicTable;
LLD_UNIQUE_BUMP_PTR(DynamicSymbolTable<ELFT>) _dynamicSymbolTable;
LLD_UNIQUE_BUMP_PTR(StringTable<ELFT>) _dynamicStringTable;
LLD_UNIQUE_BUMP_PTR(InterpSection<ELFT>) _interpSection;
LLD_UNIQUE_BUMP_PTR(HashSection<ELFT>) _hashTable;
/// @}
CRuntimeFile<ELFT> _runtimeFile;
};
//===----------------------------------------------------------------------===//
// ExecutableWriter
//===----------------------------------------------------------------------===//
template <class ELFT>
ExecutableWriter<ELFT>::ExecutableWriter(const ELFTargetInfo &ti)
: _targetInfo(ti), _targetHandler(ti.getTargetHandler<ELFT>()),
_runtimeFile(ti) {
_layout = &_targetHandler.targetLayout();
}
template <class ELFT>
void ExecutableWriter<ELFT>::buildChunks(const File &file) {
for (const DefinedAtom *definedAtom : file.defined()) {
_layout->addAtom(definedAtom);
}
for (const AbsoluteAtom *absoluteAtom : file.absolute())
_layout->addAtom(absoluteAtom);
}
template <class ELFT>
void ExecutableWriter<ELFT>::buildStaticSymbolTable(const File &file) {
for (auto sec : _layout->sections())
if (auto section = dyn_cast<AtomSection<ELFT>>(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 <class ELFT>
void ExecutableWriter<ELFT>::buildDynamicSymbolTable(const File &file) {
for (const auto sla : file.sharedLibrary()) {
_dynamicSymbolTable->addSymbol(sla, ELF::SHN_UNDEF);
}
}
template <class ELFT> void ExecutableWriter<ELFT>::buildAtomToAddressMap() {
for (auto sec : _layout->sections())
if (auto section = dyn_cast<AtomSection<ELFT>>(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<class ELFT>
void ExecutableWriter<ELFT>::buildSectionHeaderTable() {
for (auto mergedSec : _layout->mergedSections()) {
if (mergedSec->kind() != Chunk<ELFT>::K_ELFSection &&
mergedSec->kind() != Chunk<ELFT>::K_AtomSection)
continue;
if (mergedSec->hasSegment())
_shdrtab->appendSection(mergedSec);
}
}
template<class ELFT>
void ExecutableWriter<ELFT>::assignSectionsWithNoSegments() {
for (auto mergedSec : _layout->mergedSections()) {
if (mergedSec->kind() != Chunk<ELFT>::K_ELFSection &&
mergedSec->kind() != Chunk<ELFT>::K_AtomSection)
continue;
if (!mergedSec->hasSegment())
_shdrtab->appendSection(mergedSec);
}
_layout->assignOffsetsForMiscSections();
for (auto sec : _layout->sections())
if (auto section = dyn_cast<Section<ELFT>>(sec))
if (!DefaultLayout<ELFT>::hasOutputSegment(section))
_shdrtab->updateSection(section);
}
/// \brief Add absolute symbols by default. These are linker added
/// absolute symbols
template<class ELFT>
void ExecutableWriter<ELFT>::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 <class ELFT>
void ExecutableWriter<ELFT>::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<class ELFT>
void ExecutableWriter<ELFT>::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;
}
template <class ELFT>
error_code ExecutableWriter<ELFT>::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())
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();
uint64_t totalSize = _shdrtab->fileOffset() + _shdrtab->fileSize();
OwningPtr<FileOutputBuffer> 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<class ELFT>
void ExecutableWriter<ELFT>::createDefaultSections() {
_Header.reset(new (_alloc) Header<ELFT>(_targetInfo));
_programHeader.reset(new (_alloc) ProgramHeader<ELFT>(_targetInfo));
_layout->setHeader(_Header.get());
_layout->setProgramHeader(_programHeader.get());
_symtab.reset(new (_alloc) SymbolTable<ELFT>(
_targetInfo, ".symtab", DefaultLayout<ELFT>::ORDER_SYMBOL_TABLE));
_strtab.reset(new (_alloc) StringTable<ELFT>(
_targetInfo, ".strtab", DefaultLayout<ELFT>::ORDER_STRING_TABLE));
_shstrtab.reset(new (_alloc) StringTable<ELFT>(
_targetInfo, ".shstrtab", DefaultLayout<ELFT>::ORDER_SECTION_STRINGS));
_shdrtab.reset(new (_alloc) SectionHeader<ELFT>(
_targetInfo, DefaultLayout<ELFT>::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<ELFT>(
_targetInfo, ".dynamic", DefaultLayout<ELFT>::ORDER_DYNAMIC));
_dynamicStringTable.reset(new (_alloc) StringTable<ELFT>(
_targetInfo, ".dynstr", DefaultLayout<ELFT>::ORDER_DYNAMIC_STRINGS,
true));
_dynamicSymbolTable.reset(new (_alloc) DynamicSymbolTable<ELFT>(
_targetInfo, ".dynsym", DefaultLayout<ELFT>::ORDER_DYNAMIC_SYMBOLS));
_interpSection.reset(new (_alloc) InterpSection<ELFT>(
_targetInfo, ".interp", DefaultLayout<ELFT>::ORDER_INTERP,
_targetInfo.getInterpreter()));
_hashTable.reset(new (_alloc) HashSection<ELFT>(
_targetInfo, ".hash", DefaultLayout<ELFT>::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());
}
// give a chance for the target to add sections
_targetHandler.createDefaultSections();
}
} // namespace elf
std::unique_ptr<Writer> createWriterELF(const ELFTargetInfo &TI) {
using llvm::object::ELFType;
// Set the default layout to be the static executable layout
// We would set the layout to a dynamic executable layout
// if we came across any shared libraries in the process
if (!TI.is64Bits() && TI.isLittleEndian())
return std::unique_ptr<Writer>(new
elf::ExecutableWriter<ELFType<support::little, 4, false>>(TI));
else if (TI.is64Bits() && TI.isLittleEndian())
return std::unique_ptr<Writer>(new
elf::ExecutableWriter<ELFType<support::little, 8, true>>(TI));
else if (!TI.is64Bits() && !TI.isLittleEndian())
return std::unique_ptr<Writer>(new
elf::ExecutableWriter<ELFType<support::big, 4, false>>(TI));
else if (TI.is64Bits() && !TI.isLittleEndian())
return std::unique_ptr<Writer>(new
elf::ExecutableWriter<ELFType<support::big, 8, true>>(TI));
llvm_unreachable("Invalid Options!");
}
} // namespace lld