diff options
| author | Eugene Leviant <evgeny.leviant@gmail.com> | 2016-09-07 07:08:43 +0000 |
|---|---|---|
| committer | Eugene Leviant <evgeny.leviant@gmail.com> | 2016-09-07 07:08:43 +0000 |
| commit | db741e7203b9246816bc911e3e5fa7b19ffc0c14 (patch) | |
| tree | 2b9cf7ba49c660b68a099eb23eb54c03695f3f62 | |
| parent | f333de37528567ce384554bc333386e4a474af0b (diff) | |
| download | bcm5719-llvm-db741e7203b9246816bc911e3e5fa7b19ffc0c14.tar.gz bcm5719-llvm-db741e7203b9246816bc911e3e5fa7b19ffc0c14.zip | |
Support ABSOLUE keyword in symbol assignments
This patch allows making section defined symbols absolute:
.foo : {
begin_foo = ABSOLUTE(.);
*(.foo)
}
Differential revision: https://reviews.llvm.org/D24135
llvm-svn: 280788
| -rw-r--r-- | lld/ELF/LinkerScript.cpp | 69 | ||||
| -rw-r--r-- | lld/ELF/LinkerScript.h | 6 | ||||
| -rw-r--r-- | lld/test/ELF/linkerscript/symbols-synthetic.s | 17 |
3 files changed, 62 insertions, 30 deletions
diff --git a/lld/ELF/LinkerScript.cpp b/lld/ELF/LinkerScript.cpp index 5f04382a64b..8e0016a2310 100644 --- a/lld/ELF/LinkerScript.cpp +++ b/lld/ELF/LinkerScript.cpp @@ -56,6 +56,12 @@ template <class ELFT> static void addSynthetic(SymbolAssignment *Cmd) { Cmd->Sym = Sym->body(); } +template <class ELFT> static void addSymbol(SymbolAssignment *Cmd) { + if (Cmd->IsAbsolute) + addRegular<ELFT>(Cmd); + else + addSynthetic<ELFT>(Cmd); +} // If a symbol was in PROVIDE(), we need to define it only when // it is an undefined symbol. template <class ELFT> static bool shouldDefine(SymbolAssignment *Cmd) { @@ -184,7 +190,7 @@ LinkerScript<ELFT>::createInputSectionList(OutputSectionCommand &OutCmd) { for (const std::unique_ptr<BaseCommand> &Base : OutCmd.Commands) { if (auto *OutCmd = dyn_cast<SymbolAssignment>(Base.get())) { if (shouldDefine<ELFT>(OutCmd)) - addSynthetic<ELFT>(OutCmd); + addSymbol<ELFT>(OutCmd); OutCmd->GoesAfter = Ret.empty() ? nullptr : Ret.back(); continue; } @@ -267,6 +273,26 @@ void LinkerScript<ELFT>::createSections(OutputSectionFactory<ELFT> &Factory) { } } +// Sets value of a section-defined symbol. Two kinds of +// symbols are processed: synthetic symbols, whose value +// is an offset from beginning of section and regular +// symbols whose value is absolute. +template <class ELFT> +static void assignSectionSymbol(SymbolAssignment *Cmd, + OutputSectionBase<ELFT> *Sec, + typename ELFT::uint Off) { + if (!Cmd->Sym) + return; + + if (auto *Body = dyn_cast<DefinedSynthetic<ELFT>>(Cmd->Sym)) { + Body->Section = Sec; + Body->Value = Cmd->Expression(Sec->getVA() + Off) - Sec->getVA(); + return; + } + auto *Body = cast<DefinedRegular<ELFT>>(Cmd->Sym); + Body->Value = Cmd->Expression(Sec->getVA() + Off); +} + // Linker script may define start and end symbols for special section types, // like .got, .eh_frame_hdr, .eh_frame and others. Those sections are not a list // of regular input input sections, therefore our way of defining symbols for @@ -280,12 +306,7 @@ void addStartEndSymbols(OutputSectionCommand *Cmd, for (std::unique_ptr<BaseCommand> &Base : Cmd->Commands) { if (auto *AssignCmd = dyn_cast<SymbolAssignment>(Base.get())) { - if (auto *Sym = cast_or_null<DefinedSynthetic<ELFT>>(AssignCmd->Sym)) { - Sym->Section = Sec; - Sym->Value = - AssignCmd->Expression(Sec->getVA() + (Start ? 0 : Sec->getSize())) - - Sec->getVA(); - } + assignSectionSymbol<ELFT>(AssignCmd, Sec, Start ? 0 : Sec->getSize()); } else { if (!Start && isa<SymbolAssignment>(PrevCmd)) error("section '" + Sec->getName() + @@ -322,19 +343,13 @@ void assignOffsets(OutputSectionCommand *Cmd, OutputSectionBase<ELFT> *Sec) { if (D != AssignCmd->GoesAfter) break; - uintX_t Value = AssignCmd->Expression(Sec->getVA() + Off) - Sec->getVA(); if (AssignCmd->Name == ".") { // Update to location counter means update to section size. - Off = Value; + Off = AssignCmd->Expression(Sec->getVA() + Off) - Sec->getVA(); Sec->setSize(Off); continue; } - - if (DefinedSynthetic<ELFT> *Sym = - cast_or_null<DefinedSynthetic<ELFT>>(AssignCmd->Sym)) { - Sym->Section = OutSec; - Sym->Value = Value; - } + assignSectionSymbol<ELFT>(AssignCmd, Sec, Off); } }; @@ -631,7 +646,7 @@ private: unsigned readPhdrType(); SortKind readSortKind(); SymbolAssignment *readProvideHidden(bool Provide, bool Hidden); - SymbolAssignment *readProvideOrAssignment(StringRef Tok); + SymbolAssignment *readProvideOrAssignment(StringRef Tok, bool MakeAbsolute); void readSort(); Expr readAssert(); @@ -710,7 +725,7 @@ void ScriptParser::readLinkerScript() { readSections(); } else if (Tok == "VERSION") { readVersion(); - } else if (SymbolAssignment *Cmd = readProvideOrAssignment(Tok)) { + } else if (SymbolAssignment *Cmd = readProvideOrAssignment(Tok, true)) { if (Opt.HasContents) Opt.Commands.emplace_back(Cmd); else @@ -872,7 +887,7 @@ void ScriptParser::readSections() { expect("{"); while (!Error && !skip("}")) { StringRef Tok = next(); - BaseCommand *Cmd = readProvideOrAssignment(Tok); + BaseCommand *Cmd = readProvideOrAssignment(Tok, true); if (!Cmd) { if (Tok == "ASSERT") Cmd = new AssertCommand(readAssert()); @@ -1020,7 +1035,7 @@ ScriptParser::readOutputSectionDescription(StringRef OutSec) { while (!Error && !skip("}")) { StringRef Tok = next(); - if (SymbolAssignment *Assignment = readProvideOrAssignment(Tok)) + if (SymbolAssignment *Assignment = readProvideOrAssignment(Tok, false)) Cmd->Commands.emplace_back(Assignment); else if (Tok == "FILL") Cmd->Filler = readFill(); @@ -1063,7 +1078,8 @@ SymbolAssignment *ScriptParser::readProvideHidden(bool Provide, bool Hidden) { return Cmd; } -SymbolAssignment *ScriptParser::readProvideOrAssignment(StringRef Tok) { +SymbolAssignment *ScriptParser::readProvideOrAssignment(StringRef Tok, + bool MakeAbsolute) { SymbolAssignment *Cmd = nullptr; if (peek() == "=" || peek() == "+=") { Cmd = readAssignment(Tok); @@ -1075,6 +1091,8 @@ SymbolAssignment *ScriptParser::readProvideOrAssignment(StringRef Tok) { } else if (Tok == "PROVIDE_HIDDEN") { Cmd = readProvideHidden(true, true); } + if (Cmd && MakeAbsolute) + Cmd->IsAbsolute = true; return Cmd; } @@ -1153,11 +1171,18 @@ static uint64_t getHeaderSize() { SymbolAssignment *ScriptParser::readAssignment(StringRef Name) { StringRef Op = next(); + bool IsAbsolute = false; + Expr E; assert(Op == "=" || Op == "+="); - Expr E = readExpr(); + if (skip("ABSOLUTE")) { + E = readParenExpr(); + IsAbsolute = true; + } else { + E = readExpr(); + } if (Op == "+=") E = [=](uint64_t Dot) { return getSymbolValue(Name, Dot) + E(Dot); }; - return new SymbolAssignment(Name, E); + return new SymbolAssignment(Name, E, IsAbsolute); } // This is an operator-precedence parser to parse a linker diff --git a/lld/ELF/LinkerScript.h b/lld/ELF/LinkerScript.h index bb1f092bb0c..b27d1da225b 100644 --- a/lld/ELF/LinkerScript.h +++ b/lld/ELF/LinkerScript.h @@ -54,8 +54,9 @@ struct BaseCommand { }; struct SymbolAssignment : BaseCommand { - SymbolAssignment(StringRef Name, Expr E) - : BaseCommand(AssignmentKind), Name(Name), Expression(E) {} + SymbolAssignment(StringRef Name, Expr E, bool IsAbsolute) + : BaseCommand(AssignmentKind), Name(Name), Expression(E), + IsAbsolute(IsAbsolute) {} static bool classof(const BaseCommand *C); // The LHS of an expression. Name is either a symbol name or ".". @@ -68,6 +69,7 @@ struct SymbolAssignment : BaseCommand { // Command attributes for PROVIDE, HIDDEN and PROVIDE_HIDDEN. bool Provide = false; bool Hidden = false; + bool IsAbsolute; InputSectionData *GoesAfter = nullptr; }; diff --git a/lld/test/ELF/linkerscript/symbols-synthetic.s b/lld/test/ELF/linkerscript/symbols-synthetic.s index 2ab7e6896f9..9a3389ccbb0 100644 --- a/lld/test/ELF/linkerscript/symbols-synthetic.s +++ b/lld/test/ELF/linkerscript/symbols-synthetic.s @@ -10,7 +10,9 @@ # RUN: *(.foo) \ # RUN: end_foo = .; \ # RUN: PROVIDE_HIDDEN(_end_sec = .); \ +# RUN: PROVIDE(_end_sec_abs = ABSOLUTE(.)); \ # RUN: size_foo_1 = SIZEOF(.foo); \ +# RUN: size_foo_1_abs = ABSOLUTE(SIZEOF(.foo)); \ # RUN: . = ALIGN(0x1000); \ # RUN: begin_bar = .; \ # RUN: *(.bar) \ @@ -19,10 +21,10 @@ # RUN: size_foo_3 = SIZEOF(.foo); \ # RUN: .eh_frame_hdr : { \ # RUN: __eh_frame_hdr_start = .; \ -# RUN: __eh_frame_hdr_start2 = ALIGN(0x10); \ +# RUN: __eh_frame_hdr_start2 = ABSOLUTE(ALIGN(0x10)); \ # RUN: *(.eh_frame_hdr) \ # RUN: __eh_frame_hdr_end = .; \ -# RUN: __eh_frame_hdr_end2 = ALIGN(0x10); } \ +# RUN: __eh_frame_hdr_end2 = ABSOLUTE(ALIGN(0x10)); } \ # RUN: }" > %t.script # RUN: ld.lld -o %t1 --eh-frame-hdr --script %t.script %t # RUN: llvm-objdump -t %t1 | FileCheck --check-prefix=SIMPLE %s @@ -34,7 +36,7 @@ # RUN: PROVIDE_HIDDEN(_begin_sec = .); \ # RUN: __eh_frame_hdr_start = .; \ # RUN: *(.eh_frame_hdr) \ -# RUN: __eh_frame_hdr_end = .; \ +# RUN: PROVIDE_HIDDEN(_end_sec_abs = ABSOLUTE(.)); \ # RUN: *(.eh_frame_hdr) } \ # RUN: PROVIDE_HIDDEN(_end_sec = .); \ # RUN: }" > %t.script @@ -46,23 +48,26 @@ # RUN: PROVIDE_HIDDEN(_begin_sec = .); \ # RUN: *(.eh_frame_hdr) \ # RUN: *(.eh_frame_hdr) \ +# RUN: PROVIDE_HIDDEN(_end_sec_abs = ABSOLUTE(.)); \ # RUN: PROVIDE_HIDDEN(_end_sec = .); } \ # RUN: }" > %t.script # RUN: ld.lld -o %t1 --eh-frame-hdr --script %t.script %t # SIMPLE: 0000000000000160 .foo 00000000 .hidden _end_sec # SIMPLE: 0000000000000158 .foo 00000000 _begin_sec +# SIMPLE-NEXT: 0000000000000160 *ABS* 00000000 _end_sec_abs # SIMPLE-NEXT: 0000000000000158 .foo 00000000 begin_foo # SIMPLE-NEXT: 0000000000000160 .foo 00000000 end_foo # SIMPLE-NEXT: 0000000000000008 .foo 00000000 size_foo_1 +# SIMPLE-NEXT: 0000000000000008 *ABS* 00000000 size_foo_1_abs # SIMPLE-NEXT: 0000000000001000 .foo 00000000 begin_bar # SIMPLE-NEXT: 0000000000001004 .foo 00000000 end_bar # SIMPLE-NEXT: 0000000000000eac .foo 00000000 size_foo_2 # SIMPLE-NEXT: 0000000000000eac *ABS* 00000000 size_foo_3 # SIMPLE-NEXT: 0000000000001004 .eh_frame_hdr 00000000 __eh_frame_hdr_start -# SIMPLE-NEXT: 0000000000001010 .eh_frame_hdr 00000000 __eh_frame_hdr_start2 +# SIMPLE-NEXT: 0000000000001010 *ABS* 00000000 __eh_frame_hdr_start2 # SIMPLE-NEXT: 0000000000001018 .eh_frame_hdr 00000000 __eh_frame_hdr_end -# SIMPLE-NEXT: 0000000000001020 .eh_frame_hdr 00000000 __eh_frame_hdr_end2 +# SIMPLE-NEXT: 0000000000001020 *ABS* 00000000 __eh_frame_hdr_end2 # ERROR: section '.eh_frame_hdr' supports only start and end symbols .global _start @@ -80,4 +85,4 @@ _start: nop .cfi_endproc -.global _begin_sec, _end_sec +.global _begin_sec, _end_sec, _end_sec_abs |

