]> git.saurik.com Git - apple/ld64.git/commitdiff
ld64-224.1.tar.gz developer-tools-50 ios-70 ios-703 ios-71 v224.1
authorApple <opensource@apple.com>
Mon, 22 Jul 2013 23:37:47 +0000 (23:37 +0000)
committerApple <opensource@apple.com>
Mon, 22 Jul 2013 23:37:47 +0000 (23:37 +0000)
65 files changed:
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/InputFiles.h
src/ld/LinkEdit.hpp
src/ld/LinkEditClassic.hpp
src/ld/Options.cpp
src/ld/Options.h
src/ld/OutputFile.cpp
src/ld/OutputFile.h
src/ld/Resolver.cpp
src/ld/Resolver.h
src/ld/SymbolTable.cpp
src/ld/dwarf2.h
src/ld/ld.cpp
src/ld/ld.hpp
src/ld/parsers/archive_file.cpp
src/ld/parsers/libunwind/DwarfInstructions.hpp
src/ld/parsers/libunwind/DwarfParser.hpp
src/ld/parsers/libunwind/Registers.hpp
src/ld/parsers/lto_file.cpp
src/ld/parsers/lto_file.h
src/ld/parsers/macho_dylib_file.cpp
src/ld/parsers/macho_dylib_file.h
src/ld/parsers/macho_relocatable_file.cpp
src/ld/parsers/macho_relocatable_file.h
src/ld/passes/compact_unwind.cpp
src/ld/passes/dtrace_dof.cpp
src/ld/passes/got.cpp
src/ld/passes/objc.cpp
src/ld/passes/order.cpp
src/ld/passes/stubs/stub_arm64.hpp [new file with mode: 0644]
src/ld/passes/stubs/stubs.cpp
src/other/ObjectDump.cpp
src/other/PruneTrie.cpp
src/other/dyldinfo.cpp
src/other/machochecker.cpp
src/other/unwinddump.cpp
unit-tests/include/common.makefile
unit-tests/test-cases/coalesce-force/Makefile [new file with mode: 0644]
unit-tests/test-cases/coalesce-force/foo.c [new file with mode: 0644]
unit-tests/test-cases/coalesce-force/foo.exp [new file with mode: 0644]
unit-tests/test-cases/data-in-code/Makefile
unit-tests/test-cases/data-in-code/main.c [deleted file]
unit-tests/test-cases/data-in-code/test.s
unit-tests/test-cases/linker_options-framework/Makefile [new file with mode: 0644]
unit-tests/test-cases/linker_options-framework/foo.c [new file with mode: 0644]
unit-tests/test-cases/linker_options-framework/main.c [new file with mode: 0644]
unit-tests/test-cases/linker_options-library/Makefile [new file with mode: 0644]
unit-tests/test-cases/linker_options-library/bar.c [new file with mode: 0644]
unit-tests/test-cases/linker_options-library/foo.c [new file with mode: 0644]
unit-tests/test-cases/linker_options-library/main.c [new file with mode: 0644]
unit-tests/test-cases/lto-dynamic_export/Makefile [new file with mode: 0644]
unit-tests/test-cases/lto-dynamic_export/main.c [new file with mode: 0644]
unit-tests/test-cases/order_file-archive/Makefile [new file with mode: 0644]
unit-tests/test-cases/order_file-archive/foo.c [new file with mode: 0644]
unit-tests/test-cases/order_file-archive/main.c [new file with mode: 0644]
unit-tests/test-cases/order_file-archive/main.expected [new file with mode: 0644]
unit-tests/test-cases/order_file-archive/main.order [new file with mode: 0644]
unit-tests/test-cases/re-export-symbol/Makefile
unit-tests/test-cases/re-export-symbol/foo.c

index c2eb01dde78b718a6799b0a391aedbc811108743..aef8eb94208f4d40d7366600087f89c50b821b66 100644 (file)
@@ -357,6 +357,10 @@ is a hexadecimal number with an optional leading 0x. The
 should be an even multiple of 4KB, that is the last three hexadecimal digits should be zero.
 .It Fl allow_stack_execute 
 Marks executable so that all stacks in the task will be given stack execution privilege. This includes pthread stacks.
 should be an even multiple of 4KB, that is the last three hexadecimal digits should be zero.
 .It Fl allow_stack_execute 
 Marks executable so that all stacks in the task will be given stack execution privilege. This includes pthread stacks.
+.It Fl export_dynamic
+Preserves all global symbols in main executables during LTO.  Without this option, Link Time Optimization
+is allowed to inline and remove global functions. This option is used when a main executable may load
+a plug-in which requires certain symbols from the main executable. 
 .El
 .Ss Options when creating a bundle
 .Bl -tag
 .El
 .Ss Options when creating a bundle
 .Bl -tag
@@ -695,7 +699,7 @@ order file  to cluster commonly used/dirty globals onto the same page(s).
 .Ss Obsolete Options
 .Bl -tag
 .It Fl segalign Ar value
 .Ss Obsolete Options
 .Bl -tag
 .It Fl segalign Ar value
-All segments must be page aligned.  This option is obsolete.
+All segments must be page aligned. 
 .It Fl seglinkedit
 Object files (MH_OBJECT) with a LINKEDIT segment are no longer supported. This option is obsolete.
 .It Fl noseglinkedit
 .It Fl seglinkedit
 Object files (MH_OBJECT) with a LINKEDIT segment are no longer supported. This option is obsolete.
 .It Fl noseglinkedit
@@ -703,7 +707,7 @@ This is the default.  This option is obsolete.
 .It Fl fvmlib
 Fixed VM shared libraries (MH_FVMLIB) are no longer supported. This option is obsolete.
 .It Fl preload
 .It Fl fvmlib
 Fixed VM shared libraries (MH_FVMLIB) are no longer supported. This option is obsolete.
 .It Fl preload
-Preload executables (MH_PRELOAD) are no longer supported.  This option is obsolete.
+Preload executables (MH_PRELOAD) are no longer supported. 
 .It Fl sectobjectsymbols Ar segname Ar sectname
 Adding a local label at a section start is no longer supported.  This option is obsolete.
 .It Fl nofixprebinding
 .It Fl sectobjectsymbols Ar segname Ar sectname
 Adding a local label at a section start is no longer supported.  This option is obsolete.
 .It Fl nofixprebinding
index dd746686d7f894adcd975fe75e2650852534aac2..4ffd5d86c4f2ff62ace367f656833851182c2e84 100644 (file)
@@ -87,7 +87,7 @@
 /* Begin PBXBuildRule section */
                F9E8D4BD07FCAF2000FD5801 /* PBXBuildRule */ = {
                        isa = PBXBuildRule;
 /* Begin PBXBuildRule section */
                F9E8D4BD07FCAF2000FD5801 /* PBXBuildRule */ = {
                        isa = PBXBuildRule;
-                       compilerSpec = com.apple.compilers.llvm.clang.1_0;
+                       compilerSpec = com.apple.compilers.gcc;
                        fileType = sourcecode.c;
                        isEditable = 1;
                        outputFiles = (
                        fileType = sourcecode.c;
                        isEditable = 1;
                        outputFiles = (
                F9023C3F06D5A254001BBF46 /* ld.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = ld.cpp; path = src/ld/ld.cpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
                F92D9C2710657AAB00FF369B /* stub_x86_64_classic.hpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.cpp.h; path = stub_x86_64_classic.hpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
                F933D9460929277C0083EAC8 /* FileAbstraction.hpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = FileAbstraction.hpp; path = src/abstraction/FileAbstraction.hpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
                F9023C3F06D5A254001BBF46 /* ld.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = ld.cpp; path = src/ld/ld.cpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
                F92D9C2710657AAB00FF369B /* stub_x86_64_classic.hpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.cpp.h; path = stub_x86_64_classic.hpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
                F933D9460929277C0083EAC8 /* FileAbstraction.hpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = FileAbstraction.hpp; path = src/abstraction/FileAbstraction.hpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
-               F933D9470929277C0083EAC8 /* MachOFileAbstraction.hpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = MachOFileAbstraction.hpp; path = src/abstraction/MachOFileAbstraction.hpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+               F933D9470929277C0083EAC8 /* MachOFileAbstraction.hpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 4; lastKnownFileType = sourcecode.cpp.h; name = MachOFileAbstraction.hpp; path = src/abstraction/MachOFileAbstraction.hpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
                F933DC37092A82480083EAC8 /* Architectures.hpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = Architectures.hpp; path = src/ld/Architectures.hpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
                F933DC37092A82480083EAC8 /* Architectures.hpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = Architectures.hpp; path = src/ld/Architectures.hpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+               F93A9BEC12C2E51900BAA11D /* stub_arm64.hpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.cpp.h; path = stub_arm64.hpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
                F93CB246116E69EB003233B8 /* tlvp.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.cpp.cpp; path = tlvp.cpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
                F93CB247116E69EB003233B8 /* tlvp.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.h; path = tlvp.h; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
                F971EED306D5ACF60041D381 /* ObjectDump */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = ObjectDump; sourceTree = BUILT_PRODUCTS_DIR; };
                F93CB246116E69EB003233B8 /* tlvp.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.cpp.cpp; path = tlvp.cpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
                F93CB247116E69EB003233B8 /* tlvp.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.h; path = tlvp.h; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
                F971EED306D5ACF60041D381 /* ObjectDump */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = ObjectDump; sourceTree = BUILT_PRODUCTS_DIR; };
                F9BA955D10A233000097A440 /* huge.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.h; path = huge.h; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
                F9BA963310A2545C0097A440 /* compact_unwind.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.cpp.cpp; path = compact_unwind.cpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
                F9BA963410A2545C0097A440 /* compact_unwind.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.h; path = compact_unwind.h; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
                F9BA955D10A233000097A440 /* huge.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.h; path = huge.h; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
                F9BA963310A2545C0097A440 /* compact_unwind.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.cpp.cpp; path = compact_unwind.cpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
                F9BA963410A2545C0097A440 /* compact_unwind.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.h; path = compact_unwind.h; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
-               F9C0D48A06DD1E1B001C7193 /* Options.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = Options.cpp; path = src/ld/Options.cpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
-               F9C0D48B06DD1E1B001C7193 /* Options.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = Options.h; path = src/ld/Options.h; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+               F9C0D48A06DD1E1B001C7193 /* Options.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Options.cpp; path = src/ld/Options.cpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+               F9C0D48B06DD1E1B001C7193 /* Options.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 4; lastKnownFileType = sourcecode.c.h; name = Options.h; path = src/ld/Options.h; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
                F9C12E9F0ED63DB1005BC69D /* dyldinfo.1 */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = text.man; name = dyldinfo.1; path = doc/man/man1/dyldinfo.1; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
                F9CC24141461FB4300A92174 /* blob.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.cpp.cpp; path = blob.cpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
                F9CC24151461FB4300A92174 /* blob.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.h; path = blob.h; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
                F9C12E9F0ED63DB1005BC69D /* dyldinfo.1 */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = text.man; name = dyldinfo.1; path = doc/man/man1/dyldinfo.1; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
                F9CC24141461FB4300A92174 /* blob.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.cpp.cpp; path = blob.cpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
                F9CC24151461FB4300A92174 /* blob.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.h; path = blob.h; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
                                F9AA65101051BD2B003E3539 /* stubs.cpp */,
                                F9AA650F1051BD2B003E3539 /* stub_arm.hpp */,
                                F984A13B10B614CF009E9878 /* stub_arm_classic.hpp */,
                                F9AA65101051BD2B003E3539 /* stubs.cpp */,
                                F9AA650F1051BD2B003E3539 /* stub_arm.hpp */,
                                F984A13B10B614CF009E9878 /* stub_arm_classic.hpp */,
+                               F93A9BEC12C2E51900BAA11D /* stub_arm64.hpp */,
                                F9BA8A7F1096150F0097A440 /* stub_x86.hpp */,
                                F9BA8A7E1096150F0097A440 /* stub_x86_classic.hpp */,
                                F989D0391062E6350014B60C /* stub_x86_64.hpp */,
                                F9BA8A7F1096150F0097A440 /* stub_x86.hpp */,
                                F9BA8A7E1096150F0097A440 /* stub_x86_classic.hpp */,
                                F989D0391062E6350014B60C /* stub_x86_64.hpp */,
                                GCC_MODEL_TUNING = G5;
                                GCC_SYMBOLS_PRIVATE_EXTERN = YES;
                                INSTALL_PATH = /usr/local/lib;
                                GCC_MODEL_TUNING = G5;
                                GCC_SYMBOLS_PRIVATE_EXTERN = YES;
                                INSTALL_PATH = /usr/local/lib;
+                               OTHER_CPLUSPLUSFLAGS = (
+                                       "-stdlib=libc++",
+                                       "$(OTHER_CFLAGS)",
+                               );
                                PREBINDING = NO;
                                PRODUCT_NAME = prunetrie;
                        };
                                PREBINDING = NO;
                                PRODUCT_NAME = prunetrie;
                        };
                                GCC_SYMBOLS_PRIVATE_EXTERN = YES;
                                GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES;
                                INSTALL_PATH = /usr/local/lib;
                                GCC_SYMBOLS_PRIVATE_EXTERN = YES;
                                GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES;
                                INSTALL_PATH = /usr/local/lib;
+                               OTHER_CPLUSPLUSFLAGS = (
+                                       "-stdlib=libc++",
+                                       "$(OTHER_CFLAGS)",
+                               );
                                PREBINDING = NO;
                                PRODUCT_NAME = prunetrie;
                        };
                                PREBINDING = NO;
                                PRODUCT_NAME = prunetrie;
                        };
                                GCC_MODEL_TUNING = G5;
                                GCC_SYMBOLS_PRIVATE_EXTERN = YES;
                                INSTALL_PATH = /usr/local/lib;
                                GCC_MODEL_TUNING = G5;
                                GCC_SYMBOLS_PRIVATE_EXTERN = YES;
                                INSTALL_PATH = /usr/local/lib;
+                               OTHER_CPLUSPLUSFLAGS = (
+                                       "-stdlib=libc++",
+                                       "$(OTHER_CFLAGS)",
+                               );
                                PREBINDING = NO;
                                PRODUCT_NAME = prunetrie;
                        };
                                PREBINDING = NO;
                                PRODUCT_NAME = prunetrie;
                        };
index 4fd6123b73b7b6c7844a96fd1e663b81413ed99c..60b4f10c22fecaaa02e5c3c50fd38864521e5138 100644 (file)
@@ -34,6 +34,7 @@
 #include <mach-o/compact_unwind_encoding.h>
 #include <mach/machine.h>
 #include <stddef.h>
 #include <mach-o/compact_unwind_encoding.h>
 #include <mach/machine.h>
 #include <stddef.h>
+#include <libunwind.h>
 
 #include "FileAbstraction.hpp"
 
 
 #include "FileAbstraction.hpp"
 
 
 #ifndef LC_DATA_IN_CODE
        #define LC_DATA_IN_CODE 0x29 /* table of non-instructions in __text */
 
 #ifndef LC_DATA_IN_CODE
        #define LC_DATA_IN_CODE 0x29 /* table of non-instructions in __text */
-       struct data_in_code_entry {
+       struct data_in_code_entry {
                uint32_t        offset;
                uint16_t        length;
                uint16_t        kind;
                uint32_t        offset;
                uint16_t        length;
                uint16_t        kind;
        #define LC_DYLIB_CODE_SIGN_DRS 0x2B
 #endif
 
        #define LC_DYLIB_CODE_SIGN_DRS 0x2B
 #endif
 
+#ifndef LC_ENCRYPTION_INFO_64
+       #define LC_ENCRYPTION_INFO_64 0x2C
+  struct encryption_info_command_64 {
+     uint32_t  cmd;            
+     uint32_t  cmdsize;
+     uint32_t  cryptoff;
+     uint32_t  cryptsize;
+     uint32_t  cryptid;
+     uint32_t  pad;
+  };
+#endif
+
+
+
 #ifndef CPU_SUBTYPE_ARM_V7F
   #define CPU_SUBTYPE_ARM_V7F    ((cpu_subtype_t) 10)
 #endif
 #ifndef CPU_SUBTYPE_ARM_V7F
   #define CPU_SUBTYPE_ARM_V7F    ((cpu_subtype_t) 10)
 #endif
 #endif
 
 
 #endif
 
 
+
+// hack until arm64 headers are worked out
+#define CPU_TYPE_ARM64                 (CPU_TYPE_ARM | CPU_ARCH_ABI64)
+#define CPU_SUBTYPE_ARM64_ALL  0
+#define CPU_SUBTYPE_ARM64_V8    1
+
+#define ARM64_RELOC_UNSIGNED            0 // for pointers
+#define ARM64_RELOC_SUBTRACTOR          1 // must be followed by a ARM64_RELOC_UNSIGNED
+#define ARM64_RELOC_BRANCH26            2 // a B/BL instruction with 26-bit displacement
+#define ARM64_RELOC_PAGE21              3 // pc-rel distance to page of target
+#define ARM64_RELOC_PAGEOFF12           4 // offset within page, scaled by r_length
+#define ARM64_RELOC_GOT_LOAD_PAGE21     5 // pc-rel distance to page of GOT slot
+#define ARM64_RELOC_GOT_LOAD_PAGEOFF12  6 // offset within page of GOT slot, scaled by r_length
+#define ARM64_RELOC_POINTER_TO_GOT      7 // for pointers to GOT slots
+#define ARM64_RELOC_TLVP_LOAD_PAGE21    8 // pc-rel distance to page of TLVP slot
+#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
+
+
+
+#define UNW_ARM64_X0     0
+#define UNW_ARM64_X1     1
+#define UNW_ARM64_X2     2
+#define UNW_ARM64_X3     3
+#define UNW_ARM64_X4     4
+#define UNW_ARM64_X5     5
+#define UNW_ARM64_X6     6
+#define UNW_ARM64_X7     7
+#define UNW_ARM64_X8     8
+#define UNW_ARM64_X9     9
+#define UNW_ARM64_X10   10
+#define UNW_ARM64_X11   11
+#define UNW_ARM64_X12   12
+#define UNW_ARM64_X13   13
+#define UNW_ARM64_X14   14
+#define UNW_ARM64_X15   15
+#define UNW_ARM64_X16   16
+#define UNW_ARM64_X17   17
+#define UNW_ARM64_X18   18
+#define UNW_ARM64_X19   19
+#define UNW_ARM64_X20   20
+#define UNW_ARM64_X21   21
+#define UNW_ARM64_X22   22
+#define UNW_ARM64_X23   23
+#define UNW_ARM64_X24   24
+#define UNW_ARM64_X25   25
+#define UNW_ARM64_X26   26
+#define UNW_ARM64_X27   27
+#define UNW_ARM64_X28   28
+#define UNW_ARM64_X29   29  
+#define UNW_ARM64_FP    29
+#define UNW_ARM64_X30   30  
+#define UNW_ARM64_LR    30
+#define UNW_ARM64_X31   31  
+#define UNW_ARM64_SP    31
+#define UNW_ARM64_D0    64
+#define UNW_ARM64_D1    65
+#define UNW_ARM64_D2    66
+#define UNW_ARM64_D3    67
+#define UNW_ARM64_D4    68
+#define UNW_ARM64_D5    69
+#define UNW_ARM64_D6    70
+#define UNW_ARM64_D7    71
+#define UNW_ARM64_D8    72
+#define UNW_ARM64_D9    73
+#define UNW_ARM64_D10   74
+#define UNW_ARM64_D11   75
+#define UNW_ARM64_D12   76
+#define UNW_ARM64_D13   77
+#define UNW_ARM64_D14   78
+#define UNW_ARM64_D15   79
+#define UNW_ARM64_D16   80
+#define UNW_ARM64_D17   81
+#define UNW_ARM64_D18   82
+#define UNW_ARM64_D19   83
+#define UNW_ARM64_D20   84
+#define UNW_ARM64_D21   85
+#define UNW_ARM64_D22   86
+#define UNW_ARM64_D23   87
+#define UNW_ARM64_D24   88
+#define UNW_ARM64_D25   89
+#define UNW_ARM64_D26   90
+#define UNW_ARM64_D27   91
+#define UNW_ARM64_D28   92
+#define UNW_ARM64_D29   93
+#define UNW_ARM64_D30   94
+#define UNW_ARM64_D31   95
+
+#define UNWIND_ARM64_MODE_MASK                          0x0F000000
+#define UNWIND_ARM64_MODE_FRAME_OLD                     0x01000000
+#define UNWIND_ARM64_MODE_FRAMELESS                     0x02000000
+#define UNWIND_ARM64_MODE_DWARF                         0x03000000
+#define UNWIND_ARM64_MODE_FRAME                         0x04000000
+    
+#define UNWIND_ARM64_FRAME_X19_X20_PAIR                 0x00000001
+#define UNWIND_ARM64_FRAME_X21_X22_PAIR                 0x00000002
+#define UNWIND_ARM64_FRAME_X23_X24_PAIR                 0x00000004
+#define UNWIND_ARM64_FRAME_X25_X26_PAIR                 0x00000008
+#define UNWIND_ARM64_FRAME_X27_X28_PAIR                 0x00000010
+#define UNWIND_ARM64_FRAME_D8_D9_PAIR                   0x00000100
+#define UNWIND_ARM64_FRAME_D10_D11_PAIR                 0x00000200
+#define UNWIND_ARM64_FRAME_D12_D13_PAIR                 0x00000400
+#define UNWIND_ARM64_FRAME_D14_D15_PAIR                 0x00000800
+
+#define UNWIND_ARM64_FRAMELESS_STACK_SIZE_MASK                 0x00FFF000
+
+#define UNWIND_ARM64_FRAME_X21_X22_PAIR_OLD                 0x00000001
+#define UNWIND_ARM64_FRAME_X23_X24_PAIR_OLD                 0x00000002
+#define UNWIND_ARM64_FRAME_X25_X26_PAIR_OLD                 0x00000004
+#define UNWIND_ARM64_FRAME_X27_X28_PAIR_OLD                 0x00000008
+#define UNWIND_ARM64_FRAME_D8_D9_PAIR_OLD                   0x00000010
+#define UNWIND_ARM64_FRAME_D10_D11_PAIR_OLD                 0x00000020
+#define UNWIND_ARM64_FRAME_D12_D13_PAIR_OLD                 0x00000040
+#define UNWIND_ARM64_FRAME_D14_D15_PAIR_OLD                 0x00000080
+
+
+#define UNWIND_ARM64_DWARF_SECTION_OFFSET               0x00FFFFFF
+
 #ifndef LC_SOURCE_VERSION
        #define LC_SOURCE_VERSION 0x2A
        struct source_version_command {
 #ifndef LC_SOURCE_VERSION
        #define LC_SOURCE_VERSION 0x2A
        struct source_version_command {
        #define LC_DYLIB_CODE_SIGN_DRS 0x2B 
 #endif 
 
        #define LC_DYLIB_CODE_SIGN_DRS 0x2B 
 #endif 
 
+#ifndef LC_LINKER_OPTION 
+       #define LC_LINKER_OPTION   0x2D
+
+       struct linker_option_command {
+               uint32_t        cmd;      /*LC_LINKER_OPTION only used in MH_OBJECT filetypes */
+               uint32_t        cmdsize;
+               uint32_t        count;    /* number of strings */
+               /* concatenation of zero terminated UTF8 strings.  Zero filled at end to align */
+       };
+#endif
+
+#ifndef EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE
+       #define EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE                       0x02
+#endif
+
+
+#ifndef CPU_SUBTYPE_ARM_V8
+       #define CPU_SUBTYPE_ARM_V8              ((cpu_subtype_t) 13) 
+#endif
+
+#ifndef CPU_SUBTYPE_ARM_V6M
+       #define CPU_SUBTYPE_ARM_V6M             ((cpu_subtype_t) 14) 
+#endif 
+
+#ifndef CPU_SUBTYPE_ARM_V7M
+       #define CPU_SUBTYPE_ARM_V7M             ((cpu_subtype_t) 15) 
+#endif 
+
+#ifndef CPU_SUBTYPE_ARM_V7EM
+       #define CPU_SUBTYPE_ARM_V7EM    ((cpu_subtype_t) 16) 
+#endif 
+
 
 struct ArchInfo {
        const char*                     archName;
 
 struct ArchInfo {
        const char*                     archName;
@@ -295,11 +460,33 @@ static const ArchInfo archInfoArray[] = {
 #if SUPPORT_ARCH_armv7s
        { "armv7s", CPU_TYPE_ARM,    CPU_SUBTYPE_ARM_V7S,    "thumbv7s-", "armv7s", true,  true },
        #define SUPPORT_ARCH_arm_any 1
 #if SUPPORT_ARCH_armv7s
        { "armv7s", CPU_TYPE_ARM,    CPU_SUBTYPE_ARM_V7S,    "thumbv7s-", "armv7s", true,  true },
        #define SUPPORT_ARCH_arm_any 1
+#endif
+#if SUPPORT_ARCH_armv6m
+       { "armv6m", CPU_TYPE_ARM,    CPU_SUBTYPE_ARM_V6M,    "thumbv6m-", "", true,  false },
+       #define SUPPORT_ARCH_arm_any 1
+#endif
+#if SUPPORT_ARCH_armv7m
+       { "armv7m", CPU_TYPE_ARM,    CPU_SUBTYPE_ARM_V7M,    "thumbv7m-", "armv7m", true,  true },
+       #define SUPPORT_ARCH_arm_any 1
+#endif
+#if SUPPORT_ARCH_armv7em
+       { "armv7em", CPU_TYPE_ARM,   CPU_SUBTYPE_ARM_V7EM,   "thumbv7em-", "armv7em", true,  true },
+       #define SUPPORT_ARCH_arm_any 1
+#endif
+#if SUPPORT_ARCH_armv8
+       { "armv8", CPU_TYPE_ARM,     CPU_SUBTYPE_ARM_V8,     "thumbv8-", "armv8", true,  true },
+       #define SUPPORT_ARCH_arm_any 1
+#endif
+#if SUPPORT_ARCH_arm64
+       { "arm64", CPU_TYPE_ARM64,   CPU_SUBTYPE_ARM64_ALL,  "arm64-",    "",   false,  false },
+#endif
+#if SUPPORT_ARCH_arm64v8
+       { "arm64v8", CPU_TYPE_ARM64, CPU_SUBTYPE_ARM64_V8,   "arm64v8-",  "",   true,  false },
 #endif
        { NULL, 0, 0, NULL, NULL, false, false }
 };
 
 #endif
        { NULL, 0, 0, NULL, NULL, false, false }
 };
 
-
 // weird, but this include must wait until after SUPPORT_ARCH_arm_any is set up
 #if SUPPORT_ARCH_arm_any
 #include <mach-o/arm/reloc.h>
 // weird, but this include must wait until after SUPPORT_ARCH_arm_any is set up
 #if SUPPORT_ARCH_arm_any
 #include <mach-o/arm/reloc.h>
@@ -1125,27 +1312,37 @@ private:
 //
 // mach-o encyrption info load command
 //
 //
 // mach-o encyrption info load command
 //
+template <typename P> struct macho_encryption_info_content {};
+template <> struct macho_encryption_info_content<Pointer32<BigEndian> >    { struct encryption_info_command            fields; };
+template <> struct macho_encryption_info_content<Pointer64<BigEndian> >           { struct encryption_info_command_64  fields; };
+template <> struct macho_encryption_info_content<Pointer32<LittleEndian> > { struct encryption_info_command            fields; };
+template <> struct macho_encryption_info_content<Pointer64<LittleEndian> > { struct encryption_info_command_64 fields; };
+
+
 template <typename P>
 class macho_encryption_info_command {
 public:
 template <typename P>
 class macho_encryption_info_command {
 public:
-       uint32_t                cmd() const                                             INLINE { return E::get32(fields.cmd); }
-       void                    set_cmd(uint32_t value)                 INLINE { E::set32(fields.cmd, value); }
+       uint32_t                cmd() const                                             INLINE { return E::get32(entry.fields.cmd); }
+       void                    set_cmd(uint32_t value)                 INLINE { E::set32(entry.fields.cmd, value); }
 
 
-       uint32_t                cmdsize() const                                 INLINE { return E::get32(fields.cmdsize); }
-       void                    set_cmdsize(uint32_t value)             INLINE { E::set32(fields.cmdsize, value); }
+       uint32_t                cmdsize() const                                 INLINE { return E::get32(entry.fields.cmdsize); }
+       void                    set_cmdsize(uint32_t value)             INLINE { E::set32(entry.fields.cmdsize, value); }
 
 
-       uint32_t                cryptoff() const                                INLINE { return E::get32(fields.cryptoff); }
-       void                    set_cryptoff(uint32_t value)    INLINE { E::set32(fields.cryptoff, value);  }
+       uint32_t                cryptoff() const                                INLINE { return E::get32(entry.fields.cryptoff); }
+       void                    set_cryptoff(uint32_t value)    INLINE { E::set32(entry.fields.cryptoff, value);  }
        
        
-       uint32_t                cryptsize() const                               INLINE { return E::get32(fields.cryptsize); }
-       void                    set_cryptsize(uint32_t value)   INLINE { E::set32(fields.cryptsize, value);  }
+       uint32_t                cryptsize() const                               INLINE { return E::get32(entry.fields.cryptsize); }
+       void                    set_cryptsize(uint32_t value)   INLINE { E::set32(entry.fields.cryptsize, value);  }
        
        
-       uint32_t                cryptid() const                                 INLINE { return E::get32(fields.cryptid); }
-       void                    set_cryptid(uint32_t value)             INLINE { E::set32(fields.cryptid, value);  }
+       uint32_t                cryptid() const                                 INLINE { return E::get32(entry.fields.cryptid); }
+       void                    set_cryptid(uint32_t value)             INLINE { E::set32(entry.fields.cryptid, value);  }
        
        
+       uint32_t                pad() const                                             INLINE { return E::get32(entry.fields.pad); }
+       void                    set_pad(uint32_t value)                 INLINE { E::set32(entry.fields.pad, value);  }
+
        typedef typename P::E           E;
 private:
        typedef typename P::E           E;
 private:
-       encryption_info_command fields;
+       macho_encryption_info_content<P>        entry;
 };
 
 
 };
 
 
@@ -1466,6 +1663,36 @@ private:
        data_in_code_entry      fields;
 };
 
        data_in_code_entry      fields;
 };
 
+#ifndef DICE_KIND_DATA
+  #define DICE_KIND_DATA              0x0001 
+  #define DICE_KIND_JUMP_TABLE8       0x0002 
+  #define DICE_KIND_JUMP_TABLE16      0x0003 
+  #define DICE_KIND_JUMP_TABLE32      0x0004 
+  #define DICE_KIND_ABS_JUMP_TABLE32  0x0005 
+#endif
+
+template <typename P>
+class macho_linker_option_command {
+public:
+       uint32_t                cmd() const                                                             INLINE { return E::get32(fields.cmd); }
+       void                    set_cmd(uint32_t value)                                 INLINE { E::set32(fields.cmd, value); }
+
+       uint32_t                cmdsize() const                                                 INLINE { return E::get32(fields.cmdsize); }
+       void                    set_cmdsize(uint32_t value)                             INLINE { E::set32(fields.cmdsize, value); }
+
+       uint64_t                count() const                                                   INLINE { return fields.count; }
+       void                    set_count(uint32_t value)                               INLINE { E::set32(fields.count, value); }
+
+       const char*             buffer() const                                                  INLINE { return ((char*)&fields) + sizeof(linker_option_command); }
+       char*                   buffer()                                                                INLINE { return ((char*)&fields) + sizeof(linker_option_command); }
+
+       typedef typename P::E           E;
+private:
+       linker_option_command   fields;
+};
+
+
+
 
 
 #endif // __MACH_O_FILE_ABSTRACTION__
 
 
 #endif // __MACH_O_FILE_ABSTRACTION__
index 447ec7af5e78599f208545b0a27cb6368f7307e2..aed4fa37e6748ddfab1e6afa644fbb7d5ccb7de1 100755 (executable)
@@ -11,17 +11,17 @@ else
 fi
 
 if [ -z "${RC_SUPPORTED_ARCHS}" ]; then
 fi
 
 if [ -z "${RC_SUPPORTED_ARCHS}" ]; then
-       RC_SUPPORTED_ARCHS="i386 x86_64 armv7 armv7s"
+       RC_SUPPORTED_ARCHS="i386 x86_64 armv7 armv7s arm64"
 fi
 
 for ANARCH in ${RC_SUPPORTED_ARCHS}
 do
 fi
 
 for ANARCH in ${RC_SUPPORTED_ARCHS}
 do
-       KNOWN_ARCHS=",armv4t,armv5,armv6,armv7,armv7f,armv7k,armv7s,i386,x86_64,"
+       KNOWN_ARCHS=",armv4t,armv5,armv6,armv7,armv7f,armv7k,armv7s,armv6m,armv7m,armv7em,armv8,arm64,arm64v8,i386,x86_64,"
        FOUND=`echo "$KNOWN_ARCHS" | grep ",$ANARCH,"`
        if [ $FOUND ]; then
                echo "#define SUPPORT_ARCH_$ANARCH  1" >> ${DERIVED_FILE_DIR}/configure.h
        else
        FOUND=`echo "$KNOWN_ARCHS" | grep ",$ANARCH,"`
        if [ $FOUND ]; then
                echo "#define SUPPORT_ARCH_$ANARCH  1" >> ${DERIVED_FILE_DIR}/configure.h
        else
-               echo "#error uknown architecture: $ANARCH" >> ${DERIVED_FILE_DIR}/configure.h
+               echo "#error unknown architecture: $ANARCH" >> ${DERIVED_FILE_DIR}/configure.h
        fi
 done
 
        fi
 done
 
index 11455505dd5c489b34cb4e1418cbad5878d6aa7c..fdf795b2d8bc4c7af2e14b7e96f4489394d7d88b 100644 (file)
@@ -56,6 +56,11 @@ struct arm
        typedef Pointer32<LittleEndian>         P;
 };
 
        typedef Pointer32<LittleEndian>         P;
 };
 
+struct arm64
+{
+       typedef Pointer64<LittleEndian>         P;
+};
+
 #endif // __ARCHITECTURES__
 
 
 #endif // __ARCHITECTURES__
 
 
index 088571530b81b9ec7f68ef075eba51c9a45f191b..35daef1de569ce2bba0da10190b3132bef5db4cd 100644 (file)
@@ -109,7 +109,8 @@ private:
        uint8_t*                                        copyDataInCodeLoadCommand(uint8_t* p) const;
        uint8_t*                                        copyDependentDRLoadCommand(uint8_t* p) const;
        uint8_t*                                        copyDyldEnvLoadCommand(uint8_t* p, const char* env) const;
        uint8_t*                                        copyDataInCodeLoadCommand(uint8_t* p) const;
        uint8_t*                                        copyDependentDRLoadCommand(uint8_t* p) const;
        uint8_t*                                        copyDyldEnvLoadCommand(uint8_t* p, const char* env) const;
-       
+       uint8_t*                                        copyLinkerOptionsLoadCommand(uint8_t* p, const std::vector<const char*>&) const;
+
        uint32_t                                        sectionFlags(ld::Internal::FinalSection* sect) const;
        bool                                            sectionTakesNoDiskSpace(ld::Internal::FinalSection* sect) const;
        
        uint32_t                                        sectionFlags(ld::Internal::FinalSection* sect) const;
        bool                                            sectionTakesNoDiskSpace(ld::Internal::FinalSection* sect) const;
        
@@ -143,6 +144,7 @@ private:
        std::vector<const char*>        _subUmbrellaNames;
        uint8_t                                         _uuid[16];
        mutable macho_uuid_command<P>*  _uuidCmdInOutputBuffer;
        std::vector<const char*>        _subUmbrellaNames;
        uint8_t                                         _uuid[16];
        mutable macho_uuid_command<P>*  _uuidCmdInOutputBuffer;
+       std::vector< std::vector<const char*> >  _linkerOptions;
        
        static ld::Section                      _s_section;
        static ld::Section                      _s_preload_section;
        
        static ld::Section                      _s_section;
        static ld::Section                      _s_preload_section;
@@ -192,6 +194,22 @@ HeaderAndLoadCommandsAtom<A>::HeaderAndLoadCommandsAtom(const Options& opts, ld:
                                        break;
                                }
                        }
                                        break;
                                }
                        }
+                       for (CStringSet::const_iterator it = _state.linkerOptionFrameworks.begin(); it != _state.linkerOptionFrameworks.end(); ++it) {
+                               const char* frameWorkName = *it;
+                               std::vector<const char*>* lo = new std::vector<const char*>();
+                               lo->push_back("-framework");
+                               lo->push_back(frameWorkName);
+                               _linkerOptions.push_back(*lo);
+                       };
+                       for (CStringSet::const_iterator it = _state.linkerOptionLibraries.begin(); it != _state.linkerOptionLibraries.end(); ++it) {
+                               const char* libName = *it;
+                               std::vector<const char*>* lo = new std::vector<const char*>();
+                               char * s = new char[strlen(libName)+3];
+                               strcpy(s, "-l");
+                               strcat(s, libName);
+                               lo->push_back(s);
+                               _linkerOptions.push_back(*lo);
+                       };
                        break;
                case Options::kStaticExecutable:
                        _hasDynamicSymbolTableLoadCommand = opts.positionIndependentExecutable();
                        break;
                case Options::kStaticExecutable:
                        _hasDynamicSymbolTableLoadCommand = opts.positionIndependentExecutable();
@@ -210,6 +228,7 @@ HeaderAndLoadCommandsAtom<A>::HeaderAndLoadCommandsAtom(const Options& opts, ld:
        _dylibLoadCommmandsCount = _writer.dylibCount();
        _allowableClientLoadCommmandsCount = _options.allowableClients().size();
        _dyldEnvironExrasCount = _options.dyldEnvironExtras().size();
        _dylibLoadCommmandsCount = _writer.dylibCount();
        _allowableClientLoadCommmandsCount = _options.allowableClients().size();
        _dyldEnvironExrasCount = _options.dyldEnvironExtras().size();
+       
        if ( ! _options.useSimplifiedDylibReExports() ) {
                // target OS does not support LC_REEXPORT_DYLIB, so use old complicated load commands
                for(uint32_t ord=1; ord <= _writer.dylibCount(); ++ord) {
        if ( ! _options.useSimplifiedDylibReExports() ) {
                // target OS does not support LC_REEXPORT_DYLIB, so use old complicated load commands
                for(uint32_t ord=1; ord <= _writer.dylibCount(); ++ord) {
@@ -394,6 +413,17 @@ uint64_t HeaderAndLoadCommandsAtom<A>::size() const
        if ( _hasDataInCodeLoadCommand )
                sz += sizeof(macho_linkedit_data_command<P>);
 
        if ( _hasDataInCodeLoadCommand )
                sz += sizeof(macho_linkedit_data_command<P>);
 
+       if ( !_linkerOptions.empty() ) {
+               for (ld::relocatable::File::LinkerOptionsList::const_iterator it = _linkerOptions.begin(); it != _linkerOptions.end(); ++it) {
+                       uint32_t s = sizeof(macho_linker_option_command<P>);
+                       const std::vector<const char*>& options = *it;
+                       for (std::vector<const char*>::const_iterator t=options.begin(); t != options.end(); ++t) {
+                               s += (strlen(*t) + 1);
+                       }
+                       sz += alignedSize(s);
+               }
+       }
+       
        if ( _hasDependentDRInfo ) 
                sz += sizeof(macho_linkedit_data_command<P>);
                
        if ( _hasDependentDRInfo ) 
                sz += sizeof(macho_linkedit_data_command<P>);
                
@@ -465,6 +495,12 @@ uint32_t HeaderAndLoadCommandsAtom<A>::commandsCount() const
        if ( _hasDataInCodeLoadCommand )
                ++count;
 
        if ( _hasDataInCodeLoadCommand )
                ++count;
 
+       if ( !_linkerOptions.empty() ) {
+               for (ld::relocatable::File::LinkerOptionsList::const_iterator it = _linkerOptions.begin(); it != _linkerOptions.end(); ++it) {
+                       ++count;
+               }
+       }
+
        if ( _hasDependentDRInfo ) 
                ++count;
                
        if ( _hasDependentDRInfo ) 
                ++count;
                
@@ -556,10 +592,12 @@ uint32_t HeaderAndLoadCommandsAtom<A>::flags() const
 template <> uint32_t HeaderAndLoadCommandsAtom<x86>::magic() const             { return MH_MAGIC; }
 template <> uint32_t HeaderAndLoadCommandsAtom<x86_64>::magic() const  { return MH_MAGIC_64; }
 template <> uint32_t HeaderAndLoadCommandsAtom<arm>::magic() const             { return MH_MAGIC; }
 template <> uint32_t HeaderAndLoadCommandsAtom<x86>::magic() const             { return MH_MAGIC; }
 template <> uint32_t HeaderAndLoadCommandsAtom<x86_64>::magic() const  { return MH_MAGIC_64; }
 template <> uint32_t HeaderAndLoadCommandsAtom<arm>::magic() const             { return MH_MAGIC; }
+template <> uint32_t HeaderAndLoadCommandsAtom<arm64>::magic() const           { return MH_MAGIC_64; }
 
 template <> uint32_t HeaderAndLoadCommandsAtom<x86>::cpuType() const   { return CPU_TYPE_I386; }
 template <> uint32_t HeaderAndLoadCommandsAtom<x86_64>::cpuType() const        { return CPU_TYPE_X86_64; }
 template <> uint32_t HeaderAndLoadCommandsAtom<arm>::cpuType() const   { return CPU_TYPE_ARM; }
 
 template <> uint32_t HeaderAndLoadCommandsAtom<x86>::cpuType() const   { return CPU_TYPE_I386; }
 template <> uint32_t HeaderAndLoadCommandsAtom<x86_64>::cpuType() const        { return CPU_TYPE_X86_64; }
 template <> uint32_t HeaderAndLoadCommandsAtom<arm>::cpuType() const   { return CPU_TYPE_ARM; }
+template <> uint32_t HeaderAndLoadCommandsAtom<arm64>::cpuType() const { return CPU_TYPE_ARM64; }
 
 
 
 
 
 
@@ -584,6 +622,12 @@ uint32_t HeaderAndLoadCommandsAtom<arm>::cpuSubType() const
        return _state.cpuSubType;
 }
 
        return _state.cpuSubType;
 }
 
+template <>
+uint32_t HeaderAndLoadCommandsAtom<arm64>::cpuSubType() const
+{
+       return CPU_SUBTYPE_ARM64_ALL;
+}
+
 
 
 template <typename A>
 
 
 template <typename A>
@@ -1144,6 +1188,28 @@ uint8_t* HeaderAndLoadCommandsAtom<arm>::copyThreadsLoadCommand(uint8_t* p) cons
 }
 
 
 }
 
 
+template <>
+uint32_t HeaderAndLoadCommandsAtom<arm64>::threadLoadCommandSize() const
+{
+       return this->alignedSize(16 + 34 * 8); // base size + ARM_EXCEPTION_STATE64_COUNT * 4
+}
+
+template <>
+uint8_t* HeaderAndLoadCommandsAtom<arm64>::copyThreadsLoadCommand(uint8_t* p) const
+{
+       assert(_state.entryPoint != NULL);
+       pint_t start = _state.entryPoint->finalAddress(); 
+       macho_thread_command<P>* cmd = (macho_thread_command<P>*)p;
+       cmd->set_cmd(LC_UNIXTHREAD);
+       cmd->set_cmdsize(threadLoadCommandSize());
+       cmd->set_flavor(6);      // ARM_THREAD_STATE64
+       cmd->set_count(68);      // ARM_EXCEPTION_STATE64_COUNT
+       cmd->set_thread_register(32, start);            // pc 
+       if ( _options.hasCustomStack() )
+               cmd->set_thread_register(31, _options.customStackAddr());       // sp 
+       return p + threadLoadCommandSize();
+}
+
 
 template <typename A>
 uint8_t* HeaderAndLoadCommandsAtom<A>::copyEntryPointLoadCommand(uint8_t* p) const
 
 template <typename A>
 uint8_t* HeaderAndLoadCommandsAtom<A>::copyEntryPointLoadCommand(uint8_t* p) const
@@ -1165,7 +1231,7 @@ template <typename A>
 uint8_t* HeaderAndLoadCommandsAtom<A>::copyEncryptionLoadCommand(uint8_t* p) const
 {
        macho_encryption_info_command<P>* cmd = (macho_encryption_info_command<P>*)p;
 uint8_t* HeaderAndLoadCommandsAtom<A>::copyEncryptionLoadCommand(uint8_t* p) const
 {
        macho_encryption_info_command<P>* cmd = (macho_encryption_info_command<P>*)p;
-       cmd->set_cmd(LC_ENCRYPTION_INFO);
+       cmd->set_cmd(sizeof(typename A::P::uint_t) == 4 ? LC_ENCRYPTION_INFO : LC_ENCRYPTION_INFO_64);
        cmd->set_cmdsize(sizeof(macho_encryption_info_command<P>));
        assert(_writer.encryptedTextStartOffset() != 0);
        assert(_writer.encryptedTextEndOffset() != 0);
        cmd->set_cmdsize(sizeof(macho_encryption_info_command<P>));
        assert(_writer.encryptedTextStartOffset() != 0);
        assert(_writer.encryptedTextEndOffset() != 0);
@@ -1310,6 +1376,27 @@ uint8_t* HeaderAndLoadCommandsAtom<A>::copyDataInCodeLoadCommand(uint8_t* p) con
 }
 
 
 }
 
 
+template <typename A>
+uint8_t* HeaderAndLoadCommandsAtom<A>::copyLinkerOptionsLoadCommand(uint8_t* p, const std::vector<const char*>& options) const
+{
+       macho_linker_option_command<P>* cmd = (macho_linker_option_command<P>*)p;
+       cmd->set_cmd(LC_LINKER_OPTION);
+       cmd->set_count(options.size());
+       char* buffer = cmd->buffer();
+       uint32_t sz = sizeof(macho_linker_option_command<P>);
+       for (std::vector<const char*>::const_iterator it=options.begin(); it != options.end(); ++it) {
+               const char* opt = *it;
+               uint32_t len = strlen(opt);
+               strcpy(buffer, opt);
+               sz += (len + 1);
+               buffer += (len + 1);
+       }
+       sz = alignedSize(sz);
+       cmd->set_cmdsize(sz);   
+       return p + sz;
+}
+
+
 template <typename A>
 uint8_t* HeaderAndLoadCommandsAtom<A>::copyDependentDRLoadCommand(uint8_t* p) const
 {
 template <typename A>
 uint8_t* HeaderAndLoadCommandsAtom<A>::copyDependentDRLoadCommand(uint8_t* p) const
 {
@@ -1384,7 +1471,7 @@ void HeaderAndLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
        if ( _hasSplitSegInfoLoadCommand )
                p = this->copySplitSegInfoLoadCommand(p);
                
        if ( _hasSplitSegInfoLoadCommand )
                p = this->copySplitSegInfoLoadCommand(p);
                
-       for(uint32_t ord=1; ord <= _writer.dylibCount(); ++ord) {
+       for (uint32_t ord=1; ord <= _writer.dylibCount(); ++ord) {
                p = this->copyDylibLoadCommand(p, _writer.dylibByOrdinal(ord));
        }
 
                p = this->copyDylibLoadCommand(p, _writer.dylibByOrdinal(ord));
        }
 
@@ -1425,6 +1512,12 @@ void HeaderAndLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
 
        if ( _hasDataInCodeLoadCommand )
                p = this->copyDataInCodeLoadCommand(p);
 
        if ( _hasDataInCodeLoadCommand )
                p = this->copyDataInCodeLoadCommand(p);
+
+       if ( !_linkerOptions.empty() ) {
+               for (ld::relocatable::File::LinkerOptionsList::const_iterator it = _linkerOptions.begin(); it != _linkerOptions.end(); ++it) {
+                       p = this->copyLinkerOptionsLoadCommand(p, *it);
+               }
+       }
        
        if ( _hasDependentDRInfo ) 
                p = this->copyDependentDRLoadCommand(p);
        
        if ( _hasDependentDRInfo ) 
                p = this->copyDependentDRLoadCommand(p);
index 7bf136bd848474e9e1677625645d1f53b7f27d6e..a4b256fa2b16ea3282e0179a5a5f4af6a683c7eb 100644 (file)
@@ -1,3 +1,4 @@
+
 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-*
  *
  * Copyright (c) 2009-2011 Apple Inc. All rights reserved.
 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-*
  *
  * Copyright (c) 2009-2011 Apple Inc. All rights reserved.
@@ -60,6 +61,7 @@
 #include "archive_file.h"
 #include "lto_file.h"
 #include "opaque_section_file.h"
 #include "archive_file.h"
 #include "lto_file.h"
 #include "opaque_section_file.h"
+#include "MachOFileAbstraction.hpp"
 #include "Snapshot.h"
 
 const bool _s_logPThreads = false;
 #include "Snapshot.h"
 
 const bool _s_logPThreads = false;
@@ -180,7 +182,11 @@ const char* InputFiles::fileArch(const uint8_t* p, unsigned len)
        const char* result = mach_o::relocatable::archName(p);
        if ( result != NULL  )
                 return result;
        const char* result = mach_o::relocatable::archName(p);
        if ( result != NULL  )
                 return result;
-                
+
+    result = mach_o::dylib::archName(p);
+    if ( result != NULL  )
+               return result;
+
        result = lto::archName(p, len);
        if ( result != NULL  )
                 return result;
        result = lto::archName(p, len);
        if ( result != NULL  )
                 return result;
@@ -192,7 +198,7 @@ const char* InputFiles::fileArch(const uint8_t* p, unsigned len)
        strcpy(unsupported, "unsupported file format (");
        for (unsigned i=0; i<len && i < 16; i++) {
                char buf[8];
        strcpy(unsupported, "unsupported file format (");
        for (unsigned i=0; i<len && i < 16; i++) {
                char buf[8];
-               sprintf(buf, " 0x%2x", p[i]);
+               sprintf(buf, " 0x%02X", p[i]);
                strcat(unsupported, buf);
        }
        strcat(unsupported, " )");
                strcat(unsupported, buf);
        }
        strcat(unsupported, " )");
@@ -208,7 +214,7 @@ ld::File* InputFiles::makeFile(const Options::FileInfo& info, bool indirectDylib
        if ( fd == -1 )
                throwf("can't open file, errno=%d", errno);
        if ( info.fileLen < 20 )
        if ( fd == -1 )
                throwf("can't open file, errno=%d", errno);
        if ( info.fileLen < 20 )
-               throw "file too small";
+               throwf("file too small (length=%llu)", info.fileLen);
 
        uint8_t* p = (uint8_t*)::mmap(NULL, info.fileLen, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, 0);
        if ( p == (uint8_t*)(-1) )
 
        uint8_t* p = (uint8_t*)::mmap(NULL, info.fileLen, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, 0);
        if ( p == (uint8_t*)(-1) )
@@ -273,7 +279,9 @@ ld::File* InputFiles::makeFile(const Options::FileInfo& info, bool indirectDylib
        objOpts.architecture            = _options.architecture();
        objOpts.objSubtypeMustMatch = !_options.allowSubArchitectureMismatches();
        objOpts.logAllFiles                     = _options.logAllFiles();
        objOpts.architecture            = _options.architecture();
        objOpts.objSubtypeMustMatch = !_options.allowSubArchitectureMismatches();
        objOpts.logAllFiles                     = _options.logAllFiles();
-       objOpts.convertUnwindInfo       = _options.needsUnwindInfoSection();
+       objOpts.warnUnwindConversionProblems    = _options.needsUnwindInfoSection();
+       objOpts.keepDwarfUnwind         = _options.keepDwarfUnwind();
+       objOpts.forceDwarfConversion= (_options.outputKind() == Options::kDyld);
        objOpts.subType                         = _options.subArchitecture();
        ld::relocatable::File* objResult = mach_o::relocatable::parse(p, len, info.path, info.modTime, info.ordinal, objOpts);
        if ( objResult != NULL ) {
        objOpts.subType                         = _options.subArchitecture();
        ld::relocatable::File* objResult = mach_o::relocatable::parse(p, len, info.path, info.modTime, info.ordinal, objOpts);
        if ( objResult != NULL ) {
@@ -365,12 +373,31 @@ void InputFiles::logDylib(ld::File* file, bool indirect)
                        logTraceInfo("[Logging for XBS] Used upward dynamic library: %s\n", fullPath);
                }
                else {
                        logTraceInfo("[Logging for XBS] Used upward dynamic library: %s\n", fullPath);
                }
                else {
-                       if ( indirect )
+                       if ( indirect ) 
                                logTraceInfo("[Logging for XBS] Used indirect dynamic library: %s\n", fullPath);
                                logTraceInfo("[Logging for XBS] Used indirect dynamic library: %s\n", fullPath);
-                       else
+                       else 
                                logTraceInfo("[Logging for XBS] Used dynamic library: %s\n", fullPath);
                }
        }
                                logTraceInfo("[Logging for XBS] Used dynamic library: %s\n", fullPath);
                }
        }
+       
+       if ( _options.dumpDependencyInfo() ) {
+               const ld::dylib::File* dylib = dynamic_cast<const ld::dylib::File*>(file);
+               if ( file == _bundleLoader ) {
+                       _options.dumpDependency(Options::depBundleLoader, file->path());
+               }
+               else if ( (dylib != NULL ) && dylib->willBeUpwardDylib() ) {
+                       if ( indirect ) 
+                               _options.dumpDependency(Options::depUpwardIndirectDylib, file->path());
+                       else 
+                               _options.dumpDependency(Options::depUpwardDirectDylib, file->path());
+               }
+               else {
+                       if ( indirect ) 
+                               _options.dumpDependency(Options::depIndirectDylib, file->path());
+                       else 
+                               _options.dumpDependency(Options::depDirectDylib, file->path());
+               }
+       }
 }
 
 void InputFiles::logArchive(ld::File* file) const
 }
 
 void InputFiles::logArchive(ld::File* file) const
@@ -396,7 +423,7 @@ void InputFiles::logTraceInfo(const char* format, ...) const
                if ( trace_file_path != NULL ) {
                        trace_file = open(trace_file_path, O_WRONLY | O_APPEND | O_CREAT, 0666);
                        if ( trace_file == -1 )
                if ( trace_file_path != NULL ) {
                        trace_file = open(trace_file_path, O_WRONLY | O_APPEND | O_CREAT, 0666);
                        if ( trace_file == -1 )
-                               throwf("Could not open or create trace file: %s", trace_file_path);
+                               throwf("Could not open or create trace file (errno=%d): %s", errno, trace_file_path);
                }
                else {
                        trace_file = fileno(stderr);
                }
                else {
                        trace_file = fileno(stderr);
@@ -420,6 +447,7 @@ void InputFiles::logTraceInfo(const char* format, ...) const
        }
 }
 
        }
 }
 
+
 ld::dylib::File* InputFiles::findDylib(const char* installPath, const char* fromPath)
 {
        //fprintf(stderr, "findDylib(%s, %s)\n", installPath, fromPath);
 ld::dylib::File* InputFiles::findDylib(const char* installPath, const char* fromPath)
 {
        //fprintf(stderr, "findDylib(%s, %s)\n", installPath, fromPath);
@@ -435,6 +463,7 @@ ld::dylib::File* InputFiles::findDylib(const char* installPath, const char* from
                                        Options::FileInfo info = _options.findFile(dit->useInstead);
                                        _indirectDylibOrdinal = _indirectDylibOrdinal.nextIndirectDylibOrdinal();
                                        info.ordinal = _indirectDylibOrdinal;
                                        Options::FileInfo info = _options.findFile(dit->useInstead);
                                        _indirectDylibOrdinal = _indirectDylibOrdinal.nextIndirectDylibOrdinal();
                                        info.ordinal = _indirectDylibOrdinal;
+                                       info.options.fIndirectDylib = true;
                                        ld::File* reader = this->makeFile(info, true);
                                        ld::dylib::File* dylibReader = dynamic_cast<ld::dylib::File*>(reader);
                                        if ( dylibReader != NULL ) {
                                        ld::File* reader = this->makeFile(info, true);
                                        ld::dylib::File* dylibReader = dynamic_cast<ld::dylib::File*>(reader);
                                        if ( dylibReader != NULL ) {
@@ -467,6 +496,7 @@ ld::dylib::File* InputFiles::findDylib(const char* installPath, const char* from
                Options::FileInfo info = _options.findFileUsingPaths(installPath);
                _indirectDylibOrdinal = _indirectDylibOrdinal.nextIndirectDylibOrdinal();
                info.ordinal = _indirectDylibOrdinal;
                Options::FileInfo info = _options.findFileUsingPaths(installPath);
                _indirectDylibOrdinal = _indirectDylibOrdinal.nextIndirectDylibOrdinal();
                info.ordinal = _indirectDylibOrdinal;
+               info.options.fIndirectDylib = true;
                try {
                        ld::File* reader = this->makeFile(info, true);
                        ld::dylib::File* dylibReader = dynamic_cast<ld::dylib::File*>(reader);
                try {
                        ld::File* reader = this->makeFile(info, true);
                        ld::dylib::File* dylibReader = dynamic_cast<ld::dylib::File*>(reader);
@@ -487,18 +517,86 @@ ld::dylib::File* InputFiles::findDylib(const char* installPath, const char* from
 }
 
 
 }
 
 
-
-void InputFiles::createIndirectDylibs()
-{
-       _allDirectDylibsLoaded = true;
-       _indirectDylibOrdinal = ld::File::Ordinal::indirectDylibBase();
-       
-       // mark all dylibs initially specified as required and check if they can be used
+// mark all dylibs initially specified as required, and check if they can be used
+void InputFiles::markExplicitlyLinkedDylibs()
+{      
        for (InstallNameToDylib::iterator it=_installPathToDylibs.begin(); it != _installPathToDylibs.end(); it++) {
                it->second->setExplicitlyLinked();
                this->checkDylibClientRestrictions(it->second);
        }
        for (InstallNameToDylib::iterator it=_installPathToDylibs.begin(); it != _installPathToDylibs.end(); it++) {
                it->second->setExplicitlyLinked();
                this->checkDylibClientRestrictions(it->second);
        }
-       
+}
+
+bool InputFiles::libraryAlreadyLoaded(const char* path) 
+{
+       for (std::vector<ld::File*>::const_iterator it = _inputFiles.begin(); it != _inputFiles.end(); ++it) {
+               if ( strcmp(path, (*it)->path()) == 0 )
+                       return true;
+       }
+       return false;
+}
+
+
+void InputFiles::addLinkerOptionLibraries(ld::Internal& state)
+{      
+    if ( _options.outputKind() == Options::kObjectFile ) 
+               return;
+
+       // process frameworks specified in .o linker options
+       for (CStringSet::const_iterator it = state.linkerOptionFrameworks.begin(); it != state.linkerOptionFrameworks.end(); ++it) {
+               const char* frameworkName = *it;
+               Options::FileInfo info = _options.findFramework(frameworkName);
+               if ( ! this->libraryAlreadyLoaded(info.path) ) {
+                       info.ordinal = _linkerOptionOrdinal.nextLinkerOptionOrdinal();
+                       try {
+                               ld::File* reader = this->makeFile(info, true);
+                               ld::dylib::File* dylibReader = dynamic_cast<ld::dylib::File*>(reader);
+                               if ( dylibReader != NULL ) {
+                                       if ( ! dylibReader->installPathVersionSpecific() ) {
+                                               dylibReader->setImplicitlyLinked();
+                                               this->addDylib(dylibReader, info);
+                                       }
+                               }
+                               else {
+                                       throwf("framework linker option at %s is not a dylib", info.path);
+                               }
+                       }
+                       catch (const char* msg) {
+                               throwf("in '%s', %s", info.path, msg);
+                       }
+               }
+       }
+       // process libraries specified in .o linker options
+       for (CStringSet::const_iterator it = state.linkerOptionLibraries.begin(); it != state.linkerOptionLibraries.end(); ++it) {
+               const char* libName = *it;
+               Options::FileInfo info = _options.findLibrary(libName);
+               if ( ! this->libraryAlreadyLoaded(info.path) ) {
+                       info.ordinal = _linkerOptionOrdinal.nextLinkerOptionOrdinal();
+                       try {
+                               ld::File* reader = this->makeFile(info, true);
+                               ld::dylib::File* dylibReader = dynamic_cast<ld::dylib::File*>(reader);
+                               ld::archive::File* archiveReader = dynamic_cast<ld::archive::File*>(reader);
+                               if ( dylibReader != NULL ) {
+                                       dylibReader->setImplicitlyLinked();
+                                       this->addDylib(dylibReader, info);
+                               }
+                               else if ( archiveReader != NULL ) {
+                                       _searchLibraries.push_back(LibraryInfo(archiveReader));
+                                       if ( _options.dumpDependencyInfo() )
+                                               _options.dumpDependency(Options::depArchive, archiveReader->path());
+                               }
+                               else {
+                                       throwf("linker option dylib at %s is not a dylib", info.path);
+                               }
+                       }
+                       catch (const char* msg) {
+                               throwf("in '%s', %s", info.path, msg);
+                       }
+               }
+       }
+}
+
+void InputFiles::createIndirectDylibs()
+{      
        // keep processing dylibs until no more dylibs are added
        unsigned long lastMapSize = 0;
        std::set<ld::dylib::File*>  dylibsProcessed;
        // keep processing dylibs until no more dylibs are added
        unsigned long lastMapSize = 0;
        std::set<ld::dylib::File*>  dylibsProcessed;
@@ -539,9 +637,11 @@ void InputFiles::createIndirectDylibs()
 
 void InputFiles::createOpaqueFileSections()
 {
 
 void InputFiles::createOpaqueFileSections()
 {
-       // extra command line section always at end
+       // extra command line sections always at end
        for (Options::ExtraSection::const_iterator it=_options.extraSectionsBegin(); it != _options.extraSectionsEnd(); ++it) {
                _inputFiles.push_back(opaque_section::parse(it->segmentName, it->sectionName, it->path, it->data, it->dataLen));
        for (Options::ExtraSection::const_iterator it=_options.extraSectionsBegin(); it != _options.extraSectionsEnd(); ++it) {
                _inputFiles.push_back(opaque_section::parse(it->segmentName, it->sectionName, it->path, it->data, it->dataLen));
+               if ( _options.dumpDependencyInfo() )
+                       _options.dumpDependency(Options::depSection, it->path);
        }
 
 }
        }
 
 }
@@ -672,8 +772,10 @@ InputFiles::InputFiles(Options& opts, const char** archName)
  : _totalObjectSize(0), _totalArchiveSize(0), 
    _totalObjectLoaded(0), _totalArchivesLoaded(0), _totalDylibsLoaded(0),
        _options(opts), _bundleLoader(NULL), 
  : _totalObjectSize(0), _totalArchiveSize(0), 
    _totalObjectLoaded(0), _totalArchivesLoaded(0), _totalDylibsLoaded(0),
        _options(opts), _bundleLoader(NULL), 
-       _allDirectDylibsLoaded(false), _inferredArch(false),
-       _exception(NULL)
+       _inferredArch(false),
+       _exception(NULL), 
+       _indirectDylibOrdinal(ld::File::Ordinal::indirectDylibBase()),
+       _linkerOptionOrdinal(ld::File::Ordinal::linkeOptionBase())
 {
 //     fStartCreateReadersTime = mach_absolute_time();
        if ( opts.architecture() == 0 ) {
 {
 //     fStartCreateReadersTime = mach_absolute_time();
        if ( opts.architecture() == 0 ) {
@@ -781,7 +883,8 @@ void InputFiles::parseWorkerThread() {
                        if (_s_logPThreads) printf("parsing index %u\n", slot);
                        try {
                                file = makeFile(entry, false);
                        if (_s_logPThreads) printf("parsing index %u\n", slot);
                        try {
                                file = makeFile(entry, false);
-                       } catch (const char *msg) {
+                       } 
+                       catch (const char *msg) {
                                if ( (strstr(msg, "architecture") != NULL) && !_options.errorOnOtherArchFiles() ) {
                                        if ( _options.ignoreOtherArchInputFiles() ) {
                                                // ignore, because this is about an architecture not in use
                                if ( (strstr(msg, "architecture") != NULL) && !_options.errorOnOtherArchFiles() ) {
                                        if ( _options.ignoreOtherArchInputFiles() ) {
                                                // ignore, because this is about an architecture not in use
@@ -789,8 +892,9 @@ void InputFiles::parseWorkerThread() {
                                        else {
                                                warning("ignoring file %s, %s", entry.path, msg);
                                        }
                                        else {
                                                warning("ignoring file %s, %s", entry.path, msg);
                                        }
-                               } else {
-                                       exception = msg;
+                               } 
+                               else {
+                                       asprintf((char**)&exception, "%s file '%s'", msg, entry.path);
                                }
                                file = new IgnoredFile(entry.path, entry.modTime, entry.ordinal, ld::File::Other);
                        }
                                }
                                file = new IgnoredFile(entry.path, entry.modTime, entry.ordinal, ld::File::Other);
                        }
@@ -802,7 +906,8 @@ void InputFiles::parseWorkerThread() {
                                // We are about to die, so set to zero to stop other threads from doing unneeded work.
                                _remainingInputFiles = 0;
                                _exception = exception;
                                // We are about to die, so set to zero to stop other threads from doing unneeded work.
                                _remainingInputFiles = 0;
                                _exception = exception;
-                       } else {
+                       } 
+                       else {
                                _inputFiles[slot] = file;
                                if (_neededFileSlot == slot)
                                        pthread_cond_signal(&_newFileAvailable);
                                _inputFiles[slot] = file;
                                if (_neededFileSlot == slot)
                                        pthread_cond_signal(&_newFileAvailable);
@@ -867,22 +972,23 @@ ld::File* InputFiles::addDylib(ld::dylib::File* reader, const Options::FileInfo&
                        }
                        // remove warning for <rdar://problem/10860629> Same install name for CoreServices and CFNetwork?
                        //if ( !dylibOnCommandLineTwice && !isSymlink )
                        }
                        // remove warning for <rdar://problem/10860629> Same install name for CoreServices and CFNetwork?
                        //if ( !dylibOnCommandLineTwice && !isSymlink )
-                       //      warning("dylibs with same install name: %s and %s", pos->second->path(), reader->path());
+                       //      warning("dylibs with same install name: %p %s and %p %s", pos->second, pos->second->path(), reader, reader->path());
                }
        }
        else if ( info.options.fBundleLoader )
                _bundleLoader = reader;
 
        // log direct readers
                }
        }
        else if ( info.options.fBundleLoader )
                _bundleLoader = reader;
 
        // log direct readers
-       if ( !_allDirectDylibsLoaded ) 
+       if ( ! info.options.fIndirectDylib ) 
                this->logDylib(reader, false);
 
        // update stats
        _totalDylibsLoaded++;
 
        // just add direct libraries to search-first list
                this->logDylib(reader, false);
 
        // update stats
        _totalDylibsLoaded++;
 
        // just add direct libraries to search-first list
-       if ( !_allDirectDylibsLoaded ) 
+       if ( ! info.options.fIndirectDylib ) 
                _searchLibraries.push_back(LibraryInfo(reader));
                _searchLibraries.push_back(LibraryInfo(reader));
+       
        return reader;
 }
 
        return reader;
 }
 
@@ -918,7 +1024,7 @@ void InputFiles::waitForInputFiles()
                        if (it == fileMap.end())
                                throwf("pipelined linking error - not in file list: %s\n", path_buf);
                        Options::FileInfo* inputInfo = (Options::FileInfo*)it->second;
                        if (it == fileMap.end())
                                throwf("pipelined linking error - not in file list: %s\n", path_buf);
                        Options::FileInfo* inputInfo = (Options::FileInfo*)it->second;
-                       if (!inputInfo->checkFileExists())
+                       if (!inputInfo->checkFileExists(_options))
                                throwf("pipelined linking error - file does not exist: %s\n", inputInfo->path);
                        pthread_mutex_lock(&_parseLock);
                        if (_idleWorkers)
                                throwf("pipelined linking error - file does not exist: %s\n", inputInfo->path);
                        pthread_mutex_lock(&_parseLock);
                        if (_idleWorkers)
@@ -946,7 +1052,7 @@ void InputFiles::waitForInputFiles(InputFiles *inputFiles) {
 #endif
 
 
 #endif
 
 
-void InputFiles::forEachInitialAtom(ld::File::AtomHandler& handler)
+void InputFiles::forEachInitialAtom(ld::File::AtomHandler& handler, ld::Internal& state)
 {
        // add all direct object, archives, and dylibs
        const std::vector<Options::FileInfo>& files = _options.getInputFiles();
 {
        // add all direct object, archives, and dylibs
        const std::vector<Options::FileInfo>& files = _options.getInputFiles();
@@ -986,6 +1092,8 @@ void InputFiles::forEachInitialAtom(ld::File::AtomHandler& handler)
                        {
                                ld::relocatable::File* reloc = (ld::relocatable::File*)file;
                                _options.snapshot().recordObjectFile(reloc->path());
                        {
                                ld::relocatable::File* reloc = (ld::relocatable::File*)file;
                                _options.snapshot().recordObjectFile(reloc->path());
+                               if ( _options.dumpDependencyInfo() )
+                                       _options.dumpDependency(Options::depObjectFile, reloc->path());
                        }
                                break;
                        case ld::File::Dylib:
                        }
                                break;
                        case ld::File::Dylib:
@@ -1001,6 +1109,8 @@ void InputFiles::forEachInitialAtom(ld::File::AtomHandler& handler)
                                if ( (info.options.fForceLoad || _options.fullyLoadArchives()) && _options.traceArchives() ) 
                                        logArchive(archive);
                                _searchLibraries.push_back(LibraryInfo(archive));
                                if ( (info.options.fForceLoad || _options.fullyLoadArchives()) && _options.traceArchives() ) 
                                        logArchive(archive);
                                _searchLibraries.push_back(LibraryInfo(archive));
+                               if ( _options.dumpDependencyInfo() )
+                                       _options.dumpDependency(Options::depArchive, archive->path());
                        }
                                break;
                        case ld::File::Other:
                        }
                                break;
                        case ld::File::Other:
@@ -1014,6 +1124,8 @@ void InputFiles::forEachInitialAtom(ld::File::AtomHandler& handler)
                file->forEachAtom(handler);
        }
 
                file->forEachAtom(handler);
        }
 
+       markExplicitlyLinkedDylibs();
+       addLinkerOptionLibraries(state);
        createIndirectDylibs();
        createOpaqueFileSections();
        
        createIndirectDylibs();
        createOpaqueFileSections();
        
@@ -1095,7 +1207,7 @@ bool InputFiles::searchLibraries(const char* name, bool searchDylibs, bool searc
                             logArchive(archiveFile);
                         _options.snapshot().recordArchive(archiveFile->path());
                         // found data definition in static library, done
                             logArchive(archiveFile);
                         _options.snapshot().recordArchive(archiveFile->path());
                         // found data definition in static library, done
-                        return true;
+                       return true;
                     }
                 }
                 else {
                     }
                 }
                 else {
@@ -1145,7 +1257,7 @@ bool InputFiles::searchLibraries(const char* name, bool searchDylibs, bool searc
 
 bool InputFiles::searchWeakDefInDylib(const char* name) const
 {
 
 bool InputFiles::searchWeakDefInDylib(const char* name) const
 {
-       // search all relevant dylibs to see if any of a weak-def with this name
+       // search all relevant dylibs to see if any have a weak-def with this name
        for (InstallNameToDylib::const_iterator it=_installPathToDylibs.begin(); it != _installPathToDylibs.end(); ++it) {
                ld::dylib::File* dylibFile = it->second;
                if ( dylibFile->implicitlyLinked() || dylibFile->explicitlyLinked() ) {
        for (InstallNameToDylib::const_iterator it=_installPathToDylibs.begin(); it != _installPathToDylibs.end(); ++it) {
                ld::dylib::File* dylibFile = it->second;
                if ( dylibFile->implicitlyLinked() || dylibFile->explicitlyLinked() ) {
@@ -1224,4 +1336,3 @@ void InputFiles::dylibs(ld::Internal& state)
 } // namespace tool 
 } // namespace ld 
 
 } // namespace tool 
 } // namespace ld 
 
-
index 9b969ee34aefa674ffb72c38912999ed426c386f..3c55d4539336c43240225cf1c1b6c6f1830e92ff 100644 (file)
@@ -63,7 +63,7 @@ public:
        virtual ld::dylib::File*        findDylib(const char* installPath, const char* fromPath);
        
        // iterates all atoms in initial files
        virtual ld::dylib::File*        findDylib(const char* installPath, const char* fromPath);
        
        // iterates all atoms in initial files
-       void                                            forEachInitialAtom(ld::File::AtomHandler&);
+       void                                            forEachInitialAtom(ld::File::AtomHandler&, ld::Internal& state);
        // searches libraries for name
        bool                                            searchLibraries(const char* name, bool searchDylibs, bool searchArchives,  
                                                                                                                                  bool dataSymbolOnly, ld::File::AtomHandler&) const;
        // searches libraries for name
        bool                                            searchLibraries(const char* name, bool searchDylibs, bool searchArchives,  
                                                                                                                                  bool dataSymbolOnly, ld::File::AtomHandler&) const;
@@ -90,12 +90,15 @@ private:
        void                                            logTraceInfo (const char* format, ...) const;
        void                                            logDylib(ld::File*, bool indirect);
        void                                            logArchive(ld::File*) const;
        void                                            logTraceInfo (const char* format, ...) const;
        void                                            logDylib(ld::File*, bool indirect);
        void                                            logArchive(ld::File*) const;
+       void                                            markExplicitlyLinkedDylibs();
        void                                            createIndirectDylibs();
        void                                            checkDylibClientRestrictions(ld::dylib::File*);
        void                                            createOpaqueFileSections();
        void                                            createIndirectDylibs();
        void                                            checkDylibClientRestrictions(ld::dylib::File*);
        void                                            createOpaqueFileSections();
+       void                                            addLinkerOptionLibraries(ld::Internal& state);
+       bool                                            libraryAlreadyLoaded(const char* path);
        
        // for pipelined linking
        
        // for pipelined linking
-    void                      waitForInputFiles();
+    void                                               waitForInputFiles();
        static void                                     waitForInputFiles(InputFiles *inputFiles);
 
        // for threaded input file processing
        static void                                     waitForInputFiles(InputFiles *inputFiles);
 
        // for threaded input file processing
@@ -111,7 +114,6 @@ private:
        InstallNameToDylib                      _installPathToDylibs;
        std::set<ld::dylib::File*>      _allDylibs;
        ld::dylib::File*                        _bundleLoader;
        InstallNameToDylib                      _installPathToDylibs;
        std::set<ld::dylib::File*>      _allDylibs;
        ld::dylib::File*                        _bundleLoader;
-       bool                                            _allDirectDylibsLoaded;
        bool                                            _inferredArch;
     struct strcompclass {
         bool operator() (const char *a, const char *b) const { return ::strcmp(a, b) < 0; }
        bool                                            _inferredArch;
     struct strcompclass {
         bool operator() (const char *a, const char *b) const { return ::strcmp(a, b) < 0; }
@@ -132,6 +134,7 @@ private:
        int                                                     _remainingInputFiles;   // number of input files still to parse
        
        ld::File::Ordinal                       _indirectDylibOrdinal;
        int                                                     _remainingInputFiles;   // number of input files still to parse
        
        ld::File::Ordinal                       _indirectDylibOrdinal;
+       ld::File::Ordinal                       _linkerOptionOrdinal;
     
     class LibraryInfo {
         ld::File* _lib;
     
     class LibraryInfo {
         ld::File* _lib;
index 1149f0dcb8f5fc43294d47f05eeedbc4e0971356..1b41fb2c6f664c2995a28873405949a313116ce5 100644 (file)
@@ -1005,6 +1005,14 @@ void ExportInfoAtom<A>::encode() const
                        entries.push_back(entry);
                        //fprintf(stderr, "re-export %s from lib %llu as %s\n", entry.importName, entry.other, entry.name);
                }
                        entries.push_back(entry);
                        //fprintf(stderr, "re-export %s from lib %llu as %s\n", entry.importName, entry.other, entry.name);
                }
+               else if ( atom->definition() == ld::Atom::definitionAbsolute ) {
+                       entry.name = atom->name();
+                       entry.flags = _options.canUseAbsoluteSymbols() ? EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE : EXPORT_SYMBOL_FLAGS_KIND_REGULAR;
+                       entry.address = address;
+                       entry.other = other;
+                       entry.importName = NULL;
+                       entries.push_back(entry);
+               }
                else {
                        if ( (atom->definition() == ld::Atom::definitionRegular) && (atom->combine() == ld::Atom::combineByName) )
                                flags |= EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION;
                else {
                        if ( (atom->definition() == ld::Atom::definitionRegular) && (atom->combine() == ld::Atom::combineByName) )
                                flags |= EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION;
@@ -1068,6 +1076,7 @@ private:
        mutable std::vector<uint64_t>                           _thumbHi16Locations[16];
        mutable std::vector<uint64_t>                           _armLo16Locations;
        mutable std::vector<uint64_t>                           _armHi16Locations[16];
        mutable std::vector<uint64_t>                           _thumbHi16Locations[16];
        mutable std::vector<uint64_t>                           _armLo16Locations;
        mutable std::vector<uint64_t>                           _armHi16Locations[16];
+       mutable std::vector<uint64_t>                           _adrpLocations;
 
 
        static ld::Section                      _s_section;
 
 
        static ld::Section                      _s_section;
@@ -1092,6 +1101,8 @@ void SplitSegInfoAtom<x86_64>::addSplitSegInfo(uint64_t address, ld::Fixup::Kind
                case ld::Fixup::kindStoreTargetAddressX86PCRel32:
                case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoad:
                case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoadNowLEA:
                case ld::Fixup::kindStoreTargetAddressX86PCRel32:
                case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoad:
                case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoadNowLEA:
+               case ld::Fixup::kindStoreTargetAddressX86PCRel32TLVLoad:
+               case ld::Fixup::kindStoreTargetAddressX86PCRel32TLVLoadNowLEA:
                        _32bitPointerLocations.push_back(address);
                        break;
                case ld::Fixup::kindStoreLittleEndian64:
                        _32bitPointerLocations.push_back(address);
                        break;
                case ld::Fixup::kindStoreLittleEndian64:
@@ -1110,6 +1121,8 @@ void SplitSegInfoAtom<x86>::addSplitSegInfo(uint64_t address, ld::Fixup::Kind ki
        switch (kind) {
                case ld::Fixup::kindStoreLittleEndian32:
                case ld::Fixup::kindStoreTargetAddressLittleEndian32:
        switch (kind) {
                case ld::Fixup::kindStoreLittleEndian32:
                case ld::Fixup::kindStoreTargetAddressLittleEndian32:
+               case ld::Fixup::kindStoreX86PCRel32TLVLoad:
+               case ld::Fixup::kindStoreX86PCRel32TLVLoadNowLEA:
                        _32bitPointerLocations.push_back(address);
                        break;
                default:
                        _32bitPointerLocations.push_back(address);
                        break;
                default:
@@ -1145,7 +1158,34 @@ void SplitSegInfoAtom<arm>::addSplitSegInfo(uint64_t address, ld::Fixup::Kind ki
        }
 }
 
        }
 }
 
-
+#if SUPPORT_ARCH_arm64
+template <>
+void SplitSegInfoAtom<arm64>::addSplitSegInfo(uint64_t address, ld::Fixup::Kind kind, uint32_t extra) const
+{
+       switch (kind) {
+               case ld::Fixup::kindStoreARM64Page21:
+               case ld::Fixup::kindStoreARM64GOTLoadPage21:
+               case ld::Fixup::kindStoreARM64GOTLeaPage21:
+               case ld::Fixup::kindStoreARM64TLVPLoadPage21:
+               case ld::Fixup::kindStoreTargetAddressARM64Page21:
+               case ld::Fixup::kindStoreTargetAddressARM64GOTLoadPage21:
+               case ld::Fixup::kindStoreTargetAddressARM64GOTLeaPage21:
+                       _adrpLocations.push_back(address);
+                       break;
+               case ld::Fixup::kindStoreLittleEndian32:
+               case ld::Fixup::kindStoreARM64PCRelToGOT:
+                       _32bitPointerLocations.push_back(address);
+                       break;
+               case ld::Fixup::kindStoreLittleEndian64:
+               case ld::Fixup::kindStoreTargetAddressLittleEndian64:
+                       _64bitPointerLocations.push_back(address);
+                       break;
+               default:
+                       warning("codegen at address 0x%08llX prevents image from working in dyld shared cache", address);
+                       break;
+       }
+}
+#endif
 
 template <typename A>
 void SplitSegInfoAtom<A>::uleb128EncodeAddresses(const std::vector<uint64_t>& locations) const
 
 template <typename A>
 void SplitSegInfoAtom<A>::uleb128EncodeAddresses(const std::vector<uint64_t>& locations) const
@@ -1201,6 +1241,14 @@ void SplitSegInfoAtom<A>::encode() const
                this->_encodedData.append_byte(0); // terminator
        }
 
                this->_encodedData.append_byte(0); // terminator
        }
 
+       if ( _adrpLocations.size() != 0 ) {
+               this->_encodedData.append_byte(3);
+               //fprintf(stderr, "type 3:\n");
+               std::sort(_adrpLocations.begin(), _adrpLocations.end());
+               this->uleb128EncodeAddresses(_adrpLocations);
+               this->_encodedData.append_byte(0); // terminator
+       }
+
        if ( _thumbLo16Locations.size() != 0 ) {
                this->_encodedData.append_byte(5);
                //fprintf(stderr, "type 5:\n");
        if ( _thumbLo16Locations.size() != 0 ) {
                this->_encodedData.append_byte(5);
                //fprintf(stderr, "type 5:\n");
index 60a4fa99924a6f5719a0e19f137bcd3157316c5d..b9b12156b5960355de378806cc3707218ce07e47 100644 (file)
@@ -927,6 +927,9 @@ uint64_t ExternalRelocationsAtom<A>::size() const
        return (_pointerLocations.size() + _callSiteLocations.size()) * sizeof(macho_relocation_info<P>);
 }
 
        return (_pointerLocations.size() + _callSiteLocations.size()) * sizeof(macho_relocation_info<P>);
 }
 
+#if SUPPORT_ARCH_arm64
+template <> uint32_t ExternalRelocationsAtom<arm64>::pointerReloc() { return ARM64_RELOC_UNSIGNED; }
+#endif
 #if SUPPORT_ARCH_arm_any
 template <> uint32_t ExternalRelocationsAtom<arm>::pointerReloc() { return ARM_RELOC_VANILLA; }
 #endif
 #if SUPPORT_ARCH_arm_any
 template <> uint32_t ExternalRelocationsAtom<arm>::pointerReloc() { return ARM_RELOC_VANILLA; }
 #endif
@@ -936,6 +939,10 @@ template <> uint32_t ExternalRelocationsAtom<x86_64>::pointerReloc() { return X8
 
 template <> uint32_t ExternalRelocationsAtom<x86_64>::callReloc() { return X86_64_RELOC_BRANCH; }
 template <> uint32_t ExternalRelocationsAtom<x86>::callReloc() { return GENERIC_RELOC_VANILLA; }
 
 template <> uint32_t ExternalRelocationsAtom<x86_64>::callReloc() { return X86_64_RELOC_BRANCH; }
 template <> uint32_t ExternalRelocationsAtom<x86>::callReloc() { return GENERIC_RELOC_VANILLA; }
+#if SUPPORT_ARCH_arm64
+template <> uint32_t ExternalRelocationsAtom<arm64>::callReloc() { return ARM64_RELOC_BRANCH26; }
+#endif
+
 template <typename A> 
 uint32_t ExternalRelocationsAtom<A>::callReloc() 
 { 
 template <typename A> 
 uint32_t ExternalRelocationsAtom<A>::callReloc() 
 { 
@@ -1647,6 +1654,205 @@ void SectionRelocationsAtom<arm>::encodeSectionReloc(ld::Internal::FinalSection*
 }
 #endif
 
 }
 #endif
 
+#if SUPPORT_ARCH_arm64
+template <>
+void SectionRelocationsAtom<arm64>::encodeSectionReloc(ld::Internal::FinalSection* sect, 
+                                                                                                       const Entry& entry, std::vector<macho_relocation_info<P> >& relocs)
+{
+       macho_relocation_info<P> reloc1;
+       macho_relocation_info<P> reloc2;
+       uint64_t address = entry.inAtom->finalAddress()+entry.offsetInAtom - sect->address;
+       bool external = entry.toTargetUsesExternalReloc;
+       uint32_t symbolNum = sectSymNum(external, entry.toTarget);
+       bool fromExternal = false;
+       uint32_t fromSymbolNum = 0;
+       if ( entry.fromTarget != NULL ) {
+               fromExternal = entry.fromTargetUsesExternalReloc;
+               fromSymbolNum = sectSymNum(fromExternal, entry.fromTarget);
+       }
+       
+       
+       switch ( entry.kind ) {
+               case ld::Fixup::kindStoreARM64Branch26:
+                       if ( entry.toAddend != 0 ) {
+                               assert(entry.toAddend < 0x400000);
+                               reloc2.set_r_address(address);
+                               reloc2.set_r_symbolnum(entry.toAddend);
+                               reloc2.set_r_pcrel(false);
+                               reloc2.set_r_length(2);
+                               reloc2.set_r_extern(false);
+                               reloc2.set_r_type(ARM64_RELOC_ADDEND);
+                               relocs.push_back(reloc2);
+                       }
+                       // fall into next case
+               case ld::Fixup::kindStoreTargetAddressARM64Branch26:
+               case ld::Fixup::kindStoreARM64DtraceCallSiteNop:
+               case ld::Fixup::kindStoreARM64DtraceIsEnableSiteClear:
+                       reloc1.set_r_address(address);
+                       reloc1.set_r_symbolnum(symbolNum);
+                       reloc1.set_r_pcrel(true);
+                       reloc1.set_r_length(2);
+                       reloc1.set_r_extern(external);
+                       reloc1.set_r_type(ARM64_RELOC_BRANCH26);
+                       relocs.push_back(reloc1);
+                       break;
+                       
+               case ld::Fixup::kindStoreARM64Page21:
+                       if ( entry.toAddend != 0 ) {
+                               assert(entry.toAddend < 0x400000);
+                               reloc2.set_r_address(address);
+                               reloc2.set_r_symbolnum(entry.toAddend);
+                               reloc2.set_r_pcrel(false);
+                               reloc2.set_r_length(2);
+                               reloc2.set_r_extern(false);
+                               reloc2.set_r_type(ARM64_RELOC_ADDEND);
+                               relocs.push_back(reloc2);
+                       }
+                       // fall into next case
+               case ld::Fixup::kindStoreTargetAddressARM64Page21:
+                       reloc1.set_r_address(address);
+                       reloc1.set_r_symbolnum(symbolNum);
+                       reloc1.set_r_pcrel(true);
+                       reloc1.set_r_length(2);
+                       reloc1.set_r_extern(external);
+                       reloc1.set_r_type(ARM64_RELOC_PAGE21);
+                       relocs.push_back(reloc1);
+                       break;
+
+               case ld::Fixup::kindStoreARM64PageOff12:
+                       if ( entry.toAddend != 0 ) {
+                               assert(entry.toAddend < 0x400000);
+                               reloc2.set_r_address(address);
+                               reloc2.set_r_symbolnum(entry.toAddend);
+                               reloc2.set_r_pcrel(false);
+                               reloc2.set_r_length(2);
+                               reloc2.set_r_extern(false);
+                               reloc2.set_r_type(ARM64_RELOC_ADDEND);
+                               relocs.push_back(reloc2);
+                       }
+                       // fall into next case
+               case ld::Fixup::kindStoreTargetAddressARM64PageOff12:
+                       reloc1.set_r_address(address);
+                       reloc1.set_r_symbolnum(symbolNum);
+                       reloc1.set_r_pcrel(false);
+                       reloc1.set_r_length(2);
+                       reloc1.set_r_extern(external);
+                       reloc1.set_r_type(ARM64_RELOC_PAGEOFF12);
+                       relocs.push_back(reloc1);
+                       break;
+
+               case ld::Fixup::kindStoreTargetAddressARM64GOTLoadPage21:
+               case ld::Fixup::kindStoreARM64GOTLoadPage21:
+                       reloc1.set_r_address(address);
+                       reloc1.set_r_symbolnum(symbolNum);
+                       reloc1.set_r_pcrel(true);
+                       reloc1.set_r_length(2);
+                       reloc1.set_r_extern(external);
+                       reloc1.set_r_type(ARM64_RELOC_GOT_LOAD_PAGE21);
+                       relocs.push_back(reloc1);
+                       break;
+
+               case ld::Fixup::kindStoreTargetAddressARM64GOTLoadPageOff12:
+               case ld::Fixup::kindStoreARM64GOTLoadPageOff12:
+                       reloc1.set_r_address(address);
+                       reloc1.set_r_symbolnum(symbolNum);
+                       reloc1.set_r_pcrel(false);
+                       reloc1.set_r_length(2);
+                       reloc1.set_r_extern(external);
+                       reloc1.set_r_type(ARM64_RELOC_GOT_LOAD_PAGEOFF12);
+                       relocs.push_back(reloc1);
+                       break;
+
+
+               case ld::Fixup::kindStoreLittleEndian64:
+               case ld::Fixup::kindStoreTargetAddressLittleEndian64:
+                       if ( entry.fromTarget != NULL ) {
+                               // this is a pointer-diff
+                               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_UNSIGNED);
+                               reloc2.set_r_address(address);
+                               reloc2.set_r_symbolnum(fromSymbolNum);
+                               reloc2.set_r_pcrel(false);
+                               reloc2.set_r_length(3);
+                               reloc2.set_r_extern(fromExternal);
+                               reloc2.set_r_type(ARM64_RELOC_SUBTRACTOR);
+                               relocs.push_back(reloc2);
+                               relocs.push_back(reloc1);
+                       }
+                       else {
+                               // regular pointer
+                               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_UNSIGNED);
+                               relocs.push_back(reloc1);
+                       }
+                       break;
+
+               case ld::Fixup::kindStoreLittleEndian32:
+               case ld::Fixup::kindStoreTargetAddressLittleEndian32:
+                       if ( entry.fromTarget != NULL ) {
+                               // this is a pointer-diff
+                               reloc1.set_r_address(address);
+                               reloc1.set_r_symbolnum(symbolNum);
+                               reloc1.set_r_pcrel(false);
+                               reloc1.set_r_length(2);
+                               reloc1.set_r_extern(external);
+                               reloc1.set_r_type(ARM64_RELOC_UNSIGNED);
+                               reloc2.set_r_address(address);
+                               reloc2.set_r_symbolnum(fromSymbolNum);
+                               reloc2.set_r_pcrel(false);
+                               reloc2.set_r_length(2);
+                               reloc2.set_r_extern(fromExternal);
+                               reloc2.set_r_type(ARM64_RELOC_SUBTRACTOR);
+                               relocs.push_back(reloc2);
+                               relocs.push_back(reloc1);
+                       }
+                       else {
+                               // regular pointer
+                               reloc1.set_r_address(address);
+                               reloc1.set_r_symbolnum(symbolNum);
+                               reloc1.set_r_pcrel(false);
+                               reloc1.set_r_length(2);
+                               reloc1.set_r_extern(external);
+                               reloc1.set_r_type(ARM64_RELOC_UNSIGNED);
+                               relocs.push_back(reloc1);
+                       }
+                       break;
+
+               case ld::Fixup::kindStoreARM64PointerToGOT:
+            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_POINTER_TO_GOT);
+            relocs.push_back(reloc1);
+            break;
+
+               case ld::Fixup::kindStoreARM64PCRelToGOT:
+            reloc1.set_r_address(address);
+            reloc1.set_r_symbolnum(symbolNum);
+            reloc1.set_r_pcrel(true);
+            reloc1.set_r_length(2);
+            reloc1.set_r_extern(external);
+            reloc1.set_r_type(ARM64_RELOC_POINTER_TO_GOT);
+            relocs.push_back(reloc1);
+            break;
+
+               default:
+                       assert(0 && "need to handle arm64 -r reloc");
+               
+       }
+
+}
+#endif // SUPPORT_ARCH_arm64
 
 
 template <typename A>
 
 
 template <typename A>
index 0131911afd722bb5a9363e7187a5c2f888444ca1..d916c536c120d761726c8bebe46c4b9b82794df8 100644 (file)
@@ -104,19 +104,24 @@ void throwf(const char* format, ...)
        throw t;
 }
 
        throw t;
 }
 
-bool Options::FileInfo::checkFileExists(const char *p)
+
+bool Options::FileInfo::checkFileExists(const Options& options, const char *p)
 {
        struct stat statBuffer;
 {
        struct stat statBuffer;
-       if (p == NULL) p = path;
+       if (p == NULL) 
+         p = path;
        if ( stat(p, &statBuffer) == 0 ) {
                if (p != path) path = strdup(p);
                fileLen = statBuffer.st_size;
                modTime = statBuffer.st_mtime;
                return true;
        }
        if ( stat(p, &statBuffer) == 0 ) {
                if (p != path) path = strdup(p);
                fileLen = statBuffer.st_size;
                modTime = statBuffer.st_mtime;
                return true;
        }
+       if ( options.dumpDependencyInfo() )
+               options.dumpDependency(Options::depNotFound, p);
     return false;
 }
 
     return false;
 }
 
+
 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),
 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),
@@ -131,7 +136,7 @@ Options::Options(int argc, const char* argv[])
          fClientName(NULL),
          fUmbrellaName(NULL), fInitFunctionName(NULL), fDotOutputFile(NULL), fExecutablePath(NULL),
          fBundleLoader(NULL), fDtraceScriptName(NULL), fSegAddrTablePath(NULL), fMapPath(NULL), 
          fClientName(NULL),
          fUmbrellaName(NULL), fInitFunctionName(NULL), fDotOutputFile(NULL), fExecutablePath(NULL),
          fBundleLoader(NULL), fDtraceScriptName(NULL), fSegAddrTablePath(NULL), fMapPath(NULL), 
-         fDyldInstallPath("/usr/lib/dyld"), fTempLtoObjectPath(NULL), fOverridePathlibLTO(NULL), 
+         fDyldInstallPath("/usr/lib/dyld"), fTempLtoObjectPath(NULL), fOverridePathlibLTO(NULL), fLtoCpu(NULL),
          fZeroPageSize(ULLONG_MAX), fStackSize(0), fStackAddr(0), fSourceVersion(0), fSDKVersion(0), fExecutableStack(false), 
          fNonExecutableHeap(false), fDisableNonExecutableHeap(false),
          fMinimumHeaderPad(32), fSegmentAlignment(4096), 
          fZeroPageSize(ULLONG_MAX), fStackSize(0), fStackAddr(0), fSourceVersion(0), fSDKVersion(0), fExecutableStack(false), 
          fNonExecutableHeap(false), fDisableNonExecutableHeap(false),
          fMinimumHeaderPad(32), fSegmentAlignment(4096), 
@@ -167,9 +172,14 @@ Options::Options(int argc, const char* argv[])
          fSourceVersionLoadCommand(false), 
          fSourceVersionLoadCommandForceOn(false), fSourceVersionLoadCommandForceOff(false), 
          fDependentDRInfo(false), fDependentDRInfoForcedOn(false), fDependentDRInfoForcedOff(false),
          fSourceVersionLoadCommand(false), 
          fSourceVersionLoadCommandForceOn(false), fSourceVersionLoadCommandForceOff(false), 
          fDependentDRInfo(false), fDependentDRInfoForcedOn(false), fDependentDRInfoForcedOff(false),
+         fTargetIOSSimulator(false), fExportDynamic(false), fAbsoluteSymbols(false),
+         fAllowSimulatorToLinkWithMacOSX(false), fKeepDwarfUnwind(true),
+         fKeepDwarfUnwindForcedOn(false), fKeepDwarfUnwindForcedOff(false),
+         fGenerateDtraceDOF(true),
          fDebugInfoStripping(kDebugInfoMinimal), fTraceOutputFile(NULL), 
          fMacVersionMin(ld::macVersionUnset), fIOSVersionMin(ld::iOSVersionUnset), 
          fDebugInfoStripping(kDebugInfoMinimal), fTraceOutputFile(NULL), 
          fMacVersionMin(ld::macVersionUnset), fIOSVersionMin(ld::iOSVersionUnset), 
-         fSaveTempFiles(false), fSnapshotRequested(false), fPipelineFifo(NULL)
+         fSaveTempFiles(false), fSnapshotRequested(false), fPipelineFifo(NULL), 
+         fDependencyInfoPath(NULL), fDependencyFileDescriptor(-1)
 {
        this->checkForClassic(argc, argv);
        this->parsePreCommandLineEnvironmentSettings();
 {
        this->checkForClassic(argc, argv);
        this->parsePreCommandLineEnvironmentSettings();
@@ -177,10 +187,18 @@ Options::Options(int argc, const char* argv[])
        this->parsePostCommandLineEnvironmentSettings();
        this->reconfigureDefaults();
        this->checkIllegalOptionCombinations();
        this->parsePostCommandLineEnvironmentSettings();
        this->reconfigureDefaults();
        this->checkIllegalOptionCombinations();
+       
+       if ( this->dumpDependencyInfo() ) {
+               this->dumpDependency(depOutputFile, fOutputFile);
+               if ( fMapPath != NULL ) 
+               this->dumpDependency(depOutputFile, fMapPath);
+       }
 }
 
 Options::~Options()
 {
 }
 
 Options::~Options()
 {
+  if ( fDependencyFileDescriptor != -1 )
+       ::close(fDependencyFileDescriptor);
 }
 
 bool Options::errorBecauseOfWarnings() const
 }
 
 bool Options::errorBecauseOfWarnings() const
@@ -246,7 +264,11 @@ bool Options::allGlobalsAreDeadStripRoots() const
        //
        switch ( fOutputKind ) {
                case Options::kDynamicExecutable:
        //
        switch ( fOutputKind ) {
                case Options::kDynamicExecutable:
+                       // <rdar://problem/12839986> Add the -export_dynamic flag 
+                       return fExportDynamic;
                case Options::kStaticExecutable:
                case Options::kStaticExecutable:
+                       // <rdar://problem/13361218> Support the -export_dynamic flag for xnu
+                       return fExportDynamic;
                case Options::kPreload:
                        // by default unused globals in a main executable are stripped
                        return false;
                case Options::kPreload:
                        // by default unused globals in a main executable are stripped
                        return false;
@@ -276,7 +298,6 @@ const char* Options::executablePath()
        return fExecutablePath;
 }
 
        return fExecutablePath;
 }
 
-
 uint32_t Options::initialSegProtection(const char* segName) const
 {
        for(std::vector<Options::SegmentProtect>::const_iterator it = fCustomSegmentProtections.begin(); it != fCustomSegmentProtections.end(); ++it) {
 uint32_t Options::initialSegProtection(const char* segName) const
 {
        for(std::vector<Options::SegmentProtect>::const_iterator it = fCustomSegmentProtections.begin(); it != fCustomSegmentProtections.end(); ++it) {
@@ -478,6 +499,11 @@ bool Options::forceNotWeakNonWildcard(const char* symbolName) const
        return fForceNotWeakSymbols.containsNonWildcard(symbolName);
 }
 
        return fForceNotWeakSymbols.containsNonWildcard(symbolName);
 }
 
+bool Options::forceCoalesce(const char* symbolName) const
+{
+       return fForceCoalesceSymbols.contains(symbolName);
+}
+
 
 bool Options::shouldExport(const char* symbolName) const
 {
 
 bool Options::shouldExport(const char* symbolName) const
 {
@@ -533,27 +559,29 @@ void Options::setArchitecture(cpu_type_t type, cpu_subtype_t subtype)
                                                fMacVersionMin = ld::mac10_6;
                                #endif          
                                        }
                                                fMacVersionMin = ld::mac10_6;
                                #endif          
                                        }
-                                       if ( !fMakeCompressedDyldInfo && minOS(ld::mac10_6, ld::iOS_3_1) && !fMakeCompressedDyldInfoForceOff )
-                                               fMakeCompressedDyldInfo = true;
                                        break;
                                case CPU_TYPE_ARM:
                                        break;
                                case CPU_TYPE_ARM:
+                               case CPU_TYPE_ARM64:
                                        if ( (fMacVersionMin == ld::macVersionUnset) && (fIOSVersionMin == ld::iOSVersionUnset) && (fOutputKind != Options::kObjectFile) ) {
                                #if defined(DEFAULT_IPHONEOS_MIN_VERSION)
                                                warning("-ios_version_min not specified, assuming " DEFAULT_IPHONEOS_MIN_VERSION);
                                                setIOSVersionMin(DEFAULT_IPHONEOS_MIN_VERSION);
                                        if ( (fMacVersionMin == ld::macVersionUnset) && (fIOSVersionMin == ld::iOSVersionUnset) && (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);
-                               #elif defined(DEFAULT_MACOSX_MIN_VERSION)
-                                               warning("-macosx_version_min not specified, assuming " DEFAULT_MACOSX_MIN_VERSION);
-                                               setMacOSXVersionMin(DEFAULT_MACOSX_MIN_VERSION);
                                #else
                                #else
-                                               warning("-macosx_version_min not specified, assuming 10.6");
-                                               fMacVersionMin = ld::mac10_6;
+                                               warning("-ios_version_min not specified, assuming 6.0");
+                                               setIOSVersionMin("6.0");
                                #endif
                                        }
                                #endif
                                        }
-                                       if ( !fMakeCompressedDyldInfo && minOS(ld::mac10_6, ld::iOS_3_1) && !fMakeCompressedDyldInfoForceOff )
-                                               fMakeCompressedDyldInfo = true;
                                        break;
                        }
                        fLinkSnapshot.recordArch(fArchitectureName);
                                        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 )
+                               fMakeCompressedDyldInfo = true;
+                       // Mac OS X 10.5 and iPhoneOS 2.0 support LC_REEXPORT_DYLIB
+                       if ( minOS(ld::mac10_5, ld::iOS_2_0) )
+                               fUseSimplifiedDylibReExports = true;
                        return;
                }
        }
                        return;
                }
        }
@@ -581,20 +609,20 @@ bool Options::checkForFile(const char* format, const char* dir, const char* root
 {
        char possiblePath[strlen(dir)+strlen(rootName)+strlen(format)+8];
        sprintf(possiblePath, format,  dir, rootName);
 {
        char possiblePath[strlen(dir)+strlen(rootName)+strlen(format)+8];
        sprintf(possiblePath, format,  dir, rootName);
-       bool found = result.checkFileExists(possiblePath);
+       bool found = result.checkFileExists(*this, possiblePath);
        if ( fTraceDylibSearching )
                printf("[Logging for XBS]%sfound library: '%s'\n", (found ? " " : " not "), possiblePath);
        return found;
 }
 
 
        if ( fTraceDylibSearching )
                printf("[Logging for XBS]%sfound library: '%s'\n", (found ? " " : " not "), possiblePath);
        return found;
 }
 
 
-Options::FileInfo Options::findLibrary(const char* rootName, bool dylibsOnly)
+Options::FileInfo Options::findLibrary(const char* rootName, bool dylibsOnly) const
 {
        FileInfo result;
        const int rootNameLen = strlen(rootName);
        // if rootName ends in .o there is no .a vs .dylib choice
        if ( (rootNameLen > 3) && (strcmp(&rootName[rootNameLen-2], ".o") == 0) ) {
 {
        FileInfo result;
        const int rootNameLen = strlen(rootName);
        // if rootName ends in .o there is no .a vs .dylib choice
        if ( (rootNameLen > 3) && (strcmp(&rootName[rootNameLen-2], ".o") == 0) ) {
-               for (std::vector<const char*>::iterator it = fLibrarySearchPaths.begin();
+               for (std::vector<const char*>::const_iterator it = fLibrarySearchPaths.begin();
                         it != fLibrarySearchPaths.end();
                         it++) {
                        const char* dir = *it;
                         it != fLibrarySearchPaths.end();
                         it++) {
                        const char* dir = *it;
@@ -608,14 +636,14 @@ Options::FileInfo Options::findLibrary(const char* rootName, bool dylibsOnly)
                case kSearchAllDirsForDylibsThenAllDirsForArchives:
                                // first look in all directories for just for dylibs
                                if ( lookForDylibs ) {
                case kSearchAllDirsForDylibsThenAllDirsForArchives:
                                // first look in all directories for just for dylibs
                                if ( lookForDylibs ) {
-                                       for (std::vector<const char*>::iterator it = fLibrarySearchPaths.begin();
+                                       for (std::vector<const char*>::const_iterator it = fLibrarySearchPaths.begin();
                                                 it != fLibrarySearchPaths.end();
                                                 it++) {
                                                const char* dir = *it;
                                                if ( checkForFile("%s/lib%s.dylib", dir, rootName, result) )
                                                        return result;
                                        }
                                                 it != fLibrarySearchPaths.end();
                                                 it++) {
                                                const char* dir = *it;
                                                if ( checkForFile("%s/lib%s.dylib", dir, rootName, result) )
                                                        return result;
                                        }
-                                       for (std::vector<const char*>::iterator it = fLibrarySearchPaths.begin();
+                                       for (std::vector<const char*>::const_iterator it = fLibrarySearchPaths.begin();
                                                 it != fLibrarySearchPaths.end();
                                                 it++) {
                                                const char* dir = *it;
                                                 it != fLibrarySearchPaths.end();
                                                 it++) {
                                                const char* dir = *it;
@@ -625,7 +653,7 @@ Options::FileInfo Options::findLibrary(const char* rootName, bool dylibsOnly)
                                }
                                // next look in all directories for just for archives
                                if ( !dylibsOnly ) {
                                }
                                // next look in all directories for just for archives
                                if ( !dylibsOnly ) {
-                                       for (std::vector<const char*>::iterator it = fLibrarySearchPaths.begin();
+                                       for (std::vector<const char*>::const_iterator it = fLibrarySearchPaths.begin();
                                                 it != fLibrarySearchPaths.end();
                                                 it++) {
                                                const char* dir = *it;
                                                 it != fLibrarySearchPaths.end();
                                                 it++) {
                                                const char* dir = *it;
@@ -637,7 +665,7 @@ Options::FileInfo Options::findLibrary(const char* rootName, bool dylibsOnly)
 
                        case kSearchDylibAndArchiveInEachDir:
                                // look in each directory for just for a dylib then for an archive
 
                        case kSearchDylibAndArchiveInEachDir:
                                // look in each directory for just for a dylib then for an archive
-                               for (std::vector<const char*>::iterator it = fLibrarySearchPaths.begin();
+                               for (std::vector<const char*>::const_iterator it = fLibrarySearchPaths.begin();
                                         it != fLibrarySearchPaths.end();
                                         it++) {
                                        const char* dir = *it;
                                         it != fLibrarySearchPaths.end();
                                         it++) {
                                        const char* dir = *it;
@@ -654,7 +682,7 @@ Options::FileInfo Options::findLibrary(const char* rootName, bool dylibsOnly)
        throwf("library not found for -l%s", rootName);
 }
 
        throwf("library not found for -l%s", rootName);
 }
 
-Options::FileInfo Options::findFramework(const char* frameworkName)
+Options::FileInfo Options::findFramework(const char* frameworkName) const
 {
        if ( frameworkName == NULL )
                throw "-framework missing next argument";
 {
        if ( frameworkName == NULL )
                throw "-framework missing next argument";
@@ -670,9 +698,9 @@ Options::FileInfo Options::findFramework(const char* frameworkName)
        return findFramework(name, suffix);
 }
 
        return findFramework(name, suffix);
 }
 
-Options::FileInfo Options::findFramework(const char* rootName, const char* suffix)
+Options::FileInfo Options::findFramework(const char* rootName, const char* suffix) const
 {
 {
-       for (std::vector<const char*>::iterator it = fFrameworkSearchPaths.begin();
+       for (std::vector<const char*>::const_iterator it = fFrameworkSearchPaths.begin();
                 it != fFrameworkSearchPaths.end();
                 it++) {
                // ??? Shouldn't we be using String here and just initializing it?
                 it != fFrameworkSearchPaths.end();
                 it++) {
                // ??? Shouldn't we be using String here and just initializing it?
@@ -693,7 +721,7 @@ Options::FileInfo Options::findFramework(const char* rootName, const char* suffi
                        }
                }
         FileInfo result;
                        }
                }
         FileInfo result;
-               bool found = result.checkFileExists(possiblePath);
+               bool found = result.checkFileExists(*this, possiblePath);
                if ( fTraceDylibSearching )
                        printf("[Logging for XBS]%sfound framework: '%s'\n",
                                   (found ? " " : " not "), possiblePath);
                if ( fTraceDylibSearching )
                        printf("[Logging for XBS]%sfound framework: '%s'\n",
                                   (found ? " " : " not "), possiblePath);
@@ -724,13 +752,13 @@ Options::FileInfo Options::findFile(const char* path) const
                        if ( possiblePath[sdkPathDirLen-1] == '/' )
                                possiblePath[sdkPathDirLen-1] = '\0';
                        strcat(possiblePath, path);
                        if ( possiblePath[sdkPathDirLen-1] == '/' )
                                possiblePath[sdkPathDirLen-1] = '\0';
                        strcat(possiblePath, path);
-                       if ( result.checkFileExists(possiblePath) ) {
+                       if ( result.checkFileExists(*this, possiblePath) ) {
                                return result;
                        }
                }
        }
        // try raw path
                                return result;
                        }
                }
        }
        // try raw path
-       if ( result.checkFileExists(path) ) {
+       if ( result.checkFileExists(*this, path) ) {
                return result;
        }
 
                return result;
        }
 
@@ -743,7 +771,7 @@ Options::FileInfo Options::findFile(const char* path) const
                        strcpy(&addPoint[1], &path[17]);
                else
                        strcpy(newPath, &path[17]);
                        strcpy(&addPoint[1], &path[17]);
                else
                        strcpy(newPath, &path[17]);
-               if ( result.checkFileExists(newPath) ) {
+               if ( result.checkFileExists(*this, newPath) ) {
                        return result;
                }
        }
                        return result;
                }
        }
@@ -815,7 +843,8 @@ Options::FileInfo Options::findFileUsingPaths(const char* path) const
        // If we didn't find it fall back to findFile.
        return findFile(path);
 }
        // If we didn't find it fall back to findFile.
        return findFile(path);
 }
+
+
 
 void Options::parseSegAddrTable(const char* segAddrPath, const char* installPth)
 {
 
 void Options::parseSegAddrTable(const char* segAddrPath, const char* installPth)
 {
@@ -886,12 +915,16 @@ void Options::loadFileList(const char* fileOfPaths, ld::File::Ordinal baseOrdina
                        file = fopen(realFileOfPaths, "r");
                        if ( file == NULL )
                                throwf("-filelist file '%s' could not be opened, errno=%d (%s)\n", realFileOfPaths, errno, strerror(errno));
                        file = fopen(realFileOfPaths, "r");
                        if ( file == NULL )
                                throwf("-filelist file '%s' could not be opened, errno=%d (%s)\n", realFileOfPaths, errno, strerror(errno));
+                       if ( this->dumpDependencyInfo() )
+                               this->dumpDependency(Options::depFileList, realFileOfPaths);
                }
        }
        else {
                file = fopen(fileOfPaths, "r");
                if ( file == NULL )
                        throwf("-filelist file '%s' could not be opened, errno=%d (%s)\n", fileOfPaths, errno, strerror(errno));
                }
        }
        else {
                file = fopen(fileOfPaths, "r");
                if ( file == NULL )
                        throwf("-filelist file '%s' could not be opened, errno=%d (%s)\n", fileOfPaths, errno, strerror(errno));
+               if ( this->dumpDependencyInfo() )
+                       this->dumpDependency(Options::depFileList, fileOfPaths);
        }
 
        char path[PATH_MAX];
        }
 
        char path[PATH_MAX];
@@ -1064,6 +1097,9 @@ void Options::loadExportFile(const char* fileOfExports, const char* option, SetW
        if ( read(fd, p, stat_buf.st_size) != stat_buf.st_size )
                throwf("can't read %s file: %s", option, fileOfExports);
 
        if ( read(fd, p, stat_buf.st_size) != stat_buf.st_size )
                throwf("can't read %s file: %s", option, fileOfExports);
 
+       if ( this->dumpDependencyInfo() )
+               this->dumpDependency(Options::depMisc, fileOfExports);
+
        ::close(fd);
 
        // parse into symbols and add to unordered_set
        ::close(fd);
 
        // parse into symbols and add to unordered_set
@@ -1135,6 +1171,8 @@ void Options::parseAliasFile(const char* fileOfAliases)
                throwf("can't read alias file: %s", fileOfAliases);
        p[stat_buf.st_size] = '\n';
        ::close(fd);
                throwf("can't read alias file: %s", fileOfAliases);
        p[stat_buf.st_size] = '\n';
        ::close(fd);
+       if ( this->dumpDependencyInfo() )
+               this->dumpDependency(Options::depMisc, fileOfAliases);
 
        // parse into symbols and add to fAliases
        AliasPair pair;
 
        // parse into symbols and add to fAliases
        AliasPair pair;
@@ -1248,7 +1286,14 @@ void Options::setMacOSXVersionMin(const char* version)
                throw "-macosx_version_min argument missing";
 
        if ( (strncmp(version, "10.", 3) == 0) && isdigit(version[3]) ) {
                throw "-macosx_version_min argument missing";
 
        if ( (strncmp(version, "10.", 3) == 0) && isdigit(version[3]) ) {
-               unsigned int minorVersion = version[3] - '0';
+               unsigned int minorVersion = 0;
+               for (int i=3; isdigit(version[i]); ++i) {
+                       minorVersion = minorVersion*10 + (version[i] - '0');
+               }
+               if ( minorVersion > 255 ) {
+                       warning("Mac OS X minor version > 255 in '%s'", version);
+                       minorVersion = 255;
+               }
                fMacVersionMin = (ld::MacVersionMin)(0x000A0000 | (minorVersion << 8));
        }
        else {
                fMacVersionMin = (ld::MacVersionMin)(0x000A0000 | (minorVersion << 8));
        }
        else {
@@ -1533,6 +1578,8 @@ void Options::parseOrderFile(const char* path, bool cstring)
                throwf("can't read order file: %s", path);
        ::close(fd);
        p[stat_buf.st_size] = '\n';
                throwf("can't read order file: %s", path);
        ::close(fd);
        p[stat_buf.st_size] = '\n';
+       if ( this->dumpDependencyInfo() )
+               this->dumpDependency(Options::depMisc, path);
 
        // parse into vector of pairs
        char * const end = &p[stat_buf.st_size+1];
 
        // parse into vector of pairs
        char * const end = &p[stat_buf.st_size+1];
@@ -1592,6 +1639,14 @@ void Options::parseOrderFile(const char* path, bool cstring)
                                                objFileName = symbolStart;
                                                symbolStart = &colon[3];
                                        }
                                                objFileName = symbolStart;
                                                symbolStart = &colon[3];
                                        }
+                                       else {
+                                               colon = strstr(symbolStart, ".o):");
+                                               if ( colon != NULL ) {
+                                                       colon[3] = '\0';
+                                                       objFileName = symbolStart;
+                                                       symbolStart = &colon[4];
+                                               }
+                                       }
                                        // trim leading spaces
                                        while ( isspace(*symbolStart) ) 
                                                ++symbolStart;
                                        // trim leading spaces
                                        while ( isspace(*symbolStart) ) 
                                                ++symbolStart;
@@ -2264,13 +2319,34 @@ 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 ) {
                        }
                        // Use this flag to set default behavior for deployement targets.
                        else if ( strcmp(arg, "-macosx_version_min") == 0 ) {
-                               setMacOSXVersionMin(argv[++i]);
+                               const char* macVers = argv[++i];
+                               const char* envMacVers = getenv("MACOSX_DEPLOYMENT_TARGET");
+                               const char* enviPhoneVers = getenv("IPHONEOS_DEPLOYMENT_TARGET");
+                               if ( (envMacVers != NULL) && (enviPhoneVers != NULL) ) {
+                                       // <rdar://problem/13774329> when conflicting deployments set, break tie by looking at syslibroot
+                                       warning("both MACOSX_DEPLOYMENT_TARGET and IPHONEOS_DEPLOYMENT_TARGET are set");
+                                       if ( !fSDKPaths.empty() ) {
+                                               const char* sysrootPath = fSDKPaths.back();
+                                               const char* lastSlash = strrchr(sysrootPath, '/');
+                                               if ( strstr(lastSlash, "Simulator") != NULL ) 
+                                                       setIOSVersionMin(enviPhoneVers);
+                                               else
+                                                       setMacOSXVersionMin(macVers);
+                                       }
+                                       else {
+                                               setMacOSXVersionMin(macVers);
+                                       }
+                               }
+                               else {
+                                       setMacOSXVersionMin(macVers);
+                               }
                        }
                        else if ( (strcmp(arg, "-ios_version_min") == 0) || (strcmp(arg, "-iphoneos_version_min") == 0) ) {
                                setIOSVersionMin(argv[++i]); 
                        }
                        else if ( strcmp(arg, "-ios_simulator_version_min") == 0 ) {
                                setIOSVersionMin(argv[++i]);
                        }
                        else if ( (strcmp(arg, "-ios_version_min") == 0) || (strcmp(arg, "-iphoneos_version_min") == 0) ) {
                                setIOSVersionMin(argv[++i]); 
                        }
                        else if ( strcmp(arg, "-ios_simulator_version_min") == 0 ) {
                                setIOSVersionMin(argv[++i]);
+                               fTargetIOSSimulator = true;
                        }
                        else if ( strcmp(arg, "-multiply_defined") == 0 ) {
                                //warnObsolete(arg);
                        }
                        else if ( strcmp(arg, "-multiply_defined") == 0 ) {
                                //warnObsolete(arg);
@@ -2603,6 +2679,12 @@ void Options::parse(int argc, const char* argv[])
                                        throw "missing argument to -mllvm";
                                fLLVMOptions.push_back(opts);
                        }
                                        throw "missing argument to -mllvm";
                                fLLVMOptions.push_back(opts);
                        }
+                       else if ( strcmp(arg, "-mcpu") == 0 ) {
+                               const char* cpu = argv[++i];
+                               if ( cpu == NULL )
+                                       throw "missing argument to -mcpu";
+                               fLtoCpu = cpu;
+                       }
                        else if ( strcmp(arg, "-no_order_inits") == 0 ) {
                                fAutoOrderInitializers = false;
                        }
                        else if ( strcmp(arg, "-no_order_inits") == 0 ) {
                                fAutoOrderInitializers = false;
                        }
@@ -2755,6 +2837,14 @@ void Options::parse(int argc, const char* argv[])
                        else if (strcmp(arg, "-debug_snapshot") == 0) {
                 fLinkSnapshot.setSnapshotMode(Snapshot::SNAPSHOT_DEBUG);
                 fSnapshotRequested = true;
                        else if (strcmp(arg, "-debug_snapshot") == 0) {
                 fLinkSnapshot.setSnapshotMode(Snapshot::SNAPSHOT_DEBUG);
                 fSnapshotRequested = true;
+            }
+                       else if (strcmp(arg, "-snapshot_dir") == 0) {
+                               const char* path = argv[++i];
+                               if ( path == NULL )
+                                       throw "-snapshot_dir missing path";
+                               fLinkSnapshot.setSnapshotMode(Snapshot::SNAPSHOT_DEBUG);
+                               fLinkSnapshot.setSnapshotPath(path);
+                               fSnapshotRequested = true;
             }
                        else if ( strcmp(arg, "-new_main") == 0 ) {
                                fEntryPointLoadCommandForceOn = true;
             }
                        else if ( strcmp(arg, "-new_main") == 0 ) {
                                fEntryPointLoadCommandForceOn = true;
@@ -2789,6 +2879,53 @@ void Options::parse(int argc, const char* argv[])
                        else if ( strcmp(arg, "-kexts_use_stubs") == 0 ) {
                                fKextsUseStubs = true;
                        }
                        else if ( strcmp(arg, "-kexts_use_stubs") == 0 ) {
                                fKextsUseStubs = true;
                        }
+                       else if ( strcmp(argv[i], "-dependency_info") == 0 ) {
+                               ++i;
+                               // previously handled by buildSearchPaths()
+                       }
+                       else if ( strcmp(arg, "-export_dynamic") == 0 ) {
+                               fExportDynamic = true;
+                       }
+                       else if ( strcmp(arg, "-force_symbols_coalesce_list") == 0 ) {
+                snapshotFileArgIndex = 1;
+                               loadExportFile(argv[++i], "-force_symbols_coalesce_list", fForceCoalesceSymbols);
+                       }
+                       else if ( strcmp(arg, "-add_linker_option") == 0 ) {
+                               // ex: -add_linker_option '-framework Foundation'
+                               const char* optString = argv[++i];
+                               if ( optString == NULL )
+                                       throw "-add_linker_option missing <option>";
+                               // break up into list of tokens at whitespace
+                               std::vector<const char*> opts;
+                               char* buffer = strdup(optString);
+                               char* start = buffer;
+                               for (char* s = buffer; ; ++s) {
+                                       if ( isspace(*s)  ) {
+                                               *s = '\0';
+                                               opts.push_back(start);
+                                               start = s+1;
+                                       }
+                                       else if ( *s == '\0' ) {
+                                               opts.push_back(start);
+                                               break;
+                                       }
+                               }
+                               fLinkerOptions.push_back(opts);
+                       }
+                       else if ( strcmp(arg, "-allow_simulator_linking_to_macosx_dylibs") == 0 ) {
+                               fAllowSimulatorToLinkWithMacOSX = true;
+                       }
+                       else if ( strcmp(arg, "-keep_dwarf_unwind") == 0 ) {
+                               fKeepDwarfUnwindForcedOn = true;
+                               fKeepDwarfUnwindForcedOff = false;
+                       }
+                       else if ( strcmp(arg, "-no_keep_dwarf_unwind") == 0 ) {
+                               fKeepDwarfUnwindForcedOn = false;
+                               fKeepDwarfUnwindForcedOff = true;
+                       }
+                       else if ( strcmp(arg, "-no_dtrace_dof") == 0 ) {
+                               fGenerateDtraceDOF = false;
+                       }
                        else {
                                throwf("unknown option: %s", arg);
                        }
                        else {
                                throwf("unknown option: %s", arg);
                        }
@@ -2918,6 +3055,12 @@ void Options::buildSearchPaths(int argc, const char* argv[])
                else if ( strcmp(argv[i], "-fatal_warnings") == 0 ) {
                        sFatalWarnings = true;
                }
                else if ( strcmp(argv[i], "-fatal_warnings") == 0 ) {
                        sFatalWarnings = true;
                }
+               else if ( strcmp(argv[i], "-dependency_info") == 0 ) {
+                        const char* path = argv[++i];
+                        if ( path == NULL )
+                               throw "-dependency_info missing <path>";
+                       fDependencyInfoPath = path;
+               }
        }
        int standardLibraryPathsStartIndex = libraryPaths.size();
        int standardFrameworkPathsStartIndex = frameworkPaths.size();
        }
        int standardLibraryPathsStartIndex = libraryPaths.size();
        int standardFrameworkPathsStartIndex = frameworkPaths.size();
@@ -3198,17 +3341,14 @@ void Options::reconfigureDefaults()
                        #if defined(DEFAULT_IPHONEOS_MIN_VERSION)
                                                warning("-ios_version_min not specified, assuming " DEFAULT_IPHONEOS_MIN_VERSION);
                                                setIOSVersionMin(DEFAULT_IPHONEOS_MIN_VERSION);
                        #if defined(DEFAULT_IPHONEOS_MIN_VERSION)
                                                warning("-ios_version_min not specified, assuming " DEFAULT_IPHONEOS_MIN_VERSION);
                                                setIOSVersionMin(DEFAULT_IPHONEOS_MIN_VERSION);
-                       #elif defined(DEFAULT_MACOSX_MIN_VERSION)
-                                               warning("-macosx_version_min not specified, assuming " DEFAULT_MACOSX_MIN_VERSION);
-                                               setMacOSXVersionMin(DEFAULT_MACOSX_MIN_VERSION);
                        #else
                        #else
-                                               warning("-macosx_version_min not specified, assuming 10.6");
-                                               fMacVersionMin = ld::mac10_6;
+                                               warning("-ios_version_min not specified, assuming 6.0");
+                                               setIOSVersionMin("6.0");
                        #endif
                                        }
                                        break;
                                default:
                        #endif
                                        }
                                        break;
                                default:
-                                       // architecture will be infered ;ater by examining .o files
+                                       // architecture will be infered later by examining .o files
                                        break;
                        }
                }
                                        break;
                        }
                }
@@ -3229,6 +3369,12 @@ void Options::reconfigureDefaults()
                                fMacVersionMin = ld::mac10_4;
                        }
                        break;
                                fMacVersionMin = ld::mac10_4;
                        }
                        break;
+               case CPU_TYPE_ARM64:
+                       if ( fIOSVersionMin < ld::iOS_7_0 ) {
+                               //warning("-mios_version_min should be 7.0 or later for arm64");
+                               fIOSVersionMin = ld::iOS_7_0;
+                       }
+                       break;
        }
        
        // default to adding functions start for dynamic code, static code must opt-in
        }
        
        // default to adding functions start for dynamic code, static code must opt-in
@@ -3263,6 +3409,14 @@ void Options::reconfigureDefaults()
                                fAllowTextRelocs = true;
                                fUndefinedTreatment = kUndefinedDynamicLookup;
                                break;
                                fAllowTextRelocs = true;
                                fUndefinedTreatment = kUndefinedDynamicLookup;
                                break;
+                       case CPU_TYPE_ARM64:
+                               // arm64 uses new MH_KEXT_BUNDLE type
+                               fMakeCompressedDyldInfo = false;
+                               fMakeCompressedDyldInfoForceOff = true;
+                               fAllowTextRelocs = false; 
+                               fKextsUseStubs = true;
+                               fUndefinedTreatment = kUndefinedDynamicLookup;
+                               break;
                        case CPU_TYPE_ARM:
                                if ( fIOSVersionMin >= ld::iOS_5_0 ) {
                     // iOS 5.0 and later use new MH_KEXT_BUNDLE type
                        case CPU_TYPE_ARM:
                                if ( fIOSVersionMin >= ld::iOS_5_0 ) {
                     // iOS 5.0 and later use new MH_KEXT_BUNDLE type
@@ -3475,6 +3629,7 @@ void Options::reconfigureDefaults()
        switch ( fArchitecture ) {
                case CPU_TYPE_I386:             
                case CPU_TYPE_X86_64:           
        switch ( fArchitecture ) {
                case CPU_TYPE_I386:             
                case CPU_TYPE_X86_64:           
+               case CPU_TYPE_ARM64:            
                        switch ( fOutputKind ) {
                                case Options::kObjectFile:
                                case Options::kStaticExecutable:
                        switch ( fOutputKind ) {
                                case Options::kObjectFile:
                                case Options::kStaticExecutable:
@@ -3501,10 +3656,10 @@ void Options::reconfigureDefaults()
                        break;
        }
                
                        break;
        }
                
-       // only ARM main executables can be encrypted
+       // only iOS main executables should be encrypted
        if ( fOutputKind != Options::kDynamicExecutable )
                fEncryptable = false;
        if ( fOutputKind != Options::kDynamicExecutable )
                fEncryptable = false;
-       if ( fArchitecture != CPU_TYPE_ARM )
+       if ( (fArchitecture != CPU_TYPE_ARM) && (fArchitecture != CPU_TYPE_ARM64) )
                fEncryptable = false;
 
        // don't move inits in dyld because dyld wants certain
                fEncryptable = false;
 
        // don't move inits in dyld because dyld wants certain
@@ -3554,7 +3709,6 @@ void Options::reconfigureDefaults()
                        fMakeCompressedDyldInfo = false;
        }
 
                        fMakeCompressedDyldInfo = false;
        }
 
-
        // only ARM enforces that cpu-sub-types must match
        if ( fArchitecture != CPU_TYPE_ARM )
                fAllowCpuSubtypeMismatches = true;
        // only ARM enforces that cpu-sub-types must match
        if ( fArchitecture != CPU_TYPE_ARM )
                fAllowCpuSubtypeMismatches = true;
@@ -3611,6 +3765,11 @@ void Options::reconfigureDefaults()
        if ( fDisablePositionIndependentExecutable )
                fPositionIndependentExecutable = false;
 
        if ( fDisablePositionIndependentExecutable )
                fPositionIndependentExecutable = false;
 
+       // arm64 is always PIE
+       if ( (fArchitecture == CPU_TYPE_ARM64) && (fOutputKind == kDynamicExecutable) ) {
+               fPositionIndependentExecutable = true;
+       }
+
        // set fOutputSlidable
        switch ( fOutputKind ) {
                case Options::kObjectFile:
        // set fOutputSlidable
        switch ( fOutputKind ) {
                case Options::kObjectFile:
@@ -3653,13 +3812,6 @@ void Options::reconfigureDefaults()
                case Options::kDynamicBundle:
                        if ( !fVersionLoadCommandForcedOff )
                                fVersionLoadCommand = true;
                case Options::kDynamicBundle:
                        if ( !fVersionLoadCommandForcedOff )
                                fVersionLoadCommand = true;
-                       // <rdar://problem/9945513> for now, don't create version load commands for iOS simulator builds
-                       if ( fVersionLoadCommand && (fArchitecture == CPU_TYPE_I386) ) {
-                               for (std::vector<const char*>::iterator sdkit = fSDKPaths.begin(); sdkit != fSDKPaths.end(); sdkit++) {
-                                       if ( strstr(*sdkit, "/iPhoneSimulator.platform/") != NULL )
-                                               fVersionLoadCommand = false;
-                               }
-                       }
                        break;
        }
        
                        break;
        }
        
@@ -3699,12 +3851,7 @@ void Options::reconfigureDefaults()
                                fNeedsThreadLoadCommand = true;
                        }
                        else {
                                fNeedsThreadLoadCommand = true;
                        }
                        else {
-                               if ( (fIOSVersionMin != ld::iOSVersionUnset) && (fArchitecture == CPU_TYPE_I386) ) {
-                                       // don't use LC_MAIN for simulator until min host OS is 10.8 for simulator
-                                       fNeedsThreadLoadCommand = true;
-                                       fEntryPointLoadCommand = false;
-                               }
-                               else if ( minOS(ld::mac10_8, ld::iOS_6_0) ) {
+                               if ( minOS(ld::mac10_8, ld::iOS_6_0) ) {
                                        fEntryPointLoadCommand = true;
                                        fEntryName = "_main";
                                }
                                        fEntryPointLoadCommand = true;
                                        fEntryName = "_main";
                                }
@@ -3816,6 +3963,70 @@ void Options::reconfigureDefaults()
                }
        }
        
                }
        }
        
+       // allow trie based absolute symbols if targeting new enough OS
+       if ( fMakeCompressedDyldInfo ) {
+               if ( minOS(ld::mac10_9, ld::iOS_7_0) ) {
+                       // <rdar://problem/13179029> Allow absolute symbols in export trie for device but not simulator
+                       if ( !fTargetIOSSimulator ) 
+                               fAbsoluteSymbols = true;
+               }
+       }
+       
+       // <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/12258065> ARM64 needs 16KB page size for user land code
+       if ( fArchitecture == CPU_TYPE_ARM64 ) {
+               if ( fSegmentAlignment == 4096 ) {
+                       switch ( fOutputKind ) {
+                               case Options::kDynamicExecutable:
+                               case Options::kDynamicLibrary:
+                               case Options::kDynamicBundle:
+                               case Options::kDyld:
+                                       fSegmentAlignment = 4096*4;
+                                       break;
+                               case Options::kStaticExecutable:
+                               case Options::kKextBundle:
+                               case Options::kObjectFile:
+                               case Options::kPreload:
+                                       break;
+                       }
+               }
+       }
+       
+       // <rdar://problem/13624134> linker should not convert dwarf unwind if .o file has compact unwind section
+       switch ( fOutputKind ) {
+               case Options::kDynamicExecutable:
+               case Options::kDynamicLibrary:
+               case Options::kDynamicBundle:
+               case Options::kDyld:
+                       if ( fKeepDwarfUnwindForcedOn ) {
+                               fKeepDwarfUnwind = true;
+                       }
+                       else if ( fKeepDwarfUnwindForcedOff ) {
+                               fKeepDwarfUnwind = false;
+                       }
+                       else {
+                               if ( minOS(ld::mac10_9, ld::iOS_7_0) ) 
+                                       fKeepDwarfUnwind = false;
+                               else
+                                       fKeepDwarfUnwind = true;
+                       }
+                       break;
+               case Options::kKextBundle:
+               case Options::kStaticExecutable:
+               case Options::kObjectFile:
+               case Options::kPreload:
+                       fKeepDwarfUnwind = true;
+                       break;
+       }
+       
 }
 
 void Options::checkIllegalOptionCombinations()
 }
 
 void Options::checkIllegalOptionCombinations()
@@ -3890,6 +4101,7 @@ void Options::checkIllegalOptionCombinations()
                                        throw "-stack_addr must be < 4G for 32-bit processes";
                                break;
                        case CPU_TYPE_X86_64:
                                        throw "-stack_addr must be < 4G for 32-bit processes";
                                break;
                        case CPU_TYPE_X86_64:
+                       case CPU_TYPE_ARM64:
                                break;
                }
                if ( (fStackAddr & -4096) != fStackAddr )
                                break;
                }
                if ( (fStackAddr & -4096) != fStackAddr )
@@ -3917,11 +4129,19 @@ void Options::checkIllegalOptionCombinations()
                                        fStackAddr = 0x2F000000;
                 if ( fStackAddr > 0x30000000)
                     throw "-stack_addr must be < 0x30000000 for arm";
                                        fStackAddr = 0x2F000000;
                 if ( fStackAddr > 0x30000000)
                     throw "-stack_addr must be < 0x30000000 for arm";
+                               break;
                        case CPU_TYPE_X86_64:
                                if ( fStackAddr == 0 ) {
                                        fStackAddr = 0x00007FFF5C000000LL;
                                }
                                break;
                        case CPU_TYPE_X86_64:
                                if ( fStackAddr == 0 ) {
                                        fStackAddr = 0x00007FFF5C000000LL;
                                }
                                break;
+                       case CPU_TYPE_ARM64:
+                               if ( fStackSize > 0x20000000 )
+                                       throw "-stack_size must be < 512MB";
+                               if ( fStackAddr == 0 ) {
+                                       fStackAddr = 0x120000000;
+                               }
+                               break;
                }
                if ( (fStackSize & -4096) != fStackSize )
                        throw "-stack_size must be multiples of 4K";
                }
                if ( (fStackSize & -4096) != fStackSize )
                        throw "-stack_size must be multiples of 4K";
@@ -4018,6 +4238,10 @@ void Options::checkIllegalOptionCombinations()
        if ( fSetuidSafe && (fOutputKind == Options::kObjectFile) )
                throw "-setuid_safe cannot be used with -r";
 
        if ( fSetuidSafe && (fOutputKind == Options::kObjectFile) )
                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 )
+               fObjCABIVersion2Override = true;
+
        // rdar://problem/4718189 map ObjC class names to new runtime names
        bool alterObjC1ClassNamesToObjC2 = false;
        switch (fArchitecture) {
        // rdar://problem/4718189 map ObjC class names to new runtime names
        bool alterObjC1ClassNamesToObjC2 = false;
        switch (fArchitecture) {
@@ -4028,6 +4252,7 @@ void Options::checkIllegalOptionCombinations()
                        break;
                case CPU_TYPE_X86_64:
                case CPU_TYPE_ARM:
                        break;
                case CPU_TYPE_X86_64:
                case CPU_TYPE_ARM:
+               case CPU_TYPE_ARM64:
                        alterObjC1ClassNamesToObjC2 = true;
                        break;
        }
                        alterObjC1ClassNamesToObjC2 = true;
                        break;
        }
@@ -4123,6 +4348,7 @@ void Options::checkIllegalOptionCombinations()
                                // first 4KB for 32-bit architectures
                                fZeroPageSize = 0x1000;
                                break;
                                // first 4KB for 32-bit architectures
                                fZeroPageSize = 0x1000;
                                break;
+                       case CPU_TYPE_ARM64:
                        case CPU_TYPE_X86_64:
                                // first 4GB for x86_64 on all OS's
                                fZeroPageSize = 0x100000000ULL;
                        case CPU_TYPE_X86_64:
                                // first 4GB for x86_64 on all OS's
                                fZeroPageSize = 0x100000000ULL;
@@ -4392,3 +4618,41 @@ const char* Options::demangleSymbol(const char* sym) const
        return sym;
 }
 
        return sym;
 }
 
+
+void Options::dumpDependency(uint8_t opcode, const char* path) const
+{
+       if ( !this->dumpDependencyInfo() ) 
+               return;
+
+       // one time open() of -dependency_info file
+       if ( fDependencyFileDescriptor == -1 ) {
+               fDependencyFileDescriptor = open(this->dependencyInfoPath(), O_WRONLY | O_TRUNC | O_CREAT, 0666);
+               if ( fDependencyFileDescriptor == -1 )
+                       throwf("Could not open or create -dependency_info file: %s", this->dependencyInfoPath());
+
+               // write header
+               uint8_t version = depLinkerVersion;
+               if ( write(fDependencyFileDescriptor, &version, 1) == -1 )
+                       throwf("write() to -dependency_info failed, errno=%d", errno);
+               extern const char ldVersionString[];
+               if ( write(fDependencyFileDescriptor, ldVersionString, strlen(ldVersionString)+1) == -1 )
+                       throwf("write() to -dependency_info failed, errno=%d", errno);
+       }
+
+       char realPath[PATH_MAX];
+       if ( path[0] != '/' ) {
+               if ( realpath(path, realPath) != NULL ) {
+                       path = realPath;
+               }
+       }
+
+       if ( write(fDependencyFileDescriptor, &opcode, 1) == -1 )
+               throwf("write() to -dependency_info failed, errno=%d", errno);
+       if ( write(fDependencyFileDescriptor, path, strlen(path)+1) == -1 )
+               throwf("write() to -dependency_info failed, errno=%d", errno);
+
+       //fprintf(stderr, "0x%02X %s\n", opcode, path);
+}
+
+
+
index 41e5653a0f7ea9c195d0fd81210a7e4cb73e1636..d3e8d3fb7223f2b15bd165d576be75c37f878bf0 100644 (file)
@@ -45,13 +45,15 @@ class LibraryOptions
 {
 public:
        LibraryOptions() : fWeakImport(false), fReExport(false), fBundleLoader(false), 
 {
 public:
        LibraryOptions() : fWeakImport(false), fReExport(false), fBundleLoader(false), 
-                                               fLazyLoad(false), fUpward(false), fForceLoad(false) {}
+                                               fLazyLoad(false), fUpward(false), fIndirectDylib(false), 
+                                               fForceLoad(false) {}
        // for dynamic libraries
        bool            fWeakImport;
        bool            fReExport;
        bool            fBundleLoader;
        bool            fLazyLoad;
        bool            fUpward;
        // for dynamic libraries
        bool            fWeakImport;
        bool            fReExport;
        bool            fBundleLoader;
        bool            fLazyLoad;
        bool            fUpward;
+       bool            fIndirectDylib;
        // for static libraries
        bool            fForceLoad;
 };
        // for static libraries
        bool            fForceLoad;
 };
@@ -115,12 +117,12 @@ public:
         // If the object already has a path the p must be NULL.
         // If the object does not have a path then p can be any candidate path, and if the file exists the object permanently remembers the path.
         // Returns true if the file exists, false if not.
         // If the object already has a path the p must be NULL.
         // If the object does not have a path then p can be any candidate path, and if the file exists the object permanently remembers the path.
         // Returns true if the file exists, false if not.
-        bool checkFileExists(const char *p=NULL);
+        bool checkFileExists(const Options& options, const char *p=NULL);
         
         // Returns true if a previous call to checkFileExists() succeeded.
         // Returns false if the file does not exist of checkFileExists() has never been called.
         bool missing() const { return modTime==0; }
         
         // Returns true if a previous call to checkFileExists() succeeded.
         // Returns false if the file does not exist of checkFileExists() has never been called.
         bool missing() const { return modTime==0; }
-};
+       };
 
        struct ExtraSection {
                const char*                             segmentName;
 
        struct ExtraSection {
                const char*                             segmentName;
@@ -170,6 +172,13 @@ public:
                const char*                     alias;
        };
 
                const char*                     alias;
        };
 
+       enum { depLinkerVersion=0x00, depObjectFile=0x10, depDirectDylib=0x10, depIndirectDylib=0x10, 
+                 depUpwardDirectDylib=0x10, depUpwardIndirectDylib=0x10, depArchive=0x10,
+                 depFileList=0x10, depSection=0x10, depBundleLoader=0x10, depMisc=0x10, depNotFound=0x11,
+                 depOutputFile = 0x40 };
+       
+       void                                            dumpDependency(uint8_t, const char* path) const;
+       
        typedef const char* const*      UndefinesIterator;
 
 //     const ObjectFile::ReaderOptions&        readerOptions();
        typedef const char* const*      UndefinesIterator;
 
 //     const ObjectFile::ReaderOptions&        readerOptions();
@@ -322,25 +331,38 @@ public:
        bool                                            canReExportSymbols() const { return fCanReExportSymbols; }
        const char*                                     tempLtoObjectPath() const { return fTempLtoObjectPath; }
        const char*                                     overridePathlibLTO() const { return fOverridePathlibLTO; }
        bool                                            canReExportSymbols() const { return fCanReExportSymbols; }
        const char*                                     tempLtoObjectPath() const { return fTempLtoObjectPath; }
        const char*                                     overridePathlibLTO() const { return fOverridePathlibLTO; }
+       const char*                                     mcpuLTO() const { return fLtoCpu; }
        bool                                            objcCategoryMerging() const { return fObjcCategoryMerging; }
        bool                                            pageAlignDataAtoms() const { return fPageAlignDataAtoms; }
        bool                                            objcCategoryMerging() const { return fObjcCategoryMerging; }
        bool                                            pageAlignDataAtoms() const { return fPageAlignDataAtoms; }
+       bool                                            keepDwarfUnwind() const { return fKeepDwarfUnwind; }
+       bool                                            generateDtraceDOF() const { return fGenerateDtraceDOF; }
        bool                                            hasWeakBitTweaks() const;
        bool                                            forceWeak(const char* symbolName) const;
        bool                                            forceNotWeak(const char* symbolName) const;
        bool                                            forceWeakNonWildCard(const char* symbolName) const;
        bool                                            forceNotWeakNonWildcard(const char* symbolName) const;
        bool                                            hasWeakBitTweaks() const;
        bool                                            forceWeak(const char* symbolName) const;
        bool                                            forceNotWeak(const char* symbolName) const;
        bool                                            forceWeakNonWildCard(const char* symbolName) const;
        bool                                            forceNotWeakNonWildcard(const char* symbolName) const;
+       bool                                            forceCoalesce(const char* symbolName) const;
     Snapshot&                   snapshot() const { return fLinkSnapshot; }
        bool                                            errorBecauseOfWarnings() const;
        bool                                            needsThreadLoadCommand() const { return fNeedsThreadLoadCommand; }
        bool                                            needsEntryPointLoadCommand() const { return fEntryPointLoadCommand; }
        bool                                            needsSourceVersionLoadCommand() const { return fSourceVersionLoadCommand; }
        bool                                            needsDependentDRInfo() const { return fDependentDRInfo; }
     Snapshot&                   snapshot() const { return fLinkSnapshot; }
        bool                                            errorBecauseOfWarnings() const;
        bool                                            needsThreadLoadCommand() const { return fNeedsThreadLoadCommand; }
        bool                                            needsEntryPointLoadCommand() const { return fEntryPointLoadCommand; }
        bool                                            needsSourceVersionLoadCommand() const { return fSourceVersionLoadCommand; }
        bool                                            needsDependentDRInfo() const { return fDependentDRInfo; }
+       bool                                            canUseAbsoluteSymbols() const { return fAbsoluteSymbols; }
+       bool                                            allowSimulatorToLinkWithMacOSX() const { return fAllowSimulatorToLinkWithMacOSX; }
        uint64_t                                        sourceVersion() const { return fSourceVersion; }
        uint32_t                                        sdkVersion() const { return fSDKVersion; }
        const char*                                     demangleSymbol(const char* sym) const;
     bool                                               pipelineEnabled() const { return fPipelineFifo != NULL; }
     const char*                                        pipelineFifo() const { return fPipelineFifo; }
        uint64_t                                        sourceVersion() const { return fSourceVersion; }
        uint32_t                                        sdkVersion() const { return fSDKVersion; }
        const char*                                     demangleSymbol(const char* sym) const;
     bool                                               pipelineEnabled() const { return fPipelineFifo != NULL; }
     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&       
+                                                               linkerOptions() const { return fLinkerOptions; }
+       FileInfo                                        findFramework(const char* frameworkName) const;
+       FileInfo                                        findLibrary(const char* rootName, bool dylibsOnly=false) const;
+
 private:
        typedef std::unordered_map<const char*, unsigned int, ld::CStringHash, ld::CStringEquals> NameToOrder;
        typedef std::unordered_set<const char*, ld::CStringHash, ld::CStringEquals>  NameSet;
 private:
        typedef std::unordered_map<const char*, unsigned int, ld::CStringHash, ld::CStringEquals> NameToOrder;
        typedef std::unordered_set<const char*, ld::CStringHash, ld::CStringEquals>  NameSet;
@@ -372,9 +394,7 @@ private:
        void                                            checkIllegalOptionCombinations();
        void                                            buildSearchPaths(int argc, const char* argv[]);
        void                                            parseArch(const char* architecture);
        void                                            checkIllegalOptionCombinations();
        void                                            buildSearchPaths(int argc, const char* argv[]);
        void                                            parseArch(const char* architecture);
-       FileInfo                                        findLibrary(const char* rootName, bool dylibsOnly=false);
-       FileInfo                                        findFramework(const char* frameworkName);
-       FileInfo                                        findFramework(const char* rootName, const char* suffix);
+       FileInfo                                        findFramework(const char* rootName, const char* suffix) const;
        bool                                            checkForFile(const char* format, const char* dir, const char* rootName,
                                                                                         FileInfo& result) const;
        uint64_t                                        parseVersionNumber64(const char*);
        bool                                            checkForFile(const char* format, const char* dir, const char* rootName,
                                                                                         FileInfo& result) const;
        uint64_t                                        parseVersionNumber64(const char*);
@@ -441,6 +461,7 @@ private:
        SetWithWildcards                                        fForceWeakSymbols;
        SetWithWildcards                                        fForceNotWeakSymbols;
        SetWithWildcards                                        fReExportSymbols;
        SetWithWildcards                                        fForceWeakSymbols;
        SetWithWildcards                                        fForceNotWeakSymbols;
        SetWithWildcards                                        fReExportSymbols;
+       SetWithWildcards                                        fForceCoalesceSymbols;
        NameSet                                                         fRemovedExports;
        NameToOrder                                                     fExportSymbolsOrder;
        ExportMode                                                      fExportMode;
        NameSet                                                         fRemovedExports;
        NameToOrder                                                     fExportSymbolsOrder;
        ExportMode                                                      fExportMode;
@@ -464,6 +485,7 @@ private:
        const char*                                                     fDyldInstallPath;
        const char*                                                     fTempLtoObjectPath;
        const char*                                                     fOverridePathlibLTO;
        const char*                                                     fDyldInstallPath;
        const char*                                                     fTempLtoObjectPath;
        const char*                                                     fOverridePathlibLTO;
+       const char*                                                     fLtoCpu;
        uint64_t                                                        fZeroPageSize;
        uint64_t                                                        fStackSize;
        uint64_t                                                        fStackAddr;
        uint64_t                                                        fZeroPageSize;
        uint64_t                                                        fStackSize;
        uint64_t                                                        fStackAddr;
@@ -562,6 +584,14 @@ private:
        bool                                                            fDependentDRInfo;
        bool                                                            fDependentDRInfoForcedOn;
        bool                                                            fDependentDRInfoForcedOff;
        bool                                                            fDependentDRInfo;
        bool                                                            fDependentDRInfoForcedOn;
        bool                                                            fDependentDRInfoForcedOff;
+       bool                                                            fTargetIOSSimulator;
+       bool                                                            fExportDynamic;
+       bool                                                            fAbsoluteSymbols;
+       bool                                                            fAllowSimulatorToLinkWithMacOSX;
+       bool                                                            fKeepDwarfUnwind;
+       bool                                                            fKeepDwarfUnwindForcedOn;
+       bool                                                            fKeepDwarfUnwindForcedOff;
+       bool                                                            fGenerateDtraceDOF;
        DebugInfoStripping                                      fDebugInfoStripping;
        const char*                                                     fTraceOutputFile;
        ld::MacVersionMin                                       fMacVersionMin;
        DebugInfoStripping                                      fDebugInfoStripping;
        const char*                                                     fTraceOutputFile;
        ld::MacVersionMin                                       fMacVersionMin;
@@ -582,10 +612,13 @@ private:
        std::vector<const char*>                        fFrameworkSearchPaths;
        std::vector<const char*>                        fSDKPaths;
        std::vector<const char*>                        fDyldEnvironExtras;
        std::vector<const char*>                        fFrameworkSearchPaths;
        std::vector<const char*>                        fSDKPaths;
        std::vector<const char*>                        fDyldEnvironExtras;
+       std::vector< std::vector<const char*> > fLinkerOptions;
        bool                                                            fSaveTempFiles;
        bool                                                            fSaveTempFiles;
-    mutable Snapshot                  fLinkSnapshot;
-    bool                              fSnapshotRequested;
-    const char *                      fPipelineFifo;
+    mutable Snapshot                                   fLinkSnapshot;
+    bool                                                               fSnapshotRequested;
+    const char*                                                        fPipelineFifo;
+       const char*                                                     fDependencyInfoPath;
+       mutable int                                                     fDependencyFileDescriptor;
 };
 
 
 };
 
 
index 16fdd66cc3d07a3756f9802b4cfbc60e2305347b..8b0be0a1398d11bbeda23e4c2ebd3d60c6635829 100644 (file)
@@ -344,14 +344,25 @@ void OutputFile::setSectionSizesAndAlignments(ld::Internal& state)
                                const ld::Atom* atom = *ait;
                                bool pagePerAtom = false;
                                uint32_t atomAlignmentPowerOf2 = atom->alignment().powerOf2;
                                const ld::Atom* atom = *ait;
                                bool pagePerAtom = false;
                                uint32_t atomAlignmentPowerOf2 = atom->alignment().powerOf2;
+                               uint32_t atomModulus = atom->alignment().modulus;
                                if ( _options.pageAlignDataAtoms() && ( strcmp(atom->section().segmentName(), "__DATA") == 0) ) { 
                                if ( _options.pageAlignDataAtoms() && ( strcmp(atom->section().segmentName(), "__DATA") == 0) ) { 
+                                       // most objc sections cannot be padded
+                                       bool contiguousObjCSection = ( strncmp(atom->section().sectionName(), "__objc_", 7) == 0 );
+                                       if ( strcmp(atom->section().sectionName(), "__objc_const") == 0 )
+                                               contiguousObjCSection = false;
+                                       if ( strcmp(atom->section().sectionName(), "__objc_data") == 0 )
+                                               contiguousObjCSection = false;
                                        switch ( atom->section().type() ) {
                                                case ld::Section::typeUnclassified:
                                                case ld::Section::typeTentativeDefs:
                                                case ld::Section::typeZeroFill:
                                        switch ( atom->section().type() ) {
                                                case ld::Section::typeUnclassified:
                                                case ld::Section::typeTentativeDefs:
                                                case ld::Section::typeZeroFill:
+                                                       if ( contiguousObjCSection ) 
+                                                               break;
                                                        pagePerAtom = true;
                                                        pagePerAtom = true;
-                                                       if ( atomAlignmentPowerOf2 < 12 )
+                                                       if ( atomAlignmentPowerOf2 < 12 ) {
                                                                atomAlignmentPowerOf2 = 12;
                                                                atomAlignmentPowerOf2 = 12;
+                                                               atomModulus = 0;
+                                                       }
                                                        break;
                                                default:
                                                        break;
                                                        break;
                                                default:
                                                        break;
@@ -362,7 +373,7 @@ void OutputFile::setSectionSizesAndAlignments(ld::Internal& state)
                                // calculate section offset for this atom
                                uint64_t alignment = 1 << atomAlignmentPowerOf2;
                                uint64_t currentModulus = (offset % alignment);
                                // calculate section offset for this atom
                                uint64_t alignment = 1 << atomAlignmentPowerOf2;
                                uint64_t currentModulus = (offset % alignment);
-                               uint64_t requiredModulus = atom->alignment().modulus;
+                               uint64_t requiredModulus = atomModulus;
                                if ( currentModulus != requiredModulus ) {
                                        if ( requiredModulus > currentModulus )
                                                offset += requiredModulus-currentModulus;
                                if ( currentModulus != requiredModulus ) {
                                        if ( requiredModulus > currentModulus )
                                                offset += requiredModulus-currentModulus;
@@ -965,7 +976,33 @@ void OutputFile::rangeCheckThumbBranch22(int64_t displacement, ld::Internal& sta
 }
 
 
 }
 
 
+void OutputFile::rangeCheckARM64Branch26(int64_t displacement, ld::Internal& state, const ld::Atom* atom, const ld::Fixup* fixup)
+{
+       const int64_t bl_128MegLimit = 0x07FFFFFF;
+       if ( (displacement > bl_128MegLimit) || (displacement < (-bl_128MegLimit)) ) {
+               // show layout of final image
+               printSectionLayout(state);
+               
+               const ld::Atom* target; 
+               throwf("b(l) ARM64 branch out of range (%lld max is +/-128MB): from %s (0x%08llX) to %s (0x%08llX)", 
+                               displacement, atom->name(), atom->finalAddress(), referenceTargetAtomName(state, fixup), 
+                               addressOf(state, fixup, &target));
+       }
+}
 
 
+void OutputFile::rangeCheckARM64Page21(int64_t displacement, ld::Internal& state, const ld::Atom* atom, const ld::Fixup* fixup)
+{
+       const int64_t adrp_4GigLimit = 0x100000000ULL;
+       if ( (displacement > adrp_4GigLimit) || (displacement < (-adrp_4GigLimit)) ) {
+               // show layout of final image
+               printSectionLayout(state);
+               
+               const ld::Atom* target; 
+               throwf("ARM64 ADRP out of range (%lld max is +/-4GB): from %s (0x%08llX) to %s (0x%08llX)", 
+                               displacement, atom->name(), atom->finalAddress(), referenceTargetAtomName(state, fixup), 
+                               addressOf(state, fixup, &target));
+       }
+}
 
 
 uint16_t OutputFile::get16LE(uint8_t* loc) { return LittleEndian::get16(*(uint16_t*)loc); }
 
 
 uint16_t OutputFile::get16LE(uint8_t* loc) { return LittleEndian::get16(*(uint16_t*)loc); }
@@ -1023,16 +1060,18 @@ void OutputFile::applyFixUps(ld::Internal& state, uint64_t mhAddress, const ld::
                                        accumulator -= delta;
                                break;
                        case ld::Fixup::kindAddAddend:
                                        accumulator -= delta;
                                break;
                        case ld::Fixup::kindAddAddend:
-                               // <rdar://problem/8342028> ARM main executables main contain .long constants pointing
-                               // into themselves such as jump tables.  These .long should not have thumb bit set
-                               // even though the target is a thumb instruction. We can tell it is an interior pointer
-                               // because we are processing an addend. 
-                               if ( thumbTarget && (toTarget == atom) && ((int32_t)fit->u.addend > 0) ) {
-                                       accumulator &= (-2);
-                                       //warning("removing thumb bit from intra-atom pointer in %s %s+0x%0X", 
-                                       //              atom->section().sectionName(), atom->name(), fit->offsetInAtom);
+                               if ( ! fit->contentIgnoresAddend ) {
+                                       // <rdar://problem/8342028> ARM main executables main contain .long constants pointing
+                                       // into themselves such as jump tables.  These .long should not have thumb bit set
+                                       // even though the target is a thumb instruction. We can tell it is an interior pointer
+                                       // because we are processing an addend. 
+                                       if ( thumbTarget && (toTarget == atom) && ((int32_t)fit->u.addend > 0) ) {
+                                               accumulator &= (-2);
+                                               //warning("removing thumb bit from intra-atom pointer in %s %s+0x%0X", 
+                                               //              atom->section().sectionName(), atom->name(), fit->offsetInAtom);
+                                       }
+                                       accumulator += fit->u.addend;
                                }
                                }
-                               accumulator += fit->u.addend;
                                break;
                        case ld::Fixup::kindSubtractAddend:
                                accumulator -= fit->u.addend;
                                break;
                        case ld::Fixup::kindSubtractAddend:
                                accumulator -= fit->u.addend;
@@ -1229,6 +1268,18 @@ void OutputFile::applyFixUps(ld::Internal& state, uint64_t mhAddress, const ld::
                                        set32LE(fixUpLocation, 0x46C04040);
                                }
                                break;
                                        set32LE(fixUpLocation, 0x46C04040);
                                }
                                break;
+                       case ld::Fixup::kindStoreARM64DtraceCallSiteNop:
+                               if ( _options.outputKind() != Options::kObjectFile ) {
+                                       // change call site to a NOP
+                                       set32LE(fixUpLocation, 0xD503201F);
+                               }
+                               break;
+                       case ld::Fixup::kindStoreARM64DtraceIsEnableSiteClear:
+                               if ( _options.outputKind() != Options::kObjectFile ) {
+                                       // change call site to 'MOVZ X0,0'
+                                       set32LE(fixUpLocation, 0xD2800000);
+                               }
+                               break;
                        case ld::Fixup::kindLazyTarget:
                                break;
                        case ld::Fixup::kindSetLazyOffset:
                        case ld::Fixup::kindLazyTarget:
                                break;
                        case ld::Fixup::kindSetLazyOffset:
@@ -1504,6 +1555,126 @@ void OutputFile::applyFixUps(ld::Internal& state, uint64_t mhAddress, const ld::
                                        set32LE(fixUpLocation, newInstruction);         
                                }
                                break;
                                        set32LE(fixUpLocation, newInstruction);         
                                }
                                break;
+#if SUPPORT_ARCH_arm64
+                       case ld::Fixup::kindStoreTargetAddressARM64Branch26:
+                               accumulator = addressOf(state, fit, &toTarget);
+                               // fall into kindStoreARM64Branch26 case
+                       case ld::Fixup::kindStoreARM64Branch26:
+                               if ( fit->contentAddendOnly )
+                                       delta = accumulator;
+                               else
+                    delta = accumulator - (atom->finalAddress() + fit->offsetInAtom);
+                               rangeCheckARM64Branch26(delta, state, atom, fit);
+                               instruction = get32LE(fixUpLocation);
+                               newInstruction = (instruction & 0xFC000000) | ((uint32_t)(delta >> 2) & 0x03FFFFFF);
+                               set32LE(fixUpLocation, newInstruction);
+                               break;
+                       case ld::Fixup::kindStoreTargetAddressARM64GOTLeaPage21:
+                       case ld::Fixup::kindStoreTargetAddressARM64GOTLoadPage21:
+                       case ld::Fixup::kindStoreTargetAddressARM64Page21:
+                               accumulator = addressOf(state, fit, &toTarget);
+                               // fall into kindStoreARM64Branch26 case
+                       case ld::Fixup::kindStoreARM64GOTLeaPage21:
+                       case ld::Fixup::kindStoreARM64GOTLoadPage21:
+                       case ld::Fixup::kindStoreARM64TLVPLoadPage21:
+                       case ld::Fixup::kindStoreARM64Page21:
+                               {
+                                       // the ADRP instruction adds the imm << 12 to the page that the pc is on
+                                       if ( fit->contentAddendOnly )
+                                               delta = 0;
+                                       else
+                                               delta = (accumulator & (-4096)) - ((atom->finalAddress() + fit->offsetInAtom) & (-4096));
+                                       rangeCheckARM64Page21(delta, state, atom, fit);
+                                       instruction = get32LE(fixUpLocation);
+                                       uint32_t immhi = (delta >> 9) & (0x00FFFFE0);
+                                       uint32_t immlo = (delta << 17) & (0x60000000);
+                                       newInstruction = (instruction & 0x9F00001F) | immlo | immhi;
+                                       set32LE(fixUpLocation, newInstruction);
+                               }
+                               break;
+                       case ld::Fixup::kindStoreTargetAddressARM64GOTLoadPageOff12:
+                       case ld::Fixup::kindStoreTargetAddressARM64PageOff12:
+                               accumulator = addressOf(state, fit, &toTarget);
+                               // fall into kindAddressARM64PageOff12 case
+                       case ld::Fixup::kindStoreARM64TLVPLoadPageOff12:
+                       case ld::Fixup::kindStoreARM64GOTLoadPageOff12:
+                       case ld::Fixup::kindStoreARM64PageOff12:
+                               {
+                                       uint32_t offset = accumulator & 0x00000FFF;
+                                       instruction = get32LE(fixUpLocation);
+                                       // LDR/STR instruction have implicit scale factor, need to compensate for that
+                                       if ( instruction & 0x08000000 ) {
+                                               uint32_t implictShift = ((instruction >> 30) & 0x3);
+                                               switch ( implictShift ) {
+                                                       case 0:
+                                                               if ( (instruction & 0x04800000) == 0x04800000 ) {
+                                                                       // vector and byte LDR/STR have same "size" bits, need to check other bits to differenciate
+                                                                       implictShift = 4;
+                                                                       if ( (offset & 0xF) != 0 ) {
+                                                                                       throwf("128-bit LDR/STR not 16-byte aligned: from %s (0x%08llX) to %s (0x%08llX)", 
+                                                                                               atom->name(), atom->finalAddress(), referenceTargetAtomName(state, fit), 
+                                                                                               addressOf(state, fit, &toTarget));
+                                                                       }
+                                                               }
+                                                               break;
+                                                       case 1:
+                                                               if ( (offset & 0x1) != 0 ) {
+                                                                               throwf("16-bit LDR/STR not 2-byte aligned: from %s (0x%08llX) to %s (0x%08llX)", 
+                                                                                       atom->name(), atom->finalAddress(), referenceTargetAtomName(state, fit), 
+                                                                                       addressOf(state, fit, &toTarget));
+                                                               }
+                                                               break;
+                                                       case 2:
+                                                               if ( (offset & 0x3) != 0 ) {
+                                                                               throwf("32-bit LDR/STR not 4-byte aligned: from %s (0x%08llX) to %s (0x%08llX)", 
+                                                                                       atom->name(), atom->finalAddress(), referenceTargetAtomName(state, fit), 
+                                                                                       addressOf(state, fit, &toTarget));
+                                                               }
+                                                               break;
+                                                       case 3:
+                                                               if ( (offset & 0x7) != 0 ) {
+                                                                               throwf("64-bit LDR/STR not 8-byte aligned: from %s (0x%08llX) to %s (0x%08llX)", 
+                                                                                       atom->name(), atom->finalAddress(), referenceTargetAtomName(state, fit), 
+                                                                                       addressOf(state, fit, &toTarget));
+                                                               }
+                                                               break;
+                                               }
+                                               // compensate for implicit scale
+                                               offset >>= implictShift;
+                                       }
+                                       if ( fit->contentAddendOnly )
+                                               offset = 0;
+                                       uint32_t imm12 = offset << 10;
+                                       newInstruction = (instruction & 0xFFC003FF) | imm12;
+                                       set32LE(fixUpLocation, newInstruction);
+                               }
+                               break;
+                       case ld::Fixup::kindStoreTargetAddressARM64GOTLeaPageOff12:
+                               accumulator = addressOf(state, fit, &toTarget);
+                               // fall into kindStoreARM64GOTLoadPage21 case
+                       case ld::Fixup::kindStoreARM64GOTLeaPageOff12:
+                               {
+                                       // GOT entry was optimized away, change LDR instruction to a ADD
+                                       instruction = get32LE(fixUpLocation);
+                                       if ( (instruction & 0xFFC00000) != 0xF9400000 )
+                                               throwf("GOT load reloc does not point to a LDR instruction in %s", atom->name());
+                                       uint32_t offset = accumulator & 0x00000FFF;
+                                       uint32_t imm12 = offset << 10;
+                                       newInstruction = 0x91000000 | imm12 | (instruction & 0x000003FF);
+                                       set32LE(fixUpLocation, newInstruction);
+                               }
+                               break;
+                       case ld::Fixup::kindStoreARM64PointerToGOT:
+                               set64LE(fixUpLocation, accumulator);
+                               break;
+            case ld::Fixup::kindStoreARM64PCRelToGOT:
+                               if ( fit->contentAddendOnly )
+                                       delta = accumulator;
+                               else
+                                       delta = accumulator - (atom->finalAddress() + fit->offsetInAtom);
+                               set32LE(fixUpLocation, delta);
+                               break;
+#endif
                }
        }
 }
                }
        }
 }
@@ -1746,8 +1917,15 @@ void OutputFile::writeOutputFile(ld::Internal& state)
                        fd = open(tmpOutput, O_RDWR|O_CREAT, permissions);
                }
                if ( fd == -1 ) 
                        fd = open(tmpOutput, O_RDWR|O_CREAT, permissions);
                }
                if ( fd == -1 ) 
-                       throwf("can't open output file for writing: %s, errno=%d", tmpOutput, errno);
-               ftruncate(fd, _fileSize);
+                       throwf("can't open output file for writing '%s', errno=%d", tmpOutput, errno);
+               if ( ftruncate(fd, _fileSize) == -1 ) {
+                       int err = errno;
+                       unlink(tmpOutput);
+                       if ( err == ENOSPC )
+                               throwf("not enough disk space for writing '%s'", _options.outputFilePath());
+                       else
+                               throwf("can't grow file for writing '%s', errno=%d", _options.outputFilePath(), err);
+               }
                
                wholeBuffer = (uint8_t *)mmap(NULL, _fileSize, PROT_WRITE|PROT_READ, MAP_SHARED, fd, 0);
                if ( wholeBuffer == MAP_FAILED )
                
                wholeBuffer = (uint8_t *)mmap(NULL, _fileSize, PROT_WRITE|PROT_READ, MAP_SHARED, fd, 0);
                if ( wholeBuffer == MAP_FAILED )
@@ -1792,6 +1970,10 @@ void OutputFile::writeOutputFile(ld::Internal& state)
                if ( ::write(fd, wholeBuffer, _fileSize) == -1 ) {
                        throwf("can't write to output file: %s, errno=%d", _options.outputFilePath(), errno);
                }
                if ( ::write(fd, wholeBuffer, _fileSize) == -1 ) {
                        throwf("can't write to output file: %s, errno=%d", _options.outputFilePath(), errno);
                }
+               ::close(fd);
+               // <rdar://problem/13118223> NFS: iOS incremental builds in Xcode 4.6 fail with codesign error
+               // NFS seems to pad the end of the file sometimes.  Calling trunc seems to correct it...
+               ::truncate(_options.outputFilePath(), _fileSize);
        }
 }
 
        }
 }
 
@@ -1837,7 +2019,7 @@ void OutputFile::buildSymbolTable(ld::Internal& state)
                                
                        // in -r mode, clarify symbolTableNotInFinalLinkedImages
                        if ( _options.outputKind() == Options::kObjectFile ) {
                                
                        // in -r mode, clarify symbolTableNotInFinalLinkedImages
                        if ( _options.outputKind() == Options::kObjectFile ) {
-                               if ( _options.architecture() == CPU_TYPE_X86_64 ) {
+                               if ( (_options.architecture() == CPU_TYPE_X86_64) || (_options.architecture() == CPU_TYPE_ARM64) ) {
                                        // x86_64 .o files need labels on anonymous literal strings
                                        if ( (sect->type() == ld::Section::typeCString) && (atom->combine() == ld::Atom::combineByNameAndContent) ) {
                                                (const_cast<ld::Atom*>(atom))->setSymbolTableInclusion(ld::Atom::symbolTableIn);
                                        // x86_64 .o files need labels on anonymous literal strings
                                        if ( (sect->type() == ld::Section::typeCString) && (atom->combine() == ld::Atom::combineByNameAndContent) ) {
                                                (const_cast<ld::Atom*>(atom))->setSymbolTableInclusion(ld::Atom::symbolTableIn);
@@ -1929,7 +2111,6 @@ void OutputFile::buildSymbolTable(ld::Internal& state)
                                case ld::Atom::scopeLinkageUnit:
                                        if ( _options.outputKind() == Options::kObjectFile ) {
                                                if ( _options.keepPrivateExterns() ) {
                                case ld::Atom::scopeLinkageUnit:
                                        if ( _options.outputKind() == Options::kObjectFile ) {
                                                if ( _options.keepPrivateExterns() ) {
-                                                       assert( (atom->combine() == ld::Atom::combineNever) || (atom->combine() == ld::Atom::combineByName) );
                                                        _exportedAtoms.push_back(atom);
                                                }
                                                else if ( _options.keepLocalSymbol(atom->name()) ) {
                                                        _exportedAtoms.push_back(atom);
                                                }
                                                else if ( _options.keepLocalSymbol(atom->name()) ) {
@@ -2048,9 +2229,29 @@ void OutputFile::addPreloadLinkEdit(ld::Internal& state)
                                stringPoolSection = state.addAtom(*_stringPoolAtom);
                        }
                        break;
                                stringPoolSection = state.addAtom(*_stringPoolAtom);
                        }
                        break;
+#endif
+#if SUPPORT_ARCH_arm64
+               case CPU_TYPE_ARM64:
+                       if ( _hasLocalRelocations ) {
+                               _localRelocsAtom = new LocalRelocationsAtom<arm64>(_options, state, *this);
+                               localRelocationsSection = state.addAtom(*_localRelocsAtom);
+                       }
+                       if ( _hasExternalRelocations ) {
+                               _externalRelocsAtom = new ExternalRelocationsAtom<arm64>(_options, state, *this);
+                               externalRelocationsSection = state.addAtom(*_externalRelocsAtom);
+                       }
+                       if ( _hasSymbolTable ) {
+                               _indirectSymbolTableAtom = new IndirectSymbolTableAtom<arm64>(_options, state, *this);
+                               indirectSymbolTableSection = state.addAtom(*_indirectSymbolTableAtom);
+                               _symbolTableAtom = new SymbolTableAtom<arm64>(_options, state, *this);
+                               symbolTableSection = state.addAtom(*_symbolTableAtom);
+                               _stringPoolAtom = new StringPoolAtom(_options, state, *this, 4);
+                               stringPoolSection = state.addAtom(*_stringPoolAtom);
+                       }
+                       break;
 #endif
                default:
 #endif
                default:
-                       throw "architecture not supported for -preload";
+                       throw "-preload not supported";
        }
 
 }
        }
 
 }
@@ -2236,6 +2437,64 @@ void OutputFile::addLinkEdit(ld::Internal& state)
                                stringPoolSection = state.addAtom(*_stringPoolAtom);
                        }
                        break;
                                stringPoolSection = state.addAtom(*_stringPoolAtom);
                        }
                        break;
+#endif
+#if SUPPORT_ARCH_arm64
+               case CPU_TYPE_ARM64:
+                       if ( _hasSectionRelocations ) {
+                               _sectionsRelocationsAtom = new SectionRelocationsAtom<arm64>(_options, state, *this);
+                               sectionRelocationsSection = state.addAtom(*_sectionsRelocationsAtom);
+                       }
+                       if ( _hasDyldInfo ) {
+                               _rebasingInfoAtom = new RebaseInfoAtom<arm64>(_options, state, *this);
+                               rebaseSection = state.addAtom(*_rebasingInfoAtom);
+                               
+                               _bindingInfoAtom = new BindingInfoAtom<arm64>(_options, state, *this);
+                               bindingSection = state.addAtom(*_bindingInfoAtom);
+                               
+                               _weakBindingInfoAtom = new WeakBindingInfoAtom<arm64>(_options, state, *this);
+                               weakBindingSection = state.addAtom(*_weakBindingInfoAtom);
+                               
+                               _lazyBindingInfoAtom = new LazyBindingInfoAtom<arm64>(_options, state, *this);
+                               lazyBindingSection = state.addAtom(*_lazyBindingInfoAtom);
+                               
+                               _exportInfoAtom = new ExportInfoAtom<arm64>(_options, state, *this);
+                               exportSection = state.addAtom(*_exportInfoAtom);
+                       }
+                       if ( _hasLocalRelocations ) {
+                               _localRelocsAtom = new LocalRelocationsAtom<arm64>(_options, state, *this);
+                               localRelocationsSection = state.addAtom(*_localRelocsAtom);
+                       }
+                       if  ( _hasSplitSegInfo ) {
+                               _splitSegInfoAtom = new SplitSegInfoAtom<arm64>(_options, state, *this);
+                               splitSegInfoSection = state.addAtom(*_splitSegInfoAtom);
+                       }
+                       if ( _hasFunctionStartsInfo ) {
+                               _functionStartsAtom = new FunctionStartsAtom<arm64>(_options, state, *this);
+                               functionStartsSection = state.addAtom(*_functionStartsAtom);
+                       }
+                       if ( _hasDataInCodeInfo ) {
+                               _dataInCodeAtom = new DataInCodeAtom<arm64>(_options, state, *this);
+                               dataInCodeSection = state.addAtom(*_dataInCodeAtom);
+                       }
+                       if ( _hasDependentDRInfo ) {
+                               _dependentDRInfoAtom = new DependentDRAtom<arm64>(_options, state, *this);
+                               dependentDRsSection = state.addAtom(*_dependentDRInfoAtom);
+                       }
+                       if ( _hasSymbolTable ) {
+                               _symbolTableAtom = new SymbolTableAtom<arm64>(_options, state, *this);
+                               symbolTableSection = state.addAtom(*_symbolTableAtom);
+                       }
+                       if ( _hasExternalRelocations ) {
+                               _externalRelocsAtom = new ExternalRelocationsAtom<arm64>(_options, state, *this);
+                               externalRelocationsSection = state.addAtom(*_externalRelocsAtom);
+                       }
+                       if ( _hasSymbolTable ) {
+                               _indirectSymbolTableAtom = new IndirectSymbolTableAtom<arm64>(_options, state, *this);
+                               indirectSymbolTableSection = state.addAtom(*_indirectSymbolTableAtom);
+                               _stringPoolAtom = new StringPoolAtom(_options, state, *this, 4);
+                               stringPoolSection = state.addAtom(*_stringPoolAtom);
+                       }
+                       break;
 #endif
                default:
                        throw "unknown architecture";
 #endif
                default:
                        throw "unknown architecture";
@@ -2257,6 +2516,12 @@ void OutputFile::addLoadCommands(ld::Internal& state)
                        headerAndLoadCommandsSection = state.addAtom(*_headersAndLoadCommandAtom);
                        break;
 #endif
                        headerAndLoadCommandsSection = state.addAtom(*_headersAndLoadCommandAtom);
                        break;
 #endif
+#if SUPPORT_ARCH_arm64
+               case CPU_TYPE_ARM64:
+                       _headersAndLoadCommandAtom = new HeaderAndLoadCommandsAtom<arm64>(_options, state, *this);
+                       headerAndLoadCommandsSection = state.addAtom(*_headersAndLoadCommandAtom);
+                       break;
+#endif
 #if SUPPORT_ARCH_i386
                case CPU_TYPE_I386:
                        _headersAndLoadCommandAtom = new HeaderAndLoadCommandsAtom<x86>(_options, state, *this);
 #if SUPPORT_ARCH_i386
                case CPU_TYPE_I386:
                        _headersAndLoadCommandAtom = new HeaderAndLoadCommandsAtom<x86>(_options, state, *this);
@@ -2430,8 +2695,26 @@ bool OutputFile::isPcRelStore(ld::Fixup::Kind kind)
                case ld::Fixup::kindStoreTargetAddressARMBranch24:
                case ld::Fixup::kindStoreTargetAddressThumbBranch22:
                case ld::Fixup::kindStoreTargetAddressARMLoad12:
                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::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:
+#endif
                        return true;
                case ld::Fixup::kindStoreTargetAddressX86BranchPCRel32:
                        return true;
                case ld::Fixup::kindStoreTargetAddressX86BranchPCRel32:
+#if SUPPORT_ARCH_arm64
+               case ld::Fixup::kindStoreTargetAddressARM64Branch26:
+#endif
                        return (_options.outputKind() != Options::kKextBundle);
                default:
                        break;
                        return (_options.outputKind() != Options::kKextBundle);
                default:
                        break;
@@ -2476,15 +2759,27 @@ bool OutputFile::setsTarget(ld::Fixup::Kind kind)
                case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoad:
                case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoadNowLEA:
                case ld::Fixup::kindStoreTargetAddressX86PCRel32TLVLoad:
                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:
                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:
+#endif
                        return true;
                case ld::Fixup::kindStoreX86DtraceCallSiteNop:
                case ld::Fixup::kindStoreX86DtraceIsEnableSiteClear:
                case ld::Fixup::kindStoreARMDtraceCallSiteNop:
                case ld::Fixup::kindStoreARMDtraceIsEnableSiteClear:
                        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);
                case ld::Fixup::kindStoreThumbDtraceCallSiteNop:
                case ld::Fixup::kindStoreThumbDtraceIsEnableSiteClear:
                        return (_options.outputKind() == Options::kObjectFile);
@@ -2590,6 +2885,7 @@ void OutputFile::generateLinkEditInfo(ld::Internal& state)
                        ld::Fixup*                      fixupWithTarget = NULL;
                        ld::Fixup*                      fixupWithMinusTarget = NULL;
                        ld::Fixup*                      fixupWithStore = NULL;
                        ld::Fixup*                      fixupWithTarget = NULL;
                        ld::Fixup*                      fixupWithMinusTarget = NULL;
                        ld::Fixup*                      fixupWithStore = NULL;
+                       ld::Fixup*                      fixupWithAddend = NULL;
                        const ld::Atom*         target = NULL;
                        const ld::Atom*         minusTarget = NULL;
                        uint64_t                        targetAddend = 0;
                        const ld::Atom*         target = NULL;
                        const ld::Atom*         minusTarget = NULL;
                        uint64_t                        targetAddend = 0;
@@ -2624,9 +2920,11 @@ void OutputFile::generateLinkEditInfo(ld::Internal& state)
                                switch ( fit->kind ) {
                                        case ld::Fixup::kindAddAddend:
                                                targetAddend = fit->u.addend;
                                switch ( fit->kind ) {
                                        case ld::Fixup::kindAddAddend:
                                                targetAddend = fit->u.addend;
+                                               fixupWithAddend = fit;
                                                break;
                                        case ld::Fixup::kindSubtractAddend:
                                                minusTargetAddend = fit->u.addend;
                                                break;
                                        case ld::Fixup::kindSubtractAddend:
                                                minusTargetAddend = fit->u.addend;
+                                               fixupWithAddend = fit;
                                                break;
                                        case ld::Fixup::kindSubtractTargetAddress:
                                                switch ( fit->binding ) {
                                                break;
                                        case ld::Fixup::kindSubtractTargetAddress:
                                                switch ( fit->binding ) {
@@ -2662,7 +2960,7 @@ void OutputFile::generateLinkEditInfo(ld::Internal& state)
                                if ( fit->lastInCluster() ) {
                                        if ( (fixupWithStore != NULL) && (target != NULL) ) {
                                                if ( _options.outputKind() == Options::kObjectFile ) {
                                if ( fit->lastInCluster() ) {
                                        if ( (fixupWithStore != NULL) && (target != NULL) ) {
                                                if ( _options.outputKind() == Options::kObjectFile ) {
-                                                       this->addSectionRelocs(state, sect, atom, fixupWithTarget, fixupWithMinusTarget, fixupWithStore,
+                                                       this->addSectionRelocs(state, sect, atom, fixupWithTarget, fixupWithMinusTarget, fixupWithAddend, fixupWithStore,
                                                                                                        target, minusTarget, targetAddend, minusTargetAddend);
                                                }
                                                else {
                                                                                                        target, minusTarget, targetAddend, minusTargetAddend);
                                                }
                                                else {
@@ -2701,10 +2999,19 @@ void OutputFile::noteTextReloc(const ld::Atom* atom, const ld::Atom* target)
        else if ( _options.positionIndependentExecutable() && (_options.outputKind() == Options::kDynamicExecutable) 
                && ((_options.iOSVersionMin() >= ld::iOS_4_3) || (_options.macosxVersionMin() >= ld::mac10_7)) ) {
                if ( ! this->pieDisabled ) {
        else if ( _options.positionIndependentExecutable() && (_options.outputKind() == Options::kDynamicExecutable) 
                && ((_options.iOSVersionMin() >= ld::iOS_4_3) || (_options.macosxVersionMin() >= ld::mac10_7)) ) {
                if ( ! this->pieDisabled ) {
-                       warning("PIE disabled. Absolute addressing (perhaps -mdynamic-no-pic) not allowed in code signed PIE, "
+#if SUPPORT_ARCH_arm64
+                       if ( _options.architecture() == CPU_TYPE_ARM64 ) {
+                               const char* demangledName = strdup(_options.demangleSymbol(atom->name()));
+                               throwf("Absolute addressing not allowed in arm64 code but used in '%s' referencing '%s'", demangledName, _options.demangleSymbol(target->name()));
+                       }
+                       else
+#endif
+                        {
+                               warning("PIE disabled. Absolute addressing (perhaps -mdynamic-no-pic) not allowed in code signed PIE, "
                                "but used in %s from %s. " 
                                "To fix this warning, don't compile with -mdynamic-no-pic or link with -Wl,-no_pie", 
                                atom->name(), atom->file()->path());
                                "but used in %s from %s. " 
                                "To fix this warning, don't compile with -mdynamic-no-pic or link with -Wl,-no_pie", 
                                atom->name(), atom->file()->path());
+                       }
                }
                this->pieDisabled = true;
        }
                }
                this->pieDisabled = true;
        }
@@ -2712,7 +3019,10 @@ void OutputFile::noteTextReloc(const ld::Atom* atom, const ld::Atom* target)
                throwf("illegal text-relocoation (direct reference) to (global,weak) %s in %s from %s in %s", target->name(), target->file()->path(), atom->name(), atom->file()->path());
        }
        else {
                throwf("illegal text-relocoation (direct reference) to (global,weak) %s in %s from %s in %s", target->name(), target->file()->path(), atom->name(), atom->file()->path());
        }
        else {
-               throwf("illegal text-relocation to %s in %s from %s in %s", target->name(), target->file()->path(), atom->name(), atom->file()->path());
+               if ( (target->file() != NULL) && (atom->file() != NULL) )
+                       throwf("illegal text-relocation to '%s' in %s from '%s' in %s", target->name(), target->file()->path(), atom->name(), atom->file()->path());
+        else
+            throwf("illegal text reloc in '%s' to '%s'", atom->name(), target->name());
        }
 }
 
        }
 }
 
@@ -2736,6 +3046,11 @@ void OutputFile::addDyldInfo(ld::Internal& state,  ld::Internal::FinalSection* s
                                        // ok for __eh_frame and __uwind_info to use pointer diffs to global weak symbols
                                        return;
                                }
                                        // 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 %s to global weak symbol %s means the weak symbol cannot be overridden at runtime. "
                                // Have direct reference to weak-global.  This should be an indrect reference
                                const char* demangledName = strdup(_options.demangleSymbol(atom->name()));
                                warning("direct access in %s to global weak symbol %s means the weak symbol cannot be overridden at runtime. "
@@ -2817,8 +3132,11 @@ void OutputFile::addDyldInfo(ld::Internal& state,  ld::Internal::FinalSection* s
                                // this will be done by other cluster on lazy pointer atom
                        }
                }
                                // this will be done by other cluster on lazy pointer atom
                        }
                }
-               else if ( (target->contentType() == ld::Atom::typeResolver) && (target->scope() != ld::Atom::scopeGlobal) ) {
+               else if ( target->contentType() == ld::Atom::typeResolver ) {
                        // <rdar://problem/8553647> Hidden resolver functions should not have lazy binding info
                        // <rdar://problem/8553647> Hidden resolver functions should not have lazy binding info
+                       // <rdar://problem/12629331> Resolver function run before initializers when overriding the dyld shared cache
+                       // The lazy pointers used by stubs used when non-lazy binding to a resolver are not normal lazy pointers
+                       // and should not be in lazy binding info.
                        needsLazyBinding = false;
                }
                else {
                        needsLazyBinding = false;
                }
                else {
@@ -2873,6 +3191,9 @@ void OutputFile::addDyldInfo(ld::Internal& state,  ld::Internal::FinalSection* s
                                                needsRebase = false;
                                                needsBinding = true;
                                        }
                                                needsRebase = false;
                                                needsBinding = true;
                                        }
+                                       else if ( _options.forceCoalesce(target->name()) ) {
+                                               needsWeakBinding = true;
+                                       }
                                }
                                break;
                        case ld::Atom::definitionAbsolute:
                                }
                                break;
                        case ld::Atom::definitionAbsolute:
@@ -2880,6 +3201,20 @@ void OutputFile::addDyldInfo(ld::Internal& state,  ld::Internal::FinalSection* s
                }
        }
        
                }
        }
        
+       // <rdar://problem/13828711> if target is an import alias, use base of alias
+       if ( target->isAlias() && (target->definition() == ld::Atom::definitionProxy) ) {
+               for (ld::Fixup::iterator fit = target->fixupsBegin(), end=target->fixupsEnd(); fit != end; ++fit) {
+                       if ( fit->firstInCluster() ) {
+                               if ( fit->kind == ld::Fixup::kindNoneFollowOn ) {
+                                       if ( fit->binding == ld::Fixup::bindingDirectlyBound ) {
+                                               //fprintf(stderr, "switching import of %s to import of %s\n", target->name(),  fit->u.target->name());
+                                               target = fit->u.target;
+                                       }
+                               }
+                       }
+               }
+       } 
+
        // record dyld info for this cluster
        if ( needsRebase ) {
                if ( inReadOnlySeg ) {
        // record dyld info for this cluster
        if ( needsRebase ) {
                if ( inReadOnlySeg ) {
@@ -2887,18 +3222,24 @@ void OutputFile::addDyldInfo(ld::Internal& state,  ld::Internal::FinalSection* s
                        sect->hasLocalRelocs = true;  // so dyld knows to change permissions on __TEXT segment
                        rebaseType = REBASE_TYPE_TEXT_ABSOLUTE32;
                }
                        sect->hasLocalRelocs = true;  // so dyld knows to change permissions on __TEXT segment
                        rebaseType = REBASE_TYPE_TEXT_ABSOLUTE32;
                }
-               if ( (addend != 0) && _options.sharedRegionEligible() ) {
-                       // make sure the addend does not cause the pointer to point outside the target's segment
-                       // if it does, update_dyld_shared_cache will not be able to put this dylib into the shared cache
-                       uint64_t targetAddress = target->finalAddress();
-                       for (std::vector<ld::Internal::FinalSection*>::iterator sit = state.sections.begin(); sit != state.sections.end(); ++sit) {
-                               ld::Internal::FinalSection* sct = *sit;
-                               uint64_t sctEnd = (sct->address+sct->size);
-                               if ( (sct->address <= targetAddress) && (targetAddress < sctEnd) ) {
-                                       if ( (targetAddress+addend) > sctEnd ) {
-                                               warning("data symbol %s from %s has pointer to %s + 0x%08llX. "  
-                                                               "That large of an addend may disable %s from being put in the dyld shared cache.", 
-                                                               atom->name(), atom->file()->path(), target->name(), addend, _options.installPath() );
+               if ( _options.sharedRegionEligible() ) {
+                       // <rdar://problem/13287063> when range checking, ignore high byte of arm64 addends
+                       uint64_t checkAddend = addend;
+                       if ( _options.architecture() == CPU_TYPE_ARM64 )
+                               checkAddend &= 0x0FFFFFFFFFFFFFFFULL;
+                       if ( checkAddend != 0 ) {
+                               // make sure the addend does not cause the pointer to point outside the target's segment
+                               // if it does, update_dyld_shared_cache will not be able to put this dylib into the shared cache
+                               uint64_t targetAddress = target->finalAddress();
+                               for (std::vector<ld::Internal::FinalSection*>::iterator sit = state.sections.begin(); sit != state.sections.end(); ++sit) {
+                                       ld::Internal::FinalSection* sct = *sit;
+                                       uint64_t sctEnd = (sct->address+sct->size);
+                                       if ( (sct->address <= targetAddress) && (targetAddress < sctEnd) ) {
+                                               if ( (targetAddress+checkAddend) > sctEnd ) {
+                                                       warning("data symbol %s from %s has pointer to %s + 0x%08llX. "  
+                                                                       "That large of an addend may disable %s from being put in the dyld shared cache.", 
+                                                                       atom->name(), atom->file()->path(), target->name(), addend, _options.installPath() );
+                                               }
                                        }
                                }
                        }
                                        }
                                }
                        }
@@ -3013,7 +3354,8 @@ void OutputFile::addClassicRelocs(ld::Internal& state, ld::Internal::FinalSectio
                                        if ( (target->combine() == ld::Atom::combineByName) 
                                                && (target->definition() == ld::Atom::definitionRegular)
                                                && (_options.outputKind() != Options::kStaticExecutable)
                                        if ( (target->combine() == ld::Atom::combineByName) 
                                                && (target->definition() == ld::Atom::definitionRegular)
                                                && (_options.outputKind() != Options::kStaticExecutable)
-                                               && (_options.outputKind() != Options::kPreload) ) {
+                                               && (_options.outputKind() != Options::kPreload) 
+                                               && (atom != target) ) {
                                                needsExternReloc = true;
                                        }
                                        else if ( _options.outputKind() == Options::kDynamicExecutable ) {
                                                needsExternReloc = true;
                                        }
                                        else if ( _options.outputKind() == Options::kDynamicExecutable ) {
@@ -3057,6 +3399,9 @@ void OutputFile::addClassicRelocs(ld::Internal& state, ld::Internal::FinalSectio
                        }
                        break;
                case ld::Fixup::kindStoreTargetAddressX86BranchPCRel32:
                        }
                        break;
                case ld::Fixup::kindStoreTargetAddressX86BranchPCRel32:
+#if SUPPORT_ARCH_arm64
+               case ld::Fixup::kindStoreTargetAddressARM64Branch26:
+#endif
                        if ( _options.outputKind() == Options::kKextBundle ) {
                                assert(target != NULL);
                                if ( target->definition() == ld::Atom::definitionProxy ) {
                        if ( _options.outputKind() == Options::kKextBundle ) {
                                assert(target != NULL);
                                if ( target->definition() == ld::Atom::definitionProxy ) {
@@ -3088,8 +3433,8 @@ void OutputFile::addClassicRelocs(ld::Internal& state, ld::Internal::FinalSectio
 
 bool OutputFile::useExternalSectionReloc(const ld::Atom* atom, const ld::Atom* target, ld::Fixup* fixupWithTarget)
 {
 
 bool OutputFile::useExternalSectionReloc(const ld::Atom* atom, const ld::Atom* target, ld::Fixup* fixupWithTarget)
 {
-       if ( _options.architecture() == CPU_TYPE_X86_64 ) {
-               // x86_64 uses external relocations for everthing that has a symbol
+       if ( (_options.architecture() == CPU_TYPE_X86_64) || (_options.architecture() == CPU_TYPE_ARM64) ) {
+               // x86_64 and ARM64 use external relocations for everthing that has a symbol
                return ( target->symbolTableInclusion() != ld::Atom::symbolTableNotIn );
        }
        
                return ( target->symbolTableInclusion() != ld::Atom::symbolTableNotIn );
        }
        
@@ -3127,11 +3472,29 @@ bool OutputFile::useExternalSectionReloc(const ld::Atom* atom, const ld::Atom* t
        return false;
 }
 
        return false;
 }
 
+bool OutputFile::useSectionRelocAddend(ld::Fixup* fixupWithTarget)
+{
+#if SUPPORT_ARCH_arm64
+       if ( _options.architecture() == CPU_TYPE_ARM64 ) {
+               switch ( fixupWithTarget->kind ) {
+                       case ld::Fixup::kindStoreARM64Branch26:
+                       case ld::Fixup::kindStoreARM64Page21:
+                       case ld::Fixup::kindStoreARM64PageOff12:
+                               return true;
+                       default:
+                               return false;
+               }
+       }
+#endif
+       return false;
+}
+
 
 
 
 void OutputFile::addSectionRelocs(ld::Internal& state, ld::Internal::FinalSection* sect, const ld::Atom* atom, 
 
 
 
 void OutputFile::addSectionRelocs(ld::Internal& state, ld::Internal::FinalSection* sect, const ld::Atom* atom, 
-                                                               ld::Fixup* fixupWithTarget, ld::Fixup* fixupWithMinusTarget, ld::Fixup* fixupWithStore,
+                                                               ld::Fixup* fixupWithTarget, ld::Fixup* fixupWithMinusTarget,  
+                                                               ld::Fixup* fixupWithAddend, ld::Fixup* fixupWithStore, 
                                                                const ld::Atom* target, const ld::Atom* minusTarget, 
                                                                uint64_t targetAddend, uint64_t minusTargetAddend)
 {
                                                                const ld::Atom* target, const ld::Atom* minusTarget, 
                                                                uint64_t targetAddend, uint64_t minusTargetAddend)
 {
@@ -3155,11 +3518,13 @@ void OutputFile::addSectionRelocs(ld::Internal& state, ld::Internal::FinalSectio
        bool targetUsesExternalReloc = this->useExternalSectionReloc(atom, target, fixupWithTarget);
        bool minusTargetUsesExternalReloc = (minusTarget != NULL) && this->useExternalSectionReloc(atom, minusTarget, fixupWithMinusTarget);
        
        bool targetUsesExternalReloc = this->useExternalSectionReloc(atom, target, fixupWithTarget);
        bool minusTargetUsesExternalReloc = (minusTarget != NULL) && this->useExternalSectionReloc(atom, minusTarget, fixupWithMinusTarget);
        
-       // in x86_64 .o files an external reloc means the content contains just the addend
-       if ( _options.architecture() == CPU_TYPE_X86_64 ) {
+       // in x86_64 and arm64 .o files an external reloc means the content contains just the addend
+       if ( (_options.architecture() == CPU_TYPE_X86_64) ||(_options.architecture() == CPU_TYPE_ARM64)  ) {
                if ( targetUsesExternalReloc ) {
                        fixupWithTarget->contentAddendOnly = true;
                        fixupWithStore->contentAddendOnly = true;
                if ( targetUsesExternalReloc ) {
                        fixupWithTarget->contentAddendOnly = true;
                        fixupWithStore->contentAddendOnly = true;
+                       if ( this->useSectionRelocAddend(fixupWithStore) && (fixupWithAddend != NULL) )
+                               fixupWithAddend->contentIgnoresAddend = true;
                }
                if ( minusTargetUsesExternalReloc )
                        fixupWithMinusTarget->contentAddendOnly = true;
                }
                if ( minusTargetUsesExternalReloc )
                        fixupWithMinusTarget->contentAddendOnly = true;
@@ -3252,11 +3617,25 @@ void OutputFile::makeSplitSegInfo(ld::Internal& state)
                                        case ld::Fixup::kindStoreX86PCRel32GOTLoad:
                                        case ld::Fixup::kindStoreX86PCRel32GOTLoadNowLEA:
                                        case ld::Fixup::kindStoreX86PCRel32GOT:
                                        case ld::Fixup::kindStoreX86PCRel32GOTLoad:
                                        case ld::Fixup::kindStoreX86PCRel32GOTLoadNowLEA:
                                        case ld::Fixup::kindStoreX86PCRel32GOT:
+                                       case ld::Fixup::kindStoreX86PCRel32TLVLoad:
+                                       case ld::Fixup::kindStoreX86PCRel32TLVLoadNowLEA:
                                        case ld::Fixup::kindStoreTargetAddressX86PCRel32:
                                        case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoad:
                                        case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoadNowLEA:
                                        case ld::Fixup::kindStoreTargetAddressX86PCRel32:
                                        case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoad:
                                        case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoadNowLEA:
+                                       case ld::Fixup::kindStoreTargetAddressX86PCRel32TLVLoad:
+                                       case ld::Fixup::kindStoreTargetAddressX86PCRel32TLVLoadNowLEA:
                     case ld::Fixup::kindStoreARMLow16:
                     case ld::Fixup::kindStoreThumbLow16: 
                     case ld::Fixup::kindStoreARMLow16:
                     case ld::Fixup::kindStoreThumbLow16: 
+#if SUPPORT_ARCH_arm64
+                                       case ld::Fixup::kindStoreARM64Page21:
+                                       case ld::Fixup::kindStoreARM64GOTLoadPage21:
+                                       case ld::Fixup::kindStoreARM64GOTLeaPage21:
+                                       case ld::Fixup::kindStoreARM64TLVPLoadPage21:
+                                       case ld::Fixup::kindStoreTargetAddressARM64Page21:
+                                       case ld::Fixup::kindStoreTargetAddressARM64GOTLoadPage21:
+                                       case ld::Fixup::kindStoreTargetAddressARM64GOTLeaPage21:
+                                       case ld::Fixup::kindStoreARM64PCRelToGOT:
+#endif
                                                assert(target != NULL);
                                                if ( strcmp(sect->segmentName(), target->section().segmentName()) != 0 ) {      
                                                        _splitSegInfos.push_back(SplitSegInfoEntry(atom->finalAddress()+fit->offsetInAtom,fit->kind));
                                                assert(target != NULL);
                                                if ( strcmp(sect->segmentName(), target->section().segmentName()) != 0 ) {      
                                                        _splitSegInfos.push_back(SplitSegInfoEntry(atom->finalAddress()+fit->offsetInAtom,fit->kind));
index d3567ae51764888aaad53180371dd401e67b883a..bfc89367717d2713b2ce81b0626c1fdafa5fd48e 100644 (file)
@@ -154,7 +154,8 @@ private:
        void                                            setSectionSizesAndAlignments(ld::Internal& state);
        void                                            addSectionRelocs(ld::Internal& state, ld::Internal::FinalSection* sect,  
                                                                                                const ld::Atom* atom, ld::Fixup* fixupWithTarget, 
        void                                            setSectionSizesAndAlignments(ld::Internal& state);
        void                                            addSectionRelocs(ld::Internal& state, ld::Internal::FinalSection* sect,  
                                                                                                const ld::Atom* atom, ld::Fixup* fixupWithTarget, 
-                                                                                               ld::Fixup* fixupWithMinusTarget, ld::Fixup* fixupWithStore,
+                                                                                               ld::Fixup* fixupWithMinusTarget, ld::Fixup* fixupWithAddend,
+                                                                                                ld::Fixup* fixupWithStore,
                                                                                                const ld::Atom* target, const ld::Atom* minusTarget, 
                                                                                                uint64_t targetAddend, uint64_t minusTargetAddend);
        void                                            addDyldInfo(ld::Internal& state, ld::Internal::FinalSection* sect,  
                                                                                                const ld::Atom* target, const ld::Atom* minusTarget, 
                                                                                                uint64_t targetAddend, uint64_t minusTargetAddend);
        void                                            addDyldInfo(ld::Internal& state, ld::Internal::FinalSection* sect,  
@@ -169,6 +170,7 @@ private:
                                                                                                uint64_t targetAddend, uint64_t minusTargetAddend);
        bool                                            useExternalSectionReloc(const ld::Atom* atom, const ld::Atom* target, 
                                                                                                                        ld::Fixup* fixupWithTarget);
                                                                                                uint64_t targetAddend, uint64_t minusTargetAddend);
        bool                                            useExternalSectionReloc(const ld::Atom* atom, const ld::Atom* target, 
                                                                                                                        ld::Fixup* fixupWithTarget);
+       bool                                            useSectionRelocAddend(ld::Fixup* fixupWithTarget);
        uint64_t                                        pageAlign(uint64_t addr);
        uint64_t                                        pageAlign(uint64_t addr, uint64_t pageSize);
        void                                            setLoadCommandsPadding(ld::Internal& state);
        uint64_t                                        pageAlign(uint64_t addr);
        uint64_t                                        pageAlign(uint64_t addr, uint64_t pageSize);
        void                                            setLoadCommandsPadding(ld::Internal& state);
@@ -215,6 +217,12 @@ private:
                                                                                                                                                                                        const ld::Fixup* fixup);
        void                                            rangeCheckThumbBranch22(int64_t delta, ld::Internal& state, const ld::Atom* atom, 
                                                                                                                                                                                        const ld::Fixup* fixup);
                                                                                                                                                                                        const ld::Fixup* fixup);
        void                                            rangeCheckThumbBranch22(int64_t delta, ld::Internal& state, const ld::Atom* atom, 
                                                                                                                                                                                        const ld::Fixup* fixup);
+       void                                            rangeCheckARM64Branch26(int64_t delta, ld::Internal& state, const ld::Atom* atom, 
+                                                                                                                                                                                       const ld::Fixup* fixup);
+       void                                            rangeCheckARM64Page21(int64_t delta, ld::Internal& state, const ld::Atom* atom, 
+                                                                                                                                                                                       const ld::Fixup* fixup);
+                                                                                                                                                                                       
+                                                                                                                                                                                       
        uint64_t                                        sectionOffsetOf(const ld::Internal& state, const ld::Fixup* fixup);
        uint64_t                                        tlvTemplateOffsetOf(const ld::Internal& state, const ld::Fixup* fixup);
        void                                            dumpAtomsBySection(ld::Internal& state, bool);
        uint64_t                                        sectionOffsetOf(const ld::Internal& state, const ld::Fixup* fixup);
        uint64_t                                        tlvTemplateOffsetOf(const ld::Internal& state, const ld::Fixup* fixup);
        void                                            dumpAtomsBySection(ld::Internal& state, bool);
index ad4b22dbd287eaa7c81666574f7a683ad03354a2..25d0c666d0571567a85203146decb7b5f87ad695 100644 (file)
@@ -132,6 +132,7 @@ public:
 
        void                                                                    setFinalAliasOf() const {
                                                                                                (const_cast<AliasAtom*>(this))->setAttributesFromAtom(_aliasOf);
 
        void                                                                    setFinalAliasOf() const {
                                                                                                (const_cast<AliasAtom*>(this))->setAttributesFromAtom(_aliasOf);
+                                                                                               (const_cast<AliasAtom*>(this))->setScope(ld::Atom::scopeGlobal);
                                                                                        }
                                                                                                                        
 private:
                                                                                        }
                                                                                                                        
 private:
@@ -281,13 +282,21 @@ void Resolver::initializeState()
                _internal.objcObjectConstraint = ld::File::objcConstraintGC;
        
        _internal.cpuSubType = _options.subArchitecture();
                _internal.objcObjectConstraint = ld::File::objcConstraintGC;
        
        _internal.cpuSubType = _options.subArchitecture();
+       
+       // In -r mode, look for -linker_option additions
+       if ( _options.outputKind() == Options::kObjectFile ) {
+               ld::relocatable::File::LinkerOptionsList lo = _options.linkerOptions();
+               for (relocatable::File::LinkerOptionsList::const_iterator it=lo.begin(); it != lo.end(); ++it) {
+                       doLinkerOption(*it, "command line");
+               }
+       }
 }
 
 void Resolver::buildAtomList()
 {
        // each input files contributes initial atoms
        _atoms.reserve(1024);
 }
 
 void Resolver::buildAtomList()
 {
        // each input files contributes initial atoms
        _atoms.reserve(1024);
-       _inputFiles.forEachInitialAtom(*this);
+       _inputFiles.forEachInitialAtom(*this, _internal);
     
        _completedInitialObjectFiles = true;
        
     
        _completedInitialObjectFiles = true;
        
@@ -295,12 +304,46 @@ void Resolver::buildAtomList()
 }
 
 
 }
 
 
+void Resolver::doLinkerOption(const std::vector<const char*>& linkerOption, const char* fileName)
+{
+       if ( linkerOption.size() == 1 ) {
+               const char* lo1 = linkerOption.front();
+               if ( strncmp(lo1, "-l", 2) == 0 ) {
+                       _internal.linkerOptionLibraries.insert(&lo1[2]);
+               }
+               else {
+                       warning("unknown linker option from object file ignored: '%s' in %s", lo1, fileName);
+               }
+       }
+       else if ( linkerOption.size() == 2 ) {
+               const char* lo2a = linkerOption[0];
+               const char* lo2b = linkerOption[1];
+               if ( strcmp(lo2a, "-framework") == 0 ) {
+                       _internal.linkerOptionFrameworks.insert(lo2b);
+               }
+               else {
+                       warning("unknown linker option from object file ignored: '%s' '%s' from %s", lo2a, lo2b, fileName);
+               }
+       }
+       else {
+               warning("unknown linker option from object file ignored, starting with: '%s' from %s", linkerOption.front(), fileName);
+       }
+}
+
 void Resolver::doFile(const ld::File& file)
 {
        const ld::relocatable::File* objFile = dynamic_cast<const ld::relocatable::File*>(&file);
        const ld::dylib::File* dylibFile = dynamic_cast<const ld::dylib::File*>(&file);
 
        if ( objFile != NULL ) {
 void Resolver::doFile(const ld::File& file)
 {
        const ld::relocatable::File* objFile = dynamic_cast<const ld::relocatable::File*>(&file);
        const ld::dylib::File* dylibFile = dynamic_cast<const ld::dylib::File*>(&file);
 
        if ( objFile != NULL ) {
+               // if file has linker options, process them
+               ld::relocatable::File::LinkerOptionsList* lo = objFile->linkerOptions();
+               if ( lo != NULL ) {
+                       for (relocatable::File::LinkerOptionsList::const_iterator it=lo->begin(); it != lo->end(); ++it) {
+                               this->doLinkerOption(*it, file.path());
+                       }
+               }
+               
                // update which form of ObjC is being used
                switch ( file.objCConstraint() ) {
                        case ld::File::objcConstraintNone:
                // update which form of ObjC is being used
                switch ( file.objCConstraint() ) {
                        case ld::File::objcConstraintNone:
@@ -312,16 +355,31 @@ void Resolver::doFile(const ld::File& file)
                                        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());
                                        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());
-                               _internal.objcObjectConstraint = ld::File::objcConstraintRetainRelease;
+                               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;
                                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;
                                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;
                }
        
                                break;
                }
        
@@ -376,16 +434,30 @@ void Resolver::doFile(const ld::File& file)
                                        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());
                                        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;
                                _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());
                                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());
-                               _internal.objcDylibConstraint = ld::File::objcConstraintGC;
+                               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;
+                               }
                                break;
                }
        }
                                break;
                }
        }
@@ -510,6 +582,8 @@ bool Resolver::isDtraceProbe(ld::Fixup::Kind kind)
                case ld::Fixup::kindStoreX86DtraceIsEnableSiteClear:
                case ld::Fixup::kindStoreARMDtraceCallSiteNop:
                case ld::Fixup::kindStoreARMDtraceIsEnableSiteClear:
                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:
                case ld::Fixup::kindDtraceExtra:
                case ld::Fixup::kindStoreThumbDtraceCallSiteNop:
                case ld::Fixup::kindStoreThumbDtraceIsEnableSiteClear:
                case ld::Fixup::kindDtraceExtra:
@@ -638,7 +712,21 @@ void Resolver::resolveUndefines()
                        }
                }
        }
                        }
                }
        }
-               
+       
+       // Use linker options to resolve an remaining undefined symbols
+       if ( !_internal.linkerOptionLibraries.empty() || !_internal.linkerOptionFrameworks.empty() ) {
+               std::vector<const char*> undefineNames;
+               _symbolTable.undefines(undefineNames);
+               if ( undefineNames.size() != 0 ) {
+                       for (std::vector<const char*>::iterator it = undefineNames.begin(); it != undefineNames.end(); ++it) {
+                               const char* undef = *it;
+                               if ( ! _symbolTable.hasName(undef) ) {
+                                       _inputFiles.searchLibraries(undef, true, true, false, *this);
+                               }
+                       }
+               }
+       }
+       
        // create proxies as needed for undefined symbols
        if ( (_options.undefinedTreatment() != Options::kUndefinedError) || (_options.outputKind() == Options::kObjectFile) ) {
                std::vector<const char*> undefineNames;
        // create proxies as needed for undefined symbols
        if ( (_options.undefinedTreatment() != Options::kUndefinedError) || (_options.outputKind() == Options::kObjectFile) ) {
                std::vector<const char*> undefineNames;
@@ -697,6 +785,7 @@ void Resolver::markLive(const ld::Atom& atom, WhyLiveBackChain* previous)
                        case ld::Fixup::kindNoneGroupSubordinate:
                        case ld::Fixup::kindNoneGroupSubordinateFDE:
                        case ld::Fixup::kindNoneGroupSubordinateLSDA:
                        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::kindStoreTargetAddressLittleEndian32:
                        case ld::Fixup::kindSetTargetAddress:
                        case ld::Fixup::kindSubtractTargetAddress:
                        case ld::Fixup::kindStoreTargetAddressLittleEndian32:
@@ -713,6 +802,12 @@ void Resolver::markLive(const ld::Atom& atom, WhyLiveBackChain* previous)
                        case ld::Fixup::kindStoreTargetAddressX86Abs32TLVLoadNowLEA:
                        case ld::Fixup::kindStoreTargetAddressARMBranch24:
                        case ld::Fixup::kindStoreTargetAddressThumbBranch22:
                        case ld::Fixup::kindStoreTargetAddressX86Abs32TLVLoadNowLEA:
                        case ld::Fixup::kindStoreTargetAddressARMBranch24:
                        case ld::Fixup::kindStoreTargetAddressThumbBranch22:
+#if SUPPORT_ARCH_arm64
+                       case ld::Fixup::kindStoreTargetAddressARM64Branch26:
+                       case ld::Fixup::kindStoreTargetAddressARM64Page21:
+                       case ld::Fixup::kindStoreTargetAddressARM64GOTLoadPage21:
+                       case ld::Fixup::kindStoreTargetAddressARM64GOTLeaPage21:
+#endif
                                if ( fit->binding == ld::Fixup::bindingByContentBound ) {
                                        // normally this was done in convertReferencesToIndirect()
                                        // but a archive loaded .o file may have a forward reference
                                if ( fit->binding == ld::Fixup::bindingByContentBound ) {
                                        // normally this was done in convertReferencesToIndirect()
                                        // but a archive loaded .o file may have a forward reference
@@ -1338,7 +1433,10 @@ void Resolver::linkTimeOptimize()
        optOpt.relocatable                                      = (_options.outputKind() == Options::kObjectFile);
        optOpt.allowTextRelocs                          = _options.allowTextRelocs();
        optOpt.linkerDeadStripping                      = _options.deadCodeStrip();
        optOpt.relocatable                                      = (_options.outputKind() == Options::kObjectFile);
        optOpt.allowTextRelocs                          = _options.allowTextRelocs();
        optOpt.linkerDeadStripping                      = _options.deadCodeStrip();
+       optOpt.needsUnwindInfoSection           = _options.needsUnwindInfoSection();
+       optOpt.keepDwarfUnwind                          = _options.keepDwarfUnwind();
        optOpt.arch                                                     = _options.architecture();
        optOpt.arch                                                     = _options.architecture();
+       optOpt.mcpu                                                     = _options.mcpuLTO();
        optOpt.llvmOptions                                      = &_options.llvmOptions();
        
        std::vector<const ld::Atom*>            newAtoms;
        optOpt.llvmOptions                                      = &_options.llvmOptions();
        
        std::vector<const ld::Atom*>            newAtoms;
index 32d1d50e8676f561e7aa29b0d837a3d9aa72e856..bdb4e3edfc31b1404271536ce87f50611904c361 100644 (file)
@@ -89,7 +89,7 @@ private:
        void                                    fillInInternalState();
        void                                    fillInHelpersInInternalState();
        void                                    removeCoalescedAwayAtoms();
        void                                    fillInInternalState();
        void                                    fillInHelpersInInternalState();
        void                                    removeCoalescedAwayAtoms();
-  void                                 fillInEntryPoint();
+       void                                    fillInEntryPoint();
        void                                    linkTimeOptimize();
        void                                    convertReferencesToIndirect(const ld::Atom& atom);
        const ld::Atom*                 entryPoint(bool searchArchives);
        void                                    linkTimeOptimize();
        void                                    convertReferencesToIndirect(const ld::Atom& atom);
        const ld::Atom*                 entryPoint(bool searchArchives);
@@ -99,6 +99,7 @@ private:
        void                                    remainingUndefines(std::vector<const char*>&);
        bool                                    printReferencedBy(const char* name, SymbolTable::IndirectBindingSlot slot);
        void                                    tweakWeakness();
        void                                    remainingUndefines(std::vector<const char*>&);
        bool                                    printReferencedBy(const char* name, SymbolTable::IndirectBindingSlot slot);
        void                                    tweakWeakness();
+       void                                    doLinkerOption(const std::vector<const char*>& linkerOption, const char* fileName);
 
        typedef std::unordered_set<const char*, CStringHash, CStringEquals>  StringSet;
 
 
        typedef std::unordered_set<const char*, CStringHash, CStringEquals>  StringSet;
 
index 2ea690fa2eb1aea3dd2387f00dc404f0e5858ccb..309de8b6835fa155c00733903cdb9d79d60cdac3 100644 (file)
@@ -312,6 +312,7 @@ private:
        }
        
        void pickAtom() {
        }
        
        void pickAtom() {
+               //fprintf(stderr, "pickAtom(), a=%p, def=%d, b=%p, def=%d\n", &_atomA, _atomA.definition(), &_atomB, _atomB.definition());
                // First, discriminate by definition
                switch (_atomA.definition()) {
                        case ld::Atom::definitionRegular:
                // First, discriminate by definition
                switch (_atomA.definition()) {
                        case ld::Atom::definitionRegular:
@@ -320,6 +321,12 @@ private:
                                                pickBetweenRegularAtoms();
                                                break;
                                        case ld::Atom::definitionTentative:
                                                pickBetweenRegularAtoms();
                                                break;
                                        case ld::Atom::definitionTentative:
+                                               if ( _atomB.size() > _atomA.size() ) {
+                                                       const char* atomApath = (_atomA.file() != NULL) ? _atomA.file()->path() : "<internal>";
+                                                       const char* atomBpath = (_atomB.file() != NULL) ? _atomB.file()->path() : "<internal>";
+                                                       warning("tentative definition of '%s' with size %llu from '%s' is being replaced by real definition of smaller size %llu from '%s'",
+                                                                       _atomA.name(), _atomB.size(), atomBpath, _atomA.size(), atomApath);
+                                               }
                                                pickAtomA();
                                                break;
                                        case ld::Atom::definitionAbsolute:
                                                pickAtomA();
                                                break;
                                        case ld::Atom::definitionAbsolute:
@@ -334,6 +341,12 @@ private:
                        case ld::Atom::definitionTentative:
                                switch (_atomB.definition()) {
                                        case ld::Atom::definitionRegular:
                        case ld::Atom::definitionTentative:
                                switch (_atomB.definition()) {
                                        case ld::Atom::definitionRegular:
+                                               if ( _atomA.size() > _atomB.size() ) {
+                                                       const char* atomApath = (_atomA.file() != NULL) ? _atomA.file()->path() : "<internal>";
+                                                       const char* atomBpath = (_atomB.file() != NULL) ? _atomB.file()->path() : "<internal>";
+                                                       warning("tentative definition of '%s' with size %llu from '%s' is being replaced by real definition of smaller size %llu from '%s'",
+                                                                       _atomA.name(), _atomA.size(),atomApath, _atomB.size(), atomBpath);
+                                               }
                                                pickAtomB();
                                                break;
                                        case ld::Atom::definitionTentative:
                                                pickAtomB();
                                                break;
                                        case ld::Atom::definitionTentative:
index 411dbbc94d9bd40b023b4a4cfe831a73b954fcca..ecdf89897235977ae4fc57388a5299232a7af208 100644 (file)
@@ -62,9 +62,15 @@ enum {
   DW_FORM_ref4,
   DW_FORM_ref8,
   DW_FORM_ref_udata,
   DW_FORM_ref4,
   DW_FORM_ref8,
   DW_FORM_ref_udata,
-  DW_FORM_indirect /* 22 */
+  DW_FORM_indirect, 
+  /* new in Dwarf 4 */
+  DW_FORM_sec_offset, 
+  DW_FORM_exprloc,
+  DW_FORM_flag_present,
+  DW_FORM_ref_sig8 
 };
 
 };
 
+
 enum {
   DW_LNS_extended_op = 0,
   DW_LNS_copy,
 enum {
   DW_LNS_extended_op = 0,
   DW_LNS_copy,
index a5db06eb35f5aef3efc374d7bad3398e037864b0..7f7161d2abb8f9a7577a29d9b2e09426137a55a3 100644 (file)
@@ -333,8 +333,11 @@ uint32_t InternalState::FinalSection::sectionOrder(const ld::Section& sect, uint
                                else
                                        return INT_MAX-2;
                        default:
                                else
                                        return INT_MAX-2;
                        default:
+                               // <rdar://problem/14348664> __DATA,__const section should be near __mod_init_func not __data
+                               if ( strcmp(sect.sectionName(), "__const") == 0 )
+                                       return 14;
                                // <rdar://problem/7435296> Reorder sections to reduce page faults in object files
                                // <rdar://problem/7435296> Reorder sections to reduce page faults in object files
-                               if ( strcmp(sect.sectionName(), "__objc_classlist") == 0 ) 
+                               else if ( strcmp(sect.sectionName(), "__objc_classlist") == 0 ) 
                                        return 20;
                                else if ( strcmp(sect.sectionName(), "__objc_nlclslist") == 0 ) 
                                        return 21;
                                        return 20;
                                else if ( strcmp(sect.sectionName(), "__objc_nlclslist") == 0 ) 
                                        return 21;
@@ -587,10 +590,9 @@ static void printTime(const char* msg, uint64_t partTime, uint64_t totalTime)
        static uint64_t sUnitsPerSecond = 0;
        if ( sUnitsPerSecond == 0 ) {
                struct mach_timebase_info timeBaseInfo;
        static uint64_t sUnitsPerSecond = 0;
        if ( sUnitsPerSecond == 0 ) {
                struct mach_timebase_info timeBaseInfo;
-               if ( mach_timebase_info(&timeBaseInfo) == KERN_SUCCESS ) {
-                       sUnitsPerSecond = 1000000000ULL * timeBaseInfo.denom / timeBaseInfo.numer;
-                       //fprintf(stderr, "sUnitsPerSecond=%llu\n", sUnitsPerSecond);
-               }
+               if ( mach_timebase_info(&timeBaseInfo) != KERN_SUCCESS )
+      return;
+    sUnitsPerSecond = 1000000000ULL * timeBaseInfo.denom / timeBaseInfo.numer;
        }
        if ( partTime < sUnitsPerSecond ) {
                uint32_t milliSecondsTimeTen = (partTime*10000)/sUnitsPerSecond;
        }
        if ( partTime < sUnitsPerSecond ) {
                uint32_t milliSecondsTimeTen = (partTime*10000)/sUnitsPerSecond;
index 7be00a3a624af6cc79a5cda5f865a42ac8e30f86..42d5aa62713136f237a5a353a501dac87343956b 100644 (file)
@@ -32,8 +32,9 @@
 #include <assert.h>
 
 #include <vector>
 #include <assert.h>
 
 #include <vector>
-#include <set>
+#include <unordered_set>
 
 
+#include "configure.h"
 
 namespace ld {
 
 
 namespace ld {
 
@@ -51,7 +52,9 @@ namespace ld {
 class File
 {
 public:
 class File
 {
 public:
-       enum ObjcConstraint { objcConstraintNone, objcConstraintRetainRelease, objcConstraintRetainReleaseOrGC, objcConstraintGC };
+       enum ObjcConstraint { objcConstraintNone, objcConstraintRetainRelease, 
+                                                       objcConstraintRetainReleaseOrGC, objcConstraintGC,
+                                                       objcConstraintRetainReleaseForSimulator };
        
        class AtomHandler {
        public:
        
        class AtomHandler {
        public:
@@ -84,7 +87,7 @@ public:
                
                Ordinal (uint64_t ordinal) : _ordinal(ordinal) {}
                
                
                Ordinal (uint64_t ordinal) : _ordinal(ordinal) {}
                
-               enum { ArgListPartition=0, IndirectDylibPartition=1, LTOPartition = 2, InvalidParition=0xffff };
+               enum { kArgListPartition=0, kIndirectDylibPartition=1, kLTOPartition = 2, kLinkerOptionPartition = 2, InvalidParition=0xffff };
                Ordinal(uint16_t partition, uint16_t majorIndex, uint16_t minorIndex, uint16_t counter) {
                        _ordinal = ((uint64_t)partition<<48) | ((uint64_t)majorIndex<<32) | ((uint64_t)minorIndex<<16) | ((uint64_t)counter<<0);
                }
                Ordinal(uint16_t partition, uint16_t majorIndex, uint16_t minorIndex, uint16_t counter) {
                        _ordinal = ((uint64_t)partition<<48) | ((uint64_t)majorIndex<<32) | ((uint64_t)minorIndex<<16) | ((uint64_t)counter<<0);
                }
@@ -115,16 +118,21 @@ public:
                // The minorIndex is used for files pulled in by a file list and the value is the index of the file in the file list.
                // The counter is used for .a files and the value is the index of the object in the archive.
                // Thus, an object pulled in from a .a that was listed in a file list could use all three fields.
                // The minorIndex is used for files pulled in by a file list and the value is the index of the file in the file list.
                // The counter is used for .a files and the value is the index of the object in the archive.
                // Thus, an object pulled in from a .a that was listed in a file list could use all three fields.
-               static const Ordinal makeArgOrdinal(uint16_t argIndex) { return Ordinal(ArgListPartition, argIndex, 0, 0); };
+               static const Ordinal makeArgOrdinal(uint16_t argIndex) { return Ordinal(kArgListPartition, argIndex, 0, 0); };
                const Ordinal nextFileListOrdinal() const { return nextMinorIndex(); }
                const Ordinal nextFileListOrdinal() const { return nextMinorIndex(); }
-               const Ordinal archiveOrdinalWithMemberIndex(uint16_t index) const { return Ordinal(ArgListPartition, majorIndex(), minorIndex(), index); }
+               const Ordinal archiveOrdinalWithMemberIndex(uint16_t index) const { return Ordinal(kArgListPartition, majorIndex(), minorIndex(), index); }
                
                // For indirect libraries the partition is IndirectDylibPartition and the counter is used or order the libraries.
                
                // For indirect libraries the partition is IndirectDylibPartition and the counter is used or order the libraries.
-               static const ld::File::Ordinal indirectDylibBase() { return Ordinal(IndirectDylibPartition, 0, 0, 0); }
+               static const ld::File::Ordinal indirectDylibBase() { return Ordinal(kIndirectDylibPartition, 0, 0, 0); }
                const Ordinal nextIndirectDylibOrdinal() const { return nextCounter(); }
                
                // For the LTO mach-o the partition is LTOPartition. As there is only one LTO file no other fields are needed.
                const Ordinal nextIndirectDylibOrdinal() const { return nextCounter(); }
                
                // For the LTO mach-o the partition is LTOPartition. As there is only one LTO file no other fields are needed.
-               static const ld::File::Ordinal LTOOrdinal()                     { return Ordinal(LTOPartition, 0, 0, 0); }
+               static const ld::File::Ordinal LTOOrdinal()                     { return Ordinal(kLTOPartition, 0, 0, 0); }
+
+               // For linker options embedded in object files
+               static const ld::File::Ordinal linkeOptionBase() { return Ordinal(kIndirectDylibPartition, 1, 0, 0); }
+               const Ordinal nextLinkerOptionOrdinal() { nextCounter(); return *this; };
+               
        };
        
        typedef enum { Reloc, Dylib, Archive, Other } Type;
        };
        
        typedef enum { Reloc, Dylib, Archive, Other } Type;
@@ -155,10 +163,10 @@ private:
 //
 enum MacVersionMin { macVersionUnset=0, mac10_4=0x000A0400, mac10_5=0x000A0500, 
                                                mac10_6=0x000A0600, mac10_7=0x000A0700, mac10_8=0x000A0800,
 //
 enum MacVersionMin { macVersionUnset=0, mac10_4=0x000A0400, mac10_5=0x000A0500, 
                                                mac10_6=0x000A0600, mac10_7=0x000A0700, mac10_8=0x000A0800,
-                                               mac10_Future=0x10000000 };
+                                               mac10_9=0x000A0900, 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,
 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_Future=0x10000000};
+                                               iOS_6_0=0x00060000, iOS_7_0=0x00070000, iOS_Future=0x10000000};
  
 namespace relocatable {
        //
  
 namespace relocatable {
        //
@@ -189,6 +197,7 @@ namespace relocatable {
                        uint32_t                        value;
                        const char*                     string;
                };
                        uint32_t                        value;
                        const char*                     string;
                };
+               typedef const std::vector< std::vector<const char*> > LinkerOptionsList;
 
                                                                                        File(const char* pth, time_t modTime, Ordinal ord)
                                                                                                : ld::File(pth, modTime, ord, Reloc) { }
 
                                                                                        File(const char* pth, time_t modTime, Ordinal ord)
                                                                                                : ld::File(pth, modTime, ord, Reloc) { }
@@ -199,6 +208,7 @@ namespace relocatable {
                virtual const std::vector<Stab>*        stabs() const = 0;
                virtual bool                                            canScatterAtoms() const = 0;
                virtual bool                                            hasLongBranchStubs()            { return false; }
                virtual const std::vector<Stab>*        stabs() const = 0;
                virtual bool                                            canScatterAtoms() const = 0;
                virtual bool                                            hasLongBranchStubs()            { return false; }
+               virtual LinkerOptionsList*                      linkerOptions() const = 0;
        };
 } // namespace relocatable
 
        };
 } // namespace relocatable
 
@@ -258,6 +268,7 @@ namespace dylib {
                virtual bool                                            hasPublicInstallName() const = 0;
                virtual bool                                            allSymbolsAreWeakImported() const = 0;
                virtual const void*                                     codeSignatureDR() const = 0;
                virtual bool                                            hasPublicInstallName() const = 0;
                virtual bool                                            allSymbolsAreWeakImported() const = 0;
                virtual const void*                                     codeSignatureDR() const = 0;
+               virtual bool                                            installPathVersionSpecific() const { return false; }
        protected:
                const char*                                                     _dylibInstallPath;
                uint32_t                                                        _dylibTimeStamp;
        protected:
                const char*                                                     _dylibInstallPath;
                uint32_t                                                        _dylibTimeStamp;
@@ -391,10 +402,20 @@ struct Fixup
                                        kindStoreARMLoad12,
                                        kindStoreARMLow16, kindStoreARMHigh16, 
                                        kindStoreThumbLow16, kindStoreThumbHigh16, 
                                        kindStoreARMLoad12,
                                        kindStoreARMLow16, kindStoreARMHigh16, 
                                        kindStoreThumbLow16, kindStoreThumbHigh16, 
+#if SUPPORT_ARCH_arm64
+                                       // ARM64 specific store kinds
+                                       kindStoreARM64Branch26,  
+                                       kindStoreARM64Page21, kindStoreARM64PageOff12,
+                                       kindStoreARM64GOTLoadPage21, kindStoreARM64GOTLoadPageOff12,
+                                       kindStoreARM64GOTLeaPage21, kindStoreARM64GOTLeaPageOff12,
+                                       kindStoreARM64TLVPLoadPage21, kindStoreARM64TLVPLoadPageOff12,
+                                       kindStoreARM64PointerToGOT, kindStoreARM64PCRelToGOT,
+#endif
                                        // dtrace probes
                                        kindDtraceExtra,
                                        kindStoreX86DtraceCallSiteNop, kindStoreX86DtraceIsEnableSiteClear,
                                        kindStoreARMDtraceCallSiteNop, kindStoreARMDtraceIsEnableSiteClear,
                                        // dtrace probes
                                        kindDtraceExtra,
                                        kindStoreX86DtraceCallSiteNop, kindStoreX86DtraceIsEnableSiteClear,
                                        kindStoreARMDtraceCallSiteNop, kindStoreARMDtraceIsEnableSiteClear,
+                                       kindStoreARM64DtraceCallSiteNop, kindStoreARM64DtraceIsEnableSiteClear,
                                        kindStoreThumbDtraceCallSiteNop, kindStoreThumbDtraceIsEnableSiteClear,
                                        // lazy binding
                                        kindLazyTarget, kindSetLazyOffset,
                                        kindStoreThumbDtraceCallSiteNop, kindStoreThumbDtraceIsEnableSiteClear,
                                        // lazy binding
                                        kindLazyTarget, kindSetLazyOffset,
@@ -421,6 +442,16 @@ struct Fixup
                                        kindStoreTargetAddressARMBranch24,              // kindSetTargetAddress + kindStoreARMBranch24
                                        kindStoreTargetAddressThumbBranch22,    // kindSetTargetAddress + kindStoreThumbBranch22
                                        kindStoreTargetAddressARMLoad12,                // kindSetTargetAddress + kindStoreARMLoad12
                                        kindStoreTargetAddressARMBranch24,              // kindSetTargetAddress + kindStoreARMBranch24
                                        kindStoreTargetAddressThumbBranch22,    // kindSetTargetAddress + kindStoreThumbBranch22
                                        kindStoreTargetAddressARMLoad12,                // kindSetTargetAddress + kindStoreARMLoad12
+#if SUPPORT_ARCH_arm64
+                                       // ARM64 value calculation and store combinations
+                                       kindStoreTargetAddressARM64Branch26,            // kindSetTargetAddress + kindStoreARM64Branch26
+                                       kindStoreTargetAddressARM64Page21,                      // kindSetTargetAddress + kindStoreARM64Page21
+                                       kindStoreTargetAddressARM64PageOff12,           // kindSetTargetAddress + kindStoreARM64PageOff12
+                                       kindStoreTargetAddressARM64GOTLoadPage21,       // kindSetTargetAddress + kindStoreARM64GOTLoadPage21
+                                       kindStoreTargetAddressARM64GOTLoadPageOff12,// kindSetTargetAddress + kindStoreARM64GOTLoadPageOff12
+                                       kindStoreTargetAddressARM64GOTLeaPage21,        // kindSetTargetAddress + kindStoreARM64GOTLeaPage21
+                                       kindStoreTargetAddressARM64GOTLeaPageOff12,     // kindSetTargetAddress + kindStoreARM64GOTLeaPageOff12
+#endif
                        };
 
        union {
                        };
 
        union {
@@ -436,52 +467,53 @@ struct Fixup
        TargetBinding   binding : 3;
        bool                    contentAddendOnly : 1;
        bool                    contentDetlaToAddendOnly : 1;
        TargetBinding   binding : 3;
        bool                    contentAddendOnly : 1;
        bool                    contentDetlaToAddendOnly : 1;
+       bool                    contentIgnoresAddend : 1;
        
        typedef Fixup*          iterator;
 
        Fixup() :
                offsetInAtom(0), kind(kindNone), clusterSize(k1of1), weakImport(false), 
                binding(bindingNone),  
        
        typedef Fixup*          iterator;
 
        Fixup() :
                offsetInAtom(0), kind(kindNone), clusterSize(k1of1), weakImport(false), 
                binding(bindingNone),  
-               contentAddendOnly(false), contentDetlaToAddendOnly(false) { u.target = NULL; }
+               contentAddendOnly(false), contentDetlaToAddendOnly(false), contentIgnoresAddend(false) { u.target = NULL; }
 
        Fixup(Kind k, Atom* targetAtom) :
                offsetInAtom(0), kind(k), clusterSize(k1of1), weakImport(false), 
                binding(Fixup::bindingDirectlyBound),  
 
        Fixup(Kind k, Atom* targetAtom) :
                offsetInAtom(0), kind(k), clusterSize(k1of1), weakImport(false), 
                binding(Fixup::bindingDirectlyBound),  
-               contentAddendOnly(false), contentDetlaToAddendOnly(false)  
+               contentAddendOnly(false), contentDetlaToAddendOnly(false), contentIgnoresAddend(false)  
                        { assert(targetAtom != NULL); u.target = targetAtom; }
 
        Fixup(uint32_t off, Cluster c, Kind k) :
                offsetInAtom(off), kind(k), clusterSize(c), weakImport(false), 
                binding(Fixup::bindingNone),  
                        { assert(targetAtom != NULL); u.target = targetAtom; }
 
        Fixup(uint32_t off, Cluster c, Kind k) :
                offsetInAtom(off), kind(k), clusterSize(c), weakImport(false), 
                binding(Fixup::bindingNone),  
-               contentAddendOnly(false), contentDetlaToAddendOnly(false)  
+               contentAddendOnly(false), contentDetlaToAddendOnly(false), contentIgnoresAddend(false)  
                        { u.addend = 0; }
 
        Fixup(uint32_t off, Cluster c, Kind k, bool weakIm, const char* name) :
                offsetInAtom(off), kind(k), clusterSize(c), weakImport(weakIm), 
                binding(Fixup::bindingByNameUnbound),  
                        { u.addend = 0; }
 
        Fixup(uint32_t off, Cluster c, Kind k, bool weakIm, const char* name) :
                offsetInAtom(off), kind(k), clusterSize(c), weakImport(weakIm), 
                binding(Fixup::bindingByNameUnbound),  
-               contentAddendOnly(false), contentDetlaToAddendOnly(false) 
+               contentAddendOnly(false), contentDetlaToAddendOnly(false), contentIgnoresAddend(false) 
                        { assert(name != NULL); u.name = name; }
                
        Fixup(uint32_t off, Cluster c, Kind k, TargetBinding b, const char* name) :
                offsetInAtom(off), kind(k), clusterSize(c), weakImport(false), binding(b),  
                        { assert(name != NULL); u.name = name; }
                
        Fixup(uint32_t off, Cluster c, Kind k, TargetBinding b, const char* name) :
                offsetInAtom(off), kind(k), clusterSize(c), weakImport(false), binding(b),  
-               contentAddendOnly(false), contentDetlaToAddendOnly(false) 
+               contentAddendOnly(false), contentDetlaToAddendOnly(false), contentIgnoresAddend(false) 
                        { assert(name != NULL); u.name = name; }
                
        Fixup(uint32_t off, Cluster c, Kind k, const Atom* targetAtom) :
                offsetInAtom(off), kind(k), clusterSize(c), weakImport(false), 
                binding(Fixup::bindingDirectlyBound),  
                        { assert(name != NULL); u.name = name; }
                
        Fixup(uint32_t off, Cluster c, Kind k, const Atom* targetAtom) :
                offsetInAtom(off), kind(k), clusterSize(c), weakImport(false), 
                binding(Fixup::bindingDirectlyBound),  
-               contentAddendOnly(false), contentDetlaToAddendOnly(false) 
+               contentAddendOnly(false), contentDetlaToAddendOnly(false), contentIgnoresAddend(false) 
                        { assert(targetAtom != NULL); u.target = targetAtom; }
                
        Fixup(uint32_t off, Cluster c, Kind k, TargetBinding b, const Atom* targetAtom) :
                offsetInAtom(off), kind(k), clusterSize(c), weakImport(false), binding(b),  
                        { assert(targetAtom != NULL); u.target = targetAtom; }
                
        Fixup(uint32_t off, Cluster c, Kind k, TargetBinding b, const Atom* targetAtom) :
                offsetInAtom(off), kind(k), clusterSize(c), weakImport(false), binding(b),  
-               contentAddendOnly(false), contentDetlaToAddendOnly(false) 
+               contentAddendOnly(false), contentDetlaToAddendOnly(false), contentIgnoresAddend(false) 
                        { assert(targetAtom != NULL); u.target = targetAtom; }
                
        Fixup(uint32_t off, Cluster c, Kind k, uint64_t addend) :
                offsetInAtom(off), kind(k), clusterSize(c), weakImport(false), 
                binding(Fixup::bindingNone),  
                        { assert(targetAtom != NULL); u.target = targetAtom; }
                
        Fixup(uint32_t off, Cluster c, Kind k, uint64_t addend) :
                offsetInAtom(off), kind(k), clusterSize(c), weakImport(false), 
                binding(Fixup::bindingNone),  
-               contentAddendOnly(false), contentDetlaToAddendOnly(false) 
+               contentAddendOnly(false), contentDetlaToAddendOnly(false), contentIgnoresAddend(false) 
                        { u.addend = addend; }
                        
        bool firstInCluster() const { 
                        { u.addend = addend; }
                        
        bool firstInCluster() const { 
@@ -611,7 +643,7 @@ public:
                                                                                                                switch ( _combine ) {
                                                                                                                        case combineByNameAndContent:
                                                                                                                        case combineByNameAndReferences:
                                                                                                                switch ( _combine ) {
                                                                                                                        case combineByNameAndContent:
                                                                                                                        case combineByNameAndReferences:
-                                                                                                                               assert(_symbolTableInclusion == symbolTableNotIn);
+                                                                                                                               assert(_symbolTableInclusion != symbolTableIn);
                                                                                                                                assert(_scope != scopeGlobal);
                                                                 break;
                                                             case combineByName:
                                                                                                                                assert(_scope != scopeGlobal);
                                                                 break;
                                                             case combineByName:
@@ -692,7 +724,6 @@ protected:
                                                                                                        _combine = a._combine;
                                                                                                        _dontDeadStrip = a._dontDeadStrip;
                                                                                                        _thumb = a._thumb;
                                                                                                        _combine = a._combine;
                                                                                                        _dontDeadStrip = a._dontDeadStrip;
                                                                                                        _thumb = a._thumb;
-                                                                                                       _alias = a._alias;
                                                                                                        _autoHide = a._autoHide;
                                                                                                        _contentType = a._contentType;
                                                                                                        _symbolTableInclusion = a._symbolTableInclusion;
                                                                                                        _autoHide = a._autoHide;
                                                                                                        _contentType = a._contentType;
                                                                                                        _symbolTableInclusion = a._symbolTableInclusion;
@@ -733,6 +764,23 @@ public:
 };
 
 
 };
 
 
+       
+// utility classes for using std::unordered_map with c-strings
+struct CStringHash {
+       size_t operator()(const char* __s) const {
+               size_t __h = 0;
+               for ( ; *__s; ++__s)
+                       __h = 5 * __h + *__s;
+               return __h;
+       };
+};
+struct CStringEquals
+{
+       bool operator()(const char* left, const char* right) const { return (strcmp(left, right) == 0); }
+};
+
+typedef        std::unordered_set<const char*, ld::CStringHash, ld::CStringEquals>  CStringSet;
+
 class Internal
 {
 public:
 class Internal
 {
 public:
@@ -757,6 +805,7 @@ public:
                bool                                                    hasExternalRelocs;
        };
        
                bool                                                    hasExternalRelocs;
        };
        
+
        virtual ld::Internal::FinalSection*     addAtom(const Atom&) = 0;
        virtual ld::Internal::FinalSection* getFinalSection(const ld::Section& inputSection) = 0;
        virtual                                                         ~Internal() {}
        virtual ld::Internal::FinalSection*     addAtom(const Atom&) = 0;
        virtual ld::Internal::FinalSection* getFinalSection(const ld::Section& inputSection) = 0;
        virtual                                                         ~Internal() {}
@@ -772,6 +821,8 @@ public:
        std::vector<FinalSection*>                                      sections;
        std::vector<ld::dylib::File*>                           dylibs;
        std::vector<ld::relocatable::File::Stab>        stabs;
        std::vector<FinalSection*>                                      sections;
        std::vector<ld::dylib::File*>                           dylibs;
        std::vector<ld::relocatable::File::Stab>        stabs;
+       CStringSet                                                                      linkerOptionLibraries;
+       CStringSet                                                                      linkerOptionFrameworks;
        std::vector<const ld::Atom*>                            indirectBindingTable;
        const ld::dylib::File*                                          bundleLoader;
        const Atom*                                                                     entryPoint;
        std::vector<const ld::Atom*>                            indirectBindingTable;
        const ld::dylib::File*                                          bundleLoader;
        const Atom*                                                                     entryPoint;
@@ -788,21 +839,6 @@ public:
 
 
 
 
 
 
-       
-// utility classes for using std::unordered_map with c-strings
-struct CStringHash {
-       size_t operator()(const char* __s) const {
-               size_t __h = 0;
-               for ( ; *__s; ++__s)
-                       __h = 5 * __h + *__s;
-               return __h;
-       };
-};
-struct CStringEquals
-{
-       bool operator()(const char* left, const char* right) const { return (strcmp(left, right) == 0); }
-};
-
 
 
 
 
 
 
index 708f1fb4f8fe56d2cd43a87e214eb535b28d37c7..49240b3008b3156b0ffe2695941a067f64c8190e 100644 (file)
@@ -109,7 +109,7 @@ private:
 
        };
 
 
        };
 
-       struct MemberState { ld::relocatable::File* file; const Entry *entry; bool logged; bool loaded; uint16_t index;};
+       struct MemberState { ld::relocatable::File* file; const Entry *entry; bool logged; bool loaded; uint32_t index;};
        bool                                                                                    loadMember(MemberState& state, ld::File::AtomHandler& handler, const char *format, ...) const;
 
        typedef std::unordered_map<const char*, const struct ranlib*, ld::CStringHash, ld::CStringEquals> NameToEntryMap;
        bool                                                                                    loadMember(MemberState& state, ld::File::AtomHandler& handler, const char *format, ...) const;
 
        typedef std::unordered_map<const char*, const struct ranlib*, ld::CStringHash, ld::CStringEquals> NameToEntryMap;
@@ -223,6 +223,7 @@ const class File<A>::Entry* File<A>::Entry::next() const
 template <> cpu_type_t File<x86>::architecture()    { return CPU_TYPE_I386; }
 template <> cpu_type_t File<x86_64>::architecture() { return CPU_TYPE_X86_64; }
 template <> cpu_type_t File<arm>::architecture()    { return CPU_TYPE_ARM; }
 template <> cpu_type_t File<x86>::architecture()    { return CPU_TYPE_I386; }
 template <> cpu_type_t File<x86_64>::architecture() { return CPU_TYPE_X86_64; }
 template <> cpu_type_t File<arm>::architecture()    { return CPU_TYPE_ARM; }
+template <> cpu_type_t File<arm64>::architecture()  { return CPU_TYPE_ARM64; }
 
 
 template <typename A>
 
 
 template <typename A>
@@ -323,13 +324,13 @@ bool File<A>::memberHasObjCCategories(const Entry* member) const
 template <typename A>
 typename File<A>::MemberState& File<A>::makeObjectFileForMember(const Entry* member) const
 {
 template <typename A>
 typename File<A>::MemberState& File<A>::makeObjectFileForMember(const Entry* member) const
 {
-       uint16_t memberIndex = 0;
+       uint32_t memberIndex = 0;
        // in case member was instantiated earlier but not needed yet
        typename MemberToStateMap::iterator pos = _instantiatedEntries.find(member);
        if ( pos == _instantiatedEntries.end() ) {
                // Have to find the index of this member
                const Entry* start;
        // in case member was instantiated earlier but not needed yet
        typename MemberToStateMap::iterator pos = _instantiatedEntries.find(member);
        if ( pos == _instantiatedEntries.end() ) {
                // Have to find the index of this member
                const Entry* start;
-               uint16_t index;
+               uint32_t index;
                if (_instantiatedEntries.size() == 0) {
                        start = (Entry*)&_archiveFileContent[8];
                        index = 1;
                if (_instantiatedEntries.size() == 0) {
                        start = (Entry*)&_archiveFileContent[8];
                        index = 1;
@@ -598,6 +599,12 @@ ld::archive::File* parse(const uint8_t* fileContent, uint64_t fileLength,
                        if ( archive::Parser<arm>::validFile(fileContent, fileLength, opts.objOpts) )
                                return archive::Parser<arm>::parse(fileContent, fileLength, path, modTime, ordinal, opts);
                        break;
                        if ( archive::Parser<arm>::validFile(fileContent, fileLength, opts.objOpts) )
                                return archive::Parser<arm>::parse(fileContent, fileLength, path, modTime, ordinal, opts);
                        break;
+#endif
+#if SUPPORT_ARCH_arm64
+               case CPU_TYPE_ARM64:
+                       if ( archive::Parser<arm64>::validFile(fileContent, fileLength, opts.objOpts) )
+                               return archive::Parser<arm64>::parse(fileContent, fileLength, path, modTime, ordinal, opts);
+                       break;
 #endif
        }
        return NULL;
 #endif
        }
        return NULL;
index b04582d80b18fd88a00be1e7a9bdf1bbef26ee73..c67a2372bbb30c0b0f258a5d62817056bfcc03da 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
  *
 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
  *
- * Copyright (c) 2008 Apple Inc. All rights reserved.
+ * Copyright (c) 2008-2013 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  *
  *
  * @APPLE_LICENSE_HEADER_START@
  *
@@ -95,7 +95,8 @@ public:
        typedef typename A::sint_t              sint_t; 
 
        static const char* parseCFIs(A& addressSpace, pint_t ehSectionStart, uint32_t sectionLength, 
        typedef typename A::sint_t              sint_t; 
 
        static const char* parseCFIs(A& addressSpace, pint_t ehSectionStart, uint32_t sectionLength, 
-                                               CFI_Atom_Info<A>* infos, uint32_t infosCount, void* ref, WarnFunc warn);
+                            const pint_t cuStarts[], uint32_t cuCount, bool keepDwarfWhichHasCU, bool forceDwarfConversion,
+                            CFI_Atom_Info<A>* infos, uint32_t& infosCount, void* ref, WarnFunc warn);
 
 
        static compact_unwind_encoding_t createCompactEncodingFromFDE(A& addressSpace, pint_t fdeStart, 
 
 
        static compact_unwind_encoding_t createCompactEncodingFromFDE(A& addressSpace, pint_t fdeStart, 
@@ -152,6 +153,18 @@ private:
        static compact_unwind_encoding_t createCompactEncodingFromProlog(A& addressSpace, pint_t funcAddr,
                                                                                                const Registers_ppc&, const typename CFI_Parser<A>::PrologInfo& prolog,
                                                                                                char warningBuffer[1024]);
        static compact_unwind_encoding_t createCompactEncodingFromProlog(A& addressSpace, pint_t funcAddr,
                                                                                                const Registers_ppc&, const typename CFI_Parser<A>::PrologInfo& prolog,
                                                                                                char warningBuffer[1024]);
+                                                                                               
+       // arm64 specific variants
+       static bool   isReturnAddressRegister(int regNum, const Registers_arm64&);
+       static int    lastRestoreReg(const Registers_arm64&);
+       static pint_t getCFA(A& addressSpace, const typename CFI_Parser<A>::PrologInfo& prolog, const Registers_arm64&);
+       static bool checkRegisterPair(uint32_t reg, const typename CFI_Parser<A>::PrologInfo& prolog,
+                                                                                               int& offset, char warningBuffer[1024]);
+       static compact_unwind_encoding_t encodeToUseDwarf(const Registers_arm64&);
+       static compact_unwind_encoding_t createCompactEncodingFromProlog(A& addressSpace, pint_t funcAddr,
+                                                                                               const Registers_arm64&, const typename CFI_Parser<A>::PrologInfo& prolog,
+                                                                                               char warningBuffer[1024]);
+       
 };
 
 
 };
 
 
@@ -159,7 +172,8 @@ private:
 
 template <typename A, typename R>
 const char* DwarfInstructions<A,R>::parseCFIs(A& addressSpace, pint_t ehSectionStart, uint32_t sectionLength, 
 
 template <typename A, typename R>
 const char* DwarfInstructions<A,R>::parseCFIs(A& addressSpace, pint_t ehSectionStart, uint32_t sectionLength, 
-                                                                                               CFI_Atom_Info<A>* infos, uint32_t infosCount, void* ref, WarnFunc warn)
+                                      const pint_t cuStarts[], uint32_t cuCount,  bool keepDwarfWhichHasCU,  bool forceDwarfConversion,
+                                      CFI_Atom_Info<A>* infos, uint32_t& infosCount, void* ref, WarnFunc warn)
 {
        typename CFI_Parser<A>::CIE_Info cieInfo;
        CFI_Atom_Info<A>* entry = infos;
 {
        typename CFI_Parser<A>::CIE_Info cieInfo;
        CFI_Atom_Info<A>* entry = infos;
@@ -221,7 +235,6 @@ const char* DwarfInstructions<A,R>::parseCFIs(A& addressSpace, pint_t ehSectionS
                        pint_t pcStart = addressSpace.getEncodedP(p, nextCFI, cieInfo.pointerEncoding);
                        pint_t pcRange = addressSpace.getEncodedP(p, nextCFI, cieInfo.pointerEncoding & 0x0F);
                        //fprintf(stderr, "FDE with pcRange [0x%08llX, 0x%08llX)\n",(uint64_t)pcStart, (uint64_t)(pcStart+pcRange));
                        pint_t pcStart = addressSpace.getEncodedP(p, nextCFI, cieInfo.pointerEncoding);
                        pint_t pcRange = addressSpace.getEncodedP(p, nextCFI, cieInfo.pointerEncoding & 0x0F);
                        //fprintf(stderr, "FDE with pcRange [0x%08llX, 0x%08llX)\n",(uint64_t)pcStart, (uint64_t)(pcStart+pcRange));
-                       // test if pc is within the function this FDE covers
                        entry->u.fdeInfo.function.targetAddress = pcStart;
                        entry->u.fdeInfo.function.offsetInCFI = offsetOfFunctionAddress;
                        entry->u.fdeInfo.function.encodingOfTargetAddress = cieInfo.pointerEncoding;
                        entry->u.fdeInfo.function.targetAddress = pcStart;
                        entry->u.fdeInfo.function.offsetInCFI = offsetOfFunctionAddress;
                        entry->u.fdeInfo.function.encodingOfTargetAddress = cieInfo.pointerEncoding;
@@ -243,34 +256,60 @@ const char* DwarfInstructions<A,R>::parseCFIs(A& addressSpace, pint_t ehSectionS
                                }
                                p = endOfAug;
                        }
                                }
                                p = endOfAug;
                        }
-                       // compute compact unwind encoding
-                       typename CFI_Parser<A>::FDE_Info fdeInfo;
-                       fdeInfo.fdeStart = currentCFI;
-                       fdeInfo.fdeLength = nextCFI - currentCFI;
-                       fdeInfo.fdeInstructions = p;
-                       fdeInfo.pcStart = pcStart;
-                       fdeInfo.pcEnd = pcStart +  pcRange;
-                       fdeInfo.lsda = entry->u.fdeInfo.lsda.targetAddress;
-                       typename CFI_Parser<A>::PrologInfo prolog;
-                       R dummy; // for proper selection of architecture specific functions
-                       if ( CFI_Parser<A>::parseFDEInstructions(addressSpace, fdeInfo, cieInfo, CFI_INVALID_ADDRESS, &prolog) ) {
-                               char warningBuffer[1024];
-                               entry->u.fdeInfo.compactUnwindInfo = createCompactEncodingFromProlog(addressSpace, fdeInfo.pcStart, dummy, prolog, warningBuffer);
-                               if ( fdeInfo.lsda != CFI_INVALID_ADDRESS ) 
-                                       entry->u.fdeInfo.compactUnwindInfo |= UNWIND_HAS_LSDA;
-                               if ( warningBuffer[0] != '\0' )
-                                       warn(ref, fdeInfo.pcStart, warningBuffer);
+                       // See if already is a compact unwind for this address.  
+                       bool alreadyHaveCU = false;
+                       for (uint32_t i=0; i < cuCount; ++i) {
+                               if (cuStarts[i] == entry->u.fdeInfo.function.targetAddress) {
+                                 alreadyHaveCU = true;
+                                 break;
+                               }
+                       }
+                       //fprintf(stderr, "FDE for func at 0x%08X, alreadyHaveCU=%d\n", (uint32_t)entry->u.fdeInfo.function.targetAddress, alreadyHaveCU);
+                       if ( alreadyHaveCU && !forceDwarfConversion ) {
+                               if ( keepDwarfWhichHasCU )
+                                       ++entry;
                        }
                        else {
                        }
                        else {
-                               warn(ref, CFI_INVALID_ADDRESS, "dwarf unwind instructions could not be parsed");
-                               entry->u.fdeInfo.compactUnwindInfo = encodeToUseDwarf(dummy);
+                               if ( (cuCount != 0) && !forceDwarfConversion ) {
+                                       // Have some compact unwind, so this is a new .o file, therefore anything without
+                                       // compact unwind must be something not expressable in compact unwind.
+                                       R dummy;
+                                       entry->u.fdeInfo.compactUnwindInfo = encodeToUseDwarf(dummy);
+                               }
+                               else {
+                                       // compute compact unwind encoding by parsing dwarf
+                                       typename CFI_Parser<A>::FDE_Info fdeInfo;
+                                       fdeInfo.fdeStart = currentCFI;
+                                       fdeInfo.fdeLength = nextCFI - currentCFI;
+                                       fdeInfo.fdeInstructions = p;
+                                       fdeInfo.pcStart = pcStart;
+                                       fdeInfo.pcEnd = pcStart +  pcRange;
+                                       fdeInfo.lsda = entry->u.fdeInfo.lsda.targetAddress;
+                                       typename CFI_Parser<A>::PrologInfo prolog;
+                                       R dummy; // for proper selection of architecture specific functions
+                                       if ( CFI_Parser<A>::parseFDEInstructions(addressSpace, fdeInfo, cieInfo, CFI_INVALID_ADDRESS, &prolog) ) {
+                                               char warningBuffer[1024];
+                                               entry->u.fdeInfo.compactUnwindInfo = createCompactEncodingFromProlog(addressSpace, fdeInfo.pcStart, dummy, prolog, warningBuffer);
+                                               if ( fdeInfo.lsda != CFI_INVALID_ADDRESS ) 
+                                                       entry->u.fdeInfo.compactUnwindInfo |= UNWIND_HAS_LSDA;
+                                               if ( warningBuffer[0] != '\0' )
+                                                       warn(ref, fdeInfo.pcStart, warningBuffer);
+                                       }
+                                       else {
+                                               warn(ref, CFI_INVALID_ADDRESS, "dwarf unwind instructions could not be parsed");
+                                               entry->u.fdeInfo.compactUnwindInfo = encodeToUseDwarf(dummy);
+                                       }
+                               }
+                               ++entry;
                        }
                        }
-                       ++entry;
                }
                p = nextCFI;
        }
                }
                p = nextCFI;
        }
-       if ( entry != end )
-               return "wrong entry count for parseCFIs";
+       if ( entry != end ) {
+               //fprintf(stderr, "DwarfInstructions<A,R>::parseCFIs() infosCount was %d on input, now %ld\n", infosCount, entry - infos); 
+               infosCount = (entry - infos);
+       }
+       
        return NULL; // success
 }
 
        return NULL; // success
 }
 
@@ -1037,7 +1076,7 @@ compact_unwind_encoding_t DwarfInstructions<A,R>::createCompactEncodingFromProlo
        for (int i=0; i < 64; ++i) {
                if ( prolog.savedRegisters[i].location != CFI_Parser<A>::kRegisterUnused ) {
                        if ( prolog.savedRegisters[i].location != CFI_Parser<A>::kRegisterInCFA ) {
        for (int i=0; i < 64; ++i) {
                if ( prolog.savedRegisters[i].location != CFI_Parser<A>::kRegisterUnused ) {
                        if ( prolog.savedRegisters[i].location != CFI_Parser<A>::kRegisterInCFA ) {
-                               sprintf(warningBuffer, "register %d saved somewhere other that in frame", i);
+                               sprintf(warningBuffer, "register %d saved somewhere other than in frame", i);
                                return UNWIND_X86_64_MODE_DWARF;
                        }
                        switch (i) {
                                return UNWIND_X86_64_MODE_DWARF;
                        }
                        switch (i) {
@@ -1184,15 +1223,19 @@ compact_unwind_encoding_t DwarfInstructions<A,R>::createCompactEncodingFromProlo
                                strcpy(warningBuffer, "stack size is large but stack subq instruction not found");
                                return UNWIND_X86_64_MODE_DWARF;
                        }
                                strcpy(warningBuffer, "stack size is large but stack subq instruction not found");
                                return UNWIND_X86_64_MODE_DWARF;
                        }
-                       pint_t functionContentAdjustStackIns = funcAddr + prolog.codeOffsetAtStackDecrement - 4;                
+                       pint_t functionContentAdjustStackIns = funcAddr + prolog.codeOffsetAtStackDecrement - 4;
+        #if __EXCEPTIONS 
                        try {
                        try {
+        #endif
                                uint32_t stackDecrementInCode = addressSpace.get32(functionContentAdjustStackIns);
                                stackAdjust = (prolog.cfaRegisterOffset - stackDecrementInCode)/8;
                                uint32_t stackDecrementInCode = addressSpace.get32(functionContentAdjustStackIns);
                                stackAdjust = (prolog.cfaRegisterOffset - stackDecrementInCode)/8;
+        #if __EXCEPTIONS 
                        }
                        catch (...) {
                                strcpy(warningBuffer, "stack size is large but stack subq instruction not found");
                                return UNWIND_X86_64_MODE_DWARF;
                        }
                        }
                        catch (...) {
                                strcpy(warningBuffer, "stack size is large but stack subq instruction not found");
                                return UNWIND_X86_64_MODE_DWARF;
                        }
+        #endif
                        stackValue = functionContentAdjustStackIns - funcAddr;
                        immedStackSize = false;
                        if ( stackAdjust > 7 ) {
                        stackValue = functionContentAdjustStackIns - funcAddr;
                        immedStackSize = false;
                        if ( stackAdjust > 7 ) {
@@ -1410,7 +1453,7 @@ compact_unwind_encoding_t DwarfInstructions<A,R>::createCompactEncodingFromProlo
        for (int i=0; i < 64; ++i) {
                if ( prolog.savedRegisters[i].location != CFI_Parser<A>::kRegisterUnused ) {
                        if ( prolog.savedRegisters[i].location != CFI_Parser<A>::kRegisterInCFA ) {
        for (int i=0; i < 64; ++i) {
                if ( prolog.savedRegisters[i].location != CFI_Parser<A>::kRegisterUnused ) {
                        if ( prolog.savedRegisters[i].location != CFI_Parser<A>::kRegisterInCFA ) {
-                               sprintf(warningBuffer, "register %d saved somewhere other that in frame", i);
+                               sprintf(warningBuffer, "register %d saved somewhere other than in frame", i);
                                return UNWIND_X86_MODE_DWARF;
                        }
                        switch (i) {
                                return UNWIND_X86_MODE_DWARF;
                        }
                        switch (i) {
@@ -1554,12 +1597,22 @@ compact_unwind_encoding_t DwarfInstructions<A,R>::createCompactEncodingFromProlo
                if ( stackValue > stackMaxImmedValue ) {
                        // stack size is too big to fit as an immediate value, so encode offset of subq instruction in function
                        pint_t functionContentAdjustStackIns = funcAddr + prolog.codeOffsetAtStackDecrement - 4;                
                if ( stackValue > stackMaxImmedValue ) {
                        // stack size is too big to fit as an immediate value, so encode offset of subq instruction in function
                        pint_t functionContentAdjustStackIns = funcAddr + prolog.codeOffsetAtStackDecrement - 4;                
-                       uint32_t stackDecrementInCode = addressSpace.get32(functionContentAdjustStackIns);
-                       stackAdjust = (prolog.cfaRegisterOffset - stackDecrementInCode)/4;
+        #if __EXCEPTIONS 
+                       try {
+        #endif
+                uint32_t stackDecrementInCode = addressSpace.get32(functionContentAdjustStackIns);
+                stackAdjust = (prolog.cfaRegisterOffset - stackDecrementInCode)/4;
+        #if __EXCEPTIONS 
+                       }
+                       catch (...) {
+                               strcpy(warningBuffer, "stack size is large but stack subl instruction not found");
+                               return UNWIND_X86_MODE_DWARF;
+                       }
+        #endif
                        stackValue = functionContentAdjustStackIns - funcAddr;
                        immedStackSize = false;
                        if ( stackAdjust > 7 ) {
                        stackValue = functionContentAdjustStackIns - funcAddr;
                        immedStackSize = false;
                        if ( stackAdjust > 7 ) {
-                               strcpy(warningBuffer, "stack subq instruction is too different from dwarf stack size");
+                               strcpy(warningBuffer, "stack subl instruction is too different from dwarf stack size");
                                return UNWIND_X86_MODE_DWARF;
                        }
                        encoding = UNWIND_X86_MODE_STACK_IND;
                                return UNWIND_X86_MODE_DWARF;
                        }
                        encoding = UNWIND_X86_MODE_STACK_IND;
@@ -1715,6 +1768,195 @@ compact_unwind_encoding_t DwarfInstructions<A,R>::createCompactEncodingFromProlo
 
 
 
 
 
 
+//
+// arm64 specific functions
+//
+
+template <typename A, typename R>
+compact_unwind_encoding_t DwarfInstructions<A,R>::encodeToUseDwarf(const Registers_arm64&) 
+{
+       return UNWIND_ARM64_MODE_DWARF;
+}
+
+template <typename A, typename R>
+bool DwarfInstructions<A,R>::isReturnAddressRegister(int regNum, const Registers_arm64&) 
+{
+       return (regNum == UNW_ARM64_LR); 
+}
+
+template <typename A, typename R>
+int DwarfInstructions<A,R>::lastRestoreReg(const Registers_arm64&) 
+{
+       COMPILE_TIME_ASSERT( (int)CFI_Parser<A>::kMaxRegisterNumber > (int)UNW_ARM64_D31 );
+       return UNW_ARM64_D31; 
+}
+
+
+template <typename A, typename R>
+typename A::pint_t DwarfInstructions<A,R>::getCFA(A& addressSpace, const typename CFI_Parser<A>::PrologInfo& prolog, 
+                                                                               const Registers_arm64& registers)
+{
+       if ( prolog.cfaRegister != 0 )
+               return registers.getRegister(prolog.cfaRegister) + prolog.cfaRegisterOffset;
+       else
+               ABORT("getCFA(): unsupported location for arm64 cfa");
+}
+
+template <typename A, typename R>
+bool DwarfInstructions<A,R>::checkRegisterPair(uint32_t reg, const typename CFI_Parser<A>::PrologInfo& prolog,
+                                                                                               int& offset, char warningBuffer[1024])
+{
+       if ( (prolog.savedRegisters[reg].location != CFI_Parser<A>::kRegisterUnused)
+         || (prolog.savedRegisters[reg+1].location != CFI_Parser<A>::kRegisterUnused) ) {
+               if ( prolog.savedRegisters[reg].location != CFI_Parser<A>::kRegisterInCFA ) {
+                       sprintf(warningBuffer, "register %d saved somewhere other than in frame", reg);
+                       return false;
+               }
+               if ( prolog.savedRegisters[reg+1].location != CFI_Parser<A>::kRegisterInCFA ) {
+                       sprintf(warningBuffer, "register %d saved somewhere other than in frame", reg+1);
+                       return false;
+               }
+               if ( prolog.savedRegisters[reg].value != prolog.savedRegisters[reg+1].value + 8 ) {
+                       sprintf(warningBuffer, "registers %d and %d not saved contiguously in frame", reg, reg+1);
+                       return false;
+               }
+               if ( prolog.savedRegisters[reg].value != offset ) {
+                       sprintf(warningBuffer, "registers %d not saved contiguously in frame", reg);
+                       return false;
+               }
+               offset -= 16;
+               return true;
+       }
+       return false;
+}
+
+
+template <typename A, typename R>
+compact_unwind_encoding_t DwarfInstructions<A,R>::createCompactEncodingFromProlog(A& addressSpace, pint_t funcAddr,
+                                                                                               const Registers_arm64& r, const typename CFI_Parser<A>::PrologInfo& prolog,
+                                                                                               char warningBuffer[1024])
+{
+       warningBuffer[0] = '\0';
+       
+       if ( prolog.registerSavedTwiceInCIE == UNW_ARM64_LR ) {
+               warningBuffer[0] = '\0';        // silently disable conversion to compact unwind by linker
+               return UNWIND_ARM64_MODE_DWARF;
+       }
+       // don't create compact unwind info for unsupported dwarf kinds
+       if ( prolog.registerSavedMoreThanOnce ) {
+               strcpy(warningBuffer, "register saved more than once (might be shrink wrap)");
+               return UNWIND_ARM64_MODE_DWARF;
+       }
+       if ( prolog.spExtraArgSize != 0 ) {
+               strcpy(warningBuffer, "dwarf uses DW_CFA_GNU_args_size");
+               return UNWIND_ARM64_MODE_DWARF;
+       }
+       if ( prolog.sameValueUsed ) {
+               strcpy(warningBuffer, "dwarf uses DW_CFA_same_value");
+               return UNWIND_ARM64_MODE_DWARF;
+       }
+       
+       compact_unwind_encoding_t encoding = 0;
+       int offset = 0;
+
+       // figure out which kind of frame this function uses
+       bool standardFPframe = ( 
+                (prolog.cfaRegister == UNW_ARM64_FP) 
+         && (prolog.cfaRegisterOffset == 16)
+         && (prolog.savedRegisters[UNW_ARM64_FP].location == CFI_Parser<A>::kRegisterInCFA)
+         && (prolog.savedRegisters[UNW_ARM64_FP].value == -16) 
+         && (prolog.savedRegisters[UNW_ARM64_LR].location == CFI_Parser<A>::kRegisterInCFA)
+         && (prolog.savedRegisters[UNW_ARM64_LR].value == -8) );
+
+       bool standardFrameless = ( prolog.cfaRegister == UNW_ARM64_SP );
+       
+       if ( standardFrameless ) {
+               // verify enough space for registers saved
+               int count = 0;
+               for (int i=0; i < 96; ++i) {
+                       if ( prolog.savedRegisters[i].location != CFI_Parser<A>::kRegisterUnused ) 
+                               ++count;
+               }
+               if ( count * 8 > prolog.cfaRegisterOffset ) {
+                       strcpy(warningBuffer, "saved registers do not fit in stack size");
+                       return UNWIND_ARM64_MODE_DWARF;
+               }
+               if ( (prolog.cfaRegisterOffset % 16) != 0 ) {
+                       strcpy(warningBuffer, "stack size is not 16-byte multiple");
+                       return UNWIND_ARM64_MODE_DWARF;
+               }
+               const int32_t maxStack = (UNWIND_ARM64_FRAMELESS_STACK_SIZE_MASK >> __builtin_ctz(UNWIND_ARM64_FRAMELESS_STACK_SIZE_MASK));
+               if ( (prolog.cfaRegisterOffset / 16) > maxStack ) {
+                       strcpy(warningBuffer, "stack size is too large for frameless function");
+                       return UNWIND_ARM64_MODE_DWARF;
+               }
+               encoding = UNWIND_ARM64_MODE_FRAMELESS | ((prolog.cfaRegisterOffset/16) << __builtin_ctz(UNWIND_ARM64_FRAMELESS_STACK_SIZE_MASK));
+               offset = -16;
+       }
+       else if ( standardFPframe  ) {
+               encoding = UNWIND_ARM64_MODE_FRAME;
+               offset = -24;
+       }
+       else {
+               // no compact encoding for this
+               strcpy(warningBuffer, "does not use standard frame");
+               return UNWIND_ARM64_MODE_DWARF;
+       }
+               
+       // make sure no volatile registers are saved
+       for (int i=UNW_ARM64_X0; i < UNW_ARM64_X19; ++i) {
+               if ( prolog.savedRegisters[i].location != CFI_Parser<A>::kRegisterUnused ) {
+                       sprintf(warningBuffer, "non standard register %d saved in frame", i);
+                       return UNWIND_ARM64_MODE_DWARF;
+               }
+       }
+       for (int i=UNW_ARM64_SP+1; i < UNW_ARM64_D8; ++i) {
+               if ( prolog.savedRegisters[i].location != CFI_Parser<A>::kRegisterUnused ) {
+                       sprintf(warningBuffer, "non standard register %d saved in frame", i);
+                       return UNWIND_ARM64_MODE_DWARF;
+               }
+       }
+       for (int i=UNW_ARM64_D16; i < UNW_ARM64_D31+1; ++i) {
+               if ( prolog.savedRegisters[i].location != CFI_Parser<A>::kRegisterUnused ) {
+                       sprintf(warningBuffer, "non standard register %d saved in frame", i);
+                       return UNWIND_ARM64_MODE_DWARF;
+               }
+       }
+
+       // compute encoding
+       bool X19_X20_saved = checkRegisterPair(UNW_ARM64_X19, prolog, offset, warningBuffer);
+       bool X21_X22_saved = checkRegisterPair(UNW_ARM64_X21, prolog, offset, warningBuffer);
+       bool X23_X24_saved = checkRegisterPair(UNW_ARM64_X23, prolog, offset, warningBuffer);
+       bool X25_X26_saved = checkRegisterPair(UNW_ARM64_X25, prolog, offset, warningBuffer);
+       bool X27_X28_saved = checkRegisterPair(UNW_ARM64_X27, prolog, offset, warningBuffer);
+       bool D8_D9_saved   = checkRegisterPair(UNW_ARM64_D8,  prolog, offset, warningBuffer);
+       bool D10_D11_saved = checkRegisterPair(UNW_ARM64_D10, prolog, offset, warningBuffer);
+       bool D12_D13_saved = checkRegisterPair(UNW_ARM64_D12, prolog, offset, warningBuffer);
+       bool D14_D15_saved = checkRegisterPair(UNW_ARM64_D14, prolog, offset, warningBuffer);
+       if ( warningBuffer[0] != '\0' )
+               return UNWIND_ARM64_MODE_DWARF;
+
+       if ( X19_X20_saved )
+               encoding |= UNWIND_ARM64_FRAME_X19_X20_PAIR;
+       if ( X21_X22_saved )
+               encoding |= UNWIND_ARM64_FRAME_X21_X22_PAIR;
+       if ( X23_X24_saved )
+               encoding |= UNWIND_ARM64_FRAME_X23_X24_PAIR;
+       if ( X25_X26_saved )
+               encoding |= UNWIND_ARM64_FRAME_X25_X26_PAIR;
+       if ( X27_X28_saved )
+               encoding |= UNWIND_ARM64_FRAME_X27_X28_PAIR;
+       if ( D8_D9_saved )
+               encoding |= UNWIND_ARM64_FRAME_D8_D9_PAIR;
+       if ( D10_D11_saved )
+               encoding |= UNWIND_ARM64_FRAME_D10_D11_PAIR;
+       if ( D12_D13_saved )
+               encoding |= UNWIND_ARM64_FRAME_D12_D13_PAIR;
+       if ( D14_D15_saved )
+               encoding |= UNWIND_ARM64_FRAME_D14_D15_PAIR;
+
+  return encoding;
+}
 
 } // namespace libunwind
 
 
 } // namespace libunwind
 
index 3824d2e2f80d837ffa5613b608341354e307216a..2e4a3bbeb43cb217d71c49fe1c5e4aada26714a8 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
  *
 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
  *
- * Copyright (c) 2008 Apple Inc. All rights reserved.
+ * Copyright (c) 2008-2010 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  *
  *
  * @APPLE_LICENSE_HEADER_START@
  *
index 7d39fd74ad9eb5b72acdaf7e4aba32425be4b585..02470665623f62a79df30e548de1ec03862adef1 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
  *
 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
  *
- * Copyright (c) 2007-2009 Apple Inc. All rights reserved.
+ * Copyright (c) 2007-2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  *
  *
  * @APPLE_LICENSE_HEADER_START@
  *
@@ -1035,9 +1035,288 @@ inline const char* Registers_ppc::getRegisterName(int regNum)
                        return "unknown register";
        }
 
                        return "unknown register";
        }
 
+}
+
+
+
+
+
+struct arm_thread_state64_t
+{
+       __uint64_t    __x[29];  /* General purpose registers x0-x28 */
+       __uint64_t    __fp;             /* Frame pointer x29 */
+       __uint64_t    __lr;             /* Link register x30 */
+       __uint64_t    __sp;             /* Stack pointer x31 */
+       __uint64_t    __pc;             /* Program counter */
+       __uint32_t    __cpsr;   /* Current program status register */
+       __uint32_t        padding[3]; /* round up struct size to be 0x110 */
+};
+
+
+///
+/// Registers_arm64  holds the register state of a thread in a 64-bit intel process.  
+///
+class Registers_arm64
+{
+public:        
+                                       Registers_arm64();
+                                       Registers_arm64(const void* registers); 
+
+       bool                    validRegister(int num) const;
+       uint64_t                getRegister(int num) const;
+       void                    setRegister(int num, uint64_t value);
+       bool                    validFloatRegister(int num) const;
+       double                  getFloatRegister(int num) const;
+       void                    setFloatRegister(int num, double value);
+       bool                    validVectorRegister(int num) const;
+       v128                    getVectorRegister(int num) const;
+       void                    setVectorRegister(int num, v128 value);
+       const char*             getRegisterName(int num);
+       void                    jumpto();
+       uint64_t                getSP() const                   { return fRegisters.__sp; }
+       void                    setSP(uint64_t value)   { fRegisters.__sp = value; }
+       uint64_t                getIP() const                   { return fRegisters.__pc; }
+       void                    setIP(uint64_t value)   { fRegisters.__pc = value; }
+       uint64_t                getFP() const                   { return fRegisters.__fp; }
+       void                    setFP(uint64_t value)   { fRegisters.__fp = value; }
+private:
+       arm_thread_state64_t    fRegisters;
+       double                                  fHalfVectorRegisters[32];
+       // Currently only the lower double in 128-bit vectore registers
+       // is perserved during unwinding.  We could define new register
+       // numbers (> 96) which mean whole vector registers, then this
+       // struct would need to change to contain whole vector registers.
+};
+
+inline Registers_arm64::Registers_arm64(const void* registers)
+{
+       COMPILE_TIME_ASSERT( sizeof(Registers_arm64) < sizeof(unw_context_t) );
+       fRegisters = *((arm_thread_state64_t*)registers); 
+}
+
+inline Registers_arm64::Registers_arm64()
+{
+       bzero(&fRegisters, sizeof(fRegisters)); 
+       bzero(&fRegisters, sizeof(fHalfVectorRegisters)); 
+}
+
+
+inline bool Registers_arm64::validRegister(int regNum) const
+{
+       if ( regNum == UNW_REG_IP )
+               return true;
+       if ( regNum == UNW_REG_SP )
+               return true;
+       if ( regNum < 0 )
+               return false;
+       if ( regNum > 95 )
+               return false;
+       if ( (regNum > 31) && (regNum < 64) )
+               return false;
+       return true;
+}
+
+inline uint64_t Registers_arm64::getRegister(int regNum) const
+{
+       if ( regNum == UNW_REG_IP )
+               return fRegisters.__pc;
+       if ( regNum == UNW_REG_SP )
+               return fRegisters.__sp;
+       if ( (regNum >= 0) && (regNum < 32) )
+               return fRegisters.__x[regNum];
+       ABORT("unsupported arm64 register");
+}
+
+inline void Registers_arm64::setRegister(int regNum, uint64_t value)
+{
+       if ( regNum == UNW_REG_IP )
+               fRegisters.__pc = value;
+       else if ( regNum == UNW_REG_SP )
+               fRegisters.__sp = value;
+       else if ( (regNum >= 0) && (regNum < 32) )
+               fRegisters.__x[regNum] = value;
+       else
+               ABORT("unsupported arm64 register");
+}
+
+inline const char* Registers_arm64::getRegisterName(int regNum)
+{
+       switch (regNum) {
+               case UNW_REG_IP:
+                       return "pc";
+               case UNW_REG_SP:
+                       return "sp";
+               case UNW_ARM64_X0:
+                       return "x0";
+               case UNW_ARM64_X1:
+                       return "x1";
+               case UNW_ARM64_X2:
+                       return "x2";
+               case UNW_ARM64_X3:
+                       return "x3";
+               case UNW_ARM64_X4:
+                       return "x4";
+               case UNW_ARM64_X5:
+                       return "x5";
+               case UNW_ARM64_X6:
+                       return "x6";
+               case UNW_ARM64_X7:
+                       return "x7";
+               case UNW_ARM64_X8:
+                       return "x8";
+               case UNW_ARM64_X9:
+                       return "x9";
+               case UNW_ARM64_X10:
+                       return "x10";
+               case UNW_ARM64_X11:
+                       return "x11";
+               case UNW_ARM64_X12:
+                       return "x12";
+               case UNW_ARM64_X13:
+                       return "x13";
+               case UNW_ARM64_X14:
+                       return "x14";
+               case UNW_ARM64_X15:
+                       return "x15";
+               case UNW_ARM64_X16:
+                       return "x16";
+               case UNW_ARM64_X17:
+                       return "x17";
+               case UNW_ARM64_X18:
+                       return "x18";
+               case UNW_ARM64_X19:
+                       return "x19";
+               case UNW_ARM64_X20:
+                       return "x20";
+               case UNW_ARM64_X21:
+                       return "x21";
+               case UNW_ARM64_X22:
+                       return "x22";
+               case UNW_ARM64_X23:
+                       return "x23";
+               case UNW_ARM64_X24:
+                       return "x24";
+               case UNW_ARM64_X25:
+                       return "x25";
+               case UNW_ARM64_X26:
+                       return "x26";
+               case UNW_ARM64_X27:
+                       return "x27";
+               case UNW_ARM64_X28:
+                       return "x28";
+               case UNW_ARM64_X29:
+                       return "fp";
+               case UNW_ARM64_X30:
+                       return "lr";
+               case UNW_ARM64_X31:
+                       return "sp";
+               case UNW_ARM64_D0:
+                       return "d0";
+               case UNW_ARM64_D1:
+                       return "d1";
+               case UNW_ARM64_D2:
+                       return "d2";
+               case UNW_ARM64_D3:
+                       return "d3";
+               case UNW_ARM64_D4:
+                       return "d4";
+               case UNW_ARM64_D5:
+                       return "d5";
+               case UNW_ARM64_D6:
+                       return "d6";
+               case UNW_ARM64_D7:
+                       return "d7";
+               case UNW_ARM64_D8:
+                       return "d8";
+               case UNW_ARM64_D9:
+                       return "d9";
+               case UNW_ARM64_D10:
+                       return "d10";
+               case UNW_ARM64_D11:
+                       return "d11";
+               case UNW_ARM64_D12:
+                       return "d12";
+               case UNW_ARM64_D13:
+                       return "d13";
+               case UNW_ARM64_D14:
+                       return "d14";
+               case UNW_ARM64_D15:
+                       return "d15";
+               case UNW_ARM64_D16:
+                       return "d16";
+               case UNW_ARM64_D17:
+                       return "d17";
+               case UNW_ARM64_D18:
+                       return "d18";
+               case UNW_ARM64_D19:
+                       return "d19";
+               case UNW_ARM64_D20:
+                       return "d20";
+               case UNW_ARM64_D21:
+                       return "d21";
+               case UNW_ARM64_D22:
+                       return "d22";
+               case UNW_ARM64_D23:
+                       return "d23";
+               case UNW_ARM64_D24:
+                       return "d24";
+               case UNW_ARM64_D25:
+                       return "d25";
+               case UNW_ARM64_D26:
+                       return "d26";
+               case UNW_ARM64_D27:
+                       return "d27";
+               case UNW_ARM64_D28:
+                       return "d28";
+               case UNW_ARM64_D29:
+                       return "d29";
+               case UNW_ARM64_D30:
+                       return "d30";
+               case UNW_ARM64_D31:
+                       return "d31";
+               default:
+                       return "unknown register";
+       }
+}
+
+bool Registers_arm64::validFloatRegister(int regNum) const
+{
+       if ( regNum < UNW_ARM64_D0 )
+               return false;
+       if ( regNum > UNW_ARM64_D31 )
+               return false;
+       return true;
+}
+
 
 
+double Registers_arm64::getFloatRegister(int regNum) const
+{
+       assert(validFloatRegister(regNum));
+       return fHalfVectorRegisters[regNum-UNW_ARM64_D0];
+}
+
+void Registers_arm64::setFloatRegister(int regNum, double value)
+{
+       assert(validFloatRegister(regNum));
+       fHalfVectorRegisters[regNum-UNW_ARM64_D0] = value;
 }
 
 }
 
+inline bool Registers_arm64::validVectorRegister(int regNum) const
+{
+       return false;
+}
+
+inline v128 Registers_arm64::getVectorRegister(int regNum) const
+{
+       ABORT("no arm64 vector register support yet");
+}
+
+inline void Registers_arm64::setVectorRegister(int regNum, v128 value)
+{
+       ABORT("no arm64 vector register support yet");
+}
+
+
 
 } // namespace libunwind 
 
 
 } // namespace libunwind 
 
index 023f6e303e2962fcb2ff7d24042b676e3a08891f..460dcf0b837da5d9751a7bcb76f0b06c91c073bd 100644 (file)
@@ -106,6 +106,8 @@ public:
                                                                                                                                                                        { return _debugInfoModTime; }
        virtual const std::vector<ld::relocatable::File::Stab>* stabs() const                   { return NULL; }
        virtual bool                                                                            canScatterAtoms() const         { return true; }
                                                                                                                                                                        { return _debugInfoModTime; }
        virtual const std::vector<ld::relocatable::File::Stab>* stabs() const                   { return NULL; }
        virtual bool                                                                            canScatterAtoms() const         { return true; }
+       virtual LinkerOptionsList*                                                      linkerOptions() const           { return NULL; }
+
 
        lto_module_t                                                                            module()                                        { return _module; }
        class InternalAtom&                                                                     internalAtom()                          { return _internalAtom; }
 
        lto_module_t                                                                            module()                                        { return _module; }
        class InternalAtom&                                                                     internalAtom()                          { return _internalAtom; }
@@ -290,7 +292,9 @@ ld::relocatable::File* Parser::parseMachOFile(const uint8_t* p, size_t len, cons
        objOpts.architecture            = options.arch;
        objOpts.objSubtypeMustMatch = false; 
        objOpts.logAllFiles                     = false;
        objOpts.architecture            = options.arch;
        objOpts.objSubtypeMustMatch = false; 
        objOpts.logAllFiles                     = false;
-       objOpts.convertUnwindInfo       = true;
+       objOpts.warnUnwindConversionProblems    = options.needsUnwindInfoSection;
+       objOpts.keepDwarfUnwind         = options.keepDwarfUnwind;
+       objOpts.forceDwarfConversion = false;
        objOpts.subType                         = 0;
        
        // mach-o parsing is done in-memory, but need path for debug notes
        objOpts.subType                         = 0;
        
        // mach-o parsing is done in-memory, but need path for debug notes
@@ -447,6 +451,16 @@ void Atom::setCompiledAtom(const ld::Atom& atom)
 
 
 
 
 
 
+// <rdar://problem/12379604> The order that files are merged must match command line order
+struct CommandLineOrderFileSorter
+{
+     bool operator()(File* left, File* right)
+     {
+        return ( left->ordinal() < right->ordinal() );
+     }
+};
+
+
 bool Parser::optimize(  const std::vector<const ld::Atom*>&    allAtoms,
                                                ld::Internal&                                           state,
                                                const OptimizeOptions&                          options,
 bool Parser::optimize(  const std::vector<const ld::Atom*>&    allAtoms,
                                                ld::Internal&                                           state,
                                                const OptimizeOptions&                          options,
@@ -469,10 +483,16 @@ bool Parser::optimize(  const std::vector<const ld::Atom*>&       allAtoms,
        
        // create optimizer and add each Reader
        lto_code_gen_t generator = ::lto_codegen_create();
        
        // create optimizer and add each Reader
        lto_code_gen_t generator = ::lto_codegen_create();
+       // <rdar://problem/12379604> The order that files are merged must match command line order
+       std::sort(_s_files.begin(), _s_files.end(), CommandLineOrderFileSorter());
+       ld::File::Ordinal lastOrdinal;
        for (std::vector<File*>::iterator it=_s_files.begin(); it != _s_files.end(); ++it) {
        for (std::vector<File*>::iterator it=_s_files.begin(); it != _s_files.end(); ++it) {
-               if ( logBitcodeFiles ) fprintf(stderr, "lto_codegen_add_module(%s)\n", (*it)->path());
-               if ( ::lto_codegen_add_module(generator, (*it)->module()) )
-                       throwf("lto: could not merge in %s because '%s', using libLTO version '%s'", (*it)->path(), ::lto_get_error_message(), ::lto_get_version());
+               File* f = *it;
+               assert(f->ordinal() > lastOrdinal);
+               if ( logBitcodeFiles ) fprintf(stderr, "lto_codegen_add_module(%s)\n", f->path());
+               if ( ::lto_codegen_add_module(generator, f->module()) )
+                       throwf("lto: could not merge in %s because '%s', using libLTO version '%s'", f->path(), ::lto_get_error_message(), ::lto_get_version());
+               lastOrdinal = f->ordinal();
        }
 
        // add any -mllvm command line options
        }
 
        // add any -mllvm command line options
@@ -481,6 +501,10 @@ bool Parser::optimize(  const std::vector<const ld::Atom*>&        allAtoms,
                ::lto_codegen_debug_options(generator, *it);
        }
 
                ::lto_codegen_debug_options(generator, *it);
        }
 
+       // <rdar://problem/13687397> Need a way for LTO to get cpu variants (until that info is in bitcode)
+       if ( options.mcpu != NULL )
+               ::lto_codegen_set_cpu(generator, options.mcpu);
+
        // The atom graph uses directed edges (references). Collect all references where 
        // originating atom is not part of any LTO Reader. This allows optimizer to optimize an 
        // external (i.e. not originated from same .o file) reference if all originating atoms are also 
        // The atom graph uses directed edges (references). Collect all references where 
        // originating atom is not part of any LTO Reader. This allows optimizer to optimize an 
        // external (i.e. not originated from same .o file) reference if all originating atoms are also 
@@ -775,7 +799,8 @@ void Parser::AtomSyncer::doAtom(const ld::Atom& machoAtom)
                                                fit->u.target = pos->second;
                                        }
                                        else {
                                                fit->u.target = pos->second;
                                        }
                                        else {
-                                               if ( _deadllvmAtoms.find(targetName) != _deadllvmAtoms.end() ) {
+                                               // <rdar://problem/12859831> Don't unbind follow-on reference into by-name reference 
+                                               if ( (_deadllvmAtoms.find(targetName) != _deadllvmAtoms.end()) && (fit->kind != ld::Fixup::kindNoneFollowOn) ) {
                                                        // target was coalesed away and replace by mach-o atom from a non llvm .o file
                                                        fit->binding = ld::Fixup::bindingByNameUnbound;
                                                        fit->u.name = targetName;
                                                        // target was coalesed away and replace by mach-o atom from a non llvm .o file
                                                        fit->binding = ld::Fixup::bindingByNameUnbound;
                                                        fit->u.name = targetName;
index 3503fa9a69a4300475bc7bb09a01bf9d5e3e51ee..4140a3ae4bc27944c6fbb8f4a9db6d02cc33e33d 100644 (file)
@@ -53,7 +53,10 @@ struct OptimizeOptions {
        bool                                                            relocatable;
        bool                                                            allowTextRelocs; 
        bool                                                            linkerDeadStripping; 
        bool                                                            relocatable;
        bool                                                            allowTextRelocs; 
        bool                                                            linkerDeadStripping; 
+       bool                                                            needsUnwindInfoSection; 
+       bool                                                            keepDwarfUnwind; 
        cpu_type_t                                                      arch;
        cpu_type_t                                                      arch;
+       const char*                                                     mcpu;
        const std::vector<const char*>*         llvmOptions;
 };
 
        const std::vector<const char*>*         llvmOptions;
 };
 
index aad1a8b19194a91337b4a73e201bbb24b0261dd4..b30e727417a59d9a8dcf5dc3731ec76e3e5e34ec 100644 (file)
@@ -1,3 +1,4 @@
+
 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
  *
  * Copyright (c) 2005-2011 Apple Inc. All rights reserved.
 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
  *
  * Copyright (c) 2005-2011 Apple Inc. All rights reserved.
@@ -142,7 +143,7 @@ public:
                                                                                        File(const uint8_t* fileContent, uint64_t fileLength, const char* path,   
                                                                                                        time_t mTime, ld::File::Ordinal ordinal, bool linkingFlatNamespace, 
                                                                                                        bool linkingMainExecutable, bool hoistImplicitPublicDylibs, 
                                                                                        File(const uint8_t* fileContent, uint64_t fileLength, const char* path,   
                                                                                                        time_t mTime, ld::File::Ordinal ordinal, bool linkingFlatNamespace, 
                                                                                                        bool linkingMainExecutable, bool hoistImplicitPublicDylibs, 
-                                                                                                       ld::MacVersionMin macMin, ld::IOSVersionMin iPhoneMin, bool addVers, 
+                                                                                                       ld::MacVersionMin macMin, ld::IOSVersionMin iPhoneMin, bool allowSimToMacOSX, bool addVers, 
                                                                                                        bool logAllFiles, const char* installPath, bool indirectDylib);
        virtual                                                                 ~File() {}
 
                                                                                                        bool logAllFiles, const char* installPath, bool indirectDylib);
        virtual                                                                 ~File() {}
 
@@ -162,6 +163,7 @@ public:
        virtual bool                                                    hasWeakDefinition(const char* name) const;
        virtual bool                                                    allSymbolsAreWeakImported() const;
        virtual const void*                                             codeSignatureDR() const         { return _codeSignatureDR; }
        virtual bool                                                    hasWeakDefinition(const char* name) const;
        virtual bool                                                    allSymbolsAreWeakImported() const;
        virtual const void*                                             codeSignatureDR() const         { return _codeSignatureDR; }
+       virtual bool                                                    installPathVersionSpecific() const { return _installPathOverride; }
 
 
 protected:
 
 
 protected:
@@ -194,6 +196,7 @@ private:
 
        bool                                                                            containsOrReExports(const char* name, bool* weakDef, bool* tlv, pint_t* defAddress) const;
        bool                                                                            isPublicLocation(const char* pth);
 
        bool                                                                            containsOrReExports(const char* name, bool* weakDef, bool* tlv, pint_t* defAddress) const;
        bool                                                                            isPublicLocation(const char* pth);
+       bool                                                                            wrongOS() { return _wrongOS; }
        void                                                                            addSymbol(const char* name, bool weak, bool tlv, pint_t address);
        void                                                                            addDyldFastStub();
        void                                                                            buildExportHashTableFromExportInfo(const macho_dyld_info_command<P>* dyldInfo,
        void                                                                            addSymbol(const char* name, bool weak, bool tlv, pint_t address);
        void                                                                            addDyldFastStub();
        void                                                                            buildExportHashTableFromExportInfo(const macho_dyld_info_command<P>* dyldInfo,
@@ -206,6 +209,7 @@ private:
        
        const ld::MacVersionMin                                         _macVersionMin;
        const ld::IOSVersionMin                                         _iOSVersionMin;
        
        const ld::MacVersionMin                                         _macVersionMin;
        const ld::IOSVersionMin                                         _iOSVersionMin;
+       const bool                                                                      _allowSimToMacOSXLinking;
        const bool                                                                      _addVersionLoadCommand;
        bool                                                                            _linkingFlat;
        bool                                                                            _implicitlyLinkPublicDylibs;
        const bool                                                                      _addVersionLoadCommand;
        bool                                                                            _linkingFlat;
        bool                                                                            _implicitlyLinkPublicDylibs;
@@ -225,7 +229,9 @@ private:
        bool                                                                            _hasPublicInstallName;
        mutable bool                                                            _providedAtom;
        bool                                                                            _explictReExportFound;
        bool                                                                            _hasPublicInstallName;
        mutable bool                                                            _providedAtom;
        bool                                                                            _explictReExportFound;
-
+       bool                                                                            _wrongOS;
+       bool                                                                            _installPathOverride;
+       
        static bool                                                                     _s_logHashtable;
 };
 
        static bool                                                                     _s_logHashtable;
 };
 
@@ -243,10 +249,10 @@ template <typename A> const char* File<A>::objCInfoSectionName() { return "__ima
 template <typename A>
 File<A>::File(const uint8_t* fileContent, uint64_t fileLength, const char* pth, time_t mTime, ld::File::Ordinal ord,
                                bool linkingFlatNamespace, bool linkingMainExecutable, bool hoistImplicitPublicDylibs,
 template <typename A>
 File<A>::File(const uint8_t* fileContent, uint64_t fileLength, const char* pth, time_t mTime, ld::File::Ordinal ord,
                                bool linkingFlatNamespace, bool linkingMainExecutable, bool hoistImplicitPublicDylibs,
-                               ld::MacVersionMin macMin, ld::IOSVersionMin iOSMin, bool addVers,
+                               ld::MacVersionMin macMin, ld::IOSVersionMin iOSMin, bool allowSimToMacOSX, bool addVers,
                                bool logAllFiles, const char* targetInstallPath, bool indirectDylib)
        : ld::dylib::File(strdup(pth), mTime, ord), 
                                bool logAllFiles, const char* targetInstallPath, bool indirectDylib)
        : ld::dylib::File(strdup(pth), mTime, ord), 
-       _macVersionMin(macMin), _iOSVersionMin(iOSMin), _addVersionLoadCommand(addVers), 
+       _macVersionMin(macMin), _iOSVersionMin(iOSMin), _allowSimToMacOSXLinking(allowSimToMacOSX), _addVersionLoadCommand(addVers), 
        _linkingFlat(linkingFlatNamespace), _implicitlyLinkPublicDylibs(hoistImplicitPublicDylibs),
        _objcContraint(ld::File::objcConstraintNone),
        _importProxySection("__TEXT", "__import", ld::Section::typeImportProxies, true),
        _linkingFlat(linkingFlatNamespace), _implicitlyLinkPublicDylibs(hoistImplicitPublicDylibs),
        _objcContraint(ld::File::objcConstraintNone),
        _importProxySection("__TEXT", "__import", ld::Section::typeImportProxies, true),
@@ -254,7 +260,7 @@ File<A>::File(const uint8_t* fileContent, uint64_t fileLength, const char* pth,
        _parentUmbrella(NULL), _importAtom(NULL), _codeSignatureDR(NULL), 
        _noRexports(false), _hasWeakExports(false), 
        _deadStrippable(false), _hasPublicInstallName(false), 
        _parentUmbrella(NULL), _importAtom(NULL), _codeSignatureDR(NULL), 
        _noRexports(false), _hasWeakExports(false), 
        _deadStrippable(false), _hasPublicInstallName(false), 
-        _providedAtom(false), _explictReExportFound(false)
+        _providedAtom(false), _explictReExportFound(false), _wrongOS(false), _installPathOverride(false)
 {
        const macho_header<P>* header = (const macho_header<P>*)fileContent;
        const uint32_t cmd_count = header->ncmds();
 {
        const macho_header<P>* header = (const macho_header<P>*)fileContent;
        const uint32_t cmd_count = header->ncmds();
@@ -331,12 +337,18 @@ File<A>::File(const uint8_t* fileContent, uint64_t fileLength, const char* pth,
                                _allowableClients.push_back(strdup(((macho_sub_client_command<P>*)cmd)->client()));
                                break;
                        case LC_VERSION_MIN_MACOSX:
                                _allowableClients.push_back(strdup(((macho_sub_client_command<P>*)cmd)->client()));
                                break;
                        case LC_VERSION_MIN_MACOSX:
-                               if ( _addVersionLoadCommand && !indirectDylib && (_iOSVersionMin != ld::iOSVersionUnset) )
-                                       warning("building for iOS, but linking against dylib built for MacOSX: %s", pth);
+                               if ( (_iOSVersionMin != ld::iOSVersionUnset) && !_allowSimToMacOSXLinking ) { 
+                                       _wrongOS = true;
+                                       if ( _addVersionLoadCommand && !indirectDylib )
+                                               throw "building for iOS Simulator, but linking against dylib built for MacOSX";
+                               }
                                break;
                        case LC_VERSION_MIN_IPHONEOS:
                                break;
                        case LC_VERSION_MIN_IPHONEOS:
-                               if ( _addVersionLoadCommand && !indirectDylib && (_macVersionMin != ld::macVersionUnset) )
-                                       warning("building for MacOSX, but linking against dylib built for iOS: %s", pth);
+                               if ( _macVersionMin != ld::macVersionUnset ) {
+                                       _wrongOS = true;
+                                       if ( _addVersionLoadCommand && !indirectDylib )
+                                               throw "building for MacOSX, but linking against dylib built for iOS Simulator";
+                               }
                                break;
                        case LC_CODE_SIGNATURE:
                                codeSignature = (macho_linkedit_data_command<P>* )cmd;
                                break;
                        case LC_CODE_SIGNATURE:
                                codeSignature = (macho_linkedit_data_command<P>* )cmd;
@@ -355,6 +367,7 @@ File<A>::File(const uint8_t* fileContent, uint64_t fileLength, const char* pth,
                                                        //      };
                                                        // #define OBJC_IMAGE_SUPPORTS_GC   2
                                                        // #define OBJC_IMAGE_GC_ONLY       4
                                                        //      };
                                                        // #define OBJC_IMAGE_SUPPORTS_GC   2
                                                        // #define OBJC_IMAGE_GC_ONLY       4
+                                                       // #define OBJC_IMAGE_IS_SIMULATED  32
                                                        //
                                                        const uint32_t* contents = (uint32_t*)(&fileContent[sect->offset()]);
                                                        if ( (sect->size() >= 8) && (contents[0] == 0) ) {
                                                        //
                                                        const uint32_t* contents = (uint32_t*)(&fileContent[sect->offset()]);
                                                        if ( (sect->size() >= 8) && (contents[0] == 0) ) {
@@ -363,6 +376,8 @@ File<A>::File(const uint8_t* fileContent, uint64_t fileLength, const char* pth,
                                                                        _objcContraint = ld::File::objcConstraintGC;
                                                                else if ( (flags & 2) == 2 )
                                                                        _objcContraint = ld::File::objcConstraintRetainReleaseOrGC;
                                                                        _objcContraint = ld::File::objcConstraintGC;
                                                                else if ( (flags & 2) == 2 )
                                                                        _objcContraint = ld::File::objcConstraintRetainReleaseOrGC;
+                                                               else if ( (flags & 32) == 32 )
+                                                                       _objcContraint = ld::File::objcConstraintRetainReleaseForSimulator;
                                                                else
                                                                        _objcContraint = ld::File::objcConstraintRetainRelease;
                                                        }
                                                                else
                                                                        _objcContraint = ld::File::objcConstraintRetainRelease;
                                                        }
@@ -605,6 +620,7 @@ void File<A>::addSymbol(const char* name, bool weakDef, bool tlv, pint_t address
                                        }
                                        else if ( strncmp(symAction, "install_name$", 13) == 0 ) {
                                                _dylibInstallPath = symName;
                                        }
                                        else if ( strncmp(symAction, "install_name$", 13) == 0 ) {
                                                _dylibInstallPath = symName;
+                                               _installPathOverride = true;
                                                return;
                                        }
                                        else {
                                                return;
                                        }
                                        else {
@@ -794,7 +810,7 @@ void File<A>::processIndirectLibraries(ld::dylib::File::DylibHandler* handler, b
                                if ( log ) fprintf(stderr, "processIndirectLibraries() parent=%s, child=%s\n", this->installPath(), it->path);
                                // a LC_REEXPORT_DYLIB, LC_SUB_UMBRELLA or LC_SUB_LIBRARY says we re-export this child
                                it->dylib = (File<A>*)handler->findDylib(it->path, this->path());
                                if ( log ) fprintf(stderr, "processIndirectLibraries() parent=%s, child=%s\n", this->installPath(), it->path);
                                // a LC_REEXPORT_DYLIB, LC_SUB_UMBRELLA or LC_SUB_LIBRARY says we re-export this child
                                it->dylib = (File<A>*)handler->findDylib(it->path, this->path());
-                               if ( it->dylib->hasPublicInstallName() ) {
+                               if ( it->dylib->hasPublicInstallName() && !it->dylib->wrongOS() ) {
                                        // promote this child to be automatically added as a direct dependent if this already is
                                        if ( (this->explicitlyLinked() || this->implicitlyLinked()) && (strcmp(it->path,it->dylib->installPath()) == 0) ) {
                                                if ( log ) fprintf(stderr, "processIndirectLibraries() implicitly linking %s\n", it->dylib->installPath());
                                        // promote this child to be automatically added as a direct dependent if this already is
                                        if ( (this->explicitlyLinked() || this->implicitlyLinked()) && (strcmp(it->path,it->dylib->installPath()) == 0) ) {
                                                if ( log ) fprintf(stderr, "processIndirectLibraries() implicitly linking %s\n", it->dylib->installPath());
@@ -866,6 +882,7 @@ public:
        typedef typename A::P                                   P;
 
        static bool                                                                             validFile(const uint8_t* fileContent, bool executableOrDyliborBundle);
        typedef typename A::P                                   P;
 
        static bool                                                                             validFile(const uint8_t* fileContent, bool executableOrDyliborBundle);
+       static const char*                                                              fileKind(const uint8_t* fileContent);
        static ld::dylib::File*                                                 parse(const uint8_t* fileContent, uint64_t fileLength, 
                                                                                                                        const char* path, time_t mTime, 
                                                                                                                        ld::File::Ordinal ordinal, const Options& opts, bool indirectDylib) {
        static ld::dylib::File*                                                 parse(const uint8_t* fileContent, uint64_t fileLength, 
                                                                                                                        const char* path, time_t mTime, 
                                                                                                                        ld::File::Ordinal ordinal, const Options& opts, bool indirectDylib) {
@@ -875,6 +892,7 @@ public:
                                                                                                                                                        opts.implicitlyLinkIndirectPublicDylibs(), 
                                                                                                                                                        opts.macosxVersionMin(), 
                                                                                                                                                        opts.iOSVersionMin(),
                                                                                                                                                        opts.implicitlyLinkIndirectPublicDylibs(), 
                                                                                                                                                        opts.macosxVersionMin(), 
                                                                                                                                                        opts.iOSVersionMin(),
+                                                                                                                                                       opts.allowSimulatorToLinkWithMacOSX(),
                                                                                                                                                        opts.addVersionLoadCommand(),
                                                                                                                                                        opts.logAllFiles(), 
                                                                                                                                                        opts.installPath(),
                                                                                                                                                        opts.addVersionLoadCommand(),
                                                                                                                                                        opts.logAllFiles(), 
                                                                                                                                                        opts.installPath(),
@@ -968,6 +986,145 @@ bool Parser<arm>::validFile(const uint8_t* fileContent, bool executableOrDylibor
 
 
 
 
 
 
+template <>
+bool Parser<arm64>::validFile(const uint8_t* fileContent, bool executableOrDyliborBundle)
+{
+       const macho_header<P>* header = (const macho_header<P>*)fileContent;
+       if ( header->magic() != MH_MAGIC_64 )
+               return false;
+       if ( header->cputype() != CPU_TYPE_ARM64 )
+               return false;
+       switch ( header->filetype() ) {
+               case MH_DYLIB:
+               case MH_DYLIB_STUB:
+                       return true;
+               case MH_BUNDLE:
+                       if ( executableOrDyliborBundle )
+                               return true;
+                       else
+                               throw "can't link with bundle (MH_BUNDLE) only dylibs (MH_DYLIB)";
+               case MH_EXECUTE:
+                       if ( executableOrDyliborBundle )
+                               return true;
+                       else
+                               throw "can't link with a main executable";
+               default:
+                       return false;
+       }
+}
+
+
+bool isDylibFile(const uint8_t* fileContent, cpu_type_t* result, cpu_subtype_t* subResult)
+{
+       if ( Parser<x86_64>::validFile(fileContent, false) ) {
+               *result = CPU_TYPE_X86_64;
+               *subResult = CPU_SUBTYPE_X86_64_ALL;
+               return true;
+       }
+       if ( Parser<x86>::validFile(fileContent, false) ) {
+               *result = CPU_TYPE_I386;
+               *subResult = CPU_SUBTYPE_X86_ALL;
+               return true;
+       }
+       if ( Parser<arm>::validFile(fileContent, false) ) {
+               *result = CPU_TYPE_ARM;
+               const macho_header<Pointer32<LittleEndian> >* header = (const macho_header<Pointer32<LittleEndian> >*)fileContent;
+               *subResult = header->cpusubtype();
+               return true;
+       }
+       if ( Parser<arm64>::validFile(fileContent, false) ) {
+               *result = CPU_TYPE_ARM64;
+               *subResult = CPU_SUBTYPE_ARM64_ALL;
+               return true;
+       }
+       if ( Parser<ppc>::validFile(fileContent, false) ) {
+               *result = CPU_TYPE_POWERPC;
+               const macho_header<Pointer32<BigEndian> >* header = (const macho_header<Pointer32<BigEndian> >*)fileContent;
+               *subResult = header->cpusubtype();
+               return true;
+       }
+       if ( Parser<ppc64>::validFile(fileContent, false) ) {
+               *result = CPU_TYPE_POWERPC64;
+               *subResult = CPU_SUBTYPE_POWERPC_ALL;
+               return true;
+       }
+       return false;
+}
+
+template <>
+const char* Parser<x86>::fileKind(const uint8_t* fileContent)
+{
+       const macho_header<P>* header = (const macho_header<P>*)fileContent;
+       if ( header->magic() != MH_MAGIC )
+               return NULL;
+       if ( header->cputype() != CPU_TYPE_I386 )
+               return NULL;
+       return "i386";
+}
+
+template <>
+const char* Parser<x86_64>::fileKind(const uint8_t* fileContent)
+{
+       const macho_header<P>* header = (const macho_header<P>*)fileContent;
+       if ( header->magic() != MH_MAGIC_64 )
+               return NULL;
+       if ( header->cputype() != CPU_TYPE_X86_64 )
+               return NULL;
+       return "x86_64";
+}
+
+template <>
+const char* Parser<arm>::fileKind(const uint8_t* fileContent)
+{
+       const macho_header<P>* header = (const macho_header<P>*)fileContent;
+       if ( header->magic() != MH_MAGIC )
+               return NULL;
+       if ( header->cputype() != CPU_TYPE_ARM )
+               return NULL;
+       for (const ArchInfo* t=archInfoArray; t->archName != NULL; ++t) {
+               if ( (t->cpuType == CPU_TYPE_ARM) && ((cpu_subtype_t)header->cpusubtype() == t->cpuSubType) ) {
+                       return t->archName;
+               }
+       }
+       return "arm???";
+}
+
+#if SUPPORT_ARCH_arm64
+template <>
+const char* Parser<arm64>::fileKind(const uint8_t* fileContent)
+{
+  const macho_header<P>* header = (const macho_header<P>*)fileContent;
+  if ( header->magic() != MH_MAGIC_64 )
+    return NULL;
+  if ( header->cputype() != CPU_TYPE_ARM64 )
+    return NULL;
+  return "arm64";
+}
+#endif
+
+//
+// used by linker is error messages to describe mismatched files
+//
+const char* archName(const uint8_t* fileContent)
+{
+       if ( Parser<x86_64>::validFile(fileContent, true) ) {
+               return Parser<x86_64>::fileKind(fileContent);
+       }
+       if ( Parser<x86>::validFile(fileContent, true) ) {
+               return Parser<x86>::fileKind(fileContent);
+       }
+       if ( Parser<arm>::validFile(fileContent, true) ) {
+               return Parser<arm>::fileKind(fileContent);
+       }
+#if SUPPORT_ARCH_arm64
+       if ( Parser<arm64>::validFile(fileContent, false) ) {
+               return Parser<arm64>::fileKind(fileContent);
+       }
+#endif
+       return NULL;
+}
+
+
 //
 // main function used by linker to instantiate ld::Files
 //
 //
 // main function used by linker to instantiate ld::Files
 //
@@ -993,6 +1150,12 @@ ld::dylib::File* parse(const uint8_t* fileContent, uint64_t fileLength,
                        if ( Parser<arm>::validFile(fileContent, bundleLoader) )
                                return Parser<arm>::parse(fileContent, fileLength, path, modTime, ordinal, opts, indirectDylib);
                        break;
                        if ( Parser<arm>::validFile(fileContent, bundleLoader) )
                                return Parser<arm>::parse(fileContent, fileLength, path, modTime, ordinal, opts, indirectDylib);
                        break;
+#endif
+#if SUPPORT_ARCH_arm64
+               case CPU_TYPE_ARM64:
+                       if ( Parser<arm64>::validFile(fileContent, bundleLoader) )
+                               return Parser<arm64>::parse(fileContent, fileLength, path, modTime, ordinal, opts, indirectDylib);
+                       break;
 #endif
        }
        return NULL;
 #endif
        }
        return NULL;
index ad03af1af1c9e0f5811037018f0f7331bfd55f82..4d093f139d921e3528a32e3bcb42eb74d972c2fd 100644 (file)
 namespace mach_o {
 namespace dylib {
 
 namespace mach_o {
 namespace dylib {
 
+
+extern bool isDylibFile(const uint8_t* fileContent, cpu_type_t* result, cpu_subtype_t* subResult);                                     
+
+extern const char* archName(const uint8_t* fileContent);
+
+
 extern ld::dylib::File* parse(const uint8_t* fileContent, uint64_t fileLength, const char* path, 
                                                                time_t modTime, const Options& opts, ld::File::Ordinal ordinal, 
                                                                bool bundleLoader, bool indirectDylib);
 extern ld::dylib::File* parse(const uint8_t* fileContent, uint64_t fileLength, const char* path, 
                                                                time_t modTime, const Options& opts, ld::File::Ordinal ordinal, 
                                                                bool bundleLoader, bool indirectDylib);
index b49d63f6580a78b610480f4c506588c782e97434..c22af18c0a4a3d2f2b4628abdbf71ef59c22654c 100644 (file)
@@ -92,9 +92,10 @@ public:
        virtual ObjcConstraint                                                          objCConstraint() const                  { return _objConstraint; }
        virtual uint32_t                                                                        cpuSubType() const                              { return _cpuSubType; }
        virtual DebugInfoKind                                                           debugInfo() const                               { return _debugInfoKind; }
        virtual ObjcConstraint                                                          objCConstraint() const                  { return _objConstraint; }
        virtual uint32_t                                                                        cpuSubType() const                              { return _cpuSubType; }
        virtual DebugInfoKind                                                           debugInfo() const                               { return _debugInfoKind; }
-       virtual const std::vector<ld::relocatable::File::Stab>* stabs() const                                   { return &_stabs; }
+       virtual const std::vector<ld::relocatable::File::Stab>* stabs() const                           { return &_stabs; }
        virtual bool                                                                            canScatterAtoms() const                 { return _canScatterAtoms; }
        virtual const char*                                                                     translationUnitSource() const;
        virtual bool                                                                            canScatterAtoms() const                 { return _canScatterAtoms; }
        virtual const char*                                                                     translationUnitSource() const;
+       virtual LinkerOptionsList*                                                      linkerOptions() const                   { return &_linkerOptions; }
        
        const uint8_t*                                                                          fileContent()                                   { return _fileContent; }
 private:
        
        const uint8_t*                                                                          fileContent()                                   { return _fileContent; }
 private:
@@ -123,6 +124,7 @@ private:
        ld::File::ObjcConstraint                                _objConstraint;
        uint32_t                                                                _cpuSubType;
        bool                                                                    _canScatterAtoms;
        ld::File::ObjcConstraint                                _objConstraint;
        uint32_t                                                                _cpuSubType;
        bool                                                                    _canScatterAtoms;
+       std::vector<std::vector<const char*> >  _linkerOptions;
 };
 
 
 };
 
 
@@ -154,6 +156,7 @@ public:
        virtual unsigned long                   contentHash(const class Atom<A>* atom, const ld::IndirectBindingTable& ind) const { return 0; }
        virtual bool                                    canCoalesceWith(const class Atom<A>* atom, const ld::Atom& rhs, 
                                                                                                        const ld::IndirectBindingTable& ind) const { return false; }
        virtual unsigned long                   contentHash(const class Atom<A>* atom, const ld::IndirectBindingTable& ind) const { return 0; }
        virtual bool                                    canCoalesceWith(const class Atom<A>* atom, const ld::Atom& rhs, 
                                                                                                        const ld::IndirectBindingTable& ind) const { return false; }
+       virtual bool                                    ignoreLabel(const char* label) const { return false; }
        static const char*                              makeSectionName(const macho_section<typename A::P>* s);
 
 protected:     
        static const char*                              makeSectionName(const macho_section<typename A::P>* s);
 
 protected:     
@@ -235,7 +238,7 @@ public:
        typedef typename A::P::uint_t                   pint_t;
        typedef libunwind::CFI_Atom_Info<OAS>   CFI_Atom_Info;
        
        typedef typename A::P::uint_t                   pint_t;
        typedef libunwind::CFI_Atom_Info<OAS>   CFI_Atom_Info;
        
-       void                            cfiParse(class Parser<A>& parser, uint8_t* buffer, CFI_Atom_Info cfiArray[], uint32_t cfiCount);
+       void                            cfiParse(class Parser<A>& parser, uint8_t* buffer, CFI_Atom_Info cfiArray[], uint32_t& cfiCount, const pint_t cuStarts[], uint32_t cuCount);
        bool                            needsRelocating();
 
        static bool                     bigEndian();
        bool                            needsRelocating();
 
        static bool                     bigEndian();
@@ -274,6 +277,7 @@ public:
 
        uint32_t                                count();
        void                                    parse(class Parser<A>& parser, uint32_t cnt, Info array[]);
 
        uint32_t                                count();
        void                                    parse(class Parser<A>& parser, uint32_t cnt, Info array[]);
+       static bool                             encodingMeansUseDwarf(compact_unwind_encoding_t enc);
        
        
 private:
        
        
 private:
@@ -379,16 +383,17 @@ protected:
        
        virtual bool                                            addFollowOnFixups() const               { return false; }
        virtual const char*                                     unlabeledAtomName(Parser<A>& parser, pint_t addr) = 0;
        
        virtual bool                                            addFollowOnFixups() const               { return false; }
        virtual const char*                                     unlabeledAtomName(Parser<A>& parser, pint_t addr) = 0;
-       virtual ld::Atom::SymbolTableInclusion  symbolTableInclusion()          { return ld::Atom::symbolTableNotIn; }
+       virtual ld::Atom::SymbolTableInclusion  symbolTableInclusion();
        virtual pint_t                                          elementSizeAtAddress(pint_t addr) = 0;
        virtual ld::Atom::Scope                         scopeAtAddress(Parser<A>& parser, pint_t addr) { return ld::Atom::scopeLinkageUnit; }
        virtual bool                                            useElementAt(Parser<A>& parser, 
                                                                                                struct Parser<A>::LabelAndCFIBreakIterator& it, pint_t addr) = 0;
        virtual ld::Atom::Definition            definition()                                    { return ld::Atom::definitionRegular; }
        virtual ld::Atom::Combine                       combine(Parser<A>& parser, pint_t addr) = 0;
        virtual pint_t                                          elementSizeAtAddress(pint_t addr) = 0;
        virtual ld::Atom::Scope                         scopeAtAddress(Parser<A>& parser, pint_t addr) { return ld::Atom::scopeLinkageUnit; }
        virtual bool                                            useElementAt(Parser<A>& parser, 
                                                                                                struct Parser<A>::LabelAndCFIBreakIterator& it, pint_t addr) = 0;
        virtual ld::Atom::Definition            definition()                                    { return ld::Atom::definitionRegular; }
        virtual ld::Atom::Combine                       combine(Parser<A>& parser, pint_t addr) = 0;
-       virtual bool                                            ignoreLabel(const char* label)  { return (label[0] == 'L'); }
+       virtual bool                                            ignoreLabel(const char* label) const { return (label[0] == 'L'); }
 };
 
 };
 
+
 template <typename A>
 class FixedSizeSection : public ImplicitSizeSection<A>
 {
 template <typename A>
 class FixedSizeSection : public ImplicitSizeSection<A>
 {
@@ -481,7 +486,7 @@ protected:
        virtual pint_t                                  elementSizeAtAddress(pint_t addr)               { return sizeof(pint_t); }
        virtual ld::Atom::Scope                 scopeAtAddress(Parser<A>& parser, pint_t addr);
        virtual ld::Atom::Combine               combine(Parser<A>&, pint_t);
        virtual pint_t                                  elementSizeAtAddress(pint_t addr)               { return sizeof(pint_t); }
        virtual ld::Atom::Scope                 scopeAtAddress(Parser<A>& parser, pint_t addr);
        virtual ld::Atom::Combine               combine(Parser<A>&, pint_t);
-       virtual bool                                    ignoreLabel(const char* label)                  { return true; }
+       virtual bool                                    ignoreLabel(const char* label) const    { return true; }
        virtual unsigned long                   contentHash(const class Atom<A>* atom, const ld::IndirectBindingTable& ind) const;
        virtual bool                                    canCoalesceWith(const class Atom<A>* atom, const ld::Atom& rhs, 
                                                                                                        const ld::IndirectBindingTable& ind) const;
        virtual unsigned long                   contentHash(const class Atom<A>* atom, const ld::IndirectBindingTable& ind) const;
        virtual bool                                    canCoalesceWith(const class Atom<A>* atom, const ld::Atom& rhs, 
                                                                                                        const ld::IndirectBindingTable& ind) const;
@@ -505,7 +510,7 @@ protected:
        virtual const char*                             unlabeledAtomName(Parser<A>&, pint_t)   { return "CFString"; }
        virtual pint_t                                  elementSizeAtAddress(pint_t addr)               { return 4*sizeof(pint_t); }
        virtual ld::Atom::Combine               combine(Parser<A>&, pint_t)                             { return ld::Atom::combineByNameAndReferences; }
        virtual const char*                             unlabeledAtomName(Parser<A>&, pint_t)   { return "CFString"; }
        virtual pint_t                                  elementSizeAtAddress(pint_t addr)               { return 4*sizeof(pint_t); }
        virtual ld::Atom::Combine               combine(Parser<A>&, pint_t)                             { return ld::Atom::combineByNameAndReferences; }
-       virtual bool                                    ignoreLabel(const char* label)                  { return true; }
+       virtual bool                                    ignoreLabel(const char* label) const    { return true; }
        virtual unsigned long                   contentHash(const class Atom<A>* atom, const ld::IndirectBindingTable& ind) const;
        virtual bool                                    canCoalesceWith(const class Atom<A>* atom, const ld::Atom& rhs, 
                                                                                                        const ld::IndirectBindingTable& ind) const;
        virtual unsigned long                   contentHash(const class Atom<A>* atom, const ld::IndirectBindingTable& ind) const;
        virtual bool                                    canCoalesceWith(const class Atom<A>* atom, const ld::Atom& rhs, 
                                                                                                        const ld::IndirectBindingTable& ind) const;
@@ -533,7 +538,7 @@ protected:
        virtual ld::Atom::SymbolTableInclusion  symbolTableInclusion()                  { return ld::Atom::symbolTableIn; }
        virtual pint_t                                  elementSizeAtAddress(pint_t addr);
        virtual ld::Atom::Combine               combine(Parser<A>&, pint_t)                             { return ld::Atom::combineNever; }
        virtual ld::Atom::SymbolTableInclusion  symbolTableInclusion()                  { return ld::Atom::symbolTableIn; }
        virtual pint_t                                  elementSizeAtAddress(pint_t addr);
        virtual ld::Atom::Combine               combine(Parser<A>&, pint_t)                             { return ld::Atom::combineNever; }
-       virtual bool                                    ignoreLabel(const char* label)                  { return true; }
+       virtual bool                                    ignoreLabel(const char* label) const    { return true; }
        virtual unsigned long                   contentHash(const class Atom<A>* atom, const ld::IndirectBindingTable& ind) const
                                                                                                                                                        { return 0; }
        virtual bool                                    canCoalesceWith(const class Atom<A>* atom, const ld::Atom& rhs, 
        virtual unsigned long                   contentHash(const class Atom<A>* atom, const ld::IndirectBindingTable& ind) const
                                                                                                                                                        { return 0; }
        virtual bool                                    canCoalesceWith(const class Atom<A>* atom, const ld::Atom& rhs, 
@@ -555,7 +560,7 @@ protected:
        virtual const char*                             unlabeledAtomName(Parser<A>&, pint_t)   { return "objc-class-ref"; }
        virtual pint_t                                  elementSizeAtAddress(pint_t addr)               { return sizeof(pint_t); }
        virtual ld::Atom::Combine               combine(Parser<A>&, pint_t)                             { return ld::Atom::combineByNameAndReferences; }
        virtual const char*                             unlabeledAtomName(Parser<A>&, pint_t)   { return "objc-class-ref"; }
        virtual pint_t                                  elementSizeAtAddress(pint_t addr)               { return sizeof(pint_t); }
        virtual ld::Atom::Combine               combine(Parser<A>&, pint_t)                             { return ld::Atom::combineByNameAndReferences; }
-       virtual bool                                    ignoreLabel(const char* label)                  { return true; }
+       virtual bool                                    ignoreLabel(const char* label) const    { return true; }
        virtual unsigned long                   contentHash(const class Atom<A>* atom, const ld::IndirectBindingTable& ind) const;
        virtual bool                                    canCoalesceWith(const class Atom<A>* atom, const ld::Atom& rhs, 
                                                                                                        const ld::IndirectBindingTable& ind) const;
        virtual unsigned long                   contentHash(const class Atom<A>* atom, const ld::IndirectBindingTable& ind) const;
        virtual bool                                    canCoalesceWith(const class Atom<A>* atom, const ld::Atom& rhs, 
                                                                                                        const ld::IndirectBindingTable& ind) const;
@@ -578,7 +583,7 @@ protected:
        virtual const char*                             unlabeledAtomName(Parser<A>&, pint_t)   { return "objc-cat-list"; }
        virtual pint_t                                  elementSizeAtAddress(pint_t addr)               { return sizeof(pint_t); }
        virtual ld::Atom::Combine               combine(Parser<A>&, pint_t)                             { return ld::Atom::combineNever; }
        virtual const char*                             unlabeledAtomName(Parser<A>&, pint_t)   { return "objc-cat-list"; }
        virtual pint_t                                  elementSizeAtAddress(pint_t addr)               { return sizeof(pint_t); }
        virtual ld::Atom::Combine               combine(Parser<A>&, pint_t)                             { return ld::Atom::combineNever; }
-       virtual bool                                    ignoreLabel(const char* label)                  { return true; }
+       virtual bool                                    ignoreLabel(const char* label) const    { return true; }
 private:
        const char*                                             targetClassName(const class Atom<A>* atom, const ld::IndirectBindingTable& ind) const;
 };
 private:
        const char*                                             targetClassName(const class Atom<A>* atom, const ld::IndirectBindingTable& ind) const;
 };
@@ -597,7 +602,7 @@ protected:
        virtual const char*                             unlabeledAtomName(Parser<A>&, pint_t)   { return "pointer-to-literal-cstring"; }
        virtual pint_t                                  elementSizeAtAddress(pint_t addr)               { return sizeof(pint_t); }
        virtual ld::Atom::Combine               combine(Parser<A>&, pint_t)                             { return ld::Atom::combineByNameAndReferences; }
        virtual const char*                             unlabeledAtomName(Parser<A>&, pint_t)   { return "pointer-to-literal-cstring"; }
        virtual pint_t                                  elementSizeAtAddress(pint_t addr)               { return sizeof(pint_t); }
        virtual ld::Atom::Combine               combine(Parser<A>&, pint_t)                             { return ld::Atom::combineByNameAndReferences; }
-       virtual bool                                    ignoreLabel(const char* label)                  { return true; }
+       virtual bool                                    ignoreLabel(const char* label) const    { return true; }
        virtual unsigned long                   contentHash(const class Atom<A>* atom, const ld::IndirectBindingTable& ind) const;
        virtual bool                                    canCoalesceWith(const class Atom<A>* atom, const ld::Atom& rhs, 
                                                                                                        const ld::IndirectBindingTable& ind) const;
        virtual unsigned long                   contentHash(const class Atom<A>* atom, const ld::IndirectBindingTable& ind) const;
        virtual bool                                    canCoalesceWith(const class Atom<A>* atom, const ld::Atom& rhs, 
                                                                                                        const ld::IndirectBindingTable& ind) const;
@@ -635,7 +640,7 @@ protected:
        virtual Atom<A>*                                findAtomByAddress(pint_t addr);
        virtual const char*                             unlabeledAtomName(Parser<A>&, pint_t)   { return "cstring"; }
        virtual pint_t                                  elementSizeAtAddress(pint_t addr);
        virtual Atom<A>*                                findAtomByAddress(pint_t addr);
        virtual const char*                             unlabeledAtomName(Parser<A>&, pint_t)   { return "cstring"; }
        virtual pint_t                                  elementSizeAtAddress(pint_t addr);
-       virtual bool                                    ignoreLabel(const char* label);
+       virtual bool                                    ignoreLabel(const char* label) const;
        virtual bool                                    useElementAt(Parser<A>& parser, 
                                                                                                struct Parser<A>::LabelAndCFIBreakIterator& it, pint_t addr);
        virtual ld::Atom::Combine               combine(Parser<A>&, pint_t)                             { return ld::Atom::combineByNameAndContent; }
        virtual bool                                    useElementAt(Parser<A>& parser, 
                                                                                                struct Parser<A>::LabelAndCFIBreakIterator& it, pint_t addr);
        virtual ld::Atom::Combine               combine(Parser<A>&, pint_t)                             { return ld::Atom::combineByNameAndContent; }
@@ -865,7 +870,8 @@ public:
                                                                                                                        const char* path, time_t modTime, ld::File::Ordinal ordinal,
                                                                                                                         const ParserOptions& opts) {
                                                                                                                                Parser p(fileContent, fileLength, path, modTime, 
                                                                                                                        const char* path, time_t modTime, ld::File::Ordinal ordinal,
                                                                                                                         const ParserOptions& opts) {
                                                                                                                                Parser p(fileContent, fileLength, path, modTime, 
-                                                                                                                                               ordinal, opts.convertUnwindInfo);
+                                                                                                                                               ordinal, opts.warnUnwindConversionProblems,
+                                                                                                                                               opts.keepDwarfUnwind, opts.forceDwarfConversion);
                                                                                                                                return p.parse(opts);
                                                                                                                }
 
                                                                                                                                return p.parse(opts);
                                                                                                                }
 
@@ -934,7 +940,7 @@ public:
                _allFixups.push_back(FixupInAtom(src, c, k)); 
        }
 
                _allFixups.push_back(FixupInAtom(src, c, k)); 
        }
 
-
+       const char*                                                                             path() { return _path; }
        uint32_t                                                                                symbolCount() { return _symbolCount; }
        uint32_t                                                                                indirectSymbol(uint32_t indirectIndex);
        const macho_nlist<P>&                                                   symbolFromIndex(uint32_t index);
        uint32_t                                                                                symbolCount() { return _symbolCount; }
        uint32_t                                                                                indirectSymbol(uint32_t indirectIndex);
        const macho_nlist<P>&                                                   symbolFromIndex(uint32_t index);
@@ -971,9 +977,11 @@ public:
        unsigned int                                                                    stubsSectionNum() { return _stubsSectionNum; }
        void                                                                                    addDtraceExtraInfos(const SourceLocation& src, const char* provider);
        const char*                                                                             scanSymbolTableForAddress(uint64_t addr);
        unsigned int                                                                    stubsSectionNum() { return _stubsSectionNum; }
        void                                                                                    addDtraceExtraInfos(const SourceLocation& src, const char* provider);
        const char*                                                                             scanSymbolTableForAddress(uint64_t addr);
-       bool                                                                                    convertUnwindInfo() { return _convertUnwindInfo; }
+       bool                                                                                    warnUnwindConversionProblems() { return _warnUnwindConversionProblems; }
        bool                                                                                    hasDataInCodeLabels() { return _hasDataInCodeLabels; }
        bool                                                                                    hasDataInCodeLabels() { return _hasDataInCodeLabels; }
-
+       bool                                                                                    keepDwarfUnwind() { return _keepDwarfUnwind; }
+       bool                                                                                    forceDwarfConversion() { return _forceDwarfConversion; }
+       
        macho_data_in_code_entry<P>*                                    dataInCodeStart() { return _dataInCodeStart; }
        macho_data_in_code_entry<P>*                                    dataInCodeEnd()   { return _dataInCodeEnd; }
        
        macho_data_in_code_entry<P>*                                    dataInCodeStart() { return _dataInCodeStart; }
        macho_data_in_code_entry<P>*                                    dataInCodeEnd()   { return _dataInCodeEnd; }
        
@@ -989,7 +997,7 @@ public:
                                                                        : sortedSymbolIndexes(ssa), sortedSymbolCount(ssc), cfiStartsArray(cfisa), 
                                                                                cfiStartsCount(cfisc), fileHasOverlappingSymbols(ols),
                                                                                newSection(false), cfiIndex(0), symIndex(0) {}
                                                                        : sortedSymbolIndexes(ssa), sortedSymbolCount(ssc), cfiStartsArray(cfisa), 
                                                                                cfiStartsCount(cfisc), fileHasOverlappingSymbols(ols),
                                                                                newSection(false), cfiIndex(0), symIndex(0) {}
-               bool                                    next(Parser<A>& parser, uint32_t sectNum, pint_t startAddr, pint_t endAddr, 
+               bool                                    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>** sym);
                pint_t                                  peek(Parser<A>& parser, pint_t startAddr, pint_t endAddr);
                void                                    beginSection() { newSection = true; symIndex = 0; }
                                                                                pint_t* addr, pint_t* size, const macho_nlist<P>** sym);
                pint_t                                  peek(Parser<A>& parser, pint_t startAddr, pint_t endAddr);
                void                                    beginSection() { newSection = true; symIndex = 0; }
@@ -1050,8 +1058,8 @@ private:
        
 
                                                                                                        Parser(const uint8_t* fileContent, uint64_t fileLength, 
        
 
                                                                                                        Parser(const uint8_t* fileContent, uint64_t fileLength, 
-                                                                                                                       const char* path, time_t modTime, 
-                                                                                                                       ld::File::Ordinal ordinal, bool convertUnwindInfo);
+                                                                                                                       const char* path, time_t modTime, ld::File::Ordinal ordinal, 
+                                                                                                                       bool warnUnwindConversionProblems, bool keepDwarfUnwind, bool forceDwarfConversion);
        ld::relocatable::File*                                                  parse(const ParserOptions& opts);
        uint8_t                                                                                 loadCommandSizeMask();
        bool                                                                                    parseLoadCommands();
        ld::relocatable::File*                                                  parse(const ParserOptions& opts);
        uint8_t                                                                                 loadCommandSizeMask();
        bool                                                                                    parseLoadCommands();
@@ -1106,8 +1114,10 @@ private:
        bool                                                                            _hasLongBranchStubs;
        bool                                                                            _AppleObjc; // FSF has objc that uses different data layout
        bool                                                                            _overlappingSymbols;
        bool                                                                            _hasLongBranchStubs;
        bool                                                                            _AppleObjc; // FSF has objc that uses different data layout
        bool                                                                            _overlappingSymbols;
-       bool                                                                            _convertUnwindInfo;
+       bool                                                                            _warnUnwindConversionProblems;
        bool                                                                            _hasDataInCodeLabels;
        bool                                                                            _hasDataInCodeLabels;
+       bool                                                                            _keepDwarfUnwind;
+       bool                                                                            _forceDwarfConversion;
        unsigned int                                                            _stubsSectionNum;
        const macho_section<P>*                                         _stubsMachOSection;
        std::vector<const char*>                                        _dtraceProviderInfo;
        unsigned int                                                            _stubsSectionNum;
        const macho_section<P>*                                         _stubsMachOSection;
        std::vector<const char*>                                        _dtraceProviderInfo;
@@ -1118,7 +1128,7 @@ private:
 
 template <typename A>
 Parser<A>::Parser(const uint8_t* fileContent, uint64_t fileLength, const char* path, time_t modTime, 
 
 template <typename A>
 Parser<A>::Parser(const uint8_t* fileContent, uint64_t fileLength, const char* path, time_t modTime, 
-                                       ld::File::Ordinal ordinal, bool convertDUI)
+                                       ld::File::Ordinal ordinal, bool convertDUI, bool keepDwarfUnwind, bool forceDwarfConversion)
                : _fileContent(fileContent), _fileLength(fileLength), _path(path), _modTime(modTime),
                        _ordinal(ordinal), _file(NULL),
                        _symbols(NULL), _symbolCount(0), _strings(NULL), _stringsSize(0),
                : _fileContent(fileContent), _fileLength(fileLength), _path(path), _modTime(modTime),
                        _ordinal(ordinal), _file(NULL),
                        _symbols(NULL), _symbolCount(0), _strings(NULL), _stringsSize(0),
@@ -1129,7 +1139,8 @@ Parser<A>::Parser(const uint8_t* fileContent, uint64_t fileLength, const char* p
                        _EHFrameSection(NULL), _compactUnwindSection(NULL), _absoluteSection(NULL),
                        _tentativeDefinitionCount(0), _absoluteSymbolCount(0),
                        _symbolsInSections(0), _hasLongBranchStubs(false),  _AppleObjc(false),
                        _EHFrameSection(NULL), _compactUnwindSection(NULL), _absoluteSection(NULL),
                        _tentativeDefinitionCount(0), _absoluteSymbolCount(0),
                        _symbolsInSections(0), _hasLongBranchStubs(false),  _AppleObjc(false),
-                       _overlappingSymbols(false), _convertUnwindInfo(convertDUI), _hasDataInCodeLabels(false), 
+                       _overlappingSymbols(false), _warnUnwindConversionProblems(convertDUI), _hasDataInCodeLabels(false),
+                       _keepDwarfUnwind(keepDwarfUnwind), _forceDwarfConversion(forceDwarfConversion),
                        _stubsSectionNum(0), _stubsMachOSection(NULL)
 {
 }
                        _stubsSectionNum(0), _stubsMachOSection(NULL)
 {
 }
@@ -1183,6 +1194,19 @@ bool Parser<arm>::validFile(const uint8_t* fileContent, bool subtypeMustMatch, c
 }
 
 
 }
 
 
+template <>
+bool Parser<arm64>::validFile(const uint8_t* fileContent, bool subtypeMustMatch, cpu_subtype_t subtype)
+{
+       const macho_header<P>* header = (const macho_header<P>*)fileContent;
+       if ( header->magic() != MH_MAGIC_64 )
+               return false;
+       if ( header->cputype() != CPU_TYPE_ARM64 )
+               return false;
+       if ( header->filetype() != MH_OBJECT )
+               return false;
+       return true;
+}
+
 
 template <>
 const char* Parser<x86>::fileKind(const uint8_t* fileContent)
 
 template <>
 const char* Parser<x86>::fileKind(const uint8_t* fileContent)
@@ -1222,6 +1246,18 @@ const char* Parser<arm>::fileKind(const uint8_t* fileContent)
        return "arm???";
 }
 
        return "arm???";
 }
 
+#if SUPPORT_ARCH_arm64
+template <>
+const char* Parser<arm64>::fileKind(const uint8_t* fileContent)
+{
+       const macho_header<P>* header = (const macho_header<P>*)fileContent;
+       if ( header->magic() != MH_MAGIC )
+               return NULL;
+       if ( header->cputype() != CPU_TYPE_ARM64 )
+               return NULL;
+       return "arm64";
+}
+#endif
 
 template <typename A>
 bool Parser<A>::hasObjC2Categories(const uint8_t* fileContent)
 
 template <typename A>
 bool Parser<A>::hasObjC2Categories(const uint8_t* fileContent)
@@ -1322,7 +1358,7 @@ typename A::P::uint_t Parser<A>::LabelAndCFIBreakIterator::peek(Parser<A>& parse
 // was becuase of a label, the symbol). Returns false when no more chunks.
 //
 template <typename A>
 // was becuase of a label, the symbol). Returns false when no more chunks.
 //
 template <typename A>
-bool Parser<A>::LabelAndCFIBreakIterator::next(Parser<A>& parser, uint32_t sectNum, pint_t startAddr, pint_t endAddr, 
+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)
 {
        // may not be a label on start of section, but need atom demarcation there
                                                                                                pint_t* addr, pint_t* size, const macho_nlist<P>** symbol)
 {
        // may not be a label on start of section, but need atom demarcation there
@@ -1331,10 +1367,12 @@ bool Parser<A>::LabelAndCFIBreakIterator::next(Parser<A>& parser, uint32_t sectN
                // 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]);
                // 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]);
-                       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)) )
-                               break;
+                       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)) )
+                                       break;
+                       }
                        ++symIndex;
                }
                if ( symIndex < sortedSymbolCount ) {
                        ++symIndex;
                }
                if ( symIndex < sortedSymbolCount ) {
@@ -1381,7 +1419,19 @@ bool Parser<A>::LabelAndCFIBreakIterator::next(Parser<A>& parser, uint32_t sectN
                        *symbol = NULL;
                        return true;
                }
                        *symbol = NULL;
                        return true;
                }
-               // no symbols left in whole file, so entire section is one chunk
+               // no symbols in section, check CFI
+               if ( cfiIndex < cfiStartsCount ) {
+                       pint_t nextCfiAddr = cfiStartsArray[cfiIndex];
+                       if ( nextCfiAddr < endAddr ) {
+                               // use cfi
+                               ++cfiIndex;
+                               *addr = nextCfiAddr;
+                               *size = peek(parser, startAddr, endAddr) - nextCfiAddr;
+                               *symbol = NULL;
+                               return true;
+                       }
+               }
+               // no cfi, so whole section is one chunk
                *addr = startAddr;
                *size = endAddr - startAddr;
                *symbol = NULL;
                *addr = startAddr;
                *size = endAddr - startAddr;
                *symbol = NULL;
@@ -1459,6 +1509,16 @@ bool Parser<A>::LabelAndCFIBreakIterator::next(Parser<A>& parser, uint32_t sectN
        return false;
 }
 
        return false;
 }
 
+#define STACK_ALLOC_IF_SMALL(_type, _name, _actual_count, _maxCount) \
+       _type*  _name = NULL;   \
+       uint32_t _name##_count = 1; \
+       if ( _actual_count > _maxCount ) \
+               _name = (_type*)malloc(sizeof(_type) * _actual_count); \
+       else \
+               _name##_count = _actual_count; \
+       _type  _name##_buffer[_name##_count]; \
+       if ( _name == NULL ) \
+               _name = _name##_buffer;
 
 
 template <typename A>
 
 
 template <typename A>
@@ -1475,7 +1535,7 @@ ld::relocatable::File* Parser<A>::parse(const ParserOptions& opts)
        if ( ! parseLoadCommands() )
                return _file;
        
        if ( ! parseLoadCommands() )
                return _file;
        
-       // make array of 
+       // make array of
        uint32_t sortedSectionIndexes[_machOSectionsCount];
        this->makeSortedSectionsArray(sortedSectionIndexes);
        
        uint32_t sortedSectionIndexes[_machOSectionsCount];
        this->makeSortedSectionsArray(sortedSectionIndexes);
        
@@ -1491,40 +1551,46 @@ ld::relocatable::File* Parser<A>::parse(const ParserOptions& opts)
        uint32_t countOfCUs = 0;
        if ( _compactUnwindSection != NULL )
                countOfCUs = _compactUnwindSection->count();
        uint32_t countOfCUs = 0;
        if ( _compactUnwindSection != NULL )
                countOfCUs = _compactUnwindSection->count();
-       uint8_t cuInfoBuffer[sizeof(typename CUSection<A>::Info) * countOfCUs];
-       typename CUSection<A>::Info*  cuInfoArray = (typename CUSection<A>::Info*)cuInfoBuffer;
+       // stack allocate (if not too large) cuInfoBuffer
+       STACK_ALLOC_IF_SMALL(typename CUSection<A>::Info, cuInfoArray, countOfCUs, 1024);
        if ( countOfCUs != 0 )
                _compactUnwindSection->parse(*this, countOfCUs, cuInfoArray);
        if ( countOfCUs != 0 )
                _compactUnwindSection->parse(*this, countOfCUs, cuInfoArray);
+
+       // create lists of address that already have compact unwind and thus don't need the dwarf parsed
+       unsigned cuLsdaCount = 0;
+       pint_t cuStarts[countOfCUs];
+       for (uint32_t i=0; i < countOfCUs; ++i) {
+               if ( CUSection<A>::encodingMeansUseDwarf(cuInfoArray[i].compactUnwindInfo) )
+                       cuStarts[i] = -1;
+               else
+                       cuStarts[i] = cuInfoArray[i].functionStartAddress;
+               if ( cuInfoArray[i].lsdaAddress != 0 )
+                       ++cuLsdaCount;
+       }
+       
        
        // if it exists, do special early parsing of __eh_frame section 
        
        // if it exists, do special early parsing of __eh_frame section 
-       // stack allocate array of CFI_Atom_Info
+       // stack allocate (if not too large) array of CFI_Atom_Info
        uint32_t countOfCFIs = 0;
        if ( _EHFrameSection != NULL )
                countOfCFIs = _EHFrameSection->cfiCount();
        uint32_t countOfCFIs = 0;
        if ( _EHFrameSection != NULL )
                countOfCFIs = _EHFrameSection->cfiCount();
-       typename CFISection<A>::CFI_Atom_Info  cfiArray[countOfCFIs];
+       STACK_ALLOC_IF_SMALL(typename CFISection<A>::CFI_Atom_Info, cfiArray, countOfCFIs, 1024);
+       
        // stack allocate (if not too large) a copy of __eh_frame to apply relocations to
        // stack allocate (if not too large) a copy of __eh_frame to apply relocations to
-       uint8_t* ehBuffer = NULL;
-       uint32_t stackAllocSize = 0;
-       if ( (countOfCFIs != 0) && _EHFrameSection->needsRelocating() ) {
-               uint32_t sectSize = _EHFrameSection->machoSection()->size();
-               if ( sectSize > 50*1024 )
-                       ehBuffer = (uint8_t*)malloc(sectSize);
-               else
-                       stackAllocSize = sectSize;
-       }
-       uint32_t ehStackBuffer[1+stackAllocSize/4]; // make 4-byte aligned stack bufffer
-       if ( ehBuffer == NULL )
-               ehBuffer = (uint8_t*)&ehStackBuffer;
+       uint32_t sectSize = 4;
+       if ( (countOfCFIs != 0) && _EHFrameSection->needsRelocating() ) 
+               sectSize = _EHFrameSection->machoSection()->size()+4;
+       STACK_ALLOC_IF_SMALL(uint8_t, ehBuffer, sectSize, 50*1024);
        uint32_t cfiStartsCount = 0;
        if ( countOfCFIs != 0 ) {
        uint32_t cfiStartsCount = 0;
        if ( countOfCFIs != 0 ) {
-               _EHFrameSection->cfiParse(*this, ehBuffer, cfiArray, countOfCFIs);
+               _EHFrameSection->cfiParse(*this, ehBuffer, cfiArray, countOfCFIs, cuStarts, countOfCUs);
                // count functions and lsdas
                for(uint32_t i=0; i < countOfCFIs; ++i) {
                        if ( cfiArray[i].isCIE )
                                continue;
                // count functions and lsdas
                for(uint32_t i=0; i < countOfCFIs; ++i) {
                        if ( cfiArray[i].isCIE )
                                continue;
-                       //fprintf(stderr, "cfiArray[i].func = 0x%08llX, cfiArray[i].lsda = 0x%08llX, encoding=0x%08X\n", 
-                       //                      (uint64_t)cfiArray[i].u.fdeInfo.function.targetAddress, 
-                       //                      (uint64_t)cfiArray[i].u.fdeInfo.lsda.targetAddress, 
+                       //fprintf(stderr, "cfiArray[i].func = 0x%08llX, cfiArray[i].lsda = 0x%08llX, encoding=0x%08X\n",
+                       //                      (uint64_t)cfiArray[i].u.fdeInfo.function.targetAddress,
+                       //                      (uint64_t)cfiArray[i].u.fdeInfo.lsda.targetAddress,
                        //                      cfiArray[i].u.fdeInfo.compactUnwindInfo);
                        if ( cfiArray[i].u.fdeInfo.function.targetAddress != CFI_INVALID_ADDRESS )
                                ++cfiStartsCount;
                        //                      cfiArray[i].u.fdeInfo.compactUnwindInfo);
                        if ( cfiArray[i].u.fdeInfo.function.targetAddress != CFI_INVALID_ADDRESS )
                                ++cfiStartsCount;
@@ -1535,23 +1601,41 @@ ld::relocatable::File* Parser<A>::parse(const ParserOptions& opts)
        CFI_CU_InfoArrays cfis(cfiArray, countOfCFIs, cuInfoArray, countOfCUs);
        
        // create sorted array of function starts and lsda starts
        CFI_CU_InfoArrays cfis(cfiArray, countOfCFIs, cuInfoArray, countOfCUs);
        
        // create sorted array of function starts and lsda starts
-       pint_t cfiStartsArray[cfiStartsCount];
+       pint_t cfiStartsArray[cfiStartsCount+cuLsdaCount];
        uint32_t countOfFDEs = 0;
        uint32_t countOfFDEs = 0;
+       uint32_t cfiStartsArrayCount = 0;
        if ( countOfCFIs != 0 ) {
        if ( countOfCFIs != 0 ) {
-               int index = 0;
                for(uint32_t i=0; i < countOfCFIs; ++i) {
                        if ( cfiArray[i].isCIE )
                                continue;
                        if ( cfiArray[i].u.fdeInfo.function.targetAddress != CFI_INVALID_ADDRESS )
                for(uint32_t i=0; i < countOfCFIs; ++i) {
                        if ( cfiArray[i].isCIE )
                                continue;
                        if ( cfiArray[i].u.fdeInfo.function.targetAddress != CFI_INVALID_ADDRESS )
-                               cfiStartsArray[index++] = cfiArray[i].u.fdeInfo.function.targetAddress;
+                               cfiStartsArray[cfiStartsArrayCount++] = cfiArray[i].u.fdeInfo.function.targetAddress;
                        if ( cfiArray[i].u.fdeInfo.lsda.targetAddress != CFI_INVALID_ADDRESS )
                        if ( cfiArray[i].u.fdeInfo.lsda.targetAddress != CFI_INVALID_ADDRESS )
-                               cfiStartsArray[index++] = cfiArray[i].u.fdeInfo.lsda.targetAddress;
+                               cfiStartsArray[cfiStartsArrayCount++] = cfiArray[i].u.fdeInfo.lsda.targetAddress;
                        ++countOfFDEs;
                }
                        ++countOfFDEs;
                }
-               ::qsort(cfiStartsArray, cfiStartsCount, sizeof(pint_t), pointerSorter);
+       }
+       if ( cuLsdaCount != 0 ) {
+               // merge in an lsda info from compact unwind
+               for (uint32_t i=0; i < countOfCUs; ++i) {
+                       if ( cuInfoArray[i].lsdaAddress == 0 )
+                               continue;
+                       // append to cfiStartsArray if not already in that list
+                       bool found = false;
+                       for(uint32_t j=0; j < cfiStartsArrayCount; ++j) {
+                               if ( cfiStartsArray[j] == cuInfoArray[i].lsdaAddress )
+                                       found = true;
+                       }
+                       if ( ! found ) {
+                               cfiStartsArray[cfiStartsArrayCount++] = cuInfoArray[i].lsdaAddress;
+                       }
+               }
+       }
+       if ( cfiStartsArrayCount != 0 ) {
+               ::qsort(cfiStartsArray, cfiStartsArrayCount, sizeof(pint_t), pointerSorter);
        #ifndef NDEBUG
                // scan for FDEs claming the same function
        #ifndef NDEBUG
                // scan for FDEs claming the same function
-               for(int i=1; i < index; ++i) {
+               for(uint32_t i=1; i < cfiStartsArrayCount; ++i) {
                        assert( cfiStartsArray[i] != cfiStartsArray[i-1] );
                }
        #endif  
                        assert( cfiStartsArray[i] != cfiStartsArray[i-1] );
                }
        #endif  
@@ -1562,7 +1646,7 @@ ld::relocatable::File* Parser<A>::parse(const ParserOptions& opts)
 
        // figure out how many atoms will be allocated and allocate
        LabelAndCFIBreakIterator breakIterator(sortedSymbolIndexes, _symbolsInSections, cfiStartsArray, 
 
        // figure out how many atoms will be allocated and allocate
        LabelAndCFIBreakIterator breakIterator(sortedSymbolIndexes, _symbolsInSections, cfiStartsArray, 
-                                                                                       cfiStartsCount, _overlappingSymbols);
+                                                                                       cfiStartsArrayCount, _overlappingSymbols);
        uint32_t computedAtomCount = 0;
        for (uint32_t i=0; i < sectionsCount; ++i ) {
                breakIterator.beginSection();
        uint32_t computedAtomCount = 0;
        for (uint32_t i=0; i < sectionsCount; ++i ) {
                breakIterator.beginSection();
@@ -1577,7 +1661,7 @@ ld::relocatable::File* Parser<A>::parse(const ParserOptions& opts)
        
        // have each section append atoms to _atomsArray
        LabelAndCFIBreakIterator breakIterator2(sortedSymbolIndexes, _symbolsInSections, cfiStartsArray, 
        
        // have each section append atoms to _atomsArray
        LabelAndCFIBreakIterator breakIterator2(sortedSymbolIndexes, _symbolsInSections, cfiStartsArray, 
-                                                                                               cfiStartsCount, _overlappingSymbols);
+                                                                                               cfiStartsArrayCount, _overlappingSymbols);
        for (uint32_t i=0; i < sectionsCount; ++i ) {
                uint8_t* atoms = _file->_atomsArray + _file->_atomsArrayCount*sizeof(Atom<A>);
                breakIterator2.beginSection();
        for (uint32_t i=0; i < sectionsCount; ++i ) {
                uint8_t* atoms = _file->_atomsArray + _file->_atomsArrayCount*sizeof(Atom<A>);
                breakIterator2.beginSection();
@@ -1628,6 +1712,7 @@ ld::relocatable::File* Parser<A>::parse(const ParserOptions& opts)
                        _file->_unwindInfos.push_back(info);
                        Atom<A>* func = findAtomByAddress(cfiArray[i].u.fdeInfo.function.targetAddress);
                        func->setUnwindInfoRange(_file->_unwindInfos.size()-1, 1);
                        _file->_unwindInfos.push_back(info);
                        Atom<A>* func = findAtomByAddress(cfiArray[i].u.fdeInfo.function.targetAddress);
                        func->setUnwindInfoRange(_file->_unwindInfos.size()-1, 1);
+                       //fprintf(stderr, "cu from dwarf =0x%08X, atom=%s\n", info.unwindInfo, func->name());
                }
        }
        // apply compact infos in __LD,__compact_unwind section to each function
                }
        }
        // apply compact infos in __LD,__compact_unwind section to each function
@@ -1639,22 +1724,26 @@ ld::relocatable::File* Parser<A>::parse(const ParserOptions& opts)
                assert(info->function != NULL);
                ld::Atom::UnwindInfo ui;
                ui.startOffset = info->functionStartAddress - info->function->objectAddress();
                assert(info->function != NULL);
                ld::Atom::UnwindInfo ui;
                ui.startOffset = info->functionStartAddress - info->function->objectAddress();
-               ui.unwindInfo = info->compactUnwindInfo;                
+               ui.unwindInfo = info->compactUnwindInfo;
                _file->_unwindInfos.push_back(ui);
                _file->_unwindInfos.push_back(ui);
-               // if previous is for same function, extend range
-               if ( info->function == lastFunc ) {
-                       if ( lastEnd != ui.startOffset ) {
-                               if ( lastEnd < ui.startOffset )
-                                       warning("__LD,__compact_unwind entries for %s have a gap at offset 0x%0X", info->function->name(), lastEnd);
-                               else
-                                       warning("__LD,__compact_unwind entries for %s overlap at offset 0x%0X", info->function->name(), lastEnd);
+               // don't override with converted cu with "use dwarf" cu, if forcing dwarf conversion
+               if ( !_forceDwarfConversion || !CUSection<A>::encodingMeansUseDwarf(info->compactUnwindInfo) ) {
+                       //fprintf(stderr, "cu=0x%08X, atom=%s\n", ui.unwindInfo, info->function->name());
+                       // if previous is for same function, extend range
+                       if ( info->function == lastFunc ) {
+                               if ( lastEnd != ui.startOffset ) {
+                                       if ( lastEnd < ui.startOffset )
+                                               warning("__LD,__compact_unwind entries for %s have a gap at offset 0x%0X", info->function->name(), lastEnd);
+                                       else
+                                               warning("__LD,__compact_unwind entries for %s overlap at offset 0x%0X", info->function->name(), lastEnd);
+                               }
+                               lastFunc->extendUnwindInfoRange();
                        }
                        }
-                       lastFunc->extendUnwindInfoRange();
+                       else 
+                               info->function->setUnwindInfoRange(_file->_unwindInfos.size()-1, 1);
+                       lastFunc = info->function;
+                       lastEnd = ui.startOffset + info->rangeLength;
                }
                }
-               else 
-                       info->function->setUnwindInfoRange(_file->_unwindInfos.size()-1, 1);
-               lastFunc = info->function;
-               lastEnd = ui.startOffset + info->rangeLength;
        }
        
        // parse dwarf debug info to get line info
        }
        
        // parse dwarf debug info to get line info
@@ -1668,6 +1757,7 @@ ld::relocatable::File* Parser<A>::parse(const ParserOptions& opts)
 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<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 <typename A>
 bool Parser<A>::parseLoadCommands()
 
 template <typename A>
 bool Parser<A>::parseLoadCommands()
@@ -1738,6 +1828,21 @@ bool Parser<A>::parseLoadCommands()
                                        if ( _dataInCodeEnd > (macho_data_in_code_entry<P>*)endOfFile )
                                                throw "LC_DATA_IN_CODE table extends beyond end of file";
                                }
                                        if ( _dataInCodeEnd > (macho_data_in_code_entry<P>*)endOfFile )
                                                throw "LC_DATA_IN_CODE table extends beyond end of file";
                                }
+                               break;
+                       case LC_LINKER_OPTION:
+                               {
+                                       const macho_linker_option_command<P>* loc = (macho_linker_option_command<P>*)cmd;
+                                       const char* buffer = loc->buffer();
+                                       _file->_linkerOptions.resize(_file->_linkerOptions.size() + 1);
+                                       std::vector<const char*>& vec = _file->_linkerOptions.back();
+                                       for (uint32_t j=0; j < loc->count(); ++j) {
+                                               vec.push_back(buffer);
+                                               buffer += strlen(buffer) + 1;
+                                       }
+                                       if ( buffer > ((char*)cmd + loc->cmdsize()) )
+                                               throw "malformed LC_LINKER_OPTION";
+                               }
+                               break;
                        default:
                                if ( cmd->cmd() == macho_segment_command<P>::CMD ) {
                                        if ( segment != NULL )
                        default:
                                if ( cmd->cmd() == macho_segment_command<P>::CMD ) {
                                        if ( segment != NULL )
@@ -1984,7 +2089,6 @@ void Parser<A>::makeSortedSymbolsArray(uint32_t array[], const uint32_t sectionA
        }
 }
 
        }
 }
 
-
 template <typename A>
 void Parser<A>::makeSections()
 {
 template <typename A>
 void Parser<A>::makeSections()
 {
@@ -2034,6 +2138,7 @@ void Parser<A>::makeSections()
                        //      };
                        // #define OBJC_IMAGE_SUPPORTS_GC   2
                        // #define OBJC_IMAGE_GC_ONLY       4
                        //      };
                        // #define OBJC_IMAGE_SUPPORTS_GC   2
                        // #define OBJC_IMAGE_GC_ONLY       4
+                       // #define OBJC_IMAGE_IS_SIMULATED  32
                        //
                        const uint32_t* contents = (uint32_t*)(_file->fileContent()+sect->offset());
                        if ( (sect->size() >= 8) && (contents[0] == 0) ) {
                        //
                        const uint32_t* contents = (uint32_t*)(_file->fileContent()+sect->offset());
                        if ( (sect->size() >= 8) && (contents[0] == 0) ) {
@@ -2042,6 +2147,8 @@ void Parser<A>::makeSections()
                                        _file->_objConstraint = ld::File::objcConstraintGC;
                                else if ( (flags & 2) == 2 )
                                        _file->_objConstraint = ld::File::objcConstraintRetainReleaseOrGC;
                                        _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;
                                if ( sect->size() > 8 ) {
                                else
                                        _file->_objConstraint = ld::File::objcConstraintRetainRelease;
                                if ( sect->size() > 8 ) {
@@ -2463,8 +2570,14 @@ const char* Parser<A>::scanSymbolTableForAddress(uint64_t addr)
                        continue;
 
                // return with exact match
                        continue;
 
                // return with exact match
-               if ( sym.n_value() == addr )
-                       return nameFromSymbol(sym);
+               if ( sym.n_value() == addr ) {
+                       const char* name = nameFromSymbol(sym);
+                       if ( strncmp(name, "ltmp", 4) != 0 ) 
+                               return name;
+                       // treat 'ltmp*' labels as close match
+                       closestSymAddr = sym.n_value();
+                       closestSymName = name;
+               }
                
                // record closest seen so far
                if ( (sym.n_value() < addr) && ((sym.n_value() > closestSymAddr) || (closestSymName == NULL)) )
                
                // record closest seen so far
                if ( (sym.n_value() < addr) && ((sym.n_value() > closestSymAddr) || (closestSymName == NULL)) )
@@ -2519,6 +2632,23 @@ void Parser<A>::addFixups(const SourceLocation& src, ld::Fixup::Kind setKind, co
                        case ld::Fixup::kindStoreThumbBranch22:
                                firstKind = ld::Fixup::kindStoreTargetAddressThumbBranch22;
                                break;
                        case ld::Fixup::kindStoreThumbBranch22:
                                firstKind = ld::Fixup::kindStoreTargetAddressThumbBranch22;
                                break;
+#if SUPPORT_ARCH_arm64
+                       case ld::Fixup::kindStoreARM64Branch26:
+                               firstKind = ld::Fixup::kindStoreTargetAddressARM64Branch26;
+                               break;
+                       case ld::Fixup::kindStoreARM64Page21:
+                               firstKind = ld::Fixup::kindStoreTargetAddressARM64Page21;
+                               break;
+                       case ld::Fixup::kindStoreARM64PageOff12:
+                               firstKind = ld::Fixup::kindStoreTargetAddressARM64PageOff12;
+                               break;
+                       case ld::Fixup::kindStoreARM64GOTLoadPage21:
+                               firstKind = ld::Fixup::kindStoreTargetAddressARM64GOTLoadPage21;
+                               break;
+                       case ld::Fixup::kindStoreARM64GOTLoadPageOff12:
+                               firstKind = ld::Fixup::kindStoreTargetAddressARM64GOTLoadPageOff12;
+                               break;
+#endif
                        default:
                                combined = false;
                                cl = ld::Fixup::k1of2;
                        default:
                                combined = false;
                                cl = ld::Fixup::k1of2;
@@ -2537,6 +2667,10 @@ void Parser<A>::addFixups(const SourceLocation& src, ld::Fixup::Kind setKind, co
                        // backing string in CFStrings should always be direct
                        addFixup(src, cl, firstKind, target.atom);
                }
                        // backing string in CFStrings should always be direct
                        addFixup(src, cl, firstKind, target.atom);
                }
+               else if ( (src.atom == target.atom) && (target.atom->combine() == ld::Atom::combineByName) ) {
+                       // reference to self should always be direct
+                       addFixup(src, cl, firstKind, target.atom);
+               }
                else {
                        // change direct fixup to by-name fixup
                        addFixup(src, cl, firstKind, false, target.atom->name());
                else {
                        // change direct fixup to by-name fixup
                        addFixup(src, cl, firstKind, false, target.atom->name());
@@ -2922,6 +3056,22 @@ bool Parser<A>::skip_form(const uint8_t ** offset, const uint8_t * end, uint64_t
       sz = 4;
       break;
 
       sz = 4;
       break;
 
+       case DW_FORM_sec_offset:
+         sz = sizeof(typename A::P::uint_t);
+      break;
+       
+       case DW_FORM_exprloc:
+      sz = read_uleb128 (offset, end);
+      break;
+
+    case DW_FORM_flag_present:
+         sz = 0;
+         break;
+         
+    case DW_FORM_ref_sig8:
+         sz = 8;
+         break;
+
     default:
       return false;
     }
     default:
       return false;
     }
@@ -3723,7 +3873,7 @@ template <typename A>
 void CFISection<A>::warnFunc(void* ref, uint64_t funcAddr, const char* msg)
 {
        Parser<A>* parser = (Parser<A>*)ref;
 void CFISection<A>::warnFunc(void* ref, uint64_t funcAddr, const char* msg)
 {
        Parser<A>* parser = (Parser<A>*)ref;
-       if ( ! parser->convertUnwindInfo() ) 
+       if ( ! parser->warnUnwindConversionProblems() ) 
                return;
        if ( funcAddr != CFI_INVALID_ADDRESS ) {
                // atoms are not constructed yet, so scan symbol table for labels
                return;
        if ( funcAddr != CFI_INVALID_ADDRESS ) {
                // atoms are not constructed yet, so scan symbol table for labels
@@ -3741,6 +3891,12 @@ bool CFISection<x86_64>::needsRelocating()
        return true;
 }
 
        return true;
 }
 
+template <>
+bool CFISection<arm64>::needsRelocating()
+{
+       return true;
+}
+
 template <typename A>
 bool CFISection<A>::needsRelocating()
 {
 template <typename A>
 bool CFISection<A>::needsRelocating()
 {
@@ -3748,9 +3904,9 @@ bool CFISection<A>::needsRelocating()
 }
 
 template <>
 }
 
 template <>
-void CFISection<x86_64>::cfiParse(class Parser<x86_64>& parser, uint8_t* buffer, 
+void CFISection<x86_64>::cfiParse(class Parser<x86_64>& parser, uint8_t* buffer,
                                                                        libunwind::CFI_Atom_Info<CFISection<x86_64>::OAS>::CFI_Atom_Info cfiArray[], 
                                                                        libunwind::CFI_Atom_Info<CFISection<x86_64>::OAS>::CFI_Atom_Info cfiArray[], 
-                                                                       uint32_t count)
+                                                                       uint32_t& count, const pint_t cuStarts[], uint32_t cuCount)
 {
        // copy __eh_frame data to buffer
        memcpy(buffer, file().fileContent() + this->_machOSection->offset(), this->_machOSection->size());
 {
        // copy __eh_frame data to buffer
        memcpy(buffer, file().fileContent() + this->_machOSection->offset(), this->_machOSection->size());
@@ -3796,7 +3952,6 @@ void CFISection<x86_64>::cfiParse(class Parser<x86_64>& parser, uint8_t* buffer,
                }
        }
        
                }
        }
        
-       
        // create ObjectAddressSpace object for use by libunwind
        OAS oas(*this, buffer);
        
        // create ObjectAddressSpace object for use by libunwind
        OAS oas(*this, buffer);
        
@@ -3804,7 +3959,7 @@ void CFISection<x86_64>::cfiParse(class Parser<x86_64>& parser, uint8_t* buffer,
        const char* msg;
        msg = libunwind::DwarfInstructions<OAS, libunwind::Registers_x86_64>::parseCFIs(
                                                        oas, this->_machOSection->addr(), this->_machOSection->size(), 
        const char* msg;
        msg = libunwind::DwarfInstructions<OAS, libunwind::Registers_x86_64>::parseCFIs(
                                                        oas, this->_machOSection->addr(), this->_machOSection->size(), 
-                                                       cfiArray, count, (void*)&parser, warnFunc);
+                                                       cuStarts, cuCount, parser.keepDwarfUnwind(), parser.forceDwarfConversion(), cfiArray, count, (void*)&parser, warnFunc);
        if ( msg != NULL ) 
                throwf("malformed __eh_frame section: %s", msg);
 }
        if ( msg != NULL ) 
                throwf("malformed __eh_frame section: %s", msg);
 }
@@ -3812,7 +3967,7 @@ void CFISection<x86_64>::cfiParse(class Parser<x86_64>& parser, uint8_t* buffer,
 template <>
 void CFISection<x86>::cfiParse(class Parser<x86>& parser, uint8_t* buffer, 
                                                                        libunwind::CFI_Atom_Info<CFISection<x86>::OAS>::CFI_Atom_Info cfiArray[], 
 template <>
 void CFISection<x86>::cfiParse(class Parser<x86>& parser, uint8_t* buffer, 
                                                                        libunwind::CFI_Atom_Info<CFISection<x86>::OAS>::CFI_Atom_Info cfiArray[], 
-                                                                       uint32_t count)
+                                                                       uint32_t& count, const pint_t cuStarts[], uint32_t cuCount)
 {
        // create ObjectAddressSpace object for use by libunwind
        OAS oas(*this, (uint8_t*)this->file().fileContent()+this->_machOSection->offset());
 {
        // create ObjectAddressSpace object for use by libunwind
        OAS oas(*this, (uint8_t*)this->file().fileContent()+this->_machOSection->offset());
@@ -3821,7 +3976,7 @@ void CFISection<x86>::cfiParse(class Parser<x86>& parser, uint8_t* buffer,
        const char* msg;
        msg = libunwind::DwarfInstructions<OAS, libunwind::Registers_x86>::parseCFIs(
                                                        oas, this->_machOSection->addr(), this->_machOSection->size(), 
        const char* msg;
        msg = libunwind::DwarfInstructions<OAS, libunwind::Registers_x86>::parseCFIs(
                                                        oas, this->_machOSection->addr(), this->_machOSection->size(), 
-                                                       cfiArray, count, (void*)&parser, warnFunc);
+                                                       cuStarts, cuCount, parser.keepDwarfUnwind(), parser.forceDwarfConversion(), cfiArray, count, (void*)&parser, warnFunc);
        if ( msg != NULL ) 
                throwf("malformed __eh_frame section: %s", msg);
 }
        if ( msg != NULL ) 
                throwf("malformed __eh_frame section: %s", msg);
 }
@@ -3832,12 +3987,76 @@ void CFISection<x86>::cfiParse(class Parser<x86>& parser, uint8_t* buffer,
 template <>
 void CFISection<arm>::cfiParse(class Parser<arm>& parser, uint8_t* buffer, 
                                                                        libunwind::CFI_Atom_Info<CFISection<arm>::OAS>::CFI_Atom_Info cfiArray[], 
 template <>
 void CFISection<arm>::cfiParse(class Parser<arm>& parser, uint8_t* buffer, 
                                                                        libunwind::CFI_Atom_Info<CFISection<arm>::OAS>::CFI_Atom_Info cfiArray[], 
-                                                                       uint32_t count)
+                                                                       uint32_t& count, const pint_t cuStarts[], uint32_t cuCount)
 {
        // arm does not use zero cost exceptions
        assert(count == 0);
 }
 
 {
        // arm does not use zero cost exceptions
        assert(count == 0);
 }
 
+template <>
+void CFISection<arm64>::cfiParse(class Parser<arm64>& parser, uint8_t* buffer, 
+                                                                       libunwind::CFI_Atom_Info<CFISection<arm64>::OAS>::CFI_Atom_Info cfiArray[], 
+                                                                       uint32_t& count, const pint_t cuStarts[], uint32_t cuCount)
+{
+       // copy __eh_frame data to buffer
+       memcpy(buffer, file().fileContent() + this->_machOSection->offset(), this->_machOSection->size());
+
+       // and apply relocations
+       const macho_relocation_info<P>* relocs = (macho_relocation_info<P>*)(file().fileContent() + this->_machOSection->reloff());
+       const macho_relocation_info<P>* relocsEnd = &relocs[this->_machOSection->nreloc()];
+       for (const macho_relocation_info<P>* reloc = relocs; reloc < relocsEnd; ++reloc) {
+               uint64_t* p64 = (uint64_t*)&buffer[reloc->r_address()];
+               uint32_t* p32 = (uint32_t*)&buffer[reloc->r_address()];
+               uint32_t addend32 = E::get32(*p32); 
+               uint64_t addend64 = E::get64(*p64); 
+               uint64_t value = 0;
+               switch ( reloc->r_type() ) {
+                       case ARM64_RELOC_SUBTRACTOR:    
+                               value =  0 - parser.symbolFromIndex(reloc->r_symbolnum()).n_value();
+                               ++reloc;
+                               if ( reloc->r_extern() )
+                                       value += parser.symbolFromIndex(reloc->r_symbolnum()).n_value();
+                               break;
+                       case ARM64_RELOC_UNSIGNED:
+                               value = parser.symbolFromIndex(reloc->r_symbolnum()).n_value();
+                               break;
+                       case ARM64_RELOC_POINTER_TO_GOT:
+                               // this is used for the reference to the personality function in CIEs
+                               // store the symbol number of the personality function for later use as a Fixup
+                               value = reloc->r_symbolnum();
+                               addend32 = 0;
+                               addend64 = 0;
+                               break;
+                       default:
+                               fprintf(stderr, "CFISection::cfiParse() unexpected relocation type at r_address=0x%08X\n", reloc->r_address());
+                               break;
+               }
+               switch ( reloc->r_length() ) {
+                       case 3:
+                               E::set64(*p64, value + addend64);
+                               break;
+                       case 2:
+                               E::set32(*p32, value + addend32);
+                               break;
+                       default:
+                               fprintf(stderr, "CFISection::cfiParse() unexpected relocation size at r_address=0x%08X\n", reloc->r_address());
+                               break;
+               }
+       }
+       
+       
+       // create ObjectAddressSpace object for use by libunwind
+       OAS oas(*this, buffer);
+       
+       // use libuwind to parse __eh_frame data into array of CFI_Atom_Info
+       const char* msg;
+       msg = libunwind::DwarfInstructions<OAS, libunwind::Registers_arm64>::parseCFIs(
+                                                       oas, this->_machOSection->addr(), this->_machOSection->size(), 
+                                                       cuStarts, cuCount, parser.keepDwarfUnwind(), parser.forceDwarfConversion(), 
+                                                       cfiArray, count, (void*)&parser, warnFunc);
+       if ( msg != NULL ) 
+               throwf("malformed __eh_frame section: %s", msg);
+}
 
 
 template <typename A>
 
 
 template <typename A>
@@ -3875,6 +4094,7 @@ uint32_t CFISection<A>::appendAtoms(class Parser<A>& parser, uint8_t* p,
 template <> bool CFISection<x86_64>::bigEndian() { return false; }
 template <> bool CFISection<x86>::bigEndian() { return false; }
 template <> bool CFISection<arm>::bigEndian() { return false; }
 template <> bool CFISection<x86_64>::bigEndian() { return false; }
 template <> bool CFISection<x86>::bigEndian() { return false; }
 template <> bool CFISection<arm>::bigEndian() { return false; }
+template <> bool CFISection<arm64>::bigEndian() { return false; }
 
 
 template <>
 
 
 template <>
@@ -3924,11 +4144,36 @@ void CFISection<x86>::addCiePersonalityFixups(class Parser<x86>& parser, const C
 }
 
 
 }
 
 
+
+#if SUPPORT_ARCH_arm64
+template <>
+void CFISection<arm64>::addCiePersonalityFixups(class Parser<arm64>& parser, const CFI_Atom_Info* cieInfo)
+{
+       uint8_t personalityEncoding = cieInfo->u.cieInfo.personality.encodingOfTargetAddress;
+       if ( personalityEncoding == 0x9B ) {
+               // compiler always produces ARM64_RELOC_GOT r_pcrel=1 to personality function
+               // CFISection<arm64>::cfiParse() set targetAddress to be symbolIndex + addressInCIE
+               uint32_t symbolIndex = cieInfo->u.cieInfo.personality.targetAddress 
+                                                                       - cieInfo->address - cieInfo->u.cieInfo.personality.offsetInCFI;
+               const macho_nlist<P>& sym = parser.symbolFromIndex(symbolIndex);
+               const char* personalityName = parser.nameFromSymbol(sym);
+
+               Atom<arm64>* cieAtom = this->findAtomByAddress(cieInfo->address);
+               Parser<arm64>::SourceLocation src(cieAtom, cieInfo->u.cieInfo.personality.offsetInCFI);
+               parser.addFixup(src, ld::Fixup::k1of2, ld::Fixup::kindSetTargetAddress, false, personalityName);
+               parser.addFixup(src, ld::Fixup::k2of2, ld::Fixup::kindStoreARM64PCRelToGOT);
+       }
+       else if ( personalityEncoding != 0 ) {
+               throwf("unsupported address encoding (%02X) of personality function in CIE", 
+                               personalityEncoding);
+       }
+}
+#endif
+
 template <typename A>
 void CFISection<A>::addCiePersonalityFixups(class Parser<A>& parser, const CFI_Atom_Info* cieInfo)
 {
 template <typename A>
 void CFISection<A>::addCiePersonalityFixups(class Parser<A>& parser, const CFI_Atom_Info* cieInfo)
 {
-       // FIX ME
-       assert(0);
+       assert(0 && "addCiePersonalityFixups() not implemented for arch");
 }
 
 template <typename A>
 }
 
 template <typename A>
@@ -4162,27 +4407,103 @@ typename A::P::uint_t CFISection<A>::OAS::getEncodedP(pint_t& addr, pint_t end,
 template <>
 const char* CUSection<x86_64>::personalityName(class Parser<x86_64>& parser, const macho_relocation_info<x86_64::P>* reloc)
 {
 template <>
 const char* CUSection<x86_64>::personalityName(class Parser<x86_64>& parser, const macho_relocation_info<x86_64::P>* reloc)
 {
-       assert(reloc->r_extern() && "reloc not extern on personality column in __compact_unwind section");
-       assert((reloc->r_type() == X86_64_RELOC_UNSIGNED) && "wrong reloc type on personality column in __compact_unwind section");
-       const macho_nlist<P>& sym = parser.symbolFromIndex(reloc->r_symbolnum());
-       return parser.nameFromSymbol(sym);
+       if ( reloc->r_extern() ) {
+               assert((reloc->r_type() == X86_64_RELOC_UNSIGNED) && "wrong reloc type on personality column in __compact_unwind section");
+               const macho_nlist<P>& sym = parser.symbolFromIndex(reloc->r_symbolnum());
+               return parser.nameFromSymbol(sym);
+       }
+       else {
+               const pint_t* content = (pint_t*)(this->file().fileContent() + this->_machOSection->offset() + reloc->r_address());
+               pint_t personalityAddr = *content;
+               Section<x86_64>* personalitySection = parser.sectionForAddress(personalityAddr);
+               assert((personalitySection->type() == ld::Section::typeCode) && "personality column in __compact_unwind section is not pointer to function");
+               // atoms may not be constructed yet, so scan symbol table for labels
+               const char* name = parser.scanSymbolTableForAddress(personalityAddr);
+               return name;
+       }
 }
 
 template <>
 const char* CUSection<x86>::personalityName(class Parser<x86>& parser, const macho_relocation_info<x86::P>* reloc)
 {
 }
 
 template <>
 const char* CUSection<x86>::personalityName(class Parser<x86>& parser, const macho_relocation_info<x86::P>* reloc)
 {
-       assert(reloc->r_extern() && "reloc not extern on personality column in __compact_unwind section");
-       assert((reloc->r_type() == GENERIC_RELOC_VANILLA) && "wrong reloc type on personality column in __compact_unwind section");
-       const macho_nlist<P>& sym = parser.symbolFromIndex(reloc->r_symbolnum());
-       return parser.nameFromSymbol(sym);
+       if ( reloc->r_extern() ) {
+               assert((reloc->r_type() == GENERIC_RELOC_VANILLA) && "wrong reloc type on personality column in __compact_unwind section");
+               const macho_nlist<P>& sym = parser.symbolFromIndex(reloc->r_symbolnum());
+               return parser.nameFromSymbol(sym);
+       }
+       else {
+               // support __LD, __compact_unwind personality entries which are pointer to personality non-lazy pointer
+               const pint_t* content = (pint_t*)(this->file().fileContent() + this->_machOSection->offset() + reloc->r_address());
+               pint_t nlPointerAddr = *content;
+               Section<x86>* nlSection = parser.sectionForAddress(nlPointerAddr);
+               if ( nlSection->type() == ld::Section::typeCode ) {
+                       // personality function is defined in this .o file, so this is a direct reference to it
+                       // atoms may not be constructed yet, so scan symbol table for labels
+                       const char* name = parser.scanSymbolTableForAddress(nlPointerAddr);
+                       return name;
+               }
+               else {
+                       uint32_t symIndex = parser.symbolIndexFromIndirectSectionAddress(nlPointerAddr, nlSection->machoSection());
+                       const macho_nlist<P>& nlSymbol = parser.symbolFromIndex(symIndex);
+                       return parser.nameFromSymbol(nlSymbol);
+               }
+       }
 }
 
 }
 
+#if SUPPORT_ARCH_arm64
+template <>
+const char* CUSection<arm64>::personalityName(class Parser<arm64>& parser, const macho_relocation_info<arm64::P>* reloc)
+{
+       if ( reloc->r_extern() ) {
+               assert((reloc->r_type() == ARM64_RELOC_UNSIGNED) && "wrong reloc type on personality column in __compact_unwind section");
+               const macho_nlist<P>& sym = parser.symbolFromIndex(reloc->r_symbolnum());
+               return parser.nameFromSymbol(sym);
+       }
+       else {
+               const pint_t* content = (pint_t*)(this->file().fileContent() + this->_machOSection->offset() + reloc->r_address());
+               pint_t personalityAddr = *content;
+               Section<arm64>* personalitySection = parser.sectionForAddress(personalityAddr);
+               assert((personalitySection->type() == ld::Section::typeCode) && "personality column in __compact_unwind section is not pointer to function");
+               // atoms may not be constructed yet, so scan symbol table for labels
+               const char* name = parser.scanSymbolTableForAddress(personalityAddr);
+               return name;
+       }
+}
+#endif
+
 template <typename A>
 const char* CUSection<A>::personalityName(class Parser<A>& parser, const macho_relocation_info<P>* reloc)
 {
        return NULL;
 }
 
 template <typename A>
 const char* CUSection<A>::personalityName(class Parser<A>& parser, const macho_relocation_info<P>* reloc)
 {
        return NULL;
 }
 
+template <>
+bool CUSection<x86>::encodingMeansUseDwarf(compact_unwind_encoding_t enc)
+{
+       return ((enc & UNWIND_X86_MODE_MASK) == UNWIND_X86_MODE_DWARF);
+}
+
+template <>
+bool CUSection<x86_64>::encodingMeansUseDwarf(compact_unwind_encoding_t enc)
+{
+       return ((enc & UNWIND_X86_64_MODE_MASK) == UNWIND_X86_64_MODE_DWARF);
+}
+
+#if SUPPORT_ARCH_arm_any
+template <>
+bool CUSection<arm>::encodingMeansUseDwarf(compact_unwind_encoding_t enc)
+{
+       return false;
+}
+#endif
+
+#if SUPPORT_ARCH_arm64
+template <>
+bool CUSection<arm64>::encodingMeansUseDwarf(compact_unwind_encoding_t enc)
+{
+       return ((enc & UNWIND_ARM64_MODE_MASK) == UNWIND_ARM64_MODE_DWARF);
+}
+#endif
 
 template <typename A>
 int CUSection<A>::infoSorter(const void* l, const void* r)
 
 template <typename A>
 int CUSection<A>::infoSorter(const void* l, const void* r)
@@ -4219,8 +4540,7 @@ void CUSection<A>::parse(class Parser<A>& parser, uint32_t cnt, Info array[])
                }
        }
        
                }
        }
        
-       // scan relocs, local relocs are useless - ignore them
-       // extern relocs are needed for personality references (possibly for function/lsda refs??)
+       // scan relocs, extern relocs are needed for personality references (possibly for function/lsda refs??)
        const macho_relocation_info<P>* relocs = (macho_relocation_info<P>*)(this->file().fileContent() + this->_machOSection->reloff());
        const macho_relocation_info<P>* relocsEnd = &relocs[this->_machOSection->nreloc()];
        for (const macho_relocation_info<P>* reloc = relocs; reloc < relocsEnd; ++reloc) {
        const macho_relocation_info<P>* relocs = (macho_relocation_info<P>*)(this->file().fileContent() + this->_machOSection->reloff());
        const macho_relocation_info<P>* relocsEnd = &relocs[this->_machOSection->nreloc()];
        for (const macho_relocation_info<P>* reloc = relocs; reloc < relocsEnd; ++reloc) {
@@ -4241,11 +4561,18 @@ void CUSection<A>::parse(class Parser<A>& parser, uint32_t cnt, Info array[])
                        else if ( (reloc->r_address() % sizeof(macho_compact_unwind_entry<P>)) == macho_compact_unwind_entry<P>::codeStartFieldOffset() ) {
                                uint32_t entryIndex = reloc->r_address() / sizeof(macho_compact_unwind_entry<P>);
                                array[entryIndex].functionSymbolIndex = reloc->r_symbolnum();
                        else if ( (reloc->r_address() % sizeof(macho_compact_unwind_entry<P>)) == macho_compact_unwind_entry<P>::codeStartFieldOffset() ) {
                                uint32_t entryIndex = reloc->r_address() / sizeof(macho_compact_unwind_entry<P>);
                                array[entryIndex].functionSymbolIndex = reloc->r_symbolnum();
+                               array[entryIndex].functionStartAddress += parser.symbolFromIndex(reloc->r_symbolnum()).n_value();
                        }
                        else {
                                warning("unexpected extern relocation in __compact_unwind section");
                        }
                }
                        }
                        else {
                                warning("unexpected extern relocation in __compact_unwind section");
                        }
                }
+               else {
+                       if ( (reloc->r_address() % sizeof(macho_compact_unwind_entry<P>)) == macho_compact_unwind_entry<P>::personalityFieldOffset() ) {
+                               uint32_t entryIndex = reloc->r_address() / sizeof(macho_compact_unwind_entry<P>);
+                               array[entryIndex].personality = this->personalityName(parser, reloc);
+                       }
+               }
        }
        
        // sort array by function start address so unwind infos will be contiguous for a given function
        }
        
        // sort array by function start address so unwind infos will be contiguous for a given function
@@ -4268,9 +4595,6 @@ void CUSection<A>::makeFixups(class Parser<A>& parser, const struct Parser<A>::C
        Info* const arrayStart = cus.cuArray;
        Info* const arrayEnd = &cus.cuArray[cus.cuCount];
        for (Info* info=arrayStart; info < arrayEnd; ++info) {
        Info* const arrayStart = cus.cuArray;
        Info* const arrayEnd = &cus.cuArray[cus.cuCount];
        for (Info* info=arrayStart; info < arrayEnd; ++info) {
-               // if external reloc was used, real address is symbol n_value + addend
-               if ( info->functionSymbolIndex != 0xFFFFFFFF )
-                       info->functionStartAddress += parser.symbolFromIndex(info->functionSymbolIndex).n_value();
                // find function atom from address
                info->function = parser.findAtomByAddress(info->functionStartAddress);  
                // find lsda atom from address
                // find function atom from address
                info->function = parser.findAtomByAddress(info->functionStartAddress);  
                // find lsda atom from address
@@ -4356,7 +4680,7 @@ uint32_t SymboledSection<A>::computeAtomCount(class Parser<A>& parser,
        pint_t  addr;
        pint_t  size;
        const macho_nlist<P>* sym;
        pint_t  addr;
        pint_t  size;
        const macho_nlist<P>* sym;
-       while ( it.next(parser, sectNum, startAddr, endAddr, &addr, &size, &sym) ) {
+       while ( it.next(parser, *this, sectNum, startAddr, endAddr, &addr, &size, &sym) ) {
                ++count;
        }
        //fprintf(stderr, "computeAtomCount(%s,%s) => %d\n", this->segmentName(), this->sectionName(), count);
                ++count;
        }
        //fprintf(stderr, "computeAtomCount(%s,%s) => %d\n", this->segmentName(), this->sectionName(), count);
@@ -4365,7 +4689,7 @@ uint32_t SymboledSection<A>::computeAtomCount(class Parser<A>& parser,
 
 template <typename A>
 uint32_t SymboledSection<A>::appendAtoms(class Parser<A>& parser, uint8_t* p, 
 
 template <typename A>
 uint32_t SymboledSection<A>::appendAtoms(class Parser<A>& parser, uint8_t* p, 
-                                                                                       struct Parser<A>::LabelAndCFIBreakIterator& it, 
+                                                                                       struct Parser<A>::LabelAndCFIBreakIterator& it,
                                                                                        const struct Parser<A>::CFI_CU_InfoArrays&)
 {
        this->_beginAtoms = (Atom<A>*)p;
                                                                                        const struct Parser<A>::CFI_CU_InfoArrays&)
 {
        this->_beginAtoms = (Atom<A>*)p;
@@ -4379,7 +4703,7 @@ uint32_t SymboledSection<A>::appendAtoms(class Parser<A>& parser, uint8_t* p,
        pint_t  addr;
        pint_t  size;
        const macho_nlist<P>* label;
        pint_t  addr;
        pint_t  size;
        const macho_nlist<P>* label;
-       while ( it.next(parser, sectNum, startAddr, endAddr, &addr, &size, &label) ) {
+       while ( it.next(parser, *this, sectNum, startAddr, endAddr, &addr, &size, &label) ) {
                Atom<A>* allocatedSpace = (Atom<A>*)p;
                // is break because of label or CFI?
                if ( label != NULL ) {
                Atom<A>* allocatedSpace = (Atom<A>*)p;
                // is break because of label or CFI?
                if ( label != NULL ) {
@@ -4396,7 +4720,7 @@ uint32_t SymboledSection<A>::appendAtoms(class Parser<A>& parser, uint8_t* p,
                        ld::Atom::ContentType ctype = this->contentType();
                        if ( ctype == ld::Atom::typeLSDA )
                                inclusion = ld::Atom::symbolTableInWithRandomAutoStripLabel;
                        ld::Atom::ContentType ctype = this->contentType();
                        if ( ctype == ld::Atom::typeLSDA )
                                inclusion = ld::Atom::symbolTableInWithRandomAutoStripLabel;
-                       new (allocatedSpace) Atom<A>(*this, "anon", addr, size, ld::Atom::definitionRegular, ld::Atom::combineNever, 
+                       new (allocatedSpace) Atom<A>(*this, "anon", addr, size, ld::Atom::definitionRegular, ld::Atom::combineNever,
                                                                                ld::Atom::scopeTranslationUnit, ctype, inclusion, 
                                                                                this->dontDeadStrip(), false, false, this->alignmentForAddress(addr));
                }
                                                                                ld::Atom::scopeTranslationUnit, ctype, inclusion, 
                                                                                this->dontDeadStrip(), false, false, this->alignmentForAddress(addr));
                }
@@ -4409,6 +4733,19 @@ uint32_t SymboledSection<A>::appendAtoms(class Parser<A>& parser, uint8_t* p,
 }
 
 
 }
 
 
+template <>
+ld::Atom::SymbolTableInclusion ImplicitSizeSection<arm64>::symbolTableInclusion()
+{
+       return ld::Atom::symbolTableInWithRandomAutoStripLabel;
+}
+
+template <typename A>
+ld::Atom::SymbolTableInclusion ImplicitSizeSection<A>::symbolTableInclusion()
+{
+       return ld::Atom::symbolTableNotIn;
+}
+
+
 template <typename A>
 uint32_t ImplicitSizeSection<A>::computeAtomCount(class Parser<A>& parser, 
                                                                                                        struct Parser<A>::LabelAndCFIBreakIterator& it, 
 template <typename A>
 uint32_t ImplicitSizeSection<A>::computeAtomCount(class Parser<A>& parser, 
                                                                                                        struct Parser<A>::LabelAndCFIBreakIterator& it, 
@@ -4426,15 +4763,18 @@ uint32_t ImplicitSizeSection<A>::computeAtomCount(class Parser<A>& parser,
                // if there are multiple labels in this section for the same address, then clone them into multi atoms
                pint_t  prevSymbolAddr = (pint_t)(-1);
                uint8_t prevSymbolSectNum = 0;
                // if there are multiple labels in this section for the same address, then clone them into multi atoms
                pint_t  prevSymbolAddr = (pint_t)(-1);
                uint8_t prevSymbolSectNum = 0;
+               bool prevIgnore = false;
                for(uint32_t i=0; i < it.sortedSymbolCount; ++i) {
                        const macho_nlist<P>& sym = parser.symbolFromIndex(it.sortedSymbolIndexes[i]);
                        const pint_t symbolAddr = sym.n_value();
                for(uint32_t i=0; i < it.sortedSymbolCount; ++i) {
                        const macho_nlist<P>& sym = parser.symbolFromIndex(it.sortedSymbolIndexes[i]);
                        const pint_t symbolAddr = sym.n_value();
-                       const pint_t symbolSectNum = sym.n_sect();
-                       if ( (symbolAddr == prevSymbolAddr) && (prevSymbolSectNum == symbolSectNum) && (symbolSectNum == this->sectionNum(parser)) ) { 
+                       const uint8_t symbolSectNum = sym.n_sect();
+                       const bool ignore = this->ignoreLabel(parser.nameFromSymbol(sym));
+                       if ( !ignore && !prevIgnore && (symbolAddr == prevSymbolAddr) && (prevSymbolSectNum == symbolSectNum) && (symbolSectNum == this->sectionNum(parser)) ) { 
                                ++count;
                        }
                        prevSymbolAddr = symbolAddr;
                        prevSymbolSectNum = symbolSectNum;
                                ++count;
                        }
                        prevSymbolAddr = symbolAddr;
                        prevSymbolSectNum = symbolSectNum;
+                       prevIgnore = ignore;
                }
        }
        return count;
                }
        }
        return count;
@@ -4457,33 +4797,44 @@ uint32_t ImplicitSizeSection<A>::appendAtoms(class Parser<A>& parser, uint8_t* p
        pint_t  size;
        const macho_nlist<P>* foundLabel;
        Atom<A>* allocatedSpace;
        pint_t  size;
        const macho_nlist<P>* foundLabel;
        Atom<A>* allocatedSpace;
-       while ( it.next(parser, sectNum, startAddr, endAddr, &foundAddr, &size, &foundLabel) ) {
+       while ( it.next(parser, *this, sectNum, startAddr, endAddr, &foundAddr, &size, &foundLabel) ) {
                if ( foundLabel != NULL ) {
                if ( foundLabel != NULL ) {
+                       bool skip = false;
                        pint_t labeledAtomSize = this->elementSizeAtAddress(foundAddr);
                        allocatedSpace = (Atom<A>*)p;
                        if ( this->ignoreLabel(parser.nameFromSymbol(*foundLabel)) ) {
                        pint_t labeledAtomSize = this->elementSizeAtAddress(foundAddr);
                        allocatedSpace = (Atom<A>*)p;
                        if ( this->ignoreLabel(parser.nameFromSymbol(*foundLabel)) ) {
-                               //fprintf(stderr, "  0x%08llX make annon\n", (uint64_t)foundAddr);
-                               new (allocatedSpace) Atom<A>(*this, this->unlabeledAtomName(parser, foundAddr), foundAddr, 
+                               if ( size == 0 ) {
+                                       // <rdar://problem/10018737> 
+                                       // a size of zero means there is another label at same location 
+                                       // and we are supposed to ignore this label
+                                       skip = true;
+                               }
+                               else {
+                                       //fprintf(stderr, "  0x%08llX make annon, size=%lld\n", (uint64_t)foundAddr, (uint64_t)size);
+                                       new (allocatedSpace) Atom<A>(*this, this->unlabeledAtomName(parser, foundAddr), foundAddr, 
                                                                                        this->elementSizeAtAddress(foundAddr), this->definition(), 
                                                                                        this->combine(parser, foundAddr), this->scopeAtAddress(parser, foundAddr), 
                                                                                        this->contentType(), this->symbolTableInclusion(), 
                                                                                        this->dontDeadStrip(), false, false, this->alignmentForAddress(foundAddr));
                                                                                        this->elementSizeAtAddress(foundAddr), this->definition(), 
                                                                                        this->combine(parser, foundAddr), this->scopeAtAddress(parser, foundAddr), 
                                                                                        this->contentType(), this->symbolTableInclusion(), 
                                                                                        this->dontDeadStrip(), false, false, this->alignmentForAddress(foundAddr));
+                               }
                        }
                        else {
                                // make named atom for label
                                //fprintf(stderr, "  0x%08llX make labeled\n", (uint64_t)foundAddr);
                                new (allocatedSpace) Atom<A>(*this, parser, *foundLabel, labeledAtomSize);
                        }
                        }
                        else {
                                // make named atom for label
                                //fprintf(stderr, "  0x%08llX make labeled\n", (uint64_t)foundAddr);
                                new (allocatedSpace) Atom<A>(*this, parser, *foundLabel, labeledAtomSize);
                        }
-                       ++count;
-                       p += sizeof(Atom<A>);
-                       foundAddr += labeledAtomSize;
-                       size -= labeledAtomSize;
+                       if ( !skip ) {
+                               ++count;
+                               p += sizeof(Atom<A>);
+                               foundAddr += labeledAtomSize;
+                               size -= labeledAtomSize;
+                       }
                }
                // some number of anonymous atoms
                for (pint_t addr = foundAddr; addr < (foundAddr+size); addr += elementSizeAtAddress(addr) ) {
                        // make anon atoms for area before label
                        if ( this->useElementAt(parser, it, addr) ) {
                }
                // some number of anonymous atoms
                for (pint_t addr = foundAddr; addr < (foundAddr+size); addr += elementSizeAtAddress(addr) ) {
                        // make anon atoms for area before label
                        if ( this->useElementAt(parser, it, addr) ) {
-                               //fprintf(stderr, "  0x%08llX make annon\n", (uint64_t)addr);
+                               //fprintf(stderr, "  0x%08llX make annon, size=%lld\n", (uint64_t)addr, (uint64_t)elementSizeAtAddress(addr));
                                allocatedSpace = (Atom<A>*)p;
                                new (allocatedSpace) Atom<A>(*this, this->unlabeledAtomName(parser, addr), addr, this->elementSizeAtAddress(addr), 
                                                                                        this->definition(), this->combine(parser, addr), this->scopeAtAddress(parser, addr), 
                                allocatedSpace = (Atom<A>*)p;
                                new (allocatedSpace) Atom<A>(*this, this->unlabeledAtomName(parser, addr), addr, this->elementSizeAtAddress(addr), 
                                                                                        this->definition(), this->combine(parser, addr), this->scopeAtAddress(parser, addr), 
@@ -4606,11 +4957,12 @@ bool CStringSection<A>::useElementAt(Parser<A>& parser, struct Parser<A>::LabelA
 }
 
 template <typename A>
 }
 
 template <typename A>
-bool CStringSection<A>::ignoreLabel(const char* label)  
+bool CStringSection<A>::ignoreLabel(const char* label) const
 { 
        return (label[0] == 'L') || (label[0] == 'l'); 
 }
 
 { 
        return (label[0] == 'L') || (label[0] == 'l'); 
 }
 
+
 template <typename A>
 Atom<A>* CStringSection<A>::findAtomByAddress(pint_t addr)
 {
 template <typename A>
 Atom<A>* CStringSection<A>::findAtomByAddress(pint_t addr)
 {
@@ -4665,6 +5017,12 @@ ld::Fixup::Kind NonLazyPointerSection<arm>::fixupKind()
        return ld::Fixup::kindStoreLittleEndian32;
 }
 
        return ld::Fixup::kindStoreLittleEndian32;
 }
 
+template <>
+ld::Fixup::Kind NonLazyPointerSection<arm64>::fixupKind()
+{
+       return ld::Fixup::kindStoreLittleEndian64;
+}
+
 
 template <>
 void NonLazyPointerSection<x86_64>::makeFixups(class Parser<x86_64>& parser, const struct Parser<x86_64>::CFI_CU_InfoArrays&)
 
 template <>
 void NonLazyPointerSection<x86_64>::makeFixups(class Parser<x86_64>& parser, const struct Parser<x86_64>::CFI_CU_InfoArrays&)
@@ -5056,12 +5414,16 @@ const char* PointerToCStringSection<A>::targetCString(const class Atom<A>* atom,
                case ld::Fixup::bindingsIndirectlyBound:
                        targetAtom = ind.indirectAtom(fit->u.bindingIndex);
                        break;
                case ld::Fixup::bindingsIndirectlyBound:
                        targetAtom = ind.indirectAtom(fit->u.bindingIndex);
                        break;
+               case ld::Fixup::bindingDirectlyBound:
+                       targetAtom = fit->u.target;
+                       break;
                default:
                default:
-                       assert(0);
+                       assert(0 && "unsupported reference to selector");
        }
        assert(targetAtom != NULL);
        const Atom<A>* target = dynamic_cast<const Atom<A>*>(targetAtom);
        }
        assert(targetAtom != NULL);
        const Atom<A>* target = dynamic_cast<const Atom<A>*>(targetAtom);
-       assert(target !=  NULL);
+       assert(target != NULL);
+       assert(target->contentType() == ld::Atom::typeCString);
        return (char*)target->contentPointer();
 }
 
        return (char*)target->contentPointer();
 }
 
@@ -6054,8 +6416,314 @@ bool Section<arm>::addRelocFixup(class Parser<arm>& parser, const macho_relocati
 #endif
 
 
 #endif
 
 
-
-
+#if SUPPORT_ARCH_arm64
+template <>
+bool Section<arm64>::addRelocFixup(class Parser<arm64>& parser, const macho_relocation_info<P>* reloc)
+{
+       bool result = false;
+       Parser<arm64>::SourceLocation   src;
+       Parser<arm64>::TargetDesc               target = { NULL, NULL, false, 0 };
+       Parser<arm64>::TargetDesc               toTarget;
+       int32_t prefixRelocAddend = 0;
+       if ( reloc->r_type() == ARM64_RELOC_ADDEND ) {
+               uint32_t rawAddend = reloc->r_symbolnum(); 
+               prefixRelocAddend = rawAddend;
+               if ( rawAddend & 0x00800000 )
+                       prefixRelocAddend |= 0xFF000000; // sign extend 24-bit signed int to 32-bits
+               uint32_t addendAddress = reloc->r_address();
+               ++reloc;  //advance to next reloc record
+               result = true;
+               if ( reloc->r_address() != addendAddress )
+                       throw "ARM64_RELOC_ADDEND r_address does not match next reloc's r_address";
+       }
+       const macho_section<P>* sect = this->machoSection();
+       uint64_t srcAddr = sect->addr() + reloc->r_address();
+       src.atom = this->findAtomByAddress(srcAddr);
+       src.offsetInAtom = srcAddr - src.atom->_objAddress;
+       const uint8_t* fixUpPtr = file().fileContent() + sect->offset() + reloc->r_address();
+       uint64_t contentValue = 0;
+       const macho_relocation_info<arm64::P>* nextReloc = &reloc[1];
+       bool useDirectBinding;
+       uint32_t instruction;
+       uint32_t encodedAddend;
+       switch ( reloc->r_length() ) {
+               case 0:
+                       contentValue = *fixUpPtr;
+                       break;
+               case 1:
+                       contentValue = (int64_t)(int16_t)E::get16(*((uint16_t*)fixUpPtr));
+                       break;
+               case 2:
+                       contentValue = (int64_t)(int32_t)E::get32(*((uint32_t*)fixUpPtr));
+                       break;
+               case 3:
+                       contentValue = E::get64(*((uint64_t*)fixUpPtr));
+                       break;
+       }
+       if ( reloc->r_extern() ) {
+               const macho_nlist<P>& sym = parser.symbolFromIndex(reloc->r_symbolnum());
+               const char* symbolName = parser.nameFromSymbol(sym);
+               if ( ((sym.n_type() & N_TYPE) == N_SECT) && (((sym.n_type() & N_EXT) == 0) || (symbolName[0] == 'L') || (symbolName[0] == 'l')) ) {
+                       // use direct reference for local symbols
+                       parser.findTargetFromAddressAndSectionNum(sym.n_value(), sym.n_sect(), target);
+                       //target.addend += contentValue;
+               }
+               else if ( ((sym.n_type() & N_TYPE) == N_SECT) && (src.atom->_objAddress <= sym.n_value()) && (sym.n_value() < (src.atom->_objAddress+src.atom->size())) ) {
+                       // <rdar://problem/13700961> spurious warning when weak function has reference to itself
+                       // use direct reference when atom targets itself
+                       target.atom = src.atom;
+                       target.name = NULL;
+               }
+               else {
+                       target.name = symbolName;
+                       target.weakImport = parser.weakImportFromSymbol(sym);
+                       //target.addend = contentValue;
+               }
+               // cfstrings should always use direct reference to backing store
+               if ( (this->type() == ld::Section::typeCFString) && (src.offsetInAtom != 0) ) {
+                       parser.findTargetFromAddressAndSectionNum(sym.n_value(), sym.n_sect(), target);
+                       //target.addend = contentValue;
+               }
+       }
+       else {
+               if ( reloc->r_pcrel()  )
+                       contentValue += srcAddr;
+               parser.findTargetFromAddressAndSectionNum(contentValue, reloc->r_symbolnum(), target);
+       }
+       switch ( reloc->r_type() ) {
+               case ARM64_RELOC_UNSIGNED:
+                       if ( reloc->r_pcrel() )
+                               throw "pcrel and ARM64_RELOC_UNSIGNED not supported";
+                       target.addend = contentValue;
+                       switch ( reloc->r_length() ) {
+                               case 0:
+                               case 1:
+                                       throw "length < 2 and ARM64_RELOC_UNSIGNED not supported";
+                               case 2:
+                                       parser.addFixups(src, ld::Fixup::kindStoreLittleEndian32, target);
+                                       break;
+                               case 3:
+                                       parser.addFixups(src, ld::Fixup::kindStoreLittleEndian64, target);
+                                       break;
+                       }
+                       break;
+               case ARM64_RELOC_BRANCH26:
+                       if ( ! reloc->r_pcrel() )
+                               throw "not pcrel and ARM64_RELOC_BRANCH26 not supported";
+                       if ( ! reloc->r_extern() ) 
+                               throw "r_extern == 0 and ARM64_RELOC_BRANCH26 not supported";
+                       if ( reloc->r_length() != 2 )
+                               throw "r_length != 2 and ARM64_RELOC_BRANCH26 not supported";
+                       if ( (target.name != NULL) && (strncmp(target.name, "___dtrace_probe$", 16) == 0) ) {
+                               parser.addFixup(src, ld::Fixup::k1of1, ld::Fixup::kindStoreARM64DtraceCallSiteNop, false, target.name);
+                               parser.addDtraceExtraInfos(src, &target.name[16]);
+                       }
+                       else if ( (target.name != NULL) && (strncmp(target.name, "___dtrace_isenabled$", 20) == 0) ) {
+                               parser.addFixup(src, ld::Fixup::k1of1, ld::Fixup::kindStoreARM64DtraceIsEnableSiteClear, false, target.name);
+                               parser.addDtraceExtraInfos(src, &target.name[20]);
+                       }
+                       else {
+                               target.addend = prefixRelocAddend;
+                               instruction = contentValue;
+                               encodedAddend = (instruction & 0x03FFFFFF) << 2;
+                               if ( encodedAddend != 0 ) {
+                                       if ( prefixRelocAddend == 0 ) {
+                                               warning("branch26 instruction at 0x%08X has embedded addend. ARM64_RELOC_ADDEND should be used instead", reloc->r_address());
+                                               target.addend = encodedAddend;
+                                       }
+                                       else {
+                                               throwf("branch26 instruction at 0x%08X has embedded addend and ARM64_RELOC_ADDEND also used", reloc->r_address());
+                                       }
+                               }
+                               parser.addFixups(src, ld::Fixup::kindStoreARM64Branch26, target);
+                       }
+                       break;
+               case ARM64_RELOC_PAGE21:
+                       if ( ! reloc->r_pcrel() )
+                               throw "not pcrel and ARM64_RELOC_PAGE21 not supported";
+                       if ( ! reloc->r_extern() ) 
+                               throw "r_extern == 0 and ARM64_RELOC_PAGE21 not supported";
+                       if ( reloc->r_length() != 2 ) 
+                               throw "length != 2 and ARM64_RELOC_PAGE21 not supported";
+                       target.addend = prefixRelocAddend;
+                       instruction = contentValue;
+                       encodedAddend  = ((instruction & 0x60000000) >> 29) | ((instruction & 0x01FFFFE0) >> 3);
+                       encodedAddend *= 4096; // internally addend is in bytes, so scale
+                       if ( encodedAddend != 0 ) {
+                               if ( prefixRelocAddend == 0 ) {
+                                       warning("adrp instruction at 0x%08X has embedded addend. ARM64_RELOC_ADDEND should be used instead", reloc->r_address());
+                                       target.addend = encodedAddend;
+                               }
+                               else {
+                                       throwf("adrp instruction at 0x%08X has embedded addend and ARM64_RELOC_ADDEND also used", reloc->r_address());
+                               }
+                       }
+                       parser.addFixups(src, ld::Fixup::kindStoreARM64Page21, target);
+                       break;
+               case ARM64_RELOC_PAGEOFF12:
+                       if ( reloc->r_pcrel() )
+                               throw "pcrel and ARM64_RELOC_PAGEOFF12 not supported";
+                       if ( ! reloc->r_extern() ) 
+                               throw "r_extern == 0 and ARM64_RELOC_PAGEOFF12 not supported";
+                       if ( reloc->r_length() != 2 ) 
+                               throw "length != 2 and ARM64_RELOC_PAGEOFF12 not supported";
+                       target.addend = prefixRelocAddend;
+                       instruction = contentValue;
+                       encodedAddend = ((instruction & 0x003FFC00) >> 10);
+            // internally addend is in bytes.  Some instructions have an implicit scale factor
+            if ( (instruction & 0x3B000000) == 0x39000000 ) {
+                switch ( instruction & 0xC0000000 ) {
+                    case 0x00000000:
+                        break;
+                    case 0x40000000:
+                        encodedAddend *= 2;
+                        break;
+                    case 0x80000000:
+                        encodedAddend *= 4;
+                        break;
+                    case 0xC0000000:
+                        encodedAddend *= 8;
+                        break;
+                               }
+            }
+                       if ( encodedAddend != 0 ) {
+                               if ( prefixRelocAddend == 0 ) {
+                                       warning("pageoff12 instruction at 0x%08X has embedded addend. ARM64_RELOC_ADDEND should be used instead", reloc->r_address());
+                                       target.addend = encodedAddend;
+                               }
+                               else {  
+                                       throwf("pageoff12 instruction at 0x%08X has embedded addend and ARM64_RELOC_ADDEND also used", reloc->r_address());
+                               }
+                       }
+                       parser.addFixups(src, ld::Fixup::kindStoreARM64PageOff12, target);
+                       break;
+               case ARM64_RELOC_GOT_LOAD_PAGE21:
+                       if ( ! reloc->r_pcrel() )
+                               throw "not pcrel and ARM64_RELOC_GOT_LOAD_PAGE21 not supported";
+                       if ( ! reloc->r_extern() ) 
+                               throw "r_extern == 0 and ARM64_RELOC_GOT_LOAD_PAGE21 not supported";
+                       if ( reloc->r_length() != 2 ) 
+                               throw "length != 2 and ARM64_RELOC_GOT_LOAD_PAGE21 not supported";
+                       if ( prefixRelocAddend != 0 )
+                               throw "ARM64_RELOC_ADDEND followed by ARM64_RELOC_GOT_LOAD_PAGE21 not supported";
+                       instruction = contentValue;
+                       target.addend = ((instruction & 0x60000000) >> 29) | ((instruction & 0x01FFFFE0) >> 3);
+            if ( target.addend != 0 )
+                throw "non-zero addend with ARM64_RELOC_GOT_LOAD_PAGE21 is not supported";
+                       parser.addFixups(src, ld::Fixup::kindStoreARM64GOTLoadPage21, target);
+                       break;
+               case ARM64_RELOC_GOT_LOAD_PAGEOFF12:
+                       if ( reloc->r_pcrel() )
+                               throw "pcrel and ARM64_RELOC_GOT_LOAD_PAGEOFF12 not supported";
+                       if ( ! reloc->r_extern() ) 
+                               throw "r_extern == 0 and ARM64_RELOC_GOT_LOAD_PAGEOFF12 not supported";
+                       if ( reloc->r_length() != 2 ) 
+                               throw "length != 2 and ARM64_RELOC_GOT_LOAD_PAGEOFF12 not supported";
+                       if ( prefixRelocAddend != 0 )
+                               throw "ARM64_RELOC_ADDEND followed by ARM64_RELOC_GOT_LOAD_PAGEOFF12 not supported";
+                       instruction = contentValue;
+                       target.addend = ((instruction & 0x003FFC00) >> 10);
+                       parser.addFixups(src, ld::Fixup::kindStoreARM64GOTLoadPageOff12, target);
+                       break;
+               case ARM64_RELOC_TLVP_LOAD_PAGE21:
+                       if ( ! reloc->r_pcrel() )
+                               throw "not pcrel and ARM64_RELOC_TLVP_LOAD_PAGE21 not supported";
+                       if ( ! reloc->r_extern() ) 
+                               throw "r_extern == 0 and ARM64_RELOC_TLVP_LOAD_PAGE21 not supported";
+                       if ( reloc->r_length() != 2 ) 
+                               throw "length != 2 and ARM64_RELOC_TLVP_LOAD_PAGE21 not supported";
+                       if ( prefixRelocAddend != 0 )
+                               throw "ARM64_RELOC_ADDEND followed by ARM64_RELOC_TLVP_LOAD_PAGE21 not supported";
+                       instruction = contentValue;
+                       target.addend = ((instruction & 0x60000000) >> 29) | ((instruction & 0x01FFFFE0) >> 3);
+            if ( target.addend != 0 )
+                throw "non-zero addend with ARM64_RELOC_GOT_LOAD_PAGE21 is not supported";
+                       parser.addFixups(src, ld::Fixup::kindStoreARM64TLVPLoadPage21, target);
+                       break;
+               case ARM64_RELOC_TLVP_LOAD_PAGEOFF12:
+                       if ( reloc->r_pcrel() )
+                               throw "pcrel and ARM64_RELOC_TLVP_LOAD_PAGEOFF12 not supported";
+                       if ( ! reloc->r_extern() ) 
+                               throw "r_extern == 0 and ARM64_RELOC_TLVP_LOAD_PAGEOFF12 not supported";
+                       if ( reloc->r_length() != 2 ) 
+                               throw "length != 2 and ARM64_RELOC_TLVP_LOAD_PAGEOFF12 not supported";
+                       if ( prefixRelocAddend != 0 )
+                               throw "ARM64_RELOC_ADDEND followed by ARM64_RELOC_TLVP_LOAD_PAGEOFF12 not supported";
+                       instruction = contentValue;
+                       target.addend = ((instruction & 0x003FFC00) >> 10);
+                       parser.addFixups(src, ld::Fixup::kindStoreARM64TLVPLoadPageOff12, target);
+                       break;
+               case ARM64_RELOC_SUBTRACTOR:
+                       if ( reloc->r_pcrel() )
+                               throw "ARM64_RELOC_SUBTRACTOR cannot be pc-relative";
+                       if ( reloc->r_length() < 2 )
+                               throw "ARM64_RELOC_SUBTRACTOR must have r_length of 2 or 3";
+                       if ( !reloc->r_extern() )
+                               throw "ARM64_RELOC_SUBTRACTOR must have r_extern=1";
+                       if ( nextReloc->r_type() != ARM64_RELOC_UNSIGNED )
+                               throw "ARM64_RELOC_SUBTRACTOR must be followed by ARM64_RELOC_UNSIGNED";
+                       if ( prefixRelocAddend != 0 )
+                               throw "ARM64_RELOC_ADDEND followed by ARM64_RELOC_SUBTRACTOR not supported";
+                       result = true;
+                       if ( nextReloc->r_pcrel() )
+                               throw "ARM64_RELOC_UNSIGNED following a ARM64_RELOC_SUBTRACTOR cannot be pc-relative";
+                       if ( nextReloc->r_length() != reloc->r_length() )
+                               throw "ARM64_RELOC_UNSIGNED following a ARM64_RELOC_SUBTRACTOR must have same r_length";
+                       if ( nextReloc->r_extern() ) {
+                               const macho_nlist<P>& sym = parser.symbolFromIndex(nextReloc->r_symbolnum());
+                               // use direct reference for local symbols
+                               if ( ((sym.n_type() & N_TYPE) == N_SECT) && (((sym.n_type() & N_EXT) == 0) || (parser.nameFromSymbol(sym)[0] == 'L')) ) {
+                                       parser.findTargetFromAddressAndSectionNum(sym.n_value(), sym.n_sect(), toTarget);
+                                       toTarget.addend = contentValue;
+                                       useDirectBinding = true;
+                               }
+                               else {
+                                       toTarget.name = parser.nameFromSymbol(sym);
+                                       toTarget.weakImport = parser.weakImportFromSymbol(sym);
+                                       toTarget.addend = contentValue;
+                                       useDirectBinding = false;
+                               }
+                       }
+                       else {
+                               parser.findTargetFromAddressAndSectionNum(contentValue, nextReloc->r_symbolnum(), toTarget);
+                               useDirectBinding = (toTarget.atom->scope() == ld::Atom::scopeTranslationUnit);
+                       }
+                       if ( useDirectBinding )
+                               parser.addFixup(src, ld::Fixup::k1of4, ld::Fixup::kindSetTargetAddress, toTarget.atom);
+                       else
+                               parser.addFixup(src, ld::Fixup::k1of4, ld::Fixup::kindSetTargetAddress, toTarget.weakImport, toTarget.name);
+                       parser.addFixup(src, ld::Fixup::k2of4, ld::Fixup::kindAddAddend, toTarget.addend);
+                       if ( target.atom == NULL )
+                               parser.addFixup(src, ld::Fixup::k3of4, ld::Fixup::kindSubtractTargetAddress, false, target.name);
+                       else
+                               parser.addFixup(src, ld::Fixup::k3of4, ld::Fixup::kindSubtractTargetAddress, target.atom);
+                       if ( reloc->r_length() == 2 )
+                               parser.addFixup(src, ld::Fixup::k4of4, ld::Fixup::kindStoreLittleEndian32);
+                       else
+                               parser.addFixup(src, ld::Fixup::k4of4, ld::Fixup::kindStoreLittleEndian64);
+                       break;
+        case ARM64_RELOC_POINTER_TO_GOT:
+                       if ( ! reloc->r_extern() ) 
+                               throw "r_extern == 0 and ARM64_RELOC_POINTER_TO_GOT not supported";
+                       if ( prefixRelocAddend != 0 )
+                               throw "ARM64_RELOC_ADDEND followed by ARM64_RELOC_POINTER_TO_GOT not supported";
+                       if ( reloc->r_pcrel() ) {
+                if ( reloc->r_length() != 2 ) 
+                    throw "r_length != 2 and r_extern = 1 and ARM64_RELOC_POINTER_TO_GOT not supported";
+                parser.addFixups(src, ld::Fixup::kindStoreARM64PCRelToGOT, target);
+            }
+            else {
+                if ( reloc->r_length() != 3 ) 
+                    throw "r_length != 3 and r_extern = 0 and ARM64_RELOC_POINTER_TO_GOT not supported";
+                parser.addFixups(src, ld::Fixup::kindStoreARM64PointerToGOT, target);
+            }
+            break;
+               default:
+                       throwf("unknown relocation type %d", reloc->r_type());
+       }
+       return result;
+}
+#endif
 
 template <typename A>
 bool ObjC1ClassSection<A>::addRelocFixup(class Parser<A>& parser, const macho_relocation_info<P>* reloc)
 
 template <typename A>
 bool ObjC1ClassSection<A>::addRelocFixup(class Parser<A>& parser, const macho_relocation_info<P>* reloc)
@@ -6302,6 +6970,12 @@ ld::relocatable::File* parse(const uint8_t* fileContent, uint64_t fileLength,
                        if ( mach_o::relocatable::Parser<arm>::validFile(fileContent, opts.objSubtypeMustMatch, opts.subType) )
                                return mach_o::relocatable::Parser<arm>::parse(fileContent, fileLength, path, modTime, ordinal, opts);
                        break;
                        if ( mach_o::relocatable::Parser<arm>::validFile(fileContent, opts.objSubtypeMustMatch, opts.subType) )
                                return mach_o::relocatable::Parser<arm>::parse(fileContent, fileLength, path, modTime, ordinal, opts);
                        break;
+#endif
+#if SUPPORT_ARCH_arm64
+               case CPU_TYPE_ARM64:
+                       if ( mach_o::relocatable::Parser<arm64>::validFile(fileContent, opts.objSubtypeMustMatch, opts.subType) )
+                               return mach_o::relocatable::Parser<arm64>::parse(fileContent, fileLength, path, modTime, ordinal, opts);
+                       break;
 #endif
        }
        return NULL;
 #endif
        }
        return NULL;
@@ -6319,6 +6993,8 @@ bool isObjectFile(const uint8_t* fileContent, uint64_t fileLength, const ParserO
                        return ( mach_o::relocatable::Parser<x86>::validFile(fileContent) );
                case CPU_TYPE_ARM:
                        return ( mach_o::relocatable::Parser<arm>::validFile(fileContent, opts.objSubtypeMustMatch, opts.subType) );
                        return ( mach_o::relocatable::Parser<x86>::validFile(fileContent) );
                case CPU_TYPE_ARM:
                        return ( mach_o::relocatable::Parser<arm>::validFile(fileContent, opts.objSubtypeMustMatch, opts.subType) );
+               case CPU_TYPE_ARM64:
+                       return ( mach_o::relocatable::Parser<arm64>::validFile(fileContent, opts.objSubtypeMustMatch, opts.subType) );
        }
        return false;
 }
        }
        return false;
 }
@@ -6344,6 +7020,11 @@ bool isObjectFile(const uint8_t* fileContent, cpu_type_t* result, cpu_subtype_t*
                *subResult = header->cpusubtype();
                return true;
        }
                *subResult = header->cpusubtype();
                return true;
        }
+       if ( mach_o::relocatable::Parser<arm64>::validFile(fileContent, false, 0) ) {
+               *result = CPU_TYPE_ARM64;
+               *subResult = CPU_SUBTYPE_ARM64_ALL;
+               return true;
+       }
        return false;
 }                                      
 
        return false;
 }                                      
 
@@ -6378,6 +7059,11 @@ bool hasObjC2Categories(const uint8_t* fileContent)
        else if ( mach_o::relocatable::Parser<x86>::validFile(fileContent, false, 0) ) {
                return mach_o::relocatable::Parser<x86>::hasObjC2Categories(fileContent);
        }
        else if ( mach_o::relocatable::Parser<x86>::validFile(fileContent, false, 0) ) {
                return mach_o::relocatable::Parser<x86>::hasObjC2Categories(fileContent);
        }
+#if SUPPORT_ARCH_arm64
+    else if ( mach_o::relocatable::Parser<arm64>::validFile(fileContent, false, 0) ) {
+        return mach_o::relocatable::Parser<arm64>::hasObjC2Categories(fileContent);
+    }
+#endif
        return false;
 }                              
 
        return false;
 }                              
 
index 021c3f2ff6f77340d4e2db133ce5a6e6cf64444e..a576f527afcb87e862f60887a8d5f5e86b747ae4 100644 (file)
@@ -35,7 +35,9 @@ struct ParserOptions {
        uint32_t                architecture;
        bool                    objSubtypeMustMatch;
        bool                    logAllFiles;
        uint32_t                architecture;
        bool                    objSubtypeMustMatch;
        bool                    logAllFiles;
-       bool                    convertUnwindInfo;
+       bool                    warnUnwindConversionProblems;
+       bool                    keepDwarfUnwind;
+       bool                    forceDwarfConversion;
        uint32_t                subType;
 };
 
        uint32_t                subType;
 };
 
index f86aee003662208d95a7c411ac4bb7bccabcb690..8b4a6bf190794a665fb991955e35fc6e8a6c40c3 100644 (file)
@@ -156,7 +156,6 @@ UnwindInfoAtom<A>::UnwindInfoAtom(const std::vector<UnwindEntry>& entries, uint6
        std::vector<LSDAEntry>  lsdaIndex;
        makeLsdaIndex(uniqueEntries, lsdaIndex, lsdaIndexOffsetMap);
        
        std::vector<LSDAEntry>  lsdaIndex;
        makeLsdaIndex(uniqueEntries, lsdaIndex, lsdaIndexOffsetMap);
        
-       
        // calculate worst case size for all unwind info pages when allocating buffer
        const unsigned int entriesPerRegularPage = (4096-sizeof(unwind_info_regular_second_level_page_header))/sizeof(unwind_info_regular_second_level_entry);
        assert(uniqueEntries.size() > 0);
        // calculate worst case size for all unwind info pages when allocating buffer
        const unsigned int entriesPerRegularPage = (4096-sizeof(unwind_info_regular_second_level_page_header))/sizeof(unwind_info_regular_second_level_entry);
        assert(uniqueEntries.size() > 0);
@@ -294,6 +293,12 @@ bool UnwindInfoAtom<x86_64>::encodingMeansUseDwarf(compact_unwind_encoding_t enc
        return ((enc & UNWIND_X86_64_MODE_MASK) == UNWIND_X86_64_MODE_DWARF);
 }
 
        return ((enc & UNWIND_X86_64_MODE_MASK) == UNWIND_X86_64_MODE_DWARF);
 }
 
+template <>
+bool UnwindInfoAtom<arm64>::encodingMeansUseDwarf(compact_unwind_encoding_t enc)
+{
+       return ((enc & UNWIND_ARM64_MODE_MASK) == UNWIND_ARM64_MODE_DWARF);
+}
+
 template <typename A>
 void UnwindInfoAtom<A>::compressDuplicates(const std::vector<UnwindEntry>& entries, std::vector<UnwindEntry>& uniqueEntries)
 {
 template <typename A>
 void UnwindInfoAtom<A>::compressDuplicates(const std::vector<UnwindEntry>& entries, std::vector<UnwindEntry>& uniqueEntries)
 {
@@ -400,6 +405,14 @@ void UnwindInfoAtom<x86_64>::addCompressedAddressOffsetFixup(uint32_t offset, co
        _fixups.push_back(ld::Fixup(offset, ld::Fixup::k3of3, ld::Fixup::kindStoreLittleEndianLow24of32));
 }
 
        _fixups.push_back(ld::Fixup(offset, ld::Fixup::k3of3, ld::Fixup::kindStoreLittleEndianLow24of32));
 }
 
+template <>
+void UnwindInfoAtom<arm64>::addCompressedAddressOffsetFixup(uint32_t offset, const ld::Atom* func, const ld::Atom* fromFunc)
+{
+       _fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of3, ld::Fixup::kindSetTargetAddress, func));
+       _fixups.push_back(ld::Fixup(offset, ld::Fixup::k2of3, ld::Fixup::kindSubtractTargetAddress, fromFunc));
+       _fixups.push_back(ld::Fixup(offset, ld::Fixup::k3of3, ld::Fixup::kindStoreLittleEndianLow24of32));
+}
+
 template <>
 void UnwindInfoAtom<x86>::addCompressedEncodingFixup(uint32_t offset, const ld::Atom* fde)
 {
 template <>
 void UnwindInfoAtom<x86>::addCompressedEncodingFixup(uint32_t offset, const ld::Atom* fde)
 {
@@ -414,6 +427,12 @@ void UnwindInfoAtom<x86_64>::addCompressedEncodingFixup(uint32_t offset, const l
        _fixups.push_back(ld::Fixup(offset, ld::Fixup::k2of2, ld::Fixup::kindStoreLittleEndianLow24of32));
 }
 
        _fixups.push_back(ld::Fixup(offset, ld::Fixup::k2of2, ld::Fixup::kindStoreLittleEndianLow24of32));
 }
 
+template <>
+void UnwindInfoAtom<arm64>::addCompressedEncodingFixup(uint32_t offset, const ld::Atom* fde)
+{
+       _fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of2, ld::Fixup::kindSetTargetSectionOffset, fde));
+       _fixups.push_back(ld::Fixup(offset, ld::Fixup::k2of2, ld::Fixup::kindStoreLittleEndianLow24of32));
+}
 
 template <>
 void UnwindInfoAtom<x86>::addRegularAddressFixup(uint32_t offset, const ld::Atom* func)
 
 template <>
 void UnwindInfoAtom<x86>::addRegularAddressFixup(uint32_t offset, const ld::Atom* func)
@@ -429,6 +448,13 @@ void UnwindInfoAtom<x86_64>::addRegularAddressFixup(uint32_t offset, const ld::A
        _fixups.push_back(ld::Fixup(offset, ld::Fixup::k2of2, ld::Fixup::kindStoreLittleEndian32));
 }
 
        _fixups.push_back(ld::Fixup(offset, ld::Fixup::k2of2, ld::Fixup::kindStoreLittleEndian32));
 }
 
+template <>
+void UnwindInfoAtom<arm64>::addRegularAddressFixup(uint32_t offset, const ld::Atom* func)
+{
+       _fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of2, ld::Fixup::kindSetTargetImageOffset, func));
+       _fixups.push_back(ld::Fixup(offset, ld::Fixup::k2of2, ld::Fixup::kindStoreLittleEndian32));
+}
+
 template <>
 void UnwindInfoAtom<x86>::addRegularFDEOffsetFixup(uint32_t offset, const ld::Atom* fde)
 {
 template <>
 void UnwindInfoAtom<x86>::addRegularFDEOffsetFixup(uint32_t offset, const ld::Atom* fde)
 {
@@ -443,6 +469,13 @@ void UnwindInfoAtom<x86_64>::addRegularFDEOffsetFixup(uint32_t offset, const ld:
        _fixups.push_back(ld::Fixup(offset+4, ld::Fixup::k2of2, ld::Fixup::kindStoreLittleEndianLow24of32));
 }
 
        _fixups.push_back(ld::Fixup(offset+4, ld::Fixup::k2of2, ld::Fixup::kindStoreLittleEndianLow24of32));
 }
 
+template <>
+void UnwindInfoAtom<arm64>::addRegularFDEOffsetFixup(uint32_t offset, const ld::Atom* fde)
+{
+       _fixups.push_back(ld::Fixup(offset+4, ld::Fixup::k1of2, ld::Fixup::kindSetTargetSectionOffset, fde));
+       _fixups.push_back(ld::Fixup(offset+4, ld::Fixup::k2of2, ld::Fixup::kindStoreLittleEndianLow24of32));
+}
+
 template <>
 void UnwindInfoAtom<x86>::addImageOffsetFixup(uint32_t offset, const ld::Atom* targ)
 {
 template <>
 void UnwindInfoAtom<x86>::addImageOffsetFixup(uint32_t offset, const ld::Atom* targ)
 {
@@ -457,6 +490,13 @@ void UnwindInfoAtom<x86_64>::addImageOffsetFixup(uint32_t offset, const ld::Atom
        _fixups.push_back(ld::Fixup(offset, ld::Fixup::k2of2, ld::Fixup::kindStoreLittleEndian32));
 }
 
        _fixups.push_back(ld::Fixup(offset, ld::Fixup::k2of2, ld::Fixup::kindStoreLittleEndian32));
 }
 
+template <>
+void UnwindInfoAtom<arm64>::addImageOffsetFixup(uint32_t offset, const ld::Atom* targ)
+{
+       _fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of2, ld::Fixup::kindSetTargetImageOffset, targ));
+       _fixups.push_back(ld::Fixup(offset, ld::Fixup::k2of2, ld::Fixup::kindStoreLittleEndian32));
+}
+
 template <>
 void UnwindInfoAtom<x86>::addImageOffsetFixupPlusAddend(uint32_t offset, const ld::Atom* targ, uint32_t addend)
 {
 template <>
 void UnwindInfoAtom<x86>::addImageOffsetFixupPlusAddend(uint32_t offset, const ld::Atom* targ, uint32_t addend)
 {
@@ -473,6 +513,13 @@ void UnwindInfoAtom<x86_64>::addImageOffsetFixupPlusAddend(uint32_t offset, cons
        _fixups.push_back(ld::Fixup(offset, ld::Fixup::k3of3, ld::Fixup::kindStoreLittleEndian32));
 }
 
        _fixups.push_back(ld::Fixup(offset, ld::Fixup::k3of3, ld::Fixup::kindStoreLittleEndian32));
 }
 
+template <>
+void UnwindInfoAtom<arm64>::addImageOffsetFixupPlusAddend(uint32_t offset, const ld::Atom* targ, uint32_t addend)
+{
+       _fixups.push_back(ld::Fixup(offset, ld::Fixup::k1of3, ld::Fixup::kindSetTargetImageOffset, targ));
+       _fixups.push_back(ld::Fixup(offset, ld::Fixup::k2of3, ld::Fixup::kindAddAddend, addend));
+       _fixups.push_back(ld::Fixup(offset, ld::Fixup::k3of3, ld::Fixup::kindStoreLittleEndian32));
+}
 
 
 
 
 
 
@@ -552,6 +599,7 @@ unsigned int UnwindInfoAtom<A>::makeCompressedSecondLevelPage(const std::vector<
                                encodingIndex = commonEncodings.size() + pageSpecificEncodings.size();
                                if ( encodingIndex <= 255 ) {
                                        pageSpecificEncodings[encoding] = encodingIndex;
                                encodingIndex = commonEncodings.size() + pageSpecificEncodings.size();
                                if ( encodingIndex <= 255 ) {
                                        pageSpecificEncodings[encoding] = encodingIndex;
+                                       if (_s_log) fprintf(stderr, "makeCompressedSecondLevelPage(): pageSpecificEncodings[%d]=0x%08X\n", encodingIndex, encoding); 
                                }
                                else {
                                        canDo = false; // case 3)
                                }
                                else {
                                        canDo = false; // case 3)
@@ -685,7 +733,7 @@ static void getAllUnwindInfos(const ld::Internal& state, std::vector<UnwindEntry
 
                        if ( atom->beginUnwind() == atom->endUnwind() ) {
                                // be sure to mark that we have no unwind info for stuff in the TEXT segment without unwind info
 
                        if ( atom->beginUnwind() == atom->endUnwind() ) {
                                // be sure to mark that we have no unwind info for stuff in the TEXT segment without unwind info
-                               if ( atom->section().type() == ld::Section::typeCode ) {
+                               if ( (atom->section().type() == ld::Section::typeCode) && (atom->size() !=0) ) {
                                        entries.push_back(UnwindEntry(atom, address, 0, NULL, NULL, NULL, 0));
                                }
                        }
                                        entries.push_back(UnwindEntry(atom, address, 0, NULL, NULL, NULL, 0));
                                }
                        }
@@ -781,6 +829,11 @@ static void makeFinalLinkedImageCompactUnwindSection(const Options& opts, ld::In
                case CPU_TYPE_I386:
                        state.addAtom(*new UnwindInfoAtom<x86>(entries, ehFrameSize));
                        break;
                case CPU_TYPE_I386:
                        state.addAtom(*new UnwindInfoAtom<x86>(entries, ehFrameSize));
                        break;
+#endif
+#if SUPPORT_ARCH_arm64
+               case CPU_TYPE_ARM64:
+                       state.addAtom(*new UnwindInfoAtom<arm64>(entries, ehFrameSize));
+                       break;
 #endif
                default:
                        assert(0 && "no compact unwind for arch");
 #endif
                default:
                        assert(0 && "no compact unwind for arch");
@@ -830,13 +883,17 @@ template <> ld::Fixup::Kind CompactUnwindAtom<x86>::_s_pointerKind = ld::Fixup::
 template <> ld::Fixup::Kind CompactUnwindAtom<x86>::_s_pointerStoreKind = ld::Fixup::kindStoreTargetAddressLittleEndian32;
 template <> ld::Fixup::Kind CompactUnwindAtom<x86_64>::_s_pointerKind = ld::Fixup::kindStoreLittleEndian64;
 template <> ld::Fixup::Kind CompactUnwindAtom<x86_64>::_s_pointerStoreKind = ld::Fixup::kindStoreTargetAddressLittleEndian64;
 template <> ld::Fixup::Kind CompactUnwindAtom<x86>::_s_pointerStoreKind = ld::Fixup::kindStoreTargetAddressLittleEndian32;
 template <> ld::Fixup::Kind CompactUnwindAtom<x86_64>::_s_pointerKind = ld::Fixup::kindStoreLittleEndian64;
 template <> ld::Fixup::Kind CompactUnwindAtom<x86_64>::_s_pointerStoreKind = ld::Fixup::kindStoreTargetAddressLittleEndian64;
+#if SUPPORT_ARCH_arm64
+template <> ld::Fixup::Kind CompactUnwindAtom<arm64>::_s_pointerKind = ld::Fixup::kindStoreLittleEndian64;
+template <> ld::Fixup::Kind CompactUnwindAtom<arm64>::_s_pointerStoreKind = ld::Fixup::kindStoreTargetAddressLittleEndian64;
+#endif
 
 template <typename A>
 CompactUnwindAtom<A>::CompactUnwindAtom(ld::Internal& state,const ld::Atom* funcAtom, uint32_t startOffset,
                                                                                uint32_t len, uint32_t cui)
        : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
                                ld::Atom::scopeTranslationUnit, ld::Atom::typeUnclassified, 
 
 template <typename A>
 CompactUnwindAtom<A>::CompactUnwindAtom(ld::Internal& state,const ld::Atom* funcAtom, uint32_t startOffset,
                                                                                uint32_t len, uint32_t cui)
        : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
                                ld::Atom::scopeTranslationUnit, ld::Atom::typeUnclassified, 
-                               symbolTableNotIn, false, false, false, ld::Atom::Alignment(0)),
+                               symbolTableNotIn, false, false, false, ld::Atom::Alignment(log2(sizeof(pint_t)))),
        _atom(funcAtom), _startOffset(startOffset), _len(len), _compactUnwindInfo(cui)
 {
        _fixups.push_back(ld::Fixup(macho_compact_unwind_entry<P>::codeStartFieldOffset(), ld::Fixup::k1of3, ld::Fixup::kindSetTargetAddress, funcAtom));
        _atom(funcAtom), _startOffset(startOffset), _len(len), _compactUnwindInfo(cui)
 {
        _fixups.push_back(ld::Fixup(macho_compact_unwind_entry<P>::codeStartFieldOffset(), ld::Fixup::k1of3, ld::Fixup::kindSetTargetAddress, funcAtom));
@@ -885,6 +942,11 @@ static void makeCompactUnwindAtom(const Options& opts, ld::Internal& state, cons
                case CPU_TYPE_I386:
                        state.addAtom(*new CompactUnwindAtom<x86>(state, atom, startOffset, endOffset-startOffset, cui));
                        break;
                case CPU_TYPE_I386:
                        state.addAtom(*new CompactUnwindAtom<x86>(state, atom, startOffset, endOffset-startOffset, cui));
                        break;
+#endif
+#if SUPPORT_ARCH_arm64
+               case CPU_TYPE_ARM64:
+                       state.addAtom(*new CompactUnwindAtom<arm64>(state, atom, startOffset, endOffset-startOffset, cui));
+                       break;
 #endif
        }
 }
 #endif
        }
 }
index 74328ffbe81275ec924550930d4e137b8abcff38..6f8a5440a174f5ba3be496fae74e8c54d7b7ed50 100644 (file)
@@ -34,6 +34,7 @@
 #include <unordered_set>
 
 #include "ld.hpp"
 #include <unordered_set>
 
 #include "ld.hpp"
+#include "MachOFileAbstraction.hpp"
 #include "dtrace_dof.h"
 
 // prototype for entry point in libdtrace.dylib
 #include "dtrace_dof.h"
 
 // prototype for entry point in libdtrace.dylib
@@ -122,6 +123,10 @@ void doPass(const Options& opts, ld::Internal& internal)
        // only make __dof section in final linked images
        if ( opts.outputKind() == Options::kObjectFile )
                return;
        // only make __dof section in final linked images
        if ( opts.outputKind() == Options::kObjectFile )
                return;
+       
+       // skip making __dof section if command line option said not to
+       if ( ! opts.generateDtraceDOF() )
+               return;
 
        // scan all atoms looking for dtrace probes
        std::vector<DTraceProbeInfo>                                    probeSites;
 
        // scan all atoms looking for dtrace probes
        std::vector<DTraceProbeInfo>                                    probeSites;
@@ -138,11 +143,13 @@ void doPass(const Options& opts, ld::Internal& internal)
                                        case ld::Fixup::kindStoreX86DtraceCallSiteNop:
                                        case ld::Fixup::kindStoreARMDtraceCallSiteNop:
                                        case ld::Fixup::kindStoreThumbDtraceCallSiteNop:
                                        case ld::Fixup::kindStoreX86DtraceCallSiteNop:
                                        case ld::Fixup::kindStoreARMDtraceCallSiteNop:
                                        case ld::Fixup::kindStoreThumbDtraceCallSiteNop:
+                                       case ld::Fixup::kindStoreARM64DtraceCallSiteNop:
                                                probeSites.push_back(DTraceProbeInfo(atom, fit->offsetInAtom, fit->u.name));
                                                break;
                                        case ld::Fixup::kindStoreX86DtraceIsEnableSiteClear:
                                        case ld::Fixup::kindStoreARMDtraceIsEnableSiteClear:
                                        case ld::Fixup::kindStoreThumbDtraceIsEnableSiteClear:
                                                probeSites.push_back(DTraceProbeInfo(atom, fit->offsetInAtom, fit->u.name));
                                                break;
                                        case ld::Fixup::kindStoreX86DtraceIsEnableSiteClear:
                                        case ld::Fixup::kindStoreARMDtraceIsEnableSiteClear:
                                        case ld::Fixup::kindStoreThumbDtraceIsEnableSiteClear:
+                                       case ld::Fixup::kindStoreARM64DtraceIsEnableSiteClear:
                                                isEnabledSites.push_back(DTraceProbeInfo(atom, fit->offsetInAtom, fit->u.name));
                                                break;
                                        case ld::Fixup::kindDtraceExtra:
                                                isEnabledSites.push_back(DTraceProbeInfo(atom, fit->offsetInAtom, fit->u.name));
                                                break;
                                        case ld::Fixup::kindDtraceExtra:
@@ -164,6 +171,7 @@ void doPass(const Options& opts, ld::Internal& internal)
                case CPU_TYPE_I386:
                case CPU_TYPE_X86_64:
                case CPU_TYPE_ARM:
                case CPU_TYPE_I386:
                case CPU_TYPE_X86_64:
                case CPU_TYPE_ARM:
+               case CPU_TYPE_ARM64:
                        storeKind = ld::Fixup::kindStoreLittleEndian32;
                        break;
                default:
                        storeKind = ld::Fixup::kindStoreLittleEndian32;
                        break;
                default:
index 3e6824f415af25663e82735d6046dd108c2a7427..2b9da3a9816b99b68bc388d78155f20eddc951c2 100644 (file)
 #include <vector>
 #include <map>
 
 #include <vector>
 #include <map>
 
+#include "MachOFileAbstraction.hpp"
 #include "ld.hpp"
 #include "got.h"
 #include "ld.hpp"
 #include "got.h"
+#include "configure.h"
 
 namespace ld {
 namespace passes {
 
 namespace ld {
 namespace passes {
@@ -42,17 +44,18 @@ class File; // forward reference
 
 class GOTEntryAtom : public ld::Atom {
 public:
 
 class GOTEntryAtom : public ld::Atom {
 public:
-                                                                                       GOTEntryAtom(ld::Internal& internal, const ld::Atom* target, bool weakImport)
+                                                                                       GOTEntryAtom(ld::Internal& internal, const ld::Atom* target, bool weakImport, bool is64)
                                : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
                                                        ld::Atom::scopeLinkageUnit, ld::Atom::typeNonLazyPointer, 
                                : 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, target),
-                               _target(target)
+                                                       symbolTableNotIn, false, false, false, (is64 ? ld::Atom::Alignment(3) : ld::Atom::Alignment(2))),
+                               _fixup(0, ld::Fixup::k1of1, (is64 ? ld::Fixup::kindStoreTargetAddressLittleEndian64 : ld::Fixup::kindStoreTargetAddressLittleEndian32), target),
+                               _target(target),
+                               _is64(is64)
                                        { _fixup.weakImport = weakImport; internal.addAtom(*this); }
 
        virtual const ld::File*                                 file() const                                    { return NULL; }
        virtual const char*                                             name() const                                    { return _target->name(); }
                                        { _fixup.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                                                size() const                                    { return (_is64 ? 8 : 4); }
        virtual uint64_t                                                objectAddress() const                   { return 0; }
        virtual void                                                    copyRawContent(uint8_t buffer[]) const { }
        virtual void                                                    setScope(Scope)                                 { }
        virtual uint64_t                                                objectAddress() const                   { return 0; }
        virtual void                                                    copyRawContent(uint8_t buffer[]) const { }
        virtual void                                                    setScope(Scope)                                 { }
@@ -62,6 +65,7 @@ public:
 private:
        mutable ld::Fixup                                               _fixup;
        const ld::Atom*                                                 _target;
 private:
        mutable ld::Fixup                                               _fixup;
        const ld::Atom*                                                 _target;
+       bool                                                                    _is64;
        
        static ld::Section                                              _s_section;
 };
        
        static ld::Section                                              _s_section;
 };
@@ -73,6 +77,10 @@ static bool gotFixup(const Options& opts, ld::Internal& internal, const ld::Atom
 {
        switch (fixup->kind) {
                case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoad:
 {
        switch (fixup->kind) {
                case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoad:
+#if SUPPORT_ARCH_arm64
+               case ld::Fixup::kindStoreTargetAddressARM64GOTLoadPage21:
+               case ld::Fixup::kindStoreTargetAddressARM64GOTLoadPageOff12:
+#endif
                        // start by assuming this can be optimized
                        *optimizable = true;
                        // cannot do LEA optimization if target is in another dylib
                        // start by assuming this can be optimized
                        *optimizable = true;
                        // cannot do LEA optimization if target is in another dylib
@@ -122,6 +130,9 @@ static bool gotFixup(const Options& opts, ld::Internal& internal, const ld::Atom
                        }
                        return true;
                case ld::Fixup::kindStoreX86PCRel32GOT:
                        }
                        return true;
                case ld::Fixup::kindStoreX86PCRel32GOT:
+#if SUPPORT_ARCH_arm64
+               case ld::Fixup::kindStoreARM64PCRelToGOT:
+#endif
                        *optimizable = false;
                        return true;
                case ld::Fixup::kindNoneGroupSubordinatePersonality:
                        *optimizable = false;
                        return true;
                case ld::Fixup::kindNoneGroupSubordinatePersonality:
@@ -189,7 +200,22 @@ void doPass(const Options& opts, ld::Internal& internal)
                                                case ld::Fixup::bindingDirectlyBound:
                                                        fit->binding = ld::Fixup::bindingDirectlyBound;
                                                        fit->u.target = targetOfGOT;
                                                case ld::Fixup::bindingDirectlyBound:
                                                        fit->binding = ld::Fixup::bindingDirectlyBound;
                                                        fit->u.target = targetOfGOT;
-                                                       fit->kind = ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoadNowLEA;
+                                                       switch ( fit->kind ) {
+                                                               case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoad:
+                                                                       fit->kind = ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoadNowLEA;
+                                                                       break;
+#if SUPPORT_ARCH_arm64
+                                                               case ld::Fixup::kindStoreTargetAddressARM64GOTLoadPage21:
+                                                                       fit->kind = ld::Fixup::kindStoreTargetAddressARM64GOTLeaPage21;
+                                                                       break;
+                                                               case ld::Fixup::kindStoreTargetAddressARM64GOTLoadPageOff12:
+                                                                       fit->kind = ld::Fixup::kindStoreTargetAddressARM64GOTLeaPageOff12;
+                                                                       break;
+#endif
+                                                               default:
+                                                                       assert(0 && "unsupported GOT reference kind");
+                                                                       break;
+                                                       }
                                                        break;
                                                default:
                                                        assert(0 && "unsupported GOT reference");
                                                        break;
                                                default:
                                                        assert(0 && "unsupported GOT reference");
@@ -232,9 +258,33 @@ void doPass(const Options& opts, ld::Internal& internal)
                }
        }
        
                }
        }
        
+       bool is64 = false;
+       switch ( opts.architecture() ) {
+#if SUPPORT_ARCH_i386
+               case CPU_TYPE_I386:
+                       is64 = false;
+                       break;
+#endif
+#if SUPPORT_ARCH_x86_64
+               case CPU_TYPE_X86_64:
+                       is64 = true;
+                       break;
+#endif
+#if SUPPORT_ARCH_arm_any
+               case CPU_TYPE_ARM: 
+                       is64 = false;
+                       break;
+#endif
+#if SUPPORT_ARCH_arm64
+               case CPU_TYPE_ARM64: 
+                       is64 = true;
+                       break;
+#endif
+       }
+       
        // make GOT entries     
        for (std::map<const ld::Atom*,ld::Atom*>::iterator it = gotMap.begin(); it != gotMap.end(); ++it) {
        // make GOT entries     
        for (std::map<const ld::Atom*,ld::Atom*>::iterator it = gotMap.begin(); it != gotMap.end(); ++it) {
-               it->second = new GOTEntryAtom(internal, it->first, weakImportMap[it->first]);
+               it->second = new GOTEntryAtom(internal, it->first, weakImportMap[it->first], is64);
        }
        
        // update atoms to use GOT entries
        }
        
        // update atoms to use GOT entries
index d471d98f9421204b79dd02eec2b02189263ccae9..d921a64fb515100d69668828fa22fc6c6b0721a6 100644 (file)
@@ -54,6 +54,7 @@ struct objc_image_info  {
 #define OBJC_IMAGE_REQUIRES_GC                 (1<<2)
 #define OBJC_IMAGE_OPTIMIZED_BY_DYLD   (1<<3)
 #define OBJC_IMAGE_SUPPORTS_COMPACTION (1<<4)
 #define OBJC_IMAGE_REQUIRES_GC                 (1<<2)
 #define OBJC_IMAGE_OPTIMIZED_BY_DYLD   (1<<3)
 #define OBJC_IMAGE_SUPPORTS_COMPACTION (1<<4)
+#define OBJC_IMAGE_IS_SIMULATED                        (1<<5)
 
 
 
 
 
 
@@ -111,6 +112,9 @@ ObjCImageInfoAtom<A>::ObjCImageInfoAtom(ld::File::ObjcConstraint objcConstraint,
                        if ( compaction ) 
                                value |= OBJC_IMAGE_SUPPORTS_COMPACTION;
                        break;
                        if ( compaction ) 
                                value |= OBJC_IMAGE_SUPPORTS_COMPACTION;
                        break;
+               case ld::File::objcConstraintRetainReleaseForSimulator:
+                               value |= OBJC_IMAGE_IS_SIMULATED;
+                       break;
        }
 
        _content.version = 0;
        }
 
        _content.version = 0;
@@ -1176,10 +1180,18 @@ void doPass(const Options& opts, ld::Internal& state)
                                                        opts.objCABIVersion2POverride() ? true : false));
                                break;
 #endif
                                                        opts.objCABIVersion2POverride() ? true : false));
                                break;
 #endif
+#if SUPPORT_ARCH_arm_any
                        case CPU_TYPE_ARM:
                                state.addAtom(*new ObjCImageInfoAtom<arm>(state.objcObjectConstraint, compaction, 
                                                        true));
                                break;
                        case CPU_TYPE_ARM:
                                state.addAtom(*new ObjCImageInfoAtom<arm>(state.objcObjectConstraint, compaction, 
                                                        true));
                                break;
+#endif
+#if SUPPORT_ARCH_arm64
+                       case CPU_TYPE_ARM64:
+                               state.addAtom(*new ObjCImageInfoAtom<arm64>(state.objcObjectConstraint, compaction, 
+                                                       true));
+                               break;
+#endif
                        default:
                                assert(0 && "unknown objc arch");
                }       
                        default:
                                assert(0 && "unknown objc arch");
                }       
@@ -1195,16 +1207,19 @@ void doPass(const Options& opts, ld::Internal& state)
 #endif
 #if SUPPORT_ARCH_i386
                        case CPU_TYPE_I386:
 #endif
 #if SUPPORT_ARCH_i386
                        case CPU_TYPE_I386:
-                               // disable optimization until fully tested
                                if ( opts.objCABIVersion2POverride() )
                     OptimizeCategories<x86>::doit(opts, state);
                                break;
 #endif
 #if SUPPORT_ARCH_arm_any
                        case CPU_TYPE_ARM:
                                if ( opts.objCABIVersion2POverride() )
                     OptimizeCategories<x86>::doit(opts, state);
                                break;
 #endif
 #if SUPPORT_ARCH_arm_any
                        case CPU_TYPE_ARM:
-                               // disable optimization until fully tested
                                OptimizeCategories<arm>::doit(opts, state);
                                break;
                                OptimizeCategories<arm>::doit(opts, state);
                                break;
+#endif
+#if SUPPORT_ARCH_arm64
+                       case CPU_TYPE_ARM64:
+                               // disabled until tested
+                               break;
 #endif
                        default:
                                assert(0 && "unknown objc arch");
 #endif
                        default:
                                assert(0 && "unknown objc arch");
index b4be79fd0fc953ebeefa90d6f01d2532bc685a60..af73d66ecb4860f444964dd772704ee482bba465 100644 (file)
@@ -31,6 +31,7 @@
 
 #include <vector>
 #include <map>
 
 #include <vector>
 #include <map>
+#include <set>
 #include <unordered_map>
 
 #include "ld.hpp"
 #include <unordered_map>
 
 #include "ld.hpp"
@@ -122,7 +123,7 @@ bool Layout::Comparer::operator()(const ld::Atom* left, const ld::Atom* right)
 {
        if ( left == right )
                return false;
 {
        if ( left == right )
                return false;
-       
+
        // magic section$start symbol always sorts to the start of its section
        if ( left->contentType() == ld::Atom::typeSectionStart )
                return true;
        // magic section$start symbol always sorts to the start of its section
        if ( left->contentType() == ld::Atom::typeSectionStart )
                return true;
@@ -162,6 +163,32 @@ bool Layout::Comparer::operator()(const ld::Atom* left, const ld::Atom* right)
        if ( right->contentType() == ld::Atom::typeSectionEnd )
                return true;
 
        if ( right->contentType() == ld::Atom::typeSectionEnd )
                return true;
 
+       // aliases sort before their target
+       bool leftIsAlias = left->isAlias();
+       if ( leftIsAlias ) {
+               for (ld::Fixup::iterator fit=left->fixupsBegin(); fit != left->fixupsEnd(); ++fit) {
+                       if ( fit->kind == ld::Fixup::kindNoneFollowOn ) {
+                               assert(fit->binding == ld::Fixup::bindingDirectlyBound);
+                           if ( fit->u.target == right )
+                                       return true; // left already before right
+                               left = fit->u.target; // sort as if alias was its target
+                               break;
+                   }
+               }
+       }
+       bool rightIsAlias = right->isAlias();
+    if ( rightIsAlias ) {
+        for (ld::Fixup::iterator fit=right->fixupsBegin(); fit != right->fixupsEnd(); ++fit) {
+                       if ( fit->kind == ld::Fixup::kindNoneFollowOn ) {
+                               assert(fit->binding == ld::Fixup::bindingDirectlyBound);
+                if ( fit->u.target == left )
+                    return false; // need to swap, alias is after target
+                               right = fit->u.target; // continue with sort as if right was target
+                break;
+                       }       
+               }
+    }
+
        // the __common section can have real or tentative definitions
        // we want the real ones to sort before tentative ones
        bool leftIsTent  =  (left->definition() == ld::Atom::definitionTentative);
        // the __common section can have real or tentative definitions
        // we want the real ones to sort before tentative ones
        bool leftIsTent  =  (left->definition() == ld::Atom::definitionTentative);
@@ -204,8 +231,6 @@ bool Layout::Comparer::operator()(const ld::Atom* left, const ld::Atom* right)
        int64_t addrDiff = left->objectAddress() - right->objectAddress();
        if ( addrDiff == 0 ) {
                // have same address so one might be an alias, and aliases need to sort before target
        int64_t addrDiff = left->objectAddress() - right->objectAddress();
        if ( addrDiff == 0 ) {
                // have same address so one might be an alias, and aliases need to sort before target
-               bool leftIsAlias = left->isAlias();
-               bool rightIsAlias = right->isAlias();
                if ( leftIsAlias != rightIsAlias )
                        return leftIsAlias;
 
                if ( leftIsAlias != rightIsAlias )
                        return leftIsAlias;
 
@@ -539,6 +564,7 @@ void Layout::doPass()
        // sort atoms in each section
        for (std::vector<ld::Internal::FinalSection*>::iterator sit=_state.sections.begin(); sit != _state.sections.end(); ++sit) {
                ld::Internal::FinalSection* sect = *sit;
        // sort atoms in each section
        for (std::vector<ld::Internal::FinalSection*>::iterator sit=_state.sections.begin(); sit != _state.sections.end(); ++sit) {
                ld::Internal::FinalSection* sect = *sit;
+               //fprintf(stderr, "sorting section %s\n", sect->sectionName());
                std::sort(sect->atoms.begin(), sect->atoms.end(), _comparer);
        }
 
                std::sort(sect->atoms.begin(), sect->atoms.end(), _comparer);
        }
 
@@ -547,7 +573,7 @@ void Layout::doPass()
        //      ld::Internal::FinalSection* sect = *sit;
        //      for (std::vector<const ld::Atom*>::iterator ait=sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
        //              const ld::Atom* atom = *ait;
        //      ld::Internal::FinalSection* sect = *sit;
        //      for (std::vector<const ld::Atom*>::iterator ait=sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
        //              const ld::Atom* atom = *ait;
-       //              fprintf(stderr, "\t%s\t%s\n", sect->sectionName(), atom->name());
+       //              fprintf(stderr, "\t%p\t%s\t%s\n", atom, sect->sectionName(), atom->name());
        //      }
        //}
 
        //      }
        //}
 
diff --git a/src/ld/passes/stubs/stub_arm64.hpp b/src/ld/passes/stubs/stub_arm64.hpp
new file mode 100644 (file)
index 0000000..cb1ceb3
--- /dev/null
@@ -0,0 +1,390 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2010-2013 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@
+ */
+
+
+// already in ld::passes::stubs namespace
+namespace arm64 {
+
+
+
+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)) 
+                                       { 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*)&_fixup4)[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;
+       
+       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(1)), 
+                               _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(1)), 
+                               _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, 0xd61f0200); // br   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)
+                               : ld::Atom(_s_section, 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::k1of1, ld::Fixup::kindStoreTargetAddressLittleEndian64, 
+                                                                                                       stubToResolver ? &_resolverHelper : 
+                                                                                                               (stubToGlobalWeakDef ?  &stubTo : &_helper)),
+                               _fixup2(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*)&_fixup2)[1]; }
+
+private:
+       const ld::Atom&                                                 _stubTo;
+       StubHelperAtom                                                  _helper;
+       ResolverHelperAtom                                              _resolverHelper;
+       mutable ld::Fixup                                               _fixup1;
+       ld::Fixup                                                               _fixup2;
+       
+       static ld::Section                                              _s_section;
+};
+
+ld::Section LazyPointerAtom::_s_section("__DATA", "__la_symbol_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)
+                               : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
+                                                       ld::Atom::scopeLinkageUnit, ld::Atom::typeStub, 
+                                                       symbolTableNotIn, false, false, false, ld::Atom::Alignment(1)), 
+                               _stubTo(stubTo), 
+                               _lazyPointer(pass, stubTo, stubToGlobalWeakDef, stubToResolver, weakImport),
+                               _fixup1(0, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressARM64Page21, &_lazyPointer),
+                               _fixup2(4, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressARM64PageOff12, &_lazyPointer) 
+                                       { 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, 0xD61F0200); // BR    X16
+       }
+       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;
+       LazyPointerAtom                                                 _lazyPointer;
+       mutable ld::Fixup                                               _fixup1;
+       mutable ld::Fixup                                               _fixup2;
+       
+       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)
+                               : 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) {
+                                       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*)&_fixup1)[1]; }
+
+private:
+       const ld::Atom&                                                 _stubTo;
+       ld::Fixup                                                               _fixup1;
+       
+       static ld::Section                                              _s_section;
+};
+
+ld::Section NonLazyPointerAtom::_s_section("__DATA", "__got", ld::Section::typeNonLazyPointer);
+
+
+class KextStubAtom : public ld::Atom {
+public:
+                               KextStubAtom(ld::passes::stubs::Pass& pass, const ld::Atom& stubTo)
+                               : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
+                                                       ld::Atom::scopeLinkageUnit, ld::Atom::typeStub, 
+                                                       symbolTableIn, false, false, false, ld::Atom::Alignment(1)), 
+                               _stubTo(stubTo), 
+                               _nonLazyPointer(pass, stubTo),
+                               _fixup1(0, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressARM64Page21, &_nonLazyPointer),
+                               _fixup2(4, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressARM64PageOff12, &_nonLazyPointer) { 
+                                       pass.addAtom(*this);
+                                       asprintf((char**)&_name, "%s.stub", _stubTo.name());
+                               }
+
+       virtual const ld::File*                                 file() const                                    { return _stubTo.file(); }
+       virtual const char*                                             name() const                                    { return _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, non_lazy_pointer@page
+               OSWriteLittleInt32(&buffer[4], 0, 0xF9400210); // LDR   X16, [X16, non_lazy_pointer@pageoff]
+               OSWriteLittleInt32(&buffer[8], 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*)&_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 KextStubAtom::_s_section("__TEXT", "__stubs", ld::Section::typeCode);
+
+
+} // namespace x86_64 
+
index 5ea1b05606cfa9ef6158a273c2963da38d0f2636..c01f3f9cc86adebc28a1eabdd7bf1181d75c4c33 100644 (file)
@@ -35,8 +35,8 @@
 #include <map>
 
 #include "Options.h"
 #include <map>
 
 #include "Options.h"
-#include "ld.hpp"
 #include "MachOFileAbstraction.hpp"
 #include "MachOFileAbstraction.hpp"
+#include "ld.hpp"
 
 #include "make_stubs.h"
 
 
 #include "make_stubs.h"
 
@@ -90,8 +90,9 @@ private:
 #include "stub_x86_classic.hpp"
 #include "stub_arm.hpp"
 #include "stub_arm_classic.hpp"
 #include "stub_x86_classic.hpp"
 #include "stub_arm.hpp"
 #include "stub_arm_classic.hpp"
-
-
+#if SUPPORT_ARCH_arm64
+#include "stub_arm64.hpp"
+#endif
 
 Pass::Pass(const Options& opts) 
        :       compressedHelperHelper(NULL), 
 
 Pass::Pass(const Options& opts) 
        :       compressedHelperHelper(NULL), 
@@ -119,6 +120,9 @@ const ld::Atom* Pass::stubableFixup(const ld::Fixup* fixup, ld::Internal& state)
                        case ld::Fixup::kindStoreTargetAddressX86BranchPCRel32:
                        case ld::Fixup::kindStoreTargetAddressARMBranch24:
                        case ld::Fixup::kindStoreTargetAddressThumbBranch22:
                        case ld::Fixup::kindStoreTargetAddressX86BranchPCRel32:
                        case ld::Fixup::kindStoreTargetAddressARMBranch24:
                        case ld::Fixup::kindStoreTargetAddressThumbBranch22:
+#if SUPPORT_ARCH_arm64
+                       case ld::Fixup::kindStoreTargetAddressARM64Branch26:
+#endif
                 assert(target != NULL);
                                // create stub if target is in a dylib
                                if ( target->definition() == ld::Atom::definitionProxy ) 
                 assert(target != NULL);
                                // create stub if target is in a dylib
                                if ( target->definition() == ld::Atom::definitionProxy ) 
@@ -216,6 +220,14 @@ ld::Atom* Pass::makeStub(const ld::Atom& target, bool weakImport)
                                        return new ld::passes::stubs::arm::classic::StubNoPICAtom(*this, target, forLazyDylib, weakImport);
                        }
                        break;
                                        return new ld::passes::stubs::arm::classic::StubNoPICAtom(*this, target, forLazyDylib, weakImport);
                        }
                        break;
+#endif
+#if SUPPORT_ARCH_arm64
+               case CPU_TYPE_ARM64:
+                       if ( (_options.outputKind() == Options::kKextBundle) && _options.kextsUseStubs() ) 
+                               return new ld::passes::stubs::arm64::KextStubAtom(*this, target);
+                       else
+                               return new ld::passes::stubs::arm64::StubAtom(*this, target, stubToGlobalWeakDef, stubToResolver, weakImport);
+                       break;
 #endif
        }
        throw "unsupported arch for stub";
 #endif
        }
        throw "unsupported arch for stub";
index cc673a3d767fae08ca0d10676fe52eaa94589deb..36fcce9f9f312c54ff67922c478845642f455411 100644 (file)
@@ -804,6 +804,39 @@ void dumper::dumpFixup(const ld::Fixup* ref)
                case ld::Fixup::kindStoreThumbHigh16:
                        printf(", then store high-16 in Thumb movt");
                        break;
                case ld::Fixup::kindStoreThumbHigh16:
                        printf(", then store high-16 in Thumb movt");
                        break;
+               case ld::Fixup::kindStoreARM64Branch26:
+                       printf(", then store as ARM64 26-bit pcrel branch");
+                       break;
+               case ld::Fixup::kindStoreARM64Page21:
+                       printf(", then store as ARM64 21-bit pcrel ADRP");
+                       break;
+               case ld::Fixup::kindStoreARM64PageOff12:
+                       printf(", then store as ARM64 12-bit offset");
+                       break;
+               case ld::Fixup::kindStoreARM64GOTLoadPage21:
+                       printf(", then store as ARM64 21-bit pcrel ADRP of GOT");
+                       break;
+               case ld::Fixup::kindStoreARM64GOTLoadPageOff12:
+                       printf(", then store as ARM64 12-bit page offset of GOT");
+                       break;
+               case ld::Fixup::kindStoreARM64GOTLeaPage21:
+                       printf(", then store as ARM64 21-bit pcrel ADRP of GOT lea");
+                       break;
+               case ld::Fixup::kindStoreARM64GOTLeaPageOff12:
+                       printf(", then store as ARM64 12-bit page offset of GOT lea");
+                       break;
+               case ld::Fixup::kindStoreARM64TLVPLoadPage21:
+                       printf(", then store as ARM64 21-bit pcrel ADRP of TLVP");
+                       break;
+               case ld::Fixup::kindStoreARM64TLVPLoadPageOff12:
+                       printf(", then store as ARM64 12-bit page offset of TLVP");
+                       break;
+               case ld::Fixup::kindStoreARM64PointerToGOT:
+                       printf(", then store as 64-bit pointer to GOT entry");
+                       break;
+               case ld::Fixup::kindStoreARM64PCRelToGOT:
+                       printf(", then store as 32-bit delta to GOT entry");
+                       break;
                case ld::Fixup::kindDtraceExtra:
                        printf("dtrace static probe extra info");
                        break;
                case ld::Fixup::kindDtraceExtra:
                        printf("dtrace static probe extra info");
                        break;
@@ -825,6 +858,12 @@ void dumper::dumpFixup(const ld::Fixup* ref)
                case ld::Fixup::kindStoreThumbDtraceIsEnableSiteClear:
                        printf("Thumb dtrace static is-enabled site");
                        break;
                case ld::Fixup::kindStoreThumbDtraceIsEnableSiteClear:
                        printf("Thumb dtrace static is-enabled site");
                        break;
+               case ld::Fixup::kindStoreARM64DtraceCallSiteNop:
+                       printf("ARM64 dtrace static probe site");
+                       break;
+               case ld::Fixup::kindStoreARM64DtraceIsEnableSiteClear:
+                       printf("ARM64 dtrace static is-enabled site");
+                       break;
                case ld::Fixup::kindLazyTarget:
                        printf("lazy reference to external symbol %s", referenceTargetAtomName(ref));
                        break;
                case ld::Fixup::kindLazyTarget:
                        printf("lazy reference to external symbol %s", referenceTargetAtomName(ref));
                        break;
@@ -898,6 +937,28 @@ void dumper::dumpFixup(const ld::Fixup* ref)
                case ld::Fixup::kindSetTargetTLVTemplateOffsetLittleEndian32:
                case ld::Fixup::kindSetTargetTLVTemplateOffsetLittleEndian64:
                        printf("tlv template offset of %s", referenceTargetAtomName(ref));
                case ld::Fixup::kindSetTargetTLVTemplateOffsetLittleEndian32:
                case ld::Fixup::kindSetTargetTLVTemplateOffsetLittleEndian64:
                        printf("tlv template offset of %s", referenceTargetAtomName(ref));
+                       break;
+               case ld::Fixup::kindStoreTargetAddressARM64Branch26:
+                       printf("ARM64 store 26-bit pcrel branch to %s", referenceTargetAtomName(ref));
+                       break;
+               case ld::Fixup::kindStoreTargetAddressARM64Page21:
+                       printf("ARM64 store 21-bit pcrel ADRP to %s", referenceTargetAtomName(ref));
+                       break;
+               case ld::Fixup::kindStoreTargetAddressARM64PageOff12:
+                       printf("ARM64 store 12-bit page offset of %s", referenceTargetAtomName(ref));
+                       break;
+               case ld::Fixup::kindStoreTargetAddressARM64GOTLoadPage21:
+                       printf("ARM64 store 21-bit pcrel ADRP to GOT for %s", referenceTargetAtomName(ref));
+                       break;
+               case ld::Fixup::kindStoreTargetAddressARM64GOTLoadPageOff12:
+                       printf("ARM64 store 12-bit page offset of GOT of %s", referenceTargetAtomName(ref));
+                       break;
+               case ld::Fixup::kindStoreTargetAddressARM64GOTLeaPage21:
+                       printf("ARM64 store 21-bit pcrel ADRP for lea of %s", referenceTargetAtomName(ref));
+                       break;
+               case ld::Fixup::kindStoreTargetAddressARM64GOTLeaPageOff12:
+                       printf("ARM64 store 12-bit page offset of lea of %s", referenceTargetAtomName(ref));
+                       break;
                //default:
                //      printf("unknown fixup");
                //      break;
                //default:
                //      printf("unknown fixup");
                //      break;
@@ -1116,7 +1177,9 @@ static ld::relocatable::File* createReader(const char* path)
        objOpts.architecture            = sPreferredArch;
        objOpts.objSubtypeMustMatch = false;
        objOpts.logAllFiles                     = false;
        objOpts.architecture            = sPreferredArch;
        objOpts.objSubtypeMustMatch = false;
        objOpts.logAllFiles                     = false;
-       objOpts.convertUnwindInfo       = true;
+       objOpts.warnUnwindConversionProblems    = true;
+       objOpts.keepDwarfUnwind         = false;
+       objOpts.forceDwarfConversion = false;
        objOpts.subType                         = sPreferredSubArch;
 #if 1
        if ( ! foundFatSlice ) {
        objOpts.subType                         = sPreferredSubArch;
 #if 1
        if ( ! foundFatSlice ) {
index 766ae947696e5264b923e259b4e32d801dc6a43b..e47d482ad799b78713c904d3530e3b79fa43cb3e 100644 (file)
@@ -98,3 +98,16 @@ prune_trie(
        // success
        return NULL;
 }
        // success
        return NULL;
 }
+
+
+// <rdar://problem/12764051> Switch libprunetrie to use libc++ instead of libstdc++
+// The one undefined when building libprunetrie.a with libc++ is throw_length_error().
+// Adding this define here resolves that and means libprunetrie.a can be linked
+// by cctools with libc++ or libstdc++.
+extern "C" void foobar() __asm("__ZNKSt3__120__vector_base_commonILb1EE20__throw_length_errorEv");
+void foobar()
+{
+       throw "Size of vecor cannot be grown";
+}
+
+
index 71f13b8df469511f2da9a724f30576a5e19507c5..b43ff3fc73a71b957a0490bdc9e5b6aa115563f8 100644 (file)
@@ -252,6 +252,26 @@ bool DyldInfoPrinter<arm>::validFile(const uint8_t* fileContent)
 }
 #endif
 
 }
 #endif
 
+#if SUPPORT_ARCH_arm64
+template <>
+bool DyldInfoPrinter<arm64>::validFile(const uint8_t* fileContent)
+{      
+       const macho_header<P>* header = (const macho_header<P>*)fileContent;
+       if ( header->magic() != MH_MAGIC_64 )
+               return false;
+       if ( header->cputype() != CPU_TYPE_ARM64 )
+               return false;
+       switch (header->filetype()) {
+               case MH_EXECUTE:
+               case MH_DYLIB:
+               case MH_BUNDLE:
+               case MH_DYLINKER:
+                       return true;
+       }
+       return false;
+}
+#endif
+
 template <typename A>
 DyldInfoPrinter<A>::DyldInfoPrinter(const uint8_t* fileContent, uint32_t fileLength, const char* path, bool printArch)
  : fHeader(NULL), fLength(fileLength), 
 template <typename A>
 DyldInfoPrinter<A>::DyldInfoPrinter(const uint8_t* fileContent, uint32_t fileLength, const char* path, bool printArch)
  : fHeader(NULL), fLength(fileLength), 
@@ -612,7 +632,7 @@ void DyldInfoPrinter<A>::printRebaseInfo()
                uint64_t segOffset = 0;
                uint32_t count;
                uint32_t skip;
                uint64_t segOffset = 0;
                uint32_t count;
                uint32_t skip;
-               int segIndex;
+               int segIndex = 0;
                pint_t segStartAddr = 0;
                const char* segName = "??";
                const char* typeName = "??";
                pint_t segStartAddr = 0;
                const char* segName = "??";
                const char* typeName = "??";
@@ -1267,13 +1287,14 @@ void DyldInfoPrinter<A>::printExportInfo()
                        const bool reExport = (it->flags & EXPORT_SYMBOL_FLAGS_REEXPORT);
                        const bool weakDef = (it->flags & EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION);
                        const bool threadLocal = ((it->flags & EXPORT_SYMBOL_FLAGS_KIND_MASK) == EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL);
                        const bool reExport = (it->flags & EXPORT_SYMBOL_FLAGS_REEXPORT);
                        const bool weakDef = (it->flags & EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION);
                        const bool threadLocal = ((it->flags & EXPORT_SYMBOL_FLAGS_KIND_MASK) == EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL);
+                       const bool abs = ((it->flags & EXPORT_SYMBOL_FLAGS_KIND_MASK) == EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE);
                        const bool resolver = (it->flags & EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER);
                        if ( reExport )
                                printf("[re-export] ");
                        else
                                printf("0x%08llX  ", fBaseAddress+it->address);
                        printf("%s", it->name);
                        const bool resolver = (it->flags & EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER);
                        if ( reExport )
                                printf("[re-export] ");
                        else
                                printf("0x%08llX  ", fBaseAddress+it->address);
                        printf("%s", it->name);
-                       if ( weakDef || threadLocal || resolver ) {
+                       if ( weakDef || threadLocal || resolver || abs ) {
                                bool needComma = false;
                                printf(" [");
                                if ( weakDef ) {
                                bool needComma = false;
                                printf(" [");
                                if ( weakDef ) {
@@ -1286,6 +1307,12 @@ void DyldInfoPrinter<A>::printExportInfo()
                                        printf("per-thread");
                                        needComma = true;
                                }
                                        printf("per-thread");
                                        needComma = true;
                                }
+                               if ( abs ) {
+                                       if ( needComma )
+                                               printf(", ");
+                                       printf("absolute");
+                                       needComma = true;
+                               }
                                if ( resolver ) {
                                        if ( needComma ) 
                                                printf(", ");
                                if ( resolver ) {
                                        if ( needComma ) 
                                                printf(", ");
@@ -1432,6 +1459,8 @@ void DyldInfoPrinter<A>::printExportInfoNodes()
                                                printf("[addr=0x%06llX] ", address);
                                        else if ( (flags & EXPORT_SYMBOL_FLAGS_KIND_MASK) == EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL)
                                                printf("[flags=THREAD_LOCAL addr=0x%06llX] ", address);
                                                printf("[addr=0x%06llX] ", address);
                                        else if ( (flags & EXPORT_SYMBOL_FLAGS_KIND_MASK) == EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL)
                                                printf("[flags=THREAD_LOCAL addr=0x%06llX] ", address);
+                                       else if ( (flags & EXPORT_SYMBOL_FLAGS_KIND_MASK) == EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE)
+                                               printf("[flags=ABSOLUTE addr=0x%06llX] ", address);
                                        else
                                                printf("[flags=0x%llX addr=0x%06llX] ", flags, address);
                                }
                                        else
                                                printf("[flags=0x%llX addr=0x%06llX] ", flags, address);
                                }
@@ -1467,7 +1496,12 @@ const uint8_t* DyldInfoPrinter<A>::printSharedRegionInfoForEachULEB128Address(co
                        kindStr = "64-bit pointer";
                        break;
                case 3:
                        kindStr = "64-bit pointer";
                        break;
                case 3:
-                       kindStr = "ppc hi16";
+#if SUPPORT_ARCH_arm64
+                       if ( fHeader->cputype() == CPU_TYPE_ARM64 )
+                               kindStr = "arm64 ADRP";
+                       else
+#endif
+                               kindStr = "ppc hi16";
                        break;
                case 4:
                        kindStr = "32-bit offset to IMPORT";
                        break;
                case 4:
                        kindStr = "32-bit offset to IMPORT";
@@ -1751,7 +1785,6 @@ x86::P::uint_t DyldInfoPrinter<x86>::relocBase()
 template <>
 x86_64::P::uint_t DyldInfoPrinter<x86_64>::relocBase()
 {
 template <>
 x86_64::P::uint_t DyldInfoPrinter<x86_64>::relocBase()
 {
-       // check for split-seg
        return fFirstWritableSegment->vmaddr();
 }
 
        return fFirstWritableSegment->vmaddr();
 }
 
@@ -1766,6 +1799,13 @@ arm::P::uint_t DyldInfoPrinter<arm>::relocBase()
 }
 #endif
 
 }
 #endif
 
+#if SUPPORT_ARCH_arm64
+template <>
+arm64::P::uint_t DyldInfoPrinter<arm64>::relocBase()
+{
+       return fFirstWritableSegment->vmaddr();
+}
+#endif
 
 template <>
 const char*    DyldInfoPrinter<ppc>::relocTypeName(uint8_t r_type)
 
 template <>
 const char*    DyldInfoPrinter<ppc>::relocTypeName(uint8_t r_type)
@@ -1818,6 +1858,16 @@ const char*      DyldInfoPrinter<arm>::relocTypeName(uint8_t r_type)
 }
 #endif
 
 }
 #endif
 
+#if SUPPORT_ARCH_arm64 
+template <>
+const char*    DyldInfoPrinter<arm64>::relocTypeName(uint8_t r_type)
+{
+       if ( r_type == ARM64_RELOC_UNSIGNED )
+               return "pointer";
+       return "??";
+}
+#endif
+
 template <typename A>
 void DyldInfoPrinter<A>::printRelocRebaseInfo()
 {
 template <typename A>
 void DyldInfoPrinter<A>::printRelocRebaseInfo()
 {
@@ -2114,6 +2164,14 @@ static void dump(const char* path)
                                                else
                                                        throw "in universal file, arm slice does not contain arm mach-o";
                                                break;
                                                else
                                                        throw "in universal file, arm slice does not contain arm mach-o";
                                                break;
+#endif
+#if SUPPORT_ARCH_arm64
+                                       case CPU_TYPE_ARM64:
+                                               if ( DyldInfoPrinter<arm64>::validFile(p + offset) )
+                                                       DyldInfoPrinter<arm64>::make(p + offset, size, path, (sPreferredArch == 0));
+                                               else
+                                                       throw "in universal file, arm64 slice does not contain arm mach-o";
+                                               break;
 #endif
                                        default:
                                                        throwf("in universal file, unknown architecture slice 0x%x\n", cputype);
 #endif
                                        default:
                                                        throwf("in universal file, unknown architecture slice 0x%x\n", cputype);
@@ -2137,6 +2195,11 @@ static void dump(const char* path)
                else if ( DyldInfoPrinter<arm>::validFile(p) ) {
                        DyldInfoPrinter<arm>::make(p, length, path, false);
                }
                else if ( DyldInfoPrinter<arm>::validFile(p) ) {
                        DyldInfoPrinter<arm>::make(p, length, path, false);
                }
+#endif
+#if SUPPORT_ARCH_arm64
+               else if ( DyldInfoPrinter<arm64>::validFile(p) ) {
+                       DyldInfoPrinter<arm64>::make(p, length, path, false);
+               }
 #endif
                else {
                        throw "not a known file type";
 #endif
                else {
                        throw "not a known file type";
@@ -2187,6 +2250,10 @@ int main(int argc, const char* argv[])
                                                sPreferredArch = CPU_TYPE_I386;
                                        else if ( strcmp(arch, "x86_64") == 0 )
                                                sPreferredArch = CPU_TYPE_X86_64;
                                                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";
                                        else {
                                                if ( arch == NULL )
                                                        throw "-arch missing architecture name";
index bd585d139063b4aac8a577dca387371b546193ca..aec6ebe1ff88a8336173033dad0e2e7ba91b507c 100644 (file)
@@ -264,11 +264,34 @@ bool MachOChecker<arm>::validFile(const uint8_t* fileContent)
        return false;
 }
 
        return false;
 }
 
+#if SUPPORT_ARCH_arm64
+template <>
+bool MachOChecker<arm64>::validFile(const uint8_t* fileContent)
+{      
+       const macho_header<P>* header = (const macho_header<P>*)fileContent;
+       if ( header->magic() != MH_MAGIC_64 )
+               return false;
+       if ( header->cputype() != CPU_TYPE_ARM64 )
+               return false;
+       switch (header->filetype()) {
+               case MH_EXECUTE:
+               case MH_DYLIB:
+               case MH_BUNDLE:
+               case MH_DYLINKER:
+                       return true;
+       }
+       return false;
+}
+#endif
+
 template <> uint8_t MachOChecker<ppc>::loadCommandSizeMask()   { return 0x03; }
 template <> uint8_t MachOChecker<ppc64>::loadCommandSizeMask() { return 0x07; }
 template <> uint8_t MachOChecker<x86>::loadCommandSizeMask()   { return 0x03; }
 template <> uint8_t MachOChecker<x86_64>::loadCommandSizeMask() { return 0x07; }
 template <> uint8_t MachOChecker<arm>::loadCommandSizeMask()   { return 0x03; }
 template <> uint8_t MachOChecker<ppc>::loadCommandSizeMask()   { return 0x03; }
 template <> uint8_t MachOChecker<ppc64>::loadCommandSizeMask() { return 0x07; }
 template <> uint8_t MachOChecker<x86>::loadCommandSizeMask()   { return 0x03; }
 template <> uint8_t MachOChecker<x86_64>::loadCommandSizeMask() { return 0x07; }
 template <> uint8_t MachOChecker<arm>::loadCommandSizeMask()   { return 0x03; }
+#if SUPPORT_ARCH_arm64
+template <> uint8_t MachOChecker<arm64>::loadCommandSizeMask() { return 0x07; }
+#endif
 
 
 template <>
 
 
 template <>
@@ -301,9 +324,13 @@ arm::P::uint_t MachOChecker<arm>::getInitialStackPointer(const macho_thread_comm
        return threadInfo->thread_register(13);
 }
 
        return threadInfo->thread_register(13);
 }
 
-
-
-
+#if SUPPORT_ARCH_arm64
+template <>
+arm64::P::uint_t MachOChecker<arm64>::getInitialStackPointer(const macho_thread_command<arm64::P>* threadInfo)
+{
+       throw "LC_UNIXTHREAD not supported for arm64";
+}
+#endif
 
 template <>
 ppc::P::uint_t MachOChecker<ppc>::getEntryPoint(const macho_thread_command<ppc::P>* threadInfo)
 
 template <>
 ppc::P::uint_t MachOChecker<ppc>::getEntryPoint(const macho_thread_command<ppc::P>* threadInfo)
@@ -335,6 +362,13 @@ arm::P::uint_t MachOChecker<arm>::getEntryPoint(const macho_thread_command<arm::
        return threadInfo->thread_register(15);
 }
 
        return threadInfo->thread_register(15);
 }
 
+#if SUPPORT_ARCH_arm64
+template <>
+arm64::P::uint_t MachOChecker<arm64>::getEntryPoint(const macho_thread_command<arm64::P>* threadInfo)
+{
+       throw "LC_UNIXTHREAD not supported for arm64";
+}
+#endif
 
 template <typename A>
 MachOChecker<A>::MachOChecker(const uint8_t* fileContent, uint32_t fileLength, const char* path)
 
 template <typename A>
 MachOChecker<A>::MachOChecker(const uint8_t* fileContent, uint32_t fileLength, const char* path)
@@ -447,6 +481,7 @@ void MachOChecker<A>::checkLoadCommands()
                                fDyldInfo = (macho_dyld_info_command<P>*)cmd;
                                break;
                        case LC_ENCRYPTION_INFO:
                                fDyldInfo = (macho_dyld_info_command<P>*)cmd;
                                break;
                        case LC_ENCRYPTION_INFO:
+                       case LC_ENCRYPTION_INFO_64:
                                encryption_info = (macho_encryption_info_command<P>*)cmd;
                                break;
                        case LC_SUB_UMBRELLA:
                                encryption_info = (macho_encryption_info_command<P>*)cmd;
                                break;
                        case LC_SUB_UMBRELLA:
@@ -993,6 +1028,15 @@ arm::P::uint_t MachOChecker<arm>::relocBase()
                return fFirstSegment->vmaddr();
 }
 
                return fFirstSegment->vmaddr();
 }
 
+#if SUPPORT_ARCH_arm64
+template <>
+arm64::P::uint_t MachOChecker<arm64>::relocBase()
+{
+       return fFirstWritableSegment->vmaddr();
+}
+#endif
+
+
 
 template <typename A>
 bool MachOChecker<A>::addressInWritableSegment(pint_t address)
 
 template <typename A>
 bool MachOChecker<A>::addressInWritableSegment(pint_t address)
@@ -1107,6 +1151,14 @@ void MachOChecker<arm>::checkExternalReloation(const macho_relocation_info<P>* r
 }
 #endif
 
 }
 #endif
 
+#if SUPPORT_ARCH_arm64
+template <>
+void MachOChecker<arm64>::checkExternalReloation(const macho_relocation_info<P>* reloc)
+{
+  throw "external relocations not used for arm64";
+}
+#endif
+
 
 template <>
 void MachOChecker<ppc>::checkLocalReloation(const macho_relocation_info<P>* reloc)
 
 template <>
 void MachOChecker<ppc>::checkLocalReloation(const macho_relocation_info<P>* reloc)
@@ -1184,6 +1236,15 @@ void MachOChecker<arm>::checkLocalReloation(const macho_relocation_info<P>* relo
 }
 #endif
 
 }
 #endif
 
+#if SUPPORT_ARCH_arm64
+template <>
+void MachOChecker<arm64>::checkLocalReloation(const macho_relocation_info<P>* reloc)
+{
+  throw "local relocations not used for arm64";
+}
+#endif
+
+
 template <typename A>
 void MachOChecker<A>::checkRelocations()
 {
 template <typename A>
 void MachOChecker<A>::checkRelocations()
 {
@@ -1602,6 +1663,11 @@ static void check(const char* path)
                else if ( MachOChecker<arm>::validFile(p) ) {
                        MachOChecker<arm>::make(p, length, path);
                }
                else if ( MachOChecker<arm>::validFile(p) ) {
                        MachOChecker<arm>::make(p, length, path);
                }
+#endif
+#if SUPPORT_ARCH_arm64
+               else if ( MachOChecker<arm64>::validFile(p) ) {
+                       MachOChecker<arm64>::make(p, length, path);
+               }
 #endif
                else {
                        throw "not a known file type";
 #endif
                else {
                        throw "not a known file type";
index 731f2a36d4600a40048deb50dce570513e5c8997..3da01c540f39391561697034d58a65b3c3e7c776 100644 (file)
@@ -35,7 +35,7 @@
 #include <set>
 #include <unordered_set>
 
 #include <set>
 #include <unordered_set>
 
-
+#include "configure.h"
 #include "MachOFileAbstraction.hpp"
 #include "Architectures.hpp"
 
 #include "MachOFileAbstraction.hpp"
 #include "Architectures.hpp"
 
@@ -99,7 +99,9 @@ private:
 template <>     const char*    UnwindPrinter<x86>::archName()          { return "i386"; }
 template <>     const char*    UnwindPrinter<x86_64>::archName()       { return "x86_64"; }
 template <>     const char*    UnwindPrinter<arm>::archName()          { return "arm"; }
 template <>     const char*    UnwindPrinter<x86>::archName()          { return "i386"; }
 template <>     const char*    UnwindPrinter<x86_64>::archName()       { return "x86_64"; }
 template <>     const char*    UnwindPrinter<arm>::archName()          { return "arm"; }
-
+#if SUPPORT_ARCH_arm64
+template <>     const char*    UnwindPrinter<arm64>::archName()        { return "arm64"; }
+#endif
 
 template <>
 bool UnwindPrinter<x86>::validFile(const uint8_t* fileContent)
 
 template <>
 bool UnwindPrinter<x86>::validFile(const uint8_t* fileContent)
@@ -140,6 +142,27 @@ bool UnwindPrinter<x86_64>::validFile(const uint8_t* fileContent)
 }
 
 
 }
 
 
+#if SUPPORT_ARCH_arm64
+template <>
+bool UnwindPrinter<arm64>::validFile(const uint8_t* fileContent)
+{      
+       const macho_header<P>* header = (const macho_header<P>*)fileContent;
+       if ( header->magic() != MH_MAGIC_64 )
+               return false;
+       if ( header->cputype() != CPU_TYPE_ARM64 )
+               return false;
+       switch (header->filetype()) {
+               case MH_EXECUTE:
+               case MH_DYLIB:
+               case MH_BUNDLE:
+               case MH_DYLINKER:
+               case MH_OBJECT:
+                       return true;
+       }
+       return false;
+}
+#endif
+
 template <typename A>
 UnwindPrinter<A>::UnwindPrinter(const uint8_t* fileContent, uint32_t fileLength, const char* path, bool showFunctionNames)
  : fHeader(NULL), fLength(fileLength), fUnwindSection(NULL),
 template <typename A>
 UnwindPrinter<A>::UnwindPrinter(const uint8_t* fileContent, uint32_t fileLength, const char* path, bool showFunctionNames)
  : fHeader(NULL), fLength(fileLength), fUnwindSection(NULL),
@@ -628,7 +651,84 @@ void UnwindPrinter<x86>::decode(uint32_t encoding, const uint8_t* funcStart, cha
 
 }
 
 
 }
 
-
+#if SUPPORT_ARCH_arm64
+template <>
+void UnwindPrinter<arm64>::decode(uint32_t encoding, const uint8_t* funcStart, char* str)
+{
+       uint32_t stackSize;
+       switch ( encoding & UNWIND_ARM64_MODE_MASK ) {
+               case UNWIND_ARM64_MODE_FRAMELESS:
+                       stackSize = EXTRACT_BITS(encoding, UNWIND_ARM64_FRAMELESS_STACK_SIZE_MASK);
+                       if ( stackSize == 0 )
+                               strcpy(str, "no frame, no saved registers ");
+                       else
+                               sprintf(str, "stack size=%d: ", 16 * stackSize);
+                       if ( encoding & UNWIND_ARM64_FRAME_X19_X20_PAIR )
+                               strcat(str, "x19/20 ");
+                       if ( encoding & UNWIND_ARM64_FRAME_X21_X22_PAIR )
+                               strcat(str, "x21/22 ");
+                       if ( encoding & UNWIND_ARM64_FRAME_X23_X24_PAIR )
+                               strcat(str, "x23/24 ");
+                       if ( encoding & UNWIND_ARM64_FRAME_X25_X26_PAIR )
+                               strcat(str, "x25/26 ");
+                       if ( encoding & UNWIND_ARM64_FRAME_X27_X28_PAIR )
+                               strcat(str, "x27/28 ");
+                       if ( encoding & UNWIND_ARM64_FRAME_D8_D9_PAIR )
+                               strcat(str, "d8/9 ");
+                       if ( encoding & UNWIND_ARM64_FRAME_D10_D11_PAIR )
+                               strcat(str, "d10/11 ");
+                       if ( encoding & UNWIND_ARM64_FRAME_D12_D13_PAIR )
+                               strcat(str, "d12/13 ");
+                       if ( encoding & UNWIND_ARM64_FRAME_D14_D15_PAIR )
+                               strcat(str, "d14/15 ");
+                       break;
+                       break;
+               case UNWIND_ARM64_MODE_DWARF:
+                       sprintf(str, "dwarf offset 0x%08X, ", encoding & UNWIND_X86_64_DWARF_SECTION_OFFSET);
+                       break;
+               case UNWIND_ARM64_MODE_FRAME:
+                       strcpy(str, "std frame: ");
+                       if ( encoding & UNWIND_ARM64_FRAME_X19_X20_PAIR )
+                               strcat(str, "x19/20 ");
+                       if ( encoding & UNWIND_ARM64_FRAME_X21_X22_PAIR )
+                               strcat(str, "x21/22 ");
+                       if ( encoding & UNWIND_ARM64_FRAME_X23_X24_PAIR )
+                               strcat(str, "x23/24 ");
+                       if ( encoding & UNWIND_ARM64_FRAME_X25_X26_PAIR )
+                               strcat(str, "x25/26 ");
+                       if ( encoding & UNWIND_ARM64_FRAME_X27_X28_PAIR )
+                               strcat(str, "x27/28 ");
+                       if ( encoding & UNWIND_ARM64_FRAME_D8_D9_PAIR )
+                               strcat(str, "d8/9 ");
+                       if ( encoding & UNWIND_ARM64_FRAME_D10_D11_PAIR )
+                               strcat(str, "d10/11 ");
+                       if ( encoding & UNWIND_ARM64_FRAME_D12_D13_PAIR )
+                               strcat(str, "d12/13 ");
+                       if ( encoding & UNWIND_ARM64_FRAME_D14_D15_PAIR )
+                               strcat(str, "d14/15 ");
+                       break;
+               case UNWIND_ARM64_MODE_FRAME_OLD:
+                       strcpy(str, "old frame: ");
+                       if ( encoding & UNWIND_ARM64_FRAME_X21_X22_PAIR_OLD )
+                               strcat(str, "x21/22 ");
+                       if ( encoding & UNWIND_ARM64_FRAME_X23_X24_PAIR_OLD )
+                               strcat(str, "x23/24 ");
+                       if ( encoding & UNWIND_ARM64_FRAME_X25_X26_PAIR_OLD )
+                               strcat(str, "x25/26 ");
+                       if ( encoding & UNWIND_ARM64_FRAME_X27_X28_PAIR_OLD )
+                               strcat(str, "x27/28 ");
+                       if ( encoding & UNWIND_ARM64_FRAME_D8_D9_PAIR_OLD )
+                               strcat(str, "d8/9 ");
+                       if ( encoding & UNWIND_ARM64_FRAME_D10_D11_PAIR_OLD )
+                               strcat(str, "d10/11 ");
+                       if ( encoding & UNWIND_ARM64_FRAME_D12_D13_PAIR_OLD )
+                               strcat(str, "d12/13 ");
+                       if ( encoding & UNWIND_ARM64_FRAME_D14_D15_PAIR_OLD )
+                               strcat(str, "d14/15 ");
+                       break;
+       }
+}
+#endif
 
 template <>
 const char* UnwindPrinter<x86_64>::personalityName(const macho_relocation_info<x86_64::P>* reloc)
 
 template <>
 const char* UnwindPrinter<x86_64>::personalityName(const macho_relocation_info<x86_64::P>* reloc)
@@ -648,6 +748,17 @@ const char* UnwindPrinter<x86>::personalityName(const macho_relocation_info<x86:
        return &fStrings[sym.n_strx()];
 }
 
        return &fStrings[sym.n_strx()];
 }
 
+#if SUPPORT_ARCH_arm64
+template <>
+const char* UnwindPrinter<arm64>::personalityName(const macho_relocation_info<arm64::P>* reloc)
+{
+       //assert(reloc->r_extern() && "reloc not extern on personality column in __compact_unwind section");
+       //assert((reloc->r_type() == ARM64_RELOC_UNSIGNED) && "wrong reloc type on personality column in __compact_unwind section");
+       const macho_nlist<P>& sym = fSymbols[reloc->r_symbolnum()];
+       return &fStrings[sym.n_strx()];
+}
+#endif
+
 template <typename A>
 bool UnwindPrinter<A>::hasExernReloc(uint64_t sectionOffset, const char** personalityStr, pint_t* addr)
 {
 template <typename A>
 bool UnwindPrinter<A>::hasExernReloc(uint64_t sectionOffset, const char** personalityStr, pint_t* addr)
 {
@@ -715,7 +826,6 @@ void UnwindPrinter<A>::printObjectUnwindSection(bool showFunctionNames)
                                printf("  lsda:         0x%08llX  %s+0x%X\n", (uint64_t)entry->lsda(), lsdaName, lsdaOffset);
                }
        }
                                printf("  lsda:         0x%08llX  %s+0x%X\n", (uint64_t)entry->lsda(), lsdaName, lsdaOffset);
                }
        }
-       
 }
 
 
 }
 
 
@@ -789,7 +899,7 @@ void UnwindPrinter<A>::printUnwindSection(bool showFunctionNames)
                                char encodingString[100];
                                decode(entry[j].encoding(), ((const uint8_t*)fHeader)+funcOffset, encodingString);
                                const char* name = showFunctionNames ? functionName(funcOffset+fMachHeaderAddress) : "";
                                char encodingString[100];
                                decode(entry[j].encoding(), ((const uint8_t*)fHeader)+funcOffset, encodingString);
                                const char* name = showFunctionNames ? functionName(funcOffset+fMachHeaderAddress) : "";
-                               printf("\t\t\t[%3u] funcOffset=0x%08X, encoding=0x%08X (%-40s) %s\n", 
+                               printf("\t\t\t[%3u] funcOffset=0x%08X, encoding=0x%08X (%-56s) %s\n", 
                                        j, funcOffset, entry[j].encoding(), encodingString, name);
                        }
                }
                                        j, funcOffset, entry[j].encoding(), encodingString, name);
                        }
                }
@@ -827,7 +937,7 @@ void UnwindPrinter<A>::printUnwindSection(bool showFunctionNames)
                                                fprintf(stderr, "MISSING LSDA entry for %s\n", name);
                                        }
                                } 
                                                fprintf(stderr, "MISSING LSDA entry for %s\n", name);
                                        }
                                } 
-                               printf("\t\t\t[%3u] funcOffset=0x%08X, encoding[%3u]=0x%08X (%-40s) %s\n", 
+                               printf("\t\t\t[%3u] funcOffset=0x%08X, encoding[%3u]=0x%08X (%-56s) %s\n", 
                                        j, funcOff, encodingIndex, encoding, encodingString, name);
                        }                                       
                }
                                        j, funcOff, encodingIndex, encoding, encodingString, name);
                        }                                       
                }
@@ -875,6 +985,14 @@ static void dump(const char* path, const std::set<cpu_type_t>& onlyArchs, bool s
                                                else
                                                        throw "in universal file, x86_64 slice does not contain x86_64 mach-o";
                                                break;
                                                else
                                                        throw "in universal file, x86_64 slice does not contain x86_64 mach-o";
                                                break;
+#if SUPPORT_ARCH_arm64
+                                       case CPU_TYPE_ARM64:
+                                               if ( UnwindPrinter<arm64>::validFile(p + offset) )
+                                                       UnwindPrinter<arm64>::make(p + offset, size, path, showFunctionNames);
+                                               else
+                                                       throw "in universal file, arm64 slice does not contain arm mach-o";
+                                               break;
+#endif
                                        default:
                                                        throwf("in universal file, unknown architecture slice 0x%x\n", cputype);
                                        }
                                        default:
                                                        throwf("in universal file, unknown architecture slice 0x%x\n", cputype);
                                        }
@@ -887,6 +1005,11 @@ static void dump(const char* path, const std::set<cpu_type_t>& onlyArchs, bool s
                else if ( UnwindPrinter<x86_64>::validFile(p) && onlyArchs.count(CPU_TYPE_X86_64) ) {
                        UnwindPrinter<x86_64>::make(p, length, path, showFunctionNames);
                }
                else if ( UnwindPrinter<x86_64>::validFile(p) && onlyArchs.count(CPU_TYPE_X86_64) ) {
                        UnwindPrinter<x86_64>::make(p, length, path, showFunctionNames);
                }
+#if SUPPORT_ARCH_arm64
+               else if ( UnwindPrinter<arm64>::validFile(p) && onlyArchs.count(CPU_TYPE_ARM64) ) {
+                       UnwindPrinter<arm64>::make(p, length, path, showFunctionNames);
+               }
+#endif         
                else {
                        throw "not a known file type";
                }
                else {
                        throw "not a known file type";
                }
@@ -913,6 +1036,10 @@ int main(int argc, const char* argv[])
                                                onlyArchs.insert(CPU_TYPE_I386);
                                        else if ( strcmp(arch, "x86_64") == 0 )
                                                onlyArchs.insert(CPU_TYPE_X86_64);
                                                onlyArchs.insert(CPU_TYPE_I386);
                                        else if ( strcmp(arch, "x86_64") == 0 )
                                                onlyArchs.insert(CPU_TYPE_X86_64);
+#if SUPPORT_ARCH_arm64
+                                       else if ( strcmp(arch, "arm64") == 0 )
+                                               onlyArchs.insert(CPU_TYPE_ARM64);
+#endif
                                        else 
                                                throwf("unknown architecture %s", arch);
                                }
                                        else 
                                                throwf("unknown architecture %s", arch);
                                }
@@ -932,6 +1059,9 @@ int main(int argc, const char* argv[])
                if ( onlyArchs.size() == 0 ) {
                        onlyArchs.insert(CPU_TYPE_I386);
                        onlyArchs.insert(CPU_TYPE_X86_64);
                if ( onlyArchs.size() == 0 ) {
                        onlyArchs.insert(CPU_TYPE_I386);
                        onlyArchs.insert(CPU_TYPE_X86_64);
+#if SUPPORT_ARCH_arm64
+                       onlyArchs.insert(CPU_TYPE_ARM64);
+#endif
                }
                
                // process each file
                }
                
                // process each file
index 41cf6cf51de07467ebd7314603cfcc8df55a549d..fdb62126dbe893a6deef7719d4b80648c0cfebed 100644 (file)
@@ -125,6 +125,17 @@ else
   FILEARCH = $(ARCH)
 endif
 
   FILEARCH = $(ARCH)
 endif
 
+ifeq ($(ARCH),arm64)
+  LDFLAGS := -syslibroot $(IOS_SDK)
+  CC = $(shell xcrun --sdk iphoneos.internal -find clang) -arch ${ARCH} -ccc-install-dir ${LD_PATH} -miphoneos-version-min=7.0 -isysroot $(IOS_SDK)
+  CXX = $(shell xcrun --sdk iphoneos.internal -find clang++) -arch ${ARCH} -ccc-install-dir ${LD_PATH} -miphoneos-version-min=7.0 -isysroot $(IOS_SDK)
+  VERSION_NEW_LINKEDIT = -miphoneos-version-min=7.0
+  VERSION_OLD_LINKEDIT = -miphoneos-version-min=3.0
+  LD_SYSROOT = -syslibroot $(IOS_SDK)
+  LD_NEW_LINKEDIT = -ios_version_min 7.0
+else
+  FILEARCH = $(ARCH)
+endif
 
 RM      = rm
 RMFLAGS = -rf
 
 RM      = rm
 RMFLAGS = -rf
diff --git a/unit-tests/test-cases/coalesce-force/Makefile b/unit-tests/test-cases/coalesce-force/Makefile
new file mode 100644 (file)
index 0000000..92aadd7
--- /dev/null
@@ -0,0 +1,45 @@
+##
+# Copyright (c) 2013 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
+
+#
+# Test -force_symbols_coalesce_list
+#
+
+
+run: all
+
+all:   
+       ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo.dylib 
+       ${DYLDINFO} -weak_bind libfoo.dylib | grep _foo1 | ${FAIL_IF_STDIN}
+       ${DYLDINFO} -weak_bind libfoo.dylib | grep _wildcheck | ${FAIL_IF_STDIN}
+       ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo2.dylib -Wl,-force_symbols_coalesce_list,foo.exp
+       ${DYLDINFO} -weak_bind libfoo2.dylib | grep _foo1 | ${FAIL_IF_EMPTY}
+       ${DYLDINFO} -weak_bind libfoo2.dylib | grep _wildcheck | ${FAIL_IF_EMPTY}
+       ${PASS_IFF_GOOD_MACHO} libfoo2.dylib
+
+
+               
+clean:
+       rm -rf libfoo.dylib  libfoo2.dylib
diff --git a/unit-tests/test-cases/coalesce-force/foo.c b/unit-tests/test-cases/coalesce-force/foo.c
new file mode 100644 (file)
index 0000000..411d4c0
--- /dev/null
@@ -0,0 +1,21 @@
+
+
+void foo1() {}
+void foo3() {}
+
+
+__attribute__((weak)) void foo2() {}
+__attribute__((weak)) void foo4() {}
+
+
+void wildcheck() {}
+void willnot() {}
+
+
+
+__attribute__((weak)) void patterncheck() {}
+__attribute__((weak)) void patnot() {}
+
+
+void* pointers[] = { &foo1, &foo2, &foo3, &foo4, &wildcheck, &willnot, &patterncheck, &patnot };
+
diff --git a/unit-tests/test-cases/coalesce-force/foo.exp b/unit-tests/test-cases/coalesce-force/foo.exp
new file mode 100644 (file)
index 0000000..7268896
--- /dev/null
@@ -0,0 +1,2 @@
+_foo1
+_wild*
index 0897726e45e5baa95b9c3a5a632168cfa13de79c..b1e7fd5be2a61d03a56e8a9c0a6eaa73767a7435 100644 (file)
@@ -29,9 +29,12 @@ include ${TESTROOT}/include/common.makefile
 
 all: 
        ${CC} ${CCFLAGS} -c test.s -o test.o
 
 all: 
        ${CC} ${CCFLAGS} -c test.s -o test.o
+       ${CC} ${CCFLAGS} test.o -dynamiclib -o libtest.dylib
+       dyldinfo -arch ${ARCH} -data_in_code libtest.dylib| ${FAIL_IF_EMPTY}
        ${LD} -r -arch ${ARCH} test.o -o test2.o
        ${LD} -r -arch ${ARCH} test.o -o test2.o
-       #nm main | grep _dtrace_probe | ${FAIL_IF_EMPTY}
-       #${PASS_IFF_GOOD_MACHO} main
+       ${CC} ${CCFLAGS} test2.o -dynamiclib -o libtest2.dylib
+       dyldinfo -arch ${ARCH} -data_in_code libtest2.dylib| ${FAIL_IF_EMPTY}
+       ${PASS_IFF_GOOD_MACHO} libtest.dylib
        
 clean:
        
 clean:
-       rm -rf test.o test2.o
+       rm -rf test.o test2.o libtest.dylib libtest2.dylib
diff --git a/unit-tests/test-cases/data-in-code/main.c b/unit-tests/test-cases/data-in-code/main.c
deleted file mode 100644 (file)
index 811449a..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-
-#include <stdio.h>
-
-#define DTRACE_STRINGIFY(s) #s
-#define DTRACE_TOSTRING(s) DTRACE_STRINGIFY(s)
-
-#define DTRACE_NOPS                    \
-       "nop"                   "\n\t"  \
-       "nop"                   "\n\t"  \
-       "nop"                   "\n\t"  
-
-
-#define DTRACE_LAB(p, n)               \
-   "__dtrace_probe$" DTRACE_TOSTRING(%=__LINE__) DTRACE_STRINGIFY(_##p##___##n)
-
-#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:"
-
-#define DTRACE_CALL(p,n)       \
-       DTRACE_LABEL(p,n)       \
-       DTRACE_NOPS
-
-#define DTRACE_CALL0ARGS(provider, name)                                                       \
-       __asm volatile (                                                                                \
-                     DTRACE_CALL(provider, name)                                               \
-                     :                                                                         \
-                     :                                                                         \
-       );
-
-int deadwood()
-{
-       DTRACE_CALL0ARGS(__foo__, test2)
-       return 0;
-}
-
-
-int main() {
-       int a = 1;
-
-       while(a) {
-               DTRACE_CALL0ARGS(__foo__, test1)
-       }
-
-       return 0;
-}
index 8dc92b885a7503bf93d8785981a264da7884e216..19c2448c63f65b5a441baa1c6ba54a1043531b98 100644 (file)
@@ -4,21 +4,23 @@
 _foo:
        nop
        nop
 _foo:
        nop
        nop
-l$start$data$1:
+ .data_region
        nop
        nop
        nop
        nop
        nop
        nop
-l$start$jt8$2:
+ .data_region jt8
        nop
        nop
        nop
        nop
-l$start$jt16$3: 
+.data_region jt16
        nop
        nop
        nop
        nop
-l$start$code$n4:
+.data_region jt32
        nop
        nop
        nop
        nop
-       
-       
+.end_data_region
+       nop
+       nop
+
        
        .subsections_via_symbols
        
        
        .subsections_via_symbols
        
diff --git a/unit-tests/test-cases/linker_options-framework/Makefile b/unit-tests/test-cases/linker_options-framework/Makefile
new file mode 100644 (file)
index 0000000..3ac482e
--- /dev/null
@@ -0,0 +1,43 @@
+##
+# Copyright (c) 2013 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
+
+#
+# Check linker options work for -framework 
+#
+
+run: all
+
+all:
+       mkdir -p Foo.framework
+       ${CC} ${CCFLAGS} foo.c -dynamiclib -o Foo.framework/Foo
+       ${CC} ${CCFLAGS} main.c -c -o main.o
+       ${LD} -r main.o -add_linker_option '-framework Foo' -o main2.o 
+       ${CC} ${CCFLAGS} main2.o -o main -F.
+       ${DYLDINFO} -lazy_bind main | grep _foo | grep Foo | ${FAIL_IF_EMPTY}
+       ${PASS_IFF_GOOD_MACHO} main
+
+clean:
+       rm -rf main libfoo.dylib main.o main2.o Foo.framework
+       
diff --git a/unit-tests/test-cases/linker_options-framework/foo.c b/unit-tests/test-cases/linker_options-framework/foo.c
new file mode 100644 (file)
index 0000000..e704870
--- /dev/null
@@ -0,0 +1,3 @@
+
+
+void foo() { }
diff --git a/unit-tests/test-cases/linker_options-framework/main.c b/unit-tests/test-cases/linker_options-framework/main.c
new file mode 100644 (file)
index 0000000..4f56fe0
--- /dev/null
@@ -0,0 +1,8 @@
+
+extern void foo();
+
+int main()
+{
+       foo();
+       return 0;
+}
diff --git a/unit-tests/test-cases/linker_options-library/Makefile b/unit-tests/test-cases/linker_options-library/Makefile
new file mode 100644 (file)
index 0000000..93697e5
--- /dev/null
@@ -0,0 +1,44 @@
+##
+# Copyright (c) 2013 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
+
+#
+# Check linker options work for -l 
+#
+
+run: all
+
+all:
+       ${CC} ${CCFLAGS} foo.c -dynamiclib -o libfoo.dylib
+       ${CC} ${CCFLAGS} bar.c -c -o bar.o
+       libtool -static bar.o -o libbar.a
+       ${CC} ${CCFLAGS} main.c -c -o main.o
+       ${LD} -r main.o -add_linker_option -lfoo -add_linker_option -lbar -o main2.o 
+       ${CC} ${CCFLAGS} main2.o -o main -L.
+       ${DYLDINFO} -lazy_bind main | grep _foo | grep libfoo | ${FAIL_IF_EMPTY}
+       ${PASS_IFF_GOOD_MACHO} main
+
+clean:
+       rm -f main libfoo.dylib main.o main2.o bar.o libbar.a
+       
diff --git a/unit-tests/test-cases/linker_options-library/bar.c b/unit-tests/test-cases/linker_options-library/bar.c
new file mode 100644 (file)
index 0000000..981110f
--- /dev/null
@@ -0,0 +1 @@
+void bar() { }
diff --git a/unit-tests/test-cases/linker_options-library/foo.c b/unit-tests/test-cases/linker_options-library/foo.c
new file mode 100644 (file)
index 0000000..e704870
--- /dev/null
@@ -0,0 +1,3 @@
+
+
+void foo() { }
diff --git a/unit-tests/test-cases/linker_options-library/main.c b/unit-tests/test-cases/linker_options-library/main.c
new file mode 100644 (file)
index 0000000..594cf17
--- /dev/null
@@ -0,0 +1,10 @@
+
+extern void foo();
+extern void bar();
+
+int main()
+{
+       foo();
+  bar();
+       return 0;
+}
diff --git a/unit-tests/test-cases/lto-dynamic_export/Makefile b/unit-tests/test-cases/lto-dynamic_export/Makefile
new file mode 100644 (file)
index 0000000..416c5a9
--- /dev/null
@@ -0,0 +1,42 @@
+##
+# Copyright (c) 2012 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
+
+#
+# verify -preload -pie produces relocations
+#
+
+run: all
+
+all:
+       ${CC} ${CCFLAGS} -flto main.c -c -o main.o
+       ${CC} ${CCFLAGS} main.o -o main 
+       nm -g main | grep _bar | ${FAIL_IF_STDIN}
+       ${CC} ${CCFLAGS} main.o -o main-de -Wl,-export_dynamic
+       nm -g main-de  | grep _bar | ${FAIL_IF_EMPTY}
+       ${PASS_IFF_GOOD_MACHO} main-de
+
+       
+clean:
+       rm  main.o main main-de 
diff --git a/unit-tests/test-cases/lto-dynamic_export/main.c b/unit-tests/test-cases/lto-dynamic_export/main.c
new file mode 100644 (file)
index 0000000..bb3ced0
--- /dev/null
@@ -0,0 +1,14 @@
+
+__attribute__((visibility("hidden")))
+void foo() { }
+
+void bar() { }
+
+
+int main()
+{
+  foo();
+  bar();
+
+  return 0;
+}
\ No newline at end of file
diff --git a/unit-tests/test-cases/order_file-archive/Makefile b/unit-tests/test-cases/order_file-archive/Makefile
new file mode 100644 (file)
index 0000000..eb77525
--- /dev/null
@@ -0,0 +1,43 @@
+##
+# Copyright (c) 2013 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
+
+#
+#  Verify order files can pick file in archives
+#
+
+run: all
+
+all:
+       ${CC} ${CCFLAGS} foo.c -c -o foo.o
+       libtool -static foo.o -o libfoo.a 
+       ${CC} ${CCFLAGS} main.c -c -o main.o
+       ${CC} ${CCFLAGS} main.o libfoo.a -Wl,-order_file,main.order -o main
+       ${FAIL_IF_BAD_MACHO} main
+       nm -n -j main | egrep "_main|_foo" > main.actual
+       ${PASS_IFF} diff main.actual main.expected
+
+
+clean:
+       rm -rf *.o libfoo.a main main.actual
diff --git a/unit-tests/test-cases/order_file-archive/foo.c b/unit-tests/test-cases/order_file-archive/foo.c
new file mode 100644 (file)
index 0000000..61be976
--- /dev/null
@@ -0,0 +1,4 @@
+void foo1() { }
+void foo2() {}
+void foo3() {}
+
diff --git a/unit-tests/test-cases/order_file-archive/main.c b/unit-tests/test-cases/order_file-archive/main.c
new file mode 100644 (file)
index 0000000..298aedc
--- /dev/null
@@ -0,0 +1,33 @@
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 
+ *
+ * Copyright (c) 2013 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <stdio.h>
+
+
+extern void foo1();
+
+int main()
+{
+       foo1();
+       return 0;
+}
diff --git a/unit-tests/test-cases/order_file-archive/main.expected b/unit-tests/test-cases/order_file-archive/main.expected
new file mode 100644 (file)
index 0000000..31a7e2f
--- /dev/null
@@ -0,0 +1,4 @@
+_foo2
+_main
+_foo3
+_foo1
diff --git a/unit-tests/test-cases/order_file-archive/main.order b/unit-tests/test-cases/order_file-archive/main.order
new file mode 100644 (file)
index 0000000..195b1d7
--- /dev/null
@@ -0,0 +1,5 @@
+_foo2
+_main
+libfoo.a(foo.o):_foo3
+_foo1
+
index 4da677c6493ef762467b084f01a5309b63b2308c..2ad9e0c834cc931cd27f13ebcb162317ae33f900 100644 (file)
@@ -44,10 +44,12 @@ all:
        ${DYLDINFO}  -bind -lazy_bind main1 | grep _bar | grep libfoo | ${FAIL_IF_EMPTY}
        ${DYLDINFO}  -bind -lazy_bind main1 | grep _bar_weak | grep libfoo | ${FAIL_IF_EMPTY}
 
        ${DYLDINFO}  -bind -lazy_bind main1 | grep _bar | grep libfoo | ${FAIL_IF_EMPTY}
        ${DYLDINFO}  -bind -lazy_bind main1 | grep _bar_weak | grep libfoo | ${FAIL_IF_EMPTY}
 
-       # build library the re-exports _bar from base library as _mybar
-       ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo2.dylib libbar.dylib -Wl,-alias,_bar,_mybar -exported_symbols_list foo2.exp
+       # build library that re-exports _bar from base library as _mybar
+       ${CC} ${CCFLAGS} -dynamiclib foo.c -o libfoo2.dylib libbar.dylib -Wl,-alias,_bar,_mybar -exported_symbols_list foo2.exp -DUSE_MY
        ${FAIL_IF_BAD_MACHO} libfoo2.dylib
        ${DYLDINFO} -export libfoo2.dylib | grep _mybar | grep 're-export' | grep _bar | ${FAIL_IF_EMPTY} 
        ${FAIL_IF_BAD_MACHO} libfoo2.dylib
        ${DYLDINFO} -export libfoo2.dylib | grep _mybar | grep 're-export' | grep _bar | ${FAIL_IF_EMPTY} 
+       ${DYLDINFO} -lazy_bind libfoo2.dylib | grep _bar | grep libbar | ${FAIL_IF_EMPTY} 
+       ${DYLDINFO} -bind libfoo2.dylib | grep _bar | grep libbar | ${FAIL_IF_EMPTY} 
        # link against dylib and verify _mybar is marked as coming from libfoo
        ${CC} ${CCFLAGS} main2.c libfoo2.dylib -o main2
        ${DYLDINFO}  -bind -lazy_bind main2 | grep _mybar | grep libfoo2 | ${FAIL_IF_EMPTY}
        # link against dylib and verify _mybar is marked as coming from libfoo
        ${CC} ${CCFLAGS} main2.c libfoo2.dylib -o main2
        ${DYLDINFO}  -bind -lazy_bind main2 | grep _mybar | grep libfoo2 | ${FAIL_IF_EMPTY}
index 714540a528f1229ec79afafa631f64d324d516dd..61981fe265da2a331dc0be35bb8a1039880666c0 100644 (file)
@@ -1,4 +1,21 @@
+
+#if USE_MY
+  extern int mybar();
+#else
+  extern int bar();
+#endif
+
 int foo(void)
 {
 int foo(void)
 {
-  return 1;
+#if USE_MY
+  return mybar() + 1;
+#else
+  return bar() + 1;
+#endif
 }
 }
+
+#if USE_MY
+  void* p = &mybar;
+#else
+  void* p = &bar;
+#endif