diff --git a/llvm/include/llvm/ObjCopy/MachO/MachOConfig.h b/llvm/include/llvm/ObjCopy/MachO/MachOConfig.h --- a/llvm/include/llvm/ObjCopy/MachO/MachOConfig.h +++ b/llvm/include/llvm/ObjCopy/MachO/MachOConfig.h @@ -29,6 +29,9 @@ // install-name-tool's id option Optional SharedLibId; + // Segments to remove if they are empty + DenseSet EmptySegmentsToRemove; + // Boolean options bool StripSwiftSymbols = false; bool KeepUndefined = false; diff --git a/llvm/lib/ObjCopy/MachO/MachOObjcopy.cpp b/llvm/lib/ObjCopy/MachO/MachOObjcopy.cpp --- a/llvm/lib/ObjCopy/MachO/MachOObjcopy.cpp +++ b/llvm/lib/ObjCopy/MachO/MachOObjcopy.cpp @@ -269,6 +269,21 @@ return E; } + // Remove any empty segments if required. + if (!MachOConfig.EmptySegmentsToRemove.empty()) { + auto RemovePred = [&MachOConfig](const LoadCommand &LC) { + if (LC.MachOLoadCommand.load_command_data.cmd == MachO::LC_SEGMENT_64 || + LC.MachOLoadCommand.load_command_data.cmd == MachO::LC_SEGMENT) { + return LC.Sections.empty() && + MachOConfig.EmptySegmentsToRemove.contains( + LC.getSegmentName().getValue()); + } + return false; + }; + if (Error E = Obj.removeLoadCommands(RemovePred)) + return E; + } + return Error::success(); } diff --git a/llvm/test/tools/llvm-objcopy/MachO/bitcode-strip-remove.test b/llvm/test/tools/llvm-objcopy/MachO/bitcode-strip-remove-nonempty-segment.test copy from llvm/test/tools/llvm-objcopy/MachO/bitcode-strip-remove.test copy to llvm/test/tools/llvm-objcopy/MachO/bitcode-strip-remove-nonempty-segment.test --- a/llvm/test/tools/llvm-objcopy/MachO/bitcode-strip-remove.test +++ b/llvm/test/tools/llvm-objcopy/MachO/bitcode-strip-remove-nonempty-segment.test @@ -1,7 +1,8 @@ -## Test bitcode section removal. +## Test bitcode section and segment removal. # RUN: yaml2obj %s -o %t # RUN: llvm-bitcode-strip -r %t -o %t2 # RUN: llvm-readobj --sections %t2 | FileCheck --implicit-check-not=Name %s +# RUN: llvm-otool -l %t2 | FileCheck --check-prefix=SEGMENTS %s # CHECK: Name: __text # CHECK-NEXT: Segment: __TEXT @@ -10,27 +11,29 @@ # CHECK: Name: __notbundle # CHECK-NEXT: Segment: __LLVM +# SEGMENTS: segname __LLVM + --- !mach-o FileHeader: magic: 0xFEEDFACF cputype: 0x01000007 cpusubtype: 0x00000003 filetype: 0x00000001 - ncmds: 1 - sizeofcmds: 392 + ncmds: 3 + sizeofcmds: 536 flags: 0x00002000 reserved: 0x00000000 LoadCommands: - cmd: LC_SEGMENT_64 - cmdsize: 392 - segname: '' + cmdsize: 152 + segname: __TEXT vmaddr: 0 - vmsize: 16 - fileoff: 424 - filesize: 16 + vmsize: 4 + fileoff: 568 + filesize: 4 maxprot: 7 initprot: 7 - nsects: 4 + nsects: 1 flags: 0 Sections: - sectname: __text @@ -38,7 +41,7 @@ addr: 0x0000000000000000 content: 'AABBCCDD' size: 4 - offset: 424 + offset: 568 align: 0 reloff: 0x00000000 nreloc: 0 @@ -46,12 +49,24 @@ reserved1: 0x00000000 reserved2: 0x00000000 reserved3: 0x00000000 + - cmd: LC_SEGMENT_64 + cmdsize: 152 + segname: __DATA + vmaddr: 4 + vmsize: 4 + fileoff: 572 + filesize: 4 + maxprot: 7 + initprot: 7 + nsects: 1 + flags: 0 + Sections: - sectname: __bundle segname: __DATA addr: 0x0000000000000004 content: 'DDAADDAA' size: 4 - offset: 428 + offset: 572 align: 0 reloff: 0x00000000 nreloc: 0 @@ -59,12 +74,24 @@ reserved1: 0x00000000 reserved2: 0x00000000 reserved3: 0x00000000 + - cmd: LC_SEGMENT_64 + cmdsize: 232 + segname: __LLVM + vmaddr: 8 + vmsize: 8 + fileoff: 576 + filesize: 8 + maxprot: 7 + initprot: 7 + nsects: 2 + flags: 0 + Sections: - sectname: __bundle segname: __LLVM addr: 0x0000000000000008 content: 'EEFFEEFF' size: 4 - offset: 432 + offset: 576 align: 0 reloff: 0x00000000 nreloc: 0 @@ -77,7 +104,7 @@ addr: 0x0000000000000008 content: 'EEFFEEFF' size: 4 - offset: 436 + offset: 580 align: 0 reloff: 0x00000000 nreloc: 0 diff --git a/llvm/test/tools/llvm-objcopy/MachO/bitcode-strip-remove.test b/llvm/test/tools/llvm-objcopy/MachO/bitcode-strip-remove.test --- a/llvm/test/tools/llvm-objcopy/MachO/bitcode-strip-remove.test +++ b/llvm/test/tools/llvm-objcopy/MachO/bitcode-strip-remove.test @@ -1,14 +1,15 @@ -## Test bitcode section removal. +## Test bitcode section and segment removal. # RUN: yaml2obj %s -o %t # RUN: llvm-bitcode-strip -r %t -o %t2 # RUN: llvm-readobj --sections %t2 | FileCheck --implicit-check-not=Name %s +# RUN: llvm-otool -l %t2 | FileCheck --check-prefix=SEGMENTS %s # CHECK: Name: __text # CHECK-NEXT: Segment: __TEXT # CHECK: Name: __bundle # CHECK-NEXT: Segment: __DATA -# CHECK: Name: __notbundle -# CHECK-NEXT: Segment: __LLVM + +# SEGMENTS-NOT: segname __LLVM --- !mach-o FileHeader: @@ -16,21 +17,21 @@ cputype: 0x01000007 cpusubtype: 0x00000003 filetype: 0x00000001 - ncmds: 1 - sizeofcmds: 392 + ncmds: 3 + sizeofcmds: 456 flags: 0x00002000 reserved: 0x00000000 LoadCommands: - cmd: LC_SEGMENT_64 - cmdsize: 392 - segname: '' + cmdsize: 152 + segname: __TEXT vmaddr: 0 - vmsize: 16 - fileoff: 424 - filesize: 16 + vmsize: 4 + fileoff: 488 + filesize: 4 maxprot: 7 initprot: 7 - nsects: 4 + nsects: 1 flags: 0 Sections: - sectname: __text @@ -38,7 +39,7 @@ addr: 0x0000000000000000 content: 'AABBCCDD' size: 4 - offset: 424 + offset: 488 align: 0 reloff: 0x00000000 nreloc: 0 @@ -46,12 +47,24 @@ reserved1: 0x00000000 reserved2: 0x00000000 reserved3: 0x00000000 + - cmd: LC_SEGMENT_64 + cmdsize: 152 + segname: __DATA + vmaddr: 4 + vmsize: 4 + fileoff: 492 + filesize: 4 + maxprot: 7 + initprot: 7 + nsects: 1 + flags: 0 + Sections: - sectname: __bundle segname: __DATA addr: 0x0000000000000004 content: 'DDAADDAA' size: 4 - offset: 428 + offset: 492 align: 0 reloff: 0x00000000 nreloc: 0 @@ -59,25 +72,24 @@ reserved1: 0x00000000 reserved2: 0x00000000 reserved3: 0x00000000 + - cmd: LC_SEGMENT_64 + cmdsize: 152 + segname: __LLVM + vmaddr: 8 + vmsize: 4 + fileoff: 496 + filesize: 4 + maxprot: 7 + initprot: 7 + nsects: 1 + flags: 0 + Sections: - sectname: __bundle segname: __LLVM addr: 0x0000000000000008 content: 'EEFFEEFF' size: 4 - offset: 432 - align: 0 - reloff: 0x00000000 - nreloc: 0 - flags: 0x00000000 - reserved1: 0x00000000 - reserved2: 0x00000000 - reserved3: 0x00000000 - - sectname: __notbundle - segname: __LLVM - addr: 0x0000000000000008 - content: 'EEFFEEFF' - size: 4 - offset: 436 + offset: 496 align: 0 reloff: 0x00000000 nreloc: 0 diff --git a/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp b/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp --- a/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp +++ b/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp @@ -1220,9 +1220,11 @@ if (!InputArgs.hasArg(BITCODE_STRIP_remove)) return createStringError(errc::invalid_argument, "no action specified"); - // We only support -r for now, which removes all bitcode sections. + // We only support -r for now, which removes all bitcode sections and + // the __LLVM segment if its now empty. cantFail(Config.ToRemove.addMatcher(NameOrPattern::create( "__LLVM,__bundle", MatchStyle::Literal, ErrorCallback))); + MachOConfig.EmptySegmentsToRemove.insert("__LLVM"); // By default remove codesign load commands as they will be invalid after // stripping.