[llvm-objcopy][MachO] Fix adding multiple sections
authorCornelius Aschermann <eqv@fb.com>
Sun, 8 Nov 2020 02:12:51 +0000 (18:12 -0800)
committerAlexander Shaposhnikov <alexshap@fb.com>
Sun, 8 Nov 2020 02:16:06 +0000 (18:16 -0800)
This diff fixes missing fields initialization (Size, VMSize).
Previously this resulted in broken binaries when multiple sections
were added in one tool's invocatation.

Test plan: make check-all

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

llvm/test/tools/llvm-objcopy/MachO/add-multiple-sections.test [new file with mode: 0644]
llvm/tools/llvm-objcopy/MachO/MachOObjcopy.cpp
llvm/tools/llvm-objcopy/MachO/Object.cpp
llvm/tools/llvm-objcopy/MachO/Object.h

diff --git a/llvm/test/tools/llvm-objcopy/MachO/add-multiple-sections.test b/llvm/test/tools/llvm-objcopy/MachO/add-multiple-sections.test
new file mode 100644 (file)
index 0000000..2b6c12e
--- /dev/null
@@ -0,0 +1,189 @@
+## This test verifies that llvm-objcopy can add multiple sections to a Mach-O binary.
+
+# RUN: yaml2obj %s -o %t
+# RUN: echo -n FOOabcdefg > %t.foo.data
+# RUN: echo -n BARabcdefg > %t.bar.data
+
+## Case 1: Add a new section twice into an existing segment.
+# RUN: llvm-objcopy --add-section __TEXT,__foo=%t.foo.data %t %t.foo.1
+# RUN: llvm-objcopy --add-section __TEXT,__bar=%t.bar.data %t.foo.1 %t.foo.bar.1
+# RUN: llvm-readobj --sections --section-data %t.foo.bar.1 \
+# RUN:   | FileCheck %s -check-prefix=CASE1
+
+## Case 2: Add two new sections into an existing segment.
+# RUN: llvm-objcopy --add-section __TEXT,__foo=%t.foo.data --add-section __TEXT,__bar=%t.bar.data %t %t.foo.bar.2
+# RUN: llvm-readobj --sections --section-data %t.foo.bar.2 \
+# RUN:   | FileCheck %s -check-prefix=CASE1
+
+## Case 3: Add two new sections into two different segments.
+# RUN: llvm-objcopy --add-section __FOO,__foo=%t.foo.data --add-section __BAR,__bar=%t.bar.data %t %t.foo.bar.3
+# RUN: llvm-readobj --sections --section-data %t.foo.bar.3 \
+# RUN:   | FileCheck %s -check-prefix=CASE3
+
+--- !mach-o
+FileHeader:
+  magic:           0xFEEDFACF
+  cputype:         0x01000007
+  cpusubtype:      0x00000003
+  filetype:        0x00000001
+  ncmds:           1
+  sizeofcmds:      152
+  flags:           0x00002000
+  reserved:        0x00000000
+LoadCommands:
+  - cmd:             LC_SEGMENT_64
+    cmdsize:         152
+    segname:         __TEXT
+    vmaddr:          0
+    vmsize:          4
+    fileoff:         184
+    filesize:        4
+    maxprot:         7
+    initprot:        7
+    nsects:          1
+    flags:           0
+    Sections:
+      - sectname:        __text
+        segname:         __TEXT
+        addr:            0x0000000000000000
+        content:         'AABBCCDD'
+        size:            4
+        offset:          184
+        align:           0
+        reloff:          0x00000000
+        nreloc:          0
+        flags:           0x80000400
+        reserved1:       0x00000000
+        reserved2:       0x00000000
+        reserved3:       0x00000000
+
+# CASE1:        Sections [
+# CASE1-NEXT:    Section {
+# CASE1-NEXT:      Index: 0
+# CASE1-NEXT:      Name: __text (5F 5F 74 65 78 74 00 00 00 00 00 00 00 00 00 00)
+# CASE1-NEXT:      Segment: __TEXT (5F 5F 54 45 58 54 00 00 00 00 00 00 00 00 00 00)
+# CASE1-NEXT:      Address: 0x0
+# CASE1-NEXT:      Size: 0x4
+# CASE1-NEXT:      Offset: 344
+# CASE1-NEXT:      Alignment: 0
+# CASE1-NEXT:      RelocationOffset: 0x0
+# CASE1-NEXT:      RelocationCount: 0
+# CASE1-NEXT:      Type: Regular (0x0)
+# CASE1-NEXT:      Attributes [ (0x800004)
+# CASE1-NEXT:        PureInstructions (0x800000)
+# CASE1-NEXT:        SomeInstructions (0x4)
+# CASE1-NEXT:      ]
+# CASE1-NEXT:      Reserved1: 0x0
+# CASE1-NEXT:      Reserved2: 0x0
+# CASE1-NEXT:      Reserved3: 0x0
+# CASE1-NEXT:      SectionData (
+# CASE1-NEXT:        0000: AABBCCDD                             |....|
+# CASE1-NEXT:      )
+# CASE1-NEXT:    }
+# CASE1-NEXT:    Section {
+# CASE1-NEXT:      Index: 1
+# CASE1-NEXT:      Name: __foo (5F 5F 66 6F 6F 00 00 00 00 00 00 00 00 00 00 00)
+# CASE1-NEXT:      Segment: __TEXT (5F 5F 54 45 58 54 00 00 00 00 00 00 00 00 00 00)
+# CASE1-NEXT:      Address: 0x4
+# CASE1-NEXT:      Size: 0xA
+# CASE1-NEXT:      Offset: 348
+# CASE1-NEXT:      Alignment: 0
+# CASE1-NEXT:      RelocationOffset: 0x0
+# CASE1-NEXT:      RelocationCount: 0
+# CASE1-NEXT:      Type: Regular (0x0)
+# CASE1-NEXT:      Attributes [ (0x0)
+# CASE1-NEXT:      ]
+# CASE1-NEXT:      Reserved1: 0x0
+# CASE1-NEXT:      Reserved2: 0x0
+# CASE1-NEXT:      Reserved3: 0x0
+# CASE1-NEXT:      SectionData (
+# CASE1-NEXT:        0000: 464F4F61 62636465 6667               |FOOabcdefg|
+# CASE1-NEXT:      )
+# CASE1-NEXT:    }
+# CASE1-NEXT:    Section {
+# CASE1-NEXT:      Index: 2
+# CASE1-NEXT:      Name: __bar (5F 5F 62 61 72 00 00 00 00 00 00 00 00 00 00 00)
+# CASE1-NEXT:      Segment: __TEXT (5F 5F 54 45 58 54 00 00 00 00 00 00 00 00 00 00)
+# CASE1-NEXT:      Address: 0xE
+# CASE1-NEXT:      Size: 0xA
+# CASE1-NEXT:      Offset: 358
+# CASE1-NEXT:      Alignment: 0
+# CASE1-NEXT:      RelocationOffset: 0x0
+# CASE1-NEXT:      RelocationCount: 0
+# CASE1-NEXT:      Type: Regular (0x0)
+# CASE1-NEXT:      Attributes [ (0x0)
+# CASE1-NEXT:      ]
+# CASE1-NEXT:      Reserved1: 0x0
+# CASE1-NEXT:      Reserved2: 0x0
+# CASE1-NEXT:      Reserved3: 0x0
+# CASE1-NEXT:      SectionData (
+# CASE1-NEXT:        0000: 42415261 62636465 6667               |BARabcdefg|
+# CASE1-NEXT:      )
+# CASE1-NEXT:    }
+# CASE1-NEXT:  ]
+
+# CASE3:        Sections [
+# CASE3-NEXT:    Section {
+# CASE3-NEXT:      Index: 0
+# CASE3-NEXT:      Name: __text (5F 5F 74 65 78 74 00 00 00 00 00 00 00 00 00 00)
+# CASE3-NEXT:      Segment: __TEXT (5F 5F 54 45 58 54 00 00 00 00 00 00 00 00 00 00)
+# CASE3-NEXT:      Address: 0x0
+# CASE3-NEXT:      Size: 0x4
+# CASE3-NEXT:      Offset: 488
+# CASE3-NEXT:      Alignment: 0
+# CASE3-NEXT:      RelocationOffset: 0x0
+# CASE3-NEXT:      RelocationCount: 0
+# CASE3-NEXT:      Type: Regular (0x0)
+# CASE3-NEXT:      Attributes [ (0x800004)
+# CASE3-NEXT:        PureInstructions (0x800000)
+# CASE3-NEXT:        SomeInstructions (0x4)
+# CASE3-NEXT:      ]
+# CASE3-NEXT:      Reserved1: 0x0
+# CASE3-NEXT:      Reserved2: 0x0
+# CASE3-NEXT:      Reserved3: 0x0
+# CASE3-NEXT:      SectionData (
+# CASE3-NEXT:        0000: AABBCCDD                             |....|
+# CASE3-NEXT:      )
+# CASE3-NEXT:    }
+# CASE3-NEXT:    Section {
+# CASE3-NEXT:      Index: 1
+# CASE3-NEXT:      Name: __foo (5F 5F 66 6F 6F 00 00 00 00 00 00 00 00 00 00 00)
+# CASE3-NEXT:      Segment: __FOO (5F 5F 46 4F 4F 00 00 00 00 00 00 00 00 00 00 00)
+# CASE3-NEXT:      Address: 0xB8
+# CASE3-NEXT:      Size: 0xA
+# CASE3-NEXT:      Offset: 492
+# CASE3-NEXT:      Alignment: 0
+# CASE3-NEXT:      RelocationOffset: 0x0
+# CASE3-NEXT:      RelocationCount: 0
+# CASE3-NEXT:      Type: Regular (0x0)
+# CASE3-NEXT:      Attributes [ (0x0)
+# CASE3-NEXT:      ]
+# CASE3-NEXT:      Reserved1: 0x0
+# CASE3-NEXT:      Reserved2: 0x0
+# CASE3-NEXT:      Reserved3: 0x0
+# CASE3-NEXT:      SectionData (
+# CASE3-NEXT:        0000: 464F4F61 62636465 6667               |FOOabcdefg|
+# CASE3-NEXT:      )
+# CASE3-NEXT:    }
+# CASE3-NEXT:    Section {
+# CASE3-NEXT:      Index: 2
+# CASE3-NEXT:      Name: __bar (5F 5F 62 61 72 00 00 00 00 00 00 00 00 00 00 00)
+# CASE3-NEXT:      Segment: __BAR (5F 5F 42 41 52 00 00 00 00 00 00 00 00 00 00 00)
+# CASE3-NEXT:      Address: 0x40B8
+# CASE3-NEXT:      Size: 0xA
+# CASE3-NEXT:      Offset: 502
+# CASE3-NEXT:      Alignment: 0
+# CASE3-NEXT:      RelocationOffset: 0x0
+# CASE3-NEXT:      RelocationCount: 0
+# CASE3-NEXT:      Type: Regular (0x0)
+# CASE3-NEXT:      Attributes [ (0x0)
+# CASE3-NEXT:      ]
+# CASE3-NEXT:      Reserved1: 0x0
+# CASE3-NEXT:      Reserved2: 0x0
+# CASE3-NEXT:      Reserved3: 0x0
+# CASE3-NEXT:      SectionData (
+# CASE3-NEXT:        0000: 42415261 62636465 6667               |BARabcdefg|
+# CASE3-NEXT:      )
+# CASE3-NEXT:    }
+# CASE3-NEXT:  ]
+
index 469dc6f..4376802 100644 (file)
@@ -280,6 +280,7 @@ static Error addSection(StringRef SecName, StringRef Filename, Object &Obj) {
   StringRef TargetSegName = Pair.first;
   Section Sec(TargetSegName, Pair.second);
   Sec.Content = Obj.NewSectionsContents.save(Buf->getBuffer());
+  Sec.Size = Sec.Content.size();
 
   // Add the a section into an existing segment.
   for (LoadCommand &LC : Obj.LoadCommands) {
@@ -296,7 +297,8 @@ static Error addSection(StringRef SecName, StringRef Filename, Object &Obj) {
 
   // There's no segment named TargetSegName. Create a new load command and
   // Insert a new section into it.
-  LoadCommand &NewSegment = Obj.addSegment(TargetSegName);
+  LoadCommand &NewSegment =
+      Obj.addSegment(TargetSegName, alignTo(Sec.Size, 16384));
   NewSegment.Sections.push_back(std::make_unique<Section>(Sec));
   NewSegment.Sections.back()->Addr = *NewSegment.getSegmentVMAddr();
   return Error::success();
index 4302904..e0a59b1 100644 (file)
@@ -134,9 +134,9 @@ uint64_t Object::nextAvailableSegmentAddress() const {
 }
 
 template <typename SegmentType>
-static void constructSegment(SegmentType &Seg,
-                             llvm::MachO::LoadCommandType CmdType,
-                             StringRef SegName, uint64_t SegVMAddr) {
+static void
+constructSegment(SegmentType &Seg, llvm::MachO::LoadCommandType CmdType,
+                 StringRef SegName, uint64_t SegVMAddr, uint64_t SegVMSize) {
   assert(SegName.size() <= sizeof(Seg.segname) && "too long segment name");
   memset(&Seg, 0, sizeof(SegmentType));
   Seg.cmd = CmdType;
@@ -146,17 +146,18 @@ static void constructSegment(SegmentType &Seg,
   Seg.initprot |=
       (MachO::VM_PROT_READ | MachO::VM_PROT_WRITE | MachO::VM_PROT_EXECUTE);
   Seg.vmaddr = SegVMAddr;
+  Seg.vmsize = SegVMSize;
 }
 
-LoadCommand &Object::addSegment(StringRef SegName) {
+LoadCommand &Object::addSegment(StringRef SegName, uint64_t SegVMSize) {
   LoadCommand LC;
   const uint64_t SegVMAddr = nextAvailableSegmentAddress();
   if (is64Bit())
     constructSegment(LC.MachOLoadCommand.segment_command_64_data,
-                     MachO::LC_SEGMENT_64, SegName, SegVMAddr);
+                     MachO::LC_SEGMENT_64, SegName, SegVMAddr, SegVMSize);
   else
     constructSegment(LC.MachOLoadCommand.segment_command_data,
-                     MachO::LC_SEGMENT, SegName, SegVMAddr);
+                     MachO::LC_SEGMENT, SegName, SegVMAddr, SegVMSize);
 
   LoadCommands.push_back(std::move(LC));
   return LoadCommands.back();
index a743e12..0bb4b34 100644 (file)
@@ -343,7 +343,7 @@ struct Object {
   /// Creates a new segment load command in the object and returns a reference
   /// to the newly created load command. The caller should verify that SegName
   /// is not too long (SegName.size() should be less than or equal to 16).
-  LoadCommand &addSegment(StringRef SegName);
+  LoadCommand &addSegment(StringRef SegName, uint64_t SegVMSize);
 
   bool is64Bit() const {
     return Header.Magic == MachO::MH_MAGIC_64 ||