[PATCH] D101560: [llvm-objcopy][ELF] --only-keep-debug: set offset/size of segments with no sections to zero

Fangrui Song via Phabricator via llvm-commits llvm-commits at lists.llvm.org
Thu Apr 29 11:58:36 PDT 2021


MaskRay created this revision.
MaskRay added reviewers: jhenderson, rupprecht.
Herald added subscribers: abrachet, emaste.
Herald added a reviewer: alexshap.
MaskRay requested review of this revision.
Herald added a project: LLVM.
Herald added a subscriber: llvm-commits.

PR50160: we currently ignore non-PT_PHDR segments with no sections, not
accounting for its p_offset and p_filesz: this can cause an out-of-bounds write
in `writeSegmentData` if the p_offset+p_filesz is larger than the total file
size.

This can be fixed by setting p_offset=p_filesz=0. The logic nicely unifies with
the logic added in D90897 <https://reviews.llvm.org/D90897>.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D101560

Files:
  llvm/test/tools/llvm-objcopy/ELF/only-keep-debug.test
  llvm/tools/llvm-objcopy/ELF/Object.cpp


Index: llvm/tools/llvm-objcopy/ELF/Object.cpp
===================================================================
--- llvm/tools/llvm-objcopy/ELF/Object.cpp
+++ llvm/tools/llvm-objcopy/ELF/Object.cpp
@@ -2315,18 +2315,19 @@
                                                uint64_t HdrEnd) {
   uint64_t MaxOffset = 0;
   for (Segment *Seg : Segments) {
-    // An empty segment contains no section (see sectionWithinSegment). If it
-    // has a parent segment, copy the parent segment's offset field. This works
-    // for empty PT_TLS. We don't handle empty segments without a parent for
-    // now.
-    if (Seg->ParentSegment != nullptr && Seg->MemSize == 0)
-      Seg->Offset = Seg->ParentSegment->Offset;
+    if (Seg->Type == PT_PHDR)
+      continue;
 
+    // The segment offset is generally the offset of the first section.
+    //
+    // For an empty segment contains no section (see sectionWithinSegment). If
+    // it has a parent segment, copy the parent segment's offset field. This
+    // works for empty PT_TLS. If no parent segment, use 0: the segment is
+    // not useful for debugging.
     const SectionBase *FirstSec = Seg->firstSection();
-    if (Seg->Type == PT_PHDR || !FirstSec)
-      continue;
-
-    uint64_t Offset = FirstSec->Offset;
+    uint64_t Offset =
+        FirstSec ? FirstSec->Offset
+                 : (Seg->ParentSegment ? Seg->ParentSegment->Offset : 0);
     uint64_t FileSize = 0;
     for (const SectionBase *Sec : Seg->Sections) {
       uint64_t Size = Sec->Type == SHT_NOBITS ? 0 : Sec->Size;
Index: llvm/test/tools/llvm-objcopy/ELF/only-keep-debug.test
===================================================================
--- llvm/test/tools/llvm-objcopy/ELF/only-keep-debug.test
+++ llvm/test/tools/llvm-objcopy/ELF/only-keep-debug.test
@@ -129,11 +129,11 @@
 # CHECK2-NEXT: [ 4] .strtab     STRTAB   0000000000000000 000221 000001 00      0   0  1
 # CHECK2-NEXT: [ 5] .shstrtab   STRTAB   0000000000000000 000222 00002b 00      0   0  1
 
-## Check that p_offset or p_filesz of empty segments or PT_PHDR are not modified.
+## Check that p_offset or p_filesz of PT_PHDR are not modified.
 # CHECK2:      Type Offset   VirtAddr           PhysAddr           FileSiz  MemSiz   Flg Align
 # CHECK2-NEXT: PHDR 0x000040 0x0000000000000040 0x0000000000000040 0x0000a8 0x0000a8 R   0x8
 # CHECK2-NEXT: LOAD 0x000000 0x0000000000000000 0x0000000000000000 0x000202 0x000202 R E 0x1000
-# CHECK2-NEXT: LOAD 0x000202 0x0000000000000202 0x0000000000000202 0x00000e 0x00000e RW  0x1
+# CHECK2-NEXT: LOAD 0x000000 0x0000000000000202 0x0000000000000202 0x000000 0x00000e RW  0x1
 
 --- !ELF
 FileHeader:
@@ -280,3 +280,34 @@
     VAddr:    0x1240
     FirstSec: .tdata
     LastSec:  .tdata
+
+
+## The offset and size fields of segments which contain no section and have no
+## parent segment are set to zeros, so that we can decrease the file size. Such
+## segments are not useful for debugging.
+# RUN: yaml2obj --docnum=5 %s -o %t5
+# RUN: llvm-objcopy --only-keep-debug %t5 %t5.dbg
+# RUN: llvm-readelf -S -l %t5.dbg | FileCheck --check-prefix=CHECK5 %s
+
+# CHECK5:      [Nr] Name        Type     Address          Off    Size   ES Flg Lk Inf Al
+# CHECK5:      [ 1] .foo        NOBITS   0000000000000000 000078 001000 00   A  0   0  0
+# CHECK5-NEXT: [ 2] .strtab     STRTAB   0000000000000000 000078 000001 00      0   0  1
+# CHECK5-NEXT: [ 3] .shstrtab   STRTAB   0000000000000000 000079 000018 00      0   0  1
+
+# CHECK5:      Type Offset   VirtAddr           PhysAddr           FileSiz  MemSiz   Flg Align
+# CHECK5-NEXT: NULL 0x000000 0x0000000000000000 0x0000000000000000 0x000078 0x000000     0x1
+# CHECK5-EMPTY:
+--- !ELF
+FileHeader:
+  Class:   ELFCLASS64
+  Data:    ELFDATA2LSB
+  Type:    ET_DYN
+Sections:
+  - Name:    .foo
+    Type:    SHT_PROGBITS
+    Flags:   [ SHF_ALLOC ]
+    Size:    0x01000
+ProgramHeaders:
+  - Type:     PT_NULL
+    Flags:    []
+    FileSize: 0x01000


-------------- next part --------------
A non-text attachment was scrubbed...
Name: D101560.341599.patch
Type: text/x-patch
Size: 3953 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20210429/980d907f/attachment.bin>


More information about the llvm-commits mailing list