[lld] r283429 - [ELF] Linker script: implement LOADADDR

Eugene Leviant via llvm-commits llvm-commits at lists.llvm.org
Thu Oct 6 02:39:29 PDT 2016


Author: evgeny777
Date: Thu Oct  6 04:39:28 2016
New Revision: 283429

URL: http://llvm.org/viewvc/llvm-project?rev=283429&view=rev
Log:
[ELF] Linker script: implement LOADADDR

Differential revision: https://reviews.llvm.org/D24298

Added:
    lld/trunk/test/ELF/linkerscript/loadaddr.s
Modified:
    lld/trunk/ELF/LinkerScript.cpp
    lld/trunk/ELF/LinkerScript.h
    lld/trunk/ELF/OutputSections.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=283429&r1=283428&r2=283429&view=diff
==============================================================================
--- lld/trunk/ELF/LinkerScript.cpp (original)
+++ lld/trunk/ELF/LinkerScript.cpp Thu Oct  6 04:39:28 2016
@@ -416,6 +416,12 @@ void LinkerScript<ELFT>::switchTo(Output
 
   Dot = alignTo(Dot, CurOutSec->getAlignment());
   CurOutSec->setVA(isTbss(CurOutSec) ? Dot + ThreadBssOffset : Dot);
+
+  // If neither AT nor AT> is specified for an allocatable section, the linker
+  // will set the LMA such that the difference between VMA and LMA for the
+  // section is the same as the preceding output section in the same region
+  // https://sourceware.org/binutils/docs-2.20/ld/Output-Section-LMA.html
+  CurOutSec->setLMAOffset(LMAOffset);
 }
 
 template <class ELFT> void LinkerScript<ELFT>::process(BaseCommand &Base) {
@@ -466,12 +472,13 @@ findSections(OutputSectionCommand &Cmd,
 
 template <class ELFT>
 void LinkerScript<ELFT>::assignOffsets(OutputSectionCommand *Cmd) {
+  if (Cmd->LMAExpr)
+    LMAOffset = Cmd->LMAExpr(Dot) - Dot;
   std::vector<OutputSectionBase<ELFT> *> Sections =
       findSections(*Cmd, *OutputSections);
   if (Sections.empty())
     return;
   switchTo(Sections[0]);
-
   // Find the last section output location. We will output orphan sections
   // there so that end symbols point to the correct location.
   auto E = std::find_if(Cmd->Commands.rbegin(), Cmd->Commands.rend(),
@@ -755,12 +762,12 @@ void LinkerScript<ELFT>::writeDataBytes(
       writeInt<ELFT>(&Buf[DataCmd->Offset], DataCmd->Data, DataCmd->Size);
 }
 
-template <class ELFT> Expr LinkerScript<ELFT>::getLma(StringRef Name) {
+template <class ELFT> bool LinkerScript<ELFT>::hasLMA(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 {};
+      if (Cmd->LMAExpr && Cmd->Name == Name)
+        return true;
+  return false;
 }
 
 // Returns the index of the given section name in linker script
@@ -792,6 +799,15 @@ uint64_t LinkerScript<ELFT>::getOutputSe
 }
 
 template <class ELFT>
+uint64_t LinkerScript<ELFT>::getOutputSectionLMA(StringRef Name) {
+  for (OutputSectionBase<ELFT> *Sec : *OutputSections)
+    if (Sec->getName() == Name)
+      return Sec->getLMA();
+  error("undefined section " + Name);
+  return 0;
+}
+
+template <class ELFT>
 uint64_t LinkerScript<ELFT>::getOutputSectionSize(StringRef Name) {
   for (OutputSectionBase<ELFT> *Sec : *OutputSections)
     if (Sec->getName() == Name)
@@ -899,6 +915,7 @@ private:
 
   Expr readExpr();
   Expr readExpr1(Expr Lhs, int MinPrec);
+  StringRef readParenLiteral();
   Expr readPrimary();
   Expr readTernary(Expr Cond);
   Expr readParenExpr();
@@ -1303,7 +1320,7 @@ ScriptParser::readOutputSectionDescripti
   expect(":");
 
   if (skip("AT"))
-    Cmd->LmaExpr = readParenExpr();
+    Cmd->LMAExpr = readParenExpr();
   if (skip("ALIGN"))
     Cmd->AlignExpr = readParenExpr();
   if (skip("SUBALIGN"))
@@ -1538,6 +1555,13 @@ BytesDataCommand *ScriptParser::readByte
   return new BytesDataCommand(Val, Size);
 }
 
+StringRef ScriptParser::readParenLiteral() {
+  expect("(");
+  StringRef Tok = next();
+  expect(")");
+  return Tok;
+}
+
 Expr ScriptParser::readPrimary() {
   if (peek() == "(")
     return readParenExpr();
@@ -1556,12 +1580,14 @@ Expr ScriptParser::readPrimary() {
   // Built-in functions are parsed here.
   // https://sourceware.org/binutils/docs/ld/Builtin-Functions.html.
   if (Tok == "ADDR") {
-    expect("(");
-    StringRef Name = next();
-    expect(")");
+    StringRef Name = readParenLiteral();
     return
         [=](uint64_t Dot) { return ScriptBase->getOutputSectionAddress(Name); };
   }
+  if (Tok == "LOADADDR") {
+    StringRef Name = readParenLiteral();
+    return [=](uint64_t Dot) { return ScriptBase->getOutputSectionLMA(Name); };
+  }
   if (Tok == "ASSERT")
     return readAssert();
   if (Tok == "ALIGN") {
@@ -1569,10 +1595,8 @@ Expr ScriptParser::readPrimary() {
     return [=](uint64_t Dot) { return alignTo(Dot, E(Dot)); };
   }
   if (Tok == "CONSTANT") {
-    expect("(");
-    StringRef Tok = next();
-    expect(")");
-    return [=](uint64_t Dot) { return getConstant(Tok); };
+    StringRef Name = readParenLiteral();
+    return [=](uint64_t Dot) { return getConstant(Name); };
   }
   if (Tok == "DEFINED") {
     expect("(");
@@ -1614,15 +1638,11 @@ Expr ScriptParser::readPrimary() {
     return [](uint64_t Dot) { return alignTo(Dot, Target->PageSize); };
   }
   if (Tok == "SIZEOF") {
-    expect("(");
-    StringRef Name = next();
-    expect(")");
+    StringRef Name = readParenLiteral();
     return [=](uint64_t Dot) { return ScriptBase->getOutputSectionSize(Name); };
   }
   if (Tok == "ALIGNOF") {
-    expect("(");
-    StringRef Name = next();
-    expect(")");
+    StringRef Name = readParenLiteral();
     return
         [=](uint64_t Dot) { return ScriptBase->getOutputSectionAlign(Name); };
   }

Modified: lld/trunk/ELF/LinkerScript.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/LinkerScript.h?rev=283429&r1=283428&r2=283429&view=diff
==============================================================================
--- lld/trunk/ELF/LinkerScript.h (original)
+++ lld/trunk/ELF/LinkerScript.h Thu Oct  6 04:39:28 2016
@@ -90,7 +90,7 @@ struct OutputSectionCommand : BaseComman
   StringRef Name;
   Expr AddrExpr;
   Expr AlignExpr;
-  Expr LmaExpr;
+  Expr LMAExpr;
   Expr SubalignExpr;
   std::vector<std::unique_ptr<BaseCommand>> Commands;
   std::vector<StringRef> Phdrs;
@@ -165,6 +165,7 @@ public:
   virtual uint64_t getOutputSectionAddress(StringRef Name) = 0;
   virtual uint64_t getOutputSectionSize(StringRef Name) = 0;
   virtual uint64_t getOutputSectionAlign(StringRef Name) = 0;
+  virtual uint64_t getOutputSectionLMA(StringRef Name) = 0;
   virtual uint64_t getHeaderSize() = 0;
   virtual uint64_t getSymbolValue(StringRef S) = 0;
   virtual bool isDefined(StringRef S) = 0;
@@ -205,7 +206,7 @@ public:
 
   ArrayRef<uint8_t> getFiller(StringRef Name);
   void writeDataBytes(StringRef Name, uint8_t *Buf);
-  Expr getLma(StringRef Name);
+  bool hasLMA(StringRef Name);
   bool shouldKeep(InputSectionBase<ELFT> *S);
   void assignOffsets(OutputSectionCommand *Cmd);
   void assignAddresses(std::vector<PhdrEntry<ELFT>> &Phdrs);
@@ -213,6 +214,7 @@ public:
   uint64_t getOutputSectionAddress(StringRef Name) override;
   uint64_t getOutputSectionSize(StringRef Name) override;
   uint64_t getOutputSectionAlign(StringRef Name) override;
+  uint64_t getOutputSectionLMA(StringRef Name) override;
   uint64_t getHeaderSize() override;
   uint64_t getSymbolValue(StringRef S) override;
   bool isDefined(StringRef S) override;
@@ -238,6 +240,7 @@ private:
   size_t getPhdrIndex(StringRef PhdrName);
 
   uintX_t Dot;
+  uintX_t LMAOffset = 0;
   OutputSectionBase<ELFT> *CurOutSec = nullptr;
   uintX_t ThreadBssOffset = 0;
   void switchTo(OutputSectionBase<ELFT> *Sec);

Modified: lld/trunk/ELF/OutputSections.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/OutputSections.h?rev=283429&r1=283428&r2=283429&view=diff
==============================================================================
--- lld/trunk/ELF/OutputSections.h (original)
+++ lld/trunk/ELF/OutputSections.h Thu Oct  6 04:39:28 2016
@@ -76,6 +76,8 @@ public:
   OutputSectionBase(StringRef Name, uint32_t Type, uintX_t Flags);
   void setVA(uintX_t VA) { Header.sh_addr = VA; }
   uintX_t getVA() const { return Header.sh_addr; }
+  void setLMAOffset(uintX_t LMAOff) { LMAOffset = LMAOff; }
+  uintX_t getLMA() const { return Header.sh_addr + LMAOffset; }
   void setFileOffset(uintX_t Off) { Header.sh_offset = Off; }
   uintX_t getFileOffset() { return Header.sh_offset; }
   void setSHName(unsigned Val) { Header.sh_name = Val; }
@@ -126,6 +128,7 @@ public:
 protected:
   StringRef Name;
   Elf_Shdr Header;
+  uintX_t LMAOffset = 0;
 };
 
 template <class ELFT> class GotSection final : public OutputSectionBase<ELFT> {

Modified: lld/trunk/ELF/Writer.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Writer.cpp?rev=283429&r1=283428&r2=283429&view=diff
==============================================================================
--- lld/trunk/ELF/Writer.cpp (original)
+++ lld/trunk/ELF/Writer.cpp Thu Oct  6 04:39:28 2016
@@ -1034,7 +1034,6 @@ static typename ELFT::uint computeFlags(
 template <class ELFT>
 std::vector<PhdrEntry<ELFT>> Writer<ELFT>::createPhdrs() {
   std::vector<Phdr> Ret;
-
   auto AddHdr = [&](unsigned Type, unsigned Flags) -> Phdr * {
     Ret.emplace_back(Type, Flags);
     return &Ret.back();
@@ -1080,7 +1079,7 @@ std::vector<PhdrEntry<ELFT>> Writer<ELFT
     // different flags or is loaded at a discontiguous address using AT linker
     // script command.
     uintX_t NewFlags = computeFlags<ELFT>(Sec->getPhdrFlags());
-    if (Script<ELFT>::X->getLma(Sec->getName()) || Flags != NewFlags) {
+    if (Script<ELFT>::X->hasLMA(Sec->getName()) || Flags != NewFlags) {
       Load = AddHdr(PT_LOAD, NewFlags);
       Flags = NewFlags;
     }
@@ -1257,21 +1256,14 @@ template <class ELFT> void Writer<ELFT>:
       H.p_memsz = Last->getVA() + Last->getSize() - First->getVA();
       H.p_offset = First->getFileOff();
       H.p_vaddr = First->getVA();
+      if (!P.HasLMA)
+        H.p_paddr = First->getLMA();
     }
     if (H.p_type == PT_LOAD)
       H.p_align = Config->MaxPageSize;
     else if (H.p_type == PT_GNU_RELRO)
       H.p_align = 1;
 
-    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.
     if (H.p_type == PT_TLS) {

Added: lld/trunk/test/ELF/linkerscript/loadaddr.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/linkerscript/loadaddr.s?rev=283429&view=auto
==============================================================================
--- lld/trunk/test/ELF/linkerscript/loadaddr.s (added)
+++ lld/trunk/test/ELF/linkerscript/loadaddr.s Thu Oct  6 04:39:28 2016
@@ -0,0 +1,42 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: echo "SECTIONS { \
+# RUN:  . = 0x1000; \
+# RUN:  .aaa : AT(0x2000) { *(.aaa) } \
+# RUN:  .bbb : { *(.bbb) } \
+# RUN:  .ccc : AT(0x3000) { *(.ccc) } \
+# RUN:  .ddd : AT(0x4000) { *(.ddd) } \
+# RUN:  .text : { *(.text) } \
+# RUN:  aaa_lma = LOADADDR(.aaa);  \
+# RUN:  bbb_lma = LOADADDR(.bbb);  \
+# RUN:  ccc_lma = LOADADDR(.ccc);  \
+# RUN:  ddd_lma = LOADADDR(.ddd);  \
+# RUN:  txt_lma = LOADADDR(.text); \
+# RUN: }" > %t.script
+# RUN: ld.lld %t --script %t.script -o %t2
+# RUN: llvm-objdump -t %t2 | FileCheck %s
+# RUN: echo "SECTIONS { v = LOADADDR(.zzz); }" > %t.script
+# RUN: not ld.lld %t --script %t.script -o %t2 2>&1 | FileCheck --check-prefix=ERROR %s
+
+# CHECK:      0000000000002000         *ABS*     00000000 aaa_lma
+# CHECK-NEXT: 0000000000002008         *ABS*     00000000 bbb_lma
+# CHECK-NEXT: 0000000000003000         *ABS*     00000000 ccc_lma
+# CHECK-NEXT: 0000000000004000         *ABS*     00000000 ddd_lma
+# CHECK-NEXT: 0000000000004008         *ABS*     00000000 txt_lma
+# ERROR: undefined section .zzz
+
+.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