diff options
| author | George Rimar <grimar@accesssoftek.com> | 2016-08-17 07:44:19 +0000 |
|---|---|---|
| committer | George Rimar <grimar@accesssoftek.com> | 2016-08-17 07:44:19 +0000 |
| commit | 8ceadb38a88fa5a71c8c325f420ba3dfd073ce3c (patch) | |
| tree | 40aa7a7c40cfc4d2a31f770472bea85df6218fc9 | |
| parent | c96f421ad46734d721de8acee4d3ddb3fbd9b3fe (diff) | |
| download | bcm5719-llvm-8ceadb38a88fa5a71c8c325f420ba3dfd073ce3c.tar.gz bcm5719-llvm-8ceadb38a88fa5a71c8c325f420ba3dfd073ce3c.zip | |
[ELF] - linkerscript AT keyword (in output section description) implemented.
The linker will normally set the LMA equal to the VMA.
You can change that by using the AT keyword.
The expression lma that follows the AT keyword specifies
the load address of the section.
Patch implements this keyword.
Differential revision: https://reviews.llvm.org/D19272
llvm-svn: 278911
| -rw-r--r-- | lld/ELF/LinkerScript.cpp | 18 | ||||
| -rw-r--r-- | lld/ELF/LinkerScript.h | 2 | ||||
| -rw-r--r-- | lld/ELF/Writer.cpp | 12 | ||||
| -rw-r--r-- | lld/test/ELF/linkerscript/linkerscript-at.s | 128 |
4 files changed, 158 insertions, 2 deletions
diff --git a/lld/ELF/LinkerScript.cpp b/lld/ELF/LinkerScript.cpp index df400a4d0d2..1b6ff233443 100644 --- a/lld/ELF/LinkerScript.cpp +++ b/lld/ELF/LinkerScript.cpp @@ -504,6 +504,14 @@ ArrayRef<uint8_t> LinkerScript<ELFT>::getFiller(StringRef Name) { return {}; } +template <class ELFT> typename Expr LinkerScript<ELFT>::getLma(StringRef Name) { + for (const std::unique_ptr<BaseCommand> &Base : Opt.Commands) + if (auto *Cmd = dyn_cast<OutputSectionCommand>(Base.get())) + if (Cmd->LmaExpr && Cmd->Name == Name) + return Cmd->LmaExpr; + return {}; +} + // Returns the index of the given section name in linker script // SECTIONS commands. Sections are laid out as the same order as they // were in the script. If a given name did not appear in the script, @@ -613,6 +621,7 @@ private: SortKind readSortKind(); SymbolAssignment *readProvideHidden(bool Provide, bool Hidden); SymbolAssignment *readProvideOrAssignment(StringRef Tok); + void readAt(OutputSectionCommand *Cmd); Expr readAlign(); void readSort(); Expr readAssert(); @@ -918,6 +927,12 @@ Expr ScriptParser::readAssert() { }; } +void ScriptParser::readAt(OutputSectionCommand *Cmd) { + expect("("); + Cmd->LmaExpr = readExpr(); + expect(")"); +} + OutputSectionCommand * ScriptParser::readOutputSectionDescription(StringRef OutSec) { OutputSectionCommand *Cmd = new OutputSectionCommand(OutSec); @@ -929,6 +944,9 @@ ScriptParser::readOutputSectionDescription(StringRef OutSec) { expect(":"); + if (skip("AT")) + readAt(Cmd); + if (skip("ALIGN")) Cmd->AlignExpr = readAlign(); diff --git a/lld/ELF/LinkerScript.h b/lld/ELF/LinkerScript.h index d33c12e41ee..4cb9e99f52e 100644 --- a/lld/ELF/LinkerScript.h +++ b/lld/ELF/LinkerScript.h @@ -83,6 +83,7 @@ struct OutputSectionCommand : BaseCommand { StringRef Name; Expr AddrExpr; Expr AlignExpr; + Expr LmaExpr; std::vector<std::unique_ptr<BaseCommand>> Commands; std::vector<StringRef> Phdrs; std::vector<uint8_t> Filler; @@ -147,6 +148,7 @@ public: bool ignoreInterpSection(); ArrayRef<uint8_t> getFiller(StringRef Name); + Expr getLma(StringRef Name); bool shouldKeep(InputSectionBase<ELFT> *S); void assignAddresses(); int compareSections(StringRef A, StringRef B); diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp index 5a395599ed0..e3699818add 100644 --- a/lld/ELF/Writer.cpp +++ b/lld/ELF/Writer.cpp @@ -963,9 +963,13 @@ std::vector<PhdrEntry<ELFT>> Writer<ELFT>::createPhdrs() { if (!needsPtLoad(Sec)) continue; - // If flags changed then we want new load segment. + // Segments are contiguous memory regions that has the same attributes + // (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 + // different flags or is loaded at a discontiguous address using AT linker + // script command. uintX_t NewFlags = Sec->getPhdrFlags(); - if (Flags != NewFlags) { + if (Script<ELFT>::X->getLma(Sec->getName()) || Flags != NewFlags) { Load = AddHdr(PT_LOAD, NewFlags); Flags = NewFlags; } @@ -1128,7 +1132,11 @@ template <class ELFT> void Writer<ELFT>::setPhdrs() { H.p_align = Target->PageSize; else if (H.p_type == PT_GNU_RELRO) H.p_align = 1; + H.p_paddr = H.p_vaddr; + if (H.p_type == PT_LOAD && First) + if (Expr LmaExpr = Script<ELFT>::X->getLma(First->getName())) + H.p_paddr = LmaExpr(H.p_vaddr); // The TLS pointer goes after PT_TLS. At least glibc will align it, // so round up the size to make sure the offsets are correct. diff --git a/lld/test/ELF/linkerscript/linkerscript-at.s b/lld/test/ELF/linkerscript/linkerscript-at.s new file mode 100644 index 00000000000..c26461c9d27 --- /dev/null +++ b/lld/test/ELF/linkerscript/linkerscript-at.s @@ -0,0 +1,128 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t +# RUN: echo "SECTIONS { \ +# RUN: . = 0x1000; \ +# RUN: .aaa : AT(0x2000) \ +# RUN: { \ +# RUN: *(.aaa) \ +# RUN: } \ +# RUN: .bbb : \ +# RUN: { \ +# RUN: *(.bbb) \ +# RUN: } \ +# RUN: .ccc : AT(0x3000) \ +# RUN: { \ +# RUN: *(.ccc) \ +# RUN: } \ +# RUN: .ddd : AT(0x4000) \ +# RUN: { \ +# RUN: *(.ddd) \ +# RUN: } \ +# RUN: }" > %t.script +# RUN: ld.lld %t --script %t.script -o %t2 +# RUN: llvm-readobj -program-headers %t2 | FileCheck %s + +# CHECK: ProgramHeaders [ +# CHECK-NEXT: ProgramHeader { +# CHECK-NEXT: Type: PT_PHDR +# CHECK-NEXT: Offset: 0x40 +# CHECK-NEXT: VirtualAddress: 0x40 +# CHECK-NEXT: PhysicalAddress: 0x40 +# CHECK-NEXT: FileSize: +# CHECK-NEXT: MemSize: +# CHECK-NEXT: Flags [ +# CHECK-NEXT: PF_R +# CHECK-NEXT: ] +# CHECK-NEXT: Alignment: 8 +# CHECK-NEXT: } +# CHECK-NEXT: ProgramHeader { +# CHECK-NEXT: Type: PT_LOAD +# CHECK-NEXT: Offset: 0x0 +# CHECK-NEXT: VirtualAddress: 0x0 +# CHECK-NEXT: PhysicalAddress: 0x0 +# CHECK-NEXT: FileSize: +# CHECK-NEXT: MemSize: +# CHECK-NEXT: Flags [ +# CHECK-NEXT: PF_R +# CHECK-NEXT: ] +# CHECK-NEXT: Alignment: +# CHECK-NEXT: } +# CHECK-NEXT: ProgramHeader { +# CHECK-NEXT: Type: PT_LOAD +# CHECK-NEXT: Offset: 0x1000 +# CHECK-NEXT: VirtualAddress: 0x1000 +# CHECK-NEXT: PhysicalAddress: 0x2000 +# CHECK-NEXT: FileSize: 16 +# CHECK-NEXT: MemSize: 16 +# CHECK-NEXT: Flags [ +# CHECK-NEXT: PF_R +# CHECK-NEXT: ] +# CHECK-NEXT: Alignment: +# CHECK-NEXT: } +# CHECK-NEXT: ProgramHeader { +# CHECK-NEXT: Type: PT_LOAD +# CHECK-NEXT: Offset: 0x1010 +# CHECK-NEXT: VirtualAddress: 0x1010 +# CHECK-NEXT: PhysicalAddress: 0x3000 +# CHECK-NEXT: FileSize: 8 +# CHECK-NEXT: MemSize: 8 +# CHECK-NEXT: Flags [ +# CHECK-NEXT: PF_R +# CHECK-NEXT: ] +# CHECK-NEXT: Alignment: 4096 +# CHECK-NEXT: } +# CHECK-NEXT: ProgramHeader { +# CHECK-NEXT: Type: PT_LOAD +# CHECK-NEXT: Offset: 0x1018 +# CHECK-NEXT: VirtualAddress: 0x1018 +# CHECK-NEXT: PhysicalAddress: 0x4000 +# CHECK-NEXT: FileSize: 8 +# CHECK-NEXT: MemSize: 8 +# CHECK-NEXT: Flags [ +# CHECK-NEXT: PF_R +# CHECK-NEXT: ] +# CHECK-NEXT: Alignment: 4096 +# CHECK-NEXT: } +# CHECK-NEXT: ProgramHeader { +# CHECK-NEXT: Type: PT_LOAD +# CHECK-NEXT: Offset: 0x1020 +# CHECK-NEXT: VirtualAddress: 0x1020 +# CHECK-NEXT: PhysicalAddress: 0x1020 +# CHECK-NEXT: FileSize: 1 +# CHECK-NEXT: MemSize: 1 +# CHECK-NEXT: Flags [ +# CHECK-NEXT: PF_R +# CHECK-NEXT: PF_X +# CHECK-NEXT: ] +# CHECK-NEXT: Alignment: 4096 +# CHECK-NEXT: } +# CHECK-NEXT: ProgramHeader { +# CHECK-NEXT: Type: PT_GNU_STACK +# CHECK-NEXT: Offset: +# CHECK-NEXT: VirtualAddress: 0x0 +# CHECK-NEXT: PhysicalAddress: 0x0 +# CHECK-NEXT: FileSize: +# CHECK-NEXT: MemSize: +# CHECK-NEXT: Flags [ +# CHECK-NEXT: PF_R +# CHECK-NEXT: PF_W +# CHECK-NEXT: ] +# CHECK-NEXT: Alignment: 0 +# CHECK-NEXT: } +# CHECK-NEXT: ] + +.global _start +_start: + nop + +.section .aaa, "a" +.quad 0 + +.section .bbb, "a" +.quad 0 + +.section .ccc, "a" +.quad 0 + +.section .ddd, "a" +.quad 0 |

