summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGeorge Rimar <grimar@accesssoftek.com>2016-08-17 07:44:19 +0000
committerGeorge Rimar <grimar@accesssoftek.com>2016-08-17 07:44:19 +0000
commit8ceadb38a88fa5a71c8c325f420ba3dfd073ce3c (patch)
tree40aa7a7c40cfc4d2a31f770472bea85df6218fc9
parentc96f421ad46734d721de8acee4d3ddb3fbd9b3fe (diff)
downloadbcm5719-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.cpp18
-rw-r--r--lld/ELF/LinkerScript.h2
-rw-r--r--lld/ELF/Writer.cpp12
-rw-r--r--lld/test/ELF/linkerscript/linkerscript-at.s128
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
OpenPOWER on IntegriCloud