]> git.saurik.com Git - apple/ld64.git/commitdiff
ld64-409.12.tar.gz master developer-tools-100 developer-tools-101 v409.12
authorApple <opensource@apple.com>
Tue, 18 Sep 2018 22:03:37 +0000 (22:03 +0000)
committerApple <opensource@apple.com>
Tue, 18 Sep 2018 22:03:37 +0000 (22:03 +0000)
81 files changed:
.gitignore
doc/man/man1/ld.1
ld64.xcodeproj/project.pbxproj
src/abstraction/MachOFileAbstraction.hpp
src/create_configure
src/ld/Architectures.hpp
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/Snapshot.cpp
src/ld/Snapshot.h
src/ld/ld.cpp
src/ld/ld.hpp
src/ld/parsers/generic_dylib_file.hpp
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/textstub_dylib_file.cpp
src/ld/parsers/textstub_dylib_file.hpp
src/ld/passes/bitcode_bundle.cpp
src/ld/passes/got.cpp
src/ld/passes/objc.cpp
src/ld/passes/stubs/stub_arm.hpp
src/ld/passes/stubs/stub_arm64.hpp
src/ld/passes/stubs/stub_x86.hpp
src/ld/passes/stubs/stub_x86_64.hpp
src/ld/passes/stubs/stubs.cpp
src/ld/passes/thread_starts.cpp [new file with mode: 0644]
src/ld/passes/thread_starts.h [new file with mode: 0644]
src/other/ObjectDump.cpp
src/other/dyldinfo.cpp
src/other/machochecker.cpp
unit-tests/include/common.makefile
unit-tests/run-all-unit-tests
unit-tests/test-cases/auto-arch/Makefile
unit-tests/test-cases/blank-stubs/Makefile
unit-tests/test-cases/cstring-labels/Makefile
unit-tests/test-cases/dtrace-old-probes/main.c
unit-tests/test-cases/dwarf-archive-all_load/Makefile
unit-tests/test-cases/dwarf-debug-notes-lto/Makefile
unit-tests/test-cases/dwarf-debug-notes-r/expected-stabs
unit-tests/test-cases/efi-basic/Makefile
unit-tests/test-cases/efi-basic/efi-pecoff-util [new file with mode: 0755]
unit-tests/test-cases/efi-basic/mtoctest.py
unit-tests/test-cases/exported-symbols-wildcards-dead_strip/Makefile
unit-tests/test-cases/exported-symbols-wildcards/Makefile
unit-tests/test-cases/lto-dylib-export_list/Makefile
unit-tests/test-cases/lto-live_support_section/Makefile
unit-tests/test-cases/lto-unexport-sym/Makefile
unit-tests/test-cases/no-object-symbols/Makefile
unit-tests/test-cases/objc-gc-checks/Makefile [deleted file]
unit-tests/test-cases/objc-gc-checks/bar.m [deleted file]
unit-tests/test-cases/objc-gc-checks/comment.txt [deleted file]
unit-tests/test-cases/objc-gc-checks/foo.m [deleted file]
unit-tests/test-cases/objc-gc-checks/none.c [deleted file]
unit-tests/test-cases/objc-gc-checks/runtime.c [deleted file]
unit-tests/test-cases/re-export-optimizations-indirect/Makefile
unit-tests/test-cases/special-labels/Makefile
unit-tests/test-cases/stabs-coalesce/Makefile [deleted file]
unit-tests/test-cases/stabs-coalesce/comment.txt [deleted file]
unit-tests/test-cases/stabs-coalesce/header.h [deleted file]
unit-tests/test-cases/stabs-coalesce/hello.cxx [deleted file]
unit-tests/test-cases/stabs-coalesce/other.cxx [deleted file]
unit-tests/test-cases/stabs-directory-slash/Makefile [deleted file]
unit-tests/test-cases/stabs-directory-slash/main.c [deleted file]
unit-tests/test-cases/stack_addr_size/Makefile [deleted file]
unit-tests/test-cases/stack_addr_size/comment.txt [deleted file]
unit-tests/test-cases/stack_addr_size/main.c [deleted file]
unit-tests/test-cases/stack_size_no_addr/Makefile
unit-tests/test-cases/static-executable-pie/Makefile
unit-tests/test-cases/thumb-blx/test.c
unit-tests/test-cases/umbrella-dylib/Makefile
unit-tests/test-cases/undefined-dynamic-lookup/Makefile

index 9190838bf3c8313ceac5b1e63af0a70b39f02950..a994d26f682b96005d637f9ddb036e4b94143fb4 100644 (file)
@@ -1,2 +1,4 @@
 build
 DerivedData
+ld64.xcodeproj/project.xcworkspace
+ld64.xcodeproj/xcuserdata
index 64641a6aae486b3a9fcc5f88486e564653444e26..d448b5c5ca4943b4e4d8ab7c31c3ede367057c3c 100644 (file)
@@ -552,6 +552,8 @@ Prints names of functions that are eliminated by deduplication and total code sa
 Error if the output contains any static initializers
 .It Fl no_warn_inits
 Do not warn if the output contains any static initializers
+.It Fl debug_variant
+Do not warn about issues that are only problems for binaries shipping to customers.
 .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
@@ -767,9 +769,6 @@ interposable then if _malloc was interposed at runtime, calls to malloc from wit
 .It Fl no_function_starts
 By default the linker creates a compress table of function start addresses in the LINKEDIT of
 final linked image.  This option disables that behavior.
-.It Fl no_version_load_command
-By default the linker creates a load command in final linked images that contains the -macosx_version_min.
-This option disables that behavior.
 .It Fl no_objc_category_merging
 By default when producing final linked image, the linker will optimize Objective-C classes by merging
 any categories on a class into the class.  Both the class and its categories must be defined in the image
@@ -787,7 +786,8 @@ to load instead.
 .It Fl cache_path_lto Ar path
 When performing Incremental Link Time Optimization (LTO), use this directory as a cache for incremental rebuild.
 .It Fl prune_interval_lto Ar seconds
-When performing Incremental Link Time Optimization (LTO), the cache will pruned after the specified interval.
+When performing Incremental Link Time Optimization (LTO), the cache will pruned after the specified interval. A value 0
+will force pruning to occur and a value of -1 will disable pruning.
 .It Fl prune_after_lto Ar seconds
 When pruning the cache for Incremental Link Time Optimization (LTO), the cache entries are removed after the
 specificied interval.
index 3297210e0ba0325677ba0e9e44310911d813ed25..f6c54d00e93272988878c89bda63117dfdd7424f 100644 (file)
@@ -47,6 +47,7 @@
                83046A851C8FF2F700024A7E /* objcimageinfo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 83046A841C8FF2D000024A7E /* objcimageinfo.cpp */; };
                B028FCF21A9E7C3F00E3584B /* bitcode_bundle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B028FCF11A9E7C3F00E3584B /* bitcode_bundle.cpp */; };
                B3B672421406D42800A376BB /* Snapshot.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B3B672411406D42800A376BB /* Snapshot.cpp */; };
+               C1E27B581F6B1B68003B8FA6 /* thread_starts.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C1E27B571F6B1B67003B8FA6 /* thread_starts.cpp */; };
                F9023C4E06D5A272001BBF46 /* ld.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F9023C3F06D5A254001BBF46 /* ld.cpp */; };
                F933E3D9092E855B0083EAC8 /* ObjectDump.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F971EED706D5AD240041D381 /* ObjectDump.cpp */; };
                F93CB248116E69EB003233B8 /* tlvp.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F93CB246116E69EB003233B8 /* tlvp.cpp */; };
                F97F5025070D0B6300B9FCD7 /* copy man page */ = {
                        isa = PBXCopyFilesBuildPhase;
                        buildActionMask = 8;
-                       dstPath = "$(DT_VARIANT)/$(DT_TOOLCHAIN_DIR)/usr/share/man/man1";
+                       dstPath = "$(DT_VARIANT)/$(TOOLCHAIN_INSTALL_DIR)/usr/share/man/man1";
                        dstSubfolderSpec = 0;
                        files = (
                                F97F5029070D0BB200B9FCD7 /* ld.1 in copy man page */,
                F9A3DE140ED76D7700C590B9 /* CopyFiles */ = {
                        isa = PBXCopyFilesBuildPhase;
                        buildActionMask = 8;
-                       dstPath = "$(DT_VARIANT)/$(DT_TOOLCHAIN_DIR)/usr/local/include/mach-o";
+                       dstPath = "$(DT_VARIANT)/$(TOOLCHAIN_INSTALL_DIR)/usr/local/include/mach-o";
                        dstSubfolderSpec = 0;
                        files = (
                                F9A3DE1E0ED7738300C590B9 /* prune_trie.h in CopyFiles */,
                F9B1A25E0A3A44CB00DA8FAB /* install man page */ = {
                        isa = PBXCopyFilesBuildPhase;
                        buildActionMask = 8;
-                       dstPath = "$(DT_VARIANT)/$(DT_TOOLCHAIN_DIR)/usr/share/man/man1";
+                       dstPath = "$(DT_VARIANT)/$(TOOLCHAIN_INSTALL_DIR)/usr/share/man/man1";
                        dstSubfolderSpec = 0;
                        files = (
                                F9B1A2640A3A563E00DA8FAB /* rebase.1 in install man page */,
                F9B813870EC2659600F94C13 /* install man page */ = {
                        isa = PBXCopyFilesBuildPhase;
                        buildActionMask = 8;
-                       dstPath = "$(DT_VARIANT)/$(DT_TOOLCHAIN_DIR)/usr/share/man/man1";
+                       dstPath = "$(DT_VARIANT)/$(TOOLCHAIN_INSTALL_DIR)/usr/share/man/man1";
                        dstSubfolderSpec = 0;
                        files = (
                                F9B813850EC2657800F94C13 /* unwinddump.1 in install man page */,
                F9C12EA50ED63E05005BC69D /* install man page */ = {
                        isa = PBXCopyFilesBuildPhase;
                        buildActionMask = 8;
-                       dstPath = "$(DT_VARIANT)/$(DT_TOOLCHAIN_DIR)/usr/share/man/man1";
+                       dstPath = "$(DT_VARIANT)/$(TOOLCHAIN_INSTALL_DIR)/usr/share/man/man1";
                        dstSubfolderSpec = 0;
                        files = (
                                F9C12EA30ED63DE7005BC69D /* dyldinfo.1 in install man page */,
                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; };
+               C1E27B571F6B1B67003B8FA6 /* thread_starts.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.cpp.cpp; path = thread_starts.cpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+               C1E27B591F6B1B70003B8FA6 /* thread_starts.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = thread_starts.h; sourceTree = "<group>"; };
                F9023C3906D5A23E001BBF46 /* ld */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = ld; sourceTree = BUILT_PRODUCTS_DIR; };
                F9023C3F06D5A254001BBF46 /* ld.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ld.cpp; path = src/ld/ld.cpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
                F91B7B0318987D5F0099486F /* AddressSpace.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = AddressSpace.hpp; sourceTree = "<group>"; };
                F9CC24181461FB4300A92174 /* superblob.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.h; path = superblob.h; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
                F9CCF761144CE1AD007CB524 /* create_configure */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = text.script.sh; name = create_configure; path = src/create_configure; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
                F9EA72CB097454A6008B4F1D /* machocheck */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = machocheck; sourceTree = BUILT_PRODUCTS_DIR; };
-               F9EA72D4097454FF008B4F1D /* machochecker.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = machochecker.cpp; path = src/other/machochecker.cpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+               F9EA72D4097454FF008B4F1D /* machochecker.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 4; lastKnownFileType = sourcecode.cpp.cpp; name = machochecker.cpp; path = src/other/machochecker.cpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
                F9EA7582097882F3008B4F1D /* debugline.c */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.c.c; name = debugline.c; path = src/ld/debugline.c; sourceTree = "<group>"; tabWidth = 8; 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; };
                                F9AE20FE1107D1440007ED5D /* dylibs.h */,
                                F9A4DB8F10F816FF00BD8423 /* objc.cpp */,
                                F9A4DB9010F816FF00BD8423 /* objc.h */,
+                               C1E27B571F6B1B67003B8FA6 /* thread_starts.cpp */,
+                               C1E27B591F6B1B70003B8FA6 /* thread_starts.h */,
                                F9AA650C1051BD2B003E3539 /* stubs */,
                        );
                        name = passes;
                        buildActionMask = 2147483647;
                        files = (
                                F9FC510A1BC893C400FEC3F8 /* code_dedup.cpp in Sources */,
+                               C1E27B581F6B1B68003B8FA6 /* thread_starts.cpp in Sources */,
                                FA95D6141AB25CF400395811 /* textstub_dylib_file.cpp in Sources */,
                                F9C0D4BD06DD28D2001C7193 /* Options.cpp in Sources */,
                                F9023C4E06D5A272001BBF46 /* ld.cpp in Sources */,
                                        "$(DEVELOPER_DIR)/usr/local/include",
                                        "$(DT_TOOLCHAIN_DIR)/usr/local/include",
                                );
-                               INSTALL_PATH = "$(DT_VARIANT)/$(DT_TOOLCHAIN_DIR)/usr/local/bin";
+                               INSTALL_PATH = "$(DT_VARIANT)/$(TOOLCHAIN_INSTALL_DIR)/usr/local/bin";
                                ONLY_ACTIVE_ARCH = NO;
                                PRODUCT_NAME = objcimageinfo;
                                SDKROOT = macosx.internal;
                                        "$(DEVELOPER_DIR)/usr/local/include",
                                        "$(DT_TOOLCHAIN_DIR)/usr/local/include",
                                );
-                               INSTALL_PATH = "$(DT_VARIANT)/$(DT_TOOLCHAIN_DIR)/usr/local/bin";
+                               INSTALL_PATH = "$(DT_VARIANT)/$(TOOLCHAIN_INSTALL_DIR)/usr/local/bin";
                                PRODUCT_NAME = objcimageinfo;
                                SDKROOT = macosx.internal;
                                WARNING_CFLAGS = (
                                        "$(DEVELOPER_DIR)/usr/local/include",
                                        "$(DT_TOOLCHAIN_DIR)/usr/local/include",
                                );
-                               INSTALL_PATH = "$(DT_VARIANT)/$(DT_TOOLCHAIN_DIR)/usr/local/bin";
+                               INSTALL_PATH = "$(DT_VARIANT)/$(TOOLCHAIN_INSTALL_DIR)/usr/local/bin";
                                PRODUCT_NAME = objcimageinfo;
                                SDKROOT = macosx.internal;
                                WARNING_CFLAGS = (
                                        "$(DT_TOOLCHAIN_DIR)/usr/local/include",
                                        "$(TOOLCHAIN_DIR)/usr/local/include",
                                );
-                               INSTALL_PATH = "$(DT_VARIANT)/$(DT_TOOLCHAIN_DIR)/usr/bin";
+                               INSTALL_PATH = "$(DT_VARIANT)/$(TOOLCHAIN_INSTALL_DIR)/usr/bin";
                                LD_RUNPATH_SEARCH_PATHS = "@executable_path/../lib/";
                                LINKER_DISPLAYS_MANGLED_NAMES = NO;
                                MACOSX_DEPLOYMENT_TARGET = "";
                                        "-L$(DT_TOOLCHAIN_DIR)/usr/lib",
                                        "-ltapi",
                                        "@$(DERIVED_FILE_DIR)/linkExtras",
+                                       "-Wl,-stack_size,0x10000000",
                                );
                                PREBINDING = NO;
                                PRODUCT_NAME = ld;
                                        "$(DT_TOOLCHAIN_DIR)/usr/local/include",
                                        "$(TOOLCHAIN_DIR)/usr/local/include",
                                );
-                               INSTALL_PATH = "$(DT_VARIANT)/$(DT_TOOLCHAIN_DIR)/usr/bin";
+                               INSTALL_PATH = "$(DT_VARIANT)/$(TOOLCHAIN_INSTALL_DIR)/usr/bin";
                                LD_RUNPATH_SEARCH_PATHS = "@executable_path/../lib/";
                                OTHER_CPLUSPLUSFLAGS = (
                                        "-stdlib=libc++",
                                        "-L$(DT_TOOLCHAIN_DIR)/usr/lib",
                                        "-ltapi",
                                        "@$(DERIVED_FILE_DIR)/linkExtras",
+                                       "-Wl,-stack_size,0x01000000",
                                );
                                PREBINDING = NO;
                                PRODUCT_NAME = ld;
                                        "$(TOOLCHAIN_DIR)/usr/local/include",
                                        "$(SRCROOT)/src/ld",
                                );
-                               INSTALL_PATH = "$(DT_VARIANT)/$(DT_TOOLCHAIN_DIR)/usr/local/bin";
+                               INSTALL_PATH = "$(DT_VARIANT)/$(TOOLCHAIN_INSTALL_DIR)/usr/local/bin";
                                ONLY_ACTIVE_ARCH = NO;
                                OTHER_CPLUSPLUSFLAGS = (
                                        "-stdlib=libc++",
                                        "$(TOOLCHAIN_DIR)/usr/local/include",
                                        "$(SRCROOT)/src/ld",
                                );
-                               INSTALL_PATH = "$(DT_VARIANT)/$(DT_TOOLCHAIN_DIR)/usr/local/bin";
+                               INSTALL_PATH = "$(DT_VARIANT)/$(TOOLCHAIN_INSTALL_DIR)/usr/local/bin";
                                OTHER_CPLUSPLUSFLAGS = (
                                        "-stdlib=libc++",
                                        "$(OTHER_CFLAGS)",
                        isa = XCBuildConfiguration;
                        buildSettings = {
                                ALWAYS_SEARCH_USER_PATHS = NO;
+                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
                                CLANG_WARN_BOOL_CONVERSION = YES;
                                CLANG_WARN_CONSTANT_CONVERSION = YES;
                                CLANG_WARN_EMPTY_BODY = YES;
                        isa = XCBuildConfiguration;
                        buildSettings = {
                                ALWAYS_SEARCH_USER_PATHS = NO;
+                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
                                CLANG_WARN_BOOL_CONVERSION = YES;
                                CLANG_WARN_CONSTANT_CONVERSION = YES;
                                CLANG_WARN_EMPTY_BODY = YES;
                        isa = XCBuildConfiguration;
                        buildSettings = {
                                ALWAYS_SEARCH_USER_PATHS = NO;
+                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
                                CLANG_WARN_BOOL_CONVERSION = YES;
                                CLANG_WARN_CONSTANT_CONVERSION = YES;
                                CLANG_WARN_EMPTY_BODY = YES;
                                        "$(DT_TOOLCHAIN_DIR)/usr/local/include",
                                        "$(TOOLCHAIN_DIR)/usr/local/include",
                                );
-                               INSTALL_PATH = "$(DT_VARIANT)/$(DT_TOOLCHAIN_DIR)/usr/bin";
+                               INSTALL_PATH = "$(DT_VARIANT)/$(TOOLCHAIN_INSTALL_DIR)/usr/bin";
                                LD_RUNPATH_SEARCH_PATHS = "@executable_path/../lib/";
                                OTHER_CPLUSPLUSFLAGS = (
                                        "-stdlib=libc++",
                                GCC_MODEL_TUNING = G5;
                                GCC_PREPROCESSOR_DEFINITIONS = "$(GCC_PREPROCESSOR_DEFINITIONS_$(RC_RELEASE))";
                                HEADER_SEARCH_PATHS = "";
-                               INSTALL_PATH = "$(DT_VARIANT)/$(DT_TOOLCHAIN_DIR)/usr/bin";
+                               INSTALL_PATH = "$(DT_VARIANT)/$(TOOLCHAIN_INSTALL_DIR)/usr/bin";
                                OTHER_LDFLAGS = "-Wl,-exported_symbol,__mh_execute_header";
                                PREBINDING = NO;
                                PRODUCT_NAME = rebase;
                                GCC_WARN_ABOUT_INVALID_OFFSETOF_MACRO = NO;
                                GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES;
                                HEADER_SEARCH_PATHS = "";
-                               INSTALL_PATH = "$(DT_VARIANT)/$(DT_TOOLCHAIN_DIR)/usr/bin";
+                               INSTALL_PATH = "$(DT_VARIANT)/$(TOOLCHAIN_INSTALL_DIR)/usr/bin";
                                OTHER_CPLUSPLUSFLAGS = (
                                        "-stdlib=libc++",
                                        "$(OTHER_CFLAGS)",
                                        "$(TOOLCHAIN_DIR)/usr/local/include",
                                        "$(SRCROOT)/src/ld",
                                );
-                               INSTALL_PATH = "$(DT_VARIANT)/$(DT_TOOLCHAIN_DIR)/usr/local/bin";
+                               INSTALL_PATH = "$(DT_VARIANT)/$(TOOLCHAIN_INSTALL_DIR)/usr/local/bin";
                                OTHER_CPLUSPLUSFLAGS = (
                                        "-stdlib=libc++",
                                        "$(OTHER_CFLAGS)",
                                GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
                                GCC_MODEL_TUNING = G5;
                                HEADER_SEARCH_PATHS = "";
-                               INSTALL_PATH = "$(DT_VARIANT)/$(DT_TOOLCHAIN_DIR)/usr/local/bin";
+                               INSTALL_PATH = "$(DT_VARIANT)/$(TOOLCHAIN_INSTALL_DIR)/usr/local/bin";
                                OTHER_CPLUSPLUSFLAGS = (
                                        "-stdlib=libc++",
                                        "$(OTHER_CFLAGS)",
                        isa = XCBuildConfiguration;
                        buildSettings = {
                                ALWAYS_SEARCH_USER_PATHS = NO;
+                               CLANG_CXX_LANGUAGE_STANDARD = "c++0x";
                                CLANG_CXX_LIBRARY = "libc++";
                                COPY_PHASE_STRIP = NO;
                                DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
                                GCC_ENABLE_FIX_AND_CONTINUE = NO;
                                GCC_MODEL_TUNING = G5;
-                               INSTALL_PATH = "$(DT_VARIANT)/$(DT_TOOLCHAIN_DIR)/usr/bin";
+                               INSTALL_PATH = "$(DT_VARIANT)/$(TOOLCHAIN_INSTALL_DIR)/usr/bin";
                                OTHER_CPLUSPLUSFLAGS = (
                                        "-stdlib=libc++",
                                        "$(OTHER_CFLAGS)",
                                GCC_ENABLE_FIX_AND_CONTINUE = NO;
                                GCC_MODEL_TUNING = G5;
                                GCC_SYMBOLS_PRIVATE_EXTERN = YES;
-                               INSTALL_PATH = "$(DT_VARIANT)/$(DT_TOOLCHAIN_DIR)/usr/local/lib";
+                               INSTALL_PATH = "$(DT_VARIANT)/$(TOOLCHAIN_INSTALL_DIR)/usr/local/lib";
                                OTHER_CPLUSPLUSFLAGS = (
                                        "-stdlib=libc++",
                                        "$(OTHER_CFLAGS)",
                                GCC_OPTIMIZATION_LEVEL = 0;
                                GCC_SYMBOLS_PRIVATE_EXTERN = YES;
                                GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES;
-                               INSTALL_PATH = "$(DT_VARIANT)/$(DT_TOOLCHAIN_DIR)/usr/local/lib";
+                               INSTALL_PATH = "$(DT_VARIANT)/$(TOOLCHAIN_INSTALL_DIR)/usr/local/lib";
                                OTHER_CPLUSPLUSFLAGS = (
                                        "-stdlib=libc++",
                                        "$(OTHER_CFLAGS)",
                                GCC_ENABLE_FIX_AND_CONTINUE = NO;
                                GCC_MODEL_TUNING = G5;
                                GCC_SYMBOLS_PRIVATE_EXTERN = YES;
-                               INSTALL_PATH = "$(DT_VARIANT)/$(DT_TOOLCHAIN_DIR)/usr/local/lib";
+                               INSTALL_PATH = "$(DT_VARIANT)/$(TOOLCHAIN_INSTALL_DIR)/usr/local/lib";
                                OTHER_CPLUSPLUSFLAGS = (
                                        "-stdlib=libc++",
                                        "$(OTHER_CFLAGS)",
                                GCC_OPTIMIZATION_LEVEL = 0;
                                GCC_WARN_ABOUT_INVALID_OFFSETOF_MACRO = NO;
                                GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES;
-                               INSTALL_PATH = "$(DT_VARIANT)/$(DT_TOOLCHAIN_DIR)/usr/bin";
+                               INSTALL_PATH = "$(DT_VARIANT)/$(TOOLCHAIN_INSTALL_DIR)/usr/bin";
                                OTHER_CPLUSPLUSFLAGS = (
                                        "-stdlib=libc++",
                                        "$(OTHER_CFLAGS)",
                                GCC_WARN_ABOUT_INVALID_OFFSETOF_MACRO = NO;
                                GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES;
                                HEADER_SEARCH_PATHS = "";
-                               INSTALL_PATH = "$(DT_VARIANT)/$(DT_TOOLCHAIN_DIR)/usr/bin";
+                               INSTALL_PATH = "$(DT_VARIANT)/$(TOOLCHAIN_INSTALL_DIR)/usr/bin";
                                OTHER_CPLUSPLUSFLAGS = (
                                        "-stdlib=libc++",
                                        "$(OTHER_CFLAGS)",
                        isa = XCBuildConfiguration;
                        buildSettings = {
                                ALWAYS_SEARCH_USER_PATHS = NO;
+                               CLANG_CXX_LANGUAGE_STANDARD = "c++0x";
                                CLANG_CXX_LIBRARY = "libc++";
                                COPY_PHASE_STRIP = NO;
                                GCC_DYNAMIC_NO_PIC = NO;
                                GCC_WARN_UNUSED_LABEL = NO;
                                GCC_WARN_UNUSED_VALUE = YES;
                                GCC_WARN_UNUSED_VARIABLE = YES;
-                               INSTALL_PATH = "$(DT_VARIANT)/$(DT_TOOLCHAIN_DIR)/usr/bin";
+                               INSTALL_PATH = "$(DT_VARIANT)/$(TOOLCHAIN_INSTALL_DIR)/usr/bin";
                                OTHER_CPLUSPLUSFLAGS = (
                                        "-stdlib=libc++",
                                        "$(OTHER_CFLAGS)",
                        isa = XCBuildConfiguration;
                        buildSettings = {
                                ALWAYS_SEARCH_USER_PATHS = NO;
+                               CLANG_CXX_LANGUAGE_STANDARD = "c++0x";
                                CLANG_CXX_LIBRARY = "libc++";
                                COPY_PHASE_STRIP = NO;
                                DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
                                GCC_ENABLE_FIX_AND_CONTINUE = NO;
                                GCC_MODEL_TUNING = G5;
-                               INSTALL_PATH = "$(DT_VARIANT)/$(DT_TOOLCHAIN_DIR)/usr/bin";
+                               INSTALL_PATH = "$(DT_VARIANT)/$(TOOLCHAIN_INSTALL_DIR)/usr/bin";
                                OTHER_CPLUSPLUSFLAGS = (
                                        "-stdlib=libc++",
                                        "$(OTHER_CFLAGS)",
                                GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
                                GCC_MODEL_TUNING = G5;
                                GCC_OPTIMIZATION_LEVEL = 0;
-                               INSTALL_PATH = "$(DT_VARIANT)/$(DT_TOOLCHAIN_DIR)/usr/local/bin";
+                               INSTALL_PATH = "$(DT_VARIANT)/$(TOOLCHAIN_INSTALL_DIR)/usr/local/bin";
                                OTHER_CPLUSPLUSFLAGS = (
                                        "-stdlib=libc++",
                                        "$(OTHER_CFLAGS)",
                                GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
                                GCC_MODEL_TUNING = G5;
                                HEADER_SEARCH_PATHS = "";
-                               INSTALL_PATH = "$(DT_VARIANT)/$(DT_TOOLCHAIN_DIR)/usr/local/bin";
+                               INSTALL_PATH = "$(DT_VARIANT)/$(TOOLCHAIN_INSTALL_DIR)/usr/local/bin";
                                OTHER_CPLUSPLUSFLAGS = (
                                        "-stdlib=libc++",
                                        "$(OTHER_CFLAGS)",
                                GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
                                GCC_MODEL_TUNING = G5;
                                GCC_OPTIMIZATION_LEVEL = 0;
-                               INSTALL_PATH = "$(DT_VARIANT)/$(DT_TOOLCHAIN_DIR)/usr/bin";
+                               INSTALL_PATH = "$(DT_VARIANT)/$(TOOLCHAIN_INSTALL_DIR)/usr/bin";
                                PREBINDING = NO;
                                PRODUCT_NAME = rebase;
                                SDKROOT = macosx.internal;
                                GCC_MODEL_TUNING = G5;
                                GCC_PREPROCESSOR_DEFINITIONS = "$(GCC_PREPROCESSOR_DEFINITIONS_$(RC_RELEASE))";
                                HEADER_SEARCH_PATHS = "";
-                               INSTALL_PATH = "$(DT_VARIANT)/$(DT_TOOLCHAIN_DIR)/usr/bin";
+                               INSTALL_PATH = "$(DT_VARIANT)/$(TOOLCHAIN_INSTALL_DIR)/usr/bin";
                                OTHER_LDFLAGS = "-Wl,-exported_symbol,__mh_execute_header";
                                PREBINDING = NO;
                                PRODUCT_NAME = rebase;
index 252e41326bc0b6a28f44620a244f05c74214ad5c..a7198dfc60c4caca2e8c963a137c682aeabe42fe 100644 (file)
@@ -64,6 +64,9 @@
 #ifndef MH_KEXT_BUNDLE
        #define MH_KEXT_BUNDLE 11
 #endif
+#ifndef MH_SIM_SUPPORT
+       #define MH_SIM_SUPPORT 0x08000000
+#endif
 #ifndef LC_DYLD_INFO
        #define LC_DYLD_INFO    0x22    /* compressed dyld information */
        #define LC_DYLD_INFO_ONLY (0x22|LC_REQ_DYLD)    /* compressed dyld information only */
        #define EXPORT_SYMBOL_FLAGS_INDIRECT_DEFINITION                 0x08
        #define EXPORT_SYMBOL_FLAGS_HAS_SPECIALIZATIONS                 0x10
 
-#endif 
+#endif
+
+#ifndef BIND_SPECIAL_DYLIB_WEAK_LOOKUP
+#define BIND_SPECIAL_DYLIB_WEAK_LOOKUP                         -3
+#endif
+
+#ifndef BIND_OPCODE_THREADED
+#define BIND_OPCODE_THREADED   0xD0
+#endif
+
+#ifndef BIND_SUBOPCODE_THREADED_SET_BIND_ORDINAL_TABLE_SIZE_ULEB
+#define BIND_SUBOPCODE_THREADED_SET_BIND_ORDINAL_TABLE_SIZE_ULEB       0x00
+#endif
+
+#ifndef BIND_SUBOPCODE_THREADED_APPLY
+#define BIND_SUBOPCODE_THREADED_APPLY                                                          0x01
+#endif
+
+#if SUPPORT_ARCH_arm64e
+
+// clang encodes the combination of the key bits as these values.
+typedef enum {
+       ptrauth_key_asia = 0,
+       ptrauth_key_asib = 1,
+       ptrauth_key_asda = 2,
+       ptrauth_key_asdb = 3,
+} ptrauth_key;
+
+#endif
 
 #ifndef S_THREAD_LOCAL_REGULAR
        #define S_THREAD_LOCAL_REGULAR                   0x11
 #define ARM64_RELOC_TLVP_LOAD_PAGEOFF12 9 // offset within page of TLVP slot, scaled by r_length
 #define ARM64_RELOC_ADDEND                             10 // r_symbolnum is addend for next reloc
 
+#if SUPPORT_ARCH_arm64e
+       #define ARM64_RELOC_AUTHENTICATED_POINTER                               11 // An authenticated pointer.
+#endif
 
 
 #define UNW_ARM64_X0     0
 #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
+#define DYLD_CACHE_ADJ_V2_THREADED_POINTER_64                  0x0D
 
 
 #ifndef LC_BUILD_VERSION
        };
 #endif
 
+#ifndef PLATFORM_IOSMAC
+       #define PLATFORM_IOSMAC 6
+#endif
 
 // kind target-address fixup-addr [adj] 
 
index 7ba470b339b833cf37fcebd4ca838a1445b51279..4ab39985fd883755389196b213630f97bed637da 100755 (executable)
@@ -25,18 +25,7 @@ do
        fi
 done
 
-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
+echo "#define ALL_SUPPORTED_ARCHS  \"${RC_SUPPORTED_ARCHS}\"" >> ${DERIVED_FILE_DIR}/configure.h
 
 if [ -f "${DT_TOOLCHAIN_DIR}/usr/lib/libswiftDemangle.dylib" ]; then
        echo "${DT_TOOLCHAIN_DIR}/usr/lib/libswiftDemangle.dylib" >  ${DERIVED_FILE_DIR}/linkExtras
index eca8c561ed5b5fdc3523b264c9d24e0cf73cef7c..3bfd95b1c2affcad9b339cf8342c8197962166a8 100644 (file)
@@ -62,6 +62,7 @@ struct arm64
 };
 
 
+
 #endif // __ARCHITECTURES__
 
 
index fbcc13fe7c4ceb35d34eed24896decce70671dfa..e03c59c35c5a7fb53e46c92b4e2e7ebbc98f2b92 100644 (file)
@@ -69,6 +69,8 @@ public:
        virtual const char*                                                     name() const            { return "mach-o header and load commands"; }
        virtual uint64_t                                                        size() const;
        virtual uint64_t                                                        objectAddress() const { return _address; }
+       virtual bool                                                            lcBuildVersionDisabled() const;
+
        virtual void                                                            copyRawContent(uint8_t buffer[]) const;
 
        // overrides of HeaderAndLoadCommandsAbtract
@@ -105,8 +107,8 @@ private:
        uint8_t*                                        copyDylibIDLoadCommand(uint8_t* p) const;
        uint8_t*                                        copyRoutinesLoadCommand(uint8_t* p) const;
        uint8_t*                                        copyUUIDLoadCommand(uint8_t* p) const;
-       uint8_t*                                        copyVersionLoadCommand(uint8_t* p) const;
-       uint8_t*                                        copyBuildVersionLoadCommand(uint8_t* p) const;
+       uint8_t*                                        copyVersionLoadCommand(uint8_t* p, const ld::Platform& platform, uint32_t minVersion, uint32_t sdkVersion) const;
+       uint8_t*                                        copyBuildVersionLoadCommand(uint8_t* p, const ld::Platform& platform, uint32_t minVersion, uint32_t sdkVersion) const;
        uint8_t*                                        copySourceVersionLoadCommand(uint8_t* p) const;
        uint8_t*                                        copyThreadsLoadCommand(uint8_t* p) const;
        uint8_t*                                        copyEntryPointLoadCommand(uint8_t* p) const;
@@ -146,12 +148,12 @@ private:
        bool                                            _hasRPathLoadCommands;
        bool                                            _hasSubFrameworkLoadCommand;
        bool                                            _hasVersionLoadCommand;
-       bool                                            _hasBuildVersionLoadCommand;
        bool                                            _hasFunctionStartsLoadCommand;
        bool                                            _hasDataInCodeLoadCommand;
        bool                                            _hasSourceVersionLoadCommand;
        bool                                            _hasOptimizationHints;
-       Options::Platform                       _platform;
+       bool                                            _simulatorSupportDylib;
+       ld::VersionSet                          _platforms;
        uint32_t                                        _dylibLoadCommmandsCount;
        uint32_t                                        _allowableClientLoadCommmandsCount;
        uint32_t                                        _dyldEnvironExrasCount;
@@ -238,21 +240,24 @@ HeaderAndLoadCommandsAtom<A>::HeaderAndLoadCommandsAtom(const Options& opts, ld:
        }
        _hasRPathLoadCommands = (_options.rpaths().size() != 0);
        _hasSubFrameworkLoadCommand = (_options.umbrellaName() != NULL);
-       _platform = _options.platform();
-       if ( (_platform == Options::kPlatformUnknown) && (_state.derivedPlatform != 0) )
-               _platform = (Options::Platform)_state.derivedPlatform;
-       if ( _options.addVersionLoadCommand() ) {
-               _hasBuildVersionLoadCommand = _options.addBuildVersionLoadCommand();
-               _hasVersionLoadCommand = !_hasBuildVersionLoadCommand;
-       }
-       else if (((_options.outputKind() == Options::kObjectFile) && (_platform != Options::kPlatformUnknown) && !state.objectFileFoundWithNoVersion) ) {
-               _hasBuildVersionLoadCommand = (_platform == Options::kPlatform_bridgeOS);
-               _hasVersionLoadCommand = !_hasBuildVersionLoadCommand;
-       }
-       else {
-               _hasVersionLoadCommand = false;
-               _hasBuildVersionLoadCommand = false;
+       _platforms = _options.platforms();
+       if ( _platforms.empty() && (!_state.derivedPlatforms.empty()) )
+               _platforms = _state.derivedPlatforms;
+       if (_platforms.contains(ld::kPlatform_macOS) &&
+               ((strcmp(_options.installPath(), "/usr/lib/system/libsystem_kernel.dylib") == 0)
+                || (strcmp(_options.installPath(), "/usr/lib/system/libsystem_platform.dylib") == 0)
+                || (strcmp(_options.installPath(), "/usr/lib/system/libsystem_pthread.dylib") == 0)
+                || (strcmp(_options.installPath(), "/usr/lib/system/libsystem_platform_debug.dylib") == 0)
+                || (strcmp(_options.installPath(), "/usr/lib/system/libsystem_pthread_debug.dylib") == 0)
+                || (strcmp(_options.installPath(), "/System/Library/PrivateFrameworks/SiriUI.framework/Versions/A/SiriUI") == 0))) {
+               _simulatorSupportDylib = true;
+       } else {
+               _simulatorSupportDylib = false;
        }
+       _hasVersionLoadCommand = _options.addVersionLoadCommand();
+       // in ld -r mode, only if all input .o files have load command, then add one to output
+       if ( !_hasVersionLoadCommand && (_options.outputKind() == Options::kObjectFile) && !state.objectFileFoundWithNoVersion )
+               _hasVersionLoadCommand = true;
        _hasFunctionStartsLoadCommand = _options.addFunctionStarts();
        _hasDataInCodeLoadCommand = _options.addDataInCodeInfo();
        _hasSourceVersionLoadCommand = _options.needsSourceVersionLoadCommand();
@@ -424,12 +429,22 @@ uint64_t HeaderAndLoadCommandsAtom<A>::size() const
        if ( _hasUUIDLoadCommand )
                sz += sizeof(macho_uuid_command<P>);
 
-       if ( _hasVersionLoadCommand )
-               sz += sizeof(macho_version_min_command<P>);
-       
-       if ( _hasBuildVersionLoadCommand )
-               sz += alignedSize(sizeof(macho_build_version_command<P>) + sizeof(macho_build_tool_version<P>)*_toolsVersions.size());
-       
+       if ( _hasVersionLoadCommand ) {
+               if (_simulatorSupportDylib) {
+#if 0
+//FIXME hack to workaround simulator issues without cctools changes
+                       sz += sizeof(macho_version_min_command<P>);
+                       sz += (_options.platforms().count() * alignedSize(sizeof(macho_build_version_command<P>) + sizeof(macho_build_tool_version<P>)*_toolsVersions.size()));
+#else
+                       sz += sizeof(macho_version_min_command<P>);
+#endif
+               } else if (_options.platforms().minOS(ld::supportsLCBuildVersion) && !lcBuildVersionDisabled()) {
+                       sz += (_options.platforms().count() * alignedSize(sizeof(macho_build_version_command<P>) + sizeof(macho_build_tool_version<P>)*_toolsVersions.size()));
+               } else {
+                       sz += sizeof(macho_version_min_command<P>);
+               }
+       }
+
        if ( _hasSourceVersionLoadCommand )
                sz += sizeof(macho_source_version_command<P>);
                
@@ -529,13 +544,23 @@ uint32_t HeaderAndLoadCommandsAtom<A>::commandsCount() const
                
        if ( _hasUUIDLoadCommand )
                ++count;
-       
-       if ( _hasVersionLoadCommand )
-               ++count;
 
-       if ( _hasBuildVersionLoadCommand )
-               ++count;
-       
+       if ( _hasVersionLoadCommand ) {
+               if (_simulatorSupportDylib) {
+#if 0
+                       //FIXME hack to workaround simulator issues without cctools changes
+                       ++count;
+                       count += _options.platforms().count();
+#else
+                       ++count;
+#endif
+               } else if (_options.platforms().minOS(ld::supportsLCBuildVersion) && !lcBuildVersionDisabled()) {
+                       count += _options.platforms().count();
+               } else {
+                       ++count;
+               }
+       }
+
        if ( _hasSourceVersionLoadCommand )
                ++count;
                
@@ -642,10 +667,6 @@ uint32_t HeaderAndLoadCommandsAtom<A>::flags() const
                                bits |= MH_WEAK_DEFINES;
                        if ( _writer.usesWeakExternalSymbols || _state.hasWeakExternalSymbols )
                                bits |= MH_BINDS_TO_WEAK;
-                       if ( _options.prebind() )
-                               bits |= MH_PREBOUND;
-                       if ( _options.splitSeg() )
-                               bits |= MH_SPLIT_SEGS;
                        if ( (_options.outputKind() == Options::kDynamicLibrary) 
                                        && _writer._noReExportedDylibs 
                                        && _options.useSimplifiedDylibReExports() ) {
@@ -661,6 +682,11 @@ uint32_t HeaderAndLoadCommandsAtom<A>::flags() const
                                bits |= MH_NO_HEAP_EXECUTION;
                        if ( _options.markAppExtensionSafe() && (_options.outputKind() == Options::kDynamicLibrary) )
                                bits |= MH_APP_EXTENSION_SAFE;
+#if 0
+                       //FIXME hack to workaround simulator issues without cctools changes
+                       if (_simulatorSupportDylib)
+                               bits |= MH_SIM_SUPPORT;
+#endif
                }
                if ( _options.hasExecutableStack() )
                        bits |= MH_ALLOW_STACK_EXECUTION;
@@ -688,7 +714,7 @@ uint32_t HeaderAndLoadCommandsAtom<x86>::cpuSubType() const
 template <>
 uint32_t HeaderAndLoadCommandsAtom<x86_64>::cpuSubType() const
 {
-       if ( (_options.outputKind() == Options::kDynamicExecutable) && (_state.cpuSubType == CPU_SUBTYPE_X86_64_ALL) && (_options.macosxVersionMin() >= ld::mac10_5) )
+       if ( (_options.outputKind() == Options::kDynamicExecutable) && (_state.cpuSubType == CPU_SUBTYPE_X86_64_ALL) && _options.platforms().minOS(ld::mac10_5) )
                return (_state.cpuSubType | 0x80000000);
        else
                return _state.cpuSubType;
@@ -847,6 +873,8 @@ uint32_t HeaderAndLoadCommandsAtom<A>::sectionFlags(ld::Internal::FinalSection*
                        return S_DTRACE_DOF;
                case ld::Section::typeUnwindInfo:
                        return S_REGULAR;
+               case ld::Section::typeThreadStarts:
+                       return S_REGULAR;
                case ld::Section::typeObjCClassRefs:
                case ld::Section::typeObjC2CategoryList:
                        return S_REGULAR | S_ATTR_NO_DEAD_STRIP;
@@ -1179,40 +1207,44 @@ uint8_t* HeaderAndLoadCommandsAtom<A>::copyUUIDLoadCommand(uint8_t* p) const
 
 
 template <typename A>
-uint8_t* HeaderAndLoadCommandsAtom<A>::copyVersionLoadCommand(uint8_t* p) const
+uint8_t* HeaderAndLoadCommandsAtom<A>::copyVersionLoadCommand(uint8_t* p, const ld::Platform& platform, uint32_t minVersion, uint32_t sdkVersion) const
 {
        macho_version_min_command<P>* cmd = (macho_version_min_command<P>*)p;
-       switch (_platform) {
-               case Options::kPlatformOSX:
+       switch (platform) {
+               case ld::kPlatform_macOS:
                        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());
+                       cmd->set_version(minVersion);
+                       cmd->set_sdk(sdkVersion);
                        break;
-               case Options::kPlatformiOS:
+               case ld::kPlatform_iOS:
+               case ld::kPlatform_iOSSimulator:
                        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());
+                       cmd->set_version(minVersion);
+                       cmd->set_sdk(sdkVersion);
                        break;
-               case Options::kPlatformWatchOS:
+               case ld::kPlatform_watchOS:
+               case ld::kPlatform_watchOSSimulator:
                        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());
+                       cmd->set_version(minVersion);
+                       cmd->set_sdk(sdkVersion);
                        break;
-#if SUPPORT_APPLE_TV
-               case Options::kPlatform_tvOS:
+               case ld::kPlatform_tvOS:
+               case ld::kPlatform_tvOSSimulator:
                        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());
+                       cmd->set_version(minVersion);
+                       cmd->set_sdk(sdkVersion);
                        break;
-#endif
-               case Options::kPlatformUnknown:
+               case ld::kPlatform_unknown:
                        assert(0 && "unknown platform");
                        break;
-               case Options::kPlatform_bridgeOS:
+               case ld::kPlatform_iOSMac:
+                       assert(0 && "iOSMac uses LC_BUILD_VERSION");
+                       break;
+               case ld::kPlatform_bridgeOS:
                        assert(0 && "bridgeOS uses LC_BUILD_VERSION");
                        break;
        }
@@ -1222,15 +1254,15 @@ uint8_t* HeaderAndLoadCommandsAtom<A>::copyVersionLoadCommand(uint8_t* p) const
 
 
 template <typename A>
-uint8_t* HeaderAndLoadCommandsAtom<A>::copyBuildVersionLoadCommand(uint8_t* p) const
+       uint8_t* HeaderAndLoadCommandsAtom<A>::copyBuildVersionLoadCommand(uint8_t* p, const ld::Platform& platform, uint32_t minVersion, uint32_t sdkVersion) const
 {
        macho_build_version_command<P>* cmd = (macho_build_version_command<P>*)p;
        
        cmd->set_cmd(LC_BUILD_VERSION);
        cmd->set_cmdsize(alignedSize(sizeof(macho_build_version_command<P>) + sizeof(macho_build_tool_version<P>)*_toolsVersions.size()));
-       cmd->set_platform(_options.platform());
-       cmd->set_minos(_state.minOSVersion);
-       cmd->set_sdk(_options.sdkVersion());
+       cmd->set_platform(platform);
+       cmd->set_minos(minVersion);
+       cmd->set_sdk(sdkVersion);
        cmd->set_ntools(_toolsVersions.size());
        macho_build_tool_version<P>* tools = (macho_build_tool_version<P>*)(p + sizeof(macho_build_version_command<P>));
        for (uint64_t tool : _toolsVersions) {
@@ -1551,6 +1583,17 @@ uint8_t* HeaderAndLoadCommandsAtom<A>::copyOptimizationHintsLoadCommand(uint8_t*
        return p + sizeof(macho_linkedit_data_command<P>);
 }
 
+template <typename A>
+bool HeaderAndLoadCommandsAtom<A>::lcBuildVersionDisabled() const {
+       static std::once_flag envChecked;
+       static bool disabled = false;
+       std::call_once(envChecked, [&](){
+               if (getenv("LD_FORCE_LEGACY_VERSION_LOAD_CMDS") != nullptr ) {
+                       disabled = true;
+               }
+       });
+       return disabled;
+}
 
 template <typename A>
 void HeaderAndLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
@@ -1568,7 +1611,7 @@ void HeaderAndLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
        mh->set_flags(this->flags());
 
        // copy load commands
-       uint8_t* p = &buffer[sizeof(macho_header<P>)];
+       __block uint8_t* p = &buffer[sizeof(macho_header<P>)];
        
        if ( _options.outputKind() == Options::kObjectFile )
                p = this->copySingleSegmentLoadCommand(p);
@@ -1595,12 +1638,33 @@ void HeaderAndLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
                
        if ( _hasUUIDLoadCommand )
                p = this->copyUUIDLoadCommand(p);
-       
-       if ( _hasVersionLoadCommand )
-               p = this->copyVersionLoadCommand(p);
 
-       if ( _hasBuildVersionLoadCommand )
-               p = this->copyBuildVersionLoadCommand(p);
+       if ( _hasVersionLoadCommand ) {
+               if (_simulatorSupportDylib) {
+#if 0
+                       //FIXME hack to workaround simulator issues without cctools changes
+                       p = this->copyVersionLoadCommand(p, ld::kPlatform_macOS, 0, _options.sdkVersion());
+                       _options.platforms().forEach(^(ld::Platform platform, uint32_t version, bool &stop) {
+                               p = this->copyBuildVersionLoadCommand(p, platform, version, _options.sdkVersion());
+                       });
+#else
+                       _options.platforms().forEach(^(ld::Platform platform, uint32_t version, bool &stop) {
+                               if (platform == ld::kPlatform_macOS) {
+                                       p = this->copyVersionLoadCommand(p, platform, version, _options.sdkVersion());
+                               }
+                       });
+#endif
+               } else if (_options.platforms().minOS(ld::supportsLCBuildVersion) && !lcBuildVersionDisabled()) {
+                       _options.platforms().forEach(^(ld::Platform platform, uint32_t version, bool &stop) {
+                               p = this->copyBuildVersionLoadCommand(p, platform, version, _options.sdkVersion());
+                       });
+               } else {
+                       assert(_platforms.count() == 1 && "LC_BUILD_VERSION required when there are multiple platforms");
+                       _options.platforms().forEach(^(ld::Platform platform, uint32_t version, bool &stop) {
+                               p = this->copyVersionLoadCommand(p, platform, version, _options.sdkVersion());
+                       });
+               }
+       }
 
        if ( _hasSourceVersionLoadCommand )
                p = this->copySourceVersionLoadCommand(p);
index 2a79ae2ced8b5edcff7df38a3250c81e0ec1f6f8..af66ec71994c2accc5c1a620774bc370a42ff85d 100644 (file)
@@ -217,10 +217,11 @@ ld::File* InputFiles::makeFile(const Options::FileInfo& info, bool indirectDylib
        // handle inlined framework first.
        if (info.isInlined) {
                auto interface = _options.findTAPIFile(info.path);
-               auto file = textstub::dylib::parse(info.path, std::move(interface), info.modTime, info.ordinal, _options, indirectDylib);
-               assert(file && "could not locate the inlined file");
+               if (!interface)
+                       throwf("could not find inlined dylib file: %s", info.path);
+               auto file = textstub::dylib::parse(info.path, interface, info.modTime, info.ordinal, _options, indirectDylib);
                if (!file)
-                       throwf("could not parse inline dylib file: %s(%s)", interface->getInstallName().c_str(), info.path);
+                       throwf("could not parse inlined dylib file: %s(%s)", interface->getInstallName().c_str(), info.path);
                return file;
        }
        // map in whole file
@@ -247,11 +248,19 @@ ld::File* InputFiles::makeFile(const Options::FileInfo& info, bool indirectDylib
                const struct fat_arch* archs = (struct fat_arch*)(p + sizeof(struct fat_header));
                bool sliceFound = false;
                sliceCount = OSSwapBigToHostInt32(fh->nfat_arch);
-               if ( _options.preferSubArchitecture() ) {
-                       // first try to find a slice that match cpu-type and cpu-sub-type
+               // first try to find a slice that match cpu-type and cpu-sub-type
+               for (uint32_t i=0; i < sliceCount; ++i) {
+                       if ( (OSSwapBigToHostInt32(archs[i].cputype) == (uint32_t)_options.architecture())
+                         && ((OSSwapBigToHostInt32(archs[i].cpusubtype) & ~CPU_SUBTYPE_MASK) == (uint32_t)_options.subArchitecture()) ) {
+                               sliceToUse = i;
+                               sliceFound = true;
+                               break;
+                       }
+               }
+               if ( !sliceFound && _options.allowSubArchitectureMismatches() ) {
+                       // look for any slice that matches just cpu-type
                        for (uint32_t i=0; i < sliceCount; ++i) {
-                               if ( (OSSwapBigToHostInt32(archs[i].cputype) == (uint32_t)_options.architecture())
-                                 && (OSSwapBigToHostInt32(archs[i].cpusubtype) == (uint32_t)_options.subArchitecture()) ) {
+                               if ( OSSwapBigToHostInt32(archs[i].cputype) == (uint32_t)_options.architecture() ) {
                                        sliceToUse = i;
                                        sliceFound = true;
                                        break;
@@ -259,9 +268,10 @@ ld::File* InputFiles::makeFile(const Options::FileInfo& info, bool indirectDylib
                        }
                }
                if ( !sliceFound ) {
-                       // look for any slice that matches just cpu-type
-                       for (uint32_t i=0; i < sliceCount; ++i) {
-                               if ( OSSwapBigToHostInt32(archs[i].cputype) == (uint32_t)_options.architecture() ) {
+                       // Look for a fallback slice.
+                       for (uint32_t i = 0; i < sliceCount; ++i) {
+                               if ( OSSwapBigToHostInt32(archs[i].cputype) == (uint32_t)_options.fallbackArchitecture() &&
+                                       OSSwapBigToHostInt32(archs[i].cpusubtype) == (uint32_t)_options.fallbackSubArchitecture() ) {
                                        sliceToUse = i;
                                        sliceFound = true;
                                        break;
@@ -313,9 +323,11 @@ ld::File* InputFiles::makeFile(const Options::FileInfo& info, bool indirectDylib
        objOpts.armUsesZeroCostExceptions = _options.armUsesZeroCostExceptions();
        objOpts.simulator                       = _options.targetIOSSimulator();
        objOpts.ignoreMismatchPlatform = ((_options.outputKind() == Options::kPreload) || (_options.outputKind() == Options::kStaticExecutable));
+#if SUPPORT_ARCH_arm64e
+       objOpts.supportsAuthenticatedPointers = _options.supportsAuthenticatedPointers();
+#endif
        objOpts.subType                         = _options.subArchitecture();
-       objOpts.platform                        = _options.platform();
-       objOpts.minOSVersion            = _options.minOSversion();
+       objOpts.platforms                       = _options.platforms();
        objOpts.srcKind                         = ld::relocatable::File::kSourceObj;
        objOpts.treateBitcodeAsData     = _options.bitcodeKind() == Options::kBitcodeAsData;
        objOpts.usingBitcode            = _options.bundleBitcode();
@@ -427,7 +439,7 @@ ld::File* InputFiles::makeFile(const Options::FileInfo& info, bool indirectDylib
        }
        else {
                if ( isFatFile )
-                       throwf("file is universal (%u slices) but does not contain a(n) %s slice: %s", sliceCount, _options.architectureName(), info.path);
+                       throwf("file is universal (%u slices) but does not contain the %s architecture: %s", sliceCount, _options.architectureName(), info.path);
                else
                        throwf("file was built for %s which is not the architecture being linked (%s): %s", fileArch(p, len), _options.architectureName(), info.path);
        }
@@ -659,7 +671,8 @@ void InputFiles::addLinkerOptionLibraries(ld::Internal& state, ld::File::AtomHan
                                }
                        }
                        catch (const char* msg) {
-                               warning("Auto-Linking %s", msg);
+                               // <rdar://problem/40829444> only warn about missing auto-linked framework if some missing symbol error happens later
+                               state.missingLinkerOptionFrameworks.insert(frameworkName);
                        }
                        state.linkerOptionFrameworks.insert(frameworkName);
                }
@@ -701,7 +714,8 @@ void InputFiles::addLinkerOptionLibraries(ld::Internal& state, ld::File::AtomHan
                                }
                        }
                        catch (const char* msg) {
-                               warning("Auto-Linking %s", msg);
+                               // <rdar://problem/40829444> only warn about missing auto-linked library if some missing symbol error happens later
+                               state.missingLinkerOptionLibraries.insert(libName);
                        }
                        state.linkerOptionLibraries.insert(libName);
                }
@@ -861,9 +875,10 @@ void InputFiles::inferArchitecture(Options& opts, const char** archName)
                                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);
+                                       ld::Platform platform;
+                                       uint32_t        minOsVersion;
+                                       if ( mach_o::relocatable::isObjectFile(buffer, &type, &subtype, &platform, &minOsVersion) ) {
+                                               opts.setArchitecture(type, subtype, platform, minOsVersion);
                                                *archName = opts.architectureName();
                                                return;
                                        }
@@ -875,11 +890,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__
-       opts.setArchitecture(CPU_TYPE_I386, CPU_SUBTYPE_X86_ALL, Options::kPlatformOSX);
+       opts.setArchitecture(CPU_TYPE_I386, CPU_SUBTYPE_X86_ALL, ld::kPlatform_macOS, 0);
 #elif __x86_64__
-       opts.setArchitecture(CPU_TYPE_X86_64, CPU_SUBTYPE_X86_64_ALL, Options::kPlatformOSX);
+       opts.setArchitecture(CPU_TYPE_X86_64, CPU_SUBTYPE_X86_64_ALL, ld::kPlatform_macOS, 0);
 #elif __arm__
-       opts.setArchitecture(CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V6, Options::kPlatformOSX);
+       opts.setArchitecture(CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V6, ld::kPlatform_macOS, 0);
 #else
        #error unknown default architecture
 #endif
@@ -1485,8 +1500,16 @@ void InputFiles::dylibs(ld::Internal& state)
        state.bundleLoader = _bundleLoader;
        
        // <rdar://problem/10807040> give an error when -nostdlib is used and libSystem is missing
-       if ( (state.dylibs.size() == 0) && _options.needsEntryPointLoadCommand() ) 
-               throw "dynamic main executables must link with libSystem.dylib";
+       if ( (state.dylibs.size() == 0) && _options.needsEntryPointLoadCommand() )  {
+               // HACK until 39514191 is fixed
+               bool grandfather = false;
+               for (const File* inFile : _inputFiles) {
+                       if ( strstr(inFile->path(), "exit-asm.o") != NULL )
+                               grandfather = true;
+               }
+               if ( !grandfather )
+                       throw "dynamic main executables must link with libSystem.dylib";
+       }
 }
 
 void InputFiles::archives(ld::Internal& state)
index bde04736665d011582e45372911a190ca35be1ac..4387ffd724297a9c13f91b065696a49ac3122726 100644 (file)
@@ -176,6 +176,8 @@ public:
        virtual void                                                            encode() const;
 
 private:
+       void                                            encodeV1() const;
+
        struct rebase_tmp
        {
                rebase_tmp(uint8_t op, uint64_t p1, uint64_t p2=0) : opcode(op), operand1(p1), operand2(p2) {}
@@ -204,8 +206,28 @@ void RebaseInfoAtom<A>::encode() const
 
        // sort rebase info by type, then address
        std::vector<OutputFile::RebaseInfo>& info = this->_writer._rebaseInfo;
+       if (info.empty())
+               return;
+
        std::sort(info.begin(), info.end());
        
+       // use encoding based on target minOS
+       if ( _options.useLinkedListBinding() && !this->_writer._hasUnalignedFixup ) {
+               if ( info.back()._type != REBASE_TYPE_POINTER )
+                       throw "unsupported rebase type with linked list opcodes";
+               // As the binding and rebasing are both linked lists, just use the binds
+               // to do everything.
+       } else {
+               encodeV1();
+       }
+}
+
+
+template <typename A>
+void RebaseInfoAtom<A>::encodeV1() const
+{
+       std::vector<OutputFile::RebaseInfo>& info = this->_writer._rebaseInfo;
+
        // convert to temp encoding that can be more easily optimized
        std::vector<rebase_tmp> mid;
        uint64_t curSegStart = 0;
@@ -388,6 +410,9 @@ public:
 
 
 private:
+       void                                            encodeV1() const;
+       void                                            encodeV2() const;
+
        typedef typename A::P                                           P;
        typedef typename A::P::E                                        E;
        typedef typename A::P::uint_t                           pint_t;
@@ -411,11 +436,23 @@ ld::Section BindingInfoAtom<A>::_s_section("__LINKEDIT", "__binding", ld::Sectio
 
 template <typename A>
 void BindingInfoAtom<A>::encode() const
+{
+       // use encoding based on target minOS
+       if ( _options.useLinkedListBinding() && !this->_writer._hasUnalignedFixup ) {
+               encodeV2();
+       } else {
+               encodeV1();
+       }
+}
+
+
+template <typename A>
+void BindingInfoAtom<A>::encodeV1() const
 {
        // sort by library, symbol, type, then address
        std::vector<OutputFile::BindingInfo>& info = this->_writer._bindingInfo;
        std::sort(info.begin(), info.end());
-       
+
        // convert to temp encoding that can be more easily optimized
        std::vector<binding_tmp> mid;
        uint64_t curSegStart = 0;
@@ -600,6 +637,229 @@ void BindingInfoAtom<A>::encode() const
        if (log) fprintf(stderr, "total binding info size = %ld\n", this->_encodedData.size());
 }
 
+template <typename A>
+void BindingInfoAtom<A>::encodeV2() const
+{
+       std::vector<OutputFile::BindingInfo>& bindInfo = this->_writer._bindingInfo;
+       std::vector<OutputFile::RebaseInfo>& rebaseInfo = this->_writer._rebaseInfo;
+       const static bool log = false;
+
+       std::sort(bindInfo.begin(), bindInfo.end());
+
+       // convert to temp encoding that can be more easily optimized
+       std::vector<binding_tmp> mid;
+       uint64_t curSegStart = 0;
+       uint64_t curSegEnd = 0;
+       uint32_t curSegIndex = 0;
+       int ordinal = 0x80000000;
+       const char* symbolName = NULL;
+       uint8_t type = 0;
+       uint64_t address = (uint64_t)(-1);
+       int64_t addend = 0;
+       uint64_t numBinds = (uint64_t)(-1);
+       for (std::vector<OutputFile::BindingInfo>::iterator it = bindInfo.begin(); it != bindInfo.end(); ++it) {
+               bool madeChange = false;
+               if ( ordinal != it->_libraryOrdinal ) {
+                       if ( it->_libraryOrdinal <= 0 ) {
+                               // special lookups are encoded as negative numbers in BindingInfo
+                               mid.push_back(binding_tmp(BIND_OPCODE_SET_DYLIB_SPECIAL_IMM, it->_libraryOrdinal));
+                       }
+                       else if ( it->_libraryOrdinal <= 15 ) {
+                               mid.push_back(binding_tmp(BIND_OPCODE_SET_DYLIB_ORDINAL_IMM, it->_libraryOrdinal));
+                       }
+                       else {
+                               mid.push_back(binding_tmp(BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB, it->_libraryOrdinal));
+                       }
+                       ordinal = it->_libraryOrdinal;
+                       madeChange = true;
+               }
+               if ( symbolName != it->_symbolName ) {
+                       mid.push_back(binding_tmp(BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM, it->_flags, 0, it->_symbolName));
+                       symbolName = it->_symbolName;
+                       madeChange = true;
+               }
+               if ( type != it->_type ) {
+                       if ( it->_type != BIND_TYPE_POINTER )
+                               throw "unsupported bind type with linked list opcodes";
+                       mid.push_back(binding_tmp(BIND_OPCODE_SET_TYPE_IMM, it->_type));
+                       type = it->_type;
+                       madeChange = true;
+               }
+               if ( address != it->_address ) {
+                       // Note, we don't push the addresses here.  That is all done later with the threaded chains
+                       if ( (it->_address < curSegStart) || ( it->_address >= curSegEnd) ) {
+                               if ( ! this->_writer.findSegment(this->_state, it->_address, &curSegStart, &curSegEnd, &curSegIndex) )
+                                       throw "binding address outside range of any segment";
+                       }
+                       address = it->_address;
+               }
+               if ( addend != it->_addend ) {
+                       mid.push_back(binding_tmp(BIND_OPCODE_SET_ADDEND_SLEB, it->_addend));
+                       addend = it->_addend;
+                       madeChange = true;
+               }
+
+               if (madeChange) {
+                       ++numBinds;
+                       mid.push_back(binding_tmp(BIND_OPCODE_DO_BIND, 0));
+               }
+               it->_threadedBindOrdinal = numBinds;
+       }
+
+       // We can only support 2^16 bind ordinals.
+       if ( (numBinds > 0x10000) && (numBinds != (uint64_t)(-1)) )
+               throwf("too many binds (%llu).  The limit is 65536", numBinds);
+
+       // Now that we have the bind ordinal table populate, set the page starts.
+
+       std::vector<int64_t>& threadedRebaseBindIndices = this->_writer._threadedRebaseBindIndices;
+       threadedRebaseBindIndices.reserve(bindInfo.size() + rebaseInfo.size());
+
+       for (int64_t i = 0, e = rebaseInfo.size(); i != e; ++i)
+               threadedRebaseBindIndices.push_back(-i);
+
+       for (int64_t i = 0, e = bindInfo.size(); i != e; ++i)
+               threadedRebaseBindIndices.push_back(i + 1);
+
+       // Now sort the entries by address.
+       std::sort(threadedRebaseBindIndices.begin(), threadedRebaseBindIndices.end(),
+                         [&rebaseInfo, &bindInfo](int64_t indexA, int64_t indexB) {
+                                 if (indexA == indexB)
+                                         return false;
+                                 uint64_t addressA = indexA <= 0 ? rebaseInfo[-indexA]._address : bindInfo[indexA - 1]._address;
+                                 uint64_t addressB = indexB <= 0 ? rebaseInfo[-indexB]._address : bindInfo[indexB - 1]._address;
+                                 assert(addressA != addressB);
+                                 return addressA < addressB;
+                         });
+
+       curSegStart = 0;
+       curSegEnd = 0;
+       curSegIndex = 0;
+       uint64_t prevPageIndex = 0;
+       for (int64_t entryIndex : threadedRebaseBindIndices) {
+               OutputFile::RebaseInfo* rebase = nullptr;
+               OutputFile::BindingInfo* bind = nullptr;
+               uint64_t address = 0;
+               if (entryIndex <= 0) {
+                       rebase = &rebaseInfo[-entryIndex];
+                       address = rebase->_address;
+               } else {
+                       bind = &bindInfo[entryIndex - 1];
+                       address = bind->_address;
+               }
+               assert((address & 7) == 0);
+
+               bool newSegment = false;
+               if ( (address < curSegStart) || ( address >= curSegEnd) ) {
+                       // Start of a new segment.
+                       if ( ! this->_writer.findSegment(this->_state, address, &curSegStart, &curSegEnd, &curSegIndex) )
+                               throw "binding address outside range of any segment";
+                       newSegment = true;
+               }
+
+               // At this point we know we have the page starts array space reserved
+               // so set the page start for this entry if we haven't got one already.
+               uint64_t pageIndex = ( address - curSegStart ) / 4096;
+               if ( newSegment || (pageIndex != prevPageIndex) ) {
+                       mid.push_back(binding_tmp(BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB, curSegIndex, address - curSegStart));
+                       mid.push_back(binding_tmp(BIND_OPCODE_THREADED | BIND_SUBOPCODE_THREADED_APPLY, 0));
+               }
+               prevPageIndex = pageIndex;
+       }
+       mid.push_back(binding_tmp(BIND_OPCODE_DONE, 0));
+
+       // convert to compressed encoding
+       this->_encodedData.reserve(bindInfo.size()*2);
+
+       // First push the total number of binds so that we can allocate space for this in dyld.
+       if ( log ) fprintf(stderr, "BIND_SUBOPCODE_THREADED_SET_BIND_ORDINAL_TABLE_SIZE_ULEB(%lld)\n", numBinds + 1);
+       this->_encodedData.append_byte(BIND_OPCODE_THREADED | BIND_SUBOPCODE_THREADED_SET_BIND_ORDINAL_TABLE_SIZE_ULEB);
+       this->_encodedData.append_uleb128(numBinds + 1);
+
+       bool done = false;
+       for (typename std::vector<binding_tmp>::iterator it = mid.begin(); !done && it != mid.end() ; ++it) {
+               switch ( it->opcode ) {
+                       case BIND_OPCODE_DONE:
+                               if ( log ) fprintf(stderr, "BIND_OPCODE_DONE()\n");
+                               done = true;
+                               break;
+                       case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM:
+                               if ( log ) fprintf(stderr, "BIND_OPCODE_SET_DYLIB_ORDINAL_IMM(%lld)\n", it->operand1);
+                               this->_encodedData.append_byte(BIND_OPCODE_SET_DYLIB_ORDINAL_IMM | it->operand1);
+                               break;
+                       case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB:
+                               if ( log ) fprintf(stderr, "BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB(%lld)\n", it->operand1);
+                               this->_encodedData.append_byte(BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB);
+                               this->_encodedData.append_uleb128(it->operand1);
+                               break;
+                       case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM:
+                               if ( log ) fprintf(stderr, "BIND_OPCODE_SET_DYLIB_SPECIAL_IMM(%lld)\n", it->operand1);
+                               this->_encodedData.append_byte(BIND_OPCODE_SET_DYLIB_SPECIAL_IMM | (it->operand1 & BIND_IMMEDIATE_MASK));
+                               break;
+                       case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
+                               if ( log ) fprintf(stderr, "BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM(0x%0llX, %s)\n", it->operand1, it->name);
+                               this->_encodedData.append_byte(BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM | it->operand1);
+                               this->_encodedData.append_string(it->name);
+                               break;
+                       case BIND_OPCODE_SET_TYPE_IMM:
+                               if ( log ) fprintf(stderr, "BIND_OPCODE_SET_TYPE_IMM(%lld)\n", it->operand1);
+                               this->_encodedData.append_byte(BIND_OPCODE_SET_TYPE_IMM | it->operand1);
+                               break;
+                       case BIND_OPCODE_SET_ADDEND_SLEB:
+                               if ( log ) fprintf(stderr, "BIND_OPCODE_SET_ADDEND_SLEB(%lld)\n", it->operand1);
+                               this->_encodedData.append_byte(BIND_OPCODE_SET_ADDEND_SLEB);
+                               this->_encodedData.append_sleb128(it->operand1);
+                               break;
+                       case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
+                               if ( log ) fprintf(stderr, "BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB(%lld, 0x%llX)\n", it->operand1, it->operand2);
+                               this->_encodedData.append_byte(BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | it->operand1);
+                               this->_encodedData.append_uleb128(it->operand2);
+                               break;
+                       case BIND_OPCODE_ADD_ADDR_ULEB:
+                               if ( log ) fprintf(stderr, "BIND_OPCODE_ADD_ADDR_ULEB(0x%llX)\n", it->operand1);
+                               this->_encodedData.append_byte(BIND_OPCODE_ADD_ADDR_ULEB);
+                               this->_encodedData.append_uleb128(it->operand1);
+                               break;
+                       case BIND_OPCODE_DO_BIND:
+                               if ( log ) fprintf(stderr, "BIND_OPCODE_DO_BIND()\n");
+                               this->_encodedData.append_byte(BIND_OPCODE_DO_BIND);
+                               break;
+                       case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
+                               if ( log ) fprintf(stderr, "BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB(0x%llX)\n", it->operand1);
+                               this->_encodedData.append_byte(BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB);
+                               this->_encodedData.append_uleb128(it->operand1);
+                               break;
+                       case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:
+                               if ( log ) fprintf(stderr, "BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED(%lld=0x%llX)\n", it->operand1, it->operand1*sizeof(pint_t));
+                               this->_encodedData.append_byte(BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED | it->operand1 );
+                               break;
+                       case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB:
+                               if ( log ) fprintf(stderr, "BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB(%lld, %lld)\n", it->operand1, it->operand2);
+                               this->_encodedData.append_byte(BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB);
+                               this->_encodedData.append_uleb128(it->operand1);
+                               this->_encodedData.append_uleb128(it->operand2);
+                               break;
+                       case BIND_OPCODE_THREADED | BIND_SUBOPCODE_THREADED_SET_BIND_ORDINAL_TABLE_SIZE_ULEB:
+                               if ( log ) fprintf(stderr, "BIND_SUBOPCODE_THREADED_SET_BIND_ORDINAL_TABLE_SIZE_ULEB(%lld)\n", it->operand1);
+                               this->_encodedData.append_byte(BIND_OPCODE_THREADED | BIND_SUBOPCODE_THREADED_SET_BIND_ORDINAL_TABLE_SIZE_ULEB);
+                               this->_encodedData.append_uleb128(it->operand1);
+                               break;
+                       case BIND_OPCODE_THREADED | BIND_SUBOPCODE_THREADED_APPLY:
+                               this->_encodedData.append_byte(BIND_OPCODE_THREADED | BIND_SUBOPCODE_THREADED_APPLY);
+                               if ( log ) fprintf(stderr, "BIND_SUBOPCODE_THREADED_APPLY()\n");
+                               break;
+               }
+       }
+
+       // align to pointer size
+       this->_encodedData.append_byte(BIND_OPCODE_DONE);
+       this->_encodedData.pad_to_size(sizeof(pint_t));
+
+       this->_encoded = true;
+
+       if (log) fprintf(stderr, "total binding info size = %ld\n", this->_encodedData.size());
+}
+
 
 
 template <typename A>
@@ -1135,6 +1395,12 @@ void SplitSegInfoV1Atom<x86_64>::addSplitSegInfo(uint64_t address, ld::Fixup::Ki
                case ld::Fixup::kindStoreTargetAddressLittleEndian64:
                        _64bitPointerLocations.push_back(address);
                        break;
+#if SUPPORT_ARCH_arm64e
+               case ld::Fixup::kindStoreLittleEndianAuth64:
+               case ld::Fixup::kindStoreTargetAddressLittleEndianAuth64:
+                       assert(false);
+                       break;
+#endif
                default:
                        warning("codegen at address 0x%08llX prevents image from working in dyld shared cache", address);
                        break;
@@ -1206,6 +1472,12 @@ void SplitSegInfoV1Atom<arm64>::addSplitSegInfo(uint64_t address, ld::Fixup::Kin
                case ld::Fixup::kindStoreTargetAddressLittleEndian64:
                        _64bitPointerLocations.push_back(address);
                        break;
+#if SUPPORT_ARCH_arm64e
+               case ld::Fixup::kindStoreLittleEndianAuth64:
+               case ld::Fixup::kindStoreTargetAddressLittleEndianAuth64:
+                       warning("authenticated pointer at address 0x%08llX prevents image from working in dyld shared cache", address);
+                       break;
+#endif
                default:
                        warning("codegen at address 0x%08llX prevents image from working in dyld shared cache", address);
                        break;
index fd9098f15d76876793a45fb85f31ff9bfe756eba..be25666f5619632d893f528ed0c0b25ba6a87998 100644 (file)
@@ -491,10 +491,7 @@ void SymbolTableAtom<A>::addImport(const ld::Atom* atom, StringPoolAtom* pool)
                        entry.set_n_type(N_UNDF | N_EXT);
        }
        else {
-               if ( this->_options.prebind() )
-                       entry.set_n_type(N_PBUD | N_EXT);
-               else 
-                       entry.set_n_type(N_UNDF | N_EXT);
+               entry.set_n_type(N_UNDF | N_EXT);
        }
 
        // set n_sect
@@ -760,6 +757,9 @@ public:
        virtual void                                                    addSectionReloc(ld::Internal::FinalSection*     sect, ld::Fixup::Kind, 
                                                                                                                        const ld::Atom* inAtom, uint32_t offsetInAtom, 
                                                                                                                        bool toTargetUsesExternalReloc ,bool fromTargetExternalReloc,
+#if SUPPORT_ARCH_arm64e
+                                                                                                                       ld::Fixup* fixupWithAuthData,
+#endif
                                                                                                                        const ld::Atom* toTarget, uint64_t toAddend, 
                                                                                                                        const ld::Atom* fromTarget, uint64_t fromAddend) = 0;
 protected:
@@ -804,6 +804,9 @@ public:
        virtual void                                                            addSectionReloc(ld::Internal::FinalSection*     sect, ld::Fixup::Kind, 
                                                                                                                        const ld::Atom* inAtom, uint32_t offsetInAtom, 
                                                                                                                        bool toTargetUsesExternalReloc ,bool fromTargetExternalReloc,
+#if SUPPORT_ARCH_arm64e
+                                                                                                                               ld::Fixup* fixupWithAuthData,
+#endif
                                                                                                                        const ld::Atom* toTarget, uint64_t toAddend, 
                                                                                                                        const ld::Atom* fromTarget, uint64_t fromAddend) { }
 
@@ -901,6 +904,9 @@ public:
        virtual void                                                            addSectionReloc(ld::Internal::FinalSection*     sect, ld::Fixup::Kind, 
                                                                                                                        const ld::Atom* inAtom, uint32_t offsetInAtom, 
                                                                                                                        bool toTargetUsesExternalReloc ,bool fromTargetExternalReloc,
+#if SUPPORT_ARCH_arm64e
+                                                                                                                               ld::Fixup* fixupWithAuthData,
+#endif
                                                                                                                        const ld::Atom* toTarget, uint64_t toAddend, 
                                                                                                                        const ld::Atom* fromTarget, uint64_t fromAddend) { }
        
@@ -1060,6 +1066,9 @@ public:
        virtual void                                                            addSectionReloc(ld::Internal::FinalSection*     sect, ld::Fixup::Kind, 
                                                                                                                        const ld::Atom* inAtom, uint32_t offsetInAtom, 
                                                                                                                        bool toTargetUsesExternalReloc ,bool fromTargetExternalReloc,
+#if SUPPORT_ARCH_arm64e
+                                                                                                                               ld::Fixup* fixupWithAuthData,
+#endif
                                                                                                                        const ld::Atom* toTarget, uint64_t toAddend, 
                                                                                                                        const ld::Atom* fromTarget, uint64_t fromAddend);
                
@@ -1079,6 +1088,10 @@ private:
                uint64_t                                        toAddend; 
                const ld::Atom*                         fromTarget; 
                uint64_t                                        fromAddend;
+#if SUPPORT_ARCH_arm64e
+               bool                                            hasAuthData;
+               ld::Fixup::AuthData                     authData;
+#endif
        };
        uint32_t                                                                        sectSymNum(bool external, const ld::Atom* target);
        void                                                                            encodeSectionReloc(ld::Internal::FinalSection* sect, 
@@ -1928,6 +1941,33 @@ void SectionRelocationsAtom<arm64>::encodeSectionReloc(ld::Internal::FinalSectio
             relocs.push_back(reloc1);
             break;
 
+#if SUPPORT_ARCH_arm64e
+               case ld::Fixup::kindStoreLittleEndianAuth64:
+               case ld::Fixup::kindStoreTargetAddressLittleEndianAuth64: {
+                       assert(entry.fromTarget == NULL);
+                       assert(entry.hasAuthData);
+
+                       // An authenticated pointer is:
+                       // {
+                       //       int32_t addend;
+                       //       uint16_t diversityData;
+                       //       uint16_t hasAddressDiversity : 1;
+                       //       uint16_t key : 2;
+                       //       uint16_t zeroes : 11;
+                       //       uint16_t zero : 1;
+                       //       uint16_t authenticated : 1;
+                       // }
+                       reloc1.set_r_address(address);
+                       reloc1.set_r_symbolnum(symbolNum);
+                       reloc1.set_r_pcrel(false);
+                       reloc1.set_r_length(3);
+                       reloc1.set_r_extern(external);
+                       reloc1.set_r_type(ARM64_RELOC_AUTHENTICATED_POINTER);
+                       relocs.push_back(reloc1);
+               }
+               break;
+#endif
+
                default:
                        assert(0 && "need to handle arm64 -r reloc");
                
@@ -1941,6 +1981,9 @@ template <typename A>
 void SectionRelocationsAtom<A>::addSectionReloc(ld::Internal::FinalSection*    sect, ld::Fixup::Kind kind, 
                                                                                                const ld::Atom* inAtom, uint32_t offsetInAtom,  
                                                                                                bool toTargetUsesExternalReloc ,bool fromTargetExternalReloc,
+#if SUPPORT_ARCH_arm64e
+                                                                                               ld::Fixup* fixupWithAuthData,
+#endif
                                                                                                const ld::Atom* toTarget, uint64_t toAddend, 
                                                                                                const ld::Atom* fromTarget, uint64_t fromAddend)
 {
@@ -1954,6 +1997,14 @@ void SectionRelocationsAtom<A>::addSectionReloc(ld::Internal::FinalSection*      sect
        entry.toAddend = toAddend;
        entry.fromTarget = fromTarget;
        entry.fromAddend = fromAddend;
+#if SUPPORT_ARCH_arm64e
+       if (fixupWithAuthData) {
+               entry.hasAuthData = true;
+               entry.authData = fixupWithAuthData->u.authData;
+       } else {
+               entry.hasAuthData = false;
+       }
+#endif
        
        static ld::Internal::FinalSection* lastSection = NULL;
        static SectionAndEntries* lastSectionAndEntries = NULL;
@@ -2072,10 +2123,20 @@ uint32_t IndirectSymbolTableAtom<A>::symIndexOfStubAtom(const ld::Atom* stubAtom
 template <typename A>
 uint32_t IndirectSymbolTableAtom<A>::symIndexOfLazyPointerAtom(const ld::Atom* lpAtom)
 {
-       for (ld::Fixup::iterator fit = lpAtom->fixupsBegin(); fit != lpAtom->fixupsEnd(); ++fit) {
-               if ( fit->kind == ld::Fixup::kindLazyTarget ) {
-                       assert(fit->binding == ld::Fixup::bindingDirectlyBound);
-                       return symbolIndex(fit->u.target);
+       if ( lpAtom->contentType() == ld::Atom::typeLazyPointer || lpAtom->contentType() == ld::Atom::typeLazyDylibPointer ) {
+               for (ld::Fixup::iterator fit = lpAtom->fixupsBegin(); fit != lpAtom->fixupsEnd(); ++fit) {
+                       if ( fit->kind == ld::Fixup::kindLazyTarget ) {
+                               assert(fit->binding == ld::Fixup::bindingDirectlyBound);
+                               return symbolIndex(fit->u.target);
+                       }
+               }
+       }
+       else if ( lpAtom->contentType() == ld::Atom::typeNonLazyPointer ) {
+               for (ld::Fixup::iterator fit = lpAtom->fixupsBegin(); fit != lpAtom->fixupsEnd(); ++fit) {
+                       if ( (fit->kind == ld::Fixup::kindStoreTargetAddressLittleEndian32) || (fit->kind == ld::Fixup::kindStoreTargetAddressLittleEndian64) ) {
+                               assert(fit->binding == ld::Fixup::bindingDirectlyBound);
+                               return symbolIndex(fit->u.target);
+                       }
                }
        }
        throw "internal error: lazy pointer missing fixupLazyTarget fixup";
@@ -2086,9 +2147,18 @@ uint32_t IndirectSymbolTableAtom<A>::symIndexOfNonLazyPointerAtom(const ld::Atom
 {
        //fprintf(stderr, "symIndexOfNonLazyPointerAtom(%p) %s\n", nlpAtom, nlpAtom->name());
        for (ld::Fixup::iterator fit = nlpAtom->fixupsBegin(); fit != nlpAtom->fixupsEnd(); ++fit) {
-               // non-lazy-pointer to a stripped symbol => no symbol index
-               if ( fit->clusterSize != ld::Fixup::k1of1 )
-                       return INDIRECT_SYMBOL_LOCAL;
+#if SUPPORT_ARCH_arm64e
+               // Skip authentication fixups
+               if ( fit->clusterSize == ld::Fixup::k1of2 ) {
+                       if ( fit->kind != ld::Fixup::kindSetAuthData )
+                               break;
+                       ++fit;
+               } else
+#endif
+               {
+                       if ( fit->clusterSize != ld::Fixup::k1of1 )
+                               return INDIRECT_SYMBOL_LOCAL;
+               }
                const ld::Atom* target;
                switch ( fit->binding ) {
                        case ld::Fixup::bindingDirectlyBound:
index 6f115d8a5edae5074a5c39f408b1eea081d04cf6..09290a921b95267872e14a233ad24bf2681bba97 100644 (file)
@@ -40,6 +40,7 @@
 #include <map>
 #include <sstream>
 
+#include "ld.hpp"
 #include "Options.h"
 #include "Architectures.hpp"
 #include "MachOFileAbstraction.hpp"
@@ -135,20 +136,22 @@ bool Options::FileInfo::checkFileExists(const Options& options, const char *p)
 
 
 Options::Options(int argc, const char* argv[])
-       : fOutputFile("a.out"), fArchitecture(0), fSubArchitecture(0), fArchitectureName("unknown"), fOutputKind(kDynamicExecutable), 
-         fHasPreferredSubType(false), fArchSupportsThumb2(false), fPrebind(false), fBindAtLoad(false), fKeepPrivateExterns(false),
-         fNeedsModuleTable(false), fIgnoreOtherArchFiles(false), fErrorOnOtherArchFiles(false), fForceSubtypeAll(false), 
+       : fOutputFile("a.out"), fArchitecture(0), fSubArchitecture(0),
+         fFallbackArchitecture(0), fFallbackSubArchitecture(0), fArchitectureName("unknown"), fOutputKind(kDynamicExecutable),
+         fHasPreferredSubType(false), fArchSupportsThumb2(false), fBindAtLoad(false), fKeepPrivateExterns(false),
+         fIgnoreOtherArchFiles(false), fErrorOnOtherArchFiles(false), fForceSubtypeAll(false),
          fInterposeMode(kInterposeNone), fDeadStrip(false), fNameSpace(kTwoLevelNameSpace),
-         fDylibCompatVersion(0), fDylibCurrentVersion(0), fDylibInstallName(NULL), fFinalName(NULL), fEntryName(NULL), 
-         fBaseAddress(0), fMaxAddress(0x7FFFFFFFFFFFFFFFLL), 
-         fBaseWritableAddress(0), fSplitSegs(false),
+         fDylibCompatVersion(0), fDylibCurrentVersion(0), fDylibInstallName(NULL), fFinalName(NULL), fEntryName(NULL),
+         fBaseAddress(0), fMaxAddress(0xFFFFFFFFFFFFFFFFULL),
+         fBaseWritableAddress(0),
          fExportMode(kExportDefault), fLibrarySearchMode(kSearchDylibAndArchiveInEachDir),
          fUndefinedTreatment(kUndefinedError), fMessagesPrefixedWithArchitecture(true), 
          fWeakReferenceMismatchTreatment(kWeakReferenceMismatchNonWeak),
          fClientName(NULL),
          fUmbrellaName(NULL), fInitFunctionName(NULL), fDotOutputFile(NULL), fExecutablePath(NULL),
-         fBundleLoader(NULL), fDtraceScriptName(NULL), fSegAddrTablePath(NULL), fMapPath(NULL), 
+         fBundleLoader(NULL), fDtraceScriptName(NULL), fMapPath(NULL),
          fDyldInstallPath("/usr/lib/dyld"), fLtoCachePath(NULL), fTempLtoObjectPath(NULL), fOverridePathlibLTO(NULL), fLtoCpu(NULL),
+         fKextObjectsEnable(-1),fKextObjectsDirPath(NULL),fToolchainPath(NULL),
          fZeroPageSize(ULLONG_MAX), fStackSize(0), fStackAddr(0), fSourceVersion(0), fSDKVersion(0), fExecutableStack(false), 
          fNonExecutableHeap(false), fDisableNonExecutableHeap(false),
          fMinimumHeaderPad(32), fSegmentAlignment(4096), 
@@ -161,7 +164,8 @@ Options::Options(int argc, const char* argv[])
          fDeadStripDylibs(false),  fAllowTextRelocs(false), fWarnTextRelocs(false), fKextsUseStubs(false),
          fUsingLazyDylibLinking(false), fEncryptable(true), fEncryptableForceOn(false), fEncryptableForceOff(false),
          fOrderData(true), fMarkDeadStrippableDylib(false),
-         fMakeCompressedDyldInfo(true), fMakeCompressedDyldInfoForceOff(false), fNoEHLabels(false),
+         fMakeCompressedDyldInfo(true), fMakeCompressedDyldInfoForceOff(false),
+         fMakeThreadedStartsSection(false), fNoEHLabels(false),
          fAllowCpuSubtypeMismatches(false), fEnforceDylibSubtypesMatch(false),
          fWarnOnSwiftABIVersionMismatches(false), fUseSimplifiedDylibReExports(false),
          fObjCABIVersion2Override(false), fObjCABIVersion1Override(false), fCanUseUpwardDylib(false),
@@ -176,15 +180,14 @@ Options::Options(int argc, const char* argv[])
          fObjcGcCompaction(false), fObjCGc(false), fObjCGcOnly(false), 
          fDemangle(false), fTLVSupport(false), 
          fVersionLoadCommand(false), fVersionLoadCommandForcedOn(false), 
-         fVersionLoadCommandForcedOff(false), fBuildVersionLoadCommand(false), fFunctionStartsLoadCommand(false),
+         fVersionLoadCommandForcedOff(false), fFunctionStartsLoadCommand(false),
          fFunctionStartsForcedOn(false), fFunctionStartsForcedOff(false),
          fDataInCodeInfoLoadCommand(false), fDataInCodeInfoLoadCommandForcedOn(false), fDataInCodeInfoLoadCommandForcedOff(false),
          fCanReExportSymbols(false), fObjcCategoryMerging(true), fPageAlignDataAtoms(false), 
          fNeedsThreadLoadCommand(false), fEntryPointLoadCommand(false),
-         fEntryPointLoadCommandForceOn(false), fEntryPointLoadCommandForceOff(false),
-         fSourceVersionLoadCommand(false), 
+         fSourceVersionLoadCommand(false),
          fSourceVersionLoadCommandForceOn(false), fSourceVersionLoadCommandForceOff(false), 
-         fTargetIOSSimulator(false), fExportDynamic(false), fAbsoluteSymbols(false),
+         fExportDynamic(false), fAbsoluteSymbols(false),
          fAllowSimulatorToLinkWithMacOSX(false), fKeepDwarfUnwind(true),
          fKeepDwarfUnwindForcedOn(false), fKeepDwarfUnwindForcedOff(false),
          fVerboseOptimizationHints(false), fIgnoreOptimizationHints(false),
@@ -194,13 +197,13 @@ Options::Options(int argc, const char* argv[])
          fUseDataConstSegmentForceOn(false), fUseDataConstSegmentForceOff(false), fUseTextExecSegment(false),
          fBundleBitcode(false), fHideSymbols(false), fVerifyBitcode(false),
          fReverseMapUUIDRename(false), fDeDupe(true), fVerboseDeDupe(false),
+         fUseLinkedListBinding(false), fNoLazyBinding(false), fDebugVariant(false),
          fReverseMapPath(NULL), fLTOCodegenOnly(false),
          fIgnoreAutoLink(false), fAllowDeadDups(false), fAllowWeakImports(true), fInitializersTreatment(Options::kInvalid),
          fZeroModTimeInDebugMap(false), fBitcodeKind(kBitcodeProcess),
-         fPlatform(kPlatformUnknown), fDebugInfoStripping(kDebugInfoMinimal), fTraceOutputFile(NULL),
-         fMacVersionMin(ld::macVersionUnset), fIOSVersionMin(ld::iOSVersionUnset), fWatchOSVersionMin(ld::wOSVersionUnset),
-         fSaveTempFiles(false), fSnapshotRequested(false), fPipelineFifo(NULL),
-         fDependencyInfoPath(NULL), fTraceFileDescriptor(-1), fMaxDefaultCommonAlign(0),
+         fDebugInfoStripping(kDebugInfoMinimal), fTraceOutputFile(NULL),
+         fSaveTempFiles(false), fLinkSnapshot(this), fSnapshotRequested(false), fPipelineFifo(NULL),
+         fDependencyInfoPath(NULL), fBuildContextName(NULL), fTraceFileDescriptor(-1), fMaxDefaultCommonAlign(0),
          fUnalignedPointerTreatment(kUnalignedPointerIgnore)
 {
        this->checkForClassic(argc, argv);
@@ -346,7 +349,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
-       if ( (fPlatform != kPlatformOSX) && !fTargetIOSSimulator )
+       if ( (platforms().contains(ld::kPlatform_macOS) == 0) && !targetIOSSimulator() )
                return initialSegProtection(segName);
 
        for(std::vector<Options::SegmentProtect>::const_iterator it = fCustomSegmentProtections.begin(); it != fCustomSegmentProtections.end(); ++it) {
@@ -587,28 +590,7 @@ const std::vector<const char*>* Options::sectionOrder(const char* segName) const
        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
-               case kPlatform_bridgeOS:
-                       return iOSVersionMin();
-               case kPlatformUnknown:
-                       return 0;
-       }
-       return 0;
-}
-
-void Options::setArchitecture(cpu_type_t type, cpu_subtype_t subtype, Options::Platform platform)
+void Options::setArchitecture(cpu_type_t type, cpu_subtype_t subtype, ld::Platform platform, uint32_t minOsVers)
 {
        for (const ArchInfo* t=archInfoArray; t->archName != NULL; ++t) {
                if ( (type == t->cpuType) && (subtype == t->cpuSubType) ) {
@@ -617,42 +599,47 @@ void Options::setArchitecture(cpu_type_t type, cpu_subtype_t subtype, Options::P
                        fArchitectureName = t->archName;
                        fHasPreferredSubType = t->isSubType;
                        fArchSupportsThumb2 = t->supportsThumb2;
-                       if ( fPlatform == kPlatformUnknown)
-                               fPlatform = platform;
+                       if ( platforms().empty() && (platform != ld::kPlatform_unknown) )
+                               fPlatforms.add({platform, minOsVers});
                        switch ( type ) {
                                case CPU_TYPE_I386:
                                case CPU_TYPE_X86_64:
-                                       if ( (fPlatform == kPlatformOSX) && (fOutputKind != Options::kObjectFile) && (fMacVersionMin == ld::macVersionUnset) ) {
+                                       if ( platforms().contains(ld::kPlatform_macOS) && (fOutputKind != Options::kObjectFile) && (platforms().minOS(ld::kPlatform_macOS) == 0) ) {
                                #ifdef DEFAULT_MACOSX_MIN_VERSION
                                                warning("-macosx_version_min not specified, assuming " DEFAULT_MACOSX_MIN_VERSION);
-                                               setMacOSXVersionMin(DEFAULT_MACOSX_MIN_VERSION);
+                                               setVersionMin(ld::kPlatform_macOS, DEFAULT_MACOSX_MIN_VERSION);
                                #else
                                                warning("-macosx_version_min not specified, assuming 10.6");
-                                               fMacVersionMin = ld::mac10_6;
-                               #endif          
+                                               setVersionMin(ld::kPlatform_macOS, "10.6");
+                               #endif
                                        }
                                        break;
                                case CPU_TYPE_ARM:
                                case CPU_TYPE_ARM64:
-                                       if ( (fMacVersionMin == ld::macVersionUnset) && (fIOSVersionMin == ld::iOSVersionUnset) && (fOutputKind != Options::kObjectFile) ) {
+                               if ( platforms().contains(ld::kPlatform_iOS) && (platforms().minOS(ld::kPlatform_iOS) == 0) && (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);
+                                               setVersionMin(ld::kPlatformiOS, DEFAULT_IPHONEOS_MIN_VERSION);
                                #else
                                                warning("-ios_version_min not specified, assuming 6.0");
-                                               setIOSVersionMin("6.0");
+                                               setVersionMin(ld::kPlatform_iOS, "6.0");
                                #endif
                                        }
+#if SUPPORT_ARCH_arm64e
+                                       if ( (fArchitecture == CPU_TYPE_ARM64) && (fSubArchitecture == CPU_SUBTYPE_ARM64_E) ) {
+                                               fSupportsAuthenticatedPointers = true;
+                                       }
+#endif
                                        break;
                        }
                        fLinkSnapshot.recordArch(fArchitectureName);
                        // only use compressed LINKEDIT for:
                        //                      Mac OS X 10.6 or later
                        //                      iOS 3.1 or later
-                       if ( !fMakeCompressedDyldInfo && minOS(ld::mac10_6, ld::iOS_3_1) && !fMakeCompressedDyldInfoForceOff )
+                       if ( !fMakeCompressedDyldInfo && platforms().minOS(ld::version2009) && !fMakeCompressedDyldInfoForceOff )
                                fMakeCompressedDyldInfo = true;
                        // Mac OS X 10.5 and iPhoneOS 2.0 support LC_REEXPORT_DYLIB
-                       if ( minOS(ld::mac10_5, ld::iOS_2_0) )
+                       if ( platforms().minOS(ld::version2008) )
                                fUseSimplifiedDylibReExports = true;
                        return;
                }
@@ -665,6 +652,35 @@ bool Options::armUsesZeroCostExceptions() const
        return ( (fArchitecture == CPU_TYPE_ARM) && (fSubArchitecture == CPU_SUBTYPE_ARM_V7K) );
 }
 
+void Options::selectFallbackArch(const char *arch)
+{
+       // Should have the format "desired_arch:fallback_arch", for example "arm64_32:armv7k" to allow an armv7k
+       // slice to substitute for arm64_32 if the latter isn't present.
+       if (const char* fallbackEnv = getenv("LD_DYLIB_ARCH_FALLBACK") ) {
+               std::string fallback(fallbackEnv);
+               auto delimPos = fallback.find(':');
+
+               // Check we've got a potentially valid fallback string and that it's this architecture we're falling back from.
+               if ( delimPos == std::string::npos || fallback.substr(0, delimPos) != arch )
+                       return;
+
+               std::string fallbackTo = fallback.substr(delimPos + 1);
+               for (const ArchInfo *t = archInfoArray; t->archName != nullptr; ++t) {
+                       if ( fallbackTo == t->archName ) {
+                               fFallbackArchitecture = t->cpuType;
+                               fFallbackSubArchitecture = t->cpuSubType;
+                       }
+               }
+       }
+       else {
+               // <rdar://problem/39797337> let x86_64h fallback and use x86_64 slice
+               if ( (fArchitecture == CPU_TYPE_X86_64) && (fSubArchitecture == CPU_SUBTYPE_X86_64_H) ) {
+                       fFallbackArchitecture    = CPU_TYPE_X86_64;
+                       fFallbackSubArchitecture = CPU_SUBTYPE_X86_ALL;
+               }
+       }
+}
+
 void Options::parseArch(const char* arch)
 {
        if ( arch == NULL )
@@ -676,6 +692,7 @@ void Options::parseArch(const char* arch)
                        fSubArchitecture = t->cpuSubType;
                        fHasPreferredSubType = t->isSubType;
                        fArchSupportsThumb2 = t->supportsThumb2;
+                       selectFallbackArch(arch);
                        return;
                }
        }
@@ -826,7 +843,7 @@ static std::string replace_extension(const std::string &path, const std::string
        return result;
 }
 
-void Options::addTAPIInterface(tapi::LinkerInterfaceFile *interface, const char *path) const {
+void Options::addTAPIInterface(tapi::LinkerInterfaceFileinterface, const char *path) const {
 #if ((TAPI_API_VERSION_MAJOR == 1 &&  TAPI_API_VERSION_MINOR >= 3) || (TAPI_API_VERSION_MAJOR > 1))
        if (tapi::APIVersion::isAtLeast(1, 3)) {
                for (auto &name : interface->inlinedFrameworkNames()) {
@@ -968,9 +985,10 @@ bool Options::hasInlinedTAPIFile(const std::string &path) const {
        return false;
 }
 
-std::unique_ptr<tapi::LinkerInterfaceFile> Options::findTAPIFile(const std::string &path) const
+tapi::LinkerInterfaceFile* Options::findTAPIFile(const std::string &path) const
 {
-       std::unique_ptr<tapi::LinkerInterfaceFile> interface;
+#if ((TAPI_API_VERSION_MAJOR == 1 &&  TAPI_API_VERSION_MINOR >= 3) || (TAPI_API_VERSION_MAJOR > 1))
+       tapi::LinkerInterfaceFile* interface = nullptr;
        std::string TBDPath;
        
        // create parsing options.
@@ -980,20 +998,29 @@ std::unique_ptr<tapi::LinkerInterfaceFile> Options::findTAPIFile(const std::stri
        
        if (!allowWeakImports())
                flags |= tapi::ParsingFlags::DisallowWeakImports;
-       
+
+       __block uint32_t linkMinOSVersion = 0;
+       //FIXME handle this correctly once we have multi-platform TAPI.
+       platforms().forEach(^(ld::Platform platform, uint32_t version, bool &stop) {
+               if (linkMinOSVersion == 0)
+                       linkMinOSVersion = version;
+               if (platform == ld::kPlatform_macOS)
+                       linkMinOSVersion = version;
+       });
+
        // Search through all the inlined framework.
        for (const auto &dylib : fTAPIFiles) {
                if (dylib.getInstallName() == path) {
                        // If the install name matches, parse the framework.
                        std::string errorMessage;
                        auto file = dylib.getInterfaceFile()->getInlinedFramework(path.c_str(), architecture(), subArchitecture(),
-                                                                                                                                         flags, tapi::PackedVersion32(minOSversion()), errorMessage);
+                                                                                                                                         flags, tapi::PackedVersion32(linkMinOSVersion), errorMessage);
                        if (!file)
                                throw strdup(errorMessage.c_str());
 
                        if (!interface) {
                                // If this is the first inlined framework found, record the information.
-                               interface.reset(file);
+                               interface = file;
                                TBDPath = dylib.getTAPIFilePath();
                        } else {
                                // If we found other inlined framework already, check to see if their versions are the same.
@@ -1003,13 +1030,16 @@ std::unique_ptr<tapi::LinkerInterfaceFile> Options::findTAPIFile(const std::stri
                                warning("Inlined framework/dylib mismatch: %s (%s and %s)", path.c_str(),
                                                TBDPath.c_str(), dylib.getTAPIFilePath().c_str());
                                if (interface->getCurrentVersion() < file->getCurrentVersion()) {
-                                       interface.reset(file);
+                                       interface = file;
                                        TBDPath = dylib.getTAPIFilePath();
                                }
                        }
                }
        }
        return interface;
+#else
+       return nullptr;
+#endif
 }
 
 // search for indirect dylib first using -F and -L paths first
@@ -1065,60 +1095,6 @@ Options::FileInfo Options::findIndirectDylib(const std::string& installName, con
        return findFile(installName, fromDylib);
 }
 
-
-
-void Options::parseSegAddrTable(const char* segAddrPath, const char* installPth)
-{
-       FILE* file = fopen(segAddrPath, "r");
-       if ( file == NULL ) {
-               warning("-seg_addr_table file cannot be read: %s", segAddrPath);
-               return;
-       }
-       
-       char path[PATH_MAX];
-       uint64_t firstColumAddress = 0;
-       uint64_t secondColumAddress = 0;
-       bool hasSecondColumn = false;
-       while ( fgets(path, PATH_MAX, file) != NULL ) {
-               path[PATH_MAX-1] = '\0';
-               char* eol = strchr(path, '\n');
-               if ( eol != NULL )
-                       *eol = '\0';
-               // ignore lines not starting with 0x number
-               if ( (path[0] == '0') && (path[1] == 'x') ) {
-                       char* p;
-                       firstColumAddress = strtoull(path, &p, 16);
-                       while ( isspace(*p) )
-                               ++p;
-                       // see if second column is a number
-                       if ( (p[0] == '0') && (p[1] == 'x') ) {
-                               secondColumAddress = strtoull(p, &p, 16);
-                               hasSecondColumn = true;
-                               while ( isspace(*p) )
-                                       ++p;
-                       }
-                       while ( isspace(*p) )
-                               ++p;
-                       if ( p[0] == '/' ) {
-                               // remove any trailing whitespace
-                               for(char* end = eol-1; (end > p) && isspace(*end); --end)
-                                       *end = '\0';
-                               // see if this line is for the dylib being linked
-                               if ( strcmp(p, installPth) == 0 ) {
-                                       fBaseAddress = firstColumAddress;
-                                       if ( hasSecondColumn ) {
-                                               fBaseWritableAddress = secondColumAddress;
-                                               fSplitSegs = true;
-                                       }
-                                       break; // out of while loop
-                               }
-                       }
-               }
-       }
-
-       fclose(file);
-}
-
 void Options::loadFileList(const char* fileOfPaths, ld::File::Ordinal baseOrdinal)
 {
        FILE* file;
@@ -1535,61 +1511,29 @@ Options::Treatment Options::parseTreatment(const char* treatment)
                return kInvalid;
 }
 
-void Options::setMacOSXVersionMin(const char* version)
-{
-       uint32_t value;
-       if ( !parsePackedVersion32(version, value) ) {
-               throwf("-macosx_version_min value malformed: '%s'", version);
-       }
-       fMacVersionMin = (ld::MacVersionMin)value;
-       fPlatform = kPlatformOSX;
-}
-
-void Options::setIOSVersionMin(const char* version)
-{
-       uint32_t value;
-       if ( !parsePackedVersion32(version, value) ) {
-               throwf("-ios_version_min value malformed: '%s'", version);
-       }
-       fIOSVersionMin = (ld::IOSVersionMin)value;
-       fPlatform = kPlatformiOS;
-}
-
-
-void Options::setWatchOSVersionMin(const char* version)
-{
-       uint32_t value;
-       if ( !parsePackedVersion32(version, value) ) {
-               throwf("-watchos_version_min value malformed: '%s'", version);
-       }
-       fWatchOSVersionMin = (ld::WatchOSVersionMin)value;
-       fPlatform = kPlatformWatchOS;
-}
-
-
-bool Options::minOS(ld::MacVersionMin requiredMacMin, ld::IOSVersionMin requirediPhoneOSMin)
-{
-       if ( fMacVersionMin != ld::macVersionUnset ) {
-               return ( fMacVersionMin >= requiredMacMin );
-       }
-       else {
-               return min_iOS(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 if ( fPlatform == Options::kPlatform_bridgeOS ) {
-               // Hack until we fully track bridge and ios versions seperately
-               return ( (fIOSVersionMin + 0x00090000) >= requirediOSMin);
-       }
-       else {
-               return ( fIOSVersionMin >= requirediOSMin );
-       }
+void Options::setVersionMin(const ld::Platform& platform, const char *version) {
+       auto checkAndParse = [&](const char *errorFlag) {
+               if ( version == NULL )
+                       throwf("%s missing version argument", errorFlag);
+               uint32_t value;
+               if ( !parsePackedVersion32(version, value) ) {
+                       throwf("%s value malformed: '%s'", errorFlag, version);
+               }
+               fPlatforms.add({platform, value});
+       };
+
+       switch(platform) {
+               case ld::kPlatform_macOS:                               checkAndParse("-macosx_version_min"); break;
+               case ld::kPlatform_iOS:                                 checkAndParse("-ios_version_min"); break;
+               case ld::kPlatform_tvOS:                                checkAndParse("-tvos_version_min"); break;
+               case ld::kPlatform_watchOS:                     checkAndParse("-watchos_version_min"); break;
+               case ld::kPlatform_bridgeOS:                    checkAndParse("-bridgeos_version_min"); break;
+               case ld::kPlatform_iOSSimulator:                checkAndParse("-ios_simulator_version_min"); break;
+               case ld::kPlatform_tvOSSimulator:               checkAndParse("-tvos_simulator_version_min"); break;
+               case ld::kPlatform_watchOSSimulator:    checkAndParse("-watchos_simulator_version_min"); break;
+               case ld::kPlatform_unknown:                     throw "kPlatformUnknown is an invalid argument to setVersionMin()";
+               case ld::kPlatform_iOSMac:                              checkAndParse("-iosmac_version_min"); break;
+       };
 }
 
 void Options::setWeakReferenceMismatchTreatment(const char* treatment)
@@ -2061,6 +2005,16 @@ bool Options::moveRwSymbol(const char* symName, const char* filePath, const char
        return false;
 }
 
+bool Options::moveAXMethodList(const char* className) const
+{
+       for (const SymbolsMove& sm : fSymbolsMovesAXMethodLists) {
+               bool wildcard;
+               if ( sm.symbols.containsWithPrefix(className, NULL, wildcard) )
+                       return true;
+       }
+       return false;
+}
+
 bool Options::moveRoSymbol(const char* symName, const char* filePath, const char*& seg, bool& wildCardMatch) const
 {
        for (std::vector<SymbolsMove>::const_iterator it=fSymbolsMovesCode.begin(); it != fSymbolsMovesCode.end(); ++it) {
@@ -2212,7 +2166,7 @@ bool Options::parsePackedVersion32(const std::string& versionStr, uint32_t &resu
                                return false;
                }
 
-               result = (majorValue << 16) | (minorValue << 8) | microValue;
+               result = (uint32_t)((majorValue << 16) | (minorValue << 8) | microValue);
 
                return true;
        }
@@ -2227,39 +2181,9 @@ 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::kPlatform_bridgeOS:
-                       return "bridgeOS";
-               case Options::kPlatformUnknown:
-                       return "Unknown";
-       }
-}
-
 std::vector<std::string> Options::writeBitcodeLinkOptions() const
 {
-       std::vector<std::string> linkCommand;
+       __block std::vector<std::string> linkCommand;
        switch ( fOutputKind ) {
                case Options::kDynamicLibrary:
                        linkCommand.push_back("-dylib");
@@ -2291,45 +2215,53 @@ std::vector<std::string> Options::writeBitcodeLinkOptions() const
 
        // 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
+
+       platforms().forEach(^(ld::Platform platform, uint32_t version, bool &stop) {
+               switch (platform) {
+                       case ld::kPlatform_macOS:
+                               linkCommand.push_back("-macosx_version_min");
+                               linkCommand.push_back(getVersionString32(version));
+                               break;
+                       case ld::kPlatform_iOS:
                                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(getVersionString32(version));
+                               break;
+                       case ld::kPlatform_iOSSimulator:
+                               linkCommand.push_back("-ios_simulator_version_min");
+                               linkCommand.push_back(getVersionString32(version));
+                               break;
+                       case ld::kPlatform_watchOS:
                                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(getVersionString32(version));
+                               break;
+                       case ld::kPlatform_watchOSSimulator:
+                               linkCommand.push_back("-watchos_simulator_version_min");
+                               linkCommand.push_back(getVersionString32(version));
+                               break;
+                       case ld::kPlatform_tvOS:
                                linkCommand.push_back("-tvos_version_min");
-                       linkCommand.push_back(getVersionString32((unsigned)fIOSVersionMin));
-                       break;
-#endif
-               case Options::kPlatform_bridgeOS:
-                       linkCommand.push_back("-bridgeos_version_min");
-                       linkCommand.push_back(getVersionString32((unsigned)fIOSVersionMin));
-                       break;
-               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;
-       }
+                               linkCommand.push_back(getVersionString32(version));
+                               break;
+                       case ld::kPlatform_tvOSSimulator:
+                               linkCommand.push_back("-tvos_simulator_version_min");
+                               linkCommand.push_back(getVersionString32(version));
+                               break;
+                       case ld::kPlatform_bridgeOS:
+                               linkCommand.push_back("-bridgeos_version_min");
+                               linkCommand.push_back(getVersionString32(version));
+                               break;
+                       case ld::kPlatform_iOSMac:
+                               linkCommand.push_back("-iosmac_version_min");
+                               linkCommand.push_back(getVersionString32(version));
+                               break;
+                       case ld::kPlatform_unknown:
+                               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
@@ -2380,6 +2312,20 @@ std::vector<std::string> Options::writeBitcodeLinkOptions() const
        return linkCommand;
 }
 
+const char* Options::checkForNullArgument(const char* argument_name, const char* arg) const
+{
+       if ( arg == NULL )
+               throwf("missing argument for %s", argument_name);
+       return arg;
+}
+
+const char* Options::checkForNullVersionArgument(const char* argument_name, const char* arg) const
+{
+       if ( arg == NULL )
+               throwf("%s missing version argument", argument_name);
+       return arg;
+}
+
 //
 // Process all command line arguments.
 //
@@ -2430,7 +2376,9 @@ void Options::parse(int argc, const char* argv[])
                                exit (0);
                        }
                        else if ( strcmp(arg, "-arch") == 0 ) {
-                               parseArch(argv[++i]);
+                               const char* arch = argv[++i];
+                               parseArch(arch);
+                               fLinkSnapshot.recordArch(arch);
                        }
                        else if ( strcmp(arg, "-dynamic") == 0 ) {
                                // default
@@ -2468,10 +2416,19 @@ void Options::parse(int argc, const char* argv[])
                                fOutputKind = kKextBundle;
                                cannotBeUsedWithBitcode(arg);
                        }
+                       else if ( strcmp(arg, "-kext_objects_dir") == 0 ) {
+                               fKextObjectsDirPath = argv[++i];
+                               if ( fKextObjectsDirPath == NULL )
+                                       throw "missing argument to -kext_objects_dir";
+                               fKextObjectsEnable = 1;
+                       }
+                       else if ( strcmp(arg, "-no_kext_objects") == 0 ) {
+                               fKextObjectsEnable = 0;
+                       }
                        else if ( strcmp(arg, "-o") == 0 ) {
-                snapshotArgCount = 0;
-                               fOutputFile = argv[++i];
-                fLinkSnapshot.setSnapshotName(fOutputFile);
+                               snapshotArgCount = 0;
+                               fOutputFile = checkForNullArgument(arg, argv[++i]);
+                               fLinkSnapshot.setOutputPath(fOutputFile);
                        }
                        else if ( strncmp(arg, "-lazy-l", 7) == 0 ) {
                 snapshotArgCount = 0;
@@ -2498,6 +2455,7 @@ void Options::parse(int argc, const char* argv[])
                                if ( value == NULL )
                                        throw "missing argument to -prune_interval_lto";
                                char* endptr;
+                               fLtoPruneIntervalOverwrite = true;
                                fLtoPruneInterval = strtoul(value, &endptr, 10);
                                if ( *endptr != '\0')
                                        throw "invalid argument for -prune_interval_lto";
@@ -2570,7 +2528,8 @@ void Options::parse(int argc, const char* argv[])
                        }
                        // Similar to -all_load, but for the following archive only.
                        else if ( strcmp(arg, "-force_load") == 0 ) {
-                               FileInfo info = findFile(argv[++i]);
+                               const char* path = checkForNullArgument(arg, argv[++i]);
+                               FileInfo info = findFile(path);
                                info.options.fForceLoad = true;
                                info.ordinal = ld::File::Ordinal::makeArgOrdinal((uint16_t)i);
                                addLibrary(info);
@@ -2697,13 +2656,15 @@ void Options::parse(int argc, const char* argv[])
                                if ( fExportMode == kDontExportSome )
                                        throw "can't use -exported_symbol and -unexported_symbols";
                                fExportMode = kExportSome;
-                               fExportSymbols.insert(argv[++i]);
+                               const char* symbol = checkForNullArgument(arg, argv[++i]);
+                               fExportSymbols.insert(symbol);
                        }
                        else if ( strcmp(arg, "-unexported_symbol") == 0 ) {
                                if ( fExportMode == kExportSome )
                                        throw "can't use -unexported_symbol and -exported_symbol";
                                fExportMode = kDontExportSome;
-                               fDontExportSymbols.insert(argv[++i]);
+                               const char* symbol = checkForNullArgument(arg, argv[++i]);
+                               fDontExportSymbols.insert(symbol);
                        }
                        else if ( strcmp(arg, "-non_global_symbols_no_strip_list") == 0 ) {
                 snapshotFileArgIndex = 1;
@@ -2734,7 +2695,8 @@ void Options::parse(int argc, const char* argv[])
                        else if ( strcmp(arg, "-weak_library") == 0 ) {
                 // SNAPSHOT FIXME: what should we do for link snapshots? (ignore for now)
                 snapshotArgCount = 0;
-                               FileInfo info = findFile(argv[++i]);
+                               const char* path = checkForNullArgument(arg, argv[++i]);
+                               FileInfo info = findFile(path);
                                info.options.fWeakImport = true;
                                info.ordinal = ld::File::Ordinal::makeArgOrdinal((uint16_t)i);
                                addLibrary(info);
@@ -2743,7 +2705,8 @@ void Options::parse(int argc, const char* argv[])
                        else if ( strcmp(arg, "-lazy_library") == 0 ) {
                 // SNAPSHOT FIXME: what should we do for link snapshots? (ignore for now)
                 snapshotArgCount = 0;
-                               FileInfo info = findFile(argv[++i]);
+                               const char* path = checkForNullArgument(arg, argv[++i]);
+                               FileInfo info = findFile(path);
                                info.options.fLazyLoad = true;
                                info.ordinal = ld::File::Ordinal::makeArgOrdinal((uint16_t)i);
                                addLibrary(info);
@@ -2827,12 +2790,11 @@ void Options::parse(int argc, const char* argv[])
                        // are prebound.  This can then be fixed up by update_prebinding
                        // later.  Prebinding is less useful on 10.4 and greater.
                        else if ( strcmp(arg, "-prebind") == 0 ) {
-                               fPrebind = true;
+                               warnObsolete(arg);
                                cannotBeUsedWithBitcode(arg);
                        }
                        else if ( strcmp(arg, "-noprebind") == 0 ) {
                                warnObsolete(arg);
-                               fPrebind = false;
                        }
                        else if ( strcmp(arg, "-prebind_allow_overlap") == 0 ) {
                                warnObsolete(arg);
@@ -2901,22 +2863,23 @@ void Options::parse(int argc, const char* argv[])
                        }
                        // ??? Deprecate when we deprecate split-seg.
                        else if ( strcmp(arg, "-segs_read_only_addr") == 0 ) {
-                               fBaseAddress = parseAddress(argv[++i]);
+                               warnObsolete(arg);
+                               ++i;
                                cannotBeUsedWithBitcode(arg);
                        }
                        // ??? Deprecate when we deprecate split-seg.
                        else if ( strcmp(arg, "-segs_read_write_addr") == 0 ) {
-                               fBaseWritableAddress = parseAddress(argv[++i]);
-                               fSplitSegs = true;
+                               warnObsolete(arg);
+                               ++i;
                                cannotBeUsedWithBitcode(arg);
                        }
                        // ??? Deprecate when we get rid of basing at build time.
                        else if ( strcmp(arg, "-seg_addr_table") == 0 ) {
+                               warnObsolete(arg);
                 snapshotFileArgIndex = 1;
                                const char* name = argv[++i];
                                if ( name == NULL )
                                        throw "-seg_addr_table missing argument";
-                               fSegAddrTablePath = name;
                                cannotBeUsedWithBitcode(arg);
                        }
                        else if ( strcmp(arg, "-seg_addr_table_filename") == 0 ) {
@@ -3000,9 +2963,7 @@ void Options::parse(int argc, const char* argv[])
                        }
                        // Use this flag to set default behavior for deployement targets.
                        else if ( strcmp(arg, "-macosx_version_min") == 0 ) {
-                               const char* macVers = argv[++i];
-                               if ( macVers == NULL )
-                                       throw "-macosx_version_min missing version argument";
+                               const char* macVers = checkForNullVersionArgument(arg, argv[++i]);
                                const char* envMacVers = getenv("MACOSX_DEPLOYMENT_TARGET");
                                const char* enviPhoneVers = getenv("IPHONEOS_DEPLOYMENT_TARGET");
                                if ( (envMacVers != NULL) && (enviPhoneVers != NULL) ) {
@@ -3012,67 +2973,49 @@ void Options::parse(int argc, const char* argv[])
                                                const char* sysrootPath = fSDKPaths.back();
                                                const char* lastSlash = strrchr(sysrootPath, '/');
                                                if ( strstr(lastSlash, "Simulator") != NULL ) 
-                                                       setIOSVersionMin(enviPhoneVers);
+                                                       setVersionMin(ld::kPlatform_iOS, enviPhoneVers);
                                                else
-                                                       setMacOSXVersionMin(macVers);
+                                                       setVersionMin(ld::kPlatform_macOS, macVers);
                                        }
                                        else {
-                                               setMacOSXVersionMin(macVers);
+                                               setVersionMin(ld::kPlatform_macOS, macVers);
                                        }
                                }
                                else {
-                                       setMacOSXVersionMin(macVers);
+                                       setVersionMin(ld::kPlatform_macOS, macVers);
                                }
                        }
                        else if ( (strcmp(arg, "-ios_version_min") == 0) || (strcmp(arg, "-iphoneos_version_min") == 0) ) {
-                               const char* vers = argv[++i];
-                               if ( vers == NULL )
-                                       throw "-ios_version_min missing version argument";
-                               setIOSVersionMin(vers);
+                               const char* vers = checkForNullVersionArgument(arg, argv[++i]);
+                               setVersionMin(ld::kPlatform_iOS, vers);
                        }
                        else if ( strcmp(arg, "-ios_simulator_version_min") == 0 ) {
-                               const char* vers = argv[++i];
-                               if ( vers == NULL )
-                                       throw "-ios_simulator_version_min missing version argument";
-                               setIOSVersionMin(vers);
-                               fTargetIOSSimulator = true;
+                               const char* vers = checkForNullVersionArgument(arg, argv[++i]);
+                               setVersionMin(ld::kPlatform_iOSSimulator, vers);
                        }
                        else if ( strcmp(arg, "-watchos_version_min") == 0 ) {
-                               const char* vers = argv[++i];
-                               if ( vers == NULL )
-                                       throw "-watchos_version_min missing version argument";
-                               setWatchOSVersionMin(vers);
+                               const char* vers = checkForNullVersionArgument(arg, argv[++i]);
+                               setVersionMin(ld::kPlatform_watchOS, vers);
                        }
                        else if ( strcmp(arg, "-watchos_simulator_version_min") == 0 ) {
-                               const char* vers = argv[++i];
-                               if ( vers == NULL )
-                                       throw "-watchos_simulator_version_min missing version argument";
-                               setWatchOSVersionMin(vers);
-                               fTargetIOSSimulator = true;
+                               const char* vers = checkForNullVersionArgument(arg, argv[++i]);
+                               setVersionMin(ld::kPlatform_watchOSSimulator, vers);
                        }
-       #if SUPPORT_APPLE_TV
                        else if ( strcmp(arg, "-tvos_version_min") == 0 ) {
-                               const char* vers = argv[++i];
-                               if ( vers == NULL )
-                                       throw "-tvos_version_min missing version argument";
-                               setIOSVersionMin(vers);
-                               fPlatform = kPlatform_tvOS;
+                               const char* vers = checkForNullVersionArgument(arg, argv[++i]);
+                               setVersionMin(ld::kPlatform_tvOS, vers);
                        }
                        else if ( strcmp(arg, "-tvos_simulator_version_min") == 0 ) {
-                               const char* vers = argv[++i];
-                               if ( vers == NULL )
-                                       throw "-tvos_simulator_version_min missing version argument";
-                               setIOSVersionMin(vers);
-                               fPlatform = kPlatform_tvOS;
-                               fTargetIOSSimulator = true;
-                       }
-       #endif
+                               const char* vers = checkForNullVersionArgument(arg, argv[++i]);
+                               setVersionMin(ld::kPlatform_tvOSSimulator, vers);
+                       }
                        else if ( strcmp(arg, "-bridgeos_version_min") == 0 ) {
-                               const char* vers = argv[++i];
-                               if ( vers == NULL )
-                                       throw "-bridgeos_version_min missing version argument";
-                               setIOSVersionMin(vers);
-                               fPlatform = kPlatform_bridgeOS;
+                               const char* vers = checkForNullVersionArgument(arg, argv[++i]);
+                               setVersionMin(ld::kPlatform_bridgeOS, vers);
+                       }
+                       else if ( strcmp(arg, "-iosmac_version_min") == 0 ) {
+                               const char* vers = checkForNullVersionArgument(arg, argv[++i]);
+                               setVersionMin(ld::kPlatform_iOSMac, vers);
                        }
                        else if ( strcmp(arg, "-multiply_defined") == 0 ) {
                                //warnObsolete(arg);
@@ -3307,12 +3250,8 @@ void Options::parse(int argc, const char* argv[])
                        }
                        else if ( strcmp(arg, "-alias") == 0 ) {
                                Options::AliasPair pair;
-                               pair.realName = argv[++i];
-                               if ( pair.realName == NULL )
-                                       throw "missing argument to -alias";
-                               pair.alias = argv[++i];
-                               if ( pair.alias == NULL )
-                                       throw "missing argument to -alias";
+                               pair.realName = checkForNullArgument(arg, argv[++i]);
+                               pair.alias = checkForNullArgument(arg, argv[++i]);
                                fAliases.push_back(pair);
                                cannotBeUsedWithBitcode(arg);
                        }
@@ -3331,9 +3270,7 @@ void Options::parse(int argc, const char* argv[])
                                fVerifyBitcode = true;
                        }
                        else if ( strcmp(arg, "-bitcode_symbol_map") == 0) {
-                               fReverseMapPath = argv[++i];
-                               if ( fReverseMapPath == NULL )
-                                       throw "missing argument to -bitcode_symbol_map";
+                               fReverseMapPath = checkForNullArgument(arg, argv[++i]);
                                struct stat statbuf;
                                int ret = ::stat(fReverseMapPath, &statbuf);
                                if ( ret == 0 && S_ISDIR(statbuf.st_mode)) {
@@ -3348,20 +3285,18 @@ void Options::parse(int argc, const char* argv[])
                                } else
                                        fReverseMapTempPath = std::string(fReverseMapPath);
                        }
-                       else if ( strcmp(argv[i], "-flto-codegen-only") == 0) {
+                       else if ( strcmp(arg, "-flto-codegen-only") == 0) {
                                fLTOCodegenOnly = true;
                        }
-                       else if ( strcmp(argv[i], "-ignore_auto_link") == 0) {
+                       else if ( strcmp(arg, "-ignore_auto_link") == 0) {
                                fIgnoreAutoLink = true;
                        }
-                       else if ( strcmp(argv[i], "-allow_dead_duplicates") == 0) {
+                       else if ( strcmp(arg, "-allow_dead_duplicates") == 0) {
                                fAllowDeadDups = true;
                        }
-                       else if ( strcmp(argv[i], "-bitcode_process_mode") == 0 ) {
-                               const char* bitcode_type = argv[++i];
-                               if ( bitcode_type == NULL )
-                                       throw "missing argument to -bitcode_process_mode";
-                               else if ( strcmp(bitcode_type, "strip") == 0 )
+                       else if ( strcmp(arg, "-bitcode_process_mode") == 0 ) {
+                               const char* bitcode_type = checkForNullArgument(arg, argv[++i]);
+                               if ( strcmp(bitcode_type, "strip") == 0 )
                                        fBitcodeKind = kBitcodeStrip;
                                else if ( strcmp(bitcode_type, "marker") == 0 )
                                        fBitcodeKind = kBitcodeMarker;
@@ -3373,9 +3308,7 @@ void Options::parse(int argc, const char* argv[])
                                        throw "unknown argument to -bitcode_process_mode {strip,marker,data,bitcode}";
                        }
                        else if ( strcmp(arg, "-rpath") == 0 ) {
-                               const char* path = argv[++i];
-                               if ( path == NULL )
-                                       throw "missing argument to -rpath";
+                               const char* path = checkForNullArgument(arg, argv[++i]);
                                fRPaths.push_back(path);
                        }
                        else if ( strcmp(arg, "-read_only_stubs") == 0 ) {
@@ -3385,9 +3318,7 @@ void Options::parse(int argc, const char* argv[])
                                warnObsolete(arg);
                        }
                        else if ( strcmp(arg, "-map") == 0 ) {
-                               fMapPath = argv[++i];
-                               if ( fMapPath == NULL )
-                                       throw "missing argument to -map";
+                               fMapPath = checkForNullArgument(arg, argv[++i]);
                        }
                        else if ( strcmp(arg, "-pie") == 0 ) {
                                fPositionIndependentExecutable = true;
@@ -3409,7 +3340,8 @@ void Options::parse(int argc, const char* argv[])
                        else if ( strcmp(arg, "-reexport_library") == 0 ) {
                 // SNAPSHOT FIXME: what should we do for link snapshots? (ignore for now)
                 snapshotArgCount = 0;
-                               FileInfo info = findFile(argv[++i]);
+                               const char* path = checkForNullArgument(arg, argv[++i]);
+                               FileInfo info = findFile(path);
                                info.options.fReExport = true;
                                info.ordinal = ld::File::Ordinal::makeArgOrdinal((uint16_t)i);
                                addLibrary(info);
@@ -3436,7 +3368,8 @@ void Options::parse(int argc, const char* argv[])
                        else if ( strcmp(arg, "-upward_library") == 0 ) {
                 // SNAPSHOT FIXME: what should we do for link snapshots? (ignore for now)
                 snapshotArgCount = 0;
-                               FileInfo info = findFile(argv[++i]);
+                               const char* path = checkForNullArgument(arg, argv[++i]);
+                               FileInfo info = findFile(path);
                                info.options.fUpward = true;
                                info.ordinal = ld::File::Ordinal::makeArgOrdinal((uint16_t)i);
                                addLibrary(info);
@@ -3474,16 +3407,12 @@ void Options::parse(int argc, const char* argv[])
                                cannotBeUsedWithBitcode(arg);
                        }
                        else if ( strcmp(arg, "-mllvm") == 0 ) {
-                               const char* opts = argv[++i];
-                               if ( opts == NULL )
-                                       throw "missing argument to -mllvm";
+                               const char* opts = checkForNullArgument(arg, argv[++i]);
                                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";
+                               const char* cpu = checkForNullArgument(arg, argv[++i]);
                                fLtoCpu = cpu;
                                cannotBeUsedWithBitcode(arg);
                        }
@@ -3539,9 +3468,7 @@ void Options::parse(int argc, const char* argv[])
                                cannotBeUsedWithBitcode(arg);
                        }
                        else if ( strcmp(arg, "-objc_abi_version") == 0 ) {
-                               const char* version = argv[++i];
-                                if ( version == NULL )
-                                       throw "-objc_abi_version missing version number";
+                               const char* version = checkForNullVersionArgument(arg, argv[++i]);
                                if ( strcmp(version, "2") == 0 ) {
                                        fObjCABIVersion1Override = false;
                                        fObjCABIVersion2Override = true;
@@ -3565,17 +3492,17 @@ void Options::parse(int argc, const char* argv[])
                        }
                        else if ( strcmp(arg, "-objc_gc") == 0 ) {
                                fObjCGc = true;
-                               if ( fObjCGcOnly ) { 
+                               if ( fObjCGcOnly ) {
                                        warning("-objc_gc overriding -objc_gc_only");
-                                       fObjCGcOnly = false;    
+                                       fObjCGcOnly = false;
                                }
                                cannotBeUsedWithBitcode(arg);
                        }
                        else if ( strcmp(arg, "-objc_gc_only") == 0 ) {
                                fObjCGcOnly = true;
-                               if ( fObjCGc ) { 
+                               if ( fObjCGc ) {
                                        warning("-objc_gc_only overriding -objc_gc");
-                                       fObjCGc = false;        
+                                       fObjCGc = false;
                                }
                                cannotBeUsedWithBitcode(arg);
                        }
@@ -3586,11 +3513,6 @@ void Options::parse(int argc, const char* argv[])
                                fVersionLoadCommandForcedOn = true;
                                fVersionLoadCommandForcedOff = 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;
                                fFunctionStartsForcedOff = false;
@@ -3610,9 +3532,7 @@ void Options::parse(int argc, const char* argv[])
                                fDataInCodeInfoLoadCommandForcedOff = false;
                        }
                        else if ( strcmp(arg, "-object_path_lto") == 0 ) {
-                               fTempLtoObjectPath = argv[++i];
-                               if ( fTempLtoObjectPath == NULL )
-                                       throw "missing argument to -object_path_lto";
+                               fTempLtoObjectPath = checkForNullArgument(arg, argv[++i]);
                        }
                        else if ( strcmp(arg, "-no_objc_category_merging") == 0 ) {
                                fObjcCategoryMerging = false;
@@ -3674,14 +3594,6 @@ void Options::parse(int argc, const char* argv[])
                                fSnapshotRequested = true;
                                cannotBeUsedWithBitcode(arg);
             }
-                       else if ( strcmp(arg, "-new_main") == 0 ) {
-                               fEntryPointLoadCommandForceOn = true;
-                               cannotBeUsedWithBitcode(arg);
-                       }
-                       else if ( strcmp(arg, "-no_new_main") == 0 ) {
-                               fEntryPointLoadCommandForceOff = true;
-                               cannotBeUsedWithBitcode(arg);
-                       }
                        else if ( strcmp(arg, "-source_version") == 0 ) {
                                 const char* vers = argv[++i];
                                 if ( vers == NULL )
@@ -3711,7 +3623,7 @@ void Options::parse(int argc, const char* argv[])
                                fKextsUseStubs = true;
                                cannotBeUsedWithBitcode(arg);
                        }
-                       else if ( strcmp(argv[i], "-dependency_info") == 0 ) {
+                       else if ( strcmp(arg, "-dependency_info") == 0 ) {
                 snapshotArgCount = 0;
                                ++i;
                                // previously handled by buildSearchPaths()
@@ -3928,15 +3840,24 @@ void Options::parse(int argc, const char* argv[])
                                }
                                fMaxDefaultCommonAlign = alignment;
                        }
-                       else if ( strcmp(argv[i], "-no_weak_imports") == 0 ) {
+                       else if ( strcmp(arg, "-no_weak_imports") == 0 ) {
                                fAllowWeakImports = false;
                        }
-                       else if ( strcmp(argv[i], "-no_inits") == 0 ) {
+                       else if ( strcmp(arg, "-no_inits") == 0 ) {
                                fInitializersTreatment = Options::kError;
                        }
-                       else if ( strcmp(argv[i], "-no_warn_inits") == 0 ) {
+                       else if ( strcmp(arg, "-no_warn_inits") == 0 ) {
                                fInitializersTreatment = Options::kSuppress;
                        }
+                       else if ( strcmp(arg, "-threaded_starts_section") == 0 ) {
+                               fMakeThreadedStartsSection = true;
+                       }
+                       else if (strcmp(arg, "-debug_variant") == 0) {
+                           fDebugVariant = true;
+            }
+                       else if (strcmp(arg, "-no_new_main") == 0) {
+                               // HACK until 39514191 is fixed
+                       }
                        // 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, ':');
@@ -3977,9 +3898,25 @@ void Options::parse(int argc, const char* argv[])
     
     if (fSnapshotRequested)
         fLinkSnapshot.createSnapshot();
-}
-
 
+       if ( kKextBundle == fOutputKind ) {
+               if ( fKextObjectsEnable < 0 )
+                       fKextObjectsEnable = ((fArchitecture == CPU_TYPE_ARM64) || (fArchitecture == CPU_TYPE_ARM));
+
+               if (fKextObjectsEnable > 0) {
+                       if ( !fKextObjectsDirPath ) {
+                               const char* dstroot;
+                               const char* objdir = getenv("LD_KEXT_OBJECTS_DIR");
+                               if ( objdir )
+                                       fKextObjectsDirPath = strdup(objdir);
+                               else if ( (dstroot = getenv("DSTROOT")) )
+                                       asprintf((char **)&fKextObjectsDirPath, "%s/AppleInternal/KextObjects", dstroot);
+                       }
+                       fLinkSnapshot.setSnapshotMode(Snapshot::SNAPSHOT_KEXT);
+                       fLinkSnapshot.createSnapshot();
+               }
+       }
+}
 
 //
 // -syslibroot <path> is used for SDK support.
@@ -4033,6 +3970,7 @@ void Options::buildSearchPaths(int argc, const char* argv[])
                        fVerbose = true;
                        extern const char ldVersionString[];
                        fprintf(stderr, "%s", ldVersionString);
+                       fprintf(stderr, "BUILD "  __TIME__ " "  __DATE__"\n");
                        fprintf(stderr, "configured to support archs: %s\n", ALL_SUPPORTED_ARCHS);
                         // if only -v specified, exit cleanly
                         if ( argc == 2 ) {
@@ -4243,9 +4181,6 @@ void Options::parsePreCommandLineEnvironmentSettings()
        if (getenv("LD_PRINT_ORDER_FILE_STATISTICS") != NULL)
                fPrintOrderFileStatistics = true;
 
-       if (getenv("LD_SPLITSEGS_NEW_LIBRARIES") != NULL)
-               fSplitSegs = true;
-               
        if (getenv("LD_NO_ENCRYPT") != NULL) {
                fEncryptable = false;
                fMarkAppExtensionSafe = true; // temporary
@@ -4288,6 +4223,21 @@ void Options::parsePreCommandLineEnvironmentSettings()
        // <rdar://problem/30746905> [Reproducible Builds] If env ZERO_AR_DATE is set, zero out timestamp in N_OSO stab
        if ( getenv("ZERO_AR_DATE") != NULL )
                fZeroModTimeInDebugMap = true;
+
+       char rawPath[PATH_MAX];
+       char path[PATH_MAX];
+       char *base;
+       uint32_t bufSize = PATH_MAX;
+       if ( _NSGetExecutablePath(rawPath, &bufSize) != -1 ) {
+               if ( realpath(rawPath, path) != NULL ) {
+#define TOOLCHAINBASEPATH "/Developer/Toolchains/"
+                       if ( (base = strstr(path, TOOLCHAINBASEPATH)) )
+                               fToolchainPath = strndup(path, base - path + strlen(TOOLCHAINBASEPATH));
+               }
+       }
+
+       // <rdar://problem/38679559> ld64 should consider RC_RELEASE when calculating a binary's UUID
+       fBuildContextName = getenv("RC_RELEASE");
 }
 
 
@@ -4299,15 +4249,6 @@ void Options::parsePostCommandLineEnvironmentSettings()
                fExecutablePath = fOutputFile;
        }
 
-       // allow build system to set default seg_addr_table
-       if ( fSegAddrTablePath == NULL )
-               fSegAddrTablePath = getenv("LD_SEG_ADDR_TABLE");
-
-       // allow build system to turn on prebinding
-       if ( !fPrebind ) {
-               fPrebind = ( getenv("LD_PREBIND") != NULL );
-       }
-       
        // allow build system to force on dead-code-stripping
        if ( !fDeadStrip ) {
                if ( getenv("LD_DEAD_STRIP") != NULL ) {
@@ -4374,20 +4315,22 @@ void Options::reconfigureDefaults()
        }
 
        // set default min OS version
-       if ( (fMacVersionMin == ld::macVersionUnset) && (fIOSVersionMin == ld::iOSVersionUnset) && (fWatchOSVersionMin == ld::wOSVersionUnset) ) {
+       if ( platforms().empty() ) {
                // if neither -macosx_version_min nor -iphoneos_version_min used, try environment variables
+               if ( (fOutputKind != Options::kObjectFile) && (fOutputKind != Options::kPreload) )
+                       warning("No version-min specified on command line");
                const char* macVers = getenv("MACOSX_DEPLOYMENT_TARGET");
                const char* iPhoneVers = getenv("IPHONEOS_DEPLOYMENT_TARGET");
                const char* iOSVers = getenv("IOS_DEPLOYMENT_TARGET");
                const char* wOSVers = getenv("WATCHOS_DEPLOYMENT_TARGET");
                if ( macVers != NULL )
-                       setMacOSXVersionMin(macVers);
+                       setVersionMin(ld::kPlatform_macOS, macVers);
                else if ( iPhoneVers != NULL )
-                       setIOSVersionMin(iPhoneVers);
+                       setVersionMin(ld::kPlatform_iOS, iPhoneVers);
                else if ( iOSVers != NULL )
-                       setIOSVersionMin(iOSVers);
+                       setVersionMin(ld::kPlatform_iOS, iOSVers);
                else if ( wOSVers != NULL )
-                       setWatchOSVersionMin(wOSVers);
+                       setVersionMin(ld::kPlatform_watchOS, wOSVers);
                else {
                        // if still nothing, set default based on architecture
                        switch ( fArchitecture ) {
@@ -4396,26 +4339,26 @@ void Options::reconfigureDefaults()
                                        if ( (fOutputKind != Options::kObjectFile) && (fOutputKind != Options::kPreload) ) {
                        #ifdef DEFAULT_MACOSX_MIN_VERSION
                                                warning("-macosx_version_min not specified, assuming " DEFAULT_MACOSX_MIN_VERSION);
-                                               setMacOSXVersionMin(DEFAULT_MACOSX_MIN_VERSION);
+                                               setVersionMin(ld::kPlatform_macOS, DEFAULT_MACOSX_MIN_VERSION);
                        #else
                                                warning("-macosx_version_min not specified, assuming 10.6");
-                                               setMacOSXVersionMin("10.6");
-                       #endif          
+                                               setVersionMin(ld::kPlatform_macOS, "10.6");
+                       #endif
                                        }
                                        break;
                                case CPU_TYPE_ARM:
                                        if ( (fOutputKind != Options::kObjectFile) && (fOutputKind != Options::kPreload) ) {
                        #if defined(DEFAULT_IPHONEOS_MIN_VERSION)
                                                warning("-ios_version_min not specified, assuming " DEFAULT_IPHONEOS_MIN_VERSION);
-                                               setIOSVersionMin(DEFAULT_IPHONEOS_MIN_VERSION);
+                                               setVersionMin(ld::kPlatformiOS, DEFAULT_IPHONEOS_MIN_VERSION);
                        #else
                                                if ( fSubArchitecture == CPU_SUBTYPE_ARM_V7K ) {
                                                        warning("-watchos_version_min not specified, assuming 2.0");
-                                                       setWatchOSVersionMin("2.0");
+                                                       setVersionMin(ld::kPlatform_watchOS, "2.0");
                                                }
                                                else {
                                                        warning("-ios_version_min not specified, assuming 6.0");
-                                                       setIOSVersionMin("6.0");
+                                                       setVersionMin(ld::kPlatform_iOS, "6.0");
                                                }
                        #endif
                                        }
@@ -4427,29 +4370,23 @@ void Options::reconfigureDefaults()
                }
        }
 
-
+       __block ld::VersionSet platformOverrides;
        // adjust min based on architecture
-       switch ( fArchitecture ) {
-               case CPU_TYPE_I386:
-                       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:
-                       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:
-                       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;
-                       }
-                       break;
-       }
-       
+       platforms().forEach(^(ld::Platform platform, uint32_t version, bool &stop) {
+               if ( (fArchitecture == CPU_TYPE_I386 || fArchitecture == CPU_TYPE_X86_64)
+                               && platform == ld::kPlatform_macOS && !platforms().minOS(ld::mac10_4) ) {
+                       platformOverrides.add(ld::mac10_4);
+               } else if (fArchitecture == CPU_TYPE_ARM64 && platform == ld::kPlatform_iOS
+                                  && !platforms().minOS(ld::iOS_7_0)) {
+                       platformOverrides.add(ld::iOS_7_0);
+               }
+       });
+
+       // Insert the overrides into fPlatfroms
+       platformOverrides.forEach(^(ld::Platform platform, uint32_t version, bool &stop) {
+               fPlatforms.add({platform, version});
+       });
+
        // default to adding functions start for dynamic code, static code must opt-in
        switch ( fOutputKind ) {
                case Options::kPreload:
@@ -4496,17 +4433,12 @@ void Options::reconfigureDefaults()
                                fUndefinedTreatment = kUndefinedDynamicLookup;
                                break;
                        case CPU_TYPE_ARM:
-                               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
-                                       fAllowTextRelocs = !min_iOS(ld::iOS_6_0);
-                                       fKextsUseStubs = !fAllowTextRelocs;
-                    fUndefinedTreatment = kUndefinedDynamicLookup;
-                                       break;
-                               }
-                               // else use object file
+                               fMakeCompressedDyldInfo = false;
+                               fMakeCompressedDyldInfoForceOff = true;
+                               fAllowTextRelocs = false;
+                               fKextsUseStubs = !fAllowTextRelocs;
+                               fUndefinedTreatment = kUndefinedDynamicLookup;
+                               break;
                        case CPU_TYPE_I386:
                                // use .o files
                                fOutputKind = kObjectFile;
@@ -4516,65 +4448,9 @@ void Options::reconfigureDefaults()
 
        // disable implicit dylibs when targeting 10.3
        // <rdar://problem/5451987> add option to disable implicit load commands for indirectly used public dylibs
-       if ( !minOS(ld::mac10_4, ld::iOS_2_0) )
+       if ( !platforms().minOS(ld::version2007) )
                fImplicitlyLinkPublicDylibs = false;
 
-
-       // allow build system to force linker to ignore -prebind
-       if ( getenv("LD_FORCE_NO_PREBIND") != NULL )
-               fPrebind = false;                       
-
-       // allow build system to force linker to ignore -seg_addr_table
-       if ( getenv("LD_FORCE_NO_SEG_ADDR_TABLE") != NULL )
-                  fSegAddrTablePath = NULL;
-
-       // check for base address specified externally
-       if ( (fSegAddrTablePath != NULL) &&  (fOutputKind == Options::kDynamicLibrary) ) {
-               parseSegAddrTable(fSegAddrTablePath, this->installPath());
-               // HACK to support seg_addr_table entries that are physical paths instead of install paths
-               if ( fBaseAddress == 0 ) {
-                       if ( strcmp(this->installPath(), "/usr/lib/libstdc++.6.dylib") == 0 ) {
-                               parseSegAddrTable(fSegAddrTablePath, "/usr/lib/libstdc++.6.0.4.dylib");
-                               if ( fBaseAddress == 0 )
-                                       parseSegAddrTable(fSegAddrTablePath, "/usr/lib/libstdc++.6.0.9.dylib");
-                       }
-                               
-                       else if ( strcmp(this->installPath(), "/usr/lib/libz.1.dylib") == 0 ) 
-                               parseSegAddrTable(fSegAddrTablePath, "/usr/lib/libz.1.2.3.dylib");
-                               
-                       else if ( strcmp(this->installPath(), "/usr/lib/libutil.dylib") == 0 ) 
-                               parseSegAddrTable(fSegAddrTablePath, "/usr/lib/libutil1.0.dylib");
-               }               
-       }
-       
-       // split segs only allowed for dylibs
-       if ( fSplitSegs ) {
-        // split seg only supported for i386, and arm.
-        switch ( fArchitecture ) {
-            case CPU_TYPE_I386:
-                if ( fOutputKind != Options::kDynamicLibrary )
-                    fSplitSegs = false;
-                // make sure read and write segments are proper distance apart
-                if ( fSplitSegs && (fBaseWritableAddress-fBaseAddress != 0x10000000) )
-                    fBaseWritableAddress = fBaseAddress + 0x10000000;
-                break;
-            case CPU_TYPE_ARM:
-                if ( fOutputKind != Options::kDynamicLibrary ) {
-                    fSplitSegs = false;
-                               }
-                               else {
-                                       // make sure read and write segments are proper distance apart
-                                       if ( fSplitSegs && (fBaseWritableAddress-fBaseAddress != 0x08000000) )
-                                               fBaseWritableAddress = fBaseAddress + 0x08000000;
-                               }
-                break;
-            default:
-                fSplitSegs = false;
-                fBaseAddress = 0;
-                fBaseWritableAddress = 0;
-               }
-       }
-
        // set too-large size
        switch ( fArchitecture ) {
                case CPU_TYPE_I386:
@@ -4606,77 +4482,10 @@ void Options::reconfigureDefaults()
                        break;
        }
 
-       // <rdar://problem/6138961> -r implies no prebinding for all architectures
-       if ( fOutputKind == Options::kObjectFile )
-               fPrebind = false;                       
-
-       // disable prebinding depending on arch and min OS version
-       if ( fPrebind ) {
-               switch ( fArchitecture ) {
-                       case CPU_TYPE_I386:
-                               if ( fMacVersionMin == ld::mac10_4 ) {
-                                       // in 10.4 only split seg dylibs are prebound
-                                       if ( (fOutputKind != Options::kDynamicLibrary) || ! fSplitSegs )
-                                               fPrebind = false;
-                               }
-                               else if ( fMacVersionMin >= ld::mac10_5 ) {
-                                       // in 10.5 nothing is prebound
-                                       fPrebind = false;
-                               }
-                               else if ( fIOSVersionMin != ld::iOSVersionUnset ) {
-                                       // nothing in simulator is prebound
-                                       fPrebind = false;
-                               }
-                               else {
-                                       // in 10.3 and earlier only dylibs and main executables could be prebound
-                                       switch ( fOutputKind ) {
-                                               case Options::kDynamicExecutable:
-                                               case Options::kDynamicLibrary:
-                                                       // only main executables and dylibs can be prebound
-                                                       break;
-                                               case Options::kStaticExecutable:
-                                               case Options::kDynamicBundle:
-                                               case Options::kObjectFile:
-                                               case Options::kDyld:
-                                               case Options::kPreload:
-                                               case Options::kKextBundle:
-                                                       // disable prebinding for everything else
-                                                       fPrebind = false;
-                                                       break;
-                                       }
-                               }
-                               break;
-                       case CPU_TYPE_X86_64:
-                               fPrebind = false;
-                               break;
-            case CPU_TYPE_ARM:
-                               switch ( fOutputKind ) {
-                                       case Options::kDynamicExecutable:
-                                       case Options::kDynamicLibrary:
-                                               // only main executables and dylibs can be prebound
-                                               break;
-                                       case Options::kStaticExecutable:
-                                       case Options::kDynamicBundle:
-                                       case Options::kObjectFile:
-                                       case Options::kDyld:
-                                       case Options::kPreload:
-                                       case Options::kKextBundle:
-                                               // disable prebinding for everything else
-                                               fPrebind = false;
-                                               break;
-                               }
-                               break;
-               }
-       }
-
-       // only prebound images can be split-seg
-       if ( fSplitSegs && !fPrebind )
-               fSplitSegs = false;
-
        // determine if info for shared region should be added
        if ( fOutputKind == Options::kDynamicLibrary ) {
-               if ( minOS(ld::mac10_5, ld::iOS_3_1) )
-                       if ( !fPrebind && !fSharedRegionEligibleForceOff )
+               if ( platforms().minOS(ld::version2008Fall) )
+                       if ( !fSharedRegionEligibleForceOff )
                                if ( sharedCacheEligiblePath(this->installPath()) )
                                        fSharedRegionEligible = true;
        }
@@ -4685,21 +4494,26 @@ void Options::reconfigureDefaults()
         fSharedRegionEligible = true;
        }
 
-       // automatically use __DATA_CONST in iOS dylibs
-       if ( fSharedRegionEligible && minOS(ld::mac10_Future, ld::iOS_9_0) && !fUseDataConstSegmentForceOff && !fTargetIOSSimulator) {
+       // automatically use __DATA_CONST in dylibs on all platforms except macOS
+       if ( fSharedRegionEligible && !fUseDataConstSegmentForceOff
+               && !platforms().contains(ld::kPlatform_macOS) && !targetIOSSimulator()) {
                fUseDataConstSegment = true;
        }
        if ( fUseDataConstSegmentForceOn ) {
                fUseDataConstSegment = true;
        }
        // A -kext for iOS 10 ==>  -data_const, -text_exec, -add_split_seg_info
-       if ( (fOutputKind == Options::kKextBundle) && minOS(ld::mac10_Future, ld::iOS_10_0) && (fArchitecture == CPU_TYPE_ARM64) ) {
+       if ( (fOutputKind == Options::kKextBundle) && (fArchitecture == CPU_TYPE_ARM64) ) {
                fUseDataConstSegment = true;
                fUseTextExecSegment = true;
                fSharedRegionEligible = true;
        }
        if ( fUseDataConstSegment ) {
                addSectionRename("__DATA", "__got",                             "__DATA_CONST", "__got");
+
+#if SUPPORT_ARCH_arm64e
+               addSectionRename("__DATA", "__auth_got",                "__DATA_CONST", "__auth_got");
+#endif
                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");
@@ -4720,9 +4534,9 @@ void Options::reconfigureDefaults()
        }
        
        // Use V2 shared cache info when targetting newer OSs
-       if ( fSharedRegionEligible && minOS(ld::mac10_12, ld::iOS_9_0)) {
+       if ( fSharedRegionEligible && platforms().minOS(ld::supportsSplitSegV2)) {
                fSharedRegionEncodingV2 = true;
-               if ( fPlatform == kPlatformOSX ) {
+               if ( platforms().contains(ld::kPlatform_macOS) ) {
                        fSharedRegionEncodingV2 = false;
                        // <rdar://problem/24772435> only use v2 for Swift dylibs on Mac OS X
                        if ( strncmp(this->installPath(), "/System/Library/PrivateFrameworks/Swift/", 40) == 0 )
@@ -4741,19 +4555,6 @@ void Options::reconfigureDefaults()
                fIgnoreOptimizationHints = true;
        }
 
-       // figure out if module table is needed for compatibility with old ld/dyld
-       if ( fOutputKind == Options::kDynamicLibrary ) {
-               switch ( fArchitecture ) {
-                       case CPU_TYPE_I386:
-                               if ( fIOSVersionMin != ld::iOSVersionUnset ) // simulator never needs modules
-                                       break;
-                       case CPU_TYPE_ARM:
-                               if ( fPrebind )
-                                       fNeedsModuleTable = true; // redo_prebinding requires a module table
-                               break;
-               }
-       }
-       
        // <rdar://problem/5366363> -r -x implies -S
        if ( (fOutputKind == Options::kObjectFile) && (fLocalSymbolHandling == kLocalSymbolsNone) )
                fDebugInfoStripping = Options::kDebugInfoNone;                  
@@ -4825,7 +4626,7 @@ void Options::reconfigureDefaults()
                case Options::kDynamicLibrary:
                case Options::kDynamicBundle:
                        // <rdar://problem/16293398> Add LC_ENCRYPTION_INFO load command to bundled frameworks
-                       if ( !min_iOS(ld::iOS_7_0) )
+                       if ( !platforms().minOS(ld::version2013) )
                                fEncryptable = false;
                        break;
        }
@@ -4864,35 +4665,33 @@ void Options::reconfigureDefaults()
                case Options::kDynamicLibrary:
                case Options::kDynamicBundle:
                        break;
+               case Options::kDyld:
+                       // arm64e has support for compressed LINKEDIT.
+                       if ( (fArchitecture == CPU_TYPE_ARM64) && (fSubArchitecture == CPU_SUBTYPE_ARM64_E) )
+                               break;
                case Options::kPreload:
                case Options::kStaticExecutable:
                case Options::kObjectFile:
-               case Options::kDyld:
                case Options::kKextBundle:
                        fMakeCompressedDyldInfoForceOff = true;
                        break;
        }
-       if ( fMakeCompressedDyldInfoForceOff ) 
-               fMakeCompressedDyldInfo = false;
 
-       
-       // only use compressed LINKEDIT for:
-       //                      Mac OS X 10.6 or later
-       //                      iOS 3.1 or later
-       if ( fMakeCompressedDyldInfo ) {
-               if ( !minOS(ld::mac10_6, ld::iOS_3_1) )
-                       fMakeCompressedDyldInfo = false;
-       }
+       // only use legacy LINKEDIT if compressed LINKEDIT is forced off of:
+       //                      macOS before 10.6
+       //                      iOS before 3.1
+       if ( fMakeCompressedDyldInfoForceOff || !platforms().minOS(ld::version2009) )
+               fMakeCompressedDyldInfo = false;
 
        // only ARM and x86_64 enforces that cpu-sub-types must match
        switch ( fArchitecture ) {
                case CPU_TYPE_ARM:
+               case CPU_TYPE_ARM64:
                        break;
                case CPU_TYPE_X86_64:
                        fEnforceDylibSubtypesMatch = false;
                        break;
                case CPU_TYPE_I386:
-               case CPU_TYPE_ARM64:
                        fEnforceDylibSubtypesMatch = false;
                        break;
        }
@@ -4924,34 +4723,107 @@ void Options::reconfigureDefaults()
        }
        
        // Mac OS X 10.5 and iPhoneOS 2.0 support LC_REEXPORT_DYLIB
-       if ( minOS(ld::mac10_5, ld::iOS_2_0) )
+       if ( platforms().minOS(ld::version2008) )
                fUseSimplifiedDylibReExports = true;
        
        // Mac OS X 10.7 and iOS 4.2 support LC_LOAD_UPWARD_DYLIB
-       if ( minOS(ld::mac10_7, ld::iOS_4_2) && (fOutputKind == kDynamicLibrary) )
+       if ( platforms().minOS(ld::version2010) && (fOutputKind == kDynamicLibrary) )
                fCanUseUpwardDylib = true;
-               
+
+       if (fArchitecture == CPU_TYPE_ARM64) {
+#if SUPPORT_ARCH_arm64e
+               if (fSubArchitecture == CPU_SUBTYPE_ARM64_E)
+               {
+                       // FIXME: Move some of these to arm64
+                       fNoLazyBinding = true;
+                       switch ( fOutputKind ) {
+                               case Options::kDynamicExecutable:
+                               case Options::kDynamicLibrary:
+                               case Options::kDynamicBundle:
+                               case Options::kDyld:
+                                       fUseLinkedListBinding = true;
+                                       fUseAuthenticatedStubs = true;
+                                       break;
+                               case Options::kPreload:
+                               case Options::kStaticExecutable:
+                               case Options::kObjectFile:
+                               case Options::kKextBundle:
+                                       break;
+                       }
+                       switch ( fOutputKind ) {
+                               case Options::kDynamicExecutable:
+                               case Options::kDyld:
+                               case Options::kDynamicLibrary:
+                               case Options::kObjectFile:
+                               case Options::kDynamicBundle:
+                               case Options::kKextBundle:
+                                       fSupportsAuthenticatedPointers = true;
+                                       break;
+                               case Options::kStaticExecutable:
+                               case Options::kPreload:
+                                       fSupportsAuthenticatedPointers = false;
+                                       break;
+                       }
+               }
+#endif
+       }
+
+       if ( fMakeThreadedStartsSection && (fArchitecture != CPU_TYPE_ARM64) ) {
+               // Threaded starts isn't valid here so ignore it.
+               warning("-threaded_starts_section ignored ignored for non-arm64");
+               fMakeThreadedStartsSection = false;
+       }
+
+       if (fMakeThreadedStartsSection) {
+               switch ( fOutputKind ) {
+                       case Options::kDynamicExecutable:
+                       case Options::kDyld:
+                       case Options::kDynamicLibrary:
+                       case Options::kObjectFile:
+                       case Options::kDynamicBundle:
+                       case Options::kKextBundle:
+                               // Threaded starts isn't valid here so ignore it.
+                               warning("-threaded_starts_section ignored for binaries other than -static or -preload");
+                               fMakeThreadedStartsSection = false;
+                               break;
+                       case Options::kStaticExecutable:
+                       case Options::kPreload:
+                               fUseLinkedListBinding = true;
+                               fNoLazyBinding = true;
+#if SUPPORT_ARCH_arm64e
+                               if ( (fArchitecture == CPU_TYPE_ARM64) && (fSubArchitecture == CPU_SUBTYPE_ARM64_E) )
+                                       fSupportsAuthenticatedPointers = true;
+#endif
+                               break;
+               }
+       }
+
+       // Weak binding requires that if we want to use linked list binding, we must
+       // also be using no lazy binding.
+       if ( fUseLinkedListBinding )
+               assert(fNoLazyBinding);
+       
        // MacOSX 10.7 defaults to PIE
        if ( (fArchitecture == CPU_TYPE_I386)
                && (fOutputKind == kDynamicExecutable)
-               && (fMacVersionMin >= ld::mac10_7) ) {
+               && platforms().minOS(ld::mac10_7) ) {
                        fPositionIndependentExecutable = true;
        }
 
        // armv7 for iOS4.3 defaults to PIE
        if ( (fArchitecture == CPU_TYPE_ARM) 
                && fArchSupportsThumb2
-               && (fOutputKind == kDynamicExecutable) 
-               && min_iOS(ld::iOS_4_3) ) {
+               && (fOutputKind == kDynamicExecutable)
+               && (platforms().contains(ld::kPlatform_watchOS) || platforms().minOS(ld::iOS_4_3)) ) {
                        fPositionIndependentExecutable = true;
        }
 
-       // <rdar://problem/24535196> x86_64 defaults PIE (regardless of minOS version)
-       if ( (fArchitecture == CPU_TYPE_X86_64) && (fOutputKind == kDynamicExecutable) && (fMacVersionMin >= ld::mac10_6) )
+       // <rdar://problem/24535196> x86_64 defaults PIE (for 10.6 and later)
+       if ( (fArchitecture == CPU_TYPE_X86_64) && (fOutputKind == kDynamicExecutable) && (platforms().minOS(ld::mac10_6) || platforms().contains(ld::kPlatform_iOSMac)) )
                fPositionIndependentExecutable = true;
 
        // Simulator defaults to PIE
-       if ( fTargetIOSSimulator && (fOutputKind == kDynamicExecutable) )
+       if ( targetIOSSimulator() && (fOutputKind == kDynamicExecutable) )
                fPositionIndependentExecutable = true;
 
        // -no_pie anywhere on command line disable PIE
@@ -4987,22 +4859,12 @@ void Options::reconfigureDefaults()
                        break;
        }
 
-       // let linker know if thread local variables are supported
-       if ( fMacVersionMin >= ld::mac10_7 ) {
-               fTLVSupport = true;
-       }
-       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;
-       }
-       else if ( fTargetIOSSimulator && (fArchitecture == CPU_TYPE_X86_64) && min_iOS(ld::iOS_8_0) ) {
-               fTLVSupport = true;
-       }
-       else if ( fTargetIOSSimulator && (fArchitecture == CPU_TYPE_I386) && min_iOS(ld::iOS_9_0) ) {
+       // Let linker know if thread local variables are supported
+       // This is more complex than normal version checks since
+       // runtime support varies by architecture
+       if (platforms().minOS(ld::supportsTLV)
+                       || ((fArchitecture == CPU_TYPE_ARM64) && platforms().minOS(ld::iOS_8_0))
+                       || ((fArchitecture == CPU_TYPE_X86_64) && platforms().minOS(ld::iOS_9_0))) {
                fTLVSupport = true;
        }
 
@@ -5027,7 +4889,7 @@ void Options::reconfigureDefaults()
        }
        
        // support re-export of individual symbols in MacOSX 10.7 and iOS 4.2
-       if ( (fOutputKind == kDynamicLibrary) && minOS(ld::mac10_7, ld::iOS_4_2) )
+       if ( (fOutputKind == kDynamicLibrary) && platforms().minOS(ld::version2010) )
                fCanReExportSymbols = true;
        
        // ObjC optimization is only in dynamic final linked images
@@ -5054,33 +4916,21 @@ void Options::reconfigureDefaults()
        // Use LC_MAIN instead of LC_UNIXTHREAD for newer OSs
        switch ( fOutputKind ) {
                case Options::kDynamicExecutable:
-                       if ( fEntryPointLoadCommandForceOn ) {
+                       // <rdar://problem/16310363> Linker should look for "_main" not "start" when building for sim regardless of min OS
+                       if ( platforms().minOS(ld::version2012) ) {
                                fEntryPointLoadCommand = true;
-                               if ( fEntryName == NULL ) 
+                               if ( fEntryName == NULL )
                                        fEntryName = "_main";
+                               if ( strcmp(fEntryName, "start") == 0 ) {
+                                       warning("Ignoring '-e start' because entry point 'start' is not used for the targeted OS version");
+                                       fEntryName = "_main";
+                               }
                        }
-                       else if ( fEntryPointLoadCommandForceOff ) {
+                       else {
                                fNeedsThreadLoadCommand = true;
-                               if ( fEntryName == NULL ) 
+                               if ( fEntryName == NULL )
                                        fEntryName = "start";
                        }
-                       else {
-                               // <rdar://problem/16310363> Linker should look for "_main" not "start" when building for sim regardless of min OS
-                               if ( minOS(ld::mac10_8, ld::iOS_6_0) || fTargetIOSSimulator ) {
-                                       fEntryPointLoadCommand = true;
-                                       if ( fEntryName == NULL ) 
-                                               fEntryName = "_main";
-                                       if ( strcmp(fEntryName, "start") == 0 ) {
-                                               warning("Ignoring '-e start' because entry point 'start' is not used for the targeted OS version");
-                                               fEntryName = "_main";
-                                       }
-                               } 
-                               else {
-                                       fNeedsThreadLoadCommand = true;
-                                       if ( fEntryName == NULL ) 
-                                               fEntryName = "start";
-                               }
-                       }
                        break;
                case Options::kObjectFile:
                case Options::kKextBundle:
@@ -5112,7 +4962,7 @@ void Options::reconfigureDefaults()
                                fSourceVersionLoadCommand = false;
                        }
                        else {
-                               if ( minOS(ld::mac10_8, ld::iOS_6_0) ) {
+                               if ( platforms().minOS(ld::version2012) ) {
                                        fSourceVersionLoadCommand = true;
                                }
                                else
@@ -5141,12 +4991,12 @@ void Options::reconfigureDefaults()
                        fSDKVersion = parseVersionNumber32(sdkVersionStr);
                }
        }
-       
+
        // if -sdk_version and -syslibroot not used, but targeting MacOSX, use current OS version
-       if ( (fSDKVersion == 0) && (fMacVersionMin != ld::macVersionUnset) ) {
+       if ( (fSDKVersion == 0) && platforms().contains(ld::kPlatform_macOS) ) {
                // special case if RC_ProjectName and MACOSX_DEPLOYMENT_TARGET are both set that sdkversion=minos
                if ( getenv("RC_ProjectName") && getenv("MACOSX_DEPLOYMENT_TARGET") ) {
-                       fSDKVersion = fMacVersionMin;
+                       fSDKVersion = platforms().minOS(ld::kPlatform_macOS);
                }
                else {
                        int mib[2] = { CTL_KERN, KERN_OSRELEASE };
@@ -5162,18 +5012,15 @@ void Options::reconfigureDefaults()
        
        // allow trie based absolute symbols if targeting new enough OS
        if ( fMakeCompressedDyldInfo ) {
-               if ( minOS(ld::mac10_9, ld::iOS_7_0) ) {
+               if ( platforms().minOS(ld::version2013) ) {
                        fAbsoluteSymbols = true;
                }
        }
-       
-       // <rdar://problem/12959510> iOS main executables now default to 16KB page size
-       if ( (fIOSVersionMin != ld::iOSVersionUnset) && (fOutputKind == Options::kDynamicExecutable) ) {
-               // <rdar://problem/13070042> Only third party apps should have 16KB page segments by default
-               if ( fEncryptable ) {
-                       if ( fSegmentAlignment == 4096 )
-                               fSegmentAlignment = 4096*4;
-               }
+
+       // <rdar://problem/13070042> Only third party apps should have 16KB page segments by default
+       if ( fEncryptable ) {
+               if ( fSegmentAlignment == 4096 )
+                       fSegmentAlignment = 4096*4;
        }
   
        // <rdar://problem/12258065> ARM64 needs 16KB page size for user land code
@@ -5184,18 +5031,17 @@ void Options::reconfigureDefaults()
                        case Options::kDynamicLibrary:
                        case Options::kDynamicBundle:
                        case Options::kDyld:
-                               if ( ((fArchitecture == CPU_TYPE_ARM64)
-                     )
-                               || ((fArchitecture == CPU_TYPE_ARM) && min_iOS(ld::iOS_7_0)) ) {
+                               // <rdar://problem/14676611> 16KB segments for arm64 kexts
+                               if ( (fArchitecture == CPU_TYPE_ARM64)
+                     || (fArchitecture == CPU_TYPE_ARM) ) {
                                        fSegmentAlignment = 4096*4;
                                }
                                break;
                        case Options::kStaticExecutable:
                        case Options::kKextBundle:
                                // <rdar://problem/14676611> 16KB segments for arm64 kexts
-                               if ( ((fArchitecture == CPU_TYPE_ARM64)
-                     )
-                                   && min_iOS(ld::iOS_9_0) ) {
+                               if ( (fArchitecture == CPU_TYPE_ARM64)
+                                       ) {
                                        fSegmentAlignment = 4096*4;
                                }
                                break;
@@ -5220,7 +5066,7 @@ void Options::reconfigureDefaults()
                                fKeepDwarfUnwind = false;
                        }
                        else {
-                               if ( minOS(ld::mac10_9, ld::iOS_7_0) ) 
+                               if ( platforms().minOS(ld::version2013) )
                                        fKeepDwarfUnwind = false;
                                else
                                        fKeepDwarfUnwind = true;
@@ -5257,6 +5103,24 @@ void Options::reconfigureDefaults()
        }
 
 
+       // Look in $SDKROOT/AppleInternal/AccessibilityLinkerSymbols/<dylib>.axsymbols for objc-class names
+       if ( 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/AccessibilityLinkerSymbols", sizeof(path));
+                       strlcat(path , dylibLeaf, sizeof(path));
+                       strlcat(path , ".axsymbols", sizeof(path));
+                       FileInfo info;
+                       if ( info.checkFileExists(*this, path) ) {
+                               SymbolsMove tmp;
+                               fSymbolsMovesAXMethodLists.push_back(tmp);
+                               loadExportFile(path, ".axsymbols", fSymbolsMovesAXMethodLists.back().symbols);
+                       }
+               }
+       }
+
        // <rdar://problem/32138080> Automatically use OrderFiles found in the AppleInternal SDK
        if ( (fFinalName != NULL) && fOrderedSymbols.empty() && !fSDKPaths.empty() ) {
                char path[PATH_MAX];
@@ -5278,11 +5142,11 @@ void Options::reconfigureDefaults()
        }
 
        // Add warnings for issues likely to cause OS verification issues
-       if ( fSharedRegionEligible && !fRPaths.empty() ) {
+       if ( fSharedRegionEligible && !fRPaths.empty() && !fDebugVariant ) {
                // <rdar://problem/18719327> warn if -rpath is used with OS dylibs
                warning("OS dylibs should not add rpaths (linker option: -rpath) (Xcode build setting: LD_RUNPATH_SEARCH_PATHS)");
        }
-       if ( (fOutputKind == Options::kDynamicLibrary) && (fDylibInstallName != NULL) && (fFinalName != NULL) && sharedCacheEligiblePath(fFinalName) ) {
+       if ( (fOutputKind == Options::kDynamicLibrary) && (fDylibInstallName != NULL) && (fFinalName != NULL) && sharedCacheEligiblePath(fFinalName) && !fDebugVariant ) {
                if ( strncmp(fDylibInstallName, "@rpath", 6) == 0 )
                        warning("OS dylibs should not use @rpath for -install_name.  Use absolute path instead");
                if ( strcmp(fDylibInstallName, fFinalName) != 0 ) {
@@ -5312,15 +5176,20 @@ void Options::reconfigureDefaults()
        }
 
        // set if unaligned pointers are warnings or errors
-       if ( fMacVersionMin >= ld::mac10_12 ) {
+       if ( platforms().minOS(ld::mac10_12) ) {
                // ignore unaligned pointers when targeting older macOS versions
                if ( fSharedRegionEligible )
                        fUnalignedPointerTreatment = Options::kUnalignedPointerWarning;
                else
                        fUnalignedPointerTreatment = Options::kUnalignedPointerIgnore;
        }
-       else if ( min_iOS(ld::iOS_10_0) ) {
-               fUnalignedPointerTreatment = Options::kUnalignedPointerWarning;
+       else if ( platforms().minOS(ld::iOS_10_0) ) {
+#if SUPPORT_ARCH_arm64e
+               if ( (fArchitecture == CPU_TYPE_ARM64) && (fSubArchitecture == CPU_SUBTYPE_ARM64_E) ) {
+                               fUnalignedPointerTreatment = Options::kUnalignedPointerError;
+               } else
+#endif
+                       fUnalignedPointerTreatment = Options::kUnalignedPointerWarning;
        }
        else {
                fUnalignedPointerTreatment = Options::kUnalignedPointerIgnore;
@@ -5328,11 +5197,8 @@ void Options::reconfigureDefaults()
 
        // warn by default for OS dylibs
        if ( fInitializersTreatment == Options::kInvalid ) {
-               if ( fSharedRegionEligible && (fOutputKind == Options::kDynamicLibrary) ) {
+               if ( fSharedRegionEligible && (fOutputKind == Options::kDynamicLibrary) && !fDebugVariant ) {
                        fInitializersTreatment = Options::kWarning;
-                       // TEMP HACK
-                       if ( (fOutputKind == Options::kDynamicLibrary) && (fDylibInstallName != NULL) && (strstr(fDylibInstallName, "EmbeddedAcousticRecognition.framework") != NULL) && !fNoWeakExports )
-                               fInitializersTreatment = Options::kSuppress;
                }
                else
                        fInitializersTreatment = Options::kSuppress;
@@ -5347,23 +5213,26 @@ void Options::checkIllegalOptionCombinations()
                case kUndefinedError:
                        // always legal
                        break;
-               case kUndefinedDynamicLookup:
-                       switch (fPlatform) {
-                               case kPlatformOSX:
-                                       break;
-                               case kPlatformiOS:
-                               case kPlatformWatchOS:
-                               case kPlatform_bridgeOS:
-               #if SUPPORT_APPLE_TV
-                               case kPlatform_tvOS:
-               #endif
-                                       if ( fOutputKind != kKextBundle )
-                                               warning("-undefined dynamic_lookup is deprecated on %s", platformName(fPlatform));
-                                       break;
-                               default:
-                                       break;
-                       }
-                       break;
+               case kUndefinedDynamicLookup: {
+                       platforms().forEach(^(ld::Platform platform, uint32_t version, bool &stop) {
+                               switch (platform) {
+                                       case ld::kPlatform_macOS:
+                                       case ld::kPlatform_iOSMac:
+                                       case ld::kPlatform_unknown:
+                                               break;
+                                       case ld::kPlatform_iOS:
+                                       case ld::kPlatform_iOSSimulator:
+                                       case ld::kPlatform_watchOS:
+                                       case ld::kPlatform_watchOSSimulator:
+                                       case ld::kPlatform_bridgeOS:
+                                       case ld::kPlatform_tvOS:
+                                       case ld::kPlatform_tvOSSimulator:
+                                               if ( fOutputKind != kKextBundle )
+                                                       warning("-undefined dynamic_lookup is deprecated on %s", platformName(platform));
+                                               break;
+                               }
+                       });
+               } break;
                case kUndefinedWarning:
                case kUndefinedSuppress:
                        // requires flat namespace
@@ -5422,20 +5291,24 @@ void Options::checkIllegalOptionCombinations()
        // sync reader options
        if ( fNameSpace != kTwoLevelNameSpace ) {
                fFlatNamespace = true;
-               switch (fPlatform) {
-                       case kPlatformOSX:
-                               break;
-                       case kPlatformiOS:
-                       case kPlatformWatchOS:
-                       case kPlatform_bridgeOS:
-       #if SUPPORT_APPLE_TV
-                       case Options::kPlatform_tvOS:
-       #endif
-                               warning("-flat_namespace is deprecated on %s", platformName(fPlatform));
-                               break;
-                       default:
-                               break;
-               }
+               platforms().forEach(^(ld::Platform platform, uint32_t version, bool &stop) {
+                       switch (platform) {
+                               case ld::kPlatform_unknown:
+                               case ld::kPlatform_macOS:
+                               case ld::kPlatform_iOSMac:
+                                       break;
+                               case ld::kPlatform_iOS:
+                               case ld::kPlatform_iOSSimulator:
+                               case ld::kPlatform_watchOS:
+                               case ld::kPlatform_watchOSSimulator:
+                               case ld::kPlatform_bridgeOS:
+                               case ld::kPlatform_tvOS:
+                               case ld::kPlatform_tvOSSimulator:
+                                       warning("-flat_namespace is deprecated on %s", platformName(platform));
+                                       break;
+                       }
+               });
+
        }
 
 
@@ -5461,7 +5334,7 @@ void Options::checkIllegalOptionCombinations()
        if ( fStackSize != 0 ) {
                switch (fArchitecture) {
                        case CPU_TYPE_I386:
-                               if ( fPlatform == kPlatformOSX ) {
+                               if ( platforms().contains(ld::kPlatform_macOS) ) {
                                        if ( fStackSize > 0xFFFFFFFF )
                                                throw "-stack_size must be < 4GB for 32-bit processes";
                                        if ( fStackAddr == 0 )
@@ -5485,7 +5358,7 @@ void Options::checkIllegalOptionCombinations()
                     throw "-stack_addr must be < 0x20000000 for arm";
                                break;
                        case CPU_TYPE_X86_64:
-                               if ( fPlatform == kPlatformOSX ) {
+                               if ( platforms().contains(ld::kPlatform_macOS) ) {
                                        if ( fStackSize > 0x10000000000 )
                                                throw "-stack_size must be <= 1TB";
                                        if ( fStackAddr == 0 ) {
@@ -5603,7 +5476,7 @@ void Options::checkIllegalOptionCombinations()
                throw "-setuid_safe cannot be used with -r";
 
        // <rdar://problem/12781832> compiler driver no longer uses -objc_abi_version, it uses -ios_simulator_version_min instead
-       if ( !fObjCABIVersion1Override && !fObjCABIVersion2Override && fTargetIOSSimulator )
+       if ( !fObjCABIVersion1Override && !fObjCABIVersion2Override && targetIOSSimulator() )
                fObjCABIVersion2Override = true;
 
        // rdar://problem/4718189 map ObjC class names to new runtime names
@@ -5753,7 +5626,7 @@ void Options::checkIllegalOptionCombinations()
 
        // can't use -rpath unless targeting 10.5 or later
        if ( fRPaths.size() > 0 ) {
-               if ( !minOS(ld::mac10_5, ld::iOS_2_0) )
+               if ( !platforms().minOS(ld::version2008) )
                        throw "-rpath can only be used when targeting Mac OS X 10.5 or later";
                switch ( fOutputKind ) {
                        case Options::kDynamicExecutable:
@@ -5773,11 +5646,8 @@ void Options::checkIllegalOptionCombinations()
                switch ( fOutputKind ) {
                        case Options::kDynamicExecutable:
                                // check -pie is only used when building a dynamic main executable for 10.5
-                               if ( !minOS(ld::mac10_5, ld::iOS_4_2) ) {
-                                       if ( fIOSVersionMin == ld::iOSVersionUnset )
-                                               throw "-pie can only be used when targeting Mac OS X 10.5 or later";
-                                       else
-                                               throw "-pie can only be used when targeting iOS 4.2 or later";
+                               if ( !platforms().minOS(ld::supportsPIE) ) {
+                                       throw "-pie requires targetting a newer minimum version";
                                }
                                break;
                        case Options::kStaticExecutable:
@@ -5796,12 +5666,15 @@ void Options::checkIllegalOptionCombinations()
                }
        }
        
-       // check -read_only_relocs is not used with x86_64
+       // check -read_only_relocs is not used with x86_64 or arm64
        if ( fAllowTextRelocs ) {
                if ( (fArchitecture == CPU_TYPE_X86_64) && (fOutputKind != kKextBundle) ) {
                        warning("-read_only_relocs cannot be used with x86_64");
                        fAllowTextRelocs = false;
                }
+               else if ( fArchitecture == CPU_TYPE_ARM64 ) {
+                       warning("-read_only_relocs cannot be used with arm64");
+               }
        }
        
        // check -mark_auto_dead_strip is only used with dylibs
@@ -5823,7 +5696,7 @@ void Options::checkIllegalOptionCombinations()
        if ( !fReExportSymbols.empty() ) {
                if ( fOutputKind != Options::kDynamicLibrary )
                        throw "-reexported_symbols_list can only used used when created dynamic libraries";
-               if ( !minOS(ld::mac10_7, ld::iOS_4_2) )
+               if ( !platforms().minOS(ld::version2010) )
                        throw "targeted OS version does not support -reexported_symbols_list";
        }
        
@@ -5852,21 +5725,80 @@ void Options::checkIllegalOptionCombinations()
 
        // <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 ( !min_iOS(ld::iOS_8_0) && (fDylibInstallName[0] == '@') && !fEncryptableForceOff )
+       if ( (fOutputKind == Options::kDynamicLibrary) && (fDylibInstallName != NULL) ) {
+               if ( platforms().contains(ld::kPlatform_iOS) && !platforms().minOS(ld::iOS_8_0) && (fDylibInstallName[0] == '@') && !fEncryptableForceOff )
                        warning("embedded dylibs/frameworks only run on iOS 8 or later");
        }
 
-       // bridgeOS always generates new load command
-       if ( fVersionLoadCommand && (fPlatform == kPlatform_bridgeOS) ) {
-               fBuildVersionLoadCommand = true;
-       }
-
        // produce nicer error when no input
        if ( fInputFiles.empty() ) {
                throw "no object files specified";
        }
-}      
+
+       // Check zippered combinations.
+       if (platforms().count() > 2) {
+               throw "Illegal platform count.  Only 2 platforms at a maximum can be specified";
+       }
+
+       // Convert from -ios_version_min to -ios_simulator_version_min for now until clang has been updated
+       if (architecture() == CPU_TYPE_X86_64 || architecture() == CPU_TYPE_X86) {
+               if (platforms().contains(ld::kPlatform_iOS)) {
+                       uint32_t version = platforms().minOS(ld::kPlatform_iOS);
+                       fPlatforms.erase(ld::kPlatform_iOS);
+                       // HACK infer the build environment from the SDK path
+                       bool macOSSDK = false;
+                       for (const auto& sdkPath : fSDKPaths) {
+                               if (strstr(sdkPath, "MacOSX10") != 0) {
+                                       macOSSDK = true;
+                                       break;
+                               }
+                       }
+                       if (macOSSDK) {
+                               fPlatforms.add({ ld::kPlatform_iOSMac, version });
+                               warning("URGENT: -ios_version_min is invalid for architecture x86/x86_64, inferring -iosmac_version_min. "
+                                               "This will be an error in the future.");
+                       } else {
+                               fPlatforms.add({ ld::kPlatform_iOSSimulator, version });
+                               warning("URGENT: -ios_version_min is invalid for architecture x86/x86_64, inferring -ios_simulator_version_min. "
+                                               "This will be an error in the future.");
+                       }
+               }
+       }
+
+       if (platforms().count() == 2) {
+               if (!platforms().minOS(ld::mac10_14))
+                       throw "Zippered macOS version platform must be at least 10.14";
+               if (!platforms().minOS(ld::iOS_12_0))
+                       throw "Zippered iosmac version platform must be at least 12.0";
+       }
+
+       if (platforms().contains(ld::kPlatform_iOSMac) && !platforms().minOS(ld::iOS_12_0)) {
+               throw "iosmac platform version must be at least 12.0";
+       }
+
+       // <rdar://problem/38155581> ld64 shouldn't allow final executables to have more than one version load command
+       if ( platforms().contains(ld::kPlatform_iOSMac) && platforms().contains(ld::kPlatform_macOS) ) {
+               if ( (fOutputKind != Options::kDynamicLibrary) && (fOutputKind != Options::kDynamicBundle) ) {
+                       warning("Only dylibs and bundles can be zippered, changing output to be macOS only.");
+                       fPlatforms.erase(ld::kPlatform_iOSMac);
+               }
+       }
+
+       // <rdar://problem/39095109> Linker warning for i386 macOS binaries
+       if ( (architecture() == CPU_TYPE_I386) && platforms().contains(ld::kPlatform_macOS) ) {
+               bool internalSDK = false;
+               for (const char* sdkPath : fSDKPaths) {
+                       std::string possiblePath = std::string(sdkPath) + "/AppleInternal/";
+                       struct stat statBuffer;
+                       if ( stat(possiblePath.c_str(), &statBuffer) == 0 ) {
+                               internalSDK = true;
+                               break;
+                       }
+               }
+               if ( !internalSDK )
+                       warning("The i386 architecture is deprecated for macOS (remove from the Xcode build setting: ARCHS)");
+       }
+}
 
 
 void Options::checkForClassic(int argc, const char* argv[])
@@ -6006,7 +5938,7 @@ const char* Options::demangleSymbol(const char* sym) const
 
 #if DEMANGLE_SWIFT
        // only try to demangle symbols that look like Swift symbols
-       if ( strncmp(sym, "__T", 3) == 0 ) {
+       if ( strncmp(sym, "_$", 2) == 0 ) {
                size_t demangledSize = fnd_get_demangled_name(&sym[1], buff, size);
                if ( demangledSize > size ) {
                        size = demangledSize+2;
index 3b0a37ce8599ddf1d416bd0a57de20eb9ba1d8c9..62bcddfa0e9111824c3c806a0666f43cdbb1f142 100644 (file)
@@ -91,46 +91,34 @@ public:
        enum BitcodeMode { kBitcodeProcess, kBitcodeAsData, kBitcodeMarker, kBitcodeStrip };
        enum DebugInfoStripping { kDebugInfoNone, kDebugInfoMinimal, kDebugInfoFull };
        enum UnalignedPointerTreatment { kUnalignedPointerError, kUnalignedPointerWarning, kUnalignedPointerIgnore };
-#if SUPPORT_APPLE_TV
-       enum Platform { kPlatformUnknown, kPlatformOSX=1, kPlatformiOS=2, kPlatformWatchOS=3, kPlatform_tvOS=4, kPlatform_bridgeOS=5 };
-#else
-       enum Platform { kPlatformUnknown, kPlatformOSX, kPlatformiOS, kPlatformWatchOS };
-#endif
 
-       static Platform platformForLoadCommand(uint32_t lc) {
+       static ld::Platform platformForLoadCommand(uint32_t lc, bool useSimulatorVariant) {
                switch (lc) {
                        case LC_VERSION_MIN_MACOSX:
-                               return kPlatformOSX;
+                               return ld::kPlatform_macOS;
                        case LC_VERSION_MIN_IPHONEOS:
-                               return kPlatformiOS;
+                               return useSimulatorVariant ? ld::kPlatform_iOSSimulator : ld::kPlatform_iOS;
                        case LC_VERSION_MIN_WATCHOS:
-                               return kPlatformWatchOS;
-               #if SUPPORT_APPLE_TV
+                               return useSimulatorVariant ? ld::kPlatform_watchOSSimulator : ld::kPlatform_watchOS;
                        case LC_VERSION_MIN_TVOS:
-                               return kPlatform_tvOS;
-               #endif
+                               return useSimulatorVariant ? ld::kPlatform_tvOSSimulator : ld::kPlatform_tvOS;
                }
                assert(!lc && "unknown LC_VERSION_MIN load command");
-               return kPlatformUnknown;
+               return ld::kPlatform_unknown;
        }
 
-       static const char* platformName(Platform platform) {
+       static const char* platformName(ld::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 kPlatform_bridgeOS:
-                               return "bridgeOS";
-                       case kPlatformUnknown:
-                       default:
-                               return "(unknown)";
+                       case ld::kPlatform_macOS:                               return "OSX";
+                       case ld::kPlatform_iOS:                                 return "iOS";
+                       case ld::kPlatform_iOSSimulator:                return "iOS Simulator";
+                       case ld::kPlatform_iOSMac:                              return "iOSMac";
+                       case ld::kPlatform_watchOS:                     return "watchOS";
+                       case ld::kPlatform_watchOSSimulator:    return "watchOS Simulator";
+                       case ld::kPlatform_tvOS:                                return "tvOS";
+                       case ld::kPlatform_tvOSSimulator:               return "tvOS Simulator";
+                       case ld::kPlatform_bridgeOS:                    return "bridgeOS";
+                       case ld::kPlatform_unknown:                             return "(unknown)";
                }
        }
 
@@ -209,13 +197,13 @@ public:
 
        class TAPIInterface {
        public:
-               TAPIInterface(tapi::LinkerInterfaceFile *file, const char* path, const char *installName) :
+               TAPIInterface(tapi::LinkerInterfaceFilefile, const char* path, const char *installName) :
                        _file(file), _tbdPath(path), _installName(installName) {}
-               tapi::LinkerInterfaceFile *getInterfaceFile() const { return _file; }
+               tapi::LinkerInterfaceFilegetInterfaceFile() const { return _file; }
                std::string getTAPIFilePath() const { return _tbdPath; }
                const std::string &getInstallName() const { return _installName; }
        private:
-               tapi::LinkerInterfaceFile *_file;
+               tapi::LinkerInterfaceFile_file;
                std::string _tbdPath;
                std::string _installName;
        };
@@ -301,15 +289,16 @@ public:
        cpu_type_t                                      architecture() const { return fArchitecture; }
        bool                                            preferSubArchitecture() const { return fHasPreferredSubType; }
        cpu_subtype_t                           subArchitecture() const { return fSubArchitecture; }
+       cpu_type_t                  fallbackArchitecture() const { return fFallbackArchitecture; }
+       cpu_subtype_t                           fallbackSubArchitecture() const { return fFallbackSubArchitecture; }
        bool                                            allowSubArchitectureMismatches() const { return fAllowCpuSubtypeMismatches; }
        bool                                            enforceDylibSubtypesMatch() const { return fEnforceDylibSubtypesMatch; }
        bool                                            warnOnSwiftABIVersionMismatches() const { return fWarnOnSwiftABIVersionMismatches; }
        bool                                            forceCpuSubtypeAll() const { return fForceSubtypeAll; }
        const char*                                     architectureName() const { return fArchitectureName; }
-       void                                            setArchitecture(cpu_type_t, cpu_subtype_t subtype, Options::Platform platform);
+       void                                            setArchitecture(cpu_type_t, cpu_subtype_t subtype, ld::Platform platform, uint32_t minOsVers);
        bool                                            archSupportsThumb2() const { return fArchSupportsThumb2; }
        OutputKind                                      outputKind() const { return fOutputKind; }
-       bool                                            prebind() const { return fPrebind; }
        bool                                            bindAtLoad() const { return fBindAtLoad; }
        NameSpace                                       nameSpace() const { return fNameSpace; }
        const char*                                     installPath() const;                    // only for kDynamicLibrary
@@ -321,7 +310,6 @@ public:
        uint64_t                                        baseAddress() const { return fBaseAddress; }
        uint64_t                                        maxAddress() const { return fMaxAddress; }
        bool                                            keepPrivateExterns() const { return fKeepPrivateExterns; }              // only for kObjectFile
-       bool                                            needsModuleTable() const { return fNeedsModuleTable; }                  // only for kDynamicLibrary
        bool                                            interposable(const char* name) const;
        bool                                            hasExportRestrictList() const { return (fExportMode != kExportDefault); }       // -exported_symbol or -unexported_symbol
        bool                                            hasExportMaskList() const { return (fExportMode == kExportSome); }              // just -exported_symbol
@@ -338,12 +326,7 @@ public:
        bool                                            traceEmitJSON() const { return fTraceEmitJSON; }
        bool                                            deadCodeStrip() const   { return fDeadStrip; }
        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                                            min_iOS(ld::IOSVersionMin requirediOSMin);
+       uint32_t                                        minOSversion(const ld::Platform& platform) const;
        bool                                            messagesPrefixedWithArchitecture();
        Treatment                                       picTreatment();
        WeakReferenceMismatchTreatment  weakReferenceMismatchTreatment() const { return fWeakReferenceMismatchTreatment; }
@@ -372,7 +355,7 @@ public:
        FileInfo                                        findFile(const std::string &path, const ld::dylib::File* fromDylib=nullptr) const;
        bool                                            findFile(const std::string &path, const std::vector<std::string> &tbdExtensions, FileInfo& result) const;
        bool                                            hasInlinedTAPIFile(const std::string &path) const;
-       std::unique_ptr<tapi::LinkerInterfaceFile>      findTAPIFile(const std::string &path) const;
+       tapi::LinkerInterfaceFile*      findTAPIFile(const std::string &path) const;
        UUIDMode                                        UUIDMode() const { return fUUIDMode; }
        bool                                            warnStabs();
        bool                                            pauseAtEnd() { return fPause; }
@@ -386,7 +369,6 @@ public:
        unsigned long                           orderedSymbolsCount() const { return fOrderedSymbols.size(); }
        OrderedSymbolsIterator          orderedSymbolsBegin() const { return &fOrderedSymbols[0]; }
        OrderedSymbolsIterator          orderedSymbolsEnd() const { return &fOrderedSymbols[fOrderedSymbols.size()]; }
-       bool                                            splitSeg() const { return fSplitSegs; }
        uint64_t                                        baseWritableAddress() { return fBaseWritableAddress; }
        uint64_t                                        segmentAlignment() const { return fSegmentAlignment; }
        uint64_t                                        segPageSize(const char* segName) const;
@@ -422,6 +404,7 @@ public:
        const std::vector<const char*>& dyldEnvironExtras() const{ return fDyldEnvironExtras; }
        const std::vector<const char*>& astFilePaths() const{ return fASTFilePaths; }
        bool                                            makeCompressedDyldInfo() const { return fMakeCompressedDyldInfo; }
+       bool                                            makeThreadedStartsSection() const { return fMakeThreadedStartsSection; }
        bool                                            hasExportedSymbolOrder();
        bool                                            exportedSymbolOrder(const char* sym, unsigned int* order) const;
        bool                                            orderData() { return fOrderData; }
@@ -454,18 +437,21 @@ public:
        bool                                            objcGc() const { return fObjCGc; }
        bool                                            objcGcOnly() const { return fObjCGcOnly; }
        bool                                            canUseThreadLocalVariables() const { return fTLVSupport; }
-       bool                                            addVersionLoadCommand() const { return fVersionLoadCommand && (fPlatform != kPlatformUnknown); }
-       bool                                            addBuildVersionLoadCommand() const { return fBuildVersionLoadCommand; }
+       bool                                            addVersionLoadCommand() const { return fVersionLoadCommand && (platforms().count() != 0); }
        bool                                            addFunctionStarts() const { return fFunctionStartsLoadCommand; }
        bool                                            addDataInCodeInfo() const { return fDataInCodeInfoLoadCommand; }
        bool                                            canReExportSymbols() const { return fCanReExportSymbols; }
        const char*                                     ltoCachePath() const { return fLtoCachePath; }
+       bool                                            ltoPruneIntervalOverwrite() const { return fLtoPruneIntervalOverwrite; }
        int                                                     ltoPruneInterval() const { return fLtoPruneInterval; }
        int                                                     ltoPruneAfter() const { return fLtoPruneAfter; }
        unsigned                                        ltoMaxCacheSize() const { return fLtoMaxCacheSize; }
        const char*                                     tempLtoObjectPath() const { return fTempLtoObjectPath; }
        const char*                                     overridePathlibLTO() const { return fOverridePathlibLTO; }
        const char*                                     mcpuLTO() const { return fLtoCpu; }
+       const char*                                     kextObjectsPath() const { return fKextObjectsDirPath; }
+       int                                                     kextObjectsEnable() const { return fKextObjectsEnable; }
+       const char*                                     toolchainPath() const { return fToolchainPath; }
        bool                                            objcCategoryMerging() const { return fObjcCategoryMerging; }
        bool                                            pageAlignDataAtoms() const { return fPageAlignDataAtoms; }
        bool                                            keepDwarfUnwind() const { return fKeepDwarfUnwind; }
@@ -483,6 +469,13 @@ public:
        bool                                            renameReverseSymbolMap() const { return fReverseMapUUIDRename; }
        bool                                            deduplicateFunctions() const { return fDeDupe; }
        bool                                            verboseDeduplicate() const { return fVerboseDeDupe; }
+       bool                                            useLinkedListBinding() const { return fUseLinkedListBinding; }
+#if SUPPORT_ARCH_arm64e
+       bool                                            useAuthenticatedStubs() const { return fUseAuthenticatedStubs; }
+       bool                                            supportsAuthenticatedPointers() const { return fSupportsAuthenticatedPointers; }
+#endif
+       bool                                            noLazyBinding() const { return fNoLazyBinding; }
+       bool                                            debugVariant() const { return fDebugVariant; }
        const char*                                     reverseSymbolMapPath() const { return fReverseMapPath; }
        std::string                                     reverseMapTempPath() const { return fReverseMapTempPath; }
        bool                                            ltoCodegenOnly() const { return fLTOCodegenOnly; }
@@ -514,8 +507,8 @@ public:
     const char*                                        pipelineFifo() const { return fPipelineFifo; }
        bool                                            dumpDependencyInfo() const { return (fDependencyInfoPath != NULL); }
        const char*                                     dependencyInfoPath() const { return fDependencyInfoPath; }
-       bool                                            targetIOSSimulator() const { return fTargetIOSSimulator; }
-       ld::relocatable::File::LinkerOptionsList&       
+       bool                                            targetIOSSimulator() const { return platforms().contains(ld::simulatorPlatforms); }
+       ld::relocatable::File::LinkerOptionsList&
                                                                linkerOptions() const { return fLinkerOptions; }
        FileInfo                                        findFramework(const char* frameworkName) const;
        FileInfo                                        findLibrary(const char* rootName, bool dylibsOnly=false) const;
@@ -524,11 +517,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;
-       Platform                                        platform() const { return fPlatform; }
+       bool                                            moveAXMethodList(const char* className) const;
+       const ld::VersionSet&           platforms() const { return fPlatforms; }
        const std::vector<const char*>& sdkPaths() const { return fSDKPaths; }
        std::vector<std::string>        writeBitcodeLinkOptions() const;
        std::string                                     getSDKVersionStr() const;
-       std::string                                     getPlatformStr() const;
        uint8_t                                         maxDefaultCommonAlign() const { return fMaxDefaultCommonAlign; }
        bool                                            hasDataSymbolMoves() const { return !fSymbolsMovesData.empty(); }
        bool                                            hasCodeSymbolMoves() const { return !fSymbolsMovesCode.empty(); }
@@ -537,7 +530,8 @@ public:
        bool                                            zeroModTimeInDebugMap() const { return fZeroModTimeInDebugMap; }
        void                                            writeDependencyInfo() const;
        std::vector<TAPIInterface>      &TAPIFiles() { return fTAPIFiles; }
-       void                                            addTAPIInterface(tapi::LinkerInterfaceFile *interface, const char *path) const;
+       void                                            addTAPIInterface(tapi::LinkerInterfaceFile* interface, const char *path) const;
+       const char*                                     buildContextName() const { return fBuildContextName; }
 
        static uint32_t                         parseVersionNumber32(const char*);
 
@@ -579,10 +573,13 @@ private:
                std::string                     path;
        };
 
+       const char*                                     checkForNullArgument(const char* argument_name, const char* arg) const;
+       const char*                                     checkForNullVersionArgument(const char* argument_name, const char* arg) const;
        void                                            parse(int argc, const char* argv[]);
        void                                            checkIllegalOptionCombinations();
        void                                            buildSearchPaths(int argc, const char* argv[]);
        void                                            parseArch(const char* architecture);
+       void                                            selectFallbackArch(const char *architecture);
        FileInfo                                        findFramework(const char* rootName, const char* suffix) const;
        bool                                            checkForFile(const char* format, const char* dir, const char* rootName,
                                                                                         FileInfo& result) const;
@@ -601,9 +598,7 @@ private:
        void                                            parsePreCommandLineEnvironmentSettings();
        void                                            parsePostCommandLineEnvironmentSettings();
        void                                            setUndefinedTreatment(const char* treatment);
-       void                                            setMacOSXVersionMin(const char* version);
-       void                                            setIOSVersionMin(const char* version);
-       void                                            setWatchOSVersionMin(const char* version);
+       void                                            setVersionMin(const ld::Platform& platform, const char *version);
        void                                            setWeakReferenceMismatchTreatment(const char* treatment);
        void                                            addDylibOverride(const char* paths);
        void                                            addSectionAlignment(const char* segment, const char* section, const char* alignment);
@@ -627,14 +622,14 @@ private:
        std::vector<Options::FileInfo>          fInputFiles;
        cpu_type_t                                                      fArchitecture;
        cpu_subtype_t                                           fSubArchitecture;
+       cpu_type_t                                                      fFallbackArchitecture;
+       cpu_subtype_t                                           fFallbackSubArchitecture;
        const char*                                                     fArchitectureName;
        OutputKind                                                      fOutputKind;
        bool                                                            fHasPreferredSubType;
        bool                                                            fArchSupportsThumb2;
-       bool                                                            fPrebind;
        bool                                                            fBindAtLoad;
        bool                                                            fKeepPrivateExterns;
-       bool                                                            fNeedsModuleTable;
        bool                                                            fIgnoreOtherArchFiles;
        bool                                                            fErrorOnOtherArchFiles;
        bool                                                            fForceSubtypeAll;
@@ -649,7 +644,6 @@ private:
        uint64_t                                                        fBaseAddress;
        uint64_t                                                        fMaxAddress;
        uint64_t                                                        fBaseWritableAddress;
-       bool                                                            fSplitSegs;
        SetWithWildcards                                        fExportSymbols;
        SetWithWildcards                                        fDontExportSymbols;
        SetWithWildcards                                        fInterposeList;
@@ -675,16 +669,19 @@ private:
        const char*                                                     fExecutablePath;
        const char*                                                     fBundleLoader;
        const char*                                                     fDtraceScriptName;
-       const char*                                                     fSegAddrTablePath;
        const char*                                                     fMapPath;
        const char*                                                     fDyldInstallPath;
        const char*                                                     fLtoCachePath;
+       bool                                                            fLtoPruneIntervalOverwrite;
        int                                                                     fLtoPruneInterval;
        int                                                                     fLtoPruneAfter;
        unsigned                                                        fLtoMaxCacheSize;
        const char*                                                     fTempLtoObjectPath;
        const char*                                                     fOverridePathlibLTO;
        const char*                                                     fLtoCpu;
+       int                                                             fKextObjectsEnable;
+       const char*                                                     fKextObjectsDirPath;
+       const char*                                                     fToolchainPath;
        uint64_t                                                        fZeroPageSize;
        uint64_t                                                        fStackSize;
        uint64_t                                                        fStackAddr;
@@ -728,6 +725,7 @@ private:
        bool                                                            fMarkDeadStrippableDylib;
        bool                                                            fMakeCompressedDyldInfo;
        bool                                                            fMakeCompressedDyldInfoForceOff;
+       bool                                                            fMakeThreadedStartsSection;
        bool                                                            fNoEHLabels;
        bool                                                            fAllowCpuSubtypeMismatches;
        bool                                                            fEnforceDylibSubtypesMatch;
@@ -771,7 +769,6 @@ private:
        bool                                                            fVersionLoadCommand;
        bool                                                            fVersionLoadCommandForcedOn;
        bool                                                            fVersionLoadCommandForcedOff;
-       bool                                                            fBuildVersionLoadCommand;
        bool                                                            fFunctionStartsLoadCommand;
        bool                                                            fFunctionStartsForcedOn;
        bool                                                            fFunctionStartsForcedOff;
@@ -783,12 +780,9 @@ private:
        bool                                                            fPageAlignDataAtoms;
        bool                                                            fNeedsThreadLoadCommand;
        bool                                                            fEntryPointLoadCommand;
-       bool                                                            fEntryPointLoadCommandForceOn;
-       bool                                                            fEntryPointLoadCommandForceOff;
        bool                                                            fSourceVersionLoadCommand;
        bool                                                            fSourceVersionLoadCommandForceOn;
        bool                                                            fSourceVersionLoadCommandForceOff;      
-       bool                                                            fTargetIOSSimulator;
        bool                                                            fExportDynamic;
        bool                                                            fAbsoluteSymbols;
        bool                                                            fAllowSimulatorToLinkWithMacOSX;
@@ -814,6 +808,13 @@ private:
        bool                                                            fReverseMapUUIDRename;
        bool                                                            fDeDupe;
        bool                                                            fVerboseDeDupe;
+       bool                                                            fUseLinkedListBinding;
+#if SUPPORT_ARCH_arm64e
+       bool                                                            fUseAuthenticatedStubs = false;
+       bool                                                            fSupportsAuthenticatedPointers = false;
+#endif
+       bool                                                            fNoLazyBinding;
+       bool                                                            fDebugVariant;
        const char*                                                     fReverseMapPath;
        std::string                                                     fReverseMapTempPath;
        bool                                                            fLTOCodegenOnly;
@@ -823,12 +824,9 @@ private:
        Treatment                                                       fInitializersTreatment;
        bool                                                            fZeroModTimeInDebugMap;
        BitcodeMode                                                     fBitcodeKind;
-       Platform                                                        fPlatform;
        DebugInfoStripping                                      fDebugInfoStripping;
        const char*                                                     fTraceOutputFile;
-       ld::MacVersionMin                                       fMacVersionMin;
-       ld::IOSVersionMin                                       fIOSVersionMin;
-       ld::WatchOSVersionMin                           fWatchOSVersionMin;
+       ld::VersionSet                                          fPlatforms;
        std::vector<AliasPair>                          fAliases;
        std::vector<const char*>                        fInitialUndefines;
        NameSet                                                         fAllowedUndefined;
@@ -853,11 +851,13 @@ private:
        std::vector<SegmentRename>                      fSegmentRenames;
        std::vector<SymbolsMove>                        fSymbolsMovesData;
        std::vector<SymbolsMove>                        fSymbolsMovesCode;
+       std::vector<SymbolsMove>                        fSymbolsMovesAXMethodLists;
        bool                                                            fSaveTempFiles;
     mutable Snapshot                                   fLinkSnapshot;
     bool                                                               fSnapshotRequested;
     const char*                                                        fPipelineFifo;
        const char*                                                     fDependencyInfoPath;
+       const char*                                                     fBuildContextName;
        mutable int                                                     fTraceFileDescriptor;
        uint8_t                                                         fMaxDefaultCommonAlign;
        UnalignedPointerTreatment                       fUnalignedPointerTreatment;
index e5059d55e89838551167889412e9f08f5029c442..4daa51013317f23d3db6cb9208c94b63bc6b2fe5 100644 (file)
@@ -88,17 +88,19 @@ OutputFile::OutputFile(const Options& opts)
                symbolTableSection(NULL), stringPoolSection(NULL), 
                localRelocationsSection(NULL), externalRelocationsSection(NULL), 
                sectionRelocationsSection(NULL), 
-               indirectSymbolTableSection(NULL), 
+               indirectSymbolTableSection(NULL),
+               threadedPageStartsSection(NULL),
                _options(opts),
                _hasDyldInfo(opts.makeCompressedDyldInfo()),
+               _hasThreadedPageStarts(opts.makeThreadedStartsSection()),
                _hasSymbolTable(true),
                _hasSectionRelocations(opts.outputKind() == Options::kObjectFile),
                _hasSplitSegInfo(opts.sharedRegionEligible()),
                _hasFunctionStartsInfo(opts.addFunctionStarts()),
                _hasDataInCodeInfo(opts.addDataInCodeInfo()),
                _hasDynamicSymbolTable(true),
-               _hasLocalRelocations(!opts.makeCompressedDyldInfo()),
-               _hasExternalRelocations(!opts.makeCompressedDyldInfo()),
+               _hasLocalRelocations(!opts.makeCompressedDyldInfo() && !opts.makeThreadedStartsSection()),
+               _hasExternalRelocations(!opts.makeCompressedDyldInfo() && !opts.makeThreadedStartsSection()),
                _hasOptimizationHints(opts.outputKind() == Options::kObjectFile),
                _encryptedTEXTstartOffset(0),
                _encryptedTEXTendOffset(0),
@@ -283,7 +285,7 @@ void OutputFile::updateLINKEDITAddresses(ld::Internal& state)
                _sectionsRelocationsAtom->encode();
        }
 
-       if ( ! _options.makeCompressedDyldInfo() ) {
+       if ( !_options.makeCompressedDyldInfo() && !_options.makeThreadedStartsSection() ) {
                // build external relocations 
                assert(_externalRelocsAtom != NULL);
                _externalRelocsAtom->encode();
@@ -367,7 +369,7 @@ void OutputFile::setLoadCommandsPadding(ld::Internal& state)
                        // work backwards from end of segment and lay out sections so that extra room goes to padding atom
                        uint64_t addr = 0;
                        uint64_t textSegPageSize = _options.segPageSize("__TEXT");
-                       if ( _options.sharedRegionEligible() && (_options.iOSVersionMin() >= ld::iOS_8_0) && (textSegPageSize == 0x4000) )
+                       if ( _options.sharedRegionEligible() && _options.platforms().minOS(ld::iOS_8_0) && (textSegPageSize == 0x4000) )
                                textSegPageSize = 0x1000;
                        for (std::vector<ld::Internal::FinalSection*>::reverse_iterator it = state.sections.rbegin(); it != state.sections.rend(); ++it) {
                                ld::Internal::FinalSection* sect = *it;
@@ -476,7 +478,8 @@ bool OutputFile::targetIsThumb(ld::Internal& state, const ld::Fixup* fixup)
 
 uint64_t OutputFile::addressOf(const ld::Internal& state, const ld::Fixup* fixup, const ld::Atom** target)
 {
-       if ( !_options.makeCompressedDyldInfo() ) {
+       // FIXME: Is this right for makeThreadedStartsSection?
+       if ( !_options.makeCompressedDyldInfo() && !_options.makeThreadedStartsSection() ) {
                // For external relocations the classic mach-o format
                // has addend only stored in the content.  That means
                // that the address of the target is not used.
@@ -1345,6 +1348,9 @@ void OutputFile::applyFixUps(ld::Internal& state, uint64_t mhAddress, const ld::
        bool is_b;
        bool thumbTarget = false;
        std::map<uint32_t, const Fixup*> usedByHints;
+#if SUPPORT_ARCH_arm64e
+       Fixup::AuthData authData;
+#endif
        for (ld::Fixup::iterator fit = atom->fixupsBegin(), end=atom->fixupsEnd(); fit != end; ++fit) {
                uint8_t* fixUpLocation = &buffer[fit->offsetInAtom];
                ld::Fixup::LOH_arm64 lohExtra;
@@ -1634,6 +1640,68 @@ void OutputFile::applyFixUps(ld::Internal& state, uint64_t mhAddress, const ld::
                                        accumulator = 0;
                                set64LE(fixUpLocation, accumulator);
                                break;
+#if SUPPORT_ARCH_arm64e
+                       case ld::Fixup::kindStoreTargetAddressLittleEndianAuth64: {
+                               accumulator = addressOf(state, fit, &toTarget);
+                               if ( fit->contentAddendOnly ) {
+                                       // ld -r mode.  We want to write out the original relocation again
+
+                                       // FIXME: Should we zero out the accumulator here as done in kindStoreTargetAddressLittleEndian64?
+                                       // Make sure the high bits aren't set.  The low-32-bits should be the addend.
+                                       assert((accumulator & 0xFFFFFFFF00000000ULL) == 0);
+                                       accumulator |= ((uint64_t)authData.discriminator) << 32;
+                                       accumulator |= ((uint64_t)authData.hasAddressDiversity) << 48;
+                                       accumulator |= ((uint64_t)authData.key) << 49;
+                                       // Set the high bit as we are authenticated
+                                       accumulator |= 1ULL << 63;
+                                       set64LE(fixUpLocation, accumulator);
+                               }
+                               else if  (_options.outputKind() == Options::kKextBundle ) {
+                                       // kexts dont' handle auth pointers, write unauth pointer
+                                       set64LE(fixUpLocation, accumulator);
+                               }
+                               else {
+                                       auto fixupOffset = (uintptr_t)(fixUpLocation - mhAddress);
+                                       assert(_authenticatedFixupData.find(fixupOffset) == _authenticatedFixupData.end());
+                                       auto authneticatedData = std::make_pair(authData, accumulator);
+                                       _authenticatedFixupData[fixupOffset] = authneticatedData;
+                                       // Zero out this entry which we will expect later.
+                                       set64LE(fixUpLocation, 0);
+                               }
+                               break;
+                  }
+                       case ld::Fixup::kindStoreLittleEndianAuth64: {
+                               if ( fit->contentAddendOnly ) {
+                                       // ld -r mode.  We want to write out the original relocation again
+
+                                       // FIXME: Should we zero out the accumulator here as done in kindStoreTargetAddressLittleEndian64?
+                                       // Make sure the high bits aren't set.  The low-32-bits should be the addend.
+                                       assert((accumulator & 0xFFFFFFFF00000000ULL) == 0);
+                                       accumulator |= ((uint64_t)authData.discriminator) << 32;
+                                       accumulator |= ((uint64_t)authData.hasAddressDiversity) << 48;
+                                       accumulator |= ((uint64_t)authData.key) << 49;
+                                       // Set the high bit as we are authenticated
+                                       accumulator |= 1ULL << 63;
+                                       set64LE(fixUpLocation, accumulator);
+                               }
+                               else if  (_options.outputKind() == Options::kKextBundle ) {
+                                       // kexts dont' handle auth pointers, write unauth pointer
+                                       set64LE(fixUpLocation, accumulator);
+                               }
+                               else {
+                                       auto fixupOffset = (uintptr_t)(fixUpLocation - mhAddress);
+                                       assert(_authenticatedFixupData.find(fixupOffset) == _authenticatedFixupData.end());
+                                       auto authneticatedData = std::make_pair(authData, accumulator);
+                                       _authenticatedFixupData[fixupOffset] = authneticatedData;
+                                       // Zero out this entry which we will expect later.
+                                       set64LE(fixUpLocation, 0);
+                               }
+                               break;
+                       }
+                       case ld::Fixup::kindSetAuthData:
+                               authData = fit->u.authData;
+                               break;
+#endif
                        case ld::Fixup::kindStoreTargetAddressBigEndian32:
                                accumulator = addressOf(state, fit, &toTarget);
                                if ( fit->contentAddendOnly )
@@ -1981,6 +2049,10 @@ void OutputFile::applyFixUps(ld::Internal& state, uint64_t mhAddress, const ld::
                                }
                                break;
                        case ld::Fixup::kindStoreTargetAddressARM64GOTLoadPageOff12:
+                               // In -r mode, the GOT doesn't exist but the relocations track it
+                               // so the address doesn't need to be aligned.
+                               if ( _options.outputKind() == Options::kObjectFile )
+                                       break;
                        case ld::Fixup::kindStoreTargetAddressARM64PageOff12:
                        case ld::Fixup::kindStoreTargetAddressARM64TLVPLoadPageOff12:
                                accumulator = addressOf(state, fit, &toTarget);
@@ -2640,6 +2712,262 @@ void OutputFile::writeAtoms(ld::Internal& state, uint8_t* wholeBuffer)
                //fprintf(stderr, "ADRPs changed to NOPs: %d\n", sAdrpNoped);
                //fprintf(stderr, "ADRPs unchanged:       %d\n", sAdrpNotNoped);
        }
+
+       if ( _options.makeThreadedStartsSection() ) {
+               assert(_threadedRebaseBindIndices.empty());
+
+               std::vector<OutputFile::BindingInfo>& bindInfo = _bindingInfo;
+               std::vector<OutputFile::RebaseInfo>& rebaseInfo = _rebaseInfo;
+
+               std::vector<int64_t>& threadedRebaseBindIndices = _threadedRebaseBindIndices;
+               threadedRebaseBindIndices.reserve(bindInfo.size() + rebaseInfo.size());
+
+               for (int64_t i = 0, e = rebaseInfo.size(); i != e; ++i)
+                       threadedRebaseBindIndices.push_back(-i);
+
+               for (int64_t i = 0, e = bindInfo.size(); i != e; ++i)
+                       threadedRebaseBindIndices.push_back(i + 1);
+
+               // Now sort the entries by address.
+               std::sort(threadedRebaseBindIndices.begin(), threadedRebaseBindIndices.end(),
+                                 [&rebaseInfo, &bindInfo](int64_t indexA, int64_t indexB) {
+                                         if (indexA == indexB)
+                                                 return false;
+                                         uint64_t addressA = indexA <= 0 ? rebaseInfo[-indexA]._address : bindInfo[indexA - 1]._address;
+                                         uint64_t addressB = indexB <= 0 ? rebaseInfo[-indexB]._address : bindInfo[indexB - 1]._address;
+                                         assert(addressA != addressB);
+                                         return addressA < addressB;
+                                 });
+       }
+
+       // new rebasing/binding scheme requires making another pass at DATA
+       // segment and building linked list of rebase locations
+       if ( _options.useLinkedListBinding() && !_threadedRebaseBindIndices.empty() ) {
+               uint64_t curSegStart = 0;
+               uint64_t curSegEnd = 0;
+               uint32_t curSegIndex = 0;
+               ld::Internal::FinalSection* curSection = NULL;
+
+               const uint64_t deltaBits = 11;
+               const uint32_t fixupAlignment = _options.makeThreadedStartsSection() ? 4 : 8;
+               const bool allowThreadsToCrossPages = _options.makeThreadedStartsSection();
+               std::vector<uint64_t> threadStarts;
+
+               // Find the thread starts section
+               ld::Internal::FinalSection* threadStartsSection = nullptr;
+               uint64_t threadStartsReservedSpace = 0;
+               if ( _options.makeThreadedStartsSection() ) {
+                       for (ld::Internal::FinalSection* sect : state.sections) {
+                               if ( sect->type() == ld::Section::typeThreadStarts ) {
+                                       threadStartsSection = sect;
+                                       break;
+                               }
+                       }
+                       assert(threadStartsSection);
+                       threadStartsReservedSpace = (threadStartsSection->size - 4) / 4;
+                       threadStarts.reserve(threadStartsReservedSpace);
+               }
+               
+               auto getAddress = [this](int64_t index) {
+                       if (index <= 0)
+                               return _rebaseInfo[-index]._address;
+                       else
+                               return _bindingInfo[index - 1]._address;
+               };
+
+               if ( (_bindingInfo.size() > 1)
+                       && ! findSegment(state, getAddress(_threadedRebaseBindIndices.front()),
+                                                        &curSegStart, &curSegEnd, &curSegIndex) )
+                       throw "binding address outside range of any segment";
+               
+               auto applyBind = [&](int64_t currentIndex, int64_t nextIndex) {
+                       uint64_t currentAddress = getAddress(currentIndex);
+                       uint64_t nextAddress = getAddress(nextIndex);
+
+                       // The very first pointer we see must be a new chain
+                       if ( _options.makeThreadedStartsSection() && curSection == NULL )
+                               threadStarts.push_back(currentAddress);
+
+                       if ( (curSection == NULL)
+                               || (currentAddress < curSection->address)
+                               || (currentAddress >= curSection->address+curSection->size) ) {
+                               for (ld::Internal::FinalSection* sect : state.sections) {
+                                       if ( (sect->address <= currentAddress)
+                                               && (currentAddress < sect->address+sect->size) ) {
+                                               curSection = sect;
+                                               break;
+                                       }
+                               }
+                       }
+
+                       bool makeChainToNextAddress = true;
+                       if ( allowThreadsToCrossPages ) {
+                               // Even if we allow threads to cross pages, we still need to have the same section.
+                               if ( (nextAddress < curSection->address) || (nextAddress >= curSection->address+curSection->size) )
+                                       makeChainToNextAddress = false;
+                       } else {
+                               // If threads can't cross pages then make sure they are on the same page.
+                               uint64_t currentPageIndex = ( currentAddress - curSegStart) / 4096;
+                               uint64_t nextPageIndex = ( nextAddress - curSegStart) / 4096;
+                               if ( currentPageIndex != nextPageIndex )
+                                       makeChainToNextAddress = false;
+                       }
+
+                       uint64_t delta = 0;
+                       if (makeChainToNextAddress) {
+                               delta = nextAddress - currentAddress;
+
+                               // The value should already be aligned to 4 or 8, so make sure the low bits are zeroes
+                               assert( (delta & (fixupAlignment - 1)) == 0 );
+                               delta /= fixupAlignment;
+                               if ( delta >= (1 << deltaBits) ) {
+                                       // Current and next are both in the same segment, so see if they are
+                                       // on the same page.  If so, patch current to point to next.
+                                       makeChainToNextAddress = false;
+                               }
+                       }
+
+                       if (!makeChainToNextAddress) {
+                               delta = 0;
+                               if (_options.makeThreadedStartsSection())
+                                       threadStarts.push_back(nextAddress);
+                       }
+
+                       uint8_t* lastBindLocation = wholeBuffer + curSection->fileOffset + currentAddress - curSection->address;
+                       switch ( _options.architecture() ) {
+                               case CPU_TYPE_X86_64:
+                               case CPU_TYPE_ARM64:
+                                       uint64_t value = 0;
+                                       if (currentIndex <= 0) {
+                                               // For rebases, bits [0..50] is the mh offset which is already set
+                                               // Bit 62 is a 0 to say this is a rebase
+                                               value = get64LE(lastBindLocation);
+#if SUPPORT_ARCH_arm64e
+                                               auto fixupOffset = (uintptr_t)(lastBindLocation - mhAddress);
+                                               auto it = _authenticatedFixupData.find(fixupOffset);
+                                               if (it != _authenticatedFixupData.end()) {
+                                                       // For authenticated data, we zeroed out the location
+                                                       assert(value == 0);
+                                                       const auto &authData = it->second.first;
+                                                       uint64_t accumulator = it->second.second;
+                                                       assert(accumulator >= mhAddress);
+                                                       accumulator -= mhAddress;
+
+                                                       // Make sure the high bits aren't set.  The low 32-bits may
+                                                       // be the target value.
+                                                       assert((accumulator & 0xFFFFFFFF00000000ULL) == 0);
+                                                       accumulator |= ((uint64_t)authData.discriminator) << 32;
+                                                       accumulator |= ((uint64_t)authData.hasAddressDiversity) << 48;
+                                                       accumulator |= ((uint64_t)authData.key) << 49;
+                                                       // Set the high bit as we are authenticated
+                                                       accumulator |= 1ULL << 63;
+
+                                                       value = accumulator;
+                                               } else
+#endif
+                                               {
+                                                       // Regular pointer which needs to fit in 51-bits of value.
+                                                       // C++ RTTI uses the top bit, so we'll allow the whole top-byte
+                                                       // and the bottom 43-bits with sign-extension to be fit in to 51-bits.
+                                                       uint64_t top8Bits = value & 0xFF00000000000000ULL;
+                                                       uint64_t bottom43Bits = value & 0x000007FFFFFFFFFFULL;
+                                                       // Ensure that the sign-extended bottom 43-bits is equivalent in sign to the gap bits
+                                                       assert( ((value & ~0xFF0003FFFFFFFFFF) == 0) || ((value & ~0xFF0003FFFFFFFFFF) == ~0xFF0003FFFFFFFFFF) );
+                                                       value = ( top8Bits >> 13 ) | bottom43Bits;
+                                               }
+                                       } else {
+                                               // The ordinal in [0..15]
+                                               // Bit 62 is a 1 to say this is a bind
+                                               value = get64LE(lastBindLocation);
+#if SUPPORT_ARCH_arm64e
+                                               auto fixupOffset = (uintptr_t)(lastBindLocation - mhAddress);
+                                               auto it = _authenticatedFixupData.find(fixupOffset);
+                                               if (it != _authenticatedFixupData.end()) {
+                                                       // For authenticated data, we zeroed out the location
+                                                       assert(value == 0);
+                                                       const auto &authData = it->second.first;
+                                                       uint64_t accumulator = it->second.second;
+
+                                                       // Make sure the high bits aren't set.  The low 32-bits may
+                                                       // be the target value.
+                                                       // Note, this doesn't work for binds to a weak def as we actually
+                                                       // manage to resolve their address to an address in this binary so
+                                                       // its not 0.
+                                                       if (_bindingInfo[currentIndex - 1]._libraryOrdinal == BIND_SPECIAL_DYLIB_WEAK_LOOKUP)
+                                                               accumulator = 0;
+                                                       assert((accumulator & 0xFFFFFFFF00000000ULL) == 0);
+                                                       accumulator |= ((uint64_t)authData.discriminator) << 32;
+                                                       accumulator |= ((uint64_t)authData.hasAddressDiversity) << 48;
+                                                       accumulator |= ((uint64_t)authData.key) << 49;
+                                                       // Set the high bit as we are authenticated
+                                                       accumulator |= 1ULL << 63;
+
+                                                       value = accumulator;
+                                               } else
+#endif
+                                               {
+                                                       // Regular pointer
+                                                       // The current data is unused as we get a new address from the bind table.
+                                                       // So zero it out to avoid the bits interfering with the authentication bits.
+                                                       value = 0;
+                                               }
+                                               value &= 0xFFFFFFFFFFFF0000;
+                                               value |= _bindingInfo[currentIndex - 1]._threadedBindOrdinal;
+                                               value |= 1ULL << 62;
+                                       }
+
+                                       // The delta is bits [51..61]
+                                       value |= ( delta << 51 );
+                                       set64LE(lastBindLocation, value);
+                                       break;
+                       }
+               };
+
+               // Loop over every value and see if it needs to point to its successor.
+               // Note that on every iteration, info[i] is already known to be in the current
+               // segment.
+               for (int64_t i = 0, e = _threadedRebaseBindIndices.size() - 1; i != e; ++i) {
+                       int64_t currentIndex = _threadedRebaseBindIndices[i];
+                       int64_t nextIndex = _threadedRebaseBindIndices[i + 1];
+                       uint64_t nextAddress = getAddress(nextIndex);
+                       if ( (nextAddress < curSegStart) || ( nextAddress >= curSegEnd) ) {
+                               // The next pointer is in a new segment.
+                               // This means current is the end of a chain, and we need to move
+                               // the segment addresses on to be the next ones.
+                               if ( ! findSegment(state, nextAddress, &curSegStart, &curSegEnd, &curSegIndex) )
+                                       throw "binding address outside range of any segment";
+                       }
+                       
+                       applyBind(currentIndex, nextIndex);
+               }
+               
+               applyBind(_threadedRebaseBindIndices.back(), _threadedRebaseBindIndices.back());
+
+               if ( _options.makeThreadedStartsSection() ) {
+                       if ( threadStarts.size() > threadStartsReservedSpace )
+                               throw "overflow in thread starts section";
+
+                       // Now write over this section content with the new array.
+                       const ld::Atom *threadStartsAtom = nullptr;
+                       for (const ld::Atom *atom : threadStartsSection->atoms) {
+                               if ( (atom->contentType() == ld::Atom::typeSectionStart) || (atom->contentType() == ld::Atom::typeSectionEnd) ) {
+                                       assert(atom->size() == 0);
+                                       continue;
+                               }
+                               assert(threadStartsAtom == nullptr);
+                               threadStartsAtom = atom;
+                       }
+                       uint64_t threadStartsFileOffset = threadStartsAtom->finalAddress() - threadStartsSection->address + threadStartsSection->fileOffset;
+                       // Skip the header
+                       threadStartsFileOffset += sizeof(uint32_t);
+                       for (uint64_t threadStart : threadStarts) {
+                               uint64_t offset = threadStart - mhAddress;
+                               assert(offset < 0x100000000);
+                               set32LE(&wholeBuffer[threadStartsFileOffset], offset);
+                               threadStartsFileOffset += sizeof(uint32_t);
+                       }
+               }
+       }
 }
 
 void OutputFile::computeContentUUID(ld::Internal& state, uint8_t* wholeBuffer)
@@ -2714,6 +3042,11 @@ void OutputFile::computeContentUUID(ld::Internal& state, uint8_t* wholeBuffer)
                        if ( lastSlash !=  NULL ) {
                                CC_MD5_Update(&md5state, lastSlash, strlen(lastSlash));
                        }
+                       // <rdar://problem/38679559> use train name when calculating a binary's UUID
+                       const char* buildName = _options.buildContextName();
+                       if ( buildName != NULL ) {
+                               CC_MD5_Update(&md5state, buildName, strlen(buildName));
+                       }
                        std::sort(excludeRegions.begin(), excludeRegions.end());
                        uint64_t checksumStart = 0;
                        for ( auto& region : excludeRegions ) {
@@ -3058,7 +3391,14 @@ void OutputFile::buildSymbolTable(ld::Internal& state)
                                case ld::Atom::scopeLinkageUnit:
                                        if ( _options.outputKind() == Options::kObjectFile ) {
                                                if ( _options.keepPrivateExterns() ) {
-                                                       _exportedAtoms.push_back(atom);
+                                                       if ( atom->symbolTableInclusion() == ld::Atom::symbolTableInWithRandomAutoStripLabel ) {
+                                                               // <rdar://problem/42150005> ld -r should not promote static 'l' labels to hidden
+                                                               (const_cast<ld::Atom*>(atom))->setScope(ld::Atom::scopeTranslationUnit);
+                                                               _localAtoms.push_back(atom);
+                                                       }
+                                                       else {
+                                                               _exportedAtoms.push_back(atom);
+                                                       }
                                                }
                                                else if ( _options.keepLocalSymbol(atom->name()) ) {
                                                        _localAtoms.push_back(atom);
@@ -3073,7 +3413,7 @@ void OutputFile::buildSymbolTable(ld::Internal& state)
                                                        _localAtoms.push_back(atom);
                                                // <rdar://problem/5804214> ld should never have a symbol in the non-lazy indirect symbol table with index 0
                                                // this works by making __mh_execute_header be a local symbol which takes symbol index 0
-                                               else if ( (atom->symbolTableInclusion() == ld::Atom::symbolTableInAndNeverStrip) && !_options.makeCompressedDyldInfo() )
+                                               else if ( (atom->symbolTableInclusion() == ld::Atom::symbolTableInAndNeverStrip) && !_options.makeCompressedDyldInfo() && !_options.makeThreadedStartsSection() )
                                                        _localAtoms.push_back(atom);
                                                else
                                                        (const_cast<ld::Atom*>(atom))->setSymbolTableInclusion(ld::Atom::symbolTableNotIn);
@@ -3180,6 +3520,10 @@ void OutputFile::addPreloadLinkEdit(ld::Internal& state)
                                _externalRelocsAtom = new ExternalRelocationsAtom<x86>(_options, state, *this);
                                externalRelocationsSection = state.addAtom(*_externalRelocsAtom);
                        }
+                       if ( _hasDataInCodeInfo ) {
+                               _dataInCodeAtom = new DataInCodeAtom<x86_64>(_options, state, *this);
+                               dataInCodeSection = state.addAtom(*_dataInCodeAtom);
+                       }
                        if ( _hasSymbolTable ) {
                                _indirectSymbolTableAtom = new IndirectSymbolTableAtom<x86>(_options, state, *this);
                                indirectSymbolTableSection = state.addAtom(*_indirectSymbolTableAtom);
@@ -3200,6 +3544,10 @@ void OutputFile::addPreloadLinkEdit(ld::Internal& state)
                                _externalRelocsAtom = new ExternalRelocationsAtom<x86_64>(_options, state, *this);
                                externalRelocationsSection = state.addAtom(*_externalRelocsAtom);
                        }
+                       if ( _hasDataInCodeInfo ) {
+                               _dataInCodeAtom = new DataInCodeAtom<x86_64>(_options, state, *this);
+                               dataInCodeSection = state.addAtom(*_dataInCodeAtom);
+                       }
                        if ( _hasSymbolTable ) {
                                _indirectSymbolTableAtom = new IndirectSymbolTableAtom<x86_64>(_options, state, *this);
                                indirectSymbolTableSection = state.addAtom(*_indirectSymbolTableAtom);
@@ -3220,6 +3568,10 @@ void OutputFile::addPreloadLinkEdit(ld::Internal& state)
                                _externalRelocsAtom = new ExternalRelocationsAtom<arm>(_options, state, *this);
                                externalRelocationsSection = state.addAtom(*_externalRelocsAtom);
                        }
+                       if ( _hasDataInCodeInfo ) {
+                               _dataInCodeAtom = new DataInCodeAtom<x86_64>(_options, state, *this);
+                               dataInCodeSection = state.addAtom(*_dataInCodeAtom);
+                       }
                        if ( _hasSymbolTable ) {
                                _indirectSymbolTableAtom = new IndirectSymbolTableAtom<arm>(_options, state, *this);
                                indirectSymbolTableSection = state.addAtom(*_indirectSymbolTableAtom);
@@ -3240,6 +3592,10 @@ void OutputFile::addPreloadLinkEdit(ld::Internal& state)
                                _externalRelocsAtom = new ExternalRelocationsAtom<arm64>(_options, state, *this);
                                externalRelocationsSection = state.addAtom(*_externalRelocsAtom);
                        }
+                       if ( _hasDataInCodeInfo ) {
+                               _dataInCodeAtom = new DataInCodeAtom<x86_64>(_options, state, *this);
+                               dataInCodeSection = state.addAtom(*_dataInCodeAtom);
+                       }
                        if ( _hasSymbolTable ) {
                                _indirectSymbolTableAtom = new IndirectSymbolTableAtom<arm64>(_options, state, *this);
                                indirectSymbolTableSection = state.addAtom(*_indirectSymbolTableAtom);
@@ -3680,66 +4036,9 @@ int OutputFile::compressedOrdinalForAtom(const ld::Atom* target)
 }
 
 
-bool OutputFile::isPcRelStore(ld::Fixup::Kind kind)
+bool OutputFile::isPcRelStore(const ld::Fixup* fixup)
 {
-       switch ( kind ) { 
-               case ld::Fixup::kindStoreX86BranchPCRel8:
-               case ld::Fixup::kindStoreX86BranchPCRel32:
-               case ld::Fixup::kindStoreX86PCRel8:
-               case ld::Fixup::kindStoreX86PCRel16:
-               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::kindStoreARMBranch24:
-               case ld::Fixup::kindStoreThumbBranch22:
-               case ld::Fixup::kindStoreARMLoad12:
-               case ld::Fixup::kindStoreTargetAddressX86PCRel32:
-               case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoad:
-               case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoadNowLEA:
-               case ld::Fixup::kindStoreTargetAddressX86PCRel32TLVLoad:
-               case ld::Fixup::kindStoreTargetAddressX86PCRel32TLVLoadNowLEA:
-               case ld::Fixup::kindStoreTargetAddressARMBranch24:
-               case ld::Fixup::kindStoreTargetAddressThumbBranch22:
-               case ld::Fixup::kindStoreTargetAddressARMLoad12:
-#if SUPPORT_ARCH_arm64
-               case ld::Fixup::kindStoreARM64Page21:
-               case ld::Fixup::kindStoreARM64PageOff12:
-               case ld::Fixup::kindStoreARM64GOTLoadPage21:
-               case ld::Fixup::kindStoreARM64GOTLoadPageOff12:
-               case ld::Fixup::kindStoreARM64GOTLeaPage21:
-               case ld::Fixup::kindStoreARM64GOTLeaPageOff12:
-               case ld::Fixup::kindStoreARM64TLVPLoadPage21:
-               case ld::Fixup::kindStoreARM64TLVPLoadPageOff12:
-               case ld::Fixup::kindStoreARM64TLVPLoadNowLeaPage21:
-               case ld::Fixup::kindStoreARM64TLVPLoadNowLeaPageOff12:
-               case ld::Fixup::kindStoreARM64PCRelToGOT:
-               case ld::Fixup::kindStoreTargetAddressARM64Page21:
-               case ld::Fixup::kindStoreTargetAddressARM64PageOff12:
-               case ld::Fixup::kindStoreTargetAddressARM64GOTLoadPage21:
-               case ld::Fixup::kindStoreTargetAddressARM64GOTLoadPageOff12:
-               case ld::Fixup::kindStoreTargetAddressARM64GOTLeaPage21:
-               case ld::Fixup::kindStoreTargetAddressARM64GOTLeaPageOff12:
-               case ld::Fixup::kindStoreTargetAddressARM64TLVPLoadPage21:
-               case ld::Fixup::kindStoreTargetAddressARM64TLVPLoadPageOff12:
-               case ld::Fixup::kindStoreTargetAddressARM64TLVPLoadNowLeaPage21:
-               case ld::Fixup::kindStoreTargetAddressARM64TLVPLoadNowLeaPageOff12:
-#endif
-                       return true;
-               case ld::Fixup::kindStoreTargetAddressX86BranchPCRel32:
-#if SUPPORT_ARCH_arm64
-               case ld::Fixup::kindStoreTargetAddressARM64Branch26:
-#endif
-                       return (_options.outputKind() != Options::kKextBundle);
-               default:
-                       break;
-       }
-       return false;
+       return fixup->isPcRelStore(_options.outputKind() == Options::kKextBundle);
 }
 
 bool OutputFile::isStore(ld::Fixup::Kind kind)
@@ -3757,6 +4056,9 @@ bool OutputFile::isStore(ld::Fixup::Kind kind)
                case ld::Fixup::kindSubtractAddend:
                case ld::Fixup::kindSetTargetImageOffset:
                case ld::Fixup::kindSetTargetSectionOffset:
+#if SUPPORT_ARCH_arm64e
+               case ld::Fixup::kindSetAuthData:
+#endif
                        return false;
                default:
                        break;
@@ -3765,52 +4067,9 @@ bool OutputFile::isStore(ld::Fixup::Kind kind)
 }
 
 
-bool OutputFile::setsTarget(ld::Fixup::Kind kind)
+bool OutputFile::setsTarget(const ld::Fixup &fixup)
 {
-       switch ( kind ) { 
-               case ld::Fixup::kindSetTargetAddress:
-               case ld::Fixup::kindLazyTarget:
-               case ld::Fixup::kindStoreTargetAddressLittleEndian32:
-               case ld::Fixup::kindStoreTargetAddressLittleEndian64:
-               case ld::Fixup::kindStoreTargetAddressBigEndian32:
-               case ld::Fixup::kindStoreTargetAddressBigEndian64:
-               case ld::Fixup::kindStoreTargetAddressX86PCRel32:
-               case ld::Fixup::kindStoreTargetAddressX86BranchPCRel32:
-               case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoad:
-               case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoadNowLEA:
-               case ld::Fixup::kindStoreTargetAddressX86PCRel32TLVLoad:
-               case ld::Fixup::kindStoreTargetAddressX86PCRel32TLVLoadNowLEA:
-               case ld::Fixup::kindStoreTargetAddressX86Abs32TLVLoad:
-               case ld::Fixup::kindStoreTargetAddressARMBranch24:
-               case ld::Fixup::kindStoreTargetAddressThumbBranch22:
-               case ld::Fixup::kindStoreTargetAddressARMLoad12:
-#if SUPPORT_ARCH_arm64
-               case ld::Fixup::kindStoreTargetAddressARM64Branch26:
-               case ld::Fixup::kindStoreTargetAddressARM64Page21:
-               case ld::Fixup::kindStoreTargetAddressARM64PageOff12:
-               case ld::Fixup::kindStoreTargetAddressARM64GOTLoadPage21:
-               case ld::Fixup::kindStoreTargetAddressARM64GOTLoadPageOff12:
-               case ld::Fixup::kindStoreTargetAddressARM64GOTLeaPage21:
-               case ld::Fixup::kindStoreTargetAddressARM64GOTLeaPageOff12:
-               case ld::Fixup::kindStoreTargetAddressARM64TLVPLoadPage21:
-               case ld::Fixup::kindStoreTargetAddressARM64TLVPLoadPageOff12:
-               case ld::Fixup::kindStoreTargetAddressARM64TLVPLoadNowLeaPage21:
-               case ld::Fixup::kindStoreTargetAddressARM64TLVPLoadNowLeaPageOff12:
-#endif
-                       return true;
-               case ld::Fixup::kindStoreX86DtraceCallSiteNop:
-               case ld::Fixup::kindStoreX86DtraceIsEnableSiteClear:
-               case ld::Fixup::kindStoreARMDtraceCallSiteNop:
-               case ld::Fixup::kindStoreARMDtraceIsEnableSiteClear:
-               case ld::Fixup::kindStoreARM64DtraceCallSiteNop:
-               case ld::Fixup::kindStoreARM64DtraceIsEnableSiteClear:
-               case ld::Fixup::kindStoreThumbDtraceCallSiteNop:
-               case ld::Fixup::kindStoreThumbDtraceIsEnableSiteClear:
-                       return (_options.outputKind() == Options::kObjectFile);
-               default:
-                       break;
-       }
-       return false;
+       return fixup.setsTarget(_options.outputKind() == Options::kObjectFile);
 }
 
 bool OutputFile::isPointerToTarget(ld::Fixup::Kind kind)
@@ -3819,6 +4078,9 @@ bool OutputFile::isPointerToTarget(ld::Fixup::Kind kind)
                case ld::Fixup::kindSetTargetAddress:
                case ld::Fixup::kindStoreTargetAddressLittleEndian32:
                case ld::Fixup::kindStoreTargetAddressLittleEndian64:
+#if SUPPORT_ARCH_arm64e
+               case ld::Fixup::kindStoreTargetAddressLittleEndianAuth64:
+#endif
                case ld::Fixup::kindStoreTargetAddressBigEndian32:
                case ld::Fixup::kindStoreTargetAddressBigEndian64:
                case ld::Fixup::kindLazyTarget:
@@ -3900,7 +4162,10 @@ void OutputFile::generateLinkEditInfo(ld::Internal& state)
                                if ( _options.makeCompressedDyldInfo() ) {
                                        uint8_t wtype = BIND_TYPE_OVERRIDE_OF_WEAKDEF_IN_DYLIB;
                                        bool nonWeakDef = (atom->combine() == ld::Atom::combineNever);
-                                       _weakBindingInfo.push_back(BindingInfo(wtype, atom->name(), nonWeakDef, atom->finalAddress(), 0));
+                                       // Don't push weak binding info for threaded bind.
+                                       // Instead we use a special ordinal in the regular bind info
+                                       if ( !_options.useLinkedListBinding() )
+                                               _weakBindingInfo.push_back(BindingInfo(wtype, atom->name(), nonWeakDef, atom->finalAddress(), 0));
                                }
                                this->overridesWeakExternalSymbols = true;
                                if ( _options.warnWeakExports() )
@@ -3915,6 +4180,9 @@ void OutputFile::generateLinkEditInfo(ld::Internal& state)
                        const ld::Atom*         minusTarget = NULL;
                        uint64_t                        targetAddend = 0;
                        uint64_t                        minusTargetAddend = 0;
+#if SUPPORT_ARCH_arm64e
+                       ld::Fixup*                      fixupWithAuthData = NULL;
+#endif
                        for (ld::Fixup::iterator fit = atom->fixupsBegin(); fit != atom->fixupsEnd(); ++fit) {
                                if ( fit->firstInCluster() ) {
                                        fixupWithTarget = NULL;
@@ -3925,7 +4193,7 @@ void OutputFile::generateLinkEditInfo(ld::Internal& state)
                                        targetAddend = 0;
                                        minusTargetAddend = 0;
                                }
-                               if ( this->setsTarget(fit->kind) ) {
+                               if ( this->setsTarget(*fit) ) {
                                        switch ( fit->binding ) {
                                                case ld::Fixup::bindingNone:
                                                case ld::Fixup::bindingByNameUnbound:
@@ -3976,22 +4244,33 @@ void OutputFile::generateLinkEditInfo(ld::Internal& state)
                                        case ld::Fixup::kindDataInCodeEnd:
                                                hasDataInCode = true;
                                                break;
+#if SUPPORT_ARCH_arm64e
+                                       case ld::Fixup::kindSetAuthData:
+                                               fixupWithAuthData = fit;
+                                               break;
+#endif
                                        default:
                         break;    
                                }
-                               if ( this->isStore(fit->kind) ) {
+                               if ( fit->isStore() ) {
                                        fixupWithStore = fit;
                                }
                                if ( fit->lastInCluster() ) {
                                        if ( (fixupWithStore != NULL) && (target != NULL) ) {
                                                if ( _options.outputKind() == Options::kObjectFile ) {
                                                        this->addSectionRelocs(state, sect, atom, fixupWithTarget, fixupWithMinusTarget, fixupWithAddend, fixupWithStore,
+#if SUPPORT_ARCH_arm64e
+                                                                                                  fixupWithAuthData,
+#endif
                                                                                                        target, minusTarget, targetAddend, minusTargetAddend);
                                                }
                                                else {
                                                        if ( _options.makeCompressedDyldInfo() ) {
                                                                this->addDyldInfo(state, sect, atom, fixupWithTarget, fixupWithMinusTarget, fixupWithStore,
-                                                                                                       target, minusTarget, targetAddend, minusTargetAddend);
+                                                                                                 target, minusTarget, targetAddend, minusTargetAddend);
+                                                       } else if ( _options.makeThreadedStartsSection() ) {
+                                                               this->addThreadedRebaseInfo(state, sect, atom, fixupWithTarget, fixupWithMinusTarget, fixupWithStore,
+                                                                                                                       target, minusTarget, targetAddend, minusTargetAddend);
                                                        }
                                                        else { 
                                                                this->addClassicRelocs(state, sect, atom, fixupWithTarget, fixupWithMinusTarget, fixupWithStore,
@@ -4022,7 +4301,7 @@ void OutputFile::noteTextReloc(const ld::Atom* atom, const ld::Atom* target)
                        warning("text reloc in %s to %s", atom->name(), target->name());
        } 
        else if ( _options.positionIndependentExecutable() && (_options.outputKind() == Options::kDynamicExecutable) 
-               && ((_options.iOSVersionMin() >= ld::iOS_4_3) || (_options.macosxVersionMin() >= ld::mac10_7)) ) {
+                        && _options.platforms().minOS(ld::version2010Fall)) {
                if ( ! this->pieDisabled ) {
                        switch ( _options.architecture()) {
 #if SUPPORT_ARCH_arm64
@@ -4063,7 +4342,7 @@ void OutputFile::addDyldInfo(ld::Internal& state,  ld::Internal::FinalSection* s
                return;
 
        // no need to rebase or bind PCRel stores
-       if ( this->isPcRelStore(fixupWithStore->kind) ) {
+       if ( this->isPcRelStore(fixupWithStore) ) {
                // as long as target is in same linkage unit
                if ( (target == NULL) || (target->definition() != ld::Atom::definitionProxy) ) {
                        // make sure target is not global and weak
@@ -4242,7 +4521,21 @@ void OutputFile::addDyldInfo(ld::Internal& state,  ld::Internal::FinalSection* s
                                }
                        }
                }
-       } 
+       }
+
+       // Find the ordinal for the bind target
+       int compressedOrdinal = 0;
+       if ( needsBinding || needsLazyBinding || needsWeakBinding ) {
+               compressedOrdinal = this->compressedOrdinalForAtom(target);
+       }
+       // Linked list binding puts the weak binds in to the regular binds but with a special ordinal.
+       if ( needsWeakBinding && _options.useLinkedListBinding() ) {
+               assert(!needsLazyBinding);
+               needsWeakBinding = false;
+               needsBinding = true;
+               needsRebase = false;
+               compressedOrdinal = BIND_SPECIAL_DYLIB_WEAK_LOOKUP;
+       }
 
        // record dyld info for this cluster
        if ( needsRebase ) {
@@ -4288,9 +4581,11 @@ void OutputFile::addDyldInfo(ld::Internal& state,  ld::Internal::FinalSection* s
                                        // do nothing
                                        break;
                        }
+                       _hasUnalignedFixup = true;
                }
                _rebaseInfo.push_back(RebaseInfo(rebaseType, address));
        }
+
        if ( needsBinding ) {
                if ( inReadOnlySeg ) {
                        noteTextReloc(atom, target);
@@ -4310,19 +4605,124 @@ void OutputFile::addDyldInfo(ld::Internal& state,  ld::Internal::FinalSection* s
                                        // do nothing
                                        break;
                        }
+                       _hasUnalignedFixup = true;
                }
-               _bindingInfo.push_back(BindingInfo(type, this->compressedOrdinalForAtom(target), target->name(), weak_import, address, addend));
+               _bindingInfo.push_back(BindingInfo(type, compressedOrdinal, target->name(), weak_import, address, addend));
        }
        if ( needsLazyBinding ) {
                if ( _options.bindAtLoad() )
-                       _bindingInfo.push_back(BindingInfo(type, this->compressedOrdinalForAtom(target), target->name(), weak_import, address, addend));
+                       _bindingInfo.push_back(BindingInfo(type, compressedOrdinal, target->name(), weak_import, address, addend));
                else
-                       _lazyBindingInfo.push_back(BindingInfo(type, this->compressedOrdinalForAtom(target), target->name(), weak_import, address, addend));
+                       _lazyBindingInfo.push_back(BindingInfo(type, compressedOrdinal, target->name(), weak_import, address, addend));
        }
        if ( needsWeakBinding )
                _weakBindingInfo.push_back(BindingInfo(type, 0, target->name(), false, address, addend));
 }
 
+void OutputFile::addThreadedRebaseInfo(ld::Internal& state,  ld::Internal::FinalSection* sect, const ld::Atom* atom,
+                                                                          ld::Fixup* fixupWithTarget, ld::Fixup* fixupWithMinusTarget, ld::Fixup* fixupWithStore,
+                                                                          const ld::Atom* target, const ld::Atom* minusTarget,
+                                                                          uint64_t targetAddend, uint64_t minusTargetAddend)
+{
+       if ( sect->isSectionHidden() )
+               return;
+
+       // no need to rebase or bind PCRel stores
+       if ( this->isPcRelStore(fixupWithStore) ) {
+               // as long as target is in same linkage unit
+               if ( (target == NULL) || (target->definition() != ld::Atom::definitionProxy) ) {
+                       // make sure target is not global and weak
+                       if ( (target->scope() == ld::Atom::scopeGlobal) && (target->combine() == ld::Atom::combineByName) && (target->definition() == ld::Atom::definitionRegular)) {
+                               if ( (atom->section().type() == ld::Section::typeCFI)
+                                       || (atom->section().type() == ld::Section::typeDtraceDOF)
+                                       || (atom->section().type() == ld::Section::typeUnwindInfo) ) {
+                                       // ok for __eh_frame and __uwind_info to use pointer diffs to global weak symbols
+                                       return;
+                               }
+                               // <rdar://problem/13700961> spurious warning when weak function has reference to itself
+                               if ( fixupWithTarget->binding == ld::Fixup::bindingDirectlyBound ) {
+                                       // ok to ignore pc-rel references within a weak function to itself
+                                       return;
+                               }
+                               // Have direct reference to weak-global.  This should be an indrect reference
+                               const char* demangledName = strdup(_options.demangleSymbol(atom->name()));
+                               warning("direct access in function '%s' from file '%s' to global weak symbol '%s' from file '%s' means the weak symbol cannot be overridden at runtime. "
+                                               "This was likely caused by different translation units being compiled with different visibility settings.",
+                                                 demangledName, atom->safeFilePath(), _options.demangleSymbol(target->name()), target->safeFilePath());
+                       }
+                       return;
+               }
+       }
+
+       // no need to rebase or bind PIC internal pointer diff
+       if ( minusTarget != NULL ) {
+               // with pointer diffs, both need to be in same linkage unit
+               assert(minusTarget->definition() != ld::Atom::definitionProxy);
+               assert(target != NULL);
+               assert(target->definition() != ld::Atom::definitionProxy);
+               if ( target == minusTarget ) {
+                       // This is a compile time constant and could have been optimized away by compiler
+                       return;
+               }
+
+               // check if target of pointer-diff is global and weak
+               if ( (target->scope() == ld::Atom::scopeGlobal) && (target->combine() == ld::Atom::combineByName) && (target->definition() == ld::Atom::definitionRegular) ) {
+                       if ( (atom->section().type() == ld::Section::typeCFI)
+                               || (atom->section().type() == ld::Section::typeDtraceDOF)
+                               || (atom->section().type() == ld::Section::typeUnwindInfo) ) {
+                               // ok for __eh_frame and __uwind_info to use pointer diffs to global weak symbols
+                               return;
+                       }
+                       // Have direct reference to weak-global.  This should be an indrect reference
+                       const char* demangledName = strdup(_options.demangleSymbol(atom->name()));
+                       warning("direct access in function '%s' from file '%s' to global weak symbol '%s' from file '%s' means the weak symbol cannot be overridden at runtime. "
+                                       "This was likely caused by different translation units being compiled with different visibility settings.",
+                                         demangledName, atom->safeFilePath(), _options.demangleSymbol(target->name()), target->safeFilePath());
+               }
+               return;
+       }
+
+       // no need to rebase or bind an atom's references to itself if the output is not slidable
+       if ( (atom == target) && !_options.outputSlidable() )
+               return;
+
+       // cluster has no target, so needs no rebasing or binding
+       if ( target == NULL )
+               return;
+
+       const uint64_t minAlignment = 4;
+       bool inReadOnlySeg = ( strcmp(sect->segmentName(), "__TEXT") == 0 );
+       bool needsRebase = false;
+
+       uint8_t rebaseType = REBASE_TYPE_POINTER;
+       uint64_t address =  atom->finalAddress() + fixupWithTarget->offsetInAtom;
+
+       // special case lazy pointers
+       switch ( target->definition() ) {
+               case ld::Atom::definitionProxy:
+                       break;
+               case ld::Atom::definitionRegular:
+               case ld::Atom::definitionTentative:
+                       needsRebase = true;
+                       break;
+               case ld::Atom::definitionAbsolute:
+                       break;
+       }
+
+       // record dyld info for this cluster
+       if ( needsRebase ) {
+               if ( inReadOnlySeg ) {
+                       noteTextReloc(atom, target);
+                       sect->hasLocalRelocs = true;  // so dyld knows to change permissions on __TEXT segment
+               }
+               if ( ((address & (minAlignment-1)) != 0) ) {
+                       throwf("pointer not aligned to at least 4-bytes at address 0x%llX (%s + %lld from %s)",
+                                  address, atom->name(), (address - atom->finalAddress()), atom->safeFilePath());
+               }
+               _rebaseInfo.push_back(RebaseInfo(rebaseType, address));
+       }
+}
+
 
 void OutputFile::addClassicRelocs(ld::Internal& state, ld::Internal::FinalSection* sect, const ld::Atom* atom, 
                                                                ld::Fixup* fixupWithTarget, ld::Fixup* fixupWithMinusTarget, ld::Fixup* fixupWithStore,
@@ -4350,7 +4750,7 @@ void OutputFile::addClassicRelocs(ld::Internal& state, ld::Internal::FinalSectio
        }
        
        // no need to rebase or bind PCRel stores
-       if ( this->isPcRelStore(fixupWithStore->kind) ) {
+       if ( this->isPcRelStore(fixupWithStore) ) {
                // as long as target is in same linkage unit
                if ( (target == NULL) || (target->definition() != ld::Atom::definitionProxy) )
                        return;
@@ -4400,6 +4800,9 @@ void OutputFile::addClassicRelocs(ld::Internal& state, ld::Internal::FinalSectio
                case ld::Fixup::kindStoreBigEndian64:
                case ld::Fixup::kindStoreTargetAddressLittleEndian32:
                case ld::Fixup::kindStoreTargetAddressLittleEndian64:
+#if SUPPORT_ARCH_arm64e
+               case ld::Fixup::kindStoreTargetAddressLittleEndianAuth64:
+#endif
                case ld::Fixup::kindStoreTargetAddressBigEndian32:
                case ld::Fixup::kindStoreTargetAddressBigEndian64:
                        // is pointer 
@@ -4490,6 +4893,24 @@ void OutputFile::addClassicRelocs(ld::Internal& state, ld::Internal::FinalSectio
                                throwf("no supported runtime hi16 relocation in %s from %s to %s", atom->name(), atom->safeFilePath(), target->name());
                        break;
 
+#if SUPPORT_ARCH_arm64e
+               case ld::Fixup::kindStoreLittleEndianAuth64:
+                       if ( _options.outputKind() == Options::kKextBundle ) {
+                               if ( target->definition() == ld::Atom::definitionProxy ) {
+                                       _externalRelocsAtom->addExternalPointerReloc(relocAddress, target);
+                                       sect->hasExternalRelocs = true;
+                                       fixupWithTarget->contentAddendOnly = true;
+                               }
+                               else {
+                                       _localRelocsAtom->addPointerReloc(relocAddress, target->machoSection());
+                                       sect->hasLocalRelocs = true;
+                               }
+                       }
+                       else {
+                               throwf("authenticated pointer in atom %s from %s to %s is not supported", atom->name(), atom->safeFilePath(), target->name());
+                       }
+                       break;
+#endif
                default:
                        break;
        }
@@ -4561,7 +4982,10 @@ bool OutputFile::useSectionRelocAddend(ld::Fixup* fixupWithTarget)
 
 void OutputFile::addSectionRelocs(ld::Internal& state, ld::Internal::FinalSection* sect, const ld::Atom* atom, 
                                                                ld::Fixup* fixupWithTarget, ld::Fixup* fixupWithMinusTarget,  
-                                                               ld::Fixup* fixupWithAddend, ld::Fixup* fixupWithStore, 
+                                                               ld::Fixup* fixupWithAddend, ld::Fixup* fixupWithStore,
+#if SUPPORT_ARCH_arm64e
+                                                                 ld::Fixup* fixupWithAuthData,
+#endif
                                                                const ld::Atom* target, const ld::Atom* minusTarget, 
                                                                uint64_t targetAddend, uint64_t minusTargetAddend)
 {
@@ -4611,7 +5035,7 @@ void OutputFile::addSectionRelocs(ld::Internal& state, ld::Internal::FinalSectio
                                fixupWithTarget->contentAddendOnly = true;
                                fixupWithStore->contentAddendOnly = true;
                        }
-                       else if ( isPcRelStore(fixupWithStore->kind) ) {
+                       else if ( isPcRelStore(fixupWithStore) ) {
                                fixupWithTarget->contentDetlaToAddendOnly = true;
                                fixupWithStore->contentDetlaToAddendOnly = true;
                        }
@@ -4625,6 +5049,9 @@ void OutputFile::addSectionRelocs(ld::Internal& state, ld::Internal::FinalSectio
        if ( fixupWithStore != NULL ) {
                _sectionsRelocationsAtom->addSectionReloc(sect, fixupWithStore->kind, atom, fixupWithStore->offsetInAtom, 
                                                                                                        targetUsesExternalReloc, minusTargetUsesExternalReloc,
+#if SUPPORT_ARCH_arm64e
+                                                                                                 fixupWithAuthData,
+#endif
                                                                                                        target, targetAddend, minusTarget, minusTargetAddend);
        }
 
@@ -4651,7 +5078,7 @@ void OutputFile::makeSplitSegInfo(ld::Internal& state)
                        for (ld::Fixup::iterator fit = atom->fixupsBegin(), end=atom->fixupsEnd(); fit != end; ++fit) {
                                if ( fit->firstInCluster() ) 
                                        target = NULL;
-                               if ( this->setsTarget(fit->kind) ) {
+                               if ( this->setsTarget(*fit) ) {
                                        accumulator = addressOf(state, fit, &target);
                                        thumbTarget = targetIsThumb(state, fit);
                                        if ( thumbTarget ) 
@@ -4726,6 +5153,13 @@ void OutputFile::makeSplitSegInfo(ld::Internal& state)
                                                assert(target != NULL);
                                                hadSubtract = true;
                                                break;
+#if SUPPORT_ARCH_arm64e
+                                       case ld::Fixup::kindStoreLittleEndianAuth64:
+                                       case ld::Fixup::kindStoreTargetAddressLittleEndianAuth64:
+                                       case ld::Fixup::kindSetAuthData:
+                                               throw "authenticated pointers are not supported in split seg v1";
+                                               break;
+#endif
                                        default:
                                                break;
                                }
@@ -4770,7 +5204,7 @@ void OutputFile::makeSplitSegInfoV2(ld::Internal& state)
                                        toSectionIndex = 255;
                                        fromOffset = atom->finalAddress() + fit->offsetInAtom - sect->address;
                                }
-                               if ( this->setsTarget(fit->kind) ) {
+                               if ( this->setsTarget(*fit) ) {
                                        accumulator = addressAndTarget(state, fit, &target);
                                        thumbTarget = targetIsThumb(state, fit);
                                        if ( thumbTarget ) 
@@ -4812,9 +5246,19 @@ void OutputFile::makeSplitSegInfoV2(ld::Internal& state)
                                        case ld::Fixup::kindStoreTargetAddressLittleEndian64:
                                                if ( hadSubtract )
                                                        kind = DYLD_CACHE_ADJ_V2_DELTA_64;
+                                               else if ( _options.useLinkedListBinding() && !this->_hasUnalignedFixup )
+                                                       kind = DYLD_CACHE_ADJ_V2_THREADED_POINTER_64;
                                                else
                                                        kind = DYLD_CACHE_ADJ_V2_POINTER_64;
                                                break;
+#if SUPPORT_ARCH_arm64e
+                                       case ld::Fixup::kindStoreLittleEndianAuth64:
+                                       case ld::Fixup::kindStoreTargetAddressLittleEndianAuth64:
+                                               // FIXME: Do we need to handle subtracts on authenticated pointers?
+                                               assert(!hadSubtract);
+                                               kind = DYLD_CACHE_ADJ_V2_THREADED_POINTER_64;
+                                               break;
+#endif
                                        case ld::Fixup::kindStoreX86PCRel32:
                                        case ld::Fixup::kindStoreX86PCRel32_1:
                                        case ld::Fixup::kindStoreX86PCRel32_2:
index 81f2cfb842e2691ca669202907e456dca7f3de0c..d4024eb1257a416250a7c853941a6dd18ce509d1 100644 (file)
@@ -89,6 +89,7 @@ public:
        ld::Internal::FinalSection*     externalRelocationsSection;
        ld::Internal::FinalSection*     sectionRelocationsSection;
        ld::Internal::FinalSection*     indirectSymbolTableSection;
+       ld::Internal::FinalSection*     threadedPageStartsSection;
        
        struct RebaseInfo {
                                                RebaseInfo(uint8_t t, uint64_t addr) : _type(t), _address(addr) {}
@@ -105,13 +106,15 @@ public:
 
        struct BindingInfo {
                                                BindingInfo(uint8_t t, int ord, const char* sym, bool weak_import, uint64_t addr, int64_t add) 
-                                                       : _type(t), _flags(weak_import ? BIND_SYMBOL_FLAGS_WEAK_IMPORT : 0 ), _libraryOrdinal(ord), 
+                                                       : _type(t), _flags(weak_import ? BIND_SYMBOL_FLAGS_WEAK_IMPORT : 0 ),
+                                                               _threadedBindOrdinal(0), _libraryOrdinal(ord),
                                                                _symbolName(sym), _address(addr), _addend(add) {}
                                                BindingInfo(uint8_t t, const char* sym, bool non_weak_definition, uint64_t addr, int64_t add) 
                                                        : _type(t), _flags(non_weak_definition ? BIND_SYMBOL_FLAGS_NON_WEAK_DEFINITION : 0 ), 
-                                                        _libraryOrdinal(0), _symbolName(sym), _address(addr), _addend(add) {}
+                                                        _threadedBindOrdinal(0), _libraryOrdinal(0), _symbolName(sym), _address(addr), _addend(add) {}
                uint8_t                 _type;
                uint8_t                 _flags;
+               uint16_t                _threadedBindOrdinal;
                int                             _libraryOrdinal;
                const char*             _symbolName;
                uint64_t                _address;
@@ -164,6 +167,9 @@ private:
                                                                                                const ld::Atom* atom, ld::Fixup* fixupWithTarget, 
                                                                                                ld::Fixup* fixupWithMinusTarget, ld::Fixup* fixupWithAddend,
                                                                                                 ld::Fixup* fixupWithStore,
+#if SUPPORT_ARCH_arm64e
+                                                                                                ld::Fixup* fixupWithAuthData,
+#endif
                                                                                                const ld::Atom* target, const ld::Atom* minusTarget, 
                                                                                                uint64_t targetAddend, uint64_t minusTargetAddend);
        void                                            addDyldInfo(ld::Internal& state, ld::Internal::FinalSection* sect,  
@@ -171,6 +177,11 @@ private:
                                                                                                ld::Fixup* fixupWithMinusTarget, ld::Fixup* fixupWithStore,
                                                                                                const ld::Atom* target, const ld::Atom* minusTarget, 
                                                                                                uint64_t targetAddend, uint64_t minusTargetAddend);
+       void                                            addThreadedRebaseInfo(ld::Internal& state, ld::Internal::FinalSection* sect,
+                                                                                                         const ld::Atom* atom, ld::Fixup* fixupWithTarget,
+                                                                                                         ld::Fixup* fixupWithMinusTarget, ld::Fixup* fixupWithStore,
+                                                                                                         const ld::Atom* target, const ld::Atom* minusTarget,
+                                                                                                         uint64_t targetAddend, uint64_t minusTargetAddend);
        void                                            addClassicRelocs(ld::Internal& state, ld::Internal::FinalSection* sect,  
                                                                                                const ld::Atom* atom, ld::Fixup* fixupWithTarget, 
                                                                                                ld::Fixup* fixupWithMinusTarget, ld::Fixup* fixupWithStore,
@@ -195,10 +206,10 @@ private:
        void                                            copyNoOps(uint8_t* from, uint8_t* to, bool thumb);
        bool                                            isPointerToTarget(ld::Fixup::Kind kind);
        bool                                            isPointerFromTarget(ld::Fixup::Kind kind);
-       bool                                            isPcRelStore(ld::Fixup::Kind kind);
+       bool                                            isPcRelStore(const ld::Fixup* fixup);
        bool                                            isStore(ld::Fixup::Kind kind);
        bool                                            storeAddendOnly(const ld::Atom* inAtom, const ld::Atom* target, bool pcRel=false);
-       bool                                            setsTarget(ld::Fixup::Kind kind);
+       bool                                            setsTarget(const ld::Fixup &fixup);
        void                                            addFixupOutInfo(ld::Internal& state);
        void                                            makeRelocations(ld::Internal& state);
        void                                            makeSectionRelocations(ld::Internal& state);
@@ -279,6 +290,7 @@ private:
        std::vector<const ld::dylib::File*>             _dylibsToLoad;
        std::vector<const char*>                                _dylibOrdinalPaths;
        const bool                                                              _hasDyldInfo;
+       const bool                                                              _hasThreadedPageStarts;
        const bool                                                              _hasSymbolTable;
        const bool                                                              _hasSectionRelocations;
        const bool                                                              _hasSplitSegInfo;
@@ -307,6 +319,12 @@ public:
        std::vector<BindingInfo>                                _bindingInfo;
        std::vector<BindingInfo>                                _lazyBindingInfo;
        std::vector<BindingInfo>                                _weakBindingInfo;
+       bool                                                                    _hasUnalignedFixup = false;
+       // Note, <= 0 values are indices in to rebases, > 0 are binds.
+       std::vector<int64_t>                                    _threadedRebaseBindIndices;
+#if SUPPORT_ARCH_arm64e
+       std::map<uintptr_t, std::pair<Fixup::AuthData, uint64_t>> _authenticatedFixupData;
+#endif
        std::vector<SplitSegInfoEntry>                  _splitSegInfos;
        std::vector<SplitSegInfoV2Entry>                _splitSegV2Infos;
        class HeaderAndLoadCommandsAbtract*             _headersAndLoadCommandAtom;
index 51afe8dfca9b8ac3482228c50d9c347ff28abb2a..17e00cb78e81b97b7c1e20a3e4a8579ecfd75eab 100644 (file)
@@ -179,7 +179,7 @@ private:
 
 SectionBoundaryAtom* SectionBoundaryAtom::makeSectionBoundaryAtom(const char* name, bool start, const char* segSectName)
 {
-       
+
        const char* segSectDividor = strrchr(segSectName, '$');
        if ( segSectDividor == NULL )
                throwf("malformed section$ symbol name: %s", name);
@@ -189,8 +189,12 @@ SectionBoundaryAtom* SectionBoundaryAtom::makeSectionBoundaryAtom(const char* na
                throwf("malformed section$ symbol name: %s", name);
        char segName[18];
        strlcpy(segName, segSectName, segNameLen+1);
-       
-       const ld::Section* section = new ld::Section(strdup(segName), sectionName, ld::Section::typeUnclassified);
+
+       ld::Section::Type sectType = ld::Section::typeUnclassified;
+       if (!strcmp(segName, "__TEXT") && !strcmp(sectionName, "__thread_starts"))
+               sectType = ld::Section::typeThreadStarts;
+
+       const ld::Section* section = new ld::Section(strdup(segName), sectionName, sectType);
        return new SectionBoundaryAtom(name, *section, (start ? ld::Atom::typeSectionStart : typeSectionEnd));
 }
 
@@ -279,15 +283,7 @@ SegmentBoundaryAtom* SegmentBoundaryAtom::makeOldSegmentBoundaryAtom(const char*
 
 void Resolver::initializeState()
 {
-       // set initial objc constraint based on command line options
-       if ( _options.objcGc() )
-               _internal.objcObjectConstraint = ld::File::objcConstraintRetainReleaseOrGC;
-       else if ( _options.objcGcOnly() )
-               _internal.objcObjectConstraint = ld::File::objcConstraintGC;
-       
        _internal.cpuSubType = _options.subArchitecture();
-       _internal.minOSVersion = _options.minOSversion();
-       _internal.derivedPlatform = 0;
        
        // In -r mode, look for -linker_option additions
        if ( _options.outputKind() == Options::kObjectFile ) {
@@ -364,6 +360,10 @@ void Resolver::doFile(const ld::File& file)
                                _inputFiles.createIndirectDylibs();
                        }
                }
+               // update which form of ObjC is being used
+               if ( objFile->hasObjC() )
+                       _internal.hasObjC = true;
+
                // Resolve bitcode section in the object file
                if ( _options.bundleBitcode() ) {
                        if ( objFile->getBitcode() == NULL ) {
@@ -372,27 +372,31 @@ void Resolver::doFile(const ld::File& file)
                                        _internal.filesFromCompilerRT.push_back(objFile);
                                } else if (objFile->sourceKind() != ld::relocatable::File::kSourceLTO  ) {
                                        // No bitcode section, figure out if the object file comes from LTO/compiler static library
-                                       switch ( _options.platform() ) {
-                                       case Options::kPlatformOSX:
-                                       case Options::kPlatform_bridgeOS:
-                                       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:
-#if SUPPORT_APPLE_TV
-                                       case Options::kPlatform_tvOS:
-#endif
-                                               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;
-                                       }
+                                       _options.platforms().forEach(^(ld::Platform platform, uint32_t version, bool &stop) {
+                                               switch ( platform ) {
+                                                       case ld::kPlatform_macOS:
+                                                       case ld::kPlatform_bridgeOS:
+                                                       case ld::kPlatform_iOSMac:
+                                                       case ld::kPlatform_unknown:
+                                                               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 ld::kPlatform_iOS:
+                                                       case ld::kPlatform_iOSSimulator:
+                                                               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 ld::kPlatform_watchOS:
+                                                       case ld::kPlatform_watchOSSimulator:
+                                                       case ld::kPlatform_tvOS:
+                                                       case ld::kPlatform_tvOSSimulator:
+                                                               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;
+                                               }
+                                       });
                                }
                        } else {
                                // contains bitcode, check if it is just a marker
@@ -412,47 +416,9 @@ void Resolver::doFile(const ld::File& file)
                        }
                }
 
-               // update which form of ObjC is being used
-               switch ( file.objCConstraint() ) {
-                       case ld::File::objcConstraintNone:
-                               break;
-                       case ld::File::objcConstraintRetainRelease:
-                               if ( _internal.objcObjectConstraint == ld::File::objcConstraintGC )
-                                       throwf("%s built with incompatible Garbage Collection settings to link with previous .o files", file.path());
-                               if ( _options.objcGcOnly() )
-                                       throwf("command line specified -objc_gc_only, but file is retain/release based: %s", file.path());
-                               if ( _options.objcGc() )
-                                       throwf("command line specified -objc_gc, but file is retain/release based: %s", file.path());
-                               if ( !_options.targetIOSSimulator() && (_internal.objcObjectConstraint != ld::File::objcConstraintRetainReleaseForSimulator) )
-                                       _internal.objcObjectConstraint = ld::File::objcConstraintRetainRelease;
-                               break;
-                       case ld::File::objcConstraintRetainReleaseOrGC:
-                               if ( _internal.objcObjectConstraint == ld::File::objcConstraintNone )
-                                       _internal.objcObjectConstraint = ld::File::objcConstraintRetainReleaseOrGC;
-                               if ( _options.targetIOSSimulator() )
-                                       warning("linking ObjC for iOS Simulator, but object file (%s) was compiled for MacOSX", file.path());
-                               break;
-                       case ld::File::objcConstraintGC:
-                               if ( _internal.objcObjectConstraint == ld::File::objcConstraintRetainRelease )
-                                       throwf("%s built with incompatible Garbage Collection settings to link with previous .o files", file.path());
-                               _internal.objcObjectConstraint = ld::File::objcConstraintGC;
-                               if ( _options.targetIOSSimulator() )
-                                       warning("linking ObjC for iOS Simulator, but object file (%s) was compiled for MacOSX", file.path());
-                               break;
-                       case ld::File::objcConstraintRetainReleaseForSimulator:
-                               if ( _internal.objcObjectConstraint == ld::File::objcConstraintNone ) {
-                                       if ( !_options.targetIOSSimulator() && (_options.outputKind() != Options::kObjectFile) )
-                                               warning("ObjC object file (%s) was compiled for iOS Simulator, but linking for MacOSX", file.path());
-                                       _internal.objcObjectConstraint = ld::File::objcConstraintRetainReleaseForSimulator;
-                               }
-                               else if ( _internal.objcObjectConstraint != ld::File::objcConstraintRetainReleaseForSimulator ) {
-                                       _internal.objcObjectConstraint = ld::File::objcConstraintRetainReleaseForSimulator;
-                               }
-                               break;
-               }
-       
                // verify all files use same version of Swift language
                if ( file.swiftVersion() != 0 ) {
+                       _internal.someObjectFileHasSwift = true;
                        if ( _internal.swiftVersion == 0 ) {
                                _internal.swiftVersion = file.swiftVersion();
                        }
@@ -494,17 +460,18 @@ void Resolver::doFile(const ld::File& file)
                if ( objFile->hasllvmProfiling() )
                        _havellvmProfiling = true;
 
+#if MULTI
                // update minOSVersion off all .o files
                uint32_t objMinOS = objFile->minOSVersion();
                if ( !objMinOS )
                        _internal.objectFileFoundWithNoVersion = true;
                if ( (_options.outputKind() == Options::kObjectFile) && (objMinOS > _internal.minOSVersion) )
                        _internal.minOSVersion = objMinOS;
+#endif
 
-               uint32_t objPlatform = objFile->platform();
-               if ( (objPlatform != 0) && (_options.outputKind() == Options::kObjectFile) && (_internal.derivedPlatform == 0)  )
-                       _internal.derivedPlatform = objPlatform;
-
+               auto objPlatforms = objFile->platforms();
+               if ( (!objPlatforms.empty()) && (_options.outputKind() == Options::kObjectFile) && (_internal.derivedPlatforms.empty())  )
+                       _internal.derivedPlatforms = objPlatforms;
                // update set of known tools used
                for (const std::pair<uint32_t,uint32_t>& entry : objFile->toolVersions()) {
                        uint64_t combined = (uint64_t)entry.first << 32 | entry.second;
@@ -586,27 +553,31 @@ void Resolver::doFile(const ld::File& file)
                                if ( realpath(tempPath, tcLibPath) == NULL ||
                                         realpath(dylibFile->path(), tempPath) == NULL ||
                                         strncmp(tcLibPath, tempPath, strlen(tcLibPath)) != 0 ) {
-                                       switch ( _options.platform() ) {
-                                       case Options::kPlatformOSX:
-                                       case Options::kPlatform_bridgeOS:
-                                       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:
-#if SUPPORT_APPLE_TV
-                                       case Options::kPlatform_tvOS:
-#endif
-                                               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;
-                                       }
+                                       _options.platforms().forEach(^(ld::Platform platform, uint32_t version, bool &stop) {
+                                               switch ( platform ) {
+                                                       case ld::kPlatform_macOS:
+                                                       case ld::kPlatform_bridgeOS:
+                                                       case ld::kPlatform_iOSMac:
+                                                       case ld::kPlatform_unknown:
+                                                               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 ld::kPlatform_iOS:
+                                                       case ld::kPlatform_iOSSimulator:
+                                                               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 ld::kPlatform_watchOS:
+                                                       case ld::kPlatform_watchOSSimulator:
+                                                       case ld::kPlatform_tvOS:
+                                                       case ld::kPlatform_tvOSSimulator:
+                                                               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;
+                                               }
+                                       });
                                }
                        }
                        // Error on bitcode marker in non-system frameworks if -bitcode_verify is used
@@ -617,42 +588,21 @@ void Resolver::doFile(const ld::File& file)
                                           dylibFile->path());
                }
 
-               // update which form of ObjC dylibs are being linked
-               switch ( dylibFile->objCConstraint() ) {
-                       case ld::File::objcConstraintNone:
-                               break;
-                       case ld::File::objcConstraintRetainRelease:
-                               if ( _internal.objcDylibConstraint == ld::File::objcConstraintGC )
-                                       throwf("%s built with incompatible Garbage Collection settings to link with previous dylibs", file.path());
-                               if ( _options.objcGcOnly() )
-                                       throwf("command line specified -objc_gc_only, but dylib is retain/release based: %s", file.path());
-                               if ( _options.objcGc() )
-                                       throwf("command line specified -objc_gc, but dylib is retain/release based: %s", file.path());
-                               if ( _options.targetIOSSimulator() )
-                                       warning("linking ObjC for iOS Simulator, but dylib (%s) was compiled for MacOSX", file.path());
-                               _internal.objcDylibConstraint = ld::File::objcConstraintRetainRelease;
-                               break;
-                       case ld::File::objcConstraintRetainReleaseOrGC:
-                               if ( _internal.objcDylibConstraint == ld::File::objcConstraintNone )
-                                       _internal.objcDylibConstraint = ld::File::objcConstraintRetainReleaseOrGC;
-                               if ( _options.targetIOSSimulator() )
-                                       warning("linking ObjC for iOS Simulator, but dylib (%s) was compiled for MacOSX", file.path());
-                               break;
-                       case ld::File::objcConstraintGC:
-                               if ( _internal.objcDylibConstraint == ld::File::objcConstraintRetainRelease )
-                                       throwf("%s built with incompatible Garbage Collection settings to link with previous dylibs", file.path());
-                               if ( _options.targetIOSSimulator() )
-                                       warning("linking ObjC for iOS Simulator, but dylib (%s) was compiled for MacOSX", file.path());
-                               _internal.objcDylibConstraint = ld::File::objcConstraintGC;
-                               break;
-                       case ld::File::objcConstraintRetainReleaseForSimulator:
-                               if ( _internal.objcDylibConstraint == ld::File::objcConstraintNone )
-                                       _internal.objcDylibConstraint = ld::File::objcConstraintRetainReleaseForSimulator;
-                               else if ( _internal.objcDylibConstraint != ld::File::objcConstraintRetainReleaseForSimulator ) {
-                                       warning("ObjC dylib (%s) was compiled for iOS Simulator, but dylibs others were compiled for MacOSX", file.path());
-                                       _internal.objcDylibConstraint = ld::File::objcConstraintRetainReleaseForSimulator;
+               // Don't allow swift frameworks to link other swift frameworks.
+               if ( !_internal.firstSwiftDylibFile && _options.outputKind() == Options::kDynamicLibrary
+                       && file.swiftVersion() != 0 && getenv("LD_DISALLOW_SWIFT_LINKING_SWIFT")) {
+                       // Check that we aren't a whitelisted path.
+                       bool inWhiteList = false;
+                       const char *whitelistedPaths[] = { "/System/Library/PrivateFrameworks/Swift" };
+                       for (auto whitelistedPath : whitelistedPaths) {
+                               if (!strncmp(whitelistedPath, dylibFile->installPath(), strlen(whitelistedPath))) {
+                                       inWhiteList = true;
+                                       break;
                                }
-                               break;
+                       }
+                       if (!inWhiteList) {
+                               _internal.firstSwiftDylibFile = dylibFile;
+                       }
                }
 
                // <rdar://problem/25680358> verify dylibs use same version of Swift language
@@ -692,9 +642,9 @@ void Resolver::doFile(const ld::File& file)
                const char* depInstallName = dylibFile->installPath();
                // <rdar://problem/17229513> embedded frameworks are only supported on iOS 8 and later
                if ( (depInstallName != NULL) && (depInstallName[0] != '/') ) {
-                       if ( (_options.iOSVersionMin() != iOSVersionUnset) && (_options.iOSVersionMin() < iOS_8_0) ) {
+                       if ( _options.platforms().contains(ld::kPlatform_iOS) && !_options.platforms().minOS(iOS_8_0) ) {
                                // <rdar://problem/17598404> only warn about linking against embedded dylib if it is built for iOS 8 or later
-                               if ( dylibFile->minOSVersion() >= iOS_8_0 )
+                               if ( dylibFile->platforms().minOS(ld::iOS_8_0) )
                                        throwf("embedded dylibs/frameworks are only supported on iOS 8.0 and later (%s)", depInstallName);
                        }
                }
@@ -709,7 +659,6 @@ void Resolver::doFile(const ld::File& file)
                        }
                }
        }
-
 }
 
 void Resolver::doAtom(const ld::Atom& atom)
@@ -1076,6 +1025,9 @@ void Resolver::markLive(const ld::Atom& atom, WhyLiveBackChain* previous)
                        case ld::Fixup::kindSubtractTargetAddress:
                        case ld::Fixup::kindStoreTargetAddressLittleEndian32:
                        case ld::Fixup::kindStoreTargetAddressLittleEndian64:
+#if SUPPORT_ARCH_arm64e
+                       case ld::Fixup::kindStoreTargetAddressLittleEndianAuth64:
+#endif
                        case ld::Fixup::kindStoreTargetAddressBigEndian32:
                        case ld::Fixup::kindStoreTargetAddressBigEndian64:
                        case ld::Fixup::kindStoreTargetAddressX86PCRel32:
@@ -1507,6 +1459,10 @@ void Resolver::checkUndefines(bool force)
        int unresolvableExportsCount = 0;
        if ( unresolvableCount != 0 ) {
                if ( doPrint ) {
+                       for (const auto& lib : _internal.missingLinkerOptionLibraries)
+                               warning("Could not find auto-linked library '%s'", lib);
+                       for (const auto& frm : _internal.missingLinkerOptionFrameworks)
+                               warning("Could not find auto-linked framework '%s'", frm);
                        if ( _options.printArchPrefix() )
                                fprintf(stderr, "Undefined symbols for architecture %s:\n", _options.architectureName());
                        else
@@ -1663,6 +1619,7 @@ void Resolver::fillInHelpersInInternalState()
        }
        
        _internal.classicBindingHelper = NULL;
+       // FIXME: What about fMakeThreadedStartsSection?
        if ( needsStubHelper && !_options.makeCompressedDyldInfo() ) { 
                // "dyld_stub_binding_helper" comes from .o file, so should already exist in symbol table
                if ( _symbolTable.hasName("dyld_stub_binding_helper") ) {
@@ -1683,6 +1640,7 @@ void Resolver::fillInHelpersInInternalState()
        }
        
        _internal.compressedFastBinderProxy = NULL;
+       // FIXME: What about fMakeThreadedStartsSection?
        if ( needsStubHelper && _options.makeCompressedDyldInfo() ) { 
                // "dyld_stub_binder" comes from libSystem.dylib so will need to manually resolve
                if ( !_symbolTable.hasName("dyld_stub_binder") ) {
@@ -1713,6 +1671,11 @@ void Resolver::fillInInternalState()
        // <rdar://problem/7783918> make sure there is a __text section so that codesigning works
        if ( (_options.outputKind() == Options::kDynamicLibrary) || (_options.outputKind() == Options::kDynamicBundle) )
                _internal.getFinalSection(*new ld::Section("__TEXT", "__text", ld::Section::typeCode));
+
+       // Don't allow swift frameworks to link other swift frameworks.
+       if ( _internal.someObjectFileHasSwift && _internal.firstSwiftDylibFile != nullptr )
+               throwf("linking swift frameworks against other swift frameworks (%s) is not permitted",
+                          _internal.firstSwiftDylibFile->path());
 }
 
 void Resolver::fillInEntryPoint()
@@ -1782,6 +1745,7 @@ void Resolver::linkTimeOptimize()
        optOpt.outputFilePath                           = _options.outputFilePath();
        optOpt.tmpObjectFilePath                        = _options.tempLtoObjectPath();
        optOpt.ltoCachePath                                     = _options.ltoCachePath();
+       optOpt.ltoPruneIntervalOverwrite        = _options.ltoPruneIntervalOverwrite();
        optOpt.ltoPruneInterval                         = _options.ltoPruneInterval();
        optOpt.ltoPruneAfter                            = _options.ltoPruneAfter();
        optOpt.ltoMaxCacheSize                          = _options.ltoMaxCacheSize();
@@ -1802,12 +1766,14 @@ void Resolver::linkTimeOptimize()
        optOpt.armUsesZeroCostExceptions    = _options.armUsesZeroCostExceptions();
        optOpt.simulator                                        = _options.targetIOSSimulator();
        optOpt.ignoreMismatchPlatform           = ((_options.outputKind() == Options::kPreload) || (_options.outputKind() == Options::kStaticExecutable));
+#if SUPPORT_ARCH_arm64e
+       optOpt.supportsAuthenticatedPointers = _options.supportsAuthenticatedPointers();
+#endif
        optOpt.bitcodeBundle                            = (_options.bundleBitcode() && (_options.bitcodeKind() != Options::kBitcodeMarker));
        optOpt.maxDefaultCommonAlignment        = _options.maxDefaultCommonAlign();
        optOpt.arch                                                     = _options.architecture();
        optOpt.mcpu                                                     = _options.mcpuLTO();
-       optOpt.platform                                         = _options.platform();
-       optOpt.minOSVersion                                     = _options.minOSversion();
+       optOpt.platforms                                        = _options.platforms();
        optOpt.llvmOptions                                      = &_options.llvmOptions();
        optOpt.initialUndefines                         = &_options.initialUndefines();
        
index 27ce370e2beac70c110e5ec3310c0df37b066e61..a8060f50f071eb782fa5fdb63196e4fa0e66973b 100644 (file)
@@ -8,6 +8,7 @@
 
 #include <string.h>
 #include <unistd.h>
+#include <errno.h>
 #include <stdio.h>
 #include <limits.h>
 #include <fcntl.h>
 static const char *frameworksString         = "frameworks";         // directory containing framework stubs (mach-o files)
 static const char *dylibsString             = "dylibs";             // directory containing dylib stubs (mach-o files)
 static const char *archiveFilesString       = "archive_files";      // directory containing .a files
-static const char *origCommandLineString    = "orig_command_line";  // text file containing the original command line
-static const char *linkCommandString        = "link_command";       // text file containing the snapshot equivalent command line
-static const char *dataFilesString          = "data_files";         // arbitrary data files referenced on the command line
 static const char *objectsString            = "objects";            // directory containing object files
 static const char *frameworkStubsString     = "framework_stubs";    // directory containing framework stub info (text files)
+static const char *dataFilesString          = "data_files";         // arbitrary data files referenced on the command line
 static const char *dylibStubsString         = "dylib_stubs";        // directory containing dylib stub info (text files)
+static const char *filesString              = "files";              // directory containing files
+static const char *origCommandLineString    = "orig_command_line";  // text file containing the original command line
+static const char *linkCommandString        = "link_command";       // text file containing the snapshot equivalent command line
 static const char *assertFileString         = "assert_info";        // text file containing assertion failure logs
 static const char *compileFileString        = "compile_stubs";      // text file containing compile_stubs script
 
 Snapshot *Snapshot::globalSnapshot = NULL;
 
-Snapshot::Snapshot() : fRecordArgs(false), fRecordObjects(false), fRecordDylibSymbols(false), fRecordArchiveFiles(false), fRecordUmbrellaFiles(false), fRecordDataFiles(false), fFrameworkArgAdded(false), fSnapshotLocation(NULL), fSnapshotName(NULL), fRootDir(NULL), fFilelistFile(-1), fCopiedArchives(NULL) 
+Snapshot::Snapshot(const Options * opts) : fOptions(opts), fRecordArgs(false), fRecordObjects(false), fRecordDylibSymbols(false), fRecordArchiveFiles(false), fRecordUmbrellaFiles(false), fRecordDataFiles(false), fFrameworkArgAdded(false), fRecordKext(false), fSnapshotLocation(NULL), fSnapshotName(NULL), fRootDir(NULL), fFilelistFile(-1), fCopiedArchives(NULL)
 {
     if (globalSnapshot != NULL)
         throw "only one snapshot supported";
@@ -64,6 +66,11 @@ void Snapshot::setSnapshotPath(const char *path)
 
 void Snapshot::setSnapshotMode(SnapshotMode mode) 
 {
+    if (fRootDir == NULL) {
+        // free stuff
+        fRootDir = NULL;
+    }
+
     if (fRootDir == NULL) {
         fRecordArgs = false;
         fRecordObjects = false;
@@ -71,29 +78,52 @@ void Snapshot::setSnapshotMode(SnapshotMode mode)
         fRecordArchiveFiles = false;
         fRecordUmbrellaFiles = false;
         fRecordDataFiles = false;
-        
+        fRecordKext = false;
+
         switch (mode) {
             case SNAPSHOT_DISABLED:
                 break;
             case SNAPSHOT_DEBUG:
                 fRecordArgs = fRecordObjects = fRecordDylibSymbols = fRecordArchiveFiles = fRecordUmbrellaFiles = fRecordDataFiles = true;
                 break;
+            case SNAPSHOT_KEXT:
+                fRecordKext = fRecordArgs = fRecordObjects = fRecordDylibSymbols = fRecordArchiveFiles = fRecordUmbrellaFiles = fRecordDataFiles = true;
+                break;
             default:
                 break;
         }
     }
 }
 
-void Snapshot::setSnapshotName(const char *path)
+void Snapshot::setOutputPath(const char *path)
+{
+    fOutputPath = strdup(path);
+}
+
+void Snapshot::setSnapshotName()
 {
     if (fRootDir == NULL) {
-        const char *base = basename((char *)path);
-        time_t now = time(NULL);
-        struct tm t;
-        localtime_r(&now, &t);
-        char buf[PATH_MAX];
-        snprintf(buf, sizeof(buf)-1, "%s-%4.4d-%2.2d-%2.2d-%2.2d%2.2d%2.2d.ld-snapshot", base, t.tm_year+1900, t.tm_mon, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec);
-        fSnapshotName = strdup(buf);
+        if (fOutputPath == NULL) {
+            fSnapshotName = strdup("ld_snapshot");
+        } else {
+            const char *base = basename((char *)fOutputPath);
+            if (fRecordKext) {
+                const char *kextobjects;
+                if ((kextobjects = fOptions->kextObjectsPath())) {
+                    fSnapshotLocation = strdup(kextobjects);
+                } else {
+                    fSnapshotLocation = strdup(dirname((char *)fOutputPath));
+                }
+                asprintf((char **)&fSnapshotName, "%s.%s.ld", base, fArchString);
+            } else {
+                time_t now = time(NULL);
+                struct tm t;
+                localtime_r(&now, &t);
+                char buf[PATH_MAX];
+                snprintf(buf, sizeof(buf)-1, "%s-%4.4d-%2.2d-%2.2d-%2.2d%2.2d%2.2d.ld-snapshot", base, t.tm_year+1900, t.tm_mon, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec);
+                fSnapshotName = strdup(buf);
+            }
+        }
     }
 }
 
@@ -111,7 +141,8 @@ void Snapshot::buildPath(char *buf, const char *subdir, const char *file)
     if (subdir) {
         strcat(buf, subdir);
         // implicitly create the subdirectory
-        mkdir(buf, S_IRUSR|S_IWUSR|S_IXUSR);
+        mode_t mode = fRecordKext ? (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH) : (S_IRUSR|S_IWUSR|S_IXUSR);
+        mkdir(buf, mode);
         strcat(buf, "/");
     }
     if (file != NULL)
@@ -127,7 +158,7 @@ void Snapshot::buildUniquePath(char *buf, const char *subdir, const char *file)
 {
     buildPath(buf, subdir, file);
     struct stat st;
-    if (stat(buf, &st)==0) {
+    if (!fRecordKext && (stat(buf, &st)==0)) {
         // make it unique
         int counter=1;
         char *number = strrchr(buf, 0);
@@ -139,6 +170,13 @@ void Snapshot::buildUniquePath(char *buf, const char *subdir, const char *file)
     }
 }
 
+const char * Snapshot::subdir(const char *subdir)
+{
+    if (fRecordKext) {
+        return filesString;
+    }
+    return subdir;
+}
 
 // Copy a file to the snapshot.
 // sourcePath is the original file
@@ -149,6 +187,23 @@ void Snapshot::copyFileToSnapshot(const char *sourcePath, const char *subdir, ch
 {
     const int copyBufSize=(1<<14); // 16kb buffer
     static void *copyBuf = NULL;
+    bool inSdk;
+
+    if (fRecordKext) {
+        for (const char* sdkPath : fOptions->sdkPaths()) {
+            const char *toolchainPath;
+            inSdk = (!strncmp(sdkPath, sourcePath, strlen(sdkPath)));
+            if (!inSdk && (toolchainPath = fOptions->toolchainPath()))
+                inSdk = (!strncmp(toolchainPath, sourcePath, strlen(toolchainPath)));
+            if (inSdk) {
+                if (path) {
+                    strcpy(path, sourcePath);
+                }
+                return;
+            }
+        }
+    }
+
     if (copyBuf == NULL)
         copyBuf = malloc(copyBufSize);
     
@@ -156,7 +211,8 @@ void Snapshot::copyFileToSnapshot(const char *sourcePath, const char *subdir, ch
     char buf[PATH_MAX];
     if (path == NULL) path = buf;
     buildUniquePath(path, subdir, file);
-    int out_fd = open(path, O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR);
+    mode_t mode = fRecordKext ? (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) : (S_IRUSR|S_IWUSR);
+    int out_fd = open(path, O_WRONLY|O_CREAT|O_TRUNC, mode);
     int in_fd = open(sourcePath, O_RDONLY);
     int len;
     if (out_fd != -1 && in_fd != -1) {
@@ -167,34 +223,42 @@ void Snapshot::copyFileToSnapshot(const char *sourcePath, const char *subdir, ch
     }
     close(in_fd);
     close(out_fd);
-}
 
+    const char * relPath = snapshotRelativePath(path);
+    memmove(path, relPath, 1+strlen(relPath));
+}
 
 // Create the snapshot root directory.
 void Snapshot::createSnapshot()
 {
     if (fRootDir == NULL) {
+
+        mode_t mask = umask(0);
+
         // provide default name and location
+        setSnapshotName();
         if (fSnapshotLocation == NULL)
             fSnapshotLocation = "/tmp";        
-        if (fSnapshotName == NULL) {
-            setSnapshotName("ld_snapshot");
-        }
-        
+
         char buf[PATH_MAX];
         fRootDir = (char *)fSnapshotLocation;
         buildUniquePath(buf, NULL, fSnapshotName);
         fRootDir = strdup(buf);
-        if (mkdir(fRootDir, S_IRUSR|S_IWUSR|S_IXUSR)!=0) {
+
+        int mkpatherr = mkpath_np(fRootDir, (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH|S_IXUSR|S_IXGRP|S_IXOTH));
+        if ((mkpatherr!=0) && !(fRecordKext && (mkpatherr==EEXIST))) {
             warning("unable to create link snapshot directory: %s", fRootDir);
             fRootDir = NULL;
             setSnapshotMode(SNAPSHOT_DISABLED); // don't try to write anything if we can't create snapshot dir
         }
-        
-        buildPath(buf, NULL, compileFileString);
-        int compileScript = open(buf, O_WRONLY|O_CREAT|O_TRUNC, S_IXUSR|S_IRUSR|S_IWUSR);
-        write(compileScript, compile_stubs, strlen(compile_stubs));
-        close(compileScript);
+
+        if (!fRecordKext) {
+            buildPath(buf, NULL, compileFileString);
+            mode_t mode = fRecordKext ? (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) : (S_IXUSR|S_IRUSR|S_IWUSR);
+            int compileScript = open(buf, O_WRONLY|O_CREAT|O_TRUNC, mode);
+            write(compileScript, compile_stubs, strlen(compile_stubs));
+            close(compileScript);
+        }
 
         SnapshotLog::iterator it;
         for (it = fLog.begin(); it != fLog.end(); it++) {
@@ -205,50 +269,76 @@ void Snapshot::createSnapshot()
         fLog.erase(fLog.begin(), fLog.end());
         
         if (fRecordArgs) {
-            writeCommandLine(fRawArgs, origCommandLineString, true);
-            writeCommandLine(fArgs);
+            writeCommandLine(true);
+            writeCommandLine();
         }
         
 #if STORE_PID_IN_SNAPSHOT
         char path[PATH_MAX];
         buildUniquePath(path, NULL, pidString);
-        int pidfile = open(path, O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR);
+        mode = fRecordKext ? (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) : (S_IRUSR|S_IWUSR);
+        int pidfile = open(path, O_WRONLY|O_CREAT|O_TRUNC, mode);
         char pid_buf[32];
         sprintf(pid_buf, "%lu\n", (long unsigned)getpid());
         write(pidfile, pid_buf, strlen(pid_buf));
         write(pidfile, "\n", 1);
         close(pidfile);    
 #endif
-        
+        umask(mask);
     }
 }
 
 
 // Write the current command line vector to filename.
-void Snapshot::writeCommandLine(StringVector &args, const char *filename, bool includeCWD) 
+void Snapshot::writeCommandLine(bool rawArgs)
 {
+    StringVector &args = rawArgs ? fRawArgs : fArgs;
+    const char *filename;
+
+    if (rawArgs) {
+        args = fRawArgs;
+        filename = origCommandLineString;
+    } else {
+        args = fArgs;
+        filename = linkCommandString;
+    }
+
     if (!isLazy() && fRecordArgs) {
-        // Figure out the file name and open it.
-        if (filename == NULL)
-            filename = linkCommandString;
+        // Open the file
         char path[PATH_MAX];
         buildPath(path, NULL, filename);
-        int argsFile = open(path, O_WRONLY|O_CREAT|O_TRUNC, S_IXUSR|S_IRUSR|S_IWUSR);
+
+        mode_t mode = fRecordKext ? (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) : (S_IXUSR|S_IRUSR|S_IWUSR);
+        int argsFile = open(path, O_WRONLY|O_CREAT|O_TRUNC, mode);
         FILE *argsStream = fdopen(argsFile, "w");
         
-        if (includeCWD)
+        if (rawArgs)
             fprintf(argsStream, "cd %s\n", getcwd(path, sizeof(path)));
 
         // iterate to write args, quoting as needed
-        StringVector::iterator it;
-        for (it = args.begin(); it != args.end(); it++) {
-            const char *arg = *it;
+        unsigned idx;
+        unsigned idxidx;
+        bool inner = false;
+
+        for (idx = idxidx = 0; idx < args.size(); idx++) {
+            const char *arg = args[idx];
             bool needQuotes = false;
+
+            if (fRecordKext && !rawArgs) {
+                if (idx == fArgIndicies[idxidx]) {
+                    idxidx++;
+                    if (idx > 0) {
+                        fprintf(argsStream, "\n");
+                        inner = false;
+                    }
+                }
+            }
             for (const char *c = arg; *c != 0 && !needQuotes; c++) {
                 if (isspace(*c))
                     needQuotes = true;
             }
-            if (it != args.begin()) fprintf(argsStream, " ");
+            if (inner) fprintf(argsStream, " ");
+            inner = true;
             if (needQuotes) fprintf(argsStream, "\"");
             fprintf(argsStream, "%s", arg);
             if (needQuotes) fprintf(argsStream, "\"");
@@ -266,7 +356,9 @@ void Snapshot::recordRawArgs(int argc, const char *argv[])
     for (int i=0; i<argc; i++) {
         fRawArgs.push_back(argv[i]);
     }
+    fArgIndicies.push_back(fArgs.size());
     fArgs.insert(fArgs.begin(), argv[0]);
+    fArgIndicies.push_back(fArgs.size());
     fArgs.insert(fArgs.begin()+1, "-Z"); // don't search standard paths when running in the snapshot
 }
 
@@ -282,14 +374,14 @@ void Snapshot::addSnapshotLinkArg(int argIndex, int argCount, int fileArg)
         fLog.push_back(Block_copy(^{ this->addSnapshotLinkArg(argIndex, argCount, fileArg); }));
     } else {
         char buf[PATH_MAX];
-        const char *subdir = dataFilesString;
+        fArgIndicies.push_back(fArgs.size());
         for (int i=0, arg=argIndex; i<argCount && argIndex+1<(int)fRawArgs.size(); i++, arg++) {
             if (i != fileArg) {
                 fArgs.push_back(fRawArgs[arg]);
             } else {
                 if (fRecordDataFiles) {
-                    copyFileToSnapshot(fRawArgs[arg], subdir, buf);
-                    fArgs.push_back(strdup(snapshotRelativePath(buf)));
+                    copyFileToSnapshot(fRawArgs[arg], subdir(dataFilesString), buf);
+                    fArgs.push_back(strdup(buf));
                 } else {
                     // if we don't copy the file then just record the original path
                     fArgs.push_back(strdup(fRawArgs[arg]));
@@ -306,7 +398,9 @@ void Snapshot::recordArch(const char *arch)
     if (fRawArgs.size() == 0)
         throw "raw args not set";
 
-    // only need to store the arch explicitly if it is not mentioned on the command line
+    fArchString = strdup(arch);
+
+    // only need to add the arch argument explicitly if it is not mentioned on the command line
     bool archInArgs = false;
     StringVector::iterator it;
     for (it = fRawArgs.begin(); it != fRawArgs.end() && !archInArgs; it++) {
@@ -321,7 +415,8 @@ void Snapshot::recordArch(const char *arch)
         } else {
             char path_buf[PATH_MAX];
             buildUniquePath(path_buf, NULL, "arch");
-            int fd=open(path_buf, O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR);
+            mode_t mode = fRecordKext ? (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) : (S_IRUSR|S_IWUSR);
+            int fd=open(path_buf, O_WRONLY|O_CREAT|O_TRUNC, mode);
             write(fd, arch, strlen(arch));
             close(fd);
         }
@@ -339,21 +434,27 @@ void Snapshot::recordObjectFile(const char *path)
     } else {
         if (fRecordObjects) {
                        char path_buf[PATH_MAX];
-                       copyFileToSnapshot(path, objectsString, path_buf);
+                       copyFileToSnapshot(path, subdir(objectsString), path_buf);
             
             // lazily open the filelist file
             if (fFilelistFile == -1) {
                 char filelist_path[PATH_MAX];
-                buildUniquePath(filelist_path, objectsString, "filelist");
-                fFilelistFile = open(filelist_path, O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR);
-                fArgs.push_back("-filelist");
-                fArgs.push_back(strdup(snapshotRelativePath(filelist_path)));
-                writeCommandLine(fArgs);
+                const char * dir;
+                dir = (fRecordKext ? NULL : subdir(objectsString));
+                buildUniquePath(filelist_path, dir, "filelist");
+                mode_t mode = fRecordKext ? (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) : (S_IRUSR|S_IWUSR);
+                fFilelistFile = open(filelist_path, O_WRONLY|O_CREAT|O_TRUNC, mode);
+
+                if (!fRecordKext) {
+                    fArgIndicies.push_back(fArgs.size());
+                    fArgs.push_back("-filelist");
+                    fArgs.push_back(strdup(snapshotRelativePath(filelist_path)));
+                    writeCommandLine();
+                }
             }
             
             // record the snapshot path in the filelist
-            const char *relative_path = snapshotRelativePath(path_buf);
-            write(fFilelistFile, relative_path, strlen(relative_path));
+            write(fFilelistFile, path_buf, strlen(path_buf));
             write(fFilelistFile, "\n", 1);
         }
     }
@@ -369,11 +470,13 @@ void Snapshot::addFrameworkArg(const char *framework)
     if (!found) {
         if (!fFrameworkArgAdded) {
             fFrameworkArgAdded = true;
+            fArgIndicies.push_back(fArgs.size());
             fArgs.push_back("-Fframeworks");
         }
+        fArgIndicies.push_back(fArgs.size());
         fArgs.push_back("-framework");
         fArgs.push_back(strdup(framework));
-        writeCommandLine(fArgs);
+        writeCommandLine();
     }
 }
 
@@ -386,9 +489,10 @@ void Snapshot::addDylibArg(const char *dylib)
     }
     if (!found) {
         char buf[ARG_MAX];
-        sprintf(buf, "%s/%s", dylibsString, dylib);
+        sprintf(buf, "%s/%s", subdir(dylibsString), dylib);
+        fArgIndicies.push_back(fArgs.size());
         fArgs.push_back(strdup(buf));
-        writeCommandLine(fArgs);
+        writeCommandLine();
     }
 }
 
@@ -403,14 +507,17 @@ void Snapshot::recordDylibSymbol(ld::dylib::File* dylibFile, const char *name)
             // find the dylib in the table
             DylibMap::iterator it;
             const char *dylibPath = dylibFile->path();
+
             it = fDylibSymbols.find(dylibPath);
             bool isFramework = (strstr(dylibPath, "framework") != NULL);
             int dylibFd;
             if (it == fDylibSymbols.end()) {
                 // Didn't find a file descriptor for this dylib. Create one and add it to the dylib map.
                 char path_buf[PATH_MAX];
-                buildUniquePath(path_buf, isFramework ? frameworkStubsString : dylibStubsString, dylibPath);
-                dylibFd = open(path_buf, O_WRONLY|O_APPEND|O_CREAT, S_IRUSR|S_IWUSR);
+                buildUniquePath(path_buf, subdir(isFramework ? frameworkStubsString : dylibStubsString), dylibPath);
+
+                mode_t mode = fRecordKext ? (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) : (S_IRUSR|S_IWUSR);
+                dylibFd = open(path_buf, O_WRONLY|O_APPEND|O_CREAT, mode);
                 fDylibSymbols.insert(std::pair<const char *, int>(dylibPath, dylibFd));
                 char *base_name = strdup(basename(path_buf));
                 if (isFramework) {
@@ -418,7 +525,7 @@ void Snapshot::recordDylibSymbol(ld::dylib::File* dylibFile, const char *name)
                 } else {
                     addDylibArg(base_name);
                 }
-                writeCommandLine(fArgs);
+                writeCommandLine();
             } else {
                 dylibFd = it->second;
             }
@@ -458,6 +565,7 @@ void Snapshot::recordArchive(const char *archiveFile)
         fLog.push_back(Block_copy(^{ this->recordArchive(archiveFile); ::free((void *)copy); }));
     } else {
         if (fRecordArchiveFiles) {
+
             // lazily create a vector of .a files that have been added
             if (fCopiedArchives == NULL) {
                 fCopiedArchives = new StringVector;
@@ -475,9 +583,15 @@ void Snapshot::recordArchive(const char *archiveFile)
             if (!found) {
                 char path[PATH_MAX];
                 fCopiedArchives->push_back(archiveFile);
-                copyFileToSnapshot(archiveFile, archiveFilesString, path);
-                fArgs.push_back(strdup(snapshotRelativePath(path)));
-                writeCommandLine(fArgs);
+
+                if (fRecordKext) {
+                    recordObjectFile(archiveFile);
+                } else {
+                    copyFileToSnapshot(archiveFile, subdir(archiveFilesString), path);
+                    fArgIndicies.push_back(fArgs.size());
+                    fArgs.push_back(strdup(path));
+                    writeCommandLine();
+                }
             }
         }
     }
@@ -492,7 +606,7 @@ void Snapshot::recordSubUmbrella(const char *frameworkPath)
         if (fRecordUmbrellaFiles) {
             const char *framework = basename((char *)frameworkPath);
             char buf[PATH_MAX], wrapper[PATH_MAX];
-            strcpy(wrapper, frameworksString);
+            strcpy(wrapper, subdir(frameworksString));
             buildPath(buf, wrapper, NULL); // ensure the frameworks directory exists
             strcat(wrapper, "/");
             strcat(wrapper, framework);
@@ -510,7 +624,7 @@ void Snapshot::recordSubLibrary(const char *dylibPath)
         fLog.push_back(Block_copy(^{ this->recordSubLibrary(copy); ::free((void *)copy); }));
     } else {
         if (fRecordUmbrellaFiles) {
-            copyFileToSnapshot(dylibPath, dylibsString);
+            copyFileToSnapshot(dylibPath, subdir(dylibsString));
             addDylibArg(basename((char *)dylibPath));
         }
     }
@@ -529,7 +643,8 @@ void Snapshot::recordAssertionMessage(const char *fmt, ...)
         } else {
             char path[PATH_MAX];
             buildPath(path, NULL, assertFileString);
-            int log = open(path, O_WRONLY|O_APPEND|O_CREAT, S_IRUSR|S_IWUSR);
+            mode_t mode = fRecordKext ? (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) : (S_IRUSR|S_IWUSR);
+            int log = open(path, O_WRONLY|O_APPEND|O_CREAT, mode);
             write(log, msg, strlen(msg));
             close(log);
             free(msg);
index 8cfd17e07ace33037748e13abd1b66c51bc1d788..800852f17d867a180c15b8251438cc29f9b143c4 100644 (file)
@@ -26,9 +26,10 @@ public:
     typedef enum { 
         SNAPSHOT_DISABLED, // nothing is recorded
         SNAPSHOT_DEBUG, // records: .o, .dylib, .framework, .a, and other data files
+        SNAPSHOT_KEXT, // records: .o, .a, and other data files
     } SnapshotMode;
     
-    Snapshot();
+    Snapshot(const Options * opts);
     ~Snapshot();
     
     // Control the data captured in the snapshot
@@ -36,7 +37,7 @@ public:
     
     // Use the basename of path to construct the snapshot name.
     // Must be called prior to createSnapshot().
-    void setSnapshotName(const char *path);
+    void setOutputPath(const char *path);
     
     // Set the directory in which the snapshot will be created.
     // Must be called prior to createSnapshot().
@@ -96,12 +97,18 @@ private:
     typedef std::vector<const char *> StringVector;
     typedef std::map<const char *, int, strcompclass > DylibMap;
     typedef std::map<const char *, const char *, strcompclass> PathMap;
-
+    typedef std::vector<unsigned> IntVector;
     
     // Write the current contents of the args vector to a file in the snapshot.
     // If filename is NULL then "link_command" is used.
     // This is used to write both the original and the "cooked" versions of the link command
-    void writeCommandLine(StringVector &args, const char *filename=NULL, bool includeCWD=false);
+    void writeCommandLine(bool rawArgs=false);
+
+    //
+    void setSnapshotName();
+
+    //
+    const char * subdir(const char *subdir);
 
     // Construct a path in the snapshot.
     // buf is a sring buffer in which the path is constructed
@@ -128,6 +135,7 @@ private:
     void addFrameworkArg(const char *framework);
     void addDylibArg(const char *dylib);
 
+    const Options * fOptions;
     SnapshotLog fLog;           // log of events that recorded data in a snapshot prior to createSnapshot()
     bool fRecordArgs;           // record command line 
     bool fRecordObjects;        // record .o files 
@@ -136,14 +144,18 @@ private:
     bool fRecordUmbrellaFiles;  // record re-exported sub frameworks/dylibs
     bool fRecordDataFiles;      // record other data files
     bool fFrameworkArgAdded;
+    bool fRecordKext;
 
     const char *fSnapshotLocation; // parent directory of frootDir
     const char *fSnapshotName;    // a string to use in constructing the snapshot name
+    const char *fOutputPath;    // -o path
     char *fRootDir;             // root directory of the snapshot
+    const char *fArchString;
     int fFilelistFile;          // file descriptor to the open text file used for the -filelist
 
     StringVector fRawArgs;      // stores the raw command line args
     StringVector fArgs;         // stores the "cooked" command line args
+    IntVector fArgIndicies;     // where args start in fArgs
     PathMap fPathMap;           // mapping of original paths->snapshot paths for copied files
     
     DylibMap fDylibSymbols;    // map of dylib names to string vector containing referenced symbol names
index e0830ab7cb106e1ae36089292c58794088b661d9..87c58a5e35f3bce5d0a849a12b85ddf2fbcb805a 100644 (file)
@@ -76,6 +76,7 @@ extern "C" double log2 ( double );
 #include "passes/compact_unwind.h"
 #include "passes/order.h"
 #include "passes/branch_island.h"
+#include "passes/thread_starts.h"
 #include "passes/branch_shim.h"
 #include "passes/objc.h"
 #include "passes/dylibs.h"
@@ -88,6 +89,7 @@ extern "C" double log2 ( double );
 #include "parsers/lto_file.h"
 #include "parsers/opaque_section_file.h"
 
+const ld::VersionSet ld::File::_platforms;
 
 struct PerformanceStatistics {
        uint64_t                                                startTool;
@@ -125,7 +127,6 @@ private:
        {
        public:
                                                                        FinalSection(const ld::Section& sect, uint32_t sectionsSeen, const Options&);
-               static int                                      sectionComparer(const void* l, const void* r);
                static const ld::Section&       outputSection(const ld::Section& sect, bool mergeZeroFill);
                static const ld::Section&       objectOutputSection(const ld::Section& sect, const Options&);
        private:
@@ -363,6 +364,8 @@ uint32_t InternalState::FinalSection::sectionOrder(const ld::Section& sect, uint
                                return 12;
                        case ld::Section::typeStubHelper:
                                return 13;
+                       case ld::Section::typeThreadStarts:
+                               return INT_MAX-5;
                        case ld::Section::typeLSDA:
                                return INT_MAX-4;
                        case ld::Section::typeUnwindInfo:
@@ -435,6 +438,8 @@ uint32_t InternalState::FinalSection::sectionOrder(const ld::Section& sect, uint
                                        return 32;
                                else if ( strcmp(sect.sectionName(), "__objc_data") == 0 ) 
                                        return 33;
+                               else if ( strcmp(sect.sectionName(), "__objc_const_ax") == 0 )
+                                       return 34;
                                else
                                        return sectionsSeen+40;
                }
@@ -663,6 +668,7 @@ ld::Internal::FinalSection* InternalState::addAtom(const ld::Atom& atom)
                        if ( (sectType != ld::Section::typeZeroFill) 
                          && (sectType != ld::Section::typeUnclassified) 
                          && (sectType != ld::Section::typeTentativeDefs)
+                         && (sectType != ld::Section::typeTLVDefs)
                          && (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);
@@ -688,6 +694,26 @@ ld::Internal::FinalSection* InternalState::addAtom(const ld::Atom& atom)
                        }
                }
        }
+       else if ( atom.symbolTableInclusion() == ld::Atom::symbolTableNotInFinalLinkedImages ) {
+               const char* symName = atom.name();
+               if ( strncmp(symName, "l_OBJC_$_INSTANCE_METHODS_", 26) == 0 ) {
+                       if ( _options.moveAXMethodList(&symName[26]) ) {
+                               curSectName  = "__objc_const_ax";
+                               fs = this->getFinalSection(curSegName, curSectName, sectType);
+                               if ( _options.traceSymbolLayout() )
+                                       printf("symbol '%s', .axsymbol mapped it to %s/%s\n", atom.name(), curSegName, curSectName);
+                       }
+               }
+               else if ( strncmp(symName, "l_OBJC_$_CLASS_METHODS_", 23) == 0 ) {
+                       if ( _options.moveAXMethodList(&symName[23]) ) {
+                               curSectName  = "__objc_const_ax";
+                               fs = this->getFinalSection(curSegName, curSectName, sectType);
+                               if ( _options.traceSymbolLayout() )
+                                       printf("symbol '%s', .axsymbol mapped it to %s/%s\n", atom.name(), curSegName, curSectName);
+                       }
+               }
+       }
+
        // support for -rename_section and -rename_segment
        for (const Options::SectionRename& rename : _options.sectionRenames()) {
                if ( (strcmp(curSectName, rename.fromSection) == 0) && (strcmp(curSegName, rename.fromSegment) == 0) ) {
@@ -820,22 +846,19 @@ ld::Internal::FinalSection* InternalState::getFinalSection(const ld::Section& in
 }
 
 
-int InternalState::FinalSection::sectionComparer(const void* l, const void* r)
-{
-       const FinalSection* left  = *(FinalSection**)l;
-       const FinalSection* right = *(FinalSection**)r;
-       if ( left->_segmentOrder != right->_segmentOrder )
-               return (left->_segmentOrder - right->_segmentOrder);
-       return (left->_sectionOrder - right->_sectionOrder);
-}
-
 void InternalState::sortSections()
 {
        //fprintf(stderr, "UNSORTED final sections:\n");
        //for (std::vector<ld::Internal::FinalSection*>::iterator it = sections.begin(); it != sections.end(); ++it) {
        //      fprintf(stderr, "final section %p %s/%s\n", (*it), (*it)->segmentName(), (*it)->sectionName());
        //}
-       qsort(&sections[0], sections.size(), sizeof(FinalSection*), &InternalState::FinalSection::sectionComparer);
+       std::stable_sort(sections.begin(), sections.end(), [](const ld::Internal::FinalSection* l, const ld::Internal::FinalSection* r) {
+               const FinalSection* left = (FinalSection*)l;
+               const FinalSection* right = (FinalSection*)r;
+               if ( left->_segmentOrder != right->_segmentOrder )
+                       return (left->_segmentOrder < right->_segmentOrder);
+               return (left->_sectionOrder < right->_sectionOrder);
+       });
        //fprintf(stderr, "SORTED final sections:\n");
        //for (std::vector<ld::Internal::FinalSection*>::iterator it = sections.begin(); it != sections.end(); ++it) {
        //      fprintf(stderr, "final section %p %s/%s\n", (*it), (*it)->segmentName(), (*it)->sectionName());
@@ -1349,6 +1372,10 @@ int main(int argc, const char* argv[])
                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 again so that we get the segments in order.
+               state.sortSections();
+               ld::passes::thread_starts::doPass(options, state);  // must be after dylib
                
                // sort final sections
                state.sortSections();
index 71e5a21712f577faf6bcc82df0397a5ccf251738..1794141586ce20fde7ff5296da2bb298b8ff6f55 100644 (file)
 
 namespace ld {
 
+//
+// platform
+//
+
+enum Platform {
+       kPlatform_unknown=0,
+       kPlatform_macOS=1,
+       kPlatform_iOS=2,
+       kPlatform_tvOS=3,
+       kPlatform_watchOS=4,
+       kPlatform_bridgeOS=5,
+       kPlatform_iOSMac=6,
+       kPlatform_iOSSimulator=7,
+       kPlatform_tvOSSimulator=8,
+       kPlatform_watchOSSimulator=9
+};
+
+typedef std::set<Platform> PlatformSet;
+
+//
+// minumum OS versions
+//
+
+typedef std::pair<Platform, uint32_t> Version;
+
+struct VersionSet {
+private:
+       std::map<Platform, uint32_t> _versions;
+public:
+       VersionSet() {}
+       VersionSet(const std::map<Platform, uint32_t>& P) : _versions(P) {}
+       void add(ld::Version platformVersion) {
+               _versions.insert(platformVersion);
+       }
+       void erase(const Platform& platform) {
+               _versions.erase(platform);
+       }
+       size_t count() const { return _versions.size(); }
+       size_t empty() const { return _versions.empty(); }
+
+       void forEach(void (^callback)(ld::Platform platform, uint32_t version, bool &stop)) const {
+               bool stop = false;
+               for (const auto& version : _versions) {
+                       callback(version.first, version.second, stop);
+                       if (stop)
+                               return;
+               }
+       }
+
+       bool contains(ld::Platform platform) const { return _versions.count(platform) != 0; }
+       bool contains(ld::PlatformSet platforms) const {
+               __block bool retval = true;
+               forEach(^(ld::Platform platform, uint32_t version, bool &stop) {
+                       if (platforms.find(platform) == platforms.end()) {
+                               stop = true;
+                               retval = false;
+                       }
+               });
+               return retval;
+       }
+
+       uint32_t minOS(const ld::Platform& platform) const {
+               for (const auto& version : _versions) {
+                       if (basePlatform(version.first) == platform) {
+                               return version.second;
+                       }
+               }
+               return 0;
+       }
+
+       bool minOS(const Version& version) const {
+               return minOS(version.first) >= version.second;
+       }
+
+       const ld::Platform basePlatform(const ld::Platform& platform) const {
+               switch(platform) {
+                       case kPlatform_iOSMac:
+                       case kPlatform_iOSSimulator:
+                               return kPlatform_iOS;
+                       case kPlatform_watchOSSimulator:
+                               return kPlatform_watchOS;
+                       case kPlatform_tvOSSimulator:
+                               return kPlatform_tvOS;
+                       default:
+                               return platform;
+               }
+       }
+
+       bool minOS(const ld::VersionSet& requiredMinVersions) const {
+               __block bool retval = true;
+               forEach(^(ld::Platform platform, uint32_t version, bool &stop) {
+                       if (!requiredMinVersions.contains(basePlatform(platform)))
+                               return;
+                       if (version < requiredMinVersions.minOS(basePlatform(platform))) {
+                               stop = true;
+                               retval = false;
+                       }
+               });
+               return retval;
+       }
+
+       std::string to_str() const {
+               std::string retval;
+               auto appendPlatform = [&](const std::string& platform) {
+                       if (retval.empty()) {
+                               retval = platform;
+                       } else {
+                               retval += "/";
+                               retval += platform;
+                       }
+               };
+
+               forEach(^(ld::Platform platform, uint32_t version, bool &stop) {
+                       switch (platform) {
+                               case ld::kPlatform_macOS:                               appendPlatform("macOS"); break;
+                               case ld::kPlatform_iOSMac:                              appendPlatform("iOSMac"); break;
+                               case ld::kPlatform_iOS:                                 appendPlatform("iOS"); break;
+                               case ld::kPlatform_iOSSimulator:                appendPlatform("iOS Simulator"); break;
+                               case ld::kPlatform_watchOS:                             appendPlatform("watchOS"); break;
+                               case ld::kPlatform_watchOSSimulator:    appendPlatform("watchOS Simulator"); break;
+                               case ld::kPlatform_tvOS:                                appendPlatform("tvOS"); break;
+                               case ld::kPlatform_tvOSSimulator:               appendPlatform("tvOS Simulator"); break;
+                               case ld::kPlatform_bridgeOS:                    appendPlatform("bridgeOS"); break;
+                               case ld::kPlatform_unknown:                             appendPlatform("Unkown"); break;
+                       }
+               });
+
+               return retval;
+       }
+};
+
+static const Version mac10_4           ({kPlatform_macOS, 0x000A0400});
+static const Version mac10_5           ({kPlatform_macOS, 0x000A0500});
+static const Version mac10_6           ({kPlatform_macOS, 0x000A0600});
+static const Version mac10_7           ({kPlatform_macOS, 0x000A0700});
+static const Version mac10_8           ({kPlatform_macOS, 0x000A0800});
+static const Version mac10_9           ({kPlatform_macOS, 0x000A0900});
+static const Version mac10_12          ({kPlatform_macOS, 0x000A0C00});
+static const Version mac10_14          ({kPlatform_macOS, 0x000A0E00});
+static const Version mac10_Future      ({kPlatform_macOS, 0x10000000});
+
+static const Version iOS_2_0           ({kPlatform_iOS, 0x00020000});
+static const Version iOS_3_1           ({kPlatform_iOS, 0x00030100});
+static const Version iOS_4_2           ({kPlatform_iOS, 0x00040200});
+static const Version iOS_4_3           ({kPlatform_iOS, 0x00040300});
+static const Version iOS_5_0           ({kPlatform_iOS, 0x00050000});
+static const Version iOS_6_0           ({kPlatform_iOS, 0x00060000});
+static const Version iOS_7_0           ({kPlatform_iOS, 0x00070000});
+static const Version iOS_8_0           ({kPlatform_iOS, 0x00080000});
+static const Version iOS_9_0           ({kPlatform_iOS, 0x00090000});
+static const Version iOS_10_0          ({kPlatform_iOS, 0x000A0000});
+static const Version iOS_11_0          ({kPlatform_iOS, 0x000B0000});
+static const Version iOS_12_0          ({kPlatform_iOS, 0x000C0000});
+static const Version iOS_Future        ({kPlatform_iOS, 0x10000000});
+
+static const Version watchOS_1_0               ({kPlatform_watchOS, 0x00010000});
+static const Version watchOS_2_0               ({kPlatform_watchOS, 0x00020000});
+static const Version watchOS_5_0               ({kPlatform_watchOS, 0x00050000});
+static const Version watchOS_Future            ({kPlatform_watchOS, 0x10000000});
+
+static const Version tvOS_9_0                  ({kPlatform_tvOS, 0x00090000});
+static const Version tvOS_12_0                         ({kPlatform_tvOS, 0x000C0000});
+static const Version tvOS_Future               ({kPlatform_tvOS, 0x10000000});
+       
+static const Version bridgeOS_1_0                      ({kPlatform_bridgeOS, 0x00010000});
+static const Version bridgeOS_Future           ({kPlatform_bridgeOS, 0x10000000});
+
+// Platform Sets
+
+static const PlatformSet simulatorPlatforms ( {kPlatform_iOSSimulator, kPlatform_tvOSSimulator, kPlatform_watchOSSimulator} );
+
+//FIXME do we need to add simulatots to these?
+//FIXME Are the dates correct?
+static const VersionSet version2007            ({mac10_4, iOS_2_0});
+static const VersionSet version2008    ({mac10_5, iOS_2_0});
+static const VersionSet version2008Fall ({mac10_5, iOS_3_1});
+static const VersionSet version2009    ({mac10_6, iOS_3_1});
+static const VersionSet version2010    ({mac10_7, iOS_4_2});
+static const VersionSet version2010Fall ({mac10_7, iOS_4_3});
+
+static const VersionSet version2012    ({mac10_8, iOS_6_0});
+static const VersionSet version2013    ({mac10_9, iOS_7_0});
+       
+static const VersionSet supportsSplitSegV2             ({mac10_12, iOS_9_0, watchOS_2_0, tvOS_9_0});
+// FIXME: Use the comment out line instead.
+static const VersionSet supportsLCBuildVersion         ({mac10_14, iOS_12_0, watchOS_5_0, tvOS_12_0, bridgeOS_1_0});
+static const VersionSet supportsPIE                            ({mac10_5, iOS_4_2});
+static const VersionSet supportsTLV                    ({mac10_7, iOS_9_0});
+
 // Forward declaration for bitcode support
 class Bitcode;
 
@@ -58,10 +247,7 @@ class Bitcode;
 class File
 {
 public:
-       enum ObjcConstraint { objcConstraintNone, objcConstraintRetainRelease, 
-                                                       objcConstraintRetainReleaseOrGC, objcConstraintGC,
-                                                       objcConstraintRetainReleaseForSimulator };
-       
+
        class AtomHandler {
        public:
                virtual                         ~AtomHandler() {}
@@ -151,13 +337,10 @@ public:
        Ordinal                                                         ordinal() const                 { return _ordinal; }
        virtual bool                                            forEachAtom(AtomHandler&) const = 0;
        virtual bool                                            justInTimeforEachAtom(const char* name, AtomHandler&) const = 0;
-       virtual ObjcConstraint                          objCConstraint() const                  { return objcConstraintNone; }
-    virtual bool                                               objcHasCategoryClassPropertiesField() const { return false; }
-       virtual uint8_t                                         swiftVersion() const                    { return 0; }
+       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                                        platform() const                { return 0; }
+       virtual const VersionSet&                       platforms() const               { return _platforms; }
     bool                                                               fileExists() const     { return _modTime != 0; }
        Type                                                            type() const { return _type; }
        virtual Bitcode*                                        getBitcode() const              { return NULL; }
@@ -166,22 +349,10 @@ private:
        time_t                                                          _modTime;
        const Ordinal                                           _ordinal;
        const Type                                                      _type;
+       // Note this is just a placeholder as platforms() needs something to return
+       static const VersionSet                         _platforms;
 };
 
-
-//
-// minumum OS versions
-//
-enum MacVersionMin { macVersionUnset=0, mac10_4=0x000A0400, mac10_5=0x000A0500, 
-                                               mac10_6=0x000A0600, mac10_7=0x000A0700, mac10_8=0x000A0800,
-                                               mac10_9=0x000A0900, mac10_12=0x000A0C00, mac10_Future=0x10000000 };
-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_10_0=0x000A0000, iOS_Future=0x10000000};
-enum WatchOSVersionMin  { wOSVersionUnset=0, wOS_1_0=0x00010000, wOS_2_0=0x00020000 };
-
-
 namespace relocatable {
        //
        // ld::relocatable::File 
@@ -226,6 +397,8 @@ namespace relocatable {
                virtual bool                                            canScatterAtoms() const = 0;
                virtual bool                                            hasLongBranchStubs()            { return false; }
                virtual bool                                            hasllvmProfiling() const    { return false; }
+               virtual bool                                            hasObjC() const                         { return false; }
+               virtual bool                                            objcHasCategoryClassPropertiesField() const { return false; }
                virtual LinkerOptionsList*                      linkerOptions() const = 0;
                virtual const ToolVersionList&          toolVersions() const = 0;
                virtual SourceKind                                      sourceKind() const { return kSourceUnknown; }
@@ -343,7 +516,7 @@ public:
                                typeCFI, typeLSDA, typeDtraceDOF, typeUnwindInfo, typeObjCClassRefs, typeObjC2CategoryList,
                                typeZeroFill, typeTentativeDefs, typeLazyPointer, typeStub, typeNonLazyPointer, typeDyldInfo, 
                                typeLazyDylibPointer, typeStubHelper, typeInitializerPointers, typeTerminatorPointers,
-                               typeStubClose, typeLazyPointerClose, typeAbsoluteSymbols, 
+                               typeStubClose, typeLazyPointerClose, typeAbsoluteSymbols, typeThreadStarts,
                                typeTLVDefs, typeTLVZeroFill, typeTLVInitialValues, typeTLVInitializerPointers, typeTLVPointers,
                                typeFirstSection, typeLastSection, typeDebug, typeSectCreate };
 
@@ -489,14 +662,38 @@ struct Fixup
                                        kindStoreTargetAddressARM64TLVPLoadPageOff12,// kindSetTargetAddress + kindStoreARM64TLVPLoadPageOff12
                                        kindStoreTargetAddressARM64TLVPLoadNowLeaPage21,        // kindSetTargetAddress + kindStoreARM64TLVPLoadNowLeaPage21
                                        kindStoreTargetAddressARM64TLVPLoadNowLeaPageOff12,     // kindSetTargetAddress + kindStoreARM64TLVPLoadNowLeaPageOff12
+#endif
+#if SUPPORT_ARCH_arm64e
+                                       kindStoreLittleEndianAuth64,
+                                       kindStoreTargetAddressLittleEndianAuth64,       // kindSetTargetAddress + kindStoreLittleEndianAuth64
+                                       kindSetAuthData,
 #endif
                        };
 
+#if SUPPORT_ARCH_arm64e
+       struct AuthData {
+               // clang encodes the combination of the key bits as these values.
+               typedef enum {
+                       ptrauth_key_asia = 0,
+                       ptrauth_key_asib = 1,
+                       ptrauth_key_asda = 2,
+                       ptrauth_key_asdb = 3,
+               } ptrauth_key;
+
+               uint16_t discriminator;
+               bool hasAddressDiversity;
+               ptrauth_key key;
+       };
+#endif
+
        union {
                const Atom*     target;
                const char*     name;
                uint64_t        addend;
                uint32_t        bindingIndex;
+#if SUPPORT_ARCH_arm64e
+               AuthData        authData;
+#endif
        } u;
        uint32_t                offsetInAtom;
        Kind                    kind : 8;
@@ -553,6 +750,14 @@ struct Fixup
                binding(Fixup::bindingNone),  
                contentAddendOnly(false), contentDetlaToAddendOnly(false), contentIgnoresAddend(false) 
                        { u.addend = addend; }
+               
+#if SUPPORT_ARCH_arm64e
+       Fixup(uint32_t off, Cluster c, Kind k, AuthData authData) :
+               offsetInAtom(off), kind(k), clusterSize(c), weakImport(false), 
+               binding(Fixup::bindingNone),  
+               contentAddendOnly(false), contentDetlaToAddendOnly(false), contentIgnoresAddend(false) 
+                       { u.authData = authData; }
+#endif
                        
        Fixup(Kind k, uint32_t lohKind, uint32_t off1, uint32_t off2) :
                offsetInAtom(off1), kind(k), clusterSize(k1of1),  
@@ -596,6 +801,146 @@ struct Fixup
                }
                return false;
        }
+
+       bool isStore() const {
+               switch ( kind ) {
+                       case ld::Fixup::kindNone:
+                       case ld::Fixup::kindNoneFollowOn:
+                       case ld::Fixup::kindNoneGroupSubordinate:
+                       case ld::Fixup::kindNoneGroupSubordinateFDE:
+                       case ld::Fixup::kindNoneGroupSubordinateLSDA:
+                       case ld::Fixup::kindNoneGroupSubordinatePersonality:
+                       case ld::Fixup::kindSetTargetAddress:
+                       case ld::Fixup::kindSubtractTargetAddress:
+                       case ld::Fixup::kindAddAddend:
+                       case ld::Fixup::kindSubtractAddend:
+                       case ld::Fixup::kindSetTargetImageOffset:
+                       case ld::Fixup::kindSetTargetSectionOffset:
+#if SUPPORT_ARCH_arm64e
+                       case ld::Fixup::kindSetAuthData:
+#endif
+                               return false;
+                       default:
+                               break;
+               }
+               return true;
+       }
+
+
+       bool setsTarget(bool isObjectFile) const {
+               switch ( kind ) {
+                       case ld::Fixup::kindSetTargetAddress:
+                       case ld::Fixup::kindLazyTarget:
+                       case ld::Fixup::kindStoreTargetAddressLittleEndian32:
+                       case ld::Fixup::kindStoreTargetAddressLittleEndian64:
+#if SUPPORT_ARCH_arm64e
+                       case ld::Fixup::kindStoreTargetAddressLittleEndianAuth64:
+#endif
+                       case ld::Fixup::kindStoreTargetAddressBigEndian32:
+                       case ld::Fixup::kindStoreTargetAddressBigEndian64:
+                       case ld::Fixup::kindStoreTargetAddressX86PCRel32:
+                       case ld::Fixup::kindStoreTargetAddressX86BranchPCRel32:
+                       case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoad:
+                       case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoadNowLEA:
+                       case ld::Fixup::kindStoreTargetAddressX86PCRel32TLVLoad:
+                       case ld::Fixup::kindStoreTargetAddressX86PCRel32TLVLoadNowLEA:
+                       case ld::Fixup::kindStoreTargetAddressX86Abs32TLVLoad:
+                       case ld::Fixup::kindStoreTargetAddressARMBranch24:
+                       case ld::Fixup::kindStoreTargetAddressThumbBranch22:
+                       case ld::Fixup::kindStoreTargetAddressARMLoad12:
+#if SUPPORT_ARCH_arm64
+                       case ld::Fixup::kindStoreTargetAddressARM64Branch26:
+                       case ld::Fixup::kindStoreTargetAddressARM64Page21:
+                       case ld::Fixup::kindStoreTargetAddressARM64PageOff12:
+                       case ld::Fixup::kindStoreTargetAddressARM64GOTLoadPage21:
+                       case ld::Fixup::kindStoreTargetAddressARM64GOTLoadPageOff12:
+                       case ld::Fixup::kindStoreTargetAddressARM64GOTLeaPage21:
+                       case ld::Fixup::kindStoreTargetAddressARM64GOTLeaPageOff12:
+                       case ld::Fixup::kindStoreTargetAddressARM64TLVPLoadPage21:
+                       case ld::Fixup::kindStoreTargetAddressARM64TLVPLoadPageOff12:
+                       case ld::Fixup::kindStoreTargetAddressARM64TLVPLoadNowLeaPage21:
+                       case ld::Fixup::kindStoreTargetAddressARM64TLVPLoadNowLeaPageOff12:
+#endif
+                               return true;
+                       case ld::Fixup::kindStoreX86DtraceCallSiteNop:
+                       case ld::Fixup::kindStoreX86DtraceIsEnableSiteClear:
+                       case ld::Fixup::kindStoreARMDtraceCallSiteNop:
+                       case ld::Fixup::kindStoreARMDtraceIsEnableSiteClear:
+                       case ld::Fixup::kindStoreARM64DtraceCallSiteNop:
+                       case ld::Fixup::kindStoreARM64DtraceIsEnableSiteClear:
+                       case ld::Fixup::kindStoreThumbDtraceCallSiteNop:
+                       case ld::Fixup::kindStoreThumbDtraceIsEnableSiteClear:
+                               return isObjectFile;
+                       default:
+                               break;
+               }
+               return false;
+       }
+
+       bool isPcRelStore(bool isKextBundle) const {
+               switch ( kind ) {
+                       case ld::Fixup::kindStoreX86BranchPCRel8:
+                       case ld::Fixup::kindStoreX86BranchPCRel32:
+                       case ld::Fixup::kindStoreX86PCRel8:
+                       case ld::Fixup::kindStoreX86PCRel16:
+                       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::kindStoreARMBranch24:
+                       case ld::Fixup::kindStoreThumbBranch22:
+                       case ld::Fixup::kindStoreARMLoad12:
+                       case ld::Fixup::kindStoreTargetAddressX86PCRel32:
+                       case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoad:
+                       case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoadNowLEA:
+                       case ld::Fixup::kindStoreTargetAddressX86PCRel32TLVLoad:
+                       case ld::Fixup::kindStoreTargetAddressX86PCRel32TLVLoadNowLEA:
+                       case ld::Fixup::kindStoreTargetAddressARMBranch24:
+                       case ld::Fixup::kindStoreTargetAddressThumbBranch22:
+                       case ld::Fixup::kindStoreTargetAddressARMLoad12:
+#if SUPPORT_ARCH_arm64
+                       case ld::Fixup::kindStoreARM64Page21:
+                       case ld::Fixup::kindStoreARM64PageOff12:
+                       case ld::Fixup::kindStoreARM64GOTLoadPage21:
+                       case ld::Fixup::kindStoreARM64GOTLoadPageOff12:
+                       case ld::Fixup::kindStoreARM64GOTLeaPage21:
+                       case ld::Fixup::kindStoreARM64GOTLeaPageOff12:
+                       case ld::Fixup::kindStoreARM64TLVPLoadPage21:
+                       case ld::Fixup::kindStoreARM64TLVPLoadPageOff12:
+                       case ld::Fixup::kindStoreARM64TLVPLoadNowLeaPage21:
+                       case ld::Fixup::kindStoreARM64TLVPLoadNowLeaPageOff12:
+                       case ld::Fixup::kindStoreARM64PCRelToGOT:
+                       case ld::Fixup::kindStoreTargetAddressARM64Page21:
+                       case ld::Fixup::kindStoreTargetAddressARM64PageOff12:
+                       case ld::Fixup::kindStoreTargetAddressARM64GOTLoadPage21:
+                       case ld::Fixup::kindStoreTargetAddressARM64GOTLoadPageOff12:
+                       case ld::Fixup::kindStoreTargetAddressARM64GOTLeaPage21:
+                       case ld::Fixup::kindStoreTargetAddressARM64GOTLeaPageOff12:
+                       case ld::Fixup::kindStoreTargetAddressARM64TLVPLoadPage21:
+                       case ld::Fixup::kindStoreTargetAddressARM64TLVPLoadPageOff12:
+                       case ld::Fixup::kindStoreTargetAddressARM64TLVPLoadNowLeaPage21:
+                       case ld::Fixup::kindStoreTargetAddressARM64TLVPLoadNowLeaPageOff12:
+#endif
+                               return true;
+                       case ld::Fixup::kindStoreTargetAddressX86BranchPCRel32:
+#if SUPPORT_ARCH_arm64
+                       case ld::Fixup::kindStoreTargetAddressARM64Branch26:
+#endif
+                               return !isKextBundle;
+#if SUPPORT_ARCH_arm64
+                       case ld::Fixup::kindStoreARM64Branch26:
+#endif
+                               return !isKextBundle;
+                       default:
+                               break;
+               }
+               return false;
+       }
        
        union LOH_arm64 {
                uint64_t        addend;
@@ -898,12 +1243,12 @@ public:
                                                                                Internal() : bundleLoader(NULL),
                                                                                        entryPoint(NULL), classicBindingHelper(NULL),
                                                                                        lazyBindingHelper(NULL), compressedFastBinderProxy(NULL),
-                                                                                       objcObjectConstraint(ld::File::objcConstraintNone), 
-                                                                                       objcDylibConstraint(ld::File::objcConstraintNone), 
+                                                                                       hasObjC(false),
                                                                                        swiftVersion(0), cpuSubType(0), minOSVersion(0),
                                                                                        objectFileFoundWithNoVersion(false),
                                                                                        allObjectFilesScatterable(true), 
                                                                                        someObjectFileHasDwarf(false), usingHugeSections(false),
+                                                                                       someObjectFileHasSwift(false), firstSwiftDylibFile(nullptr),
                                                                                        hasThreadLocalVariableDefinitions(false),
                                                                                        hasWeakExternalSymbols(false),
                                                                                        someObjectHasOptimizationHints(false),
@@ -919,6 +1264,8 @@ public:
        CStringSet                                                                      unprocessedLinkerOptionFrameworks;
        CStringSet                                                                      linkerOptionLibraries;
        CStringSet                                                                      linkerOptionFrameworks;
+       CStringSet                                                                      missingLinkerOptionLibraries;
+       CStringSet                                                                      missingLinkerOptionFrameworks;
        std::vector<const ld::Atom*>                            indirectBindingTable;
        std::vector<const ld::relocatable::File*>       filesWithBitcode;
        std::vector<const ld::relocatable::File*>       filesFromCompilerRT;
@@ -930,16 +1277,17 @@ public:
        const Atom*                                                                     classicBindingHelper;
        const Atom*                                                                     lazyBindingHelper;
        const Atom*                                                                     compressedFastBinderProxy;
-       ld::File::ObjcConstraint                                        objcObjectConstraint;
-       ld::File::ObjcConstraint                                        objcDylibConstraint;
+       bool                                                                            hasObjC;
        uint8_t                                                                         swiftVersion;
        uint32_t                                                                        cpuSubType;
        uint32_t                                                                        minOSVersion;
-       uint32_t                                                                        derivedPlatform;
+       VersionSet                                                                      derivedPlatforms;
        bool                                                                            objectFileFoundWithNoVersion;
        bool                                                                            allObjectFilesScatterable;
        bool                                                                            someObjectFileHasDwarf;
        bool                                                                            usingHugeSections;
+       bool                                                                            someObjectFileHasSwift;
+       const ld::dylib::File*                                          firstSwiftDylibFile;
        bool                                                                            hasThreadLocalVariableDefinitions;
        bool                                                                            hasWeakExternalSymbols;
        bool                                                                            someObjectHasOptimizationHints;
index 0b781bec7091957e5bbc75e1087a6a1564dcfc11..baf09f99e6e50bd9a1869e067dd782f0de68f36d 100644 (file)
@@ -123,17 +123,14 @@ template <typename A>
 class File : public ld::dylib::File
 {
 public:
-       File(const char* path, time_t mTime, ld::File::Ordinal ordinal, Options::Platform platform,
-                uint32_t linkMinOSVersion, bool allowWeakImports, bool linkingFlatNamespace, bool hoistImplicitPublicDylibs,
+       File(const char* path, time_t mTime, ld::File::Ordinal ordinal, const ld::VersionSet& platforms,
+                bool allowWeakImports, bool linkingFlatNamespace, bool hoistImplicitPublicDylibs,
                 bool allowSimToMacOSX, bool addVers);
 
        // overrides of ld::File
        virtual bool                                                    forEachAtom(ld::File::AtomHandler&) const override final;
        virtual bool                                                    justInTimeforEachAtom(const char* name, ld::File::AtomHandler&) const override final;
-       virtual ld::File::ObjcConstraint                objCConstraint() const override final { return _objcConstraint; }
        virtual uint8_t                                                 swiftVersion() const override final { return _swiftVersion; }
-       virtual uint32_t                                                minOSVersion() const override final { return _minVersionInDylib; }
-       virtual uint32_t                                                platform() const        override final { return _platformInDylib; }
        virtual ld::Bitcode*                                    getBitcode() const override final { return _bitcode.get(); }
 
 
@@ -207,11 +204,7 @@ protected:
        std::vector<const char*>                        _rpaths;
        const char*                                                     _parentUmbrella;
        std::unique_ptr<ld::Bitcode>            _bitcode;
-       const Options::Platform                         _platform;
-       ld::File::ObjcConstraint                        _objcConstraint;
-       const uint32_t                                          _linkMinOSVersion;
-       uint32_t                                                        _minVersionInDylib;
-       uint32_t                                                        _platformInDylib;
+       ld::VersionSet                      _platforms;
        uint8_t                                                         _swiftVersion;
        bool                                                            _wrongOS;
        bool                                                            _linkingFlat;
@@ -223,7 +216,7 @@ protected:
        bool                                                            _deadStrippable;
        bool                                                            _hasPublicInstallName;
        bool                                                            _appExtensionSafe;
-    const bool                          _allowWeakImports;
+  const bool              _allowWeakImports;
        const bool                                                      _allowSimToMacOSXLinking;
        const bool                                                      _addVersionLoadCommand;
 
@@ -234,8 +227,8 @@ template <typename A>
 bool File<A>::_s_logHashtable = false;
 
 template <typename A>
-File<A>::File(const char* path, time_t mTime, ld::File::Ordinal ord,  Options::Platform platform,
-                         uint32_t linkMinOSVersion, bool allowWeakImports, bool linkingFlatNamespace,
+File<A>::File(const char* path, time_t mTime, ld::File::Ordinal ord, const ld::VersionSet& platforms,
+                         bool allowWeakImports, bool linkingFlatNamespace,
                          bool hoistImplicitPublicDylibs,
                          bool allowSimToMacOSX, bool addVers)
        : ld::dylib::File(path, mTime, ord),
@@ -245,11 +238,7 @@ File<A>::File(const char* path, time_t mTime, ld::File::Ordinal ord,  Options::P
          _indirectDylibsProcessed(false),
          _importAtom(nullptr),
          _parentUmbrella(nullptr),
-         _platform(platform),
-         _objcConstraint(ld::File::objcConstraintNone),
-         _linkMinOSVersion(linkMinOSVersion),
-         _minVersionInDylib(0),
-         _platformInDylib(Options::kPlatformUnknown),
+    _platforms(platforms),
          _swiftVersion(0),
          _wrongOS(false),
          _linkingFlat(linkingFlatNamespace),
@@ -261,7 +250,7 @@ File<A>::File(const char* path, time_t mTime, ld::File::Ordinal ord,  Options::P
          _deadStrippable(false),
          _hasPublicInstallName(false),
          _appExtensionSafe(false),
-      _allowWeakImports(allowWeakImports),
+    _allowWeakImports(allowWeakImports),
          _allowSimToMacOSXLinking(allowSimToMacOSX),
          _addVersionLoadCommand(addVers)
 {
index 811b6b308d5a69e87db75d465df6cbab90eaf270..6282e6b736c17f9ce87e77508dc3535c32704069 100644 (file)
@@ -371,8 +371,10 @@ ld::relocatable::File* Parser::parseMachOFile(const uint8_t* p, size_t len, cons
        objOpts.armUsesZeroCostExceptions = options.armUsesZeroCostExceptions;
        objOpts.simulator                       = options.simulator;
        objOpts.ignoreMismatchPlatform = options.ignoreMismatchPlatform;
-       objOpts.platform                        = options.platform;
-       objOpts.minOSVersion            = options.minOSVersion;
+#if SUPPORT_ARCH_arm64e
+       objOpts.supportsAuthenticatedPointers = options.supportsAuthenticatedPointers;
+#endif
+       objOpts.platforms                       = options.platforms;
        objOpts.subType                         = 0;
        objOpts.srcKind                         = ld::relocatable::File::kSourceLTO;
        objOpts.treateBitcodeAsData = false;
@@ -1059,7 +1061,8 @@ thinlto_code_gen_t Parser::init_thinlto_codegen(const std::vector<File*>&
                        }
                }
                thinlto_codegen_set_cache_dir(thingenerator, options.ltoCachePath);
-               thinlto_codegen_set_cache_pruning_interval(thingenerator, options.ltoPruneInterval);
+               if (options.ltoPruneIntervalOverwrite)
+                       thinlto_codegen_set_cache_pruning_interval(thingenerator, options.ltoPruneInterval);
                thinlto_codegen_set_cache_entry_expiration(thingenerator, options.ltoPruneAfter);
                thinlto_codegen_set_final_cache_size_relative_to_available_space(thingenerator, options.ltoMaxCacheSize);
        }
@@ -1129,7 +1132,10 @@ thinlto_code_gen_t Parser::init_thinlto_codegen(const std::vector<File*>&
                        }
                }
                if (atom->contentType() == ld::Atom::typeLTOtemporary &&
-                       ((lto::File *)atom->file())->isThinLTO()) {
+                       ((lto::File *)atom->file())->isThinLTO() &&
+                       atom != &((lto::File *)atom->file())->internalAtom()) {
+                       assert(atom->scope() != ld::Atom::scopeTranslationUnit && "LTO should not expose static atoms");
+                       assert(llvmAtoms.find(atom->name()) == llvmAtoms.end() && "Unexpected llvmAtom with duplicate name");
                        llvmAtoms[atom->name()] = (Atom*)atom;
                }
        }
@@ -1179,6 +1185,13 @@ thinlto_code_gen_t Parser::init_thinlto_codegen(const std::vector<File*>&
                } else {
                        if ( logMustPreserve ) fprintf(stderr, "NOT preserving(%s)\n", name);
                }
+
+               // <rdar://problem/16165191> tell code generator to preserve initial undefines
+               for (const char* undefName : *options.initialUndefines) {
+                       if ( logMustPreserve ) fprintf(stderr, "thinlto_codegen_add_cross_referenced_symbol(%s) because it is an initial undefine\n", undefName);
+                       ::thinlto_codegen_add_cross_referenced_symbol(thingenerator, undefName, strlen(undefName));
+               }
+
 // FIXME: to be implemented
 //             else if ( options.relocatable && hasNonllvmAtoms ) {
 //                     // <rdar://problem/14334895> ld -r mode but merging in some mach-o files, so need to keep libLTO from optimizing away anything
@@ -1242,6 +1255,9 @@ bool Parser::optimizeThinLTO(const std::vector<File*>&              files,
                // Save the codegenerator
                thinlto_code_gen_t bitcode_generator = thingenerator;
                // Create a new codegen generator for the codegen part.
+               // Clear out the stored atoms so we can recompute them.
+               deadllvmAtoms.clear();
+               llvmAtoms.clear();
                thingenerator = init_thinlto_codegen(files, allAtoms, state, options, deadllvmAtoms, llvmAtoms);
                // Disable the optimizer
                thinlto_codegen_set_codegen_only(thingenerator, true);
@@ -1465,6 +1481,14 @@ void Parser::AtomSyncer::doAtom(const ld::Atom& machoAtom)
                        if (log) fprintf(stderr, "demote %s to hidden after LTO\n", name);
                        (const_cast<ld::Atom*>(&machoAtom))->setScope(ld::Atom::scopeLinkageUnit);
                }
+               // If both llvmAtom and machoAtom has the same scope and combine, but machoAtom loses auto hide, add it back.
+               // rdar://problem/38646854
+               if (pos->second->scope() == machoAtom.scope() &&
+                       pos->second->combine() == machoAtom.combine() &&
+                       pos->second->autoHide() && !machoAtom.autoHide()) {
+                       if (log) fprintf(stderr, "set %s to auto hide after LTO\n", name);
+                       (const_cast<ld::Atom*>(&machoAtom))->setAutoHide();
+               }
                pos->second->setCompiledAtom(machoAtom);
                _lastProxiedAtom = &machoAtom;
                _lastProxiedFile = pos->second->file();
@@ -1513,7 +1537,7 @@ void Parser::AtomSyncer::doAtom(const ld::Atom& machoAtom)
                        if ( (_lastProxiedAtom != NULL) && (_lastProxiedAtom->section() == machoAtom.section()) ) {
                                ld::Atom* ma = const_cast<ld::Atom*>(&machoAtom);
                                ma->setFile(_lastProxiedFile);
-                               if (log) fprintf(stderr, "AtomSyncer, mach-o atom %s is proxied to %s (path=%s)\n", machoAtom.name(), _lastProxiedAtom->name(), _lastProxiedFile->path());
+                               if (log) fprintf(stderr, "AtomSyncer, mach-o atom %s is static and being assigned to %s\n", machoAtom.name(), _lastProxiedFile->path());
                        }
                        if (log) fprintf(stderr, "AtomSyncer, mach-o atom %p is totally new (name=%s)\n", &machoAtom, machoAtom.name());
                }
index a086548da109335baba59f284f30d3a951457cc6..ad2249201064a4e51771a6b52e59bcc2492f4873 100644 (file)
@@ -55,6 +55,7 @@ struct OptimizeOptions {
        int                                                                     ltoPruneInterval;
        int                                                                     ltoPruneAfter;
        unsigned                                                        ltoMaxCacheSize;
+       bool                                                            ltoPruneIntervalOverwrite;
        bool                                                            preserveAllGlobals;
        bool                                                            verbose; 
        bool                                                            saveTemps; 
@@ -72,12 +73,14 @@ struct OptimizeOptions {
        bool                                                            armUsesZeroCostExceptions;
        bool                                                            simulator;
        bool                                                            ignoreMismatchPlatform;
+#if SUPPORT_ARCH_arm64e
+       bool                                                            supportsAuthenticatedPointers;
+#endif
        bool                                                            bitcodeBundle;
        uint8_t                                                         maxDefaultCommonAlignment;
        cpu_type_t                                                      arch;
        const char*                                                     mcpu;
-       Options::Platform                                       platform;
-       uint32_t                                                        minOSVersion;
+       ld::VersionSet                                          platforms;
        const std::vector<const char*>*         llvmOptions;
        const std::vector<const char*>*         initialUndefines;
 };
index b740c5540b111accd50110360e7fe8354320f2b9..e4f7b95c518f050d54c95e6d4250cd96d7925d35 100644 (file)
@@ -61,11 +61,12 @@ 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, 
-                                                                                                       Options::Platform platform, uint32_t linkMinOSVersion, bool allowWeakImports,
+                                                                                                       const ld::VersionSet& platforms, bool allowWeakImports,
                                                                                                        bool allowSimToMacOSX, bool addVers,  bool buildingForSimulator,
                                                                                                        bool logAllFiles, const char* installPath,
                                                                                                        bool indirectDylib, bool ignoreMismatchPlatform, bool usingBitcode);
        virtual                                                                 ~File() noexcept {}
+       virtual const ld::VersionSet&                   platforms() const { return this->_platforms; }
 
 private:
        using P = typename A::P;
@@ -81,6 +82,7 @@ private:
        void                            addSymbol(const char* name, bool weakDef = false, bool tlv = false, pint_t address = 0);
        static const char*      objCInfoSegmentName();
        static const char*      objCInfoSectionName();
+       static bool         useSimulatorVariant();
 
 
        uint64_t  _fileLength;
@@ -96,13 +98,17 @@ template <> const char* File<x86_64>::objCInfoSectionName() { return "__objc_ima
 template <> const char* File<arm>::objCInfoSectionName() { return "__objc_imageinfo"; }
 template <typename A> const char* File<A>::objCInfoSectionName() { return "__image_info"; }
 
+template <> bool File<x86>::useSimulatorVariant() { return true; }
+template <> bool File<x86_64>::useSimulatorVariant() { return true; }
+template <typename A> bool File<A>::useSimulatorVariant() { return 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 linkingMainExecutable,
-                         bool hoistImplicitPublicDylibs, Options::Platform platform, uint32_t linkMinOSVersion, bool allowWeakImports,
+                         bool hoistImplicitPublicDylibs, const ld::VersionSet& platforms, bool allowWeakImports,
                          bool allowSimToMacOSX, bool addVers, bool buildingForSimulator, bool logAllFiles,
                          const char* targetInstallPath, bool indirectDylib, bool ignoreMismatchPlatform, bool usingBitcode)
-       : Base(strdup(path), mTime, ord, platform, linkMinOSVersion, allowWeakImports, linkingFlatNamespace,
+       : Base(strdup(path), mTime, ord, platforms, allowWeakImports, linkingFlatNamespace,
                   hoistImplicitPublicDylibs, allowSimToMacOSX, addVers), _fileLength(fileLength), _linkeditStartOffset(0)
 {
        const macho_header<P>* header = (const macho_header<P>*)fileContent;
@@ -138,7 +144,7 @@ File<A>::File(const uint8_t* fileContent, uint64_t fileLength, const char* path,
        const char*     strings = nullptr;
        bool compressedLinkEdit = false;
        uint32_t dependentLibCount = 0;
-       Options::Platform lcPlatform = Options::kPlatformUnknown;
+       ld::VersionSet lcPlatforms;
        const macho_load_command<P>* cmd = cmds;
        for (uint32_t i = 0; i < cmd_count; ++i) {
                macho_dylib_command<P>* dylibID;
@@ -193,19 +199,13 @@ File<A>::File(const uint8_t* fileContent, uint64_t fileLength, const char* path,
                        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
-                               this->_minVersionInDylib = (ld::MacVersionMin)((macho_version_min_command<P>*)cmd)->version();
-                               this->_platformInDylib = cmd->cmd();
-                               lcPlatform = Options::platformForLoadCommand(this->_platformInDylib);
+                               lcPlatforms.add({Options::platformForLoadCommand(cmd->cmd(), useSimulatorVariant()), ((macho_version_min_command<P>*)cmd)->version()});
                                break;
                        case LC_BUILD_VERSION:
                                {
                                        const macho_build_version_command<P>* buildVersCmd = (macho_build_version_command<P>*)cmd;
-                                       this->_platformInDylib   = buildVersCmd->platform();
-                                       this->_minVersionInDylib = buildVersCmd->minos();
-                                       lcPlatform = (Options::Platform)this->_platformInDylib;
+                                       lcPlatforms.add({(ld::Platform)buildVersCmd->platform(), buildVersCmd->minos()});
                                }
                                break;
                        case LC_CODE_SIGNATURE:
@@ -229,14 +229,6 @@ File<A>::File(const uint8_t* fileContent, uint64_t fileLength, const char* path,
                                                        const uint32_t* contents = (uint32_t*)(&fileContent[sect->offset()]);
                                                        if ( (sect->size() >= 8) && (contents[0] == 0) ) {
                                                                uint32_t flags = E::get32(contents[1]);
-                                                               if ( (flags & 4) == 4 )
-                                                                       this->_objcConstraint = ld::File::objcConstraintGC;
-                                                               else if ( (flags & 2) == 2 )
-                                                                       this->_objcConstraint = ld::File::objcConstraintRetainReleaseOrGC;
-                                                               else if ( (flags & 32) == 32 )
-                                                                       this->_objcConstraint = ld::File::objcConstraintRetainReleaseForSimulator;
-                                                               else
-                                                                       this->_objcConstraint = ld::File::objcConstraintRetainRelease;
                                                                this->_swiftVersion = ((flags >> 8) & 0xFF);
                                                        }
                                                        else if ( sect->size() > 0 ) {
@@ -262,96 +254,35 @@ File<A>::File(const uint8_t* fileContent, uint64_t fileLength, const char* path,
        }
        // arm/arm64 objects are default to ios platform if not set.
        // rdar://problem/21746314
-       if (lcPlatform == Options::kPlatformUnknown &&
+       if (lcPlatforms.empty() &&
                (std::is_same<A, arm>::value || std::is_same<A, arm64>::value))
-               lcPlatform = Options::kPlatformiOS;
+               lcPlatforms.add({ld::kPlatform_iOS, 0});
 
        // check cross-linking
-       if ( lcPlatform != platform ) {
-               this->_wrongOS = true;
-               if ( this->_addVersionLoadCommand && !indirectDylib && !ignoreMismatchPlatform ) {
-                       if ( buildingForSimulator ) {
-                               if ( !this->_allowSimToMacOSXLinking ) {
-                                       switch (platform) {
-                                               case Options::kPlatformOSX:
-                                               case Options::kPlatform_bridgeOS:
-                                               case Options::kPlatformiOS:
-                                                       if ( lcPlatform == Options::kPlatformUnknown )
-                                                               break;
-                                                       // fall through if the Platform is not Unknown
-                                               case Options::kPlatformWatchOS:
-                                                       // WatchOS errors on cross-linking when building for bitcode
-                                                       if ( usingBitcode )
-                                                               throwf("building for %s simulator, but linking against dylib built for %s,",
-                                                                  Options::platformName(platform),
-                                                                  Options::platformName(lcPlatform));
-                                                       else
-                                                               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;
-       #if SUPPORT_APPLE_TV
-                                               case Options::kPlatform_tvOS:
-                                                       // tvOS is a warning temporarily. rdar://problem/21746965
-                                                       if ( usingBitcode )
-                                                               throwf("building for %s simulator, but linking against dylib built for %s,",
-                                                                          Options::platformName(platform),
-                                                                          Options::platformName(lcPlatform));
-                                                       else
-                                                               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::kPlatform_bridgeOS:
-                                       case Options::kPlatformiOS:
-                                               if ( lcPlatform == Options::kPlatformUnknown )
-                                                       break;
-                                               // fall through if the Platform is not Unknown
-                                       case Options::kPlatformWatchOS:
-                                               // WatchOS errors on cross-linking when building for bitcode
-                                               if ( usingBitcode )
-                                                       throwf("building for %s, but linking against dylib built for %s,",
-                                                          Options::platformName(platform),
-                                                          Options::platformName(lcPlatform));
-                                               else
-                                                       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;
-       #if SUPPORT_APPLE_TV
-                                       case Options::kPlatform_tvOS:
-                                               // tvOS is a warning temporarily. rdar://problem/21746965
-                                               if ( usingBitcode )
-                                                       throwf("building for %s, but linking against dylib built for %s,",
-                                                                  Options::platformName(platform),
-                                                                  Options::platformName(lcPlatform));
-                                               else
-                                                       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;
+       platforms.forEach(^(ld::Platform platform, uint32_t version, bool &stop) {
+               if (!lcPlatforms.contains(platform) ) {
+                       this->_wrongOS = true;
+                       if ( this->_addVersionLoadCommand && !indirectDylib && !ignoreMismatchPlatform ) {
+                               if (buildingForSimulator && !this->_allowSimToMacOSXLinking) {
+                                       if ( usingBitcode )
+                                               throwf("building for %s simulator, but linking against dylib built for %s,",
+                                                          platforms.to_str().c_str(), lcPlatforms.to_str().c_str());
+                                       else
+                                               warning("URGENT: building for %s simulator, but linking against dylib (%s) built for %s. "
+                                                               "Note: This will be an error in the future.",
+                                                               platforms.to_str().c_str(), path, lcPlatforms.to_str().c_str());
                                }
+                       } else {
+                               if ( usingBitcode )
+                                       throwf("building for %s, but linking against dylib built for %s,",
+                                                  platforms.to_str().c_str(), lcPlatforms.to_str().c_str());
+                               else if ( (getenv("RC_XBS") != NULL) && (getenv("RC_BUILDIT") == NULL) ) // FIXME: remove after platform bringup
+                                       warning("URGENT: building for %s, but linking against dylib (%s) built for %s. "
+                                                       "Note: This will be an error in the future.",
+                                                       platforms.to_str().c_str(), path, lcPlatforms.to_str().c_str());
                        }
                }
-       }
+       });
 
        // figure out if we need to examine dependent dylibs
        // with compressed LINKEDIT format, MH_NO_REEXPORTED_DYLIBS can be trusted
@@ -539,6 +470,17 @@ void File<A>::buildExportHashTableFromExportInfo(const macho_dyld_info_command<P
 template <typename A>
 void File<A>::addSymbol(const char* name, bool weakDef, bool tlv, pint_t address)
 {
+       __block uint32_t linkMinOSVersion = 0;
+
+       this->platforms().forEach(^(ld::Platform platform, uint32_t version, bool &stop) {
+               //FIXME hack to handle symbol versioning in a zippered world.
+               //This will need to be rethought
+               if (linkMinOSVersion == 0)
+                       linkMinOSVersion = version;
+               if (platform == ld::kPlatform_macOS)
+                       linkMinOSVersion = version;
+       });
+
        // 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 ) {
@@ -547,7 +489,7 @@ void File<A>::addSymbol(const char* name, bool weakDef, bool tlv, pint_t address
                const char* symCond = strchr(symAction, '$');
                if ( symCond != nullptr ) {
                        char curOSVers[16];
-                       sprintf(curOSVers, "$os%d.%d$", (this->_linkMinOSVersion >> 16), ((this->_linkMinOSVersion >> 8) & 0xFF));
+                       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 ) {
@@ -630,7 +572,7 @@ public:
        {
                return new File<A>(fileContent, fileLength, path, mTime, ordinal, opts.flatNamespace(),
                                                   opts.linkingMainExecutable(), opts.implicitlyLinkIndirectPublicDylibs(),
-                                                  opts.platform(), opts.minOSversion(), opts.allowWeakImports(),
+                                                  opts.platforms(), opts.allowWeakImports(),
                                                   opts.allowSimulatorToLinkWithMacOSX(), opts.addVersionLoadCommand(),
                                                   opts.targetIOSSimulator(), opts.logAllFiles(), opts.installPath(),
                                                   indirectDylib, opts.outputKind() == Options::kPreload, opts.bundleBitcode());
@@ -848,7 +790,7 @@ const char* archName(const uint8_t* fileContent)
                return Parser<arm>::fileKind(fileContent);
        }
 #if SUPPORT_ARCH_arm64
-       if ( Parser<arm64>::validFile(fileContent, false) ) {
+       if ( Parser<arm64>::validFile(fileContent, true) ) {
                return Parser<arm64>::fileKind(fileContent);
        }
 #endif
@@ -856,43 +798,64 @@ const char* archName(const uint8_t* fileContent)
 }
 
 
-//
-// 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)
+static ld::dylib::File* parseAsArchitecture(const uint8_t* fileContent, uint64_t fileLength, const char* path,
+                                                                                       time_t modTime, const Options& opts, ld::File::Ordinal ordinal,
+                                                                                       bool bundleLoader, bool indirectDylib,
+                                                                                       cpu_type_t architecture, cpu_subtype_t subArchitecture)
 {
        bool subTypeMustMatch = opts.enforceDylibSubtypesMatch();
-       switch ( opts.architecture() ) {
+       switch ( architecture) {
 #if SUPPORT_ARCH_x86_64
                case CPU_TYPE_X86_64:
-                       if ( Parser<x86_64>::validFile(fileContent, bundleLoader, subTypeMustMatch, opts.subArchitecture()) )
+                       if ( Parser<x86_64>::validFile(fileContent, bundleLoader, subTypeMustMatch, subArchitecture) )
                                return Parser<x86_64>::parse(fileContent, fileLength, path, modTime, ordinal, opts, indirectDylib);
-                       break;
+                               break;
 #endif
 #if SUPPORT_ARCH_i386
                case CPU_TYPE_I386:
-                       if ( Parser<x86>::validFile(fileContent, bundleLoader, subTypeMustMatch, opts.subArchitecture()) )
+                       if ( Parser<x86>::validFile(fileContent, bundleLoader, subTypeMustMatch, subArchitecture) )
                                return Parser<x86>::parse(fileContent, fileLength, path, modTime, ordinal, opts, indirectDylib);
-                       break;
+                               break;
 #endif
 #if SUPPORT_ARCH_arm_any
                case CPU_TYPE_ARM:
-                       if ( Parser<arm>::validFile(fileContent, bundleLoader, subTypeMustMatch, opts.subArchitecture()) )
+                       if ( Parser<arm>::validFile(fileContent, bundleLoader, subTypeMustMatch, subArchitecture) )
                                return Parser<arm>::parse(fileContent, fileLength, path, modTime, ordinal, opts, indirectDylib);
-                       break;
+                               break;
 #endif
 #if SUPPORT_ARCH_arm64
                case CPU_TYPE_ARM64:
-                       if ( Parser<arm64>::validFile(fileContent, bundleLoader, subTypeMustMatch, opts.subArchitecture()) )
+                       if ( Parser<arm64>::validFile(fileContent, bundleLoader, subTypeMustMatch, subArchitecture) )
                                return Parser<arm64>::parse(fileContent, fileLength, path, modTime, ordinal, opts, indirectDylib);
-                       break;
+                               break;
 #endif
        }
        return nullptr;
 }
 
+//
+// 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)
+{
+       // First make sure we are even a dylib with a known arch.  If we aren't then there's no point in continuing.
+       if (!archName(fileContent))
+               return nullptr;
+
+       auto file = parseAsArchitecture(fileContent, fileLength, path, modtime, opts, ordinal, bundleLoader, indirectDylib, opts.architecture(), opts.subArchitecture());
+
+       // If we've been provided with an architecture we can fall back to, try to parse the dylib as that instead.
+       if (!file && opts.fallbackArchitecture()) {
+               warning("architecture %s not present in dylib file %s, attempting fallback", opts.architectureName(), path);
+               file = parseAsArchitecture(fileContent, fileLength, path, modtime, opts, ordinal, bundleLoader, indirectDylib, opts.fallbackArchitecture(), opts.fallbackSubArchitecture());
+       }
+               
+       return file;
+}
+       
+
 
 }; // namespace dylib
 }; // namespace mach_o
index ae3be5f5cd5ba86d9a1bd59fcca668870ee7b339..00d5feb0839c45e6ecee4f81689d506aa369a961 100644 (file)
@@ -80,11 +80,10 @@ public:
                                                                                                _dwarfTranslationUnitPath(NULL), 
                                                                                                _dwarfDebugInfoSect(NULL), _dwarfDebugAbbrevSect(NULL), 
                                                                                                _dwarfDebugLineSect(NULL), _dwarfDebugStringSect(NULL), 
-                                                                                               _objConstraint(ld::File::objcConstraintNone),
+                                                                                               _hasObjC(false),
                                                                                                _swiftVersion(0),
                                                                                                _cpuSubType(0),
                                                                                                _minOSVersion(0),
-                                                                                               _platform(Options::kPlatformUnknown),
                                                                                                _canScatterAtoms(false),
                                                                                                _hasllvmProfiling(false),
                                                                                                _objcHasCategoryClassPropertiesField(false),
@@ -95,11 +94,10 @@ public:
        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                                                                        platform() const                        { return _platform; }
+       virtual const ld::VersionSet&                                           platforms()     const                   { return _platforms; }
 
        // overrides of ld::relocatable::File 
-       virtual ObjcConstraint                                                          objCConstraint() const                  { return _objConstraint; }
+       virtual bool                                                                            hasObjC() const                                 { return _hasObjC; }
        virtual bool                                                                            objcHasCategoryClassPropertiesField() const 
                                                                                                                                                                        { return _objcHasCategoryClassPropertiesField; }
        virtual uint32_t                                                                        cpuSubType() const                              { return _cpuSubType; }
@@ -144,11 +142,11 @@ private:
        const macho_section<P>*                                 _dwarfDebugAbbrevSect;
        const macho_section<P>*                                 _dwarfDebugLineSect;
        const macho_section<P>*                                 _dwarfDebugStringSect;
-       ld::File::ObjcConstraint                                _objConstraint;
+       bool                                                                    _hasObjC;
        uint8_t                                                                 _swiftVersion;
        uint32_t                                                                _cpuSubType;
        uint32_t                                                                _minOSVersion;
-       Options::Platform                                               _platform;
+       ld::VersionSet                                                  _platforms;
        bool                                                                    _canScatterAtoms;
        bool                                                                    _hasllvmProfiling;
        bool                                                                    _objcHasCategoryClassPropertiesField;
@@ -995,7 +993,7 @@ 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 Options::Platform                                                findPlatform(const macho_header<typename A::P>* header);
+       static ld::Platform                                                             findPlatform(const macho_header<typename A::P>* header, uint32_t* minOsVers);
        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);
@@ -1026,6 +1024,9 @@ public:
                const char*     name;           // only used if targetAtom is NULL
                int64_t         addend;
                bool            weakImport;     // only used if targetAtom is NULL
+#if SUPPORT_ARCH_arm64e
+               ld::Fixup::AuthData authData; // only used for authenticated pointers
+#endif
        };
 
        struct FixupInAtom {
@@ -1044,6 +1045,11 @@ public:
                FixupInAtom(const SourceLocation& src, ld::Fixup::Cluster c, ld::Fixup::Kind k, uint64_t addend) :
                        fixup(src.offsetInAtom, c, k, addend), atom(src.atom) { src.atom->incrementFixupCount(); }
 
+#if SUPPORT_ARCH_arm64e
+               FixupInAtom(const SourceLocation& src, ld::Fixup::Cluster c, ld::Fixup::Kind k, ld::Fixup::AuthData authData) :
+                       fixup(src.offsetInAtom, c, k, authData), atom(src.atom) { src.atom->incrementFixupCount(); }
+#endif
+
                FixupInAtom(const SourceLocation& src, ld::Fixup::Cluster c, ld::Fixup::Kind k) :
                        fixup(src.offsetInAtom, c, k, (uint64_t)0), atom(src.atom) { src.atom->incrementFixupCount(); }
 
@@ -1071,6 +1077,12 @@ public:
                _allFixups.push_back(FixupInAtom(src, c, k, addend)); 
        }
 
+#if SUPPORT_ARCH_arm64e
+       void addFixup(const SourceLocation& src, ld::Fixup::Cluster c, ld::Fixup::Kind k, ld::Fixup::AuthData authData) {
+               _allFixups.push_back(FixupInAtom(src, c, k, authData));
+       }
+#endif
+
        void addFixup(const SourceLocation& src, ld::Fixup::Cluster c, ld::Fixup::Kind k) { 
                _allFixups.push_back(FixupInAtom(src, c, k)); 
        }
@@ -1210,7 +1222,8 @@ private:
                                                                                                                        bool verboseOptimizationHints, bool ignoreMismatchPlatform);
        ld::relocatable::File*                                                  parse(const ParserOptions& opts);
        static uint8_t                                                                  loadCommandSizeMask();
-       bool                                                                                    parseLoadCommands(Options::Platform platform, uint32_t minOSVersion, bool simulator, bool ignoreMismatchPlatform);
+       static bool                                     useSimulatorVariant();
+       bool                                                                                    parseLoadCommands(ld::VersionSet platforms, bool simulator, bool ignoreMismatchPlatform);
        void                                                                                    makeSections();
        void                                                                                    prescanSymbolTable();
        void                                                                                    makeSortedSymbolsArray(uint32_t symArray[], const uint32_t sectionArray[]);
@@ -1284,6 +1297,9 @@ private:
        const macho_section<P>*                                         _stubsMachOSection;
        std::vector<const char*>                                        _dtraceProviderInfo;
        std::vector<FixupInAtom>                                        _allFixups;
+#if SUPPORT_ARCH_arm64e
+       bool                                                                            _supportsAuthenticatedPointers;
+#endif
 };
 
 
@@ -1371,6 +1387,8 @@ bool Parser<arm64>::validFile(const uint8_t* fileContent, bool subtypeMustMatch,
                return false;
        if ( header->filetype() != MH_OBJECT )
                return false;
+       if ( subtypeMustMatch && (header->cpusubtype() != (uint32_t)subtype) )
+               return false;
        return true;
 }
 
@@ -1562,16 +1580,27 @@ template <typename A>
 bool Parser<A>::LabelAndCFIBreakIterator::next(Parser<A>& parser, const Section<A>& sect, uint32_t sectNum, pint_t startAddr, pint_t endAddr, 
                                                                                                pint_t* addr, pint_t* size, const macho_nlist<P>** symbol)
 {
+       bool cfiApplicable = (sect.machoSection()->flags() & (S_ATTR_PURE_INSTRUCTIONS | S_ATTR_SOME_INSTRUCTIONS));
        // may not be a label on start of section, but need atom demarcation there
        if ( newSection ) {
                newSection = false;
                // advance symIndex until we get to the first label at or past the start of this section
                while ( symIndex < sortedSymbolCount ) {
-                       const macho_nlist<P>& sym = parser.symbolFromIndex(sortedSymbolIndexes[symIndex]);
-                       if ( ! sect.ignoreLabel(parser.nameFromSymbol(sym)) ) {
-                               pint_t nextSymbolAddr = sym.n_value();
+                       const macho_nlist<P>* sym = &parser.symbolFromIndex(sortedSymbolIndexes[symIndex]);
+                       // if compile threw in "ltmp*" symbol at start of section and there is another real label at same location, ignore ltmp one
+                       if ( symIndex+1 < sortedSymbolCount ) {
+                               const macho_nlist<P>* sym2 = &parser.symbolFromIndex(sortedSymbolIndexes[symIndex+1]);
+                               if ( (sym->n_sect() == sym2->n_sect()) && (sym->n_value() == sym2->n_value()) ) {
+                                       if ( strncmp(parser.nameFromSymbol(*sym), "ltmp", 4) == 0 ) {
+                                               ++symIndex;
+                                               sym = sym2;
+                                       }
+                               }
+                       }
+                       if ( ! sect.ignoreLabel(parser.nameFromSymbol(*sym)) ) {
+                               pint_t nextSymbolAddr = sym->n_value();
                                //fprintf(stderr, "sectNum=%d, nextSymbolAddr=0x%08llX, name=%s\n", sectNum, (uint64_t)nextSymbolAddr, parser.nameFromSymbol(sym));
-                               if ( (nextSymbolAddr > startAddr) || ((nextSymbolAddr == startAddr) && (sym.n_sect() == sectNum)) )
+                               if ( (nextSymbolAddr > startAddr) || ((nextSymbolAddr == startAddr) && (sym->n_sect() == sectNum)) )
                                        break;
                        }
                        ++symIndex;
@@ -1621,7 +1650,7 @@ bool Parser<A>::LabelAndCFIBreakIterator::next(Parser<A>& parser, const Section<
                        return true;
                }
                // no symbols in section, check CFI
-               if ( cfiIndex < cfiStartsCount ) {
+               if ( cfiApplicable && (cfiIndex < cfiStartsCount) ) {
                        pint_t nextCfiAddr = cfiStartsArray[cfiIndex];
                        if ( nextCfiAddr < endAddr ) {
                                // use cfi
@@ -1749,6 +1778,10 @@ ld::relocatable::File* Parser<A>::parse(const ParserOptions& opts)
        _treateBitcodeAsData = opts.treateBitcodeAsData;
        _usingBitcode = opts.usingBitcode;
 
+#if SUPPORT_ARCH_arm64e
+       _supportsAuthenticatedPointers = opts.supportsAuthenticatedPointers;
+#endif
+
        // respond to -t option
        if ( opts.logAllFiles )
                printf("%s\n", _path);
@@ -1757,7 +1790,7 @@ ld::relocatable::File* Parser<A>::parse(const ParserOptions& opts)
        _maxDefaultCommonAlignment = opts.maxDefaultCommonAlignment;
 
        // parse start of mach-o file
-       if ( ! parseLoadCommands(opts.platform, opts.minOSVersion, opts.simulator, opts.ignoreMismatchPlatform) )
+       if ( ! parseLoadCommands(opts.platforms, opts.simulator, opts.ignoreMismatchPlatform) )
                return _file;
        
        // make array of
@@ -1999,9 +2032,13 @@ template <> uint8_t Parser<x86>::loadCommandSizeMask()           { return 0x03; }
 template <> uint8_t Parser<x86_64>::loadCommandSizeMask()      { return 0x07; }
 template <> uint8_t Parser<arm>::loadCommandSizeMask()         { return 0x03; }
 template <> uint8_t Parser<arm64>::loadCommandSizeMask()       { return 0x07; }
+template <> bool Parser<x86>::useSimulatorVariant() { return true; }
+template <> bool Parser<x86_64>::useSimulatorVariant() { return true; }
+template <typename A> bool Parser<A>::useSimulatorVariant() { return false; }
+
 
 template <typename A>
-bool Parser<A>::parseLoadCommands(Options::Platform platform, uint32_t linkMinOSVersion, bool simulator, bool ignoreMismatchPlatform)
+bool Parser<A>::parseLoadCommands(ld::VersionSet platforms, bool simulator, bool ignoreMismatchPlatform)
 {
        const macho_header<P>* header = (const macho_header<P>*)_fileContent;
 
@@ -2015,7 +2052,7 @@ bool Parser<A>::parseLoadCommands(Options::Platform platform, uint32_t linkMinOS
        // <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;
+       ld::VersionSet lcPlatforms;
        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;
@@ -2097,23 +2134,19 @@ bool Parser<A>::parseLoadCommands(Options::Platform platform, uint32_t linkMinOS
                        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;
-                               lcPlatform = Options::platformForLoadCommand(cmd->cmd());
-                               _file->_platform = lcPlatform;
-                               _file->_minOSVersion = ((macho_version_min_command<P>*)cmd)->version();
+                               lcPlatforms.add({Options::platformForLoadCommand(cmd->cmd(), useSimulatorVariant()), ((macho_version_min_command<P>*)cmd)->version()});
+                               _file->_platforms.add({Options::platformForLoadCommand(cmd->cmd(), useSimulatorVariant()), ((macho_version_min_command<P>*)cmd)->version()});
                                break;
                        case LC_BUILD_VERSION:
                                {
                                        const macho_build_version_command<P>* buildVersCmd = (macho_build_version_command<P>*)cmd;
                                        if ( ignoreMismatchPlatform )
                                                break;
-                                       lcPlatform = (Options::Platform)buildVersCmd->platform();
-                                       _file->_platform = lcPlatform;
-                                       _file->_minOSVersion = buildVersCmd->minos();
+                                       lcPlatforms.add({(ld::Platform)buildVersCmd->platform(), buildVersCmd->minos()});
+                                       _file->_platforms.add({(ld::Platform)buildVersCmd->platform(), buildVersCmd->minos()});
                                        const macho_build_tool_version<P>* entry = (macho_build_tool_version<P>*)((uint8_t*)cmd + sizeof(macho_build_version_command<P>));
                                        for (uint32_t t=0; t < buildVersCmd->ntools(); ++t) {
                                                _file->_toolVersions.push_back(std::make_pair(entry->tool(), entry->version()));
@@ -2134,80 +2167,63 @@ bool Parser<A>::parseLoadCommands(Options::Platform platform, uint32_t linkMinOS
                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 &&
+       if (lcPlatforms.empty() &&
                (std::is_same<A, arm>::value || std::is_same<A, arm64>::value))
-               lcPlatform = Options::kPlatformiOS;
+               lcPlatforms.add({ld::kPlatform_iOS,0});
 
        // 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::kPlatform_bridgeOS:
-                               case Options::kPlatformWatchOS:
-                                       // Error when using bitcocde, warning otherwise.
-                                       if (_usingBitcode)
-                                               throwf("building for %s%s, but linking in object file built for %s,",
-                                                  Options::platformName(platform), (simulator ? " simulator" : ""),
-                                                  Options::platformName(lcPlatform));
-                                       else
-                                               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;
-       #if SUPPORT_APPLE_TV
-                               case Options::kPlatform_tvOS:
-                                       // Error when using bitcocde, warning otherwise.
-                                       if (_usingBitcode)
-                                               throwf("building for %s%s, but linking in object file built for %s,",
-                                                          Options::platformName(platform), (simulator ? " simulator" : ""),
-                                                          Options::platformName(lcPlatform));
-                                       else
-                                               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;
+               __block bool warned = false;
+               platforms.forEach(^(ld::Platform platform, uint32_t version, bool &stop) {
+                       if ( !warned && !lcPlatforms.contains(platform) ) {
+                               if (_usingBitcode)
+                                       throwf("building for %s, but linking in object file built for %s,",
+                                                  platforms.to_str().c_str(), lcPlatforms.to_str().c_str());
+#if 0
+// FIXME: Re-enable once clang supports zippering
+// <rdar://problem/36749415> Turn off "urgent:" linker warning about iOSMac / macOS mismatch
+                               else
+                                       warning("URGENT: building for %s, but linking in object file (%s) built for %s. "
+                                                       "Note: This will be an error in the future.",
+                                                       platforms.to_str().c_str(), path(), lcPlatforms.to_str().c_str());
+#endif
+                               warned = true;
                        }
-               }
-               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);
-               }
+                       if ( version && (lcPlatforms.minOS(platform) > version) ) {
+                               char t1[32];
+                               char t2[32];
+                               versionToString(lcPlatforms.minOS(platform), t1);
+                               versionToString(version, t2);
+                               warning("object file (%s) was built for newer %s version (%s) than being linked (%s)",
+                                               _path, Options::platformName(platform), t1, t2);
+                       }
+               });
        }
 
-
-       // record range of sections
+       // validate just one segment
        if ( segment == NULL ) 
                throw "missing LC_SEGMENT";
+       if ( segment->filesize() > _fileLength )
+               throw "LC_SEGMENT filesize too large";
+
+       // record and validate sections
        _sectionsStart = (macho_section<P>*)((char*)segment + sizeof(macho_segment_command<P>));
        _machOSectionsCount = segment->nsects();
        if ( (sizeof(macho_segment_command<P>) + _machOSectionsCount * sizeof(macho_section<P>)) > segment->cmdsize() )
                throw "too many sections for size of LC_SEGMENT command";
+
        return true;
 }
 
 template <typename A>
-Options::Platform Parser<A>::findPlatform(const macho_header<P>* header)
+ld::Platform Parser<A>::findPlatform(const macho_header<P>* header, uint32_t* minOsVers)
 {
        const uint32_t cmd_count = header->ncmds();
        if ( cmd_count == 0 )
-               return Options::kPlatformUnknown;
+               return ld::kPlatform_unknown;
        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;
@@ -2218,25 +2234,37 @@ Options::Platform Parser<A>::findPlatform(const macho_header<P>* header)
                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);
+               const macho_version_min_command<P>* versCmd = (macho_version_min_command<P>*)cmd;
+               const macho_build_version_command<P>* buildVersCmd = (macho_build_version_command<P>*)cmd;
+               *minOsVers = versCmd->version();
                switch (cmd->cmd()) {
                        case LC_VERSION_MIN_MACOSX:
-                               return Options::kPlatformOSX;
+                               return ld::kPlatform_macOS;
                        case LC_VERSION_MIN_IPHONEOS:
-                               return Options::kPlatformiOS;
+                               if (useSimulatorVariant())
+                                       return ld::kPlatform_iOSSimulator;
+                               else
+                                       return ld::kPlatform_iOS;
                        case LC_VERSION_MIN_WATCHOS:
-                               return Options::kPlatformWatchOS;
-       #if SUPPORT_APPLE_TV
+                               if (useSimulatorVariant())
+                                       return ld::kPlatform_watchOSSimulator;
+                               else
+                                       return ld::kPlatform_watchOS;
                        case LC_VERSION_MIN_TVOS:
-                               return Options::kPlatform_tvOS;
-       #endif
+                               if (useSimulatorVariant())
+                                       return ld::kPlatform_tvOSSimulator;
+                               else
+                                       return ld::kPlatform_tvOS;
                        case LC_BUILD_VERSION:
-                               return (Options::Platform)((macho_build_version_command<P>*)cmd)->platform();
+                               *minOsVers = buildVersCmd->minos();
+                               return (ld::Platform)buildVersCmd->platform();
                }
                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;
+       *minOsVers = 0;
+       return ld::kPlatform_unknown;
 }
 
 
@@ -2578,14 +2606,7 @@ void Parser<A>::makeSections()
                        const uint32_t* contents = (uint32_t*)(_file->fileContent()+sect->offset());
                        if ( (sect->size() >= 8) && (contents[0] == 0) ) {
                                uint32_t flags = E::get32(contents[1]);
-                               if ( (flags & 4) == 4 )
-                                       _file->_objConstraint = ld::File::objcConstraintGC;
-                               else if ( (flags & 2) == 2 )
-                                       _file->_objConstraint = ld::File::objcConstraintRetainReleaseOrGC;
-                               else if ( (flags & 32) == 32 )
-                                       _file->_objConstraint = ld::File::objcConstraintRetainReleaseForSimulator;
-                               else
-                                       _file->_objConstraint = ld::File::objcConstraintRetainRelease;
+                               _file->_hasObjC = true;
                                _file->_swiftVersion = ((flags >> 8) & 0xFF);
                 _file->_objcHasCategoryClassPropertiesField = (flags & 64);
                                if ( sect->size() > 8 ) {
@@ -3055,6 +3076,13 @@ void Parser<A>::addFixups(const SourceLocation& src, ld::Fixup::Kind setKind, co
        ld::Fixup::Cluster cl = ld::Fixup::k1of3;
        ld::Fixup::Kind firstKind = ld::Fixup::kindSetTargetAddress;
        bool combined = false;
+
+#if SUPPORT_ARCH_arm64e
+       bool isAuthenticated = setKind == ld::Fixup::kindStoreLittleEndianAuth64;
+       // Authenticated pointers need an extra fixup for the auth data.
+       if (isAuthenticated)
+               cl = ld::Fixup::k2of4;
+#endif
        if ( target.addend == 0 ) {
                cl = ld::Fixup::k1of1;
                combined = true;
@@ -3114,6 +3142,12 @@ void Parser<A>::addFixups(const SourceLocation& src, ld::Fixup::Kind setKind, co
                        case ld::Fixup::kindStoreARM64TLVPLoadPageOff12:
                                firstKind = ld::Fixup::kindStoreTargetAddressARM64TLVPLoadPageOff12;
                                break;
+#endif
+#if SUPPORT_ARCH_arm64e
+                       case ld::Fixup::kindStoreLittleEndianAuth64:
+                               firstKind = ld::Fixup::kindStoreTargetAddressLittleEndianAuth64;
+                               cl = ld::Fixup::k2of2;
+                               break;
 #endif
                        default:
                                combined = false;
@@ -3122,6 +3156,19 @@ void Parser<A>::addFixups(const SourceLocation& src, ld::Fixup::Kind setKind, co
                }
        }
 
+#if SUPPORT_ARCH_arm64e
+       // As the auth data is independent of the addend and target, we can just always
+       // put it first.
+       if (isAuthenticated) {
+               if (cl == ld::Fixup::k2of2) {
+                       addFixup(src, ld::Fixup::k1of2, ld::Fixup::kindSetAuthData, target.authData);
+               } else {
+                       assert(cl == ld::Fixup::k2of4);
+                       addFixup(src, ld::Fixup::k1of4, ld::Fixup::kindSetAuthData, target.authData);
+               }
+       }
+#endif
+
        if ( target.atom != NULL ) {
                if ( target.atom->scope() == ld::Atom::scopeTranslationUnit ) {
                        addFixup(src, cl, firstKind, target.atom);
@@ -3146,12 +3193,24 @@ void Parser<A>::addFixups(const SourceLocation& src, ld::Fixup::Kind setKind, co
                addFixup(src, cl, firstKind, target.weakImport, target.name);
        }
        if ( target.addend == 0 ) {
+#if SUPPORT_ARCH_arm64e
+               if (isAuthenticated)
+                       assert(combined);
+#endif
                if ( ! combined )
                        addFixup(src, ld::Fixup::k2of2, setKind);
        }
        else {
-               addFixup(src, ld::Fixup::k2of3, ld::Fixup::kindAddAddend, target.addend);
-               addFixup(src, ld::Fixup::k3of3, setKind);
+#if SUPPORT_ARCH_arm64e
+               if (isAuthenticated) {
+                       addFixup(src, ld::Fixup::k3of4, ld::Fixup::kindAddAddend, target.addend);
+                       addFixup(src, ld::Fixup::k4of4, setKind);
+               } else
+#endif
+               {
+                       addFixup(src, ld::Fixup::k2of3, ld::Fixup::kindAddAddend, target.addend);
+                       addFixup(src, ld::Fixup::k3of3, setKind);
+               }
        }
 }
 
@@ -5470,7 +5529,7 @@ uint32_t ImplicitSizeSection<A>::appendAtoms(class Parser<A>& parser, uint8_t* p
                        }
                        else {
                                // make named atom for label
-                               //fprintf(stderr, "  0x%08llX make labeled\n", (uint64_t)foundAddr);
+                               //fprintf(stderr, "  0x%08llX make labeled: %s\n", (uint64_t)foundAddr, parser.nameFromSymbol(*foundLabel));
                                new (allocatedSpace) Atom<A>(*this, parser, *foundLabel, labeledAtomSize);
                        }
                        if ( !skip ) {
@@ -6308,6 +6367,8 @@ bool Section<x86_64>::addRelocFixup(class Parser<x86_64>& parser, const macho_re
        Parser<x86_64>::TargetDesc              target;
        Parser<x86_64>::TargetDesc              toTarget;
        src.atom = this->findAtomByAddress(srcAddr);
+       if ( src.atom == NULL )
+               throwf("malformed mach-o, reloc addr 0x%llX not in any atom", srcAddr);
        src.offsetInAtom = srcAddr - src.atom->_objAddress;
        const uint8_t* fixUpPtr = file().fileContent() + sect->offset() + reloc->r_address();
        uint64_t contentValue = 0;
@@ -7524,6 +7585,52 @@ bool Section<arm64>::addRelocFixup(class Parser<arm64>& parser, const macho_relo
                 parser.addFixups(src, ld::Fixup::kindStoreARM64PointerToGOT, target);
             }
             break;
+#if SUPPORT_ARCH_arm64e
+               case ARM64_RELOC_AUTHENTICATED_POINTER: {
+                       if ( reloc->r_pcrel() )
+                               throw "pcrel and ARM64_RELOC_AUTHENTICATED_POINTER not supported";
+                       if ( ! reloc->r_extern() )
+                               throw "r_extern == 0 and ARM64_RELOC_AUTHENTICATED_POINTER not supported";
+                       // An authenticated pointer is:
+                       // {
+                       //       int32_t addend;
+                       //       uint16_t diversityData;
+                       //       uint16_t hasAddressDiversity : 1;
+                       //       uint16_t key : 2;
+                       //       uint16_t zeroes : 11;
+                       //       uint16_t zero : 1;
+                       //       uint16_t authenticated : 1;
+                       // }
+                       target.addend = (int32_t)(contentValue & 0xFFFFFFFF);
+                       if (parser._supportsAuthenticatedPointers) {
+                               target.authData.discriminator = (uint16_t)(contentValue >> 32);
+                               target.authData.hasAddressDiversity = (contentValue & (1ULL << 48)) != 0;
+                               target.authData.key = (ld::Fixup::AuthData::ptrauth_key)((contentValue >> 49) & 0x3);
+                       } else {
+                               static bool emittedWarning = false;
+                               if (!emittedWarning) {
+                                       emittedWarning = true;
+                                       warning("stripping authenticated relocation as image uses -preload or -static");
+                               }
+                       }
+                       bool isAuthenticated = (contentValue & (1ULL << 63)) != 0;
+                       if (!isAuthenticated)
+                               throw "ARM64_RELOC_AUTHENTICATED_POINTER value must have authenticated bit set";
+                       switch ( reloc->r_length() ) {
+                               case 0:
+                               case 1:
+                               case 2:
+                                       throw "length < 3 and ARM64_RELOC_AUTHENTICATED_POINTER not supported";
+                               case 3:
+                                       if (parser._supportsAuthenticatedPointers)
+                                               parser.addFixups(src, ld::Fixup::kindStoreLittleEndianAuth64, target);
+                                       else
+                                               parser.addFixups(src, ld::Fixup::kindStoreLittleEndian64, target);
+                                       break;
+                       }
+                       break;
+               }
+#endif
                default:
                        throwf("unknown relocation type %d", reloc->r_type());
        }
@@ -7930,34 +8037,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
 //
-bool isObjectFile(const uint8_t* fileContent, cpu_type_t* result, cpu_subtype_t* subResult, Options::Platform* platform)
+bool isObjectFile(const uint8_t* fileContent, cpu_type_t* result, cpu_subtype_t* subResult, ld::Platform* platform, uint32_t* minOsVers)
 {
        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);
+               *platform = Parser<x86_64>::findPlatform(header, minOsVers);
                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;
-               *platform = Parser<x86>::findPlatform(header);
+               *platform = Parser<x86>::findPlatform(header, minOsVers);
                return true;
        }
        if ( mach_o::relocatable::Parser<arm>::validFile(fileContent, false, 0) ) {
                const macho_header<Pointer32<LittleEndian> >* header = (const macho_header<Pointer32<LittleEndian> >*)fileContent;
                *result = CPU_TYPE_ARM;
                *subResult = header->cpusubtype();
-               *platform = Parser<arm>::findPlatform(header);
+               *platform = Parser<arm>::findPlatform(header, minOsVers);
                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 = header->cpusubtype();
-               *platform = Parser<arm64>::findPlatform(header);
+               *platform = Parser<arm64>::findPlatform(header, minOsVers);
                return true;
        }
        return false;
@@ -8027,9 +8134,11 @@ bool getNonLocalSymbols(const uint8_t* fileContent, std::vector<const char*> &sy
        else if ( mach_o::relocatable::Parser<x86>::validFile(fileContent, false, 0) ) {
                return mach_o::relocatable::Parser<x86>::getNonLocalSymbols(fileContent, syms);
        }
+#if SUPPORT_ARCH_arm64
        else if ( mach_o::relocatable::Parser<arm64>::validFile(fileContent, false, 0) ) {
                return mach_o::relocatable::Parser<arm64>::getNonLocalSymbols(fileContent, syms);
        }
+#endif
        return false;
 }
 
index e31f7f902b9e37e331713ae486ad3956bdd8d033..c8e98cf5d653845db4b3cbaacb428ca0145b6859 100644 (file)
@@ -43,9 +43,11 @@ struct ParserOptions {
        bool                    armUsesZeroCostExceptions;
        bool                    simulator;
        bool                    ignoreMismatchPlatform;
+#if SUPPORT_ARCH_arm64e
+       bool                    supportsAuthenticatedPointers;
+#endif
        uint32_t                subType;
-       Options::Platform platform;
-       uint32_t                minOSVersion;
+       ld::VersionSet  platforms;
        ld::relocatable::File::SourceKind       srcKind;
        bool                    treateBitcodeAsData;
        bool                    usingBitcode;
@@ -58,7 +60,7 @@ 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, cpu_type_t* result, cpu_subtype_t* subResult, Options::Platform* platform);
+extern bool isObjectFile(const uint8_t* fileContent, cpu_type_t* result, cpu_subtype_t* subResult, ld::Platform* platform, uint32_t* minOsVers);
 
 extern bool hasObjC2Categories(const uint8_t* fileContent);                                    
 
index 27c456010e8fde56378dcca2a7bc52d81a7330ba..e15e2e905770a5d235c2d286d5ee45dca5130d83 100644 (file)
@@ -53,82 +53,107 @@ public:
                                        File(const char* path, const uint8_t* fileContent, uint64_t fileLength, const Options *opts,
                                                 time_t mTime, ld::File::Ordinal ordinal, bool linkingFlatNamespace,
                                                 bool linkingMainExecutable, bool hoistImplicitPublicDylibs,
-                                                Options::Platform platform, uint32_t linkMinOSVersion, bool allowWeakImports,
+                                                const ld::VersionSet& platforms, bool allowWeakImports,
                                                 cpu_type_t cpuType, cpu_subtype_t cpuSubType, bool enforceDylibSubtypesMatch,
                                                 bool allowSimToMacOSX, bool addVers, bool buildingForSimulator,
-                                                bool logAllFiles, const char* installPath, bool indirectDylib);
-                                       File(std::unique_ptr<tapi::LinkerInterfaceFile> &&file, const char *path, const Options *opts,
+                                                bool logAllFiles, const char* installPath, bool indirectDylib,
+                                                bool ignoreMismatchPlatform, bool usingBitcode);
+                                       File(tapi::LinkerInterfaceFile* file, const char *path, const Options *opts,
                                                 time_t mTime, ld::File::Ordinal ordinal, bool linkingFlatNamespace,
                                                 bool linkingMainExecutable, bool hoistImplicitPublicDylibs,
-                                                Options::Platform platform, uint32_t linkMinOSVersion, bool allowWeakImports,
+                                                const ld::VersionSet& platforms, bool allowWeakImports,
                                                 cpu_type_t cpuType, cpu_subtype_t cpuSubType, bool enforceDylibSubtypesMatch,
                                                 bool allowSimToMacOSX, bool addVers, bool buildingForSimulator,
-                                                bool logAllFiles, const char* installPath, bool indirectDylib);
+                                                bool logAllFiles, const char* installPath, bool indirectDylib,
+                                                bool ignoreMismatchPlatform, bool usingBitcode);
        virtual                 ~File() noexcept {}
        
        // overrides of generic::dylib::File
        virtual void    processIndirectLibraries(ld::dylib::File::DylibHandler*, bool addImplicitDylibs) override final;
 
 private:
-       void                    init(tapi::LinkerInterfaceFile *file, const Options *opts, bool buildingForSimulator,
-                                                bool indirectDylib, bool linkingFlatNamespace, bool linkingMainExecutable,
-                                                const char *path, Options::Platform platform, const char *targetInstallPath);
-       void                    buildExportHashTable(const tapi::LinkerInterfaceFile* file);
+       void                            init(tapi::LinkerInterfaceFile* file, const Options *opts, bool buildingForSimulator,
+                                                                        bool indirectDylib, bool linkingFlatNamespace, bool linkingMainExecutable,
+                                                                        const char *path, const ld::VersionSet& platforms, const char *targetInstallPath,
+                                                                        bool ignoreMismatchPlatform, bool usingBitcode);
+       void                            buildExportHashTable(const tapi::LinkerInterfaceFile* file);
+       static bool useSimulatorVariant();
        
-       const Options   *_opts;
-       std::unique_ptr<tapi::LinkerInterfaceFile> _interface;
+       const Options_opts;
+       tapi::LinkerInterfaceFile* _interface;
 };
 
-static ld::File::ObjcConstraint mapObjCConstraint(tapi::ObjCConstraint constraint) {
-       switch (constraint) {
-       case tapi::ObjCConstraint::None:
-               return ld::File::objcConstraintNone;
-       case tapi::ObjCConstraint::Retain_Release:
-               return ld::File::objcConstraintRetainRelease;
-       case tapi::ObjCConstraint::Retain_Release_For_Simulator:
-               return ld::File::objcConstraintRetainReleaseForSimulator;
-       case tapi::ObjCConstraint::Retain_Release_Or_GC:
-               return ld::File::objcConstraintRetainReleaseOrGC;
-       case tapi::ObjCConstraint::GC:
-               return ld::File::objcConstraintGC;
-       }
+template <> bool File<x86>::useSimulatorVariant() { return true; }
+template <> bool File<x86_64>::useSimulatorVariant() { return true; }
+template <typename A> bool File<A>::useSimulatorVariant() { return false; }
 
-       return ld::File::objcConstraintNone;
-}
 
-static Options::Platform mapPlatform(tapi::Platform platform) {
+static ld::VersionSet mapPlatform(tapi::Platform platform, bool useSimulatorVariant) {
+       ld::VersionSet platforms;
        switch (platform) {
        case tapi::Platform::Unknown:
-               return Options::kPlatformUnknown;
+               break;
        case tapi::Platform::OSX:
-               return Options::kPlatformOSX;
+               platforms.add({ld::kPlatform_macOS, 0});
+               break;
        case tapi::Platform::iOS:
-               return Options::kPlatformiOS;
+               if (useSimulatorVariant)
+                       platforms.add({ld::kPlatform_iOSSimulator, 0});
+               else
+                       platforms.add({ld::kPlatform_iOS, 0});
+               break;
        case tapi::Platform::watchOS:
-               return Options::kPlatformWatchOS;
+               if (useSimulatorVariant)
+                       platforms.add({ld::kPlatform_watchOSSimulator, 0});
+               else
+                       platforms.add({ld::kPlatform_watchOS, 0});
+               break;
        case tapi::Platform::tvOS:
-               return Options::kPlatform_tvOS;
+               if (useSimulatorVariant)
+                       platforms.add({ld::kPlatform_tvOSSimulator, 0});
+               else
+                       platforms.add({ld::kPlatform_tvOS, 0});
+               break;
        #if ((TAPI_API_VERSION_MAJOR == 1 &&  TAPI_API_VERSION_MINOR >= 2) || (TAPI_API_VERSION_MAJOR > 1))
        case tapi::Platform::bridgeOS:
-               return Options::kPlatform_bridgeOS;
+               platforms.add({ld::kPlatform_bridgeOS, 0});
+               break;
+       #endif
+       #if ((TAPI_API_VERSION_MAJOR == 1 &&  TAPI_API_VERSION_MINOR >= 4) || (TAPI_API_VERSION_MAJOR > 1))
+       case tapi::Platform::iOSMac:
+               platforms.add({ld::kPlatform_iOSMac, 0});
+               break;
+       case tapi::Platform::zippered:
+               platforms.add({ld::kPlatform_macOS, 0});
+               platforms.add({ld::kPlatform_iOSMac, 0});
+               break;
        #endif
        }
 
-       return Options::kPlatformUnknown;
+       return platforms;
 }
 
-       template <typename A>
-       File<A>::File(const char* path, const uint8_t* fileContent, uint64_t fileLength, const Options *opts,
-                         time_t mTime, ld::File::Ordinal ord, bool linkingFlatNamespace,
-                         bool linkingMainExecutable, bool hoistImplicitPublicDylibs, Options::Platform platform,
-                         uint32_t linkMinOSVersion, bool allowWeakImports, cpu_type_t cpuType, cpu_subtype_t cpuSubType,
-                               bool enforceDylibSubtypesMatch, bool allowSimToMacOSX, bool addVers,
-                         bool buildingForSimulator, bool logAllFiles, const char* targetInstallPath,
-                         bool indirectDylib)
-       : Base(strdup(path), mTime, ord, platform, linkMinOSVersion, allowWeakImports, linkingFlatNamespace,
-                  hoistImplicitPublicDylibs, allowSimToMacOSX, addVers)
+template <typename A>
+File<A>::File(const char* path, const uint8_t* fileContent, uint64_t fileLength, const Options *opts,
+                 time_t mTime, ld::File::Ordinal ord, bool linkingFlatNamespace,
+                 bool linkingMainExecutable, bool hoistImplicitPublicDylibs, const ld::VersionSet& platforms,
+                 bool allowWeakImports, cpu_type_t cpuType, cpu_subtype_t cpuSubType,
+                 bool enforceDylibSubtypesMatch, bool allowSimToMacOSX, bool addVers,
+                 bool buildingForSimulator, bool logAllFiles, const char* targetInstallPath,
+                 bool indirectDylib, bool ignoreMismatchPlatform, bool usingBitcode)
+: Base(strdup(path), mTime, ord, platforms, allowWeakImports, linkingFlatNamespace,
+          hoistImplicitPublicDylibs, allowSimToMacOSX, addVers)
 {
+       std::unique_ptr<tapi::LinkerInterfaceFile> file;
        std::string errorMessage;
+       __block uint32_t linkMinOSVersion = 0;
+       //FIXME handle this correctly once we have multi-platfrom TAPI
+       platforms.forEach(^(ld::Platform platform, uint32_t version, bool &stop) {
+               if (linkMinOSVersion == 0)
+                       linkMinOSVersion = version;
+               if (platform == ld::kPlatform_macOS)
+                       linkMinOSVersion = version;
+       });
 
 // <rdar://problem/29038544> Support $ld$weak symbols in .tbd files
 #if ((TAPI_API_VERSION_MAJOR == 1 &&  TAPI_API_VERSION_MINOR >= 3) || (TAPI_API_VERSION_MAJOR > 1))
@@ -141,9 +166,9 @@ static Options::Platform mapPlatform(tapi::Platform platform) {
                if (!allowWeakImports)
                        flags |= tapi::ParsingFlags::DisallowWeakImports;
 
-               _interface.reset(tapi::LinkerInterfaceFile::create(
+               _interface = tapi::LinkerInterfaceFile::create(
                        path, cpuType, cpuSubType, flags,
-                       tapi::PackedVersion32(linkMinOSVersion), errorMessage));
+                       tapi::PackedVersion32(linkMinOSVersion), errorMessage);
        } else
 #endif
 #if ((TAPI_API_VERSION_MAJOR == 1 &&  TAPI_API_VERSION_MINOR >= 1) || (TAPI_API_VERSION_MAJOR > 1))
@@ -155,9 +180,9 @@ static Options::Platform mapPlatform(tapi::Platform platform) {
                if (!allowWeakImports)
                        flags |= tapi::ParsingFlags::DisallowWeakImports;
 
-               _interface.reset(tapi::LinkerInterfaceFile::create(
+               _interface = tapi::LinkerInterfaceFile::create(
                        path, fileContent, fileLength, cpuType, cpuSubType, flags,
-                       tapi::PackedVersion32(linkMinOSVersion), errorMessage));
+                       tapi::PackedVersion32(linkMinOSVersion), errorMessage);
        } else
 #endif
 #if (TAPI_API_VERSION_MAJOR >= 1)
@@ -165,9 +190,9 @@ static Options::Platform mapPlatform(tapi::Platform platform) {
                auto matchingType = enforceDylibSubtypesMatch ?
                        tapi::CpuSubTypeMatching::Exact : tapi::CpuSubTypeMatching::ABI_Compatible;
 
-               _interface.reset(tapi::LinkerInterfaceFile::create(
+               _interface = tapi::LinkerInterfaceFile::create(
                        path, fileContent, fileLength, cpuType, cpuSubType, matchingType,
-                       tapi::PackedVersion32(linkMinOSVersion), errorMessage));
+                       tapi::PackedVersion32(linkMinOSVersion), errorMessage);
        }
 #endif
 
@@ -181,29 +206,31 @@ static Options::Platform mapPlatform(tapi::Platform platform) {
        if ( logAllFiles )
                printf("%s\n", path);
 
-       init(_interface.get(), opts, buildingForSimulator, indirectDylib, linkingFlatNamespace,
-                linkingMainExecutable, path, platform, targetInstallPath);
+       init(_interface, opts, buildingForSimulator, indirectDylib, linkingFlatNamespace,
+                linkingMainExecutable, path, platforms, targetInstallPath, ignoreMismatchPlatform, usingBitcode);
 }
 
        template<typename A>
-       File<A>::File(std::unique_ptr<tapi::LinkerInterfaceFile> &&file, const char* path, const Options *opts,
+       File<A>::File(tapi::LinkerInterfaceFile* file, const char* path, const Options *opts,
                                  time_t mTime, ld::File::Ordinal ordinal, bool linkingFlatNamespace,
                                 bool linkingMainExecutable, bool hoistImplicitPublicDylibs,
-                                Options::Platform platform, uint32_t linkMinOSVersion, bool allowWeakImports,
+                                const ld::VersionSet& platforms, bool allowWeakImports,
                                 cpu_type_t cpuType, cpu_subtype_t cpuSubType, bool enforceDylibSubtypesMatch,
                                 bool allowSimToMacOSX, bool addVers, bool buildingForSimulator,
-                                bool logAllFiles, const char* installPath, bool indirectDylib)
-       : Base(strdup(path), mTime, ordinal, platform, linkMinOSVersion, allowWeakImports, linkingFlatNamespace,
-                  hoistImplicitPublicDylibs, allowSimToMacOSX, addVers), _interface(std::move(file))
+                                bool logAllFiles, const char* installPath, bool indirectDylib,
+                                bool ignoreMismatchPlatform, bool usingBitcode)
+       : Base(strdup(path), mTime, ordinal, platforms, allowWeakImports, linkingFlatNamespace,
+                  hoistImplicitPublicDylibs, allowSimToMacOSX, addVers), _interface(file)
 {
-       init(_interface.get(), opts, buildingForSimulator, indirectDylib, linkingFlatNamespace,
-                linkingMainExecutable, path, platform, installPath);
+       init(_interface, opts, buildingForSimulator, indirectDylib, linkingFlatNamespace,
+                linkingMainExecutable, path, platforms, installPath, ignoreMismatchPlatform, usingBitcode);
 }
        
 template<typename A>
-void File<A>::init(tapi::LinkerInterfaceFile *file, const Options *opts, bool buildingForSimulator,
+void File<A>::init(tapi::LinkerInterfaceFilefile, const Options *opts, bool buildingForSimulator,
                                   bool indirectDylib, bool linkingFlatNamespace, bool linkingMainExecutable,
-                                  const char *path, Options::Platform platform, const char *targetInstallPath) {
+                                  const char *path, const ld::VersionSet& platforms, const char *targetInstallPath,
+                                  bool ignoreMismatchPlatform, bool usingBitcode) {
        _opts = opts;
        this->_bitcode = std::unique_ptr<ld::Bitcode>(new ld::Bitcode(nullptr, 0));
        this->_noRexports = !file->hasReexportedLibraries();
@@ -213,7 +240,6 @@ void File<A>::init(tapi::LinkerInterfaceFile *file, const Options *opts, bool bu
        this->_dylibCurrentVersion = file->getCurrentVersion();
        this->_dylibCompatibilityVersion = file->getCompatibilityVersion();
        this->_swiftVersion = file->getSwiftVersion();
-       this->_objcConstraint = mapObjCConstraint(file->getObjCConstraint());
        this->_parentUmbrella = file->getParentFrameworkName().empty() ? nullptr : strdup(file->getParentFrameworkName().c_str());
        this->_appExtensionSafe = file->isApplicationExtensionSafe();
 
@@ -237,21 +263,35 @@ void File<A>::init(tapi::LinkerInterfaceFile *file, const Options *opts, bool bu
        
        for (const auto &client : file->allowableClients())
                this->_allowableClients.emplace_back(strdup(client.c_str()));
-       
-       auto dylibPlatform = mapPlatform(file->getPlatform());
-       if ( (dylibPlatform != platform) && (platform != Options::kPlatformUnknown) ) {
-               this->_wrongOS = true;
-               if ( this->_addVersionLoadCommand && !indirectDylib ) {
-                       if ( buildingForSimulator ) {
-                               if ( !this->_allowSimToMacOSXLinking )
-                                       throwf("building for %s simulator, but linking against dylib built for %s (%s).",
-                                                  Options::platformName(platform), Options::platformName(dylibPlatform), path);
+
+       ld::VersionSet lcPlatforms = mapPlatform(file->getPlatform(), useSimulatorVariant());
+       this->_platforms = lcPlatforms;
+
+       // check cross-linking
+       platforms.forEach(^(ld::Platform platform, uint32_t version, bool &stop) {
+               if (!lcPlatforms.contains(platform) ) {
+                       this->_wrongOS = true;
+                       if ( this->_addVersionLoadCommand && !indirectDylib && !ignoreMismatchPlatform ) {
+                               if (buildingForSimulator && !this->_allowSimToMacOSXLinking) {
+                                       if ( usingBitcode )
+                                               throwf("building for %s simulator, but linking against dylib built for %s,",
+                                                                        platforms.to_str().c_str(), lcPlatforms.to_str().c_str());
+                                       else
+                                               warning("URGENT: building for %s simulator, but linking against dylib (%s) built for %s. "
+                                                                               "Note: This will be an error in the future.",
+                                                                               platforms.to_str().c_str(), path, lcPlatforms.to_str().c_str());
+                               }
                        } else {
-                               throwf("building for %s, but linking against dylib built for %s (%s).",
-                                          Options::platformName(platform), Options::platformName(dylibPlatform), path);
+                               if ( usingBitcode )
+                                       throwf("building for %s, but linking against dylib built for %s,",
+                                                                platforms.to_str().c_str(), lcPlatforms.to_str().c_str());
+                               else if ( (getenv("RC_XBS") != NULL) && (getenv("RC_BUILDIT") == NULL) ) // FIXME: remove after platform bringup
+                                       warning("URGENT: building for %s, but linking against dylib (%s) built for %s. "
+                                                                       "Note: This will be an error in the future.",
+                                                                       platforms.to_str().c_str(), path, lcPlatforms.to_str().c_str());
                        }
                }
-       }
+       });
        
        for (const auto& reexport : file->reexportedLibraries()) {
                const char *path = strdup(reexport.c_str());
@@ -297,7 +337,7 @@ void File<A>::buildExportHashTable(const tapi::LinkerInterfaceFile* file) {
 template <typename A>
 void File<A>::processIndirectLibraries(ld::dylib::File::DylibHandler* handler, bool addImplicitDylibs) {
        if (_interface)
-               _opts->addTAPIInterface(_interface.get(), this->path());
+               _opts->addTAPIInterface(_interface, this->path());
        Base::processIndirectLibraries(handler, addImplicitDylibs);
 }
 
@@ -310,107 +350,143 @@ public:
        static ld::dylib::File* parse(const char* path, const uint8_t* fileContent,
                                                                  uint64_t fileLength, time_t mTime,
                                                                  ld::File::Ordinal ordinal, const Options& opts,
-                                                                 bool indirectDylib)
+                                                                 bool indirectDylib, cpu_type_t architecture, cpu_subtype_t subArchitecture)
        {
                return new File<A>(path, fileContent, fileLength, &opts, mTime, ordinal,
                                                   opts.flatNamespace(),
                                                   opts.linkingMainExecutable(),
                                                   opts.implicitlyLinkIndirectPublicDylibs(),
-                                                  opts.platform(),
-                                                  opts.minOSversion(),
+                                                  opts.platforms(),
                                                   opts.allowWeakImports(),
-                                                  opts.architecture(),
-                                                  opts.subArchitecture(),
+                                                  architecture,
+                                                  subArchitecture,
                                                   opts.enforceDylibSubtypesMatch(),
                                                   opts.allowSimulatorToLinkWithMacOSX(),
                                                   opts.addVersionLoadCommand(),
                                                   opts.targetIOSSimulator(),
                                                   opts.logAllFiles(),
                                                   opts.installPath(),
-                                                  indirectDylib);
+                                                  indirectDylib,
+                                                  opts.outputKind() == Options::kPreload,
+                                                  opts.bundleBitcode());
        }
        
-       static ld::dylib::File* parse(const char* path, std::unique_ptr<tapi::LinkerInterfaceFile> &&file, time_t mTime,
+       static ld::dylib::File* parse(const char* path, tapi::LinkerInterfaceFile* file, time_t mTime,
                                                                  ld::File::Ordinal ordinal, const Options& opts,
-                                                                 bool indirectDylib)
+                                                                 bool indirectDylib, cpu_type_t architecture, cpu_subtype_t subArchitecture)
        {
-               return new File<A>(std::move(file), path, &opts, mTime, ordinal,
+               return new File<A>(file, path, &opts, mTime, ordinal,
                                                   opts.flatNamespace(),
                                                   opts.linkingMainExecutable(),
                                                   opts.implicitlyLinkIndirectPublicDylibs(),
-                                                  opts.platform(),
-                                                  opts.minOSversion(),
+                                                  opts.platforms(),
                                                   opts.allowWeakImports(),
-                                                  opts.architecture(),
-                                                  opts.subArchitecture(),
+                                                  architecture,
+                                                  subArchitecture,
                                                   opts.enforceDylibSubtypesMatch(),
                                                   opts.allowSimulatorToLinkWithMacOSX(),
                                                   opts.addVersionLoadCommand(),
                                                   opts.targetIOSSimulator(),
                                                   opts.logAllFiles(),
                                                   opts.installPath(),
-                                                  indirectDylib);
+                                                  indirectDylib,
+                                                  opts.outputKind() == Options::kPreload,
+                                                  opts.bundleBitcode());
        }
 
 };
 
-//
-// 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() ) {
+static ld::dylib::File* parseAsArchitecture(const uint8_t* fileContent, uint64_t fileLength, const char* path,
+                                                                                       time_t modTime, ld::File::Ordinal ordinal, const Options& opts,
+                                                                                       bool bundleLoader, bool indirectDylib,
+                                                                                       cpu_type_t architecture, cpu_subtype_t subArchitecture)
+{
+       switch ( architecture ) {
 #if SUPPORT_ARCH_x86_64
                case CPU_TYPE_X86_64:
-               if (tapi::LinkerInterfaceFile::isSupported(path, fileContent, fileLength))
-                       return Parser<x86_64>::parse(path, fileContent, fileLength, modTime, ordinal, opts, indirectDylib);
+                       return Parser<x86_64>::parse(path, fileContent, fileLength, modTime, ordinal, opts, indirectDylib, architecture, subArchitecture);
 #endif
 #if SUPPORT_ARCH_i386
                case CPU_TYPE_I386:
-               if (tapi::LinkerInterfaceFile::isSupported(path, fileContent, fileLength))
-                       return Parser<x86>::parse(path, fileContent, fileLength, modTime, ordinal, opts, indirectDylib);
+                       return Parser<x86>::parse(path, fileContent, fileLength, modTime, ordinal, opts, indirectDylib, architecture, subArchitecture);
 #endif
 #if SUPPORT_ARCH_arm_any
                case CPU_TYPE_ARM:
-               if (tapi::LinkerInterfaceFile::isSupported(path, fileContent, fileLength))
-                       return Parser<arm>::parse(path, fileContent, fileLength, modTime, ordinal, opts, indirectDylib);
+                       return Parser<arm>::parse(path, fileContent, fileLength, modTime, ordinal, opts, indirectDylib, architecture, subArchitecture);
 #endif
 #if SUPPORT_ARCH_arm64
                case CPU_TYPE_ARM64:
-               if (tapi::LinkerInterfaceFile::isSupported(path, fileContent, fileLength))
-                       return Parser<arm64>::parse(path, fileContent, fileLength, modTime, ordinal, opts, indirectDylib);
+                       return Parser<arm64>::parse(path, fileContent, fileLength, modTime, ordinal, opts, indirectDylib, architecture, subArchitecture);
 #endif
+               default:
+                       throwf("unsupported architecture for tbd file");
        }
-       return nullptr;
+       assert(0 && "function should return valid pointer or throw");
 }
 
-ld::dylib::File *parse(const char *path, std::unique_ptr<tapi::LinkerInterfaceFile> &&file, time_t modTime,
-                                          ld::File::Ordinal ordinal, const Options& opts, bool indirectDylib) {
-       switch ( opts.architecture() ) {
+
+static ld::dylib::File *parseAsArchitecture(const char *path, tapi::LinkerInterfaceFile* file, time_t modTime,
+                                                                                                                                                                               ld::File::Ordinal ordinal, const Options& opts, bool indirectDylib,
+                                                                                                                                                                               cpu_type_t architecture, cpu_subtype_t subArchitecture)
+{
+       switch ( architecture ) {
 #if SUPPORT_ARCH_x86_64
                case CPU_TYPE_X86_64:
-                       return Parser<x86_64>::parse(path, std::move(file), modTime, ordinal, opts, indirectDylib);
+                       return Parser<x86_64>::parse(path, file, modTime, ordinal, opts, indirectDylib, architecture, subArchitecture);
 #endif
 #if SUPPORT_ARCH_i386
                case CPU_TYPE_I386:
-                       return Parser<x86>::parse(path, std::move(file), modTime, ordinal, opts, indirectDylib);
+                       return Parser<x86>::parse(path, file, modTime, ordinal, opts, indirectDylib, architecture, subArchitecture);
 #endif
 #if SUPPORT_ARCH_arm_any
                case CPU_TYPE_ARM:
-                       return Parser<arm>::parse(path, std::move(file), modTime, ordinal, opts, indirectDylib);
+                       return Parser<arm>::parse(path, file, modTime, ordinal, opts, indirectDylib, architecture, subArchitecture);
 #endif
 #if SUPPORT_ARCH_arm64
                case CPU_TYPE_ARM64:
-                       return Parser<arm64>::parse(path, std::move(file), modTime, ordinal, opts, indirectDylib);
+                       return Parser<arm64>::parse(path, file, modTime, ordinal, opts, indirectDylib, architecture, subArchitecture);
 #endif
+               default:
+                       throwf("unsupported architecture for tbd file");
        }
-       return nullptr;
+       assert(0 && "function should return valid pointer or throw");
+}
 
+
+//
+// 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)
+{
+       if (!tapi::LinkerInterfaceFile::isSupported(path, fileContent, fileLength))
+               return nullptr;
+
+       try {
+               return parseAsArchitecture(fileContent, fileLength, path, modtime, ordinal, opts, bundleLoader, indirectDylib, opts.architecture(), opts.subArchitecture());
+       } catch (...) {
+               if (!opts.fallbackArchitecture())
+                       throw;
+       }
+
+       warning("architecture %s not present in TBD %s, attempting fallback", opts.architectureName(), path);
+       return parseAsArchitecture(fileContent, fileLength, path, modtime, ordinal, opts, bundleLoader, indirectDylib, opts.fallbackArchitecture(), opts.fallbackSubArchitecture());
 }
 
+ld::dylib::File *parse(const char *path, tapi::LinkerInterfaceFile* file, time_t modTime,
+                                          ld::File::Ordinal ordinal, const Options& opts, bool indirectDylib) {
+       try {
+               return parseAsArchitecture(path, file, modTime, ordinal, opts, indirectDylib, opts.architecture(), opts.subArchitecture());
+       } catch (...) {
+               if (!opts.fallbackArchitecture())
+                       throw;
+       }
+
+       warning("architecture %s not present in TBD %s, attempting fallback", opts.architectureName(), path);
+       return parseAsArchitecture(path, file, modTime, ordinal, opts, indirectDylib, opts.fallbackArchitecture(), opts.fallbackSubArchitecture());
+}
 
 } // namespace dylib
 } // namespace textstub
index 9931908c58cbb446ca7c2be3ba481004154903ce..609c08eaaaa97bef738e6cb73812e7c4a8873a58 100644 (file)
@@ -36,7 +36,7 @@ extern ld::dylib::File* parse(const uint8_t* fileContent, uint64_t fileLength, c
                                                          time_t modTime, const Options& opts, ld::File::Ordinal ordinal,
                                                          bool bundleLoader, bool indirectDylib);
 
-extern ld::dylib::File *parse(const char *path, std::unique_ptr<tapi::LinkerInterfaceFile> &&file, time_t modTime,
+extern ld::dylib::File *parse(const char *path, tapi::LinkerInterfaceFile* file, time_t modTime,
                               ld::File::Ordinal ordinal, const Options& opts, bool indirectDylib);
 
 } // namespace dylib
index 7165051294fbc651d8a1d2130075bfe0b9dea368..19e8b410870b74dca053e92a50fad3b4ddc48666 100644 (file)
@@ -986,7 +986,7 @@ void BitcodeBundle::doPass()
     // 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 )
+    if ( xar_prop_create((xar_file_t)linkXML, "platform", _options.platforms().to_str().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");
index 01c2e308ba53f0905b75a891ab0a22e7ce9b54a0..51b0347a8e13b9c669521c89f74333a74da30b14 100644 (file)
@@ -74,10 +74,48 @@ private:
 ld::Section GOTEntryAtom::_s_section("__DATA", "__got", ld::Section::typeNonLazyPointer);
 ld::Section GOTEntryAtom::_s_sectionWeak("__DATA", "__got_weak", ld::Section::typeNonLazyPointer);
 
+#if SUPPORT_ARCH_arm64e
 
-static bool gotFixup(const Options& opts, ld::Internal& internal, const ld::Atom* targetOfGOT, const ld::Fixup* fixup, bool* optimizable, bool* targetIsExternalWeakDef)
+class GOTAuthEntryAtom : public ld::Atom {
+public:
+                                                                                       GOTAuthEntryAtom(ld::Internal& internal, const ld::Atom* target, bool weakImport, bool weakDef)
+                               : ld::Atom(weakDef ? _s_sectionWeak : _s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
+                                                       ld::Atom::scopeLinkageUnit, ld::Atom::typeNonLazyPointer,
+                                                       symbolTableNotIn, false, false, false, ld::Atom::Alignment(3)),
+                               _fixup1(0, ld::Fixup::k1of2, ld::Fixup::kindSetAuthData, (ld::Fixup::AuthData){ 0, true, ld::Fixup::AuthData::ptrauth_key_asia }),
+                               _fixup2(0, ld::Fixup::k2of2, ld::Fixup::kindStoreTargetAddressLittleEndianAuth64, target),
+                               _target(target)
+                                       { _fixup2.weakImport = weakImport; internal.addAtom(*this); }
+
+       virtual const ld::File*                                 file() const                                    { return NULL; }
+       virtual const char*                                             name() const                                    { return _target->name(); }
+       virtual uint64_t                                                size() const                                    { return 8; }
+       virtual uint64_t                                                objectAddress() const                   { return 0; }
+       virtual void                                                    copyRawContent(uint8_t buffer[]) const { }
+       virtual void                                                    setScope(Scope)                                 { }
+       virtual ld::Fixup::iterator                             fixupsBegin() const                             { return (ld::Fixup*)&_fixup1; }
+       virtual ld::Fixup::iterator                             fixupsEnd()     const                           { return &((ld::Fixup*)&_fixup2)[1]; }
+
+private:
+       mutable ld::Fixup                                               _fixup1;
+       mutable ld::Fixup                                               _fixup2;
+       const ld::Atom*                                                 _target;
+
+       static ld::Section                                              _s_section;
+       static ld::Section                                              _s_sectionWeak;
+};
+
+ld::Section GOTAuthEntryAtom::_s_section("__DATA", "__got", ld::Section::typeNonLazyPointer);
+ld::Section GOTAuthEntryAtom::_s_sectionWeak("__DATA", "__got_weak", ld::Section::typeNonLazyPointer);
+
+#endif
+
+
+static bool gotFixup(const Options& opts, ld::Internal& internal, const ld::Atom* targetOfGOT, const ld::Atom* fixupAtom,
+                                        const ld::Fixup* fixup, bool* optimizable, bool* targetIsExternalWeakDef, bool* targetIsPersonalityFn)
 {
        *targetIsExternalWeakDef = false;
+       *targetIsPersonalityFn = false;
        switch (fixup->kind) {
                case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoad:
 #if SUPPORT_ARCH_arm64
@@ -136,11 +174,23 @@ static bool gotFixup(const Options& opts, ld::Internal& internal, const ld::Atom
                case ld::Fixup::kindStoreX86PCRel32GOT:
 #if SUPPORT_ARCH_arm64
                case ld::Fixup::kindStoreARM64PCRelToGOT:
+#endif
+#if SUPPORT_ARCH_arm64e
+                       // Note, this handles identifying DWARF unwind info personality functions
+                       if (opts.supportsAuthenticatedPointers()) {
+                               if (fixupAtom->section().type() == ld::Section::typeCFI)
+                                       *targetIsPersonalityFn = true;
+                       }
 #endif
                        *optimizable = false;
                        return true;
                case ld::Fixup::kindNoneGroupSubordinatePersonality:
                        *optimizable = false;
+#if SUPPORT_ARCH_arm64e
+                       // Note, this is a compact unwind info personality function
+                       if (opts.supportsAuthenticatedPointers())
+                               *targetIsPersonalityFn = true;
+#endif
                        return true;
                default:
                        break;
@@ -157,6 +207,17 @@ struct AtomByNameSorter
         }
 };
 
+struct GotMapEntry {
+       const ld::Atom* atom;
+       bool isPersonalityFn;
+
+       bool operator<(const GotMapEntry& other) const {
+               if (atom != other.atom)
+                       return atom < other.atom;
+               return (int)isPersonalityFn < (int)other.isPersonalityFn;
+       }
+};
+
 void doPass(const Options& opts, ld::Internal& internal)
 {
        const bool log = false;
@@ -166,7 +227,7 @@ void doPass(const Options& opts, ld::Internal& internal)
                return;
 
        // pre-fill gotMap with existing non-lazy pointers
-       std::map<const ld::Atom*, const ld::Atom*> gotMap;
+       std::map<GotMapEntry, const ld::Atom*> gotMap;
        for (ld::Internal::FinalSection* sect : internal.sections) {
                if ( sect->type() != ld::Section::typeNonLazyPointer )
                        continue;
@@ -194,7 +255,7 @@ void doPass(const Options& opts, ld::Internal& internal)
                        }
                        if ( target != NULL ) {
                                if (log) fprintf(stderr, "found existing got entry to %s\n", target->name());
-                               gotMap[target] = atom;
+                               gotMap[{ target, false }] = atom;
                        }
                }
        }
@@ -229,7 +290,8 @@ void doPass(const Options& opts, ld::Internal& internal)
                                }
                                bool optimizable;
                                bool targetIsExternalWeakDef;
-                               if ( !gotFixup(opts, internal, targetOfGOT, fit, &optimizable, &targetIsExternalWeakDef) )
+                               bool targetIsPersonalityFn;
+                               if ( !gotFixup(opts, internal, targetOfGOT, atom, fit, &optimizable, &targetIsExternalWeakDef, &targetIsPersonalityFn) )
                                        continue;
                                if ( optimizable ) {
                                        // change from load of GOT entry to lea of target
@@ -268,8 +330,8 @@ void doPass(const Options& opts, ld::Internal& internal)
                                                atomsReferencingGOT.push_back(atom);
                                                atomUsesGOT = true;
                                        }
-                                       if ( gotMap.count(targetOfGOT) == 0 )
-                                               gotMap[targetOfGOT] = NULL;
+                                       if ( gotMap.count({ targetOfGOT, targetIsPersonalityFn }) == 0 )
+                                               gotMap[{ targetOfGOT, targetIsPersonalityFn }] = NULL;
                                        // record if target is weak def
                                        weakDefMap[targetOfGOT] = targetIsExternalWeakDef;
                                        // record weak_import attribute
@@ -327,8 +389,15 @@ void doPass(const Options& opts, ld::Internal& internal)
        // make GOT entries
        for (auto& entry : gotMap) {
                if ( entry.second == NULL ) {
-                       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 SUPPORT_ARCH_arm64e
+                       if ( entry.first.isPersonalityFn && (opts.supportsAuthenticatedPointers()) ) {
+                               entry.second = new GOTAuthEntryAtom(internal, entry.first.atom, weakImportMap[entry.first.atom], opts.useDataConstSegment() && weakDefMap[entry.first.atom]);
+                               if (log) fprintf(stderr, "making new GOT slot for %s, gotMap[%p] = %p\n", entry.first.atom->name(), entry.first.atom, entry.second);
+                               continue;
+                       }
+#endif
+                       entry.second = new GOTEntryAtom(internal, entry.first.atom, weakImportMap[entry.first.atom], opts.useDataConstSegment() && weakDefMap[entry.first.atom], is64);
+                       if (log) fprintf(stderr, "making new GOT slot for %s, gotMap[%p] = %p\n", entry.first.atom->name(), entry.first.atom, entry.second);
                }
        }
 
@@ -357,7 +426,9 @@ void doPass(const Options& opts, ld::Internal& internal)
                        }
                        bool optimizable;
                        bool targetIsExternalWeakDef;
-                       if ( (targetOfGOT == NULL) || !gotFixup(opts, internal, targetOfGOT, fit, &optimizable, &targetIsExternalWeakDef) )
+                       bool targetIsPersonalityFn;
+                       if ( (targetOfGOT == NULL) || !gotFixup(opts, internal, targetOfGOT, atom, fit,
+                                                                                                       &optimizable, &targetIsExternalWeakDef, &targetIsPersonalityFn) )
                                continue;
                        if ( !optimizable ) {
                                // GOT use not optimized away, update to bind to GOT entry
@@ -367,7 +438,7 @@ void doPass(const Options& opts, ld::Internal& internal)
                                        case ld::Fixup::bindingDirectlyBound:
                                                if ( log ) fprintf(stderr, "updating GOT use in %s to %s\n", atom->name(), targetOfGOT->name());
                                                fitThatSetTarget->binding = ld::Fixup::bindingDirectlyBound;
-                                               fitThatSetTarget->u.target = gotMap[targetOfGOT];
+                                               fitThatSetTarget->u.target = gotMap[{ targetOfGOT, targetIsPersonalityFn }];
                                                break;
                                        default:
                                                assert(0 && "unsupported GOT reference");
index a9a8c6a0b94620cd1183010f959db3cecc165150..293646b6c4a26aa77b4a60443a58b4312f4989ac 100644 (file)
@@ -65,8 +65,7 @@ struct objc_image_info  {
 template <typename A>
 class ObjCImageInfoAtom : public ld::Atom {
 public:
-                                                                                       ObjCImageInfoAtom(ld::File::ObjcConstraint objcConstraint, 
-                                                                                                                         bool compaction, bool abi2, bool hasCategoryClassProperties, uint8_t swiftVersion);
+                                                                                       ObjCImageInfoAtom(bool abi2, bool hasCategoryClassProperties, uint8_t swiftVersion);
 
        virtual const ld::File*                                 file() const                                    { return NULL; }
        virtual const char*                                             name() const                                    { return "objc image info"; }
@@ -89,35 +88,13 @@ template <typename A> ld::Section ObjCImageInfoAtom<A>::_s_sectionABI2("__DATA",
 
 
 template <typename A>
-ObjCImageInfoAtom<A>::ObjCImageInfoAtom(ld::File::ObjcConstraint objcConstraint, bool compaction, 
-                                                                               bool abi2, bool hasCategoryClassProperties, uint8_t swiftVersion)
+ObjCImageInfoAtom<A>::ObjCImageInfoAtom(bool abi2, bool hasCategoryClassProperties, uint8_t swiftVersion)
        : ld::Atom(abi2 ? _s_sectionABI2 : _s_sectionABI1, ld::Atom::definitionRegular, ld::Atom::combineNever,
                                                        ld::Atom::scopeLinkageUnit, ld::Atom::typeUnclassified, 
                                                        symbolTableNotIn, false, false, false, ld::Atom::Alignment(2))
 {  
        
        uint32_t value = 0;
-       switch ( objcConstraint ) {
-               case ld::File::objcConstraintNone:
-               case ld::File::objcConstraintRetainRelease:
-                       if ( compaction ) 
-                               warning("ignoring -objc_gc_compaction because code not compiled for ObjC garbage collection");
-                       break;
-               case ld::File::objcConstraintRetainReleaseOrGC:
-                       value |= OBJC_IMAGE_SUPPORTS_GC;
-               if ( compaction ) 
-                       value |= OBJC_IMAGE_SUPPORTS_COMPACTION;
-                       break;
-               case ld::File::objcConstraintGC:
-                       value |= OBJC_IMAGE_SUPPORTS_GC | OBJC_IMAGE_REQUIRES_GC;
-                       if ( compaction ) 
-                               value |= OBJC_IMAGE_SUPPORTS_COMPACTION;
-                       break;
-               case ld::File::objcConstraintRetainReleaseForSimulator:
-                               value |= OBJC_IMAGE_IS_SIMULATED;
-                       break;
-       }
-
        if ( hasCategoryClassProperties ) {
                value |= OBJC_IMAGE_HAS_CATEGORY_CLASS_PROPERTIES;
        }
@@ -421,9 +398,12 @@ template <typename A>
 const ld::Atom*        Category<A>::getClassProperties(ld::Internal& state, const ld::Atom* contentAtom)
 {
        // Only specially-marked files have this field.
-       if (!contentAtom->file()->objcHasCategoryClassPropertiesField()) return NULL;
-
-       return ObjCData<A>::getPointerInContent(state, contentAtom, 6*sizeof(pint_t)); // category_t.classProperties
+       if ( const ld::relocatable::File* objFile = dynamic_cast<const ld::relocatable::File*>(contentAtom->file()) ) {
+               if ( objFile->objcHasCategoryClassPropertiesField() ) {
+                       return ObjCData<A>::getPointerInContent(state, contentAtom, 6*sizeof(pint_t)); // category_t.classProperties
+               }
+       }
+       return NULL;
 }
 
 
@@ -1272,10 +1252,12 @@ void scanCategories(ld::Internal& state,
                                        haveCategoriesWithNonNullClassProperties = true;
                                        // fprintf(stderr, "category in file %s has non-null class properties\n", categoryAtom->safeFilePath());
                                }
-                               
-                               if (!categoryAtom->file()->objcHasCategoryClassPropertiesField()) {
-                                       haveCategoriesWithoutClassPropertyStorage = true;
-                                       // fprintf(stderr, "category in file %s has no storage for class properties\n", categoryAtom->safeFilePath());
+
+                               if ( const ld::relocatable::File* objFile = dynamic_cast<const ld::relocatable::File*>(categoryAtom->file()) ) {
+                                       if ( !objFile->objcHasCategoryClassPropertiesField() ) {
+                                               haveCategoriesWithoutClassPropertyStorage = true;
+                                               // fprintf(stderr, "category in file %s has no storage for class properties\n", categoryAtom->safeFilePath());
+                                       }
                                }
                        }
                }
@@ -1287,22 +1269,10 @@ template <typename A, bool isObjC2>
 void doPass(const Options& opts, ld::Internal& state)
 {
        // Do nothing if the output has no ObjC content.
-       if ( state.objcObjectConstraint == ld::File::objcConstraintNone ) {
+       if ( !state.hasObjC ) {
                return;
        }
-
-       // verify dylibs are GC compatible with object files
-       if ( state.objcObjectConstraint != state.objcDylibConstraint ) {
-               if (   (state.objcDylibConstraint == ld::File::objcConstraintRetainRelease)
-                       && (state.objcObjectConstraint == ld::File::objcConstraintGC) ) {
-                               throw "Linked dylibs built for retain/release but object files built for GC-only";
-               }
-               else if (   (state.objcDylibConstraint == ld::File::objcConstraintGC)
-                            && (state.objcObjectConstraint == ld::File::objcConstraintRetainRelease) ) {
-                               throw "Linked dylibs built for GC-only but object files built for retain/release";
-               }
-       }
-
+       
        if ( opts.objcCategoryMerging() ) {
                // optimize classes defined in this linkage unit by merging in categories also in this linkage unit
                OptimizeCategories<A>::doit(opts, state);
@@ -1324,8 +1294,7 @@ void doPass(const Options& opts, ld::Internal& state)
 
        // add image info atom
        // The HasCategoryClassProperties bit is set as often as possible.
-       state.addAtom(*new ObjCImageInfoAtom<A>(state.objcObjectConstraint, opts.objcGcCompaction(), isObjC2,
-                                                                                       !haveCategoriesWithoutClassPropertyStorage, state.swiftVersion));
+       state.addAtom(*new ObjCImageInfoAtom<A>(isObjC2, !haveCategoriesWithoutClassPropertyStorage, state.swiftVersion));
 }
 
 
@@ -1353,6 +1322,12 @@ void doPass(const Options& opts, ld::Internal& state)
 #endif
 #if SUPPORT_ARCH_arm64
                case CPU_TYPE_ARM64:
+#if SUPPORT_ARCH_arm64e
+                       if (opts.subArchitecture() == CPU_SUBTYPE_ARM64_E) {
+                               doPass<arm64e, true>(opts, state);
+                               break;
+                       }
+#endif
                        doPass<arm64, true>(opts, state);
                        break;
 #endif
index 02ae454502d3eba954ea48b630a67d8cc4fb3872..c97fab9a5fac40dd56ac687eef82107c23f4ef58 100644 (file)
@@ -293,12 +293,14 @@ ld::Section LazyPointerAtom::_s_sectionWeak("__DATA", "__la_weak_ptr", ld::Secti
 
 class NonLazyPointerAtom : public ld::Atom {
 public:
-                                                                                       NonLazyPointerAtom(ld::passes::stubs::Pass& pass, const ld::Atom& stubTo)
+       NonLazyPointerAtom(ld::passes::stubs::Pass& pass, const ld::Atom& stubTo,
+                                          bool weakImport)
                                : ld::Atom(_s_section, ld::Atom::definitionRegular, 
                                                        ld::Atom::combineNever, ld::Atom::scopeLinkageUnit, ld::Atom::typeLazyPointer, 
                                                        symbolTableNotIn, false, false, false, ld::Atom::Alignment(2)), 
                                _stubTo(stubTo),
                                _fixup1(0, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressLittleEndian32, &stubTo) {
+                                       _fixup1.weakImport = weakImport;
                                        pass.addAtom(*this);
                                }
 
@@ -324,12 +326,13 @@ ld::Section NonLazyPointerAtom::_s_section("__DATA", "__nl_symbol_ptr", ld::Sect
 
 class StubPICKextAtom : public ld::Atom {
 public:
-                                                                                       StubPICKextAtom(ld::passes::stubs::Pass& pass, const ld::Atom& stubTo)
+       StubPICKextAtom(ld::passes::stubs::Pass& pass, const ld::Atom& stubTo,
+                                       bool weakImport)
                                : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
                                                        ld::Atom::scopeLinkageUnit, ld::Atom::typeStub, 
-                                                       symbolTableIn, false, true, false, ld::Atom::Alignment(2)), 
+                                                       symbolTableNotIn, false, true, false, ld::Atom::Alignment(2)),
                                _stubTo(stubTo), 
-                               _nonLazyPointer(pass, stubTo),
+                               _nonLazyPointer(pass, stubTo, weakImport),
                                _fixup1(0, ld::Fixup::k1of4, ld::Fixup::kindSetTargetAddress, &_nonLazyPointer),
                                _fixup2(0, ld::Fixup::k2of4, ld::Fixup::kindSubtractTargetAddress, this),
                                _fixup3(0, ld::Fixup::k3of4, ld::Fixup::kindSubtractAddend, 12),
@@ -338,8 +341,8 @@ public:
                                _fixup6(4, ld::Fixup::k2of4, ld::Fixup::kindSubtractTargetAddress, this),
                                _fixup7(4, ld::Fixup::k3of4, ld::Fixup::kindSubtractAddend, 12),
                                _fixup8(4, ld::Fixup::k4of4, ld::Fixup::kindStoreThumbHigh16) {
-                                       pass.addAtom(*this); 
                                        asprintf((char**)&_name, "%s.stub", _stubTo.name());
+                                       pass.addAtom(*this);
                                }
   
        virtual const ld::File*                                 file() const                                    { return _stubTo.file(); }
index 815e28a53b1a80184a44e4f3b86d631c1b0ff7b5..e473f06540ca6db289af9fe0580e4e61d33e587d 100644 (file)
@@ -148,7 +148,7 @@ public:
                                                                                                                                                                                        const ld::Atom& stubTo)
                                : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
                                                        ld::Atom::scopeLinkageUnit, ld::Atom::typeStubHelper, 
-                                                       symbolTableNotIn, false, false, false, ld::Atom::Alignment(1)), 
+                                                       symbolTableNotIn, false, false, false, ld::Atom::Alignment(2)),
                                _stubTo(stubTo),
                                _fixup1(4, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressARM64Branch26, helperHelper(pass)),
                                _fixup2(8, ld::Fixup::k1of2, ld::Fixup::kindSetLazyOffset, lazyPointer),
@@ -191,7 +191,7 @@ public:
                                                                                                                                                                                        const ld::Atom& stubTo)
                                : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
                                                        ld::Atom::scopeLinkageUnit, ld::Atom::typeStubHelper, 
-                                                       symbolTableNotIn, false, false, false, ld::Atom::Alignment(1)), 
+                                                       symbolTableNotIn, false, false, false, ld::Atom::Alignment(2)), 
                                _stubTo(stubTo),
                                _fixup1(24, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressARM64Branch26, &stubTo),
                                _fixup2(28, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressARM64Page21, lazyPointer),
@@ -301,7 +301,7 @@ public:
                                                                                                        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)), 
+                                                       symbolTableNotIn, false, false, false, ld::Atom::Alignment(2)),
                                _stubTo(stubTo), 
                                _lazyPointer(pass, stubTo, stubToGlobalWeakDef, stubToResolver, weakImport, dataConstUsed),
                                _fixup1(0, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressARM64Page21, &_lazyPointer),
@@ -338,12 +338,14 @@ ld::Section StubAtom::_s_section("__TEXT", "__stubs", ld::Section::typeStub);
 
 class NonLazyPointerAtom : public ld::Atom {
 public:
-                               NonLazyPointerAtom(ld::passes::stubs::Pass& pass, const ld::Atom& stubTo)
+       NonLazyPointerAtom(ld::passes::stubs::Pass& pass, const ld::Atom& stubTo,
+                                          bool weakImport)
                                : ld::Atom(_s_section, ld::Atom::definitionRegular, 
                                                        ld::Atom::combineNever, ld::Atom::scopeLinkageUnit, ld::Atom::typeNonLazyPointer, 
                                                        symbolTableNotIn, false, false, false, ld::Atom::Alignment(3)), 
                                _stubTo(stubTo),
                                _fixup1(0, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressLittleEndian64, &stubTo) {
+                                       _fixup1.weakImport = weakImport;
                                        pass.addAtom(*this);
                                }
 
@@ -366,18 +368,19 @@ private:
 ld::Section NonLazyPointerAtom::_s_section("__DATA", "__got", ld::Section::typeNonLazyPointer);
 
 
-class KextStubAtom : public ld::Atom {
+class NonLazyStubAtom : public ld::Atom {
 public:
-                               KextStubAtom(ld::passes::stubs::Pass& pass, const ld::Atom& stubTo)
+                               NonLazyStubAtom(ld::passes::stubs::Pass& pass, const ld::Atom& stubTo,
+                                                               bool weakImport)
                                : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
                                                        ld::Atom::scopeLinkageUnit, ld::Atom::typeStub, 
-                                                       symbolTableIn, false, false, false, ld::Atom::Alignment(1)), 
+                                                       symbolTableNotIn, false, false, false, ld::Atom::Alignment(2)),
                                _stubTo(stubTo), 
-                               _nonLazyPointer(pass, stubTo),
+                               _nonLazyPointer(pass, stubTo, weakImport),
                                _fixup1(0, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressARM64Page21, &_nonLazyPointer),
-                               _fixup2(4, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressARM64PageOff12, &_nonLazyPointer) { 
-                                       pass.addAtom(*this);
+                               _fixup2(4, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressARM64PageOff12, &_nonLazyPointer) {
                                        asprintf((char**)&_name, "%s.stub", _stubTo.name());
+                                       pass.addAtom(*this);
                                }
 
        virtual const ld::File*                                 file() const                                    { return _stubTo.file(); }
@@ -403,8 +406,404 @@ private:
        static ld::Section                                              _s_section;
 };
 
-ld::Section KextStubAtom::_s_section("__TEXT", "__stubs", ld::Section::typeCode);
+ld::Section NonLazyStubAtom::_s_section("__TEXT", "__stubs", ld::Section::typeStub);
 
 
 } // namespace arm64
 
+#if SUPPORT_ARCH_arm64e
+
+// already in ld::passes::stubs namespace
+namespace arm64e {
+
+
+
+class FastBindingPointerAtom : public ld::Atom {
+public:
+                                                                                       FastBindingPointerAtom(ld::passes::stubs::Pass& pass)
+                               : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
+                                                       ld::Atom::scopeLinkageUnit, ld::Atom::typeNonLazyPointer, 
+                                                       symbolTableNotIn, false, false, false, ld::Atom::Alignment(3)), 
+                               _fixup(0, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressLittleEndian64, 
+                                                                                               pass.internal()->compressedFastBinderProxy)
+                                       { pass.addAtom(*this); }
+
+       virtual const ld::File*                                 file() const                                    { return NULL; }
+       virtual const char*                                             name() const                                    { return "fast binder pointer"; }
+       virtual uint64_t                                                size() const                                    { return 8; }
+       virtual uint64_t                                                objectAddress() const                   { return 0; }
+       virtual void                                                    copyRawContent(uint8_t buffer[]) const { }
+       virtual void                                                    setScope(Scope)                                 { }
+       virtual ld::Fixup::iterator                             fixupsBegin() const                             { return &_fixup; }
+       virtual ld::Fixup::iterator                             fixupsEnd()     const                           { return &((ld::Fixup*)&_fixup)[1]; }
+
+private:
+       mutable ld::Fixup                                               _fixup;
+
+       static ld::Section                                              _s_section;
+};
+
+ld::Section FastBindingPointerAtom::_s_section("__DATA", "__got", ld::Section::typeNonLazyPointer);
+
+
+class ImageCachePointerAtom : public ld::Atom {
+public:
+                                                                                       ImageCachePointerAtom(ld::passes::stubs::Pass& pass)
+                               : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
+                                                       ld::Atom::scopeLinkageUnit, ld::Atom::typeNonLazyPointer, 
+                                                       symbolTableNotIn, false, false, false, ld::Atom::Alignment(3)) { pass.addAtom(*this); }
+
+       virtual const ld::File*                                 file() const                                    { return NULL; }
+       virtual const char*                                             name() const                                    { return "image cache pointer"; }
+       virtual uint64_t                                                size() const                                    { return 8; }
+       virtual uint64_t                                                objectAddress() const                   { return 0; }
+       virtual void                                                    copyRawContent(uint8_t buffer[]) const { }
+       virtual void                                                    setScope(Scope)                                 { }
+
+private:
+       
+       static ld::Section                                              _s_section;
+};
+
+ld::Section ImageCachePointerAtom::_s_section("__DATA", "__got", ld::Section::typeNonLazyPointer);
+
+
+
+
+
+//
+//  The stub-helper-helper is the common code factored out of each helper function.
+//  It is in the same section as the stub-helpers.  
+//  Similar to the PLT0 entry in ELF. 
+//
+class StubHelperHelperAtom : public ld::Atom {
+public:
+                                                                                       StubHelperHelperAtom(ld::passes::stubs::Pass& pass)
+                               : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
+                                                       ld::Atom::scopeLinkageUnit, ld::Atom::typeStubHelper, 
+                                                       symbolTableNotIn, false, false, false, ld::Atom::Alignment(2)), 
+                               _fixup1(0,  ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressARM64Page21,    compressedImageCache(pass)),
+                               _fixup2(4,  ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressARM64PageOff12, compressedImageCache(pass)), 
+                               _fixup3(12, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressARM64Page21,    compressedFastBinder(pass)), 
+                               _fixup4(16, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressARM64PageOff12, compressedFastBinder(pass)), 
+                               _fixup5(ld::Fixup::kindLinkerOptimizationHint, LOH_ARM64_ADRP_ADD, 0, 4), 
+                               _fixup6(ld::Fixup::kindLinkerOptimizationHint, LOH_ARM64_ADRP_LDR, 12, 16) 
+                                       { pass.addAtom(*this); }
+
+       virtual ld::File*                                               file() const                                    { return NULL; }
+       virtual const char*                                             name() const                                    { return "helper helper"; }
+       virtual uint64_t                                                size() const                                    { return 24; }
+       virtual uint64_t                                                objectAddress() const                   { return 0; }
+       virtual void                                                    copyRawContent(uint8_t buffer[]) const {
+               OSWriteLittleInt32(&buffer[ 0], 0, 0x90000011); //     ADRP  X17, dyld_mageLoaderCache@page
+               OSWriteLittleInt32(&buffer[ 4], 0, 0x91000231); //     ADD       X17, X17, dyld_mageLoaderCache@pageoff
+               OSWriteLittleInt32(&buffer[ 8], 0, 0xA9BF47F0); //     STP   X16/X17, [SP, #-16]!
+               OSWriteLittleInt32(&buffer[12], 0, 0x90000010); //     ADRP  X16, _fast_lazy_bind@page
+               OSWriteLittleInt32(&buffer[16], 0, 0xF9400210); //     LDR       X16, [X16,_fast_lazy_bind@pageoff]
+               OSWriteLittleInt32(&buffer[20], 0, 0xD61F0200); //     BR    X16
+       }
+       virtual void                                                    setScope(Scope)                                 { }
+       virtual ld::Fixup::iterator                             fixupsBegin() const                             { return &_fixup1; }
+       virtual ld::Fixup::iterator                             fixupsEnd()     const                           { return &((ld::Fixup*)&_fixup6)[1]; }
+
+private:
+       static ld::Atom* compressedImageCache(ld::passes::stubs::Pass& pass) {
+               if ( pass.compressedImageCache == NULL ) 
+                       pass.compressedImageCache = new ImageCachePointerAtom(pass);
+               return pass.compressedImageCache;               
+       }
+       static ld::Atom* compressedFastBinder(ld::passes::stubs::Pass& pass) {
+               if ( pass.compressedFastBinderPointer == NULL ) 
+                       pass.compressedFastBinderPointer = new FastBindingPointerAtom(pass);
+               return pass.compressedFastBinderPointer;                
+       }
+       
+       mutable ld::Fixup                                               _fixup1;
+       ld::Fixup                                                               _fixup2;
+       ld::Fixup                                                               _fixup3;
+       ld::Fixup                                                               _fixup4;
+       ld::Fixup                                                               _fixup5;
+       ld::Fixup                                                               _fixup6;
+       
+       static ld::Section                                              _s_section;
+};
+
+ld::Section StubHelperHelperAtom::_s_section("__TEXT", "__stub_helper", ld::Section::typeStubHelper);
+
+
+
+class StubHelperAtom : public ld::Atom {
+public:
+                                                                                       StubHelperAtom(ld::passes::stubs::Pass& pass, const ld::Atom* lazyPointer,
+                                                                                                                                                                                       const ld::Atom& stubTo)
+                               : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
+                                                       ld::Atom::scopeLinkageUnit, ld::Atom::typeStubHelper, 
+                                                       symbolTableNotIn, false, false, false, ld::Atom::Alignment(2)),
+                               _stubTo(stubTo),
+                               _fixup1(4, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressARM64Branch26, helperHelper(pass)),
+                               _fixup2(8, ld::Fixup::k1of2, ld::Fixup::kindSetLazyOffset, lazyPointer),
+                               _fixup3(8, ld::Fixup::k2of2, ld::Fixup::kindStoreLittleEndian32)  { }
+                               
+       virtual const ld::File*                                 file() const                                    { return _stubTo.file(); }
+       virtual const char*                                             name() const                                    { return _stubTo.name(); }
+       virtual uint64_t                                                size() const                                    { return 12; }
+       virtual uint64_t                                                objectAddress() const                   { return 0; }
+       virtual void                                                    copyRawContent(uint8_t buffer[]) const {
+               OSWriteLittleInt32(&buffer[0], 0, 0x18000050); //     LDR   W16, L0
+               OSWriteLittleInt32(&buffer[4], 0, 0x14000000); //     B     helperhelper
+               OSWriteLittleInt32(&buffer[8], 0, 0x00000000); // L0: .long 0
+       }
+       virtual void                                                    setScope(Scope)                                 { }
+       virtual ld::Fixup::iterator                             fixupsBegin() const                             { return &_fixup1; }
+       virtual ld::Fixup::iterator                             fixupsEnd() const                               { return &((ld::Fixup*)&_fixup3)[1]; }
+
+private:
+       static ld::Atom* helperHelper(ld::passes::stubs::Pass& pass) {
+               if ( pass.compressedHelperHelper == NULL ) 
+                       pass.compressedHelperHelper = new StubHelperHelperAtom(pass);
+               return pass.compressedHelperHelper;
+       }
+
+       const ld::Atom&                                                 _stubTo;
+       mutable ld::Fixup                                               _fixup1;
+                       ld::Fixup                                               _fixup2;
+                       ld::Fixup                                               _fixup3;
+       
+       static ld::Section                                              _s_section;
+};
+
+ld::Section                                            StubHelperAtom::_s_section("__TEXT", "__stub_helper", ld::Section::typeStubHelper);
+
+
+class ResolverHelperAtom : public ld::Atom {
+public:
+                                                                                       ResolverHelperAtom(ld::passes::stubs::Pass& pass, const ld::Atom* lazyPointer,
+                                                                                                                                                                                       const ld::Atom& stubTo)
+                               : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
+                                                       ld::Atom::scopeLinkageUnit, ld::Atom::typeStubHelper, 
+                                                       symbolTableNotIn, false, false, false, ld::Atom::Alignment(2)),
+                               _stubTo(stubTo),
+                               _fixup1(24, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressARM64Branch26, &stubTo),
+                               _fixup2(28, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressARM64Page21, lazyPointer),
+                               _fixup3(32, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressARM64PageOff12, lazyPointer) { }
+                               
+       virtual const ld::File*                                 file() const                                    { return _stubTo.file(); }
+       virtual const char*                                             name() const                                    { return _stubTo.name(); }
+       virtual uint64_t                                                size() const                                    { return 68; }
+       virtual uint64_t                                                objectAddress() const                   { return 0; }
+       virtual void                                                    copyRawContent(uint8_t buffer[]) const {
+               OSWriteLittleInt32(&buffer[ 0], 0, 0xa9bf7bfd); // stp  fp, lr, [sp, #-16]!
+               OSWriteLittleInt32(&buffer[ 4], 0, 0x910003fd); // mov  fp, sp
+               OSWriteLittleInt32(&buffer[ 8], 0, 0xa9bf03e1); // stp  x1, x0, [sp, #-16]!
+               OSWriteLittleInt32(&buffer[12], 0, 0xa9bf0be3); // stp  x3, x2, [sp, #-16]!
+               OSWriteLittleInt32(&buffer[16], 0, 0xa9bf13e5); // stp  x5, x4, [sp, #-16]!
+               OSWriteLittleInt32(&buffer[20], 0, 0xa9bf1be7); // stp  x7, x6, [sp, #-16]!
+               OSWriteLittleInt32(&buffer[24], 0, 0x94000000); // bl   _foo
+               OSWriteLittleInt32(&buffer[28], 0, 0x90000010); // adrp x16, lazy_pointer@PAGE
+               OSWriteLittleInt32(&buffer[32], 0, 0x91000210); // add  x16, x16, lazy_pointer@PAGEOFF
+               OSWriteLittleInt32(&buffer[36], 0, 0xf9000200); // str  x0, [x16]
+               OSWriteLittleInt32(&buffer[40], 0, 0xaa0003f0); // mov  x16, x0
+               OSWriteLittleInt32(&buffer[44], 0, 0xa8c11be7); // ldp  x7, x6, [sp], #16
+               OSWriteLittleInt32(&buffer[48], 0, 0xa8c113e5); // ldp  x5, x4, [sp], #16
+               OSWriteLittleInt32(&buffer[52], 0, 0xa8c10be3); // ldp  x3, x2, [sp], #16
+               OSWriteLittleInt32(&buffer[56], 0, 0xa8c103e1); // ldp  x1, x0, [sp], #16
+               OSWriteLittleInt32(&buffer[60], 0, 0xa8c17bfd); // ldp  fp, lr, [sp], #16
+               OSWriteLittleInt32(&buffer[64], 0, 0xD61F0A1F); // braaz x16
+       }
+
+       virtual void                                                    setScope(Scope)                                 { }
+       virtual ld::Fixup::iterator                             fixupsBegin() const                             { return &_fixup1; }
+       virtual ld::Fixup::iterator                             fixupsEnd() const                               { return &((ld::Fixup*)&_fixup3)[1]; }
+
+private:
+
+       const ld::Atom&                                                 _stubTo;
+       mutable ld::Fixup                                               _fixup1;
+                       ld::Fixup                                               _fixup2;
+                       ld::Fixup                                               _fixup3;
+       
+       static ld::Section                                              _s_section;
+};
+
+ld::Section                                            ResolverHelperAtom::_s_section("__TEXT", "__stub_helper", ld::Section::typeStubHelper);
+
+
+
+class LazyPointerAtom : public ld::Atom {
+public:
+                                                                                       LazyPointerAtom(ld::passes::stubs::Pass& pass, const ld::Atom& stubTo,
+                                                                                                                       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),
+                               _helper(pass, this, stubTo),
+                               _resolverHelper(pass, this, stubTo),
+                               _fixup1(0, ld::Fixup::k1of2, ld::Fixup::kindSetAuthData, (ld::Fixup::AuthData){ 0, false, ld::Fixup::AuthData::ptrauth_key_asia }),
+                               _fixup2(0, ld::Fixup::k2of2, ld::Fixup::kindStoreTargetAddressLittleEndianAuth64,
+                                                                                                       stubToResolver ? &_resolverHelper : (stubToGlobalWeakDef ?  &stubTo : &_helper)),
+                               _fixup3(0, ld::Fixup::k1of1, ld::Fixup::kindLazyTarget, &stubTo) {
+                                               _fixup2.weakImport = weakImport; pass.addAtom(*this); 
+                                               if ( stubToResolver )
+                                                       pass.addAtom(_resolverHelper);
+                                               else if ( !stubToGlobalWeakDef ) 
+                                                       pass.addAtom(_helper); 
+                                       }
+
+       virtual const ld::File*                                 file() const                                    { return _stubTo.file(); }
+       virtual const char*                                             name() const                                    { return _stubTo.name(); }
+       virtual uint64_t                                                size() const                                    { return 8; }
+       virtual uint64_t                                                objectAddress() const                   { return 0; }
+       virtual void                                                    copyRawContent(uint8_t buffer[]) const { }
+       virtual void                                                    setScope(Scope)                                 { }
+       virtual ld::Fixup::iterator                             fixupsBegin() const                             { return &_fixup1; }
+       virtual ld::Fixup::iterator                             fixupsEnd()     const                           { return &((ld::Fixup*)&_fixup3)[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;
+       mutable ld::Fixup                                               _fixup1;
+       ld::Fixup                                                               _fixup2;
+       ld::Fixup                                                               _fixup3;
+
+       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_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,
+                                                                                                       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(2)),
+                               _stubTo(stubTo), 
+                               _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) 
+                                       { pass.addAtom(*this);  }
+
+       virtual const ld::File*                                 file() const                                    { return _stubTo.file(); }
+       virtual const char*                                             name() const                                    { return _stubTo.name(); }
+       virtual uint64_t                                                size() const                                    { return 12; }
+       virtual uint64_t                                                objectAddress() const                   { return 0; }
+       virtual void                                                    copyRawContent(uint8_t buffer[]) const {
+               OSWriteLittleInt32(&buffer[0], 0, 0x90000010); // ADRP  X16, lazy_pointer@page
+               OSWriteLittleInt32(&buffer[4], 0, 0xF9400210); // LDR   X16, [X16, lazy_pointer@pageoff]
+               OSWriteLittleInt32(&buffer[8], 0, 0xD61F0A1F); // BRAAZ X16
+       }
+       virtual void                                                    setScope(Scope)                                 { }
+       virtual ld::Fixup::iterator                             fixupsBegin() const                             { return &_fixup1; }
+       virtual ld::Fixup::iterator                             fixupsEnd()     const                           { return &((ld::Fixup*)&_fixup3)[1]; }
+
+private:
+       const ld::Atom&                                                 _stubTo;
+       LazyPointerAtom                                                 _lazyPointer;
+       mutable ld::Fixup                                               _fixup1;
+       mutable ld::Fixup                                               _fixup2;
+       mutable ld::Fixup                                               _fixup3;
+       
+       static ld::Section                                              _s_section;
+};
+
+ld::Section StubAtom::_s_section("__TEXT", "__stubs", ld::Section::typeStub);
+
+
+
+class NonLazyPointerAtom : public ld::Atom {
+public:
+       NonLazyPointerAtom(ld::passes::stubs::Pass& pass, const ld::Atom& stubTo,
+                                          bool weakImport)
+                               : ld::Atom(_s_section, ld::Atom::definitionRegular, 
+                                                       ld::Atom::combineNever, ld::Atom::scopeLinkageUnit, ld::Atom::typeNonLazyPointer, 
+                                                       symbolTableNotIn, false, false, false, ld::Atom::Alignment(3)), 
+                               _stubTo(stubTo),
+       _fixup1(0, ld::Fixup::k1of2, ld::Fixup::kindSetAuthData, (ld::Fixup::AuthData){ 0, true, ld::Fixup::AuthData::ptrauth_key_asia }),
+       _fixup2(0, ld::Fixup::k2of2, ld::Fixup::kindStoreTargetAddressLittleEndianAuth64, &stubTo) {
+                                       _fixup2.weakImport = weakImport;
+                                       pass.addAtom(*this);
+                               }
+
+       virtual const ld::File*                                 file() const                                    { return _stubTo.file(); }
+       virtual const char*                                             name() const                                    { return _stubTo.name(); }
+       virtual uint64_t                                                size() const                                    { return 8; }
+       virtual uint64_t                                                objectAddress() const                   { return 0; }
+       virtual void                                                    copyRawContent(uint8_t buffer[]) const { }
+       virtual void                                                    setScope(Scope)                                 { }
+       virtual ld::Fixup::iterator                             fixupsBegin() const                             { return (ld::Fixup*)&_fixup1; }
+       virtual ld::Fixup::iterator                             fixupsEnd()     const                           { return &((ld::Fixup*)&_fixup2)[1]; }
+
+private:
+       const ld::Atom&                                                 _stubTo;
+       ld::Fixup                                                               _fixup1;
+       ld::Fixup                                                               _fixup2;
+       
+       static ld::Section                                              _s_section;
+};
+
+ld::Section NonLazyPointerAtom::_s_section("__DATA", "__auth_got", ld::Section::typeNonLazyPointer);
+
+
+class NonLazyStubAtom : public ld::Atom {
+public:
+                               NonLazyStubAtom(ld::passes::stubs::Pass& pass, const ld::Atom& stubTo,
+                                                               bool weakImport)
+                               : 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), 
+                               _nonLazyPointer(pass, stubTo, weakImport),
+                               _fixup1(0, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressARM64Page21, &_nonLazyPointer),
+                               _fixup2(4, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressARM64PageOff12, &_nonLazyPointer) { 
+                                       asprintf((char**)&_name, "%s.stub", _stubTo.name());
+                                       pass.addAtom(*this);
+                               }
+
+       virtual const ld::File*                                 file() const                                    { return _stubTo.file(); }
+       virtual const char*                                             name() const                                    { return _name; }
+       virtual uint64_t                                                size() const                                    { return 16; }
+       virtual uint64_t                                                objectAddress() const                   { return 0; }
+       virtual void                                                    copyRawContent(uint8_t buffer[]) const {
+               OSWriteLittleInt32(&buffer[ 0], 0, 0x90000011); // ADRP  X17, dyld_mageLoaderCache@page
+               OSWriteLittleInt32(&buffer[ 4], 0, 0x91000231); // ADD   X17, X17, dyld_mageLoaderCache@pageoff
+               OSWriteLittleInt32(&buffer[ 8], 0, 0xF9400230); // LDR   X16, [X17]
+               OSWriteLittleInt32(&buffer[12], 0, 0xD71F0A11); // BRAA  X16, X17
+       }
+       virtual void                                                    setScope(Scope)                                 { }
+       virtual ld::Fixup::iterator                             fixupsBegin() const                             { return &_fixup1; }
+       virtual ld::Fixup::iterator                             fixupsEnd()     const                           { return &((ld::Fixup*)&_fixup2)[1]; }
+
+private:
+       const ld::Atom&                                                 _stubTo;
+       const char*                                                             _name;
+       NonLazyPointerAtom                                              _nonLazyPointer;
+       mutable ld::Fixup                                               _fixup1;
+       mutable ld::Fixup                                               _fixup2;
+       
+       static ld::Section                                              _s_section;
+};
+
+ld::Section NonLazyStubAtom::_s_section("__TEXT", "__auth_stubs", ld::Section::typeStub);
+
+
+} // namespace arm64e
+#endif
+
index 08879c1f417abb5e6d728532267874542a4dc398..8e79b39c2990c594521abbc72d7f3e9b537dff05 100644 (file)
@@ -328,6 +328,89 @@ private:
 ld::Section StubAtom::_s_section("__TEXT", "__symbol_stub", ld::Section::typeStub);
 
 
+class NonLazyPointerAtom : public ld::Atom {
+public:
+       NonLazyPointerAtom(ld::passes::stubs::Pass& pass, const ld::Atom& target,
+                                          bool weakImport)
+                               : ld::Atom(_s_section, ld::Atom::definitionRegular, 
+                                                       ld::Atom::combineNever, ld::Atom::scopeLinkageUnit, ld::Atom::typeNonLazyPointer, 
+                                                       symbolTableNotIn, false, false, false, ld::Atom::Alignment(2)),
+                               _target(target),
+                               _fixup1(0, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressLittleEndian32, &target) {
+                                       _fixup1.weakImport = weakImport;
+                                       pass.addAtom(*this);
+                               }
+
+       virtual const ld::File*                                 file() const                                    { return _target.file(); }
+       virtual const char*                                             name() const                                    { return _target.name(); }
+       virtual uint64_t                                                size() const                                    { return 4; }
+       virtual uint64_t                                                objectAddress() const                   { return 0; }
+       virtual void                                                    copyRawContent(uint8_t buffer[]) const { }
+       virtual void                                                    setScope(Scope)                                 { }
+       virtual ld::Fixup::iterator                             fixupsBegin() const                             { return (ld::Fixup*)&_fixup1; }
+       virtual ld::Fixup::iterator                             fixupsEnd()     const                           { return &((ld::Fixup*)&_fixup1)[1]; }
+
+private:
+       const ld::Atom&                                                 _target;
+       ld::Fixup                                                               _fixup1;
+       
+       static ld::Section                                              _s_section;
+};
+
+ld::Section NonLazyPointerAtom::_s_section("__DATA", "__got", ld::Section::typeNonLazyPointer);
+
+
+class NonLazyStubAtom : public ld::Atom {
+public:
+       NonLazyStubAtom(ld::passes::stubs::Pass& pass, const ld::Atom& target,
+                                       bool weakImport)
+                               : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
+                                                       ld::Atom::scopeLinkageUnit, ld::Atom::typeStub, 
+                                                       symbolTableNotIn, false, false, false, ld::Atom::Alignment(1)), 
+                               _target(target),
+                               _nonlazyPointer(pass, target, weakImport),
+                               _fixup1(8, ld::Fixup::k1of4, ld::Fixup::kindSetTargetAddress, &_nonlazyPointer),
+                               _fixup2(8, ld::Fixup::k2of4, ld::Fixup::kindSubtractTargetAddress, this),
+                               _fixup3(8, ld::Fixup::k3of4, ld::Fixup::kindSubtractAddend, 5),
+                               _fixup4(8, ld::Fixup::k4of4, ld::Fixup::kindStoreLittleEndian32) { pass.addAtom(*this); }
+
+       virtual const ld::File*                                 file() const                                    { return _target.file(); }
+       virtual const char*                                             name() const                                    { return _target.name(); }
+       virtual uint64_t                                                size() const                                    { return 14; }
+       virtual uint64_t                                                objectAddress() const                   { return 0; }
+       virtual void                                                    copyRawContent(uint8_t buffer[]) const {
+                       buffer[0]  = 0xE8;              // call next instruction (picbase)
+                       buffer[1]  = 0x00;
+                       buffer[2]  = 0x00;
+                       buffer[3]  = 0x00;
+                       buffer[4]  = 0x00;
+                       buffer[5]  = 0x58;              // pop eax
+                       buffer[6]  = 0x8D;              // lea foo$nonlazy_pointer-picbase(eax),eax
+                       buffer[7]  = 0x80;
+                       buffer[8]  = 0x00;
+                       buffer[9]  = 0x00;
+                       buffer[10] = 0x00;
+                       buffer[11] = 0x00;
+                       buffer[12] = 0xFF;              // jmp *(eax)
+                       buffer[13] = 0x20;
+       }
+       virtual void                                                    setScope(Scope)                                 { }
+       virtual ld::Fixup::iterator                             fixupsBegin() const                             { return &_fixup1; }
+       virtual ld::Fixup::iterator                             fixupsEnd()     const                           { return &((ld::Fixup*)&_fixup4)[1]; }
+
+private:
+       const ld::Atom&                                                 _target;
+       NonLazyPointerAtom                                              _nonlazyPointer;
+       mutable ld::Fixup                                               _fixup1;
+       ld::Fixup                                                               _fixup2;
+       ld::Fixup                                                               _fixup3;
+       ld::Fixup                                                               _fixup4;
+
+       static ld::Section                                              _s_section;
+};
+
+ld::Section NonLazyStubAtom::_s_section("__TEXT", "__symbol_stub", ld::Section::typeStub);
+
 
 } // namespace x86
 
index 5031dbc61f1abf3dc4ce0bbb6c935575998c7c94..5c7de1052f2f1ab1cce327a4bbcfc09d433beaa4 100644 (file)
@@ -351,12 +351,14 @@ ld::Section StubAtom::_s_section("__TEXT", "__stubs", ld::Section::typeStub);
 
 class NonLazyPointerAtom : public ld::Atom {
 public:
-                                                                                       NonLazyPointerAtom(ld::passes::stubs::Pass& pass, const ld::Atom& stubTo)
+       NonLazyPointerAtom(ld::passes::stubs::Pass& pass, const ld::Atom& stubTo,
+                                          bool weakImport)
                                : ld::Atom(_s_section, ld::Atom::definitionRegular, 
                                                        ld::Atom::combineNever, ld::Atom::scopeLinkageUnit, ld::Atom::typeNonLazyPointer, 
                                                        symbolTableNotIn, false, false, false, ld::Atom::Alignment(3)), 
                                _stubTo(stubTo),
                                _fixup1(0, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressLittleEndian64, &stubTo) {
+                                       _fixup1.weakImport = weakImport;
                                        pass.addAtom(*this);
                                }
 
@@ -380,14 +382,15 @@ ld::Section NonLazyPointerAtom::_s_section("__DATA", "__got", ld::Section::typeN
 
 
 
-class KextStubAtom : public ld::Atom {
+class NonLazyStubAtom : public ld::Atom {
 public:
-                                                                                       KextStubAtom(ld::passes::stubs::Pass& pass, const ld::Atom& stubTo)
+       NonLazyStubAtom(ld::passes::stubs::Pass& pass, const ld::Atom& stubTo,
+                                       bool weakImport)
                                : 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), 
-                               _nonLazyPointer(pass, stubTo),
+                               _nonLazyPointer(pass, stubTo, weakImport),
                                _fixup(2, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressX86PCRel32, &_nonLazyPointer) { pass.addAtom(*this); }
 
        virtual const ld::File*                                 file() const                                    { return _stubTo.file(); }
@@ -414,7 +417,7 @@ private:
        static ld::Section                                              _s_section;
 };
 
-ld::Section KextStubAtom::_s_section("__TEXT", "__stubs", ld::Section::typeStub);
+ld::Section NonLazyStubAtom::_s_section("__TEXT", "__stubs", ld::Section::typeStub);
 
 
 } // namespace x86_64 
index fb5b9f3b6d2d6ea51cdf60fb2f78f02e45b936dc..219c65e1e374e420118dc25d372fff866394e7e3 100644 (file)
@@ -75,7 +75,6 @@ private:
        const cpu_type_t                        _architecture;
        const bool                                      _lazyDylibsInUuse;
        const bool                                      _compressedLINKEDIT;
-       const bool                                      _prebind;
        const bool                                      _mightBeInSharedRegion;
        const bool                                      _pic;
        const bool                                      _flatNamespace;
@@ -102,7 +101,6 @@ Pass::Pass(const Options& opts)
                _architecture(opts.architecture()),
                _lazyDylibsInUuse(opts.usingLazyDylibLinking()),
                _compressedLINKEDIT(opts.makeCompressedDyldInfo()),
-               _prebind(opts.prebind()),
                _mightBeInSharedRegion(opts.sharedRegionEligible()), 
                _pic(opts.outputSlidable()),
                _flatNamespace(opts.nameSpace() != Options::kTwoLevelNameSpace),
@@ -190,7 +188,9 @@ ld::Atom* Pass::makeStub(const ld::Atom& target, bool weakImport)
        switch ( _architecture ) {
 #if SUPPORT_ARCH_i386
                case CPU_TYPE_I386:
-                       if ( usingCompressedLINKEDIT() && !forLazyDylib )
+                       if ( usingCompressedLINKEDIT() && !forLazyDylib && _options.noLazyBinding() && !stubToResolver)
+                               return new ld::passes::stubs::x86::NonLazyStubAtom(*this, target, weakImport);
+                       else if ( usingCompressedLINKEDIT() && !forLazyDylib )
                                return new ld::passes::stubs::x86::StubAtom(*this, target, stubToGlobalWeakDef, stubToResolver, weakImport);
                        else
                                return new ld::passes::stubs::x86::classic::StubAtom(*this, target, forLazyDylib, weakImport);
@@ -199,7 +199,9 @@ ld::Atom* Pass::makeStub(const ld::Atom& target, bool weakImport)
 #if SUPPORT_ARCH_x86_64
                case CPU_TYPE_X86_64:
                        if ( (_options.outputKind() == Options::kKextBundle) && _options.kextsUseStubs() ) 
-                               return new ld::passes::stubs::x86_64::KextStubAtom(*this, target);
+                               return new ld::passes::stubs::x86_64::NonLazyStubAtom(*this, target, weakImport);
+                       else if ( usingCompressedLINKEDIT() && !forLazyDylib && _options.noLazyBinding() && !stubToResolver )
+                               return new ld::passes::stubs::x86_64::NonLazyStubAtom(*this, target, weakImport);
                        else if ( usingCompressedLINKEDIT() && !forLazyDylib )
                                return new ld::passes::stubs::x86_64::StubAtom(*this, target, stubToGlobalWeakDef, stubToResolver, weakImport);
                        else
@@ -210,11 +212,13 @@ ld::Atom* Pass::makeStub(const ld::Atom& target, bool weakImport)
                case CPU_TYPE_ARM: 
                        if ( (_options.outputKind() == Options::kKextBundle) && _options.kextsUseStubs() ) {
                                // if text relocs are not allows in kext bundles, then linker must create a stub 
-                               return new ld::passes::stubs::arm::StubPICKextAtom(*this, target);
+                               return new ld::passes::stubs::arm::StubPICKextAtom(*this, target, weakImport);
                        }
                        else if ( usingCompressedLINKEDIT() && !forLazyDylib ) {
                                if ( (_stubCount < 900) && !_mightBeInSharedRegion && !_largeText && !_options.makeEncryptable() )
                                        return new ld::passes::stubs::arm::StubCloseAtom(*this, target, stubToGlobalWeakDef, stubToResolver, weakImport);
+                               else if ( usingCompressedLINKEDIT() && !forLazyDylib && _options.noLazyBinding() && !stubToResolver)
+                                       return new ld::passes::stubs::arm::StubPICKextAtom(*this, target, weakImport);
                                else if ( _pic )
                                        return new ld::passes::stubs::arm::StubPICAtom(*this, target, stubToGlobalWeakDef, stubToResolver, weakImport, usingDataConst);
                                else
@@ -230,8 +234,21 @@ ld::Atom* Pass::makeStub(const ld::Atom& target, bool weakImport)
 #endif
 #if SUPPORT_ARCH_arm64
                case CPU_TYPE_ARM64:
+#if SUPPORT_ARCH_arm64e
+                       if ( (_options.subArchitecture() == CPU_SUBTYPE_ARM64_E) && _options.useAuthenticatedStubs() ) {
+                               if ( (_options.outputKind() == Options::kKextBundle) && _options.kextsUseStubs() )
+                                       return new ld::passes::stubs::arm64e::NonLazyStubAtom(*this, target, weakImport);
+                               else if ( usingCompressedLINKEDIT() && !forLazyDylib && _options.noLazyBinding() && !stubToResolver )
+                                       return new ld::passes::stubs::arm64e::NonLazyStubAtom(*this, target, weakImport);
+                               else
+                                       return new ld::passes::stubs::arm64e::StubAtom(*this, target, stubToGlobalWeakDef, stubToResolver, weakImport, usingDataConst);
+                               break;
+                       }
+#endif
                        if ( (_options.outputKind() == Options::kKextBundle) && _options.kextsUseStubs() ) 
-                               return new ld::passes::stubs::arm64::KextStubAtom(*this, target);
+                               return new ld::passes::stubs::arm64::NonLazyStubAtom(*this, target, weakImport);
+                       else if ( usingCompressedLINKEDIT() && !forLazyDylib && _options.noLazyBinding() && !stubToResolver )
+                               return new ld::passes::stubs::arm64::NonLazyStubAtom(*this, target, weakImport);
                        else
                                return new ld::passes::stubs::arm64::StubAtom(*this, target, stubToGlobalWeakDef, stubToResolver, weakImport, usingDataConst);
                        break;
@@ -357,7 +374,7 @@ void Pass::process(ld::Internal& state)
                return;
        
        // <rdar://problem/8553283> lazily check for helper
-       if ( !_options.makeCompressedDyldInfo() && (state.classicBindingHelper == NULL) && (_options.outputKind() != Options::kKextBundle) ) 
+       if ( !_options.makeCompressedDyldInfo() && !_options.makeThreadedStartsSection() && (state.classicBindingHelper == NULL) && (_options.outputKind() != Options::kKextBundle) )
                throw "symbol dyld_stub_binding_helper not found, normally in crt1.o/dylib1.o/bundle1.o";
 
        // disable arm close stubs in some cases
diff --git a/src/ld/passes/thread_starts.cpp b/src/ld/passes/thread_starts.cpp
new file mode 100644 (file)
index 0000000..493b4d0
--- /dev/null
@@ -0,0 +1,250 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 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@
+ */
+
+
+#include <stdint.h>
+#include <math.h>
+#include <unistd.h>
+#include <dlfcn.h>
+#include <libkern/OSByteOrder.h>
+
+#include <vector>
+#include <map>
+
+#include "MachOFileAbstraction.hpp"
+#include "Architectures.hpp"
+#include "ld.hpp"
+#include "thread_starts.h"
+
+namespace ld {
+namespace passes {
+namespace thread_starts {
+
+
+static std::map<const Atom*, uint64_t> sAtomToAddress;
+
+
+
+
+template <typename A>
+class ThreadStartsAtom : public ld::Atom {
+public:
+                                                                                       ThreadStartsAtom(uint32_t fixupAlignment, uint32_t numThreadStarts);
+                                                                                       ~ThreadStartsAtom();
+
+       virtual const ld::File*                                 file() const                                    { return NULL; }
+       virtual const char*                                             name() const                                    { return "thread starts"; }
+       virtual uint64_t                                                size() const                                    { return 4 + (_numThreadStarts * 4); }
+       virtual uint64_t                                                objectAddress() const                   { return 0; }
+       virtual void                                                    copyRawContent(uint8_t buffer[]) const {
+               uint32_t header = 0;
+               if (_fixupAlignment == 8)
+                       header |= 1;
+               bzero(buffer, size());
+               A::P::E::set32(*((uint32_t*)(&buffer[0])), header); // header
+               // Fill in offsets with 0xFFFFFFFF's for now as that wouldn't be a valid offset
+               memset(&buffer[4], 0xFFFFFFFF, _numThreadStarts * sizeof(uint32_t));
+       }
+       virtual void                                                    setScope(Scope)                                 { }
+       virtual Fixup::iterator                                 fixupsBegin() const     { return NULL; }
+       virtual Fixup::iterator                                 fixupsEnd() const       { return NULL; }
+
+private:
+
+       uint32_t                                                                _fixupAlignment;
+       uint32_t                                                                _numThreadStarts;
+
+       static bool                                                             _s_log;
+       static ld::Section                                              _s_section;
+};
+
+template <typename A>
+bool ThreadStartsAtom<A>::_s_log = false;
+
+template <typename A>
+ld::Section ThreadStartsAtom<A>::_s_section("__TEXT", "__thread_starts", ld::Section::typeThreadStarts);
+
+
+template <typename A>
+ThreadStartsAtom<A>::ThreadStartsAtom(uint32_t fixupAlignment, uint32_t numThreadStarts)
+       : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
+                               ld::Atom::scopeLinkageUnit, ld::Atom::typeUnclassified,
+                               symbolTableNotIn, false, false, false, ld::Atom::Alignment(2)),
+               _fixupAlignment(fixupAlignment), _numThreadStarts(numThreadStarts)
+{
+       assert(_fixupAlignment == 4 || _fixupAlignment == 8);
+}
+
+template <typename A>
+ThreadStartsAtom<A>::~ThreadStartsAtom()
+{
+}
+
+
+static void buildAddressMap(const Options& opts, ld::Internal& state) {
+       // Assign addresses to sections
+       state.setSectionSizesAndAlignments();
+       state.assignFileOffsets();
+
+       // Assign addresses to atoms in a side table
+       const bool log = false;
+       if ( log ) fprintf(stderr, "buildAddressMap()\n");
+       for (std::vector<ld::Internal::FinalSection*>::iterator sit = state.sections.begin(); sit != state.sections.end(); ++sit) {
+               ld::Internal::FinalSection* sect = *sit;
+               uint16_t maxAlignment = 0;
+               uint64_t offset = 0;
+               if ( log ) fprintf(stderr, "  section=%s/%s, address=0x%08llX\n", sect->segmentName(), 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;
+                       uint32_t atomAlignmentPowerOf2 = atom->alignment().powerOf2;
+                       uint32_t atomModulus = atom->alignment().modulus;
+                       if ( atomAlignmentPowerOf2 > maxAlignment )
+                               maxAlignment = atomAlignmentPowerOf2;
+                       // calculate section offset for this atom
+                       uint64_t alignment = 1 << atomAlignmentPowerOf2;
+                       uint64_t currentModulus = (offset % alignment);
+                       uint64_t requiredModulus = atomModulus;
+                       if ( currentModulus != requiredModulus ) {
+                               if ( requiredModulus > currentModulus )
+                                       offset += requiredModulus-currentModulus;
+                               else
+                                       offset += requiredModulus+alignment-currentModulus;
+                       }
+
+                       if ( log ) fprintf(stderr, "    0x%08llX atom=%p, name=%s\n", sect->address+offset, atom, atom->name());
+                       sAtomToAddress[atom] = sect->address + offset;
+
+                       offset += atom->size();
+               }
+       }
+}
+
+static uint32_t threadStartsCountInSection(std::vector<uint64_t>& fixupAddressesInSection) {
+       if (fixupAddressesInSection.empty())
+               return 0;
+
+       std::sort(fixupAddressesInSection.begin(), fixupAddressesInSection.end());
+
+       uint32_t numThreadStarts = 0;
+
+       // Walk all the fixups, and compute the number of rebase chains we need, assuming
+       // 11-bits of delta, with 4-byte alignment for each entry.
+       const uint64_t deltaBits = 11;
+       const uint64_t minAlignment = 4;
+
+       uint64_t prevAddress = 0;
+       for (uint64_t address : fixupAddressesInSection) {
+               uint64_t delta = address - prevAddress;
+               assert( (delta & (minAlignment - 1)) == 0 );
+               delta /= minAlignment;
+               if (delta >= (1 << deltaBits)) {
+                       ++numThreadStarts;
+               }
+               prevAddress = address;
+       }
+       fixupAddressesInSection.clear();
+
+       return numThreadStarts;
+}
+
+static uint32_t processSections(ld::Internal& state, uint64_t minAlignment) {
+       uint32_t numThreadStarts = 0;
+
+       std::vector<uint64_t> fixupAddressesInSection;
+       for (ld::Internal::FinalSection* sect : state.sections) {
+               if ( sect->isSectionHidden() )
+                       continue;
+               for (const ld::Atom* atom : sect->atoms) {
+                       bool seenTarget = false;
+                       for (ld::Fixup::iterator fit = atom->fixupsBegin(), end=atom->fixupsEnd(); fit != end; ++fit) {
+                               if ( fit->firstInCluster() ) {
+                                       seenTarget = false;
+                               }
+                               if ( fit->setsTarget(false) ) {
+                                       seenTarget = true;
+                               }
+                               if ( !fit->lastInCluster() )
+                                       continue;
+                               if ( !fit->isStore() )
+                                       continue;
+                               if ( fit->isPcRelStore(false) )
+                                       continue;
+                               if ( !seenTarget )
+                                       continue;
+                               uint64_t address = sAtomToAddress[atom] + fit->offsetInAtom;
+                               fixupAddressesInSection.push_back(address);
+
+                               if ( (address & (minAlignment-1)) != 0 ) {
+                                       throwf("pointer not aligned at address 0x%llX (%s + %d from %s)",
+                                                  address, atom->name(), fit->offsetInAtom, atom->safeFilePath());
+                               }
+                       }
+               }
+               numThreadStarts += threadStartsCountInSection(fixupAddressesInSection);
+       }
+
+       return numThreadStarts;
+}
+
+void doPass(const Options& opts, ld::Internal& state)
+{
+       if ( !opts.makeThreadedStartsSection() )
+               return;
+
+       buildAddressMap(opts, state);
+
+       const uint32_t fixupAlignment = 4;
+       uint32_t numThreadStarts = processSections(state, fixupAlignment);
+
+       // create atom that contains the whole compact unwind table
+       switch ( opts.architecture() ) {
+#if SUPPORT_ARCH_x86_64
+               case CPU_TYPE_X86_64:
+                       state.addAtom(*new ThreadStartsAtom<x86_64>(fixupAlignment, numThreadStarts));
+                       break;
+#endif
+#if SUPPORT_ARCH_i386
+               case CPU_TYPE_I386:
+                       state.addAtom(*new ThreadStartsAtom<x86>(fixupAlignment, numThreadStarts));
+                       break;
+#endif
+#if SUPPORT_ARCH_arm64
+               case CPU_TYPE_ARM64:
+                       state.addAtom(*new ThreadStartsAtom<arm64>(fixupAlignment, numThreadStarts));
+                       break;
+#endif
+#if SUPPORT_ARCH_arm_any
+               case CPU_TYPE_ARM:
+                       state.addAtom(*new ThreadStartsAtom<arm>(fixupAlignment, numThreadStarts));
+                       break;
+#endif
+               default:
+                       assert(0 && "no threaded starts for arch");
+       }
+}
+
+
+} // namespace thread_starts
+} // namespace passes 
+} // namespace ld 
diff --git a/src/ld/passes/thread_starts.h b/src/ld/passes/thread_starts.h
new file mode 100644 (file)
index 0000000..a1213c4
--- /dev/null
@@ -0,0 +1,45 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 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 __THREAD_STARTS_H__
+#define __THREAD_STARTS_H__
+
+#include "Options.h"
+#include "ld.hpp"
+
+
+namespace ld {
+namespace passes {
+namespace thread_starts {
+
+// called by linker to generate a thread starts section
+extern void doPass(const Options& opts, ld::Internal& internal);
+
+
+} // namespace thread_starts
+} // namespace passes 
+} // namespace ld 
+
+#endif // __THREAD_STARTS_H__
index 6763e1a358938083c21e4cf2229e7677e736b015..5a355dc952f7ac33b3e77869ef1096baf416f09a 100644 (file)
@@ -35,6 +35,8 @@
 #include "parsers/macho_relocatable_file.h"
 #include "parsers/lto_file.h"
 
+const ld::VersionSet ld::File::_platforms;
+
 static bool                    sDumpContent= true;
 static bool                    sDumpStabs      = false;
 static bool                    sSort           = true;
@@ -1258,8 +1260,9 @@ static ld::relocatable::File* createReader(const char* path)
        if ( ! foundFatSlice ) {
                cpu_type_t archOfObj;
                cpu_subtype_t subArchOfObj;
-               Options::Platform platform;
-               if ( mach_o::relocatable::isObjectFile(p, &archOfObj, &subArchOfObj, &platform) ) {
+               ld::Platform platform;
+               uint32_t minOS;
+               if ( mach_o::relocatable::isObjectFile(p, &archOfObj, &subArchOfObj, &platform, &minOS) ) {
                        objOpts.architecture = archOfObj;
                        objOpts.subType = subArchOfObj;
                }
index e2719783b1efa0c7750c6feb791f00db5700b077..45fcb0f508bf6876323a5168fc397b28963a5f3f 100644 (file)
@@ -32,6 +32,7 @@
 #include <errno.h>
 
 #include <vector>
+#include <tuple>
 #include <set>
 #include <unordered_set>
 
@@ -615,6 +616,8 @@ const char* DyldInfoPrinter<A>::ordinalName(int libraryOrdinal)
                        return "main-executable";
                case BIND_SPECIAL_DYLIB_FLAT_LOOKUP:
                        return "flat-namespace";
+               case BIND_SPECIAL_DYLIB_WEAK_LOOKUP:
+                       return "weak";
        }
        if ( libraryOrdinal < BIND_SPECIAL_DYLIB_FLAT_LOOKUP )
                throw "unknown special ordinal";
@@ -644,12 +647,164 @@ const char* DyldInfoPrinter<A>::classicOrdinalName(int libraryOrdinal)
 template <typename A>
 void DyldInfoPrinter<A>::printRebaseInfo()
 {
+       bool seenThreadedRebase = false;
        if ( (fInfo == NULL) || (fInfo->rebase_off() == 0) ) {
-               printf("no compressed rebase info\n");
+               // If we have no rebase opcodes, then we may be using the threaded rebase/bind combined
+               // format and need to parse the bind opcodes instead.
+               if ( (fInfo->rebase_size() == 0) && (fInfo->bind_size() != 0) ) {
+                       const uint8_t* p = (uint8_t*)fHeader + fInfo->bind_off();
+                       const uint8_t* end = &p[fInfo->bind_size()];
+
+                       uint8_t type = 0;
+                       uint8_t flags = 0;
+                       uint8_t segIndex = 0;
+                       uint64_t segOffset = 0;
+                       const char* symbolName = NULL;
+                       const char* fromDylib = "??";
+                       int libraryOrdinal = 0;
+                       int64_t addend = 0;
+                       uint32_t count;
+                       uint32_t skip;
+                       pint_t segStartAddr = 0;
+                       const char* segName = "??";
+                       const char* typeName = "??";
+                       const char* weak_import = "";
+                       bool done = false;
+                       while ( !done && (p < end) ) {
+                               uint8_t immediate = *p & BIND_IMMEDIATE_MASK;
+                               uint8_t opcode = *p & BIND_OPCODE_MASK;
+                               ++p;
+                               switch (opcode) {
+                                       case BIND_OPCODE_DONE:
+                                               done = true;
+                                               break;
+                                       case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM:
+                                               libraryOrdinal = immediate;
+                                               fromDylib = ordinalName(libraryOrdinal);
+                                               break;
+                                       case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB:
+                                               libraryOrdinal = read_uleb128(p, end);
+                                               fromDylib = ordinalName(libraryOrdinal);
+                                               break;
+                                       case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM:
+                                               // the special ordinals are negative numbers
+                                               if ( immediate == 0 )
+                                                       libraryOrdinal = 0;
+                                               else {
+                                                       int8_t signExtended = BIND_OPCODE_MASK | immediate;
+                                                       libraryOrdinal = signExtended;
+                                               }
+                                               fromDylib = ordinalName(libraryOrdinal);
+                                               break;
+                                       case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
+                                               symbolName = (char*)p;
+                                               while (*p != '\0')
+                                                       ++p;
+                                               ++p;
+                                               flags = immediate & BIND_SYMBOL_FLAGS_WEAK_IMPORT;
+                                               if ( flags != 0 )
+                                                       weak_import = " (weak import)";
+                                               else
+                                                       weak_import = "";
+                                               break;
+                                       case BIND_OPCODE_SET_TYPE_IMM:
+                                               type = immediate;
+                                               typeName = bindTypeName(type);
+                                               break;
+                                       case BIND_OPCODE_SET_ADDEND_SLEB:
+                                               addend = read_sleb128(p, end);
+                                               break;
+                                       case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
+                                               segIndex = immediate;
+                                               segStartAddr = segStartAddress(segIndex);
+                                               segName = segmentName(segIndex);
+                                               segOffset = read_uleb128(p, end);
+                                               break;
+                                       case BIND_OPCODE_ADD_ADDR_ULEB:
+                                               segOffset += read_uleb128(p, end);
+                                               break;
+                                       case BIND_OPCODE_DO_BIND:
+                                               break;
+                                       case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
+                                               segOffset += read_uleb128(p, end) + sizeof(pint_t);
+                                               break;
+                                       case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:
+                                               segOffset += immediate*sizeof(pint_t) + sizeof(pint_t);
+                                               break;
+                                       case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB:
+                                               count = read_uleb128(p, end);
+                                               skip = read_uleb128(p, end);
+                                               for (uint32_t i=0; i < count; ++i) {
+                                                       segOffset += skip + sizeof(pint_t);
+                                               }
+                                               break;
+                                       case BIND_OPCODE_THREADED:
+                                               // Note the immediate is a sub opcode
+                                               switch (immediate) {
+                                                       case BIND_SUBOPCODE_THREADED_SET_BIND_ORDINAL_TABLE_SIZE_ULEB:
+                                                               printf("rebase information (from compressed dyld info):\n");
+                                                               printf("segment section          address     type         value\n");
+                                                               count = read_uleb128(p, end);
+                                                               seenThreadedRebase = true;
+                                                               break;
+                                                       case BIND_SUBOPCODE_THREADED_APPLY: {
+                                                               uint64_t delta = 0;
+                                                               do {
+                                                                       const uint8_t* pointerLocation = (uint8_t*)fHeader + fSegments[segIndex]->fileoff() + segOffset;
+                                                                       uint64_t value = P::getP(*(uint64_t*)pointerLocation);
+#if SUPPORT_ARCH_arm64e
+                                                                       uint16_t diversity = (uint16_t)(value >> 32);
+                                                                       bool hasAddressDiversity = (value & (1ULL << 48)) != 0;
+                                                                       ptrauth_key key = (ptrauth_key)((value >> 49) & 0x3);
+                                                                       bool isAuthenticated = (value & (1ULL << 63)) != 0;
+#endif
+                                                                       bool isRebase = (value & (1ULL << 62)) == 0;
+                                                                       if (isRebase) {
+
+#if SUPPORT_ARCH_arm64e
+                                                                               static const char* keyNames[] = {
+                                                                                       "IA", "IB", "DA", "DB"
+                                                                               };
+                                                                               if (isAuthenticated) {
+                                                                                       uint64_t targetValue = value & 0xFFFFFFFFULL;
+                                                                                       targetValue += fBaseAddress;
+                                                                                       printf("%-7s %-16s 0x%08llX  %s  0x%08llX (JOP: diversity %d, address %s, %s)\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName, targetValue, diversity, hasAddressDiversity ? "true" : "false", keyNames[key]);
+                                                                               } else
+#endif
+                                                                               {
+                                                                                       // Regular pointer which needs to fit in 51-bits of value.
+                                                                                       // C++ RTTI uses the top bit, so we'll allow the whole top-byte
+                                                                                       // and the signed-extended bottom 43-bits to be fit in to 51-bits.
+                                                                                       uint64_t top8Bits = value & 0x0007F80000000000ULL;
+                                                                                       uint64_t bottom43Bits = value & 0x000007FFFFFFFFFFULL;
+                                                                                       uint64_t targetValue = ( top8Bits << 13 ) | (((intptr_t)(bottom43Bits << 21) >> 21) & 0x00FFFFFFFFFFFFFF);
+                                                                                       printf("%-7s %-16s 0x%08llX  %s  0x%08llX\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName, targetValue);
+                                                                               }
+                                                                       }
+                                                                       // The delta is bits [51..61]
+                                                                       // And bit 62 is to tell us if we are a rebase (0) or bind (1)
+                                                                       value &= ~(1ULL << 62);
+                                                                       delta = ( value & 0x3FF8000000000000 ) >> 51;
+                                                                       segOffset += delta * sizeof(pint_t);
+                                                               } while ( delta != 0);
+                                                               break;
+                                                       }
+                                                       default:
+                                                               throwf("unknown threaded bind subopcode %d", immediate);
+                                               }
+                                               break;
+                                       default:
+                                               throwf("bad bind opcode %d", *p);
+                               }
+                       }
+               }
+
+               if (!seenThreadedRebase)
+                       printf("no compressed rebase info\n");
        }
        else {
                printf("rebase information (from compressed dyld info):\n");
-               printf("segment section          address     type\n");
+               printf("segment section          address     type         value\n");
 
                const uint8_t* p = (uint8_t*)fHeader + fInfo->rebase_off();
                const uint8_t* end = &p[fInfo->rebase_size()];
@@ -662,6 +817,8 @@ void DyldInfoPrinter<A>::printRebaseInfo()
                pint_t segStartAddr = 0;
                const char* segName = "??";
                const char* typeName = "??";
+               const uint8_t* pointerLocation = nullptr;
+               uint64_t value = 0;
                bool done = false;
                while ( !done && (p < end) ) {
                        uint8_t immediate = *p & REBASE_IMMEDIATE_MASK;
@@ -689,35 +846,42 @@ void DyldInfoPrinter<A>::printRebaseInfo()
                                        break;
                                case REBASE_OPCODE_DO_REBASE_IMM_TIMES:
                                        for (int i=0; i < immediate; ++i) {
-                                               printf("%-7s %-16s 0x%08llX  %s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName);
+                                               pointerLocation = (uint8_t*)fHeader + fSegments[segIndex]->fileoff() + segOffset;
+                                               value = P::getP(*(uint64_t*)pointerLocation);
+                                               printf("%-7s %-16s 0x%08llX  %s  0x%08llX\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName, value);
                                                segOffset += sizeof(pint_t);
                                        }
                                        break;
                                case REBASE_OPCODE_DO_REBASE_ULEB_TIMES:
                                        count = read_uleb128(p, end);
                                        for (uint32_t i=0; i < count; ++i) {
-                                               printf("%-7s %-16s 0x%08llX  %s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName);
+                                               pointerLocation = (uint8_t*)fHeader + fSegments[segIndex]->fileoff() + segOffset;
+                                               value = P::getP(*(uint64_t*)pointerLocation);
+                                               printf("%-7s %-16s 0x%08llX  %s  0x%08llX\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName, value);
                                                segOffset += sizeof(pint_t);
                                        }
                                        break;
                                case REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB:
-                                       printf("%-7s %-16s 0x%08llX  %s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName);
+                                       pointerLocation = (uint8_t*)fHeader + fSegments[segIndex]->fileoff() + segOffset;
+                                       value = P::getP(*(uint64_t*)pointerLocation);
+                                       printf("%-7s %-16s 0x%08llX  %s  0x%08llX\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName, value);
                                        segOffset += read_uleb128(p, end) + sizeof(pint_t);
                                        break;
                                case REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB:
                                        count = read_uleb128(p, end);
                                        skip = read_uleb128(p, end);
                                        for (uint32_t i=0; i < count; ++i) {
-                                               printf("%-7s %-16s 0x%08llX  %s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName);
+                                               pointerLocation = (uint8_t*)fHeader + fSegments[segIndex]->fileoff() + segOffset;
+                                               value = P::getP(*(uint64_t*)pointerLocation);
+                                               printf("%-7s %-16s 0x%08llX  %s  0x%08llX\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName, value);
                                                segOffset += skip + sizeof(pint_t);
                                        }
                                        break;
                                default:
                                        throwf("bad rebase opcode %d", *p);
                        }
-               }       
+               }
        }
-
 }
 
 
@@ -791,11 +955,6 @@ void DyldInfoPrinter<A>::printRebaseInfoOpcodes()
 
 }
 
-
-
-
-
-
 template <typename A>
 void DyldInfoPrinter<A>::printBindingInfoOpcodes(bool weakbinding)
 {
@@ -901,6 +1060,20 @@ void DyldInfoPrinter<A>::printBindingInfoOpcodes(bool weakbinding)
                                        skip = read_uleb128(p, end);
                                        printf("0x%04X BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB(%d, 0x%08X)\n", opcodeOffset, count, skip);
                                        break;
+                               case BIND_OPCODE_THREADED:
+                                       // Note the immediate is a sub opcode
+                                       switch (immediate) {
+                                               case BIND_SUBOPCODE_THREADED_SET_BIND_ORDINAL_TABLE_SIZE_ULEB:
+                                                       count = read_uleb128(p, end);
+                                                       printf("0x%04X BIND_SUBOPCODE_THREADED_SET_BIND_ORDINAL_TABLE_SIZE_ULEB(%d)\n", opcodeOffset, count);
+                                                       break;
+                                               case BIND_SUBOPCODE_THREADED_APPLY:
+                                                       printf("0x%04X BIND_SUBOPCODE_THREADED_APPLY\n", opcodeOffset);
+                                                       break;
+                                               default:
+                                                       throwf("unknown threaded bind subopcode %d", immediate);
+                                       }
+                                       break;
                                default:
                                        throwf("unknown bind opcode %d", *p);
                        }
@@ -909,7 +1082,20 @@ void DyldInfoPrinter<A>::printBindingInfoOpcodes(bool weakbinding)
 
 }
 
+struct ThreadedBindData {
+       ThreadedBindData(const char* symbolName, int64_t addend, int libraryOrdinal, uint8_t flags, uint8_t type)
+               : symbolName(symbolName), addend(addend), libraryOrdinal(libraryOrdinal), flags(flags), type(type) { }
 
+       std::tuple<const char*, int64_t, int, uint8_t, uint8_t> pack() const {
+               return std::make_tuple(symbolName, addend, libraryOrdinal, flags, type);
+       }
+
+       const char* symbolName  = nullptr;
+       int64_t addend                  = 0;
+       int libraryOrdinal              = 0;
+       uint8_t flags                   = 0;
+       uint8_t type                    = 0;
+};
 
 template <typename A>
 void DyldInfoPrinter<A>::printBindingInfo()
@@ -922,8 +1108,9 @@ void DyldInfoPrinter<A>::printBindingInfo()
                printf("segment section          address        type    addend dylib            symbol\n");
                const uint8_t* p = (uint8_t*)fHeader + fInfo->bind_off();
                const uint8_t* end = &p[fInfo->bind_size()];
-               
+
                uint8_t type = 0;
+               uint8_t flags = 0;
                uint8_t segIndex = 0;
                uint64_t segOffset = 0;
                const char* symbolName = NULL;
@@ -936,6 +1123,8 @@ void DyldInfoPrinter<A>::printBindingInfo()
                const char* segName = "??";
                const char* typeName = "??";
                const char* weak_import = "";
+               std::vector<ThreadedBindData> ordinalTable;
+               bool useThreadedRebaseBind = false;
                bool done = false;
                while ( !done && (p < end) ) {
                        uint8_t immediate = *p & BIND_IMMEDIATE_MASK;
@@ -968,7 +1157,8 @@ void DyldInfoPrinter<A>::printBindingInfo()
                                        while (*p != '\0')
                                                ++p;
                                        ++p;
-                                       if ( (immediate & BIND_SYMBOL_FLAGS_WEAK_IMPORT) != 0 )
+                                       flags = immediate & BIND_SYMBOL_FLAGS_WEAK_IMPORT;
+                                       if ( flags != 0 )
                                                weak_import = " (weak import)";
                                        else
                                                weak_import = "";
@@ -990,8 +1180,12 @@ void DyldInfoPrinter<A>::printBindingInfo()
                                        segOffset += read_uleb128(p, end);
                                        break;
                                case BIND_OPCODE_DO_BIND:
-                                       printf("%-7s %-16s 0x%08llX %10s  %5lld %-16s %s%s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName, addend, fromDylib, symbolName, weak_import );
-                                       segOffset += sizeof(pint_t);
+                                       if (!useThreadedRebaseBind) {
+                                               printf("%-7s %-16s 0x%08llX %10s  %5lld %-16s %s%s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName, addend, fromDylib, symbolName, weak_import );
+                                               segOffset += sizeof(pint_t);
+                                       } else {
+                                               ordinalTable.push_back(ThreadedBindData(symbolName, addend, libraryOrdinal, flags, type));
+                                       }
                                        break;
                                case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
                                        printf("%-7s %-16s 0x%08llX %10s  %5lld %-16s %s%s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName, addend, fromDylib, symbolName, weak_import );
@@ -1009,6 +1203,68 @@ void DyldInfoPrinter<A>::printBindingInfo()
                                                segOffset += skip + sizeof(pint_t);
                                        }
                                        break;
+                               case BIND_OPCODE_THREADED:
+                                       // Note the immediate is a sub opcode
+                                       switch (immediate) {
+                                               case BIND_SUBOPCODE_THREADED_SET_BIND_ORDINAL_TABLE_SIZE_ULEB:
+                                                       count = read_uleb128(p, end);
+                                                       ordinalTable.clear();
+                                                       ordinalTable.reserve(count);
+                                                       useThreadedRebaseBind = true;
+                                                       break;
+                                               case BIND_SUBOPCODE_THREADED_APPLY: {
+                                                       uint64_t delta = 0;
+                                                       do {
+                                                               const uint8_t* pointerLocation = (uint8_t*)fHeader + fSegments[segIndex]->fileoff() + segOffset;
+                                                               uint64_t value = P::getP(*(uint64_t*)pointerLocation);
+#if SUPPORT_ARCH_arm64e
+                                                               uint16_t diversity = (uint16_t)(value >> 32);
+                                                               bool hasAddressDiversity = (value & (1ULL << 48)) != 0;
+                                                               ptrauth_key key = (ptrauth_key)((value >> 49) & 0x3);
+                                                               bool isAuthenticated = (value & (1ULL << 63)) != 0;
+#endif
+                                                               bool isRebase = (value & (1ULL << 62)) == 0;
+
+                                                               if (isRebase) {
+                                                                       //printf("(rebase): %-7s %-16s 0x%08llX  %s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName);
+                                                               } else {
+                                                                       // the ordinal is bits [0..15]
+                                                                       uint16_t ordinal = value & 0xFFFF;
+                                                                       if (ordinal >= ordinalTable.size()) {
+                                                                               fprintf(stderr, "bind ordinal is out of range\n");
+                                                                               break;
+                                                                       }
+                                                                       std::tie(symbolName, addend, libraryOrdinal, flags, type) = ordinalTable[ordinal].pack();
+                                                                       if ( (flags & BIND_SYMBOL_FLAGS_WEAK_IMPORT) != 0 )
+                                                                               weak_import = " (weak import)";
+                                                                       else
+                                                                               weak_import = "";
+                                                                       fromDylib = ordinalName(libraryOrdinal);
+#if SUPPORT_ARCH_arm64e
+                                                                       if (isAuthenticated) {
+                                                                               static const char* keyNames[] = {
+                                                                                       "IA", "IB", "DA", "DB"
+                                                                               };
+                                                                               printf("%-7s %-16s 0x%08llX %10s  %5lld %-16s %s%s with value 0x%016llX (JOP: diversity %d, address %s, %s)\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName, addend, fromDylib, symbolName, weak_import, value, diversity, hasAddressDiversity ? "true" : "false", keyNames[key]);
+                                                                       } else
+#endif
+                                                                       {
+                                                                               printf("%-7s %-16s 0x%08llX %10s  %5lld %-16s %s%s with value 0x%016llX\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName, addend, fromDylib, symbolName, weak_import, value );
+                                                                       }
+                                                               }
+
+                                                               // The delta is bits [51..61]
+                                                               // And bit 62 is to tell us if we are a rebase (0) or bind (1)
+                                                               value &= ~(1ULL << 62);
+                                                               delta = ( value & 0x3FF8000000000000 ) >> 51;
+                                                               segOffset += delta * sizeof(pint_t);
+                                                       } while ( delta != 0);
+                                                       break;
+                                               }
+                                               default:
+                                                       throwf("unknown threaded bind subopcode %d", immediate);
+                                       }
+                                       break;
                                default:
                                        throwf("bad bind opcode %d", *p);
                        }
@@ -1734,6 +1990,8 @@ const char* DyldInfoPrinter<A>::sharedRegionKindName(uint8_t kind)
                        return "br22";
                case DYLD_CACHE_ADJ_V2_IMAGE_OFF_32:
                        return "off32";
+               case DYLD_CACHE_ADJ_V2_THREADED_POINTER_64:
+                       return "theaded-pointer64";
        }
 }
 
@@ -2009,6 +2267,93 @@ const char*      DyldInfoPrinter<arm64>::relocTypeName(uint8_t r_type)
 template <typename A>
 void DyldInfoPrinter<A>::printRelocRebaseInfo()
 {
+       // First check if we can find a magic section for threaded rebase
+       {
+               auto rebaseChain = [this](uintptr_t chainStartMappedAddress, uintptr_t chainStartVMAddress, uint64_t stepMultiplier, uintptr_t baseAddress) {
+                       uint64_t delta = 0;
+                       uintptr_t mappedAddress = chainStartMappedAddress;
+                       uintptr_t vmAddress = chainStartVMAddress;
+                       do {
+                               uint64_t value = *(uint64_t*)mappedAddress;
+
+                               uint8_t segIndex = segmentIndexForAddress(vmAddress);
+                               const char* segName = segmentName(segIndex);
+                               const char* sectName = sectionName(segIndex, vmAddress);
+
+#if SUPPORT_ARCH_arm64e
+                               uint16_t diversity = (uint16_t)(value >> 32);
+                               bool hasAddressDiversity = (value & (1ULL << 48)) != 0;
+                               ptrauth_key key = (ptrauth_key)((value >> 49) & 0x3);
+                               bool isAuthenticated = (value & (1ULL << 63)) != 0;
+#endif
+                               bool isRebase = (value & (1ULL << 62)) == 0;
+                               if (isRebase) {
+
+#if SUPPORT_ARCH_arm64e
+                                       if (isAuthenticated) {
+                                               uint64_t slide = 0;
+                                               static const char* keyNames[] = {
+                                                       "IA", "IB", "DA", "DB"
+                                               };
+                                               // The new value for a rebase is the low 32-bits of the threaded value plus the slide.
+                                               uint64_t newValue = (value & 0xFFFFFFFF) + slide;
+                                               // Add in the offset from the mach_header
+                                               newValue += baseAddress;
+                                               // We have bits to merge in to the discriminator
+                                               printf("%-7s %-16s 0x%08llX  %s  0x%08llX (JOP: diversity %d, address %s, %s)\n",
+                                                          segName, sectName, (uint64_t)vmAddress, "pointer", newValue,
+                                                          diversity, hasAddressDiversity ? "true" : "false", keyNames[key]);
+                                       } else
+#endif
+                                       {
+                                               // Regular pointer which needs to fit in 51-bits of value.
+                                               // C++ RTTI uses the top bit, so we'll allow the whole top-byte
+                                               // and the bottom 43-bits to be fit in to 51-bits.
+                                               uint64_t top8Bits = value & 0x0007F80000000000ULL;
+                                               uint64_t bottom43Bits = value & 0x000007FFFFFFFFFFULL;
+                                               uint64_t targetValue = ( top8Bits << 13 ) | (((intptr_t)(bottom43Bits << 21) >> 21) & 0x00FFFFFFFFFFFFFF);
+                                               printf("%-7s %-16s 0x%08llX  %s  0x%08llX\n", segName, sectName, (uint64_t)vmAddress, "pointer", targetValue);
+                                       }
+                               }
+
+                               // The delta is bits [51..61]
+                               // And bit 62 is to tell us if we are a rebase (0) or bind (1)
+                               value &= ~(1ULL << 62);
+                               delta = ( value & 0x3FF8000000000000 ) >> 51;
+                               mappedAddress += delta * stepMultiplier;
+                               vmAddress += delta * stepMultiplier;
+                       } while ( delta != 0 );
+               };
+               for(const macho_segment_command<P>* segCmd : fSegments) {
+                       if (strcmp(segCmd->segname(), "__TEXT") != 0)
+                               continue;
+                       macho_section<P>* const sectionsStart = (macho_section<P>*)((char*)segCmd + sizeof(macho_segment_command<P>));
+                       macho_section<P>* const sectionsEnd = &sectionsStart[segCmd->nsects()];
+                       for(macho_section<P>* sect = sectionsStart; sect < sectionsEnd; ++sect) {
+                               if (strcmp(sect->sectname(), "__thread_starts") != 0)
+                                       continue;
+                               printf("rebase information (from __TEXT,__thread_starts):\n");
+                               printf("segment  section          address     type\n");
+                               const uint8_t* sectionContent = (uint8_t*)fHeader + segCmd->fileoff() + sect->offset();
+                               uint32_t *threadStarts = (uint32_t*)sectionContent;
+                               uint32_t *threadEnds = (uint32_t*)(sectionContent + sect->size());
+                               uint32_t threadStartsHeader = threadStarts[0];
+                               uint64_t stepMultiplier = (threadStartsHeader & 1) == 1 ? 8 : 4;
+                               for (uint32_t* threadOffset = threadStarts + 1; threadOffset != threadEnds; ++threadOffset) {
+                                       //printf("Thread start offset: 0x%016X\n", *threadOffset);
+                                       // If we get a 0xFFFFFFFF offset then ld64 overestimated the size required.  So skip the remainder
+                                       // of the entries.
+                                       if (*threadOffset == 0xFFFFFFFF)
+                                               break;
+                                       uint64_t chainStartVMAddr = fBaseAddress + *threadOffset;
+                                       uintptr_t chainStartMappedAddress = (uintptr_t)mappedAddressForVMAddress(chainStartVMAddr);
+                                       rebaseChain(chainStartMappedAddress, chainStartVMAddr, stepMultiplier, fBaseAddress);
+                               }
+                               return;
+                       }
+               }
+       }
+
        if ( fDynamicSymbolTable == NULL ) {
                printf("no classic dynamic symbol table");
        }
@@ -2412,14 +2757,6 @@ int main(int argc, const char* argv[])
                                                sPreferredArch = CPU_TYPE_POWERPC64;
                                        else if ( strcmp(arch, "ppc") == 0 )
                                                sPreferredArch = CPU_TYPE_POWERPC;
-                                       else if ( strcmp(arch, "i386") == 0 )
-                                               sPreferredArch = CPU_TYPE_I386;
-                                       else if ( strcmp(arch, "x86_64") == 0 )
-                                               sPreferredArch = CPU_TYPE_X86_64;
-#if SUPPORT_ARCH_arm64
-                                       else if ( strcmp(arch, "arm64") == 0 )
-                                               sPreferredArch = CPU_TYPE_ARM64;
-#endif
                                        else {
                                                if ( arch == NULL )
                                                        throw "-arch missing architecture name";
index ef6ba486e1ae9b55164d8ece518d58a351972299..8e954580700b4d45565a91e07af86bbd7413bc3e 100644 (file)
@@ -134,6 +134,7 @@ private:
        uint8_t                                                                         loadCommandSizeMask();
        void                                                                            checkSymbolTable();
        void                                                                            checkInitTerms();
+       void                                                                            checkThreadedRebaseBind();
        void                                                                            checkIndirectSymbolTable();
        void                                                                            checkRelocations();
        void                                                                            checkExternalReloation(const macho_relocation_info<P>* reloc);
@@ -142,12 +143,13 @@ private:
        void                                                                            verifyInstallName();
        void                                                                            verifyNoRpaths();
        void                                                                            verifyNoFlatLookups();
+       void                                                                            verifyiOSMac();
 
        pint_t                                                                          relocBase();
        bool                                                                            addressInWritableSegment(pint_t address);
        bool                                                                            hasTextRelocInRange(pint_t start, pint_t end);
        pint_t                                                                          segStartAddress(uint8_t segIndex);
-       bool                                                                            addressIsRebaseSite(pint_t addr);
+       bool                                                                            addressIsRebaseSite(pint_t addr, pint_t& pointeeAddr);
        bool                                                                            addressIsBindingSite(pint_t addr);
        pint_t                                                                          getInitialStackPointer(const macho_thread_command<P>*);
        pint_t                                                                          getEntryPoint(const macho_thread_command<P>*);
@@ -173,6 +175,8 @@ private:
        bool                                                                            fWriteableSegmentWithAddrOver4G;
        bool                                                                            fSlidableImage;
        bool                                                                            fHasLC_RPATH;
+       bool                                                                            fIsDebugVariant;
+       uint64_t                                                                        fBaseAddress = 0;
        const macho_segment_command<P>*                         fFirstSegment;
        const macho_segment_command<P>*                         fFirstWritableSegment;
        const macho_segment_command<P>*                         fTEXTSegment;
@@ -356,7 +360,7 @@ template <typename A>
 MachOChecker<A>::MachOChecker(const uint8_t* fileContent, uint32_t fileLength, const char* path, const char* verifierDstRoot)
  : fHeader(NULL), fLength(fileLength), fInstallName(NULL), fStrings(NULL), fSymbols(NULL), fSymbolCount(0), fDynamicSymbolTable(NULL), fIndirectTableCount(0),
  fLocalRelocations(NULL),  fLocalRelocationsCount(0),  fExternalRelocations(NULL),  fExternalRelocationsCount(0),
- fWriteableSegmentWithAddrOver4G(false), fSlidableImage(false), fHasLC_RPATH(false), fFirstSegment(NULL), fFirstWritableSegment(NULL),
+ fWriteableSegmentWithAddrOver4G(false), fSlidableImage(false), fHasLC_RPATH(false), fIsDebugVariant(false), fFirstSegment(NULL), fFirstWritableSegment(NULL),
  fTEXTSegment(NULL), fDyldInfo(NULL), fSectionCount(0)
 {
        // sanity check
@@ -381,6 +385,8 @@ MachOChecker<A>::MachOChecker(const uint8_t* fileContent, uint32_t fileLength, c
        
        checkInitTerms();
 
+       checkThreadedRebaseBind();
+
        if ( verifierDstRoot != NULL )
                verify();
 }
@@ -578,6 +584,8 @@ void MachOChecker<A>::checkLoadCommands()
                                if ( segCmd->vmaddr() > 0x100000000ULL )
                                        fWriteableSegmentWithAddrOver4G = true;
                        }
+                       if ( (segCmd->fileoff() == 0) && (segCmd->filesize() != 0) )
+                               fBaseAddress = segCmd->vmaddr();
                                
                        // check section ranges
                        const macho_section<P>* const sectionsStart = (macho_section<P>*)((char*)segCmd + sizeof(macho_segment_command<P>));
@@ -848,19 +856,35 @@ void MachOChecker<A>::checkSection(const macho_segment_command<P>* segCmd, const
        // more section tests here
 }
 
+static bool endsWith(const char* str, const char* suffix)
+{
+       size_t suffixLen = strlen(suffix);
+       size_t strLen    = strlen(str);
+       if ( strLen > suffixLen ) {
+               return (strcmp(&str[strLen-suffixLen], suffix) == 0);
+       }
+       return false;
+}
 
 template <typename A>
 void MachOChecker<A>::verify()
 {
-       bool sharedCacheCandidate = false;
-       if ( fInstallName != NULL ) {
-               if ( (strncmp(fInstallName, "/usr/lib/", 9) == 0) || (strncmp(fInstallName, "/System/Library/", 16) == 0) ) {
-                       sharedCacheCandidate = true;
-                       verifyInstallName();
-                       verifyNoRpaths();
+       if ( endsWith(fPath, "_asan.dylib") || endsWith(fPath, "_asan") || endsWith(fPath, "_debug.dylib") || endsWith(fPath, "_debug") )
+               fIsDebugVariant = true;
+
+       if ( (fDstRoot != NULL) && (strlen(fDstRoot) < strlen(fPath)) ) {
+               const char* installLocationInDstRoot = &fPath[strlen(fDstRoot)];
+               if ( installLocationInDstRoot[0] != '/' )
+                       --installLocationInDstRoot;
+               if ( (strncmp(installLocationInDstRoot, "/usr/lib/", 9) == 0) || (strncmp(installLocationInDstRoot, "/System/Library/", 16) == 0) ) {
+                       if ( !fIsDebugVariant && (strstr(fPath, ".app/") == NULL) ) {
+                               verifyInstallName();
+                               verifyNoRpaths();
+                       }
                }
        }
        verifyNoFlatLookups();
+       verifyiOSMac();
 }
 
 
@@ -929,6 +953,41 @@ void MachOChecker<A>::verifyNoFlatLookups()
        }
 }
 
+template <typename A>
+void MachOChecker<A>::verifyiOSMac()
+{
+       const char* fileLocationWithinDstRoot = &fPath[strlen(fDstRoot)];
+       if ( strncmp(fileLocationWithinDstRoot, "/System/iOSSupport/", 19) == 0 ) {
+               // everything in /System/iOSSupport/ should be iOSMac only
+               bool bad = false;
+               const uint32_t cmd_count = fHeader->ncmds();
+               const macho_load_command<P>* cmd = (macho_load_command<P>*)((uint8_t*)fHeader + sizeof(macho_header<P>));
+               for (uint32_t i = 0; i < cmd_count; ++i) {
+                       const macho_build_version_command<P>* buildVersCmd;
+                       switch ( cmd->cmd() ) {
+                               case LC_VERSION_MIN_MACOSX:
+                               case LC_VERSION_MIN_IPHONEOS:
+                               case LC_VERSION_MIN_TVOS:
+                               case LC_VERSION_MIN_WATCHOS:
+                                       bad = true;
+                                       break;
+                               case LC_BUILD_VERSION:
+                                       buildVersCmd = (macho_build_version_command<P>*)cmd;
+                                       if ( buildVersCmd->platform() != PLATFORM_IOSMAC )
+                                               bad = true;
+                                       break;
+                       }
+                       cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
+               }
+               if ( bad )
+                       printf("macos_in_ios_support\twarn\tnon-iOSMac in /System/iOSSupport/ in arch %s\n", archName());
+       }
+       else {
+               // maybe someday warn about iOSMac only stuff not in /System/iOSSupport/
+       }
+}
+
+
 template <typename A>
 void MachOChecker<A>::checkIndirectSymbolTable()
 {
@@ -1084,23 +1143,28 @@ void MachOChecker<A>::checkInitTerms()
                                                        throwf("%s section size is not an even multiple of element size", sect->sectname());
                                                if ( (sect->addr() % sizeof(pint_t)) != 0 )
                                                        throwf("%s section size is not pointer size aligned", sect->sectname());
-                                               // check each pointer in array points within TEXT
                                                arrayStart = (pint_t*)((char*)fHeader + sect->offset());
                                                arrayEnd = (pint_t*)((char*)fHeader + sect->offset() + sect->size());
-                                               for (pint_t* p=arrayStart; p < arrayEnd; ++p) {
-                                                       pint_t pointer = P::getP(*p);
-                                                       if ( (pointer < fTEXTSegment->vmaddr()) ||  (pointer >= (fTEXTSegment->vmaddr()+fTEXTSegment->vmsize())) ) 
-                                                               throwf("%s 0x%08llX points outside __TEXT segment", kind, (long long)pointer);
-                                               }
                                                // check each pointer in array will be rebased and not bound
                                                if ( fSlidableImage ) {
                                                        pint_t sectionBeginAddr = sect->addr();
                                                        pint_t sectionEndddr = sect->addr() + sect->size();
-                                                       for(pint_t addr = sectionBeginAddr; addr < sectionEndddr; addr += sizeof(pint_t)) {
+                                                       for(pint_t addr = sectionBeginAddr, *p = arrayStart; addr < sectionEndddr; addr += sizeof(pint_t), ++p) {
                                                                if ( addressIsBindingSite(addr) )
                                                                        throwf("%s at 0x%0llX has binding to external symbol", kind, (long long)addr);
-                                                               if ( ! addressIsRebaseSite(addr) )
+                                                               pint_t pointer = P::getP(*p);
+                                                               if ( ! addressIsRebaseSite(addr, pointer) )
                                                                        throwf("%s at 0x%0llX is not rebased", kind, (long long)addr);
+                                                               // check each pointer in array points within TEXT
+                                                               if ( (pointer < fTEXTSegment->vmaddr()) ||  (pointer >= (fTEXTSegment->vmaddr()+fTEXTSegment->vmsize())) )
+                                                                       throwf("%s 0x%08llX points outside __TEXT segment", kind, (long long)pointer);
+                                                       }
+                                               } else {
+                                                       // check each pointer in array points within TEXT
+                                                       for (pint_t* p=arrayStart; p < arrayEnd; ++p) {
+                                                               pint_t pointer = P::getP(*p);
+                                                               if ( (pointer < fTEXTSegment->vmaddr()) ||  (pointer >= (fTEXTSegment->vmaddr()+fTEXTSegment->vmsize())) )
+                                                                       throwf("%s 0x%08llX 3 points outside __TEXT segment", kind, (long long)pointer);
                                                        }
                                                }
                                                break;
@@ -1112,6 +1176,131 @@ void MachOChecker<A>::checkInitTerms()
 
 }
 
+template <typename A>
+void MachOChecker<A>::checkThreadedRebaseBind()
+{
+       // look bind info
+       if ( fDyldInfo != NULL ) {
+               const uint8_t* p = (uint8_t*)fHeader + fDyldInfo->bind_off();
+               const uint8_t* end = &p[fDyldInfo->bind_size()];
+
+               uint8_t type = 0;
+               uint64_t segOffset = 0;
+               uint32_t count;
+               uint32_t skip;
+               const char* symbolName = NULL;
+               int libraryOrdinal = 0;
+               int segIndex;
+               int64_t addend = 0;
+               pint_t segStartAddr = 0;
+               uint64_t ordinalTableSize = 0;
+               bool useThreadedRebaseBind = false;
+               bool done = false;
+               while ( !done && (p < end) ) {
+                       uint8_t immediate = *p & BIND_IMMEDIATE_MASK;
+                       uint8_t opcode = *p & BIND_OPCODE_MASK;
+                       ++p;
+                       switch (opcode) {
+                               case BIND_OPCODE_DONE:
+                                       done = true;
+                                       break;
+                               case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM:
+                                       libraryOrdinal = immediate;
+                                       break;
+                               case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB:
+                                       libraryOrdinal = read_uleb128(p, end);
+                                       break;
+                               case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM:
+                                       // the special ordinals are negative numbers
+                                       if ( immediate == 0 )
+                                               libraryOrdinal = 0;
+                                       else {
+                                               int8_t signExtended = BIND_OPCODE_MASK | immediate;
+                                               libraryOrdinal = signExtended;
+                                       }
+                                       break;
+                               case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
+                                       symbolName = (char*)p;
+                                       while (*p != '\0')
+                                               ++p;
+                                       ++p;
+                                       break;
+                               case BIND_OPCODE_SET_TYPE_IMM:
+                                       type = immediate;
+                                       break;
+                               case BIND_OPCODE_SET_ADDEND_SLEB:
+                                       addend = read_sleb128(p, end);
+                                       break;
+                               case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
+                                       segIndex = immediate;
+                                       segStartAddr = segStartAddress(segIndex);
+                                       segOffset = read_uleb128(p, end);
+                                       break;
+                               case BIND_OPCODE_ADD_ADDR_ULEB:
+                                       segOffset += read_uleb128(p, end);
+                                       break;
+                               case BIND_OPCODE_DO_BIND:
+                                       segOffset += sizeof(pint_t);
+                                       break;
+                               case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
+                                       segOffset += read_uleb128(p, end) + sizeof(pint_t);
+                                       break;
+                               case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:
+                                       segOffset += immediate*sizeof(pint_t) + sizeof(pint_t);
+                                       break;
+                               case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB:
+                                       count = read_uleb128(p, end);
+                                       skip = read_uleb128(p, end);
+                                       for (uint32_t i=0; i < count; ++i) {
+                                               segOffset += skip + sizeof(pint_t);
+                                       }
+                                       break;
+                               case BIND_OPCODE_THREADED:
+                                       // Note the immediate is a sub opcode
+                                       switch (immediate) {
+                                               case BIND_SUBOPCODE_THREADED_SET_BIND_ORDINAL_TABLE_SIZE_ULEB:
+                                                       ordinalTableSize = read_uleb128(p, end);
+                                                       useThreadedRebaseBind = true;
+                                                       break;
+                                               case BIND_SUBOPCODE_THREADED_APPLY: {
+                                                       if ( !useThreadedRebaseBind ) {
+                                                               throwf("BIND_SUBOPCODE_THREADED_APPLY without ordinal table");
+                                                       }
+                                                       uint64_t delta = 0;
+                                                       do {
+                                                               const uint8_t* pointerLocation = (uint8_t*)fHeader + fSegments[segIndex]->fileoff() + segOffset;
+                                                               uint64_t value = P::getP(*(uint64_t*)pointerLocation);
+                                                               bool isRebase = (value & (1ULL << 62)) == 0;
+
+                                                               if (isRebase) {
+                                                                       //printf("(rebase): %-7s %-16s 0x%08llX  %s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName);
+                                                               } else {
+                                                                       // the ordinal is bits [0..15]
+                                                                       uint16_t ordinal = value & 0xFFFF;
+                                                                       if (ordinal >= ordinalTableSize) {
+                                                                               throwf("bind ordinal is out of range");
+                                                                       }
+                                                               }
+
+                                                               // The delta is bits [51..61]
+                                                               // And bit 62 is to tell us if we are a rebase (0) or bind (1)
+                                                               value &= ~(1ULL << 62);
+                                                               delta = ( value & 0x3FF8000000000000 ) >> 51;
+                                                               segOffset += delta * sizeof(pint_t);
+                                                       } while ( delta != 0);
+                                                       break;
+                                               }
+                                               default:
+                                                       throwf("unknown threaded bind subopcode %d", immediate);
+                                       }
+                                       break;
+                               default:
+                                       throwf("bad bind opcode %d", *p);
+                       }
+               }
+       }
+}
+
 
 
 template <>
@@ -1437,7 +1626,7 @@ bool MachOChecker<A>::hasTextRelocInRange(pint_t rangeStart, pint_t rangeEnd)
 }
 
 template <typename A>
-bool MachOChecker<A>::addressIsRebaseSite(pint_t targetAddr)
+bool MachOChecker<A>::addressIsRebaseSite(pint_t targetAddr, pint_t& pointeeAddr)
 {
        // look at local relocs
        const macho_relocation_info<P>* const localRelocsEnd = &fLocalRelocations[fLocalRelocationsCount];
@@ -1521,12 +1710,125 @@ bool MachOChecker<A>::addressIsRebaseSite(pint_t targetAddr)
                                default:
                                        throwf("bad rebase opcode %d", *p);
                        }
-               }       
+               }
+               
+               // If we have no rebase opcodes, then we may be using the threaded rebase/bind combined
+               // format and need to parse the bind opcodes instead.
+               if ( (fDyldInfo->rebase_size() == 0) && (fDyldInfo->bind_size() != 0) ) {
+                       const uint8_t* p = (uint8_t*)fHeader + fDyldInfo->bind_off();
+                       const uint8_t* end = &p[fDyldInfo->bind_size()];
+
+                       uint8_t segIndex = 0;
+                       uint64_t segOffset = 0;
+                       uint32_t count;
+                       uint32_t skip;
+                       pint_t segStartAddr = 0;
+                       bool done = false;
+                       while ( !done && (p < end) ) {
+                               uint8_t immediate = *p & BIND_IMMEDIATE_MASK;
+                               uint8_t opcode = *p & BIND_OPCODE_MASK;
+                               ++p;
+                               switch (opcode) {
+                                       case BIND_OPCODE_DONE:
+                                               done = true;
+                                               break;
+                                       case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM:
+                                               break;
+                                       case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB:
+                                               read_uleb128(p, end);
+                                               break;
+                                       case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM:
+                                               break;
+                                       case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
+                                               while (*p != '\0')
+                                                       ++p;
+                                               ++p;
+                                               break;
+                                       case BIND_OPCODE_SET_TYPE_IMM:
+                                               break;
+                                       case BIND_OPCODE_SET_ADDEND_SLEB:
+                                               read_sleb128(p, end);
+                                               break;
+                                       case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
+                                               segIndex = immediate;
+                                               segStartAddr = segStartAddress(segIndex);
+                                               segOffset = read_uleb128(p, end);
+                                               break;
+                                       case BIND_OPCODE_ADD_ADDR_ULEB:
+                                               segOffset += read_uleb128(p, end);
+                                               break;
+                                       case BIND_OPCODE_DO_BIND:
+                                               break;
+                                       case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
+                                               segOffset += read_uleb128(p, end) + sizeof(pint_t);
+                                               break;
+                                       case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:
+                                               segOffset += immediate*sizeof(pint_t) + sizeof(pint_t);
+                                               break;
+                                       case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB:
+                                               count = read_uleb128(p, end);
+                                               skip = read_uleb128(p, end);
+                                               for (uint32_t i=0; i < count; ++i) {
+                                                       segOffset += skip + sizeof(pint_t);
+                                               }
+                                               break;
+                                       case BIND_OPCODE_THREADED:
+                                               // Note the immediate is a sub opcode
+                                               switch (immediate) {
+                                                       case BIND_SUBOPCODE_THREADED_SET_BIND_ORDINAL_TABLE_SIZE_ULEB:
+                                                               count = read_uleb128(p, end);
+                                                               break;
+                                                       case BIND_SUBOPCODE_THREADED_APPLY: {
+                                                               uint64_t delta = 0;
+                                                               do {
+                                                                       uint8_t* pointerLocation = (uint8_t*)fHeader + fSegments[segIndex]->fileoff() + segOffset;
+                                                                       uint64_t value = P::getP(*(uint64_t*)pointerLocation);
+#if SUPPORT_ARCH_arm64e
+                                                                       bool isAuthenticated = (value & (1ULL << 63)) != 0;
+#endif
+                                                                       bool isRebase = (value & (1ULL << 62)) == 0;
+                                                                       if ( isRebase && ( (segStartAddr+segOffset) == targetAddr ) ) {
+
+#if SUPPORT_ARCH_arm64e
+                                                                               if (isAuthenticated) {
+                                                                                       uint64_t targetValue = value & 0xFFFFFFFFULL;
+                                                                                       targetValue += fBaseAddress;
+                                                                                       pointeeAddr = (pint_t)targetValue;
+                                                                               } else
+#endif
+                                                                               {
+                                                                                       // Regular pointer which needs to fit in 51-bits of value.
+                                                                                       // C++ RTTI uses the top bit, so we'll allow the whole top-byte
+                                                                                       // and the signed-extended bottom 43-bits to be fit in to 51-bits.
+                                                                                       uint64_t top8Bits = value & 0x0007F80000000000ULL;
+                                                                                       uint64_t bottom43Bits = value & 0x000007FFFFFFFFFFULL;
+                                                                                       uint64_t targetValue = ( top8Bits << 13 ) | (((intptr_t)(bottom43Bits << 21) >> 21) & 0x00FFFFFFFFFFFFFF);
+                                                                                       pointeeAddr = (pint_t)targetValue;
+                                                                               }
+                                                                               return true;
+                                                                       }
+
+                                                                       // The delta is bits [51..61]
+                                                                       // And bit 62 is to tell us if we are a rebase (0) or bind (1)
+                                                                       value &= ~(1ULL << 62);
+                                                                       delta = ( value & 0x3FF8000000000000 ) >> 51;
+                                                                       segOffset += delta * sizeof(pint_t);
+                                                               } while ( delta != 0 );
+                                                               break;
+                                                       }
+                                                       default:
+                                                               throwf("unknown threaded bind subopcode %d", immediate);
+                                               }
+                                               break;
+                                       default:
+                                               throwf("bad bind opcode %d", *p);
+                               }
+                       }
+               }
        }
        return false;
 }
 
-
 template <typename A>
 bool MachOChecker<A>::addressIsBindingSite(pint_t targetAddr)
 {
@@ -1619,6 +1921,35 @@ bool MachOChecker<A>::addressIsBindingSite(pint_t targetAddr)
                                                segOffset += skip + sizeof(pint_t);
                                        }
                                        break;
+                               case BIND_OPCODE_THREADED:
+                                       // Note the immediate is a sub opcode
+                                       switch (immediate) {
+                                               case BIND_SUBOPCODE_THREADED_SET_BIND_ORDINAL_TABLE_SIZE_ULEB:
+                                                       count = read_uleb128(p, end);
+                                                       break;
+                                               case BIND_SUBOPCODE_THREADED_APPLY: {
+                                                       uint64_t delta = 0;
+                                                       do {
+                                                               uint8_t* pointerLocation = (uint8_t*)fHeader + fSegments[segIndex]->fileoff() + segOffset;
+                                                               uint64_t value = P::getP(*(uint64_t*)pointerLocation);
+                                                               bool isRebase = (value & (1ULL << 62)) == 0;
+                                                               if (!isRebase) {
+                                                                       if ( (segStartAddr+segOffset) == targetAddr )
+                                                                               return true;
+                                                               }
+
+                                                               // The delta is bits [51..61]
+                                                               // And bit 62 is to tell us if we are a rebase (0) or bind (1)
+                                                               value &= ~(1ULL << 62);
+                                                               delta = ( value & 0x3FF8000000000000 ) >> 51;
+                                                               segOffset += delta * sizeof(pint_t);
+                                                       } while ( delta != 0 );
+                                                       break;
+                                               }
+                                               default:
+                                                       throwf("unknown threaded bind subopcode %d", immediate);
+                                       }
+                                       break;
                                default:
                                        throwf("bad bind opcode %d", *p);
                        }
@@ -1729,10 +2060,11 @@ int main(int argc, const char* argv[])
                        else if ( strcmp(arg, "-verifier_error_list") == 0 ) {
                                printf("os_dylib_rpath_install_name\tOS dylibs (those in /usr/lib/ or /System/Library/) must be built with -install_name that is an absolute path - not an @rpath\n");
                                printf("os_dylib_bad_install_name\tOS dylibs (those in /usr/lib/ or /System/Library/) must be built with -install_name matching their file system location\n");
-                               printf("os_dylib_rpath\tOS dylibs should not contain LC_RPATH load commands (from -rpath linker option)\n");
+                               printf("os_dylib_rpath\tOS dylibs should not contain LC_RPATH load commands (from -rpath linker option)(remove LD_RUNPATH_SEARCH_PATHS Xcode build setting)\n");
                                printf("os_dylib_flat_namespace\tOS dylibs should not be built with -flat_namespace\n");
                                printf("os_dylib_undefined_dynamic_lookup\tOS dylibs should not be built with -undefined dynamic_lookup\n");
-                               printf("os_dylib_malformed\the mach-o is malformed\n");
+                               printf("os_dylib_malformed\tthe mach-o file is malformed\n");
+                               printf("macos_in_ios_support\t/System/iOSSupport/ should only contain mach-o files that support iosmac\n");
                                return 0;
                        }
                        else {
index c3a7864532d19c7a5576e09fe3b0b4417f12c409..617677bc5227c9d18eb07ed8fcbe7c255004a319 100644 (file)
@@ -10,11 +10,12 @@ VALID_ARCHS ?= "i386 x86_64 armv6"
 
 
 MYDIR=$(shell cd ../../bin;pwd)
-LD                             = ld
+LD                     = ld
 OBJECTDUMP             = ObjectDump
-OBJCIMAGEINFO  = objcimageinfo
+OBJCIMAGEINFO          = objcimageinfo
 MACHOCHECK             = machocheck
 OTOOL                  = xcrun otool
+MTOC                   = xcrun mtoc
 REBASE                 = rebase
 DYLDINFO               = dyldinfo
 
@@ -60,7 +61,8 @@ ifeq ($(ARCH),ppc)
        OSX_SDK = /Developer/SDKs/MacOSX10.6.sdk
 endif
 
-CC              = $(shell xcrun -find clang) -arch ${ARCH} -mmacosx-version-min=10.8 -isysroot $(OSX_SDK)
+CC             = $(shell xcrun -find clang) -arch ${ARCH} -mmacosx-version-min=10.8 -isysroot $(OSX_SDK)
+AS             = $(shell xcrun -f as) -arch ${ARCH} -mmacosx-version-min=10.8
 CCFLAGS = -Wall 
 LDFLAGS = -syslibroot $(OSX_SDK)
 ASMFLAGS =
@@ -68,12 +70,13 @@ VERSION_NEW_LINKEDIT = -mmacosx-version-min=10.6
 VERSION_OLD_LINKEDIT = -mmacosx-version-min=10.4
 LD_NEW_LINKEDIT = -macosx_version_min 10.6
 
-CXX              = $(shell xcrun -find clang++) -arch ${ARCH} -isysroot $(OSX_SDK)
+CXX              = $(shell xcrun -find clang++) -arch ${ARCH} -mmacosx-version-min=10.9 -isysroot $(OSX_SDK)
 CXXFLAGS = -Wall -stdlib=libc++ 
 
 ifeq ($(ARCH),armv6)
   LDFLAGS := -syslibroot $(IOS_SDK)
   override FILEARCH = arm
+  AS = $(shell xcrun -f as) -arch ${ARCH} -miphoneos-version-min=5.0
   CC = $(shell xcrun -find clang) -arch ${ARCH} -ccc-install-dir ${LD_PATH} -miphoneos-version-min=5.0 -isysroot $(IOS_SDK) 
   CXX = $(shell xcrun -find clang++) -arch ${ARCH} -ccc-install-dir ${LD_PATH} -miphoneos-version-min=5.0 -isysroot $(IOS_SDK) 
   VERSION_NEW_LINKEDIT = -miphoneos-version-min=4.0
@@ -87,6 +90,7 @@ endif
 ifeq ($(ARCH),armv7)
   LDFLAGS := -syslibroot $(IOS_SDK)
   override FILEARCH = arm
+  AS = $(shell xcrun -f as) -arch ${ARCH} -miphoneos-version-min=5.0
   CC = $(shell xcrun -find clang) -arch ${ARCH} -ccc-install-dir ${LD_PATH} -miphoneos-version-min=5.0 -isysroot $(IOS_SDK)
   CXX = $(shell xcrun -find clang++) -arch ${ARCH} -ccc-install-dir ${LD_PATH} -miphoneos-version-min=5.0 -isysroot $(IOS_SDK)
   VERSION_NEW_LINKEDIT = -miphoneos-version-min=4.0
@@ -103,6 +107,7 @@ ifeq ($(ARCH),thumb)
   CXXFLAGS += -mthumb
   override ARCH = armv6
   override FILEARCH = arm
+  AS = $(shell xcrun -f as) -arch ${ARCH} -miphoneos-version-min=5.0
   CC = $(shell xcrun -find clang) -arch ${ARCH} -ccc-install-dir ${LD_PATH} -miphoneos-version-min=5.0 -isysroot $(IOS_SDK)
   CXX = $(shell xcrun -find clang++) -arch ${ARCH} -ccc-install-dir ${LD_PATH} -miphoneos-version-min=5.0 -isysroot $(IOS_SDK)
   VERSION_NEW_LINKEDIT = -miphoneos-version-min=4.0
@@ -119,6 +124,7 @@ ifeq ($(ARCH),thumb2)
   CXXFLAGS += -mthumb
   override ARCH = armv7
   override FILEARCH = arm
+  AS = $(shell xcrun -f as) -arch ${ARCH} -miphoneos-version-min=5.0
   CC = $(shell xcrun -find clang) -arch ${ARCH} -ccc-install-dir ${LD_PATH} -miphoneos-version-min=5.0 -isysroot $(IOS_SDK)
   CXX = $(shell xcrun -find clang++) -arch ${ARCH} -ccc-install-dir ${LD_PATH} -miphoneos-version-min=5.0 -isysroot $(IOS_SDK)
   VERSION_NEW_LINKEDIT = -miphoneos-version-min=4.0
@@ -131,6 +137,7 @@ endif
 
 ifeq ($(ARCH),arm64)
   LDFLAGS := -syslibroot $(IOS_SDK)
+  AS = $(shell xcrun -f as) -arch ${ARCH} -miphoneos-version-min=5.0
   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
index cdab9275ed9a43c6df18f39499b591c2458df413..058878eff076a91497ea2cf8d48461beab456a6c 100755 (executable)
@@ -12,11 +12,29 @@ cd `echo "$0" | sed 's/run-all-unit-tests/test-cases/'`
 
 all_archs="x86_64  i386"
 valid_archs="x86_64 i386"
+ios_sdk_directory="/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs"
 # only test arm code if iOS platform tools installed
-if [ -d /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs ]
+min_available_ios_sdk_version()
+{
+       ls "${ios_sdk_directory}" |
+               grep --invert-match --ignore-case "internal" |  # exclude internal SDKs
+               sort --version-sort | head -n 1 |  # take SDK with min version
+               sed "s/^iPhoneOS\(.*\)\.sdk$/\1/"  # return only the version string
+}
+version_ge()
+{
+       test "$(printf '%s\n' "$@" | sort --version-sort | head -n 1)" == "$2";
+}
+if [ -d $ios_sdk_directory ]
 then
-    all_archs="${all_archs}  armv7"
-    valid_archs="${valid_archs} armv7"
+       arm_arch="armv7"
+       # Newer SDKs don't support older architectures.
+       if version_ge "$(min_available_ios_sdk_version)" "11.0"
+       then
+               arm_arch="arm64"
+       fi
+    all_archs="${all_archs}  ${arm_arch}"
+    valid_archs="${valid_archs} ${arm_arch}"
 fi
 
 
index 06ca6edbb378b186a6ad98c11947c48bd361071f..4382cc1018f28bc76f20138a8bbc192b5ac72a35 100644 (file)
@@ -25,8 +25,15 @@ include ${TESTROOT}/include/common.makefile
 
 ifeq ($(FILEARCH),arm)
        LD_VERS = -ios_version_min 4.0 -syslibroot $(IOS_SDK)
+       CC_VERS = -miphoneos-version-min=4.0
+else
+ifeq ($(FILEARCH),arm64)
+       LD_VERS = -ios_version_min 4.0 -syslibroot $(IOS_SDK)
+       CC_VERS = -miphoneos-version-min=4.0
 else
        LD_VERS = -macosx_version_min 10.6
+       CC_VERS = -mmacosx-version-min=10.6
+endif
 endif
 
 
@@ -37,7 +44,7 @@ endif
 run: all
 
 all:
-       ${CC} ${CCFLAGS} hello.c -c -o hello.o 
+       ${CC} ${CC_VERS} ${CCFLAGS} hello.c -c -o hello.o 
        ${FAIL_IF_BAD_OBJ} hello.o
        ${LD} ${LDFLAGS} hello.o -dylib -o hello.dylib -lSystem $(LD_VERS) 
        file hello.dylib | grep ${FILEARCH} | ${PASS_IFF_STDIN}
index 19f0af18f6e83783b96841aa7f7e45e26737c4e1..9db9b976c3c07999cbc907bac5c3f92194fe0417 100644 (file)
 TESTROOT = ../..
 include ${TESTROOT}/include/common.makefile
 
-ALL_ARCH_OPTIONS = $(patsubst %,-arch %,$(subst ppc,,$(VALID_ARCHS)) )
+#ALL_ARCH_OPTIONS = $(patsubst %,-arch %,$(subst ppc,,$(VALID_ARCHS)) )
+
+# build the list of all valid archs for this platform...
+ifeq ($(ARCH),i386)
+       ALL_ARCH_OPTIONS = $(patsubst %,-arch %,$(filter-out arm%,$(VALID_ARCHS)) )
+       SYSROOT = -isysroot $(OSX_SDK)
+endif
+ifeq ($(ARCH),x86_64)
+       ALL_ARCH_OPTIONS = $(patsubst %,-arch %,$(filter-out arm%,$(VALID_ARCHS)) )
+       SYSROOT = -isysroot $(OSX_SDK)
+endif
+ifeq ($(ARCH),armv7)
+       ALL_ARCH_OPTIONS = $(patsubst %,-arch %,$(filter arm%,$(VALID_ARCHS)) )
+       SYSROOT = -isysroot $(IOS_SDK)
+endif
+ifeq ($(ARCH),arm64)
+       ALL_ARCH_OPTIONS = $(patsubst %,-arch %,$(filter arm%,$(VALID_ARCHS)) )
+       SYSROOT = -isysroot $(IOS_SDK)
+endif
 
 #
 # Test that blank stubs are handled properly
@@ -33,11 +51,10 @@ run: all
 
 all:
 # build example fully fat dylib
-
-       gcc `echo ${ALL_ARCH_OPTIONS}` -dynamiclib foo.c -o libfoo.dylib -install_name libfoo.dylib 
+       gcc $(SYSROOT) ${CCFLAGS} `echo ${ALL_ARCH_OPTIONS}` -dynamiclib foo.c -o libfoo.dylib -install_name libfoo.dylib 
        ${FAIL_IF_BAD_MACHO} libfoo.dylib
 
-       # handle the case of a native ppc compile--this sets the subtype, which must be passed to lipo
+# handle the case of a native ppc compile--this sets the subtype, which must be passed to lipo
        if [ x${ARCH} != xppc ]; \
        then \
                SUB_ARCH=${ARCH}; \
@@ -55,7 +72,6 @@ all:
        ${CC} ${CCFLAGS} main.c libfoo.dylib -o main
        ${OTOOL} -L main | grep libfoo | ${FAIL_IF_STDIN}
        ${PASS_IFF_GOOD_MACHO} main
-       
 
 clean:
        rm -rf libfoo.dylib main
index 76db33a2a23846fab1c434b77b1b25c53523f50a..fb55ccf9428671347f4f5e7cbfac7cc678a54380 100644 (file)
@@ -33,14 +33,13 @@ include ${TESTROOT}/include/common.makefile
 STRING_LABEL_COUNT = 0
 
 ifeq (${ARCH},x86_64)
-       STRING_LABEL_COUNT = 3
+       STRING_LABEL_COUNT = 2
 endif
-ifeq (${ARCH},i386)
-       STRING_LABEL_COUNT = 1
+ifeq (${ARCH},arm64)
+       STRING_LABEL_COUNT = 2
 endif
 
 
-
 run: all
 
 all:
@@ -56,4 +55,4 @@ all:
        ${PASS_IFF} /usr/bin/true
 
 clean:
-       rm  foo.o bar.o foobar.o libfoobar.dylib
+       rm -f foo.o bar.o foobar.o libfoobar.dylib
index 811449a764ca065cfdb4f91f3f40708ad8006f81..bd02587579c15534561688135f8fb01d78494eac 100644 (file)
 #define DTRACE_LAB(p, n)               \
    "__dtrace_probe$" DTRACE_TOSTRING(%=__LINE__) DTRACE_STRINGIFY(_##p##___##n)
 
+#if (defined __x86_64__ || defined __arm64__)
+#define DTRACE_LABEL(p, n)              \
+      ".section __DATA, __data\n\t"     \
+      ".globl " DTRACE_LAB(p, n) "\n\t" \
+      DTRACE_LAB(p, n) ":" ".quad 1f""\n\t"    \
+       ".text" "\n\t"                   \
+        "1:"
+#else
 #define DTRACE_LABEL(p, n)             \
       ".section __DATA, __data\n\t"    \
       ".globl " DTRACE_LAB(p, n) "\n\t"        \
        DTRACE_LAB(p, n) ":\n\t" ".long 1f""\n\t"       \
        ".text" "\n\t"                  \
        "1:"
+#endif
 
 #define DTRACE_CALL(p,n)       \
        DTRACE_LABEL(p,n)       \
index aa02b1198a32f7b3261ae99e5daaf3b70948fb5b..b284b43eae5d2942dfeb7cdd18eaeecd6cd2b12a 100644 (file)
@@ -38,7 +38,7 @@ run:
        libtool -static bar.o baz.o foo.o -o liball.a
        ${CC} ${CCFLAGS} liball.a -all_load -dynamiclib -o liball.dylib -nodefaultlibs -lSystem
        ${FAIL_IF_BAD_MACHO} liball.dylib
-       nm -fap liball.dylib | ./stabs-filter.pl > liball.dylib.stabs
+       nm -ap liball.dylib | ./stabs-filter.pl > liball.dylib.stabs
        ${PASS_IFF} diff liball.dylib.stabs expected-stabs
 
 clean:
index b498430eb9650600e80a060ed04f3cf7059a450c..c0c27c2827fe3f69ee772aed116f12965cd0a014 100644 (file)
@@ -46,9 +46,10 @@ all:
        ${CXX} ${CCXXFLAGS} -flto=thin  -gdwarf-2 hello.o other.o -o hello.thin -Wl,-object_path_lto,thinlto.o
        ${FAIL_IF_BAD_MACHO} hello.thin
        # Check that we have a non zero timestamp in the debug note
-       nm -ap hello.thin | grep '^[0-9a-z]*[1-9a-z][0-9a-z]* .*OSO.*thinlto.o/0.o$$' | ${FAIL_IF_EMPTY}
-       nm -ap hello.thin | grep '^[0-9a-z]*[1-9a-z][0-9a-z]* .*OSO.*thinlto.o/1.o$$' | ${FAIL_IF_EMPTY}
+       nm -ap hello.thin | grep '^[0-9a-z]*[1-9a-z][0-9a-z]* .*OSO.*thinlto.o/0.thinlto.o$$' | ${FAIL_IF_EMPTY}
+       nm -ap hello.thin | grep '^[0-9a-z]*[1-9a-z][0-9a-z]* .*OSO.*thinlto.o/1.thinlto.o$$' | ${FAIL_IF_EMPTY}
 
+       ${PASS_IFF} true
 
 clean:
        rm -rf hello hello.thin hello.o other.o lto.o thinlto.o
index f8abc124767132d47e7bec677ce5137669ffbbb0..8adb8913f82939150427722f017ac20689e54926 100644 (file)
@@ -12,7 +12,7 @@
 0000 BNSYM 
 0000   FUN __Z3foov
 0000   FUN 
-0000 ENSYM 
+0000 ENSYM  
 0000    SO 
 0000    SO CWD/
 0000    SO bar.cxx
@@ -20,5 +20,5 @@
 0000 BNSYM 
 0000   FUN __Z3barv
 0000   FUN 
-0000 ENSYM 
+0000 ENSYM  
 0000    SO 
index 99f2fa6edb927073fabd65ded0d2049ae0092409..7fceb5f5f3dd830714814868c2b19917bde02959 100644 (file)
@@ -60,10 +60,12 @@ all:
        ${CC} -arch $(ARCH)  -o MtocTest1.obj $(LOCAL_CC_FLAGS) -c MtocTest.c 
        libtool -static -o MtocTest1.lib MtocTest1.obj  
        ${LD} -arch $(ARCH)  -o MtocTest1.macho  -u __ModuleEntryPoint -e __ModuleEntryPoint $(LD_ARG) -preload -segalign 0x20 -pie -seg1addr 0x240 -map MtocTest1.map LibTest1.lib MtocTest1.lib
-       /usr/local/efi/bin/mtoc -subsystem application -align 0x20 -d MtocTest1.macho MtocTest1.macho MtocTest1.pecoff
-       otool -rR MtocTest1.macho > otool-reloc.log
-       otool -l MtocTest1.macho > otool-load.log 
-       /usr/local/efi/bin/objdump -b $(OBJ_DUMP_ARCH) -x MtocTest1.pecoff > objdump-raw.log
+       ${MTOC} -subsystem application -align 0x20 -d MtocTest1.macho MtocTest1.macho MtocTest1.pecoff
+       ${OTOOL} -r MtocTest1.macho > otool-reloc.log
+       ${OTOOL} -l MtocTest1.macho > otool-load.log 
+# The following will fail as the binutils objdump is no longer available.
+#      /usr/local/efi/bin/objdump -b $(OBJ_DUMP_ARCH) -x MtocTest1.pecoff > objdump-raw.log
+       ./efi-pecoff-util MtocTest1.pecoff > efi-pecoff-util-raw.log
        ${PASS_IFF_SUCCESS} ./mtoctest.py --arch $(ARCH)
   
   
diff --git a/unit-tests/test-cases/efi-basic/efi-pecoff-util b/unit-tests/test-cases/efi-basic/efi-pecoff-util
new file mode 100755 (executable)
index 0000000..8bd8ad9
--- /dev/null
@@ -0,0 +1,942 @@
+#!/usr/bin/python
+#
+# Copyright (c) 2013 - 2016 Apple Inc. All rights reserved
+#
+# Dump out a PE/COFF, PE/COFF+, or TE file using the EfiPeCoff class
+#
+# Read from memory in lldb
+# T=pecoff.EfiPeCoff(lldb.target, 0x86c7d000)
+#
+# Read from a Python file object
+# T=pecoff.EfiPeCoff(file)
+#
+# Read from a Python string
+# T=pecoff.EfiPeCoff(file.read())
+#
+
+import sys
+import struct
+import collections
+import optparse
+import commands
+import os
+import platform
+
+#----------------------------------------------------------------------
+# Code that auto imports LLDB
+#----------------------------------------------------------------------
+try: 
+    # Just try for LLDB in case PYTHONPATH is already correctly setup
+    import lldb
+except ImportError:
+    lldb_python_dirs = list()
+    # lldb is not in the PYTHONPATH, try some defaults for the current platform
+    platform_system = platform.system()
+    if platform_system == 'Darwin':
+        # On Darwin, try the currently selected Xcode directory
+        xcode_dir = commands.getoutput("xcode-select --print-path")
+        if xcode_dir:
+            lldb_python_dirs.append(os.path.realpath(xcode_dir + '/../SharedFrameworks/LLDB.framework/Resources/Python'))
+            lldb_python_dirs.append(xcode_dir + '/Library/PrivateFrameworks/LLDB.framework/Resources/Python')
+        lldb_python_dirs.append('/System/Library/PrivateFrameworks/LLDB.framework/Resources/Python')
+    success = False
+    for lldb_python_dir in lldb_python_dirs:
+        if os.path.exists(lldb_python_dir):
+            if not (sys.path.__contains__(lldb_python_dir)):
+                sys.path.append(lldb_python_dir)
+                try: 
+                    import lldb
+                except ImportError:
+                    pass
+                else:
+                    success = True
+                    break
+    if not success:
+        print "error: couldn't locate the 'lldb' module, please set PYTHONPATH correctly"
+        sys.exit(1)
+
+class ReadOnlyFile:
+  '''Abstract reading data from an object:
+     Duck type an lldb.SBTarget, string (output of file.read()), or Python File object. 
+  '''
+  def __init__(self, readAbstraction, address = 0):
+    # Python file object 
+    self.file = None
+    # offset for FAT binaries. 
+    self.offset = None
+
+    # lldb SBTarget
+    self.address = None
+    self.startingAddress = None
+    self.SBTarget = None
+    self.SBError = None
+
+    # Python string (file.read())
+    self.data = None
+    self.dataIndex = 0
+
+    if isinstance(readAbstraction, lldb.SBTarget):
+      # duck type lldb memory reads
+      self.address = address
+      self.startingAddress = address
+      self.SBTarget = readAbstraction
+      self.SBError = lldb.SBError() 
+    elif isinstance(readAbstraction, file):
+      # duck type to a Python file 
+      self.file = readAbstraction
+      self.offset = address
+    elif isinstance(readAbstraction, str):
+      # string, like the result of reading the file in via Python
+      self.data = readAbstraction
+      self.dataIndex = 0
+    else:
+      raise SyntaxError('Unsupported type for readAbstraction')
+
+  def Read (self, size, offset=None):
+    if offset is not None:
+      self.Seek (offset)
+
+    if self.file:
+      return self.file.read(size)
+
+    if self.address:
+      data = self.SBTarget.process.ReadMemory (self.address, size, self.SBError)
+      self.address += size
+      return bytearray(data)
+
+    if self.data:
+      data = self.data[self.dataIndex:self.dataIndex+size]
+      self.dataIndex += size
+      return data
+
+  def ReadCString (self, offset=None, maxSize=512):
+    if offset:
+      self.Seek (offset)
+
+    if self.file:
+      data = self.file.read(maxSize)
+      str = data.split('\x00')[0]
+      # seek to end of string
+      self.file.seek (-(maxSize - len(str)), os.SEEK_CUR)
+      return data      
+
+    if self.address:
+      data = self.SBTarget.process.ReadCStringFromMemory (self.address, maxSize, self.SBError)
+      self.address += len(data)
+      return data      
+
+    if self.data:
+      data = self.data[self.dataIndex:self.dataIndex+maxSize]
+      str = data.split('\x00')[0]
+      self.dataIndex += len(str)
+      return str
+    
+
+  def Seek (self, offset, whence = os.SEEK_SET):
+    if self.file:
+      return self.file.seek(offset, whence)
+
+    if self.address:
+      if   whence == os.SEEK_SET:
+        self.address = self.startingAddress + offset
+      elif whence == os.SEEK_CUR:
+        self.address = self.address + offset
+      elif whence == os.SEEK_END:
+        raise SyntaxError('whence does not support SEEK_END due to memory not having an end')
+      else:
+        raise SyntaxError('illegal whence value')
+
+    if self.data:
+      if   whence == os.SEEK_SET:
+        self.dataIndex = offset
+      elif whence == os.SEEK_CUR:
+        self.dataIndex = self.dataIndex + offset
+      elif whence == os.SEEK_END:
+        raise SyntaxError('whence does not support SEEK_END due to memory not having an end')
+      else:
+        raise SyntaxError('illegal whence value')
+
+  def Tell (self):
+    if self.file:
+      return self.file.tell()
+
+    if self.address:
+      return self.address
+
+    if self.data:
+      return self.dataIndex
+      
+
+  def __del__(self):
+    if self.file:
+      self.file.close()
+
+class EfiPeCoff:
+  ''' class to abstract PE/COFF walking'''
+
+  # PE/COFF class definitions
+
+  # 
+  # typedef struct {
+  #   UINT32  VirtualAddress;
+  #   UINT32  Size;
+  # } EFI_IMAGE_DATA_DIRECTORY;
+  # 
+  # typedef struct {
+  #   UINT16                    Signature;            ///< The signature for TE format = "VZ".
+  #   UINT16                    Machine;              ///< From the original file header.
+  #   UINT8                     NumberOfSections;     ///< From the original file header.
+  #   UINT8                     Subsystem;            ///< From original optional header.
+  #   UINT16                    StrippedSize;         ///< Number of bytes we removed from the header.
+  #   UINT32                    AddressOfEntryPoint;  ///< Offset to entry point -- from original optional header.
+  #   UINT32                    BaseOfCode;           ///< From original image -- required for ITP debug.
+  #   UINT64                    ImageBase;            ///< From original file header.
+  #   EFI_IMAGE_DATA_DIRECTORY  DataDirectory[2];     ///< Only base relocation and debug directory.
+  # } EFI_TE_IMAGE_HEADER;
+  # 
+
+  EFI_TE_IMAGE_HEADER_fmt = '<HHBBHLLQLLLL'
+  TeHdrLength = struct.calcsize(EFI_TE_IMAGE_HEADER_fmt)
+  EFI_TE_IMAGE_HEADER_tuple = 'Signature Machine NumberOfSections Subsystem StrippedSize AddressOfEntryPoint BaseOfCode ImageBase DataDirVirt_Reloc DataDirSize_Reloc DataDirVirt_Debug DataDirSize_Debug'
+  EFI_TE_IMAGE_HEADER = collections.namedtuple ('EFI_TE_IMAGE_HEADER', EFI_TE_IMAGE_HEADER_tuple)
+
+  EFI_IMAGE_NT_SIGNATURE = 0x00004550
+  # 
+  # ///
+  # /// PE images can start with an optional DOS header, so if an image is run
+  # /// under DOS it can print an error message.
+  # ///
+  # typedef struct {
+  #   UINT16  e_magic;    ///< Magic number.
+  #   UINT16  e_cblp;     ///< Bytes on last page of file.
+  #   UINT16  e_cp;       ///< Pages in file.
+  #   UINT16  e_crlc;     ///< Relocations.
+  #   UINT16  e_cparhdr;  ///< Size of header in paragraphs.
+  #   UINT16  e_minalloc; ///< Minimum extra paragraphs needed.
+  #   UINT16  e_maxalloc; ///< Maximum extra paragraphs needed.
+  #   UINT16  e_ss;       ///< Initial (relative) SS value.
+  #   UINT16  e_sp;       ///< Initial SP value.
+  #   UINT16  e_csum;     ///< Checksum.
+  #   UINT16  e_ip;       ///< Initial IP value.
+  #   UINT16  e_cs;       ///< Initial (relative) CS value.
+  #   UINT16  e_lfarlc;   ///< File address of relocation table.
+  #   UINT16  e_ovno;     ///< Overlay number.
+  #   UINT16  e_res[4];   ///< Reserved words.
+  #   UINT16  e_oemid;    ///< OEM identifier (for e_oeminfo).
+  #   UINT16  e_oeminfo;  ///< OEM information; e_oemid specific.
+  #   UINT16  e_res2[10]; ///< Reserved words.
+  #   UINT32  e_lfanew;   ///< File address of new exe header.
+  # } EFI_IMAGE_DOS_HEADER;
+  # 
+
+  # cheat as 58s is really e_cblp -> e_res2[10] 
+  EFI_IMAGE_DOS_HEADER_fmt = '<H58sI'
+  DosHdrLength = struct.calcsize(EFI_IMAGE_DOS_HEADER_fmt)
+  EFI_IMAGE_DOS_HEADER_tuple = 'e_magic e_ignore e_lfanew'
+  EFI_IMAGE_DOS_HEADER = collections.namedtuple ('EFI_IMAGE_DOS_HEADER', EFI_IMAGE_DOS_HEADER_tuple)
+
+  #define EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES 16
+  # 
+  # ///
+  # /// @attention
+  # /// EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC means PE32 and 
+  # /// EFI_IMAGE_OPTIONAL_HEADER32 must be used. The data structures only vary
+  # /// after NT additional fields.
+  # ///
+  EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC = 0x10b
+  # 
+  # UINT32                      Signature;
+  # typedef struct {
+  #   UINT16  Machine;
+  #   UINT16  NumberOfSections;
+  #   UINT32  TimeDateStamp;
+  #   UINT32  PointerToSymbolTable;
+  #   UINT32  NumberOfSymbols;
+  #   UINT16  SizeOfOptionalHeader;
+  #   UINT16  Characteristics;
+  # } EFI_IMAGE_FILE_HEADER;
+  # ///
+  # /// Optional Header Standard Fields for PE32.
+  # ///
+  # typedef struct {
+  #   ///
+  #   /// Standard fields.
+  #   ///
+  #   UINT16                    Magic;
+  #   UINT8                     MajorLinkerVersion;
+  #   UINT8                     MinorLinkerVersion;
+  #   UINT32                    SizeOfCode;
+  #   UINT32                    SizeOfInitializedData;
+  #   UINT32                    SizeOfUninitializedData;
+  #   UINT32                    AddressOfEntryPoint;
+  #   UINT32                    BaseOfCode;
+  #   UINT32                    BaseOfData;  ///< PE32 contains this additional field, which is absent in PE32+.
+  #   ///
+  #   /// Optional Header Windows-Specific Fields.
+  #   ///
+  #   UINT32                    ImageBase;
+  #   UINT32                    SectionAlignment;
+  #   UINT32                    FileAlignment;
+  #   UINT16                    MajorOperatingSystemVersion;
+  #   UINT16                    MinorOperatingSystemVersion;
+  #   UINT16                    MajorImageVersion;
+  #   UINT16                    MinorImageVersion;
+  #   UINT16                    MajorSubsystemVersion;
+  #   UINT16                    MinorSubsystemVersion;
+  #   UINT32                    Win32VersionValue;
+  #   UINT32                    SizeOfImage;
+  #   UINT32                    SizeOfHeaders;
+  #   UINT32                    Checksum;
+  #   UINT16                    Subsystem;
+  #   UINT16                    DllCharacteristics;
+  #   UINT32                    SizeOfStackReserve;
+  #   UINT32                    SizeOfStackCommit;
+  #   UINT32                    SizeOfHeapReserve;
+  #   UINT32                    SizeOfHeapCommit;
+  #   UINT32                    LoaderFlags;
+  #   UINT32                    NumberOfRvaAndSizes;
+  #   EFI_IMAGE_DATA_DIRECTORY  DataDirectory[EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES];
+  # } EFI_IMAGE_OPTIONAL_HEADER32;
+  # 
+
+  EFI_IMAGE_DATA_DIRECTORY_tuple = '''
+  DataDirVirt_Export DataDirSize_Export 
+  DataDirVirt_Import DataDirSize_Import 
+  DataDirVirt_Resource DataDirSize_Resource 
+  DataDirVirt_Exception DataDirSize_Exception 
+  DataDirVirt_Security DataDirSize_Security 
+  DataDirVirt_Reloc DataDirSize_Reloc 
+  DataDirVirt_Debug DataDirSize_Debug
+  DataDir7Virt DataDir7Size 
+  DataDir8Virt DataDir8Size 
+  DataDir9Virt DataDir9Size 
+  DataDir10Virt DataDir10Size 
+  DataDir11Virt DataDir11Size 
+  DataDir12Virt DataDir12Size 
+  DataDir13Virt DataDir13Size 
+  DataDir14Virt DataDir14Size 
+  DataDir15Virt DataDir15Size 
+  '''
+
+
+  EFI_IMAGE_OPTIONAL_HEADER32_fmt = '<IHHIIIHHHBBIIIIIIIIIHHHHHHIIIIHHIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII'
+  OptionalHeader32Length = struct.calcsize(EFI_IMAGE_OPTIONAL_HEADER32_fmt)
+  EFI_IMAGE_OPTIONAL_HEADER32_tuple = '''
+  Signature
+  Machine
+  NumberOfSections
+  TimeDateStamp
+  PointerToSymbolTable
+  NumberOfSymbols
+  SizeOfOptionalHeader
+  Characteristics
+  Magic
+  MajorLinkerVersion
+  MinorLinkerVersion
+  SizeOfCode
+  SizeOfInitializedData
+  SizeOfUninitializedData
+  AddressOfEntryPoint
+  BaseOfCode
+  BaseOfData
+  ImageBase
+  SectionAlignment
+  FileAlignment
+  MajorOperatingSystemVersion
+  MinorOperatingSystemVersion
+  MajorImageVersion
+  MinorImageVersion
+  MajorSubsystemVersion
+  MinorSubsystemVersion
+  Win32VersionValue
+  SizeOfImage
+  SizeOfHeaders
+  Checksum
+  Subsystem
+  DllCharacteristics
+  SizeOfStackReserve
+  SizeOfStackCommit
+  SizeOfHeapReserve
+  SizeOfHeapCommit
+  LoaderFlags
+  NumberOfRvaAndSizes
+  ''' + EFI_IMAGE_DATA_DIRECTORY_tuple
+  EFI_IMAGE_OPTIONAL_HEADER32 = collections.namedtuple ('EFI_IMAGE_OPTIONAL_HEADER32', EFI_IMAGE_OPTIONAL_HEADER32_tuple)
+
+
+  # 
+  # ///
+  # /// @attention
+  # /// EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC means PE32+ and 
+  # /// EFI_IMAGE_OPTIONAL_HEADER64 must be used. The data structures only vary
+  # /// after NT additional fields.
+  # ///
+  EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC = 0x20b
+  # 
+  # ///
+  # /// Optional Header Standard Fields for PE32+.
+  # ///
+
+
+  # UINT32                      Signature;
+  # typedef struct {
+  #   UINT16  Machine;
+  #   UINT16  NumberOfSections;
+  #   UINT32  TimeDateStamp;
+  #   UINT32  PointerToSymbolTable;
+  #   UINT32  NumberOfSymbols;
+  #   UINT16  SizeOfOptionalHeader;
+  #   UINT16  Characteristics;
+  # } EFI_IMAGE_FILE_HEADER;
+  # ///
+  # /// COFF File Header (Object and Image).
+  # ///
+  # typedef struct {
+  #   ///
+  #   /// Standard fields.
+  #   ///
+  #   UINT16                    Magic;
+  #   UINT8                     MajorLinkerVersion;
+  #   UINT8                     MinorLinkerVersion;
+  #   UINT32                    SizeOfCode;
+  #   UINT32                    SizeOfInitializedData;
+  #   UINT32                    SizeOfUninitializedData;
+  #   UINT32                    AddressOfEntryPoint;
+  #   UINT32                    BaseOfCode;
+  #   ///
+  #   /// Optional Header Windows-Specific Fields.
+  #   ///
+  #   UINT64                    ImageBase;
+  #   UINT32                    SectionAlignment;
+  #   UINT32                    FileAlignment;
+  #   UINT16                    MajorOperatingSystemVersion;
+  #   UINT16                    MinorOperatingSystemVersion;
+  #   UINT16                    MajorImageVersion;
+  #   UINT16                    MinorImageVersion;
+  #   UINT16                    MajorSubsystemVersion;
+  #   UINT16                    MinorSubsystemVersion;
+  #   UINT32                    Win32VersionValue;
+  #   UINT32                    SizeOfImage;
+  #   UINT32                    SizeOfHeaders;
+  #   UINT32                    Checksum;
+  #   UINT16                    Subsystem;
+  #   UINT16                    DllCharacteristics;
+  #   UINT64                    SizeOfStackReserve;
+  #   UINT64                    SizeOfStackCommit;
+  #   UINT64                    SizeOfHeapReserve;
+  #   UINT64                    SizeOfHeapCommit;
+  #   UINT32                    LoaderFlags;
+  #   UINT32                    NumberOfRvaAndSizes;
+  #   EFI_IMAGE_DATA_DIRECTORY  DataDirectory[EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES];
+  # } EFI_IMAGE_OPTIONAL_HEADER64;
+  # 
+
+  EFI_IMAGE_OPTIONAL_HEADER64_fmt = '<IHHIIIHHHBBIIIIIQIIHHHHHHIIIIHHQQQQIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII'
+  OptionalHeader64Length = struct.calcsize(EFI_IMAGE_OPTIONAL_HEADER64_fmt)
+  EFI_IMAGE_OPTIONAL_HEADER64_tuple = '''
+  Signature
+  Machine
+  NumberOfSections
+  TimeDateStamp
+  PointerToSymbolTable
+  NumberOfSymbols
+  SizeOfOptionalHeader
+  Characteristics
+  Magic
+  MajorLinkerVersion
+  MinorLinkerVersion
+  SizeOfCode
+  SizeOfInitializedData
+  SizeOfUninitializedData
+  AddressOfEntryPoint
+  BaseOfCode
+  ImageBase
+  SectionAlignment
+  FileAlignment
+  MajorOperatingSystemVersion
+  MinorOperatingSystemVersion
+  MajorImageVersion
+  MinorImageVersion
+  MajorSubsystemVersion
+  MinorSubsystemVersion
+  Win32VersionValue
+  SizeOfImage
+  SizeOfHeaders
+  Checksum
+  Subsystem
+  DllCharacteristics
+  SizeOfStackReserve
+  SizeOfStackCommit
+  SizeOfHeapReserve
+  SizeOfHeapCommit
+  LoaderFlags
+  NumberOfRvaAndSizes
+  ''' + EFI_IMAGE_DATA_DIRECTORY_tuple
+  EFI_IMAGE_OPTIONAL_HEADER64 = collections.namedtuple ('EFI_IMAGE_OPTIONAL_HEADER64', EFI_IMAGE_OPTIONAL_HEADER64_tuple)
+
+  # 
+  # #define EFI_IMAGE_SIZEOF_SHORT_NAME 8
+  # 
+  # ///
+  # /// Section Table. This table immediately follows the optional header.
+  # ///
+  # typedef struct {
+  #   UINT8 Name[EFI_IMAGE_SIZEOF_SHORT_NAME];
+  #   union {
+  #     UINT32  PhysicalAddress;
+  #     UINT32  VirtualSize;
+  #   } Misc;
+  #   UINT32  VirtualAddress;
+  #   UINT32  SizeOfRawData;
+  #   UINT32  PointerToRawData;
+  #   UINT32  PointerToRelocations;
+  #   UINT32  PointerToLinenumbers;
+  #   UINT16  NumberOfRelocations;
+  #   UINT16  NumberOfLinenumbers;
+  #   UINT32  Characteristics;
+  # } EFI_IMAGE_SECTION_HEADER;
+  # 
+
+  EFI_IMAGE_SECTION_HEADER_fmt = '<QIIIIIIHHI'
+  PeCoffSectionLength = struct.calcsize(EFI_IMAGE_SECTION_HEADER_fmt) 
+  EFI_IMAGE_SECTION_HEADER_tuple = 'Name VirtualSize VirtualAddress SizeOfRawData PointerToRawData PointerToRelocations PointerToLinenumbers NumberOfRelocations NumberOfLinenumbers Characteristics'
+  EFI_IMAGE_SECTION_HEADER = collections.namedtuple ('EFI_IMAGE_SECTION_HEADER', EFI_IMAGE_SECTION_HEADER_tuple)
+
+  #     
+  # ///
+  # /// Debug Directory Format.
+  # ///
+  # typedef struct {
+  #   UINT32  Characteristics;
+  #   UINT32  TimeDateStamp;
+  #   UINT16  MajorVersion;
+  #   UINT16  MinorVersion;
+  #   UINT32  Type;
+  #   UINT32  SizeOfData;
+  #   UINT32  RVA;           ///< The address of the debug data when loaded, relative to the image base.
+  #   UINT32  FileOffset;    ///< The file pointer to the debug data.
+  # } EFI_IMAGE_DEBUG_DIRECTORY_ENTRY;
+  # 
+
+  EFI_IMAGE_DEBUG_DIRECTORY_ENTRY_fmt = '<IIHHIIII'
+  EFI_IMAGE_DEBUG_DIRECTORY_ENTRY_tuple = 'Characteristics TimeDateStamp MajorVersion MinorVersion Type SizeOfData RVA FileOffset'
+  EFI_IMAGE_DEBUG_DIRECTORY_ENTRY = collections.namedtuple ('EFI_IMAGE_DEBUG_DIRECTORY_ENTRY', EFI_IMAGE_DEBUG_DIRECTORY_ENTRY_tuple)
+
+  ##define CODEVIEW_SIGNATURE_MTOC  SIGNATURE_32('M', 'T', 'O', 'C')
+  #typedef struct {
+  #  UINT32    Signature;                       ///< "MTOC".
+  #  GUID      MachOUuid;
+  #  //
+  #  //  Filename of .DLL (Mach-O with debug info) goes here
+  #  //
+  #} EFI_IMAGE_DEBUG_CODEVIEW_MTOC_ENTRY;
+
+  #typedef struct {
+  #  UINT32  Data1;
+  #  UINT16  Data2;
+  #  UINT16  Data3;
+  #  UINT8   Data4[8];
+  #} GUID;
+
+  EFI_GUID_fmt = '<IHHBBBBBBBB'
+
+  # typedef struct {
+  #   UINT32  VirtualAddress;
+  #   UINT32  SizeOfBlock;
+  # } EFI_IMAGE_BASE_RELOCATION;
+
+  EFI_IMAGE_BASE_RELOCATION_fmt = '<II'
+  BaseRelocationLength = struct.calcsize(EFI_IMAGE_BASE_RELOCATION_fmt)
+
+  # ///
+  # /// The WIN_CERTIFICATE structure is part of the PE/COFF specification.
+  # ///
+  # typedef struct {
+  #   ///
+  #   /// The length of the entire certificate,  
+  #   /// including the length of the header, in bytes.                                
+  #   ///
+  #   UINT32  dwLength;
+  #   ///
+  #   /// The revision level of the WIN_CERTIFICATE 
+  #   /// structure. The current revision level is 0x0200.                                   
+  #   ///
+  #   UINT16  wRevision;
+  #   ///
+  #   /// The certificate type. See WIN_CERT_TYPE_xxx for the UEFI      
+  #   /// certificate types. The UEFI specification reserves the range of 
+  #   /// certificate type values from 0x0EF0 to 0x0EFF.                          
+  #   ///
+  #   UINT16  wCertificateType;
+  #   ///
+  #   /// The following is the actual certificate. The format of   
+  #   /// the certificate depends on wCertificateType.
+  #   ///
+  #   /// UINT8 bCertificate[ANYSIZE_ARRAY];
+  #   ///
+  # } WIN_CERTIFICATE;
+
+  WIN_CERTIFICATE_fmt = "<IHH"
+  WinCertLength = struct.calcsize(WIN_CERTIFICATE_fmt)
+
+  def __init__(self, readAbstraction, address = 0):
+    self.f = ReadOnlyFile(readAbstraction, address)
+    # ( ImageType:        'TE'/'PE32'/'PE32+'
+    #   OptionalHeaderCollection: Optional Header and Data Directory
+    #   HeaderFormat:     in struct.Struct() form
+    #   TeOffset
+    #   HeaderSize)
+    self.PeHdr = None
+    self.TeHdr = None
+    self.TeAdjust = 0
+    
+    self.PeCoffType = ''
+    self.MachineType = ''
+    self.PeHdrFmt = None
+    self.PeSections = 0
+    self.FvSection = False
+    self.ZeroList = []
+    self.PeCoffHdrRead ()
+
+  def TeHdrTuple (self, offset=0):
+    data = self.f.Read (EfiPeCoff.TeHdrLength,offset)  
+    TeHdr = EfiPeCoff.EFI_TE_IMAGE_HEADER._make (struct.Struct(EfiPeCoff.EFI_TE_IMAGE_HEADER_fmt).unpack_from (data))
+    return (TeHdr, EfiPeCoff.TeHdrLength - TeHdr.StrippedSize) 
+
+  def DosHdrTuple (self, offset=0):
+    data = self.f.Read(EfiPeCoff.DosHdrLength,offset)
+    return EfiPeCoff.EFI_IMAGE_DOS_HEADER._make (struct.unpack_from(EfiPeCoff.EFI_IMAGE_DOS_HEADER_fmt, data))
+
+  ImageFileMachine = {
+    0x014c : "IA32",
+    0x0200 : "IPF",
+    0x0EBC : "EBC",
+    0x8664 : "X64",
+    0x01c2 : "ARM",
+    0xAA64 : "AArch64",
+  }
+  
+  def PeCoffHdrRead (self):
+    # Test for FV Section (*.te build output)
+    image = self.f.Read(4, 0) 
+    if image[0:2] == 'MZ' or image[0:2] == 'VZ' or image[0:4] == 'PE\0\0':
+      offset = 0
+    else:
+      offset = 4
+      self.FvSection = True
+    
+    image = self.f.Read(2, offset)
+    if   image[0:2] == 'MZ':
+      # PE/COFF starts with DOS Header
+      DosHdr = self.DosHdrTuple (offset)
+      offset += DosHdr.e_lfanew
+    elif image[0:2] == 'VZ':
+      # PE/COFF starts with TE Header
+      self.TeHdr, self.TeAdjust = self.TeHdrTuple (offset)
+      self.PeCoffType = "TE"
+      self.MachineType = self.ImageFileMachine.get (self.TeHdr.Machine, 'Unknown')
+      self.PeSections = EfiPeCoff.TeHdrLength
+
+      data = self.f.Read(EfiPeCoff.TeHdrLength, offset)
+      self.PeHdrFmt = EfiPeCoff.EFI_TE_IMAGE_HEADER_fmt
+      return 
+    else:  
+      # PE/COFF starts with PE/COFF header
+      offset = 0
+
+    image = self.f.Read(4, offset)
+    if image[0:4] != 'PE\0\0':
+      print "Bad PE/COFF Signature = %4s" % image
+      return ("Unknown", None, "", 0, 0)
+
+    # Check the magic to figure out if 32 or 64 bit PE/COFF
+    (Magic,) = struct.unpack_from ('<H', self.f.Read(2, offset+24))
+    if Magic == EfiPeCoff.EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC:
+      data = self.f.Read(EfiPeCoff.OptionalHeader32Length, offset)
+      self.PeHdr = EfiPeCoff.EFI_IMAGE_OPTIONAL_HEADER32._make (struct.Struct(EfiPeCoff.EFI_IMAGE_OPTIONAL_HEADER32_fmt).unpack_from (data))
+      self.PeCoffType = "PE32"
+      self.PeHdrFmt = EfiPeCoff.EFI_IMAGE_OPTIONAL_HEADER32_fmt
+
+      # TimeDateStamp: Offset, size
+      self.ZeroList.append([offset + struct.calcsize(EfiPeCoff.EFI_IMAGE_OPTIONAL_HEADER32_fmt[0:4]), 4])
+      # Checksum: Offset, size
+      self.ZeroList.append([offset + struct.calcsize(EfiPeCoff.EFI_IMAGE_OPTIONAL_HEADER32_fmt[0:29]), 4])
+    elif Magic == EfiPeCoff.EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC:
+      data = self.f.Read(EfiPeCoff.OptionalHeader64Length, offset)
+      self.PeHdr = EfiPeCoff.EFI_IMAGE_OPTIONAL_HEADER64._make (struct.Struct(EfiPeCoff.EFI_IMAGE_OPTIONAL_HEADER64_fmt).unpack_from (data))
+      self.PeCoffType = "PE32+"
+      self.PeHdrFmt = EfiPeCoff.EFI_IMAGE_OPTIONAL_HEADER64_fmt
+
+      # TimeDateStamp: Offset, size
+      self.ZeroList.append([offset + struct.calcsize(EfiPeCoff.EFI_IMAGE_OPTIONAL_HEADER64_fmt[0:4]), 4])
+      # Checksum: Offset, size
+      self.ZeroList.append([offset + struct.calcsize(EfiPeCoff.EFI_IMAGE_OPTIONAL_HEADER64_fmt[0:29]), 4])
+    else:
+      print "Unknown Magic 0x%02x" % Magic
+      return ("Unknown", None, "", 0, 0)
+
+    self.MachineType = self.ImageFileMachine.get (self.PeHdr.Machine, 'Unknown')
+
+    # ImageContext->PeCoffHeaderOffset + sizeof (UINT32) + sizeof (EFI_IMAGE_FILE_HEADER) + Hdr.Pe32->FileHeader.SizeOfOptionalHeader;
+    self.PeSections = offset + 4 + 20 + self.PeHdr.SizeOfOptionalHeader
+
+  def PeCoffDumpHdr (self):
+      PeHdr = self.PeHdr if self.TeHdr is None else self.TeHdr
+      Width = max (len (s) for s in PeHdr._fields)
+      return "\n".join('{0} = {1:#0{2}x}'.format(s.ljust(Width), getattr(PeHdr, s), FmtStrToWidth(self.PeHdrFmt[i+1])+2) for i, s in enumerate (PeHdr._fields))
+  
+  def PeCoffZeroInfo (self):
+      # Return the files offsets and number of bytes that need to get zero'ed
+      return self.ZeroList
+
+  def NumberOfSections (self):
+    if self.PeHdr is not None:
+      return self.PeHdr.NumberOfSections
+    elif self.TeHdr is not None:
+      return self.TeHdr.NumberOfSections
+    else:
+      return 0
+
+  def PeCoffGetSection (self, index):
+    offset = self.PeSections + (index * EfiPeCoff.PeCoffSectionLength)
+    data = self.f.Read(EfiPeCoff.PeCoffSectionLength, offset)
+    return (data[0:8].split('\x00')[0], EfiPeCoff.EFI_IMAGE_SECTION_HEADER._make (struct.Struct(EfiPeCoff.EFI_IMAGE_SECTION_HEADER_fmt).unpack_from (data)))
+
+  def PeCoffDumpSectionHdr (self, Name, Section):
+    Width = max (len (s) for s in Section._fields)
+    result = ''
+    for i, s in enumerate (Section._fields):
+      result += '{0} = '.format(s.ljust(Width)) 
+      if i == 0 and Name != '':
+        # print name as a string, not a hex value
+        result += Name + '\n'
+      else:
+        result += '{0:#0{1}x}\n'.format(getattr(Section, s), FmtStrToWidth(EfiPeCoff.EFI_IMAGE_SECTION_HEADER_fmt[i+1])+2)
+
+    return result
+
+  def PeCoffDumpSection (self, Name, Section):
+    data = self.f.Read (Section.SizeOfRawData, Section.VirtualAddress)
+    result = []
+    Address = Section.VirtualAddress
+    for i in xrange (0, Section.SizeOfRawData, 16):
+      HexStr  = ' '.join(["%02X"%ord(x) for x in data[i:i+16]])
+      TextStr = ''.join([x if 0x20 <= ord(x) < 0x7F else b'.'  for x in data[i:i+16]])
+      result.append("%08X  %-*s   |%s|\n" % (Address + i, 16*3, HexStr, TextStr))
+
+    return ''.join(result)
+    
+
+  def PeCoffGetPdePointer (self, DebugEntry = 0, DebugEntrySize = 0, adjust = 0):
+    #
+    if DebugEntrySize == 0:
+      if self.PeHdr is not None:
+        DebugEntry     = self.PeHdr.DataDirVirt_Debug
+        DebugEntrySize = self.PeHdr.DataDirSize_Debug
+      elif self.TeHdr is not None:
+        DebugEntry     = self.TeHdr.DataDirVirt_Debug
+        DebugEntrySize = self.TeHdr.DataDirSize_Debug
+        adjust         = self.TeAdjust        
+      else:
+        return ('','')
+
+    offset = DebugEntry + adjust
+    data = self.f.Read(DebugEntrySize, offset)
+    DirectoryEntry = EfiPeCoff.EFI_IMAGE_DEBUG_DIRECTORY_ENTRY._make (struct.Struct(EfiPeCoff.EFI_IMAGE_DEBUG_DIRECTORY_ENTRY_fmt).unpack_from (data))
+    offset = DirectoryEntry.FileOffset + adjust
+
+    data = self.f.Read(4, offset)
+    guid = ''
+    if   data == 'MTOC':
+      data = self.f.Read(16)
+      tup = struct.unpack (EfiPeCoff.EFI_GUID_fmt, data)
+      guid = '{:08X}-{:04X}-{:04X}-{:02X}{:02X}-{:02X}{:02X}{:02X}{:02X}{:02X}{:02X}'.format(*tup)
+      Str = self.f.ReadCString ()
+    elif data == 'NB10':
+      Str = self.f.ReadCString (offset + 16)
+    elif data == 'RSDS':
+      Str = self.f.ReadCString (offset + 24)
+    else:
+      Str = "\x00"
+
+
+    # Python is more that happy to print out a NULL
+    return (Str.split('\x00')[0], guid)
+
+  def PeCoffDumpRelocations (self, offset, size):
+    data = self.f.Read(size, offset)
+    base    = 0
+    baseEnd = size - EfiPeCoff.BaseRelocationLength
+    value = ''
+    while base < baseEnd:
+      (VirtualAddress, SizeOfBlock) = struct.unpack_from (EfiPeCoff.EFI_IMAGE_BASE_RELOCATION_fmt, data[base:base + EfiPeCoff.BaseRelocationLength])
+      if SizeOfBlock == 0 or SizeOfBlock > size:
+        break
+      reloc    = base + EfiPeCoff.BaseRelocationLength
+      relocEnd = base + SizeOfBlock
+      value += '0x%08x SizeOfBlock 0x%x\n' % (VirtualAddress, SizeOfBlock)
+      while reloc < relocEnd:
+        rel, = struct.unpack_from ('<H', data[reloc:reloc+2])
+        value += '    0x%04x 0x%x\n' % ((rel & 0xFFF), rel >> 12, )
+        reloc += 2
+    
+      base = relocEnd
+    return value
+
+  def PeCoffDumpCert (self, offset, size):
+    data = self.f.Read(size, offset)
+    value = '\n'
+    if size > 8:
+      (dwLength, wRevision, wCertificateType) = struct.unpack_from (EfiPeCoff.WIN_CERTIFICATE_fmt, data)
+      value += "dwLength = 0x%04x wRevision = 0x%02x wCertificateType = 0x%02x\n" % (dwLength, wRevision, wCertificateType)
+      # UEFI Scheme
+      for i in range(struct.calcsize(EfiPeCoff.WIN_CERTIFICATE_fmt), size, 0x10):
+        value += "0x{:04x}:".format(i), 
+        value += " ".join("{:02x}".format(ord(c)) for c in data[i:i+0x10])
+        value += '\n'
+    else:
+      # Loki Scheme
+      start = 0
+      while start < size:
+        (VirtualAddress, SizeOfBlock) = struct.unpack_from (EfiPeCoff.EFI_IMAGE_BASE_RELOCATION_fmt, data[start: start + struct.calcsize(EfiPeCoff.EFI_IMAGE_BASE_RELOCATION_fmt)])
+        start += struct.calcsize(EfiPeCoff.EFI_IMAGE_BASE_RELOCATION_fmt)
+        value += "CERT: 0x%X size 0x%x\n" % (VirtualAddress, SizeOfBlock)
+        cert = self.f.Read(SizeOfBlock, VirtualAddress)
+        for i in range(0, SizeOfBlock, 0x10):
+          value += "0x{:04x}:".format(i)
+          value +=  " ".join("{:02x}".format(ord(c)) for c in cert[i:i+0x10])
+          value += '\n'
+    return value
+    
+  def __str__(self):
+    return self.PeCoffDumpHdr()
+
+def FmtStrToWidth (c):
+  c = c.upper()
+  if c== 'B':
+    return 1*2
+  if c== 'H':
+    return 2*2
+  if c== 'I' or c=='L':
+    return 4*2
+  if c== 'Q':
+    return 8*2
+  return 0
+
+#define EFI_FAT_BINARY_MAGIC   0x0ef1fab9
+
+# typedef struct _EFI_FAT_BINARY_HEADER {
+#      UINT32  magic;            /* FAT_MAGIC */
+#      UINT32  nfat_arch;      /* number of structs that follow */
+# } EFI_FAT_BINARY_HEADER;
+
+# typedef struct _EFI_FAT_BINARY_ARCH {
+#      UINT32  cputype;    /* cpu specifier (int) */
+#      UINT32  cpusubtype;     /* machine specifier (int) */
+#      UINT32  offset;     /* file offset to this object file */
+#      UINT32  size;       /* size of this object file */
+#      UINT32  align;      /* alignment as a power of 2 */
+# } EFI_FAT_BINARY_ARCH;
+
+EFI_FAT_BINARY_ARCH_fmt = '<IIIII'
+
+fatCpuType = {
+  0x01000007: 'x86_64 (X64)',
+  0x00000007: 'i386 (Ia32)',
+  0x0000000C: 'ARM (Arm)',
+  0x0100000C: 'ARM64 (AArch64)',
+}
+
+def CheckForFatBinary (f):
+  '''Return a list of PE/COFF binary objects, from a file object. 
+  '''
+  fatEntry = 4 + 4
+  data = f.read(fatEntry)
+  (magic, nfat_arch) = struct.unpack_from ('<II', data)
+  if magic == 0x0ef1fab9:
+    res  = []
+    for i in range (nfat_arch):
+      f.seek(fatEntry)
+      fatEntry += struct.calcsize(EFI_FAT_BINARY_ARCH_fmt)
+      data = f.read(struct.calcsize(EFI_FAT_BINARY_ARCH_fmt))
+      (cputype, cpusubtype, offset, size, align) = struct.unpack_from (EFI_FAT_BINARY_ARCH_fmt, data)
+      f.seek(offset)
+      res.append((EfiPeCoff(f.read (size)), "FAT Binary of type %s: offset 0x%x size 0x%x alignment 0x%x" % (fatCpuType.get(cputype, 'Unknown'), offset, size, align)))
+  else:
+    # entire file is a PE/COFF image
+    f.seek(0)
+    res = [(EfiPeCoff(f.read()), "")]
+  return res
+
+if __name__ == "__main__":
+  usage = "usage: %prog [options] PECOFF_FILE"
+  parser = optparse.OptionParser(usage=usage)
+  parser.add_option('-r', '--relocations', action='store_true', dest='relocation', help='display relocation info', default=False)
+  parser.add_option('-c', '--cert', action='store_true', dest='cert', help='display security cert info', default=False)
+  parser.add_option('-s', '--section', type=str, dest='section', help='dump info on a section', default='')
+  parser.add_option('-z', '--zero', action='store_true', dest='zero', help='Zero out fields to enable build reproducibility', default=False)
+  (options, args) = parser.parse_args(sys.argv)
+
+  if len(args) <= 1:
+    parser.print_help()
+    sys.exit(-1)
+
+  with open(args[1], "rb" if not options.zero else "r+b") as f:
+    for (pecoff, description) in CheckForFatBinary (f):
+      if not options.zero:
+        if description != '':
+          print description
+
+        print "%s is a %s:%s image%s" % (args[1], pecoff.PeCoffType, pecoff.MachineType, ' wrapped in FV Section:' if pecoff.FvSection else ':')
+        if pecoff.PeCoffType == '':
+          sys.exit(-1)
+
+        # print header
+        print pecoff.PeCoffDumpHdr()
+        print
+        print "\nSections:"
+        for i in range (0, pecoff.NumberOfSections()):
+          (Name, Section) = pecoff.PeCoffGetSection (i)
+          print pecoff.PeCoffDumpSectionHdr (Name, Section)
+          print
+
+          if   '.reloc' in Name and options.relocation:
+            print pecoff.PeCoffDumpRelocations (Section.PointerToRawData, Section.VirtualSize)
+          
+          elif '.debug' in Name:
+            (PdbPointer, Guid) = pecoff.PeCoffGetPdePointer ()
+            if Guid == '':
+              print "PdbPointer:{0}\n".format(PdbPointer)
+            else:
+              print "PdbPointer (Mach-O symbol file):{0}\n           (Mach-O UUID): {1}".format(PdbPointer, Guid)
+
+          if options.section in Name and options.section != '':
+            print pecoff.PeCoffDumpSection(Name, Section) 
+
+        if options.cert:
+          print pecoff.PeCoffDumpCert (pecoff.PeHdr.DataDirVirt_Security, pecoff.PeHdr.DataDirSize_Security)
+        
+      else:
+        # this is necessary to find the 'zero list' entries for the debug section
+        for i in range (0, pecoff.NumberOfSections()):
+          (Name, Section) = pecoff.PeCoffGetSection (i)
+
+          if Section.SizeOfRawData > Section.VirtualSize:
+            sizeDiff = Section.SizeOfRawData - Section.VirtualSize
+            offset = pecoff.TeAdjust + Section.PointerToRawData + Section.SizeOfRawData - sizeDiff
+            pecoff.ZeroList.append( [offset, sizeDiff] )
+
+          # The .debug section also contains a timestamp
+          if '.debug' in Name:
+            pecoff.ZeroList.append([pecoff.TeAdjust + Section.PointerToRawData + struct.calcsize(EfiPeCoff.EFI_IMAGE_DEBUG_DIRECTORY_ENTRY_fmt[0:2]), 4])
+
+        for patch, size in pecoff.PeCoffZeroInfo():
+          #print 'patching 0x%x for 0x%x bytes' % (patch, size)
+          if patch != 0:
+            if size == -1:
+              # -1 means to the end of the file
+              f.seek(0,2)
+              size = f.tell() - patch
+            f.seek(patch)
+            f.write(bytearray(size))
+
index 460c8f5e866e4348300f375fd88a3181a137b075..6e3e1b2e27ae9cd27b7f084b2603eff7db47212d 100755 (executable)
@@ -9,30 +9,31 @@ def Usage():
   
 def main():
   try:
-    opts, args = getopt.getopt(sys.argv[1:],"hav:",["help","arch=","verbose"]) 
+    opts, args = getopt.getopt(sys.argv[1:],"ha:v",["help","arch=","verbose"])
   except getopt.GetoptError:
     print "Unkown command line args"
     sys.exit(2)
 
   Verbose = 0
+  EntryPoint = 0
   for o,a in opts:
     if o in ("-h", "--help"):
       Usage ()
       sys.exit ()
     elif o in ("-a", "--arch"):
       Arch = a
+    elif o in ("-v", "--verbose"):
+      Verbose = 1
     else:
       Usage ()
       sys.exit ()
-    
 
   if Verbose:
-       print "\nmach-o load commands:"
+    print "\nmach-o load commands:"
   otoolload = open("otool-load.log", "r")
   data = otoolload.read()
   otoolload.close()
-  
-  
+
   # extract extry point from '     ss  0x00000000 eflags 0x00000000 eip 0x00000259 cs  0x00000000'
   if Arch == "i386":
     eip = data.find("eip")
@@ -44,68 +45,127 @@ def main():
     if r15 != -1:
       EntryPoint = int (data[r15 + 4:r15 + 4 + 10], 16)
   
-  # extract entry point from '   r15  0x0000000000000000 rip 0x0000000000000253'
   if Arch == "x86_64":
     rip = data.find("rip")
     if rip != -1:
       EntryPoint = int (data[rip + 4:rip + 4 + 18], 16)
-  
+
+  if Arch == "arm64":
+    pc = data.find("pc")
+    if pc != -1:
+      EntryPoint = int (data[pc + 3:pc + 3 + 18], 16)
+
   if EntryPoint == 0:
     print "FAIL - no entry point for PE/COFF image"
     sys.exit(-1)
   else:
-       if Verbose:
-               print "Entry Point = 0x%08x" % EntryPoint
+    if Verbose:
+      print "Entry Point = 0x%08x" % EntryPoint
   
   
   if Verbose:
-       print "\nPE/COFF dump:"
-  objdump = open("objdump-raw.log", "r")
+    print "\nPE/COFF dump:"
+  objdump = open("efi-pecoff-util-raw.log", "r")
   data = objdump.read()
   objdump.close()
   
   # Extract 'SizeOfImage               00000360'
   Index = data.find("SizeOfImage")
+  Index += data[Index:].find("=")
   End = data[Index:].find("\n")
-  SizeOfImage = int (data[Index+11:Index + End], 16);
+  SizeOfImage = int (data[Index+1:Index + End], 16)
   if Verbose:
-       print "SizeOfImage = 0x%08x" % SizeOfImage
-  
+    print "SizeOfImage = 0x%08x" % SizeOfImage
+
+  # We used to parse output from objdump...
   #Parse '  0 .text         00000080  00000240  00000240  00000240  2**2'
   #      '                  CONTENTS, ALLOC, LOAD, READONLY, CODE       '
-  EndOfTable = data.find("SYMBOL TABLE:")
-  Index = data.find("Idx Name")
-  End   = data[Index:].find("\n")
-  Index = Index + End + 1
-  
+  #
+  # But now we parse efi-pecoff-util
+  #Parse 'Sections:
+  #      'Name                 = .text
+  #      'VirtualSize          = 0x00000100
+  #      'VirtualAddress       = 0x00000240
+  #      'SizeOfRawData        = 0x00000100
+  #      'PointerToRawData     = 0x00000240
+  #      'PointerToRelocations = 0x00000000
+  #      'PointerToLinenumbers = 0x00000000
+  #      'NumberOfRelocations  = 0x0000
+  #      'NumberOfLinenumbers  = 0x0000
+  #      'Characteristics      = 0x60000020
+  EndOfTable = data.find("PdbPointer")
+  Index = data.find("Sections:");
+  Index += data[Index:].find("\n");
+
+  Name = ""
+  Size = -1
+  VMA = -1
+  LMA = -1
+  FileOff = -1
   PeCoffEnd = 0
   while Index < EndOfTable:
     End   = data[Index:].find("\n")
     Split = data[Index:Index+End].split()
-    # Split[0] Indx
-    # Split[1] Name i.e. .text
-    # Split[2] Size
-    # Split[3] VMA
-    # Split[4] LMA
-    # Split[5] File Off
-    # Split[6] Align
-    if int(Split[3],16) != int(Split[5],16):
-      print "FAIL - %s VMA %08x not equal File off %08x XIP will not work" % (Split[1], int(Split[3],16), int(Split[5],16))
-      sys.exit(-1)
-  
-    if int(Split[3],16) + int(Split[2],16) > PeCoffEnd:
-      PeCoffEnd = int(Split[3],16) + int(Split[2],16)
-    
-    if Split[1] == ".text":
-      SecStart = int(Split[3],16)
-      SecEnd = int(Split[3],16) + int(Split[2],16)
-      if (EntryPoint < SecStart) or (EntryPoint > SecEnd):
-        print "FAIL - Entry point (0x%x) not in .text section (0x%x - 0x%x)" % (EntryPoint, SecStart, SecEnd)
-        sys.exit(-1)
+    # Split[0] Key
+    # Split[1] =
+    # Split[2] Value
+    if len(Split) == 0:
+      # blank line, we've finished reading a section. process results
+      if Name != "":
+        # make sure we've found everything
+        if Size == -1:
+          print "FAIL - %s Size missing" % Name
+          sys.exit(-1)
+        if VMA == -1:
+          print "FAIL - %s VMA missing" % Name
+          sys.exit(-1)
+        if LMA == -1:
+          print "FAIL - %s LMA missing" % Name
+          sys.exit(-1)
+        if FileOff == -1:
+          print "FAIL - %s FileOff missing" % Name
+          sys.exit(-1)
+
+        if VMA != FileOff:
+          print "FAIL - %s VMA %08x not equal File off %08x XIP will not work" % (Name, VMA, FileOff)
+          sys.exit(-1)
+
+        SecStart = VMA
+        SecEnd = VMA + Size
+        if SecEnd > PeCoffEnd:
+          PeCoffEnd = SecEnd
+
+        if Name == ".text":
+          if (EntryPoint < SecStart) or (EntryPoint > SecEnd):
+            print "FAIL - Entry point (0x%x) not in .text section (0x%x - 0x%x)" % (EntryPoint, SecStart, SecEnd)
+            sys.exit(-1)
+
+        if Verbose:
+          print "%10s %08x %016x %016x %08x" % (Name, Size, VMA, LMA, FileOff) + " End = %x" % PeCoffEnd
+
+        # clear values for next time
+        Name = ""
+        Size = -1
+        VMA = -1
+        LMA = -1
+        FileOff = -1
+    elif len(Split) == 3:
+      Key = Split[0]
+      Value = Split[2]
     
-    if Verbose:
-               print "%10s" % Split[1] + ' ' + Split[2] + ' ' + Split[3] + ' ' + Split[4] + ' ' + Split[5] + " End = %x" % PeCoffEnd
-    Index += data[Index:].find("\n") + 1
+      if Key == "Name":
+        Name = Value
+      if Key == "VirtualSize":
+        Size = int(Value,16)
+      if Key == "VirtualAddress":
+        VMA = int(Value,16)
+        LMA = VMA # BUG: on our platform the virtual memory address and the load memory address are the same?
+      if Key == "PointerToRawData":
+        FileOff = int(Value,16)
+    else:
+      print "FAIL - Line is not (key = value): '%s'" % data[Index:Index+End]
+      sys.exit(-1)
+
     Index += data[Index:].find("\n") + 1
   
   if SizeOfImage < PeCoffEnd:
@@ -113,7 +173,7 @@ def main():
     sys.exit(-1)
   
   if Verbose:
-       print "\nmach-o relocations:"
+    print "\nmach-o relocations:"
   otoolreloc = open("otool-reloc.log", "r")
   lines = otoolreloc.readlines()
   otoolreloc.close()
@@ -128,7 +188,7 @@ def main():
       found = True
   
   if Verbose:
-       print
+    print
 
 
 if __name__ == "__main__":
index cf300a3ec672bc23213352fafae162a835703d6d..d3b0f86f189e1d48ebc1c273315ae421debdddd7 100644 (file)
@@ -31,8 +31,8 @@ run: all
 
 all:
        ${CC} -dynamiclib foo.c -o libfoo.dylib -Wl,-exported_symbol -Wl,'_AB*' -dead_strip
-       nm -j -f libfoo.dylib | grep _good | ${FAIL_IF_EMPTY}
-       nm -j -f libfoo.dylib | grep _bad | ${FAIL_IF_STDIN}
+       nm -j libfoo.dylib | grep _good | ${FAIL_IF_EMPTY}
+       nm -j libfoo.dylib | grep _bad | ${FAIL_IF_STDIN}
        ${PASS_IFF_GOOD_MACHO} libfoo.dylib
        
 clean:
index 7b000e48e00c5f78bcc33642801ae31807ec7379..902f6b3c42c7f3b3705d896b719e6ccd7b0e6637 100644 (file)
@@ -31,47 +31,47 @@ run: all
 
 all:
        ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo.dylib -Wl,-exported_symbol -Wl,'_foo*bar'
-       nm -j -g -f -s __TEXT __text libfoo.dylib | diff - expect1 | ${FAIL_IF_STDIN}
+       nm -j -g libfoo.dylib -s __TEXT __text | diff - expect1 | ${FAIL_IF_STDIN}
        ${FAIL_IF_BAD_MACHO} libfoo.dylib
 
        ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo.dylib -Wl,-exported_symbol -Wl,'_f?o'
-       nm -j -g -f -s __TEXT __text libfoo.dylib | diff - expect2 | ${FAIL_IF_STDIN}
+       nm -j -g libfoo.dylib -s __TEXT __text | diff - expect2 | ${FAIL_IF_STDIN}
        ${FAIL_IF_BAD_MACHO} libfoo.dylib
 
        ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo.dylib -Wl,-exported_symbol -Wl,'_foo*'
-       nm -j -g -f -s __TEXT __text libfoo.dylib | diff - expect3 | ${FAIL_IF_STDIN}
+       nm -j -g libfoo.dylib -s __TEXT __text | diff - expect3 | ${FAIL_IF_STDIN}
        ${FAIL_IF_BAD_MACHO} libfoo.dylib
 
        ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo.dylib -Wl,-exported_symbol -Wl,'_f*o*'
-       nm -j -g -f -s __TEXT __text libfoo.dylib | diff - expect4 | ${FAIL_IF_STDIN}
+       nm -j -g libfoo.dylib -s __TEXT __text | diff - expect4 | ${FAIL_IF_STDIN}
        ${FAIL_IF_BAD_MACHO} libfoo.dylib
 
        ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo.dylib -Wl,-exported_symbol -Wl,_foo -Wl,-exported_symbol -Wl,'_*bar'
-       nm -j -g -f -s __TEXT __text libfoo.dylib | diff - expect5 | ${FAIL_IF_STDIN}
+       nm -j -g libfoo.dylib -s __TEXT __text | diff - expect5 | ${FAIL_IF_STDIN}
        ${FAIL_IF_BAD_MACHO} libfoo.dylib
 
        ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo.dylib -exported_symbols_list list5
-       nm -j -g -f -s __TEXT __text libfoo.dylib | diff - expect5 | ${FAIL_IF_STDIN}
+       nm -j -g libfoo.dylib -s __TEXT __text | diff - expect5 | ${FAIL_IF_STDIN}
        ${FAIL_IF_BAD_MACHO} libfoo.dylib
 
        ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo.dylib -Wl,-unexported_symbol -Wl,'_*2*'
-       nm -j -g -f -s __TEXT __text libfoo.dylib | diff - expect6 | ${FAIL_IF_STDIN}
+       nm -j -g libfoo.dylib -s __TEXT __text | diff - expect6 | ${FAIL_IF_STDIN}
        ${FAIL_IF_BAD_MACHO} libfoo.dylib
 
        ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo.dylib -Wl,-exported_symbol -Wl,'_f[abcdef]o'
-       nm -j -g -f -s __TEXT __text libfoo.dylib | diff - expect7 | ${FAIL_IF_STDIN}
+       nm -j -g libfoo.dylib -s __TEXT __text | diff - expect7 | ${FAIL_IF_STDIN}
        ${FAIL_IF_BAD_MACHO} libfoo.dylib
 
        ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo.dylib -Wl,-exported_symbol -Wl,'_f[a-f]o'
-       nm -j -g -f -s __TEXT __text libfoo.dylib | diff - expect7 | ${FAIL_IF_STDIN}
+       nm -j -g libfoo.dylib -s __TEXT __text | diff - expect7 | ${FAIL_IF_STDIN}
        ${FAIL_IF_BAD_MACHO} libfoo.dylib
 
        ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo.dylib -Wl,-exported_symbol -Wl,'_f[a-z]o'
-       nm -j -g -f -s __TEXT __text libfoo.dylib | diff - expect8 | ${FAIL_IF_STDIN}
+       nm -j -g libfoo.dylib -s __TEXT __text | diff - expect8 | ${FAIL_IF_STDIN}
        ${FAIL_IF_BAD_MACHO} libfoo.dylib
 
        ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo.dylib -Wl,-exported_symbol -Wl,'_f[a-fnop]o'
-       nm -j -g -f -s __TEXT __text libfoo.dylib | diff - expect8 | ${FAIL_IF_STDIN}
+       nm -j -g libfoo.dylib -s __TEXT __text | diff - expect8 | ${FAIL_IF_STDIN}
        ${PASS_IFF_GOOD_MACHO} libfoo.dylib
        
 clean:
index 0fa97cebed558874545c9657ac7bd15e257e0d14..c9b62e0cb733c41d258920401fb29c944a2b9e35 100644 (file)
@@ -35,7 +35,7 @@ run: all
 all:
        ${CXX} ${CXXFLAGS} -flto foo.cxx -c -o foo.o
        ${CXX} ${CXXFLAGS} -flto bar.cxx -c -o bar.o
-       ${CC} ${CCFLAGS} foo.o bar.o -dynamiclib -o libfoo.dylib -exported_symbols_list foo.exp
+       ${CXX} ${CXXFLAGS} foo.o bar.o -dynamiclib -o libfoo.dylib -exported_symbols_list foo.exp
        nm -m libfoo.dylib | grep "weak external" | ${FAIL_IF_STDIN}
        ${PASS_IFF_GOOD_MACHO} libfoo.dylib
        
index 01b417f879d11e8d6742616a0b7000c2460ecb5a..df62d3fcfd0d2492380848d752df90a81898b97a 100644 (file)
@@ -31,7 +31,7 @@ include ${TESTROOT}/include/common.makefile
 run: all
 
 all:
-       ${CC} ${CCFLAGS} -flto -o foo foo.c -Wl,-dead_strip,-exported_symbol,_my_global -v
+       ${CC} ${CCFLAGS} -flto -o foo foo.c -Wl,-dead_strip,-exported_symbol,_my_global
     # Check symbols that are expected to be preserved
        nm -m foo | grep _global_metadata | ${FAIL_IF_EMPTY}
        nm -m foo | grep _liveness_binder | ${FAIL_IF_EMPTY}
@@ -40,6 +40,7 @@ all:
 
     # Check symbols that are expected to be stripped
        nm -m foo | grep unused | ${FAIL_IF_STDIN}
-       
+
+       ${PASS_IFF} true
 clean:
        rm  foo
index de0808a071108bd5625e4d399ede343f6b3c5e7a..ba63f26658c106db41e25c794c05b03a1461ed09 100644 (file)
@@ -37,6 +37,7 @@ all:
     # Check that unexported symbols are hidden
        nm a.out | grep "t _bar" | ${FAIL_IF_EMPTY}
        nm a.out | grep "t _foo" | ${FAIL_IF_EMPTY}
-       
+       ${PASS_IFF} true
+
 clean:
        rm a.out b.o a.o
index 933533f8891c994fbe10cc224c2c6b08722e386c..8b49b1b1024964aba6312e802854d73102660da5 100644 (file)
@@ -34,12 +34,12 @@ include ${TESTROOT}/include/common.makefile
 run: all
 
 all:
-       ${CC} -arch ${ARCH} -c -Wa,-n empty.s -o empty.o
+       ${CC} -arch ${ARCH} -c empty.s -o empty.o
        ${LD} -r empty.o -x -o empty2.o
-       otool -lv empty2.o | egrep 'vmsize 0x0[0]+$$' | ${FAIL_IF_EMPTY}
-       otool -lv empty2.o | grep 'filesize 0' | ${FAIL_IF_EMPTY}
-       otool -lv empty2.o | grep 'nsyms 0' | ${FAIL_IF_EMPTY}
-       otool -lv empty2.o | grep 'symoff 0' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -lv empty2.o | egrep 'vmsize 0x0[0]+$$' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -lv empty2.o | grep 'filesize 0' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -lv empty2.o | grep 'nsyms 0' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -lv empty2.o | grep 'symoff 0' | ${FAIL_IF_EMPTY}
        ${PASS_IFF} true
        
 clean:
diff --git a/unit-tests/test-cases/objc-gc-checks/Makefile b/unit-tests/test-cases/objc-gc-checks/Makefile
deleted file mode 100644 (file)
index 426d9b2..0000000
+++ /dev/null
@@ -1,145 +0,0 @@
-##
-# Copyright (c) 2007-2008 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
-
-SHELL = bash # use bash shell so we can redirect just stderr
-
-#
-# Validate that the linker catches illegal combinations of .o files 
-# compiled with different GC settings. 
-#
-
-IMAGE_INFO = "__objc_imageinfo"
-ifeq ($(ARCH),i386)
-       IMAGE_INFO = "__image_info"
-endif
-
-ifeq ($(ARCH),i386)
-       ALL = all-gc
-else
-ifeq ($(ARCH),x86_64)
-       ALL = all-gc
-else
-       ALL = all-nogc
-endif
-endif
-
-all: ${ALL}
-
-# For platforms that do not support GC.
-all-nogc:
-       ${PASS_IFF} true
-
-# For platforms that support GC.
-all-gc:
-       ${CC} ${CCFLAGS} foo.m -c -o foo.o
-       ${FAIL_IF_BAD_OBJ} foo.o
-
-       ${CC} ${CCFLAGS} bar.m -c -o bar.o
-       ${FAIL_IF_BAD_OBJ} bar.o
-
-       # clang no longer builds GC so we create fake GC object files instead.
-
-       cp -f foo.o foo-gc.o
-       ${OBJCIMAGEINFO} +supports-gc foo-gc.o
-
-       cp -f foo.o foo-gc-only.o
-       ${OBJCIMAGEINFO} +supports-gc +requires-gc foo-gc-only.o
-
-       cp -f bar.o bar-gc.o
-       ${OBJCIMAGEINFO} +supports-gc bar-gc.o
-
-       cp -f bar.o bar-gc-only.o
-       ${OBJCIMAGEINFO} +supports-gc +requires-gc bar-gc-only.o
-
-       # check RR + RR -> RR
-       ${CC} ${CCFLAGS} foo.o bar.o runtime.c -dynamiclib -o libfoobar.dylib -framework Foundation
-       ${FAIL_IF_BAD_MACHO} libfoobar.dylib
-
-       # check GC/RR + GC/RR -> GC/RR
-       ${CC} ${CCFLAGS} foo-gc.o bar-gc.o runtime.c -dynamiclib -o libfoobar.dylib  -framework Foundation
-       ${FAIL_IF_BAD_MACHO} libfoobar.dylib
-       ${OBJCIMAGEINFO} libfoobar.dylib | grep supports-gc | ${FAIL_IF_EMPTY}
-
-       # check GC + GC -> GC
-       ${CC} ${CCFLAGS} foo-gc-only.o bar-gc-only.o runtime.c -dynamiclib -o libfoobar.dylib  -framework Foundation
-       ${FAIL_IF_BAD_MACHO} libfoobar.dylib
-       ${OBJCIMAGEINFO} libfoobar.dylib | grep 'supports-gc requires-gc' | ${FAIL_IF_EMPTY}
-
-       # check RR + GC/RR -> RR
-       ${CC} ${CCFLAGS} foo.o bar-gc.o runtime.c -dynamiclib -o libfoobar.dylib  -framework Foundation
-       ${FAIL_IF_BAD_MACHO} libfoobar.dylib
-       ${OBJCIMAGEINFO} libfoobar.dylib | grep gc | ${FAIL_IF_STDIN}
-
-       # check GC/RR + RR -> RR
-       ${CC} ${CCFLAGS} bar-gc.o foo.o runtime.c -dynamiclib -o libfoobar.dylib  -framework Foundation
-       ${FAIL_IF_BAD_MACHO} libfoobar.dylib
-       ${OBJCIMAGEINFO} libfoobar.dylib | grep gc | ${FAIL_IF_STDIN}
-
-       # check GC + GC/RR -> GC
-       ${CC} ${CCFLAGS} foo-gc-only.o bar-gc.o runtime.c -dynamiclib -o libfoobar.dylib   -framework Foundation
-       ${FAIL_IF_BAD_MACHO} libfoobar.dylib
-       ${OBJCIMAGEINFO} libfoobar.dylib | grep 'supports-gc requires-gc' | ${FAIL_IF_EMPTY}
-
-       # check RR + GC -> error
-       ${FAIL_IF_SUCCESS} ${CC} ${CCFLAGS} foo.o bar-gc-only.o runtime.c -dynamiclib -o libfoobar.dylib  -framework Foundation 2> fail.log
-
-       # check cmd line GC/RR, GC/RR + RR -> error
-       ${FAIL_IF_SUCCESS} ${CC} ${CCFLAGS} foo-gc.o foo.o runtime.c -dynamiclib -o libfoobar.dylib -Wl,-objc_gc  -framework Foundation 2> fail.log
-
-       # check GC/RR + compaction
-       ${CC} ${CCFLAGS} foo-gc.o bar-gc.o runtime.c -dynamiclib -Wl,-objc_gc_compaction -o libfoobar.dylib  -framework Foundation
-       ${OBJCIMAGEINFO} libfoobar.dylib | grep 0x12 | ${FAIL_IF_EMPTY}
-
-       # check GC + compaction
-       ${CC} ${CCFLAGS} foo-gc-only.o bar-gc-only.o runtime.c -dynamiclib -Wl,-objc_gc_compaction -o libfoobar.dylib  -framework Foundation
-       ${OBJCIMAGEINFO} libfoobar.dylib | grep 0x16 | ${FAIL_IF_EMPTY}
-
-       # none + GC/RR-dylib -> none
-       ${CC} ${CCFLAGS} foo-gc.o runtime.c -dynamiclib -o libfoo.dylib  -framework Foundation
-       ${CC} ${CCFLAGS} none.c libfoo.dylib -dynamiclib -o libnone.dylib -framework Foundation
-       size -m -l libnone.dylib | grep ${IMAGE_INFO} | ${FAIL_IF_STDIN}
-
-       # none + GC-dylib -> none
-       ${CC} ${CCFLAGS} foo-gc-only.o runtime.c -dynamiclib -o libfoo.dylib  -framework Foundation
-       ${CC} ${CCFLAGS} none.c libfoo.dylib -dynamiclib -o libnone.dylib -framework Foundation
-       size -m -l libnone.dylib | grep ${IMAGE_INFO} | ${FAIL_IF_STDIN}
-
-       # none + RR-dylib -> none
-       ${CC} ${CCFLAGS} foo.o runtime.c -dynamiclib -o libfoo.dylib  -framework Foundation
-       ${CC} ${CCFLAGS} none.c libfoo.dylib -dynamiclib -o libnone.dylib -framework Foundation
-       size -m -l libnone.dylib | grep ${IMAGE_INFO} | ${FAIL_IF_STDIN}
-
-       # check RR + GC-dylib -> error
-       ${CC} ${CCFLAGS} foo-gc-only.o runtime.c -dynamiclib -o libfoo.dylib  -framework Foundation
-       ${FAIL_IF_SUCCESS} ${CC} ${CCFLAGS} bar.o runtime.c -dynamiclib libfoo.dylib -o libbar.dylib  -framework Foundation 2> fail.log
-
-       # check GC + RR-dylib -> error
-       ${CC} ${CCFLAGS} foo.o runtime.c -dynamiclib -o libfoo.dylib  -framework Foundation
-       ${FAIL_IF_SUCCESS} ${CC} ${CCFLAGS} bar-gc-only.o runtime.c -dynamiclib libfoo.dylib -o libbar.dylib  -framework Foundation 2> fail.log
-
-       ${PASS_IFF} true
-
-clean:
-       rm -rf foo*.o bar*.o libfoobar.dylib fail.log libfoo.dylib libnone.dylib
diff --git a/unit-tests/test-cases/objc-gc-checks/bar.m b/unit-tests/test-cases/objc-gc-checks/bar.m
deleted file mode 100644 (file)
index f66df50..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-#include <Foundation/Foundation.h>
-
-@interface Bar : NSObject {
-       int f;
-}
-- (void) doit;
-@end
-
-@implementation Bar
-- (void) doit { }
-@end
-
diff --git a/unit-tests/test-cases/objc-gc-checks/comment.txt b/unit-tests/test-cases/objc-gc-checks/comment.txt
deleted file mode 100644 (file)
index 953da58..0000000
+++ /dev/null
@@ -1 +0,0 @@
-Validate that the linker catches illegal combintations of .o files compiled with different GC settings
diff --git a/unit-tests/test-cases/objc-gc-checks/foo.m b/unit-tests/test-cases/objc-gc-checks/foo.m
deleted file mode 100644 (file)
index 819049d..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-#include <Foundation/Foundation.h>
-
-@interface Foo : NSObject  {
-       int f;
-}
-- (void) doit;
-@end
-
-
-@implementation Foo
-- (void) doit {  }
-@end
-
diff --git a/unit-tests/test-cases/objc-gc-checks/none.c b/unit-tests/test-cases/objc-gc-checks/none.c
deleted file mode 100644 (file)
index 44506fa..0000000
+++ /dev/null
@@ -1 +0,0 @@
-void none() {}
diff --git a/unit-tests/test-cases/objc-gc-checks/runtime.c b/unit-tests/test-cases/objc-gc-checks/runtime.c
deleted file mode 100644 (file)
index df4aeef..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-void _objc_empty_cache() {}
-void _objc_empty_vtable() {}
index 4eb7b4336e64bfc22e48f512b2165ff7ed2c2dc7..dddf231ab6061864fe311d1c8f22a92e100f7b0e 100644 (file)
@@ -40,7 +40,7 @@ all-old:
        # -sub_library for 10.4
        ${CC} ${CCFLAGS} -dynamiclib bar.c -o libbar.dylib  -install_name /usr/lib/libbar.dylib -mmacosx-version-min=10.4
        ${FAIL_IF_BAD_MACHO} libbar.dylib
-       ${CC} ${CCFLAGS} -dynamiclib middle.c -o libmiddle.dylib -lbar -L. -sub_library libbar -install_name /mid/libmiddle.dylib -mmacosx-version-min=10.4
+       ${CC} ${CCFLAGS} -dynamiclib middle.c -o libmiddle.dylib -lbar -L. -sub_library libbar -install_name /usr/lib/libmiddle.dylib -mmacosx-version-min=10.4
        ${FAIL_IF_BAD_MACHO} libmiddle.dylib
        ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo.dylib -lmiddle -L. -sub_library libmiddle -install_name /usr/lib/libfoo.dylib -mmacosx-version-min=10.4
        ${FAIL_IF_BAD_MACHO} libfoo.dylib
@@ -54,7 +54,7 @@ all-new:
        # -sub_library for 10.5
        ${CC} ${CCFLAGS} -dynamiclib bar.c -o libbar.dylib  -install_name /usr/lib/libbar.dylib 
        ${FAIL_IF_BAD_MACHO} libbar.dylib
-       ${CC} ${CCFLAGS} -dynamiclib middle.c -o libmiddle.dylib -lbar -L. -sub_library libbar -install_name /mid/libmiddle.dylib 
+       ${CC} ${CCFLAGS} -dynamiclib middle.c -o libmiddle.dylib -lbar -L. -sub_library libbar -install_name /usr/lib/libmiddle.dylib 
        ${FAIL_IF_BAD_MACHO} libmiddle.dylib
        ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo.dylib -lmiddle -L. -sub_library libmiddle -install_name /usr/lib/libfoo.dylib 
        ${FAIL_IF_BAD_MACHO} libfoo.dylib
index 060f12e2c00198b564ddcb78469ea49f2501653e..e4d81aca4a081c8b5f9ef97e997a2270c6464572 100644 (file)
@@ -31,7 +31,7 @@ include ${TESTROOT}/include/common.makefile
 run: all
 
 all:
-       as -arch ${ARCH} -L extra.s -o extra.o
+       ${AS} -Wa,-L extra.s -o extra.o
        ${CC} ${CCFLAGS} main.c extra.o -o main
        nm main | grep "lother" | ${FAIL_IF_STDIN}
        nm main | grep "L123" | ${FAIL_IF_STDIN}
diff --git a/unit-tests/test-cases/stabs-coalesce/Makefile b/unit-tests/test-cases/stabs-coalesce/Makefile
deleted file mode 100644 (file)
index 806f406..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-##
-# Copyright (c) 2006 Apple Computer, 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
-
-#
-# The point of this test is a sanity check that ld
-# removes the stabs associated with a copy of a coalesced 
-# function that was removed.
-# Running nm through stabs-filter.pl produces connonical stabs
-# that can be diffed against a checked in know good set of stabs
-#
-
-run: all
-
-all: hello.o other.o 
-       g++-4.2 ${CCXXFLAGS} -gstabs+ -gused hello.o other.o -o stabs-hello-${ARCH}
-       ${FAIL_IF_BAD_MACHO} stabs-hello-${ARCH}
-       nm -ap stabs-hello-${ARCH} | grep FUN | grep _Z3fooi | wc -l > stabs-hello-foo-count
-       echo "       1" > one
-       ${PASS_IFF} diff stabs-hello-foo-count one
-
-hello.o : hello.cxx
-       g++-4.2 ${CCXXFLAGS} -gstabs+ -gused hello.cxx -c -o $@
-       ${FAIL_IF_BAD_OBJ} $@
-
-other.o : other.cxx
-       g++-4.2 ${CCXXFLAGS} -gstabs+ -gused other.cxx -c -o $@
-       ${FAIL_IF_BAD_OBJ} $@
-
-clean:
-       rm -rf stabs-hello-* *.o *.stabs stabs-hello-foo-count one
diff --git a/unit-tests/test-cases/stabs-coalesce/comment.txt b/unit-tests/test-cases/stabs-coalesce/comment.txt
deleted file mode 100644 (file)
index f22b9a1..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-The point of this test is a sanity check that ld removes the stabs associated with a copy of a coalesced 
-function that was removed.  Running nm through stabs-filter.pl produces connonical stabs
-that can be diffed against a checked in know good set of stabs
diff --git a/unit-tests/test-cases/stabs-coalesce/header.h b/unit-tests/test-cases/stabs-coalesce/header.h
deleted file mode 100644 (file)
index 378308f..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 
- *
- * Copyright (c) 2006 Apple Computer, 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@
- */
-
-
-inline int foo(int x) 
-{ 
-       return x + 10;
-}
-
-extern int bar(int x);
diff --git a/unit-tests/test-cases/stabs-coalesce/hello.cxx b/unit-tests/test-cases/stabs-coalesce/hello.cxx
deleted file mode 100644 (file)
index 33bf273..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 
- *
- * Copyright (c) 2006 Apple Computer, 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 "header.h"
-
-
-int main()
-{
-       foo(bar(3));
-       fprintf(stdout, "hello\n");
-}
\ No newline at end of file
diff --git a/unit-tests/test-cases/stabs-coalesce/other.cxx b/unit-tests/test-cases/stabs-coalesce/other.cxx
deleted file mode 100644 (file)
index ee97d7d..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 
- *
- * Copyright (c) 2006 Apple Computer, 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 "header.h"
-
-int uninit;
-int init = 1;
-static int suninit;
-static int sinit=0;
-
-int bar(int x)
-{
-       static int bar_uninit;
-       static int bar_init=3;
-       bar_uninit = x;
-       return 20 + suninit + sinit +
-               bar_init + bar_uninit + foo(x);
-}
-
-
diff --git a/unit-tests/test-cases/stabs-directory-slash/Makefile b/unit-tests/test-cases/stabs-directory-slash/Makefile
deleted file mode 100644 (file)
index cd857b9..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-##
-# Copyright (c) 2005 Apple Computer, 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
-
-# Test that file paths in a stab reference ends with a /
-# if there is no terminating /, gdb does not recognize this as a file path
-# The provided files coalesced1a.o coalesced1b.o are ppc64 linked
-# rdar://problem/4565088
-
-run: all
-
-all: 
-       $(CC) -gstabs+ main.c -o outfile
-       ${FAIL_IF_BAD_MACHO} outfile
-       nm -ap outfile | grep '.*\<SO\>.*test-cases.*/$$' | ${PASS_IFF_STDIN}
-
-clean:
-       rm -rf outfile* 
diff --git a/unit-tests/test-cases/stabs-directory-slash/main.c b/unit-tests/test-cases/stabs-directory-slash/main.c
deleted file mode 100644 (file)
index a46866d..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-int main()
-{
-       return 0;
-}
diff --git a/unit-tests/test-cases/stack_addr_size/Makefile b/unit-tests/test-cases/stack_addr_size/Makefile
deleted file mode 100644 (file)
index c88f66b..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-##
-# Copyright (c) 2005 Apple Computer, 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
-
-# Test the ld option -stack_addr and -stack_size used together
-
-ifeq ($(FILEARCH),arm)
-       STACK_ADDR = 0x2C000000
-       STACK_SIZE = 0x05000000
-       STACK_TOP  = 0x27000000
-else
-ifeq (,${findstring 64,$(ARCH)})
-       STACK_ADDR = 0xCC000000
-       STACK_SIZE = 0x05000000
-       STACK_TOP  = 0xc7000000
-else
-       STACK_ADDR = 0x110000000
-       STACK_TOP  = 0x000000010b000000
-       STACK_SIZE = 0x0000000005000000
-endif
-endif
-
-run: all
-
-
-
-all:
-       ${CC} ${CCFLAGS} main.c -o main -Wl,-stack_size,${STACK_SIZE} -Wl,-stack_addr,${STACK_ADDR}
-       # Check for __UNIXSTACK section in object, check that it has the correct value
-       otool -l main | grep -A6 __UNIXSTACK > main.otool
-       grep " vmsize[ ]*${STACK_SIZE}" main.otool | ${FAIL_IF_EMPTY}
-       grep " vmaddr[ ]*${STACK_TOP}" main.otool | ${FAIL_IF_EMPTY}
-       ${FAIL_IF_BAD_MACHO} main
-       ${CC} ${CCFLAGS} -static main.c -o main2 -e _main -nostdlib -Wl,-new_linker -Wl,-stack_size,${STACK_SIZE} -Wl,-stack_addr,${STACK_ADDR}
-       otool -l main2 | grep -A6 __UNIXSTACK > main2.otool
-       grep " vmsize[ ]*${STACK_SIZE}" main2.otool | ${FAIL_IF_EMPTY}
-       grep " vmaddr[ ]*${STACK_TOP}" main2.otool | ${FAIL_IF_EMPTY}
-       ${PASS_IFF_GOOD_MACHO} main2
-
-clean:
-       rm -rf main main.otool main2.otool main2
diff --git a/unit-tests/test-cases/stack_addr_size/comment.txt b/unit-tests/test-cases/stack_addr_size/comment.txt
deleted file mode 100644 (file)
index da74f89..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-Test the ld commands -stack_addr, -stack_size (3939852 and 4729162)
-
-
--stack_addr value
-Specifies the initial address of the stack pointer value, where value is a hexadecimal number rounded to the segment alignment. The default segment alignment is the target pagesize (currently, 1000 hexadecimal for the PowerPC and for i386). If -stack_size is specified and -stack_addr is not, a default stack address specific for the architecture being linked will be used and its value printed as a warning message. This creates a segment named __UNIXSTACK. Note that the initial stack address will be either at the high address of the segment or the low address of the segment depending on which direction the stack grows for the architecture being linked.
-
-
--stack_size value
-Specifies the size of the stack segment value, where value is a hexadecimal number rounded to the segment alignment. The default segment alignment is the target pagesize (currently, 1000 hexadecimal for the PowerPC and for i386). If -stack_addr is specified and -stack_size is not, a default stack size specific for the architecture being linked will be used and its value printed as a warning message. This creates a segment named __UNIXSTACK .
-
-
diff --git a/unit-tests/test-cases/stack_addr_size/main.c b/unit-tests/test-cases/stack_addr_size/main.c
deleted file mode 100644 (file)
index 5c73586..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 
- *
- * Copyright (c) 2006 Apple Computer, 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>
-
-int main()
-{
-       return 0;
-}
index cbb6d490d2caaded19deea7e7d36158c87bd9e7b..082e208c5312b37d9c8a823bacde6f3e0ca2dc46 100644 (file)
@@ -41,15 +41,15 @@ else
 endif
 endif
 
+STACK_SIZE_DEC = $(shell printf "%d" $(STACK_SIZE))
 
 run: all
 
 all:
        ${CC} ${CCFLAGS} main.c -o main -Wl,-stack_size,${STACK_SIZE}
        # Check for __UNIXSTACK section in object, check that it has the correct value
-       otool -l main | grep -A6 __UNIXSTACK > main.otool
-       grep " vmsize[ ]*${STACK_SIZE}" main.otool | ${FAIL_IF_EMPTY}
-       grep " vmaddr[ ]*${STACK_TOP}" main.otool | ${FAIL_IF_EMPTY}
+       ${OTOOL} -l main | grep -A3 LC_MAIN > main.otool
+       grep " stacksize ${STACK_SIZE_DEC}" main.otool | ${FAIL_IF_EMPTY}
        ${PASS_IFF_GOOD_MACHO} main
 
 clean:
index 5854b0fe7b728b3bda8f07b3f38f2c5d176fd918..cc02303d260bef8268c4c519c2e8381db6ecd3a7 100644 (file)
@@ -38,7 +38,7 @@ endif
 all:
        ${CC} ${CCFLAGS} test.c -c -o test.o
        ${CC} ${CCFLAGS} test.o -static -Wl,-pie -o test -e _entry  -nostdlib -Wl,-new_linker
-       otool -rv test | grep __DATA | wc -l | grep ${RELOC_COUNT} | ${FAIL_IF_EMPTY}
+       ${DYLDINFO} -rebase test | grep __DATA | wc -l | grep ${RELOC_COUNT} | ${FAIL_IF_EMPTY}
        # verify trying to use absolute addressing fails
        ${CC} ${CCFLAGS} -static bad.c -c -o bad.o
        ${FAIL_IF_SUCCESS} ${CC} ${CCFLAGS} test.o bad.o -static -Wl,-pie -o test.bad -e _entry -nostdlib -Wl,-new_linker 2>/dev/null
index ce0359ffef4579c869d22ac65e10a5688c88bf71..9755e7d6b313a7633a94bcc2b444958da96d0678 100644 (file)
 
 int main()
 {
-       malloc(1);
-       malloc(2);
-       malloc(3);
-       malloc(4);
+       (void)malloc(1);
+       (void)malloc(2);
+       (void)malloc(3);
+       (void)malloc(4);
        return 0;
 }
 
index 0835fdb21633db0ae1b859632403847bd9d559c3..89c6b3e9467cba920da158fafb7d3f50b534c710 100644 (file)
@@ -32,19 +32,19 @@ run: all
 
 all:
        # build bootstrap dylib of with all code
-       ${CC} ${CCFLAGS} -dynamiclib a.c b.c c.c -o libBig.stub  -install_name /usr/lib/libBig.dylib 
+       ${CC} ${CCFLAGS} -dynamiclib a.c b.c c.c -o libBig.stub  -install_name /usr/local/lib/libBig.dylib 
        # link each sub library against bootstrap to intra-Big symbols
-       ${CC} ${CCFLAGS} -dynamiclib a.c -o liba.dylib libBig.stub -install_name /usr/local/lib/big/liba.dylib -umbrella Big
-       ${CC} ${CCFLAGS} -dynamiclib b.c -o libb.dylib libBig.stub -install_name /usr/local/lib/big/libb.dylib -umbrella Big
-       ${CC} ${CCFLAGS} -dynamiclib c.c -o libc.dylib libBig.stub -install_name /usr/local/lib/big/libc.dylib -umbrella Big
-       ${CC} ${CCFLAGS} -dynamiclib -Wl,-reexport_library,liba.dylib -Wl,-reexport_library,libb.dylib -Wl,-reexport_library,libc.dylib -o libBig.dylib -install_name /usr/lib/libBig.dylib 
+       ${CC} ${CCFLAGS} -dynamiclib a.c -o liba.dylib libBig.stub -install_name /usr/local/lib/liba.dylib -umbrella Big
+       ${CC} ${CCFLAGS} -dynamiclib b.c -o libb.dylib libBig.stub -install_name /usr/local/lib/libb.dylib -umbrella Big
+       ${CC} ${CCFLAGS} -dynamiclib c.c -o libc.dylib libBig.stub -install_name /usr/local/lib/libc.dylib -umbrella Big
+       ${CC} ${CCFLAGS} -dynamiclib -Wl,-reexport_library,liba.dylib -Wl,-reexport_library,libb.dylib -Wl,-reexport_library,libc.dylib -o libBig.dylib -install_name /usr/local/lib/libBig.dylib 
        # re-link against correct dylibs now that everything is built
-       ${CC} ${CCFLAGS} -dynamiclib a.c -o liba.dylib libc.dylib -install_name /usr/local/lib/big/liba.dylib -umbrella Big
+       ${CC} ${CCFLAGS} -dynamiclib a.c -o liba.dylib libc.dylib -install_name /usr/local/lib/liba.dylib -umbrella Big
        ${DYLDINFO} -lazy_bind liba.dylib | grep c2 | grep libc | ${FAIL_IF_EMPTY}
-       ${CC} ${CCFLAGS} -dynamiclib b.c -o libb.dylib libc.dylib -install_name /usr/local/lib/big/libb.dylib -umbrella Big
-       ${CC} ${CCFLAGS} -dynamiclib c.c -o libc.dylib liba.dylib -install_name /usr/local/lib/big/libc.dylib -umbrella Big
+       ${CC} ${CCFLAGS} -dynamiclib b.c -o libb.dylib libc.dylib -install_name /usr/local/lib/libb.dylib -umbrella Big
+       ${CC} ${CCFLAGS} -dynamiclib c.c -o libc.dylib liba.dylib -install_name /usr/local/lib/libc.dylib -umbrella Big
        ${DYLDINFO} -lazy_bind libc.dylib | grep a2 | grep liba | ${FAIL_IF_EMPTY}
-       ${CC} ${CCFLAGS} -dynamiclib -Wl,-reexport_library,liba.dylib -Wl,-reexport_library,libb.dylib -Wl,-reexport_library,libc.dylib -o libBig.dylib -install_name /usr/lib/libBig.dylib 
+       ${CC} ${CCFLAGS} -dynamiclib -Wl,-reexport_library,liba.dylib -Wl,-reexport_library,libb.dylib -Wl,-reexport_library,libc.dylib -o libBig.dylib -install_name /usr/local/lib/libBig.dylib 
        ${CC} ${CCFLAGS} main.c -o main libBig.dylib -L.
        ${PASS_IFF_GOOD_MACHO} main
 
index 69b40c7f4a062ce9ec2bf88d9afbc95198a664c0..1f827734d6bc5d9477f3444e80ca34a1f9d0a48f 100644 (file)
@@ -27,34 +27,45 @@ include ${TESTROOT}/include/common.makefile
 # Check that -U and -undefined dynamic_lookup work
 #
 
+ALL = all-mac
+
+#  -undefined dynamic_lookup is deprecated on iOS
+ifeq ($(ARCH),arm64)
+       ALL = all-ios
+else
+ifeq ($(ARCH),armv7)
+       ALL = all-ios
+endif
+endif
+
+
 run: all
 
-all:
+all: ${ALL}
+
+all-mac:
        ${CC} ${CCFLAGS} main.c -o main -undefined dynamic_lookup
        nm -m main | grep _foo | grep "dynamically looked up" | ${FAIL_IF_EMPTY}
        ${DYLDINFO} -lazy_bind -bind main | grep _foo | grep "flat-namespace" | ${FAIL_IF_EMPTY}
-       ${DYLDINFO} -lazy_bind -bind main | grep _exit | grep "flat-namespace" | ${FAIL_IF_STDIN}
        ${FAIL_IF_BAD_MACHO} main
 
        ${CC} ${CCFLAGS} main.c -o main -Wl,-U,_foo 
        nm -m main | grep _foo | grep "dynamically looked up" | ${FAIL_IF_EMPTY}
        ${DYLDINFO} -lazy_bind -bind main | grep _foo | grep "flat-namespace" | ${FAIL_IF_EMPTY}
-       ${DYLDINFO} -lazy_bind -bind main | grep _exit | grep "flat-namespace" | ${FAIL_IF_STDIN}
        ${FAIL_IF_BAD_MACHO} main
 
        ${CC} ${CCFLAGS} main.c -o main -flat_namespace -Wl,-U,_foo
        nm -m main | grep _foo | grep "dynamically looked up" | ${FAIL_IF_STDIN}
        ${DYLDINFO} -lazy_bind -bind main | grep _foo | grep "flat-namespace" | ${FAIL_IF_EMPTY}
-       ${DYLDINFO} -lazy_bind -bind main | grep _exit | grep "flat-namespace" | ${FAIL_IF_EMPTY}
        ${FAIL_IF_BAD_MACHO} main
 
        ${CC} ${CCFLAGS} main.c -bundle -o main.bundle -nodefaultlibs -undefined dynamic_lookup 
        nm -m main.bundle | grep _foo | grep "dynamically looked up" | ${FAIL_IF_EMPTY}
        ${DYLDINFO} -lazy_bind -bind main.bundle | grep _foo | grep "flat-namespace" | ${FAIL_IF_EMPTY}
-       ${DYLDINFO} -lazy_bind -bind main.bundle | grep _exit | grep "flat-namespace" | ${FAIL_IF_STDIN}
        ${PASS_IFF_GOOD_MACHO} main.bundle
 
-
+all-ios:
+       ${PASS_IFF} true
 
 clean:
        rm -f main main.bundle