From f147f59cd377a6be68e5ca5c343eb11df8e7ee6f Mon Sep 17 00:00:00 2001 From: Alexander Shaposhnikov Date: Fri, 6 Nov 2020 13:10:41 -0800 Subject: [PATCH] [llvm-objcopy][MachO] Skip sections with zero offset Some binaries can contain regular sections with zero offset and zero size. This diff makes llvm-objcopy's handling of such sections consistent with cctools's strip (which doesn't modify them), previously the tool would allocate file space for them. Test plan: make check-all Differential revision: https://reviews.llvm.org/D90796 --- .../MachO/zero-offset-section.test | 43 +++++++++++++++++++ .../llvm-objcopy/MachO/MachOLayoutBuilder.cpp | 4 +- llvm/tools/llvm-objcopy/MachO/MachOReader.cpp | 2 +- llvm/tools/llvm-objcopy/MachO/MachOWriter.cpp | 12 ++++-- llvm/tools/llvm-objcopy/MachO/Object.h | 6 +++ 5 files changed, 61 insertions(+), 6 deletions(-) create mode 100644 llvm/test/tools/llvm-objcopy/MachO/zero-offset-section.test diff --git a/llvm/test/tools/llvm-objcopy/MachO/zero-offset-section.test b/llvm/test/tools/llvm-objcopy/MachO/zero-offset-section.test new file mode 100644 index 000000000000..3d14c34ec741 --- /dev/null +++ b/llvm/test/tools/llvm-objcopy/MachO/zero-offset-section.test @@ -0,0 +1,43 @@ +## This test verifies that a regular (non-zero-fill) section with zero offset +## and zero size is not modifed, this behavior is consistent with cctools' strip. + +# RUN: yaml2obj %s -o %t +# RUN: llvm-objcopy %t %t.copy +# RUN: cmp %t %t.copy + +--- !mach-o +FileHeader: + magic: 0xFEEDFACE + cputype: 0x00000007 + cpusubtype: 0x00000003 + filetype: 0x00000001 + ncmds: 1 + sizeofcmds: 124 + flags: 0x00002000 +LoadCommands: + - cmd: LC_SEGMENT + cmdsize: 124 + segname: __DATA + vmaddr: 4096 + vmsize: 0 + fileoff: 152 + filesize: 0 + maxprot: 7 + initprot: 7 + nsects: 1 + flags: 0 + Sections: + - sectname: __broken + segname: __DATA + addr: 0x0000000000001000 + size: 0 + offset: 0x00000000 + align: 2 + reloff: 0x00000000 + nreloc: 0 + flags: 0x00000000 + reserved1: 0x00000000 + reserved2: 0x00000000 + reserved3: 0x00000000 + content: '' +... diff --git a/llvm/tools/llvm-objcopy/MachO/MachOLayoutBuilder.cpp b/llvm/tools/llvm-objcopy/MachO/MachOLayoutBuilder.cpp index 947636ac985b..ea01e8519a5c 100644 --- a/llvm/tools/llvm-objcopy/MachO/MachOLayoutBuilder.cpp +++ b/llvm/tools/llvm-objcopy/MachO/MachOLayoutBuilder.cpp @@ -148,7 +148,7 @@ uint64_t MachOLayoutBuilder::layoutSegments() { "Section's address cannot be smaller than Segment's one"); uint32_t SectOffset = Sec->Addr - SegmentVmAddr; if (IsObjectFile) { - if (Sec->isVirtualSection()) { + if (!Sec->hasValidOffset()) { Sec->Offset = 0; } else { uint64_t PaddingSize = @@ -158,7 +158,7 @@ uint64_t MachOLayoutBuilder::layoutSegments() { SegFileSize += PaddingSize + Sec->Size; } } else { - if (Sec->isVirtualSection()) { + if (!Sec->hasValidOffset()) { Sec->Offset = 0; } else { Sec->Offset = SegOffset + SectOffset; diff --git a/llvm/tools/llvm-objcopy/MachO/MachOReader.cpp b/llvm/tools/llvm-objcopy/MachO/MachOReader.cpp index 6e6975c35139..548a85bd497e 100644 --- a/llvm/tools/llvm-objcopy/MachO/MachOReader.cpp +++ b/llvm/tools/llvm-objcopy/MachO/MachOReader.cpp @@ -35,7 +35,7 @@ Section constructSectionCommon(SectionType Sec, uint32_t Index) { S.Index = Index; S.Addr = Sec.addr; S.Size = Sec.size; - S.Offset = Sec.offset; + S.OriginalOffset = Sec.offset; S.Align = Sec.align; S.RelOff = Sec.reloff; S.NReloc = Sec.nreloc; diff --git a/llvm/tools/llvm-objcopy/MachO/MachOWriter.cpp b/llvm/tools/llvm-objcopy/MachO/MachOWriter.cpp index 78e03c818fd0..56dd08df3b09 100644 --- a/llvm/tools/llvm-objcopy/MachO/MachOWriter.cpp +++ b/llvm/tools/llvm-objcopy/MachO/MachOWriter.cpp @@ -121,8 +121,10 @@ size_t MachOWriter::totalSize() const { // Otherwise, use the last section / reloction. for (const LoadCommand &LC : O.LoadCommands) for (const std::unique_ptr
&S : LC.Sections) { - if (S->isVirtualSection()) { - assert((S->Offset == 0) && "Zero-fill section's offset must be zero"); + if (!S->hasValidOffset()) { + assert((S->Offset == 0) && "Skipped section's offset must be zero"); + assert((S->isVirtualSection() || S->Size == 0) && + "Non-zero-fill sections with zero offset must have zero size"); continue; } assert((S->Offset != 0) && @@ -246,8 +248,12 @@ void MachOWriter::writeSectionInLoadCommand(const Section &Sec, uint8_t *&Out) { void MachOWriter::writeSections() { for (const LoadCommand &LC : O.LoadCommands) for (const std::unique_ptr
&Sec : LC.Sections) { - if (Sec->isVirtualSection()) + if (!Sec->hasValidOffset()) { + assert((Sec->Offset == 0) && "Skipped section's offset must be zero"); + assert((Sec->isVirtualSection() || Sec->Size == 0) && + "Non-zero-fill sections with zero offset must have zero size"); continue; + } assert(Sec->Offset && "Section offset can not be zero"); assert((Sec->Size == Sec->Content.size()) && "Incorrect section size"); diff --git a/llvm/tools/llvm-objcopy/MachO/Object.h b/llvm/tools/llvm-objcopy/MachO/Object.h index 0a930ba19f8e..a743e125c0cd 100644 --- a/llvm/tools/llvm-objcopy/MachO/Object.h +++ b/llvm/tools/llvm-objcopy/MachO/Object.h @@ -44,6 +44,8 @@ struct Section { std::string CanonicalName; uint64_t Addr = 0; uint64_t Size = 0; + // Offset in the input file. + Optional OriginalOffset; uint32_t Offset = 0; uint32_t Align = 0; uint32_t RelOff = 0; @@ -73,6 +75,10 @@ struct Section { getType() == MachO::S_GB_ZEROFILL || getType() == MachO::S_THREAD_LOCAL_ZEROFILL); } + + bool hasValidOffset() const { + return !(isVirtualSection() || (OriginalOffset && *OriginalOffset == 0)); + } }; struct LoadCommand {