aboutsummaryrefslogtreecommitdiff
path: root/ELF/Writer.cpp
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2017-05-29 16:26:20 +0000
committerDimitry Andric <dim@FreeBSD.org>2017-05-29 16:26:20 +0000
commitbef2946c219dc621608bcc9e47f8b973e5ef5c70 (patch)
tree1e4dfae199fc27167ed7496693938fec2dab65c2 /ELF/Writer.cpp
parentc53addf38e24e4dafe992aafb3ae928bfa8fdb0a (diff)
downloadsrc-bef2946c219dc621608bcc9e47f8b973e5ef5c70.tar.gz
src-bef2946c219dc621608bcc9e47f8b973e5ef5c70.zip
Vendor import of lld trunk r304149:vendor/lld/lld-trunk-r304149
Notes
Notes: svn path=/vendor/lld/dist/; revision=319148 svn path=/vendor/lld/lld-trunk-r304149/; revision=319149; tag=vendor/lld/lld-trunk-r304149
Diffstat (limited to 'ELF/Writer.cpp')
-rw-r--r--ELF/Writer.cpp190
1 files changed, 121 insertions, 69 deletions
diff --git a/ELF/Writer.cpp b/ELF/Writer.cpp
index 7a21d2b9f13d..e539d8ffce6e 100644
--- a/ELF/Writer.cpp
+++ b/ELF/Writer.cpp
@@ -46,6 +46,7 @@ public:
void run();
private:
+ void clearOutputSections();
void createSyntheticSections();
void copyLocalSymbols();
void addSectionSymbols();
@@ -80,6 +81,8 @@ private:
void addStartStopSymbols(OutputSection *Sec);
uint64_t getEntryAddr();
OutputSection *findSection(StringRef Name);
+ OutputSection *findSectionInScript(StringRef Name);
+ OutputSectionCommand *findSectionCommand(StringRef Name);
std::vector<PhdrEntry> Phdrs;
@@ -161,7 +164,7 @@ static void combineMergableSections() {
continue;
StringRef OutsecName = getOutputSectionName(MS->Name);
- uint64_t Flags = MS->Flags & ~(uint64_t)(SHF_GROUP | SHF_COMPRESSED);
+ uint64_t Flags = MS->Flags & ~(uint64_t)SHF_GROUP;
uint32_t Alignment = std::max<uint32_t>(MS->Alignment, MS->Entsize);
auto I = llvm::find_if(MergeSections, [=](MergeSyntheticSection *Sec) {
@@ -198,6 +201,15 @@ template <class ELFT> static void combineEhFrameSections() {
V.erase(std::remove(V.begin(), V.end(), nullptr), V.end());
}
+template <class ELFT> void Writer<ELFT>::clearOutputSections() {
+ // Clear the OutputSections to make sure it is not used anymore. Any
+ // code from this point on should be using the linker script
+ // commands.
+ for (OutputSection *Sec : OutputSections)
+ Sec->Sections.clear();
+ OutputSections.clear();
+}
+
// The main function of the writer.
template <class ELFT> void Writer<ELFT>::run() {
// Create linker-synthesized sections such as .got or .plt.
@@ -244,13 +256,21 @@ template <class ELFT> void Writer<ELFT>::run() {
if (ErrorCount)
return;
+ if (!Script->Opt.HasSections) {
+ if (!Config->Relocatable)
+ fixSectionAlignments();
+ Script->fabricateDefaultCommands();
+ }
+
+ // If -compressed-debug-sections is specified, we need to compress
+ // .debug_* sections. Do it right now because it changes the size of
+ // output sections.
+ parallelForEach(OutputSections.begin(), OutputSections.end(),
+ [](OutputSection *S) { S->maybeCompress<ELFT>(); });
+
if (Config->Relocatable) {
assignFileOffsets();
} else {
- if (!Script->Opt.HasSections) {
- fixSectionAlignments();
- Script->fabricateDefaultCommands();
- }
Script->synchronize();
Script->assignAddresses(Phdrs);
@@ -281,6 +301,7 @@ template <class ELFT> void Writer<ELFT>::run() {
} else {
writeSectionsBinary();
}
+ clearOutputSections();
// Backfill .note.gnu.build-id section content. This is done at last
// because the content is usually a hash value of the entire output file.
@@ -288,10 +309,6 @@ template <class ELFT> void Writer<ELFT>::run() {
if (ErrorCount)
return;
- // Clear the OutputSections to make sure it is not used anymore. Any
- // code from this point on should be using the linker script
- // commands.
- OutputSections.clear();
// Handle -Map option.
writeMapFile<ELFT>(Script->Opt.Commands);
@@ -631,10 +648,11 @@ bool elf::isRelroSection(const OutputSection *Sec) {
// * It is easy to check if a give branch was taken.
// * It is easy two see how similar two ranks are (see getRankProximity).
enum RankFlags {
- RF_NOT_ADDR_SET = 1 << 15,
- RF_NOT_INTERP = 1 << 14,
- RF_NOT_ALLOC = 1 << 13,
- RF_WRITE = 1 << 12,
+ RF_NOT_ADDR_SET = 1 << 16,
+ RF_NOT_INTERP = 1 << 15,
+ RF_NOT_ALLOC = 1 << 14,
+ RF_WRITE = 1 << 13,
+ RF_EXEC_WRITE = 1 << 12,
RF_EXEC = 1 << 11,
RF_NON_TLS_BSS = 1 << 10,
RF_NON_TLS_BSS_RO = 1 << 9,
@@ -669,19 +687,29 @@ static unsigned getSectionRank(const OutputSection *Sec) {
if (!(Sec->Flags & SHF_ALLOC))
return Rank | RF_NOT_ALLOC;
- // We want the read only sections first so that they go in the PT_LOAD
- // covering the program headers at the start of the file.
- if (Sec->Flags & SHF_WRITE)
- Rank |= RF_WRITE;
-
- if (Sec->Flags & SHF_EXECINSTR) {
- // For a corresponding reason, put non exec sections first (the program
- // header PT_LOAD is not executable).
- // We only do that if we are not using linker scripts, since with linker
- // scripts ro and rx sections are in the same PT_LOAD, so their relative
- // order is not important. The same applies for -no-rosegment.
- if ((Rank & RF_WRITE) || !Config->SingleRoRx)
+ // Sort sections based on their access permission in the following
+ // order: R, RX, RWX, RW. This order is based on the following
+ // considerations:
+ // * Read-only sections come first such that they go in the
+ // PT_LOAD covering the program headers at the start of the file.
+ // * Read-only, executable sections come next, unless the
+ // -no-rosegment option is used.
+ // * Writable, executable sections follow such that .plt on
+ // architectures where it needs to be writable will be placed
+ // between .text and .data.
+ // * Writable sections come last, such that .bss lands at the very
+ // end of the last PT_LOAD.
+ bool IsExec = Sec->Flags & SHF_EXECINSTR;
+ bool IsWrite = Sec->Flags & SHF_WRITE;
+
+ if (IsExec) {
+ if (IsWrite)
+ Rank |= RF_EXEC_WRITE;
+ else if (!Config->SingleRoRx)
Rank |= RF_EXEC;
+ } else {
+ if (IsWrite)
+ Rank |= RF_WRITE;
}
// If we got here we know that both A and B are in the same PT_LOAD.
@@ -778,12 +806,6 @@ static bool compareSections(const OutputSection *A, const OutputSection *B) {
return compareSectionsNonScript(A, B);
}
-// Program header entry
-PhdrEntry::PhdrEntry(unsigned Type, unsigned Flags) {
- p_type = Type;
- p_flags = Flags;
-}
-
void PhdrEntry::add(OutputSection *Sec) {
Last = Sec;
if (!First)
@@ -1239,12 +1261,6 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
for (OutputSection *Sec : OutputSections)
Sec->finalize<ELFT>();
- // If -compressed-debug-sections is specified, we need to compress
- // .debug_* sections. Do it right now because it changes the size of
- // output sections.
- parallelForEach(OutputSections.begin(), OutputSections.end(),
- [](OutputSection *S) { S->maybeCompress<ELFT>(); });
-
// createThunks may have added local symbols to the static symbol table
applySynthetic({InX::SymTab, InX::ShStrTab, InX::StrTab},
[](SyntheticSection *SS) { SS->postThunkContents(); });
@@ -1297,6 +1313,21 @@ void Writer<ELFT>::addStartStopSymbols(OutputSection *Sec) {
addOptionalRegular<ELFT>(Saver.save("__stop_" + S), Sec, -1, STV_DEFAULT);
}
+template <class ELFT>
+OutputSectionCommand *Writer<ELFT>::findSectionCommand(StringRef Name) {
+ for (BaseCommand *Base : Script->Opt.Commands)
+ if (auto *Cmd = dyn_cast<OutputSectionCommand>(Base))
+ if (Cmd->Name == Name)
+ return Cmd;
+ return nullptr;
+}
+
+template <class ELFT> OutputSection *Writer<ELFT>::findSectionInScript(StringRef Name) {
+ if (OutputSectionCommand *Cmd = findSectionCommand(Name))
+ return Cmd->Sec;
+ return nullptr;
+}
+
template <class ELFT> OutputSection *Writer<ELFT>::findSection(StringRef Name) {
for (OutputSection *Sec : OutputSections)
if (Sec->Name == Name)
@@ -1583,7 +1614,7 @@ template <class ELFT> uint64_t Writer<ELFT>::getEntryAddr() {
return Addr;
// Case 4
- if (OutputSection *Sec = findSection(".text")) {
+ if (OutputSection *Sec = findSectionInScript(".text")) {
if (Config->WarnMissingEntry)
warn("cannot find entry symbol " + Config->Entry + "; defaulting to 0x" +
utohexstr(Sec->Addr));
@@ -1609,18 +1640,6 @@ static uint16_t getELFType() {
// to each section. This function fixes some predefined
// symbol values that depend on section address and size.
template <class ELFT> void Writer<ELFT>::fixPredefinedSymbols() {
- auto Set = [](DefinedRegular *S1, DefinedRegular *S2, OutputSection *Sec,
- uint64_t Value) {
- if (S1) {
- S1->Section = Sec;
- S1->Value = Value;
- }
- if (S2) {
- S2->Section = Sec;
- S2->Value = Value;
- }
- };
-
// _etext is the first location after the last read-only loadable segment.
// _edata is the first location after the last read-write loadable segment.
// _end is the first location after the uninitialized data region.
@@ -1636,15 +1655,29 @@ template <class ELFT> void Writer<ELFT>::fixPredefinedSymbols() {
else
LastRO = &P;
}
- if (Last)
- Set(ElfSym::End1, ElfSym::End2, Last->First, Last->p_memsz);
- if (LastRO)
- Set(ElfSym::Etext1, ElfSym::Etext2, LastRO->First, LastRO->p_filesz);
- if (LastRW)
- Set(ElfSym::Edata1, ElfSym::Edata2, LastRW->First, LastRW->p_filesz);
+
+ auto Set = [](DefinedRegular *S, OutputSection *Sec, uint64_t Value) {
+ if (S) {
+ S->Section = Sec;
+ S->Value = Value;
+ }
+ };
+
+ if (Last) {
+ Set(ElfSym::End1, Last->First, Last->p_memsz);
+ Set(ElfSym::End2, Last->First, Last->p_memsz);
+ }
+ if (LastRO) {
+ Set(ElfSym::Etext1, LastRO->First, LastRO->p_filesz);
+ Set(ElfSym::Etext2, LastRO->First, LastRO->p_filesz);
+ }
+ if (LastRW) {
+ Set(ElfSym::Edata1, LastRW->First, LastRW->p_filesz);
+ Set(ElfSym::Edata2, LastRW->First, LastRW->p_filesz);
+ }
if (ElfSym::Bss)
- ElfSym::Bss->Section = findSection(".bss");
+ ElfSym::Bss->Section = findSectionInScript(".bss");
// Setup MIPS _gp_disp/__gnu_local_gp symbols which should
// be equal to the _gp symbol's value.
@@ -1736,9 +1769,14 @@ template <class ELFT> void Writer<ELFT>::openFile() {
template <class ELFT> void Writer<ELFT>::writeSectionsBinary() {
uint8_t *Buf = Buffer->getBufferStart();
- for (OutputSection *Sec : OutputSections)
+ for (BaseCommand *Base : Script->Opt.Commands) {
+ auto *Cmd = dyn_cast<OutputSectionCommand>(Base);
+ if (!Cmd)
+ continue;
+ OutputSection *Sec = Cmd->Sec;
if (Sec->Flags & SHF_ALLOC)
- Sec->writeTo<ELFT>(Buf + Sec->Offset);
+ Cmd->writeTo<ELFT>(Buf + Sec->Offset);
+ }
}
// Write section contents to a mmap'ed file.
@@ -1747,31 +1785,45 @@ template <class ELFT> void Writer<ELFT>::writeSections() {
// PPC64 needs to process relocations in the .opd section
// before processing relocations in code-containing sections.
- Out::Opd = findSection(".opd");
- if (Out::Opd) {
+ if (auto *OpdCmd = findSectionCommand(".opd")) {
+ Out::Opd = OpdCmd->Sec;
Out::OpdBuf = Buf + Out::Opd->Offset;
- Out::Opd->template writeTo<ELFT>(Buf + Out::Opd->Offset);
+ OpdCmd->template writeTo<ELFT>(Buf + Out::Opd->Offset);
}
OutputSection *EhFrameHdr =
- In<ELFT>::EhFrameHdr ? In<ELFT>::EhFrameHdr->OutSec : nullptr;
+ (In<ELFT>::EhFrameHdr && !In<ELFT>::EhFrameHdr->empty())
+ ? In<ELFT>::EhFrameHdr->OutSec
+ : nullptr;
// 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
// section while doing it.
- for (OutputSection *Sec : OutputSections)
+ for (BaseCommand *Base : Script->Opt.Commands) {
+ auto *Cmd = dyn_cast<OutputSectionCommand>(Base);
+ if (!Cmd)
+ continue;
+ OutputSection *Sec = Cmd->Sec;
if (Sec->Type == SHT_REL || Sec->Type == SHT_RELA)
- Sec->writeTo<ELFT>(Buf + Sec->Offset);
+ Cmd->writeTo<ELFT>(Buf + Sec->Offset);
+ }
- for (OutputSection *Sec : OutputSections)
+ for (BaseCommand *Base : Script->Opt.Commands) {
+ auto *Cmd = dyn_cast<OutputSectionCommand>(Base);
+ if (!Cmd)
+ continue;
+ OutputSection *Sec = Cmd->Sec;
if (Sec != Out::Opd && Sec != EhFrameHdr && Sec->Type != SHT_REL &&
Sec->Type != SHT_RELA)
- Sec->writeTo<ELFT>(Buf + Sec->Offset);
+ Cmd->writeTo<ELFT>(Buf + Sec->Offset);
+ }
// The .eh_frame_hdr depends on .eh_frame section contents, therefore
// it should be written after .eh_frame is written.
- if (EhFrameHdr && !EhFrameHdr->Sections.empty())
- EhFrameHdr->writeTo<ELFT>(Buf + EhFrameHdr->Offset);
+ if (EhFrameHdr) {
+ OutputSectionCommand *Cmd = Script->getCmd(EhFrameHdr);
+ Cmd->writeTo<ELFT>(Buf + EhFrameHdr->Offset);
+ }
}
template <class ELFT> void Writer<ELFT>::writeBuildId() {