Skip to content

Commit

Permalink
Linker script: implement AT [ (address) ] for PHDR
Browse files Browse the repository at this point in the history
Differential revision: https://reviews.llvm.org/D24340

llvm-svn: 281024
  • Loading branch information
eleviant777 committed Sep 9, 2016
1 parent d63d8a7 commit 56b21c8
Show file tree
Hide file tree
Showing 5 changed files with 44 additions and 6 deletions.
10 changes: 9 additions & 1 deletion lld/ELF/LinkerScript.cpp
Expand Up @@ -463,6 +463,11 @@ std::vector<PhdrEntry<ELFT>> LinkerScript<ELFT>::createPhdrs() {
Phdr.add(Out<ELFT>::ElfHeader);
if (Cmd.HasPhdrs)
Phdr.add(Out<ELFT>::ProgramHeaders);

if (Cmd.LMAExpr) {
Phdr.H.p_paddr = Cmd.LMAExpr(0);
Phdr.HasLMA = true;
}
}

// Add output sections to program headers.
Expand Down Expand Up @@ -860,7 +865,8 @@ void ScriptParser::readPhdrs() {
expect("{");
while (!Error && !skip("}")) {
StringRef Tok = next();
Opt.PhdrsCommands.push_back({Tok, PT_NULL, false, false, UINT_MAX});
Opt.PhdrsCommands.push_back(
{Tok, PT_NULL, false, false, UINT_MAX, nullptr});
PhdrsCommand &PhdrCmd = Opt.PhdrsCommands.back();

PhdrCmd.Type = readPhdrType();
Expand All @@ -872,6 +878,8 @@ void ScriptParser::readPhdrs() {
PhdrCmd.HasFilehdr = true;
else if (Tok == "PHDRS")
PhdrCmd.HasPhdrs = true;
else if (Tok == "AT")
PhdrCmd.LMAExpr = readParenExpr();
else if (Tok == "FLAGS") {
expect("(");
// Passing 0 for the value of dot is a bit of a hack. It means that
Expand Down
1 change: 1 addition & 0 deletions lld/ELF/LinkerScript.h
Expand Up @@ -121,6 +121,7 @@ struct PhdrsCommand {
bool HasFilehdr;
bool HasPhdrs;
unsigned Flags;
Expr LMAExpr;
};

class LinkerScriptBase {
Expand Down
12 changes: 8 additions & 4 deletions lld/ELF/Writer.cpp
Expand Up @@ -1168,10 +1168,14 @@ template <class ELFT> void Writer<ELFT>::setPhdrs() {
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);
if (!P.HasLMA) {
// The p_paddr field can be set using linker script AT command.
// By default, it is the same value as p_vaddr.
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.
Expand Down
1 change: 1 addition & 0 deletions lld/ELF/Writer.h
Expand Up @@ -38,6 +38,7 @@ struct PhdrEntry {
typename ELFT::Phdr H = {};
OutputSectionBase<ELFT> *First = nullptr;
OutputSectionBase<ELFT> *Last = nullptr;
bool HasLMA = false;
};

template <class ELFT>
Expand Down
26 changes: 25 additions & 1 deletion lld/test/ELF/linkerscript/phdrs.s
Expand Up @@ -6,9 +6,19 @@
# RUN: .text : {*(.text*)} :all \
# RUN: .foo : {*(.foo.*)} :all \
# RUN: .data : {*(.data.*)} :all}" > %t.script

# RUN: ld.lld -o %t1 --script %t.script %t
# RUN: llvm-readobj -program-headers %t1 | FileCheck %s

## Check the AT(expr)
# RUN: echo "PHDRS {all PT_LOAD FILEHDR PHDRS AT(0x500 + 0x500) ;} \
# RUN: SECTIONS { \
# RUN: . = 0x10000200; \
# RUN: .text : {*(.text*)} :all \
# RUN: .foo : {*(.foo.*)} :all \
# RUN: .data : {*(.data.*)} :all}" > %t.script
# RUN: ld.lld -o %t1 --script %t.script %t
# RUN: llvm-readobj -program-headers %t1 | FileCheck --check-prefix=AT %s

# CHECK: ProgramHeaders [
# CHECK-NEXT: ProgramHeader {
# CHECK-NEXT: Type: PT_LOAD (0x1)
Expand All @@ -23,6 +33,20 @@
# CHECK-NEXT: PF_X (0x1)
# CHECK-NEXT: ]

# AT: ProgramHeaders [
# AT-NEXT: ProgramHeader {
# AT-NEXT: Type: PT_LOAD (0x1)
# AT-NEXT: Offset: 0x0
# AT-NEXT: VirtualAddress: 0x10000000
# AT-NEXT: PhysicalAddress: 0xA00
# AT-NEXT: FileSize: 521
# AT-NEXT: MemSize: 521
# AT-NEXT: Flags [ (0x7)
# AT-NEXT: PF_R (0x4)
# AT-NEXT: PF_W (0x2)
# AT-NEXT: PF_X (0x1)
# AT-NEXT: ]

.global _start
_start:
nop
Expand Down

0 comments on commit 56b21c8

Please sign in to comment.