[lld] r290136 - Fix corner cases of setting the section address.

Rafael Espindola via llvm-commits llvm-commits at lists.llvm.org
Mon Dec 19 13:21:07 PST 2016


Author: rafael
Date: Mon Dec 19 15:21:07 2016
New Revision: 290136

URL: http://llvm.org/viewvc/llvm-project?rev=290136&view=rev
Log:
Fix corner cases of setting the section address.

This handles all the corner cases if setting a section address:

- If the address is too low, we cannot allocate the program headers.
- If the load address is lowered, we have to do that before finalize

This also shares some code with the linker script since it was already
hitting similar cases.

This is used by the freebsd boot loader. It is not clear if we need to
support this with a non binary output, but it is not as bad as I was
expecting.

Added:
    lld/trunk/test/ELF/ttext-tdata-tbss.s
Modified:
    lld/trunk/ELF/LinkerScript.cpp
    lld/trunk/ELF/Writer.cpp
    lld/trunk/ELF/Writer.h

Modified: lld/trunk/ELF/LinkerScript.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/LinkerScript.cpp?rev=290136&r1=290135&r2=290136&view=diff
==============================================================================
--- lld/trunk/ELF/LinkerScript.cpp (original)
+++ lld/trunk/ELF/LinkerScript.cpp Mon Dec 19 15:21:07 2016
@@ -748,19 +748,10 @@ void LinkerScript<ELFT>::assignAddresses
   }
 
   uintX_t HeaderSize = getHeaderSize();
-  auto FirstPTLoad =
-      std::find_if(Phdrs.begin(), Phdrs.end(),
-                   [](const PhdrEntry &E) { return E.p_type == PT_LOAD; });
-  if (FirstPTLoad == Phdrs.end())
-    return;
-
   // If the linker script doesn't have PHDRS, add ElfHeader and ProgramHeaders
   // now that we know we have space.
-  if (HeaderSize <= MinVA && !hasPhdrsCommands()) {
-    FirstPTLoad->First = Out<ELFT>::ElfHeader;
-    if (!FirstPTLoad->Last)
-      FirstPTLoad->Last = Out<ELFT>::ProgramHeaders;
-  }
+  if (HeaderSize <= MinVA && !hasPhdrsCommands())
+    allocateHeaders<ELFT>(Phdrs, *OutputSections);
 
   // ELF and Program headers need to be right before the first section in
   // memory. Set their addresses accordingly.

Modified: lld/trunk/ELF/Writer.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Writer.cpp?rev=290136&r1=290135&r2=290136&view=diff
==============================================================================
--- lld/trunk/ELF/Writer.cpp (original)
+++ lld/trunk/ELF/Writer.cpp Mon Dec 19 15:21:07 2016
@@ -89,6 +89,7 @@ private:
 
   uintX_t FileSize;
   uintX_t SectionHeaderOff;
+  bool AllocateHeader = true;
 };
 } // anonymous namespace
 
@@ -192,15 +193,6 @@ template <class ELFT> void Writer<ELFT>:
   if (Config->Relocatable) {
     assignFileOffsets();
   } else {
-    // Binary output does not have PHDRS.
-    if (!Config->OFormatBinary) {
-      Phdrs = Script<ELFT>::X->hasPhdrsCommands()
-                  ? Script<ELFT>::X->createPhdrs()
-                  : createPhdrs();
-      addPtArmExid(Phdrs);
-      fixHeaders();
-    }
-
     if (ScriptConfig->HasSections) {
       Script<ELFT>::X->assignAddresses(Phdrs);
     } else {
@@ -533,6 +525,17 @@ static bool compareSectionsNonScript(con
   if (!AIsAlloc)
     return false;
 
+  // We want to put section specified by -T option first, so we
+  // can start assigning VA starting from them later.
+  auto AAddrSetI = Config->SectionStartMap.find(A->getName());
+  auto BAddrSetI = Config->SectionStartMap.find(B->getName());
+  bool AHasAddrSet = AAddrSetI != Config->SectionStartMap.end();
+  bool BHasAddrSet = BAddrSetI != Config->SectionStartMap.end();
+  if (AHasAddrSet != BHasAddrSet)
+    return AHasAddrSet;
+  if (AHasAddrSet)
+    return AAddrSetI->second < BAddrSetI->second;
+
   // We want the read only sections first so that they go in the PT_LOAD
   // covering the program headers at the start of the file.
   bool AIsWritable = A->Flags & SHF_WRITE;
@@ -1038,6 +1041,16 @@ template <class ELFT> void Writer<ELFT>:
     Sec->ShName = In<ELFT>::ShStrTab->addString(Sec->getName());
   }
 
+  // Binary and relocatable output does not have PHDRS.
+  // The headers have to be created before finalize as that can influence the
+  // image base and the dynamic section on mips includes the image base.
+  if (!Config->Relocatable && !Config->OFormatBinary) {
+    Phdrs = Script<ELFT>::X->hasPhdrsCommands() ? Script<ELFT>::X->createPhdrs()
+                                                : createPhdrs();
+    addPtArmExid(Phdrs);
+    fixHeaders();
+  }
+
   // Fill other section headers. The dynamic table is finalized
   // at the end because some tags like RELSZ depend on result
   // of finalizing other sections.
@@ -1159,10 +1172,6 @@ template <class ELFT> std::vector<PhdrEn
   // Add the first PT_LOAD segment for regular output sections.
   uintX_t Flags = computeFlags<ELFT>(PF_R);
   PhdrEntry *Load = AddHdr(PT_LOAD, Flags);
-  if (!ScriptConfig->HasSections) {
-    Load->add(Out<ELFT>::ElfHeader);
-    Load->add(Out<ELFT>::ProgramHeaders);
-  }
 
   PhdrEntry TlsHdr(PT_TLS, PF_R);
   PhdrEntry RelRo(PT_GNU_RELRO, PF_R);
@@ -1270,7 +1279,7 @@ void Writer<ELFT>::addPtArmExid(std::vec
 // have to be page aligned so that the dynamic linker can set the permissions.
 template <class ELFT> void Writer<ELFT>::fixSectionAlignments() {
   for (const PhdrEntry &P : Phdrs)
-    if (P.p_type == PT_LOAD)
+    if (P.p_type == PT_LOAD && P.First)
       P.First->PageAlign = true;
 
   for (const PhdrEntry &P : Phdrs) {
@@ -1288,6 +1297,23 @@ template <class ELFT> void Writer<ELFT>:
   }
 }
 
+template <class ELFT>
+void elf::allocateHeaders(MutableArrayRef<PhdrEntry> Phdrs,
+                          ArrayRef<OutputSectionBase *> OutputSections) {
+  auto FirstPTLoad =
+      std::find_if(Phdrs.begin(), Phdrs.end(),
+                   [](const PhdrEntry &E) { return E.p_type == PT_LOAD; });
+  if (FirstPTLoad == Phdrs.end())
+    return;
+  if (FirstPTLoad->First)
+    for (OutputSectionBase *Sec : OutputSections)
+      if (Sec->FirstInPtLoad == FirstPTLoad->First)
+        Sec->FirstInPtLoad = Out<ELFT>::ElfHeader;
+  FirstPTLoad->First = Out<ELFT>::ElfHeader;
+  if (!FirstPTLoad->Last)
+    FirstPTLoad->Last = Out<ELFT>::ProgramHeaders;
+}
+
 // We should set file offsets and VAs for elf header and program headers
 // sections. These are special, we do not include them into output sections
 // list, but have them to simplify the code.
@@ -1296,6 +1322,25 @@ template <class ELFT> void Writer<ELFT>:
   // If the script has SECTIONS, assignAddresses will compute the values.
   if (ScriptConfig->HasSections)
     return;
+
+  uintX_t HeaderSize = getHeaderSize<ELFT>();
+  // When -T<section> option is specified, lower the base to make room for those
+  // sections.
+  if (!Config->SectionStartMap.empty()) {
+    uint64_t Min = -1;
+    for (const auto &P : Config->SectionStartMap)
+      Min = std::min(Min, P.second);
+    if (HeaderSize < Min)
+      Min -= HeaderSize;
+    else
+      AllocateHeader = false;
+    if (Min < Config->ImageBase)
+      Config->ImageBase = alignDown(Min, Config->MaxPageSize);
+  }
+
+  if (AllocateHeader)
+    allocateHeaders<ELFT>(Phdrs, OutputSections);
+
   uintX_t BaseVA = Config->ImageBase;
   Out<ELFT>::ElfHeader->Addr = BaseVA;
   Out<ELFT>::ProgramHeaders->Addr = BaseVA + Out<ELFT>::ElfHeader->Size;
@@ -1303,7 +1348,9 @@ template <class ELFT> void Writer<ELFT>:
 
 // Assign VAs (addresses at run-time) to output sections.
 template <class ELFT> void Writer<ELFT>::assignAddresses() {
-  uintX_t VA = Config->ImageBase + getHeaderSize<ELFT>();
+  uintX_t VA = Config->ImageBase;
+  if (AllocateHeader)
+    VA += getHeaderSize<ELFT>();
   uintX_t ThreadBssOffset = 0;
   for (OutputSectionBase *Sec : OutputSections) {
     uintX_t Alignment = Sec->Addralign;
@@ -1682,6 +1729,15 @@ template void elf::writeResult<ELF32BE>(
 template void elf::writeResult<ELF64LE>();
 template void elf::writeResult<ELF64BE>();
 
+template void elf::allocateHeaders<ELF32LE>(MutableArrayRef<PhdrEntry>,
+                                            ArrayRef<OutputSectionBase *>);
+template void elf::allocateHeaders<ELF32BE>(MutableArrayRef<PhdrEntry>,
+                                            ArrayRef<OutputSectionBase *>);
+template void elf::allocateHeaders<ELF64LE>(MutableArrayRef<PhdrEntry>,
+                                            ArrayRef<OutputSectionBase *>);
+template void elf::allocateHeaders<ELF64BE>(MutableArrayRef<PhdrEntry>,
+                                            ArrayRef<OutputSectionBase *>);
+
 template bool elf::isRelroSection<ELF32LE>(const OutputSectionBase *);
 template bool elf::isRelroSection<ELF32BE>(const OutputSectionBase *);
 template bool elf::isRelroSection<ELF64LE>(const OutputSectionBase *);

Modified: lld/trunk/ELF/Writer.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Writer.h?rev=290136&r1=290135&r2=290136&view=diff
==============================================================================
--- lld/trunk/ELF/Writer.h (original)
+++ lld/trunk/ELF/Writer.h Mon Dec 19 15:21:07 2016
@@ -10,6 +10,7 @@
 #ifndef LLD_ELF_WRITER_H
 #define LLD_ELF_WRITER_H
 
+#include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/StringRef.h"
 #include <cstdint>
 #include <memory>
@@ -48,6 +49,9 @@ struct PhdrEntry {
 
 llvm::StringRef getOutputSectionName(llvm::StringRef Name);
 
+template <class ELFT>
+void allocateHeaders(llvm::MutableArrayRef<PhdrEntry>,
+                     llvm::ArrayRef<OutputSectionBase *>);
 template <class ELFT> void reportDiscarded(InputSectionBase<ELFT> *IS);
 
 template <class ELFT> uint32_t getMipsEFlags();

Added: lld/trunk/test/ELF/ttext-tdata-tbss.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/ttext-tdata-tbss.s?rev=290136&view=auto
==============================================================================
--- lld/trunk/test/ELF/ttext-tdata-tbss.s (added)
+++ lld/trunk/test/ELF/ttext-tdata-tbss.s Mon Dec 19 15:21:07 2016
@@ -0,0 +1,63 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+
+## Show what regular output gives to us.
+# RUN: ld.lld %t.o -o %t1
+# RUN: llvm-readobj --elf-output-style=GNU -l -s  %t1 | FileCheck %s
+# CHECK:      .rodata   PROGBITS 0000000000200158 000158 000008
+# CHECK-NEXT: .text     PROGBITS 0000000000201000 001000 000001
+# CHECK-NEXT: .aw       PROGBITS 0000000000202000 002000 000008
+# CHECK-NEXT: .data     PROGBITS 0000000000202008 002008 000008
+# CHECK-NEXT: .bss      NOBITS   0000000000202010 002010 000008
+# CHECK:      PHDR
+# CHECK-NEXT: LOAD 0x000000 0x0000000000200000
+
+## With .text at 0 there is no space to allocate the headers.
+# RUN: ld.lld -Ttext 0x0 -Tdata 0x4000 -Tbss 0x8000 %t.o -o %t2
+# RUN: llvm-readobj --elf-output-style=GNU -l -s %t2 | FileCheck %s --check-prefix=USER1
+# USER1:      .text   PROGBITS 0000000000000000 001000 000001
+# USER1-NEXT: .data   PROGBITS 0000000000004000 002000 000008
+# USER1-NEXT: .bss    NOBITS   0000000000008000 002008 000008
+# USER1-NEXT: .rodata PROGBITS 0000000000009000 003000 000008
+# USER1-NEXT: .aw     PROGBITS 000000000000a000 004000 000008
+# USER1:      PHDR
+# USER1-NEXT: LOAD 0x001000 0x0000000000000000
+
+## With .text at 0x1000 there is space to allocate the headers.
+# RUN: ld.lld -Ttext 0x1000 -Tdata 0x4000 -Tbss 0x8000 %t.o -o %t3
+# RUN: llvm-readobj --elf-output-style=GNU -l -s  %t3 | FileCheck %s --check-prefix=USER2
+# USER2:      .text   PROGBITS 0000000000001000 001000 000001
+# USER2-NEXT: .data   PROGBITS 0000000000004000 002000 000008
+# USER2-NEXT: .bss    NOBITS   0000000000008000 002008 000008
+# USER2-NEXT: .rodata PROGBITS 0000000000009000 003000 000008
+# USER2-NEXT: .aw     PROGBITS 000000000000a000 004000 000008
+# USER2:      PHDR
+# USER2-NEXT: LOAD 0x000000 0x0000000000000000
+
+## With .text well above 200000 we don't need to change the image base
+# RUN: ld.lld -Ttext 0x201000 %t.o -o %t4
+# RUN: llvm-readobj --elf-output-style=GNU -l -s %t4 | FileCheck %s --check-prefix=USER3
+# USER3:     .text   PROGBITS 0000000000201000 001000 000001
+# USER3-NEX: .rodata PROGBITS 0000000000202000 002000 000008
+# USER3-NEX: .aw     PROGBITS 0000000000203000 003000 000008
+# USER3-NEX: .data   PROGBITS 0000000000203008 003008 000008
+# USER3-NEX: .bss    NOBITS   0000000000203010 003010 000008
+# USER3:      PHDR
+# USER3-NEXT: LOAD 0x000000 0x0000000000200000
+
+.text
+.globl _start
+_start:
+ nop
+
+.section .rodata,"a"
+ .quad 0
+
+.section .aw,"aw"
+ .quad 0
+
+.section .data,"aw"
+ .quad 0
+
+.section .bss,"", at nobits
+ .quad 0




More information about the llvm-commits mailing list