]> git.saurik.com Git - apple/ld64.git/commitdiff
ld64-253.3.tar.gz developer-tools-70 ios-90 v253.3
authorApple <opensource@apple.com>
Tue, 25 Aug 2015 17:19:19 +0000 (17:19 +0000)
committerApple <opensource@apple.com>
Tue, 25 Aug 2015 17:19:19 +0000 (17:19 +0000)
49 files changed:
doc/man/man1/ld.1
ld64.xcodeproj/project.pbxproj
src/abstraction/MachOFileAbstraction.hpp
src/create_configure
src/ld/Bitcode.hpp [new file with mode: 0644]
src/ld/HeaderAndLoadCommands.hpp
src/ld/InputFiles.cpp
src/ld/LinkEdit.hpp
src/ld/LinkEditClassic.hpp
src/ld/Options.cpp
src/ld/Options.h
src/ld/OutputFile.cpp
src/ld/OutputFile.h
src/ld/Resolver.cpp
src/ld/Resolver.h
src/ld/SymbolTable.cpp
src/ld/SymbolTable.h
src/ld/code-sign-blobs/memutils.h
src/ld/ld.cpp
src/ld/ld.hpp
src/ld/lto_file.hpp [deleted file]
src/ld/parsers/lto_file.cpp
src/ld/parsers/lto_file.h
src/ld/parsers/macho_dylib_file.cpp
src/ld/parsers/macho_relocatable_file.cpp
src/ld/parsers/macho_relocatable_file.h
src/ld/parsers/opaque_section_file.cpp
src/ld/parsers/textstub_dylib_file.cpp [new file with mode: 0644]
src/ld/parsers/textstub_dylib_file.hpp [new file with mode: 0644]
src/ld/passes/bitcode_bundle.cpp [new file with mode: 0644]
src/ld/passes/bitcode_bundle.h [new file with mode: 0644]
src/ld/passes/branch_island.cpp
src/ld/passes/branch_shim.cpp
src/ld/passes/dylibs.cpp
src/ld/passes/got.cpp
src/ld/passes/huge.cpp
src/ld/passes/objc.cpp
src/ld/passes/order.cpp
src/ld/passes/stubs/stub_arm.hpp
src/ld/passes/stubs/stub_arm64.hpp
src/ld/passes/stubs/stubs.cpp
src/ld/passes/tlvp.cpp
src/other/ObjectDump.cpp
src/other/dyldinfo.cpp
unit-tests/include/common.makefile
unit-tests/test-cases/dead_strip-live-if-ref-live/Makefile [new file with mode: 0644]
unit-tests/test-cases/dead_strip-live-if-ref-live/main.c [new file with mode: 0644]
unit-tests/test-cases/tlv-basic/get.s
unit-tests/test-cases/tlv-basic/main.c

index df4b5a4b17a79b7860930fbbdc075c0979b038a6..1c118b8c8592736607a7df2eba37d1bde6843930 100644 (file)
@@ -117,6 +117,10 @@ Produce a mach-o dylinker that has file type MH_DYLINKER.  Only used when buildi
 The default.  Implied by -dylib, -bundle, or -execute
 .It Fl static
 Produces a mach-o file that does not use the dyld.  Only used building the kernel. 
 The default.  Implied by -dylib, -bundle, or -execute
 .It Fl static
 Produces a mach-o file that does not use the dyld.  Only used building the kernel. 
+.It Fl preload
+Produces a mach-o file in which the mach_header, load commands, and symbol table are
+not in any segment.  This output type is used for firmware or embedded development
+where the segments are copied out of the mach-o into ROM/Flash.
 .It Fl arch Ar arch_name
 Specifies which architecture (e.g. ppc, ppc64, i386, x86_64) the output file should be.
 .It Fl o Ar path
 .It Fl arch Ar arch_name
 Specifies which architecture (e.g. ppc, ppc64, i386, x86_64) the output file should be.
 .It Fl o Ar path
@@ -480,6 +484,7 @@ Logs a chain of references to
 .Ar symbol_name .
 Only applicable with -dead_strip .
 It can help debug why something that you think should be dead strip removed is not removed.
 .Ar symbol_name .
 Only applicable with -dead_strip .
 It can help debug why something that you think should be dead strip removed is not removed.
+See -exported_symbols_list for syntax and use of wildcards.
 .It Fl print_statistics
 Logs information about the amount of memory and time the linker used.
 .It Fl t
 .It Fl print_statistics
 Logs information about the amount of memory and time the linker used.
 .It Fl t
@@ -515,10 +520,31 @@ contains a list of non-global symbol names that should be remain in the output f
 symbol names will be removed from the output file's symbol table. See -exported_symbols_list for syntax and use
 of wildcards.
 .El
 symbol names will be removed from the output file's symbol table. See -exported_symbols_list for syntax and use
 of wildcards.
 .El
+.Ss Options for Bitcode build flow
+.Bl -tag
+.It Fl bitcode_bundle
+Generates an embedded bitcode bundle in the output binary. The bitcode bundle is embedded in __LLVM, __bundle section.
+This option requires all the object files, static libraries and user frameworks/dylibs contain bitcode.
+Note: not all the linker options are supported to use together with -bitcode_bundle.
+.It Fl bitcode_hide_symbol
+Specifies this option together with -bitcode_bundle to hide all non-exported symbols from output bitcode bundle.
+The hide symbol process might not be reversible. To obtain a reverse mapping file to recover all the symbols, use
+-bitcode_symbol_map option.
+.It Fl bitcode_symbol_map Ar path
+Specifies the output for bitcode symbol reverse mapping (.bcsymbolmap). If
+.Ar path
+is an existing directory, UUID.bcsymbolmap will be written to that directory.
+Otherwise, the reverse map will be written to a file at
+.Ar path .
+.El
 .Ss Rarely used Options
 .Bl -tag
 .It Fl v
 Prints the version of the linker.
 .Ss Rarely used Options
 .Bl -tag
 .It Fl v
 Prints the version of the linker.
+.It Fl dirty_data_list Ar filename
+Specifies a file containing the names of data symbols likely to be dirtied.
+If the linker is creating a __DATA_DIRTY segment, those symbols will be moved
+to that segment.
 .It Fl move_to_rw_segment Ar segment_name Ar filename
 Moves data symbols to another segment.  The command line option specifies the
 target segment name and a path to a file containing a list of symbols to move.
 .It Fl move_to_rw_segment Ar segment_name Ar filename
 Moves data symbols to another segment.  The command line option specifies the
 target segment name and a path to a file containing a list of symbols to move.
@@ -738,6 +764,10 @@ info in the temporary object file.
 During development, this option can be used to space out all global variables so each is on a separate page. 
 This is useful when analyzing dirty and resident pages.  The information can then be used to create an 
 order file  to cluster commonly used/dirty globals onto the same page(s).
 During development, this option can be used to space out all global variables so each is on a separate page. 
 This is useful when analyzing dirty and resident pages.  The information can then be used to create an 
 order file  to cluster commonly used/dirty globals onto the same page(s).
+.It Fl not_for_dyld_shared_cache
+Normally, the linker will add extra info to dylibs with -install_name starting with /usr/lib or
+/System/Library/ that allows the dylib to be placed into the dyld shared cache.  Adding this option
+tells the linker to not add that extra info.
 .El
 .Ss Obsolete Options
 .Bl -tag
 .El
 .Ss Obsolete Options
 .Bl -tag
@@ -749,8 +779,6 @@ Object files (MH_OBJECT) with a LINKEDIT segment are no longer supported. This o
 This is the default.  This option is obsolete.
 .It Fl fvmlib
 Fixed VM shared libraries (MH_FVMLIB) are no longer supported. This option is obsolete.
 This is the default.  This option is obsolete.
 .It Fl fvmlib
 Fixed VM shared libraries (MH_FVMLIB) are no longer supported. This option is obsolete.
-.It Fl preload
-Preload executables (MH_PRELOAD) are no longer supported. 
 .It Fl sectobjectsymbols Ar segname Ar sectname
 Adding a local label at a section start is no longer supported.  This option is obsolete.
 .It Fl nofixprebinding
 .It Fl sectobjectsymbols Ar segname Ar sectname
 Adding a local label at a section start is no longer supported.  This option is obsolete.
 .It Fl nofixprebinding
index b4d1749023a5b6e6b79f26849d3bd6228fc1c808..1c5e6228ce5db63d2368623e657cc5f0685f9ba4 100644 (file)
@@ -43,6 +43,7 @@
 /* End PBXAggregateTarget section */
 
 /* Begin PBXBuildFile section */
 /* End PBXAggregateTarget section */
 
 /* Begin PBXBuildFile section */
+               B028FCF21A9E7C3F00E3584B /* bitcode_bundle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B028FCF11A9E7C3F00E3584B /* bitcode_bundle.cpp */; };
                B3B672421406D42800A376BB /* Snapshot.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B3B672411406D42800A376BB /* Snapshot.cpp */; };
                F9023C4E06D5A272001BBF46 /* ld.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F9023C3F06D5A254001BBF46 /* ld.cpp */; };
                F933E3D9092E855B0083EAC8 /* ObjectDump.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F971EED706D5AD240041D381 /* ObjectDump.cpp */; };
                B3B672421406D42800A376BB /* Snapshot.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B3B672411406D42800A376BB /* Snapshot.cpp */; };
                F9023C4E06D5A272001BBF46 /* ld.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F9023C3F06D5A254001BBF46 /* ld.cpp */; };
                F933E3D9092E855B0083EAC8 /* ObjectDump.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F971EED706D5AD240041D381 /* ObjectDump.cpp */; };
@@ -82,6 +83,7 @@
                F9EA7584097882F3008B4F1D /* debugline.c in Sources */ = {isa = PBXBuildFile; fileRef = F9EA7582097882F3008B4F1D /* debugline.c */; };
                F9EA75BC09788857008B4F1D /* debugline.c in Sources */ = {isa = PBXBuildFile; fileRef = F9EA7582097882F3008B4F1D /* debugline.c */; };
                F9EC78060A2F8674002A3E39 /* rebase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F9EC78050A2F8674002A3E39 /* rebase.cpp */; };
                F9EA7584097882F3008B4F1D /* debugline.c in Sources */ = {isa = PBXBuildFile; fileRef = F9EA7582097882F3008B4F1D /* debugline.c */; };
                F9EA75BC09788857008B4F1D /* debugline.c in Sources */ = {isa = PBXBuildFile; fileRef = F9EA7582097882F3008B4F1D /* debugline.c */; };
                F9EC78060A2F8674002A3E39 /* rebase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F9EC78050A2F8674002A3E39 /* rebase.cpp */; };
+               FA95D6141AB25CF400395811 /* textstub_dylib_file.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA95D6121AB25CF400395811 /* textstub_dylib_file.cpp */; };
 /* End PBXBuildFile section */
 
 /* Begin PBXBuildRule section */
 /* End PBXBuildFile section */
 
 /* Begin PBXBuildRule section */
 /* End PBXCopyFilesBuildPhase section */
 
 /* Begin PBXFileReference section */
 /* End PBXCopyFilesBuildPhase section */
 
 /* Begin PBXFileReference section */
+               B028FCF01A9E7B4A00E3584B /* bitcode_bundle.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = bitcode_bundle.h; sourceTree = "<group>"; };
+               B028FCF11A9E7C3F00E3584B /* bitcode_bundle.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = bitcode_bundle.cpp; sourceTree = "<group>"; };
+               B091FB641ABA3AFB00CC8193 /* Bitcode.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = Bitcode.hpp; path = src/ld/Bitcode.hpp; sourceTree = "<group>"; };
                B3B672411406D42800A376BB /* Snapshot.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Snapshot.cpp; path = src/ld/Snapshot.cpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
                B3B672441406D44300A376BB /* Snapshot.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.h; name = Snapshot.h; path = src/ld/Snapshot.h; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
                B3C7A09914295B9C005FC714 /* compile_stubs */ = {isa = PBXFileReference; lastKnownFileType = text.script.csh; path = compile_stubs; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
                B3B672411406D42800A376BB /* Snapshot.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Snapshot.cpp; path = src/ld/Snapshot.cpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
                B3B672441406D44300A376BB /* Snapshot.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.h; name = Snapshot.h; path = src/ld/Snapshot.h; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
                B3C7A09914295B9C005FC714 /* compile_stubs */ = {isa = PBXFileReference; lastKnownFileType = text.script.csh; path = compile_stubs; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
                F9EA7583097882F3008B4F1D /* debugline.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = debugline.h; path = src/ld/debugline.h; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
                F9EC77EE0A2F85F6002A3E39 /* rebase */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = rebase; sourceTree = BUILT_PRODUCTS_DIR; };
                F9EC78050A2F8674002A3E39 /* rebase.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = rebase.cpp; path = src/other/rebase.cpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
                F9EA7583097882F3008B4F1D /* debugline.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = debugline.h; path = src/ld/debugline.h; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
                F9EC77EE0A2F85F6002A3E39 /* rebase */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = rebase; sourceTree = BUILT_PRODUCTS_DIR; };
                F9EC78050A2F8674002A3E39 /* rebase.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = rebase.cpp; path = src/other/rebase.cpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+               FA95D6121AB25CF400395811 /* textstub_dylib_file.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = textstub_dylib_file.cpp; sourceTree = "<group>"; usesTabs = 1; };
+               FA95D6131AB25CF400395811 /* textstub_dylib_file.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = textstub_dylib_file.hpp; sourceTree = "<group>"; };
 /* End PBXFileReference section */
 
 /* Begin PBXFrameworksBuildPhase section */
 /* End PBXFileReference section */
 
 /* Begin PBXFrameworksBuildPhase section */
                F9AA650B1051BD2B003E3539 /* passes */ = {
                        isa = PBXGroup;
                        children = (
                F9AA650B1051BD2B003E3539 /* passes */ = {
                        isa = PBXGroup;
                        children = (
+                               B028FCF11A9E7C3F00E3584B /* bitcode_bundle.cpp */,
+                               B028FCF01A9E7B4A00E3584B /* bitcode_bundle.h */,
                                F984A38010BB4B0D009E9878 /* branch_island.cpp */,
                                F984A38110BB4B0D009E9878 /* branch_island.h */,
                                F9AA44DA1294885F00CB8390 /* branch_shim.cpp */,
                                F984A38010BB4B0D009E9878 /* branch_island.cpp */,
                                F984A38110BB4B0D009E9878 /* branch_island.h */,
                                F9AA44DA1294885F00CB8390 /* branch_shim.cpp */,
                F9AA65861051E750003E3539 /* parsers */ = {
                        isa = PBXGroup;
                        children = (
                F9AA65861051E750003E3539 /* parsers */ = {
                        isa = PBXGroup;
                        children = (
+                               FA95D6121AB25CF400395811 /* textstub_dylib_file.cpp */,
+                               FA95D6131AB25CF400395811 /* textstub_dylib_file.hpp */,
                                F91B7B0218987D5F0099486F /* libunwind */,
                                F9AA6784105700C2003E3539 /* opaque_section_file.cpp */,
                                F9AA6785105700C2003E3539 /* opaque_section_file.h */,
                                F91B7B0218987D5F0099486F /* libunwind */,
                                F9AA6784105700C2003E3539 /* opaque_section_file.cpp */,
                                F9AA6785105700C2003E3539 /* opaque_section_file.h */,
                                F9AA650B1051BD2B003E3539 /* passes */,
                                F9AA65861051E750003E3539 /* parsers */,
                                F933DC37092A82480083EAC8 /* Architectures.hpp */,
                                F9AA650B1051BD2B003E3539 /* passes */,
                                F9AA65861051E750003E3539 /* parsers */,
                                F933DC37092A82480083EAC8 /* Architectures.hpp */,
+                               B091FB641ABA3AFB00CC8193 /* Bitcode.hpp */,
                                F9EA7582097882F3008B4F1D /* debugline.c */,
                                F9EA7583097882F3008B4F1D /* debugline.h */,
                                B3B672411406D42800A376BB /* Snapshot.cpp */,
                                F9EA7582097882F3008B4F1D /* debugline.c */,
                                F9EA7583097882F3008B4F1D /* debugline.h */,
                                B3B672411406D42800A376BB /* Snapshot.cpp */,
                        );
                        runOnlyForDeploymentPostprocessing = 1;
                        shellPath = /bin/sh;
                        );
                        runOnlyForDeploymentPostprocessing = 1;
                        shellPath = /bin/sh;
-                       shellScript = "\nif [ -n \"${DT_TOOLCHAIN_DIR}\" ]\nthen\n\tmkdir -p  \"${DSTROOT}/${DT_TOOLCHAIN_DIR}\"\n\tmv ${DSTROOT}/usr \"${DSTROOT}/${DT_TOOLCHAIN_DIR}\"\nelse\n\tif [ -n \"${RC_PURPLE}\" ]\n\tthen\n\t\tmkdir -p  ${DSTROOT}/Developer/Platforms/iPhoneOS.platform/Developer/\n\t\tmv ${DSTROOT}/usr ${DSTROOT}/Developer/Platforms/iPhoneOS.platform/Developer\n\telse\n\t\tmkdir -p  ${DSTROOT}/Developer/usr/bin\n\t\tcp ${DSTROOT}/usr/bin/ld  ${DSTROOT}/Developer/usr/bin\n\tfi\nfi\n\n";
+                       shellScript = "\nif [ -n \"${DT_TOOLCHAIN_DIR}\" ]\nthen\n\tmkdir -p  \"${DSTROOT}/${DT_VARIANT}/${DT_TOOLCHAIN_DIR}\"\n\tmv ${DSTROOT}/usr \"${DSTROOT}/${DT_VARIANT}/${DT_TOOLCHAIN_DIR}\"\nelse\n\tif [ -n \"${RC_PURPLE}\" ]\n\tthen\n\t\tmkdir -p  ${DSTROOT}/Developer/Platforms/iPhoneOS.platform/Developer/\n\t\tmv ${DSTROOT}/usr ${DSTROOT}/Developer/Platforms/iPhoneOS.platform/Developer\n\telse\n\t\tmkdir -p  ${DSTROOT}/Developer/usr/bin\n\t\tcp ${DSTROOT}/usr/bin/ld  ${DSTROOT}/Developer/usr/bin\n\tfi\nfi\n\n";
                        showEnvVarsInLog = 0;
                };
                F9CCF765144CE244007CB524 /* make configure.h */ = {
                        showEnvVarsInLog = 0;
                };
                F9CCF765144CE244007CB524 /* make configure.h */ = {
                        isa = PBXSourcesBuildPhase;
                        buildActionMask = 2147483647;
                        files = (
                        isa = PBXSourcesBuildPhase;
                        buildActionMask = 2147483647;
                        files = (
+                               FA95D6141AB25CF400395811 /* textstub_dylib_file.cpp in Sources */,
                                F9C0D4BD06DD28D2001C7193 /* Options.cpp in Sources */,
                                F9023C4E06D5A272001BBF46 /* ld.cpp in Sources */,
                                F9AA65891051E750003E3539 /* macho_relocatable_file.cpp in Sources */,
                                F9C0D4BD06DD28D2001C7193 /* Options.cpp in Sources */,
                                F9023C4E06D5A272001BBF46 /* ld.cpp in Sources */,
                                F9AA65891051E750003E3539 /* macho_relocatable_file.cpp in Sources */,
                                F93CB248116E69EB003233B8 /* tlvp.cpp in Sources */,
                                F9AA44DC1294885F00CB8390 /* branch_shim.cpp in Sources */,
                                B3B672421406D42800A376BB /* Snapshot.cpp in Sources */,
                                F93CB248116E69EB003233B8 /* tlvp.cpp in Sources */,
                                F9AA44DC1294885F00CB8390 /* branch_shim.cpp in Sources */,
                                B3B672421406D42800A376BB /* Snapshot.cpp in Sources */,
+                               B028FCF21A9E7C3F00E3584B /* bitcode_bundle.cpp in Sources */,
                                F9CC24191461FB4300A92174 /* blob.cpp in Sources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                                F9CC24191461FB4300A92174 /* blob.cpp in Sources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                F933D91C09291AC90083EAC8 /* Debug */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
                F933D91C09291AC90083EAC8 /* Debug */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
+                               ARCHS = "$(ARCHS_STANDARD_64_BIT)";
+                               CLANG_CXX_LANGUAGE_STANDARD = "c++0x";
                                CLANG_CXX_LIBRARY = "libc++";
                                COPY_PHASE_STRIP = NO;
                                CURRENT_PROJECT_VERSION = "$(RC_ProjectSourceVersion)";
                                CLANG_CXX_LIBRARY = "libc++";
                                COPY_PHASE_STRIP = NO;
                                CURRENT_PROJECT_VERSION = "$(RC_ProjectSourceVersion)";
                                LD_RUNPATH_SEARCH_PATHS = "@executable_path/../lib/";
                                LINKER_DISPLAYS_MANGLED_NAMES = NO;
                                MACOSX_DEPLOYMENT_TARGET = "";
                                LD_RUNPATH_SEARCH_PATHS = "@executable_path/../lib/";
                                LINKER_DISPLAYS_MANGLED_NAMES = NO;
                                MACOSX_DEPLOYMENT_TARGET = "";
+                               ONLY_ACTIVE_ARCH = NO;
                                OTHER_CPLUSPLUSFLAGS = (
                                        "-stdlib=libc++",
                                        "$(OTHER_CPLUSPLUSFLAGS)",
                                );
                                OTHER_LDFLAGS = (
                                        "-stdlib=libc++",
                                OTHER_CPLUSPLUSFLAGS = (
                                        "-stdlib=libc++",
                                        "$(OTHER_CPLUSPLUSFLAGS)",
                                );
                                OTHER_LDFLAGS = (
                                        "-stdlib=libc++",
+                                       "-lxar",
                                        "-Wl,-lazy_library,$(DT_TOOLCHAIN_DIR)/usr/lib/libLTO.dylib",
                                        "-Wl,-lazy_library,$(DT_TOOLCHAIN_DIR)/usr/lib/libLTO.dylib",
+                                       "@$(DERIVED_FILE_DIR)/linkExtras",
                                        "-Wl,-exported_symbol,__mh_execute_header",
                                );
                                PREBINDING = NO;
                                        "-Wl,-exported_symbol,__mh_execute_header",
                                );
                                PREBINDING = NO;
                F933D91D09291AC90083EAC8 /* Release */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
                F933D91D09291AC90083EAC8 /* Release */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
+                               ARCHS = "$(ARCHS_STANDARD_64_BIT)";
+                               CLANG_CXX_LANGUAGE_STANDARD = "c++0x";
                                CLANG_CXX_LIBRARY = "libc++";
                                COPY_PHASE_STRIP = NO;
                                CURRENT_PROJECT_VERSION = "$(RC_ProjectSourceVersion)";
                                CLANG_CXX_LIBRARY = "libc++";
                                COPY_PHASE_STRIP = NO;
                                CURRENT_PROJECT_VERSION = "$(RC_ProjectSourceVersion)";
                                );
                                OTHER_LDFLAGS = (
                                        "-stdlib=libc++",
                                );
                                OTHER_LDFLAGS = (
                                        "-stdlib=libc++",
+                                       "-lxar",
                                        "-Wl,-lazy_library,$(DT_TOOLCHAIN_DIR)/usr/lib/libLTO.dylib",
                                        "-Wl,-lazy_library,$(DT_TOOLCHAIN_DIR)/usr/lib/libLTO.dylib",
+                                       "@$(DERIVED_FILE_DIR)/linkExtras",
                                        "-Wl,-exported_symbol,__mh_execute_header",
                                );
                                PREBINDING = NO;
                                        "-Wl,-exported_symbol,__mh_execute_header",
                                );
                                PREBINDING = NO;
                F933D92009291AC90083EAC8 /* Debug */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
                F933D92009291AC90083EAC8 /* Debug */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
+                               ARCHS = "$(ARCHS_STANDARD_64_BIT)";
                                CLANG_CXX_LIBRARY = "libc++";
                                COPY_PHASE_STRIP = NO;
                                DEBUG_INFORMATION_FORMAT = dwarf;
                                CLANG_CXX_LIBRARY = "libc++";
                                COPY_PHASE_STRIP = NO;
                                DEBUG_INFORMATION_FORMAT = dwarf;
                                HEADER_SEARCH_PATHS = (
                                        "$(SRCROOT)/src/ld",
                                        "$(DEVELOPER_DIR)/usr/local/include",
                                HEADER_SEARCH_PATHS = (
                                        "$(SRCROOT)/src/ld",
                                        "$(DEVELOPER_DIR)/usr/local/include",
+                                       "$(DT_TOOLCHAIN_DIR)/usr/local/include",
                                );
                                INSTALL_PATH = "$(HOME)/bin";
                                );
                                INSTALL_PATH = "$(HOME)/bin";
+                               ONLY_ACTIVE_ARCH = NO;
                                OTHER_CPLUSPLUSFLAGS = (
                                        "-stdlib=libc++",
                                        "$(OTHER_CFLAGS)",
                                OTHER_CPLUSPLUSFLAGS = (
                                        "-stdlib=libc++",
                                        "$(OTHER_CFLAGS)",
                F933D92109291AC90083EAC8 /* Release */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
                F933D92109291AC90083EAC8 /* Release */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
+                               ARCHS = "$(ARCHS_STANDARD_64_BIT)";
                                CLANG_CXX_LIBRARY = "libc++";
                                COPY_PHASE_STRIP = YES;
                                DEBUG_INFORMATION_FORMAT = dwarf;
                                CLANG_CXX_LIBRARY = "libc++";
                                COPY_PHASE_STRIP = YES;
                                DEBUG_INFORMATION_FORMAT = dwarf;
                                HEADER_SEARCH_PATHS = (
                                        "$(SRCROOT)/src/ld",
                                        "$(DEVELOPER_DIR)/usr/local/include",
                                HEADER_SEARCH_PATHS = (
                                        "$(SRCROOT)/src/ld",
                                        "$(DEVELOPER_DIR)/usr/local/include",
+                                       "$(DT_TOOLCHAIN_DIR)/usr/local/include",
                                );
                                INSTALL_PATH = "$(HOME)/bin";
                                OTHER_CPLUSPLUSFLAGS = (
                                );
                                INSTALL_PATH = "$(HOME)/bin";
                                OTHER_CPLUSPLUSFLAGS = (
                F9849FFA10B5DE8E009E9878 /* Release-assert */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
                F9849FFA10B5DE8E009E9878 /* Release-assert */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
+                               ARCHS = "$(ARCHS_STANDARD_64_BIT)";
+                               CLANG_CXX_LANGUAGE_STANDARD = "c++0x";
                                CLANG_CXX_LIBRARY = "libc++";
                                COPY_PHASE_STRIP = NO;
                                CURRENT_PROJECT_VERSION = "$(RC_ProjectSourceVersion)";
                                CLANG_CXX_LIBRARY = "libc++";
                                COPY_PHASE_STRIP = NO;
                                CURRENT_PROJECT_VERSION = "$(RC_ProjectSourceVersion)";
                                );
                                OTHER_LDFLAGS = (
                                        "-stdlib=libc++",
                                );
                                OTHER_LDFLAGS = (
                                        "-stdlib=libc++",
+                                       "-lxar",
                                        "-Wl,-lazy_library,$(DT_TOOLCHAIN_DIR)/usr/lib/libLTO.dylib",
                                        "-Wl,-lazy_library,$(DT_TOOLCHAIN_DIR)/usr/lib/libLTO.dylib",
+                                       "@$(DERIVED_FILE_DIR)/linkExtras",
                                        "-Wl,-exported_symbol,__mh_execute_header",
                                );
                                PREBINDING = NO;
                                        "-Wl,-exported_symbol,__mh_execute_header",
                                );
                                PREBINDING = NO;
                F9849FFD10B5DE8E009E9878 /* Release-assert */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
                F9849FFD10B5DE8E009E9878 /* Release-assert */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
+                               ARCHS = "$(ARCHS_STANDARD_64_BIT)";
                                CLANG_CXX_LIBRARY = "libc++";
                                COPY_PHASE_STRIP = YES;
                                DEBUG_INFORMATION_FORMAT = dwarf;
                                CLANG_CXX_LIBRARY = "libc++";
                                COPY_PHASE_STRIP = YES;
                                DEBUG_INFORMATION_FORMAT = dwarf;
                                HEADER_SEARCH_PATHS = (
                                        "$(SRCROOT)/src/ld",
                                        "$(DEVELOPER_DIR)/usr/local/include",
                                HEADER_SEARCH_PATHS = (
                                        "$(SRCROOT)/src/ld",
                                        "$(DEVELOPER_DIR)/usr/local/include",
+                                       "$(DT_TOOLCHAIN_DIR)/usr/local/include",
                                );
                                INSTALL_PATH = "$(HOME)/bin";
                                OTHER_CPLUSPLUSFLAGS = (
                                );
                                INSTALL_PATH = "$(HOME)/bin";
                                OTHER_CPLUSPLUSFLAGS = (
index ae61d7c1893bfe102c1a6db52571f6d33d5cc97c..cfedc81d3b5c596e11f946c3099218fb4b7744c2 100644 (file)
        #define LOH_ARM64_ADRP_LDR_GOT                  8
 #endif
 
        #define LOH_ARM64_ADRP_LDR_GOT                  8
 #endif
 
+#ifndef LC_VERSION_MIN_TVOS
+       #define LC_VERSION_MIN_TVOS                     0x2F
+#endif
+
+#ifndef LC_VERSION_MIN_WATCHOS
+       #define LC_VERSION_MIN_WATCHOS          0x30
+#endif
+
 #ifndef EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE
        #define EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE                       0x02
 #endif
 
 #ifndef EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE
        #define EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE                       0x02
 #endif
 
-
 #ifndef CPU_SUBTYPE_ARM_V8
        #define CPU_SUBTYPE_ARM_V8              ((cpu_subtype_t) 13) 
 #endif
 #ifndef CPU_SUBTYPE_ARM_V8
        #define CPU_SUBTYPE_ARM_V8              ((cpu_subtype_t) 13) 
 #endif
  
 #define UNWIND_ARM_DWARF_SECTION_OFFSET               0x00FFFFFF
 
  
 #define UNWIND_ARM_DWARF_SECTION_OFFSET               0x00FFFFFF
 
+
+// ( <opcode> (delta-uleb128)+ <zero> )+ <zero>
+#define DYLD_CACHE_ADJ_V1_POINTER_32           0x01
+#define DYLD_CACHE_ADJ_V1_POINTER_64           0x02
+#define DYLD_CACHE_ADJ_V1_ADRP                         0x03
+#define DYLD_CACHE_ADJ_V1_ARM_THUMB_MOVT       0x10 // thru 0x1F
+#define DYLD_CACHE_ADJ_V1_ARM_MOVT                     0x20 // thru 0x2F
+
+
+// Whole                :== <new-marker> <count> FromToSection+
+// FromToSection :== <from-sect-index> <to-sect-index> <count> ToOffset+
+// ToOffset             :== <to-sect-offset-delta> <count> FromOffset+
+// FromOffset   :== <kind> <count> <from-sect-offset-delta>
+#define DYLD_CACHE_ADJ_V2_FORMAT                               0x7F
+
+#define DYLD_CACHE_ADJ_V2_POINTER_32                   0x01
+#define DYLD_CACHE_ADJ_V2_POINTER_64                   0x02
+#define DYLD_CACHE_ADJ_V2_DELTA_32                         0x03
+#define DYLD_CACHE_ADJ_V2_DELTA_64                         0x04
+#define DYLD_CACHE_ADJ_V2_ARM64_ADRP                   0x05
+#define DYLD_CACHE_ADJ_V2_ARM64_OFF12                  0x06
+#define DYLD_CACHE_ADJ_V2_ARM64_BR26                   0x07
+#define DYLD_CACHE_ADJ_V2_ARM_MOVW_MOVT                        0x08
+#define DYLD_CACHE_ADJ_V2_ARM_BR24                             0x09
+#define DYLD_CACHE_ADJ_V2_THUMB_MOVW_MOVT              0x0A
+#define DYLD_CACHE_ADJ_V2_THUMB_BR22                   0x0B
+#define DYLD_CACHE_ADJ_V2_IMAGE_OFF_32                 0x0C
+
+
+
+// kind target-address fixup-addr [adj] 
+
+
+
 struct ArchInfo {
        const char*                     archName;
        cpu_type_t                      cpuType;
 struct ArchInfo {
        const char*                     archName;
        cpu_type_t                      cpuType;
index f99123191cd04dd3576012832ab2d892b2240f0c..9ce654d2ffd9f6e189e683c5a78882256e69e817 100755 (executable)
@@ -25,8 +25,24 @@ do
        fi
 done
 
        fi
 done
 
-echo "#define ALL_SUPPORTED_ARCHS  \"${RC_SUPPORTED_ARCHS}\"" >> ${DERIVED_FILE_DIR}/configure.h
-
+if [ -n "${RC_HIDE_TIDE}" ]; then
+       echo "#define ALL_SUPPORTED_ARCHS  \"${RC_SUPPORTED_ARCHS}\"" >> ${DERIVED_FILE_DIR}/configure.h
+       echo "#define SUPPORT_APPLE_TV 0" >> ${DERIVED_FILE_DIR}/configure.h
+else
+       if [ -n "${DT_VARIANT}" -a "${DT_VARIANT}" != "PONDEROSA" ]; then
+               echo "#define ALL_SUPPORTED_ARCHS  \"${RC_SUPPORTED_ARCHS}\"" >> ${DERIVED_FILE_DIR}/configure.h
+               echo "#define SUPPORT_APPLE_TV 0" >> ${DERIVED_FILE_DIR}/configure.h
+       else
+               echo "#define ALL_SUPPORTED_ARCHS  \"${RC_SUPPORTED_ARCHS} (tvOS)\"" >> ${DERIVED_FILE_DIR}/configure.h
+               echo "#define SUPPORT_APPLE_TV 1" >> ${DERIVED_FILE_DIR}/configure.h
+       fi
+fi
 
 
+if [ -f "${DT_TOOLCHAIN_DIR}/usr/lib/libswiftDemangle.dylib" ]; then
+       echo "-Wl,-lazy_library,${DT_TOOLCHAIN_DIR}/usr/lib/libswiftDemangle.dylib" >  ${DERIVED_FILE_DIR}/linkExtras
+       echo "#define DEMANGLE_SWIFT 1" >> ${DERIVED_FILE_DIR}/configure.h
+else
+       echo "" > ${DERIVED_FILE_DIR}/linkExtras
+fi
 
 
+echo "#define BITCODE_XAR_VERSION \"1.0\"" >> ${DERIVED_FILE_DIR}/configure.h
diff --git a/src/ld/Bitcode.hpp b/src/ld/Bitcode.hpp
new file mode 100644 (file)
index 0000000..68822d2
--- /dev/null
@@ -0,0 +1,87 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2005-2010 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#ifndef __BITCODE_HPP__
+#define __BITCODE_HPP__
+
+#include <unistd.h>
+
+namespace ld {
+
+class Bitcode {
+public:
+    Bitcode(const uint8_t* content, uint32_t size) : _content(content), _size(size) { }
+
+    virtual bool isMarker() const                               { return _size <= 1 ; }
+    virtual const uint8_t* getContent() const                   { return _content; }
+    virtual uint32_t getSize() const                            { return _size; }
+private:
+    const uint8_t* _content;
+    uint32_t _size;
+};
+
+class LLVMBitcode : public Bitcode {
+public:
+    LLVMBitcode(const uint8_t* content, uint32_t size, const uint8_t* cmd, uint32_t cmdSize) :
+        Bitcode(content, size), _cmdline(cmd), _cmdSize(cmdSize)    { }
+
+    virtual const uint8_t* getCmdline() const                   { return _cmdline; }
+    virtual uint32_t getCmdSize() const                         { return _cmdSize; }
+    virtual const char* getBitcodeName() const                  { return "llvm"; }
+private:
+    const uint8_t* _cmdline;
+    uint32_t _cmdSize;
+};
+
+class ClangBitcode : public LLVMBitcode {
+public:
+    ClangBitcode(const uint8_t* content, uint32_t size, const uint8_t* cmd, uint32_t cmdSize) :
+        LLVMBitcode(content, size, cmd, cmdSize)    { }
+    virtual const char* getBitcodeName() const override         { return "clang"; }
+};
+
+class SwiftBitcode : public LLVMBitcode {
+public:
+    SwiftBitcode(const uint8_t* content, uint32_t size, const uint8_t* cmd, uint32_t cmdSize) :
+        LLVMBitcode(content, size, cmd, cmdSize)    { }
+    virtual const char* getBitcodeName() const override         { return "swift"; }
+};
+
+class AsmBitcode : public Bitcode {
+public:
+    AsmBitcode(const uint8_t* content, uint32_t size) : Bitcode(content, size) { }
+
+    virtual bool isMarker() const override                      { return false; }
+};
+
+class BundleBitcode : public Bitcode {
+public:
+    BundleBitcode(const uint8_t* content, uint32_t size) :
+        Bitcode(content, size)  { }
+};
+
+}
+
+
+#endif /* defined(__BITCODE_HPP__) */
index 3629af5ac3f9de32f4b7292eabea2e0dd13b8ade..b47acff9c7d5fcd62a81e4ea6cb5efc20e7a11c4 100644 (file)
@@ -49,6 +49,9 @@ public:
 
        virtual void setUUID(const uint8_t digest[16]) = 0;
        virtual void recopyUUIDCommand() = 0;
 
        virtual void setUUID(const uint8_t digest[16]) = 0;
        virtual void recopyUUIDCommand() = 0;
+       virtual const uint8_t* getUUID() const = 0;
+       virtual bool bitcodeBundleCommand(uint64_t& cmdOffset, uint64_t& cmdEnd,
+                                                                         uint64_t& sectOffset, uint64_t& sectEnd) const = 0;
 };
 
 template <typename A>
 };
 
 template <typename A>
@@ -68,6 +71,9 @@ public:
        // overrides of HeaderAndLoadCommandsAbtract
        virtual void setUUID(const uint8_t digest[16])  { memcpy(_uuid, digest, 16); }
        virtual void recopyUUIDCommand();
        // overrides of HeaderAndLoadCommandsAbtract
        virtual void setUUID(const uint8_t digest[16])  { memcpy(_uuid, digest, 16); }
        virtual void recopyUUIDCommand();
+       virtual const uint8_t* getUUID() const                          { return &_uuid[0]; }
+       virtual bool bitcodeBundleCommand(uint64_t& cmdOffset, uint64_t& cmdEnd,
+                                                                         uint64_t& sectOffset, uint64_t& sectEnd) const;
        
 private:
        typedef typename A::P                                           P;
        
 private:
        typedef typename A::P                                           P;
@@ -107,7 +113,6 @@ private:
        uint8_t*                                        copySubUmbrellaLoadCommand(uint8_t* p, const char* name) const;
        uint8_t*                                        copyFunctionStartsLoadCommand(uint8_t* p) const;
        uint8_t*                                        copyDataInCodeLoadCommand(uint8_t* p) const;
        uint8_t*                                        copySubUmbrellaLoadCommand(uint8_t* p, const char* name) const;
        uint8_t*                                        copyFunctionStartsLoadCommand(uint8_t* p) const;
        uint8_t*                                        copyDataInCodeLoadCommand(uint8_t* p) const;
-       uint8_t*                                        copyDependentDRLoadCommand(uint8_t* p) const;
        uint8_t*                                        copyDyldEnvLoadCommand(uint8_t* p, const char* env) const;
        uint8_t*                                        copyLinkerOptionsLoadCommand(uint8_t* p, const std::vector<const char*>&) const;
        uint8_t*                                        copyOptimizationHintsLoadCommand(uint8_t* p) const;
        uint8_t*                                        copyDyldEnvLoadCommand(uint8_t* p, const char* env) const;
        uint8_t*                                        copyLinkerOptionsLoadCommand(uint8_t* p, const std::vector<const char*>&) const;
        uint8_t*                                        copyOptimizationHintsLoadCommand(uint8_t* p) const;
@@ -137,7 +142,6 @@ private:
        bool                                            _hasFunctionStartsLoadCommand;
        bool                                            _hasDataInCodeLoadCommand;
        bool                                            _hasSourceVersionLoadCommand;
        bool                                            _hasFunctionStartsLoadCommand;
        bool                                            _hasDataInCodeLoadCommand;
        bool                                            _hasSourceVersionLoadCommand;
-       bool                                            _hasDependentDRInfo;
        bool                                            _hasOptimizationHints;
        uint32_t                                        _dylibLoadCommmandsCount;
        uint32_t                                        _allowableClientLoadCommmandsCount;
        bool                                            _hasOptimizationHints;
        uint32_t                                        _dylibLoadCommmandsCount;
        uint32_t                                        _allowableClientLoadCommmandsCount;
@@ -223,11 +227,12 @@ HeaderAndLoadCommandsAtom<A>::HeaderAndLoadCommandsAtom(const Options& opts, ld:
        }
        _hasRPathLoadCommands = (_options.rpaths().size() != 0);
        _hasSubFrameworkLoadCommand = (_options.umbrellaName() != NULL);
        }
        _hasRPathLoadCommands = (_options.rpaths().size() != 0);
        _hasSubFrameworkLoadCommand = (_options.umbrellaName() != NULL);
-       _hasVersionLoadCommand = _options.addVersionLoadCommand();
+       _hasVersionLoadCommand = _options.addVersionLoadCommand() ||
+                                                        (!state.objectFileFoundWithNoVersion && (_options.outputKind() == Options::kObjectFile)
+                                                        && ((_options.platform() != Options::kPlatformUnknown) || (state.derivedPlatformLoadCommand != 0)) );
        _hasFunctionStartsLoadCommand = _options.addFunctionStarts();
        _hasDataInCodeLoadCommand = _options.addDataInCodeInfo();
        _hasSourceVersionLoadCommand = _options.needsSourceVersionLoadCommand();
        _hasFunctionStartsLoadCommand = _options.addFunctionStarts();
        _hasDataInCodeLoadCommand = _options.addDataInCodeInfo();
        _hasSourceVersionLoadCommand = _options.needsSourceVersionLoadCommand();
-       _hasDependentDRInfo = _options.needsDependentDRInfo();
        _dylibLoadCommmandsCount = _writer.dylibCount();
        _allowableClientLoadCommmandsCount = _options.allowableClients().size();
        _dyldEnvironExrasCount = _options.dyldEnvironExtras().size();
        _dylibLoadCommmandsCount = _writer.dylibCount();
        _allowableClientLoadCommmandsCount = _options.allowableClients().size();
        _dyldEnvironExrasCount = _options.dyldEnvironExtras().size();
@@ -326,6 +331,31 @@ unsigned int HeaderAndLoadCommandsAtom<A>::segmentCount() const
        return count;
 }
 
        return count;
 }
 
+template <typename A>
+bool HeaderAndLoadCommandsAtom<A>::bitcodeBundleCommand(uint64_t &cmdOffset, uint64_t &cmdEnd,
+                                                                                                               uint64_t &sectOffset, uint64_t &sectEnd) const
+{
+       if ( _options.outputKind() == Options::kObjectFile ) {
+               return false;
+       }
+       cmdOffset = sizeof(macho_header<P>);
+       const char* lastSegName = "";
+       for (std::vector<ld::Internal::FinalSection*>::iterator it = _state.sections.begin(); it != _state.sections.end(); ++it) {
+               if ( strcmp(lastSegName, (*it)->segmentName()) != 0 ) {
+                       lastSegName = (*it)->segmentName();
+                       cmdOffset += sizeof(macho_segment_command<P>);
+               }
+               if ( strcmp((*it)->segmentName(), "__LLVM") == 0 && strcmp((*it)->sectionName(), "__bundle") == 0 ) {
+                       sectOffset = (*it)->fileOffset;
+                       sectEnd = (*(it + 1))->fileOffset;
+                       cmdEnd = cmdOffset + sizeof(macho_section<P>);
+                       return true;
+               }
+               if ( ! (*it)->isSectionHidden() )
+                       cmdOffset += sizeof(macho_section<P>);
+       }
+       return false;
+}
 
 template <typename A>
 uint64_t HeaderAndLoadCommandsAtom<A>::size() const
 
 template <typename A>
 uint64_t HeaderAndLoadCommandsAtom<A>::size() const
@@ -427,9 +457,6 @@ uint64_t HeaderAndLoadCommandsAtom<A>::size() const
                }
        }
        
                }
        }
        
-       if ( _hasDependentDRInfo ) 
-               sz += sizeof(macho_linkedit_data_command<P>);
-       
        if ( _hasOptimizationHints )
                sz += sizeof(macho_linkedit_data_command<P>);
                
        if ( _hasOptimizationHints )
                sz += sizeof(macho_linkedit_data_command<P>);
                
@@ -507,9 +534,6 @@ uint32_t HeaderAndLoadCommandsAtom<A>::commandsCount() const
                }
        }
 
                }
        }
 
-       if ( _hasDependentDRInfo ) 
-               ++count;
-       
        if ( _hasOptimizationHints )
                ++count;
                
        if ( _hasOptimizationHints )
                ++count;
                
@@ -692,6 +716,7 @@ struct SegInfo {
                                                                                                SegInfo(const char* n, const Options&);
        const char*                                                                     segName;
        uint32_t                                                                        nonHiddenSectionCount;
                                                                                                SegInfo(const char* n, const Options&);
        const char*                                                                     segName;
        uint32_t                                                                        nonHiddenSectionCount;
+       uint32_t                                                                        nonSectCreateSections;
        uint32_t                                                                        maxProt;
        uint32_t                                                                        initProt;
        std::vector<ld::Internal::FinalSection*>        sections;
        uint32_t                                                                        maxProt;
        uint32_t                                                                        initProt;
        std::vector<ld::Internal::FinalSection*>        sections;
@@ -699,7 +724,7 @@ struct SegInfo {
 
 
 SegInfo::SegInfo(const char* n, const Options& opts) 
 
 
 SegInfo::SegInfo(const char* n, const Options& opts) 
-       : segName(n), nonHiddenSectionCount(0), maxProt(opts.maxSegProtection(n)), initProt(opts.initialSegProtection(n)) 
+       : segName(n), nonHiddenSectionCount(0), nonSectCreateSections(0), maxProt(opts.maxSegProtection(n)), initProt(opts.initialSegProtection(n))
 { 
 }
 
 { 
 }
 
@@ -722,6 +747,8 @@ uint32_t HeaderAndLoadCommandsAtom<A>::sectionFlags(ld::Internal::FinalSection*
                                return S_REGULAR | S_ATTR_NO_DEAD_STRIP;
                        else if ( (strncmp(sect->sectionName(), "__objc_nlcatlist", 16) == 0) && (strcmp(sect->segmentName(), "__DATA") == 0) )
                                return S_REGULAR | S_ATTR_NO_DEAD_STRIP;
                                return S_REGULAR | S_ATTR_NO_DEAD_STRIP;
                        else if ( (strncmp(sect->sectionName(), "__objc_nlcatlist", 16) == 0) && (strcmp(sect->segmentName(), "__DATA") == 0) )
                                return S_REGULAR | S_ATTR_NO_DEAD_STRIP;
+                       else if (  (_options.outputKind() == Options::kObjectFile) && !sect->atoms.empty() && sect->atoms.front()->dontDeadStripIfReferencesLive() )
+                               return S_REGULAR | S_ATTR_LIVE_SUPPORT;
                        else
                                return S_REGULAR;
                case ld::Section::typeCode:
                        else
                                return S_REGULAR;
                case ld::Section::typeCode:
@@ -841,6 +868,8 @@ uint32_t HeaderAndLoadCommandsAtom<A>::sectionFlags(ld::Internal::FinalSection*
                        return S_REGULAR;
                case ld::Section::typeDebug:
                        return S_REGULAR | S_ATTR_DEBUG;
                        return S_REGULAR;
                case ld::Section::typeDebug:
                        return S_REGULAR | S_ATTR_DEBUG;
+               case ld::Section::typeSectCreate:
+                       return S_REGULAR;
        }
        return S_REGULAR;
 }
        }
        return S_REGULAR;
 }
@@ -885,6 +914,9 @@ uint8_t* HeaderAndLoadCommandsAtom<A>::copySegmentLoadCommands(uint8_t* p) const
                }
                if ( ! sect->isSectionHidden() ) 
                        segs.back().nonHiddenSectionCount++;
                }
                if ( ! sect->isSectionHidden() ) 
                        segs.back().nonHiddenSectionCount++;
+               if ( sect->type() != ld::Section::typeSectCreate )
+                       segs.back().nonSectCreateSections++;
+
                segs.back().sections.push_back(sect);
        }
        // write out segment load commands for each section with trailing sections
                segs.back().sections.push_back(sect);
        }
        // write out segment load commands for each section with trailing sections
@@ -921,7 +953,8 @@ uint8_t* HeaderAndLoadCommandsAtom<A>::copySegmentLoadCommands(uint8_t* p) const
                segCmd->set_maxprot(si.maxProt);
                segCmd->set_initprot(si.initProt);
                segCmd->set_nsects(si.nonHiddenSectionCount);
                segCmd->set_maxprot(si.maxProt);
                segCmd->set_initprot(si.initProt);
                segCmd->set_nsects(si.nonHiddenSectionCount);
-               segCmd->set_flags(0);
+               segCmd->set_flags(si.nonSectCreateSections ? 0 : SG_NORELOC); // FIXME, really should check all References
+
                p += sizeof(macho_segment_command<P>);
                macho_section<P>* msect = (macho_section<P>*)p;
                for (std::vector<ld::Internal::FinalSection*>::iterator sit = si.sections.begin(); sit != si.sections.end(); ++sit) {
                p += sizeof(macho_segment_command<P>);
                macho_section<P>* msect = (macho_section<P>*)p;
                for (std::vector<ld::Internal::FinalSection*>::iterator sit = si.sections.begin(); sit != si.sections.end(); ++sit) {
@@ -1104,20 +1137,40 @@ template <typename A>
 uint8_t* HeaderAndLoadCommandsAtom<A>::copyVersionLoadCommand(uint8_t* p) const
 {
        macho_version_min_command<P>* cmd = (macho_version_min_command<P>*)p;
 uint8_t* HeaderAndLoadCommandsAtom<A>::copyVersionLoadCommand(uint8_t* p) const
 {
        macho_version_min_command<P>* cmd = (macho_version_min_command<P>*)p;
-       ld::MacVersionMin macVersion = _options.macosxVersionMin();
-       ld::IOSVersionMin iOSVersion = _options.iOSVersionMin();
-       assert( (macVersion != ld::macVersionUnset) || (iOSVersion != ld::iOSVersionUnset) );
-       if ( macVersion != ld::macVersionUnset ) {
-               cmd->set_cmd(LC_VERSION_MIN_MACOSX);
-               cmd->set_cmdsize(sizeof(macho_version_min_command<P>));
-               cmd->set_version((uint32_t)macVersion);
-               cmd->set_sdk(_options.sdkVersion());
-       }
-       else {
-               cmd->set_cmd(LC_VERSION_MIN_IPHONEOS);
-               cmd->set_cmdsize(sizeof(macho_version_min_command<P>));
-               cmd->set_version((uint32_t)iOSVersion);
-               cmd->set_sdk(_options.sdkVersion());
+       switch (_options.platform()) {
+               case Options::kPlatformUnknown:
+                       assert(_state.derivedPlatformLoadCommand != 0 && "unknown platform");
+                       cmd->set_cmd(_state.derivedPlatformLoadCommand);
+                       cmd->set_cmdsize(sizeof(macho_version_min_command<P>));
+                       cmd->set_version(_state.minOSVersion);
+                       cmd->set_sdk(0);
+                       break;
+               case Options::kPlatformOSX:
+                       cmd->set_cmd(LC_VERSION_MIN_MACOSX);
+                       cmd->set_cmdsize(sizeof(macho_version_min_command<P>));
+                       cmd->set_version(_state.minOSVersion);
+                       cmd->set_sdk(_options.sdkVersion());
+                       break;
+               case Options::kPlatformiOS:
+                       cmd->set_cmd(LC_VERSION_MIN_IPHONEOS);
+                       cmd->set_cmdsize(sizeof(macho_version_min_command<P>));
+                       cmd->set_version(_state.minOSVersion);
+                       cmd->set_sdk(_options.sdkVersion());
+                       break;
+               case Options::kPlatformWatchOS:
+                       cmd->set_cmd(LC_VERSION_MIN_WATCHOS);
+                       cmd->set_cmdsize(sizeof(macho_version_min_command<P>));
+                       cmd->set_version(_state.minOSVersion);
+                       cmd->set_sdk(_options.sdkVersion());
+                       break;
+#if SUPPORT_APPLE_TV
+               case Options::kPlatform_tvOS:
+                       cmd->set_cmd(LC_VERSION_MIN_TVOS);
+                       cmd->set_cmdsize(sizeof(macho_version_min_command<P>));
+                       cmd->set_version(_state.minOSVersion);
+                       cmd->set_sdk(_options.sdkVersion());
+                       break;
+#endif
        }
        return p + sizeof(macho_version_min_command<P>);
 }
        }
        return p + sizeof(macho_version_min_command<P>);
 }
@@ -1158,7 +1211,7 @@ uint8_t* HeaderAndLoadCommandsAtom<x86>::copyThreadsLoadCommand(uint8_t* p) cons
 template <>
 uint32_t HeaderAndLoadCommandsAtom<x86_64>::threadLoadCommandSize() const
 {
 template <>
 uint32_t HeaderAndLoadCommandsAtom<x86_64>::threadLoadCommandSize() const
 {
-       return this->alignedSize(16 + x86_THREAD_STATE64_COUNT * 4); 
+       return this->alignedSize(16 + 42*4);    // base size + x86_THREAD_STATE64_COUNT * 4
 }
 
 template <>
 }
 
 template <>
@@ -1169,8 +1222,8 @@ uint8_t* HeaderAndLoadCommandsAtom<x86_64>::copyThreadsLoadCommand(uint8_t* p) c
        macho_thread_command<P>* cmd = (macho_thread_command<P>*)p;
        cmd->set_cmd(LC_UNIXTHREAD);
        cmd->set_cmdsize(threadLoadCommandSize());
        macho_thread_command<P>* cmd = (macho_thread_command<P>*)p;
        cmd->set_cmd(LC_UNIXTHREAD);
        cmd->set_cmdsize(threadLoadCommandSize());
-       cmd->set_flavor(x86_THREAD_STATE64);                    
-       cmd->set_count(x86_THREAD_STATE64_COUNT);       
+       cmd->set_flavor(4);                             // x86_THREAD_STATE64
+       cmd->set_count(42);                             // x86_THREAD_STATE64_COUNT
        cmd->set_thread_register(16, start);            // rip 
        if ( _options.hasCustomStack() )
                cmd->set_thread_register(7, _options.customStackAddr());        // r1
        cmd->set_thread_register(16, start);            // rip 
        if ( _options.hasCustomStack() )
                cmd->set_thread_register(7, _options.customStackAddr());        // r1
@@ -1411,18 +1464,6 @@ uint8_t* HeaderAndLoadCommandsAtom<A>::copyLinkerOptionsLoadCommand(uint8_t* p,
 }
 
 
 }
 
 
-template <typename A>
-uint8_t* HeaderAndLoadCommandsAtom<A>::copyDependentDRLoadCommand(uint8_t* p) const
-{
-       macho_linkedit_data_command<P>* cmd = (macho_linkedit_data_command<P>*)p;
-       cmd->set_cmd(LC_DYLIB_CODE_SIGN_DRS);
-       cmd->set_cmdsize(sizeof(macho_linkedit_data_command<P>));
-       cmd->set_dataoff(_writer.dependentDRsSection->fileOffset);
-       cmd->set_datasize(_writer.dependentDRsSection->size);
-       return p + sizeof(macho_linkedit_data_command<P>);
-}
-
-
 
 template <typename A>
 uint8_t* HeaderAndLoadCommandsAtom<A>::copyOptimizationHintsLoadCommand(uint8_t* p) const
 
 template <typename A>
 uint8_t* HeaderAndLoadCommandsAtom<A>::copyOptimizationHintsLoadCommand(uint8_t* p) const
@@ -1546,9 +1587,6 @@ void HeaderAndLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
                }
        }
        
                }
        }
        
-       if ( _hasDependentDRInfo ) 
-               p = this->copyDependentDRLoadCommand(p);
        if ( _hasOptimizationHints )
                p = this->copyOptimizationHintsLoadCommand(p);
  
        if ( _hasOptimizationHints )
                p = this->copyOptimizationHintsLoadCommand(p);
  
index 30c0875de7af9e3311a2212a310e8b1c38f4c60c..9eadc2e264ad25c7105b2521e63ab5e31e720454 100644 (file)
@@ -58,6 +58,7 @@
 #include "InputFiles.h"
 #include "macho_relocatable_file.h"
 #include "macho_dylib_file.h"
 #include "InputFiles.h"
 #include "macho_relocatable_file.h"
 #include "macho_dylib_file.h"
+#include "textstub_dylib_file.hpp"
 #include "archive_file.h"
 #include "lto_file.h"
 #include "opaque_section_file.h"
 #include "archive_file.h"
 #include "lto_file.h"
 #include "opaque_section_file.h"
@@ -294,7 +295,17 @@ ld::File* InputFiles::makeFile(const Options::FileInfo& info, bool indirectDylib
        objOpts.neverConvertDwarf   = !_options.needsUnwindInfoSection();
        objOpts.verboseOptimizationHints = _options.verboseOptimizationHints();
        objOpts.armUsesZeroCostExceptions = _options.armUsesZeroCostExceptions();
        objOpts.neverConvertDwarf   = !_options.needsUnwindInfoSection();
        objOpts.verboseOptimizationHints = _options.verboseOptimizationHints();
        objOpts.armUsesZeroCostExceptions = _options.armUsesZeroCostExceptions();
+       objOpts.simulator                       = _options.targetIOSSimulator();
+       objOpts.ignoreMismatchPlatform = ((_options.outputKind() == Options::kPreload) || (_options.outputKind() == Options::kStaticExecutable));
        objOpts.subType                         = _options.subArchitecture();
        objOpts.subType                         = _options.subArchitecture();
+       objOpts.platform                        = _options.platform();
+       objOpts.minOSVersion            = _options.minOSversion();
+       // workaround for strip -S
+       // when ld -r has single input file, set the srcKind to kSourceSingle so __LLVM segment will be kept
+       if (_options.outputKind() == Options::kObjectFile && _options.getInputFiles().size() == 1)
+               objOpts.srcKind                 = ld::relocatable::File::kSourceSingle;
+       else
+               objOpts.srcKind                         = ld::relocatable::File::kSourceObj;
        ld::relocatable::File* objResult = mach_o::relocatable::parse(p, len, info.path, info.modTime, info.ordinal, objOpts);
        if ( objResult != NULL ) {
                OSAtomicAdd64(len, &_totalObjectSize);
        ld::relocatable::File* objResult = mach_o::relocatable::parse(p, len, info.path, info.modTime, info.ordinal, objOpts);
        if ( objResult != NULL ) {
                OSAtomicAdd64(len, &_totalObjectSize);
@@ -310,7 +321,7 @@ ld::File* InputFiles::makeFile(const Options::FileInfo& info, bool indirectDylib
                return objResult;
        }
        
                return objResult;
        }
        
-       // see if it is a dynamic library
+       // see if it is a dynamic library (or text-based dynamic library)
        ld::dylib::File* dylibResult;
        bool dylibsNotAllowed = false;
        switch ( _options.outputKind() ) {
        ld::dylib::File* dylibResult;
        bool dylibsNotAllowed = false;
        switch ( _options.outputKind() ) {
@@ -321,6 +332,10 @@ ld::File* InputFiles::makeFile(const Options::FileInfo& info, bool indirectDylib
                        if ( dylibResult != NULL ) {
                                return dylibResult;
                        }
                        if ( dylibResult != NULL ) {
                                return dylibResult;
                        }
+                       dylibResult = textstub::dylib::parse(p, len, info.path, info.modTime, _options, info.ordinal, info.options.fBundleLoader, indirectDylib);
+                       if ( dylibResult != NULL ) {
+                               return dylibResult;
+                       }
                        break;
                case Options::kStaticExecutable:
                case Options::kDyld:
                        break;
                case Options::kStaticExecutable:
                case Options::kDyld:
@@ -331,7 +346,6 @@ ld::File* InputFiles::makeFile(const Options::FileInfo& info, bool indirectDylib
                        break;
        }
 
                        break;
        }
 
-
        // see if it is a static library
        ::archive::ParserOptions archOpts;
        archOpts.objOpts                                = objOpts;
        // see if it is a static library
        ::archive::ParserOptions archOpts;
        archOpts.objOpts                                = objOpts;
@@ -341,6 +355,12 @@ ld::File* InputFiles::makeFile(const Options::FileInfo& info, bool indirectDylib
        archOpts.objcABI2                               = _options.objCABIVersion2POverride();
        archOpts.verboseLoad                    = _options.whyLoad();
        archOpts.logAllFiles                    = _options.logAllFiles();
        archOpts.objcABI2                               = _options.objCABIVersion2POverride();
        archOpts.verboseLoad                    = _options.whyLoad();
        archOpts.logAllFiles                    = _options.logAllFiles();
+       // Set ObjSource Kind, libclang_rt is compiler static library
+       const char* libName = strrchr(info.path, '/');
+       if ( (libName != NULL) && (strncmp(libName, "/libclang_rt", 12) == 0) )
+               archOpts.objOpts.srcKind = ld::relocatable::File::kSourceCompilerArchive;
+       else
+               archOpts.objOpts.srcKind = ld::relocatable::File::kSourceArchive;
        ld::archive::File* archiveResult = ::archive::parse(p, len, info.path, info.modTime, info.ordinal, archOpts);
        if ( archiveResult != NULL ) {
                OSAtomicAdd64(len, &_totalArchiveSize);
        ld::archive::File* archiveResult = ::archive::parse(p, len, info.path, info.modTime, info.ordinal, archOpts);
        if ( archiveResult != NULL ) {
                OSAtomicAdd64(len, &_totalArchiveSize);
@@ -587,6 +607,7 @@ void InputFiles::addLinkerOptionLibraries(ld::Internal& state, ld::File::AtomHan
                                ld::dylib::File* dylibReader = dynamic_cast<ld::dylib::File*>(reader);
                                if ( dylibReader != NULL ) {
                                        if ( ! dylibReader->installPathVersionSpecific() ) {
                                ld::dylib::File* dylibReader = dynamic_cast<ld::dylib::File*>(reader);
                                if ( dylibReader != NULL ) {
                                        if ( ! dylibReader->installPathVersionSpecific() ) {
+                                               dylibReader->forEachAtom(handler);
                                                dylibReader->setImplicitlyLinked();
                                                this->addDylib(dylibReader, info);
                                        }
                                                dylibReader->setImplicitlyLinked();
                                                this->addDylib(dylibReader, info);
                                        }
@@ -613,6 +634,7 @@ void InputFiles::addLinkerOptionLibraries(ld::Internal& state, ld::File::AtomHan
                                ld::dylib::File* dylibReader = dynamic_cast<ld::dylib::File*>(reader);
                                ld::archive::File* archiveReader = dynamic_cast<ld::archive::File*>(reader);
                                if ( dylibReader != NULL ) {
                                ld::dylib::File* dylibReader = dynamic_cast<ld::dylib::File*>(reader);
                                ld::archive::File* archiveReader = dynamic_cast<ld::archive::File*>(reader);
                                if ( dylibReader != NULL ) {
+                                       dylibReader->forEachAtom(handler);
                                        dylibReader->setImplicitlyLinked();
                                        this->addDylib(dylibReader, info);
                                }
                                        dylibReader->setImplicitlyLinked();
                                        this->addDylib(dylibReader, info);
                                }
@@ -775,20 +797,27 @@ void InputFiles::inferArchitecture(Options& opts, const char** archName)
        _inferredArch = true;
        // scan all input files, looking for a thin .o file.
        // the first one found is presumably the architecture to link
        _inferredArch = true;
        // scan all input files, looking for a thin .o file.
        // the first one found is presumably the architecture to link
-       uint8_t buffer[sizeof(mach_header_64)];
+       uint8_t buffer[4096];
        const std::vector<Options::FileInfo>& files = opts.getInputFiles();
        for (std::vector<Options::FileInfo>::const_iterator it = files.begin(); it != files.end(); ++it) {
                int fd = ::open(it->path, O_RDONLY, 0);
                if ( fd != -1 ) {
        const std::vector<Options::FileInfo>& files = opts.getInputFiles();
        for (std::vector<Options::FileInfo>::const_iterator it = files.begin(); it != files.end(); ++it) {
                int fd = ::open(it->path, O_RDONLY, 0);
                if ( fd != -1 ) {
-                       ssize_t amount = read(fd, buffer, sizeof(buffer));
-                       ::close(fd);
-                       if ( amount >= (ssize_t)sizeof(buffer) ) {
-                               cpu_type_t type;
-                               cpu_subtype_t subtype;
-                               if ( mach_o::relocatable::isObjectFile(buffer, &type, &subtype) ) {
-                                       opts.setArchitecture(type, subtype);
-                                       *archName = opts.architectureName();
-                                       return;
+                       struct stat stat_buf;
+                       if ( fstat(fd, &stat_buf) != -1) {
+                               ssize_t readAmount = stat_buf.st_size;
+                               if ( 4096 < readAmount )
+                                       readAmount = 4096;
+                               ssize_t amount = read(fd, buffer, readAmount);
+                               ::close(fd);
+                               if ( amount >= readAmount ) {
+                                       cpu_type_t type;
+                                       cpu_subtype_t subtype;
+                                       Options::Platform platform;
+                                       if ( mach_o::relocatable::isObjectFile(buffer, &type, &subtype, &platform) ) {
+                                               opts.setArchitecture(type, subtype, platform);
+                                               *archName = opts.architectureName();
+                                               return;
+                                       }
                                }
                        }
                }
                                }
                        }
                }
@@ -797,11 +826,11 @@ void InputFiles::inferArchitecture(Options& opts, const char** archName)
        // no thin .o files found, so default to same architecture this tool was built as
        warning("-arch not specified");
 #if __i386__
        // no thin .o files found, so default to same architecture this tool was built as
        warning("-arch not specified");
 #if __i386__
-       opts.setArchitecture(CPU_TYPE_I386, CPU_SUBTYPE_X86_ALL);
+       opts.setArchitecture(CPU_TYPE_I386, CPU_SUBTYPE_X86_ALL, Options::kPlatformOSX);
 #elif __x86_64__
 #elif __x86_64__
-       opts.setArchitecture(CPU_TYPE_X86_64, CPU_SUBTYPE_X86_64_ALL);
+       opts.setArchitecture(CPU_TYPE_X86_64, CPU_SUBTYPE_X86_64_ALL, Options::kPlatformOSX);
 #elif __arm__
 #elif __arm__
-       opts.setArchitecture(CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V6);
+       opts.setArchitecture(CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V6, Options::kPlatformOSX);
 #else
        #error unknown default architecture
 #endif
 #else
        #error unknown default architecture
 #endif
index 3420626d4d98fe51cc18edb4236e7b98b54032f2..c4421ef5c5594e396ec51195b2c49f2bf6c437c4 100644 (file)
@@ -32,6 +32,7 @@
 #include <unistd.h>
 
 #include <vector>
 #include <unistd.h>
 
 #include <vector>
+#include <unordered_map>
 
 #include "Options.h"
 #include "ld.hpp"
 
 #include "Options.h"
 #include "ld.hpp"
@@ -81,6 +82,17 @@ public:
                while( more );
        }
        
                while( more );
        }
        
+       void append_delta_encoded_uleb128_run(uint64_t start, const std::vector<uint64_t>& locations) {
+               uint64_t lastAddr = start;
+               for(std::vector<uint64_t>::const_iterator it = locations.begin(); it != locations.end(); ++it) {
+                       uint64_t nextAddr = *it;
+                       uint64_t delta = nextAddr - lastAddr;
+                       assert(delta != 0);
+                       append_uleb128(delta);
+                       lastAddr = nextAddr;
+               }
+       }
+
        void append_string(const char* str) {
                for (const char* s = str; *s != '\0'; ++s)
                        _data.push_back(*s);
        void append_string(const char* str) {
                for (const char* s = str; *s != '\0'; ++s)
                        _data.push_back(*s);
@@ -219,6 +231,8 @@ void RebaseInfoAtom<A>::encode() const
                }
                mid.push_back(rebase_tmp(REBASE_OPCODE_DO_REBASE_ULEB_TIMES, 1));
                address += sizeof(pint_t);
                }
                mid.push_back(rebase_tmp(REBASE_OPCODE_DO_REBASE_ULEB_TIMES, 1));
                address += sizeof(pint_t);
+               if ( address >= curSegEnd )
+                       address = 0;
        }
        mid.push_back(rebase_tmp(REBASE_OPCODE_DONE, 0));
 
        }
        mid.push_back(rebase_tmp(REBASE_OPCODE_DONE, 0));
 
@@ -969,6 +983,7 @@ void ExportInfoAtom<A>::encode() const
        std::vector<const ld::Atom*>& exports = this->_writer._exportedAtoms;
        uint64_t imageBaseAddress = this->_writer.headerAndLoadCommandsSection->address;
        std::vector<mach_o::trie::Entry> entries;
        std::vector<const ld::Atom*>& exports = this->_writer._exportedAtoms;
        uint64_t imageBaseAddress = this->_writer.headerAndLoadCommandsSection->address;
        std::vector<mach_o::trie::Entry> entries;
+       unsigned int padding = 0;
        entries.reserve(exports.size());
        for (std::vector<const ld::Atom*>::const_iterator it = exports.begin(); it != exports.end(); ++it) {
                const ld::Atom* atom = *it;
        entries.reserve(exports.size());
        for (std::vector<const ld::Atom*>::const_iterator it = exports.begin(); it != exports.end(); ++it) {
                const ld::Atom* atom = *it;
@@ -1035,6 +1050,13 @@ void ExportInfoAtom<A>::encode() const
                        entry.importName = NULL;
                        entries.push_back(entry);
                }
                        entry.importName = NULL;
                        entries.push_back(entry);
                }
+
+               if (_options.sharedRegionEligible() && strncmp(atom->section().segmentName(), "__DATA", 6) == 0) {
+                       // Maximum address is 64bit which is 10 bytes as a uleb128. Minimum is 1 byte
+                       // Pad the section out so we can deal with addresses getting larger when __DATA segment
+                       // is moved before __TEXT in dyld shared cache.
+                       padding += 9;
+               }
        }
 
        // sort vector by -exported_symbols_order, and any others by address
        }
 
        // sort vector by -exported_symbols_order, and any others by address
@@ -1043,6 +1065,10 @@ void ExportInfoAtom<A>::encode() const
        // create trie
        mach_o::trie::makeTrie(entries, this->_encodedData.bytes());
 
        // create trie
        mach_o::trie::makeTrie(entries, this->_encodedData.bytes());
 
+       //Add additional data padding for the unoptimized shared cache
+       for (unsigned int i = 0; i < padding; ++i)
+               this->_encodedData.append_byte(0);
+
        // align to pointer size
        this->_encodedData.pad_to_size(sizeof(pint_t));
        
        // align to pointer size
        this->_encodedData.pad_to_size(sizeof(pint_t));
        
@@ -1051,10 +1077,10 @@ void ExportInfoAtom<A>::encode() const
 
 
 template <typename A>
 
 
 template <typename A>
-class SplitSegInfoAtom : public LinkEditAtom
+class SplitSegInfoV1Atom : public LinkEditAtom
 {
 public:
 {
 public:
-                                                                                               SplitSegInfoAtom(const Options& opts, ld::Internal& state, OutputFile& writer)
+                                                                                               SplitSegInfoV1Atom(const Options& opts, ld::Internal& state, OutputFile& writer)
                                                                                                        : LinkEditAtom(opts, state, writer, _s_section, sizeof(pint_t)) { }
 
        // overrides of ld::Atom
                                                                                                        : LinkEditAtom(opts, state, writer, _s_section, sizeof(pint_t)) { }
 
        // overrides of ld::Atom
@@ -1083,10 +1109,10 @@ private:
 };
 
 template <typename A>
 };
 
 template <typename A>
-ld::Section SplitSegInfoAtom<A>::_s_section("__LINKEDIT", "__splitSegInfo", ld::Section::typeLinkEdit, true);
+ld::Section SplitSegInfoV1Atom<A>::_s_section("__LINKEDIT", "__splitSegInfo", ld::Section::typeLinkEdit, true);
 
 template <>
 
 template <>
-void SplitSegInfoAtom<x86_64>::addSplitSegInfo(uint64_t address, ld::Fixup::Kind kind, uint32_t extra) const
+void SplitSegInfoV1Atom<x86_64>::addSplitSegInfo(uint64_t address, ld::Fixup::Kind kind, uint32_t extra) const
 {
        switch (kind) {
                case ld::Fixup::kindStoreX86PCRel32:
 {
        switch (kind) {
                case ld::Fixup::kindStoreX86PCRel32:
@@ -1116,7 +1142,7 @@ void SplitSegInfoAtom<x86_64>::addSplitSegInfo(uint64_t address, ld::Fixup::Kind
 }
 
 template <>
 }
 
 template <>
-void SplitSegInfoAtom<x86>::addSplitSegInfo(uint64_t address, ld::Fixup::Kind kind, uint32_t extra) const
+void SplitSegInfoV1Atom<x86>::addSplitSegInfo(uint64_t address, ld::Fixup::Kind kind, uint32_t extra) const
 {
        switch (kind) {
                case ld::Fixup::kindStoreLittleEndian32:
 {
        switch (kind) {
                case ld::Fixup::kindStoreLittleEndian32:
@@ -1132,7 +1158,7 @@ void SplitSegInfoAtom<x86>::addSplitSegInfo(uint64_t address, ld::Fixup::Kind ki
 }
 
 template <>
 }
 
 template <>
-void SplitSegInfoAtom<arm>::addSplitSegInfo(uint64_t address, ld::Fixup::Kind kind, uint32_t extra) const
+void SplitSegInfoV1Atom<arm>::addSplitSegInfo(uint64_t address, ld::Fixup::Kind kind, uint32_t extra) const
 {
        switch (kind) {
                case ld::Fixup::kindStoreLittleEndian32:
 {
        switch (kind) {
                case ld::Fixup::kindStoreLittleEndian32:
@@ -1160,7 +1186,7 @@ void SplitSegInfoAtom<arm>::addSplitSegInfo(uint64_t address, ld::Fixup::Kind ki
 
 #if SUPPORT_ARCH_arm64
 template <>
 
 #if SUPPORT_ARCH_arm64
 template <>
-void SplitSegInfoAtom<arm64>::addSplitSegInfo(uint64_t address, ld::Fixup::Kind kind, uint32_t extra) const
+void SplitSegInfoV1Atom<arm64>::addSplitSegInfo(uint64_t address, ld::Fixup::Kind kind, uint32_t extra) const
 {
        switch (kind) {
                case ld::Fixup::kindStoreARM64Page21:
 {
        switch (kind) {
                case ld::Fixup::kindStoreARM64Page21:
@@ -1188,7 +1214,7 @@ void SplitSegInfoAtom<arm64>::addSplitSegInfo(uint64_t address, ld::Fixup::Kind
 #endif
 
 template <typename A>
 #endif
 
 template <typename A>
-void SplitSegInfoAtom<A>::uleb128EncodeAddresses(const std::vector<uint64_t>& locations) const
+void SplitSegInfoV1Atom<A>::uleb128EncodeAddresses(const std::vector<uint64_t>& locations) const
 {
        pint_t addr = this->_options.baseAddress();
        for(typename std::vector<uint64_t>::const_iterator it = locations.begin(); it != locations.end(); ++it) {
 {
        pint_t addr = this->_options.baseAddress();
        for(typename std::vector<uint64_t>::const_iterator it = locations.begin(); it != locations.end(); ++it) {
@@ -1215,12 +1241,12 @@ void SplitSegInfoAtom<A>::uleb128EncodeAddresses(const std::vector<uint64_t>& lo
 
 
 template <typename A>
 
 
 template <typename A>
-void SplitSegInfoAtom<A>::encode() const
+void SplitSegInfoV1Atom<A>::encode() const
 {
        // sort into group by pointer adjustment kind
        std::vector<OutputFile::SplitSegInfoEntry>& info = this->_writer._splitSegInfos;
        for (std::vector<OutputFile::SplitSegInfoEntry>::const_iterator it = info.begin(); it != info.end(); ++it) {
 {
        // sort into group by pointer adjustment kind
        std::vector<OutputFile::SplitSegInfoEntry>& info = this->_writer._splitSegInfos;
        for (std::vector<OutputFile::SplitSegInfoEntry>::const_iterator it = info.begin(); it != info.end(); ++it) {
-               this->addSplitSegInfo(it->address, it->kind, it->extra);
+               this->addSplitSegInfo(it->fixupAddress, it->kind, it->extra);
        }
 
        // delta compress runs of addresses
        }
 
        // delta compress runs of addresses
@@ -1298,6 +1324,108 @@ void SplitSegInfoAtom<A>::encode() const
        _64bitPointerLocations.clear();
 }
 
        _64bitPointerLocations.clear();
 }
 
+
+template <typename A>
+class SplitSegInfoV2Atom : public LinkEditAtom
+{
+public:
+                                                                                               SplitSegInfoV2Atom(const Options& opts, ld::Internal& state, OutputFile& writer)
+                                                                                                       : LinkEditAtom(opts, state, writer, _s_section, sizeof(pint_t)) { }
+
+       // overrides of ld::Atom
+       virtual const char*                                                     name() const            { return "split seg info"; }
+       // overrides of LinkEditAtom
+       virtual void                                                            encode() const;
+
+private:
+       typedef typename A::P                                           P;
+       typedef typename A::P::E                                        E;
+       typedef typename A::P::uint_t                           pint_t;
+
+       // Whole                 :== <count> FromToSection+
+       // FromToSection :== <from-sect-index> <to-sect-index> <count> ToOffset+
+       // ToOffset              :== <to-sect-offset-delta> <count> FromOffset+
+       // FromOffset    :== <kind> <count> <from-sect-offset-delta>
+
+       typedef uint32_t SectionIndexes;
+       typedef std::map<uint8_t, std::vector<uint64_t> > FromOffsetMap;
+       typedef std::map<uint64_t, FromOffsetMap> ToOffsetMap;
+       typedef std::map<SectionIndexes, ToOffsetMap> WholeMap;
+
+
+       static ld::Section                      _s_section;
+};
+
+template <typename A>
+ld::Section SplitSegInfoV2Atom<A>::_s_section("__LINKEDIT", "__splitSegInfo", ld::Section::typeLinkEdit, true);
+
+
+template <typename A>
+void SplitSegInfoV2Atom<A>::encode() const
+{
+       // sort into group by adjustment kind
+       //fprintf(stderr, "_splitSegV2Infos.size=%lu\n", this->_writer._splitSegV2Infos.size());
+       WholeMap whole;
+       for (const OutputFile::SplitSegInfoV2Entry&  entry : this->_writer._splitSegV2Infos) {
+               //fprintf(stderr, "from=%d, to=%d\n", entry.fixupSectionIndex, entry.targetSectionIndex);
+               SectionIndexes index = entry.fixupSectionIndex << 16 | entry.targetSectionIndex;
+               ToOffsetMap& toOffsets = whole[index];
+               FromOffsetMap& fromOffsets = toOffsets[entry.targetSectionOffset];
+               fromOffsets[entry.referenceKind].push_back(entry.fixupSectionOffset);
+       }
+
+       // Add marker that this is V2 data
+       this->_encodedData.reserve(8192);
+       this->_encodedData.append_byte(DYLD_CACHE_ADJ_V2_FORMAT); 
+
+       // stream out
+       // Whole :== <count> FromToSection+
+       this->_encodedData.append_uleb128(whole.size());
+       for (auto& fromToSection : whole) {
+               uint8_t fromSectionIndex = fromToSection.first >> 16;
+               uint8_t toSectionIndex   = fromToSection.first & 0xFFFF;
+               ToOffsetMap& toOffsets   = fromToSection.second;
+               // FromToSection :== <from-sect-index> <to-sect-index> <count> ToOffset+
+               this->_encodedData.append_uleb128(fromSectionIndex);
+               this->_encodedData.append_uleb128(toSectionIndex);
+               this->_encodedData.append_uleb128(toOffsets.size());
+               //fprintf(stderr, "from sect=%d, to sect=%d, count=%lu\n", fromSectionIndex, toSectionIndex, toOffsets.size());
+               uint64_t lastToOffset = 0;
+               for (auto& fromToOffsets : toOffsets) {
+                       uint64_t toSectionOffset = fromToOffsets.first;
+                       FromOffsetMap& fromOffsets = fromToOffsets.second;
+                       // ToOffset     :== <to-sect-offset-delta> <count> FromOffset+
+                       this->_encodedData.append_uleb128(toSectionOffset - lastToOffset);
+                       this->_encodedData.append_uleb128(fromOffsets.size());
+                       for (auto& kindAndOffsets : fromOffsets) {
+                               uint8_t kind = kindAndOffsets.first;
+                               std::vector<uint64_t>& fromOffsets = kindAndOffsets.second;
+                               // FromOffset :== <kind> <count> <from-sect-offset-delta>
+                               this->_encodedData.append_uleb128(kind);
+                               this->_encodedData.append_uleb128(fromOffsets.size());
+                               std::sort(fromOffsets.begin(), fromOffsets.end());
+                               uint64_t lastFromOffset = 0;
+                               for (uint64_t offset : fromOffsets) {
+                                       this->_encodedData.append_uleb128(offset - lastFromOffset);
+                                       lastFromOffset = offset;
+                               }
+                       }
+                       lastToOffset = toSectionOffset;
+               }
+       }
+
+
+       // always add zero byte to mark end
+       this->_encodedData.append_byte(0);
+
+       // align to pointer size
+       this->_encodedData.pad_to_size(sizeof(pint_t));
+       
+       this->_encoded = true;
+}
+
+
+
 template <typename A>
 class FunctionStartsAtom : public LinkEditAtom
 {
 template <typename A>
 class FunctionStartsAtom : public LinkEditAtom
 {
@@ -1497,63 +1625,6 @@ void DataInCodeAtom<A>::encode() const
 
 
 
 
 
 
-// <rdar://problem/7209249> linker needs to cache "Designated Requirements" in linked binary
-template <typename A>
-class DependentDRAtom : public LinkEditAtom
-{
-public:
-                                                                                               DependentDRAtom(const Options& opts, ld::Internal& state, OutputFile& writer)
-                                                                                                       : LinkEditAtom(opts, state, writer, _s_section, sizeof(pint_t)) { }
-
-       // overrides of ld::Atom
-       virtual const char*                                                     name() const            { return "dependent dylib DR info"; }
-       // overrides of LinkEditAtom
-       virtual void                                                            encode() const;
-
-private:
-       typedef typename A::P                                           P;
-       typedef typename A::P::E                                        E;
-       typedef typename A::P::uint_t                           pint_t;
-
-       static ld::Section                      _s_section;
-
-};
-
-template <typename A>
-ld::Section DependentDRAtom<A>::_s_section("__LINKEDIT", "__dependentDR", ld::Section::typeLinkEdit, true);
-
-
-template <typename A>
-void DependentDRAtom<A>::encode() const
-{
-       Security::SuperBlobCore<Security::SuperBlob<Security::kSecCodeMagicDRList>, Security::kSecCodeMagicDRList, uint32_t>::Maker maker;
-       
-       uint32_t index = 0;
-       for(std::vector<ld::dylib::File*>::iterator it=_state.dylibs.begin(); it != _state.dylibs.end(); ++it) {
-               const ld::dylib::File* dylib = *it;
-               Security::BlobCore* dylibDR = (Security::BlobCore*)dylib->codeSignatureDR();
-               void* dup = NULL;
-               if ( dylibDR != NULL ) {
-                       // <rdar://problem/11315321> Maker takes ownership of every blob added
-                       // We need to make a copy here because dylib still owns the pointer returned by codeSignatureDR()
-                       dup = ::malloc(dylibDR->length());
-                       ::memcpy(dup, dylibDR, dylibDR->length());
-               }
-               maker.add(index, (Security::BlobCore*)dup);
-               ++index;
-       }
-       
-       Security::SuperBlob<Security::kSecCodeMagicDRList>* topBlob = maker.make();
-       const uint8_t* data = (uint8_t*)topBlob->data();
-       for(size_t i=0; i < topBlob->length(); ++i)
-               _encodedData.append_byte(data[i]);
-       
-       this->_encodedData.pad_to_size(sizeof(pint_t));
-
-       this->_encoded = true;
-}
-
-
 
 template <typename A>
 class OptimizationHintsAtom : public LinkEditAtom
 
 template <typename A>
 class OptimizationHintsAtom : public LinkEditAtom
index 3389f5ce69e4c8cc440377aa455e7c2859827c17..ee1c2078ef81e07d6c45680c9d73e1386667e3be 100644 (file)
@@ -1614,9 +1614,17 @@ void SectionRelocationsAtom<arm>::encodeSectionReloc(ld::Internal::FinalSection*
                        {
                                int len = 0;
                                uint32_t otherHalf = 0;
                        {
                                int len = 0;
                                uint32_t otherHalf = 0;
-                               uint32_t value = entry.toTarget->finalAddress()+entry.toAddend;
-                               if ( entry.fromTarget != NULL ) 
-                                       value -= (entry.fromTarget->finalAddress()+entry.fromAddend);
+                               uint32_t value;
+                               if ( entry.fromTarget != NULL )  {
+                                 // this is a sect-diff
+                                 value = (entry.toTarget->finalAddress()+entry.toAddend) - (entry.fromTarget->finalAddress()+entry.fromAddend);
+                               }
+                               else {
+                                       // this is an absolute address
+                                       value = entry.toAddend;
+                                       if ( !external )
+                                               value += entry.toTarget->finalAddress();
+                               }
                                switch ( entry.kind ) {
                                        case ld::Fixup::kindStoreARMLow16:
                                                len = 0;
                                switch ( entry.kind ) {
                                        case ld::Fixup::kindStoreARMLow16:
                                                len = 0;
index 228a0df8678cb584d331ec94d7b9d346e8144431..a638cb4c499696f805f50fda2e077bb46c2f5cea 100644 (file)
 #include <Availability.h>
 
 #include <vector>
 #include <Availability.h>
 
 #include <vector>
+#include <map>
+#include <sstream>
 
 #include "Options.h"
 #include "Architectures.hpp"
 #include "MachOFileAbstraction.hpp"
 #include "Snapshot.h"
 
 
 #include "Options.h"
 #include "Architectures.hpp"
 #include "MachOFileAbstraction.hpp"
 #include "Snapshot.h"
 
+
+// from FunctionNameDemangle.h
+extern "C" size_t fnd_get_demangled_name(const char *mangledName, char *outputBuffer, size_t length);
+
+
 // upward dependency on lto::version()
 namespace lto {
        extern const char* version();
 // upward dependency on lto::version()
 namespace lto {
        extern const char* version();
@@ -143,11 +150,11 @@ Options::Options(int argc, const char* argv[])
          fCommonsMode(kCommonsIgnoreDylibs),  fUUIDMode(kUUIDContent), fLocalSymbolHandling(kLocalSymbolsAll), fWarnCommons(false), 
          fVerbose(false), fKeepRelocations(false), fWarnStabs(false),
          fTraceDylibSearching(false), fPause(false), fStatistics(false), fPrintOptions(false),
          fCommonsMode(kCommonsIgnoreDylibs),  fUUIDMode(kUUIDContent), fLocalSymbolHandling(kLocalSymbolsAll), fWarnCommons(false), 
          fVerbose(false), fKeepRelocations(false), fWarnStabs(false),
          fTraceDylibSearching(false), fPause(false), fStatistics(false), fPrintOptions(false),
-         fSharedRegionEligible(false), fPrintOrderFileStatistics(false),  
+         fSharedRegionEligible(false), fSharedRegionEligibleForceOff(false), fPrintOrderFileStatistics(false),
          fReadOnlyx86Stubs(false), fPositionIndependentExecutable(false), fPIEOnCommandLine(false),
          fDisablePositionIndependentExecutable(false), fMaxMinimumHeaderPad(false),
          fDeadStripDylibs(false),  fAllowTextRelocs(false), fWarnTextRelocs(false), fKextsUseStubs(false),
          fReadOnlyx86Stubs(false), fPositionIndependentExecutable(false), fPIEOnCommandLine(false),
          fDisablePositionIndependentExecutable(false), fMaxMinimumHeaderPad(false),
          fDeadStripDylibs(false),  fAllowTextRelocs(false), fWarnTextRelocs(false), fKextsUseStubs(false),
-         fUsingLazyDylibLinking(false), fEncryptable(true), 
+         fUsingLazyDylibLinking(false), fEncryptable(true), fEncryptableForceOn(false), fEncryptableForceOff(false),
          fOrderData(true), fMarkDeadStrippableDylib(false),
          fMakeCompressedDyldInfo(true), fMakeCompressedDyldInfoForceOff(false), fNoEHLabels(false),
          fAllowCpuSubtypeMismatches(false), fUseSimplifiedDylibReExports(false),
          fOrderData(true), fMarkDeadStrippableDylib(false),
          fMakeCompressedDyldInfo(true), fMakeCompressedDyldInfoForceOff(false), fNoEHLabels(false),
          fAllowCpuSubtypeMismatches(false), fUseSimplifiedDylibReExports(false),
@@ -171,16 +178,19 @@ Options::Options(int argc, const char* argv[])
          fEntryPointLoadCommandForceOn(false), fEntryPointLoadCommandForceOff(false),
          fSourceVersionLoadCommand(false), 
          fSourceVersionLoadCommandForceOn(false), fSourceVersionLoadCommandForceOff(false), 
          fEntryPointLoadCommandForceOn(false), fEntryPointLoadCommandForceOff(false),
          fSourceVersionLoadCommand(false), 
          fSourceVersionLoadCommandForceOn(false), fSourceVersionLoadCommandForceOff(false), 
-         fDependentDRInfo(false), fDependentDRInfoForcedOn(false), fDependentDRInfoForcedOff(false),
          fTargetIOSSimulator(false), fExportDynamic(false), fAbsoluteSymbols(false),
          fAllowSimulatorToLinkWithMacOSX(false), fKeepDwarfUnwind(true),
          fKeepDwarfUnwindForcedOn(false), fKeepDwarfUnwindForcedOff(false),
          fVerboseOptimizationHints(false), fIgnoreOptimizationHints(false),
          fGenerateDtraceDOF(true), fAllowBranchIslands(true), fTraceSymbolLayout(false), 
          fTargetIOSSimulator(false), fExportDynamic(false), fAbsoluteSymbols(false),
          fAllowSimulatorToLinkWithMacOSX(false), fKeepDwarfUnwind(true),
          fKeepDwarfUnwindForcedOn(false), fKeepDwarfUnwindForcedOff(false),
          fVerboseOptimizationHints(false), fIgnoreOptimizationHints(false),
          fGenerateDtraceDOF(true), fAllowBranchIslands(true), fTraceSymbolLayout(false), 
-         fMarkAppExtensionSafe(false), fCheckAppExtensionSafe(false), fForceLoadSwiftLibs(false), 
-         fDebugInfoStripping(kDebugInfoMinimal), fTraceOutputFile(NULL), 
-         fMacVersionMin(ld::macVersionUnset), fIOSVersionMin(ld::iOSVersionUnset), 
-         fSaveTempFiles(false), fSnapshotRequested(false), fPipelineFifo(NULL), 
+         fMarkAppExtensionSafe(false), fCheckAppExtensionSafe(false), fForceLoadSwiftLibs(false),
+         fSharedRegionEncodingV2(false), fUseDataConstSegment(false),
+         fUseDataConstSegmentForceOn(false), fUseDataConstSegmentForceOff(false),
+         fBundleBitcode(false), fHideSymbols(false), fReverseMapUUIDRename(false), fReverseMapPath(NULL), fLTOCodegenOnly(false),
+         fIgnoreAutoLink(false), fPlatform(kPlatformUnknown),
+         fDebugInfoStripping(kDebugInfoMinimal), fTraceOutputFile(NULL),
+         fMacVersionMin(ld::macVersionUnset), fIOSVersionMin(ld::iOSVersionUnset),
+         fSaveTempFiles(false), fSnapshotRequested(false), fPipelineFifo(NULL),
          fDependencyInfoPath(NULL), fDependencyFileDescriptor(-1)
 {
        this->checkForClassic(argc, argv);
          fDependencyInfoPath(NULL), fDependencyFileDescriptor(-1)
 {
        this->checkForClassic(argc, argv);
@@ -236,7 +246,7 @@ bool Options::interposable(const char* name) const
 
 bool Options::printWhyLive(const char* symbolName) const
 {
 
 bool Options::printWhyLive(const char* symbolName) const
 {
-       return ( fWhyLive.find(symbolName) != fWhyLive.end() );
+       return fWhyLive.contains(symbolName);
 }
 
 
 }
 
 
@@ -325,7 +335,7 @@ uint32_t Options::maxSegProtection(const char* segName) const
 {
        // iPhoneOS always uses same protection for max and initial
        // <rdar://problem/11663436> simulator apps need to use MacOSX max-prot
 {
        // iPhoneOS always uses same protection for max and initial
        // <rdar://problem/11663436> simulator apps need to use MacOSX max-prot
-       if ( (fIOSVersionMin != ld::iOSVersionUnset) && (fArchitecture != CPU_TYPE_I386) )
+       if ( (fPlatform != kPlatformOSX) && !fTargetIOSSimulator )
                return initialSegProtection(segName);
 
        for(std::vector<Options::SegmentProtect>::const_iterator it = fCustomSegmentProtections.begin(); it != fCustomSegmentProtections.end(); ++it) {
                return initialSegProtection(segName);
 
        for(std::vector<Options::SegmentProtect>::const_iterator it = fCustomSegmentProtections.begin(); it != fCustomSegmentProtections.end(); ++it) {
@@ -391,6 +401,17 @@ uint8_t Options::customSectionAlignment(const char* segName, const char* sectNam
        return 0;
 }
 
        return 0;
 }
 
+bool Options::segmentOrderAfterFixedAddressSegment(const char* segName) const
+{
+       bool nowPinned = false;
+       for (std::vector<const char*>::const_iterator it=fSegmentOrder.begin(); it != fSegmentOrder.end(); ++it) {
+               if ( strcmp(*it, segName) == 0 )
+                       return nowPinned;
+               if ( hasCustomSegmentAddress(*it) )
+                       nowPinned = true;
+       }
+       return false;
+}
 
 bool Options::hasExportedSymbolOrder()
 {
 
 bool Options::hasExportedSymbolOrder()
 {
@@ -549,9 +570,26 @@ const std::vector<const char*>* Options::sectionOrder(const char* segName) const
        return NULL;
 }
 
        return NULL;
 }
 
+uint32_t Options::minOSversion() const
+{
+       switch (fPlatform) {
+               case kPlatformiOS:
+                       return iOSVersionMin();
+               case kPlatformOSX:
+                       return macosxVersionMin();
+               case kPlatformWatchOS:
+                       return watchOSVersionMin();
+#if SUPPORT_APPLE_TV
+               case Options::kPlatform_tvOS:
+                       return iOSVersionMin();
+#endif
+               default:
+                       break;
+       }
+       return 0;
+}
 
 
-
-void Options::setArchitecture(cpu_type_t type, cpu_subtype_t subtype)
+void Options::setArchitecture(cpu_type_t type, cpu_subtype_t subtype, Options::Platform platform)
 {
        for (const ArchInfo* t=archInfoArray; t->archName != NULL; ++t) {
                if ( (type == t->cpuType) && (subtype == t->cpuSubType) ) {
 {
        for (const ArchInfo* t=archInfoArray; t->archName != NULL; ++t) {
                if ( (type == t->cpuType) && (subtype == t->cpuSubType) ) {
@@ -560,10 +598,11 @@ void Options::setArchitecture(cpu_type_t type, cpu_subtype_t subtype)
                        fArchitectureName = t->archName;
                        fHasPreferredSubType = t->isSubType;
                        fArchSupportsThumb2 = t->supportsThumb2;
                        fArchitectureName = t->archName;
                        fHasPreferredSubType = t->isSubType;
                        fArchSupportsThumb2 = t->supportsThumb2;
+                       fPlatform = platform;
                        switch ( type ) {
                                case CPU_TYPE_I386:
                                case CPU_TYPE_X86_64:
                        switch ( type ) {
                                case CPU_TYPE_I386:
                                case CPU_TYPE_X86_64:
-                                       if ( (fMacVersionMin == ld::macVersionUnset) && (fIOSVersionMin == ld::iOSVersionUnset) && (fOutputKind != Options::kObjectFile) ) {
+                                       if ( (fPlatform == kPlatformOSX) && (fOutputKind != Options::kObjectFile) ) {
                                #ifdef DEFAULT_MACOSX_MIN_VERSION
                                                warning("-macosx_version_min not specified, assuming " DEFAULT_MACOSX_MIN_VERSION);
                                                setMacOSXVersionMin(DEFAULT_MACOSX_MIN_VERSION);
                                #ifdef DEFAULT_MACOSX_MIN_VERSION
                                                warning("-macosx_version_min not specified, assuming " DEFAULT_MACOSX_MIN_VERSION);
                                                setMacOSXVersionMin(DEFAULT_MACOSX_MIN_VERSION);
@@ -575,7 +614,7 @@ void Options::setArchitecture(cpu_type_t type, cpu_subtype_t subtype)
                                        break;
                                case CPU_TYPE_ARM:
                                case CPU_TYPE_ARM64:
                                        break;
                                case CPU_TYPE_ARM:
                                case CPU_TYPE_ARM64:
-                                       if ( (fMacVersionMin == ld::macVersionUnset) && (fIOSVersionMin == ld::iOSVersionUnset) && (fOutputKind != Options::kObjectFile) ) {
+                                       if ( (fPlatform == kPlatformiOS) && (fOutputKind != Options::kObjectFile) ) {
                                #if defined(DEFAULT_IPHONEOS_MIN_VERSION)
                                                warning("-ios_version_min not specified, assuming " DEFAULT_IPHONEOS_MIN_VERSION);
                                                setIOSVersionMin(DEFAULT_IPHONEOS_MIN_VERSION);
                                #if defined(DEFAULT_IPHONEOS_MIN_VERSION)
                                                warning("-ios_version_min not specified, assuming " DEFAULT_IPHONEOS_MIN_VERSION);
                                                setIOSVersionMin(DEFAULT_IPHONEOS_MIN_VERSION);
@@ -672,6 +711,8 @@ Options::FileInfo Options::findLibrary(const char* rootName, bool dylibsOnly) co
                                                 it != fLibrarySearchPaths.end();
                                                 it++) {
                                                const char* dir = *it;
                                                 it != fLibrarySearchPaths.end();
                                                 it++) {
                                                const char* dir = *it;
+                                               if ( checkForFile("%s/lib%s.tbd", dir, rootName, result) )
+                                                       return result;
                                                if ( checkForFile("%s/lib%s.dylib", dir, rootName, result) )
                                                        return result;
                                        }
                                                if ( checkForFile("%s/lib%s.dylib", dir, rootName, result) )
                                                        return result;
                                        }
@@ -701,6 +742,8 @@ Options::FileInfo Options::findLibrary(const char* rootName, bool dylibsOnly) co
                                         it != fLibrarySearchPaths.end();
                                         it++) {
                                        const char* dir = *it;
                                         it != fLibrarySearchPaths.end();
                                         it++) {
                                        const char* dir = *it;
+                                       if ( lookForDylibs && checkForFile("%s/lib%s.tbd", dir, rootName, result) )
+                                               return result;
                                        if ( lookForDylibs && checkForFile("%s/lib%s.dylib", dir, rootName, result) )
                                                return result;
                                        if ( lookForDylibs && checkForFile("%s/lib%s.so", dir, rootName, result) )
                                        if ( lookForDylibs && checkForFile("%s/lib%s.dylib", dir, rootName, result) )
                                                return result;
                                        if ( lookForDylibs && checkForFile("%s/lib%s.so", dir, rootName, result) )
@@ -732,31 +775,21 @@ Options::FileInfo Options::findFramework(const char* frameworkName) const
 
 Options::FileInfo Options::findFramework(const char* rootName, const char* suffix) const
 {
 
 Options::FileInfo Options::findFramework(const char* rootName, const char* suffix) const
 {
-       for (std::vector<const char*>::const_iterator it = fFrameworkSearchPaths.begin();
-                it != fFrameworkSearchPaths.end();
-                it++) {
-               // ??? Shouldn't we be using String here and just initializing it?
-               // ??? Use str.c_str () to pull out the string for the stat call.
-               const char* dir = *it;
-               char possiblePath[PATH_MAX];
-               strcpy(possiblePath, dir);
-               strcat(possiblePath, "/");
-               strcat(possiblePath, rootName);
-               strcat(possiblePath, ".framework/");
-               strcat(possiblePath, rootName);
-               if ( suffix != NULL ) {
+       for (const auto* path : fFrameworkSearchPaths) {
+               auto possiblePath = std::string(path).append("/").append(rootName).append(".framework/").append(rootName);
+               if ( suffix != nullptr ) {
                        char realPath[PATH_MAX];
                        // no symlink in framework to suffix variants, so follow main symlink
                        char realPath[PATH_MAX];
                        // no symlink in framework to suffix variants, so follow main symlink
-                       if ( realpath(possiblePath, realPath) != NULL ) {
-                               strcpy(possiblePath, realPath);
-                               strcat(possiblePath, suffix);
-                       }
+                       if ( realpath(possiblePath.c_str(), realPath) != nullptr )
+                               possiblePath = std::string(realPath).append(suffix);
                }
         FileInfo result;
                }
         FileInfo result;
-               bool found = result.checkFileExists(*this, possiblePath);
+               bool found = result.checkFileExists(*this, (possiblePath + ".tbd").c_str());
+               if ( !found )
+                       found = result.checkFileExists(*this, possiblePath.c_str());
                if ( fTraceDylibSearching )
                        printf("[Logging for XBS]%sfound framework: '%s'\n",
                if ( fTraceDylibSearching )
                        printf("[Logging for XBS]%sfound framework: '%s'\n",
-                                  (found ? " " : " not "), possiblePath);
+                                  (found ? " " : " not "), possiblePath.c_str());
                if ( found ) {
                        return result;
                }
                if ( found ) {
                        return result;
                }
@@ -768,68 +801,84 @@ Options::FileInfo Options::findFramework(const char* rootName, const char* suffi
                throwf("framework not found %s", rootName);
 }
 
                throwf("framework not found %s", rootName);
 }
 
-Options::FileInfo Options::findFile(const char* path) const
+Options::FileInfo Options::findFile(const std::string &path) const
 {
        FileInfo result;
 
 {
        FileInfo result;
 
-       // if absolute path and not a .o file, the use SDK prefix
-       if ( (path[0] == '/') && (strcmp(&path[strlen(path)-2], ".o") != 0) ) {
-               const int pathLen = strlen(path);
-               for (std::vector<const char*>::const_iterator it = fSDKPaths.begin(); it != fSDKPaths.end(); it++) {
-                       // ??? Shouldn't we be using String here?
-                       const char* sdkPathDir = *it;
-                       const int sdkPathDirLen = strlen(sdkPathDir);
-                       char possiblePath[sdkPathDirLen+pathLen+4];
-                       strcpy(possiblePath, sdkPathDir);
-                       if ( possiblePath[sdkPathDirLen-1] == '/' )
-                               possiblePath[sdkPathDirLen-1] = '\0';
-                       strcat(possiblePath, path);
-                       if ( result.checkFileExists(*this, possiblePath) ) {
+       // if absolute path and not a .o file, then use SDK prefix
+       if ( (path[0] == '/') && (strcmp(&path[path.size()-2], ".o") != 0) ) {
+               auto tbdFile = path;
+               auto lastSlashIdx = tbdFile.find_last_of('/');
+               auto lastDotIdx = tbdFile.find_last_of('.');
+               if (lastDotIdx != std::string::npos && lastDotIdx > lastSlashIdx)
+                       tbdFile.erase(lastDotIdx, std::string::npos);
+               tbdFile.append(".tbd");
+
+               for (const auto* sdkPathDir : fSDKPaths) {
+                       auto possiblePath = std::string(sdkPathDir) + tbdFile;
+                       if ( result.checkFileExists(*this, possiblePath.c_str()) )
+                               return result;
+                       possiblePath = std::string(sdkPathDir) + path;
+                       if ( result.checkFileExists(*this, possiblePath.c_str()) )
                                return result;
                                return result;
-                       }
                }
        }
        // try raw path
                }
        }
        // try raw path
-       if ( result.checkFileExists(*this, path) ) {
+       {
+               std::string file = path;
+               auto lastDotIdx = file.find_last_of('.');
+               if (lastDotIdx != std::string::npos)
+                       file.erase(lastDotIdx, std::string::npos);
+               if ( result.checkFileExists(*this, file.append(".tbd").c_str()) )
+                       return result;
+       }
+       if ( result.checkFileExists(*this, path.c_str()) ) {
                return result;
        }
 
                return result;
        }
 
+
        // try @executable_path substitution
        // try @executable_path substitution
-       if ( (strncmp(path, "@executable_path/", 17) == 0) && (fExecutablePath != NULL) ) {
-               char newPath[strlen(fExecutablePath) + strlen(path)];
+       if ( (path.find("@executable_path/") == 0) && (fExecutablePath != nullptr) ) {
+               char newPath[strlen(fExecutablePath) + path.size()];
                strcpy(newPath, fExecutablePath);
                char* addPoint = strrchr(newPath,'/');
                strcpy(newPath, fExecutablePath);
                char* addPoint = strrchr(newPath,'/');
-               if ( addPoint != NULL )
+               if ( addPoint != nullptr )
                        strcpy(&addPoint[1], &path[17]);
                else
                        strcpy(newPath, &path[17]);
                        strcpy(&addPoint[1], &path[17]);
                else
                        strcpy(newPath, &path[17]);
+
+               std::string file = newPath;
+               auto lastDotIdx = file.find_last_of('.');
+               if (lastDotIdx != std::string::npos)
+                       file.erase(lastDotIdx, std::string::npos);
+               if ( result.checkFileExists(*this, file.append(".tbd").c_str()) ) {
+                       return result;
+               }
                if ( result.checkFileExists(*this, newPath) ) {
                        return result;
                }
        }
 
        // not found
                if ( result.checkFileExists(*this, newPath) ) {
                        return result;
                }
        }
 
        // not found
-       throwf("file not found: %s", path);
+       throwf("file not found: %s", path.c_str());
 }
 
 }
 
-Options::FileInfo Options::findFileUsingPaths(const char* path) const 
+Options::FileInfo Options::findFileUsingPaths(const std::string &path) const
 {
        FileInfo result;
 
 {
        FileInfo result;
 
-       const char* lastSlash = strrchr(path, '/');
-       const char* leafName = (lastSlash == NULL) ? path : &lastSlash[1];
+       auto lastSlashPos = path.find_last_of('/');
+       auto pos = ( lastSlashPos != std::string::npos ) ? lastSlashPos + 1 : 0;
+       auto leafName = path.substr(pos);
 
        // Is this in a framework?
        // /path/Foo.framework/Foo                                                      ==> true (Foo)
        // /path/Foo.framework/Frameworks/Bar.framework/Bar ==> true (Bar)
        // /path/Foo.framework/Resources/Bar                            ==> false
        bool isFramework = false;
 
        // Is this in a framework?
        // /path/Foo.framework/Foo                                                      ==> true (Foo)
        // /path/Foo.framework/Frameworks/Bar.framework/Bar ==> true (Bar)
        // /path/Foo.framework/Resources/Bar                            ==> false
        bool isFramework = false;
-       if ( lastSlash != NULL ) {
-               char frameworkDir[strlen(leafName) + 20];
-               strcpy(frameworkDir, "/");
-               strcat(frameworkDir, leafName);
-               strcat(frameworkDir, ".framework/");
-               if ( strstr(path, frameworkDir) != NULL )
+       if ( lastSlashPos != std::string::npos ) {
+               auto frameworkDir = std::string("/").append(leafName).append(".framework/");
+               if ( path.rfind(frameworkDir) != std::string::npos )
                        isFramework = true;
        }
        
                        isFramework = true;
        }
        
@@ -838,35 +887,28 @@ Options::FileInfo Options::findFileUsingPaths(const char* path) const
        // don't need to try variations, just paths. We do need to add the additional bits
        // onto the framework path though.
        if ( isFramework ) {
        // don't need to try variations, just paths. We do need to add the additional bits
        // onto the framework path though.
        if ( isFramework ) {
-               for (std::vector<const char*>::const_iterator it = fFrameworkSearchPaths.begin();
-                        it != fFrameworkSearchPaths.end();
-                        it++) {
-                       const char* dir = *it;
-                       char possiblePath[PATH_MAX];
-                       strcpy(possiblePath, dir);
-                       strcat(possiblePath, "/");
-                       strcat(possiblePath, leafName);
-                       strcat(possiblePath, ".framework");
-
-                       //fprintf(stderr,"Finding Framework: %s/%s, leafName=%s\n", possiblePath, leafName, leafName);
-                       if ( checkForFile("%s/%s", possiblePath, leafName, result) )
+               auto endPos = path.rfind(".framework");
+               auto beginPos = path.find_last_of('/', endPos);
+               auto leafPath = path.substr(beginPos);
+               for (const auto* dir : fFrameworkSearchPaths) {
+                       auto possiblePath = dir + leafPath;
+                       if ( checkForFile("%s.%s", possiblePath.c_str(), "tbd", result) )
+                               return result;
+                       if ( checkForFile("%s", possiblePath.c_str(), "", result) )
                                return result;
                }
                                return result;
                }
-       } 
-       else {
+       } else {
                // if this is a .dylib inside a framework, do not search -L paths
                // if this is a .dylib inside a framework, do not search -L paths
-               // <rdar://problem/5427952> ld64's re-export cycle detection logic prevents use of X11 libGL on Leopard 
-               int leafLen = strlen(leafName);
-               bool embeddedDylib = ( (leafLen > 6) 
-                                       && (strcmp(&leafName[leafLen-6], ".dylib") == 0) 
-                                       && (strstr(path, ".framework/") != NULL) );
+               // <rdar://problem/5427952> ld64's re-export cycle detection logic prevents use of X11 libGL on Leopard
+               bool embeddedDylib = ( (leafName.size() > 6)
+                                       && (leafName.find(".dylib", leafName.size()-6) != std::string::npos)
+                                       && (path.find(".framework/") != std::string::npos) );
                if ( !embeddedDylib ) {
                if ( !embeddedDylib ) {
-                       for (std::vector<const char*>::const_iterator it = fLibrarySearchPaths.begin();
-                                it != fLibrarySearchPaths.end();
-                                it++) {
-                               const char* dir = *it;
+                       for (const auto* dir : fLibrarySearchPaths) {
                                //fprintf(stderr,"Finding Library: %s/%s\n", dir, leafName);
                                //fprintf(stderr,"Finding Library: %s/%s\n", dir, leafName);
-                               if ( checkForFile("%s/%s", dir, leafName, result) )
+                               if ( checkForFile("%s/%s", dir, std::string(leafName).append(".tbd").c_str(), result) )
+                                       return result;
+                               if ( checkForFile("%s/%s", dir, leafName.c_str(), result) )
                                        return result;
                        }
                }
                                        return result;
                        }
                }
@@ -1070,6 +1112,23 @@ bool Options::SetWithWildcards::containsNonWildcard(const char* symbol) const
 }
 
 
 }
 
 
+std::vector<const char*> Options::exportsData() const
+{
+       return fExportSymbols.data();
+}
+
+
+std::vector<const char*> Options::SetWithWildcards::data() const
+{
+       std::vector<const char*> data;
+       for (NameSet::iterator it=regularBegin(); it != regularEnd(); ++it) {
+               data.push_back(*it);
+       }
+       for (std::vector<const char*>::const_iterator it=fWildCard.begin(); it != fWildCard.end(); ++it) {
+               data.push_back(*it);
+       }
+       return data;
+}
 
 bool Options::SetWithWildcards::inCharRange(const char*& p, unsigned char c) const
 {
 
 bool Options::SetWithWildcards::inCharRange(const char*& p, unsigned char c) const
 {
@@ -1348,6 +1407,7 @@ void Options::setMacOSXVersionMin(const char* version)
                        minorVersion = 255;
                }
                fMacVersionMin = (ld::MacVersionMin)(0x000A0000 | (minorVersion << 8));
                        minorVersion = 255;
                }
                fMacVersionMin = (ld::MacVersionMin)(0x000A0000 | (minorVersion << 8));
+               fPlatform = kPlatformOSX;
        }
        else {
                warning("unknown option to -macosx_version_min, not 10.x");
        }
        else {
                warning("unknown option to -macosx_version_min, not 10.x");
@@ -1368,18 +1428,52 @@ void Options::setIOSVersionMin(const char* version)
        unsigned int majorVersion = version[0] - '0';
        unsigned int minorVersion = version[2] - '0';
        fIOSVersionMin = (ld::IOSVersionMin)((majorVersion << 16) | (minorVersion << 8));
        unsigned int majorVersion = version[0] - '0';
        unsigned int minorVersion = version[2] - '0';
        fIOSVersionMin = (ld::IOSVersionMin)((majorVersion << 16) | (minorVersion << 8));
+       fPlatform = kPlatformiOS;
+}
+
+
+void Options::setWatchOSVersionMin(const char* version)
+{
+       if ( version == NULL )
+               throw "-watchos_version_min argument missing";
+       if ( ! isdigit(version[0]) )
+               throw "-watchos_version_min argument is not a number";
+       if ( version[1] != '.' )
+               throw "-watchos_version_min argument is missing period as second character";
+       if ( ! isdigit(version[2]) )
+               throw "-watchos_version_min argument is not a number";
+
+       unsigned int majorVersion = version[0] - '0';
+       unsigned int minorVersion = version[2] - '0';
+       fWatchOSVersionMin = (ld::WatchOSVersionMin)((majorVersion << 16) | (minorVersion << 8));
+       fPlatform = kPlatformWatchOS;
 }
 
 }
 
+
 bool Options::minOS(ld::MacVersionMin requiredMacMin, ld::IOSVersionMin requirediPhoneOSMin)
 {
        if ( fMacVersionMin != ld::macVersionUnset ) {
                return ( fMacVersionMin >= requiredMacMin );
        }
 bool Options::minOS(ld::MacVersionMin requiredMacMin, ld::IOSVersionMin requirediPhoneOSMin)
 {
        if ( fMacVersionMin != ld::macVersionUnset ) {
                return ( fMacVersionMin >= requiredMacMin );
        }
+       else if ( fWatchOSVersionMin != ld::wOSVersionUnset ) {
+               // Hack until we fully track watch and ios versions seperately
+               return ( (fWatchOSVersionMin + 0x00070000) >= requirediPhoneOSMin);
+       }
        else {
        else {
-               return ( fIOSVersionMin >= requirediPhoneOSMin);
+               return ( fIOSVersionMin >= requirediPhoneOSMin );
        }
 }
 
        }
 }
 
+bool Options::min_iOS(ld::IOSVersionMin requirediOSMin)
+{
+        if ( fWatchOSVersionMin != ld::wOSVersionUnset ) {
+               // Hack until we fully track watch and ios versions seperately
+               return ( (fWatchOSVersionMin + 0x00070000) >= requirediOSMin);
+       }
+       else {
+               return ( fIOSVersionMin >= requirediOSMin );
+       }
+}
 
 void Options::setWeakReferenceMismatchTreatment(const char* treatment)
 {
 
 void Options::setWeakReferenceMismatchTreatment(const char* treatment)
 {
@@ -1766,7 +1860,7 @@ void Options::addSection(const char* segment, const char* section, const char* p
        ::close(fd);
 
        // record section to create
        ::close(fd);
 
        // record section to create
-       ExtraSection info = { segment, section, path, (uint8_t*)p, stat_buf.st_size };
+       ExtraSection info = { segment, section, path, (uint8_t*)p, (uint64_t)stat_buf.st_size };
        fExtraSections.push_back(info);
 }
 
        fExtraSections.push_back(info);
 }
 
@@ -1895,7 +1989,188 @@ void Options::warnObsolete(const char* arg)
 }
 
 
 }
 
 
+void Options::cannotBeUsedWithBitcode(const char* arg)
+{
+       if ( fBundleBitcode )
+               throwf("%s and -bitcode_bundle (Xcode setting ENABLE_BITCODE=YES) cannot be used together", arg);
+}
+
+std::string Options::getVersionString32(uint32_t ver) const
+{
+       if (ver == 0 || ver >= 0x10000000)
+               return "0.0.0";
+
+       unsigned microVersion = ver & 0xFF;
+       unsigned minorVersion = (ver >> 8) & 0xFF;
+       unsigned majorVersion = (ver >> 16) & 0xFF;
+       std::stringstream versionString;
+       versionString << majorVersion << "." << minorVersion << "." << microVersion;
+       return versionString.str();
+}
+
+std::string Options::getVersionString64(uint64_t ver) const
+{
+       uint64_t a = (ver >> 40) & 0xFFFFFF;
+       uint64_t b = (ver >> 30) & 0x3FF;
+       uint64_t c = (ver >> 20) & 0x3FF;
+       uint64_t d = (ver >> 10) & 0x3FF;
+       uint64_t e = ver & 0x3FF;
+       std::stringstream versionString;
+       versionString << a << "." << b << "." << c << "." << d << "." << e;
+       return versionString.str();
+}
+
+std::string Options::getSDKVersionStr() const
+{
+       return getVersionString32(fSDKVersion);
+}
+
+std::string Options::getPlatformStr() const
+{
+       switch (fPlatform) {
+               case Options::kPlatformOSX:
+                       return "MacOSX";
+               case Options::kPlatformiOS:
+                       if (targetIOSSimulator())
+                               return "iPhoneSimulator";
+                       else
+                               return "iPhoneOS";
+               case Options::kPlatformWatchOS:
+                       if (targetIOSSimulator())
+                               return "watchOS Simulator";
+                       else
+                               return "watchOS";
+#if SUPPORT_APPLE_TV
+               case Options::kPlatform_tvOS:
+                       if (targetIOSSimulator())
+                               return "AppleTVSimulator";
+                       else
+                               return "AppleTVOS";
+                       break;
+#endif
+               case Options::kPlatformUnknown:
+                       return "Unknown";
+       }
+}
+
+std::vector<std::string> Options::writeBitcodeLinkOptions() const
+{
+       std::vector<std::string> linkCommand;
+       switch ( fOutputKind ) {
+               case Options::kDynamicLibrary:
+                       linkCommand.push_back("-dylib");
+                       linkCommand.push_back("-compatibility_version");
+                       if ( fDylibCompatVersion != 0 ) {
+                               linkCommand.push_back(getVersionString32(fDylibCompatVersion));
+                       } else {
+                               linkCommand.push_back(getVersionString32(currentVersion32()));
+                       }
+                       if ( fDylibCurrentVersion != 0 ) {
+                               linkCommand.push_back("-current_version");
+                               linkCommand.push_back(getVersionString64(fDylibCurrentVersion));
+                       }
+                       linkCommand.push_back("-install_name");
+                       linkCommand.push_back(installPath());
+                       break;
+               case Options::kDynamicExecutable:
+                       linkCommand.push_back("-execute");
+                       break;
+               case Options::kObjectFile:
+                       linkCommand.push_back("-r");
+                       break;
+               default:
+                       throwf("could not write bitcode options file output kind\n");
+       }
 
 
+       if (!fImplicitlyLinkPublicDylibs)
+               linkCommand.push_back("-no_implicit_dylibs");
+
+       // Add deployment target.
+       // Platform is allowed to be unknown for "ld -r".
+       switch (fPlatform) {
+               case Options::kPlatformOSX:
+                       linkCommand.push_back("-macosx_version_min");
+                       linkCommand.push_back(getVersionString32((unsigned)fMacVersionMin));
+                       break;
+               case Options::kPlatformiOS:
+                       if (targetIOSSimulator())
+                               linkCommand.push_back("-ios_simulator_version_min");
+                       else
+                               linkCommand.push_back("-ios_version_min");
+                       linkCommand.push_back(getVersionString32((unsigned)fIOSVersionMin));
+                       break;
+               case Options::kPlatformWatchOS:
+                       if (targetIOSSimulator())
+                               linkCommand.push_back("-watchos_simulator_version_min");
+                       else
+                               linkCommand.push_back("-watchos_version_min");
+                       linkCommand.push_back(getVersionString32((unsigned)fIOSVersionMin));
+                       break;
+#if SUPPORT_APPLE_TV
+               case Options::kPlatform_tvOS:
+                       if (targetIOSSimulator())
+                               linkCommand.push_back("-tvos_simulator_version_min");
+                       else
+                               linkCommand.push_back("-tvos_version_min");
+                       linkCommand.push_back(getVersionString32((unsigned)fIOSVersionMin));
+                       break;
+#endif
+               case Options::kPlatformUnknown:
+                       if ( fOutputKind != Options::kObjectFile ) {
+                               throwf("platform is unknown for final bitcode bundle,"
+                                          "deployment target and min version is required for -bitcode_bundle");
+                       }
+                       break;
+       }
+
+
+       // entry name
+       if ( fEntryName ) {
+               linkCommand.push_back("-e");
+               linkCommand.push_back(fEntryName);
+       }
+
+       // Write rpaths
+       if (!fRPaths.empty()) {
+               for (std::vector<const char*>::const_iterator it=fRPaths.begin(); it != fRPaths.end(); ++it) {
+                       linkCommand.push_back("-rpath");
+                       linkCommand.push_back(*it);
+               }
+       }
+
+       // Other bitcode compatiable options
+       if ( fObjCABIVersion1Override ) {
+               linkCommand.push_back("-objc_abi_version");
+               linkCommand.push_back("1");
+       } else if ( fObjCABIVersion2Override ) {
+               linkCommand.push_back("-objc_abi_version");
+               linkCommand.push_back("2");
+       }
+       if ( fExecutablePath ) {
+               linkCommand.push_back("-executable_path");
+               linkCommand.push_back(fExecutablePath);
+       }
+       if ( fDeadStrip )
+               linkCommand.push_back("-dead_strip");
+       if ( fExportDynamic )
+               linkCommand.push_back("-export_dynamic");
+       if ( fMarkAppExtensionSafe && fCheckAppExtensionSafe )
+               linkCommand.push_back("-application_extension");
+
+       if ( fSourceVersionLoadCommandForceOn )
+               linkCommand.push_back("-add_source_version");
+       if ( fSourceVersion != 0 ) {
+               linkCommand.push_back("-source_version");
+               linkCommand.push_back(getVersionString64(fSourceVersion));
+       }
+
+       // linker flag added by swift driver
+       // rdar://problem/20108072
+       if ( !fObjcCategoryMerging )
+               linkCommand.push_back("-no_objc_category_merging");
+
+       return linkCommand;
+}
 
 //
 // Process all command line arguments.
 
 //
 // Process all command line arguments.
@@ -1957,15 +2232,18 @@ void Options::parse(int argc, const char* argv[])
                                if ( (fOutputKind != kObjectFile) && (fOutputKind != kKextBundle) ) {
                                        fOutputKind = kStaticExecutable;
                                }
                                if ( (fOutputKind != kObjectFile) && (fOutputKind != kKextBundle) ) {
                                        fOutputKind = kStaticExecutable;
                                }
+                               cannotBeUsedWithBitcode(arg);
                        }
                        else if ( strcmp(arg, "-dylib") == 0 ) {
                                fOutputKind = kDynamicLibrary;
                        }
                        else if ( strcmp(arg, "-bundle") == 0 ) {
                                fOutputKind = kDynamicBundle;
                        }
                        else if ( strcmp(arg, "-dylib") == 0 ) {
                                fOutputKind = kDynamicLibrary;
                        }
                        else if ( strcmp(arg, "-bundle") == 0 ) {
                                fOutputKind = kDynamicBundle;
+                               cannotBeUsedWithBitcode(arg);
                        }
                        else if ( strcmp(arg, "-dylinker") == 0 ) {
                                fOutputKind = kDyld;
                        }
                        else if ( strcmp(arg, "-dylinker") == 0 ) {
                                fOutputKind = kDyld;
+                               cannotBeUsedWithBitcode(arg);
                        }
                        else if ( strcmp(arg, "-execute") == 0 ) {
                                if ( fOutputKind != kStaticExecutable )
                        }
                        else if ( strcmp(arg, "-execute") == 0 ) {
                                if ( fOutputKind != kStaticExecutable )
@@ -1973,12 +2251,14 @@ void Options::parse(int argc, const char* argv[])
                        }
                        else if ( strcmp(arg, "-preload") == 0 ) {
                                fOutputKind = kPreload;
                        }
                        else if ( strcmp(arg, "-preload") == 0 ) {
                                fOutputKind = kPreload;
+                               cannotBeUsedWithBitcode(arg);
                        }
                        else if ( strcmp(arg, "-r") == 0 ) {
                                fOutputKind = kObjectFile;
                        }
                        else if ( strcmp(arg, "-kext") == 0 ) {
                                fOutputKind = kKextBundle;
                        }
                        else if ( strcmp(arg, "-r") == 0 ) {
                                fOutputKind = kObjectFile;
                        }
                        else if ( strcmp(arg, "-kext") == 0 ) {
                                fOutputKind = kKextBundle;
+                               cannotBeUsedWithBitcode(arg);
                        }
                        else if ( strcmp(arg, "-o") == 0 ) {
                 snapshotArgCount = 0;
                        }
                        else if ( strcmp(arg, "-o") == 0 ) {
                 snapshotArgCount = 0;
@@ -1992,6 +2272,7 @@ void Options::parse(int argc, const char* argv[])
                                info.ordinal = ld::File::Ordinal::makeArgOrdinal((uint16_t)i);
                                addLibrary(info);
                                fUsingLazyDylibLinking = true;
                                info.ordinal = ld::File::Ordinal::makeArgOrdinal((uint16_t)i);
                                addLibrary(info);
                                fUsingLazyDylibLinking = true;
+                               cannotBeUsedWithBitcode(arg);
                        }
                        else if ( strcmp(arg, "-lto_library") == 0 ) {
                 snapshotFileArgIndex = 1;
                        }
                        else if ( strcmp(arg, "-lto_library") == 0 ) {
                 snapshotFileArgIndex = 1;
@@ -2018,18 +2299,21 @@ void Options::parse(int argc, const char* argv[])
                        // Avoid lazy binding.
                        else if ( strcmp(arg, "-bind_at_load") == 0 ) {
                                fBindAtLoad = true;
                        // Avoid lazy binding.
                        else if ( strcmp(arg, "-bind_at_load") == 0 ) {
                                fBindAtLoad = true;
+                               cannotBeUsedWithBitcode(arg);
                        }
                        else if ( strcmp(arg, "-twolevel_namespace") == 0 ) {
                                fNameSpace = kTwoLevelNameSpace;
                        }
                        else if ( strcmp(arg, "-flat_namespace") == 0 ) {
                                fNameSpace = kFlatNameSpace;
                        }
                        else if ( strcmp(arg, "-twolevel_namespace") == 0 ) {
                                fNameSpace = kTwoLevelNameSpace;
                        }
                        else if ( strcmp(arg, "-flat_namespace") == 0 ) {
                                fNameSpace = kFlatNameSpace;
+                               cannotBeUsedWithBitcode(arg);
                        }
                        // Also sets a bit to ensure dyld causes everything
                        // in the namespace to be flat.
                        // ??? Deprecate
                        else if ( strcmp(arg, "-force_flat_namespace") == 0 ) {
                                fNameSpace = kForceFlatNameSpace;
                        }
                        // Also sets a bit to ensure dyld causes everything
                        // in the namespace to be flat.
                        // ??? Deprecate
                        else if ( strcmp(arg, "-force_flat_namespace") == 0 ) {
                                fNameSpace = kForceFlatNameSpace;
+                               cannotBeUsedWithBitcode(arg);
                        }
                        // Similar to --whole-archive.
                        else if ( strcmp(arg, "-all_load") == 0 ) {
                        }
                        // Similar to --whole-archive.
                        else if ( strcmp(arg, "-all_load") == 0 ) {
@@ -2070,13 +2354,16 @@ void Options::parse(int argc, const char* argv[])
                 snapshotFileArgIndex = 3;
                                parseSectionOrderFile(argv[i+1], argv[i+2], argv[i+3]);
                                i += 3;
                 snapshotFileArgIndex = 3;
                                parseSectionOrderFile(argv[i+1], argv[i+2], argv[i+3]);
                                i += 3;
+                               cannotBeUsedWithBitcode(arg);
                        }
                        else if ( strcmp(arg, "-order_file") == 0 ) {
                 snapshotFileArgIndex = 1;
                                parseOrderFile(argv[++i], false);
                        }
                        else if ( strcmp(arg, "-order_file") == 0 ) {
                 snapshotFileArgIndex = 1;
                                parseOrderFile(argv[++i], false);
+                               cannotBeUsedWithBitcode(arg);
                        }
                        else if ( strcmp(arg, "-order_file_statistics") == 0 ) {
                                fPrintOrderFileStatistics = true;
                        }
                        else if ( strcmp(arg, "-order_file_statistics") == 0 ) {
                                fPrintOrderFileStatistics = true;
+                               cannotBeUsedWithBitcode(arg);
                        }
                        // ??? Deprecate segcreate.
                        // -sectcreate puts whole files into a section in the output.
                        }
                        // ??? Deprecate segcreate.
                        // -sectcreate puts whole files into a section in the output.
@@ -2106,6 +2393,7 @@ void Options::parse(int argc, const char* argv[])
                                        warning("-seg1addr not %lld byte aligned, rounding up", fSegmentAlignment);
                                        fBaseAddress = temp;
                                }
                                        warning("-seg1addr not %lld byte aligned, rounding up", fSegmentAlignment);
                                        fBaseAddress = temp;
                                }
+                               cannotBeUsedWithBitcode(arg);
                        }
                        else if ( strcmp(arg, "-e") == 0 ) {
                                fEntryName = argv[++i];
                        }
                        else if ( strcmp(arg, "-e") == 0 ) {
                                fEntryName = argv[++i];
@@ -2120,7 +2408,8 @@ void Options::parse(int argc, const char* argv[])
                                 loadFileList(path, baseOrdinal);
                        }
                        else if ( strcmp(arg, "-keep_private_externs") == 0 ) {
                                 loadFileList(path, baseOrdinal);
                        }
                        else if ( strcmp(arg, "-keep_private_externs") == 0 ) {
-                                fKeepPrivateExterns = true;
+                               cannotBeUsedWithBitcode(arg);
+                               fKeepPrivateExterns = true;
                        }
                        else if ( strcmp(arg, "-final_output") == 0 ) {
                                fFinalName = argv[++i];
                        }
                        else if ( strcmp(arg, "-final_output") == 0 ) {
                                fFinalName = argv[++i];
@@ -2137,11 +2426,13 @@ void Options::parse(int argc, const char* argv[])
                                                // do nothing, -interposable_list overrides -interposable"
                                                break;
                                }
                                                // do nothing, -interposable_list overrides -interposable"
                                                break;
                                }
+                               cannotBeUsedWithBitcode(arg);
                        }
                        else if ( strcmp(arg, "-interposable_list") == 0 ) {
                 snapshotFileArgIndex = 1;
                                fInterposeMode = kInterposeSome;
                                loadExportFile(argv[++i], "-interposable_list", fInterposeList);
                        }
                        else if ( strcmp(arg, "-interposable_list") == 0 ) {
                 snapshotFileArgIndex = 1;
                                fInterposeMode = kInterposeSome;
                                loadExportFile(argv[++i], "-interposable_list", fInterposeList);
+                               cannotBeUsedWithBitcode(arg);
                        }
                        // Default for -interposable/-multi_module/-single_module.
                        else if ( strcmp(arg, "-single_module") == 0 ) {
                        }
                        // Default for -interposable/-multi_module/-single_module.
                        else if ( strcmp(arg, "-single_module") == 0 ) {
@@ -2160,6 +2451,7 @@ void Options::parse(int argc, const char* argv[])
                                        throw "can't use -unexported_symbols_list and -exported_symbols_list";
                                fExportMode = kDontExportSome;
                                loadExportFile(argv[++i], "-unexported_symbols_list", fDontExportSymbols);
                                        throw "can't use -unexported_symbols_list and -exported_symbols_list";
                                fExportMode = kDontExportSome;
                                loadExportFile(argv[++i], "-unexported_symbols_list", fDontExportSymbols);
+                               cannotBeUsedWithBitcode(arg);
                        }
                        else if ( strcmp(arg, "-exported_symbol") == 0 ) {
                                if ( fExportMode == kDontExportSome )
                        }
                        else if ( strcmp(arg, "-exported_symbol") == 0 ) {
                                if ( fExportMode == kDontExportSome )
@@ -2172,6 +2464,7 @@ void Options::parse(int argc, const char* argv[])
                                        throw "can't use -unexported_symbol and -exported_symbol";
                                fExportMode = kDontExportSome;
                                fDontExportSymbols.insert(argv[++i]);
                                        throw "can't use -unexported_symbol and -exported_symbol";
                                fExportMode = kDontExportSome;
                                fDontExportSymbols.insert(argv[++i]);
+                               cannotBeUsedWithBitcode(arg);
                        }
                        else if ( strcmp(arg, "-non_global_symbols_no_strip_list") == 0 ) {
                 snapshotFileArgIndex = 1;
                        }
                        else if ( strcmp(arg, "-non_global_symbols_no_strip_list") == 0 ) {
                 snapshotFileArgIndex = 1;
@@ -2179,6 +2472,7 @@ void Options::parse(int argc, const char* argv[])
                                        throw "can't use -non_global_symbols_no_strip_list and -non_global_symbols_strip_list";
                                fLocalSymbolHandling = kLocalSymbolsSelectiveInclude;
                                loadExportFile(argv[++i], "-non_global_symbols_no_strip_list", fLocalSymbolsIncluded);
                                        throw "can't use -non_global_symbols_no_strip_list and -non_global_symbols_strip_list";
                                fLocalSymbolHandling = kLocalSymbolsSelectiveInclude;
                                loadExportFile(argv[++i], "-non_global_symbols_no_strip_list", fLocalSymbolsIncluded);
+                               cannotBeUsedWithBitcode(arg);
                        }
                        else if ( strcmp(arg, "-non_global_symbols_strip_list") == 0 ) {
                 snapshotFileArgIndex = 1;
                        }
                        else if ( strcmp(arg, "-non_global_symbols_strip_list") == 0 ) {
                 snapshotFileArgIndex = 1;
@@ -2186,6 +2480,7 @@ void Options::parse(int argc, const char* argv[])
                                        throw "can't use -non_global_symbols_no_strip_list and -non_global_symbols_strip_list";
                                fLocalSymbolHandling = kLocalSymbolsSelectiveExclude;
                                loadExportFile(argv[++i], "-non_global_symbols_strip_list", fLocalSymbolsExcluded);
                                        throw "can't use -non_global_symbols_no_strip_list and -non_global_symbols_strip_list";
                                fLocalSymbolHandling = kLocalSymbolsSelectiveExclude;
                                loadExportFile(argv[++i], "-non_global_symbols_strip_list", fLocalSymbolsExcluded);
+                               cannotBeUsedWithBitcode(arg);
                        }
                        // ??? Deprecate
                        else if ( strcmp(arg, "-no_arch_warnings") == 0 ) {
                        }
                        // ??? Deprecate
                        else if ( strcmp(arg, "-no_arch_warnings") == 0 ) {
@@ -2194,6 +2489,7 @@ void Options::parse(int argc, const char* argv[])
                        else if ( strcmp(arg, "-force_cpusubtype_ALL") == 0 ) {
                                fForceSubtypeAll = true;
                                fAllowCpuSubtypeMismatches = true;
                        else if ( strcmp(arg, "-force_cpusubtype_ALL") == 0 ) {
                                fForceSubtypeAll = true;
                                fAllowCpuSubtypeMismatches = true;
+                               cannotBeUsedWithBitcode(arg);
                        }
                        // Similar to -weak-l but uses the absolute path name to the library.
                        else if ( strcmp(arg, "-weak_library") == 0 ) {
                        }
                        // Similar to -weak-l but uses the absolute path name to the library.
                        else if ( strcmp(arg, "-weak_library") == 0 ) {
@@ -2203,6 +2499,7 @@ void Options::parse(int argc, const char* argv[])
                                info.options.fWeakImport = true;
                                info.ordinal = ld::File::Ordinal::makeArgOrdinal((uint16_t)i);
                                addLibrary(info);
                                info.options.fWeakImport = true;
                                info.ordinal = ld::File::Ordinal::makeArgOrdinal((uint16_t)i);
                                addLibrary(info);
+                               cannotBeUsedWithBitcode(arg);
                        }
                        else if ( strcmp(arg, "-lazy_library") == 0 ) {
                 // SNAPSHOT FIXME: what should we do for link snapshots? (ignore for now)
                        }
                        else if ( strcmp(arg, "-lazy_library") == 0 ) {
                 // SNAPSHOT FIXME: what should we do for link snapshots? (ignore for now)
@@ -2212,6 +2509,7 @@ void Options::parse(int argc, const char* argv[])
                                info.ordinal = ld::File::Ordinal::makeArgOrdinal((uint16_t)i);
                                addLibrary(info);
                                fUsingLazyDylibLinking = true;
                                info.ordinal = ld::File::Ordinal::makeArgOrdinal((uint16_t)i);
                                addLibrary(info);
                                fUsingLazyDylibLinking = true;
+                               cannotBeUsedWithBitcode(arg);
                        }
                        else if ( strcmp(arg, "-framework") == 0 ) {
                 snapshotArgCount = 0;
                        }
                        else if ( strcmp(arg, "-framework") == 0 ) {
                 snapshotArgCount = 0;
@@ -2235,6 +2533,7 @@ void Options::parse(int argc, const char* argv[])
                                info.ordinal = ld::File::Ordinal::makeArgOrdinal((uint16_t)i);
                                addLibrary(info);
                                fUsingLazyDylibLinking = true;
                                info.ordinal = ld::File::Ordinal::makeArgOrdinal((uint16_t)i);
                                addLibrary(info);
                                fUsingLazyDylibLinking = true;
+                               cannotBeUsedWithBitcode(arg);
                        }
                        else if ( strcmp(arg, "-search_paths_first") == 0 ) {
                                // previously handled by buildSearchPaths()
                        }
                        else if ( strcmp(arg, "-search_paths_first") == 0 ) {
                                // previously handled by buildSearchPaths()
@@ -2244,6 +2543,7 @@ void Options::parse(int argc, const char* argv[])
                        }
                        else if ( strcmp(arg, "-undefined") == 0 ) {
                 setUndefinedTreatment(argv[++i]);
                        }
                        else if ( strcmp(arg, "-undefined") == 0 ) {
                 setUndefinedTreatment(argv[++i]);
+                               cannotBeUsedWithBitcode(arg);
                        }
                        // Debugging output flag.
                        else if ( strcmp(arg, "-arch_multiple") == 0 ) {
                        }
                        // Debugging output flag.
                        else if ( strcmp(arg, "-arch_multiple") == 0 ) {
@@ -2261,10 +2561,12 @@ void Options::parse(int argc, const char* argv[])
                                        case kWarning:
                                                fWarnTextRelocs = true;
                                                fAllowTextRelocs = true;
                                        case kWarning:
                                                fWarnTextRelocs = true;
                                                fAllowTextRelocs = true;
+                                               cannotBeUsedWithBitcode(arg);
                                                break;
                                        case kSuppress:
                                                fWarnTextRelocs = false;
                                                fAllowTextRelocs = true;
                                                break;
                                        case kSuppress:
                                                fWarnTextRelocs = false;
                                                fAllowTextRelocs = true;
+                                               cannotBeUsedWithBitcode(arg);
                                                break;
                                        case kError:
                                                fWarnTextRelocs = false;
                                                break;
                                        case kError:
                                                fWarnTextRelocs = false;
@@ -2287,6 +2589,7 @@ void Options::parse(int argc, const char* argv[])
                        // later.  Prebinding is less useful on 10.4 and greater.
                        else if ( strcmp(arg, "-prebind") == 0 ) {
                                fPrebind = true;
                        // later.  Prebinding is less useful on 10.4 and greater.
                        else if ( strcmp(arg, "-prebind") == 0 ) {
                                fPrebind = true;
+                               cannotBeUsedWithBitcode(arg);
                        }
                        else if ( strcmp(arg, "-noprebind") == 0 ) {
                                warnObsolete(arg);
                        }
                        else if ( strcmp(arg, "-noprebind") == 0 ) {
                                warnObsolete(arg);
@@ -2310,6 +2613,7 @@ void Options::parse(int argc, const char* argv[])
                 // ignore for snapshot because a stub dylib will be created in the snapshot
                  snapshotArgCount = 0;
                                 addDylibOverride(argv[++i]);
                 // ignore for snapshot because a stub dylib will be created in the snapshot
                  snapshotArgCount = 0;
                                 addDylibOverride(argv[++i]);
+                               cannotBeUsedWithBitcode(arg);
                        }
                        // What to expand @executable_path to if found in dependent dylibs
                        else if ( strcmp(arg, "-executable_path") == 0 ) {
                        }
                        // What to expand @executable_path to if found in dependent dylibs
                        else if ( strcmp(arg, "-executable_path") == 0 ) {
@@ -2340,6 +2644,7 @@ void Options::parse(int argc, const char* argv[])
                                        warning("alignment for -segalign %s is not a power of two, using 0x%X", size, p2aligned);
                                        fSegmentAlignment = p2aligned;
                                }
                                        warning("alignment for -segalign %s is not a power of two, using 0x%X", size, p2aligned);
                                        fSegmentAlignment = p2aligned;
                                }
+                               cannotBeUsedWithBitcode(arg);
                        }
                        // Puts a specified segment at a particular address that must
                        // be a multiple of the segment alignment.
                        }
                        // Puts a specified segment at a particular address that must
                        // be a multiple of the segment alignment.
@@ -2353,15 +2658,18 @@ void Options::parse(int argc, const char* argv[])
                                if ( seg.address != temp )
                                        warning("-segaddr %s not %lld byte aligned", seg.name, fSegmentAlignment);
                                fCustomSegmentAddresses.push_back(seg);
                                if ( seg.address != temp )
                                        warning("-segaddr %s not %lld byte aligned", seg.name, fSegmentAlignment);
                                fCustomSegmentAddresses.push_back(seg);
+                               cannotBeUsedWithBitcode(arg);
                        }
                        // ??? Deprecate when we deprecate split-seg.
                        else if ( strcmp(arg, "-segs_read_only_addr") == 0 ) {
                                fBaseAddress = parseAddress(argv[++i]);
                        }
                        // ??? Deprecate when we deprecate split-seg.
                        else if ( strcmp(arg, "-segs_read_only_addr") == 0 ) {
                                fBaseAddress = parseAddress(argv[++i]);
+                               cannotBeUsedWithBitcode(arg);
                        }
                        // ??? Deprecate when we deprecate split-seg.
                        else if ( strcmp(arg, "-segs_read_write_addr") == 0 ) {
                                fBaseWritableAddress = parseAddress(argv[++i]);
                                fSplitSegs = true;
                        }
                        // ??? Deprecate when we deprecate split-seg.
                        else if ( strcmp(arg, "-segs_read_write_addr") == 0 ) {
                                fBaseWritableAddress = parseAddress(argv[++i]);
                                fSplitSegs = true;
+                               cannotBeUsedWithBitcode(arg);
                        }
                        // ??? Deprecate when we get rid of basing at build time.
                        else if ( strcmp(arg, "-seg_addr_table") == 0 ) {
                        }
                        // ??? Deprecate when we get rid of basing at build time.
                        else if ( strcmp(arg, "-seg_addr_table") == 0 ) {
@@ -2370,6 +2678,7 @@ void Options::parse(int argc, const char* argv[])
                                if ( name == NULL )
                                        throw "-seg_addr_table missing argument";
                                fSegAddrTablePath = name;
                                if ( name == NULL )
                                        throw "-seg_addr_table missing argument";
                                fSegAddrTablePath = name;
+                               cannotBeUsedWithBitcode(arg);
                        }
                        else if ( strcmp(arg, "-seg_addr_table_filename") == 0 ) {
                                warnObsolete(arg);
                        }
                        else if ( strcmp(arg, "-seg_addr_table_filename") == 0 ) {
                                warnObsolete(arg);
@@ -2383,6 +2692,7 @@ void Options::parse(int argc, const char* argv[])
                                seg.max = parseProtection(argv[++i]);
                                seg.init = parseProtection(argv[++i]);
                                fCustomSegmentProtections.push_back(seg);
                                seg.max = parseProtection(argv[++i]);
                                seg.init = parseProtection(argv[++i]);
                                fCustomSegmentProtections.push_back(seg);
+                               cannotBeUsedWithBitcode(arg);
                        }
                        else if ( strcmp(arg, "-pagezero_size") == 0 ) {
                                 const char* size = argv[++i];
                        }
                        else if ( strcmp(arg, "-pagezero_size") == 0 ) {
                                 const char* size = argv[++i];
@@ -2393,12 +2703,14 @@ void Options::parse(int argc, const char* argv[])
                                if ( (fZeroPageSize != temp)  )
                                        warning("-pagezero_size not page aligned, rounding down");
                                 fZeroPageSize = temp;
                                if ( (fZeroPageSize != temp)  )
                                        warning("-pagezero_size not page aligned, rounding down");
                                 fZeroPageSize = temp;
+                               cannotBeUsedWithBitcode(arg);
                        }
                        else if ( strcmp(arg, "-stack_addr") == 0 ) {
                                 const char* address = argv[++i];
                                 if ( address == NULL )
                                        throw "-stack_addr missing <address>";
                                fStackAddr = parseAddress(address);
                        }
                        else if ( strcmp(arg, "-stack_addr") == 0 ) {
                                 const char* address = argv[++i];
                                 if ( address == NULL )
                                        throw "-stack_addr missing <address>";
                                fStackAddr = parseAddress(address);
+                               cannotBeUsedWithBitcode(arg);
                        }
                        else if ( strcmp(arg, "-stack_size") == 0 ) {
                                 const char* size = argv[++i];
                        }
                        else if ( strcmp(arg, "-stack_size") == 0 ) {
                                 const char* size = argv[++i];
@@ -2411,15 +2723,18 @@ void Options::parse(int argc, const char* argv[])
                        }
                        else if ( strcmp(arg, "-allow_stack_execute") == 0 ) {
                                fExecutableStack = true;
                        }
                        else if ( strcmp(arg, "-allow_stack_execute") == 0 ) {
                                fExecutableStack = true;
+                               cannotBeUsedWithBitcode(arg);
                        }
                        else if ( strcmp(arg, "-allow_heap_execute") == 0 ) {
                                fDisableNonExecutableHeap = true;
                        }
                        else if ( strcmp(arg, "-allow_heap_execute") == 0 ) {
                                fDisableNonExecutableHeap = true;
+                               cannotBeUsedWithBitcode(arg);
                        }
                        else if ( strcmp(arg, "-sectalign") == 0 ) {
                                 if ( (argv[i+1]==NULL) || (argv[i+2]==NULL) || (argv[i+3]==NULL) )
                                        throw "-sectalign missing <segment> <section> <file-path>";
                                addSectionAlignment(argv[i+1], argv[i+2], argv[i+3]);
                                i += 3;
                        }
                        else if ( strcmp(arg, "-sectalign") == 0 ) {
                                 if ( (argv[i+1]==NULL) || (argv[i+2]==NULL) || (argv[i+3]==NULL) )
                                        throw "-sectalign missing <segment> <section> <file-path>";
                                addSectionAlignment(argv[i+1], argv[i+2], argv[i+3]);
                                i += 3;
+                               cannotBeUsedWithBitcode(arg);
                        }
                        else if ( strcmp(arg, "-sectorder_detail") == 0 ) {
                                warnObsolete(arg);
                        }
                        else if ( strcmp(arg, "-sectorder_detail") == 0 ) {
                                warnObsolete(arg);
@@ -2475,6 +2790,24 @@ void Options::parse(int argc, const char* argv[])
                                setIOSVersionMin(argv[++i]);
                                fTargetIOSSimulator = true;
                        }
                                setIOSVersionMin(argv[++i]);
                                fTargetIOSSimulator = true;
                        }
+                       else if ( strcmp(arg, "-watchos_version_min") == 0 ) {
+                               setWatchOSVersionMin(argv[++i]);
+                       }
+                       else if ( strcmp(arg, "-watchos_simulator_version_min") == 0 ) {
+                               setWatchOSVersionMin(argv[++i]);
+                               fTargetIOSSimulator = true;
+                       }
+       #if SUPPORT_APPLE_TV
+                       else if ( strcmp(arg, "-tvos_version_min") == 0 ) {
+                               setIOSVersionMin(argv[++i]);
+                               fPlatform = kPlatform_tvOS;
+                       }
+                       else if ( strcmp(arg, "-tvos_simulator_version_min") == 0 ) {
+                               setIOSVersionMin(argv[++i]);
+                               fPlatform = kPlatform_tvOS;
+                               fTargetIOSSimulator = true;
+                       }
+       #endif
                        else if ( strcmp(arg, "-multiply_defined") == 0 ) {
                                //warnObsolete(arg);
                                ++i;
                        else if ( strcmp(arg, "-multiply_defined") == 0 ) {
                                //warnObsolete(arg);
                                ++i;
@@ -2515,12 +2848,14 @@ void Options::parse(int argc, const char* argv[])
                                if ( name == NULL )
                                        throw "-u missing argument";
                                fInitialUndefines.push_back(name);
                                if ( name == NULL )
                                        throw "-u missing argument";
                                fInitialUndefines.push_back(name);
+                               cannotBeUsedWithBitcode(arg);
                        }
                        else if ( strcmp(arg, "-U") == 0 ) {
                                const char* name = argv[++i];
                                if ( name == NULL )
                                        throw "-U missing argument";
                                fAllowedUndefined.insert(name);
                        }
                        else if ( strcmp(arg, "-U") == 0 ) {
                                const char* name = argv[++i];
                                if ( name == NULL )
                                        throw "-U missing argument";
                                fAllowedUndefined.insert(name);
+                               cannotBeUsedWithBitcode(arg);
                        }
                        else if ( strcmp(arg, "-s") == 0 ) {
                                warnObsolete(arg);
                        }
                        else if ( strcmp(arg, "-s") == 0 ) {
                                warnObsolete(arg);
@@ -2573,9 +2908,15 @@ void Options::parse(int argc, const char* argv[])
                                if ( size == NULL )
                                        throw "-headerpad missing argument";
                                 fMinimumHeaderPad = parseAddress(size);
                                if ( size == NULL )
                                        throw "-headerpad missing argument";
                                 fMinimumHeaderPad = parseAddress(size);
+                               cannotBeUsedWithBitcode(arg);
                        }
                        else if ( strcmp(arg, "-headerpad_max_install_names") == 0 ) {
                        }
                        else if ( strcmp(arg, "-headerpad_max_install_names") == 0 ) {
-                               fMaxMinimumHeaderPad = true;
+                               // ignore -headerpad_max_install_names when compiling with bitcode
+                               // rdar://problem/20748962
+                               if ( fBundleBitcode )
+                                       warning("-headerpad_max_install_names is ignored when used with -bitcode_bundle (Xcode setting ENABLE_BITCODE=YES)");
+                               else
+                                       fMaxMinimumHeaderPad = true;
                        }
                        else if ( strcmp(arg, "-t") == 0 ) {
                                fLogAllFiles = true;
                        }
                        else if ( strcmp(arg, "-t") == 0 ) {
                                fLogAllFiles = true;
@@ -2592,6 +2933,7 @@ void Options::parse(int argc, const char* argv[])
                                if ( name == NULL )
                                        throw "-umbrella missing argument";
                                fUmbrellaName = name;
                                if ( name == NULL )
                                        throw "-umbrella missing argument";
                                fUmbrellaName = name;
+                               cannotBeUsedWithBitcode(arg);
                        }
                        else if ( strcmp(arg, "-allowable_client") == 0 ) {
                                const char* name = argv[++i];
                        }
                        else if ( strcmp(arg, "-allowable_client") == 0 ) {
                                const char* name = argv[++i];
@@ -2600,6 +2942,7 @@ void Options::parse(int argc, const char* argv[])
                                        throw "-allowable_client missing argument";
 
                                fAllowableClients.push_back(name);
                                        throw "-allowable_client missing argument";
 
                                fAllowableClients.push_back(name);
+                               cannotBeUsedWithBitcode(arg);
                        }
                        else if ( strcmp(arg, "-client_name") == 0 ) {
                                const char* name = argv[++i];
                        }
                        else if ( strcmp(arg, "-client_name") == 0 ) {
                                const char* name = argv[++i];
@@ -2608,30 +2951,35 @@ void Options::parse(int argc, const char* argv[])
                                        throw "-client_name missing argument";
 
                                fClientName = name;
                                        throw "-client_name missing argument";
 
                                fClientName = name;
+                               cannotBeUsedWithBitcode(arg);
                        }
                        else if ( strcmp(arg, "-sub_umbrella") == 0 ) {
                                const char* name = argv[++i];
                                if ( name == NULL )
                                        throw "-sub_umbrella missing argument";
                                 fSubUmbellas.push_back(name);
                        }
                        else if ( strcmp(arg, "-sub_umbrella") == 0 ) {
                                const char* name = argv[++i];
                                if ( name == NULL )
                                        throw "-sub_umbrella missing argument";
                                 fSubUmbellas.push_back(name);
+                               cannotBeUsedWithBitcode(arg);
                        }
                        else if ( strcmp(arg, "-sub_library") == 0 ) {
                                const char* name = argv[++i];
                                if ( name == NULL )
                                        throw "-sub_library missing argument";
                                 fSubLibraries.push_back(name);
                        }
                        else if ( strcmp(arg, "-sub_library") == 0 ) {
                                const char* name = argv[++i];
                                if ( name == NULL )
                                        throw "-sub_library missing argument";
                                 fSubLibraries.push_back(name);
+                               cannotBeUsedWithBitcode(arg);
                        }
                        else if ( strcmp(arg, "-init") == 0 ) {
                                const char* name = argv[++i];
                                if ( name == NULL )
                                        throw "-init missing argument";
                                fInitFunctionName = name;
                        }
                        else if ( strcmp(arg, "-init") == 0 ) {
                                const char* name = argv[++i];
                                if ( name == NULL )
                                        throw "-init missing argument";
                                fInitFunctionName = name;
+                               cannotBeUsedWithBitcode(arg);
                        }
                        else if ( strcmp(arg, "-dot") == 0 ) {
                                const char* name = argv[++i];
                                if ( name == NULL )
                                        throw "-dot missing argument";
                                fDotOutputFile = name;
                        }
                        else if ( strcmp(arg, "-dot") == 0 ) {
                                const char* name = argv[++i];
                                if ( name == NULL )
                                        throw "-dot missing argument";
                                fDotOutputFile = name;
+                               cannotBeUsedWithBitcode(arg);
                        }
                        else if ( strcmp(arg, "-warn_commons") == 0 ) {
                                fWarnCommons = true;
                        }
                        else if ( strcmp(arg, "-warn_commons") == 0 ) {
                                fWarnCommons = true;
@@ -2665,11 +3013,17 @@ void Options::parse(int argc, const char* argv[])
                                ++i;
                                // previously handled by buildSearchPaths()
                        }
                                ++i;
                                // previously handled by buildSearchPaths()
                        }
+                       else if ( strcmp(arg, "-bitcode_bundle") == 0 ) {
+                               snapshotArgCount = 0;
+                               // previously handled by buildSearchPaths()
+                       }
                        else if ( strcmp(arg, "-no_uuid") == 0 ) {
                                fUUIDMode = kUUIDNone;
                        else if ( strcmp(arg, "-no_uuid") == 0 ) {
                                fUUIDMode = kUUIDNone;
+                               cannotBeUsedWithBitcode(arg);
                        }
                        else if ( strcmp(arg, "-random_uuid") == 0 ) {
                                fUUIDMode = kUUIDRandom;
                        }
                        else if ( strcmp(arg, "-random_uuid") == 0 ) {
                                fUUIDMode = kUUIDRandom;
+                               cannotBeUsedWithBitcode(arg);
                        }
                        else if ( strcmp(arg, "-dtrace") == 0 ) {
                 snapshotFileArgIndex = 1;
                        }
                        else if ( strcmp(arg, "-dtrace") == 0 ) {
                 snapshotFileArgIndex = 1;
@@ -2677,6 +3031,7 @@ void Options::parse(int argc, const char* argv[])
                                if ( name == NULL )
                                        throw "-dtrace missing argument";
                                fDtraceScriptName = name;
                                if ( name == NULL )
                                        throw "-dtrace missing argument";
                                fDtraceScriptName = name;
+                               cannotBeUsedWithBitcode(arg);
                        }
                        else if ( strcmp(arg, "-root_safe") == 0 ) {
                                fRootSafe = true;
                        }
                        else if ( strcmp(arg, "-root_safe") == 0 ) {
                                fRootSafe = true;
@@ -2693,14 +3048,45 @@ void Options::parse(int argc, const char* argv[])
                                if ( pair.alias == NULL )
                                        throw "missing argument to -alias";
                                fAliases.push_back(pair);
                                if ( pair.alias == NULL )
                                        throw "missing argument to -alias";
                                fAliases.push_back(pair);
+                               cannotBeUsedWithBitcode(arg);
                        }
                        else if ( strcmp(arg, "-alias_list") == 0 ) {
                 snapshotFileArgIndex = 1;
                                parseAliasFile(argv[++i]);
                        }
                        else if ( strcmp(arg, "-alias_list") == 0 ) {
                 snapshotFileArgIndex = 1;
                                parseAliasFile(argv[++i]);
+                               cannotBeUsedWithBitcode(arg);
                        }
                        else if ( strcmp(arg, "-save-temps") == 0 ) {
                                fSaveTempFiles = true;
                        }
                        }
                        else if ( strcmp(arg, "-save-temps") == 0 ) {
                                fSaveTempFiles = true;
                        }
+                       else if ( strcmp(arg, "-bitcode_hide_symbols") == 0 ) {
+                               fHideSymbols = true;
+                               if ( !fBundleBitcode )
+                                       warning("-bitcode_hide_symbols is ignored without -bitcode_bundle");
+                       }
+                       else if ( strcmp(arg, "-bitcode_symbol_map") == 0) {
+                               fReverseMapPath = argv[++i];
+                               if ( fReverseMapPath == NULL )
+                                       throw "missing argument to -bitcode_symbol_map";
+                               struct stat statbuf;
+                               ::stat(fReverseMapPath, &statbuf);
+                               if (S_ISDIR(statbuf.st_mode)) {
+                                       char tempPath[PATH_MAX];
+                                       sprintf(tempPath, "%s/XXXXXX", fReverseMapPath);
+                                       int tempFile = ::mkstemp(tempPath);
+                                       if (tempFile == -1)
+                                               throwf("could not write file to symbol map directory: %s", fReverseMapPath);
+                                       ::close(tempFile);
+                                       fReverseMapTempPath = std::string(tempPath);
+                                       fReverseMapUUIDRename = true;
+                               } else
+                                       fReverseMapTempPath = std::string(fReverseMapPath);
+                       }
+                       else if ( strcmp(argv[i], "-flto-codegen-only") == 0) {
+                               fLTOCodegenOnly = true;
+                       }
+                       else if ( strcmp(argv[i], "-ignore_auto_link") == 0) {
+                               fIgnoreAutoLink = true;
+                       }
                        else if ( strcmp(arg, "-rpath") == 0 ) {
                                const char* path = argv[++i];
                                if ( path == NULL )
                        else if ( strcmp(arg, "-rpath") == 0 ) {
                                const char* path = argv[++i];
                                if ( path == NULL )
@@ -2724,6 +3110,7 @@ void Options::parse(int argc, const char* argv[])
                        }
                        else if ( strcmp(arg, "-no_pie") == 0 ) {
                                fDisablePositionIndependentExecutable = true;
                        }
                        else if ( strcmp(arg, "-no_pie") == 0 ) {
                                fDisablePositionIndependentExecutable = true;
+                               cannotBeUsedWithBitcode(arg);
                        }
                        else if ( strncmp(arg, "-reexport-l", 11) == 0 ) {
                 // SNAPSHOT FIXME: what should we do for link snapshots? (ignore for now)
                        }
                        else if ( strncmp(arg, "-reexport-l", 11) == 0 ) {
                 // SNAPSHOT FIXME: what should we do for link snapshots? (ignore for now)
@@ -2732,6 +3119,7 @@ void Options::parse(int argc, const char* argv[])
                                info.options.fReExport = true;
                                info.ordinal = ld::File::Ordinal::makeArgOrdinal((uint16_t)i);
                                addLibrary(info);
                                info.options.fReExport = true;
                                info.ordinal = ld::File::Ordinal::makeArgOrdinal((uint16_t)i);
                                addLibrary(info);
+                               cannotBeUsedWithBitcode(arg);
                        }
                        else if ( strcmp(arg, "-reexport_library") == 0 ) {
                 // SNAPSHOT FIXME: what should we do for link snapshots? (ignore for now)
                        }
                        else if ( strcmp(arg, "-reexport_library") == 0 ) {
                 // SNAPSHOT FIXME: what should we do for link snapshots? (ignore for now)
@@ -2740,6 +3128,7 @@ void Options::parse(int argc, const char* argv[])
                                info.options.fReExport = true;
                                info.ordinal = ld::File::Ordinal::makeArgOrdinal((uint16_t)i);
                                addLibrary(info);
                                info.options.fReExport = true;
                                info.ordinal = ld::File::Ordinal::makeArgOrdinal((uint16_t)i);
                                addLibrary(info);
+                               cannotBeUsedWithBitcode(arg);
                        }
                        else if ( strcmp(arg, "-reexport_framework") == 0 ) {
                 // SNAPSHOT FIXME: what should we do for link snapshots? (ignore for now)
                        }
                        else if ( strcmp(arg, "-reexport_framework") == 0 ) {
                 // SNAPSHOT FIXME: what should we do for link snapshots? (ignore for now)
@@ -2748,6 +3137,7 @@ void Options::parse(int argc, const char* argv[])
                                info.options.fReExport = true;
                                info.ordinal = ld::File::Ordinal::makeArgOrdinal((uint16_t)i);
                                addLibrary(info);
                                info.options.fReExport = true;
                                info.ordinal = ld::File::Ordinal::makeArgOrdinal((uint16_t)i);
                                addLibrary(info);
+                               cannotBeUsedWithBitcode(arg);
                        }
                        else if ( strncmp(arg, "-upward-l", 9) == 0 ) {
                 // SNAPSHOT FIXME: what should we do for link snapshots? (ignore for now)
                        }
                        else if ( strncmp(arg, "-upward-l", 9) == 0 ) {
                 // SNAPSHOT FIXME: what should we do for link snapshots? (ignore for now)
@@ -2756,6 +3146,7 @@ void Options::parse(int argc, const char* argv[])
                                info.options.fUpward = true;
                                info.ordinal = ld::File::Ordinal::makeArgOrdinal((uint16_t)i);
                                addLibrary(info);
                                info.options.fUpward = true;
                                info.ordinal = ld::File::Ordinal::makeArgOrdinal((uint16_t)i);
                                addLibrary(info);
+                               cannotBeUsedWithBitcode(arg);
                        }
                        else if ( strcmp(arg, "-upward_library") == 0 ) {
                 // SNAPSHOT FIXME: what should we do for link snapshots? (ignore for now)
                        }
                        else if ( strcmp(arg, "-upward_library") == 0 ) {
                 // SNAPSHOT FIXME: what should we do for link snapshots? (ignore for now)
@@ -2764,6 +3155,7 @@ void Options::parse(int argc, const char* argv[])
                                info.options.fUpward = true;
                                info.ordinal = ld::File::Ordinal::makeArgOrdinal((uint16_t)i);
                                addLibrary(info);
                                info.options.fUpward = true;
                                info.ordinal = ld::File::Ordinal::makeArgOrdinal((uint16_t)i);
                                addLibrary(info);
+                               cannotBeUsedWithBitcode(arg);
                        }
                        else if ( strcmp(arg, "-upward_framework") == 0 ) {
                 // SNAPSHOT FIXME: what should we do for link snapshots? (ignore for now)
                        }
                        else if ( strcmp(arg, "-upward_framework") == 0 ) {
                 // SNAPSHOT FIXME: what should we do for link snapshots? (ignore for now)
@@ -2772,9 +3164,11 @@ void Options::parse(int argc, const char* argv[])
                                info.options.fUpward = true;
                                info.ordinal = ld::File::Ordinal::makeArgOrdinal((uint16_t)i);
                                addLibrary(info);
                                info.options.fUpward = true;
                                info.ordinal = ld::File::Ordinal::makeArgOrdinal((uint16_t)i);
                                addLibrary(info);
+                               cannotBeUsedWithBitcode(arg);
                        }
                        else if ( strcmp(arg, "-dead_strip_dylibs") == 0 ) {
                                fDeadStripDylibs = true;
                        }
                        else if ( strcmp(arg, "-dead_strip_dylibs") == 0 ) {
                                fDeadStripDylibs = true;
+                               cannotBeUsedWithBitcode(arg);
                        }
                        else if ( strcmp(arg, "-no_implicit_dylibs") == 0 ) {
                                fImplicitlyLinkPublicDylibs = false;
                        }
                        else if ( strcmp(arg, "-no_implicit_dylibs") == 0 ) {
                                fImplicitlyLinkPublicDylibs = false;
@@ -2783,28 +3177,38 @@ void Options::parse(int argc, const char* argv[])
                                // ignore
                        }
                        else if ( strcmp(arg, "-no_encryption") == 0 ) {
                                // ignore
                        }
                        else if ( strcmp(arg, "-no_encryption") == 0 ) {
-                               fEncryptable = false;
+                               fEncryptableForceOff = true;
+                               cannotBeUsedWithBitcode(arg);
+                       }
+                       else if ( strcmp(arg, "-encryptable") == 0 ) {
+                               fEncryptableForceOn = true;
+                               cannotBeUsedWithBitcode(arg);
                        }
                        else if ( strcmp(arg, "-no_compact_unwind") == 0 ) {
                                fAddCompactUnwindEncoding = false;
                        }
                        else if ( strcmp(arg, "-no_compact_unwind") == 0 ) {
                                fAddCompactUnwindEncoding = false;
+                               cannotBeUsedWithBitcode(arg);
                        }
                        else if ( strcmp(arg, "-mllvm") == 0 ) {
                                const char* opts = argv[++i];
                                if ( opts == NULL )
                                        throw "missing argument to -mllvm";
                                fLLVMOptions.push_back(opts);
                        }
                        else if ( strcmp(arg, "-mllvm") == 0 ) {
                                const char* opts = argv[++i];
                                if ( opts == NULL )
                                        throw "missing argument to -mllvm";
                                fLLVMOptions.push_back(opts);
+                               cannotBeUsedWithBitcode(arg);
                        }
                        else if ( strcmp(arg, "-mcpu") == 0 ) {
                                const char* cpu = argv[++i];
                                if ( cpu == NULL )
                                        throw "missing argument to -mcpu";
                                fLtoCpu = cpu;
                        }
                        else if ( strcmp(arg, "-mcpu") == 0 ) {
                                const char* cpu = argv[++i];
                                if ( cpu == NULL )
                                        throw "missing argument to -mcpu";
                                fLtoCpu = cpu;
+                               cannotBeUsedWithBitcode(arg);
                        }
                        else if ( strcmp(arg, "-no_order_inits") == 0 ) {
                                fAutoOrderInitializers = false;
                        }
                        else if ( strcmp(arg, "-no_order_inits") == 0 ) {
                                fAutoOrderInitializers = false;
+                               cannotBeUsedWithBitcode(arg);
                        }
                        else if ( strcmp(arg, "-no_order_data") == 0 ) {
                                fOrderData = false;
                        }
                        else if ( strcmp(arg, "-no_order_data") == 0 ) {
                                fOrderData = false;
+                               cannotBeUsedWithBitcode(arg);
                        }
                        else if ( strcmp(arg, "-seg_page_size") == 0 ) {
                                SegmentSize seg;
                        }
                        else if ( strcmp(arg, "-seg_page_size") == 0 ) {
                                SegmentSize seg;
@@ -2816,31 +3220,38 @@ void Options::parse(int argc, const char* argv[])
                                if ( (seg.size != temp)  )
                                        warning("-seg_page_size %s not 4K aligned, rounding down", seg.name);
                                fCustomSegmentSizes.push_back(seg);
                                if ( (seg.size != temp)  )
                                        warning("-seg_page_size %s not 4K aligned, rounding down", seg.name);
                                fCustomSegmentSizes.push_back(seg);
+                               cannotBeUsedWithBitcode(arg);
                        }
                        else if ( strcmp(arg, "-mark_dead_strippable_dylib") == 0 ) {
                                fMarkDeadStrippableDylib = true;
                        }
                        else if ( strcmp(arg, "-mark_dead_strippable_dylib") == 0 ) {
                                fMarkDeadStrippableDylib = true;
+                               cannotBeUsedWithBitcode(arg);
                        }
                        else if ( strcmp(arg, "-exported_symbols_order") == 0 ) {
                 snapshotFileArgIndex = 1;
                                loadSymbolOrderFile(argv[++i], fExportSymbolsOrder);
                        }
                        else if ( strcmp(arg, "-exported_symbols_order") == 0 ) {
                 snapshotFileArgIndex = 1;
                                loadSymbolOrderFile(argv[++i], fExportSymbolsOrder);
+                               cannotBeUsedWithBitcode(arg);
                        }
                        else if ( strcmp(arg, "-no_compact_linkedit") == 0 ) {
                                warnObsolete("-no_compact_linkedit");
                        }
                        else if ( strcmp(arg, "-no_eh_labels") == 0 ) {
                                fNoEHLabels = true;
                        }
                        else if ( strcmp(arg, "-no_compact_linkedit") == 0 ) {
                                warnObsolete("-no_compact_linkedit");
                        }
                        else if ( strcmp(arg, "-no_eh_labels") == 0 ) {
                                fNoEHLabels = true;
+                               cannotBeUsedWithBitcode(arg);
                        }
                        else if ( strcmp(arg, "-warn_compact_unwind") == 0 ) {
                                fWarnCompactUnwind = true;
                        }
                        else if ( strcmp(arg, "-allow_sub_type_mismatches") == 0 ) {
                                fAllowCpuSubtypeMismatches = true;
                        }
                        else if ( strcmp(arg, "-warn_compact_unwind") == 0 ) {
                                fWarnCompactUnwind = true;
                        }
                        else if ( strcmp(arg, "-allow_sub_type_mismatches") == 0 ) {
                                fAllowCpuSubtypeMismatches = true;
+                               cannotBeUsedWithBitcode(arg);
                        }
                        else if ( strcmp(arg, "-no_zero_fill_sections") == 0 ) {
                                fOptimizeZeroFill = false;
                        }
                        else if ( strcmp(arg, "-no_zero_fill_sections") == 0 ) {
                                fOptimizeZeroFill = false;
+                               cannotBeUsedWithBitcode(arg);
                        }
                        else if ( strcmp(arg, "-merge_zero_fill_sections") == 0 ) {
                                fMergeZeroFill = true;
                        }
                        else if ( strcmp(arg, "-merge_zero_fill_sections") == 0 ) {
                                fMergeZeroFill = true;
+                               cannotBeUsedWithBitcode(arg);
                        }
                        else if ( strcmp(arg, "-objc_abi_version") == 0 ) {
                                const char* version = argv[++i];
                        }
                        else if ( strcmp(arg, "-objc_abi_version") == 0 ) {
                                const char* version = argv[++i];
@@ -2862,6 +3273,7 @@ void Options::parse(int argc, const char* argv[])
                        }
                        else if ( strcmp(arg, "-objc_gc_compaction") == 0 ) {
                                fObjcGcCompaction = true;
                        }
                        else if ( strcmp(arg, "-objc_gc_compaction") == 0 ) {
                                fObjcGcCompaction = true;
+                               cannotBeUsedWithBitcode(arg);
                        }
                        else if ( strcmp(arg, "-objc_gc") == 0 ) {
                                fObjCGc = true;
                        }
                        else if ( strcmp(arg, "-objc_gc") == 0 ) {
                                fObjCGc = true;
@@ -2869,6 +3281,7 @@ void Options::parse(int argc, const char* argv[])
                                        warning("-objc_gc overriding -objc_gc_only");
                                        fObjCGcOnly = false;    
                                }
                                        warning("-objc_gc overriding -objc_gc_only");
                                        fObjCGcOnly = false;    
                                }
+                               cannotBeUsedWithBitcode(arg);
                        }
                        else if ( strcmp(arg, "-objc_gc_only") == 0 ) {
                                fObjCGcOnly = true;
                        }
                        else if ( strcmp(arg, "-objc_gc_only") == 0 ) {
                                fObjCGcOnly = true;
@@ -2876,6 +3289,7 @@ void Options::parse(int argc, const char* argv[])
                                        warning("-objc_gc_only overriding -objc_gc");
                                        fObjCGc = false;        
                                }
                                        warning("-objc_gc_only overriding -objc_gc");
                                        fObjCGc = false;        
                                }
+                               cannotBeUsedWithBitcode(arg);
                        }
                        else if ( strcmp(arg, "-demangle") == 0 ) {
                                fDemangle = true;
                        }
                        else if ( strcmp(arg, "-demangle") == 0 ) {
                                fDemangle = true;
@@ -2887,6 +3301,7 @@ void Options::parse(int argc, const char* argv[])
                        else if ( strcmp(arg, "-no_version_load_command") == 0 ) {
                                fVersionLoadCommandForcedOff = true;
                                fVersionLoadCommandForcedOn = false;
                        else if ( strcmp(arg, "-no_version_load_command") == 0 ) {
                                fVersionLoadCommandForcedOff = true;
                                fVersionLoadCommandForcedOn = false;
+                               cannotBeUsedWithBitcode(arg);
                        }
                        else if ( strcmp(arg, "-function_starts") == 0 ) {
                                fFunctionStartsForcedOn = true;
                        }
                        else if ( strcmp(arg, "-function_starts") == 0 ) {
                                fFunctionStartsForcedOn = true;
@@ -2895,10 +3310,12 @@ void Options::parse(int argc, const char* argv[])
                        else if ( strcmp(arg, "-no_function_starts") == 0 ) {
                                fFunctionStartsForcedOff = true;
                                fFunctionStartsForcedOn = false;
                        else if ( strcmp(arg, "-no_function_starts") == 0 ) {
                                fFunctionStartsForcedOff = true;
                                fFunctionStartsForcedOn = false;
+                               cannotBeUsedWithBitcode(arg);
                        }
                        else if ( strcmp(arg, "-no_data_in_code_info") == 0 ) {
                                fDataInCodeInfoLoadCommandForcedOff = true;
                                fDataInCodeInfoLoadCommandForcedOn = false;
                        }
                        else if ( strcmp(arg, "-no_data_in_code_info") == 0 ) {
                                fDataInCodeInfoLoadCommandForcedOff = true;
                                fDataInCodeInfoLoadCommandForcedOn = false;
+                               cannotBeUsedWithBitcode(arg);
                        }
                        else if ( strcmp(arg, "-data_in_code_info") == 0 ) {
                                fDataInCodeInfoLoadCommandForcedOn  = true;
                        }
                        else if ( strcmp(arg, "-data_in_code_info") == 0 ) {
                                fDataInCodeInfoLoadCommandForcedOn  = true;
@@ -2915,22 +3332,26 @@ void Options::parse(int argc, const char* argv[])
                        else if ( strcmp(arg, "-force_symbols_weak_list") == 0 ) {
                 snapshotFileArgIndex = 1;
                                loadExportFile(argv[++i], "-force_symbols_weak_list", fForceWeakSymbols);
                        else if ( strcmp(arg, "-force_symbols_weak_list") == 0 ) {
                 snapshotFileArgIndex = 1;
                                loadExportFile(argv[++i], "-force_symbols_weak_list", fForceWeakSymbols);
+                               cannotBeUsedWithBitcode(arg);
                        }
                        else if ( strcmp(arg, "-force_symbols_not_weak_list") == 0 ) {
                 snapshotFileArgIndex = 1;
                                loadExportFile(argv[++i], "-force_symbols_not_weak_list", fForceNotWeakSymbols);
                        }
                        else if ( strcmp(arg, "-force_symbols_not_weak_list") == 0 ) {
                 snapshotFileArgIndex = 1;
                                loadExportFile(argv[++i], "-force_symbols_not_weak_list", fForceNotWeakSymbols);
+                               cannotBeUsedWithBitcode(arg);
                        }
                        else if ( strcmp(arg, "-force_symbol_weak") == 0 ) {
                                const char* symbol = argv[++i];
                                if ( symbol == NULL )
                                        throw "-force_symbol_weak missing <symbol>";
                                fForceWeakSymbols.insert(symbol);
                        }
                        else if ( strcmp(arg, "-force_symbol_weak") == 0 ) {
                                const char* symbol = argv[++i];
                                if ( symbol == NULL )
                                        throw "-force_symbol_weak missing <symbol>";
                                fForceWeakSymbols.insert(symbol);
+                               cannotBeUsedWithBitcode(arg);
                        }
                        else if ( strcmp(arg, "-force_symbol_not_weak") == 0 ) {
                                const char* symbol = argv[++i];
                                if ( symbol == NULL )
                                        throw "-force_symbol_not_weak missing <symbol>";
                                fForceNotWeakSymbols.insert(symbol);
                        }
                        else if ( strcmp(arg, "-force_symbol_not_weak") == 0 ) {
                                const char* symbol = argv[++i];
                                if ( symbol == NULL )
                                        throw "-force_symbol_not_weak missing <symbol>";
                                fForceNotWeakSymbols.insert(symbol);
+                               cannotBeUsedWithBitcode(arg);
                        }
                        else if ( strcmp(arg, "-reexported_symbols_list") == 0 ) {
                 snapshotFileArgIndex = 1;
                        }
                        else if ( strcmp(arg, "-reexported_symbols_list") == 0 ) {
                 snapshotFileArgIndex = 1;
@@ -2945,13 +3366,16 @@ void Options::parse(int argc, const char* argv[])
                                if ( strchr(envarg, '=') == NULL )
                                        throw "-dyld_env missing ENV=VALUE";
                                fDyldEnvironExtras.push_back(envarg);
                                if ( strchr(envarg, '=') == NULL )
                                        throw "-dyld_env missing ENV=VALUE";
                                fDyldEnvironExtras.push_back(envarg);
+                               cannotBeUsedWithBitcode(arg);
                        }
                        else if ( strcmp(arg, "-page_align_data_atoms") == 0 ) {
                                fPageAlignDataAtoms = true;
                        }
                        else if ( strcmp(arg, "-page_align_data_atoms") == 0 ) {
                                fPageAlignDataAtoms = true;
+                               cannotBeUsedWithBitcode(arg);
                        } 
                        else if (strcmp(arg, "-debug_snapshot") == 0) {
                 fLinkSnapshot.setSnapshotMode(Snapshot::SNAPSHOT_DEBUG);
                 fSnapshotRequested = true;
                        } 
                        else if (strcmp(arg, "-debug_snapshot") == 0) {
                 fLinkSnapshot.setSnapshotMode(Snapshot::SNAPSHOT_DEBUG);
                 fSnapshotRequested = true;
+                               cannotBeUsedWithBitcode(arg);
             }
                        else if (strcmp(arg, "-snapshot_dir") == 0) {
                                const char* path = argv[++i];
             }
                        else if (strcmp(arg, "-snapshot_dir") == 0) {
                                const char* path = argv[++i];
@@ -2960,12 +3384,15 @@ void Options::parse(int argc, const char* argv[])
                                fLinkSnapshot.setSnapshotMode(Snapshot::SNAPSHOT_DEBUG);
                                fLinkSnapshot.setSnapshotPath(path);
                                fSnapshotRequested = true;
                                fLinkSnapshot.setSnapshotMode(Snapshot::SNAPSHOT_DEBUG);
                                fLinkSnapshot.setSnapshotPath(path);
                                fSnapshotRequested = true;
+                               cannotBeUsedWithBitcode(arg);
             }
                        else if ( strcmp(arg, "-new_main") == 0 ) {
                                fEntryPointLoadCommandForceOn = true;
             }
                        else if ( strcmp(arg, "-new_main") == 0 ) {
                                fEntryPointLoadCommandForceOn = true;
+                               cannotBeUsedWithBitcode(arg);
                        }
                        else if ( strcmp(arg, "-no_new_main") == 0 ) {
                                fEntryPointLoadCommandForceOff = true;
                        }
                        else if ( strcmp(arg, "-no_new_main") == 0 ) {
                                fEntryPointLoadCommandForceOff = true;
+                               cannotBeUsedWithBitcode(arg);
                        }
                        else if ( strcmp(arg, "-source_version") == 0 ) {
                                 const char* vers = argv[++i];
                        }
                        else if ( strcmp(arg, "-source_version") == 0 ) {
                                 const char* vers = argv[++i];
@@ -2978,6 +3405,7 @@ void Options::parse(int argc, const char* argv[])
                        }
                        else if ( strcmp(arg, "-no_source_version") == 0 ) {
                                fSourceVersionLoadCommandForceOff = true;
                        }
                        else if ( strcmp(arg, "-no_source_version") == 0 ) {
                                fSourceVersionLoadCommandForceOff = true;
+                               cannotBeUsedWithBitcode(arg);
                        }
                        else if ( strcmp(arg, "-sdk_version") == 0 ) {
                                 const char* vers = argv[++i];
                        }
                        else if ( strcmp(arg, "-sdk_version") == 0 ) {
                                 const char* vers = argv[++i];
@@ -2986,13 +3414,14 @@ void Options::parse(int argc, const char* argv[])
                                fSDKVersion = parseVersionNumber32(vers);
                        }
                        else if ( strcmp(arg, "-dependent_dr_info") == 0 ) {
                                fSDKVersion = parseVersionNumber32(vers);
                        }
                        else if ( strcmp(arg, "-dependent_dr_info") == 0 ) {
-                               fDependentDRInfoForcedOn = true;
+                               warnObsolete(arg);
                        }
                        else if ( strcmp(arg, "-no_dependent_dr_info") == 0 ) {
                        }
                        else if ( strcmp(arg, "-no_dependent_dr_info") == 0 ) {
-                               fDependentDRInfoForcedOff = true;
+                               warnObsolete(arg);
                        }
                        else if ( strcmp(arg, "-kexts_use_stubs") == 0 ) {
                                fKextsUseStubs = true;
                        }
                        else if ( strcmp(arg, "-kexts_use_stubs") == 0 ) {
                                fKextsUseStubs = true;
+                               cannotBeUsedWithBitcode(arg);
                        }
                        else if ( strcmp(argv[i], "-dependency_info") == 0 ) {
                 snapshotArgCount = 0;
                        }
                        else if ( strcmp(argv[i], "-dependency_info") == 0 ) {
                 snapshotArgCount = 0;
@@ -3027,23 +3456,28 @@ void Options::parse(int argc, const char* argv[])
                                        }
                                }
                                fLinkerOptions.push_back(opts);
                                        }
                                }
                                fLinkerOptions.push_back(opts);
+                               cannotBeUsedWithBitcode(arg);
                        }
                        else if ( strcmp(arg, "-allow_simulator_linking_to_macosx_dylibs") == 0 ) {
                                fAllowSimulatorToLinkWithMacOSX = true;
                        }
                        else if ( strcmp(arg, "-allow_simulator_linking_to_macosx_dylibs") == 0 ) {
                                fAllowSimulatorToLinkWithMacOSX = true;
+                               cannotBeUsedWithBitcode(arg);
                        }
                        else if ( strcmp(arg, "-keep_dwarf_unwind") == 0 ) {
                                fKeepDwarfUnwindForcedOn = true;
                                fKeepDwarfUnwindForcedOff = false;
                        }
                        else if ( strcmp(arg, "-keep_dwarf_unwind") == 0 ) {
                                fKeepDwarfUnwindForcedOn = true;
                                fKeepDwarfUnwindForcedOff = false;
+                               cannotBeUsedWithBitcode(arg);
                        }
                        else if ( strcmp(arg, "-no_keep_dwarf_unwind") == 0 ) {
                                fKeepDwarfUnwindForcedOn = false;
                                fKeepDwarfUnwindForcedOff = true;
                        }
                        else if ( strcmp(arg, "-no_keep_dwarf_unwind") == 0 ) {
                                fKeepDwarfUnwindForcedOn = false;
                                fKeepDwarfUnwindForcedOff = true;
+                               cannotBeUsedWithBitcode(arg);
                        }
                        else if ( strcmp(arg, "-verbose_optimization_hints") == 0 ) {
                                fVerboseOptimizationHints = true;
                        }
                        else if ( strcmp(arg, "-ignore_optimization_hints") == 0 ) {
                                fIgnoreOptimizationHints = true;
                        }
                        else if ( strcmp(arg, "-verbose_optimization_hints") == 0 ) {
                                fVerboseOptimizationHints = true;
                        }
                        else if ( strcmp(arg, "-ignore_optimization_hints") == 0 ) {
                                fIgnoreOptimizationHints = true;
+                               cannotBeUsedWithBitcode(arg);
                        }
                        else if ( strcmp(arg, "-no_dtrace_dof") == 0 ) {
                                fGenerateDtraceDOF = false;
                        }
                        else if ( strcmp(arg, "-no_dtrace_dof") == 0 ) {
                                fGenerateDtraceDOF = false;
@@ -3053,30 +3487,35 @@ void Options::parse(int argc, const char* argv[])
                                        throw "-rename_section missing <segment> <section> <segment> <section>";
                                addSectionRename(argv[i+1], argv[i+2], argv[i+3], argv[i+4]);
                                i += 4;
                                        throw "-rename_section missing <segment> <section> <segment> <section>";
                                addSectionRename(argv[i+1], argv[i+2], argv[i+3], argv[i+4]);
                                i += 4;
+                               cannotBeUsedWithBitcode(arg);
                        }
                        else if ( strcmp(arg, "-rename_segment") == 0 ) {
                                 if ( (argv[i+1]==NULL) || (argv[i+2]==NULL) )
                                        throw "-rename_segment missing <existing-segment> <new-segment>";
                                addSegmentRename(argv[i+1], argv[i+2]);
                                i += 2;
                        }
                        else if ( strcmp(arg, "-rename_segment") == 0 ) {
                                 if ( (argv[i+1]==NULL) || (argv[i+2]==NULL) )
                                        throw "-rename_segment missing <existing-segment> <new-segment>";
                                addSegmentRename(argv[i+1], argv[i+2]);
                                i += 2;
+                               cannotBeUsedWithBitcode(arg);
                        }
                        else if ( strcmp(arg, "-move_to_ro_segment") == 0 ) {
                                 if ( (argv[i+1]==NULL) || (argv[i+2]==NULL) )
                                        throw "-move_to_ro_segment missing <segment> <symbol-list-file>";
                                addSymbolMove(argv[i+1], argv[i+2], fSymbolsMovesCode, "-move_to_ro_segment");
                                i += 2;
                        }
                        else if ( strcmp(arg, "-move_to_ro_segment") == 0 ) {
                                 if ( (argv[i+1]==NULL) || (argv[i+2]==NULL) )
                                        throw "-move_to_ro_segment missing <segment> <symbol-list-file>";
                                addSymbolMove(argv[i+1], argv[i+2], fSymbolsMovesCode, "-move_to_ro_segment");
                                i += 2;
+                               cannotBeUsedWithBitcode(arg);
                        }
                        else if ( strcmp(arg, "-move_to_rw_segment") == 0 ) {
                                 if ( (argv[i+1]==NULL) || (argv[i+2]==NULL) )
                                        throw "-move_to_rw_segment missing <segment> <symbol-list-file>";
                                addSymbolMove(argv[i+1], argv[i+2], fSymbolsMovesData, "-move_to_rw_segment");
                                i += 2;
                        }
                        else if ( strcmp(arg, "-move_to_rw_segment") == 0 ) {
                                 if ( (argv[i+1]==NULL) || (argv[i+2]==NULL) )
                                        throw "-move_to_rw_segment missing <segment> <symbol-list-file>";
                                addSymbolMove(argv[i+1], argv[i+2], fSymbolsMovesData, "-move_to_rw_segment");
                                i += 2;
+                               cannotBeUsedWithBitcode(arg);
                        }
                        else if ( strcmp(arg, "-trace_symbol_layout") == 0 ) {
                                fTraceSymbolLayout = true;
                        }
                        else if ( strcmp(arg, "-no_branch_islands") == 0 ) {
                                fAllowBranchIslands = false;
                        }
                        else if ( strcmp(arg, "-trace_symbol_layout") == 0 ) {
                                fTraceSymbolLayout = true;
                        }
                        else if ( strcmp(arg, "-no_branch_islands") == 0 ) {
                                fAllowBranchIslands = false;
+                               cannotBeUsedWithBitcode(arg);
                        }
                        else if ( strcmp(arg, "-segment_order") == 0 ) {
                                // ex: -segment_order __TEXT:__DATA:__JUNK
                        }
                        else if ( strcmp(arg, "-segment_order") == 0 ) {
                                // ex: -segment_order __TEXT:__DATA:__JUNK
@@ -3099,6 +3538,7 @@ void Options::parse(int argc, const char* argv[])
                                                break;
                                        }
                                }
                                                break;
                                        }
                                }
+                               cannotBeUsedWithBitcode(arg);
                        }
                        else if ( strcmp(arg, "-section_order") == 0 ) {
                                // ex: -section_order __DATA  __data:__const:__nl_pointers
                        }
                        else if ( strcmp(arg, "-section_order") == 0 ) {
                                // ex: -section_order __DATA  __data:__const:__nl_pointers
@@ -3126,6 +3566,7 @@ void Options::parse(int argc, const char* argv[])
                                                break;
                                        }
                                }
                                                break;
                                        }
                                }
+                               cannotBeUsedWithBitcode(arg);
                        }                       
                        else if ( strcmp(arg, "-application_extension") == 0 ) {
                                fMarkAppExtensionSafe = true;
                        }                       
                        else if ( strcmp(arg, "-application_extension") == 0 ) {
                                fMarkAppExtensionSafe = true;
@@ -3144,6 +3585,25 @@ void Options::parse(int argc, const char* argv[])
                        else if ( strcmp(arg, "-force_load_swift_libs") == 0 ) {
                                fForceLoadSwiftLibs = true;
                        }
                        else if ( strcmp(arg, "-force_load_swift_libs") == 0 ) {
                                fForceLoadSwiftLibs = true;
                        }
+                       else if ( strcmp(arg, "-not_for_dyld_shared_cache") == 0 ) {
+                               fSharedRegionEligibleForceOff = true;
+                               cannotBeUsedWithBitcode(arg);
+                       }
+                       else if ( strcmp(arg, "-dirty_data_list") == 0 ) {
+                                if ( argv[i+1] == NULL )
+                                       throw "-dirty_data_list missing <symbol-list-file>";
+                               addSymbolMove("__DATA_DIRTY", argv[i+1], fSymbolsMovesData, "-dirty_data_list");
+                               ++i;
+                               cannotBeUsedWithBitcode(arg);
+                       }
+                       else if ( strcmp(arg, "-data_const") == 0 ) {
+                               fUseDataConstSegmentForceOn = true;
+                               cannotBeUsedWithBitcode(arg);
+                       }
+                       else if ( strcmp(arg, "-no_data_const") == 0 ) {
+                               fUseDataConstSegmentForceOff = true;
+                               cannotBeUsedWithBitcode(arg);
+                       }
                        // put this last so that it does not interfer with other options starting with 'i'
                        else if ( strncmp(arg, "-i", 2) == 0 ) {
                                const char* colon = strchr(arg, ':');
                        // put this last so that it does not interfer with other options starting with 'i'
                        else if ( strncmp(arg, "-i", 2) == 0 ) {
                                const char* colon = strchr(arg, ':');
@@ -3291,6 +3751,9 @@ void Options::buildSearchPaths(int argc, const char* argv[])
                                throw "-dependency_info missing <path>";
                        fDependencyInfoPath = path;
                }
                                throw "-dependency_info missing <path>";
                        fDependencyInfoPath = path;
                }
+               else if ( strcmp(argv[i], "-bitcode_bundle") == 0 ) {
+                       fBundleBitcode = true;
+               }
        }
        int standardLibraryPathsStartIndex = libraryPaths.size();
        int standardFrameworkPathsStartIndex = frameworkPaths.size();
        }
        int standardLibraryPathsStartIndex = libraryPaths.size();
        int standardFrameworkPathsStartIndex = frameworkPaths.size();
@@ -3544,21 +4007,20 @@ void Options::reconfigureDefaults()
        }
 
        // set default min OS version
        }
 
        // set default min OS version
-       if ( (fMacVersionMin == ld::macVersionUnset)
-               && (fIOSVersionMin == ld::iOSVersionUnset) ) {
+       if ( (fMacVersionMin == ld::macVersionUnset) && (fIOSVersionMin == ld::iOSVersionUnset) && (fWatchOSVersionMin == ld::wOSVersionUnset) ) {
                // if neither -macosx_version_min nor -iphoneos_version_min used, try environment variables
                const char* macVers = getenv("MACOSX_DEPLOYMENT_TARGET");
                const char* iPhoneVers = getenv("IPHONEOS_DEPLOYMENT_TARGET");
                const char* iOSVers = getenv("IOS_DEPLOYMENT_TARGET");
                // if neither -macosx_version_min nor -iphoneos_version_min used, try environment variables
                const char* macVers = getenv("MACOSX_DEPLOYMENT_TARGET");
                const char* iPhoneVers = getenv("IPHONEOS_DEPLOYMENT_TARGET");
                const char* iOSVers = getenv("IOS_DEPLOYMENT_TARGET");
-               const char* iOSSimulatorVers = getenv("IOS_SIMULATOR_DEPLOYMENT_TARGET");
-               if ( macVers != NULL ) 
+               const char* wOSVers = getenv("WATCHOS_DEPLOYMENT_TARGET");
+               if ( macVers != NULL )
                        setMacOSXVersionMin(macVers);
                else if ( iPhoneVers != NULL )
                        setIOSVersionMin(iPhoneVers);
                else if ( iOSVers != NULL )
                        setIOSVersionMin(iOSVers);
                        setMacOSXVersionMin(macVers);
                else if ( iPhoneVers != NULL )
                        setIOSVersionMin(iPhoneVers);
                else if ( iOSVers != NULL )
                        setIOSVersionMin(iOSVers);
-               else if ( iOSSimulatorVers != NULL )
-                       setIOSVersionMin(iOSSimulatorVers);
+               else if ( wOSVers != NULL )
+                       setWatchOSVersionMin(wOSVers);
                else {
                        // if still nothing, set default based on architecture
                        switch ( fArchitecture ) {
                else {
                        // if still nothing, set default based on architecture
                        switch ( fArchitecture ) {
@@ -3570,7 +4032,7 @@ void Options::reconfigureDefaults()
                                                setMacOSXVersionMin(DEFAULT_MACOSX_MIN_VERSION);
                        #else
                                                warning("-macosx_version_min not specified, assuming 10.6");
                                                setMacOSXVersionMin(DEFAULT_MACOSX_MIN_VERSION);
                        #else
                                                warning("-macosx_version_min not specified, assuming 10.6");
-                                               fMacVersionMin = ld::mac10_6;
+                                               setMacOSXVersionMin("10.6");
                        #endif          
                                        }
                                        break;
                        #endif          
                                        }
                                        break;
@@ -3580,8 +4042,14 @@ void Options::reconfigureDefaults()
                                                warning("-ios_version_min not specified, assuming " DEFAULT_IPHONEOS_MIN_VERSION);
                                                setIOSVersionMin(DEFAULT_IPHONEOS_MIN_VERSION);
                        #else
                                                warning("-ios_version_min not specified, assuming " DEFAULT_IPHONEOS_MIN_VERSION);
                                                setIOSVersionMin(DEFAULT_IPHONEOS_MIN_VERSION);
                        #else
-                                               warning("-ios_version_min not specified, assuming 6.0");
-                                               setIOSVersionMin("6.0");
+                                               if ( fSubArchitecture == CPU_SUBTYPE_ARM_V7K ) {
+                                                       warning("-watchos_version_min not specified, assuming 2.0");
+                                                       setWatchOSVersionMin("2.0");
+                                               }
+                                               else {
+                                                       warning("-ios_version_min not specified, assuming 6.0");
+                                                       setIOSVersionMin("6.0");
+                                               }
                        #endif
                                        }
                                        break;
                        #endif
                                        }
                                        break;
@@ -3596,19 +4064,19 @@ void Options::reconfigureDefaults()
        // adjust min based on architecture
        switch ( fArchitecture ) {
                case CPU_TYPE_I386:
        // adjust min based on architecture
        switch ( fArchitecture ) {
                case CPU_TYPE_I386:
-                       if ( (fMacVersionMin < ld::mac10_4) && (fIOSVersionMin == ld::iOSVersionUnset) ) {
+                       if ( (fPlatform == kPlatformOSX) && (fMacVersionMin < ld::mac10_4) ) {
                                //warning("-macosx_version_min should be 10.4 or later for i386");
                                fMacVersionMin = ld::mac10_4;
                        }
                        break;
                case CPU_TYPE_X86_64:
                                //warning("-macosx_version_min should be 10.4 or later for i386");
                                fMacVersionMin = ld::mac10_4;
                        }
                        break;
                case CPU_TYPE_X86_64:
-                       if ( (fMacVersionMin < ld::mac10_4) && (fIOSVersionMin == ld::iOSVersionUnset) ) {
+                       if ( (fPlatform == kPlatformOSX) && (fMacVersionMin < ld::mac10_4) ) {
                                //warning("-macosx_version_min should be 10.4 or later for x86_64");
                                fMacVersionMin = ld::mac10_4;
                        }
                        break;
                case CPU_TYPE_ARM64:
                                //warning("-macosx_version_min should be 10.4 or later for x86_64");
                                fMacVersionMin = ld::mac10_4;
                        }
                        break;
                case CPU_TYPE_ARM64:
-                       if ( fIOSVersionMin < ld::iOS_7_0 ) {
+                       if ( (fPlatform == kPlatformiOS) && (fIOSVersionMin < ld::iOS_7_0) ) {
                                //warning("-mios_version_min should be 7.0 or later for arm64");
                                fIOSVersionMin = ld::iOS_7_0;
                        }
                                //warning("-mios_version_min should be 7.0 or later for arm64");
                                fIOSVersionMin = ld::iOS_7_0;
                        }
@@ -3661,12 +4129,12 @@ void Options::reconfigureDefaults()
                                fUndefinedTreatment = kUndefinedDynamicLookup;
                                break;
                        case CPU_TYPE_ARM:
                                fUndefinedTreatment = kUndefinedDynamicLookup;
                                break;
                        case CPU_TYPE_ARM:
-                               if ( fIOSVersionMin >= ld::iOS_5_0 ) {
+                               if ( min_iOS(ld::iOS_5_0) ) {
                     // iOS 5.0 and later use new MH_KEXT_BUNDLE type
                     fMakeCompressedDyldInfo = false;
                     fMakeCompressedDyldInfoForceOff = true;
                                        // kexts are PIC in iOS 6.0 and later
                     // iOS 5.0 and later use new MH_KEXT_BUNDLE type
                     fMakeCompressedDyldInfo = false;
                     fMakeCompressedDyldInfoForceOff = true;
                                        // kexts are PIC in iOS 6.0 and later
-                                       fAllowTextRelocs = (fIOSVersionMin < ld::iOS_6_0);
+                                       fAllowTextRelocs = !min_iOS(ld::iOS_6_0);
                                        fKextsUseStubs = !fAllowTextRelocs;
                     fUndefinedTreatment = kUndefinedDynamicLookup;
                                        break;
                                        fKextsUseStubs = !fAllowTextRelocs;
                     fUndefinedTreatment = kUndefinedDynamicLookup;
                                        break;
@@ -3841,7 +4309,7 @@ void Options::reconfigureDefaults()
        // determine if info for shared region should be added
        if ( fOutputKind == Options::kDynamicLibrary ) {
                if ( minOS(ld::mac10_5, ld::iOS_3_1) )
        // determine if info for shared region should be added
        if ( fOutputKind == Options::kDynamicLibrary ) {
                if ( minOS(ld::mac10_5, ld::iOS_3_1) )
-                       if ( !fPrebind )
+                       if ( !fPrebind && !fSharedRegionEligibleForceOff )
                                if ( (strncmp(this->installPath(), "/usr/lib/", 9) == 0)
                                        || (strncmp(this->installPath(), "/System/Library/", 16) == 0) )
                                        fSharedRegionEligible = true;
                                if ( (strncmp(this->installPath(), "/usr/lib/", 9) == 0)
                                        || (strncmp(this->installPath(), "/System/Library/", 16) == 0) )
                                        fSharedRegionEligible = true;
@@ -3850,7 +4318,41 @@ void Options::reconfigureDefaults()
         // <rdar://problem/10111122> Enable dyld to be put into the dyld shared cache
         fSharedRegionEligible = true;
        }
         // <rdar://problem/10111122> Enable dyld to be put into the dyld shared cache
         fSharedRegionEligible = true;
        }
-    
+
+       // <rdar://problem/18719327> warn if -rpath is used with OS dylibs
+       if ( fSharedRegionEligible && !fRPaths.empty() ) 
+               warning("-rpath cannot be used with dylibs that will be in the dyld shared cache");
+
+       // automatically use __DATA_CONST in iOS dylibs
+       if ( fSharedRegionEligible && minOS(ld::mac10_Future, ld::iOS_9_0) && !fUseDataConstSegmentForceOff ) {
+               fUseDataConstSegment = true;
+       }
+       if ( fUseDataConstSegmentForceOn ) {
+               fUseDataConstSegment = true;
+       }
+       if ( fUseDataConstSegment ) {
+               addSectionRename("__DATA", "__got",                             "__DATA_CONST", "__got");
+               addSectionRename("__DATA", "__la_symbol_ptr",   "__DATA_CONST", "__la_symbol_ptr");
+               addSectionRename("__DATA", "__nl_symbol_ptr",   "__DATA_CONST", "__nl_symbol_ptr");
+               addSectionRename("__DATA", "__const",                   "__DATA_CONST", "__const");
+               addSectionRename("__DATA", "__cfstring",                "__DATA_CONST", "__cfstring");
+               addSectionRename("__DATA", "__mod_init_func",   "__DATA_CONST", "__mod_init_func");
+               addSectionRename("__DATA", "__mod_term_func",   "__DATA_CONST", "__mod_term_func");
+               addSectionRename("__DATA", "__objc_classlist",  "__DATA_CONST", "__objc_classlist");
+               addSectionRename("__DATA", "__objc_nlclslist",  "__DATA_CONST", "__objc_nlclslist");
+               addSectionRename("__DATA", "__objc_catlist",    "__DATA_CONST", "__objc_catlist");
+               addSectionRename("__DATA", "__objc_nlcatlist",  "__DATA_CONST", "__objc_nlcatlist");
+               addSectionRename("__DATA", "__objc_protolist",  "__DATA_CONST", "__objc_protolist");
+               addSectionRename("__DATA", "__objc_imageinfo",  "__DATA_CONST", "__objc_imageinfo");
+               addSectionRename("__DATA", "__objc_const",          "__DATA_CONST", "__objc_const");
+       }
+       
+       // Use V2 shared cache info when targetting newer OSs
+       if ( fSharedRegionEligible && minOS(ld::mac10_Future, ld::iOS_9_0)) {
+               fSharedRegionEncodingV2 = true;
+               fIgnoreOptimizationHints = true;
+       }
+
        // figure out if module table is needed for compatibility with old ld/dyld
        if ( fOutputKind == Options::kDynamicLibrary ) {
                switch ( fArchitecture ) {
        // figure out if module table is needed for compatibility with old ld/dyld
        if ( fOutputKind == Options::kDynamicLibrary ) {
                switch ( fArchitecture ) {
@@ -3935,12 +4437,16 @@ void Options::reconfigureDefaults()
                case Options::kDynamicLibrary:
                case Options::kDynamicBundle:
                        // <rdar://problem/16293398> Add LC_ENCRYPTION_INFO load command to bundled frameworks
                case Options::kDynamicLibrary:
                case Options::kDynamicBundle:
                        // <rdar://problem/16293398> Add LC_ENCRYPTION_INFO load command to bundled frameworks
-                       if ( fIOSVersionMin < ld::iOS_8_0 )
+                       if ( !min_iOS(ld::iOS_7_0) )
                                fEncryptable = false;
                        break;
        }
        if ( (fArchitecture != CPU_TYPE_ARM) && (fArchitecture != CPU_TYPE_ARM64) )
                fEncryptable = false;
                                fEncryptable = false;
                        break;
        }
        if ( (fArchitecture != CPU_TYPE_ARM) && (fArchitecture != CPU_TYPE_ARM64) )
                fEncryptable = false;
+       if ( fEncryptableForceOn )
+               fEncryptable = true;
+       else if ( fEncryptableForceOff )
+               fEncryptable = false;
 
        // don't move inits in dyld because dyld wants certain
        // entries point at stable locations at the start of __text
 
        // don't move inits in dyld because dyld wants certain
        // entries point at stable locations at the start of __text
@@ -4045,7 +4551,7 @@ void Options::reconfigureDefaults()
        if ( (fArchitecture == CPU_TYPE_ARM) 
                && fArchSupportsThumb2
                && (fOutputKind == kDynamicExecutable) 
        if ( (fArchitecture == CPU_TYPE_ARM) 
                && fArchSupportsThumb2
                && (fOutputKind == kDynamicExecutable) 
-               && (fIOSVersionMin >= ld::iOS_4_3) ) {
+               && min_iOS(ld::iOS_4_3) ) {
                        fPositionIndependentExecutable = true;
        }
 
                        fPositionIndependentExecutable = true;
        }
 
@@ -4086,7 +4592,10 @@ void Options::reconfigureDefaults()
        if ( fMacVersionMin >= ld::mac10_7 ) {
                fTLVSupport = true;
        }
        if ( fMacVersionMin >= ld::mac10_7 ) {
                fTLVSupport = true;
        }
-       else if ( (fArchitecture == CPU_TYPE_ARM64) && (fIOSVersionMin >= ld::iOS_8_0) ) {
+       else if ( (fArchitecture == CPU_TYPE_ARM64) && min_iOS(ld::iOS_8_0) ) {
+               fTLVSupport = true;
+       }
+       else if ( (fArchitecture == CPU_TYPE_ARM) && min_iOS(ld::iOS_9_0) ) {
                fTLVSupport = true;
        }
 
                fTLVSupport = true;
        }
 
@@ -4208,35 +4717,7 @@ void Options::reconfigureDefaults()
                        fSourceVersionLoadCommand = false;
                        break;
        }
                        fSourceVersionLoadCommand = false;
                        break;
        }
-       
-       
-       // add LC_DYLIB_CODE_SIGN_DRS
-       switch ( fOutputKind ) {
-               case Options::kDynamicExecutable:
-               case Options::kDynamicLibrary:
-               case Options::kDynamicBundle:
-                       if ( fDependentDRInfoForcedOn ) {
-                               fDependentDRInfo = true;
-                       }
-                       else if ( fDependentDRInfoForcedOff ) {
-                               fDependentDRInfo = false;
-                       }
-                       else {
-                               if ( minOS(ld::mac10_8, ld::iOS_6_0) ) 
-                                       fDependentDRInfo = true;
-                               else
-                                       fDependentDRInfo = false;
-                       }
-                       break;
-               case Options::kKextBundle:
-               case Options::kDyld:
-               case Options::kStaticExecutable:
-               case Options::kObjectFile:
-               case Options::kPreload:
-                       fDependentDRInfo = false;
-                       break;
-       }
-       
+
        // if -sdk_version not on command line, infer from -syslibroot
        if ( (fSDKVersion == 0) && (fSDKPaths.size() > 0) ) {
                const char* sdkPath = fSDKPaths.front();
        // if -sdk_version not on command line, infer from -syslibroot
        if ( (fSDKVersion == 0) && (fSDKPaths.size() > 0) ) {
                const char* sdkPath = fSDKPaths.front();
@@ -4275,9 +4756,7 @@ void Options::reconfigureDefaults()
        // allow trie based absolute symbols if targeting new enough OS
        if ( fMakeCompressedDyldInfo ) {
                if ( minOS(ld::mac10_9, ld::iOS_7_0) ) {
        // allow trie based absolute symbols if targeting new enough OS
        if ( fMakeCompressedDyldInfo ) {
                if ( minOS(ld::mac10_9, ld::iOS_7_0) ) {
-                       // <rdar://problem/13179029> Allow absolute symbols in export trie for device but not simulator
-                       if ( !fTargetIOSSimulator ) 
-                               fAbsoluteSymbols = true;
+                       fAbsoluteSymbols = true;
                }
        }
        
                }
        }
        
@@ -4299,15 +4778,14 @@ void Options::reconfigureDefaults()
                        case Options::kDynamicBundle:
                        case Options::kDyld:
                                if ( (fArchitecture == CPU_TYPE_ARM64) 
                        case Options::kDynamicBundle:
                        case Options::kDyld:
                                if ( (fArchitecture == CPU_TYPE_ARM64) 
-                               || ((fArchitecture == CPU_TYPE_ARM) && (fIOSVersionMin >= ld::iOS_8_0) && 
-                                       ((fSubArchitecture == CPU_SUBTYPE_ARM_V7S) || (fSubArchitecture == CPU_SUBTYPE_ARM_V7))) ) {
+                               || ((fArchitecture == CPU_TYPE_ARM) && min_iOS(ld::iOS_7_0)) ) {
                                        fSegmentAlignment = 4096*4;
                                }
                                break;
                        case Options::kStaticExecutable:
                        case Options::kKextBundle:
                                // <rdar://problem/14676611> 16KB segments for arm64 kexts
                                        fSegmentAlignment = 4096*4;
                                }
                                break;
                        case Options::kStaticExecutable:
                        case Options::kKextBundle:
                                // <rdar://problem/14676611> 16KB segments for arm64 kexts
-                               if ( (fArchitecture == CPU_TYPE_ARM64) && (fIOSVersionMin >= ld::iOS_9_0) ) {
+                               if ( (fArchitecture == CPU_TYPE_ARM64) && min_iOS(ld::iOS_9_0) ) {
                                        fSegmentAlignment = 4096*4;
                                }
                                break;
                                        fSegmentAlignment = 4096*4;
                                }
                                break;
@@ -4353,6 +4831,21 @@ void Options::reconfigureDefaults()
                fBaseAddress = alignedBaseAddress;
        }
 
                fBaseAddress = alignedBaseAddress;
        }
 
+       // If -dirty_data_list not specified, look in $SDKROOT/AppleInternal/DirtyDataFiles/<dylib>.dirty for dirty data list
+       if ( fSymbolsMovesData.empty() && fUseDataConstSegment && ( fDylibInstallName != NULL) && !fSDKPaths.empty() ) {
+               const char* dylibLeaf = strrchr(fDylibInstallName, '/');
+               if ( dylibLeaf ) {
+                       char path[PATH_MAX];
+                       strlcpy(path , fSDKPaths.front(), sizeof(path));
+                       strlcat(path , "/AppleInternal/DirtyDataFiles", sizeof(path));
+                       strlcat(path , dylibLeaf, sizeof(path));
+                       strlcat(path , ".dirty", sizeof(path));
+                       FileInfo info;
+                       if ( info.checkFileExists(*this, path) )
+                               addSymbolMove("__DATA_DIRTY", path, fSymbolsMovesData, "-dirty_data_list");
+               }
+       }
+
 }
 
 void Options::checkIllegalOptionCombinations()
 }
 
 void Options::checkIllegalOptionCombinations()
@@ -4798,8 +5291,9 @@ void Options::checkIllegalOptionCombinations()
                throw "-segment_order can only used used with -preload output";
 
        // <rdar://problem/17598404> warn if building an embedded iOS dylib for pre-iOS 8
                throw "-segment_order can only used used with -preload output";
 
        // <rdar://problem/17598404> warn if building an embedded iOS dylib for pre-iOS 8
+       // <rdar://problem/18935714> How can we suppress "ld: warning: embedded dylibs/frameworks only run on iOS 8 or laterÓ when building XCTest?
        if ( (fOutputKind == Options::kDynamicLibrary) && (fIOSVersionMin != ld::iOSVersionUnset) && (fDylibInstallName != NULL) ) {
        if ( (fOutputKind == Options::kDynamicLibrary) && (fIOSVersionMin != ld::iOSVersionUnset) && (fDylibInstallName != NULL) ) {
-               if ( (fIOSVersionMin < ld::iOS_8_0) && (fDylibInstallName[0] == '@') ) 
+               if ( !min_iOS(ld::iOS_8_0) && (fDylibInstallName[0] == '@') && !fEncryptableForceOff )
                        warning("embedded dylibs/frameworks only run on iOS 8 or later");
        }
 }      
                        warning("embedded dylibs/frameworks only run on iOS 8 or later");
        }
 }      
@@ -4937,14 +5431,28 @@ const char* Options::demangleSymbol(const char* sym) const
        if ( !fDemangle )
                return sym;
 
        if ( !fDemangle )
                return sym;
 
+       static size_t size = 1024;
+       static char* buff = (char*)malloc(size);
+       
+#if DEMANGLE_SWIFT
+       // only try to demangle symbols that look like Swift symbols
+       if ( strncmp(sym, "__T", 3) == 0 ) {
+               size_t demangledSize = fnd_get_demangled_name(&sym[1], buff, size);
+               if ( demangledSize > size ) {
+                       size = demangledSize+2;
+                       buff = (char*)realloc(buff, size);
+                       demangledSize = fnd_get_demangled_name(&sym[1], buff, size);
+               }
+               if ( demangledSize != 0 )
+                       return buff;
+       }
+#endif
+
        // only try to demangle symbols that look like C++ symbols
        if ( strncmp(sym, "__Z", 3) != 0 )
                return sym;
 
        // only try to demangle symbols that look like C++ symbols
        if ( strncmp(sym, "__Z", 3) != 0 )
                return sym;
 
-       static size_t size = 1024;
-       static char* buff = (char*)malloc(size);
        int status;
        int status;
-       
        char* result = abi::__cxa_demangle(&sym[1], buff, &size, &status); 
        if ( result != NULL ) {
                // if demangling successful, keep buffer for next demangle
        char* result = abi::__cxa_demangle(&sym[1], buff, &size, &status); 
        if ( result != NULL ) {
                // if demangling successful, keep buffer for next demangle
index 39ee6fe8db34f384d996c12dbcdceba00224bd0e..bc70e7feabb904b57feee80c7c4dde1e1ed22559 100644 (file)
@@ -35,6 +35,7 @@
 
 #include "ld.hpp"
 #include "Snapshot.h"
 
 #include "ld.hpp"
 #include "Snapshot.h"
+#include "MachOFileAbstraction.hpp"
 
 extern void throwf (const char* format, ...) __attribute__ ((noreturn,format(printf, 1, 2)));
 extern void warning(const char* format, ...) __attribute__((format(printf, 1, 2)));
 
 extern void throwf (const char* format, ...) __attribute__ ((noreturn,format(printf, 1, 2)));
 extern void warning(const char* format, ...) __attribute__((format(printf, 1, 2)));
@@ -86,6 +87,46 @@ public:
        enum UUIDMode { kUUIDNone, kUUIDRandom, kUUIDContent };
        enum LocalSymbolHandling { kLocalSymbolsAll, kLocalSymbolsNone, kLocalSymbolsSelectiveInclude, kLocalSymbolsSelectiveExclude };
        enum DebugInfoStripping { kDebugInfoNone, kDebugInfoMinimal, kDebugInfoFull };
        enum UUIDMode { kUUIDNone, kUUIDRandom, kUUIDContent };
        enum LocalSymbolHandling { kLocalSymbolsAll, kLocalSymbolsNone, kLocalSymbolsSelectiveInclude, kLocalSymbolsSelectiveExclude };
        enum DebugInfoStripping { kDebugInfoNone, kDebugInfoMinimal, kDebugInfoFull };
+#if SUPPORT_APPLE_TV
+       enum Platform { kPlatformUnknown, kPlatformOSX, kPlatformiOS, kPlatformWatchOS, kPlatform_tvOS };
+#else
+       enum Platform { kPlatformUnknown, kPlatformOSX, kPlatformiOS, kPlatformWatchOS };
+#endif
+
+       static Platform platformForLoadCommand(uint32_t lc) {
+               switch (lc) {
+                       case LC_VERSION_MIN_MACOSX:
+                               return kPlatformOSX;
+                       case LC_VERSION_MIN_IPHONEOS:
+                               return kPlatformiOS;
+                       case LC_VERSION_MIN_WATCHOS:
+                               return kPlatformWatchOS;
+               #if SUPPORT_APPLE_TV
+                       case LC_VERSION_MIN_TVOS:
+                               return kPlatform_tvOS;
+               #endif
+               }
+               assert(!lc && "unknown LC_VERSION_MIN load command");
+               return kPlatformUnknown;
+       }
+
+       static const char* platformName(Platform platform) {
+               switch (platform) {
+                       case kPlatformOSX:
+                               return "OSX";
+                       case kPlatformiOS:
+                               return "iOS";
+                       case kPlatformWatchOS:
+                               return "watchOS";
+               #if SUPPORT_APPLE_TV
+                       case kPlatform_tvOS:
+                               return "tvOS";
+               #endif
+                       case kPlatformUnknown:
+                       default:
+                               return "(unknown)";
+               }
+       }
 
        class FileInfo {
     public:
 
        class FileInfo {
     public:
@@ -208,7 +249,7 @@ public:
        bool                                            allowSubArchitectureMismatches() const { return fAllowCpuSubtypeMismatches; }
        bool                                            forceCpuSubtypeAll() const { return fForceSubtypeAll; }
        const char*                                     architectureName() const { return fArchitectureName; }
        bool                                            allowSubArchitectureMismatches() const { return fAllowCpuSubtypeMismatches; }
        bool                                            forceCpuSubtypeAll() const { return fForceSubtypeAll; }
        const char*                                     architectureName() const { return fArchitectureName; }
-       void                                            setArchitecture(cpu_type_t, cpu_subtype_t subtype);
+       void                                            setArchitecture(cpu_type_t, cpu_subtype_t subtype, Options::Platform platform);
        bool                                            archSupportsThumb2() const { return fArchSupportsThumb2; }
        OutputKind                                      outputKind() const { return fOutputKind; }
        bool                                            prebind() const { return fPrebind; }
        bool                                            archSupportsThumb2() const { return fArchSupportsThumb2; }
        OutputKind                                      outputKind() const { return fOutputKind; }
        bool                                            prebind() const { return fPrebind; }
@@ -233,6 +274,7 @@ public:
        bool                                            allGlobalsAreDeadStripRoots() const;
        bool                                            shouldExport(const char*) const;
        bool                                            shouldReExport(const char*) const;
        bool                                            allGlobalsAreDeadStripRoots() const;
        bool                                            shouldExport(const char*) const;
        bool                                            shouldReExport(const char*) const;
+       std::vector<const char*>        exportsData() const;
        bool                                            ignoreOtherArchInputFiles() const { return fIgnoreOtherArchFiles; }
        bool                                            traceDylibs() const     { return fTraceDylibs; }
        bool                                            traceArchives() const { return fTraceArchives; }
        bool                                            ignoreOtherArchInputFiles() const { return fIgnoreOtherArchFiles; }
        bool                                            traceDylibs() const     { return fTraceDylibs; }
        bool                                            traceArchives() const { return fTraceArchives; }
@@ -240,7 +282,10 @@ public:
        UndefinedTreatment                      undefinedTreatment() const { return fUndefinedTreatment; }
        ld::MacVersionMin                       macosxVersionMin() const { return fMacVersionMin; }
        ld::IOSVersionMin                       iOSVersionMin() const { return fIOSVersionMin; }
        UndefinedTreatment                      undefinedTreatment() const { return fUndefinedTreatment; }
        ld::MacVersionMin                       macosxVersionMin() const { return fMacVersionMin; }
        ld::IOSVersionMin                       iOSVersionMin() const { return fIOSVersionMin; }
+       ld::WatchOSVersionMin           watchOSVersionMin() const { return fWatchOSVersionMin; }
+       uint32_t                                        minOSversion() const;
        bool                                            minOS(ld::MacVersionMin mac, ld::IOSVersionMin iPhoneOS);
        bool                                            minOS(ld::MacVersionMin mac, ld::IOSVersionMin iPhoneOS);
+       bool                                            min_iOS(ld::IOSVersionMin requirediOSMin);
        bool                                            messagesPrefixedWithArchitecture();
        Treatment                                       picTreatment();
        WeakReferenceMismatchTreatment  weakReferenceMismatchTreatment() const { return fWeakReferenceMismatchTreatment; }
        bool                                            messagesPrefixedWithArchitecture();
        Treatment                                       picTreatment();
        WeakReferenceMismatchTreatment  weakReferenceMismatchTreatment() const { return fWeakReferenceMismatchTreatment; }
@@ -266,7 +311,7 @@ public:
        CommonsMode                                     commonsMode() const { return fCommonsMode; }
        bool                                            warnCommons() const { return fWarnCommons; }
        bool                                            keepRelocations();
        CommonsMode                                     commonsMode() const { return fCommonsMode; }
        bool                                            warnCommons() const { return fWarnCommons; }
        bool                                            keepRelocations();
-       FileInfo                                        findFile(const char* path) const;
+       FileInfo                                        findFile(const std::string &path) const;
        UUIDMode                                        UUIDMode() const { return fUUIDMode; }
        bool                                            warnStabs();
        bool                                            pauseAtEnd() { return fPause; }
        UUIDMode                                        UUIDMode() const { return fUUIDMode; }
        bool                                            warnStabs();
        bool                                            pauseAtEnd() { return fPause; }
@@ -296,7 +341,7 @@ public:
        const std::vector<DylibOverride>&       dylibOverrides() const { return fDylibOverrides; }
        const char*                                     generatedMapPath() const { return fMapPath; }
        bool                                            positionIndependentExecutable() const { return fPositionIndependentExecutable; }
        const std::vector<DylibOverride>&       dylibOverrides() const { return fDylibOverrides; }
        const char*                                     generatedMapPath() const { return fMapPath; }
        bool                                            positionIndependentExecutable() const { return fPositionIndependentExecutable; }
-       Options::FileInfo                       findFileUsingPaths(const char* path) const;
+       Options::FileInfo                       findFileUsingPaths(const std::string &path) const;
        bool                                            deadStripDylibs() const { return fDeadStripDylibs; }
        bool                                            allowedUndefined(const char* name) const { return ( fAllowedUndefined.find(name) != fAllowedUndefined.end() ); }
        bool                                            someAllowedUndefines() const { return (fAllowedUndefined.size() != 0); }
        bool                                            deadStripDylibs() const { return fDeadStripDylibs; }
        bool                                            allowedUndefined(const char* name) const { return ( fAllowedUndefined.find(name) != fAllowedUndefined.end() ); }
        bool                                            someAllowedUndefines() const { return (fAllowedUndefined.size() != 0); }
@@ -311,6 +356,7 @@ public:
        bool                                            needsUnwindInfoSection() const { return fAddCompactUnwindEncoding; }
        const std::vector<const char*>& llvmOptions() const{ return fLLVMOptions; }
        const std::vector<const char*>& segmentOrder() const{ return fSegmentOrder; }
        bool                                            needsUnwindInfoSection() const { return fAddCompactUnwindEncoding; }
        const std::vector<const char*>& llvmOptions() const{ return fLLVMOptions; }
        const std::vector<const char*>& segmentOrder() const{ return fSegmentOrder; }
+       bool                                            segmentOrderAfterFixedAddressSegment(const char* segName) const;
        const std::vector<const char*>* sectionOrder(const char* segName) const;
        const std::vector<const char*>& dyldEnvironExtras() const{ return fDyldEnvironExtras; }
        const std::vector<const char*>& astFilePaths() const{ return fASTFilePaths; }
        const std::vector<const char*>* sectionOrder(const char* segName) const;
        const std::vector<const char*>& dyldEnvironExtras() const{ return fDyldEnvironExtras; }
        const std::vector<const char*>& astFilePaths() const{ return fASTFilePaths; }
@@ -346,7 +392,7 @@ public:
        bool                                            objcGc() const { return fObjCGc; }
        bool                                            objcGcOnly() const { return fObjCGcOnly; }
        bool                                            canUseThreadLocalVariables() const { return fTLVSupport; }
        bool                                            objcGc() const { return fObjCGc; }
        bool                                            objcGcOnly() const { return fObjCGcOnly; }
        bool                                            canUseThreadLocalVariables() const { return fTLVSupport; }
-       bool                                            addVersionLoadCommand() const { return fVersionLoadCommand; }
+       bool                                            addVersionLoadCommand() const { return fVersionLoadCommand && (fPlatform != kPlatformUnknown); }
        bool                                            addFunctionStarts() const { return fFunctionStartsLoadCommand; }
        bool                                            addDataInCodeInfo() const { return fDataInCodeInfoLoadCommand; }
        bool                                            canReExportSymbols() const { return fCanReExportSymbols; }
        bool                                            addFunctionStarts() const { return fFunctionStartsLoadCommand; }
        bool                                            addDataInCodeInfo() const { return fDataInCodeInfoLoadCommand; }
        bool                                            canReExportSymbols() const { return fCanReExportSymbols; }
@@ -364,6 +410,15 @@ public:
        bool                                            markAppExtensionSafe() const { return fMarkAppExtensionSafe; }
        bool                                            checkDylibsAreAppExtensionSafe() const { return fCheckAppExtensionSafe; }
        bool                                            forceLoadSwiftLibs() const { return fForceLoadSwiftLibs; }
        bool                                            markAppExtensionSafe() const { return fMarkAppExtensionSafe; }
        bool                                            checkDylibsAreAppExtensionSafe() const { return fCheckAppExtensionSafe; }
        bool                                            forceLoadSwiftLibs() const { return fForceLoadSwiftLibs; }
+       bool                                            bundleBitcode() const { return fBundleBitcode; }
+       bool                                            hideSymbols() const { return fHideSymbols; }
+       bool                                            renameReverseSymbolMap() const { return fReverseMapUUIDRename; }
+       const char*                                     reverseSymbolMapPath() const { return fReverseMapPath; }
+       std::string                                     reverseMapTempPath() const { return fReverseMapTempPath; }
+       bool                                            ltoCodegenOnly() const { return fLTOCodegenOnly; }
+       bool                                            ignoreAutoLink() const { return fIgnoreAutoLink; }
+       bool                                            sharedRegionEncodingV2() const { return fSharedRegionEncodingV2; }
+       bool                                            useDataConstSegment() const { return fUseDataConstSegment; }
        bool                                            hasWeakBitTweaks() const;
        bool                                            forceWeak(const char* symbolName) const;
        bool                                            forceNotWeak(const char* symbolName) const;
        bool                                            hasWeakBitTweaks() const;
        bool                                            forceWeak(const char* symbolName) const;
        bool                                            forceNotWeak(const char* symbolName) const;
@@ -375,7 +430,6 @@ public:
        bool                                            needsThreadLoadCommand() const { return fNeedsThreadLoadCommand; }
        bool                                            needsEntryPointLoadCommand() const { return fEntryPointLoadCommand; }
        bool                                            needsSourceVersionLoadCommand() const { return fSourceVersionLoadCommand; }
        bool                                            needsThreadLoadCommand() const { return fNeedsThreadLoadCommand; }
        bool                                            needsEntryPointLoadCommand() const { return fEntryPointLoadCommand; }
        bool                                            needsSourceVersionLoadCommand() const { return fSourceVersionLoadCommand; }
-       bool                                            needsDependentDRInfo() const { return fDependentDRInfo; }
        bool                                            canUseAbsoluteSymbols() const { return fAbsoluteSymbols; }
        bool                                            allowSimulatorToLinkWithMacOSX() const { return fAllowSimulatorToLinkWithMacOSX; }
        uint64_t                                        sourceVersion() const { return fSourceVersion; }
        bool                                            canUseAbsoluteSymbols() const { return fAbsoluteSymbols; }
        bool                                            allowSimulatorToLinkWithMacOSX() const { return fAllowSimulatorToLinkWithMacOSX; }
        uint64_t                                        sourceVersion() const { return fSourceVersion; }
@@ -395,6 +449,11 @@ public:
        const std::vector<SegmentRename>& segmentRenames() const { return fSegmentRenames; }
        bool                                            moveRoSymbol(const char* symName, const char* filePath, const char*& seg, bool& wildCardMatch) const;
        bool                                            moveRwSymbol(const char* symName, const char* filePath, const char*& seg, bool& wildCardMatch) const;
        const std::vector<SegmentRename>& segmentRenames() const { return fSegmentRenames; }
        bool                                            moveRoSymbol(const char* symName, const char* filePath, const char*& seg, bool& wildCardMatch) const;
        bool                                            moveRwSymbol(const char* symName, const char* filePath, const char*& seg, bool& wildCardMatch) const;
+       Platform                                        platform() const { return fPlatform; }
+       const std::vector<const char*>& sdkPaths() const { return fSDKPaths; }
+       std::vector<std::string>        writeBitcodeLinkOptions() const;
+       std::string                                     getSDKVersionStr() const;
+       std::string                                     getPlatformStr() const;
 
 private:
        typedef std::unordered_map<const char*, unsigned int, ld::CStringHash, ld::CStringEquals> NameToOrder;
 
 private:
        typedef std::unordered_map<const char*, unsigned int, ld::CStringHash, ld::CStringEquals> NameToOrder;
@@ -414,6 +473,7 @@ private:
                NameSet::iterator               regularBegin() const    { return fRegular.begin(); }
                NameSet::iterator               regularEnd() const              { return fRegular.end(); }
                void                                    remove(const NameSet&); 
                NameSet::iterator               regularBegin() const    { return fRegular.begin(); }
                NameSet::iterator               regularEnd() const              { return fRegular.end(); }
                void                                    remove(const NameSet&); 
+               std::vector<const char*>                data() const;
        private:
                static bool                             hasWildCards(const char*);
                bool                                    wildCardMatch(const char* pattern, const char* candidate) const;
        private:
                static bool                             hasWildCards(const char*);
                bool                                    wildCardMatch(const char* pattern, const char* candidate) const;
@@ -437,6 +497,8 @@ private:
                                                                                         FileInfo& result) const;
        uint64_t                                        parseVersionNumber64(const char*);
        uint32_t                                        parseVersionNumber32(const char*);
                                                                                         FileInfo& result) const;
        uint64_t                                        parseVersionNumber64(const char*);
        uint32_t                                        parseVersionNumber32(const char*);
+       std::string                                     getVersionString32(uint32_t ver) const;
+       std::string                                     getVersionString64(uint64_t ver) const;
        void                                            parseSectionOrderFile(const char* segment, const char* section, const char* path);
        void                                            parseOrderFile(const char* path, bool cstring);
        void                                            addSection(const char* segment, const char* section, const char* path);
        void                                            parseSectionOrderFile(const char* segment, const char* section, const char* path);
        void                                            parseOrderFile(const char* path, bool cstring);
        void                                            addSection(const char* segment, const char* section, const char* path);
@@ -450,6 +512,7 @@ private:
        void                                            setUndefinedTreatment(const char* treatment);
        void                                            setMacOSXVersionMin(const char* version);
        void                                            setIOSVersionMin(const char* version);
        void                                            setUndefinedTreatment(const char* treatment);
        void                                            setMacOSXVersionMin(const char* version);
        void                                            setIOSVersionMin(const char* version);
+       void                                            setWatchOSVersionMin(const char* version);
        void                                            setWeakReferenceMismatchTreatment(const char* treatment);
        void                                            addDylibOverride(const char* paths);
        void                                            addSectionAlignment(const char* segment, const char* section, const char* alignment);
        void                                            setWeakReferenceMismatchTreatment(const char* treatment);
        void                                            addDylibOverride(const char* paths);
        void                                            addSectionAlignment(const char* segment, const char* section, const char* alignment);
@@ -465,6 +528,7 @@ private:
        void                                            addSectionRename(const char* srcSegment, const char* srcSection, const char* dstSegment, const char* dstSection);
        void                                            addSegmentRename(const char* srcSegment, const char* dstSegment);
        void                                            addSymbolMove(const char* dstSegment, const char* symbolList, std::vector<SymbolsMove>& list, const char* optionName);
        void                                            addSectionRename(const char* srcSegment, const char* srcSection, const char* dstSegment, const char* dstSection);
        void                                            addSegmentRename(const char* srcSegment, const char* dstSegment);
        void                                            addSymbolMove(const char* dstSegment, const char* symbolList, std::vector<SymbolsMove>& list, const char* optionName);
+       void                                            cannotBeUsedWithBitcode(const char* arg);
 
 
 //     ObjectFile::ReaderOptions                       fReaderOptions;
 
 
 //     ObjectFile::ReaderOptions                       fReaderOptions;
@@ -550,6 +614,7 @@ private:
        bool                                                            fStatistics;
        bool                                                            fPrintOptions;
        bool                                                            fSharedRegionEligible;
        bool                                                            fStatistics;
        bool                                                            fPrintOptions;
        bool                                                            fSharedRegionEligible;
+       bool                                                            fSharedRegionEligibleForceOff;
        bool                                                            fPrintOrderFileStatistics;
        bool                                                            fReadOnlyx86Stubs;
        bool                                                            fPositionIndependentExecutable;
        bool                                                            fPrintOrderFileStatistics;
        bool                                                            fReadOnlyx86Stubs;
        bool                                                            fPositionIndependentExecutable;
@@ -562,6 +627,8 @@ private:
        bool                                                            fKextsUseStubs;
        bool                                                            fUsingLazyDylibLinking;
        bool                                                            fEncryptable;
        bool                                                            fKextsUseStubs;
        bool                                                            fUsingLazyDylibLinking;
        bool                                                            fEncryptable;
+       bool                                                            fEncryptableForceOn;
+       bool                                                            fEncryptableForceOff;
        bool                                                            fOrderData;
        bool                                                            fMarkDeadStrippableDylib;
        bool                                                            fMakeCompressedDyldInfo;
        bool                                                            fOrderData;
        bool                                                            fMarkDeadStrippableDylib;
        bool                                                            fMakeCompressedDyldInfo;
@@ -621,9 +688,6 @@ private:
        bool                                                            fSourceVersionLoadCommand;
        bool                                                            fSourceVersionLoadCommandForceOn;
        bool                                                            fSourceVersionLoadCommandForceOff;      
        bool                                                            fSourceVersionLoadCommand;
        bool                                                            fSourceVersionLoadCommandForceOn;
        bool                                                            fSourceVersionLoadCommandForceOff;      
-       bool                                                            fDependentDRInfo;
-       bool                                                            fDependentDRInfoForcedOn;
-       bool                                                            fDependentDRInfoForcedOff;
        bool                                                            fTargetIOSSimulator;
        bool                                                            fExportDynamic;
        bool                                                            fAbsoluteSymbols;
        bool                                                            fTargetIOSSimulator;
        bool                                                            fExportDynamic;
        bool                                                            fAbsoluteSymbols;
@@ -639,14 +703,27 @@ private:
        bool                                                            fMarkAppExtensionSafe;
        bool                                                            fCheckAppExtensionSafe;
        bool                                                            fForceLoadSwiftLibs;
        bool                                                            fMarkAppExtensionSafe;
        bool                                                            fCheckAppExtensionSafe;
        bool                                                            fForceLoadSwiftLibs;
+       bool                                                            fSharedRegionEncodingV2;
+       bool                                                            fUseDataConstSegment;
+       bool                                                            fUseDataConstSegmentForceOn;
+       bool                                                            fUseDataConstSegmentForceOff;
+       bool                                                            fBundleBitcode;
+       bool                                                            fHideSymbols;
+       bool                                                            fReverseMapUUIDRename;
+       const char*                                                     fReverseMapPath;
+       std::string                                                     fReverseMapTempPath;
+       bool                                                            fLTOCodegenOnly;
+       bool                                                            fIgnoreAutoLink;
+       Platform                                                        fPlatform;
        DebugInfoStripping                                      fDebugInfoStripping;
        const char*                                                     fTraceOutputFile;
        ld::MacVersionMin                                       fMacVersionMin;
        ld::IOSVersionMin                                       fIOSVersionMin;
        DebugInfoStripping                                      fDebugInfoStripping;
        const char*                                                     fTraceOutputFile;
        ld::MacVersionMin                                       fMacVersionMin;
        ld::IOSVersionMin                                       fIOSVersionMin;
+       ld::WatchOSVersionMin                           fWatchOSVersionMin;
        std::vector<AliasPair>                          fAliases;
        std::vector<const char*>                        fInitialUndefines;
        NameSet                                                         fAllowedUndefined;
        std::vector<AliasPair>                          fAliases;
        std::vector<const char*>                        fInitialUndefines;
        NameSet                                                         fAllowedUndefined;
-       NameSet                                                         fWhyLive;
+       SetWithWildcards                                        fWhyLive;
        std::vector<ExtraSection>                       fExtraSections;
        std::vector<SectionAlignment>           fSectionAlignments;
        std::vector<OrderedSymbol>                      fOrderedSymbols;
        std::vector<ExtraSection>                       fExtraSections;
        std::vector<SectionAlignment>           fSectionAlignments;
        std::vector<OrderedSymbol>                      fOrderedSymbols;
index 1680ade089e8c8fa6221d187327a8924c9239cb8..dd0e5b241e8dca5f86c07e6744fc011c30b70e9b 100644 (file)
@@ -51,6 +51,7 @@
 #include <list>
 #include <algorithm>
 #include <unordered_set>
 #include <list>
 #include <algorithm>
 #include <unordered_set>
+#include <utility>
 
 #include <CommonCrypto/CommonDigest.h>
 #include <AvailabilityMacros.h>
 
 #include <CommonCrypto/CommonDigest.h>
 #include <AvailabilityMacros.h>
@@ -65,7 +66,6 @@
 #include "LinkEdit.hpp"
 #include "LinkEditClassic.hpp"
 
 #include "LinkEdit.hpp"
 #include "LinkEditClassic.hpp"
 
-
 namespace ld {
 namespace tool {
 
 namespace ld {
 namespace tool {
 
@@ -82,7 +82,7 @@ OutputFile::OutputFile(const Options& opts)
                rebaseSection(NULL), bindingSection(NULL), weakBindingSection(NULL), 
                lazyBindingSection(NULL), exportSection(NULL), 
                splitSegInfoSection(NULL), functionStartsSection(NULL), 
                rebaseSection(NULL), bindingSection(NULL), weakBindingSection(NULL), 
                lazyBindingSection(NULL), exportSection(NULL), 
                splitSegInfoSection(NULL), functionStartsSection(NULL), 
-               dataInCodeSection(NULL), optimizationHintsSection(NULL), dependentDRsSection(NULL), 
+               dataInCodeSection(NULL), optimizationHintsSection(NULL),
                symbolTableSection(NULL), stringPoolSection(NULL), 
                localRelocationsSection(NULL), externalRelocationsSection(NULL), 
                sectionRelocationsSection(NULL), 
                symbolTableSection(NULL), stringPoolSection(NULL), 
                localRelocationsSection(NULL), externalRelocationsSection(NULL), 
                sectionRelocationsSection(NULL), 
@@ -94,7 +94,6 @@ OutputFile::OutputFile(const Options& opts)
                _hasSplitSegInfo(opts.sharedRegionEligible()),
                _hasFunctionStartsInfo(opts.addFunctionStarts()),
                _hasDataInCodeInfo(opts.addDataInCodeInfo()),
                _hasSplitSegInfo(opts.sharedRegionEligible()),
                _hasFunctionStartsInfo(opts.addFunctionStarts()),
                _hasDataInCodeInfo(opts.addDataInCodeInfo()),
-               _hasDependentDRInfo(opts.needsDependentDRInfo()),
                _hasDynamicSymbolTable(true),
                _hasLocalRelocations(!opts.makeCompressedDyldInfo()),
                _hasExternalRelocations(!opts.makeCompressedDyldInfo()),
                _hasDynamicSymbolTable(true),
                _hasLocalRelocations(!opts.makeCompressedDyldInfo()),
                _hasExternalRelocations(!opts.makeCompressedDyldInfo()),
@@ -120,7 +119,6 @@ OutputFile::OutputFile(const Options& opts)
                _splitSegInfoAtom(NULL),
                _functionStartsAtom(NULL),
                _dataInCodeAtom(NULL),
                _splitSegInfoAtom(NULL),
                _functionStartsAtom(NULL),
                _dataInCodeAtom(NULL),
-               _dependentDRInfoAtom(NULL),
                _optimizationHintsAtom(NULL)
 {
 }
                _optimizationHintsAtom(NULL)
 {
 }
@@ -156,7 +154,10 @@ void OutputFile::write(ld::Internal& state)
        this->synthesizeDebugNotes(state);
        this->buildSymbolTable(state);
        this->generateLinkEditInfo(state);
        this->synthesizeDebugNotes(state);
        this->buildSymbolTable(state);
        this->generateLinkEditInfo(state);
-       this->makeSplitSegInfo(state);
+       if ( _options.sharedRegionEncodingV2() )
+               this->makeSplitSegInfoV2(state);
+       else
+               this->makeSplitSegInfo(state);
        this->updateLINKEDITAddresses(state);
        //this->dumpAtomsBySection(state, false);
        this->writeOutputFile(state);
        this->updateLINKEDITAddresses(state);
        //this->dumpAtomsBySection(state, false);
        this->writeOutputFile(state);
@@ -267,13 +268,7 @@ void OutputFile::updateLINKEDITAddresses(ld::Internal& state)
                _optimizationHintsAtom->encode();
        }
        
                _optimizationHintsAtom->encode();
        }
        
-       if ( _options.needsDependentDRInfo() ) {
-               // build dependent dylib DR info  
-               assert(_dependentDRInfoAtom != NULL);
-               _dependentDRInfoAtom->encode();
-       }
-
-       // build classic symbol table  
+       // build classic symbol table
        assert(_symbolTableAtom != NULL);
        _symbolTableAtom->encode();
        assert(_indirectSymbolTableAtom != NULL);
        assert(_symbolTableAtom != NULL);
        _symbolTableAtom->encode();
        assert(_indirectSymbolTableAtom != NULL);
@@ -1233,6 +1228,8 @@ static bool isPageKind(const ld::Fixup* fixup, bool mustBeGOT=false)
                        return !mustBeGOT;
                case ld::Fixup::kindStoreTargetAddressARM64GOTLoadPage21:
                case ld::Fixup::kindStoreTargetAddressARM64GOTLeaPage21:
                        return !mustBeGOT;
                case ld::Fixup::kindStoreTargetAddressARM64GOTLoadPage21:
                case ld::Fixup::kindStoreTargetAddressARM64GOTLeaPage21:
+               case ld::Fixup::kindStoreTargetAddressARM64TLVPLoadPage21:
+               case ld::Fixup::kindStoreTargetAddressARM64TLVPLoadNowLeaPage21:
                        return true;
                case ld::Fixup::kindSetTargetAddress:
                        f = fixup;
                        return true;
                case ld::Fixup::kindSetTargetAddress:
                        f = fixup;
@@ -1244,6 +1241,8 @@ static bool isPageKind(const ld::Fixup* fixup, bool mustBeGOT=false)
                                        return !mustBeGOT;
                                case ld::Fixup::kindStoreARM64GOTLoadPage21:
                                case ld::Fixup::kindStoreARM64GOTLeaPage21:
                                        return !mustBeGOT;
                                case ld::Fixup::kindStoreARM64GOTLoadPage21:
                                case ld::Fixup::kindStoreARM64GOTLeaPage21:
+                               case ld::Fixup::kindStoreARM64TLVPLoadPage21:
+                               case ld::Fixup::kindStoreARM64TLVPLoadNowLeaPage21:
                                        return true;
                                default:
                                        break;
                                        return true;
                                default:
                                        break;
@@ -1265,6 +1264,8 @@ static bool isPageOffsetKind(const ld::Fixup* fixup, bool mustBeGOT=false)
                        return !mustBeGOT;
                case ld::Fixup::kindStoreTargetAddressARM64GOTLoadPageOff12:
                case ld::Fixup::kindStoreTargetAddressARM64GOTLeaPageOff12:
                        return !mustBeGOT;
                case ld::Fixup::kindStoreTargetAddressARM64GOTLoadPageOff12:
                case ld::Fixup::kindStoreTargetAddressARM64GOTLeaPageOff12:
+               case ld::Fixup::kindStoreTargetAddressARM64TLVPLoadPageOff12:
+               case ld::Fixup::kindStoreTargetAddressARM64TLVPLoadNowLeaPageOff12:
                        return true;
                case ld::Fixup::kindSetTargetAddress:
                        f = fixup;
                        return true;
                case ld::Fixup::kindSetTargetAddress:
                        f = fixup;
@@ -1276,6 +1277,8 @@ static bool isPageOffsetKind(const ld::Fixup* fixup, bool mustBeGOT=false)
                                        return !mustBeGOT;
                                case ld::Fixup::kindStoreARM64GOTLoadPageOff12:
                                case ld::Fixup::kindStoreARM64GOTLeaPageOff12:
                                        return !mustBeGOT;
                                case ld::Fixup::kindStoreARM64GOTLoadPageOff12:
                                case ld::Fixup::kindStoreARM64GOTLeaPageOff12:
+                               case ld::Fixup::kindStoreARM64TLVPLoadPageOff12:
+                               case ld::Fixup::kindStoreARM64TLVPLoadNowLeaPageOff12:
                                        return true;
                                default:
                                        break;
                                        return true;
                                default:
                                        break;
@@ -1295,7 +1298,6 @@ static bool isPageOffsetKind(const ld::Fixup* fixup, bool mustBeGOT=false)
                break; \
        } 
 
                break; \
        } 
 
-
 void OutputFile::applyFixUps(ld::Internal& state, uint64_t mhAddress, const ld::Atom* atom, uint8_t* buffer)
 {
        //fprintf(stderr, "applyFixUps() on %s\n", atom->name());
 void OutputFile::applyFixUps(ld::Internal& state, uint64_t mhAddress, const ld::Atom* atom, uint8_t* buffer)
 {
        //fprintf(stderr, "applyFixUps() on %s\n", atom->name());
@@ -2098,10 +2100,25 @@ void OutputFile::applyFixUps(ld::Internal& state, uint64_t mhAddress, const ld::
                                setInfo(state, atom, buffer, usedByHints, fit->offsetInAtom, (alt.info.delta3 << 2), &infoC);
                        if ( alt.info.count > 2 )
                                setInfo(state, atom, buffer, usedByHints, fit->offsetInAtom, (alt.info.delta4 << 2), &infoD);
                                setInfo(state, atom, buffer, usedByHints, fit->offsetInAtom, (alt.info.delta3 << 2), &infoC);
                        if ( alt.info.count > 2 )
                                setInfo(state, atom, buffer, usedByHints, fit->offsetInAtom, (alt.info.delta4 << 2), &infoD);
-                               
+
+                       if ( _options.sharedRegionEligible() ) {
+                               if ( _options.sharedRegionEncodingV2() ) {
+                                       // In v2 format, all references might be move at dyld shared cache creation time
+                                       usableSegment = false;
+                               }
+                               else {
+                                       // In v1 format, only references to something in __TEXT segment could be optimized
+                                       usableSegment = (strcmp(atom->section().segmentName(), infoB.target->section().segmentName()) == 0);
+                               }
+                       }
+                       else {
+                               // main executables can optimize any reference
+                               usableSegment = true;
+                       }
+
                        switch ( alt.info.kind ) {
                                case LOH_ARM64_ADRP_ADRP:
                        switch ( alt.info.kind ) {
                                case LOH_ARM64_ADRP_ADRP:
-                                       // processed in pass 2 beacuse some ADRP may have been removed
+                                       // processed in pass 2 because some ADRP may have been removed
                                        break;
                                case LOH_ARM64_ADRP_LDR:
                                        LOH_ASSERT(alt.info.count == 1);
                                        break;
                                case LOH_ARM64_ADRP_LDR:
                                        LOH_ASSERT(alt.info.count == 1);
@@ -2109,10 +2126,12 @@ void OutputFile::applyFixUps(ld::Internal& state, uint64_t mhAddress, const ld::
                                        LOH_ASSERT(isPageOffsetKind(infoB.fixup));
                                        LOH_ASSERT(infoA.target == infoB.target);
                                        LOH_ASSERT(infoA.targetAddress == infoB.targetAddress);
                                        LOH_ASSERT(isPageOffsetKind(infoB.fixup));
                                        LOH_ASSERT(infoA.target == infoB.target);
                                        LOH_ASSERT(infoA.targetAddress == infoB.targetAddress);
-                                       usableSegment = ( !_options.sharedRegionEligible() || (strcmp(atom->section().segmentName(), infoB.target->section().segmentName()) == 0) );
                                        isADRP = parseADRP(infoA.instruction, adrpInfoA);
                                        LOH_ASSERT(isADRP);
                                        isLDR = parseLoadOrStore(infoB.instruction, ldrInfoB);
                                        isADRP = parseADRP(infoA.instruction, adrpInfoA);
                                        LOH_ASSERT(isADRP);
                                        isLDR = parseLoadOrStore(infoB.instruction, ldrInfoB);
+                                       // silently ignore LDRs transformed to ADD by TLV pass
+                                       if ( !isLDR && infoB.fixup->kind == ld::Fixup::kindStoreTargetAddressARM64TLVPLoadNowLeaPageOff12 )
+                                               break;
                                        LOH_ASSERT(isLDR);
                                        LOH_ASSERT(ldrInfoB.baseReg == adrpInfoA.destReg);
                                        LOH_ASSERT(ldrInfoB.offset == (infoA.targetAddress & 0x00000FFF));
                                        LOH_ASSERT(isLDR);
                                        LOH_ASSERT(ldrInfoB.baseReg == adrpInfoA.destReg);
                                        LOH_ASSERT(ldrInfoB.offset == (infoA.targetAddress & 0x00000FFF));
@@ -2122,7 +2141,7 @@ void OutputFile::applyFixUps(ld::Internal& state, uint64_t mhAddress, const ld::
                                                set32LE(infoA.instructionContent, makeNOP());
                                                set32LE(infoB.instructionContent, makeLDR_literal(ldrInfoB, infoA.targetAddress, infoB.instructionAddress));
                                                if ( _options.verboseOptimizationHints() )
                                                set32LE(infoA.instructionContent, makeNOP());
                                                set32LE(infoB.instructionContent, makeLDR_literal(ldrInfoB, infoA.targetAddress, infoB.instructionAddress));
                                                if ( _options.verboseOptimizationHints() )
-                                                       fprintf(stderr, "adrp-ldr at 0x%08llX transformed to LDR literal\n", infoB.instructionAddress);
+                                                       fprintf(stderr, "adrp-ldr at 0x%08llX transformed to LDR literal, usableSegment=%d usableSegment\n", infoB.instructionAddress, usableSegment);
                                        }
                                        else {
                                                if ( _options.verboseOptimizationHints() )
                                        }
                                        else {
                                                if ( _options.verboseOptimizationHints() )
@@ -2137,7 +2156,6 @@ void OutputFile::applyFixUps(ld::Internal& state, uint64_t mhAddress, const ld::
                                        LOH_ASSERT(infoC.fixup == NULL);
                                        LOH_ASSERT(infoA.target == infoB.target);
                                        LOH_ASSERT(infoA.targetAddress == infoB.targetAddress);
                                        LOH_ASSERT(infoC.fixup == NULL);
                                        LOH_ASSERT(infoA.target == infoB.target);
                                        LOH_ASSERT(infoA.targetAddress == infoB.targetAddress);
-                                       usableSegment = ( !_options.sharedRegionEligible() || (strcmp(atom->section().segmentName(), infoB.target->section().segmentName()) == 0) );
                                        isADRP = parseADRP(infoA.instruction, adrpInfoA);
                                        LOH_ASSERT(isADRP);
                                        isADD = parseADD(infoB.instruction, addInfoB);
                                        isADRP = parseADRP(infoA.instruction, adrpInfoA);
                                        LOH_ASSERT(isADRP);
                                        isADD = parseADD(infoB.instruction, addInfoB);
@@ -2193,7 +2211,6 @@ void OutputFile::applyFixUps(ld::Internal& state, uint64_t mhAddress, const ld::
                                        isADD = parseADD(infoB.instruction, addInfoB);
                                        LOH_ASSERT(isADD);
                                        LOH_ASSERT(adrpInfoA.destReg == addInfoB.srcReg);
                                        isADD = parseADD(infoB.instruction, addInfoB);
                                        LOH_ASSERT(isADD);
                                        LOH_ASSERT(adrpInfoA.destReg == addInfoB.srcReg);
-                                       usableSegment = ( !_options.sharedRegionEligible() || (strcmp(atom->section().segmentName(), infoB.target->section().segmentName()) == 0) );
                                        if ( usableSegment && withinOneMeg(infoA.targetAddress, infoA.instructionAddress) ) {
                                                // can do T4 transformation and use ADR 
                                                set32LE(infoA.instructionContent, makeADR(addInfoB.destReg, infoA.targetAddress, infoA.instructionAddress));
                                        if ( usableSegment && withinOneMeg(infoA.targetAddress, infoA.instructionAddress) ) {
                                                // can do T4 transformation and use ADR 
                                                set32LE(infoA.instructionContent, makeADR(addInfoB.destReg, infoA.targetAddress, infoA.instructionAddress));
@@ -2227,7 +2244,6 @@ void OutputFile::applyFixUps(ld::Internal& state, uint64_t mhAddress, const ld::
                                                LOH_ASSERT(!ldrInfoB.isFloat);
                                                LOH_ASSERT(ldrInfoC.baseReg == ldrInfoB.reg);
                                                //fprintf(stderr, "infoA.target=%p, %s, infoA.targetAddress=0x%08llX\n", infoA.target, infoA.target->name(), infoA.targetAddress);
                                                LOH_ASSERT(!ldrInfoB.isFloat);
                                                LOH_ASSERT(ldrInfoC.baseReg == ldrInfoB.reg);
                                                //fprintf(stderr, "infoA.target=%p, %s, infoA.targetAddress=0x%08llX\n", infoA.target, infoA.target->name(), infoA.targetAddress);
-                                               usableSegment = ( !_options.sharedRegionEligible() || (strcmp(atom->section().segmentName(), infoB.target->section().segmentName()) == 0) );
                                                targetFourByteAligned = ( ((infoA.targetAddress) & 0x3) == 0 );
                                                if ( usableSegment && targetFourByteAligned && withinOneMeg(infoB.instructionAddress, infoA.targetAddress) ) {
                                                        // can do T5 transform
                                                targetFourByteAligned = ( ((infoA.targetAddress) & 0x3) == 0 );
                                                if ( usableSegment && targetFourByteAligned && withinOneMeg(infoB.instructionAddress, infoA.targetAddress) ) {
                                                        // can do T5 transform
@@ -2246,7 +2262,6 @@ void OutputFile::applyFixUps(ld::Internal& state, uint64_t mhAddress, const ld::
                                                // target of GOT is in same linkage unit and B instruction was changed to ADD to compute LEA of target
                                                LOH_ASSERT(addInfoB.srcReg == adrpInfoA.destReg);
                                                LOH_ASSERT(addInfoB.destReg == ldrInfoC.baseReg);
                                                // target of GOT is in same linkage unit and B instruction was changed to ADD to compute LEA of target
                                                LOH_ASSERT(addInfoB.srcReg == adrpInfoA.destReg);
                                                LOH_ASSERT(addInfoB.destReg == ldrInfoC.baseReg);
-                                               usableSegment = ( !_options.sharedRegionEligible() || (strcmp(atom->section().segmentName(), infoB.target->section().segmentName()) == 0) );
                                                targetFourByteAligned = ( ((infoA.targetAddress) & 0x3) == 0 );
                                                literalableSize  = ( (ldrInfoC.size != 1) && (ldrInfoC.size != 2) );
                                                if ( usableSegment && literalableSize && targetFourByteAligned && withinOneMeg(infoC.instructionAddress, infoA.targetAddress) ) {
                                                targetFourByteAligned = ( ((infoA.targetAddress) & 0x3) == 0 );
                                                literalableSize  = ( (ldrInfoC.size != 1) && (ldrInfoC.size != 2) );
                                                if ( usableSegment && literalableSize && targetFourByteAligned && withinOneMeg(infoC.instructionAddress, infoA.targetAddress) ) {
@@ -2295,7 +2310,6 @@ void OutputFile::applyFixUps(ld::Internal& state, uint64_t mhAddress, const ld::
                                        LOH_ASSERT(infoC.fixup == NULL);
                                        LOH_ASSERT(infoA.target == infoB.target);
                                        LOH_ASSERT(infoA.targetAddress == infoB.targetAddress);
                                        LOH_ASSERT(infoC.fixup == NULL);
                                        LOH_ASSERT(infoA.target == infoB.target);
                                        LOH_ASSERT(infoA.targetAddress == infoB.targetAddress);
-                                       usableSegment = ( !_options.sharedRegionEligible() || (strcmp(atom->section().segmentName(), infoB.target->section().segmentName()) == 0) );
                                        isADRP = parseADRP(infoA.instruction, adrpInfoA);
                                        LOH_ASSERT(isADRP);
                                        isADD = parseADD(infoB.instruction, addInfoB);
                                        isADRP = parseADRP(infoA.instruction, adrpInfoA);
                                        LOH_ASSERT(isADRP);
                                        isADD = parseADD(infoB.instruction, addInfoB);
@@ -2348,7 +2362,6 @@ void OutputFile::applyFixUps(ld::Internal& state, uint64_t mhAddress, const ld::
                                                LOH_ASSERT(ldrInfoB.size == 8);
                                                LOH_ASSERT(!ldrInfoB.isFloat);
                                                LOH_ASSERT(ldrInfoC.baseReg == ldrInfoB.reg);
                                                LOH_ASSERT(ldrInfoB.size == 8);
                                                LOH_ASSERT(!ldrInfoB.isFloat);
                                                LOH_ASSERT(ldrInfoC.baseReg == ldrInfoB.reg);
-                                               usableSegment = ( !_options.sharedRegionEligible() || (strcmp(atom->section().segmentName(), infoB.target->section().segmentName()) == 0) );
                                                targetFourByteAligned = ( ((infoA.targetAddress) & 0x3) == 0 );
                                                if ( usableSegment && targetFourByteAligned && withinOneMeg(infoB.instructionAddress, infoA.targetAddress) ) {
                                                        // can do T5 transform
                                                targetFourByteAligned = ( ((infoA.targetAddress) & 0x3) == 0 );
                                                if ( usableSegment && targetFourByteAligned && withinOneMeg(infoB.instructionAddress, infoA.targetAddress) ) {
                                                        // can do T5 transform
@@ -2367,7 +2380,6 @@ void OutputFile::applyFixUps(ld::Internal& state, uint64_t mhAddress, const ld::
                                                // target of GOT is in same linkage unit and B instruction was changed to ADD to compute LEA of target
                                                LOH_ASSERT(addInfoB.srcReg == adrpInfoA.destReg);
                                                LOH_ASSERT(addInfoB.destReg == ldrInfoC.baseReg);
                                                // target of GOT is in same linkage unit and B instruction was changed to ADD to compute LEA of target
                                                LOH_ASSERT(addInfoB.srcReg == adrpInfoA.destReg);
                                                LOH_ASSERT(addInfoB.destReg == ldrInfoC.baseReg);
-                                               usableSegment = ( !_options.sharedRegionEligible() || (strcmp(atom->section().segmentName(), infoB.target->section().segmentName()) == 0) );
                                                targetFourByteAligned = ( ((infoA.targetAddress) & 0x3) == 0 );
                                                literalableSize  = ( (ldrInfoC.size != 1) && (ldrInfoC.size != 2) );
                                                if ( usableSegment && withinOneMeg(infoA.instructionAddress, infoA.targetAddress) ) {
                                                targetFourByteAligned = ( ((infoA.targetAddress) & 0x3) == 0 );
                                                literalableSize  = ( (ldrInfoC.size != 1) && (ldrInfoC.size != 2) );
                                                if ( usableSegment && withinOneMeg(infoA.instructionAddress, infoA.targetAddress) ) {
@@ -2410,7 +2422,6 @@ void OutputFile::applyFixUps(ld::Internal& state, uint64_t mhAddress, const ld::
                                        isADRP = parseADRP(infoA.instruction, adrpInfoA);
                                        isADD = parseADD(infoB.instruction, addInfoB);
                                        isLDR = parseLoadOrStore(infoB.instruction, ldrInfoB);
                                        isADRP = parseADRP(infoA.instruction, adrpInfoA);
                                        isADD = parseADD(infoB.instruction, addInfoB);
                                        isLDR = parseLoadOrStore(infoB.instruction, ldrInfoB);
-                                       usableSegment = ( !_options.sharedRegionEligible() || (strcmp(atom->section().segmentName(), infoB.target->section().segmentName()) == 0) );
                                        if ( isADRP ) {
                                                if ( isLDR ) {
                                                        if ( usableSegment && withinOneMeg(infoB.instructionAddress, infoA.targetAddress) ) {
                                        if ( isADRP ) {
                                                if ( isLDR ) {
                                                        if ( usableSegment && withinOneMeg(infoB.instructionAddress, infoA.targetAddress) ) {
@@ -2599,12 +2610,32 @@ void OutputFile::writeAtoms(ld::Internal& state, uint8_t* wholeBuffer)
        }
 }
 
        }
 }
 
-
 void OutputFile::computeContentUUID(ld::Internal& state, uint8_t* wholeBuffer)
 {
        const bool log = false;
        if ( (_options.outputKind() != Options::kObjectFile) || state.someObjectFileHasDwarf ) {
                uint8_t digest[CC_MD5_DIGEST_LENGTH];
 void OutputFile::computeContentUUID(ld::Internal& state, uint8_t* wholeBuffer)
 {
        const bool log = false;
        if ( (_options.outputKind() != Options::kObjectFile) || state.someObjectFileHasDwarf ) {
                uint8_t digest[CC_MD5_DIGEST_LENGTH];
+               std::vector<std::pair<uint64_t, uint64_t>> excludeRegions;
+               uint64_t bitcodeCmdOffset;
+               uint64_t bitcodeCmdEnd;
+               uint64_t bitcodeSectOffset;
+               uint64_t bitcodePaddingEnd;
+               if ( _headersAndLoadCommandAtom->bitcodeBundleCommand(bitcodeCmdOffset, bitcodeCmdEnd,
+                                                                                                                         bitcodeSectOffset, bitcodePaddingEnd) ) {
+                       // Exclude embedded bitcode bundle section which contains timestamps in XAR header
+                       // Note the timestamp is in the compressed XML header which means it might change the size of
+                       // bitcode section. The load command which include the size of the section and the padding after
+                       // the bitcode section should also be excluded in the UUID computation.
+                       // Bitcode section should appears before LINKEDIT
+                       // Exclude section cmd
+                       if ( log ) fprintf(stderr, "bundle cmd start=0x%08llX, bundle cmd end=0x%08llX\n",
+                                                          bitcodeCmdOffset, bitcodeCmdEnd);
+                       excludeRegions.emplace_back(std::pair<uint64_t, uint64_t>(bitcodeCmdOffset, bitcodeCmdEnd));
+                       // Exclude section content
+                       if ( log ) fprintf(stderr, "bundle start=0x%08llX, bundle end=0x%08llX\n",
+                                                          bitcodeSectOffset, bitcodePaddingEnd);
+                       excludeRegions.emplace_back(std::pair<uint64_t, uint64_t>(bitcodeSectOffset, bitcodePaddingEnd));
+               }
                uint32_t        stabsStringsOffsetStart;
                uint32_t        tabsStringsOffsetEnd;
                uint32_t        stabsOffsetStart;
                uint32_t        stabsStringsOffsetStart;
                uint32_t        tabsStringsOffsetEnd;
                uint32_t        stabsOffsetStart;
@@ -2631,20 +2662,30 @@ void OutputFile::computeContentUUID(ld::Internal& state, uint8_t* wholeBuffer)
                        if ( log ) fprintf(stderr, "firstStabStringFileOffset=0x%08llX\n", firstStabStringFileOffset);
                        if ( log ) fprintf(stderr, "lastStabStringFileOffset=0x%08llX\n", lastStabStringFileOffset);
                        assert(firstStabNlistFileOffset <= firstStabStringFileOffset);
                        if ( log ) fprintf(stderr, "firstStabStringFileOffset=0x%08llX\n", firstStabStringFileOffset);
                        if ( log ) fprintf(stderr, "lastStabStringFileOffset=0x%08llX\n", lastStabStringFileOffset);
                        assert(firstStabNlistFileOffset <= firstStabStringFileOffset);
-                       
+                       excludeRegions.emplace_back(std::pair<uint64_t, uint64_t>(firstStabNlistFileOffset, lastStabNlistFileOffset));
+                       excludeRegions.emplace_back(std::pair<uint64_t, uint64_t>(firstStabStringFileOffset, lastStabStringFileOffset));
+               }
+               if ( !excludeRegions.empty() ) {
                        CC_MD5_CTX md5state;
                        CC_MD5_Init(&md5state);
                        CC_MD5_CTX md5state;
                        CC_MD5_Init(&md5state);
-                       // checksum everything up to first stabs nlist
-                       if ( log ) fprintf(stderr, "checksum 0x%08X -> 0x%08llX\n", 0, firstStabNlistFileOffset);
-                       CC_MD5_Update(&md5state, &wholeBuffer[0], firstStabNlistFileOffset);
-                       // checkusm everything after last stabs nlist and up to first stabs string
-                       if ( log ) fprintf(stderr, "checksum 0x%08llX -> 0x%08llX\n", lastStabNlistFileOffset, firstStabStringFileOffset);
-                       CC_MD5_Update(&md5state, &wholeBuffer[lastStabNlistFileOffset], firstStabStringFileOffset-lastStabNlistFileOffset);
-                       // checksum everything after last stabs string to end of file
-                       if ( log ) fprintf(stderr, "checksum 0x%08llX -> 0x%08llX\n", lastStabStringFileOffset, _fileSize);
-                       CC_MD5_Update(&md5state, &wholeBuffer[lastStabStringFileOffset], _fileSize-lastStabStringFileOffset);
+                       // rdar://problem/19487042 include the output leaf file name in the hash
+                       const char* lastSlash = strrchr(_options.outputFilePath(), '/');
+                       if ( lastSlash !=  NULL ) {
+                               CC_MD5_Update(&md5state, lastSlash, strlen(lastSlash));
+                       }
+                       uint64_t checksumStart = 0;
+                       for ( auto& region : excludeRegions ) {
+                               uint64_t regionStart = region.first;
+                               uint64_t regionEnd = region.second;
+                               assert(checksumStart <= regionStart && regionStart <= regionEnd && "Region overlapped");
+                               if ( log ) fprintf(stderr, "checksum 0x%08llX -> 0x%08llX\n", checksumStart, regionStart);
+                               CC_MD5_Update(&md5state, &wholeBuffer[checksumStart], regionStart - checksumStart);
+                               checksumStart = regionEnd;
+                       }
+                       if ( log ) fprintf(stderr, "checksum 0x%08llX -> 0x%08llX\n", checksumStart, _fileSize);
+                       CC_MD5_Update(&md5state, &wholeBuffer[checksumStart], _fileSize-checksumStart);
                        CC_MD5_Final(digest, &md5state);
                        CC_MD5_Final(digest, &md5state);
-                       if ( log ) fprintf(stderr, "uuid=%02X, %02X, %02X, %02X, %02X, %02X, %02X, %02X\n", digest[0], digest[1], digest[2], 
+                       if ( log ) fprintf(stderr, "uuid=%02X, %02X, %02X, %02X, %02X, %02X, %02X, %02X\n", digest[0], digest[1], digest[2],
                                                           digest[3], digest[4], digest[5], digest[6],  digest[7]);
                }
                else {
                                                           digest[3], digest[4], digest[5], digest[6],  digest[7]);
                }
                else {
@@ -2658,7 +2699,18 @@ void OutputFile::computeContentUUID(ld::Internal& state, uint8_t* wholeBuffer)
                _headersAndLoadCommandAtom->recopyUUIDCommand();
        }
 }
                _headersAndLoadCommandAtom->recopyUUIDCommand();
        }
 }
-       
+
+static int sDescriptorOfPathToRemove = -1;
+static void removePathAndExit(int sig)
+{
+       if ( sDescriptorOfPathToRemove != -1 ) {
+               char path[MAXPATHLEN];
+               if ( ::fcntl(sDescriptorOfPathToRemove, F_GETPATH, path) == 0 )
+                       ::unlink(path);
+       }
+       fprintf(stderr, "ld: interrupted\n");
+       exit(1);
+}
        
 void OutputFile::writeOutputFile(ld::Internal& state)
 {
        
 void OutputFile::writeOutputFile(ld::Internal& state)
 {
@@ -2724,12 +2776,16 @@ void OutputFile::writeOutputFile(ld::Internal& state)
        char tmpOutput[PATH_MAX];
        uint8_t *wholeBuffer;
        if ( outputIsRegularFile && outputIsMappableFile ) {
        char tmpOutput[PATH_MAX];
        uint8_t *wholeBuffer;
        if ( outputIsRegularFile && outputIsMappableFile ) {
+               // <rdar://problem/20959031> ld64 should clean up temporary files on SIGINT
+               ::signal(SIGINT, removePathAndExit);
+
                strcpy(tmpOutput, _options.outputFilePath());
                // If the path is too long to add a suffix for a temporary name then
                // just fall back to using the output path. 
                if (strlen(tmpOutput)+strlen(filenameTemplate) < PATH_MAX) {
                        strcat(tmpOutput, filenameTemplate);
                        fd = mkstemp(tmpOutput);
                strcpy(tmpOutput, _options.outputFilePath());
                // If the path is too long to add a suffix for a temporary name then
                // just fall back to using the output path. 
                if (strlen(tmpOutput)+strlen(filenameTemplate) < PATH_MAX) {
                        strcat(tmpOutput, filenameTemplate);
                        fd = mkstemp(tmpOutput);
+                       sDescriptorOfPathToRemove = fd;
                } 
                else {
                        fd = open(tmpOutput, O_RDWR|O_CREAT, permissions);
                } 
                else {
                        fd = open(tmpOutput, O_RDWR|O_CREAT, permissions);
@@ -2788,11 +2844,24 @@ void OutputFile::writeOutputFile(ld::Internal& state)
                if ( ::write(fd, wholeBuffer, _fileSize) == -1 ) {
                        throwf("can't write to output file: %s, errno=%d", _options.outputFilePath(), errno);
                }
                if ( ::write(fd, wholeBuffer, _fileSize) == -1 ) {
                        throwf("can't write to output file: %s, errno=%d", _options.outputFilePath(), errno);
                }
+               sDescriptorOfPathToRemove = -1;
                ::close(fd);
                // <rdar://problem/13118223> NFS: iOS incremental builds in Xcode 4.6 fail with codesign error
                // NFS seems to pad the end of the file sometimes.  Calling trunc seems to correct it...
                ::truncate(_options.outputFilePath(), _fileSize);
        }
                ::close(fd);
                // <rdar://problem/13118223> NFS: iOS incremental builds in Xcode 4.6 fail with codesign error
                // NFS seems to pad the end of the file sometimes.  Calling trunc seems to correct it...
                ::truncate(_options.outputFilePath(), _fileSize);
        }
+
+       // Rename symbol map file if needed
+       if ( _options.renameReverseSymbolMap() ) {
+               assert(_options.hideSymbols() && _options.reverseSymbolMapPath() != NULL && "Must hide symbol and specify a path");
+               uuid_string_t UUIDString;
+               const uint8_t* rawUUID = _headersAndLoadCommandAtom->getUUID();
+               uuid_unparse_upper(rawUUID, UUIDString);
+               char outputMapPath[PATH_MAX];
+               sprintf(outputMapPath, "%s/%s.bcsymbolmap", _options.reverseSymbolMapPath(), UUIDString);
+               if ( ::rename(_options.reverseMapTempPath().c_str(), outputMapPath) != 0 )
+                       throwf("could not create bcsymbolmap file: %s", outputMapPath);
+       }
 }
 
 struct AtomByNameSorter
 }
 
 struct AtomByNameSorter
@@ -3114,7 +3183,7 @@ void OutputFile::addLinkEdit(ld::Internal& state)
                                localRelocationsSection = state.addAtom(*_localRelocsAtom);
                        }
                        if  ( _hasSplitSegInfo ) {
                                localRelocationsSection = state.addAtom(*_localRelocsAtom);
                        }
                        if  ( _hasSplitSegInfo ) {
-                               _splitSegInfoAtom = new SplitSegInfoAtom<x86>(_options, state, *this);
+                               _splitSegInfoAtom = new SplitSegInfoV1Atom<x86>(_options, state, *this);
                                splitSegInfoSection = state.addAtom(*_splitSegInfoAtom);
                        }
                        if ( _hasFunctionStartsInfo ) {
                                splitSegInfoSection = state.addAtom(*_splitSegInfoAtom);
                        }
                        if ( _hasFunctionStartsInfo ) {
@@ -3129,10 +3198,6 @@ void OutputFile::addLinkEdit(ld::Internal& state)
                                _optimizationHintsAtom = new OptimizationHintsAtom<x86>(_options, state, *this);
                                optimizationHintsSection = state.addAtom(*_optimizationHintsAtom);
                        }
                                _optimizationHintsAtom = new OptimizationHintsAtom<x86>(_options, state, *this);
                                optimizationHintsSection = state.addAtom(*_optimizationHintsAtom);
                        }
-                       if ( _hasDependentDRInfo ) {
-                               _dependentDRInfoAtom = new DependentDRAtom<x86>(_options, state, *this);
-                               dependentDRsSection = state.addAtom(*_dependentDRInfoAtom);
-                       }
                        if ( _hasSymbolTable ) {
                                _symbolTableAtom = new SymbolTableAtom<x86>(_options, state, *this);
                                symbolTableSection = state.addAtom(*_symbolTableAtom);
                        if ( _hasSymbolTable ) {
                                _symbolTableAtom = new SymbolTableAtom<x86>(_options, state, *this);
                                symbolTableSection = state.addAtom(*_symbolTableAtom);
@@ -3176,7 +3241,7 @@ void OutputFile::addLinkEdit(ld::Internal& state)
                                localRelocationsSection = state.addAtom(*_localRelocsAtom);
                        }
                        if  ( _hasSplitSegInfo ) {
                                localRelocationsSection = state.addAtom(*_localRelocsAtom);
                        }
                        if  ( _hasSplitSegInfo ) {
-                               _splitSegInfoAtom = new SplitSegInfoAtom<x86_64>(_options, state, *this);
+                               _splitSegInfoAtom = new SplitSegInfoV1Atom<x86_64>(_options, state, *this);
                                splitSegInfoSection = state.addAtom(*_splitSegInfoAtom);
                        }
                        if ( _hasFunctionStartsInfo ) {
                                splitSegInfoSection = state.addAtom(*_splitSegInfoAtom);
                        }
                        if ( _hasFunctionStartsInfo ) {
@@ -3191,10 +3256,6 @@ void OutputFile::addLinkEdit(ld::Internal& state)
                                _optimizationHintsAtom = new OptimizationHintsAtom<x86_64>(_options, state, *this);
                                optimizationHintsSection = state.addAtom(*_optimizationHintsAtom);
                        }
                                _optimizationHintsAtom = new OptimizationHintsAtom<x86_64>(_options, state, *this);
                                optimizationHintsSection = state.addAtom(*_optimizationHintsAtom);
                        }
-                       if ( _hasDependentDRInfo ) {
-                               _dependentDRInfoAtom = new DependentDRAtom<x86_64>(_options, state, *this);
-                               dependentDRsSection = state.addAtom(*_dependentDRInfoAtom);
-                       }
                        if ( _hasSymbolTable ) {
                                _symbolTableAtom = new SymbolTableAtom<x86_64>(_options, state, *this);
                                symbolTableSection = state.addAtom(*_symbolTableAtom);
                        if ( _hasSymbolTable ) {
                                _symbolTableAtom = new SymbolTableAtom<x86_64>(_options, state, *this);
                                symbolTableSection = state.addAtom(*_symbolTableAtom);
@@ -3238,7 +3299,10 @@ void OutputFile::addLinkEdit(ld::Internal& state)
                                localRelocationsSection = state.addAtom(*_localRelocsAtom);
                        }
                        if  ( _hasSplitSegInfo ) {
                                localRelocationsSection = state.addAtom(*_localRelocsAtom);
                        }
                        if  ( _hasSplitSegInfo ) {
-                               _splitSegInfoAtom = new SplitSegInfoAtom<arm>(_options, state, *this);
+                               if ( _options.sharedRegionEncodingV2() )
+                                       _splitSegInfoAtom = new SplitSegInfoV2Atom<arm>(_options, state, *this);
+                               else
+                                       _splitSegInfoAtom = new SplitSegInfoV1Atom<arm>(_options, state, *this);
                                splitSegInfoSection = state.addAtom(*_splitSegInfoAtom);
                        }
                        if ( _hasFunctionStartsInfo ) {
                                splitSegInfoSection = state.addAtom(*_splitSegInfoAtom);
                        }
                        if ( _hasFunctionStartsInfo ) {
@@ -3253,10 +3317,6 @@ void OutputFile::addLinkEdit(ld::Internal& state)
                                _optimizationHintsAtom = new OptimizationHintsAtom<arm>(_options, state, *this);
                                optimizationHintsSection = state.addAtom(*_optimizationHintsAtom);
                        }
                                _optimizationHintsAtom = new OptimizationHintsAtom<arm>(_options, state, *this);
                                optimizationHintsSection = state.addAtom(*_optimizationHintsAtom);
                        }
-                       if ( _hasDependentDRInfo ) {
-                               _dependentDRInfoAtom = new DependentDRAtom<arm>(_options, state, *this);
-                               dependentDRsSection = state.addAtom(*_dependentDRInfoAtom);
-                       }
                        if ( _hasSymbolTable ) {
                                _symbolTableAtom = new SymbolTableAtom<arm>(_options, state, *this);
                                symbolTableSection = state.addAtom(*_symbolTableAtom);
                        if ( _hasSymbolTable ) {
                                _symbolTableAtom = new SymbolTableAtom<arm>(_options, state, *this);
                                symbolTableSection = state.addAtom(*_symbolTableAtom);
@@ -3300,7 +3360,10 @@ void OutputFile::addLinkEdit(ld::Internal& state)
                                localRelocationsSection = state.addAtom(*_localRelocsAtom);
                        }
                        if  ( _hasSplitSegInfo ) {
                                localRelocationsSection = state.addAtom(*_localRelocsAtom);
                        }
                        if  ( _hasSplitSegInfo ) {
-                               _splitSegInfoAtom = new SplitSegInfoAtom<arm64>(_options, state, *this);
+                               if ( _options.sharedRegionEncodingV2() )
+                                       _splitSegInfoAtom = new SplitSegInfoV2Atom<arm64>(_options, state, *this);
+                               else
+                                       _splitSegInfoAtom = new SplitSegInfoV1Atom<arm64>(_options, state, *this);
                                splitSegInfoSection = state.addAtom(*_splitSegInfoAtom);
                        }
                        if ( _hasFunctionStartsInfo ) {
                                splitSegInfoSection = state.addAtom(*_splitSegInfoAtom);
                        }
                        if ( _hasFunctionStartsInfo ) {
@@ -3315,10 +3378,6 @@ void OutputFile::addLinkEdit(ld::Internal& state)
                                _optimizationHintsAtom = new OptimizationHintsAtom<arm64>(_options, state, *this);
                                optimizationHintsSection = state.addAtom(*_optimizationHintsAtom);
                        }
                                _optimizationHintsAtom = new OptimizationHintsAtom<arm64>(_options, state, *this);
                                optimizationHintsSection = state.addAtom(*_optimizationHintsAtom);
                        }
-                       if ( _hasDependentDRInfo ) {
-                               _dependentDRInfoAtom = new DependentDRAtom<arm64>(_options, state, *this);
-                               dependentDRsSection = state.addAtom(*_dependentDRInfoAtom);
-                       }
                        if ( _hasSymbolTable ) {
                                _symbolTableAtom = new SymbolTableAtom<arm64>(_options, state, *this);
                                symbolTableSection = state.addAtom(*_symbolTableAtom);
                        if ( _hasSymbolTable ) {
                                _symbolTableAtom = new SymbolTableAtom<arm64>(_options, state, *this);
                                symbolTableSection = state.addAtom(*_symbolTableAtom);
@@ -4401,7 +4460,6 @@ void OutputFile::addSectionRelocs(ld::Internal& state, ld::Internal::FinalSectio
 
 }
 
 
 }
 
-
 void OutputFile::makeSplitSegInfo(ld::Internal& state)
 {
        if ( !_options.sharedRegionEligible() )
 void OutputFile::makeSplitSegInfo(ld::Internal& state)
 {
        if ( !_options.sharedRegionEligible() )
@@ -4503,6 +4561,183 @@ void OutputFile::makeSplitSegInfo(ld::Internal& state)
        }
 }
 
        }
 }
 
+void OutputFile::makeSplitSegInfoV2(ld::Internal& state)
+{
+       static const bool log = false;
+       if ( !_options.sharedRegionEligible() )
+               return;
+       
+       for (std::vector<ld::Internal::FinalSection*>::iterator sit = state.sections.begin(); sit != state.sections.end(); ++sit) {
+               ld::Internal::FinalSection* sect = *sit;
+               if ( sect->isSectionHidden() )
+                       continue;
+               bool codeSection = (sect->type() == ld::Section::typeCode);
+               if (log) fprintf(stderr, "sect: %s, address=0x%llX\n", sect->sectionName(), sect->address);
+               for (std::vector<const ld::Atom*>::iterator ait = sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
+                       const ld::Atom* atom = *ait;
+                       const ld::Atom* target = NULL;
+                       const ld::Atom* fromTarget = NULL;
+                       uint32_t picBase = 0;
+            uint64_t accumulator = 0;
+            bool thumbTarget;
+                       bool hadSubtract = false;
+                       uint8_t fromSectionIndex = atom->machoSection();
+                       uint8_t toSectionIndex;
+                       uint8_t kind = 0;
+                       uint64_t fromOffset = 0;
+                       uint64_t toOffset = 0;
+                       uint64_t addend = 0;
+                       for (ld::Fixup::iterator fit = atom->fixupsBegin(), end=atom->fixupsEnd(); fit != end; ++fit) {
+                               if ( fit->firstInCluster() ) {
+                                       target = NULL;
+                                       fromTarget = NULL;
+                                       kind = 0;
+                                       addend = 0;
+                                       toSectionIndex = 255;
+                                       fromOffset = atom->finalAddress() + fit->offsetInAtom - sect->address;
+                               }
+                               if ( this->setsTarget(fit->kind) ) {
+                                       accumulator = addressOf(state, fit, &target);                   
+                                       thumbTarget = targetIsThumb(state, fit);
+                                       if ( thumbTarget ) 
+                                               accumulator |= 1;
+                                       toOffset = accumulator - state.atomToSection[target]->address;
+                                       if ( target->definition() != ld::Atom::definitionProxy ) {
+                                               if ( target->section().type() == ld::Section::typeMachHeader )
+                                                       toSectionIndex = 0;
+                                               else
+                                                       toSectionIndex = target->machoSection();
+                                       }
+                               }
+                               switch ( fit->kind ) {
+                                       case ld::Fixup::kindSubtractTargetAddress:
+                        accumulator -= addressOf(state, fit, &fromTarget);
+                                               hadSubtract = true;
+                                               break;
+                    case ld::Fixup::kindAddAddend:
+                                               accumulator += fit->u.addend;
+                                               addend = fit->u.addend;
+                                               break;
+                    case ld::Fixup::kindSubtractAddend:
+                                               accumulator -= fit->u.addend;
+                                               picBase = fit->u.addend;
+                                               break;
+                                       case ld::Fixup::kindSetLazyOffset:
+                                               break;
+                                       case ld::Fixup::kindStoreBigEndian32:
+                                       case ld::Fixup::kindStoreLittleEndian32:
+                                       case ld::Fixup::kindStoreTargetAddressLittleEndian32:
+                                               if ( kind != DYLD_CACHE_ADJ_V2_IMAGE_OFF_32 ) {
+                                                       if ( hadSubtract )
+                                                               kind = DYLD_CACHE_ADJ_V2_DELTA_32;
+                                                       else
+                                                               kind = DYLD_CACHE_ADJ_V2_POINTER_32;
+                                               }
+                                               break;
+                                       case ld::Fixup::kindStoreLittleEndian64:
+                                       case ld::Fixup::kindStoreTargetAddressLittleEndian64:
+                                               if ( hadSubtract )
+                                                       kind = DYLD_CACHE_ADJ_V2_DELTA_64;
+                                               else
+                                                       kind = DYLD_CACHE_ADJ_V2_POINTER_64;
+                                               break;
+                                       case ld::Fixup::kindStoreX86PCRel32:
+                                       case ld::Fixup::kindStoreX86PCRel32_1:
+                                       case ld::Fixup::kindStoreX86PCRel32_2:
+                                       case ld::Fixup::kindStoreX86PCRel32_4:
+                                       case ld::Fixup::kindStoreX86PCRel32GOTLoad:
+                                       case ld::Fixup::kindStoreX86PCRel32GOTLoadNowLEA:
+                                       case ld::Fixup::kindStoreX86PCRel32GOT:
+                                       case ld::Fixup::kindStoreX86PCRel32TLVLoad:
+                                       case ld::Fixup::kindStoreX86PCRel32TLVLoadNowLEA:
+                                       case ld::Fixup::kindStoreTargetAddressX86PCRel32:
+                                       case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoad:
+                                       case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoadNowLEA:
+                                       case ld::Fixup::kindStoreTargetAddressX86PCRel32TLVLoad:
+                                       case ld::Fixup::kindStoreTargetAddressX86PCRel32TLVLoadNowLEA:
+#if SUPPORT_ARCH_arm64
+                                       case ld::Fixup::kindStoreARM64PCRelToGOT:
+#endif
+                                               if ( (fromSectionIndex != toSectionIndex) || !codeSection )
+                                                       kind = DYLD_CACHE_ADJ_V2_DELTA_32;
+                                               break;
+#if SUPPORT_ARCH_arm64
+                                       case ld::Fixup::kindStoreARM64Page21:
+                                       case ld::Fixup::kindStoreARM64GOTLoadPage21:
+                                       case ld::Fixup::kindStoreARM64GOTLeaPage21:
+                                       case ld::Fixup::kindStoreARM64TLVPLoadPage21:
+                                       case ld::Fixup::kindStoreTargetAddressARM64Page21:
+                                       case ld::Fixup::kindStoreTargetAddressARM64GOTLoadPage21:
+                                       case ld::Fixup::kindStoreTargetAddressARM64GOTLeaPage21:
+                                               if ( fromSectionIndex != toSectionIndex )
+                                                       kind = DYLD_CACHE_ADJ_V2_ARM64_ADRP;
+                                               break;
+                                       case ld::Fixup::kindStoreARM64PageOff12:
+                                       case ld::Fixup::kindStoreARM64GOTLeaPageOff12:
+                                       case ld::Fixup::kindStoreARM64TLVPLoadNowLeaPageOff12:
+                                       case ld::Fixup::kindStoreTargetAddressARM64PageOff12:
+                                       case ld::Fixup::kindStoreTargetAddressARM64GOTLeaPageOff12:
+                                       case ld::Fixup::kindStoreTargetAddressARM64GOTLoadPageOff12:
+                                       case ld::Fixup::kindStoreTargetAddressARM64TLVPLoadPageOff12:
+                                       case ld::Fixup::kindStoreTargetAddressARM64TLVPLoadNowLeaPageOff12:
+                                               if ( fromSectionIndex != toSectionIndex )
+                                                       kind = DYLD_CACHE_ADJ_V2_ARM64_OFF12;
+                                               break;
+                                       case ld::Fixup::kindStoreARM64Branch26:
+                                       case ld::Fixup::kindStoreTargetAddressARM64Branch26:
+                                               if ( fromSectionIndex != toSectionIndex )
+                                                       kind = DYLD_CACHE_ADJ_V2_ARM64_BR26;
+                                               break;
+#endif
+                    case ld::Fixup::kindStoreARMHigh16:
+                    case ld::Fixup::kindStoreARMLow16:
+                                               if ( (fromSectionIndex != toSectionIndex) && (fromTarget == atom) ) {
+                                                       kind = DYLD_CACHE_ADJ_V2_ARM_MOVW_MOVT;
+                                               }
+                                               break;
+                                       case ld::Fixup::kindStoreARMBranch24:
+                                       case ld::Fixup::kindStoreTargetAddressARMBranch24:
+                                               if ( fromSectionIndex != toSectionIndex )
+                                                       kind = DYLD_CACHE_ADJ_V2_ARM_BR24;
+                                               break;
+                    case ld::Fixup::kindStoreThumbLow16:
+                    case ld::Fixup::kindStoreThumbHigh16:
+                                               if ( (fromSectionIndex != toSectionIndex) && (fromTarget == atom) ) {
+                                                       kind = DYLD_CACHE_ADJ_V2_THUMB_MOVW_MOVT;
+                                               }
+                                               break;
+                                       case ld::Fixup::kindStoreThumbBranch22:
+                                       case ld::Fixup::kindStoreTargetAddressThumbBranch22:
+                                               if ( fromSectionIndex != toSectionIndex )
+                                                       kind = DYLD_CACHE_ADJ_V2_THUMB_BR22;
+                                               break;
+                                       case ld::Fixup::kindSetTargetImageOffset:
+                                               kind = DYLD_CACHE_ADJ_V2_IMAGE_OFF_32;
+                                               accumulator = addressOf(state, fit, &target);                   
+                                               assert(target != NULL);
+                                               toSectionIndex = target->machoSection();
+                                               toOffset = accumulator - state.atomToSection[target]->address;
+                                               hadSubtract = true;
+                                               break;
+                                       default:
+                                               break;
+                               }
+                               if ( fit->lastInCluster() ) {
+                                       if ( (kind != 0) && (target != NULL) && (target->definition() != ld::Atom::definitionProxy) ) {
+                                               if ( !hadSubtract && addend )
+                                                       toOffset += addend;
+                                               assert(toSectionIndex != 255);
+                                               if (log) fprintf(stderr, "from (%d.%s + 0x%llX) to (%d.%s + 0x%llX), kind=%d, atomAddr=0x%llX, sectAddr=0x%llx\n",
+                                                                               fromSectionIndex, sect->sectionName(), fromOffset, toSectionIndex, state.atomToSection[target]->sectionName(),
+                                                                               toOffset, kind, atom->finalAddress(), sect->address);
+                                               _splitSegV2Infos.push_back(SplitSegInfoV2Entry(fromSectionIndex, fromOffset, toSectionIndex, toOffset, kind));
+                                       }
+                               }
+                       }
+               }
+       }
+}
+
 
 void OutputFile::writeMapFile(ld::Internal& state)
 {
 
 void OutputFile::writeMapFile(ld::Internal& state)
 {
@@ -4618,7 +4853,6 @@ void OutputFile::writeMapFile(ld::Internal& state)
        }
 }
 
        }
 }
 
-
 // used to sort atoms with debug notes
 class DebugNoteSorter
 {
 // used to sort atoms with debug notes
 class DebugNoteSorter
 {
index 6bb793bf951de806910865b4b783d20fad6e8283..cbb1cfe621e457af397f2f9d52d66faaa4876a78 100644 (file)
@@ -83,7 +83,6 @@ public:
        ld::Internal::FinalSection*     functionStartsSection;
        ld::Internal::FinalSection*     dataInCodeSection;
        ld::Internal::FinalSection*     optimizationHintsSection;
        ld::Internal::FinalSection*     functionStartsSection;
        ld::Internal::FinalSection*     dataInCodeSection;
        ld::Internal::FinalSection*     optimizationHintsSection;
-       ld::Internal::FinalSection*     dependentDRsSection;
        ld::Internal::FinalSection*     symbolTableSection;
        ld::Internal::FinalSection*     stringPoolSection;
        ld::Internal::FinalSection*     localRelocationsSection;
        ld::Internal::FinalSection*     symbolTableSection;
        ld::Internal::FinalSection*     stringPoolSection;
        ld::Internal::FinalSection*     localRelocationsSection;
@@ -132,12 +131,23 @@ public:
        };
        
        struct SplitSegInfoEntry {
        };
        
        struct SplitSegInfoEntry {
-                                               SplitSegInfoEntry(uint64_t a, ld::Fixup::Kind k, uint32_t e=0) : address(a), kind(k), extra(e) {}
-               uint64_t                address;
+                                               SplitSegInfoEntry(uint64_t a, ld::Fixup::Kind k, uint32_t e=0)
+                                                       : fixupAddress(a), kind(k), extra(e) {}
+               uint64_t                fixupAddress;
                ld::Fixup::Kind kind;
         uint32_t        extra;
        };
        
                ld::Fixup::Kind kind;
         uint32_t        extra;
        };
        
+       struct SplitSegInfoV2Entry {
+                                               SplitSegInfoV2Entry(uint8_t fi, uint64_t fo, uint8_t ti, uint64_t to, uint8_t k)
+                                                       : fixupSectionOffset(fo), targetSectionOffset(to), fixupSectionIndex(fi), targetSectionIndex(ti), referenceKind(k) {}
+               uint64_t                fixupSectionOffset;
+               uint64_t                targetSectionOffset;
+               uint8_t                 fixupSectionIndex;
+               uint8_t                 targetSectionIndex;
+               uint8_t                 referenceKind;
+       };
+
 private:
        void                                            writeAtoms(ld::Internal& state, uint8_t* wholeBuffer);
        void                                            computeContentUUID(ld::Internal& state, uint8_t* wholeBuffer);
 private:
        void                                            writeAtoms(ld::Internal& state, uint8_t* wholeBuffer);
        void                                            computeContentUUID(ld::Internal& state, uint8_t* wholeBuffer);
@@ -192,6 +202,7 @@ private:
        void                                            makeSectionRelocations(ld::Internal& state);
        void                                            makeDyldInfo(ld::Internal& state);
        void                                            makeSplitSegInfo(ld::Internal& state);
        void                                            makeSectionRelocations(ld::Internal& state);
        void                                            makeDyldInfo(ld::Internal& state);
        void                                            makeSplitSegInfo(ld::Internal& state);
+       void                                            makeSplitSegInfoV2(ld::Internal& state);
        void                                            writeMapFile(ld::Internal& state);
        uint64_t                                        lookBackAddend(ld::Fixup::iterator fit);
        bool                                            takesNoDiskSpace(const ld::Section* sect);
        void                                            writeMapFile(ld::Internal& state);
        uint64_t                                        lookBackAddend(ld::Fixup::iterator fit);
        bool                                            takesNoDiskSpace(const ld::Section* sect);
@@ -271,7 +282,6 @@ private:
        const bool                                                              _hasSplitSegInfo;
        const bool                                                              _hasFunctionStartsInfo;
        const bool                                                              _hasDataInCodeInfo;
        const bool                                                              _hasSplitSegInfo;
        const bool                                                              _hasFunctionStartsInfo;
        const bool                                                              _hasDataInCodeInfo;
-       const bool                                                              _hasDependentDRInfo;
                  bool                                                          _hasDynamicSymbolTable;
                  bool                                                          _hasLocalRelocations;
                  bool                                                          _hasExternalRelocations;
                  bool                                                          _hasDynamicSymbolTable;
                  bool                                                          _hasLocalRelocations;
                  bool                                                          _hasExternalRelocations;
@@ -296,6 +306,7 @@ public:
        std::vector<BindingInfo>                                _lazyBindingInfo;
        std::vector<BindingInfo>                                _weakBindingInfo;
        std::vector<SplitSegInfoEntry>                  _splitSegInfos;
        std::vector<BindingInfo>                                _lazyBindingInfo;
        std::vector<BindingInfo>                                _weakBindingInfo;
        std::vector<SplitSegInfoEntry>                  _splitSegInfos;
+       std::vector<SplitSegInfoV2Entry>                _splitSegV2Infos;
        class HeaderAndLoadCommandsAbtract*             _headersAndLoadCommandAtom;
        class RelocationsAtomAbstract*                  _sectionsRelocationsAtom;
        class RelocationsAtomAbstract*                  _localRelocsAtom;
        class HeaderAndLoadCommandsAbtract*             _headersAndLoadCommandAtom;
        class RelocationsAtomAbstract*                  _sectionsRelocationsAtom;
        class RelocationsAtomAbstract*                  _localRelocsAtom;
@@ -311,7 +322,6 @@ public:
        class LinkEditAtom*                                             _splitSegInfoAtom;
        class LinkEditAtom*                                             _functionStartsAtom;
        class LinkEditAtom*                                             _dataInCodeAtom;
        class LinkEditAtom*                                             _splitSegInfoAtom;
        class LinkEditAtom*                                             _functionStartsAtom;
        class LinkEditAtom*                                             _dataInCodeAtom;
-       class LinkEditAtom*                                             _dependentDRInfoAtom;
        class LinkEditAtom*                                             _optimizationHintsAtom;
 };
 
        class LinkEditAtom*                                             _optimizationHintsAtom;
 };
 
index 8a72b67dcd20ff1c1f16f674d99a01f50551e858..094c98d0085c73837468b421bd67e7ee111983cf 100644 (file)
@@ -53,6 +53,7 @@
 #include "Options.h"
 
 #include "ld.hpp"
 #include "Options.h"
 
 #include "ld.hpp"
+#include "Bitcode.hpp"
 #include "InputFiles.h"
 #include "SymbolTable.h"
 #include "Resolver.h"
 #include "InputFiles.h"
 #include "SymbolTable.h"
 #include "Resolver.h"
@@ -282,6 +283,8 @@ void Resolver::initializeState()
                _internal.objcObjectConstraint = ld::File::objcConstraintGC;
        
        _internal.cpuSubType = _options.subArchitecture();
                _internal.objcObjectConstraint = ld::File::objcConstraintGC;
        
        _internal.cpuSubType = _options.subArchitecture();
+       _internal.minOSVersion = _options.minOSversion();
+       _internal.derivedPlatformLoadCommand = 0;
        
        // In -r mode, look for -linker_option additions
        if ( _options.outputKind() == Options::kObjectFile ) {
        
        // In -r mode, look for -linker_option additions
        if ( _options.outputKind() == Options::kObjectFile ) {
@@ -330,14 +333,20 @@ void Resolver::doLinkerOption(const std::vector<const char*>& linkerOption, cons
        }
 }
 
        }
 }
 
-static void userReadableSwiftVersion(uint8_t value, char versionString[32])
+static void userReadableSwiftVersion(uint8_t value, char versionString[64])
 {
        switch (value) {
                case 1:
                        strcpy(versionString, "1.0");
                        break;
 {
        switch (value) {
                case 1:
                        strcpy(versionString, "1.0");
                        break;
+               case 2:
+                       strcpy(versionString, "1.1");
+                       break;
+               case 3:
+                       strcpy(versionString, "2.0");
+                       break;
                default:
                default:
-                       sprintf(versionString, "0x%02X", value);
+                       sprintf(versionString, "unknown ABI version 0x%02X", value);
        }
 }
 
        }
 }
 
@@ -349,12 +358,67 @@ void Resolver::doFile(const ld::File& file)
        if ( objFile != NULL ) {
                // if file has linker options, process them
                ld::relocatable::File::LinkerOptionsList* lo = objFile->linkerOptions();
        if ( objFile != NULL ) {
                // if file has linker options, process them
                ld::relocatable::File::LinkerOptionsList* lo = objFile->linkerOptions();
-               if ( lo != NULL ) {
+               if ( lo != NULL && !_options.ignoreAutoLink() ) {
                        for (relocatable::File::LinkerOptionsList::const_iterator it=lo->begin(); it != lo->end(); ++it) {
                                this->doLinkerOption(*it, file.path());
                        }
                }
                        for (relocatable::File::LinkerOptionsList::const_iterator it=lo->begin(); it != lo->end(); ++it) {
                                this->doLinkerOption(*it, file.path());
                        }
                }
-               
+
+               // Resolve bitcode section in the object file
+               if ( _options.bundleBitcode() ) {
+                       if ( objFile->getBitcode() == NULL ) {
+                               // No bitcode section, figure out if the object file comes from LTO/compiler static library
+                               if (objFile->sourceKind() != ld::relocatable::File::kSourceLTO &&
+                                       objFile->sourceKind() != ld::relocatable::File::kSourceCompilerArchive ) {
+                                       switch ( _options.platform() ) {
+                                       case Options::kPlatformOSX:
+                                       case Options::kPlatformUnknown:
+                                               warning("all bitcode will be dropped because '%s' was built without bitcode. "
+                                                               "You must rebuild it with bitcode enabled (Xcode setting ENABLE_BITCODE), obtain an updated library from the vendor, or disable bitcode for this target. ", file.path());
+                                               _internal.filesWithBitcode.clear();
+                                               _internal.dropAllBitcode = true;
+                                               break;
+                                       case Options::kPlatformiOS:
+                                               throwf("'%s' does not contain bitcode. "
+                                                          "You must rebuild it with bitcode enabled (Xcode setting ENABLE_BITCODE), obtain an updated library from the vendor, or disable bitcode for this target.", file.path());
+                                               break;
+                                       case Options::kPlatformWatchOS:
+                                               throwf("'%s' does not contain bitcode. "
+                                                               "You must rebuild it with bitcode enabled (Xcode setting ENABLE_BITCODE) or obtain an updated library from the vendor", file.path());
+                                               break;
+                       #if SUPPORT_APPLE_TV
+                                       case Options::kPlatform_tvOS:
+                                               warning("URGENT: all bitcode will be dropped because '%s' was built without bitcode. "
+                                                               "You must rebuild it with bitcode enabled (Xcode setting ENABLE_BITCODE) or obtain an updated library from the vendor. "
+                                                               "Note: This will be an error in the future.", file.path());
+                                               _internal.filesWithBitcode.clear();
+                                               _internal.dropAllBitcode = true;
+                                               break;
+                       #endif
+                                       }
+                               }
+                       } else {
+                               // contains bitcode, check if it is just a marker
+                               if ( objFile->getBitcode()->isMarker() ) {
+                                       // if the bitcode is just a marker,
+                                       // the executable will be created without bitcode section.
+                                       // Otherwise, create a marker.
+                                       if ( _options.outputKind() != Options::kDynamicExecutable &&
+                                                _options.outputKind() != Options::kStaticExecutable )
+                                               _internal.embedMarkerOnly = true;
+                                       // Issue a warning if the marker is in the static library and filesWithBitcode is not empty.
+                                       // That means there are object files actually compiled with full bitcode but the archive only has marker.
+                                       // Don't warn on normal object files because it can be a debug build using archives with full bitcode.
+                                       if ( !_internal.filesWithBitcode.empty() && objFile->sourceKind() == ld::relocatable::File::kSourceArchive )
+                                               warning("full bitcode bundle could not be generated because '%s' was built only with bitcode marker. "
+                                                               "The library must be generated from Xcode archive build with bitcode enabled (Xcode setting ENABLE_BITCODE)", objFile->path());
+                                       _internal.filesWithBitcode.clear();
+                                       _internal.dropAllBitcode = true;
+                               } else if ( !_internal.dropAllBitcode )
+                                       _internal.filesWithBitcode.push_back(objFile);
+                       }
+               }
+
                // update which form of ObjC is being used
                switch ( file.objCConstraint() ) {
                        case ld::File::objcConstraintNone:
                // update which form of ObjC is being used
                switch ( file.objCConstraint() ) {
                        case ld::File::objcConstraintNone:
@@ -400,8 +464,8 @@ void Resolver::doFile(const ld::File& file)
                                _internal.swiftVersion = file.swiftVersion();
                        }
                        else if ( file.swiftVersion() != _internal.swiftVersion ) {
                                _internal.swiftVersion = file.swiftVersion();
                        }
                        else if ( file.swiftVersion() != _internal.swiftVersion ) {
-                               char fileVersion[32];
-                               char otherVersion[32];
+                               char fileVersion[64];
+                               char otherVersion[64];
                                userReadableSwiftVersion(file.swiftVersion(), fileVersion);
                                userReadableSwiftVersion(_internal.swiftVersion, otherVersion);
                                if ( file.swiftVersion() > _internal.swiftVersion ) {
                                userReadableSwiftVersion(file.swiftVersion(), fileVersion);
                                userReadableSwiftVersion(_internal.swiftVersion, otherVersion);
                                if ( file.swiftVersion() > _internal.swiftVersion ) {
@@ -423,6 +487,18 @@ void Resolver::doFile(const ld::File& file)
                if ( ! objFile->canScatterAtoms() )
                        _internal.allObjectFilesScatterable = false;
        
                if ( ! objFile->canScatterAtoms() )
                        _internal.allObjectFilesScatterable = false;
        
+               // update minOSVersion off all .o files
+               uint32_t objMinOS = objFile->minOSVersion();
+               if ( !objMinOS )
+                       _internal.objectFileFoundWithNoVersion = true;
+
+               uint32_t objPlatformLC = objFile->platformLoadCommand();
+               if ( (objPlatformLC != 0) && (_internal.derivedPlatformLoadCommand == 0) && (_options.outputKind() == Options::kObjectFile) )
+                       _internal.derivedPlatformLoadCommand = objPlatformLC;
+
+               if ( (_options.outputKind() == Options::kObjectFile) && (objMinOS > _internal.minOSVersion) )
+                       _internal.minOSVersion = objMinOS;
+
                // update cpu-sub-type
                cpu_subtype_t nextObjectSubType = file.cpuSubType();
                switch ( _options.architecture() ) {
                // update cpu-sub-type
                cpu_subtype_t nextObjectSubType = file.cpuSubType();
                switch ( _options.architecture() ) {
@@ -464,6 +540,57 @@ void Resolver::doFile(const ld::File& file)
                }
        }
        if ( dylibFile != NULL ) {
                }
        }
        if ( dylibFile != NULL ) {
+               // Check dylib for bitcode, if the library install path is relative path or @rpath, it has to contain bitcode
+               if ( _options.bundleBitcode() ) {
+                       if ( dylibFile->getBitcode() == NULL &&
+                                dylibFile->installPath()[0] != '/' ) {
+                               // Check if the dylib is from toolchain by checking the path
+                               char tcLibPath[PATH_MAX];
+                               char ldPath[PATH_MAX];
+                               char tempPath[PATH_MAX];
+                               uint32_t bufSize = PATH_MAX;
+                               // toolchain library path should pointed to *.xctoolchain/usr/lib
+                               if ( _NSGetExecutablePath(ldPath, &bufSize) != -1 ) {
+                                       if ( realpath(ldPath, tempPath) != NULL ) {
+                                               char* lastSlash = strrchr(tempPath, '/');
+                                               if ( lastSlash != NULL )
+                                                       strcpy(lastSlash, "/../lib");
+                                       }
+                               }
+                               // Compare toolchain library path to the dylib path
+                               if ( realpath(tempPath, tcLibPath) == NULL ||
+                                        realpath(dylibFile->path(), tempPath) == NULL ||
+                                        strncmp(tcLibPath, tempPath, strlen(tcLibPath)) != 0 ) {
+                                       switch ( _options.platform() ) {
+                                       case Options::kPlatformOSX:
+                                       case Options::kPlatformUnknown:
+                                               warning("all bitcode will be dropped because '%s' was built without bitcode. "
+                                                               "You must rebuild it with bitcode enabled (Xcode setting ENABLE_BITCODE), obtain an updated library from the vendor, or disable bitcode for this target.", file.path());
+                                               _internal.filesWithBitcode.clear();
+                                               _internal.dropAllBitcode = true;
+                                               break;
+                                       case Options::kPlatformiOS:
+                                               throwf("'%s' does not contain bitcode. "
+                                                          "You must rebuild it with bitcode enabled (Xcode setting ENABLE_BITCODE), obtain an updated library from the vendor, or disable bitcode for this target.", file.path());
+                                               break;
+                                       case Options::kPlatformWatchOS:
+                                               throwf("'%s' does not contain bitcode. "
+                                                               "You must rebuild it with bitcode enabled (Xcode setting ENABLE_BITCODE) or obtain an updated library from the vendor", file.path());
+                                               break;
+                       #if SUPPORT_APPLE_TV
+                                       case Options::kPlatform_tvOS:
+                                               warning("URGENT: all bitcode will be dropped because '%s' was built without bitcode. "
+                                                               "You must rebuild it with bitcode enabled (Xcode setting ENABLE_BITCODE) or obtain an updated library from the vendor. "
+                                                               "Note: This will be an error in the future.", file.path());
+                                               _internal.filesWithBitcode.clear();
+                                               _internal.dropAllBitcode = true;
+                                               break;
+                       #endif
+                                       }
+                               }
+                       }
+               }
+
                // update which form of ObjC dylibs are being linked
                switch ( dylibFile->objCConstraint() ) {
                        case ld::File::objcConstraintNone:
                // update which form of ObjC dylibs are being linked
                switch ( dylibFile->objCConstraint() ) {
                        case ld::File::objcConstraintNone:
@@ -509,18 +636,19 @@ void Resolver::doFile(const ld::File& file)
                if ( (depInstallName != NULL) && (depInstallName[0] != '/') ) {
                        if ( (_options.iOSVersionMin() != iOSVersionUnset) && (_options.iOSVersionMin() < iOS_8_0) ) {
                                // <rdar://problem/17598404> only warn about linking against embedded dylib if it is built for iOS 8 or later
                if ( (depInstallName != NULL) && (depInstallName[0] != '/') ) {
                        if ( (_options.iOSVersionMin() != iOSVersionUnset) && (_options.iOSVersionMin() < iOS_8_0) ) {
                                // <rdar://problem/17598404> only warn about linking against embedded dylib if it is built for iOS 8 or later
-                               if ( dylibFile->iOSMinVersion() >= iOS_8_0 )
-                                       warning("embedded dylibs/frameworks are only supported on iOS 8.0 and later (%s)", depInstallName);
+                               if ( dylibFile->minOSVersion() >= iOS_8_0 )
+                                       throwf("embedded dylibs/frameworks are only supported on iOS 8.0 and later (%s)", depInstallName);
                        }
                }
                if ( _options.sharedRegionEligible() ) {
                        assert(depInstallName != NULL);
                        }
                }
                if ( _options.sharedRegionEligible() ) {
                        assert(depInstallName != NULL);
-                       if ( depInstallName[0] == '@' )
+                       if ( depInstallName[0] == '@' ) {
                                warning("invalid -install_name (%s) in dependent dylib (%s). Dylibs/frameworks which might go in dyld shared cache "
                                warning("invalid -install_name (%s) in dependent dylib (%s). Dylibs/frameworks which might go in dyld shared cache "
-                                               "cannot link with dylib that uses @rpath, @loaderpath, etc.", depInstallName, dylibFile->path());
-                       if ( (strncmp(depInstallName, "/usr/lib/", 9) != 0) && (strncmp(depInstallName, "/System/Library/", 16) != 0) )
+                                               "cannot link with dylib that uses @rpath, @loader_path, etc.", depInstallName, dylibFile->path());
+                       } else if ( (strncmp(depInstallName, "/usr/lib/", 9) != 0) && (strncmp(depInstallName, "/System/Library/", 16) != 0) ) {
                                warning("invalid -install_name (%s) in dependent dylib (%s). Dylibs/frameworks which might go in dyld shared cache "
                                                "cannot link with dylibs that won't be in the shared cache", depInstallName, dylibFile->path());
                                warning("invalid -install_name (%s) in dependent dylib (%s). Dylibs/frameworks which might go in dyld shared cache "
                                                "cannot link with dylibs that won't be in the shared cache", depInstallName, dylibFile->path());
+                       }
                }
        }
 
                }
        }
 
@@ -631,6 +759,8 @@ void Resolver::doAtom(const ld::Atom& atom)
                // add to set of dead-strip-roots, all symbols that the compiler marks as don't strip
                if ( atom.dontDeadStrip() )
                        _deadStripRoots.insert(&atom);
                // add to set of dead-strip-roots, all symbols that the compiler marks as don't strip
                if ( atom.dontDeadStrip() )
                        _deadStripRoots.insert(&atom);
+               else if ( atom.dontDeadStripIfReferencesLive() )
+                       _dontDeadStripIfReferencesLive.push_back(&atom);
                        
                if ( atom.scope() == ld::Atom::scopeGlobal ) {
                        // <rdar://problem/5524973> -exported_symbols_list that has wildcards and -dead_strip
                        
                if ( atom.scope() == ld::Atom::scopeGlobal ) {
                        // <rdar://problem/5524973> -exported_symbols_list that has wildcards and -dead_strip
@@ -883,6 +1013,8 @@ void Resolver::markLive(const ld::Atom& atom, WhyLiveBackChain* previous)
                        case ld::Fixup::kindStoreTargetAddressARM64Page21:
                        case ld::Fixup::kindStoreTargetAddressARM64GOTLoadPage21:
                        case ld::Fixup::kindStoreTargetAddressARM64GOTLeaPage21:
                        case ld::Fixup::kindStoreTargetAddressARM64Page21:
                        case ld::Fixup::kindStoreTargetAddressARM64GOTLoadPage21:
                        case ld::Fixup::kindStoreTargetAddressARM64GOTLeaPage21:
+                       case ld::Fixup::kindStoreTargetAddressARM64TLVPLoadPage21:
+                       case ld::Fixup::kindStoreTargetAddressARM64TLVPLoadNowLeaPage21:
 #endif
                                if ( fit->binding == ld::Fixup::bindingByContentBound ) {
                                        // normally this was done in convertReferencesToIndirect()
 #endif
                                if ( fit->binding == ld::Fixup::bindingByContentBound ) {
                                        // normally this was done in convertReferencesToIndirect()
@@ -1015,6 +1147,38 @@ void Resolver::deadStripOptimize(bool force)
                this->markLive(**it, &rootChain);
        }
        
                this->markLive(**it, &rootChain);
        }
        
+       // special case atoms that need to be live if they reference something live
+       if ( ! _dontDeadStripIfReferencesLive.empty() ) {
+               for (std::vector<const ld::Atom*>::iterator it=_dontDeadStripIfReferencesLive.begin(); it != _dontDeadStripIfReferencesLive.end(); ++it) {
+                       const Atom* liveIfRefLiveAtom = *it;
+                       //fprintf(stderr, "live-if-live atom: %s\n", liveIfRefLiveAtom->name());
+                       if ( liveIfRefLiveAtom->live() )
+                               continue;
+                       bool hasLiveRef = false;
+                       for (ld::Fixup::iterator fit=liveIfRefLiveAtom->fixupsBegin(); fit != liveIfRefLiveAtom->fixupsEnd(); ++fit) {
+                               const Atom* target = NULL;
+                               switch ( fit->binding ) {
+                                       case ld::Fixup::bindingDirectlyBound:
+                                               target = fit->u.target;
+                                               break;
+                                       case ld::Fixup::bindingsIndirectlyBound:
+                                               target = _internal.indirectBindingTable[fit->u.bindingIndex];
+                                               break;
+                                       default:
+                                               break;
+                               }
+                               if ( (target != NULL) && target->live() ) 
+                                       hasLiveRef = true;
+                       }
+                       if ( hasLiveRef ) {
+                               WhyLiveBackChain rootChain;
+                               rootChain.previous = NULL;
+                               rootChain.referer = liveIfRefLiveAtom;
+                               this->markLive(*liveIfRefLiveAtom, &rootChain);
+                       }
+               }
+       }
+       
        // now remove all non-live atoms from _atoms
        const bool log = false;
        if ( log ) {
        // now remove all non-live atoms from _atoms
        const bool log = false;
        if ( log ) {
@@ -1538,6 +1702,7 @@ void Resolver::linkTimeOptimize()
        optOpt.preserveAllGlobals                       = _options.allGlobalsAreDeadStripRoots() || _options.hasExportRestrictList();
        optOpt.verbose                                          = _options.verbose();
        optOpt.saveTemps                                        = _options.saveTempFiles();
        optOpt.preserveAllGlobals                       = _options.allGlobalsAreDeadStripRoots() || _options.hasExportRestrictList();
        optOpt.verbose                                          = _options.verbose();
        optOpt.saveTemps                                        = _options.saveTempFiles();
+       optOpt.ltoCodegenOnly                                   = _options.ltoCodegenOnly();
        optOpt.pie                                                      = _options.positionIndependentExecutable();
        optOpt.mainExecutable                           = _options.linkingMainExecutable();;
        optOpt.staticExecutable                         = (_options.outputKind() == Options::kStaticExecutable);
        optOpt.pie                                                      = _options.positionIndependentExecutable();
        optOpt.mainExecutable                           = _options.linkingMainExecutable();;
        optOpt.staticExecutable                         = (_options.outputKind() == Options::kStaticExecutable);
@@ -1548,8 +1713,12 @@ void Resolver::linkTimeOptimize()
        optOpt.keepDwarfUnwind                          = _options.keepDwarfUnwind();
        optOpt.verboseOptimizationHints     = _options.verboseOptimizationHints();
        optOpt.armUsesZeroCostExceptions    = _options.armUsesZeroCostExceptions();
        optOpt.keepDwarfUnwind                          = _options.keepDwarfUnwind();
        optOpt.verboseOptimizationHints     = _options.verboseOptimizationHints();
        optOpt.armUsesZeroCostExceptions    = _options.armUsesZeroCostExceptions();
+       optOpt.simulator                                        = _options.targetIOSSimulator();
+       optOpt.ignoreMismatchPlatform           = ((_options.outputKind() == Options::kPreload) || (_options.outputKind() == Options::kStaticExecutable));
+       optOpt.bitcodeBundle                            = _options.bundleBitcode();
        optOpt.arch                                                     = _options.architecture();
        optOpt.mcpu                                                     = _options.mcpuLTO();
        optOpt.arch                                                     = _options.architecture();
        optOpt.mcpu                                                     = _options.mcpuLTO();
+       optOpt.platform                                         = _options.platform();
        optOpt.llvmOptions                                      = &_options.llvmOptions();
        optOpt.initialUndefines                         = &_options.initialUndefines();
        
        optOpt.llvmOptions                                      = &_options.llvmOptions();
        optOpt.initialUndefines                         = &_options.initialUndefines();
        
index 975772be72d8e7287088704c3ba2eb7f941ade73..6631d11e7d46aaee5394e69f5b6e8f3d01669a76 100644 (file)
@@ -126,6 +126,7 @@ private:
        ld::Internal&                                   _internal;
        std::vector<const ld::Atom*>    _atoms;
        std::set<const ld::Atom*>               _deadStripRoots;
        ld::Internal&                                   _internal;
        std::vector<const ld::Atom*>    _atoms;
        std::set<const ld::Atom*>               _deadStripRoots;
+       std::vector<const ld::Atom*>    _dontDeadStripIfReferencesLive;
        std::vector<const ld::Atom*>    _atomsWithUnresolvedReferences;
        std::vector<const class AliasAtom*>     _aliasesFromCmdLine;
        SymbolTable                                             _symbolTable;
        std::vector<const ld::Atom*>    _atomsWithUnresolvedReferences;
        std::vector<const class AliasAtom*>     _aliasesFromCmdLine;
        SymbolTable                                             _symbolTable;
index ea552f4c5da20cae41fb3913fb76f17a447c0f44..60147796dddd4e93a2a6d6d91076537aacedc575 100644 (file)
@@ -813,6 +813,15 @@ SymbolTable::IndirectBindingSlot SymbolTable::findSlotForReferences(const ld::At
                        slot = _indirectBindingTable.size();
                        _pointerToCStringTable[atom] = slot;
                        break;
                        slot = _indirectBindingTable.size();
                        _pointerToCStringTable[atom] = slot;
                        break;
+               case ld::Section::typeTLVPointers:
+                       pos = _threadPointerTable.find(atom);
+                       if ( pos != _threadPointerTable.end() ) {
+                               *existingAtom = _indirectBindingTable[pos->second];
+                               return pos->second;
+                       }
+                       slot = _indirectBindingTable.size();
+                       _threadPointerTable[atom] = slot;
+                       break;
                default:
                        assert(0 && "section type does not support coalescing by references");
        }
                default:
                        assert(0 && "section type does not support coalescing by references");
        }
index 14c7a9e0077f45fc983d0a117f29f55424c4d0fd..ce2f1dcac522d92baed7a5bbaeb6af7f09bbe143 100644 (file)
@@ -155,6 +155,7 @@ private:
        CStringToSlot                                   _cstringTable;
        NameToMap                                               _nonStdCStringSectionToMap;
        ReferencesToSlot                                _nonLazyPointerTable;
        CStringToSlot                                   _cstringTable;
        NameToMap                                               _nonStdCStringSectionToMap;
        ReferencesToSlot                                _nonLazyPointerTable;
+       ReferencesToSlot                                _threadPointerTable;
        ReferencesToSlot                                _cfStringTable;
        ReferencesToSlot                                _objc2ClassRefTable;
        ReferencesToSlot                                _pointerToCStringTable;
        ReferencesToSlot                                _cfStringTable;
        ReferencesToSlot                                _objc2ClassRefTable;
        ReferencesToSlot                                _pointerToCStringTable;
index 391ddc14c89d2ce80841a336e73bb49b1572df89..9e752f4754908f58513dcbe938090f252d5716c0 100644 (file)
@@ -50,8 +50,11 @@ static const size_t systemAlignment = 4;
 //
 // Get the local alignment for a type, as used by the acting compiler.
 //
 //
 // Get the local alignment for a type, as used by the acting compiler.
 //
-template <class T>
-inline size_t alignof() { struct { char c; T t; } s; return sizeof(s) - sizeof(T); }
+template <typename T>
+unsigned long myalignof() {
+       struct { char c; T t; } s;
+       return sizeof(s) - sizeof(T);
+}
 
 
 //
 
 
 //
index 4ef1f146177526c4865791bf44df728cf1e91ba6..0b5bc4a867b4dc821e62f5a6110307415f054d43 100644 (file)
@@ -79,6 +79,7 @@ extern "C" double log2 ( double );
 #include "passes/branch_shim.h"
 #include "passes/objc.h"
 #include "passes/dylibs.h"
 #include "passes/branch_shim.h"
 #include "passes/objc.h"
 #include "passes/dylibs.h"
+#include "passes/bitcode_bundle.h"
 
 #include "parsers/archive_file.h"
 #include "parsers/macho_relocatable_file.h"
 
 #include "parsers/archive_file.h"
 #include "parsers/macho_relocatable_file.h"
@@ -112,6 +113,8 @@ public:
        void                                                                    setSectionSizesAndAlignments();
        void                                                                    sortSections();
        void                                                                    markAtomsOrdered() { _atomsOrderedInSections = true; }
        void                                                                    setSectionSizesAndAlignments();
        void                                                                    sortSections();
        void                                                                    markAtomsOrdered() { _atomsOrderedInSections = true; }
+       bool                                                                    hasReferenceToWeakExternal(const ld::Atom& atom);
+
        virtual                                                                 ~InternalState() {}
 private:
 
        virtual                                                                 ~InternalState() {}
 private:
 
@@ -137,6 +140,8 @@ private:
                static ld::Section              _s_DATA_nl_symbol_ptr;
                static ld::Section              _s_DATA_common;
                static ld::Section              _s_DATA_zerofill;
                static ld::Section              _s_DATA_nl_symbol_ptr;
                static ld::Section              _s_DATA_common;
                static ld::Section              _s_DATA_zerofill;
+               static ld::Section              _s_DATA_DIRTY_data;
+               static ld::Section              _s_DATA_CONST_const;
        };
        
        bool hasZeroForFileOffset(const ld::Section* sect);
        };
        
        bool hasZeroForFileOffset(const ld::Section* sect);
@@ -164,6 +169,9 @@ ld::Section InternalState::FinalSection::_s_TEXT_const("__TEXT", "__const", ld::
 ld::Section    InternalState::FinalSection::_s_DATA_nl_symbol_ptr("__DATA", "__nl_symbol_ptr", ld::Section::typeNonLazyPointer);
 ld::Section    InternalState::FinalSection::_s_DATA_common("__DATA", "__common", ld::Section::typeZeroFill);
 ld::Section    InternalState::FinalSection::_s_DATA_zerofill("__DATA", "__zerofill", ld::Section::typeZeroFill);
 ld::Section    InternalState::FinalSection::_s_DATA_nl_symbol_ptr("__DATA", "__nl_symbol_ptr", ld::Section::typeNonLazyPointer);
 ld::Section    InternalState::FinalSection::_s_DATA_common("__DATA", "__common", ld::Section::typeZeroFill);
 ld::Section    InternalState::FinalSection::_s_DATA_zerofill("__DATA", "__zerofill", ld::Section::typeZeroFill);
+ld::Section    InternalState::FinalSection::_s_DATA_DIRTY_data( "__DATA_DIRTY", "__data",  ld::Section::typeUnclassified);
+ld::Section    InternalState::FinalSection::_s_DATA_CONST_const( "__DATA_CONST", "__const",  ld::Section::typeUnclassified);
+
 std::vector<const char*> InternalState::FinalSection::_s_segmentsSeen;
 
 
 std::vector<const char*> InternalState::FinalSection::_s_segmentsSeen;
 
 
@@ -212,6 +220,14 @@ const ld::Section& InternalState::FinalSection::outputSection(const ld::Section&
                                if ( strcmp(sect.sectionName(), "__const_coal") == 0 )
                                        return _s_TEXT_const;
                        }
                                if ( strcmp(sect.sectionName(), "__const_coal") == 0 )
                                        return _s_TEXT_const;
                        }
+                       else if ( strcmp(sect.segmentName(), "__DATA_DIRTY") == 0 ) {
+                               if ( strcmp(sect.sectionName(), "__datacoal_nt") == 0 )
+                                       return _s_DATA_DIRTY_data;
+                       }
+                       else if ( strcmp(sect.segmentName(), "__DATA_CONST") == 0 ) {
+                               if ( strcmp(sect.sectionName(), "__const_coal") == 0 )
+                                       return _s_DATA_CONST_const;
+                       }
                        break;
                case ld::Section::typeZeroFill:
                        if ( mergeZeroFill )
                        break;
                case ld::Section::typeZeroFill:
                        if ( mergeZeroFill )
@@ -304,7 +320,7 @@ uint32_t InternalState::FinalSection::sectionOrder(const ld::Section& sect, uint
        if ( sect.type() == ld::Section::typeLastSection )
                return INT_MAX;
        const std::vector<const char*>* sectionList = options.sectionOrder(sect.segmentName());
        if ( sect.type() == ld::Section::typeLastSection )
                return INT_MAX;
        const std::vector<const char*>* sectionList = options.sectionOrder(sect.segmentName());
-       if ( (options.outputKind() == Options::kPreload) && (sectionList != NULL) ) {
+       if ( ((options.outputKind() == Options::kPreload) || (options.outputKind() == Options::kDyld)) && (sectionList != NULL) ) {
                uint32_t count = 10;
                for (std::vector<const char*>::const_iterator it=sectionList->begin(); it != sectionList->end(); ++it, ++count) {
                        if ( strcmp(*it, sect.sectionName()) == 0 ) 
                uint32_t count = 10;
                for (std::vector<const char*>::const_iterator it=sectionList->begin(); it != sectionList->end(); ++it, ++count) {
                        if ( strcmp(*it, sect.sectionName()) == 0 ) 
@@ -335,7 +351,7 @@ uint32_t InternalState::FinalSection::sectionOrder(const ld::Section& sect, uint
                                return sectionsSeen+20;
                }
        }
                                return sectionsSeen+20;
                }
        }
-       else if ( strcmp(sect.segmentName(), "__DATA") == 0 ) {
+       else if ( strncmp(sect.segmentName(), "__DATA", 6) == 0 ) {
                switch ( sect.type() ) {
                        case ld::Section::typeLazyPointerClose:
                                return 8;
                switch ( sect.type() ) {
                        case ld::Section::typeLazyPointerClose:
                                return 8;
@@ -492,6 +508,34 @@ static void validateFixups(const ld::Atom& atom)
 }
 #endif
 
 }
 #endif
 
+bool InternalState::hasReferenceToWeakExternal(const ld::Atom& atom)
+{
+       // if __DATA,__const atom has pointer to weak external symbol, don't move to __DATA_CONST
+       const ld::Atom* target = NULL;
+       for (ld::Fixup::iterator fit=atom.fixupsBegin(); fit != atom.fixupsEnd(); ++fit) {
+               if ( fit->firstInCluster() ) {
+                       target = NULL;
+               }
+               switch ( fit->binding ) {
+                       case ld::Fixup::bindingNone:
+                       case ld::Fixup::bindingByNameUnbound:
+                               break;
+                       case ld::Fixup::bindingByContentBound:
+                       case ld::Fixup::bindingDirectlyBound:
+                               target = fit->u.target;
+                               break;
+                       case ld::Fixup::bindingsIndirectlyBound:
+                               target = indirectBindingTable[fit->u.bindingIndex];
+                               break;
+               }
+               if ( (target != NULL) && (target->definition() == ld::Atom::definitionRegular)
+                       && (target->combine() == ld::Atom::combineByName) && (target->scope() == ld::Atom::scopeGlobal) ) {
+                       return true;
+               }
+       }
+       return false;
+}
+
 ld::Internal::FinalSection* InternalState::addAtom(const ld::Atom& atom)
 {
        ld::Internal::FinalSection* fs = NULL;
 ld::Internal::FinalSection* InternalState::addAtom(const ld::Atom& atom)
 {
        ld::Internal::FinalSection* fs = NULL;
@@ -515,7 +559,8 @@ ld::Internal::FinalSection* InternalState::addAtom(const ld::Atom& atom)
                if ( _options.moveRwSymbol(atom.name(), path, dstSeg, wildCardMatch) ) {
                        if ( (sectType != ld::Section::typeZeroFill) 
                          && (sectType != ld::Section::typeUnclassified) 
                if ( _options.moveRwSymbol(atom.name(), path, dstSeg, wildCardMatch) ) {
                        if ( (sectType != ld::Section::typeZeroFill) 
                          && (sectType != ld::Section::typeUnclassified) 
-                         && (sectType != ld::Section::typeTentativeDefs) ) {
+                         && (sectType != ld::Section::typeTentativeDefs)
+                         && (sectType != ld::Section::typeDyldInfo) ) {
                                if ( !wildCardMatch )
                                        warning("cannot move symbol '%s' from file %s to segment '%s' because symbol is not data (is %d)", atom.name(), path, dstSeg, sectType);
                        }
                                if ( !wildCardMatch )
                                        warning("cannot move symbol '%s' from file %s to segment '%s' because symbol is not data (is %d)", atom.name(), path, dstSeg, sectType);
                        }
@@ -526,7 +571,8 @@ ld::Internal::FinalSection* InternalState::addAtom(const ld::Atom& atom)
                        }
                }
                if ( (fs == NULL) && _options.moveRoSymbol(atom.name(), path, dstSeg, wildCardMatch) ) {
                        }
                }
                if ( (fs == NULL) && _options.moveRoSymbol(atom.name(), path, dstSeg, wildCardMatch) ) {
-                       if ( atom.section().type() != ld::Section::typeCode ) {
+                       if ( (sectType != ld::Section::typeCode)
+                         && (sectType != ld::Section::typeUnclassified) ) {
                                if ( !wildCardMatch )
                                        warning("cannot move symbol '%s' from file %s to segment '%s' because symbol is not code (is %d)", atom.name(), path, dstSeg, sectType);
                        }
                                if ( !wildCardMatch )
                                        warning("cannot move symbol '%s' from file %s to segment '%s' because symbol is not code (is %d)", atom.name(), path, dstSeg, sectType);
                        }
@@ -543,9 +589,24 @@ ld::Internal::FinalSection* InternalState::addAtom(const ld::Atom& atom)
                const std::vector<Options::SegmentRename>& segRenames = _options.segmentRenames();
                for ( std::vector<Options::SectionRename>::const_iterator it=sectRenames.begin(); it != sectRenames.end(); ++it) {
                        if ( (strcmp(sectName, it->fromSection) == 0) && (strcmp(atom.section().segmentName(), it->fromSegment) == 0) ) {
                const std::vector<Options::SegmentRename>& segRenames = _options.segmentRenames();
                for ( std::vector<Options::SectionRename>::const_iterator it=sectRenames.begin(); it != sectRenames.end(); ++it) {
                        if ( (strcmp(sectName, it->fromSection) == 0) && (strcmp(atom.section().segmentName(), it->fromSegment) == 0) ) {
-                               if ( _options.traceSymbolLayout() )
-                                       printf("symbol '%s', -rename_section mapped it to %s/%s\n", atom.name(), it->toSegment, it->toSection);
-                               fs = this->getFinalSection(it->toSegment, it->toSection, sectType);
+                               if ( _options.useDataConstSegment() && (strcmp(sectName, "__const") == 0)
+                                               && (strcmp(atom.section().segmentName(), "__DATA") == 0) && hasReferenceToWeakExternal(atom) ) {
+                                       // if __DATA,__const atom has pointer to weak external symbol, don't move to __DATA_CONST
+                                       fs = this->getFinalSection("__DATA", "__const_weak", sectType);
+                                       if ( _options.traceSymbolLayout() )
+                                               printf("symbol '%s', contains pointers to weak symbols, so mapped it to __DATA/_const_weak\n", atom.name());
+                               }
+                               else if ( _options.useDataConstSegment() && (sectType == ld::Section::typeNonLazyPointer) && hasReferenceToWeakExternal(atom) ) {
+                                       // if __DATA,__nl_symbol_ptr atom has pointer to weak external symbol, don't move to __DATA_CONST
+                                       fs = this->getFinalSection("__DATA", "__got_weak", sectType);
+                                       if ( _options.traceSymbolLayout() )
+                                               printf("symbol '%s', contains pointers to weak symbols, so mapped it to __DATA/__got_weak\n", atom.name());
+                               }
+                               else {
+                                       fs = this->getFinalSection(it->toSegment, it->toSection, sectType);
+                                       if ( _options.traceSymbolLayout() )
+                                               printf("symbol '%s', -rename_section mapped it to %s/%s\n", atom.name(), fs->segmentName(), fs->sectionName());
+                               }
                        }
                }
                if ( fs == NULL ) {
                        }
                }
                if ( fs == NULL ) {
@@ -558,8 +619,7 @@ ld::Internal::FinalSection* InternalState::addAtom(const ld::Atom& atom)
                        }
                }
        }
                        }
                }
        }
-       
-       
+
        // if no override, use default location
        if ( fs == NULL ) {
                fs = this->getFinalSection(atom.section());
        // if no override, use default location
        if ( fs == NULL ) {
                fs = this->getFinalSection(atom.section());
@@ -589,6 +649,7 @@ ld::Internal::FinalSection* InternalState::addAtom(const ld::Atom& atom)
                // normal case
                fs->atoms.push_back(&atom);
        }
                // normal case
                fs->atoms.push_back(&atom);
        }
+       this->atomToSection[&atom] = fs;
        return fs;
 }
 
        return fs;
 }
 
@@ -731,7 +792,7 @@ void InternalState::setSectionSizesAndAlignments()
                                bool pagePerAtom = false;
                                uint32_t atomAlignmentPowerOf2 = atom->alignment().powerOf2;
                                uint32_t atomModulus = atom->alignment().modulus;
                                bool pagePerAtom = false;
                                uint32_t atomAlignmentPowerOf2 = atom->alignment().powerOf2;
                                uint32_t atomModulus = atom->alignment().modulus;
-                               if ( _options.pageAlignDataAtoms() && ( strcmp(atom->section().segmentName(), "__DATA") == 0) ) { 
+                               if ( _options.pageAlignDataAtoms() && ( strncmp(atom->section().segmentName(), "__DATA", 6) == 0) ) {
                                        // most objc sections cannot be padded
                                        bool contiguousObjCSection = ( strncmp(atom->section().sectionName(), "__objc_", 7) == 0 );
                                        if ( strcmp(atom->section().sectionName(), "__objc_const") == 0 )
                                        // most objc sections cannot be padded
                                        bool contiguousObjCSection = ( strncmp(atom->section().sectionName(), "__objc_", 7) == 0 );
                                        if ( strcmp(atom->section().sectionName(), "__objc_const") == 0 )
@@ -811,13 +872,22 @@ uint64_t InternalState::assignFileOffsets()
        uint64_t address = 0;
        const char* lastSegName = "";
        uint64_t floatingAddressStart = _options.baseAddress();
        uint64_t address = 0;
        const char* lastSegName = "";
        uint64_t floatingAddressStart = _options.baseAddress();
+       bool haveFixedSegments = false;
        
        
+       // mark all sections as not having an address yet
+       for (std::vector<ld::Internal::FinalSection*>::iterator it = sections.begin(); it != sections.end(); ++it) {
+               ld::Internal::FinalSection* sect = *it;
+               sect->alignmentPaddingBytes = 0;
+               sect->address = ULLONG_MAX;
+       }
+
        // first pass, assign addresses to sections in segments with fixed start addresses
        if ( log ) fprintf(stderr, "Fixed address segments:\n");
        for (std::vector<ld::Internal::FinalSection*>::iterator it = sections.begin(); it != sections.end(); ++it) {
                ld::Internal::FinalSection* sect = *it;
                if ( ! _options.hasCustomSegmentAddress(sect->segmentName()) ) 
                        continue;
        // first pass, assign addresses to sections in segments with fixed start addresses
        if ( log ) fprintf(stderr, "Fixed address segments:\n");
        for (std::vector<ld::Internal::FinalSection*>::iterator it = sections.begin(); it != sections.end(); ++it) {
                ld::Internal::FinalSection* sect = *it;
                if ( ! _options.hasCustomSegmentAddress(sect->segmentName()) ) 
                        continue;
+               haveFixedSegments = true;
                if ( segmentsArePageAligned ) {
                        if ( strcmp(lastSegName, sect->segmentName()) != 0 ) {
                                address = _options.customSegmentAddress(sect->segmentName());
                if ( segmentsArePageAligned ) {
                        if ( strcmp(lastSegName, sect->segmentName()) != 0 ) {
                                address = _options.customSegmentAddress(sect->segmentName());
@@ -850,8 +920,38 @@ uint64_t InternalState::assignFileOffsets()
                        floatingAddressStart = address;
                }
        }
                        floatingAddressStart = address;
                }
        }
-       
-       // second pass, assign section address to sections in segments that are contiguous with previous segment
+
+       // second pass, assign section addresses to sections in segments that are ordered after a segment with a fixed address
+       if ( haveFixedSegments && !_options.segmentOrder().empty() ) {
+               if ( log ) fprintf(stderr, "After Fixed address segments:\n");
+               lastSegName = "";
+               ld::Internal::FinalSection* lastSect = NULL; 
+               for (std::vector<ld::Internal::FinalSection*>::iterator it = sections.begin(); it != sections.end(); ++it) {
+                       ld::Internal::FinalSection* sect = *it;
+                       if ( (sect->address == ULLONG_MAX) && _options.segmentOrderAfterFixedAddressSegment(sect->segmentName()) ) {
+                               address = lastSect->address + lastSect->size;
+                               if ( (strcmp(lastSegName, sect->segmentName()) != 0) && segmentsArePageAligned ) {
+                                       // round up size of last segment
+                                       address = pageAlign(address, _options.segPageSize(lastSegName));
+                               }
+                               // adjust section address based on alignment
+                               uint64_t unalignedAddress = address;
+                               uint64_t alignment = (1 << sect->alignment);
+                               address = ( (unalignedAddress+alignment-1) & (-alignment) );
+                               sect->alignmentPaddingBytes = (address - unalignedAddress);
+                               sect->address = address;
+                               if ( log ) fprintf(stderr, "  address=0x%08llX, hidden=%d, alignment=%02d, section=%s,%s\n",
+                                                                       sect->address, sect->isSectionHidden(), sect->alignment, sect->segmentName(), sect->sectionName());
+                               // update running totals
+                               if ( !sect->isSectionHidden() || hiddenSectionsOccupyAddressSpace )
+                                       address += sect->size;
+                       }
+                       lastSegName = sect->segmentName();
+                       lastSect = sect;
+               }
+       }
+
+       // last pass, assign addresses to remaining sections
        address = floatingAddressStart;
        lastSegName = "";
        ld::Internal::FinalSection* overlappingFixedSection = NULL;
        address = floatingAddressStart;
        lastSegName = "";
        ld::Internal::FinalSection* overlappingFixedSection = NULL;
@@ -859,7 +959,7 @@ uint64_t InternalState::assignFileOffsets()
        if ( log ) fprintf(stderr, "Regular layout segments:\n");
        for (std::vector<ld::Internal::FinalSection*>::iterator it = sections.begin(); it != sections.end(); ++it) {
                ld::Internal::FinalSection* sect = *it;
        if ( log ) fprintf(stderr, "Regular layout segments:\n");
        for (std::vector<ld::Internal::FinalSection*>::iterator it = sections.begin(); it != sections.end(); ++it) {
                ld::Internal::FinalSection* sect = *it;
-               if ( _options.hasCustomSegmentAddress(sect->segmentName()) ) 
+               if ( sect->address != ULLONG_MAX )
                        continue;
                if ( (_options.outputKind() == Options::kPreload) && (sect->type() == ld::Section::typeMachHeader) ) {
                        sect->alignmentPaddingBytes = 0;
                        continue;
                if ( (_options.outputKind() == Options::kPreload) && (sect->type() == ld::Section::typeMachHeader) ) {
                        sect->alignmentPaddingBytes = 0;
@@ -876,6 +976,7 @@ uint64_t InternalState::assignFileOffsets()
                                lastSegName = sect->segmentName();
                        }
                }
                                lastSegName = sect->segmentName();
                        }
                }
+               
                // adjust section address based on alignment
                uint64_t unalignedAddress = address;
                uint64_t alignment = (1 << sect->alignment);
                // adjust section address based on alignment
                uint64_t unalignedAddress = address;
                uint64_t alignment = (1 << sect->alignment);
@@ -1116,7 +1217,8 @@ int main(int argc, const char* argv[])
                ld::passes::branch_island::doPass(options, state);      // must be after stubs and order pass
                ld::passes::dtrace::doPass(options, state);
                ld::passes::compact_unwind::doPass(options, state);  // must be after order pass
                ld::passes::branch_island::doPass(options, state);      // must be after stubs and order pass
                ld::passes::dtrace::doPass(options, state);
                ld::passes::compact_unwind::doPass(options, state);  // must be after order pass
-               
+               ld::passes::bitcode_bundle::doPass(options, state);  // must be after dylib
+               
                // sort final sections
                state.sortSections();
 
                // sort final sections
                state.sortSections();
 
index 889cf2cd3bc080db7c0b71e12fef985e33211835..c8f272e8985edd75f88822d333175a9cd8655eaa 100644 (file)
 #include <unistd.h>
 #include <assert.h>
 
 #include <unistd.h>
 #include <assert.h>
 
+#include <set>
+#include <map>
 #include <vector>
 #include <vector>
+#include <string>
 #include <unordered_set>
 
 #include "configure.h"
 
 namespace ld {
 
 #include <unordered_set>
 
 #include "configure.h"
 
 namespace ld {
 
+// Forward declaration for bitcode support
+class Bitcode;
+
 //
 // ld::File 
 //
 //
 // ld::File 
 //
@@ -149,8 +155,11 @@ public:
        virtual uint8_t                                         swiftVersion() const                    { return 0; }
        virtual uint32_t                                        cpuSubType() const              { return 0; }
        virtual uint32_t                                        subFileCount() const    { return 1; }
        virtual uint8_t                                         swiftVersion() const                    { return 0; }
        virtual uint32_t                                        cpuSubType() const              { return 0; }
        virtual uint32_t                                        subFileCount() const    { return 1; }
+       virtual uint32_t                                        minOSVersion() const    { return 0; }
+       virtual uint32_t                                        platformLoadCommand() const             { return 0; }
     bool                                                               fileExists() const     { return _modTime != 0; }
        Type                                                            type() const { return _type; }
     bool                                                               fileExists() const     { return _modTime != 0; }
        Type                                                            type() const { return _type; }
+       virtual Bitcode*                                        getBitcode() const              { return NULL; }
 private:
        const char*                                                     _path;
        time_t                                                          _modTime;
 private:
        const char*                                                     _path;
        time_t                                                          _modTime;
@@ -169,7 +178,9 @@ enum IOSVersionMin { iOSVersionUnset=0, iOS_2_0=0x00020000, iOS_3_1=0x00030100,
                                                iOS_4_2=0x00040200, iOS_4_3=0x00040300, iOS_5_0=0x00050000,
                                                iOS_6_0=0x00060000, iOS_7_0=0x00070000, iOS_8_0=0x00080000,
                                                iOS_9_0=0x00090000, iOS_Future=0x10000000};
                                                iOS_4_2=0x00040200, iOS_4_3=0x00040300, iOS_5_0=0x00050000,
                                                iOS_6_0=0x00060000, iOS_7_0=0x00070000, iOS_8_0=0x00080000,
                                                iOS_9_0=0x00090000, iOS_Future=0x10000000};
+enum WatchOSVersionMin  { wOSVersionUnset=0, wOS_1_0=0x00010000, wOS_2_0=0x00020000 };
+
+
 namespace relocatable {
        //
        // ld::relocatable::File 
 namespace relocatable {
        //
        // ld::relocatable::File 
@@ -191,6 +202,7 @@ namespace relocatable {
        {
        public:
                enum DebugInfoKind { kDebugInfoNone=0, kDebugInfoStabs=1, kDebugInfoDwarf=2, kDebugInfoStabsUUID=3 };
        {
        public:
                enum DebugInfoKind { kDebugInfoNone=0, kDebugInfoStabs=1, kDebugInfoDwarf=2, kDebugInfoStabsUUID=3 };
+               enum SourceKind { kSourceUnknown=0, kSourceObj, kSourceLTO, kSourceArchive, kSourceCompilerArchive, kSourceSingle };
                struct Stab {
                        const class Atom*       atom;
                        uint8_t                         type;
                struct Stab {
                        const class Atom*       atom;
                        uint8_t                         type;
@@ -211,6 +223,7 @@ namespace relocatable {
                virtual bool                                            canScatterAtoms() const = 0;
                virtual bool                                            hasLongBranchStubs()            { return false; }
                virtual LinkerOptionsList*                      linkerOptions() const = 0;
                virtual bool                                            canScatterAtoms() const = 0;
                virtual bool                                            hasLongBranchStubs()            { return false; }
                virtual LinkerOptionsList*                      linkerOptions() const = 0;
+               virtual SourceKind                                      sourceKind() const { return kSourceUnknown; }
        };
 } // namespace relocatable
 
        };
 } // namespace relocatable
 
@@ -269,13 +282,15 @@ namespace dylib {
                virtual bool                                            hasWeakDefinition(const char* name) const = 0;
                virtual bool                                            hasPublicInstallName() const = 0;
                virtual bool                                            allSymbolsAreWeakImported() const = 0;
                virtual bool                                            hasWeakDefinition(const char* name) const = 0;
                virtual bool                                            hasPublicInstallName() const = 0;
                virtual bool                                            allSymbolsAreWeakImported() const = 0;
-               virtual const void*                                     codeSignatureDR() const = 0;
                virtual bool                                            installPathVersionSpecific() const { return false; }
                virtual bool                                            appExtensionSafe() const = 0;
                virtual bool                                            installPathVersionSpecific() const { return false; }
                virtual bool                                            appExtensionSafe() const = 0;
-               virtual MacVersionMin                           macMinVersion() const { return macVersionUnset; }
-               virtual IOSVersionMin                           iOSMinVersion() const { return iOSVersionUnset; }
 
        protected:
 
        protected:
+               struct ReExportChain { ReExportChain* prev; const File* file; };
+               virtual std::pair<bool, bool>           hasWeakDefinitionImpl(const char* name) const = 0;
+               virtual bool                                            containsOrReExports(const char* name, bool& weakDef, bool& tlv, uint64_t& defAddress) const = 0;
+               virtual void                                            assertNoReExportCycles(ReExportChain*) const = 0;
+
                const char*                                                     _dylibInstallPath;
                uint32_t                                                        _dylibTimeStamp;
                uint32_t                                                        _dylibCurrentVersion;
                const char*                                                     _dylibInstallPath;
                uint32_t                                                        _dylibTimeStamp;
                uint32_t                                                        _dylibCurrentVersion;
@@ -322,7 +337,7 @@ public:
                                typeLazyDylibPointer, typeStubHelper, typeInitializerPointers, typeTerminatorPointers,
                                typeStubClose, typeLazyPointerClose, typeAbsoluteSymbols, 
                                typeTLVDefs, typeTLVZeroFill, typeTLVInitialValues, typeTLVInitializerPointers, typeTLVPointers,
                                typeLazyDylibPointer, typeStubHelper, typeInitializerPointers, typeTerminatorPointers,
                                typeStubClose, typeLazyPointerClose, typeAbsoluteSymbols, 
                                typeTLVDefs, typeTLVZeroFill, typeTLVInitialValues, typeTLVInitializerPointers, typeTLVPointers,
-                               typeFirstSection, typeLastSection, typeDebug };
+                               typeFirstSection, typeLastSection, typeDebug, typeSectCreate };
 
 
                                        Section(const char* sgName, const char* sctName,
 
 
                                        Section(const char* sgName, const char* sctName,
@@ -644,7 +659,7 @@ public:
                                        typeSectionEnd, typeBranchIsland, typeLazyPointer, typeStub, typeNonLazyPointer, 
                                        typeLazyDylibPointer, typeStubHelper, typeInitializerPointers, typeTerminatorPointers,
                                        typeLTOtemporary, typeResolver,
                                        typeSectionEnd, typeBranchIsland, typeLazyPointer, typeStub, typeNonLazyPointer, 
                                        typeLazyDylibPointer, typeStubHelper, typeInitializerPointers, typeTerminatorPointers,
                                        typeLTOtemporary, typeResolver,
-                                       typeTLV, typeTLVZeroFill, typeTLVInitialValue, typeTLVInitializerPointers };
+                                       typeTLV, typeTLVZeroFill, typeTLVInitialValue, typeTLVInitializerPointers, typeTLVPointer };
 
        enum SymbolTableInclusion { symbolTableNotIn, symbolTableNotInFinalLinkedImages, symbolTableIn,
                                                                symbolTableInAndNeverStrip, symbolTableInAsAbsolute, 
 
        enum SymbolTableInclusion { symbolTableNotIn, symbolTableNotInFinalLinkedImages, symbolTableIn,
                                                                symbolTableInAndNeverStrip, symbolTableInAsAbsolute, 
@@ -679,7 +694,8 @@ public:
                                                                                                        _contentType(ct), _symbolTableInclusion(i),
                                                                                                        _scope(s), _mode(modeSectionOffset), 
                                                                                                        _overridesADylibsWeakDef(false), _coalescedAway(false),
                                                                                                        _contentType(ct), _symbolTableInclusion(i),
                                                                                                        _scope(s), _mode(modeSectionOffset), 
                                                                                                        _overridesADylibsWeakDef(false), _coalescedAway(false),
-                                                                                                       _live(false), _machoSection(0), _weakImportState(weakImportUnset)
+                                                                                                       _live(false), _dontDeadStripIfRefLive(false),
+                                                                                                       _machoSection(0), _weakImportState(weakImportUnset)
                                                                                                         {
                                                                                                        #ifndef NDEBUG
                                                                                                                switch ( _combine ) {
                                                                                                         {
                                                                                                        #ifndef NDEBUG
                                                                                                                switch ( _combine ) {
@@ -703,6 +719,7 @@ public:
        ContentType                                                             contentType() const                     { return _contentType; }
        SymbolTableInclusion                                    symbolTableInclusion() const{ return _symbolTableInclusion; }
        bool                                                                    dontDeadStrip() const           { return _dontDeadStrip; }
        ContentType                                                             contentType() const                     { return _contentType; }
        SymbolTableInclusion                                    symbolTableInclusion() const{ return _symbolTableInclusion; }
        bool                                                                    dontDeadStrip() const           { return _dontDeadStrip; }
+       bool                                                                    dontDeadStripIfReferencesLive() const { return _dontDeadStripIfRefLive; }
        bool                                                                    isThumb() const                         { return _thumb; }
        bool                                                                    isAlias() const                         { return _alias; }
        Alignment                                                               alignment() const                       { return Alignment(_alignmentPowerOf2, _alignmentModulus); }
        bool                                                                    isThumb() const                         { return _thumb; }
        bool                                                                    isAlias() const                         { return _alias; }
        Alignment                                                               alignment() const                       { return Alignment(_alignmentPowerOf2, _alignmentModulus); }
@@ -722,6 +739,7 @@ public:
        void                                                                    setCoalescedAway()                      { _coalescedAway = true; }
        void                                                                    setWeakImportState(bool w)      { assert(_definition == definitionProxy); _weakImportState = ( w ? weakImportTrue : weakImportFalse); }
        void                                                                    setAutoHide()                           { _autoHide = true; }
        void                                                                    setCoalescedAway()                      { _coalescedAway = true; }
        void                                                                    setWeakImportState(bool w)      { assert(_definition == definitionProxy); _weakImportState = ( w ? weakImportTrue : weakImportFalse); }
        void                                                                    setAutoHide()                           { _autoHide = true; }
+       void                                                                    setDontDeadStripIfReferencesLive() { _dontDeadStripIfRefLive = true; }
        void                                                                    setLive()                                       { _live = true; }
        void                                                                    setLive(bool value)                     { _live = value; }
        void                                                                    setMachoSection(unsigned x) { assert(x != 0); assert(x < 256); _machoSection = x; }
        void                                                                    setLive()                                       { _live = true; }
        void                                                                    setLive(bool value)                     { _live = value; }
        void                                                                    setMachoSection(unsigned x) { assert(x != 0); assert(x < 256); _machoSection = x; }
@@ -794,6 +812,7 @@ protected:
        bool                                                            _overridesADylibsWeakDef : 1;
        bool                                                            _coalescedAway : 1;
        bool                                                            _live : 1;
        bool                                                            _overridesADylibsWeakDef : 1;
        bool                                                            _coalescedAway : 1;
        bool                                                            _live : 1;
+       bool                                                            _dontDeadStripIfRefLive : 1;
        unsigned                                                        _machoSection : 8;
        WeakImportState                                         _weakImportState : 2;
 };
        unsigned                                                        _machoSection : 8;
        WeakImportState                                         _weakImportState : 2;
 };
@@ -824,6 +843,7 @@ struct CStringEquals
 
 typedef        std::unordered_set<const char*, ld::CStringHash, ld::CStringEquals>  CStringSet;
 
 
 typedef        std::unordered_set<const char*, ld::CStringHash, ld::CStringEquals>  CStringSet;
 
+
 class Internal
 {
 public:
 class Internal
 {
 public:
@@ -848,6 +868,8 @@ public:
                bool                                                    hasExternalRelocs;
        };
        
                bool                                                    hasExternalRelocs;
        };
        
+       typedef std::map<const ld::Atom*, FinalSection*>        AtomToSection;          
+
        virtual uint64_t                                        assignFileOffsets() = 0;
        virtual void                                            setSectionSizesAndAlignments() = 0;
        virtual ld::Internal::FinalSection*     addAtom(const Atom&) = 0;
        virtual uint64_t                                        assignFileOffsets() = 0;
        virtual void                                            setSectionSizesAndAlignments() = 0;
        virtual ld::Internal::FinalSection*     addAtom(const Atom&) = 0;
@@ -858,19 +880,23 @@ public:
                                                                                        lazyBindingHelper(NULL), compressedFastBinderProxy(NULL),
                                                                                        objcObjectConstraint(ld::File::objcConstraintNone), 
                                                                                        objcDylibConstraint(ld::File::objcConstraintNone), 
                                                                                        lazyBindingHelper(NULL), compressedFastBinderProxy(NULL),
                                                                                        objcObjectConstraint(ld::File::objcConstraintNone), 
                                                                                        objcDylibConstraint(ld::File::objcConstraintNone), 
-                                                                                       swiftVersion(0), cpuSubType(0), 
+                                                                                       swiftVersion(0), cpuSubType(0), minOSVersion(0),
+                                                                                       objectFileFoundWithNoVersion(false),
                                                                                        allObjectFilesScatterable(true), 
                                                                                        someObjectFileHasDwarf(false), usingHugeSections(false),
                                                                                        hasThreadLocalVariableDefinitions(false),
                                                                                        hasWeakExternalSymbols(false),
                                                                                        allObjectFilesScatterable(true), 
                                                                                        someObjectFileHasDwarf(false), usingHugeSections(false),
                                                                                        hasThreadLocalVariableDefinitions(false),
                                                                                        hasWeakExternalSymbols(false),
-                                                                                       someObjectHasOptimizationHints(false) { }
-                                                                               
+                                                                                       someObjectHasOptimizationHints(false),
+                                                                                       dropAllBitcode(false), embedMarkerOnly(false)   { }
+
        std::vector<FinalSection*>                                      sections;
        std::vector<ld::dylib::File*>                           dylibs;
        std::vector<ld::relocatable::File::Stab>        stabs;
        std::vector<FinalSection*>                                      sections;
        std::vector<ld::dylib::File*>                           dylibs;
        std::vector<ld::relocatable::File::Stab>        stabs;
+       AtomToSection                                                           atomToSection;          
        CStringSet                                                                      linkerOptionLibraries;
        CStringSet                                                                      linkerOptionFrameworks;
        std::vector<const ld::Atom*>                            indirectBindingTable;
        CStringSet                                                                      linkerOptionLibraries;
        CStringSet                                                                      linkerOptionFrameworks;
        std::vector<const ld::Atom*>                            indirectBindingTable;
+       std::vector<const ld::relocatable::File*>       filesWithBitcode;
        const ld::dylib::File*                                          bundleLoader;
        const Atom*                                                                     entryPoint;
        const Atom*                                                                     classicBindingHelper;
        const ld::dylib::File*                                          bundleLoader;
        const Atom*                                                                     entryPoint;
        const Atom*                                                                     classicBindingHelper;
@@ -880,12 +906,18 @@ public:
        ld::File::ObjcConstraint                                        objcDylibConstraint;
        uint8_t                                                                         swiftVersion;
        uint32_t                                                                        cpuSubType;
        ld::File::ObjcConstraint                                        objcDylibConstraint;
        uint8_t                                                                         swiftVersion;
        uint32_t                                                                        cpuSubType;
+       uint32_t                                                                        minOSVersion;
+       uint32_t                                                                        derivedPlatformLoadCommand;
+       bool                                                                            objectFileFoundWithNoVersion;
        bool                                                                            allObjectFilesScatterable;
        bool                                                                            someObjectFileHasDwarf;
        bool                                                                            usingHugeSections;
        bool                                                                            hasThreadLocalVariableDefinitions;
        bool                                                                            hasWeakExternalSymbols;
        bool                                                                            someObjectHasOptimizationHints;
        bool                                                                            allObjectFilesScatterable;
        bool                                                                            someObjectFileHasDwarf;
        bool                                                                            usingHugeSections;
        bool                                                                            hasThreadLocalVariableDefinitions;
        bool                                                                            hasWeakExternalSymbols;
        bool                                                                            someObjectHasOptimizationHints;
+       bool                                                                            dropAllBitcode;
+       bool                                                                            embedMarkerOnly;
+       std::string                                                                     ltoBitcodePath;
 };
 
 
 };
 
 
@@ -894,10 +926,6 @@ public:
 
 
 
 
 
 
-
-
-
-
 } // namespace ld 
 
 #endif // __LD_HPP__
 } // namespace ld 
 
 #endif // __LD_HPP__
diff --git a/src/ld/lto_file.hpp b/src/ld/lto_file.hpp
deleted file mode 100644 (file)
index 24d3f58..0000000
+++ /dev/null
@@ -1,642 +0,0 @@
-/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
- *
- * Copyright (c) 2006-2009 Apple Inc. All rights reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- *
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- *
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
- */
-
-#ifndef __LTO_READER_H__
-#define __LTO_READER_H__
-
-#include <stdlib.h>
-#include <mach-o/dyld.h>
-#include <vector>
-#include <ext/hash_set>
-#include <ext/hash_map>
-
-#include "MachOFileAbstraction.hpp"
-#include "Architectures.hpp"
-#include "ld.hpp"
-
-#include "llvm-c/lto.h"
-
-
-namespace lto {
-         
-
-//
-// ld64 only tracks non-internal symbols from an llvm bitcode file.  
-// We model this by having an InternalAtom which represent all internal functions and data.
-// All non-interal symbols from a bitcode file are represented by an Atom
-// and each Atom has a reference to the InternalAtom.  The InternalAtom
-// also has references to each symbol external to the bitcode file. 
-//
-class InternalAtom : public ld::Atom
-{
-public:
-                                                                                               InternalAtom(class File& f);
-       // overrides of ld::Atom
-       virtual ld::File*                                                       file() const            { return &_file; }
-       virtual bool                                                            translationUnitSource(const char** dir, const char** nm) const
-                                                                                                                                       { return false; }
-       virtual const char*                                                     name() const            { return "import-atom"; }
-       virtual uint64_t                                                        size() const            { return 0; }
-       virtual uint64_t                                                        objectAddress() const { return 0; }
-       virtual void                                                            copyRawContent(uint8_t buffer[]) const { }
-       virtual void                                                            setScope(Scope)         { }
-       virtual ld::Fixup::iterator                                     fixupsBegin()           { return &_undefs[0]; }
-       virtual ld::Fixup::iterator                                     fixupsEnd()                     { return &_undefs[_undefs.size()]; }
-
-       // for adding references to symbols outside bitcode file
-       void                                                                            addReference(const char* name)
-                                                                                                                                       { _undefs.push_back(ld::Fixup(0, ld::Fixup::k1of1, 
-                                                                                                                                                               ld::Fixup::fixupNone, false, name)); }
-private:
-
-       ld::File&                                                                       _file;
-       std::vector<ld::Fixup>                                          _undefs;
-};
-
-
-//
-// LLVM bitcode file 
-//
-class File : public ld::relocatable::File
-{
-public:
-                                                                                       File(const char* path, time_t mTime, const uint8_t* content, 
-                                                                                                       uint32_t contentLength, uint32_t ordinal, cpu_type_t arch);
-       virtual                                                                 ~File();
-
-       // overrides of ld::File
-       virtual bool                                                                            forEachAtom(ld::File::AtomHandler&);
-       virtual bool                                                                            justInTimeforEachAtom(const char* name, ld::File::AtomHandler&) 
-                                                                                                                                                                       { return false; }
-       
-       // overrides of ld::relocatable::File 
-       virtual bool                                                                            objcReplacementClasses()        { return false; }
-       virtual DebugInfoKind                                                           debugInfo()                                     { return ld::relocatable::File::kDebugInfoNone; }
-       virtual std::vector<ld::relocatable::File::Stab>*       stabs()                                         { return NULL; }
-       virtual bool                                                                            canScatterAtoms()                       { return true; }
-
-       lto_module_t                                                                            module()                                        { return _module; }
-       class InternalAtom&                                                                     internalAtom()                          { return _internalAtom; }
-private:
-       friend class Atom;
-       friend class InternalAtom;
-       
-       cpu_type_t                                                              _architecture;
-       class InternalAtom                                              _internalAtom;
-       class Atom*                                                             _atomArray;
-       uint32_t                                                                _atomArrayCount;
-       lto_module_t                                                    _module;
-       ld::Section                                                             _section;
-};
-
-//
-// Atom acts as a proxy Atom for the symbols that are exported by LLVM bitcode file. Initially,
-// Reader creates Atoms to allow linker proceed with usual symbol resolution phase. After
-// optimization is performed, real Atoms are created for these symobls. However these real Atoms
-// are not inserted into global symbol table. Atom holds real Atom and forwards appropriate
-// methods to real atom.
-//
-class Atom : public ld::Atom
-{
-public:
-                                                                               Atom(File& f, const char* name, ld::Atom::Scope s, 
-                                                                                                       ld::Atom::Definition d, ld::Atom::Alignment a);
-
-       // overrides of ld::Atom
-       virtual ld::File*                                       file() const            { return &_file; }
-       virtual bool                                            translationUnitSource(const char** dir, const char** nm) const
-                                                                                                                       { return (_compiledAtom ? _compiledAtom->translationUnitSource(dir, nm) : false); }
-       virtual const char*                                     name() const            { return _name; }
-       virtual uint64_t                                        size() const            { return (_compiledAtom ? _compiledAtom->size() : 0); }
-       virtual uint64_t                                        objectAddress() const { return (_compiledAtom ? _compiledAtom->objectAddress() : 0); }
-       virtual void                                            copyRawContent(uint8_t buffer[]) const 
-                                                                                                                       { if (_compiledAtom) _compiledAtom->copyRawContent(buffer); }
-                                                                                                                       
-       ld::Atom*                                                       compiledAtom()          { return _compiledAtom; }
-       void                                                            setCompiledAtom(ld::Atom& atom) 
-                                                                                                                       { _compiledAtom = &atom; }
-private:
-
-       File&                                                           _file;
-       const char*                                                     _name;
-       ld::Atom*                                                       _compiledAtom;
-};
-
-                                                                                       
-
-
-
-
-
-class Parser 
-{
-public:
-       static bool                                             validFile(const uint8_t* fileContent, uint64_t fileLength, cpu_type_t architecture);
-       static const char*                              fileKind(const uint8_t* fileContent);
-       static File*                                    parse(const uint8_t* fileContent, uint64_t fileLength, const char* path, 
-                                                                                       time_t modTime, uint32_t ordinal, cpu_type_t architecture);
-       static bool                                             libLTOisLoaded() { return (::lto_get_version() != NULL); }
-       static bool                                             optimize(const std::vector<ld::Atom*>& allAtoms, std::vector<ld::Atom*>& newAtoms, 
-                                                                                               std::vector<const char*>& additionalUndefines, 
-                                                                                               const std::set<ld::Atom*>&,
-                                                                                               std::vector<ld::Atom*>& newDeadAtoms,
-                                                                                               uint32_t nextInputOrdinal, 
-                                                                                               ld::OutFile* writer, ld::Atom* entryPointAtom,
-                                                                                               const std::vector<const char*>& llvmOptions,
-                                                                                               bool allGlobalsAReDeadStripRoots,
-                                                                                               bool verbose, bool saveTemps, 
-                                                                                               const char* outputFilePath,
-                                                                                               bool pie,  bool mainExecutable, bool staticExecutable, bool relocatable,
-                                                                                               bool allowTextRelocs, cpu_type_t arch);
-
-       static const char*                      ltoVersion()    { return ::lto_get_version(); }
-
-private:
-       static const char*                              tripletPrefixForArch(cpu_type_t arch);
-       static ld::relocatable::File*   parseMachOFile(const uint8_t* p, size_t len, uint32_t nextInputOrdinal, cpu_type_t arch);
-
-       class CStringEquals
-       {
-       public:
-               bool operator()(const char* left, const char* right) const { return (strcmp(left, right) == 0); }
-       };
-       typedef __gnu_cxx::hash_set<const char*, __gnu_cxx::hash<const char*>, CStringEquals>  CStringSet;
-       typedef __gnu_cxx::hash_map<const char*, Atom*, __gnu_cxx::hash<const char*>, CStringEquals> CStringToAtom;
-       
-       class AtomSyncer : public ld::File::AtomHandler {
-       public:
-                                                       AtomSyncer(std::vector<const char*>& a, std::vector<ld::Atom*>&na,
-                                                                               CStringToAtom la, CStringToAtom dla) :
-                                                                               additionalUndefines(a), newAtoms(na), llvmAtoms(la), deadllvmAtoms(dla) { }
-               virtual void            doAtom(class ld::Atom&);
-               
-               std::vector<const char*>&               additionalUndefines;
-               std::vector<ld::Atom*>&                 newAtoms;
-               CStringToAtom                                   llvmAtoms;
-               CStringToAtom                                   deadllvmAtoms;
-       };
-
-       static std::vector<File*>               _s_files;
-};
-
-std::vector<File*> Parser::_s_files;
-
-
-const char* Parser::tripletPrefixForArch(cpu_type_t arch)
-{
-       switch (arch) {
-               case CPU_TYPE_POWERPC:
-                       return "powerpc-";
-               case CPU_TYPE_POWERPC64:
-                       return "powerpc64-";
-               case CPU_TYPE_I386:
-                       return "i386-";
-               case CPU_TYPE_X86_64:
-                       return "x86_64-";
-               case CPU_TYPE_ARM:
-                       return "arm";
-       }
-       return "";
-}
-
-bool Parser::validFile(const uint8_t* fileContent, uint64_t fileLength, cpu_type_t architecture)
-{
-       return ::lto_module_is_object_file_in_memory_for_target(fileContent, fileLength, tripletPrefixForArch(architecture));
-}
-
-const char* Parser::fileKind(const uint8_t* p)
-{
-       if ( (p[0] == 0xDE) && (p[1] == 0xC0) && (p[2] == 0x17) && (p[3] == 0x0B) ) {
-               uint32_t arch = LittleEndian::get32(*((uint32_t*)(&p[16])));
-               switch (arch) {
-                       case CPU_TYPE_POWERPC:
-                               return "ppc";
-                       case CPU_TYPE_I386:
-                               return "i386";
-                       case CPU_TYPE_X86_64:
-                               return "x86_64";
-                       case CPU_TYPE_ARM:
-                               return "arm";
-               }
-               return "unknown bitcode architecture";
-       }
-       return NULL;
-}
-
-File* Parser::parse(const uint8_t* fileContent, uint64_t fileLength, const char* path, time_t modTime, 
-                                                                                                                               uint32_t ordinal, cpu_type_t architecture) 
-{
-       File* f = new File(path, modTime, fileContent, fileLength, ordinal, architecture);
-       _s_files.push_back(f);
-       return f;
-}
-
-
-ld::relocatable::File* Parser::parseMachOFile(const uint8_t* p, size_t len, uint32_t nextInputOrdinal, cpu_type_t arch) 
-{
-       switch ( arch ) {
-               case CPU_TYPE_POWERPC:
-                       if ( mach_o::relocatable::Parser<ppc>::validFile(p) )
-                               return mach_o::relocatable::Parser<ppc>::parse(p, len, "/tmp/lto.o", 0, nextInputOrdinal);
-                       break;
-               case CPU_TYPE_POWERPC64:
-                       if ( mach_o::relocatable::Parser<ppc64>::validFile(p) )
-                               return mach_o::relocatable::Parser<ppc64>::parse(p, len, "/tmp/lto.o", 0, nextInputOrdinal);
-                       break;
-               case CPU_TYPE_I386:
-                       if ( mach_o::relocatable::Parser<x86>::validFile(p) )
-                               return mach_o::relocatable::Parser<x86>::parse(p, len, "/tmp/lto.o", 0, nextInputOrdinal);
-                       break;
-               case CPU_TYPE_X86_64:
-                       if ( mach_o::relocatable::Parser<x86_64>::validFile(p) )
-                               return mach_o::relocatable::Parser<x86_64>::parse(p, len, "/tmp/lto.o", 0, nextInputOrdinal);
-                       break;
-               case CPU_TYPE_ARM:
-                       if ( mach_o::relocatable::Parser<arm>::validFile(p) )
-                               return mach_o::relocatable::Parser<arm>::parse(p, len, "/tmp/lto.o", 0, nextInputOrdinal);
-                       break;
-       }
-       throw "LLVM LTO, file is not of required architecture";
-}
-
-
-
-File::File(const char* path, time_t mTime, const uint8_t* content, uint32_t contentLength, uint32_t ordinal, cpu_type_t arch) 
-       : ld::relocatable::File(path,mTime,ordinal), _architecture(arch), _internalAtom(*this), 
-       _atomArray(NULL), _atomArrayCount(0), _module(NULL),
-       _section("__TEXT_", "__tmp_lto", ld::Section::typeUnclassified)
-{
-       // create llvm module
-       _module = ::lto_module_create_from_memory(content, contentLength);
-    if ( _module == NULL )
-               throwf("could not parse object file %s: %s", path, lto_get_error_message());
-       
-       // create atom for each global symbol in module
-       uint32_t count = ::lto_module_get_num_symbols(_module);
-       _atomArray = (Atom*)malloc(sizeof(Atom)*count);
-       for (uint32_t i=0; i < count; ++i) {
-               const char* name = ::lto_module_get_symbol_name(_module, i);
-               lto_symbol_attributes attr = lto_module_get_symbol_attribute(_module, i);
-
-               // <rdar://problem/6378110> LTO doesn't like dtrace symbols
-               // ignore dtrace static probes for now
-               // later when codegen is done and a mach-o file is produces the probes will be processed
-               if ( (strncmp(name, "___dtrace_probe$", 16) == 0) || (strncmp(name, "___dtrace_isenabled$", 20) == 0) )
-                       continue;
-                               
-               ld::Atom::Definition def;
-               switch ( attr & LTO_SYMBOL_DEFINITION_MASK ) {
-                       case LTO_SYMBOL_DEFINITION_REGULAR:
-                               def = ld::Atom::definitionRegular;
-                               break;
-                       case LTO_SYMBOL_DEFINITION_TENTATIVE:
-                               def = ld::Atom::definitionTentative;
-                               break;
-                       case LTO_SYMBOL_DEFINITION_WEAK:
-                               def = ld::Atom::definitionRegular;
-                               break;
-                       case LTO_SYMBOL_DEFINITION_UNDEFINED:
-                       case LTO_SYMBOL_DEFINITION_WEAKUNDEF:
-                               def = ld::Atom::definitionProxy;
-                               break;
-                       default:
-                               throwf("unknown definition kind for symbol %s in bitcode file %s", name, path);
-               }
-
-               // make LLVM atoms for definitions and a reference for undefines
-               if ( def != ld::Atom::definitionProxy ) {
-                       ld::Atom::Scope scope;
-                       switch ( attr & LTO_SYMBOL_SCOPE_MASK) {
-                               case LTO_SYMBOL_SCOPE_INTERNAL:
-                                       scope = ld::Atom::scopeTranslationUnit;
-                                       break;
-                               case LTO_SYMBOL_SCOPE_HIDDEN:
-                                       scope = ld::Atom::scopeLinkageUnit;
-                                       break;
-                               case LTO_SYMBOL_SCOPE_DEFAULT:
-                                       scope = ld::Atom::scopeGlobal;
-                                       break;
-                               default:
-                                       throwf("unknown scope for symbol %s in bitcode file %s", name, path);
-                       }
-                       // only make atoms for non-internal symbols 
-                       if ( scope == ld::Atom::scopeTranslationUnit )
-                               continue;
-                       uint8_t alignment = (attr & LTO_SYMBOL_ALIGNMENT_MASK);
-                       // make Atom using placement new operator
-                       new (&_atomArray[_atomArrayCount++]) Atom(*this, name, scope, def, alignment);
-               }
-               else {
-                       // add to list of external references
-                       _internalAtom.addReference(name);
-               }
-       }
-}
-
-File::~File()
-{
-       if ( _module != NULL )
-               ::lto_module_dispose(_module);
-}
-
-bool File::forEachAtom(ld::File::AtomHandler& handler)
-{
-       handler.doAtom(_internalAtom);
-       for(uint32_t i=0; i < _atomArrayCount; ++i) {
-               handler.doAtom(_atomArray[i]);
-       }
-       return true;
-}
-
-InternalAtom::InternalAtom(File& f)
-       : ld::Atom(f._section, ld::Atom::definitionRegular, ld::Atom::combineNever, ld::Atom::scopeTranslationUnit, 
-                               ld::Atom::typeLTOtemporary, ld::Atom::symbolTableNotIn, false, false, ld::Atom::Alignment(0)),
-               _file(f)
-{
-}
-
-Atom::Atom(File& f, const char* name, ld::Atom::Scope s, ld::Atom::Definition d, ld::Atom::Alignment a)
-       : ld::Atom(f._section, d, ld::Atom::combineNever, s, ld::Atom::typeLTOtemporary, ld::Atom::symbolTableIn, false, false, a),
-               _file(f), _name(name), _compiledAtom(NULL)
-{
-}
-
-
-
-
-bool Parser::optimize(const std::vector<ld::Atom*>& allAtoms, std::vector<ld::Atom*>& newAtoms, 
-                                                                                               std::vector<const char*>& additionalUndefines, 
-                                                                                               const std::set<ld::Atom*>& deadAtoms,
-                                                                                               std::vector<ld::Atom*>& newlyDeadAtoms,
-                                                                                               uint32_t nextInputOrdinal, 
-                                                                                               ld::OutFile* writer, ld::Atom* entryPointAtom,
-                                                                                               const std::vector<const char*>& llvmOptions,
-                                                                                               bool allGlobalsAReDeadStripRoots,
-                                                                                               bool verbose, bool saveTemps, 
-                                                                                               const char* outputFilePath,
-                                                                                               bool pie, bool mainExecutable, bool staticExecutable, bool relocatable,
-                                                                                               bool allowTextRelocs, cpu_type_t arch)
-{ 
-       // exit quickly if nothing to do
-       if ( _s_files.size() == 0 ) 
-               return false;
-       
-       // print out LTO version string if -v was used
-       if ( verbose )
-               fprintf(stderr, "%s\n", lto_get_version());
-       
-       // create optimizer and add each Reader
-       lto_code_gen_t generator = ::lto_codegen_create();
-       for (std::vector<File*>::iterator it=_s_files.begin(); it != _s_files.end(); ++it) {
-               if ( ::lto_codegen_add_module(generator, (*it)->module()) )
-                       throwf("lto: could not merge in %s because %s", (*it)->path(), ::lto_get_error_message());
-       }
-
-       // add any -mllvm command line options
-       for (std::vector<const char*>::const_iterator it=llvmOptions.begin(); it != llvmOptions.end(); ++it) {
-               ::lto_codegen_debug_options(generator, *it);
-       }
-
-       // The atom graph uses directed edges (references). Collect all references where 
-       // originating atom is not part of any LTO Reader. This allows optimizer to optimize an 
-       // external (i.e. not originated from same .o file) reference if all originating atoms are also 
-       // defined in llvm bitcode file.
-       CStringSet nonLLVMRefs;
-       CStringToAtom llvmAtoms;
-    bool hasNonllvmAtoms = false;
-       for (std::vector<ld::Atom*>::const_iterator it = allAtoms.begin(); it != allAtoms.end(); ++it) {
-               ld::Atom* atom = *it;
-               // only look at references that come from an atom that is not an llvm atom
-               if ( atom->contentType() != ld::Atom::typeLTOtemporary ) {
-                       // remember if we've seen any atoms not from an llvm reader and not from the writer
-//                     if ( atom->getFile() != writer )
-//                             hasNonllvmAtoms = true;
-                       for (ld::Fixup::iterator fit=atom->fixupsBegin(); fit != atom->fixupsEnd(); ++fit) {
-                               if ( fit->binding != ld::Fixup::bindingByNameBound )
-                                       continue;
-                               // and reference an llvm atom
-                               if ( fit->u.target->contentType() == ld::Atom::typeLTOtemporary ) 
-                                       nonLLVMRefs.insert(fit->u.target->name());
-                       }
-               }
-               else {
-                       llvmAtoms[atom->name()] = (Atom*)atom;
-               }
-       }
-       // if entry point is in a llvm bitcode file, it must be preserved by LTO
-       if ( entryPointAtom != NULL ) {
-               if ( entryPointAtom->contentType() == ld::Atom::typeLTOtemporary ) 
-                       nonLLVMRefs.insert(entryPointAtom->name());
-       }
-       
-       // deadAtoms are the atoms that the linker coalesced.  For instance weak or tentative definitions
-       // overriden by another atom.  If any of these deadAtoms are llvm atoms and they were replaced
-       // with a mach-o atom, we need to tell the lto engine to preserve (not optimize away) its dead 
-       // atom so that the linker can replace it with the mach-o one later.
-       CStringToAtom deadllvmAtoms;
-       for (std::set<ld::Atom*>::iterator it = deadAtoms.begin(); it != deadAtoms.end(); ++it) {
-               ld::Atom* atom = *it;
-               if ( atom->contentType() == ld::Atom::typeLTOtemporary ) {
-                       const char* name = atom->name();
-                       ::lto_codegen_add_must_preserve_symbol(generator, name);
-                       deadllvmAtoms[name] = (Atom*)atom;
-               }
-       }
-
-       
-       // tell code generator about symbols that must be preserved
-       for (CStringToAtom::iterator it = llvmAtoms.begin(); it != llvmAtoms.end(); ++it) {
-               const char* name = it->first;
-               Atom* atom = it->second;
-               // Include llvm Symbol in export list if it meets one of following two conditions
-               // 1 - atom scope is global (and not linkage unit).
-               // 2 - included in nonLLVMRefs set.
-               // If a symbol is not listed in exportList then LTO is free to optimize it away.
-               if ( (atom->scope() == ld::Atom::scopeGlobal) ) 
-                       ::lto_codegen_add_must_preserve_symbol(generator, name);
-               else if ( nonLLVMRefs.find(name) != nonLLVMRefs.end() ) 
-                       ::lto_codegen_add_must_preserve_symbol(generator, name);
-       }
-       
-    // special case running ld -r on all bitcode files to produce another bitcode file (instead of mach-o)
-    if ( relocatable && !hasNonllvmAtoms ) {
-               if ( ! ::lto_codegen_write_merged_modules(generator, outputFilePath) ) {
-                       // HACK, no good way to tell linker we are all done, so just quit
-                       exit(0);
-               }
-               warning("could not produce merged bitcode file");
-    }
-    
-       // set code-gen model
-       lto_codegen_model model = LTO_CODEGEN_PIC_MODEL_DYNAMIC;
-       if ( mainExecutable ) {
-               if ( staticExecutable ) {
-                       // darwin x86_64 "static" code model is really dynamic code model
-                       if ( arch == CPU_TYPE_X86_64 )
-                               model = LTO_CODEGEN_PIC_MODEL_DYNAMIC;
-                       else
-                               model = LTO_CODEGEN_PIC_MODEL_STATIC;
-               }
-               else {
-                       if ( pie )
-                               model = LTO_CODEGEN_PIC_MODEL_DYNAMIC;
-                       else
-                               model = LTO_CODEGEN_PIC_MODEL_DYNAMIC_NO_PIC;
-               }
-       }
-       else {
-               if ( allowTextRelocs )
-                       model = LTO_CODEGEN_PIC_MODEL_DYNAMIC_NO_PIC;
-               else
-                       model = LTO_CODEGEN_PIC_MODEL_DYNAMIC;
-       }
-       if ( ::lto_codegen_set_pic_model(generator, model) )
-               throwf("could not create set codegen model: %s", lto_get_error_message());
-
-    // if requested, save off merged bitcode file
-    if ( saveTemps ) {
-        char tempBitcodePath[MAXPATHLEN];
-        strcpy(tempBitcodePath, outputFilePath);
-        strcat(tempBitcodePath, ".lto.bc");
-        ::lto_codegen_write_merged_modules(generator, tempBitcodePath);
-    }
-
-#if LTO_API_VERSION >= 3
-       // find assembler next to linker
-       char path[PATH_MAX];
-       uint32_t bufSize = PATH_MAX;
-       if ( _NSGetExecutablePath(path, &bufSize) != -1 ) {
-               char* lastSlash = strrchr(path, '/');
-               if ( lastSlash != NULL ) {
-                       strcpy(lastSlash+1, "as");
-                       struct stat statInfo;
-                       if ( stat(path, &statInfo) == 0 )
-                               ::lto_codegen_set_assembler_path(generator, path);
-               }
-       }
-#endif
-       // run code generator
-       size_t machOFileLen;
-       const uint8_t* machOFile = (uint8_t*)::lto_codegen_compile(generator, &machOFileLen);
-       if ( machOFile == NULL ) 
-               throwf("could not do LTO codegen: %s", ::lto_get_error_message());
-       
-    // if requested, save off temp mach-o file
-    if ( saveTemps ) {
-        char tempMachoPath[MAXPATHLEN];
-        strcpy(tempMachoPath, outputFilePath);
-        strcat(tempMachoPath, ".lto.o");
-        int fd = ::open(tempMachoPath, O_CREAT | O_WRONLY | O_TRUNC, 0666);
-               if ( fd != -1) {
-                       ::write(fd, machOFile, machOFileLen);
-                       ::close(fd);
-               }
-               //      save off merged bitcode file
-               char tempOptBitcodePath[MAXPATHLEN];
-        strcpy(tempOptBitcodePath, outputFilePath);
-        strcat(tempOptBitcodePath, ".lto.opt.bc");
-        ::lto_codegen_write_merged_modules(generator, tempOptBitcodePath);
-       }
-
-       // parse generated mach-o file into a MachOReader
-       ld::File* machoFile = parseMachOFile(machOFile, machOFileLen, nextInputOrdinal, arch);
-       
-       // sync generated mach-o atoms with existing atoms ld knows about
-       AtomSyncer syncer(additionalUndefines,newAtoms,llvmAtoms,deadllvmAtoms);
-       machoFile->forEachAtom(syncer);
-                       
-       // Remove InternalAtoms from ld
-       for (std::vector<File*>::iterator it=_s_files.begin(); it != _s_files.end(); ++it) {
-               newlyDeadAtoms.push_back(&((*it)->internalAtom()));
-       }
-       // Remove Atoms from ld if code generator optimized them away
-       for (CStringToAtom::iterator li = llvmAtoms.begin(), le = llvmAtoms.end(); li != le; ++li) {
-               // check if setRealAtom() called on this Atom
-               if ( li->second->compiledAtom() == NULL )
-                       newlyDeadAtoms.push_back(li->second);
-       }
-       
-       return true;
-}
-
-
-void Parser::AtomSyncer::doAtom(ld::Atom& machoAtom)
-{
-       // update proxy atoms to point to real atoms and find new atoms
-       const char* name = machoAtom.name();
-       if ( machoAtom.scope() >= ld::Atom::scopeLinkageUnit ) {
-               CStringToAtom::iterator pos = llvmAtoms.find(name);
-               if ( pos != llvmAtoms.end() ) {
-                       // turn Atom into a proxy for this mach-o atom
-                       pos->second->setCompiledAtom(machoAtom);
-               }
-               else {
-                       // an atom of this name was not in the allAtoms list the linker gave us
-                       if ( deadllvmAtoms.find(name) != deadllvmAtoms.end() ) {
-                               // this corresponding to an atom that the linker coalesced away.  
-                               // Don't pass it back as a new atom
-                       }
-                       else
-                       {
-                               // this is something new that lto conjured up, tell ld its new
-                               newAtoms.push_back(&machoAtom);
-                       }
-               }
-       }
-       else {
-               // ld only knew about non-satic atoms, so this one must be new
-               newAtoms.push_back(&machoAtom);
-       }
-       
-       // adjust fixups to go through proxy atoms
-       for (ld::Fixup::iterator fit=machoAtom.fixupsBegin(); fit != machoAtom.fixupsEnd(); ++fit) {
-               switch ( fit->binding ) {
-                       case ld::Fixup::bindingNone:
-                               break;
-                       case ld::Fixup::bindingByNameUnbound:
-                               // don't know if this target has been seen by linker before or if it is new
-                               // be conservitive and tell linker it is new
-                               additionalUndefines.push_back(fit->u.name);
-                               break;
-                       case ld::Fixup::bindingByNameBound:
-                               break;
-                       case ld::Fixup::bindingDirectlyBound:
-                               // If mach-o atom is referencing another mach-o atom then 
-                               // reference is not going through Atom proxy. Fix it here to ensure that all
-                               // llvm symbol references always go through Atom proxy.
-                               break;
-                       case ld::Fixup::bindingByContentBound:
-                               break;
-               }
-       }
-
-}
-       
-
-
-}; // namespace lto
-
-
-#endif
-
index fbba2375185fa8ca655addd995867954e61eb8c2..26d70be8492c5b14d1842fd05abcb491f588a35a 100644 (file)
@@ -33,6 +33,7 @@
 #include <pthread.h>
 #include <mach-o/dyld.h>
 #include <vector>
 #include <pthread.h>
 #include <mach-o/dyld.h>
 #include <vector>
+#include <map>
 #include <unordered_set>
 #include <unordered_map>
 
 #include <unordered_set>
 #include <unordered_map>
 
@@ -118,6 +119,9 @@ public:
                                                                                                                                                                                _debugInfoModTime = modTime; 
                                                                                                                                                                                _cpuSubType = subtype;}
 
                                                                                                                                                                                _debugInfoModTime = modTime; 
                                                                                                                                                                                _cpuSubType = subtype;}
 
+    static bool                                         sSupportsLocalContext;
+    static bool                                         sHasTriedLocalContext;
+    bool                                                mergeIntoGenerator(lto_code_gen_t generator, bool useSetModule);
 private:
        friend class Atom;
        friend class InternalAtom;
 private:
        friend class Atom;
        friend class InternalAtom;
@@ -128,6 +132,9 @@ private:
        class Atom*                                                             _atomArray;
        uint32_t                                                                _atomArrayCount;
        lto_module_t                                                    _module;
        class Atom*                                                             _atomArray;
        uint32_t                                                                _atomArrayCount;
        lto_module_t                                                    _module;
+       const char*                             _path;
+       const uint8_t*                          _content;
+       uint32_t                                _contentLength;
        const char*                                                             _debugInfoPath;
        time_t                                                                  _debugInfoModTime;
        ld::Section                                                             _section;
        const char*                                                             _debugInfoPath;
        time_t                                                                  _debugInfoModTime;
        ld::Section                                                             _section;
@@ -303,8 +310,11 @@ ld::relocatable::File* Parser::parseMachOFile(const uint8_t* p, size_t len, cons
        objOpts.neverConvertDwarf   = false;
        objOpts.verboseOptimizationHints = options.verboseOptimizationHints;
        objOpts.armUsesZeroCostExceptions = options.armUsesZeroCostExceptions;
        objOpts.neverConvertDwarf   = false;
        objOpts.verboseOptimizationHints = options.verboseOptimizationHints;
        objOpts.armUsesZeroCostExceptions = options.armUsesZeroCostExceptions;
-
+       objOpts.simulator                       = options.simulator;
+       objOpts.ignoreMismatchPlatform = options.ignoreMismatchPlatform;
+       objOpts.platform                        = options.platform;
        objOpts.subType                         = 0;
        objOpts.subType                         = 0;
+       objOpts.srcKind                         = ld::relocatable::File::kSourceLTO;
        
        // mach-o parsing is done in-memory, but need path for debug notes
        const char* path = "/tmp/lto.o";
        
        // mach-o parsing is done in-memory, but need path for debug notes
        const char* path = "/tmp/lto.o";
@@ -326,7 +336,8 @@ ld::relocatable::File* Parser::parseMachOFile(const uint8_t* p, size_t len, cons
 
 File::File(const char* pth, time_t mTime, ld::File::Ordinal ordinal, const uint8_t* content, uint32_t contentLength, cpu_type_t arch) 
        : ld::relocatable::File(pth,mTime,ordinal), _architecture(arch), _internalAtom(*this), 
 
 File::File(const char* pth, time_t mTime, ld::File::Ordinal ordinal, const uint8_t* content, uint32_t contentLength, cpu_type_t arch) 
        : ld::relocatable::File(pth,mTime,ordinal), _architecture(arch), _internalAtom(*this), 
-       _atomArray(NULL), _atomArrayCount(0), _module(NULL), _debugInfoPath(pth), 
+       _atomArray(NULL), _atomArrayCount(0), _module(NULL), _path(pth),
+       _content(content), _contentLength(contentLength), _debugInfoPath(pth),
        _section("__TEXT_", "__tmp_lto", ld::Section::typeTempLTO),
        _fixupToInternal(0, ld::Fixup::k1of1, ld::Fixup::kindNone, &_internalAtom),
        _debugInfo(ld::relocatable::File::kDebugInfoNone), _cpuSubType(0)
        _section("__TEXT_", "__tmp_lto", ld::Section::typeTempLTO),
        _fixupToInternal(0, ld::Fixup::k1of1, ld::Fixup::kindNone, &_internalAtom),
        _debugInfo(ld::relocatable::File::kDebugInfoNone), _cpuSubType(0)
@@ -334,9 +345,19 @@ File::File(const char* pth, time_t mTime, ld::File::Ordinal ordinal, const uint8
        const bool log = false;
        
        // create llvm module
        const bool log = false;
        
        // create llvm module
+#if LTO_API_VERSION >= 11
+       if ( sSupportsLocalContext || !sHasTriedLocalContext ) {
+               _module = ::lto_module_create_in_local_context(content, contentLength, pth);
+       }
+       if ( !sHasTriedLocalContext ) {
+               sHasTriedLocalContext = true;
+               sSupportsLocalContext = (_module != NULL);
+       }
+       if ( (_module == NULL) && !sSupportsLocalContext )
+#endif
 #if LTO_API_VERSION >= 9
        _module = ::lto_module_create_from_memory_with_path(content, contentLength, pth);
 #if LTO_API_VERSION >= 9
        _module = ::lto_module_create_from_memory_with_path(content, contentLength, pth);
-       if ( _module == NULL )
+       if ( _module == NULL && !sSupportsLocalContext )
 #endif
        _module = ::lto_module_create_from_memory(content, contentLength);
     if ( _module == NULL )
 #endif
        _module = ::lto_module_create_from_memory(content, contentLength);
     if ( _module == NULL )
@@ -417,6 +438,11 @@ File::File(const char* pth, time_t mTime, ld::File::Ordinal ordinal, const uint8
                        if ( log ) fprintf(stderr, "\t%s (undefined)\n", name);
                }
        }
                        if ( log ) fprintf(stderr, "\t%s (undefined)\n", name);
                }
        }
+
+#if LTO_API_VERSION >= 11
+       if ( sSupportsLocalContext )
+               this->release();
+#endif
 }
 
 File::~File()
 }
 
 File::~File()
@@ -424,6 +450,34 @@ File::~File()
        this->release();
 }
 
        this->release();
 }
 
+bool File::mergeIntoGenerator(lto_code_gen_t generator, bool useSetModule) {
+#if LTO_API_VERSION >= 11
+    if ( sSupportsLocalContext ) {
+        assert(!_module && "Expected module to be disposed");
+        _module = ::lto_module_create_in_codegen_context(_content, _contentLength,
+                                                        _path, generator);
+        if ( _module == NULL )
+            throwf("could not reparse object file %s: '%s', using libLTO version '%s'",
+                  _path, ::lto_get_error_message(), ::lto_get_version());
+    }
+#endif
+    assert(_module && "Expected module to stick around");
+#if LTO_API_VERSION >= 13
+    if (useSetModule) {
+        // lto_codegen_set_module will transfer ownership of the module to LTO code generator,
+        // so we don't need to release the module here.
+        ::lto_codegen_set_module(generator, _module);
+        return false;
+    }
+#endif
+    if ( ::lto_codegen_add_module(generator, _module) )
+        return true;
+
+    // <rdar://problem/15471128> linker should release module as soon as possible
+    this->release();
+    return false;
+}
+
 void File::release()
 {
        if ( _module != NULL )
 void File::release()
 {
        if ( _module != NULL )
@@ -486,6 +540,8 @@ void Parser::ltoDiagnosticHandler(lto_codegen_diagnostic_severity_t severity, co
        switch ( severity ) {
 #if LTO_API_VERSION >= 10
                case LTO_DS_REMARK:
        switch ( severity ) {
 #if LTO_API_VERSION >= 10
                case LTO_DS_REMARK:
+                       fprintf(stderr, "ld: LTO remark: %s\n", message);
+                       break;
 #endif
                case LTO_DS_NOTE:
                case LTO_DS_WARNING:
 #endif
                case LTO_DS_NOTE:
                case LTO_DS_WARNING:
@@ -518,7 +574,13 @@ bool Parser::optimize(  const std::vector<const ld::Atom*>&        allAtoms,
                fprintf(stderr, "%s\n", ::lto_get_version());
        
        // create optimizer and add each Reader
                fprintf(stderr, "%s\n", ::lto_get_version());
        
        // create optimizer and add each Reader
-       lto_code_gen_t generator = ::lto_codegen_create();
+       lto_code_gen_t generator = NULL;
+#if LTO_API_VERSION >= 11
+       if ( File::sSupportsLocalContext )
+               generator = ::lto_codegen_create_in_local_context();
+       else
+#endif
+               generator = ::lto_codegen_create();
 #if LTO_API_VERSION >= 7
        lto_codegen_set_diagnostic_handler(generator, ltoDiagnosticHandler, NULL);
 #endif
 #if LTO_API_VERSION >= 7
        lto_codegen_set_diagnostic_handler(generator, ltoDiagnosticHandler, NULL);
 #endif
@@ -526,14 +588,20 @@ bool Parser::optimize(  const std::vector<const ld::Atom*>&       allAtoms,
        // <rdar://problem/12379604> The order that files are merged must match command line order
        std::sort(_s_files.begin(), _s_files.end(), CommandLineOrderFileSorter());
        ld::File::Ordinal lastOrdinal;
        // <rdar://problem/12379604> The order that files are merged must match command line order
        std::sort(_s_files.begin(), _s_files.end(), CommandLineOrderFileSorter());
        ld::File::Ordinal lastOrdinal;
+
+       // When flto_codegen_only is on and we have a single .bc file, use lto_codegen_set_module instead of
+       // lto_codegen_add_module, to make sure the the destination module will be the same as the input .bc file.
+       bool useSetModule = false;
+#if LTO_API_VERSION >= 13
+       useSetModule = (_s_files.size() == 1) && options.ltoCodegenOnly && (::lto_api_version() >= 13);
+#endif
        for (std::vector<File*>::iterator it=_s_files.begin(); it != _s_files.end(); ++it) {
                File* f = *it;
                assert(f->ordinal() > lastOrdinal);
        for (std::vector<File*>::iterator it=_s_files.begin(); it != _s_files.end(); ++it) {
                File* f = *it;
                assert(f->ordinal() > lastOrdinal);
-               if ( logBitcodeFiles ) fprintf(stderr, "lto_codegen_add_module(%s)\n", f->path());
-               if ( ::lto_codegen_add_module(generator, f->module()) )
+               if ( logBitcodeFiles && !useSetModule) fprintf(stderr, "lto_codegen_add_module(%s)\n", f->path());
+               if ( logBitcodeFiles && useSetModule) fprintf(stderr, "lto_codegen_set_module(%s)\n", f->path());
+               if ( f->mergeIntoGenerator(generator, useSetModule) )
                        throwf("lto: could not merge in %s because '%s', using libLTO version '%s'", f->path(), ::lto_get_error_message(), ::lto_get_version());
                        throwf("lto: could not merge in %s because '%s', using libLTO version '%s'", f->path(), ::lto_get_error_message(), ::lto_get_version());
-               // <rdar://problem/15471128> linker should release module as soon as possible
-               f->release();
                lastOrdinal = f->ordinal();
        }
 
                lastOrdinal = f->ordinal();
        }
 
@@ -653,6 +721,9 @@ bool Parser::optimize(  const std::vector<const ld::Atom*>& allAtoms,
 
     // special case running ld -r on all bitcode files to produce another bitcode file (instead of mach-o)
     if ( options.relocatable && !hasNonllvmAtoms ) {
 
     // special case running ld -r on all bitcode files to produce another bitcode file (instead of mach-o)
     if ( options.relocatable && !hasNonllvmAtoms ) {
+#if LTO_API_VERSION >= 15
+               ::lto_codegen_set_should_embed_uselists(generator, false);
+#endif
                if ( ! ::lto_codegen_write_merged_modules(generator, options.outputFilePath) ) {
                        // HACK, no good way to tell linker we are all done, so just quit
                        exit(0);
                if ( ! ::lto_codegen_write_merged_modules(generator, options.outputFilePath) ) {
                        // HACK, no good way to tell linker we are all done, so just quit
                        exit(0);
@@ -691,6 +762,9 @@ bool Parser::optimize(  const std::vector<const ld::Atom*>& allAtoms,
         char tempBitcodePath[MAXPATHLEN];
         strcpy(tempBitcodePath, options.outputFilePath);
         strcat(tempBitcodePath, ".lto.bc");
         char tempBitcodePath[MAXPATHLEN];
         strcpy(tempBitcodePath, options.outputFilePath);
         strcat(tempBitcodePath, ".lto.bc");
+#if LTO_API_VERSION >= 15
+        ::lto_codegen_set_should_embed_uselists(generator, true);
+#endif
         ::lto_codegen_write_merged_modules(generator, tempBitcodePath);
     }
 
         ::lto_codegen_write_merged_modules(generator, tempBitcodePath);
     }
 
@@ -708,11 +782,62 @@ bool Parser::optimize(  const std::vector<const ld::Atom*>&       allAtoms,
                }
        }
 #endif
                }
        }
 #endif
-       // run code generator
-       size_t machOFileLen;
-       const uint8_t* machOFile = (uint8_t*)::lto_codegen_compile(generator, &machOFileLen);
-       if ( machOFile == NULL ) 
-               throwf("could not do LTO codegen: '%s', using libLTO version '%s'", ::lto_get_error_message(), ::lto_get_version());
+
+       // When lto API version is greater than or equal to 12, we use lto_codegen_optimize and lto_codegen_compile_optimized
+       // instead of lto_codegen_compile, and we save the merged bitcode file in between.
+       bool useSplitAPI = false;
+#if LTO_API_VERSION >= 12
+       if ( ::lto_api_version() >= 12)
+               useSplitAPI = true;
+#endif
+
+       size_t machOFileLen = 0;
+       const uint8_t* machOFile = NULL;
+       if ( useSplitAPI) {
+#if LTO_API_VERSION >= 12
+#if LTO_API_VERSION >= 14
+       if ( ::lto_api_version() >= 14 && options.ltoCodegenOnly)
+          lto_codegen_set_should_internalize(generator, false);
+#endif
+               // run optimizer
+               if ( !options.ltoCodegenOnly && ::lto_codegen_optimize(generator) )
+                       throwf("could not do LTO optimization: '%s', using libLTO version '%s'", ::lto_get_error_message(), ::lto_get_version());
+
+               if ( options.saveTemps || options.bitcodeBundle ) {
+                       // save off merged bitcode file
+                       char tempOptBitcodePath[MAXPATHLEN];
+                       strcpy(tempOptBitcodePath, options.outputFilePath);
+                       strcat(tempOptBitcodePath, ".lto.opt.bc");
+#if LTO_API_VERSION >= 15
+                       ::lto_codegen_set_should_embed_uselists(generator, true);
+#endif
+                       ::lto_codegen_write_merged_modules(generator, tempOptBitcodePath);
+                       if ( options.bitcodeBundle )
+                               state.ltoBitcodePath = tempOptBitcodePath;
+               }
+
+               // run code generator
+               machOFile = (uint8_t*)::lto_codegen_compile_optimized(generator, &machOFileLen);
+#endif
+               if ( machOFile == NULL )
+                       throwf("could not do LTO codegen: '%s', using libLTO version '%s'", ::lto_get_error_message(), ::lto_get_version());
+       }
+       else {
+               // run optimizer and code generator
+               machOFile = (uint8_t*)::lto_codegen_compile(generator, &machOFileLen);
+               if ( machOFile == NULL )
+                       throwf("could not do LTO codegen: '%s', using libLTO version '%s'", ::lto_get_error_message(), ::lto_get_version());
+               if ( options.saveTemps ) {
+                       // save off merged bitcode file
+                       char tempOptBitcodePath[MAXPATHLEN];
+                       strcpy(tempOptBitcodePath, options.outputFilePath);
+                       strcat(tempOptBitcodePath, ".lto.opt.bc");
+#if LTO_API_VERSION >= 15
+                       ::lto_codegen_set_should_embed_uselists(generator, true);
+#endif
+                       ::lto_codegen_write_merged_modules(generator, tempOptBitcodePath);
+               }
+       }
        
     // if requested, save off temp mach-o file
     if ( options.saveTemps ) {
        
     // if requested, save off temp mach-o file
     if ( options.saveTemps ) {
@@ -724,11 +849,6 @@ bool Parser::optimize(  const std::vector<const ld::Atom*>&        allAtoms,
                        ::write(fd, machOFile, machOFileLen);
                        ::close(fd);
                }
                        ::write(fd, machOFile, machOFileLen);
                        ::close(fd);
                }
-               //      save off merged bitcode file
-               char tempOptBitcodePath[MAXPATHLEN];
-        strcpy(tempOptBitcodePath, options.outputFilePath);
-        strcat(tempOptBitcodePath, ".lto.opt.bc");
-        ::lto_codegen_write_merged_modules(generator, tempOptBitcodePath);
        }
 
        // if needed, save temp mach-o file to specific location
        }
 
        // if needed, save temp mach-o file to specific location
@@ -860,7 +980,7 @@ void Parser::AtomSyncer::doAtom(const ld::Atom& machoAtom)
                                        }
                                        else {
                                                // <rdar://problem/12859831> Don't unbind follow-on reference into by-name reference 
                                        }
                                        else {
                                                // <rdar://problem/12859831> Don't unbind follow-on reference into by-name reference 
-                                               if ( (_deadllvmAtoms.find(targetName) != _deadllvmAtoms.end()) && (fit->kind != ld::Fixup::kindNoneFollowOn) ) {
+                                               if ( (_deadllvmAtoms.find(targetName) != _deadllvmAtoms.end()) && (fit->kind != ld::Fixup::kindNoneFollowOn) && (fit->u.target->scope() != ld::Atom::scopeTranslationUnit) ) {
                                                        // target was coalesed away and replace by mach-o atom from a non llvm .o file
                                                        fit->binding = ld::Fixup::bindingByNameUnbound;
                                                        fit->u.name = targetName;
                                                        // target was coalesed away and replace by mach-o atom from a non llvm .o file
                                                        fit->binding = ld::Fixup::bindingByNameUnbound;
                                                        fit->u.name = targetName;
@@ -888,6 +1008,8 @@ public:
        ~Mutex() { pthread_mutex_unlock(&lto_lock); }
 };
 pthread_mutex_t Mutex::lto_lock = PTHREAD_MUTEX_INITIALIZER;
        ~Mutex() { pthread_mutex_unlock(&lto_lock); }
 };
 pthread_mutex_t Mutex::lto_lock = PTHREAD_MUTEX_INITIALIZER;
+bool File::sSupportsLocalContext = false;
+bool File::sHasTriedLocalContext = false;
 
 //
 // Used by archive reader to see if member is an llvm bitcode file
 
 //
 // Used by archive reader to see if member is an llvm bitcode file
@@ -899,6 +1021,18 @@ bool isObjectFile(const uint8_t* fileContent, uint64_t fileLength, cpu_type_t ar
 }
 
 
 }
 
 
+static ld::relocatable::File *parseImpl(
+          const uint8_t *fileContent, uint64_t fileLength, const char *path,
+          time_t modTime, ld::File::Ordinal ordinal, cpu_type_t architecture,
+          cpu_subtype_t subarch, bool logAllFiles,
+          bool verboseOptimizationHints)
+{
+       if ( Parser::validFile(fileContent, fileLength, architecture, subarch) )
+               return Parser::parse(fileContent, fileLength, path, modTime, ordinal, architecture, subarch, logAllFiles, verboseOptimizationHints);
+       else
+               return NULL;
+}
+
 //
 // main function used by linker to instantiate ld::Files
 //
 //
 // main function used by linker to instantiate ld::Files
 //
@@ -907,11 +1041,12 @@ ld::relocatable::File* parse(const uint8_t* fileContent, uint64_t fileLength,
                                                                cpu_type_t architecture, cpu_subtype_t subarch, bool logAllFiles,
                                                                bool verboseOptimizationHints)
 {
                                                                cpu_type_t architecture, cpu_subtype_t subarch, bool logAllFiles,
                                                                bool verboseOptimizationHints)
 {
+       // Note: Once lto_module_create_in_local_context() and friends are thread safe
+       // this lock can be removed.
        Mutex lock;
        Mutex lock;
-       if ( Parser::validFile(fileContent, fileLength, architecture, subarch) )
-               return Parser::parse(fileContent, fileLength, path, modTime, ordinal, architecture, subarch, logAllFiles, verboseOptimizationHints);
-       else
-               return NULL;
+       return parseImpl(fileContent, fileLength, path, modTime, ordinal,
+                                       architecture, subarch, logAllFiles,
+                                       verboseOptimizationHints);
 }
 
 //
 }
 
 //
index dcd6e36abbe7929ba8ca21000b6c7e4e7ad03c4b..65682326fda8d772f0ffe85ea538fd7f577e75ad 100644 (file)
@@ -48,6 +48,7 @@ struct OptimizeOptions {
        bool                                                            preserveAllGlobals;
        bool                                                            verbose; 
        bool                                                            saveTemps; 
        bool                                                            preserveAllGlobals;
        bool                                                            verbose; 
        bool                                                            saveTemps; 
+       bool                                                            ltoCodegenOnly;
        bool                                                            pie; 
        bool                                                            mainExecutable; 
        bool                                                            staticExecutable; 
        bool                                                            pie; 
        bool                                                            mainExecutable; 
        bool                                                            staticExecutable; 
@@ -58,8 +59,12 @@ struct OptimizeOptions {
        bool                                                            keepDwarfUnwind; 
        bool                                                            verboseOptimizationHints;
        bool                                                            armUsesZeroCostExceptions;
        bool                                                            keepDwarfUnwind; 
        bool                                                            verboseOptimizationHints;
        bool                                                            armUsesZeroCostExceptions;
+       bool                                                            simulator;
+       bool                                                            ignoreMismatchPlatform;
+       bool                                                            bitcodeBundle;
        cpu_type_t                                                      arch;
        const char*                                                     mcpu;
        cpu_type_t                                                      arch;
        const char*                                                     mcpu;
+       Options::Platform                                       platform;
        const std::vector<const char*>*         llvmOptions;
        const std::vector<const char*>*         initialUndefines;
 };
        const std::vector<const char*>*         llvmOptions;
        const std::vector<const char*>*         initialUndefines;
 };
index a3c14562e4baa3d32031db990404f6c6ae59f973..0ba962cf36d98b52df86aef6401028a70eac279c 100644 (file)
@@ -1,4 +1,3 @@
-
 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
  *
  * Copyright (c) 2005-2011 Apple Inc. All rights reserved.
 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
  *
  * Copyright (c) 2005-2011 Apple Inc. All rights reserved.
 
 #include <vector>
 #include <set>
 
 #include <vector>
 #include <set>
+#include <map>
 #include <algorithm>
 #include <unordered_map>
 #include <unordered_set>
 
 #include "Architectures.hpp"
 #include <algorithm>
 #include <unordered_map>
 #include <unordered_set>
 
 #include "Architectures.hpp"
+#include "Bitcode.hpp"
 #include "MachOFileAbstraction.hpp"
 #include "MachOTrie.hpp"
 #include "macho_dylib_file.h"
 #include "MachOFileAbstraction.hpp"
 #include "MachOTrie.hpp"
 #include "macho_dylib_file.h"
@@ -143,8 +144,10 @@ public:
                                                                                        File(const uint8_t* fileContent, uint64_t fileLength, const char* path,   
                                                                                                        time_t mTime, ld::File::Ordinal ordinal, bool linkingFlatNamespace, 
                                                                                                        bool linkingMainExecutable, bool hoistImplicitPublicDylibs, 
                                                                                        File(const uint8_t* fileContent, uint64_t fileLength, const char* path,   
                                                                                                        time_t mTime, ld::File::Ordinal ordinal, bool linkingFlatNamespace, 
                                                                                                        bool linkingMainExecutable, bool hoistImplicitPublicDylibs, 
-                                                                                                       ld::MacVersionMin macMin, ld::IOSVersionMin iPhoneMin, bool allowSimToMacOSX, bool addVers, 
-                                                                                                       bool logAllFiles, const char* installPath, bool indirectDylib);
+                                                                                                       Options::Platform platform, uint32_t linkMinOSVersion, bool allowSimToMacOSX,
+                                                                                                       bool addVers,  bool buildingForSimulator,
+                                                                                                       bool logAllFiles, const char* installPath,
+                                                                                                       bool indirectDylib, bool ignoreMismatchPlatform);
        virtual                                                                 ~File() {}
 
        // overrides of ld::File
        virtual                                                                 ~File() {}
 
        // overrides of ld::File
@@ -152,7 +155,9 @@ public:
        virtual bool                                                    justInTimeforEachAtom(const char* name, ld::File::AtomHandler&) const;
        virtual ld::File::ObjcConstraint                objCConstraint() const          { return _objcContraint; }
        virtual uint8_t                                                 swiftVersion() const            { return _swiftVersion; }
        virtual bool                                                    justInTimeforEachAtom(const char* name, ld::File::AtomHandler&) const;
        virtual ld::File::ObjcConstraint                objCConstraint() const          { return _objcContraint; }
        virtual uint8_t                                                 swiftVersion() const            { return _swiftVersion; }
-       
+       virtual uint32_t                                                minOSVersion() const            { return _minVersionInDylib; }
+       virtual uint32_t                                                platformLoadCommand() const     { return _platformInDylib; }
+
        // overrides of ld::dylib::File
        virtual void                                                    processIndirectLibraries(ld::dylib::File::DylibHandler*, bool);
        virtual bool                                                    providedExportAtom() const      { return _providedAtom; }
        // overrides of ld::dylib::File
        virtual void                                                    processIndirectLibraries(ld::dylib::File::DylibHandler*, bool);
        virtual bool                                                    providedExportAtom() const      { return _providedAtom; }
@@ -163,18 +168,12 @@ public:
        virtual bool                                                    hasPublicInstallName() const{ return _hasPublicInstallName; }
        virtual bool                                                    hasWeakDefinition(const char* name) const;
        virtual bool                                                    allSymbolsAreWeakImported() const;
        virtual bool                                                    hasPublicInstallName() const{ return _hasPublicInstallName; }
        virtual bool                                                    hasWeakDefinition(const char* name) const;
        virtual bool                                                    allSymbolsAreWeakImported() const;
-       virtual const void*                                             codeSignatureDR() const         { return _codeSignatureDR; }
        virtual bool                                                    installPathVersionSpecific() const { return _installPathOverride; }
        virtual bool                                                    appExtensionSafe() const        { return _appExtensionSafe; };
        virtual bool                                                    installPathVersionSpecific() const { return _installPathOverride; }
        virtual bool                                                    appExtensionSafe() const        { return _appExtensionSafe; };
-       virtual ld::MacVersionMin                               macMinVersion() const           { return _macMinVersionInDylib; }
-       virtual ld::IOSVersionMin                               iOSMinVersion() const           { return _iOSMinVersionInDylib; }
-
+       virtual ld::Bitcode*                                    getBitcode() const                      { return _bitcode.get(); }
 
 protected:
 
 protected:
-
-       struct ReExportChain { ReExportChain* prev; File<A>* file; };
-
-       void                                                                                    assertNoReExportCycles(ReExportChain*);
+       virtual void                                                    assertNoReExportCycles(ReExportChain*) const;
 
 private:
        typedef typename A::P                                   P;
 
 private:
        typedef typename A::P                                   P;
@@ -192,13 +191,14 @@ private:
                        return size_t(__h);
                };
        };
                        return size_t(__h);
                };
        };
-       struct AtomAndWeak { ld::Atom* atom; bool weakDef; bool tlv; pint_t address; };
+       struct AtomAndWeak { ld::Atom* atom; bool weakDef; bool tlv; uint64_t address; };
        typedef std::unordered_map<const char*, AtomAndWeak, ld::CStringHash, ld::CStringEquals> NameToAtomMap;
        typedef std::unordered_set<const char*, CStringHash, ld::CStringEquals>  NameSet;
 
        struct Dependent { const char* path; File<A>* dylib; bool reExport; };
 
        typedef std::unordered_map<const char*, AtomAndWeak, ld::CStringHash, ld::CStringEquals> NameToAtomMap;
        typedef std::unordered_set<const char*, CStringHash, ld::CStringEquals>  NameSet;
 
        struct Dependent { const char* path; File<A>* dylib; bool reExport; };
 
-       bool                                                                            containsOrReExports(const char* name, bool* weakDef, bool* tlv, pint_t* defAddress) const;
+       virtual std::pair<bool, bool>                           hasWeakDefinitionImpl(const char* name) const;
+       virtual bool                                                            containsOrReExports(const char* name, bool& weakDef, bool& tlv, uint64_t& defAddress) const;
        bool                                                                            isPublicLocation(const char* pth);
        bool                                                                            wrongOS() { return _wrongOS; }
        void                                                                            addSymbol(const char* name, bool weak, bool tlv, pint_t address);
        bool                                                                            isPublicLocation(const char* pth);
        bool                                                                            wrongOS() { return _wrongOS; }
        void                                                                            addSymbol(const char* name, bool weak, bool tlv, pint_t address);
@@ -211,9 +211,9 @@ private:
        static uint32_t                                                         parseVersionNumber32(const char* versionString);
        static const char*                                                      objCInfoSegmentName();
        static const char*                                                      objCInfoSectionName();
        static uint32_t                                                         parseVersionNumber32(const char* versionString);
        static const char*                                                      objCInfoSegmentName();
        static const char*                                                      objCInfoSectionName();
-       
-       const ld::MacVersionMin                                         _macVersionMin;
-       const ld::IOSVersionMin                                         _iOSVersionMin;
+
+       const Options::Platform                                         _platform;
+       const uint32_t                                                          _linkMinOSVersion;
        const bool                                                                      _allowSimToMacOSXLinking;
        const bool                                                                      _addVersionLoadCommand;
        bool                                                                            _linkingFlat;
        const bool                                                                      _allowSimToMacOSXLinking;
        const bool                                                                      _addVersionLoadCommand;
        bool                                                                            _linkingFlat;
@@ -228,7 +228,6 @@ private:
        NameSet                                                                         _ignoreExports;
        const char*                                                                     _parentUmbrella;
        ImportAtom<A>*                                                          _importAtom;
        NameSet                                                                         _ignoreExports;
        const char*                                                                     _parentUmbrella;
        ImportAtom<A>*                                                          _importAtom;
-       const void*                                                                     _codeSignatureDR;
        bool                                                                            _noRexports;
        bool                                                                            _hasWeakExports;
        bool                                                                            _deadStrippable;
        bool                                                                            _noRexports;
        bool                                                                            _hasWeakExports;
        bool                                                                            _deadStrippable;
@@ -239,8 +238,9 @@ private:
        bool                                                                            _installPathOverride;
        bool                                                                            _indirectDylibsProcessed;
        bool                                                                            _appExtensionSafe;
        bool                                                                            _installPathOverride;
        bool                                                                            _indirectDylibsProcessed;
        bool                                                                            _appExtensionSafe;
-       ld::MacVersionMin                                                       _macMinVersionInDylib;
-       ld::IOSVersionMin                                                       _iOSMinVersionInDylib;
+       uint32_t                                                                        _minVersionInDylib;
+       uint32_t                                                                        _platformInDylib;
+       std::unique_ptr<ld::Bitcode>                            _bitcode;
        
        static bool                                                                     _s_logHashtable;
 };
        
        static bool                                                                     _s_logHashtable;
 };
@@ -259,20 +259,20 @@ template <typename A> const char* File<A>::objCInfoSectionName() { return "__ima
 template <typename A>
 File<A>::File(const uint8_t* fileContent, uint64_t fileLength, const char* pth, time_t mTime, ld::File::Ordinal ord,
                                bool linkingFlatNamespace, bool linkingMainExecutable, bool hoistImplicitPublicDylibs,
 template <typename A>
 File<A>::File(const uint8_t* fileContent, uint64_t fileLength, const char* pth, time_t mTime, ld::File::Ordinal ord,
                                bool linkingFlatNamespace, bool linkingMainExecutable, bool hoistImplicitPublicDylibs,
-                               ld::MacVersionMin macMin, ld::IOSVersionMin iOSMin, bool allowSimToMacOSX, bool addVers,
-                               bool logAllFiles, const char* targetInstallPath, bool indirectDylib)
+                               Options::Platform platform, uint32_t linkMinOSVersion, bool allowSimToMacOSX, bool addVers, bool buildingForSimulator,
+                               bool logAllFiles, const char* targetInstallPath, bool indirectDylib, bool ignoreMismatchPlatform)
        : ld::dylib::File(strdup(pth), mTime, ord), 
        : ld::dylib::File(strdup(pth), mTime, ord), 
-       _macVersionMin(macMin), _iOSVersionMin(iOSMin), _allowSimToMacOSXLinking(allowSimToMacOSX), _addVersionLoadCommand(addVers), 
+       _platform(platform), _linkMinOSVersion(linkMinOSVersion), _allowSimToMacOSXLinking(allowSimToMacOSX), _addVersionLoadCommand(addVers), 
        _linkingFlat(linkingFlatNamespace), _implicitlyLinkPublicDylibs(hoistImplicitPublicDylibs),
        _objcContraint(ld::File::objcConstraintNone), _swiftVersion(0),
        _importProxySection("__TEXT", "__import", ld::Section::typeImportProxies, true),
        _flatDummySection("__LINKEDIT", "__flat_dummy", ld::Section::typeLinkEdit, true),
        _linkingFlat(linkingFlatNamespace), _implicitlyLinkPublicDylibs(hoistImplicitPublicDylibs),
        _objcContraint(ld::File::objcConstraintNone), _swiftVersion(0),
        _importProxySection("__TEXT", "__import", ld::Section::typeImportProxies, true),
        _flatDummySection("__LINKEDIT", "__flat_dummy", ld::Section::typeLinkEdit, true),
-       _parentUmbrella(NULL), _importAtom(NULL), _codeSignatureDR(NULL), 
+       _parentUmbrella(NULL), _importAtom(NULL),
        _noRexports(false), _hasWeakExports(false), 
        _deadStrippable(false), _hasPublicInstallName(false), 
         _providedAtom(false), _explictReExportFound(false), _wrongOS(false), _installPathOverride(false), 
        _indirectDylibsProcessed(false), _appExtensionSafe(false),
        _noRexports(false), _hasWeakExports(false), 
        _deadStrippable(false), _hasPublicInstallName(false), 
         _providedAtom(false), _explictReExportFound(false), _wrongOS(false), _installPathOverride(false), 
        _indirectDylibsProcessed(false), _appExtensionSafe(false),
-       _macMinVersionInDylib(ld::macVersionUnset), _iOSMinVersionInDylib(ld::iOSVersionUnset)
+       _minVersionInDylib(0), _platformInDylib(Options::kPlatformUnknown)
 {
        const macho_header<P>* header = (const macho_header<P>*)fileContent;
        const uint32_t cmd_count = header->ncmds();
 {
        const macho_header<P>* header = (const macho_header<P>*)fileContent;
        const uint32_t cmd_count = header->ncmds();
@@ -302,11 +302,11 @@ File<A>::File(const uint8_t* fileContent, uint64_t fileLength, const char* pth,
        // pass 1: get pointers, and see if this dylib uses compressed LINKEDIT format
        const macho_dysymtab_command<P>* dynamicInfo = NULL;
        const macho_dyld_info_command<P>* dyldInfo = NULL;
        // pass 1: get pointers, and see if this dylib uses compressed LINKEDIT format
        const macho_dysymtab_command<P>* dynamicInfo = NULL;
        const macho_dyld_info_command<P>* dyldInfo = NULL;
-       const macho_linkedit_data_command<P>* codeSignature = NULL;
        const macho_nlist<P>* symbolTable = NULL;
        const char*     strings = NULL;
        bool compressedLinkEdit = false;
        uint32_t dependentLibCount = 0;
        const macho_nlist<P>* symbolTable = NULL;
        const char*     strings = NULL;
        bool compressedLinkEdit = false;
        uint32_t dependentLibCount = 0;
+       Options::Platform lcPlatform = Options::kPlatformUnknown;
        const macho_load_command<P>* cmd = cmds;
        for (uint32_t i = 0; i < cmd_count; ++i) {
                macho_dylib_command<P>* dylibID;
        const macho_load_command<P>* cmd = cmds;
        for (uint32_t i = 0; i < cmd_count; ++i) {
                macho_dylib_command<P>* dylibID;
@@ -348,29 +348,24 @@ File<A>::File(const uint8_t* fileContent, uint64_t fileLength, const char* pth,
                                break;
                        case LC_SUB_CLIENT:
                                _allowableClients.push_back(strdup(((macho_sub_client_command<P>*)cmd)->client()));
                                break;
                        case LC_SUB_CLIENT:
                                _allowableClients.push_back(strdup(((macho_sub_client_command<P>*)cmd)->client()));
+                               // <rdar://problem/20627554> Don't hoist "public" (in /usr/lib/) dylibs that should not be directly linked
+                               _hasPublicInstallName = false;
                                break;
                        case LC_VERSION_MIN_MACOSX:
                                break;
                        case LC_VERSION_MIN_MACOSX:
-                               if ( (_iOSVersionMin != ld::iOSVersionUnset) && !_allowSimToMacOSXLinking ) { 
-                                       _wrongOS = true;
-                                       if ( _addVersionLoadCommand && !indirectDylib )
-                                               throw "building for iOS Simulator, but linking against dylib built for MacOSX";
-                               }
-                               _macMinVersionInDylib = (ld::MacVersionMin)((macho_version_min_command<P>*)cmd)->version();
-                               break;
                        case LC_VERSION_MIN_IPHONEOS:
                        case LC_VERSION_MIN_IPHONEOS:
-                               if ( _macVersionMin != ld::macVersionUnset ) {
-                                       _wrongOS = true;
-                                       if ( _addVersionLoadCommand && !indirectDylib )
-                                               throw "building for MacOSX, but linking against dylib built for iOS Simulator";
-                               }
-                               _iOSMinVersionInDylib = (ld::IOSVersionMin)((macho_version_min_command<P>*)cmd)->version();
+                       case LC_VERSION_MIN_WATCHOS:
+       #if SUPPORT_APPLE_TV
+                       case LC_VERSION_MIN_TVOS:
+       #endif
+                               _minVersionInDylib = (ld::MacVersionMin)((macho_version_min_command<P>*)cmd)->version();
+                               _platformInDylib = cmd->cmd();
+                               lcPlatform = Options::platformForLoadCommand(_platformInDylib);
                                break;
                        case LC_CODE_SIGNATURE:
                                break;
                        case LC_CODE_SIGNATURE:
-                               codeSignature = (macho_linkedit_data_command<P>* )cmd;
                                break;
                        case macho_segment_command<P>::CMD:
                                // check for Objective-C info
                                break;
                        case macho_segment_command<P>::CMD:
                                // check for Objective-C info
-                               if ( strcmp(((macho_segment_command<P>*)cmd)->segname(), objCInfoSegmentName()) == 0 ) {
+                               if ( strncmp(((macho_segment_command<P>*)cmd)->segname(), objCInfoSegmentName(), 6) == 0 ) {
                                        const macho_segment_command<P>* segment = (macho_segment_command<P>*)cmd;
                                        const macho_section<P>* const sectionsStart = (macho_section<P>*)((char*)segment + sizeof(macho_segment_command<P>));
                                        const macho_section<P>* const sectionsEnd = &sectionsStart[segment->nsects()];
                                        const macho_segment_command<P>* segment = (macho_segment_command<P>*)cmd;
                                        const macho_section<P>* const sectionsStart = (macho_section<P>*)((char*)segment + sizeof(macho_segment_command<P>));
                                        const macho_section<P>* const sectionsEnd = &sectionsStart[segment->nsects()];
@@ -403,11 +398,88 @@ File<A>::File(const uint8_t* fileContent, uint64_t fileLength, const char* pth,
                                                }
                                        }
                                }
                                                }
                                        }
                                }
+                               // Construct bitcode if there is a bitcode bundle section in the dylib
+                               // Record the size of the section because the content is not checked
+                               else if ( strcmp(((macho_segment_command<P>*)cmd)->segname(), "__LLVM") == 0 ) {
+                                       const macho_section<P>* const sect = (macho_section<P>*)((char*)cmd + sizeof(macho_segment_command<P>));
+                                       if ( strncmp(sect->sectname(), "__bundle", 8) == 0 )
+                                               _bitcode = std::unique_ptr<ld::Bitcode>(new ld::Bitcode(NULL, sect->size()));
+                               }
                }
                cmd = (const macho_load_command<P>*)(((char*)cmd)+cmd->cmdsize());
                if ( cmd > cmdsEnd )
                        throwf("malformed dylb, load command #%d is outside size of load commands in %s", i, pth);
        }
                }
                cmd = (const macho_load_command<P>*)(((char*)cmd)+cmd->cmdsize());
                if ( cmd > cmdsEnd )
                        throwf("malformed dylb, load command #%d is outside size of load commands in %s", i, pth);
        }
+       // arm/arm64 objects are default to ios platform if not set.
+       // rdar://problem/21746314
+       if (lcPlatform == Options::kPlatformUnknown &&
+               (std::is_same<A, arm>::value || std::is_same<A, arm64>::value))
+               lcPlatform = Options::kPlatformiOS;
+
+       // check cross-linking
+       if ( lcPlatform != platform ) {
+               _wrongOS = true;
+               if ( _addVersionLoadCommand && !indirectDylib && !ignoreMismatchPlatform ) {
+                       if ( buildingForSimulator ) {
+                               if ( !_allowSimToMacOSXLinking ) {
+                                       switch (platform) {
+                                               case Options::kPlatformOSX:
+                                               case Options::kPlatformiOS:
+                                                       if ( lcPlatform == Options::kPlatformUnknown )
+                                                               break;
+                                                       // fall through if the Platform is not Unknown
+                                               case Options::kPlatformWatchOS:
+                                                       // WatchOS errors on cross-linking all the time.
+                                                       throwf("building for %s simulator, but linking against dylib built for %s,",
+                                                                  Options::platformName(platform),
+                                                                  Options::platformName(lcPlatform));
+                                                       break;
+       #if SUPPORT_APPLE_TV
+                                               case Options::kPlatform_tvOS:
+                                                       // tvOS is a warning temporarily. rdar://problem/21746965
+                                                       if (platform == Options::kPlatform_tvOS)
+                                                               warning("URGENT: building for %s simulator, but linking against dylib (%s) built for %s. "
+                                                                               "Note: This will be an error in the future.",
+                                                                               Options::platformName(platform), path(),
+                                                                               Options::platformName(lcPlatform));
+                                                       break;
+       #endif
+                                               case Options::kPlatformUnknown:
+                                                       // skip if the target platform is unknown
+                                                       break;
+                                       }
+                               }
+                       }
+                       else {
+                               switch (platform) {
+                                       case Options::kPlatformOSX:
+                                       case Options::kPlatformiOS:
+                                               if ( lcPlatform == Options::kPlatformUnknown )
+                                                       break;
+                                               // fall through if the Platform is not Unknown
+                                       case Options::kPlatformWatchOS:
+                                               // WatchOS errors on cross-linking all the time.
+                                               throwf("building for %s, but linking against dylib built for %s,",
+                                                          Options::platformName(platform),
+                                                          Options::platformName(lcPlatform));
+                                               break;
+       #if SUPPORT_APPLE_TV
+                                       case Options::kPlatform_tvOS:
+                                               // tvOS is a warning temporarily. rdar://problem/21746965
+                                               if (platform == Options::kPlatform_tvOS)
+                                                       warning("URGENT: building for %s, but linking against dylib (%s) built for %s. "
+                                                                       "Note: This will be an error in the future.",
+                                                                       Options::platformName(platform), path(),
+                                                                       Options::platformName(lcPlatform));
+                                               break;
+       #endif
+                                       case Options::kPlatformUnknown:
+                                               // skip if the target platform is unknown
+                                               break;
+                               }
+                       }
+               }
+       }
 
        // figure out if we need to examine dependent dylibs
        // with compressed LINKEDIT format, MH_NO_REEXPORTED_DYLIBS can be trusted
 
        // figure out if we need to examine dependent dylibs
        // with compressed LINKEDIT format, MH_NO_REEXPORTED_DYLIBS can be trusted
@@ -441,7 +513,8 @@ File<A>::File(const uint8_t* fileContent, uint64_t fileLength, const char* pth,
                }
                // verify MH_NO_REEXPORTED_DYLIBS bit was correct
                if ( compressedLinkEdit && !linkingFlatNamespace ) {
                }
                // verify MH_NO_REEXPORTED_DYLIBS bit was correct
                if ( compressedLinkEdit && !linkingFlatNamespace ) {
-                       assert(reExportDylibCount != 0);
+                       if ( reExportDylibCount == 0 )
+                               throwf("malformed dylib has MH_NO_REEXPORTED_DYLIBS flag but no LC_REEXPORT_DYLIB load commands: %s", pth);
                }
                // pass 3 add re-export info
                cmd = cmds;
                }
                // pass 3 add re-export info
                cmd = cmds;
@@ -500,26 +573,7 @@ File<A>::File(const uint8_t* fileContent, uint64_t fileLength, const char* pth,
                }
                _importAtom = new ImportAtom<A>(*this, importNames);
        }
                }
                _importAtom = new ImportAtom<A>(*this, importNames);
        }
-       
-       // if the dylib is code signed, look for its Designated Requirement
-       if ( codeSignature != NULL ) {
-               const Security::BlobCore* overallSignature = (Security::BlobCore*)((char*)header + codeSignature->dataoff());
-               typedef Security::SuperBlob<Security::kSecCodeMagicEmbeddedSignature> EmbeddedSignatureBlob;
-               typedef Security::SuperBlob<Security::kSecCodeMagicRequirementSet> InternalRequirementsBlob;
-               const EmbeddedSignatureBlob* signature = EmbeddedSignatureBlob::specific(overallSignature);
-               if ( signature->validateBlob(codeSignature->datasize()) ) {
-                       const InternalRequirementsBlob* ireq = signature->find<InternalRequirementsBlob>(Security::cdRequirementsSlot);
-                       if ( (ireq != NULL) && ireq->validateBlob() ) {
-                               const Security::BlobCore* dr = ireq->find(Security::kSecDesignatedRequirementType);
-                               if ( (dr != NULL) && dr->validateBlob(Security::kSecCodeMagicRequirement) ) {
-                                       // <rdar://problem/10968461> make copy because mapped file is about to be unmapped
-                                       _codeSignatureDR = ::malloc(dr->length());
-                                       ::memcpy((void*)_codeSignatureDR, dr, dr->length());
-                               }
-                       }
-               }
-       }
-       
+
        // build hash table
        if ( dyldInfo != NULL ) 
                buildExportHashTableFromExportInfo(dyldInfo, fileContent);
        // build hash table
        if ( dyldInfo != NULL ) 
                buildExportHashTableFromExportInfo(dyldInfo, fileContent);
@@ -530,6 +584,7 @@ File<A>::File(const uint8_t* fileContent, uint64_t fileLength, const char* pth,
        munmap((caddr_t)fileContent, fileLength);
 }
 
        munmap((caddr_t)fileContent, fileLength);
 }
 
+
 //
 // Parses number of form X[.Y[.Z]] into a uint32_t where the nibbles are xxxx.yy.zz
 //
 //
 // Parses number of form X[.Y[.Z]] into a uint32_t where the nibbles are xxxx.yy.zz
 //
@@ -634,15 +689,7 @@ void File<A>::addSymbol(const char* name, bool weakDef, bool tlv, pint_t address
                const char* symCond = strchr(symAction, '$');
                if ( symCond != NULL ) {
                        char curOSVers[16];
                const char* symCond = strchr(symAction, '$');
                if ( symCond != NULL ) {
                        char curOSVers[16];
-                       if ( _macVersionMin != ld::macVersionUnset ) {
-                               sprintf(curOSVers, "$os%d.%d$", (_macVersionMin >> 16), ((_macVersionMin >> 8) & 0xFF));
-                       }
-                       else if ( _iOSVersionMin != ld::iOSVersionUnset ) {
-                               sprintf(curOSVers, "$os%d.%d$", (_iOSVersionMin >> 16), ((_iOSVersionMin >> 8) & 0xFF));
-                       }
-                       else {
-                               assert(0 && "targeting neither macosx nor iphoneos");
-                       }
+                       sprintf(curOSVers, "$os%d.%d$", (_linkMinOSVersion >> 16), ((_linkMinOSVersion >> 8) & 0xFF));
                        if ( strncmp(symCond, curOSVers, strlen(curOSVers)) == 0 ) {
                                const char* symName = strchr(&symCond[1], '$');
                                if ( symName != NULL ) {
                        if ( strncmp(symCond, curOSVers, strlen(curOSVers)) == 0 ) {
                                const char* symName = strchr(&symCond[1], '$');
                                if ( symName != NULL ) {
@@ -705,29 +752,34 @@ bool File<A>::forEachAtom(ld::File::AtomHandler& handler) const
        return false;
 }
 
        return false;
 }
 
+
+template <typename A>
+std::pair<bool, bool> File<A>::hasWeakDefinitionImpl(const char* name) const
+{
+       const auto pos = _atoms.find(name);
+       if ( pos != _atoms.end() )
+               return std::make_pair(true, pos->second.weakDef);
+
+       // look in children that I re-export
+       for (const auto &dep : _dependentDylibs) {
+               if ( dep.reExport ) {
+                       auto ret = dep.dylib->hasWeakDefinitionImpl(name);
+                       if ( ret.first )
+                               return ret;
+               }
+       }
+       return std::make_pair(false, false);
+}
+
+
 template <typename A>
 bool File<A>::hasWeakDefinition(const char* name) const
 {
        // if supposed to ignore this export, then pretend I don't have it
        if ( _ignoreExports.count(name) != 0 )
                return false;
 template <typename A>
 bool File<A>::hasWeakDefinition(const char* name) const
 {
        // if supposed to ignore this export, then pretend I don't have it
        if ( _ignoreExports.count(name) != 0 )
                return false;
-               
-       typename NameToAtomMap::const_iterator pos = _atoms.find(name);
-       if ( pos != _atoms.end() ) {
-               return pos->second.weakDef;
-       }
-       else {
-               // look in children that I re-export
-               for (typename std::vector<Dependent>::const_iterator it = _dependentDylibs.begin(); it != _dependentDylibs.end(); ++it) {
-                       if ( it->reExport ) {
-                               //fprintf(stderr, "getJustInTimeAtomsFor: %s NOT found in %s, looking in child %s\n", name, this->path(), (*it)->getInstallPath());
-                               typename NameToAtomMap::iterator cpos = it->dylib->_atoms.find(name);
-                               if ( cpos != it->dylib->_atoms.end() ) 
-                                       return cpos->second.weakDef;
-                       }
-               }
-       }
-       return false;
+
+       return hasWeakDefinitionImpl(name).second;
 }
 
 
 }
 
 
@@ -756,24 +808,24 @@ bool File<A>::allSymbolsAreWeakImported() const
 
 
 template <typename A>
 
 
 template <typename A>
-bool File<A>::containsOrReExports(const char* name, bool* weakDef, bool* tlv, pint_t* defAddress) const
+bool File<A>::containsOrReExports(const char* name, bool& weakDef, bool& tlv, uint64_t& defAddress) const
 {
        if ( _ignoreExports.count(name) != 0 )
                return false;
 
        // check myself
 {
        if ( _ignoreExports.count(name) != 0 )
                return false;
 
        // check myself
-       typename NameToAtomMap::iterator pos = _atoms.find(name);
+       const auto pos = _atoms.find(name);
        if ( pos != _atoms.end() ) {
        if ( pos != _atoms.end() ) {
-               *weakDef = pos->second.weakDef;
-               *tlv = pos->second.tlv;
-               *defAddress = pos->second.address;
+               weakDef = pos->second.weakDef;
+               tlv = pos->second.tlv;
+               defAddress = pos->second.address;
                return true;
        }
        
        // check dylibs I re-export
                return true;
        }
        
        // check dylibs I re-export
-       for (typename std::vector<Dependent>::const_iterator it = _dependentDylibs.begin(); it != _dependentDylibs.end(); ++it) {
-               if ( it->reExport && !it->dylib->implicitlyLinked() ) {
-                       if ( it->dylib->containsOrReExports(name, weakDef, tlv, defAddress) )
+       for (const auto &dep : _dependentDylibs) {
+               if ( dep.reExport && !dep.dylib->implicitlyLinked() ) {
+                       if ( dep.dylib->containsOrReExports(name, weakDef, tlv, defAddress) )
                                return true;
                }
        }
                                return true;
                }
        }
@@ -791,7 +843,7 @@ bool File<A>::justInTimeforEachAtom(const char* name, ld::File::AtomHandler& han
        
        
        AtomAndWeak bucket;
        
        
        AtomAndWeak bucket;
-       if ( this->containsOrReExports(name, &bucket.weakDef, &bucket.tlv, &bucket.address) ) {
+       if ( this->containsOrReExports(name, bucket.weakDef, bucket.tlv, bucket.address) ) {
                bucket.atom = new ExportAtom<A>(*this, name, bucket.weakDef, bucket.tlv, bucket.address);
                _atoms[name] = bucket;
                _providedAtom = true;
                bucket.atom = new ExportAtom<A>(*this, name, bucket.weakDef, bucket.tlv, bucket.address);
                _atoms[name] = bucket;
                _providedAtom = true;
@@ -903,23 +955,23 @@ void File<A>::processIndirectLibraries(ld::dylib::File::DylibHandler* handler, b
 }
 
 template <typename A>
 }
 
 template <typename A>
-void File<A>::assertNoReExportCycles(ReExportChain* prev)
+void File<A>::assertNoReExportCycles(ReExportChain* prev) const
 {
        // recursively check my re-exported dylibs
        ReExportChain chain;
        chain.prev = prev;
        chain.file = this;
 {
        // recursively check my re-exported dylibs
        ReExportChain chain;
        chain.prev = prev;
        chain.file = this;
-       for (typename std::vector<Dependent>::iterator it = _dependentDylibs.begin(); it != _dependentDylibs.end(); it++) {
-               if ( it->reExport ) {
-                       ld::File* child = it->dylib;
+       for (const auto &dep : _dependentDylibs) {
+               if ( dep.reExport ) {
+                       ld::File* child = dep.dylib;
                        // check child is not already in chain 
                        // check child is not already in chain 
-                       for (ReExportChain* p = prev; p != NULL; p = p->prev) {
+                       for (ReExportChain* p = prev; p != nullptr; p = p->prev) {
                                if ( p->file == child ) {
                                        throwf("cycle in dylib re-exports with %s and %s", child->path(), this->path());
                                }
                        }
                                if ( p->file == child ) {
                                        throwf("cycle in dylib re-exports with %s and %s", child->path(), this->path());
                                }
                        }
-                       if ( it->dylib != NULL )
-                               it->dylib->assertNoReExportCycles(&chain);
+                       if ( dep.dylib != nullptr )
+                               dep.dylib->assertNoReExportCycles(&chain);
                }
        }
 }
                }
        }
 }
@@ -940,13 +992,15 @@ public:
                                                                                                                                                        ordinal, opts.flatNamespace(), 
                                                                                                                                                        opts.linkingMainExecutable(),
                                                                                                                                                        opts.implicitlyLinkIndirectPublicDylibs(), 
                                                                                                                                                        ordinal, opts.flatNamespace(), 
                                                                                                                                                        opts.linkingMainExecutable(),
                                                                                                                                                        opts.implicitlyLinkIndirectPublicDylibs(), 
-                                                                                                                                                       opts.macosxVersionMin(), 
-                                                                                                                                                       opts.iOSVersionMin(),
+                                                                                                                                                       opts.platform(), 
+                                                                                                                                                       opts.minOSversion(),
                                                                                                                                                        opts.allowSimulatorToLinkWithMacOSX(),
                                                                                                                                                        opts.addVersionLoadCommand(),
                                                                                                                                                        opts.allowSimulatorToLinkWithMacOSX(),
                                                                                                                                                        opts.addVersionLoadCommand(),
-                                                                                                                                                       opts.logAllFiles(), 
+                                                                                                                                                       opts.targetIOSSimulator(),
+                                                                                                                                                       opts.logAllFiles(),
                                                                                                                                                        opts.installPath(),
                                                                                                                                                        opts.installPath(),
-                                                                                                                                                       indirectDylib);
+                                                                                                                                                       indirectDylib,
+                                                                                                                                                       opts.outputKind() == Options::kPreload);
                                                                                                                }
 
 };
                                                                                                                }
 
 };
index 49d333e97d05315d482c01557830506b0ae9ce0d..c023f37c8c893cf552197cc39a6908713ab98146 100644 (file)
 #include <set>
 #include <map>
 #include <algorithm>
 #include <set>
 #include <map>
 #include <algorithm>
+#include <type_traits>
 
 #include "dwarf2.h"
 #include "debugline.h"
 
 #include "Architectures.hpp"
 
 #include "dwarf2.h"
 #include "debugline.h"
 
 #include "Architectures.hpp"
+#include "Bitcode.hpp"
 #include "ld.hpp"
 #include "macho_relocatable_file.h"
 
 #include "ld.hpp"
 #include "macho_relocatable_file.h"
 
@@ -73,7 +75,7 @@ public:
                                                                                        File(const char* p, time_t mTime, const uint8_t* content, ld::File::Ordinal ord) :
                                                                                                ld::relocatable::File(p,mTime,ord), _fileContent(content),
                                                                                                _sectionsArray(NULL), _atomsArray(NULL),
                                                                                        File(const char* p, time_t mTime, const uint8_t* content, ld::File::Ordinal ord) :
                                                                                                ld::relocatable::File(p,mTime,ord), _fileContent(content),
                                                                                                _sectionsArray(NULL), _atomsArray(NULL),
-                                                                                               _sectionsArrayCount(0), _atomsArrayCount(0),
+                                                                                               _sectionsArrayCount(0), _atomsArrayCount(0), _aliasAtomsArrayCount(0),
                                                                                                _debugInfoKind(ld::relocatable::File::kDebugInfoNone),
                                                                                                _dwarfTranslationUnitPath(NULL), 
                                                                                                _dwarfDebugInfoSect(NULL), _dwarfDebugAbbrevSect(NULL), 
                                                                                                _debugInfoKind(ld::relocatable::File::kDebugInfoNone),
                                                                                                _dwarfTranslationUnitPath(NULL), 
                                                                                                _dwarfDebugInfoSect(NULL), _dwarfDebugAbbrevSect(NULL), 
@@ -81,14 +83,19 @@ public:
                                                                                                _objConstraint(ld::File::objcConstraintNone),
                                                                                                _swiftVersion(0),
                                                                                                _cpuSubType(0),
                                                                                                _objConstraint(ld::File::objcConstraintNone),
                                                                                                _swiftVersion(0),
                                                                                                _cpuSubType(0),
-                                                                                               _canScatterAtoms(false) {}
+                                                                                               _minOSVersion(0),
+                                                                                               _platform(0),
+                                                                                               _canScatterAtoms(false),
+                                                                                               _srcKind(kSourceUnknown) {}
        virtual                                                                 ~File();
 
        // overrides of ld::File
        virtual bool                                                                            forEachAtom(ld::File::AtomHandler&) const;
        virtual bool                                                                            justInTimeforEachAtom(const char* name, ld::File::AtomHandler&) const
                                                                                                                                                                        { return false; }
        virtual                                                                 ~File();
 
        // overrides of ld::File
        virtual bool                                                                            forEachAtom(ld::File::AtomHandler&) const;
        virtual bool                                                                            justInTimeforEachAtom(const char* name, ld::File::AtomHandler&) const
                                                                                                                                                                        { return false; }
-       
+       virtual uint32_t                                                                        minOSVersion() const            { return _minOSVersion; }
+       virtual uint32_t                                                                        platformLoadCommand() const     { return _platform; }
+
        // overrides of ld::relocatable::File 
        virtual ObjcConstraint                                                          objCConstraint() const                  { return _objConstraint; }
        virtual uint32_t                                                                        cpuSubType() const                              { return _cpuSubType; }
        // overrides of ld::relocatable::File 
        virtual ObjcConstraint                                                          objCConstraint() const                  { return _objConstraint; }
        virtual uint32_t                                                                        cpuSubType() const                              { return _cpuSubType; }
@@ -98,6 +105,9 @@ public:
        virtual const char*                                                                     translationUnitSource() const;
        virtual LinkerOptionsList*                                                      linkerOptions() const                   { return &_linkerOptions; }
        virtual uint8_t                                                                         swiftVersion() const                    { return _swiftVersion; }
        virtual const char*                                                                     translationUnitSource() const;
        virtual LinkerOptionsList*                                                      linkerOptions() const                   { return &_linkerOptions; }
        virtual uint8_t                                                                         swiftVersion() const                    { return _swiftVersion; }
+       virtual ld::Bitcode*                                                            getBitcode() const                              { return _bitcode.get(); }
+       virtual SourceKind                                                                      sourceKind() const                              { return _srcKind; }
+       virtual void                                                                            setSourceKind(SourceKind src)   { _srcKind = src; }
        
        const uint8_t*                                                                          fileContent()                                   { return _fileContent; }
 private:
        
        const uint8_t*                                                                          fileContent()                                   { return _fileContent; }
 private:
@@ -128,8 +138,12 @@ private:
        ld::File::ObjcConstraint                                _objConstraint;
        uint8_t                                                                 _swiftVersion;
        uint32_t                                                                _cpuSubType;
        ld::File::ObjcConstraint                                _objConstraint;
        uint8_t                                                                 _swiftVersion;
        uint32_t                                                                _cpuSubType;
+       uint32_t                                                                _minOSVersion;
+       uint32_t                                                                _platform;
        bool                                                                    _canScatterAtoms;
        std::vector<std::vector<const char*> >  _linkerOptions;
        bool                                                                    _canScatterAtoms;
        std::vector<std::vector<const char*> >  _linkerOptions;
+       std::unique_ptr<ld::Bitcode>                    _bitcode;
+       SourceKind                                                              _srcKind;
 };
 
 
 };
 
 
@@ -148,6 +162,7 @@ public:
        virtual ld::Atom::Alignment             alignmentForAddress(pint_t addr);
        virtual ld::Atom::ContentType   contentType()                           { return ld::Atom::typeUnclassified; }
        virtual bool                                    dontDeadStrip()                         { return (this->_machOSection->flags() & S_ATTR_NO_DEAD_STRIP); }
        virtual ld::Atom::Alignment             alignmentForAddress(pint_t addr);
        virtual ld::Atom::ContentType   contentType()                           { return ld::Atom::typeUnclassified; }
        virtual bool                                    dontDeadStrip()                         { return (this->_machOSection->flags() & S_ATTR_NO_DEAD_STRIP); }
+       virtual bool                                    dontDeadStripIfReferencesLive() { return ( (this->_machOSection != NULL) && (this->_machOSection->flags() & S_ATTR_LIVE_SUPPORT) );  }
        virtual Atom<A>*                                findAtomByAddress(pint_t addr) { return this->findContentAtomByAddress(addr, this->_beginAtoms, this->_endAtoms); }
        virtual bool                                    addFollowOnFixups() const       { return ! _file.canScatterAtoms(); }
        virtual uint32_t                                appendAtoms(class Parser<A>& parser, uint8_t* buffer, 
        virtual Atom<A>*                                findAtomByAddress(pint_t addr) { return this->findContentAtomByAddress(addr, this->_beginAtoms, this->_endAtoms); }
        virtual bool                                    addFollowOnFixups() const       { return ! _file.canScatterAtoms(); }
        virtual uint32_t                                appendAtoms(class Parser<A>& parser, uint8_t* buffer, 
@@ -506,6 +521,30 @@ private:
        static ld::Fixup::Kind                  fixupKind();
 };
 
        static ld::Fixup::Kind                  fixupKind();
 };
 
+template <typename A>
+class TLVPointerSection : public FixedSizeSection<A>
+{
+public:
+                                               TLVPointerSection(Parser<A>& parser, File<A>& f, const macho_section<typename A::P>* s)
+                                                       : FixedSizeSection<A>(parser, f, s) {}
+protected:
+       typedef typename A::P::uint_t   pint_t;
+       typedef typename A::P                   P;
+
+       virtual ld::Atom::ContentType   contentType()                                                   { return ld::Atom::typeTLVPointer; }
+       virtual ld::Atom::Alignment             alignmentForAddress(pint_t addr)                { return ld::Atom::Alignment(log2(sizeof(pint_t))); }
+       virtual const char*                             unlabeledAtomName(Parser<A>&, pint_t)   { return "tlv_lazy_ptr"; }
+       virtual pint_t                                  elementSizeAtAddress(pint_t addr)               { return sizeof(pint_t); }
+       virtual ld::Atom::Combine               combine(Parser<A>&, pint_t);
+       virtual bool                                    ignoreLabel(const char* label) const    { return true; }
+       virtual unsigned long                   contentHash(const class Atom<A>* atom, const ld::IndirectBindingTable& ind) const;
+       virtual bool                                    canCoalesceWith(const class Atom<A>* atom, const ld::Atom& rhs, 
+                                                                                                       const ld::IndirectBindingTable& ind) const;
+
+private:
+       static const char*                              targetName(const class Atom<A>* atom, const ld::IndirectBindingTable& ind, bool* isStatic);
+};
+
 
 template <typename A>
 class CFStringSection : public FixedSizeSection<A>
 
 template <typename A>
 class CFStringSection : public FixedSizeSection<A>
@@ -752,7 +791,7 @@ public:
                                                                                                                                parser.combineFromSymbol(sym), parser.scopeFromSymbol(sym),
                                                                                                                                parser.resolverFromSymbol(sym) ? ld::Atom::typeResolver : sct.contentType(), 
                                                                                                                                parser.inclusionFromSymbol(sym), 
                                                                                                                                parser.combineFromSymbol(sym), parser.scopeFromSymbol(sym),
                                                                                                                                parser.resolverFromSymbol(sym) ? ld::Atom::typeResolver : sct.contentType(), 
                                                                                                                                parser.inclusionFromSymbol(sym), 
-                                                                                                                               parser.dontDeadStripFromSymbol(sym) || sct.dontDeadStrip(),
+                                                                                                                               (parser.dontDeadStripFromSymbol(sym) && !sct.dontDeadStripIfReferencesLive()) || sct.dontDeadStrip(),
                                                                                                                                parser.isThumbFromSymbol(sym), alias, 
                                                                                                                                sct.alignmentForAddress(sym.n_value())),
                                                                                                                        _size(sz), _objAddress(sym.n_value()), 
                                                                                                                                parser.isThumbFromSymbol(sym), alias, 
                                                                                                                                sct.alignmentForAddress(sym.n_value())),
                                                                                                                        _size(sz), _objAddress(sym.n_value()), 
@@ -764,7 +803,9 @@ public:
                                                                                                                                if ( _scope == ld::Atom::scopeGlobal && 
                                                                                                                                                (sym.n_desc() & (N_WEAK_DEF|N_WEAK_REF)) == (N_WEAK_DEF|N_WEAK_REF) )
                                                                                                                                        this->setAutoHide();
                                                                                                                                if ( _scope == ld::Atom::scopeGlobal && 
                                                                                                                                                (sym.n_desc() & (N_WEAK_DEF|N_WEAK_REF)) == (N_WEAK_DEF|N_WEAK_REF) )
                                                                                                                                        this->setAutoHide();
-                                                                                                                                       this->verifyAlignment(*sct.machoSection());
+                                                                                                                               this->verifyAlignment(*sct.machoSection());
+                                                                                                                               if ( sct.dontDeadStripIfReferencesLive() )
+                                                                                                                                       this->setDontDeadStripIfReferencesLive();
                                                                                                                        }
 
 private:
                                                                                                                        }
 
 private:
@@ -936,15 +977,18 @@ public:
        static bool                                                                             validFile(const uint8_t* fileContent, bool subtypeMustMatch=false, 
                                                                                                                                cpu_subtype_t subtype=0);
        static const char*                                                              fileKind(const uint8_t* fileContent);
        static bool                                                                             validFile(const uint8_t* fileContent, bool subtypeMustMatch=false, 
                                                                                                                                cpu_subtype_t subtype=0);
        static const char*                                                              fileKind(const uint8_t* fileContent);
+       static Options::Platform                                                findPlatform(const macho_header<typename A::P>* header);
        static bool                                                                             hasObjC2Categories(const uint8_t* fileContent);
        static bool                                                                             hasObjC1Categories(const uint8_t* fileContent);
        static bool                                                                             hasObjC2Categories(const uint8_t* fileContent);
        static bool                                                                             hasObjC1Categories(const uint8_t* fileContent);
+       static bool                                                                             getNonLocalSymbols(const uint8_t* fileContnet, std::vector<const char*> &syms);
        static ld::relocatable::File*                                   parse(const uint8_t* fileContent, uint64_t fileLength, 
                                                                                                                        const char* path, time_t modTime, ld::File::Ordinal ordinal,
                                                                                                                         const ParserOptions& opts) {
                                                                                                                                Parser p(fileContent, fileLength, path, modTime, 
                                                                                                                                                ordinal, opts.warnUnwindConversionProblems,
                                                                                                                                                opts.keepDwarfUnwind, opts.forceDwarfConversion,
        static ld::relocatable::File*                                   parse(const uint8_t* fileContent, uint64_t fileLength, 
                                                                                                                        const char* path, time_t modTime, ld::File::Ordinal ordinal,
                                                                                                                         const ParserOptions& opts) {
                                                                                                                                Parser p(fileContent, fileLength, path, modTime, 
                                                                                                                                                ordinal, opts.warnUnwindConversionProblems,
                                                                                                                                                opts.keepDwarfUnwind, opts.forceDwarfConversion,
-                                                                                                                                               opts.neverConvertDwarf, opts.verboseOptimizationHints);
+                                                                                                                                               opts.neverConvertDwarf, opts.verboseOptimizationHints,
+                                                                                                                                               opts.ignoreMismatchPlatform);
                                                                                                                                return p.parse(opts);
                                                                                                                }
 
                                                                                                                                return p.parse(opts);
                                                                                                                }
 
@@ -1114,7 +1158,7 @@ private:
                                                sectionTypeUTF16Strings, sectionTypeCFString, sectionTypeObjC2ClassRefs, typeObjC2CategoryList,
                                                sectionTypeObjC1Classes, sectionTypeSymboled, sectionTypeObjC1ClassRefs,
                                                sectionTypeTentativeDefinitions, sectionTypeAbsoluteSymbols, sectionTypeTLVDefs,
                                                sectionTypeUTF16Strings, sectionTypeCFString, sectionTypeObjC2ClassRefs, typeObjC2CategoryList,
                                                sectionTypeObjC1Classes, sectionTypeSymboled, sectionTypeObjC1ClassRefs,
                                                sectionTypeTentativeDefinitions, sectionTypeAbsoluteSymbols, sectionTypeTLVDefs,
-                                               sectionTypeCompactUnwind };
+                                               sectionTypeCompactUnwind, sectionTypeTLVPointers};
 
        template <typename P>
        struct MachOSectionAndSectionClass
 
        template <typename P>
        struct MachOSectionAndSectionClass
@@ -1141,10 +1185,11 @@ private:
                                                                                                        Parser(const uint8_t* fileContent, uint64_t fileLength, 
                                                                                                                        const char* path, time_t modTime, ld::File::Ordinal ordinal, 
                                                                                                                        bool warnUnwindConversionProblems, bool keepDwarfUnwind,
                                                                                                        Parser(const uint8_t* fileContent, uint64_t fileLength, 
                                                                                                                        const char* path, time_t modTime, ld::File::Ordinal ordinal, 
                                                                                                                        bool warnUnwindConversionProblems, bool keepDwarfUnwind,
-                                                                                                                       bool forceDwarfConversion, bool neverConvertDwarf, bool verboseOptimizationHints);
+                                                                                                                       bool forceDwarfConversion, bool neverConvertDwarf,
+                                                                                                                       bool verboseOptimizationHints, bool ignoreMismatchPlatform);
        ld::relocatable::File*                                                  parse(const ParserOptions& opts);
        ld::relocatable::File*                                                  parse(const ParserOptions& opts);
-       uint8_t                                                                                 loadCommandSizeMask();
-       bool                                                                                    parseLoadCommands();
+       static uint8_t                                                                  loadCommandSizeMask();
+       bool                                                                                    parseLoadCommands(Options::Platform platform, uint32_t minOSVersion, bool simulator, bool ignoreMismatchPlatform);
        void                                                                                    makeSections();
        void                                                                                    prescanSymbolTable();
        void                                                                                    makeSortedSymbolsArray(uint32_t symArray[], const uint32_t sectionArray[]);
        void                                                                                    makeSections();
        void                                                                                    prescanSymbolTable();
        void                                                                                    makeSortedSymbolsArray(uint32_t symArray[], const uint32_t sectionArray[]);
@@ -1209,6 +1254,7 @@ private:
        bool                                                                            _neverConvertDwarf;
        bool                                                                            _verboseOptimizationHints;
        bool                                                                            _armUsesZeroCostExceptions;
        bool                                                                            _neverConvertDwarf;
        bool                                                                            _verboseOptimizationHints;
        bool                                                                            _armUsesZeroCostExceptions;
+       bool                                                                            _ignoreMismatchPlatform;
        unsigned int                                                            _stubsSectionNum;
        const macho_section<P>*                                         _stubsMachOSection;
        std::vector<const char*>                                        _dtraceProviderInfo;
        unsigned int                                                            _stubsSectionNum;
        const macho_section<P>*                                         _stubsMachOSection;
        std::vector<const char*>                                        _dtraceProviderInfo;
@@ -1220,7 +1266,7 @@ private:
 template <typename A>
 Parser<A>::Parser(const uint8_t* fileContent, uint64_t fileLength, const char* path, time_t modTime, 
                                        ld::File::Ordinal ordinal, bool convertDUI, bool keepDwarfUnwind, bool forceDwarfConversion, 
 template <typename A>
 Parser<A>::Parser(const uint8_t* fileContent, uint64_t fileLength, const char* path, time_t modTime, 
                                        ld::File::Ordinal ordinal, bool convertDUI, bool keepDwarfUnwind, bool forceDwarfConversion, 
-                                       bool neverConvertDwarf, bool verboseOptimizationHints)
+                                       bool neverConvertDwarf, bool verboseOptimizationHints, bool ignoreMismatchPlatform)
                : _fileContent(fileContent), _fileLength(fileLength), _path(path), _modTime(modTime),
                        _ordinal(ordinal), _file(NULL),
                        _symbols(NULL), _symbolCount(0), _indirectSymbolCount(0), _strings(NULL), _stringsSize(0),
                : _fileContent(fileContent), _fileLength(fileLength), _path(path), _modTime(modTime),
                        _ordinal(ordinal), _file(NULL),
                        _symbols(NULL), _symbolCount(0), _indirectSymbolCount(0), _strings(NULL), _stringsSize(0),
@@ -1236,6 +1282,7 @@ Parser<A>::Parser(const uint8_t* fileContent, uint64_t fileLength, const char* p
                        _keepDwarfUnwind(keepDwarfUnwind), _forceDwarfConversion(forceDwarfConversion),
                        _neverConvertDwarf(neverConvertDwarf),
                        _verboseOptimizationHints(verboseOptimizationHints),
                        _keepDwarfUnwind(keepDwarfUnwind), _forceDwarfConversion(forceDwarfConversion),
                        _neverConvertDwarf(neverConvertDwarf),
                        _verboseOptimizationHints(verboseOptimizationHints),
+                       _ignoreMismatchPlatform(ignoreMismatchPlatform),
                        _stubsSectionNum(0), _stubsMachOSection(NULL)
 {
 }
                        _stubsSectionNum(0), _stubsMachOSection(NULL)
 {
 }
@@ -1318,7 +1365,7 @@ template <>
 const char* Parser<x86_64>::fileKind(const uint8_t* fileContent)
 {
        const macho_header<P>* header = (const macho_header<P>*)fileContent;
 const char* Parser<x86_64>::fileKind(const uint8_t* fileContent)
 {
        const macho_header<P>* header = (const macho_header<P>*)fileContent;
-       if ( header->magic() != MH_MAGIC )
+       if ( header->magic() != MH_MAGIC_64 )
                return NULL;
        if ( header->cputype() != CPU_TYPE_X86_64 )
                return NULL;
                return NULL;
        if ( header->cputype() != CPU_TYPE_X86_64 )
                return NULL;
@@ -1346,7 +1393,7 @@ template <>
 const char* Parser<arm64>::fileKind(const uint8_t* fileContent)
 {
        const macho_header<P>* header = (const macho_header<P>*)fileContent;
 const char* Parser<arm64>::fileKind(const uint8_t* fileContent)
 {
        const macho_header<P>* header = (const macho_header<P>*)fileContent;
-       if ( header->magic() != MH_MAGIC )
+       if ( header->magic() != MH_MAGIC_64 )
                return NULL;
        if ( header->cputype() != CPU_TYPE_ARM64 )
                return NULL;
                return NULL;
        if ( header->cputype() != CPU_TYPE_ARM64 )
                return NULL;
@@ -1411,6 +1458,39 @@ bool Parser<A>::hasObjC1Categories(const uint8_t* fileContent)
        return false;
 }
 
        return false;
 }
 
+
+template <typename A>
+bool Parser<A>::getNonLocalSymbols(const uint8_t* fileContent, std::vector<const char*> &syms)
+{
+       const macho_header<P>* header = (const macho_header<P>*)fileContent;
+       const uint32_t cmd_count = header->ncmds();
+       const macho_load_command<P>* const cmds = (macho_load_command<P>*)((char*)header + sizeof(macho_header<P>));
+       const macho_load_command<P>* const cmdsEnd = (macho_load_command<P>*)((char*)header + sizeof(macho_header<P>) + header->sizeofcmds());
+       const macho_load_command<P>* cmd = cmds;
+       for (uint32_t i = 0; i < cmd_count; ++i) {
+               if ( cmd->cmd() == LC_SYMTAB ) {
+                       const macho_symtab_command<P>* symtab = (macho_symtab_command<P>*)cmd;
+                       uint32_t symbolCount = symtab->nsyms();
+                       const macho_nlist<P>* symbols = (const macho_nlist<P>*)(fileContent + symtab->symoff());
+                       const char* strings = (char*)fileContent + symtab->stroff();
+                       for (uint32_t i = 0; i < symbolCount; ++i) {
+                               // ignore stabs and count only ext symbols
+                               if ( (symbols[i].n_type() & N_STAB) == 0 &&
+                                        (symbols[i].n_type() & N_EXT) != 0 ) {
+                                       const char* symName = &strings[symbols[i].n_strx()];
+                                       syms.push_back(symName);
+                               }
+                       }
+                       return true;
+               }
+               cmd = (const macho_load_command<P>*)(((char*)cmd)+cmd->cmdsize());
+               if ( cmd > cmdsEnd )
+                       throwf("malformed mach-o file, load command #%d is outside size of load commands", i);
+       }
+       return false;
+}
+
+
 template <typename A>
 int Parser<A>::pointerSorter(const void* l, const void* r)
 {
 template <typename A>
 int Parser<A>::pointerSorter(const void* l, const void* r)
 {
@@ -1634,6 +1714,9 @@ ld::relocatable::File* Parser<A>::parse(const ParserOptions& opts)
        // create file object
        _file = new File<A>(_path, _modTime, _fileContent, _ordinal);
 
        // create file object
        _file = new File<A>(_path, _modTime, _fileContent, _ordinal);
 
+       // set input source
+       _file->setSourceKind(opts.srcKind);
+
        // respond to -t option
        if ( opts.logAllFiles )
                printf("%s\n", _path);
        // respond to -t option
        if ( opts.logAllFiles )
                printf("%s\n", _path);
@@ -1641,7 +1724,7 @@ ld::relocatable::File* Parser<A>::parse(const ParserOptions& opts)
        _armUsesZeroCostExceptions = opts.armUsesZeroCostExceptions;
 
        // parse start of mach-o file
        _armUsesZeroCostExceptions = opts.armUsesZeroCostExceptions;
 
        // parse start of mach-o file
-       if ( ! parseLoadCommands() )
+       if ( ! parseLoadCommands(opts.platform, opts.minOSVersion, opts.simulator, opts.ignoreMismatchPlatform) )
                return _file;
        
        // make array of
                return _file;
        
        // make array of
@@ -1797,7 +1880,7 @@ ld::relocatable::File* Parser<A>::parse(const ParserOptions& opts)
                p += sizeof(Atom<A>);
        }
        assert(fixupOffset == _allFixups.size());
                p += sizeof(Atom<A>);
        }
        assert(fixupOffset == _allFixups.size());
-       _file->_fixups.reserve(fixupOffset);
+       _file->_fixups.resize(fixupOffset);
        
        // copy each fixup for each atom 
        for(typename std::vector<FixupInAtom>::iterator it=_allFixups.begin(); it != _allFixups.end(); ++it) {
        
        // copy each fixup for each atom 
        for(typename std::vector<FixupInAtom>::iterator it=_allFixups.begin(); it != _allFixups.end(); ++it) {
@@ -1871,6 +1954,13 @@ ld::relocatable::File* Parser<A>::parse(const ParserOptions& opts)
        return _file;
 }
 
        return _file;
 }
 
+static void versionToString(uint32_t value, char buffer[32])
+{
+       if ( value & 0xFF )
+               sprintf(buffer, "%d.%d.%d", value >> 16, (value >> 8) & 0xFF, value & 0xFF);
+       else
+               sprintf(buffer, "%d.%d", value >> 16, (value >> 8) & 0xFF);
+}
 
 template <> uint8_t Parser<x86>::loadCommandSizeMask()         { return 0x03; }
 template <> uint8_t Parser<x86_64>::loadCommandSizeMask()      { return 0x07; }
 
 template <> uint8_t Parser<x86>::loadCommandSizeMask()         { return 0x03; }
 template <> uint8_t Parser<x86_64>::loadCommandSizeMask()      { return 0x07; }
@@ -1878,7 +1968,7 @@ template <> uint8_t Parser<arm>::loadCommandSizeMask()            { return 0x03; }
 template <> uint8_t Parser<arm64>::loadCommandSizeMask()       { return 0x07; }
 
 template <typename A>
 template <> uint8_t Parser<arm64>::loadCommandSizeMask()       { return 0x07; }
 
 template <typename A>
-bool Parser<A>::parseLoadCommands()
+bool Parser<A>::parseLoadCommands(Options::Platform platform, uint32_t linkMinOSVersion, bool simulator, bool ignoreMismatchPlatform)
 {
        const macho_header<P>* header = (const macho_header<P>*)_fileContent;
 
 {
        const macho_header<P>* header = (const macho_header<P>*)_fileContent;
 
@@ -1892,6 +1982,7 @@ bool Parser<A>::parseLoadCommands()
        // <rdar://problem/5394172> an empty .o file with zero load commands will crash linker
        if ( cmd_count == 0 )
                return false;
        // <rdar://problem/5394172> an empty .o file with zero load commands will crash linker
        if ( cmd_count == 0 )
                return false;
+       Options::Platform lcPlatform = Options::kPlatformUnknown;
        const macho_load_command<P>* const cmds = (macho_load_command<P>*)((char*)header + sizeof(macho_header<P>));
        const macho_load_command<P>* const cmdsEnd = (macho_load_command<P>*)((char*)header + sizeof(macho_header<P>) + header->sizeofcmds());
        const macho_load_command<P>* cmd = cmds;
        const macho_load_command<P>* const cmds = (macho_load_command<P>*)((char*)header + sizeof(macho_header<P>));
        const macho_load_command<P>* const cmdsEnd = (macho_load_command<P>*)((char*)header + sizeof(macho_header<P>) + header->sizeofcmds());
        const macho_load_command<P>* cmd = cmds;
@@ -1970,6 +2061,18 @@ bool Parser<A>::parseLoadCommands()
                                                throw "LC_LINKER_OPTIMIZATION_HINTS table extends beyond end of file";
                                }
                                break;
                                                throw "LC_LINKER_OPTIMIZATION_HINTS table extends beyond end of file";
                                }
                                break;
+                       case LC_VERSION_MIN_MACOSX:
+                       case LC_VERSION_MIN_IPHONEOS:
+                       case LC_VERSION_MIN_WATCHOS:
+       #if SUPPORT_APPLE_TV
+                       case LC_VERSION_MIN_TVOS:
+       #endif
+                               if ( ignoreMismatchPlatform )
+                                       break;
+                               _file->_platform = cmd->cmd();
+                               lcPlatform = Options::platformForLoadCommand(cmd->cmd());
+                               _file->_minOSVersion = ((macho_version_min_command<P>*)cmd)->version();
+                               break;
                        default:
                                if ( cmd->cmd() == macho_segment_command<P>::CMD ) {
                                        if ( segment != NULL )
                        default:
                                if ( cmd->cmd() == macho_segment_command<P>::CMD ) {
                                        if ( segment != NULL )
@@ -1982,6 +2085,52 @@ bool Parser<A>::parseLoadCommands()
                if ( cmd > cmdsEnd )
                        throwf("malformed mach-o file, load command #%d is outside size of load commands", i);
        }
                if ( cmd > cmdsEnd )
                        throwf("malformed mach-o file, load command #%d is outside size of load commands", i);
        }
+       // arm/arm64 objects are default to ios platform if not set.
+       // rdar://problem/21746314
+       if (lcPlatform == Options::kPlatformUnknown &&
+               (std::is_same<A, arm>::value || std::is_same<A, arm64>::value))
+               lcPlatform = Options::kPlatformiOS;
+
+       // Check platform cross-linking.
+       if ( !ignoreMismatchPlatform ) {
+               if ( lcPlatform != platform ) {
+                       switch (platform) {
+                               case Options::kPlatformOSX:
+                               case Options::kPlatformiOS:
+                                       if ( lcPlatform == Options::kPlatformUnknown )
+                                               break;
+                                       // fall through if the Platform is not Unknown
+                               case Options::kPlatformWatchOS:
+                                       // WatchOS errors on cross-linking all the time.
+                                       throwf("building for %s%s, but linking in object file built for %s,",
+                                                  Options::platformName(platform), (simulator ? " simulator" : ""),
+                                                  Options::platformName(lcPlatform));
+                                       break;
+       #if SUPPORT_APPLE_TV
+                               case Options::kPlatform_tvOS:
+                                       // tvOS is a warning temporarily. rdar://problem/21746965
+                                       if (platform == Options::kPlatform_tvOS)
+                                               warning("URGENT: building for %s%s, but linking in object file (%s) built for %s. "
+                                                               "Note: This will be an error in the future.",
+                                                               Options::platformName(platform), (simulator ? " simulator" : ""), path(),
+                                                               Options::platformName(lcPlatform));
+                                       break;
+       #endif
+                               case Options::kPlatformUnknown:
+                                       // skip if the target platform is unknown
+                                       break;
+                       }
+               }
+               if ( linkMinOSVersion && (_file->_minOSVersion > linkMinOSVersion) ) {
+                       char t1[32];
+                       char t2[32];
+                       versionToString(_file->_minOSVersion, t1);
+                       versionToString(linkMinOSVersion, t2);
+                       warning("object file (%s) was built for newer %s version (%s) than being linked (%s)",
+                                       _path, Options::platformName(lcPlatform), t1, t2);
+               }
+       }
+
 
        // record range of sections
        if ( segment == NULL ) 
 
        // record range of sections
        if ( segment == NULL ) 
@@ -1992,6 +2141,35 @@ bool Parser<A>::parseLoadCommands()
        return true;
 }
 
        return true;
 }
 
+template <typename A>
+Options::Platform Parser<A>::findPlatform(const macho_header<P>* header)
+{
+       const uint32_t cmd_count = header->ncmds();
+       if ( cmd_count == 0 )
+               return Options::kPlatformUnknown;
+       const macho_load_command<P>* const cmds = (macho_load_command<P>*)((char*)header + sizeof(macho_header<P>));
+       const macho_load_command<P>* const cmdsEnd = (macho_load_command<P>*)((char*)header + sizeof(macho_header<P>) + header->sizeofcmds());
+       const macho_load_command<P>* cmd = cmds;
+       for (uint32_t i = 0; i < cmd_count; ++i) {
+               uint32_t size = cmd->cmdsize();
+               if ( (size & loadCommandSizeMask()) != 0 )
+                       throwf("load command #%d has a unaligned size", i);
+               const uint8_t* endOfCmd = ((uint8_t*)cmd)+cmd->cmdsize();
+               if ( endOfCmd > (uint8_t*)cmdsEnd )
+                       throwf("load command #%d extends beyond the end of the load commands", i);
+               switch (cmd->cmd()) {
+                       case LC_VERSION_MIN_MACOSX:
+                               return Options::kPlatformOSX;
+                       case LC_VERSION_MIN_IPHONEOS:
+                               return Options::kPlatformiOS;
+               }
+               cmd = (const macho_load_command<P>*)(((char*)cmd)+cmd->cmdsize());
+               if ( cmd > cmdsEnd )
+                       throwf("malformed mach-o file, load command #%d is outside size of load commands", i);
+       }
+       return Options::kPlatformUnknown;
+}
+
 
 template <typename A>
 void Parser<A>::prescanSymbolTable()
 
 template <typename A>
 void Parser<A>::prescanSymbolTable()
@@ -2258,6 +2436,13 @@ void Parser<A>::makeSections()
        // allocate raw storage for all section objects on stack
        MachOSectionAndSectionClass<P>* machOSects = (MachOSectionAndSectionClass<P>*)machOSectsStorage;
        unsigned int count = 0;
        // allocate raw storage for all section objects on stack
        MachOSectionAndSectionClass<P>* machOSects = (MachOSectionAndSectionClass<P>*)machOSectsStorage;
        unsigned int count = 0;
+       // local variable for bitcode parsing
+       const macho_section<P>* bitcodeSect = NULL;
+       const macho_section<P>* cmdlineSect = NULL;
+       const macho_section<P>* swiftCmdlineSect = NULL;
+       const macho_section<P>* bundleSect = NULL;
+       bool bitcodeAsm = false;
+
        for (uint32_t i=0; i < _machOSectionsCount; ++i) {
                const macho_section<P>* sect = &_sectionsStart[i];
                if ( (sect->flags() & S_ATTR_DEBUG) != 0 ) {
        for (uint32_t i=0; i < _machOSectionsCount; ++i) {
                const macho_section<P>* sect = &_sectionsStart[i];
                if ( (sect->flags() & S_ATTR_DEBUG) != 0 ) {
@@ -2285,6 +2470,23 @@ void Parser<A>::makeSections()
                                }
                        }
                }
                                }
                        }
                }
+               if ( strcmp(sect->segname(), "__LLVM") == 0 ) {
+                       if ( strncmp(sect->sectname(), "__bitcode", 9) == 0 ) {
+                               bitcodeSect = sect;
+                       } else if ( strncmp(sect->sectname(), "__cmdline", 9) == 0 ) {
+                               cmdlineSect = sect;
+                       } else if ( strncmp(sect->sectname(), "__swift_cmdline", 15) == 0 ) {
+                               swiftCmdlineSect = sect;
+                       } else if ( strncmp(sect->sectname(), "__bundle", 8) == 0 ) {
+                               bundleSect = sect;
+                       } else if ( strncmp(sect->sectname(), "__asm", 5) == 0 ) {
+                               bitcodeAsm = true;
+                       }
+                       // If it is not single input for ld -r, don't count the section
+                       // otherwise, fall through and add it to the sections.
+                       if (_file->sourceKind() != ld::relocatable::File::kSourceSingle)
+                               continue;
+               }
                // ignore empty __OBJC sections
                if ( (sect->size() == 0) && (strcmp(sect->segname(), "__OBJC") == 0) )
                        continue;
                // ignore empty __OBJC sections
                if ( (sect->size() == 0) && (strcmp(sect->segname(), "__OBJC") == 0) )
                        continue;
@@ -2348,6 +2550,10 @@ void Parser<A>::makeSections()
                                totalSectionsSize += sizeof(NonLazyPointerSection<A>);
                                machOSects[count++].type = sectionTypeNonLazy;
                                break;
                                totalSectionsSize += sizeof(NonLazyPointerSection<A>);
                                machOSects[count++].type = sectionTypeNonLazy;
                                break;
+                       case S_THREAD_LOCAL_VARIABLE_POINTERS:
+                               totalSectionsSize += sizeof(TLVPointerSection<A>);
+                               machOSects[count++].type = sectionTypeTLVPointers;
+                               break;
                        case S_LITERAL_POINTERS:
                                if ( (strcmp(sect->segname(), "__OBJC") == 0) && (strcmp(sect->sectname(), "__cls_refs") == 0) ) {
                                        totalSectionsSize += sizeof(Objc1ClassReferences<A>);
                        case S_LITERAL_POINTERS:
                                if ( (strcmp(sect->segname(), "__OBJC") == 0) && (strcmp(sect->sectname(), "__cls_refs") == 0) ) {
                                        totalSectionsSize += sizeof(Objc1ClassReferences<A>);
@@ -2404,11 +2610,26 @@ void Parser<A>::makeSections()
                                totalSectionsSize += sizeof(TLVDefsSection<A>);
                                machOSects[count++].type = sectionTypeTLVDefs;
                                break;
                                totalSectionsSize += sizeof(TLVDefsSection<A>);
                                machOSects[count++].type = sectionTypeTLVDefs;
                                break;
-                       case S_THREAD_LOCAL_VARIABLE_POINTERS:
                        default:
                                throwf("unknown section type %d", sect->flags() & SECTION_TYPE);
                }
        }
                        default:
                                throwf("unknown section type %d", sect->flags() & SECTION_TYPE);
                }
        }
+
+       // Create bitcode
+       if ( bitcodeSect != NULL ) {
+               if ( cmdlineSect != NULL )
+                       _file->_bitcode = std::unique_ptr<ld::Bitcode>(new ld::ClangBitcode(&_fileContent[bitcodeSect->offset()], bitcodeSect->size(),
+                                                                                                                                                               &_fileContent[cmdlineSect->offset()], cmdlineSect->size()));
+               else if ( swiftCmdlineSect != NULL )
+                       _file->_bitcode = std::unique_ptr<ld::Bitcode>(new ld::SwiftBitcode(&_fileContent[bitcodeSect->offset()], bitcodeSect->size(),
+                                                                                                                                                               &_fileContent[swiftCmdlineSect->offset()], swiftCmdlineSect->size()));
+               else
+                       throwf("Object file with bitcode missing cmdline options: %s", _file->path());
+       }
+       else if ( bundleSect != NULL )
+               _file->_bitcode = std::unique_ptr<ld::Bitcode>(new ld::BundleBitcode(&_fileContent[bundleSect->offset()], bundleSect->size()));
+       else if ( bitcodeAsm )
+               _file->_bitcode = std::unique_ptr<ld::Bitcode>(new ld::AsmBitcode(_fileContent, _fileLength));
        
        // sort by address (mach-o object files don't aways have sections sorted)
        ::qsort(machOSects, count, sizeof(MachOSectionAndSectionClass<P>), MachOSectionAndSectionClass<P>::sorter);
        
        // sort by address (mach-o object files don't aways have sections sorted)
        ::qsort(machOSects, count, sizeof(MachOSectionAndSectionClass<P>), MachOSectionAndSectionClass<P>::sorter);
@@ -2451,6 +2672,10 @@ void Parser<A>::makeSections()
                                *objects++ = new (space) NonLazyPointerSection<A>(*this, *_file, machOSects[i].sect);
                                space += sizeof(NonLazyPointerSection<A>);
                                break;
                                *objects++ = new (space) NonLazyPointerSection<A>(*this, *_file, machOSects[i].sect);
                                space += sizeof(NonLazyPointerSection<A>);
                                break;
+                       case sectionTypeTLVPointers:
+                               *objects++ = new (space) TLVPointerSection<A>(*this, *_file, machOSects[i].sect);
+                               space += sizeof(TLVPointerSection<A>);
+                               break;
                        case sectionTypeCFI:
                                _EHFrameSection = new (space) CFISection<A>(*this, *_file, machOSects[i].sect);
                                *objects++ = _EHFrameSection;
                        case sectionTypeCFI:
                                _EHFrameSection = new (space) CFISection<A>(*this, *_file, machOSects[i].sect);
                                *objects++ = _EHFrameSection;
@@ -3481,7 +3706,7 @@ void Parser<A>::parseDebugInfo()
                p += sizeof(Atom<A>);
        }
        assert(liOffset == entries.size());
                p += sizeof(Atom<A>);
        }
        assert(liOffset == entries.size());
-       _file->_lineInfos.reserve(liOffset);
+       _file->_lineInfos.resize(liOffset);
 
        // copy each line info for each atom 
        for (typename std::vector<AtomAndLineInfo<A> >::iterator it = entries.begin(); it != entries.end(); ++it) {
 
        // copy each line info for each atom 
        for (typename std::vector<AtomAndLineInfo<A> >::iterator it = entries.begin(); it != entries.end(); ++it) {
@@ -3853,8 +4078,6 @@ const char* File<A>::translationUnitSource() const
        return _dwarfTranslationUnitPath;
 }
 
        return _dwarfTranslationUnitPath;
 }
 
-
-
 template <typename A>
 bool File<A>::forEachAtom(ld::File::AtomHandler& handler) const
 {
 template <typename A>
 bool File<A>::forEachAtom(ld::File::AtomHandler& handler) const
 {
@@ -4014,6 +4237,8 @@ ld::Section::Type Section<A>::sectionType(const macho_section<typename A::P>* se
                        return ld::Section::typeTLVZeroFill;
                case S_THREAD_LOCAL_VARIABLES:
                        return ld::Section::typeTLVDefs;
                        return ld::Section::typeTLVZeroFill;
                case S_THREAD_LOCAL_VARIABLES:
                        return ld::Section::typeTLVDefs;
+               case S_THREAD_LOCAL_VARIABLE_POINTERS:
+                       return ld::Section::typeTLVPointers;
                case S_THREAD_LOCAL_INIT_FUNCTION_POINTERS:
                        return ld::Section::typeTLVInitializerPointers;
        }
                case S_THREAD_LOCAL_INIT_FUNCTION_POINTERS:
                        return ld::Section::typeTLVInitializerPointers;
        }
@@ -4728,6 +4953,7 @@ const char* CUSection<arm64>::personalityName(class Parser<arm64>& parser, const
                const pint_t* content = (pint_t*)(this->file().fileContent() + this->_machOSection->offset() + reloc->r_address());
                pint_t personalityAddr = *content;
                Section<arm64>* personalitySection = parser.sectionForAddress(personalityAddr);
                const pint_t* content = (pint_t*)(this->file().fileContent() + this->_machOSection->offset() + reloc->r_address());
                pint_t personalityAddr = *content;
                Section<arm64>* personalitySection = parser.sectionForAddress(personalityAddr);
+               (void)personalitySection;
                assert((personalitySection->type() == ld::Section::typeCode) && "personality column in __compact_unwind section is not pointer to function");
                // atoms may not be constructed yet, so scan symbol table for labels
                const char* name = parser.scanSymbolTableForAddress(personalityAddr);
                assert((personalitySection->type() == ld::Section::typeCode) && "personality column in __compact_unwind section is not pointer to function");
                // atoms may not be constructed yet, so scan symbol table for labels
                const char* name = parser.scanSymbolTableForAddress(personalityAddr);
@@ -5468,6 +5694,73 @@ ld::Atom::Scope NonLazyPointerSection<A>::scopeAtAddress(Parser<A>& parser, pint
                return ld::Atom::scopeLinkageUnit; 
 }
 
                return ld::Atom::scopeLinkageUnit; 
 }
 
+
+
+template <typename A>
+ld::Atom::Combine TLVPointerSection<A>::combine(Parser<A>& parser, pint_t addr)
+{
+       return ld::Atom::combineByNameAndReferences;
+}
+
+
+template <typename A>
+const char* TLVPointerSection<A>::targetName(const class Atom<A>* atom, const ld::IndirectBindingTable& ind, bool* isStatic)
+{
+       assert(atom->combine() == ld::Atom::combineByNameAndReferences);
+       assert(atom->fixupCount() == 1);
+       *isStatic = false;
+       ld::Fixup::iterator fit = atom->fixupsBegin();
+       const char* name = NULL;
+       switch ( fit->binding ) {
+               case ld::Fixup::bindingByNameUnbound:
+                       name = fit->u.name;
+                       break;
+               case ld::Fixup::bindingByContentBound:
+                       name = fit->u.target->name();
+                       break;
+               case ld::Fixup::bindingsIndirectlyBound:
+                       name = ind.indirectName(fit->u.bindingIndex);
+                       break;
+               case ld::Fixup::bindingDirectlyBound:
+                       name = fit->u.target->name();
+                       *isStatic = (fit->u.target->scope() == ld::Atom::scopeTranslationUnit);
+                       break;
+               default:
+                       assert(0);
+       }
+       assert(name != NULL);
+       return name;
+}
+
+template <typename A>
+unsigned long TLVPointerSection<A>::contentHash(const class Atom<A>* atom, const ld::IndirectBindingTable& ind) const
+{
+       assert(atom->combine() == ld::Atom::combineByNameAndReferences);
+       unsigned long hash = 9508;
+       bool isStatic;
+       for (const char* s = this->targetName(atom, ind, &isStatic); *s != '\0'; ++s) {
+               hash = hash * 33 + *s;
+       }
+       return hash;
+}
+
+template <typename A>
+bool TLVPointerSection<A>::canCoalesceWith(const class Atom<A>* atom, const ld::Atom& rhs,
+                                                                                                       const ld::IndirectBindingTable& indirectBindingTable) const
+{
+       if ( rhs.section().type() != ld::Section::typeTLVPointers )
+               return false;
+       assert(this->type() == rhs.section().type());
+       const Atom<A>* rhsAtom = dynamic_cast<const Atom<A>*>(&rhs);
+       assert(rhsAtom !=  NULL);
+       bool thisIsStatic;
+       bool rhsIsStatic;
+       const char* thisName = this->targetName(atom, indirectBindingTable, &thisIsStatic);
+       const char* rhsName = this->targetName(rhsAtom, indirectBindingTable, &rhsIsStatic);
+       return !thisIsStatic && !rhsIsStatic && (strcmp(thisName, rhsName) == 0);
+}
+
+
 template <typename A>
 const uint8_t* CFStringSection<A>::targetContent(const class Atom<A>* atom, const ld::IndirectBindingTable& ind,
                                                                                                        ContentType* ct, unsigned int* count)
 template <typename A>
 const uint8_t* CFStringSection<A>::targetContent(const class Atom<A>* atom, const ld::IndirectBindingTable& ind,
                                                                                                        ContentType* ct, unsigned int* count)
@@ -6826,7 +7119,8 @@ bool Section<arm64>::addRelocFixup(class Parser<arm64>& parser, const macho_relo
                case ARM64_RELOC_UNSIGNED:
                        if ( reloc->r_pcrel() )
                                throw "pcrel and ARM64_RELOC_UNSIGNED not supported";
                case ARM64_RELOC_UNSIGNED:
                        if ( reloc->r_pcrel() )
                                throw "pcrel and ARM64_RELOC_UNSIGNED not supported";
-                       target.addend = contentValue;
+                       if ( reloc->r_extern() )
+                               target.addend = contentValue;
                        switch ( reloc->r_length() ) {
                                case 0:
                                case 1:
                        switch ( reloc->r_length() ) {
                                case 0:
                                case 1:
@@ -7451,28 +7745,34 @@ bool isObjectFile(const uint8_t* fileContent, uint64_t fileLength, const ParserO
 //
 // used by linker to infer architecture when no -arch is on command line
 //
 //
 // used by linker to infer architecture when no -arch is on command line
 //
-bool isObjectFile(const uint8_t* fileContent, cpu_type_t* result, cpu_subtype_t* subResult)
+bool isObjectFile(const uint8_t* fileContent, cpu_type_t* result, cpu_subtype_t* subResult, Options::Platform* platform)
 {
        if ( mach_o::relocatable::Parser<x86_64>::validFile(fileContent) ) {
                *result = CPU_TYPE_X86_64;
                const macho_header<Pointer64<LittleEndian> >* header = (const macho_header<Pointer64<LittleEndian> >*)fileContent;
                *subResult = header->cpusubtype();
 {
        if ( mach_o::relocatable::Parser<x86_64>::validFile(fileContent) ) {
                *result = CPU_TYPE_X86_64;
                const macho_header<Pointer64<LittleEndian> >* header = (const macho_header<Pointer64<LittleEndian> >*)fileContent;
                *subResult = header->cpusubtype();
+               *platform = Parser<x86_64>::findPlatform(header);
                return true;
        }
        if ( mach_o::relocatable::Parser<x86>::validFile(fileContent) ) {
                return true;
        }
        if ( mach_o::relocatable::Parser<x86>::validFile(fileContent) ) {
+               const macho_header<Pointer32<LittleEndian> >* header = (const macho_header<Pointer32<LittleEndian> >*)fileContent;
                *result = CPU_TYPE_I386;
                *subResult = CPU_SUBTYPE_X86_ALL;
                *result = CPU_TYPE_I386;
                *subResult = CPU_SUBTYPE_X86_ALL;
+               *platform = Parser<x86>::findPlatform(header);
                return true;
        }
        if ( mach_o::relocatable::Parser<arm>::validFile(fileContent, false, 0) ) {
                return true;
        }
        if ( mach_o::relocatable::Parser<arm>::validFile(fileContent, false, 0) ) {
-               *result = CPU_TYPE_ARM;
                const macho_header<Pointer32<LittleEndian> >* header = (const macho_header<Pointer32<LittleEndian> >*)fileContent;
                const macho_header<Pointer32<LittleEndian> >* header = (const macho_header<Pointer32<LittleEndian> >*)fileContent;
+               *result = CPU_TYPE_ARM;
                *subResult = header->cpusubtype();
                *subResult = header->cpusubtype();
+               *platform = Parser<arm>::findPlatform(header);
                return true;
        }
        if ( mach_o::relocatable::Parser<arm64>::validFile(fileContent, false, 0) ) {
                return true;
        }
        if ( mach_o::relocatable::Parser<arm64>::validFile(fileContent, false, 0) ) {
+               const macho_header<Pointer64<LittleEndian> >* header = (const macho_header<Pointer64<LittleEndian> >*)fileContent;
                *result = CPU_TYPE_ARM64;
                *subResult = CPU_SUBTYPE_ARM64_ALL;
                *result = CPU_TYPE_ARM64;
                *subResult = CPU_SUBTYPE_ARM64_ALL;
+               *platform = Parser<arm64>::findPlatform(header);
                return true;
        }
        return false;
                return true;
        }
        return false;
@@ -7528,6 +7828,26 @@ bool hasObjC1Categories(const uint8_t* fileContent)
        return false;
 }
 
        return false;
 }
 
+//
+// Used by bitcode obfuscator to get a list of non local symbols from object file
+//
+bool getNonLocalSymbols(const uint8_t* fileContent, std::vector<const char*> &syms)
+{
+       if ( mach_o::relocatable::Parser<x86_64>::validFile(fileContent) ) {
+               return mach_o::relocatable::Parser<x86_64>::getNonLocalSymbols(fileContent, syms);
+       }
+       else if ( mach_o::relocatable::Parser<arm>::validFile(fileContent, false, 0) ) {
+               return mach_o::relocatable::Parser<arm>::getNonLocalSymbols(fileContent, syms);
+       }
+       else if ( mach_o::relocatable::Parser<x86>::validFile(fileContent, false, 0) ) {
+               return mach_o::relocatable::Parser<x86>::getNonLocalSymbols(fileContent, syms);
+       }
+       else if ( mach_o::relocatable::Parser<arm64>::validFile(fileContent, false, 0) ) {
+               return mach_o::relocatable::Parser<arm64>::getNonLocalSymbols(fileContent, syms);
+       }
+       return false;
+}
+
 
 
 } // namespace relocatable
 
 
 } // namespace relocatable
index 92e904269b5033dfbbc1897a3497de9bf8a1e77d..40f02d65d25c35ca8f93d516152fd0ef7aa3397c 100644 (file)
@@ -41,7 +41,12 @@ struct ParserOptions {
        bool                    neverConvertDwarf;
        bool                    verboseOptimizationHints;
        bool                    armUsesZeroCostExceptions;
        bool                    neverConvertDwarf;
        bool                    verboseOptimizationHints;
        bool                    armUsesZeroCostExceptions;
+       bool                    simulator;
+       bool                    ignoreMismatchPlatform;
        uint32_t                subType;
        uint32_t                subType;
+       Options::Platform platform;
+       uint32_t                minOSVersion;
+       ld::relocatable::File::SourceKind       srcKind;
 };
 
 extern ld::relocatable::File* parse(const uint8_t* fileContent, uint64_t fileLength, 
 };
 
 extern ld::relocatable::File* parse(const uint8_t* fileContent, uint64_t fileLength, 
@@ -50,13 +55,15 @@ extern ld::relocatable::File* parse(const uint8_t* fileContent, uint64_t fileLen
                                                                        
 extern bool isObjectFile(const uint8_t* fileContent, uint64_t fileLength, const ParserOptions& opts);
 
                                                                        
 extern bool isObjectFile(const uint8_t* fileContent, uint64_t fileLength, const ParserOptions& opts);
 
-extern bool isObjectFile(const uint8_t* fileContent, cpu_type_t* result, cpu_subtype_t* subResult);                                    
+extern bool isObjectFile(const uint8_t* fileContent, cpu_type_t* result, cpu_subtype_t* subResult, Options::Platform* platform);
 
 extern bool hasObjC2Categories(const uint8_t* fileContent);                                    
 
 extern bool hasObjC1Categories(const uint8_t* fileContent);
 
 
 extern bool hasObjC2Categories(const uint8_t* fileContent);                                    
 
 extern bool hasObjC1Categories(const uint8_t* fileContent);
 
-extern const char* archName(const uint8_t* fileContent);                                       
+extern const char* archName(const uint8_t* fileContent);
+
+bool getNonLocalSymbols(const uint8_t* fileContent, std::vector<const char*> &syms);
 
 } // namespace relocatable
 } // namespace mach_o
 
 } // namespace relocatable
 } // namespace mach_o
index e60332b84c252c3552b030afc9b500f2fe31fd3b..081e957a3b8f1e8cf9437d689e3e7fcbd71b8bc5 100644 (file)
@@ -24,6 +24,7 @@
 
 
 #include <vector>
 
 
 #include <vector>
+#include <map>
 
 #include "ld.hpp"
 #include "opaque_section_file.h"
 
 #include "ld.hpp"
 #include "opaque_section_file.h"
@@ -63,7 +64,7 @@ public:
                                                                        const char* symbolName="sect_create")
                                                                        : ld::File(pth, 0, ld::File::Ordinal::NullOrdinal(), Other),
                                                                          _atom(*this, symbolName, fileContent, fileLength), 
                                                                        const char* symbolName="sect_create")
                                                                        : ld::File(pth, 0, ld::File::Ordinal::NullOrdinal(), Other),
                                                                          _atom(*this, symbolName, fileContent, fileLength), 
-                                                                         _section(segmentName, sectionName, ld::Section::typeUnclassified) { }
+                                                                         _section(segmentName, sectionName, ld::Section::typeSectCreate) { }
        virtual                                         ~File() { }
        
        virtual bool                            forEachAtom(ld::File::AtomHandler& h) const { h.doAtom(_atom); return true; }
        virtual                                         ~File() { }
        
        virtual bool                            forEachAtom(ld::File::AtomHandler& h) const { h.doAtom(_atom); return true; }
diff --git a/src/ld/parsers/textstub_dylib_file.cpp b/src/ld/parsers/textstub_dylib_file.cpp
new file mode 100644 (file)
index 0000000..cde3344
--- /dev/null
@@ -0,0 +1,1072 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2015 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+#include <sys/param.h>
+#include <sys/mman.h>
+
+#include <vector>
+
+#include "Architectures.hpp"
+#include "bitcode.hpp"
+#include "MachOFileAbstraction.hpp"
+#include "MachOTrie.hpp"
+#include "textstub_dylib_file.hpp"
+
+namespace {
+
+///
+/// A token is a light-weight reference to the content of an nmap'ed file. It
+/// doesn't own the data and it doesn't make a copy of it. The referenced data
+/// is only valid as long as the file is mapped in.
+///
+class Token {
+       const char* _p;
+       size_t _size;
+
+       int compareMemory(const char* lhs, const char* rhs, size_t size) const {
+               if (size == 0)
+                       return 0;
+               return ::memcmp(lhs, rhs, size);
+       }
+
+public:
+       Token() : _p(nullptr), _size(0) {}
+
+       Token(const char* p) : _p(p), _size(0) {
+               if (p)
+                       _size = ::strlen(p);
+       }
+
+       Token(const char* p, size_t s) : _p(p), _size(s) {}
+
+       const char* data() const { return _p; }
+
+       size_t size() const { return _size; }
+
+       std::string str() const { return std::move(std::string(_p, _size)); }
+
+       bool empty() const { return _size == 0; }
+
+       bool operator==(Token other) const {
+               if (_size != other._size)
+                       return false;
+               return compareMemory(_p, other._p, _size) == 0;
+       }
+
+       bool operator!=(Token other) const {
+               return !(*this == other);
+       }
+};
+
+///
+/// Simple text-based dynamic library file tokenizer.
+///
+class Tokenizer {
+       const char* _start;
+       const char* _current;
+       const char* _end;
+       Token _currentToken;
+
+       void fetchNextToken();
+       void scanToNextToken();
+       void skip(unsigned distance) {
+               _current += distance;
+               assert(_current <= _end && "Skipped past the end");
+       }
+
+       const char* skipLineBreak(const char* pos) const;
+       bool isDelimiter(const char* pos) const;
+
+public:
+       Tokenizer(const char* data, uint64_t size) : _start(data), _current(data), _end(data + size) {}
+
+       void reset() {
+               _current = _start;
+               fetchNextToken();
+       }
+
+       Token peek() { return _currentToken; }
+       Token next() {
+               Token token = peek();
+               fetchNextToken();
+               return token;
+       }
+};
+
+const char* Tokenizer::skipLineBreak(const char* pos) const
+{
+       if ( pos == _end )
+               return pos;
+
+       // Carriage return.
+       if ( *pos == 0x0D ) {
+               // line feed.
+               if ( pos + 1 != _end && *(pos + 1) == 0x0A)
+                       return pos + 2;
+               return pos + 1;
+       }
+
+       // line feed.
+       if ( *pos == 0x0A )
+               return pos + 1;
+
+       return pos;
+}
+
+void Tokenizer::scanToNextToken() {
+       while (true) {
+               while ( isDelimiter(_current) )
+                       skip(1);
+
+               const char* i = skipLineBreak(_current);
+               if ( i == _current )
+                       break;
+
+               _current = i;
+       }
+}
+
+
+bool Tokenizer::isDelimiter(const char* pos) const {
+       if ( pos == _end )
+               return false;
+       if ( *pos == ' ' || *pos == '\t' || *pos == '\r' || *pos == '\n' || *pos == ',' || *pos == ':' || *pos == '\'' || *pos == '\"' )
+               return true;
+       return false;
+}
+
+void Tokenizer::fetchNextToken() {
+       scanToNextToken();
+
+       if (_current == _end) {
+               _currentToken = Token();
+               return;
+       }
+
+       auto start = _current;
+       while ( !isDelimiter(_current) ) {
+               ++_current;
+       }
+
+       _currentToken = Token(start, _current - start);
+}
+
+///
+/// Representation of a parsed text-based dynamic library file.
+///
+struct DynamicLibrary {
+       Token _installName;
+       uint32_t _currentVersion;
+       uint32_t _compatibilityVersion;
+       uint8_t _swiftVersion;
+       ld::File::ObjcConstraint _objcConstraint;
+       Options::Platform _platform;
+       std::vector<Token> _allowedClients;
+       std::vector<Token> _reexportedLibraries;
+       std::vector<Token> _symbols;
+       std::vector<Token> _classes;
+       std::vector<Token> _ivars;
+       std::vector<Token> _weakDefSymbols;
+       std::vector<Token> _tlvSymbols;
+
+       DynamicLibrary() : _currentVersion(0x10000), _compatibilityVersion(0x10000), _swiftVersion(0),
+               _objcConstraint(ld::File::objcConstraintNone)  {}
+};
+
+static uint32_t parseVersionNumber32(Token token) {
+       if ( token.size() >= 128 )
+               throwf("malformed version number");
+
+       char buffer[128];
+       uint32_t x = 0;
+       uint32_t y = 0;
+       uint32_t z = 0;
+       char* end;
+
+       // Make a null-terminated string.
+       ::memcpy(buffer, token.data(), token.size());
+       buffer[token.size()] = '\0';
+
+       x = strtoul(buffer, &end, 10);
+       if ( *end == '.' ) {
+               y = strtoul(&end[1], &end, 10);
+               if ( *end == '.' ) {
+                       z = strtoul(&end[1], &end, 10);
+               }
+       }
+       if ( (x > 0xffff) || (y > 0xff) || (z > 0xff) )
+               throwf("malformed 32-bit x.y.z version number: %s", buffer);
+
+       return (x << 16) | ( y << 8 ) | z;
+}
+
+///
+/// A simple text-based dynamic library file parser.
+///
+class TBDFile {
+       Tokenizer _tokenizer;
+
+       Token peek() { return _tokenizer.peek(); }
+       Token next() { return _tokenizer.next(); }
+
+       void expectToken(Token str) {
+               Token token = next();
+               if (token != str)
+                       throwf("unexpected token: %s", token.str().c_str());
+       }
+
+       bool hasOptionalToken(Token str) {
+               auto token = peek();
+               if ( token == str ) {
+                       next();
+                       return true;
+               }
+               return false;
+       }
+
+
+       void parseFlowSequence(std::function<void (Token)> func) {
+               expectToken("[");
+
+               while ( true ) {
+                       auto token = peek();
+                       if ( token == "]" )
+                               break;
+
+                       token = next();
+                       func(token);
+               }
+
+               expectToken("]");
+       }
+
+       void parseAllowedClients(DynamicLibrary& lib) {
+               if ( !hasOptionalToken("allowed-clients") )
+                       return;
+               parseFlowSequence([&](Token name) {
+                       lib._allowedClients.emplace_back(name);
+               });
+       }
+
+       void parseReexportedDylibs(DynamicLibrary& lib) {
+               if ( !hasOptionalToken("re-exports") )
+                       return;
+               parseFlowSequence([&](Token name) {
+                       lib._reexportedLibraries.emplace_back(name);
+               });
+       }
+
+       void parseSymbols(DynamicLibrary& lib) {
+               if ( hasOptionalToken("symbols") ) {
+                       parseFlowSequence([&](Token name) {
+                               lib._symbols.emplace_back(name);
+                       });
+               }
+
+               if ( hasOptionalToken("objc-classes") ) {
+                       parseFlowSequence([&](Token name) {
+                               lib._classes.emplace_back(name);
+                       });
+               }
+
+               if ( hasOptionalToken("objc-ivars") ) {
+                       parseFlowSequence([&](Token name) {
+                               lib._ivars.emplace_back(name);
+                       });
+               }
+
+               if ( hasOptionalToken("weak-def-symbols") ) {
+                       parseFlowSequence([&](Token name) {
+                               lib._weakDefSymbols.emplace_back(name);
+                       });
+               }
+
+               if ( hasOptionalToken("thread-local-symbols") ) {
+                       parseFlowSequence([&](Token name) {
+                               lib._tlvSymbols.emplace_back(name);
+                       });
+               }
+       }
+
+       bool parseArchFlowSequence(Token archName) {
+               expectToken("archs");
+
+               bool foundArch = false;
+               parseFlowSequence([&](Token name) {
+                       if ( name == archName )
+                               foundArch = true;
+                       });
+
+               return foundArch;
+       }
+
+       void parsePlatform(DynamicLibrary& lib) {
+               expectToken("platform");
+
+               auto token =  next();
+               if (token == "macosx")
+                       lib._platform = Options::kPlatformOSX;
+               else if (token == "ios")
+                       lib._platform = Options::kPlatformiOS;
+               else if (token == "watchos")
+                       lib._platform = Options::kPlatformWatchOS;
+#if SUPPORT_APPLE_TV
+               else if (token == "tvos")
+                       lib._platform = Options::kPlatform_tvOS;
+#endif
+               else
+                       lib._platform = Options::kPlatformUnknown;
+       }
+
+       void parseInstallName(DynamicLibrary& lib) {
+               expectToken("install-name");
+
+               lib._installName = next();
+               if ( lib._installName.empty() )
+                       throwf("no install name specified");
+       }
+
+       void parseCurrentVersion(DynamicLibrary& lib) {
+               if ( !hasOptionalToken("current-version") )
+                       return;
+               lib._currentVersion = parseVersionNumber32(next());
+       }
+
+       void parseCompatibilityVersion(DynamicLibrary& lib) {
+               if ( !hasOptionalToken("compatibility-version") )
+                       return;
+               lib._compatibilityVersion = parseVersionNumber32(next());
+       }
+
+       void parseSwiftVersion(DynamicLibrary& lib) {
+               if ( !hasOptionalToken("swift-version") )
+                       return;
+               auto token = next();
+               if ( token == "1.0" )
+                       lib._swiftVersion = 1;
+               else if ( token == "1.1" )
+                       lib._swiftVersion = 2;
+               else if ( token == "2.0" )
+                       lib._swiftVersion = 3;
+               else
+                       throwf("unsupported Swift ABI version: %s", token.str().c_str());
+       }
+
+       void parseObjCConstraint(DynamicLibrary& lib) {
+               if ( !hasOptionalToken("objc-constraint") )
+                       return;
+               auto token = next();
+               if ( token == "none" )
+                       lib._objcConstraint = ld::File::objcConstraintNone;
+               else if ( token == "retain_release" )
+                       lib._objcConstraint = ld::File::objcConstraintRetainRelease;
+               else if ( token == "retain_release_for_simulator" )
+                       lib._objcConstraint = ld::File::objcConstraintRetainReleaseForSimulator;
+               else if ( token == "retain_release_or_gc" )
+                       lib._objcConstraint = ld::File::objcConstraintRetainReleaseOrGC;
+               else if ( token == "gc" )
+                       lib._objcConstraint = ld::File::objcConstraintGC;
+               else
+                       throwf("unexpected token: %s", token.str().c_str());
+       }
+       void parseExportsBlock(DynamicLibrary& lib, Token archName) {
+               if ( !hasOptionalToken("exports") )
+                       return;
+
+               if ( !hasOptionalToken("-") )
+                       return;
+
+               while ( true ) {
+                       if ( !parseArchFlowSequence(archName) ) {
+                               Token token;
+                               while ( true ) {
+                                       token = peek();
+                                       if ( token == "archs" || token == "..." || token.empty() )
+                                               break;
+                                       next();
+                               }
+                               if (token == "..." || token.empty() )
+                                       break;
+
+                               continue;
+                       }
+
+                       parseAllowedClients(lib);
+                       parseReexportedDylibs(lib);
+                       parseSymbols(lib);
+                       if ( !hasOptionalToken("-") )
+                               break;
+               }
+       }
+
+       void parseDocument(DynamicLibrary& lib, Token archName) {
+               if ( !parseArchFlowSequence(archName) )
+                       throwf("invalid arch");
+
+               parsePlatform(lib);
+               parseInstallName(lib);
+               parseCurrentVersion(lib);
+               parseCompatibilityVersion(lib);
+               parseSwiftVersion(lib);
+               parseObjCConstraint(lib);
+               parseExportsBlock(lib, archName);
+       }
+
+public:
+       TBDFile(const char* data, uint64_t size) : _tokenizer(data, size) {}
+
+       DynamicLibrary parseFileForArch(Token archName) {
+               _tokenizer.reset();
+               DynamicLibrary lib;
+               expectToken("---");
+               parseDocument(lib, archName);
+               expectToken("...");
+               return std::move(lib);
+       }
+
+       bool validForArch(Token archName) {
+               _tokenizer.reset();
+               auto token = next();
+               if ( token != "---" )
+                       return false;
+               return parseArchFlowSequence(archName);
+       }
+
+       void dumpTokens() {
+               _tokenizer.reset();
+               Token token;
+               do {
+                       token = next();
+                       printf("token: %s\n", token.str().c_str());
+               } while ( !token.empty() );
+       }
+};
+
+} // end anonymous namespace
+
+namespace textstub {
+namespace dylib {
+
+// forward reference
+template <typename A> class File;
+
+
+//
+// An ExportAtom has no content.  It exists so that the linker can track which imported
+// symbols came from which dynamic libraries.
+//
+template <typename A>
+class ExportAtom : public ld::Atom
+{
+public:
+       ExportAtom(const File<A>& f, const char* nm, bool weakDef, bool tlv)
+               : ld::Atom(f._importProxySection, ld::Atom::definitionProxy,
+                                  (weakDef? ld::Atom::combineByName : ld::Atom::combineNever),
+                                  ld::Atom::scopeLinkageUnit,
+                                  (tlv ? ld::Atom::typeTLV : ld::Atom::typeUnclassified),
+                                  symbolTableNotIn, false, false, false, ld::Atom::Alignment(0)),
+                                  _file(f), _name(nm) {}
+       // overrides of ld::Atom
+       virtual const ld::File*                 file() const            { return &_file; }
+       virtual const char*                             name() const            { return _name; }
+       virtual uint64_t                                size() const            { return 0; }
+       virtual uint64_t                                objectAddress() const { return 0; }
+       virtual void                                    copyRawContent(uint8_t buffer[]) const { }
+       virtual void                                    setScope(Scope)         { }
+
+protected:
+       typedef typename A::P                   P;
+       typedef typename A::P::uint_t   pint_t;
+
+       virtual                                                 ~ExportAtom() {}
+
+       const File<A>&                                  _file;
+       const char*                                             _name;
+};
+
+
+//
+// The reader for a dylib extracts all exported symbols names from the memory-mapped
+// dylib, builds a hash table, then unmaps the file.  This is an important memory
+// savings for large dylibs.
+//
+template <typename A>
+class File : public ld::dylib::File
+{
+public:
+       static bool             validFile(const uint8_t* fileContent, bool executableOrDylib);
+                                       File(const uint8_t* fileContent, uint64_t fileLength, const char* path,
+                                                time_t mTime, ld::File::Ordinal ordinal, bool linkingFlatNamespace,
+                                                bool hoistImplicitPublicDylibs, Options::Platform platform,
+                                                cpu_type_t cpuType, const char* archName, uint32_t linkMinOSVersion,
+                                                bool allowSimToMacOSX, bool addVers, bool buildingForSimulator,
+                                                bool logAllFiles, const char* installPath, bool indirectDylib);
+       virtual                 ~File() {}
+
+       // overrides of ld::File
+       virtual bool                                                    forEachAtom(ld::File::AtomHandler&) const;
+       virtual bool                                                    justInTimeforEachAtom(const char* name, ld::File::AtomHandler&) const;
+       virtual ld::File::ObjcConstraint                objCConstraint() const          { return _objcConstraint; }
+       virtual uint8_t                                                 swiftVersion() const            { return _swiftVersion; }
+
+       // overrides of ld::dylib::File
+       virtual void                                                    processIndirectLibraries(ld::dylib::File::DylibHandler*, bool);
+       virtual bool                                                    providedExportAtom() const      { return _providedAtom; }
+       virtual const char*                                             parentUmbrella() const { return nullptr; }
+       virtual const std::vector<const char*>* allowableClients() const        { return _allowableClients.size() != 0 ? &_allowableClients : nullptr; }
+       virtual bool                                                    hasWeakExternals() const        { return _hasWeakExports; }
+       virtual bool                                                    deadStrippable() const          { return false; }
+       virtual bool                                                    hasPublicInstallName() const{ return _hasPublicInstallName; }
+       virtual bool                                                    hasWeakDefinition(const char* name) const;
+       virtual bool                                                    allSymbolsAreWeakImported() const;
+       virtual bool                                                    installPathVersionSpecific() const { return _installPathOverride; }
+       // All text-based stubs are per definition AppExtensionSafe.
+       virtual bool                                                    appExtensionSafe() const        { return true; };
+       virtual ld::Bitcode*                                    getBitcode() const                      { return _bitcode.get(); }
+
+
+protected:
+       virtual void                                                    assertNoReExportCycles(ReExportChain*) const;
+
+private:
+       typedef typename A::P                                   P;
+       typedef typename A::P::E                                E;
+       typedef typename A::P::uint_t                   pint_t;
+
+       friend class ExportAtom<A>;
+
+       struct CStringHash {
+               std::size_t operator()(const char* __s) const {
+                       unsigned long __h = 0;
+                       for ( ; *__s; ++__s)
+                               __h = 5 * __h + *__s;
+                       return size_t(__h);
+               };
+       };
+       struct AtomAndWeak { ld::Atom* atom; bool weakDef; bool tlv; };
+       typedef std::unordered_map<const char*, AtomAndWeak, ld::CStringHash, ld::CStringEquals> NameToAtomMap;
+       typedef std::unordered_set<const char*, CStringHash, ld::CStringEquals>  NameSet;
+
+       struct Dependent { const char* path; File<A>* dylib; };
+
+       virtual std::pair<bool, bool>                   hasWeakDefinitionImpl(const char* name) const;
+       virtual bool                                                    containsOrReExports(const char* name, bool& weakDef, bool& tlv, uint64_t& address) const;
+
+       void                                                                    buildExportHashTable(const DynamicLibrary &lib);
+       bool                                                                    isPublicLocation(const char* pth);
+       bool                                                                    wrongOS() { return _wrongOS; }
+       void                                                                    addSymbol(const char* name, bool weak, bool tlv);
+
+       const Options::Platform                                 _platform;
+       cpu_type_t                                                              _cpuType;
+       const uint32_t                                                  _linkMinOSVersion;
+       const bool                                                              _allowSimToMacOSXLinking;
+       const bool                                                              _addVersionLoadCommand;
+       bool                                                                    _linkingFlat;
+       bool                                                                    _implicitlyLinkPublicDylibs;
+       ld::File::ObjcConstraint                                _objcConstraint;
+       uint8_t                                                                 _swiftVersion;
+       ld::Section                                                             _importProxySection;
+       ld::Section                                                             _flatDummySection;
+       std::vector<Dependent>                                  _dependentDylibs;
+       std::vector<const char*>                                _allowableClients;
+       mutable NameToAtomMap                                   _atoms;
+       NameSet                                                                 _ignoreExports;
+       bool                                                                    _noRexports;
+       bool                                                                    _hasWeakExports;
+       bool                                                                    _hasPublicInstallName;
+       mutable bool                                                    _providedAtom;
+       bool                                                                    _wrongOS;
+       bool                                                                    _installPathOverride;
+       bool                                                                    _indirectDylibsProcessed;
+       std::unique_ptr<ld::Bitcode>                    _bitcode;
+       static bool                                                             _s_logHashtable;
+};
+
+template <typename A>
+bool File<A>::_s_logHashtable = false;
+
+
+template <typename A>
+File<A>::File(const uint8_t* fileContent, uint64_t fileLength, const char* path, time_t mTime,
+                         ld::File::Ordinal ord, bool linkingFlatNamespace, bool hoistImplicitPublicDylibs,
+                         Options::Platform platform, cpu_type_t cpuType, const char* archName,
+                         uint32_t linkMinOSVersion, bool allowSimToMacOSX, bool addVers,
+                         bool buildingForSimulator, bool logAllFiles, const char* targetInstallPath,
+                         bool indirectDylib)
+       : ld::dylib::File(strdup(path), mTime, ord), _platform(platform), _cpuType(cpuType),
+         _linkMinOSVersion(linkMinOSVersion), _allowSimToMacOSXLinking(allowSimToMacOSX),
+         _addVersionLoadCommand(addVers), _linkingFlat(linkingFlatNamespace),
+         _implicitlyLinkPublicDylibs(hoistImplicitPublicDylibs),
+         _objcConstraint(ld::File::objcConstraintNone), _swiftVersion(0),
+         _importProxySection("__TEXT", "__import", ld::Section::typeImportProxies, true),
+         _flatDummySection("__LINKEDIT", "__flat_dummy", ld::Section::typeLinkEdit, true),
+         _noRexports(false), _hasWeakExports(false),
+         _hasPublicInstallName(false), _providedAtom(false), _wrongOS(false),
+         _installPathOverride(false), _indirectDylibsProcessed(false),
+         _bitcode(new ld::Bitcode(nullptr, 0))
+{
+       // write out path for -t option
+       if ( logAllFiles )
+               printf("%s\n", path);
+
+       TBDFile stub((const char*)fileContent, fileLength);
+       auto lib = stub.parseFileForArch(archName);
+
+       _noRexports = lib._reexportedLibraries.empty();
+       _hasWeakExports = !lib._weakDefSymbols.empty();
+       _dylibInstallPath = strdup(lib._installName.str().c_str());
+       _dylibCurrentVersion = lib._currentVersion;
+       _dylibCompatibilityVersion = lib._compatibilityVersion;
+       _swiftVersion = lib._swiftVersion;
+       _objcConstraint = lib._objcConstraint;
+       _hasPublicInstallName = isPublicLocation(_dylibInstallPath);
+
+       for (auto &client : lib._allowedClients)
+               _allowableClients.push_back(strdup(client.str().c_str()));
+
+       // <rdar://problem/20659505> [TAPI] Don't hoist "public" (in /usr/lib/) dylibs that should not be directly linked
+       if ( !_allowableClients.empty() )
+               _hasPublicInstallName = false;
+
+       if ( (lib._platform != platform) && (platform != Options::kPlatformUnknown) ) {
+               _wrongOS = true;
+               if ( _addVersionLoadCommand && !indirectDylib ) {
+                       if ( buildingForSimulator ) {
+                               if ( !_allowSimToMacOSXLinking )
+                                       throwf("building for %s simulator, but linking against dylib built for %s (%s).",
+                                                       Options::platformName(platform), Options::platformName(lib._platform), path);
+                       } else {
+                               throwf("building for %s, but linking against dylib built for %s (%s).",
+                                               Options::platformName(platform), Options::platformName(lib._platform), path);
+                       }
+               }
+       }
+
+       _dependentDylibs.reserve(lib._reexportedLibraries.size());
+       for ( auto& reexport : lib._reexportedLibraries ) {
+               Dependent entry;
+               entry.path = strdup(reexport.str().c_str());
+               entry.dylib = nullptr;
+               if ( (targetInstallPath == nullptr) || (strcmp(targetInstallPath, entry.path) != 0) )
+                       _dependentDylibs.push_back(entry);
+       }
+
+       // build hash table
+       buildExportHashTable(lib);
+
+       munmap((caddr_t)fileContent, fileLength);
+}
+
+template <typename A>
+void File<A>::buildExportHashTable(const DynamicLibrary& lib) {
+       if ( _s_logHashtable )
+               fprintf(stderr, "ld: building hashtable from text-stub info in %s\n", this->path());
+
+       for (auto &sym : lib._symbols)
+               addSymbol(sym.str().c_str(), /*weak=*/false, /*tlv=*/false);
+
+#if SUPPORT_ARCH_i386
+       if (_platform == Options::kPlatformOSX && _cpuType == CPU_TYPE_I386) {
+               for (auto &sym : lib._classes)
+                       addSymbol((".objc_class_name" + sym.str()).c_str(), /*weak=*/false, /*tlv=*/false);
+       } else {
+               for (auto &sym : lib._classes) {
+                       addSymbol(("_OBJC_CLASS_$" + sym.str()).c_str(), /*weak=*/false, /*tlv=*/false);
+                       addSymbol(("_OBJC_METACLASS_$" + sym.str()).c_str(), /*weak=*/false, /*tlv=*/false);
+               }
+       }
+#else
+       for (auto &sym : lib._classes) {
+               addSymbol(("_OBJC_CLASS_$" + sym.str()).c_str(), /*weak=*/false, /*tlv=*/false);
+               addSymbol(("_OBJC_METACLASS_$" + sym.str()).c_str(), /*weak=*/false, /*tlv=*/false);
+       }
+#endif
+
+       for (auto &sym : lib._ivars)
+               addSymbol(("_OBJC_IVAR_$" + sym.str()).c_str(), /*weak=*/false, /*tlv=*/false);
+
+       for (auto &sym : lib._weakDefSymbols)
+               addSymbol(sym.str().c_str(), /*weak=*/true, /*tlv=*/false);
+
+       for (auto &sym : lib._tlvSymbols)
+               addSymbol(sym.str().c_str(), /*weak=*/false, /*tlv=*/true);
+}
+
+
+template <typename A>
+void File<A>::addSymbol(const char* name, bool weakDef, bool tlv)
+{
+       // symbols that start with $ld$ are meta-data to the static linker
+       // <rdar://problem/5182537> need way for ld and dyld to see different exported symbols in a dylib
+       if ( strncmp(name, "$ld$", 4) == 0 ) {
+               //    $ld$ <action> $ <condition> $ <symbol-name>
+               const char* symAction = &name[4];
+               const char* symCond = strchr(symAction, '$');
+               if ( symCond != nullptr ) {
+                       char curOSVers[16];
+                       sprintf(curOSVers, "$os%d.%d$", (_linkMinOSVersion >> 16), ((_linkMinOSVersion >> 8) & 0xFF));
+                       if ( strncmp(symCond, curOSVers, strlen(curOSVers)) == 0 ) {
+                               const char* symName = strchr(&symCond[1], '$');
+                               if ( symName != nullptr ) {
+                                       ++symName;
+                                       if ( strncmp(symAction, "hide$", 5) == 0 ) {
+                                               if ( _s_logHashtable )
+                                                       fprintf(stderr, "  adding %s to ignore set for %s\n", symName, this->path());
+                                               _ignoreExports.insert(strdup(symName));
+                                               return;
+                                       }
+                                       else if ( strncmp(symAction, "add$", 4) == 0 ) {
+                                               this->addSymbol(symName, weakDef, false);
+                                               return;
+                                       }
+                                       else if ( strncmp(symAction, "install_name$", 13) == 0 ) {
+                                               _dylibInstallPath = strdup(symName);
+                                               _installPathOverride = true;
+                                               return;
+                                       }
+                                       else if ( strncmp(symAction, "compatibility_version$", 22) == 0 ) {
+                                               _dylibCompatibilityVersion = parseVersionNumber32(symName);
+                                               return;
+                                       }
+                                       else {
+                                               warning("bad symbol action: %s in dylib %s", name, this->path());
+                                       }
+                               }
+                       }
+               }
+               else {
+                       warning("bad symbol condition: %s in dylib %s", name, this->path());
+               }
+       }
+
+       // add symbol as possible export if we are not supposed to ignore it
+       if ( _ignoreExports.count(name) == 0 ) {
+               AtomAndWeak bucket;
+               bucket.atom = nullptr;
+               bucket.weakDef = weakDef;
+               bucket.tlv = tlv;
+               if ( _s_logHashtable )
+                       fprintf(stderr, "  adding %s to hash table for %s\n", name, this->path());
+               _atoms[strdup(name)] = bucket;
+       }
+}
+
+
+template <typename A>
+bool File<A>::forEachAtom(ld::File::AtomHandler& handler) const
+{
+       handler.doFile(*this);
+       return false;
+}
+
+
+template <typename A>
+std::pair<bool, bool> File<A>::hasWeakDefinitionImpl(const char* name) const
+{
+       const auto pos = _atoms.find(name);
+       if ( pos != _atoms.end() )
+               return std::make_pair(true, pos->second.weakDef);
+
+       // look in children that I re-export
+       for (const auto &dep : _dependentDylibs) {
+               auto ret = dep.dylib->hasWeakDefinitionImpl(name);
+               if ( ret.first )
+                       return ret;
+       }
+       return std::make_pair(false, false);
+}
+
+
+template <typename A>
+bool File<A>::hasWeakDefinition(const char* name) const
+{
+       // if supposed to ignore this export, then pretend I don't have it
+       if ( _ignoreExports.count(name) != 0 )
+               return false;
+
+       return hasWeakDefinitionImpl(name).second;
+}
+
+
+// <rdar://problem/5529626> If only weak_import symbols are used, linker should use LD_LOAD_WEAK_DYLIB
+template <typename A>
+bool File<A>::allSymbolsAreWeakImported() const
+{
+       bool foundNonWeakImport = false;
+       bool foundWeakImport = false;
+       for (const auto &it : _atoms) {
+               const ld::Atom* atom = it.second.atom;
+               if ( atom != nullptr ) {
+                       if ( atom->weakImported() )
+                               foundWeakImport = true;
+                       else
+                               foundNonWeakImport = true;
+               }
+       }
+
+       // don't automatically weak link dylib with no imports
+       // so at least one weak import symbol and no non-weak-imported symbols must be found
+       return foundWeakImport && !foundNonWeakImport;
+}
+
+
+template <typename A>
+bool File<A>::containsOrReExports(const char* name, bool& weakDef, bool& tlv, uint64_t& addr) const
+{
+       if ( _ignoreExports.count(name) != 0 )
+               return false;
+
+       // check myself
+       const auto pos = _atoms.find(name);
+       if ( pos != _atoms.end() ) {
+               weakDef = pos->second.weakDef;
+               tlv = pos->second.tlv;
+               addr = 0;
+               return true;
+       }
+
+       // check dylibs I re-export
+       for (const auto& lib : _dependentDylibs) {
+               if ( !lib.dylib->implicitlyLinked() ) {
+                       if ( lib.dylib->containsOrReExports(name, weakDef, tlv, addr) )
+                               return true;
+               }
+       }
+
+       return false;
+}
+
+
+template <typename A>
+bool File<A>::justInTimeforEachAtom(const char* name, ld::File::AtomHandler& handler) const
+{
+       // if supposed to ignore this export, then pretend I don't have it
+       if ( _ignoreExports.count(name) != 0 )
+               return false;
+
+
+       AtomAndWeak bucket;
+       uint64_t addr;
+       if ( this->containsOrReExports(name, bucket.weakDef, bucket.tlv, addr) ) {
+               bucket.atom = new ExportAtom<A>(*this, name, bucket.weakDef, bucket.tlv);
+               _atoms[name] = bucket;
+               _providedAtom = true;
+               if ( _s_logHashtable )
+                       fprintf(stderr, "getJustInTimeAtomsFor: %s found in %s\n", name, this->path());
+               // call handler with new export atom
+               handler.doAtom(*bucket.atom);
+               return true;
+       }
+
+       return false;
+}
+
+
+
+template <typename A>
+bool File<A>::isPublicLocation(const char* path)
+{
+       // -no_implicit_dylibs disables this optimization
+       if ( ! _implicitlyLinkPublicDylibs )
+               return false;
+
+       // /usr/lib is a public location
+       if ( (strncmp(path, "/usr/lib/", 9) == 0) && (strchr(&path[9], '/') == nullptr) )
+               return true;
+
+       // /System/Library/Frameworks/ is a public location
+       if ( strncmp(path, "/System/Library/Frameworks/", 27) == 0 ) {
+               const char* frameworkDot = strchr(&path[27], '.');
+               // but only top level framework
+               // /System/Library/Frameworks/Foo.framework/Versions/A/Foo                 ==> true
+               // /System/Library/Frameworks/Foo.framework/Resources/libBar.dylib         ==> false
+               // /System/Library/Frameworks/Foo.framework/Frameworks/Bar.framework/Bar   ==> false
+               // /System/Library/Frameworks/Foo.framework/Frameworks/Xfoo.framework/XFoo ==> false
+               if ( frameworkDot != nullptr ) {
+                       int frameworkNameLen = frameworkDot - &path[27];
+                       if ( strncmp(&path[strlen(path)-frameworkNameLen-1], &path[26], frameworkNameLen+1) == 0 )
+                               return true;
+               }
+       }
+
+       return false;
+}
+
+template <typename A>
+void File<A>::processIndirectLibraries(ld::dylib::File::DylibHandler* handler, bool addImplicitDylibs)
+{
+       // only do this once
+       if ( _indirectDylibsProcessed )
+               return;
+
+       const static bool log = false;
+       if ( log ) fprintf(stderr, "processIndirectLibraries(%s)\n", this->installPath());
+       if ( _linkingFlat ) {
+               for (auto& lib : _dependentDylibs) {
+                       lib.dylib = (File<A>*)handler->findDylib(lib.path, this->path());
+               }
+       }
+       else if ( _noRexports ) {
+               // MH_NO_REEXPORTED_DYLIBS bit set, then nothing to do
+       }
+       else {
+               // two-level, might have re-exports
+               for (auto& lib : _dependentDylibs) {
+                       if ( log )
+                               fprintf(stderr, "processIndirectLibraries() parent=%s, child=%s\n", this->installPath(), lib.path);
+                       // a LC_REEXPORT_DYLIB, LC_SUB_UMBRELLA or LC_SUB_LIBRARY says we re-export this child
+                       lib.dylib = (File<A>*)handler->findDylib(lib.path, this->path());
+                       if ( lib.dylib->hasPublicInstallName() && !lib.dylib->wrongOS() ) {
+                               // promote this child to be automatically added as a direct dependent if this already is
+                               if ( (this->explicitlyLinked() || this->implicitlyLinked()) && (strcmp(lib.path, lib.dylib->installPath()) == 0) ) {
+                                       if ( log )
+                                               fprintf(stderr, "processIndirectLibraries() implicitly linking %s\n", lib.dylib->installPath());
+                                       lib.dylib->setImplicitlyLinked();
+                               }
+                               else if ( lib.dylib->explicitlyLinked() || lib.dylib->implicitlyLinked() ) {
+                                       if ( log )
+                                               fprintf(stderr, "processIndirectLibraries() parent is not directly linked, but child is, so no need to re-export child\n");
+                               } else {
+                                       if ( log )
+                                               fprintf(stderr, "processIndirectLibraries() parent is not directly linked, so parent=%s will re-export child=%s\n", this->installPath(), lib.path);
+                               }
+                       } else {
+                               // add all child's symbols to me
+                               if ( log )
+                                       fprintf(stderr, "processIndirectLibraries() child is not public, so parent=%s will re-export child=%s\n", this->installPath(), lib.path);
+                       }
+               }
+       }
+
+       // check for re-export cycles
+       ReExportChain chain;
+       chain.prev = nullptr;
+       chain.file = this;
+       this->assertNoReExportCycles(&chain);
+
+       _indirectDylibsProcessed = true;
+}
+
+template <typename A>
+void File<A>::assertNoReExportCycles(ReExportChain* prev) const
+{
+       // recursively check my re-exported dylibs
+       ReExportChain chain;
+       chain.prev = prev;
+       chain.file = this;
+       for (const auto& dep : _dependentDylibs) {
+               ld::File* child = dep.dylib;
+               // check child is not already in chain
+               for (ReExportChain* p = prev; p != nullptr; p = p->prev) {
+                       if ( p->file == child )
+                               throwf("cycle in dylib re-exports with %s and %s", child->path(), this->path());
+               }
+               if ( dep.dylib != nullptr )
+                       dep.dylib->assertNoReExportCycles(&chain);
+       }
+}
+
+
+template <typename A>
+class Parser
+{
+public:
+       typedef typename A::P   P;
+
+       static bool                             validFile(const uint8_t* fileContent, uint64_t fileLength, const std::string &path, const char* archName);
+       static ld::dylib::File* parse(const uint8_t* fileContent, uint64_t fileLength, const char* path,
+                                                                 time_t mTime, ld::File::Ordinal ordinal, const Options& opts,
+                                                                 bool indirectDylib) {
+               return new File<A>(fileContent, fileLength, path, mTime, ordinal,
+                                                  opts.flatNamespace(),
+                                                  opts.implicitlyLinkIndirectPublicDylibs(),
+                                                  opts.platform(),
+                                                  opts.architecture(),
+                                                  opts.architectureName(),
+                                                  opts.minOSversion(),
+                                                  opts.allowSimulatorToLinkWithMacOSX(),
+                                                  opts.addVersionLoadCommand(),
+                                                  opts.targetIOSSimulator(),
+                                                  opts.logAllFiles(),
+                                                  opts.installPath(),
+                                                  indirectDylib);
+       }
+};
+
+template <typename A>
+bool Parser<A>::validFile(const uint8_t* fileContent, uint64_t fileLength, const std::string &path, const char* archName)
+{
+       if ( path.find(".tbd", path.size()-4) == std::string::npos )
+               return false;
+
+       TBDFile stub((const char*)fileContent, fileLength);
+       if ( !stub.validForArch(archName) )
+               throwf("missing required architecture %s in file %s", archName, path.c_str());
+
+       return true;
+}
+
+//
+// main function used by linker to instantiate ld::Files
+//
+ld::dylib::File* parse(const uint8_t* fileContent, uint64_t fileLength, const char* path,
+                                          time_t modTime, const Options& opts, ld::File::Ordinal ordinal,
+                                          bool bundleLoader, bool indirectDylib)
+{
+       switch ( opts.architecture() ) {
+#if SUPPORT_ARCH_x86_64
+               case CPU_TYPE_X86_64:
+                       if ( Parser<x86_64>::validFile(fileContent, fileLength, path, opts.architectureName()) )
+                               return Parser<x86_64>::parse(fileContent, fileLength, path, modTime, ordinal, opts, indirectDylib);
+                       break;
+#endif
+#if SUPPORT_ARCH_i386
+               case CPU_TYPE_I386:
+                       if ( Parser<x86>::validFile(fileContent, fileLength, path, opts.architectureName()) )
+                               return Parser<x86>::parse(fileContent, fileLength, path, modTime, ordinal, opts, indirectDylib);
+                       break;
+#endif
+#if SUPPORT_ARCH_arm_any
+               case CPU_TYPE_ARM:
+                       if ( Parser<arm>::validFile(fileContent, fileLength, path, opts.architectureName()) )
+                               return Parser<arm>::parse(fileContent, fileLength, path, modTime, ordinal, opts, indirectDylib);
+                       break;
+#endif
+#if SUPPORT_ARCH_arm64
+               case CPU_TYPE_ARM64:
+                       if ( Parser<arm64>::validFile(fileContent, fileLength, path, opts.architectureName()) )
+                               return Parser<arm64>::parse(fileContent, fileLength, path, modTime, ordinal, opts, indirectDylib);
+                       break;
+#endif
+       }
+       return nullptr;
+}
+       
+       
+} // namespace dylib
+} // namespace textstub
+
+
diff --git a/src/ld/parsers/textstub_dylib_file.hpp b/src/ld/parsers/textstub_dylib_file.hpp
new file mode 100644 (file)
index 0000000..e0a75f6
--- /dev/null
@@ -0,0 +1,43 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2015 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#ifndef __TEXTSTUB_DYLIB_FILE_H__
+#define __TEXTSTUB_DYLIB_FILE_H__
+
+#include "ld.hpp"
+#include "Options.h"
+
+namespace textstub {
+namespace dylib {
+
+
+extern ld::dylib::File* parse(const uint8_t* fileContent, uint64_t fileLength, const char* path,
+                                                         time_t modTime, const Options& opts, ld::File::Ordinal ordinal,
+                                                         bool bundleLoader, bool indirectDylib);
+
+} // namespace dylib
+} // namespace textstub
+
+
+#endif // __TEXTSTUB_DYLIB_FILE_H__
diff --git a/src/ld/passes/bitcode_bundle.cpp b/src/ld/passes/bitcode_bundle.cpp
new file mode 100644 (file)
index 0000000..bafad0b
--- /dev/null
@@ -0,0 +1,809 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2010 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <vector>
+#include <dlfcn.h>
+#include <math.h>
+#include <unistd.h>
+#include <time.h>
+#include <unordered_map>
+
+#include "llvm-c/lto.h"
+// c header
+extern "C" {
+#include <xar/xar.h>
+}
+
+#include "bitcode_bundle.h"
+
+#include "Options.h"
+#include "ld.hpp"
+#include "Bitcode.hpp"
+#include "macho_relocatable_file.h"
+
+
+namespace ld {
+namespace passes {
+namespace bitcode_bundle {
+
+class BitcodeTempFile;
+
+class BitcodeAtom : public ld::Atom {
+    static ld::Section                      bitcodeBundleSection;
+public:
+                                            BitcodeAtom();
+                                            BitcodeAtom(BitcodeTempFile& tempfile);
+                                            ~BitcodeAtom()                  { free(_content); }
+    virtual ld::File*                                          file() const                                    { return NULL; }
+    virtual const char*                                                name() const                                    { return "bitcode bundle"; }
+    virtual uint64_t                                           size() const                                    { return _size; }
+    virtual uint64_t                                           objectAddress() const                   { return 0; }
+    virtual void                                                       copyRawContent(uint8_t buffer[]) const
+                                                                            { memcpy(buffer, _content, _size); }
+    virtual void                                                       setScope(Scope)                                 { }
+
+private:
+    uint8_t*                                _content;
+    uint64_t                                                           _size;
+};
+
+ld::Section BitcodeAtom::bitcodeBundleSection("__LLVM", "__bundle", ld::Section::typeSectCreate);
+
+class BitcodeTempFile {
+public:
+                                            BitcodeTempFile(const char* path, bool deleteAfterRead);
+                                            ~BitcodeTempFile();
+    uint8_t*                                getContent() const              { return _content; }
+    uint64_t                                getSize() const                 { return _size; }
+private:
+    friend class BitcodeAtom;
+    const char* _path;
+    uint8_t* _content;
+    uint64_t _size;
+    bool _deleteAfterRead;
+};
+
+class BitcodeObfuscator {
+public:
+    BitcodeObfuscator();
+    ~BitcodeObfuscator();
+
+    void addMustPreserveSymbols(const char* name);
+    void bitcodeHideSymbols(ld::Bitcode* bc, const char* filePath, const char* outputPath);
+    void writeSymbolMap(const char* outputPath);
+private:
+    typedef void (*lto_codegen_func_t) (lto_code_gen_t);
+    typedef void (*lto_codegen_output_t) (lto_code_gen_t, const char*);
+
+    lto_code_gen_t                          _obfuscator;
+    lto_codegen_func_t                      _lto_hide_symbols;
+    lto_codegen_func_t                      _lto_reset_context;
+    lto_codegen_output_t                    _lto_write_reverse_map;
+};
+
+class FileHandler {
+    // generic handler for files in a bundle
+public:
+    virtual void populateMustPreserveSymbols(BitcodeObfuscator* _obfuscator)    { }
+    virtual void obfuscateAndWriteToPath(BitcodeObfuscator* _obfuscator, const char* path) { };
+    xar_file_t getXARFile()                 { return _xar_file; }
+
+    FileHandler(char* content, size_t size) :
+        _parent(NULL), _xar_file(NULL), _file_buffer(content), _file_size(size) {   }           // eager construct
+    FileHandler(xar_t parent, xar_file_t xar_file) :
+        _parent(parent), _xar_file(xar_file), _file_buffer(NULL), _file_size(0) {   }           // lazy construct
+    virtual ~FileHandler()                                                      {   }
+
+protected:
+    void initFile() {
+        if (!_file_buffer) {
+            if (xar_extract_tobuffersz(_parent, _xar_file, &_file_buffer, &_file_size) != 0)
+                throwf("could not extract files from bitcode bundle");
+        }
+    }
+    void destroyFile() {
+        if (_parent)
+            free(_file_buffer);
+    }
+
+    xar_t                               _parent;
+    xar_file_t                          _xar_file;
+    char*                               _file_buffer;
+    size_t                              _file_size;
+};
+
+class BundleHandler : public FileHandler {
+public:
+    BundleHandler(char* bundleContent, size_t bundleSize, const Options& options) :
+        FileHandler(bundleContent, bundleSize), _xar(NULL), _temp_dir(NULL), _options(options) { }
+    BundleHandler(xar_t parent, xar_file_t xar_file, const Options& options) :
+        FileHandler(parent, xar_file), _xar(NULL), _temp_dir(NULL), _options(options) { }
+
+    ~BundleHandler();
+
+    virtual void populateMustPreserveSymbols(BitcodeObfuscator* obfuscator) override;
+    virtual void obfuscateAndWriteToPath(BitcodeObfuscator* obfuscator, const char* path) override;
+
+private:
+    void init();
+    void copyXARProp(xar_file_t src, xar_file_t dst);
+
+    xar_t                                   _xar;
+    char*                                   _temp_dir;
+    const Options&                          _options;
+    std::vector<FileHandler*>               _handlers;
+};
+
+class BitcodeHandler : public FileHandler {
+public:
+    BitcodeHandler(char* content, size_t size) : FileHandler(content, size)      { }
+    BitcodeHandler(xar_t parent, xar_file_t xar_file) : FileHandler(parent, xar_file)   { }
+
+    ~BitcodeHandler();
+
+    virtual void populateMustPreserveSymbols(BitcodeObfuscator* obfuscator) override { } // Don't need to preserve symbols
+    virtual void obfuscateAndWriteToPath(BitcodeObfuscator* obfuscator, const char* path) override;
+};
+
+class ObjectHandler : public FileHandler {
+public:
+    ObjectHandler(char* content, size_t size) :
+        FileHandler(content, size)                      { }
+    ObjectHandler(xar_t parent, xar_file_t xar_file) :
+        FileHandler(parent, xar_file)                   { }
+
+    ~ObjectHandler();
+
+    void populateMustPreserveSymbols(BitcodeObfuscator* obfuscator) override;
+    void obfuscateAndWriteToPath(BitcodeObfuscator* obfuscator, const char* path) override;
+
+};
+
+
+class BitcodeBundle {
+public:
+    BitcodeBundle(const Options& opts, ld::Internal& internal) :
+        _options(opts), _state(internal)    { }
+    ~BitcodeBundle()                        { }
+    void                                    doPass();
+
+private:
+    const Options&                          _options;
+    ld::Internal&                           _state;
+};
+
+BitcodeAtom::BitcodeAtom()
+: ld::Atom(bitcodeBundleSection,
+           ld::Atom::definitionRegular, ld::Atom::combineNever,
+           ld::Atom::scopeTranslationUnit, ld::Atom::typeUnclassified,
+           ld::Atom::symbolTableNotIn, true, false, false, ld::Atom::Alignment(0)),
+    _size(1)
+{
+    // initialize a marker of 1 byte
+    _content = (uint8_t*)calloc(1,1);
+}
+
+BitcodeAtom::BitcodeAtom(BitcodeTempFile& tempfile)
+    : ld::Atom(bitcodeBundleSection,
+               ld::Atom::definitionRegular, ld::Atom::combineNever,
+               ld::Atom::scopeTranslationUnit, ld::Atom::typeUnclassified,
+               ld::Atom::symbolTableNotIn, true, false, false, ld::Atom::Alignment(0)),
+    _content(tempfile._content), _size(tempfile._size)
+{
+    // Creating the Atom will transfer the ownership of the buffer from Tempfile to Atom
+    tempfile._content = NULL;
+}
+
+BitcodeTempFile::BitcodeTempFile(const char* path, bool deleteAfterRead = true)
+    : _path(path), _deleteAfterRead(deleteAfterRead)
+{
+    int fd = ::open(path, O_RDONLY, 0);
+    if ( fd == -1 )
+        throwf("could not open bitcode temp file: %s", path);
+    struct stat stat_buf;
+    ::fstat(fd, &stat_buf);
+    _content = (uint8_t*)malloc(stat_buf.st_size);
+    if ( _content == NULL )
+        throwf("could not process bitcode temp file: %s", path);
+    if ( read(fd, _content, stat_buf.st_size) != stat_buf.st_size )
+        throwf("could not read bitcode temp file: %s", path);
+    ::close(fd);
+    _size = stat_buf.st_size;
+}
+
+BitcodeTempFile::~BitcodeTempFile()
+{
+    free(_content);
+    if ( _deleteAfterRead ) {
+        if ( ::unlink(_path) != 0 )
+            throwf("could not remove temp file: %s", _path);
+    }
+}
+
+BitcodeObfuscator::BitcodeObfuscator()
+{
+    // check if apple internal libLTO is used
+    if ( ::lto_get_version() == NULL )
+        throwf("libLTO is not loaded");
+    _lto_hide_symbols = (lto_codegen_func_t) dlsym(RTLD_DEFAULT, "lto_codegen_hide_symbols");
+    _lto_write_reverse_map = (lto_codegen_output_t) dlsym(RTLD_DEFAULT, "lto_codegen_write_symbol_reverse_map");
+    _lto_reset_context = (lto_codegen_func_t) dlsym(RTLD_DEFAULT, "lto_codegen_reset_context");
+    if ( _lto_hide_symbols == NULL || _lto_write_reverse_map == NULL ||
+        _lto_reset_context == NULL || ::lto_api_version() < 14 )
+        throwf("loaded libLTO doesn't support -bitcode_hide_symbols: %s", ::lto_get_version());
+    _obfuscator = ::lto_codegen_create_in_local_context();
+#if LTO_API_VERSION >= 14
+    lto_codegen_set_should_internalize(_obfuscator, false);
+#endif
+}
+
+BitcodeObfuscator::~BitcodeObfuscator()
+{
+    ::lto_codegen_dispose(_obfuscator);
+}
+
+void BitcodeObfuscator::addMustPreserveSymbols(const char* name)
+{
+    ::lto_codegen_add_must_preserve_symbol(_obfuscator, name);
+}
+
+void BitcodeObfuscator::bitcodeHideSymbols(ld::Bitcode* bc, const char* filePath, const char* outputPath)
+{
+#if LTO_API_VERSION >= 13 && LTO_APPLE_INTERNAL
+    lto_module_t module = ::lto_module_create_in_codegen_context(bc->getContent(), bc->getSize(), filePath, _obfuscator);
+    if ( module == NULL )
+        throwf("object contains invalid bitcode: %s", filePath);
+    ::lto_codegen_set_module(_obfuscator, module);
+    (*_lto_hide_symbols)(_obfuscator);
+#if LTO_API_VERSION >= 15
+    ::lto_codegen_set_should_embed_uselists(_obfuscator, true);
+#endif
+    ::lto_codegen_write_merged_modules(_obfuscator, outputPath);
+    (*_lto_reset_context)(_obfuscator);
+#endif
+    return;
+}
+
+void BitcodeObfuscator::writeSymbolMap(const char *outputPath)
+{
+    (*_lto_write_reverse_map)(_obfuscator, outputPath);
+}
+
+BundleHandler::~BundleHandler()
+{
+    // free buffers
+    destroyFile();
+    // free handlers
+    for (auto handler : _handlers)
+        delete handler;
+
+    // delete temp file if not -save-temps
+    if ( _xar ) {
+        xar_close(_xar);
+        std::string oldXARPath = std::string(_temp_dir) + std::string("/bundle.xar");
+        if ( !_options.saveTempFiles() && ::unlink(oldXARPath.c_str()) != 0)
+            warning("could not delete temp file: %s", oldXARPath.c_str());
+    }
+
+    if ( _temp_dir ) {
+        if ( !_options.saveTempFiles() && ::rmdir(_temp_dir) != 0 )
+            warning("could not delete temp directory: %s", _temp_dir);
+        free(_temp_dir);
+    }
+}
+
+BitcodeHandler::~BitcodeHandler()
+{
+    destroyFile();
+}
+
+ObjectHandler::~ObjectHandler()
+{
+    destroyFile();
+}
+
+void BundleHandler::init()
+{
+    if ( _xar != NULL )
+        return;
+
+    // make temp directory
+    const char* finalOutput = _options.outputFilePath();
+    _temp_dir = (char*)malloc(PATH_MAX * sizeof(char));
+    // Check outputFilePath.bundle-XXXXXX/YYYYYYYYYY.bc will not over flow PATH_MAX
+    // If so, fall back to /tmp
+    if ( strlen(finalOutput) + 30 >= PATH_MAX )
+        sprintf(_temp_dir, "/tmp/ld.bundle.XXXXXX");
+    else
+        sprintf(_temp_dir, "%s.bundle.XXXXXX", finalOutput);
+    ::mkdtemp(_temp_dir);
+
+    // write the bundle to the temp_directory
+    initFile();
+    std::string oldXARPath = std::string(_temp_dir) + std::string("/bundle.xar");
+    int f = ::open(oldXARPath.c_str(), O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
+    if ( f == -1 )
+        throwf("could not write file to temp directory: %s", _temp_dir);
+    if ( ::write(f, _file_buffer, _file_size) != (int)_file_size )
+        throwf("failed to write content to temp file: %s", oldXARPath.c_str());
+    ::close(f);
+
+    // read the xar file
+    _xar = xar_open(oldXARPath.c_str(), READ);
+
+    // Init the vector of handler
+    xar_iter_t iter = xar_iter_new();
+    if ( !iter )
+        throwf("could not aquire iterator for the bitcode bundle");
+    for ( xar_file_t f = xar_file_first(_xar, iter); f; f = xar_file_next(iter) ) {
+        const char* filetype = NULL;
+        if ( xar_prop_get(f, "file-type", &filetype) != 0 )
+            throwf("could not get the file type for the bitcode bundle");
+        if ( strcmp(filetype, "Bundle") == 0 )
+            _handlers.push_back(new BundleHandler(_xar, f, _options));
+        else if ( strcmp(filetype, "Object") == 0 )
+            _handlers.push_back(new ObjectHandler(_xar, f));
+        else if ( strcmp(filetype, "Bitcode") == 0 || strcmp(filetype, "LTO") == 0 )
+            _handlers.push_back(new BitcodeHandler(_xar, f));
+        else
+            assert(0 && "Unknown file type");
+    }
+    xar_iter_free(iter);
+}
+
+void BundleHandler::copyXARProp(xar_file_t src, xar_file_t dst)
+{
+    // copy the property in the XAR.
+    // Since XAR API can only get the first value from the key,
+    // Deleting the value after read.
+    int i = 0;
+    while (1) {
+        xar_iter_t p = xar_iter_new();
+        const char* key = xar_prop_first(src, p);
+        for (int x = 0; x < i; x++)
+            key = xar_prop_next(p);
+        if ( !key )
+            break;
+        const char* val = NULL;
+        xar_prop_get(src, key, &val);
+        if ( // Info from bitcode files
+             strcmp(key, "file-type") == 0 ||
+             strcmp(key, "clang/cmd") == 0 ||
+             strcmp(key, "swift/cmd") == 0 ||
+             // Info from linker subdoc
+             strcmp(key, "version") == 0 ||
+             strcmp(key, "architecture") == 0 ||
+             strcmp(key, "hide-symbols") == 0 ||
+             strcmp(key, "platform") == 0 ||
+             strcmp(key, "sdkversion") == 0 ||
+             strcmp(key, "dylibs/lib") == 0 ||
+             strcmp(key, "link-options/option") == 0 ) {
+            xar_prop_create(dst, key, val);
+            xar_prop_unset(src, key);
+        } else
+            ++ i;
+        xar_iter_free(p);
+    }
+}
+
+void BundleHandler::populateMustPreserveSymbols(BitcodeObfuscator* obfuscator)
+{
+    // init the handler
+    if ( _xar == NULL )
+        init();
+
+    // iterate through the XAR file and add symbols
+    for ( auto handler : _handlers )
+        handler->populateMustPreserveSymbols(obfuscator);
+}
+
+void ObjectHandler::populateMustPreserveSymbols(BitcodeObfuscator* obfuscator)
+{
+    initFile();
+    // Parse the object file and add the symbols
+    std::vector<const char*> symbols;
+    if ( mach_o::relocatable::getNonLocalSymbols((uint8_t*)_file_buffer, symbols) ) {
+        for ( auto sym : symbols )
+            obfuscator->addMustPreserveSymbols(sym);
+    }
+}
+
+void BundleHandler::obfuscateAndWriteToPath(BitcodeObfuscator *obfuscator, const char *path)
+{
+    // init the handler
+    if ( _xar == NULL )
+        init();
+
+    // creating the new xar
+    xar_t x = xar_open(path, WRITE);
+    if (x == NULL)
+        throwf("could not open output bundle to write %s", path);
+    // Disable compression
+    if (xar_opt_set(x, XAR_OPT_COMPRESSION, XAR_OPT_VAL_NONE) != 0)
+        throwf("could not disable compression for bitcode bundle");
+
+    // iterate through the XAR file and obfuscate
+    for ( auto handler : _handlers ) {
+        const char* name = NULL;
+        xar_file_t f = handler->getXARFile();
+        if ( xar_prop_get(f, "name", &name) != 0 )
+            throwf("could not get the name of the file from bitcode bundle");
+        char outputPath[PATH_MAX];
+        sprintf(outputPath, "%s/%s", _temp_dir, name);
+        handler->obfuscateAndWriteToPath(obfuscator, outputPath);
+        BitcodeTempFile* bcOut = new BitcodeTempFile(outputPath, !_options.saveTempFiles());
+        xar_file_t bcEntry = xar_add_frombuffer(x, NULL, name, (char*)bcOut->getContent(), bcOut->getSize());
+        copyXARProp(f, bcEntry);
+        delete bcOut;
+    }
+
+    // copy the subdoc as well
+    for ( xar_subdoc_t sub = xar_subdoc_first(_xar); sub; sub = xar_subdoc_next(sub) ) {
+        const char *name = xar_subdoc_name(sub);
+        xar_subdoc_t newDoc = xar_subdoc_new(x, name);
+        copyXARProp((xar_file_t) sub, (xar_file_t) newDoc);
+    }
+    xar_close(x);
+}
+
+void BitcodeHandler::obfuscateAndWriteToPath(BitcodeObfuscator *obfuscator, const char *path)
+{
+    initFile();
+    ld::Bitcode bc((uint8_t*)_file_buffer, _file_size);
+    obfuscator->bitcodeHideSymbols(&bc, path, path);
+}
+
+void ObjectHandler::obfuscateAndWriteToPath(BitcodeObfuscator *obfuscator, const char *path)
+{
+    initFile();
+    int f = ::open(path, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
+    if ( f == -1 || ::write(f, _file_buffer, _file_size) != (int)_file_size )
+        throwf("failed to write content to temp file: %s", path);
+    ::close(f);
+}
+
+void BitcodeBundle::doPass()
+{
+    if ( _state.embedMarkerOnly ) {
+        assert( _options.outputKind() != Options::kDynamicExecutable &&
+                _options.outputKind() != Options::kStaticExecutable &&
+                "Don't emit marker for executables");
+        BitcodeAtom* marker = new BitcodeAtom();
+        _state.addAtom(*marker);
+        return;
+    }
+
+    if ( _state.filesWithBitcode.empty() && _state.ltoBitcodePath.empty() )
+        return;
+    // Create tempdir, the temp directory should be OUTPUT/main.exe.bundle-XXXXXX
+    char tempdir[PATH_MAX];
+    const char* finalOutput = _options.outputFilePath();
+    // Check outputFilePath.bundle-XXXXXX/YYYYYYYYYY.bc will not over flow PATH_MAX
+    // If so, fall back to /tmp
+    if ( strlen(finalOutput) + 30 >= PATH_MAX )
+        sprintf(tempdir, "/tmp/ld.bundle.XXXXXX");
+    else
+        sprintf(tempdir, "%s.bundle.XXXXXX", finalOutput);
+    ::mkdtemp(tempdir);
+    // A lookup map to look for BundlerHandler base on filename
+    std::unordered_map<std::string, BundleHandler*> handlerMap;
+
+    BitcodeObfuscator* obfuscator = _options.hideSymbols() ? new BitcodeObfuscator() : NULL;
+    // Build must keep symbols if we need to hide all the symbols
+    if ( _options.hideSymbols() ) {
+        // Go through all the atoms and decide if it should be obfuscated.
+        // The following symbols are kept:
+        // 1. entry point
+        // 2. undefined symbols
+        // 3. symbols must not be stripped
+        // 4. all the globals if the globals are dead_strip root (ex. dylibs)
+        // 5. there is an exported symbol list suggests the symbol should be exported
+        // 6. the special symbols supplied by linker
+        for ( auto &sect : _state.sections ) {
+            for ( auto &atom : sect->atoms ) {
+                if ( atom == _state.entryPoint ||
+                     atom->definition() == ld::Atom::definitionProxy ||
+                     atom->symbolTableInclusion() == ld::Atom::symbolTableInAndNeverStrip ||
+                     ( _options.allGlobalsAreDeadStripRoots() && atom->scope() == ld::Atom::scopeGlobal ) ||
+                     ( _options.hasExportRestrictList() && _options.shouldExport(atom->name())) )
+                    obfuscator->addMustPreserveSymbols(atom->name());
+            }
+        }
+        // If there are assembly sources, add globals and undefined symbols from them as well
+        for ( auto &f : _state.filesWithBitcode ) {
+            if ( ld::AsmBitcode* ab = dynamic_cast<ld::AsmBitcode*>(f->getBitcode()) ) {
+                ObjectHandler objHandler((char*)ab->getContent(), ab->getSize());
+                objHandler.populateMustPreserveSymbols(obfuscator);
+            } else if ( ld::BundleBitcode* bb = dynamic_cast<ld::BundleBitcode*>(f->getBitcode()) ) {
+                BundleHandler* bh = new BundleHandler((char*)bb->getContent(), bb->getSize(), _options);
+                bh->populateMustPreserveSymbols(obfuscator);
+                handlerMap.emplace(std::string(f->path()), bh);
+            }
+        }
+        // special symbols supplied by linker
+        obfuscator->addMustPreserveSymbols("___dso_handle");
+        obfuscator->addMustPreserveSymbols("__mh_execute_header");
+        obfuscator->addMustPreserveSymbols("__mh_dylib_header");
+        obfuscator->addMustPreserveSymbols("__mh_bundle_header");
+        obfuscator->addMustPreserveSymbols("__mh_dylinker_header");
+        obfuscator->addMustPreserveSymbols("__mh_object_header");
+        obfuscator->addMustPreserveSymbols("__mh_preload_header");
+    }
+
+    // Open XAR output
+    xar_t x;
+    char outFile[PATH_MAX];
+    sprintf(outFile, "%s/bundle.xar", tempdir);
+
+    // By default, it uses gzip to compress and SHA1 as checksum
+    x = xar_open(outFile, WRITE);
+    if (x == NULL)
+        throwf("could not open output bundle to write %s", outFile);
+    // Disable compression
+    if (xar_opt_set(x, XAR_OPT_COMPRESSION, XAR_OPT_VAL_NONE) != 0)
+        throwf("could not disable compression for bitcode bundle");
+
+    // Sort all the object file according to oridnal order
+    std::sort(_state.filesWithBitcode.begin(), _state.filesWithBitcode.end(),
+              [](const ld::relocatable::File* a, const ld::relocatable::File* b) {
+                  return a->ordinal() < b->ordinal();
+              });
+
+    // Copy each bitcode file into archive
+    int index = 1;
+    char formatString[10];
+    sprintf(formatString, "%%0%ud", (unsigned int)log10(_state.filesWithBitcode.size()) + 1);
+    for ( auto &obj : _state.filesWithBitcode ) {
+        assert(obj->getBitcode() != NULL && "File should contain bitcode");
+        char outFilePath[16];
+        sprintf(outFilePath, formatString, index++);
+        if ( ld::LLVMBitcode* llvmbc = dynamic_cast<ld::LLVMBitcode*>(obj->getBitcode()) ) {
+            // Handle clang and swift bitcode
+            xar_file_t bcFile = NULL;
+            if ( _options.hideSymbols() && !llvmbc->isMarker() ) { // dont strip if it is just a marker
+                char tempfile[PATH_MAX];
+                sprintf(tempfile, "%s/%s.bc", tempdir, outFilePath);
+                obfuscator->bitcodeHideSymbols(llvmbc, obj->path(), tempfile);
+                BitcodeTempFile* bcTemp = new BitcodeTempFile(tempfile, !_options.saveTempFiles());
+                bcFile = xar_add_frombuffer(x, NULL, outFilePath, (char*)bcTemp->getContent(), bcTemp->getSize());
+                delete bcTemp;
+            } else {
+                bcFile = xar_add_frombuffer(x, NULL, outFilePath, (char*)const_cast<uint8_t*>(llvmbc->getContent()), llvmbc->getSize());
+            }
+            if ( bcFile == NULL )
+                throwf("could not add bitcode from %s to bitcode bundle", obj->path());
+            if ( xar_prop_set(bcFile, "file-type", "Bitcode") != 0 )
+                throwf("could not set bitcode property for %s in bitcode bundle", obj->path());
+            // Write commandline options
+            std::string tagName = std::string(llvmbc->getBitcodeName()) + std::string("/cmd");
+            for ( uint32_t i = 0; i < llvmbc->getCmdSize(); ++i ) {
+                if ( i == 0 || llvmbc->getCmdline()[i-1] == '\0' ) {
+                    if ( xar_prop_create(bcFile, tagName.c_str(), (const char *)llvmbc->getCmdline() + i) )
+                        throwf("could not set cmdline to XAR file");
+                }
+            }
+        }
+        else if ( ld::BundleBitcode* bundlebc = dynamic_cast<ld::BundleBitcode*>(obj->getBitcode()) ) {
+            xar_file_t bundleFile = NULL;
+            if ( _options.hideSymbols() && !bundlebc->isMarker() ) { // dont strip if it is just a marker
+                char tempfile[PATH_MAX];
+                sprintf(tempfile, "%s/%s.xar", tempdir, outFilePath);
+                auto search = handlerMap.find(std::string(obj->path()));
+                assert( search != handlerMap.end() && "Cannot find handler");
+                search->second->obfuscateAndWriteToPath(obfuscator, tempfile);
+                BitcodeTempFile* bundleTemp = new BitcodeTempFile(tempfile, !_options.saveTempFiles());
+                bundleFile = xar_add_frombuffer(x, NULL, outFilePath, (char*)bundleTemp->getContent(), bundleTemp->getSize());
+                delete bundleTemp;
+            } else {
+                bundleFile = xar_add_frombuffer(x, NULL, outFilePath,
+                                                (char*)const_cast<uint8_t*>(bundlebc->getContent()),
+                                                bundlebc->getSize());
+            }
+            if ( bundleFile == NULL )
+                throwf("could not add bitcode from the bundle %s to bitcode bundle", obj->path());
+            if ( xar_prop_set(bundleFile, "file-type", "Bundle") != 0 )
+                throwf("could not set bundle property for %s in bitcode bundle", obj->path());
+        }
+        else if ( ld::AsmBitcode* asmbc = dynamic_cast<ld::AsmBitcode*>(obj->getBitcode()) ) {
+            xar_file_t objFile = xar_add_frombuffer(x, NULL, outFilePath, (char*)asmbc->getContent(), asmbc->getSize());
+            if ( objFile == NULL )
+                throwf("could not add obj file %s to bitcode bundle", obj->path());
+            if ( xar_prop_set(objFile, "file-type", "Object") != 0 )
+                throwf("could not set object property for %s in bitcode bundle", obj->path());
+        }
+        else {
+            assert(false && "Unknown bitcode");
+        }
+    }
+
+    // Write merged LTO bitcode
+    if ( !_state.ltoBitcodePath.empty() ) {
+        xar_file_t ltoFile = NULL;
+        BitcodeTempFile* ltoTemp = new BitcodeTempFile(_state.ltoBitcodePath.c_str(), !_options.saveTempFiles());
+        if ( _options.hideSymbols() ) {
+            ld::Bitcode ltoBitcode(ltoTemp->getContent(), ltoTemp->getSize());
+            char ltoTempFile[PATH_MAX];
+            sprintf(ltoTempFile, "%s/lto.bc", tempdir);
+            obfuscator->bitcodeHideSymbols(&ltoBitcode, _state.ltoBitcodePath.c_str(), ltoTempFile);
+            BitcodeTempFile* ltoStrip = new BitcodeTempFile(ltoTempFile, !_options.saveTempFiles());
+            ltoFile = xar_add_frombuffer(x, NULL, "lto.o", (char*)ltoStrip->getContent(), ltoStrip->getSize());
+            delete ltoStrip;
+        } else {
+            ltoFile = xar_add_frombuffer(x, NULL, "lto.o", (char*)ltoTemp->getContent(), ltoTemp->getSize());
+        }
+        if ( ltoFile == NULL )
+            throwf("could not add lto file %s to bitcode bundle", _state.ltoBitcodePath.c_str());
+        if ( xar_prop_set(ltoFile, "file-type", "LTO") != 0 )
+            throwf("could not set bitcode property for %s in bitcode bundle", _state.ltoBitcodePath.c_str());
+        delete ltoTemp;
+    }
+
+    // Common LinkOptions
+    std::vector<std::string> linkCmd = _options.writeBitcodeLinkOptions();
+
+    // support -sectcreate option
+    for ( auto extraSect = _options.extraSectionsBegin(); extraSect != _options.extraSectionsEnd(); ++ extraSect ) {
+        std::string sectName = std::string(extraSect->segmentName) + std::string(",") + std::string(extraSect->sectionName);
+        BitcodeTempFile* sectFile = new BitcodeTempFile(extraSect->path, false);
+        xar_file_t sectXar = xar_add_frombuffer(x, NULL, sectName.c_str(), (char*)sectFile->getContent(), sectFile->getSize());
+        if ( sectXar == NULL )
+            throwf("could not encode sectcreate file %s into bitcode bundle", extraSect->path);
+        if ( xar_prop_set(sectXar, "file-type", "Section") != 0 )
+            throwf("could not set bitcode property for %s", sectName.c_str());
+        delete sectFile;
+        linkCmd.push_back("-sectcreate");
+        linkCmd.push_back(extraSect->segmentName);
+        linkCmd.push_back(extraSect->sectionName);
+        linkCmd.push_back(sectName);
+    }
+
+    // Write exports file
+    if ( _options.hasExportMaskList() ) {
+        linkCmd.push_back("-exported_symbols_list");
+        linkCmd.push_back("exports.exp");
+        const char* exportsPath = "exports.exp";
+        std::vector<const char*> exports = _options.exportsData();
+        std::string exps;
+        for (std::vector<const char*>::iterator it = exports.begin();
+             it != exports.end(); ++ it) {
+            exps += *it;
+            exps += "\n";
+        }
+        // always append an empty line so exps cannot be empty. rdar://problem/22404253
+        exps += "\n";
+        xar_file_t exportsFile = xar_add_frombuffer(x, NULL, exportsPath, const_cast<char*>(exps.data()), exps.size());
+        if (exportsFile == NULL)
+            throwf("could not add exports list to bitcode bundle");
+        if (xar_prop_set(exportsFile, "file-type", "Exports") != 0)
+            throwf("could not set exports property in bitcode bundle");
+    }
+
+    // Create subdoc to write link information
+    xar_subdoc_t linkXML = xar_subdoc_new(x, "Ld");
+    if ( linkXML == NULL )
+        throwf("could not create XML in bitcode bundle");
+
+    // Write version number
+    if ( xar_prop_create((xar_file_t)linkXML, "version", BITCODE_XAR_VERSION) != 0 )
+        throwf("could not add version number to bitcode bundle");
+
+    // Arch
+    if ( xar_prop_create((xar_file_t)linkXML, "architecture", _options.architectureName()) != 0 )
+        throwf("could not add achitecture name to bitcode bundle");
+
+    // Opt-out symbols
+    if ( _options.hideSymbols() ) {
+        if ( xar_prop_create((xar_file_t)linkXML, "hide-symbols", "1") != 0 )
+            throwf("could not add property to bitcode bundle");
+    }
+
+    // Write SDK version
+    if ( _options.sdkPaths().size() > 1 )
+        throwf("only one -syslibroot is accepted for bitcode bundle");
+    if ( xar_prop_create((xar_file_t)linkXML, "platform", _options.getPlatformStr().c_str()) != 0 )
+        throwf("could not add platform name to bitcode bundle");
+    if ( xar_prop_create((xar_file_t)linkXML, "sdkversion", _options.getSDKVersionStr().c_str()) != 0 )
+        throwf("could not add SDK version to bitcode bundle");
+
+    // Write dylibs
+    const char* sdkRoot = NULL;
+    if ( !_options.sdkPaths().empty() )
+        sdkRoot = _options.sdkPaths().front();
+    if ( !_state.dylibs.empty() ) {
+        std::vector<const char*> SDKPaths = _options.sdkPaths();
+        char dylibPath[PATH_MAX];
+        for ( auto &dylib : _state.dylibs ) {
+            // For every dylib/framework, figure out if it is coming from a SDK
+            // if it is coming from some SDK, we parse the path to figure out which SDK
+            // If -syslibroot is pointing to a SDK, it should end with PlatformX.Y.sdk/
+            if (sdkRoot && strncmp(dylib->path(), sdkRoot, strlen(sdkRoot)) == 0) {
+                // dylib/framework from one of the -syslibroot
+                // The path start with a string template
+                strcpy(dylibPath, "{SDKPATH}/");
+                // append the path of dylib/frameowrk in the SDK
+                strcat(dylibPath, dylib->path() + strlen(sdkRoot));
+            } else {
+                // Not in any SDKs, then assume it is a user dylib/framework
+                // strip off all the path in the front
+                const char* dylib_name = strrchr(dylib->path(), '/');
+                dylib_name = (dylib_name == NULL) ? dylib->path() : dylib_name + 1;
+                strcpy(dylibPath, dylib_name);
+            }
+            if ( dylib->forcedWeakLinked() ) {
+                if ( xar_prop_create((xar_file_t)linkXML, "dylibs/weak", dylibPath) != 0)
+                    throwf("could not add dylib options to bitcode bundle");
+            } else {
+                if ( xar_prop_create((xar_file_t)linkXML, "dylibs/lib", dylibPath) != 0)
+                    throwf("could not add dylib options to bitcode bundle");
+            }
+        }
+    }
+
+    // Write link-line into archive
+    for ( auto &it : linkCmd ) {
+        if (xar_prop_create((xar_file_t)linkXML, "link-options/option", it.c_str()) != 0)
+            throwf("could not add link options to bitcode bundle");
+    }
+    // Finish writing
+    xar_close(x);
+
+    // Read the file back
+    BitcodeTempFile* xarTemp = new BitcodeTempFile(outFile, !_options.saveTempFiles());
+
+    // Create an Atom and add to the list
+    BitcodeAtom* bundleAtom = new BitcodeAtom(*xarTemp);
+    _state.addAtom(*bundleAtom);
+
+    // write the reverse mapping file if required
+    if ( _options.hideSymbols() && !_options.reverseMapTempPath().empty() )
+        obfuscator->writeSymbolMap(_options.reverseMapTempPath().c_str());
+
+    // Clean up local variables
+    delete xarTemp;
+    delete obfuscator;
+    for ( auto &entry: handlerMap )
+        delete entry.second;
+    // delete temp directory if not using -save-temps
+    // only do so after all the BitcodeTempFiles are deleted.
+    if ( !_options.saveTempFiles() ) {
+        if ( ::rmdir(tempdir) != 0 )
+            warning("temp directory cannot be removed: %s", tempdir);
+    }
+}
+
+
+
+// called by linker to write bitcode bundle into a mach-o section
+void doPass(const Options& opts, ld::Internal& internal) {
+    BitcodeBundle BB(opts, internal);
+    BB.doPass();
+}
+
+
+} // namespace bitcode_bundle
+} // namespace passes
+} // namespace ld
diff --git a/src/ld/passes/bitcode_bundle.h b/src/ld/passes/bitcode_bundle.h
new file mode 100644 (file)
index 0000000..c87a59e
--- /dev/null
@@ -0,0 +1,43 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2010 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#ifndef _BITCODE_BUNDLE_H_
+#define _BITCODE_BUNDLE_H_
+
+#include "Options.h"
+#include "ld.hpp"
+
+namespace ld {
+namespace passes {
+namespace bitcode_bundle {
+
+// called by linker to write bitcode bundle into a mach-o section
+extern void doPass(const Options& opts, ld::Internal& internal);
+
+
+} // namespace bitcode_bundle
+} // namespace passes
+} // namespace ld
+
+#endif /* defined(_BITCODE_BUNDLE_H_) */
index a8fb3252ae776479ed2d62d60df9228e3bc34336..f7465d0ac8970291d880235aa3e7f0e4f423fa4d 100644 (file)
@@ -552,7 +552,7 @@ static void makeIslandsForSection(const Options& opts, ld::Internal& state, ld::
                                if ( target->section().type() == ld::Section::typeStub )
                                        dstAddr = totalTextSize;
                                int64_t displacement = dstAddr - srcAddr;
                                if ( target->section().type() == ld::Section::typeStub )
                                        dstAddr = totalTextSize;
                                int64_t displacement = dstAddr - srcAddr;
-                               TargetAndOffset finalTargetAndOffset = { target, addend };
+                               TargetAndOffset finalTargetAndOffset = { target, (uint32_t)addend };
                                const int64_t kBranchLimit = kBetweenRegions;
                                if ( crossSectionBranch && ((displacement > kBranchLimit) || (displacement < (-kBranchLimit))) ) {
                                        const ld::Atom* island;
                                const int64_t kBranchLimit = kBetweenRegions;
                                if ( crossSectionBranch && ((displacement > kBranchLimit) || (displacement < (-kBranchLimit))) ) {
                                        const ld::Atom* island;
@@ -565,6 +565,7 @@ static void makeIslandsForSection(const Options& opts, ld::Internal& state, ld::
                                                                                                island, island->name(), displacement);
                                                ++islandCount;
                                                regionsIslands[0]->push_back(island);
                                                                                                island, island->name(), displacement);
                                                ++islandCount;
                                                regionsIslands[0]->push_back(island);
+                                               state.atomToSection[island] = textSection;
                                        }
                                        else {
                                                island = pos->second;
                                        }
                                        else {
                                                island = pos->second;
@@ -588,6 +589,7 @@ static void makeIslandsForSection(const Options& opts, ld::Internal& state, ld::
                                                                (*region)[finalTargetAndOffset] = island;
                                                                if (_s_log) fprintf(stderr, "added forward branching island %p %s to region %d for %s\n", island, island->name(), i, atom->name());
                                                                regionsIslands[i]->push_back(island);
                                                                (*region)[finalTargetAndOffset] = island;
                                                                if (_s_log) fprintf(stderr, "added forward branching island %p %s to region %d for %s\n", island, island->name(), i, atom->name());
                                                                regionsIslands[i]->push_back(island);
+                                                               state.atomToSection[island] = textSection;
                                                                ++islandCount;
                                                                nextTarget = island;
                                                        }
                                                                ++islandCount;
                                                                nextTarget = island;
                                                        }
@@ -614,6 +616,7 @@ static void makeIslandsForSection(const Options& opts, ld::Internal& state, ld::
                                                                (*region)[finalTargetAndOffset] = island;
                                                                if (_s_log) fprintf(stderr, "added back branching island %p %s to region %d for %s\n", island, island->name(), i, atom->name());
                                                                regionsIslands[i]->push_back(island);
                                                                (*region)[finalTargetAndOffset] = island;
                                                                if (_s_log) fprintf(stderr, "added back branching island %p %s to region %d for %s\n", island, island->name(), i, atom->name());
                                                                regionsIslands[i]->push_back(island);
+                                                               state.atomToSection[island] = textSection;
                                                                ++islandCount;
                                                                prevTarget = island;
                                                        }
                                                                ++islandCount;
                                                                prevTarget = island;
                                                        }
index 840a39108a674a21c00092e71ccfdb468432a01d..efc010ca639880930026aae91872923cb7b64630 100644 (file)
@@ -328,6 +328,7 @@ void doPass(const Options& opts, ld::Internal& state)
                                                                        }
                                                                        shims.push_back(shim);
                                                                        thumbToAtomMap[target] = shim;
                                                                        }
                                                                        shims.push_back(shim);
                                                                        thumbToAtomMap[target] = shim;
+                                                                       state.atomToSection[shim] = sect;
                                                                }
                                                                else {
                                                                        shim = pos->second;
                                                                }
                                                                else {
                                                                        shim = pos->second;
@@ -361,6 +362,7 @@ void doPass(const Options& opts, ld::Internal& state)
                                                                                shim = new ARMtoThumbShimAtom(target, *sect);
                                                                        shims.push_back(shim);
                                                                        atomToThumbMap[target] = shim;
                                                                                shim = new ARMtoThumbShimAtom(target, *sect);
                                                                        shims.push_back(shim);
                                                                        atomToThumbMap[target] = shim;
+                                                                       state.atomToSection[shim] = sect;
                                                                }
                                                                else {
                                                                        shim = pos->second;
                                                                }
                                                                else {
                                                                        shim = pos->second;
index af1ecf6692b22828f925e1602da767742af879e8..f77f5cd6f50753b00fd9ff6b1d3778a442cab146 100644 (file)
@@ -30,6 +30,7 @@
 #include <mach/machine.h>
 
 #include <vector>
 #include <mach/machine.h>
 
 #include <vector>
+#include <map>
 
 #include "ld.hpp"
 #include "dylibs.h"
 
 #include "ld.hpp"
 #include "dylibs.h"
index 66caf346cc9a05ed6e3035036c52b8e846ce0aa1..01c2e308ba53f0905b75a891ab0a22e7ce9b54a0 100644 (file)
@@ -44,8 +44,8 @@ class File; // forward reference
 
 class GOTEntryAtom : public ld::Atom {
 public:
 
 class GOTEntryAtom : public ld::Atom {
 public:
-                                                                                       GOTEntryAtom(ld::Internal& internal, const ld::Atom* target, bool weakImport, bool is64)
-                               : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
+                                                                                       GOTEntryAtom(ld::Internal& internal, const ld::Atom* target, bool weakImport, bool weakDef, bool is64)
+                               : ld::Atom(weakDef ? _s_sectionWeak : _s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
                                                        ld::Atom::scopeLinkageUnit, ld::Atom::typeNonLazyPointer, 
                                                        symbolTableNotIn, false, false, false, (is64 ? ld::Atom::Alignment(3) : ld::Atom::Alignment(2))),
                                _fixup(0, ld::Fixup::k1of1, (is64 ? ld::Fixup::kindStoreTargetAddressLittleEndian64 : ld::Fixup::kindStoreTargetAddressLittleEndian32), target),
                                                        ld::Atom::scopeLinkageUnit, ld::Atom::typeNonLazyPointer, 
                                                        symbolTableNotIn, false, false, false, (is64 ? ld::Atom::Alignment(3) : ld::Atom::Alignment(2))),
                                _fixup(0, ld::Fixup::k1of1, (is64 ? ld::Fixup::kindStoreTargetAddressLittleEndian64 : ld::Fixup::kindStoreTargetAddressLittleEndian32), target),
@@ -68,13 +68,16 @@ private:
        bool                                                                    _is64;
        
        static ld::Section                                              _s_section;
        bool                                                                    _is64;
        
        static ld::Section                                              _s_section;
+       static ld::Section                                              _s_sectionWeak;
 };
 
 ld::Section GOTEntryAtom::_s_section("__DATA", "__got", ld::Section::typeNonLazyPointer);
 };
 
 ld::Section GOTEntryAtom::_s_section("__DATA", "__got", ld::Section::typeNonLazyPointer);
+ld::Section GOTEntryAtom::_s_sectionWeak("__DATA", "__got_weak", ld::Section::typeNonLazyPointer);
 
 
 
 
-static bool gotFixup(const Options& opts, ld::Internal& internal, const ld::Atom* targetOfGOT, const ld::Fixup* fixup, bool* optimizable)
+static bool gotFixup(const Options& opts, ld::Internal& internal, const ld::Atom* targetOfGOT, const ld::Fixup* fixup, bool* optimizable, bool* targetIsExternalWeakDef)
 {
 {
+       *targetIsExternalWeakDef = false;
        switch (fixup->kind) {
                case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoad:
 #if SUPPORT_ARCH_arm64
        switch (fixup->kind) {
                case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoad:
 #if SUPPORT_ARCH_arm64
@@ -92,14 +95,15 @@ static bool gotFixup(const Options& opts, ld::Internal& internal, const ld::Atom
                                                                                                || (targetOfGOT->section().type() == ld::Section::typeTentativeDefs)) ) {
                                *optimizable = false;
                        }
                                                                                                || (targetOfGOT->section().type() == ld::Section::typeTentativeDefs)) ) {
                                *optimizable = false;
                        }
-                       if ( targetOfGOT->scope() == ld::Atom::scopeGlobal ) {  
+                       if ( targetOfGOT->scope() == ld::Atom::scopeGlobal ) {
                                // cannot do LEA optimization if target is weak exported symbol
                                // cannot do LEA optimization if target is weak exported symbol
-                               if ( (targetOfGOT->definition() == ld::Atom::definitionRegular) && (targetOfGOT->combine() == ld::Atom::combineByName) ) {
+                               if ( ((targetOfGOT->definition() == ld::Atom::definitionRegular) || (targetOfGOT->definition() == ld::Atom::definitionProxy)) && (targetOfGOT->combine() == ld::Atom::combineByName) ) {
                                        switch ( opts.outputKind() ) {
                                                case Options::kDynamicExecutable:
                                                case Options::kDynamicLibrary:
                                                case Options::kDynamicBundle:
                                                case Options::kKextBundle:
                                        switch ( opts.outputKind() ) {
                                                case Options::kDynamicExecutable:
                                                case Options::kDynamicLibrary:
                                                case Options::kDynamicBundle:
                                                case Options::kKextBundle:
+                                                       *targetIsExternalWeakDef = true;
                                                        *optimizable = false;
                                                        break;
                                                case Options::kStaticExecutable:
                                                        *optimizable = false;
                                                        break;
                                                case Options::kStaticExecutable:
@@ -199,6 +203,7 @@ void doPass(const Options& opts, ld::Internal& internal)
        // don't create GOT atoms during this loop because that could invalidate the sections iterator
        std::vector<const ld::Atom*> atomsReferencingGOT;
        std::map<const ld::Atom*,bool>          weakImportMap;
        // don't create GOT atoms during this loop because that could invalidate the sections iterator
        std::vector<const ld::Atom*> atomsReferencingGOT;
        std::map<const ld::Atom*,bool>          weakImportMap;
+       std::map<const ld::Atom*,bool>          weakDefMap;
        atomsReferencingGOT.reserve(128);
        for (std::vector<ld::Internal::FinalSection*>::iterator sit=internal.sections.begin(); sit != internal.sections.end(); ++sit) {
                ld::Internal::FinalSection* sect = *sit;
        atomsReferencingGOT.reserve(128);
        for (std::vector<ld::Internal::FinalSection*>::iterator sit=internal.sections.begin(); sit != internal.sections.end(); ++sit) {
                ld::Internal::FinalSection* sect = *sit;
@@ -223,7 +228,8 @@ void doPass(const Options& opts, ld::Internal& internal)
                         break;   
                                }
                                bool optimizable;
                         break;   
                                }
                                bool optimizable;
-                               if ( !gotFixup(opts, internal, targetOfGOT, fit, &optimizable) )
+                               bool targetIsExternalWeakDef;
+                               if ( !gotFixup(opts, internal, targetOfGOT, fit, &optimizable, &targetIsExternalWeakDef) )
                                        continue;
                                if ( optimizable ) {
                                        // change from load of GOT entry to lea of target
                                        continue;
                                if ( optimizable ) {
                                        // change from load of GOT entry to lea of target
@@ -264,6 +270,8 @@ void doPass(const Options& opts, ld::Internal& internal)
                                        }
                                        if ( gotMap.count(targetOfGOT) == 0 )
                                                gotMap[targetOfGOT] = NULL;
                                        }
                                        if ( gotMap.count(targetOfGOT) == 0 )
                                                gotMap[targetOfGOT] = NULL;
+                                       // record if target is weak def
+                                       weakDefMap[targetOfGOT] = targetIsExternalWeakDef;
                                        // record weak_import attribute
                                        std::map<const ld::Atom*,bool>::iterator pos = weakImportMap.find(targetOfGOT);
                                        if ( pos == weakImportMap.end() ) {
                                        // record weak_import attribute
                                        std::map<const ld::Atom*,bool>::iterator pos = weakImportMap.find(targetOfGOT);
                                        if ( pos == weakImportMap.end() ) {
@@ -319,7 +327,7 @@ void doPass(const Options& opts, ld::Internal& internal)
        // make GOT entries
        for (auto& entry : gotMap) {
                if ( entry.second == NULL ) {
        // make GOT entries
        for (auto& entry : gotMap) {
                if ( entry.second == NULL ) {
-                       entry.second = new GOTEntryAtom(internal, entry.first, weakImportMap[entry.first], is64);
+                       entry.second = new GOTEntryAtom(internal, entry.first, weakImportMap[entry.first], opts.useDataConstSegment() && weakDefMap[entry.first], is64);
                        if (log) fprintf(stderr, "making new GOT slot for %s, gotMap[%p] = %p\n", entry.first->name(), entry.first, entry.second);
                }
        }
                        if (log) fprintf(stderr, "making new GOT slot for %s, gotMap[%p] = %p\n", entry.first->name(), entry.first, entry.second);
                }
        }
@@ -348,7 +356,8 @@ void doPass(const Options& opts, ld::Internal& internal)
                     break;    
                        }
                        bool optimizable;
                     break;    
                        }
                        bool optimizable;
-                       if ( (targetOfGOT == NULL) || !gotFixup(opts, internal, targetOfGOT, fit, &optimizable) )
+                       bool targetIsExternalWeakDef;
+                       if ( (targetOfGOT == NULL) || !gotFixup(opts, internal, targetOfGOT, fit, &optimizable, &targetIsExternalWeakDef) )
                                continue;
                        if ( !optimizable ) {
                                // GOT use not optimized away, update to bind to GOT entry
                                continue;
                        if ( !optimizable ) {
                                // GOT use not optimized away, update to bind to GOT entry
index 51dda805dad9d9e938c9b7918ddee09365327466..693976cef69b27c15a3b60e6944b62cf3d5a75d7 100644 (file)
@@ -30,6 +30,7 @@
 #include <mach/machine.h>
 
 #include <vector>
 #include <mach/machine.h>
 
 #include <vector>
+#include <map>
 
 #include "ld.hpp"
 #include "huge.h"
 
 #include "ld.hpp"
 #include "huge.h"
@@ -94,6 +95,7 @@ void doPass(const Options& opts, ld::Internal& state)
                                const ld::Atom* atom = *ait;
                                if ( atom->size() > 1024*1024 ) {
                                        hugeSection->atoms.push_back(atom);
                                const ld::Atom* atom = *ait;
                                if ( atom->size() > 1024*1024 ) {
                                        hugeSection->atoms.push_back(atom);
+                                       state.atomToSection[atom] = hugeSection;
                                        if (log) fprintf(stderr, "moved to __huge: %s, size=%llu\n", atom->name(), atom->size());
                                        *ait = NULL;  // change atom to NULL for later bulk removal
                                        movedSome = true;
                                        if (log) fprintf(stderr, "moved to __huge: %s, size=%llu\n", atom->name(), atom->size());
                                        *ait = NULL;  // change atom to NULL for later bulk removal
                                        movedSome = true;
index 2bbf54a61ead25d474a8c83fcf25e5b671d59b61..ad4673cf564f94e764e7612c3adc5d67374cde13 100644 (file)
@@ -805,7 +805,7 @@ void OptimizeCategories<A>::doit(const Options& opts, ld::Internal& state)
        std::set<const ld::Atom*> nlcatListAtoms;
        for (std::vector<ld::Internal::FinalSection*>::iterator sit=state.sections.begin(); sit != state.sections.end(); ++sit) {
                ld::Internal::FinalSection* sect = *sit;
        std::set<const ld::Atom*> nlcatListAtoms;
        for (std::vector<ld::Internal::FinalSection*>::iterator sit=state.sections.begin(); sit != state.sections.end(); ++sit) {
                ld::Internal::FinalSection* sect = *sit;
-               if ( (strcmp(sect->sectionName(), "__objc_nlcatlist") == 0) && (strcmp(sect->segmentName(), "__DATA") == 0) ) {
+               if ( (strcmp(sect->sectionName(), "__objc_nlcatlist") == 0) && (strncmp(sect->segmentName(), "__DATA", 6) == 0) ) {
                        for (std::vector<const ld::Atom*>::iterator ait=sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
                                const ld::Atom* categoryListElementAtom = *ait;
                                for (unsigned int offset=0; offset < categoryListElementAtom->size(); offset += sizeof(pint_t)) {
                        for (std::vector<const ld::Atom*>::iterator ait=sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
                                const ld::Atom* categoryListElementAtom = *ait;
                                for (unsigned int offset=0; offset < categoryListElementAtom->size(); offset += sizeof(pint_t)) {
@@ -865,7 +865,7 @@ void OptimizeCategories<A>::doit(const Options& opts, ld::Internal& state)
                        }
                }
                // record method list section
                        }
                }
                // record method list section
-               if ( (strcmp(sect->sectionName(), "__objc_const") == 0) && (strcmp(sect->segmentName(), "__DATA") == 0) )
+               if ( (strcmp(sect->sectionName(), "__objc_const") == 0) && (strncmp(sect->segmentName(), "__DATA", 6) == 0) )
                        methodListSection = sect;
        }
 
                        methodListSection = sect;
        }
 
@@ -885,9 +885,11 @@ void OptimizeCategories<A>::doit(const Options& opts, ld::Internal& state)
                                const ld::Atom* newClassRO = Class<A>::setInstanceMethodList(state, classAtom, newInstanceMethodListAtom, deadAtoms);
                                // add new method list to final sections
                                methodListSection->atoms.push_back(newInstanceMethodListAtom);
                                const ld::Atom* newClassRO = Class<A>::setInstanceMethodList(state, classAtom, newInstanceMethodListAtom, deadAtoms);
                                // add new method list to final sections
                                methodListSection->atoms.push_back(newInstanceMethodListAtom);
+                               state.atomToSection[newInstanceMethodListAtom] = methodListSection;
                                if ( newClassRO != NULL ) {
                                        assert(strcmp(newClassRO->section().sectionName(), "__objc_const") == 0);
                                        methodListSection->atoms.push_back(newClassRO);
                                if ( newClassRO != NULL ) {
                                        assert(strcmp(newClassRO->section().sectionName(), "__objc_const") == 0);
                                        methodListSection->atoms.push_back(newClassRO);
+                                       state.atomToSection[newClassRO] = methodListSection;
                                }
                        }
                        // if any category adds class methods, generate new merged method list, and replace
                                }
                        }
                        // if any category adds class methods, generate new merged method list, and replace
@@ -897,9 +899,11 @@ void OptimizeCategories<A>::doit(const Options& opts, ld::Internal& state)
                                const ld::Atom* newClassRO = Class<A>::setClassMethodList(state, classAtom, newClassMethodListAtom, deadAtoms);
                                // add new method list to final sections
                                methodListSection->atoms.push_back(newClassMethodListAtom);
                                const ld::Atom* newClassRO = Class<A>::setClassMethodList(state, classAtom, newClassMethodListAtom, deadAtoms);
                                // add new method list to final sections
                                methodListSection->atoms.push_back(newClassMethodListAtom);
+                               state.atomToSection[newClassMethodListAtom] = methodListSection;
                                if ( newClassRO != NULL ) {
                                        assert(strcmp(newClassRO->section().sectionName(), "__objc_const") == 0);
                                        methodListSection->atoms.push_back(newClassRO);
                                if ( newClassRO != NULL ) {
                                        assert(strcmp(newClassRO->section().sectionName(), "__objc_const") == 0);
                                        methodListSection->atoms.push_back(newClassRO);
+                                       state.atomToSection[newClassRO] = methodListSection;
                                }
                        }
                        // if any category adds protocols, generate new merged protocol list, and replace
                                }
                        }
                        // if any category adds protocols, generate new merged protocol list, and replace
@@ -910,13 +914,16 @@ void OptimizeCategories<A>::doit(const Options& opts, ld::Internal& state)
                                const ld::Atom* newMetaClassRO = Class<A>::setClassProtocolList(state, classAtom, newProtocolListAtom, deadAtoms);
                                // add new protocol list to final sections
                                methodListSection->atoms.push_back(newProtocolListAtom);
                                const ld::Atom* newMetaClassRO = Class<A>::setClassProtocolList(state, classAtom, newProtocolListAtom, deadAtoms);
                                // add new protocol list to final sections
                                methodListSection->atoms.push_back(newProtocolListAtom);
+                               state.atomToSection[newProtocolListAtom] = methodListSection;
                                if ( newClassRO != NULL ) {
                                        assert(strcmp(newClassRO->section().sectionName(), "__objc_const") == 0);
                                        methodListSection->atoms.push_back(newClassRO);
                                if ( newClassRO != NULL ) {
                                        assert(strcmp(newClassRO->section().sectionName(), "__objc_const") == 0);
                                        methodListSection->atoms.push_back(newClassRO);
+                                       state.atomToSection[newClassRO] = methodListSection;
                                }
                                if ( newMetaClassRO != NULL ) {
                                        assert(strcmp(newMetaClassRO->section().sectionName(), "__objc_const") == 0);
                                        methodListSection->atoms.push_back(newMetaClassRO);
                                }
                                if ( newMetaClassRO != NULL ) {
                                        assert(strcmp(newMetaClassRO->section().sectionName(), "__objc_const") == 0);
                                        methodListSection->atoms.push_back(newMetaClassRO);
+                                       state.atomToSection[newMetaClassRO] = methodListSection;
                                }
                        }
                        // if any category adds properties, generate new merged property list, and replace
                                }
                        }
                        // if any category adds properties, generate new merged property list, and replace
@@ -926,9 +933,11 @@ void OptimizeCategories<A>::doit(const Options& opts, ld::Internal& state)
                                const ld::Atom* newClassRO = Class<A>::setInstancePropertyList(state, classAtom, newPropertyListAtom, deadAtoms);
                                // add new property list to final sections
                                methodListSection->atoms.push_back(newPropertyListAtom);
                                const ld::Atom* newClassRO = Class<A>::setInstancePropertyList(state, classAtom, newPropertyListAtom, deadAtoms);
                                // add new property list to final sections
                                methodListSection->atoms.push_back(newPropertyListAtom);
+                               state.atomToSection[newPropertyListAtom] = methodListSection;
                                if ( newClassRO != NULL ) {
                                        assert(strcmp(newClassRO->section().sectionName(), "__objc_const") == 0);
                                        methodListSection->atoms.push_back(newClassRO);
                                if ( newClassRO != NULL ) {
                                        assert(strcmp(newClassRO->section().sectionName(), "__objc_const") == 0);
                                        methodListSection->atoms.push_back(newClassRO);
+                                       state.atomToSection[newClassRO] = methodListSection;
                                }
                        }
                 
                                }
                        }
                 
index 139e761d08cf57f8fccffbf8b3d1a8fa3047e335..a7d31f31618a77f910a4b67f416b3d6a18e0f0dd 100644 (file)
@@ -510,8 +510,14 @@ void Layout::buildOrdinalOverrideMap()
                        switch ( atom->section().type() ) {
                                case ld::Section::typeZeroFill:
                                case ld::Section::typeTentativeDefs:
                        switch ( atom->section().type() ) {
                                case ld::Section::typeZeroFill:
                                case ld::Section::typeTentativeDefs:
-                                       if ( atom->size() <= 512 ) 
-                                               moveToData.insert(atom);
+                                       if ( atom->size() <= 512 ) {
+                                               const char* dstSeg;
+                                               bool wildCardMatch;
+                                               const ld::File* f = atom->file();
+                                               const char* path = (f != NULL) ? f->path() : NULL;
+                                               if ( !_options.moveRwSymbol(atom->name(), path, dstSeg, wildCardMatch) )
+                                                       moveToData.insert(atom);
+                                       }
                                        break;
                                default:
                                        break;
                                        break;
                                default:
                                        break;
@@ -579,6 +585,10 @@ void Layout::buildOrdinalOverrideMap()
                                                break;
                                }
                        }
                                                break;
                                }
                        }
+                       // update atom-to-section map
+                       for (std::set<const ld::Atom*>::iterator it=moveToData.begin(); it != moveToData.end(); ++it) {
+                               _state.atomToSection[*it] = dataSect;
+                       }
                }
        }
 
                }
        }
 
index 5c8fc42f5d125f6f8cc2b7f552cdaf6b1ab8dd70..02ae454502d3eba954ea48b630a67d8cc4fb3872 100644 (file)
@@ -234,8 +234,9 @@ class LazyPointerAtom : public ld::Atom {
 public:
                                                                                        LazyPointerAtom(ld::passes::stubs::Pass& pass, const ld::Atom& stubTo,
                                                                                                                        bool stubToGlobalWeakDef, bool stubToResolver, 
 public:
                                                                                        LazyPointerAtom(ld::passes::stubs::Pass& pass, const ld::Atom& stubTo,
                                                                                                                        bool stubToGlobalWeakDef, bool stubToResolver, 
-                                                                                                                       bool weakImport, bool close)
-                               : ld::Atom(close ? _s_sectionClose : _s_section, ld::Atom::definitionRegular, 
+                                                                                                                       bool weakImport, bool close, bool usingDataConst)
+                               : ld::Atom(selectSection(close, stubToGlobalWeakDef, stubToResolver, usingDataConst),
+                                                       ld::Atom::definitionRegular,
                                                        ld::Atom::combineNever, ld::Atom::scopeLinkageUnit, ld::Atom::typeLazyPointer, 
                                                        symbolTableNotIn, false, false, false, ld::Atom::Alignment(2)), 
                                _stubTo(stubTo),
                                                        ld::Atom::combineNever, ld::Atom::scopeLinkageUnit, ld::Atom::typeLazyPointer, 
                                                        symbolTableNotIn, false, false, false, ld::Atom::Alignment(2)), 
                                _stubTo(stubTo),
@@ -243,7 +244,7 @@ public:
                                _resolverHelper(pass, stubTo, this),
                                _fixup1(0, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressLittleEndian32, 
                                                                stubToResolver ? &_resolverHelper : (stubToGlobalWeakDef ?  &stubTo : &_helper)),
                                _resolverHelper(pass, stubTo, this),
                                _fixup1(0, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressLittleEndian32, 
                                                                stubToResolver ? &_resolverHelper : (stubToGlobalWeakDef ?  &stubTo : &_helper)),
-                               _fixup2(0, ld::Fixup::k1of1, ld::Fixup::kindLazyTarget, &stubTo) { 
+                               _fixup2(0, ld::Fixup::k1of1, ld::Fixup::kindLazyTarget, &stubTo) {
                                                _fixup2.weakImport = weakImport; pass.addAtom(*this); 
                                                if ( stubToResolver )
                                                        pass.addAtom(_resolverHelper);
                                                _fixup2.weakImport = weakImport; pass.addAtom(*this); 
                                                if ( stubToResolver )
                                                        pass.addAtom(_resolverHelper);
@@ -261,6 +262,17 @@ public:
        virtual ld::Fixup::iterator                             fixupsEnd()     const                           { return &((ld::Fixup*)&_fixup2)[1]; }
 
 private:
        virtual ld::Fixup::iterator                             fixupsEnd()     const                           { return &((ld::Fixup*)&_fixup2)[1]; }
 
 private:
+       static ld::Section& selectSection(bool close, bool stubToGlobalWeakDef, bool stubToResolver, bool usingDataConst) {
+               if ( close )
+                       return _s_sectionClose;
+               else if ( stubToGlobalWeakDef && usingDataConst )
+                       return _s_sectionWeak;
+               else if ( stubToResolver && usingDataConst )
+                       return _s_sectionResolver;
+               else
+                       return _s_section;
+       }
+
        const ld::Atom&                                                 _stubTo;
        StubHelperAtom                                                  _helper;
        ResolverHelperAtom                                              _resolverHelper;
        const ld::Atom&                                                 _stubTo;
        StubHelperAtom                                                  _helper;
        ResolverHelperAtom                                              _resolverHelper;
@@ -269,10 +281,14 @@ private:
        
        static ld::Section                                              _s_section;
        static ld::Section                                              _s_sectionClose;
        
        static ld::Section                                              _s_section;
        static ld::Section                                              _s_sectionClose;
+       static ld::Section                                              _s_sectionResolver;
+       static ld::Section                                              _s_sectionWeak;
 };
 
 ld::Section LazyPointerAtom::_s_section("__DATA", "__la_symbol_ptr", ld::Section::typeLazyPointer);
 ld::Section LazyPointerAtom::_s_sectionClose("__DATA", "__lazy_symbol", ld::Section::typeLazyPointerClose);
 };
 
 ld::Section LazyPointerAtom::_s_section("__DATA", "__la_symbol_ptr", ld::Section::typeLazyPointer);
 ld::Section LazyPointerAtom::_s_sectionClose("__DATA", "__lazy_symbol", ld::Section::typeLazyPointerClose);
+ld::Section LazyPointerAtom::_s_sectionResolver("__DATA_DIRTY", "__la_resolver", ld::Section::typeLazyPointer);
+ld::Section LazyPointerAtom::_s_sectionWeak("__DATA", "__la_weak_ptr", ld::Section::typeLazyPointer);
 
 
 class NonLazyPointerAtom : public ld::Atom {
 
 
 class NonLazyPointerAtom : public ld::Atom {
@@ -364,12 +380,12 @@ ld::Section StubPICKextAtom::_s_section("__TEXT", "__stub", ld::Section::typeCod
 class StubPICAtom : public ld::Atom {
 public:
                                                                                        StubPICAtom(ld::passes::stubs::Pass& pass, const ld::Atom& stubTo,
 class StubPICAtom : public ld::Atom {
 public:
                                                                                        StubPICAtom(ld::passes::stubs::Pass& pass, const ld::Atom& stubTo,
-                                                                                                               bool stubToGlobalWeakDef, bool stubToResolver, bool weakImport)
+                                                                                                               bool stubToGlobalWeakDef, bool stubToResolver, bool weakImport, bool usingDataConst)
                                : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
                                                        ld::Atom::scopeLinkageUnit, ld::Atom::typeStub, 
                                                        symbolTableNotIn, false, false, false, ld::Atom::Alignment(2)), 
                                _stubTo(stubTo), 
                                : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
                                                        ld::Atom::scopeLinkageUnit, ld::Atom::typeStub, 
                                                        symbolTableNotIn, false, false, false, ld::Atom::Alignment(2)), 
                                _stubTo(stubTo), 
-                               _lazyPointer(pass, stubTo, stubToGlobalWeakDef, stubToResolver, weakImport, false),
+                               _lazyPointer(pass, stubTo, stubToGlobalWeakDef, stubToResolver, weakImport, false, usingDataConst),
                                _fixup1(12, ld::Fixup::k1of4, ld::Fixup::kindSetTargetAddress, &_lazyPointer),
                                _fixup2(12, ld::Fixup::k2of4, ld::Fixup::kindSubtractTargetAddress, this),
                                _fixup3(12, ld::Fixup::k3of4, ld::Fixup::kindSubtractAddend, 12),
                                _fixup1(12, ld::Fixup::k1of4, ld::Fixup::kindSetTargetAddress, &_lazyPointer),
                                _fixup2(12, ld::Fixup::k2of4, ld::Fixup::kindSubtractTargetAddress, this),
                                _fixup3(12, ld::Fixup::k3of4, ld::Fixup::kindSubtractAddend, 12),
@@ -413,7 +429,7 @@ public:
                                                        ld::Atom::scopeLinkageUnit, ld::Atom::typeStub, 
                                                        symbolTableNotIn, false, false, false, ld::Atom::Alignment(2)), 
                                _stubTo(stubTo), 
                                                        ld::Atom::scopeLinkageUnit, ld::Atom::typeStub, 
                                                        symbolTableNotIn, false, false, false, ld::Atom::Alignment(2)), 
                                _stubTo(stubTo), 
-                               _lazyPointer(pass, stubTo, stubToGlobalWeakDef, stubToResolver, weakImport, false),
+                               _lazyPointer(pass, stubTo, stubToGlobalWeakDef, stubToResolver, weakImport, false, false),
                                _fixup(8, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressLittleEndian32, &_lazyPointer) 
                                        { pass.addAtom(*this); }
 
                                _fixup(8, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressLittleEndian32, &_lazyPointer) 
                                        { pass.addAtom(*this); }
 
@@ -451,7 +467,7 @@ public:
                                                        ld::Atom::scopeLinkageUnit, ld::Atom::typeStub, 
                                                        symbolTableNotIn, false, false, false, ld::Atom::Alignment(2)), 
                                _stubTo(stubTo), 
                                                        ld::Atom::scopeLinkageUnit, ld::Atom::typeStub, 
                                                        symbolTableNotIn, false, false, false, ld::Atom::Alignment(2)), 
                                _stubTo(stubTo), 
-                               _lazyPointer(pass, stubTo, stubToGlobalWeakDef, stubToResolver, weakImport, true),
+                               _lazyPointer(pass, stubTo, stubToGlobalWeakDef, stubToResolver, weakImport, true, false),
                                _fixup(0, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressARMLoad12, &_lazyPointer) 
                                { pass.addAtom(*this); }
 
                                _fixup(0, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressARMLoad12, &_lazyPointer) 
                                { pass.addAtom(*this); }
 
index 63382e58fa9022c6e7ad53e7839da1135e6ff67a..09de1fa108cea34a52c534dac24bdebaa44f2480 100644 (file)
@@ -241,8 +241,9 @@ ld::Section                                         ResolverHelperAtom::_s_section("__TEXT", "__stub_helper", ld::S
 class LazyPointerAtom : public ld::Atom {
 public:
                                                                                        LazyPointerAtom(ld::passes::stubs::Pass& pass, const ld::Atom& stubTo,
 class LazyPointerAtom : public ld::Atom {
 public:
                                                                                        LazyPointerAtom(ld::passes::stubs::Pass& pass, const ld::Atom& stubTo,
-                                                                                                                       bool stubToGlobalWeakDef, bool stubToResolver, bool weakImport)
-                               : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
+                                                                                                                       bool stubToGlobalWeakDef, bool stubToResolver, bool weakImport, bool dataConstUsed)
+                               : ld::Atom(selectSection(stubToGlobalWeakDef, stubToResolver, dataConstUsed),
+                                                       ld::Atom::definitionRegular, ld::Atom::combineNever,
                                                        ld::Atom::scopeTranslationUnit, ld::Atom::typeLazyPointer, 
                                                        symbolTableNotIn, false, false, false, ld::Atom::Alignment(3)), 
                                _stubTo(stubTo),
                                                        ld::Atom::scopeTranslationUnit, ld::Atom::typeLazyPointer, 
                                                        symbolTableNotIn, false, false, false, ld::Atom::Alignment(3)), 
                                _stubTo(stubTo),
@@ -269,6 +270,15 @@ public:
        virtual ld::Fixup::iterator                             fixupsEnd()     const                           { return &((ld::Fixup*)&_fixup2)[1]; }
 
 private:
        virtual ld::Fixup::iterator                             fixupsEnd()     const                           { return &((ld::Fixup*)&_fixup2)[1]; }
 
 private:
+       static ld::Section& selectSection(bool stubToGlobalWeakDef, bool stubToResolver, bool dataConstUsed) {
+               if ( stubToGlobalWeakDef && dataConstUsed )
+                       return _s_sectionWeak;
+               else if ( stubToResolver && dataConstUsed )
+                       return _s_sectionResolver;
+               else
+                       return _s_section;
+       }
+
        const ld::Atom&                                                 _stubTo;
        StubHelperAtom                                                  _helper;
        ResolverHelperAtom                                              _resolverHelper;
        const ld::Atom&                                                 _stubTo;
        StubHelperAtom                                                  _helper;
        ResolverHelperAtom                                              _resolverHelper;
@@ -276,20 +286,24 @@ private:
        ld::Fixup                                                               _fixup2;
        
        static ld::Section                                              _s_section;
        ld::Fixup                                                               _fixup2;
        
        static ld::Section                                              _s_section;
+       static ld::Section                                              _s_sectionResolver;
+       static ld::Section                                              _s_sectionWeak;
 };
 
 ld::Section LazyPointerAtom::_s_section("__DATA", "__la_symbol_ptr", ld::Section::typeLazyPointer);
 };
 
 ld::Section LazyPointerAtom::_s_section("__DATA", "__la_symbol_ptr", ld::Section::typeLazyPointer);
+ld::Section LazyPointerAtom::_s_sectionResolver("__DATA_DIRTY", "__la_resolver", ld::Section::typeLazyPointer);
+ld::Section LazyPointerAtom::_s_sectionWeak("__DATA", "__la_weak_ptr", ld::Section::typeLazyPointer);
 
 
 class StubAtom : public ld::Atom {
 public:
                                                                                        StubAtom(ld::passes::stubs::Pass& pass, const ld::Atom& stubTo,
 
 
 class StubAtom : public ld::Atom {
 public:
                                                                                        StubAtom(ld::passes::stubs::Pass& pass, const ld::Atom& stubTo,
-                                                                                                       bool stubToGlobalWeakDef, bool stubToResolver, bool weakImport)
+                                                                                                       bool stubToGlobalWeakDef, bool stubToResolver, bool weakImport, bool dataConstUsed)
                                : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
                                                        ld::Atom::scopeLinkageUnit, ld::Atom::typeStub, 
                                                        symbolTableNotIn, false, false, false, ld::Atom::Alignment(1)), 
                                _stubTo(stubTo), 
                                : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
                                                        ld::Atom::scopeLinkageUnit, ld::Atom::typeStub, 
                                                        symbolTableNotIn, false, false, false, ld::Atom::Alignment(1)), 
                                _stubTo(stubTo), 
-                               _lazyPointer(pass, stubTo, stubToGlobalWeakDef, stubToResolver, weakImport),
+                               _lazyPointer(pass, stubTo, stubToGlobalWeakDef, stubToResolver, weakImport, dataConstUsed),
                                _fixup1(0, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressARM64Page21, &_lazyPointer),
                                _fixup2(4, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressARM64PageOff12, &_lazyPointer),
                                _fixup3(ld::Fixup::kindLinkerOptimizationHint, LOH_ARM64_ADRP_LDR, 0, 4) 
                                _fixup1(0, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressARM64Page21, &_lazyPointer),
                                _fixup2(4, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressARM64PageOff12, &_lazyPointer),
                                _fixup3(ld::Fixup::kindLinkerOptimizationHint, LOH_ARM64_ADRP_LDR, 0, 4) 
index c01f3f9cc86adebc28a1eabdd7bf1181d75c4c33..bee5f2f67c4f3f2432c4c4a8b8eb91a7525818e3 100644 (file)
@@ -164,16 +164,17 @@ const ld::Atom* Pass::stubableFixup(const ld::Fixup* fixup, ld::Internal& state)
 
 ld::Atom* Pass::makeStub(const ld::Atom& target, bool weakImport)
 {
 
 ld::Atom* Pass::makeStub(const ld::Atom& target, bool weakImport)
 {
-       //fprintf(stderr, "makeStub(target=%p %s in sect %s)\n", &target, target.name(), target.section().sectionName());
-       bool stubToGlobalWeakDef = ( (target.scope() == ld::Atom::scopeGlobal)
-                                                               && (target.definition() == ld::Atom::definitionRegular) 
-                                                               && (target.combine() == ld::Atom::combineByName) );
+       //fprintf(stderr, "makeStub(target=%p %s in sect %s, def=%d)\n", &target, target.name(), target.section().sectionName(), target.definition());
+       bool stubToGlobalWeakDef = ( (target.combine() == ld::Atom::combineByName) &&
+                                                                (((target.definition() == ld::Atom::definitionRegular) && (target.scope() == ld::Atom::scopeGlobal))
+                                                                 || (target.definition() == ld::Atom::definitionProxy)) );
 
        bool forLazyDylib = false;
        const ld::dylib::File* dylib = dynamic_cast<const ld::dylib::File*>(target.file());
        if ( (dylib != NULL) && dylib->willBeLazyLoadedDylib() ) 
                forLazyDylib = true;
        bool stubToResolver = (target.contentType() == ld::Atom::typeResolver);
 
        bool forLazyDylib = false;
        const ld::dylib::File* dylib = dynamic_cast<const ld::dylib::File*>(target.file());
        if ( (dylib != NULL) && dylib->willBeLazyLoadedDylib() ) 
                forLazyDylib = true;
        bool stubToResolver = (target.contentType() == ld::Atom::typeResolver);
+       bool usingDataConst =  _options.useDataConstSegment();
        
        if ( usingCompressedLINKEDIT() && !forLazyDylib ) {
                if ( _internal->compressedFastBinderProxy == NULL )
        
        if ( usingCompressedLINKEDIT() && !forLazyDylib ) {
                if ( _internal->compressedFastBinderProxy == NULL )
@@ -209,7 +210,7 @@ ld::Atom* Pass::makeStub(const ld::Atom& target, bool weakImport)
                                if ( (_stubCount < 900) && !_mightBeInSharedRegion && !_largeText )
                                        return new ld::passes::stubs::arm::StubCloseAtom(*this, target, stubToGlobalWeakDef, stubToResolver, weakImport);
                                else if ( _pic )
                                if ( (_stubCount < 900) && !_mightBeInSharedRegion && !_largeText )
                                        return new ld::passes::stubs::arm::StubCloseAtom(*this, target, stubToGlobalWeakDef, stubToResolver, weakImport);
                                else if ( _pic )
-                                       return new ld::passes::stubs::arm::StubPICAtom(*this, target, stubToGlobalWeakDef, stubToResolver, weakImport);
+                                       return new ld::passes::stubs::arm::StubPICAtom(*this, target, stubToGlobalWeakDef, stubToResolver, weakImport, usingDataConst);
                                else
                                        return new ld::passes::stubs::arm::StubNoPICAtom(*this, target, stubToGlobalWeakDef, stubToResolver, weakImport);
                        } 
                                else
                                        return new ld::passes::stubs::arm::StubNoPICAtom(*this, target, stubToGlobalWeakDef, stubToResolver, weakImport);
                        } 
@@ -226,7 +227,7 @@ ld::Atom* Pass::makeStub(const ld::Atom& target, bool weakImport)
                        if ( (_options.outputKind() == Options::kKextBundle) && _options.kextsUseStubs() ) 
                                return new ld::passes::stubs::arm64::KextStubAtom(*this, target);
                        else
                        if ( (_options.outputKind() == Options::kKextBundle) && _options.kextsUseStubs() ) 
                                return new ld::passes::stubs::arm64::KextStubAtom(*this, target);
                        else
-                               return new ld::passes::stubs::arm64::StubAtom(*this, target, stubToGlobalWeakDef, stubToResolver, weakImport);
+                               return new ld::passes::stubs::arm64::StubAtom(*this, target, stubToGlobalWeakDef, stubToResolver, weakImport, usingDataConst);
                        break;
 #endif
        }
                        break;
 #endif
        }
index e84fc25b8f710c09db737cdc517a13339a6607ed..aec956271d3aa074ab1af8ab719ea296c22061f5 100644 (file)
@@ -48,7 +48,7 @@ public:
                                                        symbolTableNotIn, false, false, false, ld::Atom::Alignment(3)), 
                                _fixup(0, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressLittleEndian64, target),
                                _target(target)
                                                        symbolTableNotIn, false, false, false, ld::Atom::Alignment(3)), 
                                _fixup(0, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressLittleEndian64, target),
                                _target(target)
-                                       { _fixup.weakImport = weakImport; internal.addAtom(*this); }
+                                       {       _fixup.weakImport = weakImport; internal.addAtom(*this); }
 
        virtual const ld::File*                                 file() const                                    { return NULL; }
        virtual const char*                                             name() const                                    { return _target->name(); }
 
        virtual const ld::File*                                 file() const                                    { return NULL; }
        virtual const char*                                             name() const                                    { return _target->name(); }
@@ -236,7 +236,7 @@ void doPass(const Options& opts, ld::Internal& internal)
                                        break;
 #if SUPPORT_ARCH_arm64
                                case ld::Fixup::kindStoreTargetAddressARM64TLVPLoadPage21:
                                        break;
 #if SUPPORT_ARCH_arm64
                                case ld::Fixup::kindStoreTargetAddressARM64TLVPLoadPage21:
-                                       it->fixupWithTLVStore->kind = ld::Fixup::kindStoreARM64TLVPLoadNowLeaPage21;
+                                       it->fixupWithTLVStore->kind = ld::Fixup::kindStoreTargetAddressARM64TLVPLoadNowLeaPage21;
                                        break;
                                case ld::Fixup::kindStoreTargetAddressARM64TLVPLoadPageOff12:
                                        it->fixupWithTLVStore->kind = ld::Fixup::kindStoreTargetAddressARM64TLVPLoadNowLeaPageOff12;
                                        break;
                                case ld::Fixup::kindStoreTargetAddressARM64TLVPLoadPageOff12:
                                        it->fixupWithTLVStore->kind = ld::Fixup::kindStoreTargetAddressARM64TLVPLoadNowLeaPageOff12;
@@ -265,6 +265,9 @@ void doPass(const Options& opts, ld::Internal& internal)
                        continue;
                for (std::vector<const ld::Atom*>::iterator ait=sect->atoms.begin();  ait != sect->atoms.end(); ++ait) {
                        const ld::Atom* atom = *ait;
                        continue;
                for (std::vector<const ld::Atom*>::iterator ait=sect->atoms.begin();  ait != sect->atoms.end(); ++ait) {
                        const ld::Atom* atom = *ait;
+                       if ( ! opts.canUseThreadLocalVariables() ) {
+                               throwf("targeted OS version does not support use of thread local variables in %s", atom->name());
+                       }
                        for (ld::Fixup::iterator fit = atom->fixupsBegin(), end=atom->fixupsEnd(); fit != end; ++fit) {
                                if ( fit->offsetInAtom != 0 ) {
                                        assert(fit->binding == ld::Fixup::bindingDirectlyBound && "thread variable def contains pointer to global");
                        for (ld::Fixup::iterator fit = atom->fixupsBegin(), end=atom->fixupsEnd(); fit != end; ++fit) {
                                if ( fit->offsetInAtom != 0 ) {
                                        assert(fit->binding == ld::Fixup::bindingDirectlyBound && "thread variable def contains pointer to global");
index ceab63c552264b13ac68a76b78026da1731e11aa..dfadf71d518ba37760a34d9708ad2de3d912ec3a 100644 (file)
@@ -1244,11 +1244,13 @@ static ld::relocatable::File* createReader(const char* path)
        objOpts.verboseOptimizationHints = true;
        objOpts.armUsesZeroCostExceptions = true;
        objOpts.subType                         = sPreferredSubArch;
        objOpts.verboseOptimizationHints = true;
        objOpts.armUsesZeroCostExceptions = true;
        objOpts.subType                         = sPreferredSubArch;
+       objOpts.srcKind                         = ld::relocatable::File::kSourceObj;
 #if 1
        if ( ! foundFatSlice ) {
                cpu_type_t archOfObj;
                cpu_subtype_t subArchOfObj;
 #if 1
        if ( ! foundFatSlice ) {
                cpu_type_t archOfObj;
                cpu_subtype_t subArchOfObj;
-               if ( mach_o::relocatable::isObjectFile(p, &archOfObj, &subArchOfObj) ) {
+               Options::Platform platform;
+               if ( mach_o::relocatable::isObjectFile(p, &archOfObj, &subArchOfObj, &platform) ) {
                        objOpts.architecture = archOfObj;
                        objOpts.subType = subArchOfObj;
                }
                        objOpts.architecture = archOfObj;
                        objOpts.subType = subArchOfObj;
                }
index 6ac33119a0240262fce67521747a6fca0b06d3b0..f19538f1533ef31385a1fedb4d1cf0036493efa5 100644 (file)
@@ -104,12 +104,19 @@ private:
        void                                                                            printClassicLazyBindingInfo();
        void                                                                            printClassicBindingInfo();
        void                                                                            printSharedRegionInfo();
        void                                                                            printClassicLazyBindingInfo();
        void                                                                            printClassicBindingInfo();
        void                                                                            printSharedRegionInfo();
+       const char*                                                                     sharedRegionKindName(uint8_t kind);
        void                                                                            printFunctionStartsInfo();
        void                                                                            printDylibsInfo();
        void                                                                            printDRInfo();
        void                                                                            printDataInCode();
        void                                                                            printFunctionStartLine(uint64_t addr);
        void                                                                            printFunctionStartsInfo();
        void                                                                            printDylibsInfo();
        void                                                                            printDRInfo();
        void                                                                            printDataInCode();
        void                                                                            printFunctionStartLine(uint64_t addr);
-       const uint8_t*                                                          printSharedRegionInfoForEachULEB128Address(const uint8_t* p, uint8_t kind);
+       const uint8_t*                                                          printSharedRegionV1InfoForEachULEB128Address(const uint8_t* p, const uint8_t* end, uint8_t kind);
+       const uint8_t*                                                          printSharedRegionV2InfoForEachULEB128Address(const uint8_t* p, const uint8_t* end);
+       const uint8_t*                                                          printSharedRegionV2InfoForEachULEB128AddressAndAdj(const uint8_t* p, const uint8_t* end);
+       const uint8_t*                                                          printSharedRegionV2SectionPair(const uint8_t* p, const uint8_t* end);
+       const uint8_t*                                                          printSharedRegionV2ToSectionOffset(const uint8_t* p, const uint8_t* end);
+       const uint8_t*                                                          printSharedRegionV2Kind(const uint8_t* p, const uint8_t* end);
+
        pint_t                                                                          relocBase();
        const char*                                                                     relocTypeName(uint8_t r_type);
        uint8_t                                                                         segmentIndexForAddress(pint_t addr);
        pint_t                                                                          relocBase();
        const char*                                                                     relocTypeName(uint8_t r_type);
        uint8_t                                                                         segmentIndexForAddress(pint_t addr);
@@ -129,6 +136,7 @@ private:
        const char*                                                                     classicOrdinalName(int libraryOrdinal);
        pint_t*                                                                         mappedAddressForVMAddress(pint_t vmaddress);
        const char*                                                                     symbolNameForAddress(uint64_t);
        const char*                                                                     classicOrdinalName(int libraryOrdinal);
        pint_t*                                                                         mappedAddressForVMAddress(pint_t vmaddress);
        const char*                                                                     symbolNameForAddress(uint64_t);
+       const char*                                                                     closestSymbolNameForAddress(uint64_t addr, uint64_t* offset, uint8_t sectIndex=0);
 
                
        const char*                                                                     fPath;
 
                
        const char*                                                                     fPath;
@@ -149,8 +157,10 @@ private:
        const macho_segment_command<P>*                         fFirstWritableSegment;
        bool                                                                            fWriteableSegmentWithAddrOver4G;
        std::vector<const macho_segment_command<P>*>fSegments;
        const macho_segment_command<P>*                         fFirstWritableSegment;
        bool                                                                            fWriteableSegmentWithAddrOver4G;
        std::vector<const macho_segment_command<P>*>fSegments;
+       std::vector<const macho_section<P>*>            fSections;
        std::vector<const char*>                                        fDylibs;
        std::vector<const macho_dylib_command<P>*>      fDylibLoadCommands;
        std::vector<const char*>                                        fDylibs;
        std::vector<const macho_dylib_command<P>*>      fDylibLoadCommands;
+       macho_section<P>                                                        fMachHeaderPseudoSection;
 };
 
 
 };
 
 
@@ -286,7 +296,12 @@ DyldInfoPrinter<A>::DyldInfoPrinter(const uint8_t* fileContent, uint32_t fileLen
 
        fPath = strdup(path);
        fHeader = (const macho_header<P>*)fileContent;
 
        fPath = strdup(path);
        fHeader = (const macho_header<P>*)fileContent;
-       
+
+       fMachHeaderPseudoSection.set_segname("__TEXT");
+       fMachHeaderPseudoSection.set_sectname("");
+       fMachHeaderPseudoSection.set_addr(0);
+       fSections.push_back(&fMachHeaderPseudoSection);
+
        // get LC_DYLD_INFO
        const uint8_t* const endOfFile = (uint8_t*)fHeader + fLength;
        const uint8_t* const endOfLoadCommands = (uint8_t*)fHeader + sizeof(macho_header<P>) + fHeader->sizeofcmds();
        // get LC_DYLD_INFO
        const uint8_t* const endOfFile = (uint8_t*)fHeader + fLength;
        const uint8_t* const endOfLoadCommands = (uint8_t*)fHeader + sizeof(macho_header<P>) + fHeader->sizeofcmds();
@@ -318,6 +333,10 @@ DyldInfoPrinter<A>::DyldInfoPrinter(const uint8_t* fileContent, uint32_t fileLen
                                        if ( segCmd->vmaddr() > 0x100000000ULL )
                                                fWriteableSegmentWithAddrOver4G = true;
                                }
                                        if ( segCmd->vmaddr() > 0x100000000ULL )
                                                fWriteableSegmentWithAddrOver4G = true;
                                }
+                               const macho_section<P>* const sectionsStart = (macho_section<P>*)((char*)segCmd + sizeof(macho_segment_command<P>));
+                               const macho_section<P>* const sectionsEnd = &sectionsStart[segCmd->nsects()];
+                               for(const macho_section<P>* sect = sectionsStart; sect < sectionsEnd; ++sect)
+                                       fSections.push_back(sect);
                                }
                                break;
                        case LC_LOAD_DYLIB:
                                }
                                break;
                        case LC_LOAD_DYLIB:
@@ -704,9 +723,10 @@ void DyldInfoPrinter<A>::printRebaseInfoOpcodes()
        }
        else {
                printf("rebase opcodes:\n");
        }
        else {
                printf("rebase opcodes:\n");
-               const uint8_t* p = (uint8_t*)fHeader + fInfo->rebase_off();
-               const uint8_t* end = &p[fInfo->rebase_size()];
-               
+               const uint8_t* start = (uint8_t*)fHeader + fInfo->rebase_off();
+               const uint8_t* end = &start[fInfo->rebase_size()];
+               const uint8_t* p = start;
+
                uint8_t type = 0;
                uint64_t address = fBaseAddress;
                uint32_t count;
                uint8_t type = 0;
                uint64_t address = fBaseAddress;
                uint32_t count;
@@ -716,44 +736,45 @@ void DyldInfoPrinter<A>::printRebaseInfoOpcodes()
                while ( !done && (p < end) ) {
                        uint8_t immediate = *p & REBASE_IMMEDIATE_MASK;
                        uint8_t opcode = *p & REBASE_OPCODE_MASK;
                while ( !done && (p < end) ) {
                        uint8_t immediate = *p & REBASE_IMMEDIATE_MASK;
                        uint8_t opcode = *p & REBASE_OPCODE_MASK;
+                       uint32_t opcodeOffset = p-start;
                        ++p;
                        switch (opcode) {
                                case REBASE_OPCODE_DONE:
                                        done = true;
                        ++p;
                        switch (opcode) {
                                case REBASE_OPCODE_DONE:
                                        done = true;
-                                       printf("REBASE_OPCODE_DONE()\n");
+                                       printf("0x%04X REBASE_OPCODE_DONE()\n", opcodeOffset);
                                        break;
                                case REBASE_OPCODE_SET_TYPE_IMM:
                                        type = immediate;
                                        break;
                                case REBASE_OPCODE_SET_TYPE_IMM:
                                        type = immediate;
-                                       printf("REBASE_OPCODE_SET_TYPE_IMM(%d)\n", type);
+                                       printf("0x%04X REBASE_OPCODE_SET_TYPE_IMM(%d)\n", opcodeOffset, type);
                                        break;
                                case REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
                                        segmentIndex = immediate;
                                        address = read_uleb128(p, end);
                                        break;
                                case REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
                                        segmentIndex = immediate;
                                        address = read_uleb128(p, end);
-                                       printf("REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB(%d, 0x%08llX)\n", segmentIndex, address);
+                                       printf("0x%04X REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB(%d, 0x%08llX)\n", opcodeOffset, segmentIndex, address);
                                        break;
                                case REBASE_OPCODE_ADD_ADDR_ULEB:
                                        address = read_uleb128(p, end);
                                        break;
                                case REBASE_OPCODE_ADD_ADDR_ULEB:
                                        address = read_uleb128(p, end);
-                                       printf("REBASE_OPCODE_ADD_ADDR_ULEB(0x%0llX)\n", address);
+                                       printf("0x%04X REBASE_OPCODE_ADD_ADDR_ULEB(0x%0llX)\n", opcodeOffset, address);
                                        break;
                                case REBASE_OPCODE_ADD_ADDR_IMM_SCALED:
                                        address = immediate*sizeof(pint_t);
                                        break;
                                case REBASE_OPCODE_ADD_ADDR_IMM_SCALED:
                                        address = immediate*sizeof(pint_t);
-                                       printf("REBASE_OPCODE_ADD_ADDR_IMM_SCALED(0x%0llX)\n", address);
+                                       printf("0x%04X REBASE_OPCODE_ADD_ADDR_IMM_SCALED(0x%0llX)\n", opcodeOffset, address);
                                        break;
                                case REBASE_OPCODE_DO_REBASE_IMM_TIMES:
                                        break;
                                case REBASE_OPCODE_DO_REBASE_IMM_TIMES:
-                                       printf("REBASE_OPCODE_DO_REBASE_IMM_TIMES(%d)\n", immediate);
+                                       printf("0x%04X REBASE_OPCODE_DO_REBASE_IMM_TIMES(%d)\n", opcodeOffset, immediate);
                                        break;
                                case REBASE_OPCODE_DO_REBASE_ULEB_TIMES:
                                        count = read_uleb128(p, end);
                                        break;
                                case REBASE_OPCODE_DO_REBASE_ULEB_TIMES:
                                        count = read_uleb128(p, end);
-                                       printf("REBASE_OPCODE_DO_REBASE_ULEB_TIMES(%d)\n", count);
+                                       printf("0x%04X REBASE_OPCODE_DO_REBASE_ULEB_TIMES(%d)\n", opcodeOffset, count);
                                        break;
                                case REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB:
                                        skip = read_uleb128(p, end) + sizeof(pint_t);
                                        break;
                                case REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB:
                                        skip = read_uleb128(p, end) + sizeof(pint_t);
-                                       printf("REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB(%d)\n", skip);
+                                       printf("0x%04X REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB(%d)\n", opcodeOffset, skip);
                                        break;
                                case REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB:
                                        count = read_uleb128(p, end);
                                        skip = read_uleb128(p, end);
                                        break;
                                case REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB:
                                        count = read_uleb128(p, end);
                                        skip = read_uleb128(p, end);
-                                       printf("REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB(%d, %d)\n", count, skip);
+                                       printf("0x%04X REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB(%d, %d)\n", opcodeOffset, count, skip);
                                        break;
                                default:
                                        throwf("bad rebase opcode %d", *p);
                                        break;
                                default:
                                        throwf("bad rebase opcode %d", *p);
@@ -1485,102 +1506,126 @@ void DyldInfoPrinter<A>::printExportInfoNodes()
 
 
 template <typename A>
 
 
 template <typename A>
-const uint8_t* DyldInfoPrinter<A>::printSharedRegionInfoForEachULEB128Address(const uint8_t* p, uint8_t kind)
+const uint8_t* DyldInfoPrinter<A>::printSharedRegionV1InfoForEachULEB128Address(const uint8_t* p, const uint8_t* end, uint8_t kind)
 {
        const char* kindStr =  "??";
 {
        const char* kindStr =  "??";
-       switch (kind) {
-               case 1:
+       switch (kind ) {
+               case DYLD_CACHE_ADJ_V1_POINTER_32:
                        kindStr = "32-bit pointer";
                        break;
                        kindStr = "32-bit pointer";
                        break;
-               case 2:
+               case DYLD_CACHE_ADJ_V1_POINTER_64:
                        kindStr = "64-bit pointer";
                        break;
                        kindStr = "64-bit pointer";
                        break;
-               case 3:
-#if SUPPORT_ARCH_arm64
-                       if ( fHeader->cputype() == CPU_TYPE_ARM64 )
-                               kindStr = "arm64 ADRP";
-                       else
-#endif
-                               kindStr = "ppc hi16";
-                       break;
-               case 4:
-                       kindStr = "32-bit offset to IMPORT";
-                       break;
-               case 5:
-                       kindStr = "thumb2 movw";
-                       break;
-               case 6:
-                       kindStr = "ARM movw";
+               case DYLD_CACHE_ADJ_V1_ADRP:
+                       kindStr = "arm64 ADRP";
                        break;
                        break;
-               case 0x10:
+               case DYLD_CACHE_ADJ_V1_ARM_THUMB_MOVT+0:
                        kindStr = "thumb2 movt low high 4 bits=0";
                        break;
                        kindStr = "thumb2 movt low high 4 bits=0";
                        break;
-               case 0x11:
+               case DYLD_CACHE_ADJ_V1_ARM_THUMB_MOVT+1:
                        kindStr = "thumb2 movt low high 4 bits=1";
                        break;
                        kindStr = "thumb2 movt low high 4 bits=1";
                        break;
-               case 0x12:
+               case DYLD_CACHE_ADJ_V1_ARM_THUMB_MOVT+2:
                        kindStr = "thumb2 movt low high 4 bits=2";
                        break;
                        kindStr = "thumb2 movt low high 4 bits=2";
                        break;
-               case 0x13:
+               case DYLD_CACHE_ADJ_V1_ARM_THUMB_MOVT+3:
                        kindStr = "thumb2 movt low high 4 bits=3";
                        break;
                        kindStr = "thumb2 movt low high 4 bits=3";
                        break;
-               case 0x14:
+               case DYLD_CACHE_ADJ_V1_ARM_THUMB_MOVT+4:
                        kindStr = "thumb2 movt low high 4 bits=4";
                        break;
                        kindStr = "thumb2 movt low high 4 bits=4";
                        break;
-               case 0x15:
+               case DYLD_CACHE_ADJ_V1_ARM_THUMB_MOVT+5:
                        kindStr = "thumb2 movt low high 4 bits=5";
                        break;
                        kindStr = "thumb2 movt low high 4 bits=5";
                        break;
-               case 0x16:
+               case DYLD_CACHE_ADJ_V1_ARM_THUMB_MOVT+6:
                        kindStr = "thumb2 movt low high 4 bits=6";
                        break;
                        kindStr = "thumb2 movt low high 4 bits=6";
                        break;
-               case 0x17:
+               case DYLD_CACHE_ADJ_V1_ARM_THUMB_MOVT+7:
                        kindStr = "thumb2 movt low high 4 bits=7";
                        break;
                        kindStr = "thumb2 movt low high 4 bits=7";
                        break;
-               case 0x18:
+               case DYLD_CACHE_ADJ_V1_ARM_THUMB_MOVT+8:
                        kindStr = "thumb2 movt low high 4 bits=8";
                        break;
                        kindStr = "thumb2 movt low high 4 bits=8";
                        break;
-               case 0x19:
+               case DYLD_CACHE_ADJ_V1_ARM_THUMB_MOVT+9:
                        kindStr = "thumb2 movt low high 4 bits=9";
                        break;
                        kindStr = "thumb2 movt low high 4 bits=9";
                        break;
-               case 0x1A:
-                       kindStr = "thumb2 movt low high 4 bits=0xA";
+               case DYLD_CACHE_ADJ_V1_ARM_THUMB_MOVT+10:
+                       kindStr = "thumb2 movt low high 4 bits=10";
+                       break;
+               case DYLD_CACHE_ADJ_V1_ARM_THUMB_MOVT+11:
+                       kindStr = "thumb2 movt low high 4 bits=11";
+                       break;
+               case DYLD_CACHE_ADJ_V1_ARM_THUMB_MOVT+12:
+                       kindStr = "thumb2 movt low high 4 bits=12";
+                       break;
+               case DYLD_CACHE_ADJ_V1_ARM_THUMB_MOVT+13:
+                       kindStr = "thumb2 movt low high 4 bits=13";
+                       break;
+               case DYLD_CACHE_ADJ_V1_ARM_THUMB_MOVT+14:
+                       kindStr = "thumb2 movt low high 4 bits=14";
+                       break;
+               case DYLD_CACHE_ADJ_V1_ARM_THUMB_MOVT+15:
+                       kindStr = "thumb2 movt low high 4 bits=15";
+                       break;
+               case DYLD_CACHE_ADJ_V1_ARM_MOVT+0:
+                       kindStr = "arm movt low high 4 bits=0";
+                       break;
+               case DYLD_CACHE_ADJ_V1_ARM_MOVT+1:
+                       kindStr = "arm movt low high 4 bits=1";
+                       break;
+               case DYLD_CACHE_ADJ_V1_ARM_MOVT+2:
+                       kindStr = "arm movt low high 4 bits=2";
+                       break;
+               case DYLD_CACHE_ADJ_V1_ARM_MOVT+3:
+                       kindStr = "arm movt low high 4 bits=3";
+                       break;
+               case DYLD_CACHE_ADJ_V1_ARM_MOVT+4:
+                       kindStr = "arm movt low high 4 bits=4";
+                       break;
+               case DYLD_CACHE_ADJ_V1_ARM_MOVT+5:
+                       kindStr = "arm movt low high 4 bits=5";
+                       break;
+               case DYLD_CACHE_ADJ_V1_ARM_MOVT+6:
+                       kindStr = "arm movt low high 4 bits=6";
+                       break;
+               case DYLD_CACHE_ADJ_V1_ARM_MOVT+7:
+                       kindStr = "arm movt low high 4 bits=7";
+                       break;
+               case DYLD_CACHE_ADJ_V1_ARM_MOVT+8:
+                       kindStr = "arm movt low high 4 bits=8";
+                       break;
+               case DYLD_CACHE_ADJ_V1_ARM_MOVT+9:
+                       kindStr = "arm movt low high 4 bits=9";
+                       break;
+               case DYLD_CACHE_ADJ_V1_ARM_MOVT+10:
+                       kindStr = "arm movt low high 4 bits=10";
                        break;
                        break;
-               case 0x1B:
-                       kindStr = "thumb2 movt low high 4 bits=0xB";
+               case DYLD_CACHE_ADJ_V1_ARM_MOVT+11:
+                       kindStr = "arm movt low high 4 bits=11";
                        break;
                        break;
-               case 0x1C:
-                       kindStr = "thumb2 movt low high 4 bits=0xC";
+               case DYLD_CACHE_ADJ_V1_ARM_MOVT+12:
+                       kindStr = "arm movt low high 4 bits=12";
                        break;
                        break;
-               case 0x1D:
-                       kindStr = "thumb2 movt low high 4 bits=0xD";
+               case DYLD_CACHE_ADJ_V1_ARM_MOVT+13:
+                       kindStr = "arm movt low high 4 bits=13";
                        break;
                        break;
-               case 0x1E:
-                       kindStr = "thumb2 movt low high 4 bits=0xE";
+               case DYLD_CACHE_ADJ_V1_ARM_MOVT+14:
+                       kindStr = "arm movt low high 4 bits=14";
                        break;
                        break;
-               case 0x1F:
-                       kindStr = "thumb2 movt low high 4 bits=0xF";
+               case DYLD_CACHE_ADJ_V1_ARM_MOVT+15:
+                       kindStr = "arm movt low high 4 bits=15";
                        break;
                        break;
+               default:
+                       kindStr = "<<unknown>>";
        }
        uint64_t address = 0;
        uint64_t delta = 0;
        }
        uint64_t address = 0;
        uint64_t delta = 0;
-       uint32_t shift = 0;
-       bool more = true;
        do {
        do {
-               uint8_t byte = *p++;
-               delta |= ((byte & 0x7F) << shift);
-               shift += 7;
-               if ( byte < 0x80 ) {
-                       if ( delta != 0 ) {
-                               address += delta;
-                               printf("0x%0llX   %s\n", address+fBaseAddress, kindStr); 
-                               delta = 0;
-                               shift = 0;
-                       }
-                       else {
-                               more = false;
-                       }
-               }
-       } while (more);
+               delta = read_uleb128(p, end);
+               address += delta;
+               printf("0x%0llX   %s\n", address+fBaseAddress, kindStr); 
+       } while (delta);
+
        return p;
 }
 
        return p;
 }
 
@@ -1593,14 +1638,96 @@ void DyldInfoPrinter<A>::printSharedRegionInfo()
        else {
                const uint8_t* infoStart = (uint8_t*)fHeader + fSharedRegionInfo->dataoff();
                const uint8_t* infoEnd = &infoStart[fSharedRegionInfo->datasize()];
        else {
                const uint8_t* infoStart = (uint8_t*)fHeader + fSharedRegionInfo->dataoff();
                const uint8_t* infoEnd = &infoStart[fSharedRegionInfo->datasize()];
-               for(const uint8_t* p = infoStart; (*p != 0) && (p < infoEnd);) {
-                       uint8_t kind = *p++;
-                       p = this->printSharedRegionInfoForEachULEB128Address(p, kind);
+               if ( *infoStart == DYLD_CACHE_ADJ_V2_FORMAT ) {
+                       ++infoStart;
+                       // Whole                 :== <count> FromToSection+
+                       // FromToSection :== <from-sect-index> <to-sect-index> <count> ToOffset+
+                       // ToOffset              :== <to-sect-offset-delta> <count> FromOffset+
+                       // FromOffset    :== <kind> <count> <from-sect-offset-delta>
+                       const uint8_t* p = infoStart;
+                       uint64_t sectionCount = read_uleb128(p, infoEnd);
+                       for (uint64_t i=0; i < sectionCount; ++i) {
+                               uint64_t fromSectionIndex = read_uleb128(p, infoEnd);
+                               uint64_t toSectionIndex = read_uleb128(p, infoEnd);
+                               uint64_t toOffsetCount = read_uleb128(p, infoEnd);
+                               const macho_section<P>* fromSection = fSections[fromSectionIndex];
+                               const macho_section<P>* toSection = fSections[toSectionIndex];
+                               printf("from sect=%s, to sect=%s, count=%lld:\n", fromSection->sectname(), toSection->sectname(), toOffsetCount);
+                               uint64_t toSectionOffset = 0;
+                               const char* lastFromSymbol = NULL;
+                               for (uint64_t j=0; j < toOffsetCount; ++j) {
+                                       uint64_t toSectionDelta = read_uleb128(p, infoEnd);
+                                       uint64_t fromOffsetCount = read_uleb128(p, infoEnd);
+                                       toSectionOffset += toSectionDelta;
+                                       for (uint64_t k=0; k < fromOffsetCount; ++k) {
+                                               uint64_t kind = read_uleb128(p, infoEnd);
+                                               uint64_t fromSectDeltaCount = read_uleb128(p, infoEnd);
+                                               uint64_t fromSectionOffset = 0;
+                                               for (uint64_t l=0; l < fromSectDeltaCount; ++l) {
+                                                       uint64_t delta = read_uleb128(p, infoEnd);
+                                                       fromSectionOffset += delta;
+                                                       uint64_t symbolOffset;
+                                                       const char* s = closestSymbolNameForAddress(fromSection->addr()+fromSectionOffset, &symbolOffset, fromSectionIndex);
+                                                       if ( (s != lastFromSymbol) && (s != NULL) )
+                                                               printf("  %s:\n", s);
+                                                       const char* toSymbol = closestSymbolNameForAddress(toSection->addr()+toSectionOffset, &symbolOffset, toSectionIndex);
+                                                       printf("       from addr=0x%0llX %s to addr=0x%0llX", fromSection->addr()+fromSectionOffset, sharedRegionKindName(kind), toSection->addr()+toSectionOffset);
+                                                       if ( toSymbol != NULL ) {
+                                                               if ( symbolOffset == 0 )
+                                                                       printf(" (%s)", toSymbol);
+                                                               else
+                                                                       printf(" (%s + %lld)", toSymbol, symbolOffset);
+                                                       }
+                                                       printf("\n");
+                                                       lastFromSymbol = s;
+                                               }
+                                       }
+                               }
+                       }
+               }
+               else {
+                       for(const uint8_t* p = infoStart; (*p != 0) && (p < infoEnd);) {
+                               uint8_t kind = *p++;
+                               p = this->printSharedRegionV1InfoForEachULEB128Address(p, infoEnd, kind);
+                       }
                }
                }
+       }
+}
 
 
+template <typename A>
+const char* DyldInfoPrinter<A>::sharedRegionKindName(uint8_t kind)
+{
+       switch (kind) {
+               default:
+                       return "<<unknown>>";
+               case DYLD_CACHE_ADJ_V2_POINTER_32:
+                       return "pointer32";
+               case DYLD_CACHE_ADJ_V2_POINTER_64:
+                       return "pointer64";
+               case DYLD_CACHE_ADJ_V2_DELTA_32:
+                       return "delta32";
+               case DYLD_CACHE_ADJ_V2_DELTA_64:
+                       return "delta64";
+               case DYLD_CACHE_ADJ_V2_ARM64_ADRP:
+                       return "adrp";
+               case DYLD_CACHE_ADJ_V2_ARM64_OFF12:
+                       return "off12";
+               case DYLD_CACHE_ADJ_V2_ARM64_BR26:
+                       return "br26";
+               case DYLD_CACHE_ADJ_V2_ARM_MOVW_MOVT:
+                       return "movw/movt";
+               case DYLD_CACHE_ADJ_V2_ARM_BR24:
+                       return "br24";
+               case DYLD_CACHE_ADJ_V2_THUMB_MOVW_MOVT:
+                       return "movw/movt";
+               case DYLD_CACHE_ADJ_V2_THUMB_BR22:
+                       return "br22";
+               case DYLD_CACHE_ADJ_V2_IMAGE_OFF_32:
+                       return "off32";
        }
 }
 
        }
 }
 
+
 #if SUPPORT_ARCH_arm_any
 template <>
 void DyldInfoPrinter<arm>::printFunctionStartLine(uint64_t addr)
 #if SUPPORT_ARCH_arm_any
 template <>
 void DyldInfoPrinter<arm>::printFunctionStartLine(uint64_t addr)
@@ -1686,7 +1813,6 @@ void DyldInfoPrinter<A>::printDRInfo()
                const uint8_t* start = ((uint8_t*)fHeader + fDRInfo->dataoff());
                //const uint8_t* end   = ((uint8_t*)fHeader + fDRInfo->dataoff() + fDRInfo->datasize());
                typedef Security::SuperBlob<Security::kSecCodeMagicDRList> DRListSuperBlob;
                const uint8_t* start = ((uint8_t*)fHeader + fDRInfo->dataoff());
                //const uint8_t* end   = ((uint8_t*)fHeader + fDRInfo->dataoff() + fDRInfo->datasize());
                typedef Security::SuperBlob<Security::kSecCodeMagicDRList> DRListSuperBlob;
-               typedef Security::SuperBlob<Security::kSecCodeMagicRequirementSet> InternalRequirementsSetBlob;
                const DRListSuperBlob* topBlob = (DRListSuperBlob*)start;
                if ( topBlob->validateBlob(fDRInfo->datasize()) ) {
                        if ( topBlob->count() == fDylibLoadCommands.size() ) {
                const DRListSuperBlob* topBlob = (DRListSuperBlob*)start;
                if ( topBlob->validateBlob(fDRInfo->datasize()) ) {
                        if ( topBlob->count() == fDylibLoadCommands.size() ) {
@@ -1951,37 +2077,65 @@ void DyldInfoPrinter<A>::printSymbolTableExportInfo()
 }
 
 template <typename A>
 }
 
 template <typename A>
-const char* DyldInfoPrinter<A>::symbolNameForAddress(uint64_t addr)
+const char* DyldInfoPrinter<A>::closestSymbolNameForAddress(uint64_t addr, uint64_t* offset, uint8_t sectIndex)
 {
 {
+       const macho_nlist<P>* bestSymbol = NULL;
        if ( fDynamicSymbolTable != NULL ) {
        if ( fDynamicSymbolTable != NULL ) {
-               // find exact match in globals
-               const macho_nlist<P>* lastExport = &fSymbols[fDynamicSymbolTable->iextdefsym()+fDynamicSymbolTable->nextdefsym()];
-               for (const macho_nlist<P>* sym = &fSymbols[fDynamicSymbolTable->iextdefsym()]; sym < lastExport; ++sym) {
-                       if ( (sym->n_value() == addr) && ((sym->n_type() & N_TYPE) == N_SECT) && ((sym->n_type() & N_STAB) == 0) ) {
-                               return &fStrings[sym->n_strx()];
+               // find closest match in globals
+               const macho_nlist<P>* const globalsStart = &fSymbols[fDynamicSymbolTable->iextdefsym()];
+               const macho_nlist<P>* const globalsEnd   = &globalsStart[fDynamicSymbolTable->nextdefsym()];
+               for (const macho_nlist<P>* s = globalsStart; s < globalsEnd; ++s) {
+                       if ( (s->n_type() & N_TYPE) == N_SECT ) {
+                               if ( (s->n_value() <= addr) && ((s->n_sect() == sectIndex) || (sectIndex ==0)) ) {
+                                       if ( (bestSymbol == NULL) || (bestSymbol->n_value() < s->n_value()) )
+                                               bestSymbol = s;
+                               }
                        }
                }
                        }
                }
-               // find exact match in local symbols
-               const macho_nlist<P>* lastLocal = &fSymbols[fDynamicSymbolTable->ilocalsym()+fDynamicSymbolTable->nlocalsym()];
-               for (const macho_nlist<P>* sym = &fSymbols[fDynamicSymbolTable->ilocalsym()]; sym < lastLocal; ++sym) {
-                       if ( (sym->n_value() == addr) && ((sym->n_type() & N_TYPE) == N_SECT) && ((sym->n_type() & N_STAB) == 0) ) {
-                               return &fStrings[sym->n_strx()];
+
+               // find closest match in locals
+               const macho_nlist<P>* const localsStart = &fSymbols[fDynamicSymbolTable->ilocalsym()];
+               const macho_nlist<P>* const localsEnd   = &localsStart[fDynamicSymbolTable->nlocalsym()];
+               for (const macho_nlist<P>* s = localsStart; s < localsEnd; ++s) {
+                       if ( ((s->n_type() & N_TYPE) == N_SECT) && ((s->n_type() & N_STAB) == 0) ) {
+                               if ( (s->n_value() <= addr) && ((s->n_sect() == sectIndex) || (sectIndex ==0)) ) {
+                                       if ( (bestSymbol == NULL) || (bestSymbol->n_value() < s->n_value()) )
+                                               bestSymbol = s;
+                               }
                        }
                }
        }
        else {
                        }
                }
        }
        else {
-               // find exact match in all symbols
-               const macho_nlist<P>* lastSym = &fSymbols[fSymbolCount];
-               for (const macho_nlist<P>* sym = &fSymbols[0]; sym < lastSym; ++sym) {
-                       if ( (sym->n_value() == addr) && ((sym->n_type() & N_TYPE) == N_SECT) && ((sym->n_type() & N_STAB) == 0) ) {
-                               return &fStrings[sym->n_strx()];
+               // find closest match in locals
+               const macho_nlist<P>* const allStart = &fSymbols[0];
+               const macho_nlist<P>* const allEnd   = &fSymbols[fSymbolCount];
+               for (const macho_nlist<P>* s = allStart; s < allEnd; ++s) {
+                       if ( ((s->n_type() & N_TYPE) == N_SECT) && ((s->n_type() & N_STAB) == 0) ) {
+                               if ( (s->n_value() <= addr) && ((s->n_sect() == sectIndex) || (sectIndex ==0)) ) {
+                                       if ( (bestSymbol == NULL) || (bestSymbol->n_value() < s->n_value()) )
+                                               bestSymbol = s;
+                               }
                        }
                }
        }
                        }
                }
        }
+       if ( bestSymbol != NULL ) {
+               *offset = addr - bestSymbol->n_value();
+               return &fStrings[bestSymbol->n_strx()];
+       }
+       *offset = 0;
+       return NULL;
+}
 
 
+template <typename A>
+const char* DyldInfoPrinter<A>::symbolNameForAddress(uint64_t addr)
+{
+       uint64_t offset;
+       const char* s = closestSymbolNameForAddress(addr, &offset);
+       if ( (offset == 0) && (s != NULL) )
+               return s;
        return "?";
 }
        return "?";
 }
+
 template <typename A>
 void DyldInfoPrinter<A>::printClassicBindingInfo()
 {
 template <typename A>
 void DyldInfoPrinter<A>::printClassicBindingInfo()
 {
@@ -2223,7 +2377,7 @@ static void usage()
                        "\t-opcodes          print opcodes used to generate the rebase and binding information\n"
                        "\t-function_starts  print table of function start addresses\n"
                        "\t-export_dot       print a GraphViz .dot file of the exported symbols trie\n"
                        "\t-opcodes          print opcodes used to generate the rebase and binding information\n"
                        "\t-function_starts  print table of function start addresses\n"
                        "\t-export_dot       print a GraphViz .dot file of the exported symbols trie\n"
-                       "\t-data_in_code     print any data-in-code inforamtion\n"
+                       "\t-data_in_code     print any data-in-code information\n"
                );
 }
 
                );
 }
 
index 545b4a7714321de8a68211042bd2f6b7334f4004..f0cbbf177147d5872859f2e6d7a49003c1f564ea 100644 (file)
@@ -55,7 +55,7 @@ ifeq ($(ARCH),ppc)
        SDKExtra = -isysroot /Developer/SDKs/MacOSX10.6.sdk
 endif
 
        SDKExtra = -isysroot /Developer/SDKs/MacOSX10.6.sdk
 endif
 
-CC              = $(shell xcrun -find clang) -arch ${ARCH} ${SDKExtra}
+CC              = $(shell xcrun -find clang) -arch ${ARCH} ${SDKExtra} -mmacosx-version-min=10.8
 CCFLAGS = -Wall 
 ASMFLAGS =
 VERSION_NEW_LINKEDIT = -mmacosx-version-min=10.6
 CCFLAGS = -Wall 
 ASMFLAGS =
 VERSION_NEW_LINKEDIT = -mmacosx-version-min=10.6
@@ -65,7 +65,7 @@ LD_NEW_LINKEDIT = -macosx_version_min 10.6
 CXX              = $(shell xcrun -find clang++) -arch ${ARCH} ${SDKExtra}
 CXXFLAGS = -Wall -stdlib=libc++ 
 
 CXX              = $(shell xcrun -find clang++) -arch ${ARCH} ${SDKExtra}
 CXXFLAGS = -Wall -stdlib=libc++ 
 
-IOS_SDK = $(shell xcodebuild -sdk iphoneos8.0.internal -version Path  2>/dev/null)
+IOS_SDK = $(shell xcodebuild -sdk iphoneos.internal -version Path  2>/dev/null)
 
 ifeq ($(ARCH),armv6)
   LDFLAGS := -syslibroot $(IOS_SDK)
 
 ifeq ($(ARCH),armv6)
   LDFLAGS := -syslibroot $(IOS_SDK)
@@ -127,16 +127,13 @@ endif
 
 ifeq ($(ARCH),arm64)
   LDFLAGS := -syslibroot $(IOS_SDK)
 
 ifeq ($(ARCH),arm64)
   LDFLAGS := -syslibroot $(IOS_SDK)
-  CC = /Applications/Xcode.app/Contents/Developer/Toolchains/iOS7.1.xctoolchain/usr/bin/clang -arch ${ARCH} -ccc-install-dir ${LD_PATH} -miphoneos-version-min=7.0 -isysroot $(IOS_SDK)
-  #CC = $(shell xcrun --sdk iphoneos.internal -find clang) -arch ${ARCH} -ccc-install-dir ${LD_PATH} -miphoneos-version-min=7.0 -isysroot $(IOS_SDK)
-  #CC =  /Applications/Xcode.app/Contents/Developer/Toolchains/iOS7.0.xctoolchain/usr/bin/clang-loh -arch ${ARCH} -ccc-install-dir ${LD_PATH} -miphoneos-version-min=7.0 -isysroot $(IOS_SDK)
-  CXX = $(shell xcrun --sdk iphoneos.internal -find clang++) -arch ${ARCH} -ccc-install-dir ${LD_PATH} -miphoneos-version-min=7.0 -isysroot $(IOS_SDK)
+  CC  = $(shell xcrun --sdk iphoneos.internal -find clang) -arch ${ARCH} -ccc-install-dir ${LD_PATH} -miphoneos-version-min=9.0 -isysroot $(IOS_SDK)
+  CXX = $(shell xcrun --sdk iphoneos.internal -find clang++) -arch ${ARCH} -ccc-install-dir ${LD_PATH} -miphoneos-version-min=9.0 -isysroot $(IOS_SDK)
   VERSION_NEW_LINKEDIT = -miphoneos-version-min=7.0
   VERSION_OLD_LINKEDIT = -miphoneos-version-min=3.0
   LD_SYSROOT = -syslibroot $(IOS_SDK)
   LD_NEW_LINKEDIT = -ios_version_min 7.0
   VERSION_NEW_LINKEDIT = -miphoneos-version-min=7.0
   VERSION_OLD_LINKEDIT = -miphoneos-version-min=3.0
   LD_SYSROOT = -syslibroot $(IOS_SDK)
   LD_NEW_LINKEDIT = -ios_version_min 7.0
-  OTOOL =   /Applications/Xcode.app/Contents/Developer/Toolchains/iOS7.1.xctoolchain/usr/bin/otool
-  #OTOOL =  $(shell xcrun --sdk iphoneos.internal -find otool)
+  OTOOL =  $(shell xcrun --sdk iphoneos.internal -find otool)
 else
   FILEARCH = $(ARCH)
 endif
 else
   FILEARCH = $(ARCH)
 endif
diff --git a/unit-tests/test-cases/dead_strip-live-if-ref-live/Makefile b/unit-tests/test-cases/dead_strip-live-if-ref-live/Makefile
new file mode 100644 (file)
index 0000000..0949507
--- /dev/null
@@ -0,0 +1,48 @@
+##
+# Copyright (c) 2014 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+# 
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+# 
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+# 
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Sanity check -dead_strip does not remove initializers and terminators
+#
+
+
+run: all
+
+all:
+       ${CC} ${CCFLAGS} main.c -c -o main.o
+       ${CC} ${CCFLAGS} main.o -dead_strip -o main
+       ${FAIL_IF_BAD_MACHO} main
+       nm main | grep _aa | ${FAIL_IF_EMPTY}
+       nm main | grep _aaInfo | ${FAIL_IF_EMPTY}
+       nm main | grep _bb | ${FAIL_IF_STDIN}
+       ${LD} -r main.o -o main-r.o
+       ${CC} ${CCFLAGS} main-r.o -dead_strip -o main-r
+       nm main-r | grep _aa | ${FAIL_IF_EMPTY}
+       nm main-r | grep _aaInfo | ${FAIL_IF_EMPTY}
+       nm main-r | grep _bb | ${FAIL_IF_STDIN}
+       ${PASS_IFF_GOOD_MACHO} main-r
+
+clean:
+       rm -rf main.o main main-r.o main-r
diff --git a/unit-tests/test-cases/dead_strip-live-if-ref-live/main.c b/unit-tests/test-cases/dead_strip-live-if-ref-live/main.c
new file mode 100644 (file)
index 0000000..e038a28
--- /dev/null
@@ -0,0 +1,29 @@
+#include <stdio.h>
+
+int aa = 10;
+int bb = 20;
+int cc = 30;
+
+
+int main()
+{
+  printf("%p %p\n", &aa, &cc);
+       return 0;
+}
+
+
+struct MetaData {
+  void*                addr;
+  unsigned long        size;
+  const char*  name;
+};
+
+
+#define META_DATA(__x)                                                   \
+  __attribute__((used, section("__DATA,__meta,regular,live_support")))   \
+  static struct MetaData __x##Info = { &__x, sizeof(__x), #__x };
+
+
+META_DATA(aa);
+META_DATA(bb);
+META_DATA(cc);
index 92558413cf3a4eb70c1ec02391e24d23c14417b3..b0eb6de481d9052394b43e18279682f8099ee419 100644 (file)
@@ -159,4 +159,117 @@ _get_d:
 
 #endif
 
 
 #endif
 
+
+#if __arm__
+
+               # _a is global TLV
+               .tlv
+               .globl _a
+_a:            .long   __tlv_bootstrap
+               .long   0
+               .long   _a$tlv$init
+
+               # _b is a global TLV
+               .tlv
+               .globl _b
+_b:            .long   __tlv_bootstrap
+               .long   0
+               .long   _b$tlv$init
+
+               # _c is a non-external TLV
+               .tlv
+_c:            .long   __tlv_bootstrap
+               .long   0
+               .long   _c$tlv$init
+
+               # _d is a non-external TLV
+               .tlv
+_d:            .long   __tlv_bootstrap
+               .long   0
+               .long   _d$tlv$init
+
+
+  .text
+
+  .globl       _get_a
+       .align  2
+       .code   16
+       .thumb_func     _get_a
+_get_a:
+  push {r7, lr}
+  mov  r7, sp
+       movw    r0, :lower16:(La-(LPC0_0+4))
+       movt    r0, :upper16:(La-(LPC0_0+4))
+LPC0_0:
+       add     r0, pc
+       ldr     r0, [r0]
+       ldr     ip, [r0]
+  blx ip
+  pop  {r7, pc}
+
+
+  .globl       _get_b
+       .align  2
+       .code   16
+       .thumb_func     _get_b
+_get_b:
+  push {r7, lr}
+  mov  r7, sp
+       movw    r0, :lower16:(Lb-(LPC0_1+4))
+       movt    r0, :upper16:(Lb-(LPC0_1+4))
+LPC0_1:
+       add     r0, pc
+       ldr     r0, [r0]
+       ldr     ip, [r0]
+  blx ip
+  pop  {r7, pc}
+
+
+  .globl       _get_c
+       .align  2
+       .code   16
+       .thumb_func     _get_c
+_get_c:
+  push {r7, lr}
+  mov  r7, sp
+       movw    r0, :lower16:(Lc-(LPC0_2+4))
+       movt    r0, :upper16:(Lc-(LPC0_2+4))
+LPC0_2:
+       add     r0, pc
+       ldr     r0, [r0]
+       ldr     ip, [r0]
+  blx ip
+  pop  {r7, pc}
+
+
+  .globl       _get_d
+       .align  2
+       .code   16
+       .thumb_func     _get_d
+_get_d:
+  push {r7, lr}
+  mov  r7, sp
+       movw    r0, :lower16:(Ld-(LPC0_3+4))
+       movt    r0, :upper16:(Ld-(LPC0_3+4))
+LPC0_3:
+       add     r0, pc
+       ldr     r0, [r0]
+       ldr     ip, [r0]
+  blx ip
+  pop  {r7, pc}
+
+
+  .section __DATA,__thread_ptr,thread_local_variable_pointers
+La:
+  .long _a
+Lb:
+  .long _b
+Lc:
+  .long _c
+Ld:
+  .long _d
+
+
+#endif
+
 .subsections_via_symbols
 .subsections_via_symbols
index fc56a13ce4f2960654ae45b5e67c3d43445967b0..b5fd7f63b1c4e858e1f0f754f52252d557dfa8bf 100644 (file)
@@ -22,6 +22,8 @@
  * @APPLE_LICENSE_HEADER_END@
  */
 
  * @APPLE_LICENSE_HEADER_END@
  */
 
+#include <stdio.h>
+
 // work around until compiler supports __thread
 extern int* get_a();           
 extern int* get_b();
 // work around until compiler supports __thread
 extern int* get_a();           
 extern int* get_b();
@@ -30,10 +32,19 @@ extern int* get_d();
 
 int main()
 {
 
 int main()
 {
-       get_a();
-       get_b();
-       get_c();
-       get_d();
+       int* p;
+  p = get_a();
+  printf("&a=%p, a=%d\n", p, *p);
+
+       p = get_b();
+  printf("&b=%p, b=%d\n", p, *p);
+
+       p = get_c();
+  printf("&c=%p, c=%d\n", p, *p);
+
+       p = get_d();
+  printf("&d=%p, e=%d\n", p, *p);
+
        return 0;
 }
 
        return 0;
 }