diff options
Diffstat (limited to 'lld/ELF/Writer.cpp')
| -rw-r--r-- | lld/ELF/Writer.cpp | 117 |
1 files changed, 81 insertions, 36 deletions
diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp index 0a316391c4f..68e14ce539d 100644 --- a/lld/ELF/Writer.cpp +++ b/lld/ELF/Writer.cpp @@ -54,6 +54,7 @@ private: void sortSections(); void finalizeSections(); void addPredefinedSections(); + void addPredefinedSymbols(); std::vector<PhdrEntry *> createPhdrs(); void removeEmptyPTLoad(); @@ -200,6 +201,12 @@ template <class ELFT> void Writer<ELFT>::run() { parallelForEach(OutputSections, [](OutputSection *Sec) { Sec->maybeCompress<ELFT>(); }); + // Generate assignments for predefined symbols (e.g. _end or _etext) + // before assigning addresses. These symbols may be referred to from + // the linker script and we need to ensure they have the correct value + // prior evaluating any expressions using these symbols. + addPredefinedSymbols(); + Script->assignAddresses(); Script->allocateHeaders(Phdrs); @@ -920,6 +927,80 @@ template <class ELFT> void Writer<ELFT>::createSections() { sortCtorsDtors(findSection(".dtors")); } +// This function generates assignments for predefined symbols (e.g. _end or +// _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 +// time any references to these symbols are processed and is equivalent to +// defining these symbols explicitly in the linker script. +template <class ELFT> void Writer<ELFT>::addPredefinedSymbols() { + PhdrEntry *Last = nullptr; + PhdrEntry *LastRO = nullptr; + PhdrEntry *LastRW = nullptr; + for (PhdrEntry *P : Phdrs) { + if (P->p_type != PT_LOAD) + continue; + Last = P; + if (P->p_flags & PF_W) + LastRW = P; + else + LastRO = P; + } + + auto Make = [](DefinedRegular *S) { + auto *Cmd = make<SymbolAssignment>( + S->getName(), [=] { return Script->getSymbolValue("", "."); }, ""); + Cmd->Sym = S; + return Cmd; + }; + + auto IsSection = [](OutputSection *Sec) { + return [=](BaseCommand *Base) { return Base == Sec; }; + }; + + auto IsNoBits = [](BaseCommand *Base) { + if (auto *Sec = dyn_cast<OutputSection>(Base)) + return Sec->Type == SHT_NOBITS; + return false; + }; + + if (Last) { + // _end is the first location after the uninitialized data region. + auto E = Script->Opt.Commands.end(); + auto I = Script->Opt.Commands.begin(); + I = std::find_if(I, E, IsSection(Last->Last)); + if (I != E) { + if (ElfSym::End1) + Script->Opt.Commands.insert(++I, Make(ElfSym::End1)); + if (ElfSym::End2) + Script->Opt.Commands.insert(++I, Make(ElfSym::End2)); + } + } + if (LastRO) { + // _etext is the first location after the last read-only loadable segment. + auto E = Script->Opt.Commands.end(); + auto I = Script->Opt.Commands.begin(); + I = std::find_if(I, E, IsSection(LastRO->Last)); + if (I != E) { + if (ElfSym::Etext1) + Script->Opt.Commands.insert(++I, Make(ElfSym::Etext1)); + if (ElfSym::Etext2) + Script->Opt.Commands.insert(++I, Make(ElfSym::Etext2)); + } + } + if (LastRW) { + // _edata points to the end of the last non SHT_NOBITS section. + auto E = Script->Opt.Commands.end(); + auto I = Script->Opt.Commands.begin(); + I = std::find_if(std::find_if(I, E, IsSection(LastRW->First)), E, IsNoBits); + if (I != E) { + if (ElfSym::Edata2) + I = Script->Opt.Commands.insert(I, Make(ElfSym::Edata2)); + if (ElfSym::Edata1) + I = Script->Opt.Commands.insert(I, Make(ElfSym::Edata1)); + } + } +} + // We want to find how similar two ranks are. // The more branches in getSectionRank that match, the more similar they are. // Since each branch corresponds to a bit flag, we can just use @@ -1718,42 +1799,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() { - // _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. - PhdrEntry *Last = nullptr; - PhdrEntry *LastRO = nullptr; - PhdrEntry *LastRW = nullptr; - for (PhdrEntry *P : Phdrs) { - if (P->p_type != PT_LOAD) - continue; - Last = P; - if (P->p_flags & PF_W) - LastRW = P; - else - LastRO = P; - } - - auto Set = [](DefinedRegular *S, OutputSection *Cmd, uint64_t Value) { - if (S) { - S->Section = Cmd; - 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"); |

