Index: lld/trunk/include/lld/ReaderWriter/MachOLinkingContext.h =================================================================== --- lld/trunk/include/lld/ReaderWriter/MachOLinkingContext.h +++ lld/trunk/include/lld/ReaderWriter/MachOLinkingContext.h @@ -84,7 +84,8 @@ /// Initializes the context to sane default values given the specified output /// file type, arch, os, and minimum os version. This should be called before /// other setXXX() methods. - void configure(HeaderFileType type, Arch arch, OS os, uint32_t minOSVersion); + void configure(HeaderFileType type, Arch arch, OS os, uint32_t minOSVersion, + bool exportDynamicSymbols); void addPasses(PassManager &pm) override; bool validateImpl(raw_ostream &diagnostics) override; Index: lld/trunk/lib/Driver/DarwinLdDriver.cpp =================================================================== --- lld/trunk/lib/Driver/DarwinLdDriver.cpp +++ lld/trunk/lib/Driver/DarwinLdDriver.cpp @@ -385,9 +385,16 @@ // No min-os version on command line, check environment variables } + // Handle export_dynamic + // FIXME: Should we warn when this applies to something other than a static + // executable or dylib? Those are the only cases where this has an effect. + // Note, this has to come before ctx.configure() so that we get the correct + // value for _globalsAreDeadStripRoots. + bool exportDynamicSymbols = parsedArgs.hasArg(OPT_export_dynamic); + // Now that there's enough information parsed in, let the linking context // set up default values. - ctx.configure(fileType, arch, os, minOSVersion); + ctx.configure(fileType, arch, os, minOSVersion, exportDynamicSymbols); // Handle -e xxx if (llvm::opt::Arg *entry = parsedArgs.getLastArg(OPT_entry)) Index: lld/trunk/lib/Driver/DarwinLdOptions.td =================================================================== --- lld/trunk/lib/Driver/DarwinLdOptions.td +++ lld/trunk/lib/Driver/DarwinLdOptions.td @@ -84,6 +84,9 @@ HelpText<"Specifies the maximum stack size for the main thread in a program. " "Must be a page-size multiple. (default=8Mb)">, Group; +def export_dynamic : Flag<["-"], "export_dynamic">, + HelpText<"Preserves all global symbols in main executables during LTO">, + Group; // dylib executable options def grp_dylib : OptionGroup<"opts">, HelpText<"DYLIB EXECUTABLE OPTIONS">; Index: lld/trunk/lib/ReaderWriter/MachO/MachOLinkingContext.cpp =================================================================== --- lld/trunk/lib/ReaderWriter/MachO/MachOLinkingContext.cpp +++ lld/trunk/lib/ReaderWriter/MachO/MachOLinkingContext.cpp @@ -155,7 +155,8 @@ MachOLinkingContext::~MachOLinkingContext() {} void MachOLinkingContext::configure(HeaderFileType type, Arch arch, OS os, - uint32_t minOSVersion) { + uint32_t minOSVersion, + bool exportDynamicSymbols) { _outputMachOType = type; _arch = arch; _os = os; @@ -218,9 +219,10 @@ case OS::unknown: break; } + setGlobalsAreDeadStripRoots(exportDynamicSymbols); break; case llvm::MachO::MH_DYLIB: - setGlobalsAreDeadStripRoots(true); + setGlobalsAreDeadStripRoots(exportDynamicSymbols); break; case llvm::MachO::MH_BUNDLE: break; Index: lld/trunk/test/mach-o/dead-strip-globals.yaml =================================================================== --- lld/trunk/test/mach-o/dead-strip-globals.yaml +++ lld/trunk/test/mach-o/dead-strip-globals.yaml @@ -0,0 +1,27 @@ +# RUN: lld -flavor darwin -arch x86_64 -dead_strip -export_dynamic %s -dylib %p/Inputs/libSystem.yaml -o %t.dylib -print_atoms | FileCheck -check-prefix=CHECK1 %s +# RUN: lld -flavor darwin -arch x86_64 -export_dynamic -dead_strip %s -dylib %p/Inputs/libSystem.yaml -o %t.dylib -print_atoms | FileCheck -check-prefix=CHECK1 %s +# RUN: lld -flavor darwin -arch x86_64 -dead_strip %s -dylib %p/Inputs/libSystem.yaml -o %t2.dylib -print_atoms | FileCheck -check-prefix=CHECK2 %s + +# +# Test that -export_dynamic -dead-strip from removing globals. +# + +--- +defined-atoms: + - name: def + scope: global + dead-strip: never + - name: dead + scope: global +shared-library-atoms: + - name: dyld_stub_binder + load-name: /usr/lib/libSystem.B.dylib + type: unknown +... + +# CHECK1: name: def +# CHECK1: name: dead + +# CHECK2: name: def +# CHECK2-NOT: name: dead + Index: lld/trunk/unittests/DriverTests/DarwinLdDriverTest.cpp =================================================================== --- lld/trunk/unittests/DriverTests/DarwinLdDriverTest.cpp +++ lld/trunk/unittests/DriverTests/DarwinLdDriverTest.cpp @@ -84,9 +84,34 @@ TEST_F(DarwinLdParserTest, DeadStripRootsDylib) { EXPECT_TRUE(parse("ld", "-arch", "x86_64", "-dylib", "-dead_strip", "foo.o", nullptr)); + EXPECT_FALSE(_ctx.globalsAreDeadStripRoots()); +} + +TEST_F(DarwinLdParserTest, DeadStripRootsRelocatable) { + EXPECT_TRUE(parse("ld", "-arch", "x86_64", "-r", "-dead_strip", "foo.o", + nullptr)); + EXPECT_FALSE(_ctx.globalsAreDeadStripRoots()); +} + +TEST_F(DarwinLdParserTest, DeadStripRootsExportDynamicExe) { + EXPECT_TRUE(parse("ld", "-arch", "x86_64", "-dead_strip", + "-export_dynamic", "foo.o", nullptr)); EXPECT_TRUE(_ctx.globalsAreDeadStripRoots()); } +TEST_F(DarwinLdParserTest, DeadStripRootsExportDynamicDylib) { + EXPECT_TRUE(parse("ld", "-arch", "x86_64", "-dylib", "-dead_strip", + "-export_dynamic", "foo.o", + nullptr)); + EXPECT_TRUE(_ctx.globalsAreDeadStripRoots()); +} + +TEST_F(DarwinLdParserTest, DeadStripRootsExportDynamicRelocatable) { + EXPECT_TRUE(parse("ld", "-arch", "x86_64", "-r", "-dead_strip", + "-export_dynamic", "foo.o", nullptr)); + EXPECT_FALSE(_ctx.globalsAreDeadStripRoots()); +} + TEST_F(DarwinLdParserTest, Arch) { EXPECT_TRUE(parse("ld", "-arch", "x86_64", "foo.o", nullptr)); EXPECT_EQ(MachOLinkingContext::arch_x86_64, _ctx.arch());