[lld] r242096 - [LinkerScript] Don't create unnecessarily large segments

Rafael Auler rafaelauler at gmail.com
Mon Jul 13 17:34:43 PDT 2015


Author: rafauler
Date: Mon Jul 13 19:34:43 2015
New Revision: 242096

URL: http://llvm.org/viewvc/llvm-project?rev=242096&view=rev
Log:
[LinkerScript] Don't create unnecessarily large segments

When using a linker script expression to change the address of a section, even
if the new address is more than a page of distance from the old address, lld
may put everything in the same segment, forcing it to be unnecessarily large.
This patch changes the logic in Segment::assignVirtualAddress() and
Segment::assignFileOffsets() to allow the segment to be sliced into two or more
if it detects a linker script expression that changes a section address.

Differential Revision: http://reviews.llvm.org/D10952

Modified:
    lld/trunk/lib/ReaderWriter/ELF/SegmentChunks.cpp
    lld/trunk/test/elf/linkerscript/sections-order.test

Modified: lld/trunk/lib/ReaderWriter/ELF/SegmentChunks.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/ELF/SegmentChunks.cpp?rev=242096&r1=242095&r2=242096&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/ELF/SegmentChunks.cpp (original)
+++ lld/trunk/lib/ReaderWriter/ELF/SegmentChunks.cpp Mon Jul 13 19:34:43 2015
@@ -118,13 +118,23 @@ void Segment<ELFT>::assignFileOffsets(ui
   uint64_t lastVirtualAddress = 0;
 
   this->setFileOffset(startOffset);
+  bool changeOffset = false;
+  uint64_t newOffset = 0;
   for (auto &slice : slices()) {
     bool isFirstSection = true;
     for (auto section : slice->sections()) {
       // Handle linker script expressions, which may change the offset
-      if (!isFirstSection)
-        if (auto expr = dyn_cast<ExpressionChunk<ELFT>>(section))
-          fileOffset += expr->virtualAddr() - lastVirtualAddress;
+      if (auto expr = dyn_cast<ExpressionChunk<ELFT>>(section)) {
+        if (!isFirstSection) {
+          changeOffset = true;
+          newOffset = fileOffset + expr->virtualAddr() - lastVirtualAddress;
+        }
+        continue;
+      }
+      if (changeOffset) {
+        changeOffset = false;
+        fileOffset = newOffset;
+      }
       // Align fileoffset to the alignment of the section.
       fileOffset = llvm::RoundUpToAlignment(fileOffset, section->alignment());
       // If the linker outputmagic is set to OutputMagic::NMAGIC, align the Data
@@ -136,17 +146,14 @@ void Segment<ELFT>::assignFileOffsets(ui
         // OutputMagic::NMAGIC/OutputMagic::OMAGIC
         if (alignSegments)
           fileOffset = llvm::RoundUpToAlignment(fileOffset, p_align);
-        else {
-          // Align according to ELF spec.
-          // in p75, http://www.sco.com/developers/devspecs/gabi41.pdf
-          uint64_t virtualAddress = slice->virtualAddr();
-          Section<ELFT> *sect = dyn_cast<Section<ELFT>>(section);
-          if (sect && sect->isLoadableSection() &&
-              ((virtualAddress & (p_align - 1)) !=
-               (fileOffset & (p_align - 1))))
-            fileOffset = llvm::RoundUpToAlignment(fileOffset, p_align) +
-                         (virtualAddress % p_align);
-        }
+        // Align according to ELF spec.
+        // in p75, http://www.sco.com/developers/devspecs/gabi41.pdf
+        uint64_t virtualAddress = slice->virtualAddr();
+        Section<ELFT> *sect = dyn_cast<Section<ELFT>>(section);
+        if (sect && sect->isLoadableSection() &&
+            ((virtualAddress & (p_align - 1)) != (fileOffset & (p_align - 1))))
+          fileOffset = llvm::RoundUpToAlignment(fileOffset, p_align) +
+                       (virtualAddress % p_align);
       } else if (!isDataPageAlignedForNMagic && needAlign(section)) {
         fileOffset =
             llvm::RoundUpToAlignment(fileOffset, this->_ctx.getPageSize());
@@ -161,6 +168,7 @@ void Segment<ELFT>::assignFileOffsets(ui
       fileOffset += section->fileSize();
       lastVirtualAddress = section->virtualAddr() + section->memSize();
     }
+    changeOffset = false;
     slice->setFileSize(fileOffset - curSliceFileOffset);
   }
   this->setFileSize(fileOffset - startOffset);
@@ -242,6 +250,8 @@ template <class ELFT> void Segment<ELFT>
     ++si;
   }
 
+  uint64_t scriptAddr = 0;
+  bool forceScriptAddr = false;
   for (auto e = _sections.end(); si != e; ++si) {
     uint64_t curAddr = curSliceAddress + curSliceSize;
     if (!isDataPageAlignedForNMagic && needAlign(*si)) {
@@ -251,23 +261,25 @@ template <class ELFT> void Segment<ELFT>
       curAddr = llvm::RoundUpToAlignment(curAddr, this->_ctx.getPageSize());
       isDataPageAlignedForNMagic = true;
     }
-    uint64_t newAddr = llvm::RoundUpToAlignment(curAddr, (*si)->alignment());
-    // Handle linker script expressions, which *may update newAddr* if the
-    // expression assigns to "."
-    if (auto expr = dyn_cast<ExpressionChunk<ELFT>>(*si))
+    uint64_t newAddr = llvm::RoundUpToAlignment(
+        forceScriptAddr ? scriptAddr : curAddr, (*si)->alignment());
+    forceScriptAddr = false;
+
+    // Handle linker script expressions, which may force an address change if
+    // the expression assigns to "."
+    if (auto expr = dyn_cast<ExpressionChunk<ELFT>>(*si)) {
+      uint64_t oldAddr = newAddr;
       expr->evalExpr(newAddr);
-    Section<ELFT> *sec = dyn_cast<Section<ELFT>>(*si);
-    StringRef curOutputSectionName;
-    if (sec) {
-      curOutputSectionName = sec->outputSectionName();
-    } else {
-      // If this is a linker script expression, propagate the name of the
-      // previous section instead
-      if (isa<ExpressionChunk<ELFT>>(*si))
-        curOutputSectionName = prevOutputSectionName;
-      else
-        curOutputSectionName = (*si)->name();
+      if (oldAddr != newAddr) {
+        forceScriptAddr = true;
+        scriptAddr = newAddr;
+      }
+      (*si)->setVirtualAddr(newAddr);
+      continue;
     }
+    Section<ELFT> *sec = dyn_cast<Section<ELFT>>(*si);
+    StringRef curOutputSectionName =
+        sec ? sec->outputSectionName() : (*si)->name();
     bool autoCreateSlice = true;
     if (curOutputSectionName == prevOutputSectionName)
       autoCreateSlice = false;

Modified: lld/trunk/test/elf/linkerscript/sections-order.test
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/elf/linkerscript/sections-order.test?rev=242096&r1=242095&r2=242096&view=diff
==============================================================================
--- lld/trunk/test/elf/linkerscript/sections-order.test (original)
+++ lld/trunk/test/elf/linkerscript/sections-order.test Mon Jul 13 19:34:43 2015
@@ -94,4 +94,20 @@ CHECKSYMS-NEXT: Value: 0x506038
 
 CHECKSYMS:      Name: prog2
 CHECKSYMS-NEXT: Value: 0x506050
+
+RUN: llvm-readobj -program-headers %t1 | FileCheck -check-prefix CHECKPHDRS %s
+
+CHECKPHDRS:           Type: PT_LOAD (0x1)
+CHECKPHDRS:           Offset: 0x1000
+CHECKPHDRS-NEXT:      VirtualAddress: 0x500000
+CHECKPHDRS-NEXT:      PhysicalAddress: 0x500000
+CHECKPHDRS-NEXT:      FileSize: 48
+CHECKPHDRS-NEXT:      MemSize: 48
+
+CHECKPHDRS:           Type: PT_LOAD (0x1)
+CHECKPHDRS:           Offset: 0x2030
+CHECKPHDRS-NEXT:      VirtualAddress: 0x506030
+CHECKPHDRS-NEXT:      PhysicalAddress: 0x506030
+CHECKPHDRS-NEXT:      FileSize: 168
+CHECKPHDRS-NEXT:      MemSize: 168
 */





More information about the llvm-commits mailing list