[llvm] aa3a85c - [yaml2obj] - Allocate the file space for SHT_NOBITS sections in some cases.

Georgii Rymar via llvm-commits llvm-commits at lists.llvm.org
Tue Jun 2 07:19:40 PDT 2020


Author: Georgii Rymar
Date: 2020-06-02T17:19:24+03:00
New Revision: aa3a85cdaa4432ca389bdbf48049eaa64dc6e266

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

LOG: [yaml2obj] - Allocate the file space for SHT_NOBITS sections in some cases.

This teaches yaml2obj to allocate file space for a no-bits section
when there is a non-nobits section in the same segment that follows it.

It was discussed in D78005 thread and matches GNU linkers and LLD behavior.

Differential revision: https://reviews.llvm.org/D80629

Added: 
    

Modified: 
    llvm/lib/ObjectYAML/ELFEmitter.cpp
    llvm/test/tools/llvm-objcopy/ELF/preserve-segment-contents.test
    llvm/test/tools/yaml2obj/ELF/program-header-nobits.yaml

Removed: 
    


################################################################################
diff  --git a/llvm/lib/ObjectYAML/ELFEmitter.cpp b/llvm/lib/ObjectYAML/ELFEmitter.cpp
index 254cbef2f60a..b87db48fa78c 100644
--- a/llvm/lib/ObjectYAML/ELFEmitter.cpp
+++ b/llvm/lib/ObjectYAML/ELFEmitter.cpp
@@ -164,6 +164,9 @@ template <class ELFT> class ELFState {
 
   void finalizeStrings();
   void writeELFHeader(ContiguousBlobAccumulator &CBA, raw_ostream &OS);
+  void writeSectionContent(Elf_Shdr &SHeader,
+                           const ELFYAML::NoBitsSection &Section,
+                           ContiguousBlobAccumulator &CBA);
   void writeSectionContent(Elf_Shdr &SHeader,
                            const ELFYAML::RawContentSection &Section,
                            ContiguousBlobAccumulator &CBA);
@@ -570,9 +573,7 @@ void ELFState<ELFT>::initSectionHeaders(std::vector<Elf_Shdr> &SHeaders,
     } else if (auto S = dyn_cast<ELFYAML::MipsABIFlags>(Sec)) {
       writeSectionContent(SHeader, *S, CBA);
     } else if (auto S = dyn_cast<ELFYAML::NoBitsSection>(Sec)) {
-      // SHT_NOBITS sections do not have any content to write.
-      SHeader.sh_entsize = 0;
-      SHeader.sh_size = S->Size;
+      writeSectionContent(SHeader, *S, CBA);
     } else if (auto S = dyn_cast<ELFYAML::DynamicSection>(Sec)) {
       writeSectionContent(SHeader, *S, CBA);
     } else if (auto S = dyn_cast<ELFYAML::SymverSection>(Sec)) {
@@ -953,6 +954,35 @@ void ELFState<ELFT>::setProgramHeaderLayout(std::vector<Elf_Phdr> &PHeaders,
   }
 }
 
+static bool shouldAllocateFileSpace(ArrayRef<ELFYAML::ProgramHeader> Phdrs,
+                                    const ELFYAML::NoBitsSection &S) {
+  for (const ELFYAML::ProgramHeader &PH : Phdrs) {
+    auto It = llvm::find_if(
+        PH.Chunks, [&](ELFYAML::Chunk *C) { return C->Name == S.Name; });
+    if (std::any_of(It, PH.Chunks.end(), [](ELFYAML::Chunk *C) {
+          return (isa<ELFYAML::Fill>(C) ||
+                  cast<ELFYAML::Section>(C)->Type != ELF::SHT_NOBITS);
+        }))
+      return true;
+  }
+  return false;
+}
+
+template <class ELFT>
+void ELFState<ELFT>::writeSectionContent(Elf_Shdr &SHeader,
+                                         const ELFYAML::NoBitsSection &S,
+                                         ContiguousBlobAccumulator &CBA) {
+  // SHT_NOBITS sections do not have any content to write.
+  SHeader.sh_entsize = 0;
+  SHeader.sh_size = S.Size;
+
+  // When a nobits section is followed by a non-nobits section or fill
+  // in the same segment, we allocate the file space for it. This behavior
+  // matches linkers.
+  if (shouldAllocateFileSpace(Doc.ProgramHeaders, S))
+    CBA.getOS().write_zeros(S.Size);
+}
+
 template <class ELFT>
 void ELFState<ELFT>::writeSectionContent(
     Elf_Shdr &SHeader, const ELFYAML::RawContentSection &Section,

diff  --git a/llvm/test/tools/llvm-objcopy/ELF/preserve-segment-contents.test b/llvm/test/tools/llvm-objcopy/ELF/preserve-segment-contents.test
index 5555a42c5a22..ff575c8bc2d8 100644
--- a/llvm/test/tools/llvm-objcopy/ELF/preserve-segment-contents.test
+++ b/llvm/test/tools/llvm-objcopy/ELF/preserve-segment-contents.test
@@ -13,7 +13,7 @@
 # RUN: llvm-objcopy %t.base %t.stripped --regex -R blob.*
 # Show that the removal leaves the bytes as zeroes, as desired, for all our
 # test cases.
-# RUN: od -t x1 -j 0x2000 -N 24 %t.stripped | FileCheck %s --ignore-case --check-prefix=CHECK1 -DPATTERN="00 00 00 00"
+# RUN: od -t x1 -j 0x2000 -N 28 %t.stripped | FileCheck %s --ignore-case --check-prefix=CHECK1 -DPATTERN="00 00 00 00"
 # RUN: od -t x1 -j 0x2100 -N 12 %t.stripped | FileCheck %s --ignore-case --check-prefix=CHECK2 -DPATTERN="00 00 00 00"
 # RUN: od -t x1 -j 0x2200 -N 4  %t.stripped | FileCheck %s --ignore-case --check-prefix=CHECK3 -DPATTERN="00 00 00 00"
 # RUN: od -t x1 -j 0x2300 -N 12 %t.stripped | FileCheck %s --ignore-case --check-prefix=CHECK4 -DPATTERN="00 00 00 00"
@@ -24,7 +24,7 @@
 # RUN: cp %t.stripped %t.in
 # RUN: echo "with open('%/t.in', 'rb+') as input:"                                 > %t.py
 # RUN: echo "  for offset in ["                                                   >> %t.py
-# RUN: echo "   0x2000, 0x2008, 0x200C, 0x2014, 0x2104, 0x2300,"                  >> %t.py
+# RUN: echo "   0x2000, 0x2008, 0x200C, 0x2018, 0x2104, 0x2300,"                  >> %t.py
 # RUN: echo "   0x3008, 0x3010, 0x3018, 0x3020, 0x3028, 0x302C, 0x3034, 0x303C,"  >> %t.py
 # RUN: echo "   0x4000, 0x4008, 0x4010, 0x4014, 0x401C, 0x4024, 0x4034,"          >> %t.py
 # RUN: echo "   0x5000, 0x5008, 0x5010, 0x501C, 0x5024, 0x502C, 0x5030, 0x5038]:" >> %t.py
@@ -32,7 +32,7 @@
 # RUN: echo "    input.write(bytearray.fromhex('DEADBEEF'))"                      >> %t.py
 # RUN: %python %t.py
 # RUN: llvm-objcopy %t.in %t.out
-# RUN: od -t x1 -j 0x2000 -N 24 %t.out | FileCheck %s --ignore-case --check-prefix=CHECK1 -DPATTERN="de ad be ef"
+# RUN: od -t x1 -j 0x2000 -N 28 %t.out | FileCheck %s --ignore-case --check-prefix=CHECK1 -DPATTERN="de ad be ef"
 # RUN: od -t x1 -j 0x2100 -N 12 %t.out | FileCheck %s --ignore-case --check-prefix=CHECK2 -DPATTERN="de ad be ef"
 # RUN: od -t x1 -j 0x2200 -N 4  %t.out | FileCheck %s --ignore-case --check-prefix=CHECK3 -DPATTERN="de ad be ef"
 # RUN: od -t x1 -j 0x2300 -N 12 %t.out | FileCheck %s --ignore-case --check-prefix=CHECK4 -DPATTERN="de ad be ef"
@@ -41,7 +41,7 @@
 # RUN: od -t x1 -j 0x5000 -N 60 %t.out | FileCheck %s --ignore-case --check-prefix=CHECK7 -DPATTERN="de ad be ef"
 
 # CHECK1:      [[PATTERN]] 11 22 33 44 [[PATTERN]] [[PATTERN]]
-# CHECK1-NEXT: 55 66 77 88 [[PATTERN]]
+# CHECK1-NEXT: 00 00 00 00 55 66 77 88 [[PATTERN]]
 # CHECK2:      99 00 aa bb [[PATTERN]] cc dd ee ff
 # CHECK3:      fe fe fe fe
 # CHECK4:      [[PATTERN]] 00 00 00 00 00 00 00 00

diff  --git a/llvm/test/tools/yaml2obj/ELF/program-header-nobits.yaml b/llvm/test/tools/yaml2obj/ELF/program-header-nobits.yaml
index 81fdb9372286..0704c4834d69 100644
--- a/llvm/test/tools/yaml2obj/ELF/program-header-nobits.yaml
+++ b/llvm/test/tools/yaml2obj/ELF/program-header-nobits.yaml
@@ -1,39 +1,142 @@
-# RUN: yaml2obj %s -o %t
-# RUN: llvm-readobj -l %t | FileCheck %s
+## In this test we check that we allocate file space for SHT_NOBITS sections when
+## there are non-nobits sections in the same segment after them. When an object has
+## multiple segments, we check each and allocate the space if at least one matches the
+## condition mentioned.
 
-!ELF
+## Case A. In this case there are no non-nobits sections after SHT_NOBITS sections in segments.
+##         Because of this the file space for SHT_NOBITS sections is not allocated.
+# RUN: yaml2obj %s -D SEC1=.data.before -D SEC2=.nobits.1 -o %t1
+# RUN: llvm-readelf --sections --segments %t1 | FileCheck %s --check-prefix=NO-ALLOC
+
+# NO-ALLOC:      [Nr] Name         Type     Address          Off    Size
+# NO-ALLOC:      [ 1] .data.before PROGBITS 0000000000000000 0000b0 000001
+# NO-ALLOC-NEXT: [ 2] .nobits.1    NOBITS   0000000000000001 0000b1 000002
+# NO-ALLOC-NEXT: [ 3] .data.after  PROGBITS 0000000000000003 0000b1 000003
+# NO-ALLOC-NEXT: [ 4] .nobits.2    NOBITS   0000000000000006 0000b4 000004
+## .fill of size 0x5 is placed here.
+# NO-ALLOC-NEXT: [ 5] .data.last   PROGBITS 000000000000000f 0000b9 000006
+
+# NO-ALLOC:       Type Offset   VirtAddr           PhysAddr           FileSiz  MemSiz
+# NO-ALLOC-NEXT:  LOAD 0x0000b0 0x0000000000000000 0x0000000000000000 0x000001 0x000003
+# NO-ALLOC-NEXT:  LOAD 0x0000b0 0x0000000000000000 0x0000000000000000 0x000001 0x000003
+
+## Case B. We have a segment that has a non-nobits section after the SHT_NOBITS section ".nobits.1".
+##         The file space is allocated for it, but not for ".nobits.2",
+##         which does not belong to any segment.
+# RUN: yaml2obj %s -D SEC1=.nobits.1 -D SEC2=.data.after -o %t2
+# RUN: llvm-readelf --sections --segments %t2 | FileCheck %s --check-prefix=ALLOC-FIRST
+
+# ALLOC-FIRST:      [Nr] Name         Type     Address          Off    Size
+# ALLOC-FIRST:      [ 1] .data.before PROGBITS 0000000000000000 0000b0 000001
+# ALLOC-FIRST-NEXT: [ 2] .nobits.1    NOBITS   0000000000000001 0000b1 000002
+# ALLOC-FIRST-NEXT: [ 3] .data.after  PROGBITS 0000000000000003 0000b3 000003
+# ALLOC-FIRST-NEXT: [ 4] .nobits.2    NOBITS   0000000000000006 0000b6 000004
+## .fill of size 0x5 is placed here.
+# ALLOC-FIRST-NEXT: [ 5] .data.last   PROGBITS 000000000000000f 0000bb 000006
+
+# ALLOC-FIRST:       Type Offset   VirtAddr           PhysAddr           FileSiz  MemSiz
+# ALLOC-FIRST-NEXT:  LOAD 0x0000b0 0x0000000000000000 0x0000000000000000 0x000001 0x000003
+# ALLOC-FIRST-NEXT:  LOAD 0x0000b1 0x0000000000000000 0x0000000000000000 0x000005 0x000005
+
+## Case C. We have a Fill after the ".nobits.2" section. In this case the file space is
+##         allocated for it, because fills are handled just like any other non-nobits sections.
+# RUN: yaml2obj %s -D SEC1=.nobits.2 -D SEC2=.fill -o %t3
+# RUN: llvm-readelf --sections --segments %t3 | FileCheck %s --check-prefix=FILL-AT-END
+
+# FILL-AT-END: [Nr] Name       Type     Address          Off    Size
+# FILL-AT-END: [ 4] .nobits.2  NOBITS   0000000000000006 0000b4 000004
+## .fill of size 0x5 is placed here.
+# FILL-AT-END: [ 5] .data.last PROGBITS 000000000000000f 0000bd 000006
+
+# FILL-AT-END:      Type Offset   VirtAddr           PhysAddr           FileSiz  MemSiz
+# FILL-AT-END-NEXT: LOAD 0x0000b0 0x0000000000000000 0x0000000000000000 0x000001 0x000003
+# FILL-AT-END-NEXT: LOAD 0x0000b4 0x0000000000000000 0x0000000000000000 0x000009 0x000009
+
+--- !ELF
+FileHeader:
+  Class:   ELFCLASS64
+  Data:    ELFDATA2LSB
+  Type:    ET_EXEC
+  Machine: EM_X86_64
+Sections:
+  - Name:  .data.before
+    Type:  SHT_PROGBITS
+    Flags: [ SHF_ALLOC ]
+    Size:  0x1
+  - Name:  .nobits.1
+    Type:  SHT_NOBITS
+    Flags: [ SHF_ALLOC ]
+    Size:  0x2
+  - Name:  .data.after
+    Type:  SHT_PROGBITS
+    Flags: [ SHF_ALLOC ]
+    Size:  0x3
+  - Name:  .nobits.2
+    Type:  SHT_NOBITS
+    Flags: [ SHF_ALLOC ]
+    Size:  0x4
+  - Type:    Fill
+    Name:    .fill
+    Pattern: "00"
+    Size:    5
+  - Name:  .data.last
+    Type:  SHT_PROGBITS
+    Flags: [ SHF_ALLOC ]
+    Size:  0x6
+ProgramHeaders:
+## We have 2 segments, the first is predefined and the second can be customized.
+## We want to have more than one segment to show we check all of them when
+## trying to find a non-nobits section after a nobits one.
+  - Type:  PT_LOAD
+    Flags: [ PF_R ]
+    Sections:
+      - Section: .data.before
+      - Section: .nobits.1
+  - Type:  PT_LOAD
+    Flags: [ PF_R ]
+    Sections:
+      - Section: [[SEC1]]
+      - Section: [[SEC2]]
+
+## Case D. We have a segment with SHT_NOBITS sections on its borders and one
+##         non-nobits in the middle. Check we allocate the file space only for
+##         the first nobits section.
+
+# RUN: yaml2obj --docnum=2 %s -o %t4
+# RUN: llvm-readelf --sections --segments %t4 | FileCheck %s --check-prefix=MIDDLE
+
+# MIDDLE:      [Nr] Name      Type     Address          Off    Size
+# MIDDLE:      [ 1] .nobits.1 NOBITS   0000000000000000 000078 000001
+# MIDDLE-NEXT: [ 2] .data     PROGBITS 0000000000000001 000079 000010
+# MIDDLE-NEXT: [ 3] .nobits.2 NOBITS   0000000000000011 000089 000100
+# MIDDLE-NEXT: [ 4] .strtab   STRTAB   0000000000000000 000089 000001
+
+# MIDDLE:      Type Offset   VirtAddr           PhysAddr           FileSiz  MemSiz
+# MIDDLE-NEXT: LOAD 0x000078 0x0000000000000000 0x0000000000000000 0x000011 0x000111
+
+--- !ELF
 FileHeader:
-  Class:           ELFCLASS64
-  Data:            ELFDATA2LSB
-  Type:            ET_EXEC
-  Machine:         EM_X86_64
+  Class:   ELFCLASS64
+  Data:    ELFDATA2LSB
+  Type:    ET_EXEC
+  Machine: EM_X86_64
 Sections:
-  - Name:            .data
-    Type:            SHT_PROGBITS
-    Flags:           [ SHF_ALLOC ]
-    Content:         "00000000"
-  - Name:            .after
-    Type:            SHT_NOBITS
-    Flags:           [ SHF_ALLOC ]
-    Size:            64
+  - Name:  .nobits.1
+    Type:  SHT_NOBITS
+    Flags: [ SHF_ALLOC ]
+    Size:  0x1
+  - Name:  .data
+    Type:  SHT_PROGBITS
+    Flags: [ SHF_ALLOC ]
+    Size:  0x10
+  - Name:  .nobits.2
+    Type:  SHT_NOBITS
+    Flags: [ SHF_ALLOC ]
+    Size:  0x100
 ProgramHeaders:
-  - Type: PT_LOAD
+  - Type:  PT_LOAD
     Flags: [ PF_R ]
     Sections:
+      - Section: .nobits.1
       - Section: .data
-      - Section: .after
-
-#CHECK:     ProgramHeaders [
-#CHECK-NEXT:  ProgramHeader {
-#CHECK-NEXT:    Type: PT_LOAD
-#CHECK-NEXT:    Offset:
-#CHECK-NEXT:    VirtualAddress:
-#CHECK-NEXT:    PhysicalAddress:
-#CHECK-NEXT:    FileSize: 4
-#CHECK-NEXT:    MemSize: 68
-#CHECK-NEXT:    Flags [
-#CHECK-NEXT:      PF_R
-#CHECK-NEXT:    ]
-#CHECK-NEXT:    Alignment:
-#CHECK-NEXT:  }
-#CHECK-NEXT:]
+      - Section: .nobits.2


        


More information about the llvm-commits mailing list