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 @@ -258,6 +258,21 @@ if (!MachOConfig.RPathToPrepend.empty()) Obj.updateLoadCommandIndexes(); + // 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,8 +1,9 @@ -## Test bitcode section removal. +## Test bitcode segment is not removed when not empty. # 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-readobj -h --sections %t2 | FileCheck --implicit-check-not=Name %s +# CHECK: NumOfLoadCommands: 3 # CHECK: Name: __text # CHECK-NEXT: Segment: __TEXT # CHECK: Name: __bundle @@ -16,21 +17,21 @@ 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 +39,7 @@ addr: 0x0000000000000000 content: 'AABBCCDD' size: 4 - offset: 424 + offset: 568 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: 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 +72,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 +102,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,13 @@ -## 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-readobj -h --sections %t2 | FileCheck --implicit-check-not=Name: %s +# CHECK: NumOfLoadCommands: 2 # CHECK: Name: __text # CHECK-NEXT: Segment: __TEXT # CHECK: Name: __bundle # CHECK-NEXT: Segment: __DATA -# CHECK: Name: __notbundle -# CHECK-NEXT: Segment: __LLVM --- !mach-o FileHeader: @@ -16,21 +15,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 +37,7 @@ addr: 0x0000000000000000 content: 'AABBCCDD' size: 4 - offset: 424 + offset: 488 align: 0 reloff: 0x00000000 nreloc: 0 @@ -46,12 +45,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 +70,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 @@ -14,6 +14,7 @@ #include "llvm/BinaryFormat/COFF.h" #include "llvm/ObjCopy/CommonConfig.h" #include "llvm/ObjCopy/ConfigManager.h" +#include "llvm/ObjCopy/MachO/MachOConfig.h" #include "llvm/Option/Arg.h" #include "llvm/Option/ArgList.h" #include "llvm/Support/CRC.h" @@ -1189,6 +1190,7 @@ DriverConfig DC; ConfigManager ConfigMgr; CommonConfig &Config = ConfigMgr.Common; + MachOConfig &MachOConfig = ConfigMgr.MachO; BitcodeStripOptTable T; unsigned MissingArgumentIndex, MissingArgumentCount; opt::InputArgList InputArgs = @@ -1233,9 +1235,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 it's now empty. cantFail(Config.ToRemove.addMatcher(NameOrPattern::create( "__LLVM,__bundle", MatchStyle::Literal, ErrorCallback))); + MachOConfig.EmptySegmentsToRemove.insert("__LLVM"); DC.CopyConfigs.push_back(std::move(ConfigMgr)); return std::move(DC);