Linker script: implement AT [ (address) ] for PHDR
authorEugene Leviant <evgeny.leviant@gmail.com>
Fri, 9 Sep 2016 09:46:16 +0000 (09:46 +0000)
committerEugene Leviant <evgeny.leviant@gmail.com>
Fri, 9 Sep 2016 09:46:16 +0000 (09:46 +0000)
Differential revision: https://reviews.llvm.org/D24340

llvm-svn: 281024

lld/ELF/LinkerScript.cpp
lld/ELF/LinkerScript.h
lld/ELF/Writer.cpp
lld/ELF/Writer.h
lld/test/ELF/linkerscript/phdrs.s

index 223218f..9d6935f 100644 (file)
@@ -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.
@@ -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
index 3849b47..ea57ee9 100644 (file)
@@ -121,6 +121,7 @@ struct PhdrsCommand {
   bool HasFilehdr;
   bool HasPhdrs;
   unsigned Flags;
+  Expr LMAExpr;
 };
 
 class LinkerScriptBase {
index 17d3d85..1dd73eb 100644 (file)
@@ -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.
index 8383a04..4d9df93 100644 (file)
@@ -38,6 +38,7 @@ struct PhdrEntry {
   typename ELFT::Phdr H = {};
   OutputSectionBase<ELFT> *First = nullptr;
   OutputSectionBase<ELFT> *Last = nullptr;
+  bool HasLMA = false;
 };
 
 template <class ELFT>
index cd6bf82..2c41d75 100644 (file)
@@ -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)
 # 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