[lld] r278911 - [ELF] - linkerscript AT keyword (in output section description) implemented.

George Rimar via llvm-commits llvm-commits at lists.llvm.org
Wed Aug 17 00:44:19 PDT 2016


Author: grimar
Date: Wed Aug 17 02:44:19 2016
New Revision: 278911

URL: http://llvm.org/viewvc/llvm-project?rev=278911&view=rev
Log:
[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

Added:
    lld/trunk/test/ELF/linkerscript/linkerscript-at.s
Modified:
    lld/trunk/ELF/LinkerScript.cpp
    lld/trunk/ELF/LinkerScript.h
    lld/trunk/ELF/Writer.cpp

Modified: lld/trunk/ELF/LinkerScript.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/LinkerScript.cpp?rev=278911&r1=278910&r2=278911&view=diff
==============================================================================
--- lld/trunk/ELF/LinkerScript.cpp (original)
+++ lld/trunk/ELF/LinkerScript.cpp Wed Aug 17 02:44:19 2016
@@ -504,6 +504,14 @@ ArrayRef<uint8_t> LinkerScript<ELFT>::ge
   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::readOutputSectionDescripti
 
   expect(":");
 
+  if (skip("AT"))
+    readAt(Cmd);
+
   if (skip("ALIGN"))
     Cmd->AlignExpr = readAlign();
 

Modified: lld/trunk/ELF/LinkerScript.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/LinkerScript.h?rev=278911&r1=278910&r2=278911&view=diff
==============================================================================
--- lld/trunk/ELF/LinkerScript.h (original)
+++ lld/trunk/ELF/LinkerScript.h Wed Aug 17 02:44:19 2016
@@ -83,6 +83,7 @@ struct OutputSectionCommand : BaseComman
   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);

Modified: lld/trunk/ELF/Writer.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Writer.cpp?rev=278911&r1=278910&r2=278911&view=diff
==============================================================================
--- lld/trunk/ELF/Writer.cpp (original)
+++ lld/trunk/ELF/Writer.cpp Wed Aug 17 02:44:19 2016
@@ -963,9 +963,13 @@ std::vector<PhdrEntry<ELFT>> Writer<ELFT
     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>:
       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.

Added: lld/trunk/test/ELF/linkerscript/linkerscript-at.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/linkerscript/linkerscript-at.s?rev=278911&view=auto
==============================================================================
--- lld/trunk/test/ELF/linkerscript/linkerscript-at.s (added)
+++ lld/trunk/test/ELF/linkerscript/linkerscript-at.s Wed Aug 17 02:44:19 2016
@@ -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




More information about the llvm-commits mailing list