From 56b21c869ef8dc07e2b46ccfc8a719364bc1e85a Mon Sep 17 00:00:00 2001 From: Eugene Leviant Date: Fri, 9 Sep 2016 09:46:16 +0000 Subject: [PATCH] Linker script: implement AT [ (address) ] for PHDR Differential revision: https://reviews.llvm.org/D24340 llvm-svn: 281024 --- lld/ELF/LinkerScript.cpp | 10 +++++++++- lld/ELF/LinkerScript.h | 1 + lld/ELF/Writer.cpp | 12 ++++++++---- lld/ELF/Writer.h | 1 + lld/test/ELF/linkerscript/phdrs.s | 26 +++++++++++++++++++++++++- 5 files changed, 44 insertions(+), 6 deletions(-) diff --git a/lld/ELF/LinkerScript.cpp b/lld/ELF/LinkerScript.cpp index 223218f40843a..9d6935f77424e 100644 --- a/lld/ELF/LinkerScript.cpp +++ b/lld/ELF/LinkerScript.cpp @@ -463,6 +463,11 @@ std::vector> LinkerScript::createPhdrs() { Phdr.add(Out::ElfHeader); if (Cmd.HasPhdrs) Phdr.add(Out::ProgramHeaders); + + if (Cmd.LMAExpr) { + Phdr.H.p_paddr = Cmd.LMAExpr(0); + Phdr.HasLMA = true; + } } // Add output sections to program headers. @@ -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(); @@ -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 diff --git a/lld/ELF/LinkerScript.h b/lld/ELF/LinkerScript.h index 3849b47b70b33..ea57ee97d55e6 100644 --- a/lld/ELF/LinkerScript.h +++ b/lld/ELF/LinkerScript.h @@ -121,6 +121,7 @@ struct PhdrsCommand { bool HasFilehdr; bool HasPhdrs; unsigned Flags; + Expr LMAExpr; }; class LinkerScriptBase { diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp index 17d3d850f04ac..1dd73eb107861 100644 --- a/lld/ELF/Writer.cpp +++ b/lld/ELF/Writer.cpp @@ -1168,10 +1168,14 @@ template void Writer::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::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::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/ELF/Writer.h b/lld/ELF/Writer.h index 8383a0493c293..4d9df9302bb32 100644 --- a/lld/ELF/Writer.h +++ b/lld/ELF/Writer.h @@ -38,6 +38,7 @@ struct PhdrEntry { typename ELFT::Phdr H = {}; OutputSectionBase *First = nullptr; OutputSectionBase *Last = nullptr; + bool HasLMA = false; }; template diff --git a/lld/test/ELF/linkerscript/phdrs.s b/lld/test/ELF/linkerscript/phdrs.s index cd6bf82b55b81..2c41d75d06909 100644 --- a/lld/test/ELF/linkerscript/phdrs.s +++ b/lld/test/ELF/linkerscript/phdrs.s @@ -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) @@ -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