Changeset View
Changeset View
Standalone View
Standalone View
head/contrib/llvm/tools/lld/ELF/Writer.cpp
Show First 20 Lines • Show All 44 Lines • ▼ Show 20 Lines | public: | ||||
void run(); | void run(); | ||||
private: | private: | ||||
void clearOutputSections(); | void clearOutputSections(); | ||||
void createSyntheticSections(); | void createSyntheticSections(); | ||||
void copyLocalSymbols(); | void copyLocalSymbols(); | ||||
void addSectionSymbols(); | void addSectionSymbols(); | ||||
void addReservedSymbols(); | |||||
void createSections(); | void createSections(); | ||||
void forEachRelSec(std::function<void(InputSectionBase &)> Fn); | void forEachRelSec(std::function<void(InputSectionBase &)> Fn); | ||||
void sortSections(); | void sortSections(); | ||||
void finalizeSections(); | void finalizeSections(); | ||||
void addPredefinedSections(); | void addPredefinedSections(); | ||||
std::vector<PhdrEntry> createPhdrs(); | std::vector<PhdrEntry> createPhdrs(); | ||||
void removeEmptyPTLoad(); | void removeEmptyPTLoad(); | ||||
▲ Show 20 Lines • Show All 101 Lines • ▼ Show 20 Lines | |||||
template <class ELFT> void Writer<ELFT>::run() { | template <class ELFT> void Writer<ELFT>::run() { | ||||
// Create linker-synthesized sections such as .got or .plt. | // Create linker-synthesized sections such as .got or .plt. | ||||
// Such sections are of type input section. | // Such sections are of type input section. | ||||
createSyntheticSections(); | createSyntheticSections(); | ||||
if (!Config->Relocatable) | if (!Config->Relocatable) | ||||
combineEhFrameSections<ELFT>(); | combineEhFrameSections<ELFT>(); | ||||
// We need to create some reserved symbols such as _end. Create them. | |||||
if (!Config->Relocatable) | |||||
addReservedSymbols(); | |||||
// Create output sections. | // Create output sections. | ||||
if (Script->Opt.HasSections) { | if (Script->Opt.HasSections) { | ||||
// If linker script contains SECTIONS commands, let it create sections. | // If linker script contains SECTIONS commands, let it create sections. | ||||
Script->processCommands(Factory); | Script->processCommands(Factory); | ||||
// Linker scripts may have left some input sections unassigned. | // Linker scripts may have left some input sections unassigned. | ||||
// Assign such sections using the default rule. | // Assign such sections using the default rule. | ||||
Script->addOrphanSections(Factory); | Script->addOrphanSections(Factory); | ||||
▲ Show 20 Lines • Show All 98 Lines • ▼ Show 20 Lines | template <class ELFT> void Writer<ELFT>::createSyntheticSections() { | ||||
auto Add = [](InputSectionBase *Sec) { InputSections.push_back(Sec); }; | auto Add = [](InputSectionBase *Sec) { InputSections.push_back(Sec); }; | ||||
InX::DynStrTab = make<StringTableSection>(".dynstr", true); | InX::DynStrTab = make<StringTableSection>(".dynstr", true); | ||||
InX::Dynamic = make<DynamicSection<ELFT>>(); | InX::Dynamic = make<DynamicSection<ELFT>>(); | ||||
In<ELFT>::RelaDyn = make<RelocationSection<ELFT>>( | In<ELFT>::RelaDyn = make<RelocationSection<ELFT>>( | ||||
Config->IsRela ? ".rela.dyn" : ".rel.dyn", Config->ZCombreloc); | Config->IsRela ? ".rela.dyn" : ".rel.dyn", Config->ZCombreloc); | ||||
InX::ShStrTab = make<StringTableSection>(".shstrtab", false); | InX::ShStrTab = make<StringTableSection>(".shstrtab", false); | ||||
Out::ElfHeader = make<OutputSection>("", 0, SHF_ALLOC); | |||||
Out::ElfHeader->Size = sizeof(Elf_Ehdr); | |||||
Out::ProgramHeaders = make<OutputSection>("", 0, SHF_ALLOC); | Out::ProgramHeaders = make<OutputSection>("", 0, SHF_ALLOC); | ||||
Out::ProgramHeaders->updateAlignment(Config->Wordsize); | Out::ProgramHeaders->updateAlignment(Config->Wordsize); | ||||
if (needsInterpSection<ELFT>()) { | if (needsInterpSection<ELFT>()) { | ||||
InX::Interp = createInterpSection(); | InX::Interp = createInterpSection(); | ||||
Add(InX::Interp); | Add(InX::Interp); | ||||
} else { | } else { | ||||
InX::Interp = nullptr; | InX::Interp = nullptr; | ||||
▲ Show 20 Lines • Show All 492 Lines • ▼ Show 20 Lines | template <class ELFT> void Writer<ELFT>::addRelIpltSymbols() { | ||||
addOptionalRegular<ELFT>(S, In<ELFT>::RelaIplt, 0, STV_HIDDEN, STB_WEAK); | addOptionalRegular<ELFT>(S, In<ELFT>::RelaIplt, 0, STV_HIDDEN, STB_WEAK); | ||||
S = Config->IsRela ? "__rela_iplt_end" : "__rel_iplt_end"; | S = Config->IsRela ? "__rela_iplt_end" : "__rel_iplt_end"; | ||||
addOptionalRegular<ELFT>(S, In<ELFT>::RelaIplt, -1, STV_HIDDEN, STB_WEAK); | addOptionalRegular<ELFT>(S, In<ELFT>::RelaIplt, -1, STV_HIDDEN, STB_WEAK); | ||||
} | } | ||||
// The linker is expected to define some symbols depending on | // The linker is expected to define some symbols depending on | ||||
// the linking result. This function defines such symbols. | // the linking result. This function defines such symbols. | ||||
template <class ELFT> void Writer<ELFT>::addReservedSymbols() { | template <class ELFT> void elf::addReservedSymbols() { | ||||
if (Config->EMachine == EM_MIPS) { | if (Config->EMachine == EM_MIPS) { | ||||
// Define _gp for MIPS. st_value of _gp symbol will be updated by Writer | // Define _gp for MIPS. st_value of _gp symbol will be updated by Writer | ||||
// so that it points to an absolute address which by default is relative | // so that it points to an absolute address which by default is relative | ||||
// to GOT. Default offset is 0x7ff0. | // to GOT. Default offset is 0x7ff0. | ||||
// See "Global Data Symbols" in Chapter 6 in the following document: | // See "Global Data Symbols" in Chapter 6 in the following document: | ||||
// ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf | // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf | ||||
ElfSym::MipsGp = Symtab<ELFT>::X->addAbsolute("_gp", STV_HIDDEN, STB_LOCAL); | ElfSym::MipsGp = Symtab<ELFT>::X->addAbsolute("_gp", STV_HIDDEN, STB_LOCAL); | ||||
// On MIPS O32 ABI, _gp_disp is a magic symbol designates offset between | // On MIPS O32 ABI, _gp_disp is a magic symbol designates offset between | ||||
// start of function and 'gp' pointer into GOT. | // start of function and 'gp' pointer into GOT. | ||||
if (Symtab<ELFT>::X->find("_gp_disp")) | if (Symtab<ELFT>::X->find("_gp_disp")) | ||||
ElfSym::MipsGpDisp = | ElfSym::MipsGpDisp = | ||||
Symtab<ELFT>::X->addAbsolute("_gp_disp", STV_HIDDEN, STB_LOCAL); | Symtab<ELFT>::X->addAbsolute("_gp_disp", STV_HIDDEN, STB_LOCAL); | ||||
// The __gnu_local_gp is a magic symbol equal to the current value of 'gp' | // The __gnu_local_gp is a magic symbol equal to the current value of 'gp' | ||||
// pointer. This symbol is used in the code generated by .cpload pseudo-op | // pointer. This symbol is used in the code generated by .cpload pseudo-op | ||||
// in case of using -mno-shared option. | // in case of using -mno-shared option. | ||||
// https://sourceware.org/ml/binutils/2004-12/msg00094.html | // https://sourceware.org/ml/binutils/2004-12/msg00094.html | ||||
if (Symtab<ELFT>::X->find("__gnu_local_gp")) | if (Symtab<ELFT>::X->find("__gnu_local_gp")) | ||||
ElfSym::MipsLocalGp = | ElfSym::MipsLocalGp = | ||||
Symtab<ELFT>::X->addAbsolute("__gnu_local_gp", STV_HIDDEN, STB_LOCAL); | Symtab<ELFT>::X->addAbsolute("__gnu_local_gp", STV_HIDDEN, STB_LOCAL); | ||||
} | } | ||||
// The _GLOBAL_OFFSET_TABLE_ symbol is defined by target convention to | |||||
// be at some offset from the base of the .got section, usually 0 or the end | |||||
// of the .got | |||||
InputSection *GotSection = InX::MipsGot ? cast<InputSection>(InX::MipsGot) | |||||
: cast<InputSection>(InX::Got); | |||||
ElfSym::GlobalOffsetTable = addOptionalRegular<ELFT>( | ElfSym::GlobalOffsetTable = addOptionalRegular<ELFT>( | ||||
"_GLOBAL_OFFSET_TABLE_", GotSection, Target->GotBaseSymOff); | "_GLOBAL_OFFSET_TABLE_", Out::ElfHeader, Target->GotBaseSymOff); | ||||
// __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 (!InX::DynSymTab) | |||||
Symtab<ELFT>::X->addIgnored("__tls_get_addr"); | |||||
// __ehdr_start is the location of ELF file headers. Note that we define | // __ehdr_start is the location of ELF file headers. Note that we define | ||||
// this symbol unconditionally even when using a linker script, which | // this symbol unconditionally even when using a linker script, which | ||||
// differs from the behavior implemented by GNU linker which only define | // differs from the behavior implemented by GNU linker which only define | ||||
// this symbol if ELF headers are in the memory mapped segment. | // this symbol if ELF headers are in the memory mapped segment. | ||||
// __executable_start is not documented, but the expectation of at | // __executable_start is not documented, but the expectation of at | ||||
// least the android libc is that it points to the elf header too. | // least the android libc is that it points to the elf header too. | ||||
// __dso_handle symbol is passed to cxa_finalize as a marker to identify | // __dso_handle symbol is passed to cxa_finalize as a marker to identify | ||||
// each DSO. The address of the symbol doesn't matter as long as they are | // each DSO. The address of the symbol doesn't matter as long as they are | ||||
▲ Show 20 Lines • Show All 870 Lines • ▼ Show 20 Lines | if (Config->Relocatable) | ||||
return ET_REL; | return ET_REL; | ||||
return ET_EXEC; | return ET_EXEC; | ||||
} | } | ||||
// This function is called after we have assigned address and size | // This function is called after we have assigned address and size | ||||
// to each section. This function fixes some predefined | // to each section. This function fixes some predefined | ||||
// symbol values that depend on section address and size. | // symbol values that depend on section address and size. | ||||
template <class ELFT> void Writer<ELFT>::fixPredefinedSymbols() { | template <class ELFT> void Writer<ELFT>::fixPredefinedSymbols() { | ||||
if (ElfSym::GlobalOffsetTable) { | |||||
// The _GLOBAL_OFFSET_TABLE_ symbol is defined by target convention to | |||||
// be at some offset from the base of the .got section, usually 0 or the end | |||||
// of the .got | |||||
InputSection *GotSection = InX::MipsGot ? cast<InputSection>(InX::MipsGot) | |||||
: cast<InputSection>(InX::Got); | |||||
ElfSym::GlobalOffsetTable->Section = GotSection; | |||||
} | |||||
// _etext is the first location after the last read-only loadable segment. | // _etext is the first location after the last read-only loadable segment. | ||||
// _edata is the first location after the last read-write loadable segment. | // _edata is the first location after the last read-write loadable segment. | ||||
// _end is the first location after the uninitialized data region. | // _end is the first location after the uninitialized data region. | ||||
PhdrEntry *Last = nullptr; | PhdrEntry *Last = nullptr; | ||||
PhdrEntry *LastRO = nullptr; | PhdrEntry *LastRO = nullptr; | ||||
PhdrEntry *LastRW = nullptr; | PhdrEntry *LastRW = nullptr; | ||||
for (PhdrEntry &P : Phdrs) { | for (PhdrEntry &P : Phdrs) { | ||||
if (P.p_type != PT_LOAD) | if (P.p_type != PT_LOAD) | ||||
▲ Show 20 Lines • Show All 174 Lines • ▼ Show 20 Lines | template <class ELFT> void Writer<ELFT>::writeBuildId() { | ||||
uint8_t *End = Start + FileSize; | uint8_t *End = Start + FileSize; | ||||
InX::BuildId->writeBuildId({Start, End}); | InX::BuildId->writeBuildId({Start, End}); | ||||
} | } | ||||
template void elf::writeResult<ELF32LE>(); | template void elf::writeResult<ELF32LE>(); | ||||
template void elf::writeResult<ELF32BE>(); | template void elf::writeResult<ELF32BE>(); | ||||
template void elf::writeResult<ELF64LE>(); | template void elf::writeResult<ELF64LE>(); | ||||
template void elf::writeResult<ELF64BE>(); | template void elf::writeResult<ELF64BE>(); | ||||
template void elf::addReservedSymbols<ELF32LE>(); | |||||
template void elf::addReservedSymbols<ELF32BE>(); | |||||
template void elf::addReservedSymbols<ELF64LE>(); | |||||
template void elf::addReservedSymbols<ELF64BE>(); |