Please use GitHub pull requests for new patches. Phabricator shutdown timeline
Changeset View
Changeset View
Standalone View
Standalone View
lld/ELF/Writer.cpp
Show First 20 Lines • Show All 55 Lines • ▼ Show 20 Lines | private: | ||||
void sortSections(); | void sortSections(); | ||||
void resolveShfLinkOrder(); | void resolveShfLinkOrder(); | ||||
void finalizeAddressDependentContent(); | void finalizeAddressDependentContent(); | ||||
void sortInputSections(); | void sortInputSections(); | ||||
void finalizeSections(); | void finalizeSections(); | ||||
void checkExecuteOnly(); | void checkExecuteOnly(); | ||||
void setReservedSymbolSections(); | void setReservedSymbolSections(); | ||||
std::vector<PhdrEntry *> createPhdrs(); | std::vector<PhdrEntry *> createPhdrs(Partition &Part); | ||||
void removeEmptyPTLoad(); | void removeEmptyPTLoad(std::vector<PhdrEntry *> &PhdrEntry); | ||||
void addPhdrForSection(std::vector<PhdrEntry *> &Phdrs, unsigned ShType, | void addPhdrForSection(Partition &Part, unsigned ShType, unsigned PType, | ||||
unsigned PType, unsigned PFlags); | unsigned PFlags); | ||||
void assignFileOffsets(); | void assignFileOffsets(); | ||||
void assignFileOffsetsBinary(); | void assignFileOffsetsBinary(); | ||||
void setPhdrs(); | void setPhdrs(Partition &Part); | ||||
void checkSections(); | void checkSections(); | ||||
void fixSectionAlignments(); | void fixSectionAlignments(); | ||||
void openFile(); | void openFile(); | ||||
void writeTrapInstr(); | void writeTrapInstr(); | ||||
void writeHeader(); | void writeHeader(); | ||||
void writeSections(); | void writeSections(); | ||||
void writeSectionsBinary(); | void writeSectionsBinary(); | ||||
void writeBuildId(); | void writeBuildId(); | ||||
std::unique_ptr<FileOutputBuffer> &Buffer; | std::unique_ptr<FileOutputBuffer> &Buffer; | ||||
void addRelIpltSymbols(); | void addRelIpltSymbols(); | ||||
void addStartEndSymbols(); | void addStartEndSymbols(); | ||||
void addStartStopSymbols(OutputSection *Sec); | void addStartStopSymbols(OutputSection *Sec); | ||||
std::vector<PhdrEntry *> Phdrs; | |||||
uint64_t FileSize; | uint64_t FileSize; | ||||
uint64_t SectionHeaderOff; | uint64_t SectionHeaderOff; | ||||
}; | }; | ||||
} // anonymous namespace | } // anonymous namespace | ||||
static bool isSectionPrefix(StringRef Prefix, StringRef Name) { | static bool isSectionPrefix(StringRef Prefix, StringRef Name) { | ||||
return Name.startswith(Prefix) || Name == Prefix.drop_back(); | return Name.startswith(Prefix) || Name == Prefix.drop_back(); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 42 Lines • ▼ Show 20 Lines | |||||
} | } | ||||
static bool needsInterpSection() { | static bool needsInterpSection() { | ||||
return !Config->DynamicLinker.empty() && Script->needsInterpSection(); | return !Config->DynamicLinker.empty() && Script->needsInterpSection(); | ||||
} | } | ||||
template <class ELFT> void elf::writeResult() { Writer<ELFT>().run(); } | template <class ELFT> void elf::writeResult() { Writer<ELFT>().run(); } | ||||
template <class ELFT> void Writer<ELFT>::removeEmptyPTLoad() { | template <class ELFT> | ||||
void Writer<ELFT>::removeEmptyPTLoad(std::vector<PhdrEntry *> &Phdrs) { | |||||
llvm::erase_if(Phdrs, [&](const PhdrEntry *P) { | llvm::erase_if(Phdrs, [&](const PhdrEntry *P) { | ||||
if (P->p_type != PT_LOAD) | if (P->p_type != PT_LOAD) | ||||
return false; | return false; | ||||
if (!P->FirstSec) | if (!P->FirstSec) | ||||
return true; | return true; | ||||
uint64_t Size = P->LastSec->Addr + P->LastSec->Size - P->FirstSec->Addr; | uint64_t Size = P->LastSec->Addr + P->LastSec->Size - P->FirstSec->Addr; | ||||
return Size == 0; | return Size == 0; | ||||
}); | }); | ||||
} | } | ||||
template <class ELFT> static void copySectionsIntoPartitions() { | |||||
std::vector<InputSectionBase *> NewSections; | |||||
for (unsigned Part = 2; Part != Partitions.size() + 1; ++Part) { | |||||
for (InputSectionBase *S : InputSections) { | |||||
if (!(S->Flags & SHF_ALLOC) || !S->isLive()) | |||||
continue; | |||||
InputSectionBase *Copy; | |||||
if (S->Type == SHT_NOTE) | |||||
Copy = make<InputSection>(cast<InputSection>(*S)); | |||||
else if (auto *ES = dyn_cast<EhInputSection>(S)) | |||||
Copy = make<EhInputSection>(*ES); | |||||
else | |||||
continue; | |||||
Copy->Partition = Part; | |||||
NewSections.push_back(Copy); | |||||
} | |||||
} | |||||
InputSections.insert(InputSections.end(), NewSections.begin(), | |||||
NewSections.end()); | |||||
} | |||||
template <class ELFT> static void combineEhSections() { | template <class ELFT> static void combineEhSections() { | ||||
for (InputSectionBase *&S : InputSections) { | for (InputSectionBase *&S : InputSections) { | ||||
if (!S->isLive()) | if (!S->isLive()) | ||||
continue; | continue; | ||||
Partition &Part = S->getPartition(); | |||||
if (auto *ES = dyn_cast<EhInputSection>(S)) { | if (auto *ES = dyn_cast<EhInputSection>(S)) { | ||||
In.EhFrame->addSection<ELFT>(ES); | Part.EhFrame->addSection<ELFT>(ES); | ||||
S = nullptr; | S = nullptr; | ||||
} else if (S->kind() == SectionBase::Regular && In.ARMExidx && | } else if (S->kind() == SectionBase::Regular && Part.ARMExidx && | ||||
In.ARMExidx->addSection(cast<InputSection>(S))) { | Part.ARMExidx->addSection(cast<InputSection>(S))) { | ||||
S = nullptr; | S = nullptr; | ||||
} | } | ||||
} | } | ||||
std::vector<InputSectionBase *> &V = InputSections; | std::vector<InputSectionBase *> &V = InputSections; | ||||
V.erase(std::remove(V.begin(), V.end(), nullptr), V.end()); | V.erase(std::remove(V.begin(), V.end(), nullptr), V.end()); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 93 Lines • ▼ Show 20 Lines | void elf::addReservedSymbols() { | ||||
ElfSym::End1 = Add("end", -1); | ElfSym::End1 = Add("end", -1); | ||||
ElfSym::End2 = Add("_end", -1); | ElfSym::End2 = Add("_end", -1); | ||||
ElfSym::Etext1 = Add("etext", -1); | ElfSym::Etext1 = Add("etext", -1); | ||||
ElfSym::Etext2 = Add("_etext", -1); | ElfSym::Etext2 = Add("_etext", -1); | ||||
ElfSym::Edata1 = Add("edata", -1); | ElfSym::Edata1 = Add("edata", -1); | ||||
ElfSym::Edata2 = Add("_edata", -1); | ElfSym::Edata2 = Add("_edata", -1); | ||||
} | } | ||||
static OutputSection *findSection(StringRef Name) { | static OutputSection *findSection(StringRef Name, unsigned Partition = 1) { | ||||
for (BaseCommand *Base : Script->SectionCommands) | for (BaseCommand *Base : Script->SectionCommands) | ||||
if (auto *Sec = dyn_cast<OutputSection>(Base)) | if (auto *Sec = dyn_cast<OutputSection>(Base)) | ||||
if (Sec->Name == Name) | if (Sec->Name == Name && Sec->Partition == Partition) | ||||
return Sec; | return Sec; | ||||
return nullptr; | return nullptr; | ||||
} | } | ||||
// Initialize Out members. | // Initialize Out members. | ||||
template <class ELFT> static void createSyntheticSections() { | template <class ELFT> static void createSyntheticSections() { | ||||
// Initialize all pointers with NULL. This is needed because | // Initialize all pointers with NULL. This is needed because | ||||
// you can call lld::elf::main more than once as a library. | // you can call lld::elf::main more than once as a library. | ||||
memset(&Out::First, 0, sizeof(Out)); | memset(&Out::First, 0, sizeof(Out)); | ||||
auto Add = [](InputSectionBase *Sec) { InputSections.push_back(Sec); }; | auto Add = [](InputSectionBase *Sec) { InputSections.push_back(Sec); }; | ||||
In.DynStrTab = make<StringTableSection>(".dynstr", true); | |||||
In.Dynamic = make<DynamicSection<ELFT>>(); | |||||
if (Config->AndroidPackDynRelocs) { | |||||
In.RelaDyn = make<AndroidPackedRelocationSection<ELFT>>( | |||||
Config->IsRela ? ".rela.dyn" : ".rel.dyn"); | |||||
} else { | |||||
In.RelaDyn = make<RelocationSection<ELFT>>( | |||||
Config->IsRela ? ".rela.dyn" : ".rel.dyn", Config->ZCombreloc); | |||||
} | |||||
In.ShStrTab = make<StringTableSection>(".shstrtab", false); | In.ShStrTab = make<StringTableSection>(".shstrtab", false); | ||||
Out::ProgramHeaders = make<OutputSection>("", 0, SHF_ALLOC); | Out::ProgramHeaders = make<OutputSection>("", 0, SHF_ALLOC); | ||||
Out::ProgramHeaders->Alignment = Config->Wordsize; | Out::ProgramHeaders->Alignment = Config->Wordsize; | ||||
if (needsInterpSection()) | |||||
Add(createInterpSection()); | |||||
if (Config->Strip != StripPolicy::All) { | if (Config->Strip != StripPolicy::All) { | ||||
In.StrTab = make<StringTableSection>(".strtab", false); | In.StrTab = make<StringTableSection>(".strtab", false); | ||||
In.SymTab = make<SymbolTableSection<ELFT>>(*In.StrTab); | In.SymTab = make<SymbolTableSection<ELFT>>(*In.StrTab); | ||||
In.SymTabShndx = make<SymtabShndxSection>(); | In.SymTabShndx = make<SymtabShndxSection>(); | ||||
} | } | ||||
if (Config->BuildId != BuildIdKind::None) { | |||||
In.BuildId = make<BuildIdSection>(); | |||||
Add(In.BuildId); | |||||
} | |||||
In.Bss = make<BssSection>(".bss", 0, 1); | In.Bss = make<BssSection>(".bss", 0, 1); | ||||
Add(In.Bss); | Add(In.Bss); | ||||
// If there is a SECTIONS command and a .data.rel.ro section name use name | // If there is a SECTIONS command and a .data.rel.ro section name use name | ||||
// .data.rel.ro.bss so that we match in the .data.rel.ro output section. | // .data.rel.ro.bss so that we match in the .data.rel.ro output section. | ||||
// This makes sure our relro is contiguous. | // This makes sure our relro is contiguous. | ||||
bool HasDataRelRo = Script->HasSectionsCommand && findSection(".data.rel.ro"); | bool HasDataRelRo = | ||||
Script->HasSectionsCommand && findSection(".data.rel.ro", 0); | |||||
In.BssRelRo = | In.BssRelRo = | ||||
make<BssSection>(HasDataRelRo ? ".data.rel.ro.bss" : ".bss.rel.ro", 0, 1); | make<BssSection>(HasDataRelRo ? ".data.rel.ro.bss" : ".bss.rel.ro", 0, 1); | ||||
Add(In.BssRelRo); | Add(In.BssRelRo); | ||||
// Add MIPS-specific sections. | // Add MIPS-specific sections. | ||||
if (Config->EMachine == EM_MIPS) { | if (Config->EMachine == EM_MIPS) { | ||||
if (!Config->Shared && Config->HasDynSymTab) { | if (!Config->Shared && Config->HasDynSymTab) { | ||||
In.MipsRldMap = make<MipsRldMapSection>(); | In.MipsRldMap = make<MipsRldMapSection>(); | ||||
Add(In.MipsRldMap); | Add(In.MipsRldMap); | ||||
} | } | ||||
if (auto *Sec = MipsAbiFlagsSection<ELFT>::create()) | if (auto *Sec = MipsAbiFlagsSection<ELFT>::create()) | ||||
Add(Sec); | Add(Sec); | ||||
if (auto *Sec = MipsOptionsSection<ELFT>::create()) | if (auto *Sec = MipsOptionsSection<ELFT>::create()) | ||||
Add(Sec); | Add(Sec); | ||||
if (auto *Sec = MipsReginfoSection<ELFT>::create()) | if (auto *Sec = MipsReginfoSection<ELFT>::create()) | ||||
Add(Sec); | Add(Sec); | ||||
} | } | ||||
for (Partition &Part : Partitions) { | |||||
auto Add = [&](InputSectionBase *Sec) { | |||||
Sec->Partition = Part.getNumber(); | |||||
InputSections.push_back(Sec); | |||||
}; | |||||
if (!Part.Name.empty()) { | |||||
Part.ElfHeader = make<PartitionElfHeaderSection<ELFT>>(); | |||||
Part.ElfHeader->Name = Part.Name; | |||||
Add(Part.ElfHeader); | |||||
Part.ProgramHeaders = make<PartitionProgramHeadersSection<ELFT>>(); | |||||
Add(Part.ProgramHeaders); | |||||
} | |||||
if (Config->BuildId != BuildIdKind::None) { | |||||
Part.BuildId = make<BuildIdSection>(); | |||||
Add(Part.BuildId); | |||||
} | |||||
Part.DynStrTab = make<StringTableSection>(".dynstr", true); | |||||
Part.DynSymTab = make<SymbolTableSection<ELFT>>(*Part.DynStrTab); | |||||
Part.Dynamic = make<DynamicSection<ELFT>>(); | |||||
if (Config->AndroidPackDynRelocs) { | |||||
Part.RelaDyn = make<AndroidPackedRelocationSection<ELFT>>( | |||||
Config->IsRela ? ".rela.dyn" : ".rel.dyn"); | |||||
} else { | |||||
Part.RelaDyn = make<RelocationSection<ELFT>>( | |||||
Config->IsRela ? ".rela.dyn" : ".rel.dyn", Config->ZCombreloc); | |||||
} | |||||
if (needsInterpSection()) | |||||
Add(createInterpSection()); | |||||
if (Config->HasDynSymTab) { | if (Config->HasDynSymTab) { | ||||
In.DynSymTab = make<SymbolTableSection<ELFT>>(*In.DynStrTab); | Part.DynSymTab = make<SymbolTableSection<ELFT>>(*Part.DynStrTab); | ||||
Add(In.DynSymTab); | Add(Part.DynSymTab); | ||||
In.VerSym = make<VersionTableSection>(); | Part.VerSym = make<VersionTableSection>(); | ||||
Add(In.VerSym); | Add(Part.VerSym); | ||||
if (!Config->VersionDefinitions.empty()) { | if (!Config->VersionDefinitions.empty()) { | ||||
In.VerDef = make<VersionDefinitionSection>(); | Part.VerDef = make<VersionDefinitionSection>(); | ||||
Add(In.VerDef); | Add(Part.VerDef); | ||||
} | } | ||||
In.VerNeed = make<VersionNeedSection<ELFT>>(); | Part.VerNeed = make<VersionNeedSection<ELFT>>(); | ||||
Add(In.VerNeed); | Add(Part.VerNeed); | ||||
if (Config->GnuHash) { | if (Config->GnuHash) { | ||||
In.GnuHashTab = make<GnuHashTableSection>(); | Part.GnuHashTab = make<GnuHashTableSection>(); | ||||
Add(In.GnuHashTab); | Add(Part.GnuHashTab); | ||||
} | } | ||||
if (Config->SysvHash) { | if (Config->SysvHash) { | ||||
In.HashTab = make<HashTableSection>(); | Part.HashTab = make<HashTableSection>(); | ||||
Add(In.HashTab); | Add(Part.HashTab); | ||||
} | } | ||||
Add(In.Dynamic); | Add(Part.Dynamic); | ||||
Add(In.DynStrTab); | Add(Part.DynStrTab); | ||||
Add(In.RelaDyn); | Add(Part.RelaDyn); | ||||
} | } | ||||
if (Config->RelrPackDynRelocs) { | if (Config->RelrPackDynRelocs) { | ||||
In.RelrDyn = make<RelrSection<ELFT>>(); | Part.RelrDyn = make<RelrSection<ELFT>>(); | ||||
Add(In.RelrDyn); | Add(Part.RelrDyn); | ||||
} | |||||
if (!Config->Relocatable) { | |||||
if (Config->EhFrameHdr) { | |||||
Part.EhFrameHdr = make<EhFrameHeader>(); | |||||
Add(Part.EhFrameHdr); | |||||
} | |||||
Part.EhFrame = make<EhFrameSection>(); | |||||
Add(Part.EhFrame); | |||||
} | |||||
if (Config->EMachine == EM_ARM && !Config->Relocatable) { | |||||
// The ARMExidxsyntheticsection replaces all the individual .ARM.exidx | |||||
// InputSections. | |||||
Part.ARMExidx = make<ARMExidxSyntheticSection>(); | |||||
Add(Part.ARMExidx); | |||||
} | |||||
} | |||||
if (Partitions.size() != 1) { | |||||
// Create the partition end marker. This needs to be in partition number 255 | |||||
// so that it is sorted after all other partitions. It also has other | |||||
// special handling (see createPhdrs()). | |||||
In.PartEnd = make<BssSection>(".part.end", Config->MaxPageSize, 1); | |||||
In.PartEnd->Partition = 255; | |||||
Add(In.PartEnd); | |||||
In.PartIndex = make<PartitionIndexSection>(); | |||||
addOptionalRegular("__part_index_begin", In.PartIndex, 0); | |||||
addOptionalRegular("__part_index_end", In.PartIndex, | |||||
In.PartIndex->getSize()); | |||||
Add(In.PartIndex); | |||||
} | } | ||||
// Add .got. MIPS' .got is so different from the other archs, | // Add .got. MIPS' .got is so different from the other archs, | ||||
// it has its own class. | // it has its own class. | ||||
if (Config->EMachine == EM_MIPS) { | if (Config->EMachine == EM_MIPS) { | ||||
In.MipsGot = make<MipsGotSection>(); | In.MipsGot = make<MipsGotSection>(); | ||||
Add(In.MipsGot); | Add(In.MipsGot); | ||||
} else { | } else { | ||||
▲ Show 20 Lines • Show All 50 Lines • ▼ Show 20 Lines | template <class ELFT> static void createSyntheticSections() { | ||||
// .note.GNU-stack is always added when we are creating a re-linkable | // .note.GNU-stack is always added when we are creating a re-linkable | ||||
// object file. Other linkers are using the presence of this marker | // object file. Other linkers are using the presence of this marker | ||||
// section to control the executable-ness of the stack area, but that | // section to control the executable-ness of the stack area, but that | ||||
// is irrelevant these days. Stack area should always be non-executable | // is irrelevant these days. Stack area should always be non-executable | ||||
// by default. So we emit this section unconditionally. | // by default. So we emit this section unconditionally. | ||||
if (Config->Relocatable) | if (Config->Relocatable) | ||||
Add(make<GnuStackSection>()); | Add(make<GnuStackSection>()); | ||||
if (!Config->Relocatable) { | |||||
if (Config->EhFrameHdr) { | |||||
In.EhFrameHdr = make<EhFrameHeader>(); | |||||
Add(In.EhFrameHdr); | |||||
} | |||||
In.EhFrame = make<EhFrameSection>(); | |||||
Add(In.EhFrame); | |||||
} | |||||
if (In.SymTab) | if (In.SymTab) | ||||
Add(In.SymTab); | Add(In.SymTab); | ||||
if (In.SymTabShndx) | if (In.SymTabShndx) | ||||
Add(In.SymTabShndx); | Add(In.SymTabShndx); | ||||
Add(In.ShStrTab); | Add(In.ShStrTab); | ||||
if (In.StrTab) | if (In.StrTab) | ||||
Add(In.StrTab); | Add(In.StrTab); | ||||
if (Config->EMachine == EM_ARM && !Config->Relocatable) { | |||||
// The ARMExidxsyntheticsection replaces all the individual .ARM.exidx | |||||
// InputSections. | |||||
In.ARMExidx = make<ARMExidxSyntheticSection>(); | |||||
Add(In.ARMExidx); | |||||
} | |||||
} | } | ||||
// The main function of the writer. | // The main function of the writer. | ||||
template <class ELFT> void Writer<ELFT>::run() { | template <class ELFT> void Writer<ELFT>::run() { | ||||
// Make copies of any input sections that need to be copied into each | |||||
// partition. | |||||
copySectionsIntoPartitions<ELFT>(); | |||||
// 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<ELFT>(); | createSyntheticSections<ELFT>(); | ||||
// Some input sections that are used for exception handling need to be moved | // Some input sections that are used for exception handling need to be moved | ||||
// into synthetic sections. Do that now so that they aren't assigned to | // into synthetic sections. Do that now so that they aren't assigned to | ||||
// output sections in the usual way. | // output sections in the usual way. | ||||
if (!Config->Relocatable) | if (!Config->Relocatable) | ||||
Show All 26 Lines | template <class ELFT> void Writer<ELFT>::run() { | ||||
Script->assignAddresses(); | Script->assignAddresses(); | ||||
// If -compressed-debug-sections is specified, we need to compress | // If -compressed-debug-sections is specified, we need to compress | ||||
// .debug_* sections. Do it right now because it changes the size of | // .debug_* sections. Do it right now because it changes the size of | ||||
// output sections. | // output sections. | ||||
for (OutputSection *Sec : OutputSections) | for (OutputSection *Sec : OutputSections) | ||||
Sec->maybeCompress<ELFT>(); | Sec->maybeCompress<ELFT>(); | ||||
Script->allocateHeaders(Phdrs); | Script->allocateHeaders(Main->Phdrs); | ||||
// Remove empty PT_LOAD to avoid causing the dynamic linker to try to mmap a | // Remove empty PT_LOAD to avoid causing the dynamic linker to try to mmap a | ||||
// 0 sized region. This has to be done late since only after assignAddresses | // 0 sized region. This has to be done late since only after assignAddresses | ||||
// we know the size of the sections. | // we know the size of the sections. | ||||
removeEmptyPTLoad(); | for (Partition &Part : Partitions) | ||||
removeEmptyPTLoad(Part.Phdrs); | |||||
if (!Config->OFormatBinary) | if (!Config->OFormatBinary) | ||||
assignFileOffsets(); | assignFileOffsets(); | ||||
else | else | ||||
assignFileOffsetsBinary(); | assignFileOffsetsBinary(); | ||||
setPhdrs(); | for (Partition &Part : Partitions) | ||||
setPhdrs(Part); | |||||
if (Config->Relocatable) | if (Config->Relocatable) | ||||
for (OutputSection *Sec : OutputSections) | for (OutputSection *Sec : OutputSections) | ||||
Sec->Addr = 0; | Sec->Addr = 0; | ||||
if (Config->CheckSections) | if (Config->CheckSections) | ||||
checkSections(); | checkSections(); | ||||
▲ Show 20 Lines • Show All 198 Lines • ▼ Show 20 Lines | static bool isRelroSection(const OutputSection *Sec) { | ||||
// However, if "-z now" is given, the lazy symbol resolution is | // However, if "-z now" is given, the lazy symbol resolution is | ||||
// disabled, which enables us to put it into RELRO. | // disabled, which enables us to put it into RELRO. | ||||
if (Sec == In.GotPlt->getParent()) | if (Sec == In.GotPlt->getParent()) | ||||
return Config->ZNow; | return Config->ZNow; | ||||
// .dynamic section contains data for the dynamic linker, and | // .dynamic section contains data for the dynamic linker, and | ||||
// there's no need to write to it at runtime, so it's better to put | // there's no need to write to it at runtime, so it's better to put | ||||
// it into RELRO. | // it into RELRO. | ||||
if (Sec == In.Dynamic->getParent()) | if (Sec->Name == ".dynamic") | ||||
return true; | return true; | ||||
// Sections with some special names are put into RELRO. This is a | // Sections with some special names are put into RELRO. This is a | ||||
// bit unfortunate because section names shouldn't be significant in | // bit unfortunate because section names shouldn't be significant in | ||||
// ELF in spirit. But in reality many linker features depend on | // ELF in spirit. But in reality many linker features depend on | ||||
// magic section names. | // magic section names. | ||||
StringRef S = Sec->Name; | StringRef S = Sec->Name; | ||||
return S == ".data.rel.ro" || S == ".bss.rel.ro" || S == ".ctors" || | return S == ".data.rel.ro" || S == ".bss.rel.ro" || S == ".ctors" || | ||||
S == ".dtors" || S == ".jcr" || S == ".eh_frame" || | S == ".dtors" || S == ".jcr" || S == ".eh_frame" || | ||||
S == ".openbsd.randomdata"; | S == ".openbsd.randomdata"; | ||||
} | } | ||||
// We compute a rank for each section. The rank indicates where the | // We compute a rank for each section. The rank indicates where the | ||||
// section should be placed in the file. Instead of using simple | // section should be placed in the file. Instead of using simple | ||||
// numbers (0,1,2...), we use a series of flags. One for each decision | // numbers (0,1,2...), we use a series of flags. One for each decision | ||||
// point when placing the section. | // point when placing the section. | ||||
// Using flags has two key properties: | // Using flags has two key properties: | ||||
// * It is easy to check if a give branch was taken. | // * It is easy to check if a give branch was taken. | ||||
// * It is easy two see how similar two ranks are (see getRankProximity). | // * It is easy two see how similar two ranks are (see getRankProximity). | ||||
enum RankFlags { | enum RankFlags { | ||||
RF_NOT_ADDR_SET = 1 << 25, | RF_NOT_ADDR_SET = 1 << 27, | ||||
RF_NOT_ALLOC = 1 << 24, | RF_NOT_ALLOC = 1 << 26, | ||||
RF_PARTITION = 1 << 16, // Partition number (8 bits) | RF_PARTITION = 1 << 18, // Partition number (8 bits) | ||||
RF_NOT_PART_EHDR = 1 << 17, | |||||
RF_NOT_PART_PHDR = 1 << 16, | |||||
RF_NOT_INTERP = 1 << 15, | RF_NOT_INTERP = 1 << 15, | ||||
RF_NOT_NOTE = 1 << 14, | RF_NOT_NOTE = 1 << 14, | ||||
RF_WRITE = 1 << 13, | RF_WRITE = 1 << 13, | ||||
RF_EXEC_WRITE = 1 << 12, | RF_EXEC_WRITE = 1 << 12, | ||||
RF_EXEC = 1 << 11, | RF_EXEC = 1 << 11, | ||||
RF_RODATA = 1 << 10, | RF_RODATA = 1 << 10, | ||||
RF_NOT_RELRO = 1 << 9, | RF_NOT_RELRO = 1 << 9, | ||||
RF_NOT_TLS = 1 << 8, | RF_NOT_TLS = 1 << 8, | ||||
Show All 16 Lines | if (Config->SectionStartMap.count(Sec->Name)) | ||||
return Rank; | return Rank; | ||||
Rank |= RF_NOT_ADDR_SET; | Rank |= RF_NOT_ADDR_SET; | ||||
// Allocatable sections go first to reduce the total PT_LOAD size and | // Allocatable sections go first to reduce the total PT_LOAD size and | ||||
// so debug info doesn't change addresses in actual code. | // so debug info doesn't change addresses in actual code. | ||||
if (!(Sec->Flags & SHF_ALLOC)) | if (!(Sec->Flags & SHF_ALLOC)) | ||||
return Rank | RF_NOT_ALLOC; | return Rank | RF_NOT_ALLOC; | ||||
if (Sec->Type == SHT_LLVM_PART_EHDR) | |||||
return Rank; | |||||
Rank |= RF_NOT_PART_EHDR; | |||||
if (Sec->Type == SHT_LLVM_PART_PHDR) | |||||
return Rank; | |||||
Rank |= RF_NOT_PART_PHDR; | |||||
// Put .interp first because some loaders want to see that section | // Put .interp first because some loaders want to see that section | ||||
// on the first page of the executable file when loaded into memory. | // on the first page of the executable file when loaded into memory. | ||||
if (Sec->Name == ".interp") | if (Sec->Name == ".interp") | ||||
return Rank; | return Rank; | ||||
Rank |= RF_NOT_INTERP; | Rank |= RF_NOT_INTERP; | ||||
// Put .note sections (which make up one PT_NOTE) at the beginning so that | // Put .note sections (which make up one PT_NOTE) at the beginning so that | ||||
// they are likely to be included in a core file even if core file size is | // they are likely to be included in a core file even if core file size is | ||||
▲ Show 20 Lines • Show All 144 Lines • ▼ Show 20 Lines | void Writer<ELFT>::forEachRelSec( | ||||
// Scan all relocations. Each relocation goes through a series | // Scan all relocations. Each relocation goes through a series | ||||
// of tests to determine if it needs special treatment, such as | // of tests to determine if it needs special treatment, such as | ||||
// creating GOT, PLT, copy relocations, etc. | // creating GOT, PLT, copy relocations, etc. | ||||
// Note that relocations for non-alloc sections are directly | // Note that relocations for non-alloc sections are directly | ||||
// processed by InputSection::relocateNonAlloc. | // processed by InputSection::relocateNonAlloc. | ||||
for (InputSectionBase *IS : InputSections) | for (InputSectionBase *IS : InputSections) | ||||
if (IS->isLive() && isa<InputSection>(IS) && (IS->Flags & SHF_ALLOC)) | if (IS->isLive() && isa<InputSection>(IS) && (IS->Flags & SHF_ALLOC)) | ||||
Fn(*IS); | Fn(*IS); | ||||
for (EhInputSection *ES : In.EhFrame->Sections) | for (Partition &Part : Partitions) { | ||||
for (EhInputSection *ES : Part.EhFrame->Sections) | |||||
Fn(*ES); | Fn(*ES); | ||||
if (In.ARMExidx && In.ARMExidx->isLive()) | if (Part.ARMExidx && Part.ARMExidx->isLive()) | ||||
for (InputSection *Ex : In.ARMExidx->ExidxSections) | for (InputSection *Ex : Part.ARMExidx->ExidxSections) | ||||
Fn(*Ex); | Fn(*Ex); | ||||
} | } | ||||
} | |||||
// This function generates assignments for predefined symbols (e.g. _end or | // This function generates assignments for predefined symbols (e.g. _end or | ||||
// _etext) and inserts them into the commands sequence to be processed at the | // _etext) and inserts them into the commands sequence to be processed at the | ||||
// appropriate time. This ensures that the value is going to be correct by the | // appropriate time. This ensures that the value is going to be correct by the | ||||
// time any references to these symbols are processed and is equivalent to | // time any references to these symbols are processed and is equivalent to | ||||
// defining these symbols explicitly in the linker script. | // defining these symbols explicitly in the linker script. | ||||
template <class ELFT> void Writer<ELFT>::setReservedSymbolSections() { | template <class ELFT> void Writer<ELFT>::setReservedSymbolSections() { | ||||
if (ElfSym::GlobalOffsetTable) { | if (ElfSym::GlobalOffsetTable) { | ||||
Show All 11 Lines | if (ElfSym::RelaIpltStart && In.RelaIplt->isNeeded()) { | ||||
ElfSym::RelaIpltStart->Section = In.RelaIplt; | ElfSym::RelaIpltStart->Section = In.RelaIplt; | ||||
ElfSym::RelaIpltEnd->Section = In.RelaIplt; | ElfSym::RelaIpltEnd->Section = In.RelaIplt; | ||||
ElfSym::RelaIpltEnd->Value = In.RelaIplt->getSize(); | ElfSym::RelaIpltEnd->Value = In.RelaIplt->getSize(); | ||||
} | } | ||||
PhdrEntry *Last = nullptr; | PhdrEntry *Last = nullptr; | ||||
PhdrEntry *LastRO = nullptr; | PhdrEntry *LastRO = nullptr; | ||||
for (PhdrEntry *P : Phdrs) { | for (Partition &Part : Partitions) { | ||||
for (PhdrEntry *P : Part.Phdrs) { | |||||
if (P->p_type != PT_LOAD) | if (P->p_type != PT_LOAD) | ||||
continue; | continue; | ||||
Last = P; | Last = P; | ||||
if (!(P->p_flags & PF_W)) | if (!(P->p_flags & PF_W)) | ||||
LastRO = P; | LastRO = P; | ||||
} | } | ||||
} | |||||
if (LastRO) { | if (LastRO) { | ||||
// _etext is the first location after the last read-only loadable segment. | // _etext is the first location after the last read-only loadable segment. | ||||
if (ElfSym::Etext1) | if (ElfSym::Etext1) | ||||
ElfSym::Etext1->Section = LastRO->LastSec; | ElfSym::Etext1->Section = LastRO->LastSec; | ||||
if (ElfSym::Etext2) | if (ElfSym::Etext2) | ||||
ElfSym::Etext2->Section = LastRO->LastSec; | ElfSym::Etext2->Section = LastRO->LastSec; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 483 Lines • ▼ Show 20 Lines | if (Config->FixCortexA53Errata843419) { | ||||
if (Changed) | if (Changed) | ||||
Script->assignAddresses(); | Script->assignAddresses(); | ||||
Changed |= A64P.createFixes(); | Changed |= A64P.createFixes(); | ||||
} | } | ||||
if (In.MipsGot) | if (In.MipsGot) | ||||
In.MipsGot->updateAllocSize(); | In.MipsGot->updateAllocSize(); | ||||
Changed |= In.RelaDyn->updateAllocSize(); | for (Partition &Part : Partitions) { | ||||
Changed |= Part.RelaDyn->updateAllocSize(); | |||||
if (In.RelrDyn) | if (Part.RelrDyn) | ||||
Changed |= In.RelrDyn->updateAllocSize(); | Changed |= Part.RelrDyn->updateAllocSize(); | ||||
} | |||||
if (!Changed) | if (!Changed) | ||||
return; | return; | ||||
} | } | ||||
} | } | ||||
static void finalizeSynthetic(SyntheticSection *Sec) { | static void finalizeSynthetic(SyntheticSection *Sec) { | ||||
if (Sec && Sec->isNeeded() && Sec->getParent()) | if (Sec && Sec->isNeeded() && Sec->getParent()) | ||||
▲ Show 20 Lines • Show All 79 Lines • ▼ Show 20 Lines | for (BaseCommand *Base : Script->SectionCommands) | ||||
if (auto *Sec = dyn_cast<OutputSection>(Base)) | if (auto *Sec = dyn_cast<OutputSection>(Base)) | ||||
addStartStopSymbols(Sec); | addStartStopSymbols(Sec); | ||||
} | } | ||||
// Add _DYNAMIC symbol. Unlike GNU gold, our _DYNAMIC symbol has no type. | // Add _DYNAMIC symbol. Unlike GNU gold, our _DYNAMIC symbol has no type. | ||||
// It should be okay as no one seems to care about the type. | // It should be okay as no one seems to care about the type. | ||||
// Even the author of gold doesn't remember why gold behaves that way. | // Even the author of gold doesn't remember why gold behaves that way. | ||||
// https://sourceware.org/ml/binutils/2002-03/msg00360.html | // https://sourceware.org/ml/binutils/2002-03/msg00360.html | ||||
if (In.Dynamic->Parent) | if (Main->Dynamic->Parent) | ||||
Symtab->addSymbol(Defined{/*File=*/nullptr, "_DYNAMIC", STB_WEAK, | Symtab->addSymbol(Defined{/*File=*/nullptr, "_DYNAMIC", STB_WEAK, | ||||
STV_HIDDEN, STT_NOTYPE, | STV_HIDDEN, STT_NOTYPE, | ||||
/*Value=*/0, /*Size=*/0, In.Dynamic}); | /*Value=*/0, /*Size=*/0, Main->Dynamic}); | ||||
// Define __rel[a]_iplt_{start,end} symbols if needed. | // Define __rel[a]_iplt_{start,end} symbols if needed. | ||||
addRelIpltSymbols(); | addRelIpltSymbols(); | ||||
// RISC-V's gp can address +/- 2 KiB, set it to .sdata + 0x800 if not defined. | // RISC-V's gp can address +/- 2 KiB, set it to .sdata + 0x800 if not defined. | ||||
if (Config->EMachine == EM_RISCV) | if (Config->EMachine == EM_RISCV) | ||||
if (!dyn_cast_or_null<Defined>(Symtab->find("__global_pointer$"))) | if (!dyn_cast_or_null<Defined>(Symtab->find("__global_pointer$"))) | ||||
addOptionalRegular("__global_pointer$", findSection(".sdata"), 0x800); | addOptionalRegular("__global_pointer$", findSection(".sdata"), 0x800); | ||||
Show All 17 Lines | if (S && S->isUndefined()) { | ||||
/*Section=*/nullptr}); | /*Section=*/nullptr}); | ||||
ElfSym::TlsModuleBase = cast<Defined>(S); | ElfSym::TlsModuleBase = cast<Defined>(S); | ||||
} | } | ||||
} | } | ||||
// This responsible for splitting up .eh_frame section into | // This responsible for splitting up .eh_frame section into | ||||
// pieces. The relocation scan uses those pieces, so this has to be | // pieces. The relocation scan uses those pieces, so this has to be | ||||
// earlier. | // earlier. | ||||
finalizeSynthetic(In.EhFrame); | for (Partition &Part : Partitions) | ||||
finalizeSynthetic(Part.EhFrame); | |||||
Symtab->forEachSymbol([](Symbol *S) { | Symtab->forEachSymbol([](Symbol *S) { | ||||
if (!S->IsPreemptible) | if (!S->IsPreemptible) | ||||
S->IsPreemptible = computeIsPreemptible(*S); | S->IsPreemptible = computeIsPreemptible(*S); | ||||
}); | }); | ||||
// Scan relocations. This must be done after every symbol is declared so that | // Scan relocations. This must be done after every symbol is declared so that | ||||
// we can correctly decide if a dynamic relocation is needed. | // we can correctly decide if a dynamic relocation is needed. | ||||
Show All 33 Lines | template <class ELFT> void Writer<ELFT>::finalizeSections() { | ||||
// synthesized ones. Visit all symbols to give the finishing touches. | // synthesized ones. Visit all symbols to give the finishing touches. | ||||
Symtab->forEachSymbol([](Symbol *Sym) { | Symtab->forEachSymbol([](Symbol *Sym) { | ||||
if (!includeInSymtab(*Sym)) | if (!includeInSymtab(*Sym)) | ||||
return; | return; | ||||
if (In.SymTab) | if (In.SymTab) | ||||
In.SymTab->addSymbol(Sym); | In.SymTab->addSymbol(Sym); | ||||
if (Sym->includeInDynsym()) { | if (Sym->includeInDynsym()) { | ||||
In.DynSymTab->addSymbol(Sym); | Partitions[Sym->Partition - 1].DynSymTab->addSymbol(Sym); | ||||
if (auto *File = dyn_cast_or_null<SharedFile>(Sym->File)) | if (auto *File = dyn_cast_or_null<SharedFile>(Sym->File)) | ||||
if (File->IsNeeded && !Sym->isUndefined()) | if (File->IsNeeded && !Sym->isUndefined()) | ||||
addVerneed(Sym); | addVerneed(Sym); | ||||
} | } | ||||
}); | }); | ||||
// We also need to scan the dynamic relocation tables of the other partitions | |||||
// and add any referenced symbols to the partition's dynsym. | |||||
for (Partition &Part : MutableArrayRef<Partition>(Partitions).slice(1)) { | |||||
DenseSet<Symbol *> Syms; | |||||
for (const SymbolTableEntry &E : Part.DynSymTab->getSymbols()) | |||||
Syms.insert(E.Sym); | |||||
for (DynamicReloc &Reloc : Part.RelaDyn->Relocs) | |||||
if (Reloc.Sym && !Reloc.UseSymVA && Syms.insert(Reloc.Sym).second) | |||||
Part.DynSymTab->addSymbol(Reloc.Sym); | |||||
} | |||||
// Do not proceed if there was an undefined symbol. | // Do not proceed if there was an undefined symbol. | ||||
if (errorCount()) | if (errorCount()) | ||||
return; | return; | ||||
if (In.MipsGot) | if (In.MipsGot) | ||||
In.MipsGot->build(); | In.MipsGot->build(); | ||||
removeUnusedSyntheticSections(); | removeUnusedSyntheticSections(); | ||||
Show All 23 Lines | for (size_t I = 0, E = OutputSections.size(); I != E; ++I) { | ||||
Sec->SectionIndex = I + 1; | Sec->SectionIndex = I + 1; | ||||
Sec->ShName = In.ShStrTab->addString(Sec->Name); | Sec->ShName = In.ShStrTab->addString(Sec->Name); | ||||
} | } | ||||
// Binary and relocatable output does not have PHDRS. | // Binary and relocatable output does not have PHDRS. | ||||
// The headers have to be created before finalize as that can influence the | // The headers have to be created before finalize as that can influence the | ||||
// image base and the dynamic section on mips includes the image base. | // image base and the dynamic section on mips includes the image base. | ||||
if (!Config->Relocatable && !Config->OFormatBinary) { | if (!Config->Relocatable && !Config->OFormatBinary) { | ||||
Phdrs = Script->hasPhdrsCommands() ? Script->createPhdrs() : createPhdrs(); | for (Partition &Part : Partitions) { | ||||
Part.Phdrs = Script->hasPhdrsCommands() ? Script->createPhdrs() | |||||
: createPhdrs(Part); | |||||
if (Config->EMachine == EM_ARM) { | if (Config->EMachine == EM_ARM) { | ||||
// PT_ARM_EXIDX is the ARM EHABI equivalent of PT_GNU_EH_FRAME | // PT_ARM_EXIDX is the ARM EHABI equivalent of PT_GNU_EH_FRAME | ||||
addPhdrForSection(Phdrs, SHT_ARM_EXIDX, PT_ARM_EXIDX, PF_R); | addPhdrForSection(Part, SHT_ARM_EXIDX, PT_ARM_EXIDX, PF_R); | ||||
} | } | ||||
if (Config->EMachine == EM_MIPS) { | if (Config->EMachine == EM_MIPS) { | ||||
// Add separate segments for MIPS-specific sections. | // Add separate segments for MIPS-specific sections. | ||||
addPhdrForSection(Phdrs, SHT_MIPS_REGINFO, PT_MIPS_REGINFO, PF_R); | addPhdrForSection(Part, SHT_MIPS_REGINFO, PT_MIPS_REGINFO, PF_R); | ||||
addPhdrForSection(Phdrs, SHT_MIPS_OPTIONS, PT_MIPS_OPTIONS, PF_R); | addPhdrForSection(Part, SHT_MIPS_OPTIONS, PT_MIPS_OPTIONS, PF_R); | ||||
addPhdrForSection(Phdrs, SHT_MIPS_ABIFLAGS, PT_MIPS_ABIFLAGS, PF_R); | addPhdrForSection(Part, SHT_MIPS_ABIFLAGS, PT_MIPS_ABIFLAGS, PF_R); | ||||
} | |||||
} | } | ||||
Out::ProgramHeaders->Size = sizeof(Elf_Phdr) * Phdrs.size(); | Out::ProgramHeaders->Size = sizeof(Elf_Phdr) * Main->Phdrs.size(); | ||||
// Find the TLS segment. This happens before the section layout loop so that | // Find the TLS segment. This happens before the section layout loop so that | ||||
// Android relocation packing can look up TLS symbol addresses. | // Android relocation packing can look up TLS symbol addresses. We only need | ||||
for (PhdrEntry *P : Phdrs) | // to care about the main partition here because all TLS symbols were moved | ||||
// to the main partition (see MarkLive.cpp). | |||||
for (PhdrEntry *P : Main->Phdrs) | |||||
if (P->p_type == PT_TLS) | if (P->p_type == PT_TLS) | ||||
Out::TlsPhdr = P; | Out::TlsPhdr = P; | ||||
} | } | ||||
// Some symbols are defined in term of program headers. Now that we | // Some symbols are defined in term of program headers. Now that we | ||||
// have the headers, we can find out which sections they point to. | // have the headers, we can find out which sections they point to. | ||||
setReservedSymbolSections(); | setReservedSymbolSections(); | ||||
// Dynamic section must be the last one in this list and dynamic | |||||
// symbol table section (DynSymTab) must be the first one. | |||||
finalizeSynthetic(In.DynSymTab); | |||||
finalizeSynthetic(In.ARMExidx); | |||||
finalizeSynthetic(In.Bss); | finalizeSynthetic(In.Bss); | ||||
finalizeSynthetic(In.BssRelRo); | finalizeSynthetic(In.BssRelRo); | ||||
finalizeSynthetic(In.GnuHashTab); | |||||
finalizeSynthetic(In.HashTab); | |||||
finalizeSynthetic(In.SymTabShndx); | finalizeSynthetic(In.SymTabShndx); | ||||
finalizeSynthetic(In.ShStrTab); | finalizeSynthetic(In.ShStrTab); | ||||
finalizeSynthetic(In.StrTab); | finalizeSynthetic(In.StrTab); | ||||
finalizeSynthetic(In.VerDef); | |||||
finalizeSynthetic(In.Got); | finalizeSynthetic(In.Got); | ||||
finalizeSynthetic(In.MipsGot); | finalizeSynthetic(In.MipsGot); | ||||
finalizeSynthetic(In.IgotPlt); | finalizeSynthetic(In.IgotPlt); | ||||
finalizeSynthetic(In.GotPlt); | finalizeSynthetic(In.GotPlt); | ||||
finalizeSynthetic(In.RelaDyn); | |||||
finalizeSynthetic(In.RelrDyn); | |||||
finalizeSynthetic(In.RelaIplt); | finalizeSynthetic(In.RelaIplt); | ||||
finalizeSynthetic(In.RelaPlt); | finalizeSynthetic(In.RelaPlt); | ||||
finalizeSynthetic(In.Plt); | finalizeSynthetic(In.Plt); | ||||
finalizeSynthetic(In.Iplt); | finalizeSynthetic(In.Iplt); | ||||
finalizeSynthetic(In.EhFrameHdr); | finalizeSynthetic(In.PartIndex); | ||||
finalizeSynthetic(In.VerSym); | |||||
finalizeSynthetic(In.VerNeed); | // Dynamic section must be the last one in this list and dynamic | ||||
finalizeSynthetic(In.Dynamic); | // symbol table section (DynSymTab) must be the first one. | ||||
for (Partition &Part : Partitions) { | |||||
finalizeSynthetic(Part.ARMExidx); | |||||
finalizeSynthetic(Part.DynSymTab); | |||||
finalizeSynthetic(Part.GnuHashTab); | |||||
finalizeSynthetic(Part.HashTab); | |||||
finalizeSynthetic(Part.VerDef); | |||||
finalizeSynthetic(Part.RelaDyn); | |||||
finalizeSynthetic(Part.RelrDyn); | |||||
finalizeSynthetic(Part.EhFrameHdr); | |||||
finalizeSynthetic(Part.VerSym); | |||||
finalizeSynthetic(Part.VerNeed); | |||||
finalizeSynthetic(Part.Dynamic); | |||||
} | |||||
if (!Script->HasSectionsCommand && !Config->Relocatable) | if (!Script->HasSectionsCommand && !Config->Relocatable) | ||||
fixSectionAlignments(); | fixSectionAlignments(); | ||||
// SHFLinkOrder processing must be processed after relative section placements are | // SHFLinkOrder processing must be processed after relative section placements are | ||||
// known but before addresses are allocated. | // known but before addresses are allocated. | ||||
resolveShfLinkOrder(); | resolveShfLinkOrder(); | ||||
▲ Show 20 Lines • Show All 124 Lines • ▼ Show 20 Lines | if (Config->ExecuteOnly && (Flags & PF_X)) | ||||
return Flags & ~PF_R; | return Flags & ~PF_R; | ||||
if (Config->SingleRoRx && !(Flags & PF_W)) | if (Config->SingleRoRx && !(Flags & PF_W)) | ||||
return Flags | PF_X; | return Flags | PF_X; | ||||
return Flags; | return Flags; | ||||
} | } | ||||
// Decide which program headers to create and which sections to include in each | // Decide which program headers to create and which sections to include in each | ||||
// one. | // one. | ||||
template <class ELFT> std::vector<PhdrEntry *> Writer<ELFT>::createPhdrs() { | template <class ELFT> | ||||
std::vector<PhdrEntry *> Writer<ELFT>::createPhdrs(Partition &Part) { | |||||
std::vector<PhdrEntry *> Ret; | std::vector<PhdrEntry *> Ret; | ||||
auto AddHdr = [&](unsigned Type, unsigned Flags) -> PhdrEntry * { | auto AddHdr = [&](unsigned Type, unsigned Flags) -> PhdrEntry * { | ||||
Ret.push_back(make<PhdrEntry>(Type, Flags)); | Ret.push_back(make<PhdrEntry>(Type, Flags)); | ||||
return Ret.back(); | return Ret.back(); | ||||
}; | }; | ||||
unsigned PartNo = Part.getNumber(); | |||||
bool IsMain = PartNo == 1; | |||||
// The first phdr entry is PT_PHDR which describes the program header itself. | // The first phdr entry is PT_PHDR which describes the program header itself. | ||||
if (IsMain) | |||||
AddHdr(PT_PHDR, PF_R)->add(Out::ProgramHeaders); | AddHdr(PT_PHDR, PF_R)->add(Out::ProgramHeaders); | ||||
else | |||||
AddHdr(PT_PHDR, PF_R)->add(Part.ProgramHeaders->getParent()); | |||||
// PT_INTERP must be the second entry if exists. | // PT_INTERP must be the second entry if exists. | ||||
if (OutputSection *Cmd = findSection(".interp")) | if (OutputSection *Cmd = findSection(".interp", PartNo)) | ||||
AddHdr(PT_INTERP, Cmd->getPhdrFlags())->add(Cmd); | AddHdr(PT_INTERP, Cmd->getPhdrFlags())->add(Cmd); | ||||
// Add the first PT_LOAD segment for regular output sections. | // Add the first PT_LOAD segment for regular output sections. | ||||
uint64_t Flags = computeFlags(PF_R); | uint64_t Flags = computeFlags(PF_R); | ||||
PhdrEntry *Load = AddHdr(PT_LOAD, Flags); | PhdrEntry *Load = nullptr; | ||||
// Add the headers. We will remove them if they don't fit. | // Add the headers. We will remove them if they don't fit. | ||||
// In the other partitions the headers are ordinary sections, so they don't | |||||
// need to be added here. | |||||
if (IsMain) { | |||||
Load = AddHdr(PT_LOAD, Flags); | |||||
Load->add(Out::ElfHeader); | Load->add(Out::ElfHeader); | ||||
Load->add(Out::ProgramHeaders); | Load->add(Out::ProgramHeaders); | ||||
} | |||||
// PT_GNU_RELRO includes all sections that should be marked as | // PT_GNU_RELRO includes all sections that should be marked as | ||||
// read-only by dynamic linker after proccessing relocations. | // read-only by dynamic linker after proccessing relocations. | ||||
// Current dynamic loaders only support one PT_GNU_RELRO PHDR, give | // Current dynamic loaders only support one PT_GNU_RELRO PHDR, give | ||||
// an error message if more than one PT_GNU_RELRO PHDR is required. | // an error message if more than one PT_GNU_RELRO PHDR is required. | ||||
PhdrEntry *RelRo = make<PhdrEntry>(PT_GNU_RELRO, PF_R); | PhdrEntry *RelRo = make<PhdrEntry>(PT_GNU_RELRO, PF_R); | ||||
bool InRelroPhdr = false; | bool InRelroPhdr = false; | ||||
OutputSection *RelroEnd = nullptr; | OutputSection *RelroEnd = nullptr; | ||||
for (OutputSection *Sec : OutputSections) { | for (OutputSection *Sec : OutputSections) { | ||||
if (!needsPtLoad(Sec)) | if (Sec->Partition != PartNo || !needsPtLoad(Sec)) | ||||
continue; | continue; | ||||
if (isRelroSection(Sec)) { | if (isRelroSection(Sec)) { | ||||
InRelroPhdr = true; | InRelroPhdr = true; | ||||
if (!RelroEnd) | if (!RelroEnd) | ||||
RelRo->add(Sec); | RelRo->add(Sec); | ||||
else | else | ||||
error("section: " + Sec->Name + " is not contiguous with other relro" + | error("section: " + Sec->Name + " is not contiguous with other relro" + | ||||
" sections"); | " sections"); | ||||
} else if (InRelroPhdr) { | } else if (InRelroPhdr) { | ||||
InRelroPhdr = false; | InRelroPhdr = false; | ||||
RelroEnd = Sec; | RelroEnd = Sec; | ||||
} | } | ||||
} | } | ||||
for (OutputSection *Sec : OutputSections) { | for (OutputSection *Sec : OutputSections) { | ||||
if (!(Sec->Flags & SHF_ALLOC)) | if (!(Sec->Flags & SHF_ALLOC)) | ||||
break; | break; | ||||
if (!needsPtLoad(Sec)) | if (!needsPtLoad(Sec)) | ||||
continue; | continue; | ||||
// Normally, sections in partitions other than the current partition are | |||||
// ignored. But partition number 255 is a special case: it contains the | |||||
// partition end marker (.part.end). It needs to be added to the main | |||||
// partition so that a segment is created for it in the main partition, | |||||
// which will cause the dynamic loader to reserve space for the other | |||||
// partitions. | |||||
if (Sec->Partition != PartNo) { | |||||
if (IsMain && Sec->Partition == 255) | |||||
AddHdr(PT_LOAD, computeFlags(Sec->getPhdrFlags()))->add(Sec); | |||||
continue; | |||||
} | |||||
// Segments are contiguous memory regions that has the same attributes | // Segments are contiguous memory regions that has the same attributes | ||||
// (e.g. executable or writable). There is one phdr for each segment. | // (e.g. executable or writable). There is one phdr for each segment. | ||||
// Therefore, we need to create a new phdr when the next section has | // Therefore, we need to create a new phdr when the next section has | ||||
// different flags or is loaded at a discontiguous address or memory | // different flags or is loaded at a discontiguous address or memory | ||||
// region using AT or AT> linker script command, respectively. At the same | // region using AT or AT> linker script command, respectively. At the same | ||||
// time, we don't want to create a separate load segment for the headers, | // time, we don't want to create a separate load segment for the headers, | ||||
// even if the first output section has an AT or AT> attribute. | // even if the first output section has an AT or AT> attribute. | ||||
uint64_t NewFlags = computeFlags(Sec->getPhdrFlags()); | uint64_t NewFlags = computeFlags(Sec->getPhdrFlags()); | ||||
if (((Sec->LMAExpr || | if (!Load || | ||||
((Sec->LMAExpr || | |||||
(Sec->LMARegion && (Sec->LMARegion != Load->FirstSec->LMARegion))) && | (Sec->LMARegion && (Sec->LMARegion != Load->FirstSec->LMARegion))) && | ||||
Load->LastSec != Out::ProgramHeaders) || | Load->LastSec != Out::ProgramHeaders) || | ||||
Sec->MemRegion != Load->FirstSec->MemRegion || Flags != NewFlags || | Sec->MemRegion != Load->FirstSec->MemRegion || Flags != NewFlags || | ||||
Sec == RelroEnd) { | Sec == RelroEnd) { | ||||
Load = AddHdr(PT_LOAD, NewFlags); | Load = AddHdr(PT_LOAD, NewFlags); | ||||
Flags = NewFlags; | Flags = NewFlags; | ||||
} | } | ||||
Load->add(Sec); | Load->add(Sec); | ||||
} | } | ||||
// Add a TLS segment if any. | // Add a TLS segment if any. | ||||
PhdrEntry *TlsHdr = make<PhdrEntry>(PT_TLS, PF_R); | PhdrEntry *TlsHdr = make<PhdrEntry>(PT_TLS, PF_R); | ||||
for (OutputSection *Sec : OutputSections) | for (OutputSection *Sec : OutputSections) | ||||
if (Sec->Flags & SHF_TLS) | if (Sec->Partition == PartNo && Sec->Flags & SHF_TLS) | ||||
TlsHdr->add(Sec); | TlsHdr->add(Sec); | ||||
if (TlsHdr->FirstSec) | if (TlsHdr->FirstSec) | ||||
Ret.push_back(TlsHdr); | Ret.push_back(TlsHdr); | ||||
// Add an entry for .dynamic. | // Add an entry for .dynamic. | ||||
if (OutputSection *Sec = In.Dynamic->getParent()) | if (OutputSection *Sec = Part.Dynamic->getParent()) | ||||
AddHdr(PT_DYNAMIC, Sec->getPhdrFlags())->add(Sec); | AddHdr(PT_DYNAMIC, Sec->getPhdrFlags())->add(Sec); | ||||
if (RelRo->FirstSec) | if (RelRo->FirstSec) | ||||
Ret.push_back(RelRo); | Ret.push_back(RelRo); | ||||
// PT_GNU_EH_FRAME is a special section pointing on .eh_frame_hdr. | // PT_GNU_EH_FRAME is a special section pointing on .eh_frame_hdr. | ||||
if (In.EhFrame->isNeeded() && In.EhFrameHdr && In.EhFrame->getParent() && | if (Part.EhFrame->isNeeded() && Part.EhFrameHdr && | ||||
In.EhFrameHdr->getParent()) | Part.EhFrame->getParent() && Part.EhFrameHdr->getParent()) | ||||
AddHdr(PT_GNU_EH_FRAME, In.EhFrameHdr->getParent()->getPhdrFlags()) | AddHdr(PT_GNU_EH_FRAME, Part.EhFrameHdr->getParent()->getPhdrFlags()) | ||||
->add(In.EhFrameHdr->getParent()); | ->add(Part.EhFrameHdr->getParent()); | ||||
// PT_OPENBSD_RANDOMIZE is an OpenBSD-specific feature. That makes | // PT_OPENBSD_RANDOMIZE is an OpenBSD-specific feature. That makes | ||||
// the dynamic linker fill the segment with random data. | // the dynamic linker fill the segment with random data. | ||||
if (OutputSection *Cmd = findSection(".openbsd.randomdata")) | if (OutputSection *Cmd = findSection(".openbsd.randomdata", PartNo)) | ||||
AddHdr(PT_OPENBSD_RANDOMIZE, Cmd->getPhdrFlags())->add(Cmd); | AddHdr(PT_OPENBSD_RANDOMIZE, Cmd->getPhdrFlags())->add(Cmd); | ||||
// PT_GNU_STACK is a special section to tell the loader to make the | // PT_GNU_STACK is a special section to tell the loader to make the | ||||
// pages for the stack non-executable. If you really want an executable | // pages for the stack non-executable. If you really want an executable | ||||
// stack, you can pass -z execstack, but that's not recommended for | // stack, you can pass -z execstack, but that's not recommended for | ||||
// security reasons. | // security reasons. | ||||
unsigned Perm = PF_R | PF_W; | unsigned Perm = PF_R | PF_W; | ||||
if (Config->ZExecstack) | if (Config->ZExecstack) | ||||
Perm |= PF_X; | Perm |= PF_X; | ||||
AddHdr(PT_GNU_STACK, Perm)->p_memsz = Config->ZStackSize; | AddHdr(PT_GNU_STACK, Perm)->p_memsz = Config->ZStackSize; | ||||
// PT_OPENBSD_WXNEEDED is a OpenBSD-specific header to mark the executable | // PT_OPENBSD_WXNEEDED is a OpenBSD-specific header to mark the executable | ||||
// is expected to perform W^X violations, such as calling mprotect(2) or | // is expected to perform W^X violations, such as calling mprotect(2) or | ||||
// mmap(2) with PROT_WRITE | PROT_EXEC, which is prohibited by default on | // mmap(2) with PROT_WRITE | PROT_EXEC, which is prohibited by default on | ||||
// OpenBSD. | // OpenBSD. | ||||
if (Config->ZWxneeded) | if (Config->ZWxneeded) | ||||
AddHdr(PT_OPENBSD_WXNEEDED, PF_X); | AddHdr(PT_OPENBSD_WXNEEDED, PF_X); | ||||
// Create one PT_NOTE per a group of contiguous SHT_NOTE sections with the | // Create one PT_NOTE per a group of contiguous SHT_NOTE sections with the | ||||
// same alignment. | // same alignment. | ||||
PhdrEntry *Note = nullptr; | PhdrEntry *Note = nullptr; | ||||
for (OutputSection *Sec : OutputSections) { | for (OutputSection *Sec : OutputSections) { | ||||
if (Sec->Partition != PartNo) | |||||
continue; | |||||
if (Sec->Type == SHT_NOTE && (Sec->Flags & SHF_ALLOC)) { | if (Sec->Type == SHT_NOTE && (Sec->Flags & SHF_ALLOC)) { | ||||
if (!Note || Sec->LMAExpr || Note->LastSec->Alignment != Sec->Alignment) | if (!Note || Sec->LMAExpr || Note->LastSec->Alignment != Sec->Alignment) | ||||
Note = AddHdr(PT_NOTE, PF_R); | Note = AddHdr(PT_NOTE, PF_R); | ||||
Note->add(Sec); | Note->add(Sec); | ||||
} else { | } else { | ||||
Note = nullptr; | Note = nullptr; | ||||
} | } | ||||
} | } | ||||
return Ret; | return Ret; | ||||
} | } | ||||
template <class ELFT> | template <class ELFT> | ||||
void Writer<ELFT>::addPhdrForSection(std::vector<PhdrEntry *> &Phdrs, | void Writer<ELFT>::addPhdrForSection(Partition &Part, unsigned ShType, | ||||
unsigned ShType, unsigned PType, | unsigned PType, unsigned PFlags) { | ||||
unsigned PFlags) { | unsigned PartNo = Part.getNumber(); | ||||
auto I = llvm::find_if( | auto I = llvm::find_if(OutputSections, [=](OutputSection *Cmd) { | ||||
OutputSections, [=](OutputSection *Cmd) { return Cmd->Type == ShType; }); | return Cmd->Partition == PartNo && Cmd->Type == ShType; | ||||
}); | |||||
if (I == OutputSections.end()) | if (I == OutputSections.end()) | ||||
return; | return; | ||||
PhdrEntry *Entry = make<PhdrEntry>(PType, PFlags); | PhdrEntry *Entry = make<PhdrEntry>(PType, PFlags); | ||||
Entry->add(*I); | Entry->add(*I); | ||||
Phdrs.push_back(Entry); | Part.Phdrs.push_back(Entry); | ||||
} | } | ||||
// The first section of each PT_LOAD, the first section in PT_GNU_RELRO and the | // The first section of each PT_LOAD, the first section in PT_GNU_RELRO and the | ||||
// first section after PT_GNU_RELRO have to be page aligned so that the dynamic | // first section after PT_GNU_RELRO have to be page aligned so that the dynamic | ||||
// linker can set the permissions. | // linker can set the permissions. | ||||
template <class ELFT> void Writer<ELFT>::fixSectionAlignments() { | template <class ELFT> void Writer<ELFT>::fixSectionAlignments() { | ||||
auto PageAlign = [](OutputSection *Cmd) { | auto PageAlign = [](OutputSection *Cmd) { | ||||
if (Cmd && !Cmd->AddrExpr) | if (Cmd && !Cmd->AddrExpr) | ||||
Cmd->AddrExpr = [=] { | Cmd->AddrExpr = [=] { | ||||
return alignTo(Script->getDot(), Config->MaxPageSize); | return alignTo(Script->getDot(), Config->MaxPageSize); | ||||
}; | }; | ||||
}; | }; | ||||
for (const PhdrEntry *P : Phdrs) | for (Partition &Part : Partitions) { | ||||
for (const PhdrEntry *P : Part.Phdrs) | |||||
if (P->p_type == PT_LOAD && P->FirstSec) | if (P->p_type == PT_LOAD && P->FirstSec) | ||||
PageAlign(P->FirstSec); | PageAlign(P->FirstSec); | ||||
for (const PhdrEntry *P : Phdrs) { | for (const PhdrEntry *P : Part.Phdrs) { | ||||
if (P->p_type != PT_GNU_RELRO) | if (P->p_type != PT_GNU_RELRO) | ||||
continue; | continue; | ||||
if (P->FirstSec) | if (P->FirstSec) | ||||
PageAlign(P->FirstSec); | PageAlign(P->FirstSec); | ||||
// Find the first section after PT_GNU_RELRO. If it is in a PT_LOAD we | // Find the first section after PT_GNU_RELRO. If it is in a PT_LOAD we | ||||
// have to align it to a page. | // have to align it to a page. | ||||
auto End = OutputSections.end(); | auto End = OutputSections.end(); | ||||
auto I = llvm::find(OutputSections, P->LastSec); | auto I = llvm::find(OutputSections, P->LastSec); | ||||
if (I == End || (I + 1) == End) | if (I == End || (I + 1) == End) | ||||
continue; | continue; | ||||
OutputSection *Cmd = (*(I + 1)); | OutputSection *Cmd = (*(I + 1)); | ||||
if (needsPtLoad(Cmd)) | if (needsPtLoad(Cmd)) | ||||
PageAlign(Cmd); | PageAlign(Cmd); | ||||
} | } | ||||
} | } | ||||
} | |||||
// Compute an in-file position for a given section. The file offset must be the | // Compute an in-file position for a given section. The file offset must be the | ||||
// same with its virtual address modulo the page size, so that the loader can | // same with its virtual address modulo the page size, so that the loader can | ||||
// load executables without any address adjustment. | // load executables without any address adjustment. | ||||
static uint64_t computeFileOffset(OutputSection *OS, uint64_t Off) { | static uint64_t computeFileOffset(OutputSection *OS, uint64_t Off) { | ||||
// File offsets are not significant for .bss sections. By convention, we keep | // File offsets are not significant for .bss sections. By convention, we keep | ||||
// section offsets monotonically increasing rather than setting to zero. | // section offsets monotonically increasing rather than setting to zero. | ||||
if (OS->Type == SHT_NOBITS) | if (OS->Type == SHT_NOBITS) | ||||
▲ Show 20 Lines • Show All 41 Lines • ▼ Show 20 Lines | |||||
// Assign file offsets to output sections. | // Assign file offsets to output sections. | ||||
template <class ELFT> void Writer<ELFT>::assignFileOffsets() { | template <class ELFT> void Writer<ELFT>::assignFileOffsets() { | ||||
uint64_t Off = 0; | uint64_t Off = 0; | ||||
Off = setFileOffset(Out::ElfHeader, Off); | Off = setFileOffset(Out::ElfHeader, Off); | ||||
Off = setFileOffset(Out::ProgramHeaders, Off); | Off = setFileOffset(Out::ProgramHeaders, Off); | ||||
PhdrEntry *LastRX = nullptr; | PhdrEntry *LastRX = nullptr; | ||||
for (PhdrEntry *P : Phdrs) | for (Partition &Part : Partitions) | ||||
for (PhdrEntry *P : Part.Phdrs) | |||||
if (P->p_type == PT_LOAD && (P->p_flags & PF_X)) | if (P->p_type == PT_LOAD && (P->p_flags & PF_X)) | ||||
LastRX = P; | LastRX = P; | ||||
for (OutputSection *Sec : OutputSections) { | for (OutputSection *Sec : OutputSections) { | ||||
Off = setFileOffset(Sec, Off); | Off = setFileOffset(Sec, Off); | ||||
if (Script->HasSectionsCommand) | if (Script->HasSectionsCommand) | ||||
continue; | continue; | ||||
// If this is a last section of the last executable segment and that | // If this is a last section of the last executable segment and that | ||||
// segment is the last loadable segment, align the offset of the | // segment is the last loadable segment, align the offset of the | ||||
Show All 21 Lines | if ((Sec->Offset > FileSize) || (Sec->Offset + Sec->Size > FileSize)) | ||||
error("unable to place section " + Sec->Name + " at file offset " + | error("unable to place section " + Sec->Name + " at file offset " + | ||||
rangeToString(Sec->Offset, Sec->Size) + | rangeToString(Sec->Offset, Sec->Size) + | ||||
"; check your linker script for overflows"); | "; check your linker script for overflows"); | ||||
} | } | ||||
} | } | ||||
// Finalize the program headers. We call this function after we assign | // Finalize the program headers. We call this function after we assign | ||||
// file offsets and VAs to all sections. | // file offsets and VAs to all sections. | ||||
template <class ELFT> void Writer<ELFT>::setPhdrs() { | template <class ELFT> void Writer<ELFT>::setPhdrs(Partition &Part) { | ||||
for (PhdrEntry *P : Phdrs) { | for (PhdrEntry *P : Part.Phdrs) { | ||||
OutputSection *First = P->FirstSec; | OutputSection *First = P->FirstSec; | ||||
OutputSection *Last = P->LastSec; | OutputSection *Last = P->LastSec; | ||||
if (First) { | if (First) { | ||||
P->p_filesz = Last->Offset - First->Offset; | P->p_filesz = Last->Offset - First->Offset; | ||||
if (Last->Type != SHT_NOBITS) | if (Last->Type != SHT_NOBITS) | ||||
P->p_filesz += Last->Size; | P->p_filesz += Last->Size; | ||||
P->p_memsz = Last->Addr + Last->Size - First->Addr; | P->p_memsz = Last->Addr + Last->Size - First->Addr; | ||||
P->p_offset = First->Offset; | P->p_offset = First->Offset; | ||||
P->p_vaddr = First->Addr; | P->p_vaddr = First->Addr; | ||||
// File offsets in partitions other than the main partition are relative | |||||
// to the offset of the ELF headers. Perform that adjustment now. | |||||
if (Part.ElfHeader) | |||||
P->p_offset -= Part.ElfHeader->getParent()->Offset; | |||||
if (!P->HasLMA) | if (!P->HasLMA) | ||||
P->p_paddr = First->getLMA(); | P->p_paddr = First->getLMA(); | ||||
} | } | ||||
if (P->p_type == PT_LOAD) { | if (P->p_type == PT_LOAD) { | ||||
P->p_align = std::max<uint64_t>(P->p_align, Config->MaxPageSize); | P->p_align = std::max<uint64_t>(P->p_align, Config->MaxPageSize); | ||||
} else if (P->p_type == PT_GNU_RELRO) { | } else if (P->p_type == PT_GNU_RELRO) { | ||||
P->p_align = 1; | P->p_align = 1; | ||||
▲ Show 20 Lines • Show All 131 Lines • ▼ Show 20 Lines | |||||
static uint16_t getELFType() { | static uint16_t getELFType() { | ||||
if (Config->Pic) | if (Config->Pic) | ||||
return ET_DYN; | return ET_DYN; | ||||
if (Config->Relocatable) | if (Config->Relocatable) | ||||
return ET_REL; | return ET_REL; | ||||
return ET_EXEC; | return ET_EXEC; | ||||
} | } | ||||
static uint8_t getAbiVersion() { | |||||
// MIPS non-PIC executable gets ABI version 1. | |||||
if (Config->EMachine == EM_MIPS) { | |||||
if (getELFType() == ET_EXEC && | |||||
(Config->EFlags & (EF_MIPS_PIC | EF_MIPS_CPIC)) == EF_MIPS_CPIC) | |||||
return 1; | |||||
return 0; | |||||
} | |||||
if (Config->EMachine == EM_AMDGPU) { | |||||
uint8_t Ver = ObjectFiles[0]->ABIVersion; | |||||
for (InputFile *File : makeArrayRef(ObjectFiles).slice(1)) | |||||
if (File->ABIVersion != Ver) | |||||
error("incompatible ABI version: " + toString(File)); | |||||
return Ver; | |||||
} | |||||
return 0; | |||||
} | |||||
template <class ELFT> void Writer<ELFT>::writeHeader() { | template <class ELFT> void Writer<ELFT>::writeHeader() { | ||||
// For executable segments, the trap instructions are written before writing | writeEhdr<ELFT>(Out::BufferStart, *Main); | ||||
// the header. Setting Elf header bytes to zero ensures that any unused bytes | writePhdrs<ELFT>(Out::BufferStart + sizeof(Elf_Ehdr), *Main); | ||||
// in header are zero-cleared, instead of having trap instructions. | |||||
memset(Out::BufferStart, 0, sizeof(Elf_Ehdr)); | |||||
memcpy(Out::BufferStart, "\177ELF", 4); | |||||
// Write the ELF header. | |||||
auto *EHdr = reinterpret_cast<Elf_Ehdr *>(Out::BufferStart); | auto *EHdr = reinterpret_cast<Elf_Ehdr *>(Out::BufferStart); | ||||
EHdr->e_ident[EI_CLASS] = Config->Is64 ? ELFCLASS64 : ELFCLASS32; | |||||
EHdr->e_ident[EI_DATA] = Config->IsLE ? ELFDATA2LSB : ELFDATA2MSB; | |||||
EHdr->e_ident[EI_VERSION] = EV_CURRENT; | |||||
EHdr->e_ident[EI_OSABI] = Config->OSABI; | |||||
EHdr->e_ident[EI_ABIVERSION] = getAbiVersion(); | |||||
EHdr->e_type = getELFType(); | EHdr->e_type = getELFType(); | ||||
EHdr->e_machine = Config->EMachine; | |||||
EHdr->e_version = EV_CURRENT; | |||||
EHdr->e_entry = getEntryAddr(); | EHdr->e_entry = getEntryAddr(); | ||||
EHdr->e_shoff = SectionHeaderOff; | EHdr->e_shoff = SectionHeaderOff; | ||||
EHdr->e_flags = Config->EFlags; | |||||
EHdr->e_ehsize = sizeof(Elf_Ehdr); | |||||
EHdr->e_phnum = Phdrs.size(); | |||||
EHdr->e_shentsize = sizeof(Elf_Shdr); | |||||
if (!Config->Relocatable) { | |||||
EHdr->e_phoff = sizeof(Elf_Ehdr); | |||||
EHdr->e_phentsize = sizeof(Elf_Phdr); | |||||
} | |||||
// Write the program header table. | |||||
auto *HBuf = reinterpret_cast<Elf_Phdr *>(Out::BufferStart + EHdr->e_phoff); | |||||
for (PhdrEntry *P : Phdrs) { | |||||
HBuf->p_type = P->p_type; | |||||
HBuf->p_flags = P->p_flags; | |||||
HBuf->p_offset = P->p_offset; | |||||
HBuf->p_vaddr = P->p_vaddr; | |||||
HBuf->p_paddr = P->p_paddr; | |||||
HBuf->p_filesz = P->p_filesz; | |||||
HBuf->p_memsz = P->p_memsz; | |||||
HBuf->p_align = P->p_align; | |||||
++HBuf; | |||||
} | |||||
// Write the section header table. | // Write the section header table. | ||||
// | // | ||||
// The ELF header can only store numbers up to SHN_LORESERVE in the e_shnum | // The ELF header can only store numbers up to SHN_LORESERVE in the e_shnum | ||||
// and e_shstrndx fields. When the value of one of these fields exceeds | // and e_shstrndx fields. When the value of one of these fields exceeds | ||||
// SHN_LORESERVE ELF requires us to put sentinel values in the ELF header and | // SHN_LORESERVE ELF requires us to put sentinel values in the ELF header and | ||||
// use fields in the section header at index 0 to store | // use fields in the section header at index 0 to store | ||||
// the value. The sentinel values and fields are: | // the value. The sentinel values and fields are: | ||||
▲ Show 20 Lines • Show All 58 Lines • ▼ Show 20 Lines | |||||
// standard, it is in general a good thing to do for security reasons. | // standard, it is in general a good thing to do for security reasons. | ||||
// | // | ||||
// We'll leave other pages in segments as-is because the rest will be | // We'll leave other pages in segments as-is because the rest will be | ||||
// overwritten by output sections. | // overwritten by output sections. | ||||
template <class ELFT> void Writer<ELFT>::writeTrapInstr() { | template <class ELFT> void Writer<ELFT>::writeTrapInstr() { | ||||
if (Script->HasSectionsCommand) | if (Script->HasSectionsCommand) | ||||
return; | return; | ||||
for (Partition &Part : Partitions) { | |||||
// Fill the last page. | // Fill the last page. | ||||
for (PhdrEntry *P : Phdrs) | for (PhdrEntry *P : Part.Phdrs) | ||||
if (P->p_type == PT_LOAD && (P->p_flags & PF_X)) | if (P->p_type == PT_LOAD && (P->p_flags & PF_X)) | ||||
fillTrap(Out::BufferStart + alignDown(P->p_offset + P->p_filesz, | fillTrap(Out::BufferStart + alignDown(P->FirstSec->Offset + P->p_filesz, | ||||
Config->CommonPageSize), | Config->CommonPageSize), | ||||
Out::BufferStart + | Out::BufferStart + alignTo(P->FirstSec->Offset + P->p_filesz, | ||||
alignTo(P->p_offset + P->p_filesz, Config->CommonPageSize)); | Config->CommonPageSize)); | ||||
// Round up the file size of the last segment to the page boundary iff it is | // Round up the file size of the last segment to the page boundary iff it is | ||||
// an executable segment to ensure that other tools don't accidentally | // an executable segment to ensure that other tools don't accidentally | ||||
// trim the instruction padding (e.g. when stripping the file). | // trim the instruction padding (e.g. when stripping the file). | ||||
PhdrEntry *Last = nullptr; | PhdrEntry *Last = nullptr; | ||||
for (PhdrEntry *P : Phdrs) | for (PhdrEntry *P : Part.Phdrs) | ||||
if (P->p_type == PT_LOAD) | if (P->p_type == PT_LOAD) | ||||
Last = P; | Last = P; | ||||
if (Last && (Last->p_flags & PF_X)) | if (Last && (Last->p_flags & PF_X)) | ||||
Last->p_memsz = Last->p_filesz = | Last->p_memsz = Last->p_filesz = | ||||
alignTo(Last->p_filesz, Config->CommonPageSize); | alignTo(Last->p_filesz, Config->CommonPageSize); | ||||
} | } | ||||
} | |||||
// Write section contents to a mmap'ed file. | // Write section contents to a mmap'ed file. | ||||
template <class ELFT> void Writer<ELFT>::writeSections() { | template <class ELFT> void Writer<ELFT>::writeSections() { | ||||
// In -r or -emit-relocs mode, write the relocation sections first as in | // In -r or -emit-relocs mode, write the relocation sections first as in | ||||
// ELf_Rel targets we might find out that we need to modify the relocated | // ELf_Rel targets we might find out that we need to modify the relocated | ||||
// section while doing it. | // section while doing it. | ||||
for (OutputSection *Sec : OutputSections) | for (OutputSection *Sec : OutputSections) | ||||
if (Sec->Type == SHT_REL || Sec->Type == SHT_RELA) | if (Sec->Type == SHT_REL || Sec->Type == SHT_RELA) | ||||
Show All 33 Lines | parallelForEachN(0, Chunks.size(), [&](size_t I) { | ||||
HashFn(Hashes.data() + I * HashBuf.size(), Chunks[I]); | HashFn(Hashes.data() + I * HashBuf.size(), Chunks[I]); | ||||
}); | }); | ||||
// Write to the final output buffer. | // Write to the final output buffer. | ||||
HashFn(HashBuf.data(), Hashes); | HashFn(HashBuf.data(), Hashes); | ||||
} | } | ||||
template <class ELFT> void Writer<ELFT>::writeBuildId() { | template <class ELFT> void Writer<ELFT>::writeBuildId() { | ||||
if (!In.BuildId || !In.BuildId->getParent()) | if (!Main->BuildId || !Main->BuildId->getParent()) | ||||
return; | return; | ||||
if (Config->BuildId == BuildIdKind::Hexstring) { | if (Config->BuildId == BuildIdKind::Hexstring) { | ||||
In.BuildId->writeBuildId(Config->BuildIdVector); | for (Partition &Part : Partitions) | ||||
Part.BuildId->writeBuildId(Config->BuildIdVector); | |||||
return; | return; | ||||
} | } | ||||
// Compute a hash of all sections of the output file. | // Compute a hash of all sections of the output file. | ||||
std::vector<uint8_t> BuildId(In.BuildId->HashSize); | size_t HashSize = Main->BuildId->HashSize; | ||||
std::vector<uint8_t> BuildId(HashSize); | |||||
llvm::ArrayRef<uint8_t> Buf{Out::BufferStart, size_t(FileSize)}; | llvm::ArrayRef<uint8_t> Buf{Out::BufferStart, size_t(FileSize)}; | ||||
switch (Config->BuildId) { | switch (Config->BuildId) { | ||||
case BuildIdKind::Fast: | case BuildIdKind::Fast: | ||||
computeHash(BuildId, Buf, [](uint8_t *Dest, ArrayRef<uint8_t> Arr) { | computeHash(BuildId, Buf, [](uint8_t *Dest, ArrayRef<uint8_t> Arr) { | ||||
write64le(Dest, xxHash64(Arr)); | write64le(Dest, xxHash64(Arr)); | ||||
}); | }); | ||||
break; | break; | ||||
case BuildIdKind::Md5: | case BuildIdKind::Md5: | ||||
computeHash(BuildId, Buf, [&](uint8_t *Dest, ArrayRef<uint8_t> Arr) { | computeHash(BuildId, Buf, [&](uint8_t *Dest, ArrayRef<uint8_t> Arr) { | ||||
memcpy(Dest, MD5::hash(Arr).data(), In.BuildId->HashSize); | memcpy(Dest, MD5::hash(Arr).data(), HashSize); | ||||
}); | }); | ||||
break; | break; | ||||
case BuildIdKind::Sha1: | case BuildIdKind::Sha1: | ||||
computeHash(BuildId, Buf, [&](uint8_t *Dest, ArrayRef<uint8_t> Arr) { | computeHash(BuildId, Buf, [&](uint8_t *Dest, ArrayRef<uint8_t> Arr) { | ||||
memcpy(Dest, SHA1::hash(Arr).data(), In.BuildId->HashSize); | memcpy(Dest, SHA1::hash(Arr).data(), HashSize); | ||||
}); | }); | ||||
break; | break; | ||||
case BuildIdKind::Uuid: | case BuildIdKind::Uuid: | ||||
if (auto EC = llvm::getRandomBytes(BuildId.data(), In.BuildId->HashSize)) | if (auto EC = llvm::getRandomBytes(BuildId.data(), HashSize)) | ||||
error("entropy source failure: " + EC.message()); | error("entropy source failure: " + EC.message()); | ||||
break; | break; | ||||
default: | default: | ||||
llvm_unreachable("unknown BuildIdKind"); | llvm_unreachable("unknown BuildIdKind"); | ||||
} | } | ||||
In.BuildId->writeBuildId(BuildId); | for (Partition &Part : Partitions) | ||||
Part.BuildId->writeBuildId(BuildId); | |||||
} | } | ||||
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>(); |