[llvm] 0c01f42 - [llvm-objcopy] -O binary: align sh_offset for section changed from SHT_NOBITS

Fangrui Song via llvm-commits llvm-commits at lists.llvm.org
Mon Jul 4 21:45:28 PDT 2022


Author: Fangrui Song
Date: 2022-07-04T21:45:19-07:00
New Revision: 0c01f42fad413163320c24ab4e513fbd282e4168

URL: https://github.com/llvm/llvm-project/commit/0c01f42fad413163320c24ab4e513fbd282e4168
DIFF: https://github.com/llvm/llvm-project/commit/0c01f42fad413163320c24ab4e513fbd282e4168.diff

LOG: [llvm-objcopy] -O binary: align sh_offset for section changed from SHT_NOBITS

For a SHT_NOBITS section like .bss, its sh_offset is typically not
aligned by sh_addralign. If it is converted to SHT_PROGBITS by
`--set-section-flags .bss=alloc,contents`, we should conceptually align
it when computing the output size for -O binary. Otherwise the output
size may be smaller than GNU objcopy produced output.

* binary-no-paddr.test has a case with non-sensical p_paddr=1 which has
  a changed behavior. Update it.

Close https://github.com/llvm/llvm-project/issues/55246

Reviewed By: jhenderson

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

Added: 
    

Modified: 
    llvm/lib/ObjCopy/ELF/ELFObject.cpp
    llvm/test/tools/llvm-objcopy/ELF/binary-no-paddr.test
    llvm/test/tools/llvm-objcopy/ELF/binary-paddr.test

Removed: 
    


################################################################################
diff  --git a/llvm/lib/ObjCopy/ELF/ELFObject.cpp b/llvm/lib/ObjCopy/ELF/ELFObject.cpp
index b241bd817ff56..72ea63d521376 100644
--- a/llvm/lib/ObjCopy/ELF/ELFObject.cpp
+++ b/llvm/lib/ObjCopy/ELF/ELFObject.cpp
@@ -2643,9 +2643,12 @@ Error BinaryWriter::finalize() {
   // MinAddr will be skipped.
   uint64_t MinAddr = UINT64_MAX;
   for (SectionBase &Sec : Obj.allocSections()) {
+    // If Sec's type is changed from SHT_NOBITS due to --set-section-flags,
+    // Offset may not be aligned. Align it to max(Align, 1).
     if (Sec.ParentSegment != nullptr)
-      Sec.Addr =
-          Sec.Offset - Sec.ParentSegment->Offset + Sec.ParentSegment->PAddr;
+      Sec.Addr = alignTo(Sec.Offset - Sec.ParentSegment->Offset +
+                             Sec.ParentSegment->PAddr,
+                         std::max(Sec.Align, uint64_t(1)));
     if (Sec.Type != SHT_NOBITS && Sec.Size > 0)
       MinAddr = std::min(MinAddr, Sec.Addr);
   }

diff  --git a/llvm/test/tools/llvm-objcopy/ELF/binary-no-paddr.test b/llvm/test/tools/llvm-objcopy/ELF/binary-no-paddr.test
index 3914ff88e355c..f54cf3b517002 100644
--- a/llvm/test/tools/llvm-objcopy/ELF/binary-no-paddr.test
+++ b/llvm/test/tools/llvm-objcopy/ELF/binary-no-paddr.test
@@ -1,16 +1,15 @@
-# RUN: yaml2obj -D PADDR=1 %s -o %t1
+# RUN: yaml2obj -D PADDR1=0x1000 -D PADDR2=0x1004 %s -o %t1
 # RUN: llvm-objcopy -O binary %t1 %t1.out
 # RUN: od -t x2 -v %t1.out | FileCheck %s --ignore-case
-# RUN: wc -c < %t1.out | FileCheck %s --check-prefix=SIZE
 
 ## When all p_paddr fields are 0, GNU objcopy resets LMA to VMA
 ## and gives a 
diff erent output.
 ## https://sourceware.org/git/?p=binutils-gdb.git;a=commit;h=6ffd79000b45e77b3625143932ffbf781b6aecab
-## We don't implement this special rule. The p_paddr=0 output is the same as
-## the p_paddr=1 case.
-# RUN: yaml2obj -D PADDR=0 %s -o %t0
+## We don't implement this special rule. For the p_paddr=0 case: .text and
+## .data are rewritten to the same place. The size is 4. # the p_paddr=1 case.
+# RUN: yaml2obj %s -o %t0
 # RUN: llvm-objcopy -O binary %t0 %t0.out
-# RUN: cmp %t1.out %t0.out
+# RUN: od -t x2 -v %t0.out | FileCheck %s --check-prefix=CHECK0 --ignore-case
 
 !ELF
 FileHeader:
@@ -35,15 +34,18 @@ ProgramHeaders:
   - Type:     PT_LOAD
     Flags:    [ PF_X, PF_R ]
     VAddr:    0x1000
-    PAddr:    [[PADDR]]
+    PAddr:    [[PADDR1=0]]
     FirstSec: .text
     LastSec:  .text
   - Type:     PT_LOAD
     Flags:    [ PF_R, PF_W ]
     VAddr:    0x1004
-    PAddr:    [[PADDR]]
+    PAddr:    [[PADDR2=0]]
     FirstSec: .data
     LastSec:  .data
 
-# CHECK: 0000000 3232 c3c3
-# SIZE:  4
+# CHECK:       0000000 c3c3 c3c3 3232
+# CHECK-NEXT:  0000006
+
+# CHECK0:      0000000 3232 c3c3
+# CHECK0-NEXT: 0000004

diff  --git a/llvm/test/tools/llvm-objcopy/ELF/binary-paddr.test b/llvm/test/tools/llvm-objcopy/ELF/binary-paddr.test
index 023414429a3c7..311da40ae0991 100644
--- a/llvm/test/tools/llvm-objcopy/ELF/binary-paddr.test
+++ b/llvm/test/tools/llvm-objcopy/ELF/binary-paddr.test
@@ -214,3 +214,43 @@ Sections:
     Address:      0x4000
     AddressAlign: 0x1000
     Content:      "c3c3c3c3"
+
+## If .bss is converted to non-SHT_NOBITS, align its new offset. This may affect
+## the output size.
+# RUN: yaml2obj --docnum=7 %s -o %t7
+# RUN: llvm-objcopy -O binary --set-section-flags .bss=alloc,contents %t7 %t7.out
+# RUN: od -A x -t x2 %t7.out | FileCheck %s --check-prefix=FILLNOBITS --ignore-case
+
+# FILLNOBITS:      000000 c3c3 0000 0000 0000 0000 0000 0000 0000
+# FILLNOBITS-NEXT: 000010 0000 00
+# FILLNOBITS-NEXT: 000013
+
+--- !ELF
+FileHeader:
+  Class:   ELFCLASS64
+  Data:    ELFDATA2LSB
+  Type:    ET_EXEC
+  Machine: EM_X86_64
+Sections:
+  - Name:         .text
+    Type:         SHT_PROGBITS
+    Flags:        [ SHF_ALLOC, SHF_EXECINSTR ]
+    Address:      0x1000
+    AddressAlign: 0x1000
+    Content:      "c3c3"
+  - Name:         .bss
+    Type:         SHT_NOBITS
+    Flags:        [ SHF_ALLOC ]
+    ## sh_offset is not aligned.
+    ShOffset:     0x1002
+    Size:         0x3
+    AddressAlign: 0x10
+ProgramHeaders:
+  - Type:     PT_LOAD
+    Flags:    [ PF_R, PF_W, PF_X ]
+    Offset:   0x1000
+    VAddr:    0x1000
+    PAddr:    0x1000
+    FileSize: 0x2
+    MemSize:  0x13
+    Align:    0x1000


        


More information about the llvm-commits mailing list