Skip to content

Commit 18821b6

Browse files
committedSep 1, 2017
[ELF] Generate symbol assignments for predefined symbols
The problem with symbol assignments in implicit linker scripts is that they can refer synthetic symbols such as _end, _etext or _edata. The value of these symbols is currently fixed only after all linker script commands are processed, so these assignments will be using non-final and hence invalid value. Rather than fixing the symbol values after all command processing have finished, we instead change the logic to generate symbol assignment commands that set the value of these symbols while processing the commands, this ensures that the value is going to be correct by the time any reference to these symbol is processed and is equivalent to defining these symbols explicitly in linker script as BFD ld does. Differential Revision: https://reviews.llvm.org/D36986 llvm-svn: 312305
1 parent 04567fd commit 18821b6

File tree

3 files changed

+88
-37
lines changed

3 files changed

+88
-37
lines changed
 

‎lld/ELF/Writer.cpp

+81-36
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ template <class ELFT> class Writer {
5454
void sortSections();
5555
void finalizeSections();
5656
void addPredefinedSections();
57+
void addPredefinedSymbols();
5758

5859
std::vector<PhdrEntry *> createPhdrs();
5960
void removeEmptyPTLoad();
@@ -200,6 +201,12 @@ template <class ELFT> void Writer<ELFT>::run() {
200201
parallelForEach(OutputSections,
201202
[](OutputSection *Sec) { Sec->maybeCompress<ELFT>(); });
202203

204+
// Generate assignments for predefined symbols (e.g. _end or _etext)
205+
// before assigning addresses. These symbols may be referred to from
206+
// the linker script and we need to ensure they have the correct value
207+
// prior evaluating any expressions using these symbols.
208+
addPredefinedSymbols();
209+
203210
Script->assignAddresses();
204211
Script->allocateHeaders(Phdrs);
205212

@@ -920,6 +927,80 @@ template <class ELFT> void Writer<ELFT>::createSections() {
920927
sortCtorsDtors(findSection(".dtors"));
921928
}
922929

930+
// This function generates assignments for predefined symbols (e.g. _end or
931+
// _etext) and inserts them into the commands sequence to be processed at the
932+
// appropriate time. This ensures that the value is going to be correct by the
933+
// time any references to these symbols are processed and is equivalent to
934+
// defining these symbols explicitly in the linker script.
935+
template <class ELFT> void Writer<ELFT>::addPredefinedSymbols() {
936+
PhdrEntry *Last = nullptr;
937+
PhdrEntry *LastRO = nullptr;
938+
PhdrEntry *LastRW = nullptr;
939+
for (PhdrEntry *P : Phdrs) {
940+
if (P->p_type != PT_LOAD)
941+
continue;
942+
Last = P;
943+
if (P->p_flags & PF_W)
944+
LastRW = P;
945+
else
946+
LastRO = P;
947+
}
948+
949+
auto Make = [](DefinedRegular *S) {
950+
auto *Cmd = make<SymbolAssignment>(
951+
S->getName(), [=] { return Script->getSymbolValue("", "."); }, "");
952+
Cmd->Sym = S;
953+
return Cmd;
954+
};
955+
956+
auto IsSection = [](OutputSection *Sec) {
957+
return [=](BaseCommand *Base) { return Base == Sec; };
958+
};
959+
960+
auto IsNoBits = [](BaseCommand *Base) {
961+
if (auto *Sec = dyn_cast<OutputSection>(Base))
962+
return Sec->Type == SHT_NOBITS;
963+
return false;
964+
};
965+
966+
if (Last) {
967+
// _end is the first location after the uninitialized data region.
968+
auto E = Script->Opt.Commands.end();
969+
auto I = Script->Opt.Commands.begin();
970+
I = std::find_if(I, E, IsSection(Last->Last));
971+
if (I != E) {
972+
if (ElfSym::End1)
973+
Script->Opt.Commands.insert(++I, Make(ElfSym::End1));
974+
if (ElfSym::End2)
975+
Script->Opt.Commands.insert(++I, Make(ElfSym::End2));
976+
}
977+
}
978+
if (LastRO) {
979+
// _etext is the first location after the last read-only loadable segment.
980+
auto E = Script->Opt.Commands.end();
981+
auto I = Script->Opt.Commands.begin();
982+
I = std::find_if(I, E, IsSection(LastRO->Last));
983+
if (I != E) {
984+
if (ElfSym::Etext1)
985+
Script->Opt.Commands.insert(++I, Make(ElfSym::Etext1));
986+
if (ElfSym::Etext2)
987+
Script->Opt.Commands.insert(++I, Make(ElfSym::Etext2));
988+
}
989+
}
990+
if (LastRW) {
991+
// _edata points to the end of the last non SHT_NOBITS section.
992+
auto E = Script->Opt.Commands.end();
993+
auto I = Script->Opt.Commands.begin();
994+
I = std::find_if(std::find_if(I, E, IsSection(LastRW->First)), E, IsNoBits);
995+
if (I != E) {
996+
if (ElfSym::Edata2)
997+
I = Script->Opt.Commands.insert(I, Make(ElfSym::Edata2));
998+
if (ElfSym::Edata1)
999+
I = Script->Opt.Commands.insert(I, Make(ElfSym::Edata1));
1000+
}
1001+
}
1002+
}
1003+
9231004
// We want to find how similar two ranks are.
9241005
// The more branches in getSectionRank that match, the more similar they are.
9251006
// Since each branch corresponds to a bit flag, we can just use
@@ -1718,42 +1799,6 @@ static uint16_t getELFType() {
17181799
// to each section. This function fixes some predefined
17191800
// symbol values that depend on section address and size.
17201801
template <class ELFT> void Writer<ELFT>::fixPredefinedSymbols() {
1721-
// _etext is the first location after the last read-only loadable segment.
1722-
// _edata is the first location after the last read-write loadable segment.
1723-
// _end is the first location after the uninitialized data region.
1724-
PhdrEntry *Last = nullptr;
1725-
PhdrEntry *LastRO = nullptr;
1726-
PhdrEntry *LastRW = nullptr;
1727-
for (PhdrEntry *P : Phdrs) {
1728-
if (P->p_type != PT_LOAD)
1729-
continue;
1730-
Last = P;
1731-
if (P->p_flags & PF_W)
1732-
LastRW = P;
1733-
else
1734-
LastRO = P;
1735-
}
1736-
1737-
auto Set = [](DefinedRegular *S, OutputSection *Cmd, uint64_t Value) {
1738-
if (S) {
1739-
S->Section = Cmd;
1740-
S->Value = Value;
1741-
}
1742-
};
1743-
1744-
if (Last) {
1745-
Set(ElfSym::End1, Last->First, Last->p_memsz);
1746-
Set(ElfSym::End2, Last->First, Last->p_memsz);
1747-
}
1748-
if (LastRO) {
1749-
Set(ElfSym::Etext1, LastRO->First, LastRO->p_filesz);
1750-
Set(ElfSym::Etext2, LastRO->First, LastRO->p_filesz);
1751-
}
1752-
if (LastRW) {
1753-
Set(ElfSym::Edata1, LastRW->First, LastRW->p_filesz);
1754-
Set(ElfSym::Edata2, LastRW->First, LastRW->p_filesz);
1755-
}
1756-
17571802
if (ElfSym::Bss)
17581803
ElfSym::Bss->Section = findSection(".bss");
17591804

‎lld/test/ELF/edata-etext.s

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
# CHECK: SYMBOL TABLE:
2020
# CHECK-NEXT: 0000000000000000 *UND* 00000000
2121
# CHECK-NEXT: 0000000000202002 .data 00000000 _edata
22-
# CHECK-NEXT: 000000000020200a .data 00000000 _end
22+
# CHECK-NEXT: 000000000020200a .bss 00000000 _end
2323
# CHECK-NEXT: 0000000000201001 .text 00000000 _etext
2424
# CHECK-NEXT: 0000000000201000 .text 00000000 _start
2525

‎lld/test/ELF/linkerscript/symbol-reserved.s

+6
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,12 @@
2727
# RUN: llvm-objdump -t %t1 | FileCheck --check-prefix=ALIGN-SUB %s
2828
# ALIGN-SUB: 0000000000000006 *ABS* 00000000 .hidden newsym
2929

30+
# RUN: echo "PROVIDE_HIDDEN(newsym = ALIGN(_end, CONSTANT(MAXPAGESIZE)) + 5);" > %t.script
31+
# RUN: ld.lld -o %t1 %t %t.script
32+
# RUN: llvm-objdump -t %t1 | FileCheck --check-prefix=RELATIVE %s
33+
# RELATIVE: 0000000000202005 .text 00000000 .hidden newsym
34+
# RELATIVE: 0000000000201007 .text 00000000 _end
35+
3036
# RUN: echo "PROVIDE_HIDDEN(newsym = ALIGN(_end, CONSTANT(MAXPAGESIZE)) + 5);" > %t.script
3137
# RUN: ld.lld -o %t1 --script %p/Inputs/symbol-reserved.script %t %t.script
3238
# RUN: llvm-objdump -t %t1 | FileCheck --check-prefix=RELATIVE-ADD %s

0 commit comments

Comments
 (0)
Please sign in to comment.