Skip to content

Commit 8ceadb3

Browse files
author
George Rimar
committedAug 17, 2016
[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
1 parent c96f421 commit 8ceadb3

File tree

4 files changed

+158
-2
lines changed

4 files changed

+158
-2
lines changed
 

‎lld/ELF/LinkerScript.cpp

+18
Original file line numberDiff line numberDiff line change
@@ -504,6 +504,14 @@ ArrayRef<uint8_t> LinkerScript<ELFT>::getFiller(StringRef Name) {
504504
return {};
505505
}
506506

507+
template <class ELFT> typename Expr LinkerScript<ELFT>::getLma(StringRef Name) {
508+
for (const std::unique_ptr<BaseCommand> &Base : Opt.Commands)
509+
if (auto *Cmd = dyn_cast<OutputSectionCommand>(Base.get()))
510+
if (Cmd->LmaExpr && Cmd->Name == Name)
511+
return Cmd->LmaExpr;
512+
return {};
513+
}
514+
507515
// Returns the index of the given section name in linker script
508516
// SECTIONS commands. Sections are laid out as the same order as they
509517
// were in the script. If a given name did not appear in the script,
@@ -613,6 +621,7 @@ class elf::ScriptParser : public ScriptParserBase {
613621
SortKind readSortKind();
614622
SymbolAssignment *readProvideHidden(bool Provide, bool Hidden);
615623
SymbolAssignment *readProvideOrAssignment(StringRef Tok);
624+
void readAt(OutputSectionCommand *Cmd);
616625
Expr readAlign();
617626
void readSort();
618627
Expr readAssert();
@@ -918,6 +927,12 @@ Expr ScriptParser::readAssert() {
918927
};
919928
}
920929

930+
void ScriptParser::readAt(OutputSectionCommand *Cmd) {
931+
expect("(");
932+
Cmd->LmaExpr = readExpr();
933+
expect(")");
934+
}
935+
921936
OutputSectionCommand *
922937
ScriptParser::readOutputSectionDescription(StringRef OutSec) {
923938
OutputSectionCommand *Cmd = new OutputSectionCommand(OutSec);
@@ -929,6 +944,9 @@ ScriptParser::readOutputSectionDescription(StringRef OutSec) {
929944

930945
expect(":");
931946

947+
if (skip("AT"))
948+
readAt(Cmd);
949+
932950
if (skip("ALIGN"))
933951
Cmd->AlignExpr = readAlign();
934952

‎lld/ELF/LinkerScript.h

+2
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ struct OutputSectionCommand : BaseCommand {
8383
StringRef Name;
8484
Expr AddrExpr;
8585
Expr AlignExpr;
86+
Expr LmaExpr;
8687
std::vector<std::unique_ptr<BaseCommand>> Commands;
8788
std::vector<StringRef> Phdrs;
8889
std::vector<uint8_t> Filler;
@@ -147,6 +148,7 @@ template <class ELFT> class LinkerScript {
147148
bool ignoreInterpSection();
148149

149150
ArrayRef<uint8_t> getFiller(StringRef Name);
151+
Expr getLma(StringRef Name);
150152
bool shouldKeep(InputSectionBase<ELFT> *S);
151153
void assignAddresses();
152154
int compareSections(StringRef A, StringRef B);

‎lld/ELF/Writer.cpp

+10-2
Original file line numberDiff line numberDiff line change
@@ -963,9 +963,13 @@ std::vector<PhdrEntry<ELFT>> Writer<ELFT>::createPhdrs() {
963963
if (!needsPtLoad(Sec))
964964
continue;
965965

966-
// If flags changed then we want new load segment.
966+
// Segments are contiguous memory regions that has the same attributes
967+
// (e.g. executable or writable). There is one phdr for each segment.
968+
// Therefore, we need to create a new phdr when the next section has
969+
// different flags or is loaded at a discontiguous address using AT linker
970+
// script command.
967971
uintX_t NewFlags = Sec->getPhdrFlags();
968-
if (Flags != NewFlags) {
972+
if (Script<ELFT>::X->getLma(Sec->getName()) || Flags != NewFlags) {
969973
Load = AddHdr(PT_LOAD, NewFlags);
970974
Flags = NewFlags;
971975
}
@@ -1128,7 +1132,11 @@ template <class ELFT> void Writer<ELFT>::setPhdrs() {
11281132
H.p_align = Target->PageSize;
11291133
else if (H.p_type == PT_GNU_RELRO)
11301134
H.p_align = 1;
1135+
11311136
H.p_paddr = H.p_vaddr;
1137+
if (H.p_type == PT_LOAD && First)
1138+
if (Expr LmaExpr = Script<ELFT>::X->getLma(First->getName()))
1139+
H.p_paddr = LmaExpr(H.p_vaddr);
11321140

11331141
// The TLS pointer goes after PT_TLS. At least glibc will align it,
11341142
// so round up the size to make sure the offsets are correct.
+128
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
# REQUIRES: x86
2+
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
3+
# RUN: echo "SECTIONS { \
4+
# RUN: . = 0x1000; \
5+
# RUN: .aaa : AT(0x2000) \
6+
# RUN: { \
7+
# RUN: *(.aaa) \
8+
# RUN: } \
9+
# RUN: .bbb : \
10+
# RUN: { \
11+
# RUN: *(.bbb) \
12+
# RUN: } \
13+
# RUN: .ccc : AT(0x3000) \
14+
# RUN: { \
15+
# RUN: *(.ccc) \
16+
# RUN: } \
17+
# RUN: .ddd : AT(0x4000) \
18+
# RUN: { \
19+
# RUN: *(.ddd) \
20+
# RUN: } \
21+
# RUN: }" > %t.script
22+
# RUN: ld.lld %t --script %t.script -o %t2
23+
# RUN: llvm-readobj -program-headers %t2 | FileCheck %s
24+
25+
# CHECK: ProgramHeaders [
26+
# CHECK-NEXT: ProgramHeader {
27+
# CHECK-NEXT: Type: PT_PHDR
28+
# CHECK-NEXT: Offset: 0x40
29+
# CHECK-NEXT: VirtualAddress: 0x40
30+
# CHECK-NEXT: PhysicalAddress: 0x40
31+
# CHECK-NEXT: FileSize:
32+
# CHECK-NEXT: MemSize:
33+
# CHECK-NEXT: Flags [
34+
# CHECK-NEXT: PF_R
35+
# CHECK-NEXT: ]
36+
# CHECK-NEXT: Alignment: 8
37+
# CHECK-NEXT: }
38+
# CHECK-NEXT: ProgramHeader {
39+
# CHECK-NEXT: Type: PT_LOAD
40+
# CHECK-NEXT: Offset: 0x0
41+
# CHECK-NEXT: VirtualAddress: 0x0
42+
# CHECK-NEXT: PhysicalAddress: 0x0
43+
# CHECK-NEXT: FileSize:
44+
# CHECK-NEXT: MemSize:
45+
# CHECK-NEXT: Flags [
46+
# CHECK-NEXT: PF_R
47+
# CHECK-NEXT: ]
48+
# CHECK-NEXT: Alignment:
49+
# CHECK-NEXT: }
50+
# CHECK-NEXT: ProgramHeader {
51+
# CHECK-NEXT: Type: PT_LOAD
52+
# CHECK-NEXT: Offset: 0x1000
53+
# CHECK-NEXT: VirtualAddress: 0x1000
54+
# CHECK-NEXT: PhysicalAddress: 0x2000
55+
# CHECK-NEXT: FileSize: 16
56+
# CHECK-NEXT: MemSize: 16
57+
# CHECK-NEXT: Flags [
58+
# CHECK-NEXT: PF_R
59+
# CHECK-NEXT: ]
60+
# CHECK-NEXT: Alignment:
61+
# CHECK-NEXT: }
62+
# CHECK-NEXT: ProgramHeader {
63+
# CHECK-NEXT: Type: PT_LOAD
64+
# CHECK-NEXT: Offset: 0x1010
65+
# CHECK-NEXT: VirtualAddress: 0x1010
66+
# CHECK-NEXT: PhysicalAddress: 0x3000
67+
# CHECK-NEXT: FileSize: 8
68+
# CHECK-NEXT: MemSize: 8
69+
# CHECK-NEXT: Flags [
70+
# CHECK-NEXT: PF_R
71+
# CHECK-NEXT: ]
72+
# CHECK-NEXT: Alignment: 4096
73+
# CHECK-NEXT: }
74+
# CHECK-NEXT: ProgramHeader {
75+
# CHECK-NEXT: Type: PT_LOAD
76+
# CHECK-NEXT: Offset: 0x1018
77+
# CHECK-NEXT: VirtualAddress: 0x1018
78+
# CHECK-NEXT: PhysicalAddress: 0x4000
79+
# CHECK-NEXT: FileSize: 8
80+
# CHECK-NEXT: MemSize: 8
81+
# CHECK-NEXT: Flags [
82+
# CHECK-NEXT: PF_R
83+
# CHECK-NEXT: ]
84+
# CHECK-NEXT: Alignment: 4096
85+
# CHECK-NEXT: }
86+
# CHECK-NEXT: ProgramHeader {
87+
# CHECK-NEXT: Type: PT_LOAD
88+
# CHECK-NEXT: Offset: 0x1020
89+
# CHECK-NEXT: VirtualAddress: 0x1020
90+
# CHECK-NEXT: PhysicalAddress: 0x1020
91+
# CHECK-NEXT: FileSize: 1
92+
# CHECK-NEXT: MemSize: 1
93+
# CHECK-NEXT: Flags [
94+
# CHECK-NEXT: PF_R
95+
# CHECK-NEXT: PF_X
96+
# CHECK-NEXT: ]
97+
# CHECK-NEXT: Alignment: 4096
98+
# CHECK-NEXT: }
99+
# CHECK-NEXT: ProgramHeader {
100+
# CHECK-NEXT: Type: PT_GNU_STACK
101+
# CHECK-NEXT: Offset:
102+
# CHECK-NEXT: VirtualAddress: 0x0
103+
# CHECK-NEXT: PhysicalAddress: 0x0
104+
# CHECK-NEXT: FileSize:
105+
# CHECK-NEXT: MemSize:
106+
# CHECK-NEXT: Flags [
107+
# CHECK-NEXT: PF_R
108+
# CHECK-NEXT: PF_W
109+
# CHECK-NEXT: ]
110+
# CHECK-NEXT: Alignment: 0
111+
# CHECK-NEXT: }
112+
# CHECK-NEXT: ]
113+
114+
.global _start
115+
_start:
116+
nop
117+
118+
.section .aaa, "a"
119+
.quad 0
120+
121+
.section .bbb, "a"
122+
.quad 0
123+
124+
.section .ccc, "a"
125+
.quad 0
126+
127+
.section .ddd, "a"
128+
.quad 0

0 commit comments

Comments
 (0)