[llvm] r323144 - [llvm-objcopy] Use physical instead of virtual address when aligning and placing sections in binary

Jake Ehrlich via llvm-commits llvm-commits at lists.llvm.org
Mon Jan 22 11:27:30 PST 2018


Author: jakehehrlich
Date: Mon Jan 22 11:27:30 2018
New Revision: 323144

URL: http://llvm.org/viewvc/llvm-project?rev=323144&view=rev
Log:
[llvm-objcopy] Use physical instead of virtual address when aligning and placing sections in binary

For sections with different virtual and physical addresses, alignment and
placement in the output binary should be based on the physical address.

Ran into this problem with a bare metal ARM project where llvm-objcopy added a
lot of zero-padding before the .data section that had differing addresses. GNU
objcopy did not add the padding, and after this fix, neither does llvm-objcopy.

Update a test case so a section has different physical and virtual addresses.

Fixes B35708

Authored By: Owen Shaw (owenpshaw)

Differential Revision: https://reviews.llvm.org/D41619

Added:
    llvm/trunk/test/tools/llvm-objcopy/binary-no-paddr.test
      - copied, changed from r323136, llvm/trunk/test/tools/llvm-objcopy/basic-align-copy.test
    llvm/trunk/test/tools/llvm-objcopy/binary-paddr.test
      - copied, changed from r323136, llvm/trunk/test/tools/llvm-objcopy/basic-align-copy.test
    llvm/trunk/test/tools/llvm-objcopy/binary-segment-layout.test
      - copied, changed from r323136, llvm/trunk/test/tools/llvm-objcopy/basic-align-copy.test
Removed:
    llvm/trunk/test/tools/llvm-objcopy/basic-align-copy.test
Modified:
    llvm/trunk/test/tools/llvm-objcopy/two-seg-remove-end.test
    llvm/trunk/test/tools/llvm-objcopy/two-seg-remove-first.test
    llvm/trunk/test/tools/llvm-objcopy/two-seg-remove-third-sec.test
    llvm/trunk/tools/llvm-objcopy/Object.cpp

Removed: llvm/trunk/test/tools/llvm-objcopy/basic-align-copy.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-objcopy/basic-align-copy.test?rev=323143&view=auto
==============================================================================
--- llvm/trunk/test/tools/llvm-objcopy/basic-align-copy.test (original)
+++ llvm/trunk/test/tools/llvm-objcopy/basic-align-copy.test (removed)
@@ -1,37 +0,0 @@
-# RUN: yaml2obj %s -o %t
-# RUN: llvm-objcopy -O binary %t %t2
-# RUN: od -t x2 %t2 | FileCheck %s
-# RUN: wc -c < %t2 | FileCheck %s --check-prefix=SIZE
-
-!ELF
-FileHeader:
-  Class:           ELFCLASS64
-  Data:            ELFDATA2LSB
-  Type:            ET_EXEC
-  Machine:         EM_X86_64
-Sections:
-  - Name:            .text
-    Type:            SHT_PROGBITS
-    Flags:           [ SHF_ALLOC, SHF_EXECINSTR ]
-    AddressAlign:    0x0000000000001000
-    Content:         "c3c3c3c3"
-  - Name:            .data
-    Type:            SHT_PROGBITS
-    Flags:           [ SHF_ALLOC, SHF_EXECINSTR ]
-    AddressAlign:    0x0000000000001000
-    Content:         "3232"
-ProgramHeaders:
-  - Type: PT_LOAD
-    Flags: [ PF_X, PF_R ]
-    Sections:
-      - Section: .text
-  - Type: PT_LOAD
-    Flags: [ PF_R ]
-    Sections:
-      - Section: .data
-
-# CHECK:       0000000 c3c3 c3c3 0000 0000 0000 0000 0000 0000
-# CHECK-NEXT:  0000020 0000 0000 0000 0000 0000 0000 0000 0000
-# CHECK-NEXT:  *
-# CHECK-NEXT:  0010000 3232
-# SIZE:        4098

Copied: llvm/trunk/test/tools/llvm-objcopy/binary-no-paddr.test (from r323136, llvm/trunk/test/tools/llvm-objcopy/basic-align-copy.test)
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-objcopy/binary-no-paddr.test?p2=llvm/trunk/test/tools/llvm-objcopy/binary-no-paddr.test&p1=llvm/trunk/test/tools/llvm-objcopy/basic-align-copy.test&r1=323136&r2=323144&rev=323144&view=diff
==============================================================================
--- llvm/trunk/test/tools/llvm-objcopy/basic-align-copy.test (original)
+++ llvm/trunk/test/tools/llvm-objcopy/binary-no-paddr.test Mon Jan 22 11:27:30 2018
@@ -1,6 +1,6 @@
 # RUN: yaml2obj %s -o %t
 # RUN: llvm-objcopy -O binary %t %t2
-# RUN: od -t x2 %t2 | FileCheck %s
+# RUN: od -t x2 -v %t2 | FileCheck %s
 # RUN: wc -c < %t2 | FileCheck %s --check-prefix=SIZE
 
 !ELF
@@ -13,25 +13,30 @@ Sections:
   - Name:            .text
     Type:            SHT_PROGBITS
     Flags:           [ SHF_ALLOC, SHF_EXECINSTR ]
+    Address:         0x1000
     AddressAlign:    0x0000000000001000
     Content:         "c3c3c3c3"
   - Name:            .data
     Type:            SHT_PROGBITS
-    Flags:           [ SHF_ALLOC, SHF_EXECINSTR ]
-    AddressAlign:    0x0000000000001000
+    Flags:           [ SHF_ALLOC ]
+    Address:         0x1004
+    AddressAlign:    0x0000000000000004
     Content:         "3232"
 ProgramHeaders:
   - Type: PT_LOAD
     Flags: [ PF_X, PF_R ]
+    VAddr: 0x1000
+    PAddr: 0x0000
+    Align: 0x1000
     Sections:
       - Section: .text
   - Type: PT_LOAD
-    Flags: [ PF_R ]
+    Flags: [ PF_R, PF_W ]
+    VAddr: 0x1004
+    PAddr: 0x0000
+    Align: 0x1000
     Sections:
       - Section: .data
 
-# CHECK:       0000000 c3c3 c3c3 0000 0000 0000 0000 0000 0000
-# CHECK-NEXT:  0000020 0000 0000 0000 0000 0000 0000 0000 0000
-# CHECK-NEXT:  *
-# CHECK-NEXT:  0010000 3232
-# SIZE:        4098
+# CHECK: 0000000 c3c3 c3c3 3232
+# SIZE:  6

Copied: llvm/trunk/test/tools/llvm-objcopy/binary-paddr.test (from r323136, llvm/trunk/test/tools/llvm-objcopy/basic-align-copy.test)
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-objcopy/binary-paddr.test?p2=llvm/trunk/test/tools/llvm-objcopy/binary-paddr.test&p1=llvm/trunk/test/tools/llvm-objcopy/basic-align-copy.test&r1=323136&r2=323144&rev=323144&view=diff
==============================================================================
--- llvm/trunk/test/tools/llvm-objcopy/basic-align-copy.test (original)
+++ llvm/trunk/test/tools/llvm-objcopy/binary-paddr.test Mon Jan 22 11:27:30 2018
@@ -13,25 +13,33 @@ Sections:
   - Name:            .text
     Type:            SHT_PROGBITS
     Flags:           [ SHF_ALLOC, SHF_EXECINSTR ]
+    Address:         0x1000
     AddressAlign:    0x0000000000001000
     Content:         "c3c3c3c3"
   - Name:            .data
     Type:            SHT_PROGBITS
-    Flags:           [ SHF_ALLOC, SHF_EXECINSTR ]
+    Flags:           [ SHF_ALLOC ]
+    Address:         0x2000
     AddressAlign:    0x0000000000001000
     Content:         "3232"
 ProgramHeaders:
   - Type: PT_LOAD
     Flags: [ PF_X, PF_R ]
+    VAddr: 0x1000
+    PAddr: 0x1000
+    Align: 0x1000
     Sections:
       - Section: .text
   - Type: PT_LOAD
-    Flags: [ PF_R ]
+    Flags: [ PF_R, PF_W ]
+    VAddr: 0x2000
+    PAddr: 0x4000
+    Align: 0x1000
     Sections:
       - Section: .data
 
 # CHECK:       0000000 c3c3 c3c3 0000 0000 0000 0000 0000 0000
 # CHECK-NEXT:  0000020 0000 0000 0000 0000 0000 0000 0000 0000
 # CHECK-NEXT:  *
-# CHECK-NEXT:  0010000 3232
-# SIZE:        4098
+# CHECK-NEXT:  0030000 3232
+# SIZE:        12290

Copied: llvm/trunk/test/tools/llvm-objcopy/binary-segment-layout.test (from r323136, llvm/trunk/test/tools/llvm-objcopy/basic-align-copy.test)
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-objcopy/binary-segment-layout.test?p2=llvm/trunk/test/tools/llvm-objcopy/binary-segment-layout.test&p1=llvm/trunk/test/tools/llvm-objcopy/basic-align-copy.test&r1=323136&r2=323144&rev=323144&view=diff
==============================================================================
--- llvm/trunk/test/tools/llvm-objcopy/basic-align-copy.test (original)
+++ llvm/trunk/test/tools/llvm-objcopy/binary-segment-layout.test Mon Jan 22 11:27:30 2018
@@ -14,24 +14,25 @@ Sections:
     Type:            SHT_PROGBITS
     Flags:           [ SHF_ALLOC, SHF_EXECINSTR ]
     AddressAlign:    0x0000000000001000
+    Address:         0x00
     Content:         "c3c3c3c3"
   - Name:            .data
     Type:            SHT_PROGBITS
     Flags:           [ SHF_ALLOC, SHF_EXECINSTR ]
-    AddressAlign:    0x0000000000001000
+    AddressAlign:    0x0000000000000008
+    Address:         0x08
     Content:         "3232"
 ProgramHeaders:
   - Type: PT_LOAD
     Flags: [ PF_X, PF_R ]
+    VAddr: 0x00
     Sections:
       - Section: .text
   - Type: PT_LOAD
     Flags: [ PF_R ]
+    VAddr: 0x08
     Sections:
       - Section: .data
 
-# CHECK:       0000000 c3c3 c3c3 0000 0000 0000 0000 0000 0000
-# CHECK-NEXT:  0000020 0000 0000 0000 0000 0000 0000 0000 0000
-# CHECK-NEXT:  *
-# CHECK-NEXT:  0010000 3232
-# SIZE:        4098
+# CHECK:       0000000 c3c3 c3c3 0000 0000 3232
+# SIZE:        10

Modified: llvm/trunk/test/tools/llvm-objcopy/two-seg-remove-end.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-objcopy/two-seg-remove-end.test?rev=323144&r1=323143&r2=323144&view=diff
==============================================================================
--- llvm/trunk/test/tools/llvm-objcopy/two-seg-remove-end.test (original)
+++ llvm/trunk/test/tools/llvm-objcopy/two-seg-remove-end.test Mon Jan 22 11:27:30 2018
@@ -48,8 +48,8 @@ ProgramHeaders:
       - Section: .text2
   - Type: PT_LOAD
     Flags: [ PF_R ]
-    VAddr: 0x1000
-    PAddr: 0x1000
+    VAddr: 0x3000
+    PAddr: 0x3000
     Sections:
       - Section: .text3
       - Section: .text4

Modified: llvm/trunk/test/tools/llvm-objcopy/two-seg-remove-first.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-objcopy/two-seg-remove-first.test?rev=323144&r1=323143&r2=323144&view=diff
==============================================================================
--- llvm/trunk/test/tools/llvm-objcopy/two-seg-remove-first.test (original)
+++ llvm/trunk/test/tools/llvm-objcopy/two-seg-remove-first.test Mon Jan 22 11:27:30 2018
@@ -48,8 +48,8 @@ ProgramHeaders:
       - Section: .text2
   - Type: PT_LOAD
     Flags: [ PF_R ]
-    VAddr: 0x1000
-    PAddr: 0x1000
+    VAddr: 0x3000
+    PAddr: 0x3000
     Sections:
       - Section: .text3
       - Section: .text4

Modified: llvm/trunk/test/tools/llvm-objcopy/two-seg-remove-third-sec.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-objcopy/two-seg-remove-third-sec.test?rev=323144&r1=323143&r2=323144&view=diff
==============================================================================
--- llvm/trunk/test/tools/llvm-objcopy/two-seg-remove-third-sec.test (original)
+++ llvm/trunk/test/tools/llvm-objcopy/two-seg-remove-third-sec.test Mon Jan 22 11:27:30 2018
@@ -48,8 +48,8 @@ ProgramHeaders:
       - Section: .text2
   - Type: PT_LOAD
     Flags: [ PF_R ]
-    VAddr: 0x1000
-    PAddr: 0x1000
+    VAddr: 0x3000
+    PAddr: 0x3000
     Sections:
       - Section: .text3
       - Section: .text4

Modified: llvm/trunk/tools/llvm-objcopy/Object.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-objcopy/Object.cpp?rev=323144&r1=323143&r2=323144&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-objcopy/Object.cpp (original)
+++ llvm/trunk/tools/llvm-objcopy/Object.cpp Mon Jan 22 11:27:30 2018
@@ -409,7 +409,7 @@ static bool segmentOverlapsSegment(const
          Parent.OriginalOffset + Parent.FileSize > Child.OriginalOffset;
 }
 
-static bool compareSegments(const Segment *A, const Segment *B) {
+static bool compareSegmentsByOffset(const Segment *A, const Segment *B) {
   // Any segment without a parent segment should come before a segment
   // that has a parent segment.
   if (A->OriginalOffset < B->OriginalOffset)
@@ -419,6 +419,14 @@ static bool compareSegments(const Segmen
   return A->Index < B->Index;
 }
 
+static bool compareSegmentsByPAddr(const Segment *A, const Segment *B) {
+  if (A->PAddr < B->PAddr)
+    return true;
+  if (A->PAddr > B->PAddr)
+    return false;
+  return A->Index < B->Index;
+}
+
 template <class ELFT>
 void Object<ELFT>::readProgramHeaders(const ELFFile<ELFT> &ElfFile) {
   uint32_t Index = 0;
@@ -456,9 +464,9 @@ void Object<ELFT>::readProgramHeaders(co
       if (&Child != &Parent && segmentOverlapsSegment(*Child, *Parent)) {
         // We want a canonical "most parental" segment but this requires
         // inspecting the ParentSegment.
-        if (compareSegments(Parent.get(), Child.get()))
+        if (compareSegmentsByOffset(Parent.get(), Child.get()))
           if (Child->ParentSegment == nullptr ||
-              compareSegments(Parent.get(), Child->ParentSegment)) {
+              compareSegmentsByOffset(Parent.get(), Child->ParentSegment)) {
             Child->ParentSegment = Parent.get();
           }
       }
@@ -784,7 +792,8 @@ static uint64_t alignToAddr(uint64_t Off
 
 // Orders segments such that if x = y->ParentSegment then y comes before x.
 static void OrderSegments(std::vector<Segment *> &Segments) {
-  std::stable_sort(std::begin(Segments), std::end(Segments), compareSegments);
+  std::stable_sort(std::begin(Segments), std::end(Segments),
+                   compareSegmentsByOffset);
 }
 
 // This function finds a consistent layout for a list of segments starting from
@@ -793,7 +802,7 @@ static void OrderSegments(std::vector<Se
 static uint64_t LayoutSegments(std::vector<Segment *> &Segments,
                                uint64_t Offset) {
   assert(std::is_sorted(std::begin(Segments), std::end(Segments),
-                        compareSegments));
+                        compareSegmentsByOffset));
   // The only way a segment should move is if a section was between two
   // segments and that section was removed. If that section isn't in a segment
   // then it's acceptable, but not ideal, to simply move it to after the
@@ -947,7 +956,20 @@ template <class ELFT> void BinaryObject<
       OrderedSegments.push_back(Section->ParentSegment);
     }
   }
-  OrderSegments(OrderedSegments);
+
+  // For binary output, we're going to use physical addresses instead of
+  // virtual addresses, since a binary output is used for cases like ROM
+  // loading and physical addresses are intended for ROM loading.
+  // However, if no segment has a physical address, we'll fallback to using
+  // virtual addresses for all.
+  if (std::all_of(std::begin(OrderedSegments), std::end(OrderedSegments),
+                  [](const Segment *Segment) { return Segment->PAddr == 0; }))
+    for (const auto &Segment : OrderedSegments)
+      Segment->PAddr = Segment->VAddr;
+
+  std::stable_sort(std::begin(OrderedSegments), std::end(OrderedSegments),
+                   compareSegmentsByPAddr);
+
   // Because we add a ParentSegment for each section we might have duplicate
   // segments in OrderedSegments. If there were duplicates then LayoutSegments
   // would do very strange things.
@@ -955,6 +977,8 @@ template <class ELFT> void BinaryObject<
       std::unique(std::begin(OrderedSegments), std::end(OrderedSegments));
   OrderedSegments.erase(End, std::end(OrderedSegments));
 
+  uint64_t Offset = 0;
+
   // Modify the first segment so that there is no gap at the start. This allows
   // our layout algorithm to proceed as expected while not out writing out the
   // gap at the start.
@@ -963,19 +987,18 @@ template <class ELFT> void BinaryObject<
     auto Sec = Seg->firstSection();
     auto Diff = Sec->OriginalOffset - Seg->OriginalOffset;
     Seg->OriginalOffset += Diff;
-    // The size needs to be shrunk as well
+    // The size needs to be shrunk as well.
     Seg->FileSize -= Diff;
-    Seg->MemSize -= Diff;
-    // The VAddr needs to be adjusted so that the alignment is correct as well
-    Seg->VAddr += Diff;
-    Seg->PAddr = Seg->VAddr;
-    // We don't want this to be shifted by alignment so we need to set the
-    // alignment to zero.
-    Seg->Align = 0;
+    // The PAddr needs to be increased to remove the gap before the first
+    // section.
+    Seg->PAddr += Diff;
+    uint64_t LowestPAddr = Seg->PAddr;
+    for (auto &Segment : OrderedSegments) {
+      Segment->Offset = Segment->PAddr - LowestPAddr;
+      Offset = std::max(Offset, Segment->Offset + Segment->FileSize);
+    }
   }
 
-  uint64_t Offset = LayoutSegments(OrderedSegments, 0);
-
   // TODO: generalize LayoutSections to take a range. Pass a special range
   // constructed from an iterator that skips values for which a predicate does
   // not hold. Then pass such a range to LayoutSections instead of constructing




More information about the llvm-commits mailing list