diff --git a/llvm/include/llvm/ObjCopy/MachO/MachOConfig.h b/llvm/include/llvm/ObjCopy/MachO/MachOConfig.h index f65cea36a920..c5f861363297 100644 --- a/llvm/include/llvm/ObjCopy/MachO/MachOConfig.h +++ b/llvm/include/llvm/ObjCopy/MachO/MachOConfig.h @@ -29,6 +29,9 @@ struct MachOConfig { // 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 index 8eebdd6f8c65..94e89224b3c8 100644 --- a/llvm/lib/ObjCopy/MachO/MachOObjcopy.cpp +++ b/llvm/lib/ObjCopy/MachO/MachOObjcopy.cpp @@ -258,6 +258,21 @@ static Error processLoadCommands(const MachOConfig &MachOConfig, Object &Obj) { 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-nonempty-segment.test b/llvm/test/tools/llvm-objcopy/MachO/bitcode-strip-remove-nonempty-segment.test new file mode 100644 index 000000000000..175dea8f05fb --- /dev/null +++ b/llvm/test/tools/llvm-objcopy/MachO/bitcode-strip-remove-nonempty-segment.test @@ -0,0 +1,117 @@ +## 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 --macho-segment --sections %t2 | FileCheck --implicit-check-not=Name: %s + +# CHECK: Name: __text +# CHECK-NEXT: Segment: __TEXT +# CHECK: Name: __bundle +# CHECK-NEXT: Segment: __DATA +# CHECK: Name: __notbundle +# CHECK-NEXT: Segment: __LLVM +# CHECK: Cmd: LC_SEGMENT_64 +# CHECK-NEXT: Name: __TEXT +# CHECK: Cmd: LC_SEGMENT_64 +# CHECK-NEXT: Name: __DATA +# CHECK: Cmd: LC_SEGMENT_64 +# CHECK-NEXT: Name: __LLVM + +--- !mach-o +FileHeader: + magic: 0xFEEDFACF + cputype: 0x01000007 + cpusubtype: 0x00000003 + filetype: 0x00000001 + ncmds: 3 + sizeofcmds: 536 + flags: 0x00002000 + reserved: 0x00000000 +LoadCommands: + - cmd: LC_SEGMENT_64 + cmdsize: 152 + segname: __TEXT + vmaddr: 0 + vmsize: 4 + fileoff: 568 + filesize: 4 + maxprot: 7 + initprot: 7 + nsects: 1 + flags: 0 + Sections: + - sectname: __text + segname: __TEXT + addr: 0x0000000000000000 + content: 'AABBCCDD' + size: 4 + offset: 568 + align: 0 + reloff: 0x00000000 + nreloc: 0 + flags: 0x80000400 + 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: 572 + align: 0 + reloff: 0x00000000 + nreloc: 0 + flags: 0x00000000 + 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: 576 + 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: 580 + align: 0 + reloff: 0x00000000 + nreloc: 0 + flags: 0x00000000 + reserved1: 0x00000000 + reserved2: 0x00000000 + reserved3: 0x00000000 diff --git a/llvm/test/tools/llvm-objcopy/MachO/bitcode-strip-remove.test b/llvm/test/tools/llvm-objcopy/MachO/bitcode-strip-remove.test index a7acd1700454..7282febcab17 100644 --- 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,16 @@ -## 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 --macho-segment --sections %t2 | FileCheck --implicit-check-not=Name: %s # CHECK: Name: __text # CHECK-NEXT: Segment: __TEXT # CHECK: Name: __bundle # CHECK-NEXT: Segment: __DATA -# CHECK: Name: __notbundle -# CHECK-NEXT: Segment: __LLVM +# CHECK: Cmd: LC_SEGMENT_64 +# CHECK-NEXT: Name: __TEXT +# CHECK: Cmd: LC_SEGMENT_64 +# CHECK-NEXT: Name: __DATA --- !mach-o FileHeader: @@ -16,21 +18,21 @@ FileHeader: 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 +40,7 @@ LoadCommands: addr: 0x0000000000000000 content: 'AABBCCDD' size: 4 - offset: 424 + offset: 488 align: 0 reloff: 0x00000000 nreloc: 0 @@ -46,12 +48,24 @@ LoadCommands: 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 +73,24 @@ LoadCommands: 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 index 6457be21fa4d..1281af3b6237 100644 --- 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 @@ objcopy::parseBitcodeStripOptions(ArrayRef ArgsArr, DriverConfig DC; ConfigManager ConfigMgr; CommonConfig &Config = ConfigMgr.Common; + MachOConfig &MachOConfig = ConfigMgr.MachO; BitcodeStripOptTable T; unsigned MissingArgumentIndex, MissingArgumentCount; opt::InputArgList InputArgs = @@ -1233,9 +1235,11 @@ objcopy::parseBitcodeStripOptions(ArrayRef ArgsArr, 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);