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 --- /dev/null +++ b/llvm/test/tools/llvm-objcopy/MachO/add-multiple-sections.test @@ -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: ] + diff --git a/llvm/tools/llvm-objcopy/MachO/MachOObjcopy.cpp b/llvm/tools/llvm-objcopy/MachO/MachOObjcopy.cpp --- a/llvm/tools/llvm-objcopy/MachO/MachOObjcopy.cpp +++ b/llvm/tools/llvm-objcopy/MachO/MachOObjcopy.cpp @@ -280,6 +280,7 @@ 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 @@ // 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
(Sec)); NewSegment.Sections.back()->Addr = *NewSegment.getSegmentVMAddr(); return Error::success(); diff --git a/llvm/tools/llvm-objcopy/MachO/Object.h b/llvm/tools/llvm-objcopy/MachO/Object.h --- a/llvm/tools/llvm-objcopy/MachO/Object.h +++ b/llvm/tools/llvm-objcopy/MachO/Object.h @@ -343,7 +343,7 @@ /// 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 || diff --git a/llvm/tools/llvm-objcopy/MachO/Object.cpp b/llvm/tools/llvm-objcopy/MachO/Object.cpp --- a/llvm/tools/llvm-objcopy/MachO/Object.cpp +++ b/llvm/tools/llvm-objcopy/MachO/Object.cpp @@ -134,9 +134,9 @@ } template -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 @@ 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();