]> 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.
+.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
@@ -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
-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
@@ -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
-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
index dd746686d7f894adcd975fe75e2650852534aac2..4ffd5d86c4f2ff62ace367f656833851182c2e84 100644 (file)
@@ -87,7 +87,7 @@
 /* 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 = (
                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; };
+               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; };
                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; };
                                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 */,
                                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;
                        };
                                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;
                        };
                                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;
                        };
index 4fd6123b73b7b6c7844a96fd1e663b81413ed99c..60b4f10c22fecaaa02e5c3c50fd38864521e5138 100644 (file)
@@ -34,6 +34,7 @@
 #include <mach-o/compact_unwind_encoding.h>
 #include <mach/machine.h>
 #include <stddef.h>
+#include <libunwind.h>
 
 #include "FileAbstraction.hpp"
 
 
 #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;
        #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
 #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 {
        #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;
@@ -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
+#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 }
 };
 
-
 // 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
 //
+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:
-       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:
-       encryption_info_command fields;
+       macho_encryption_info_content<P>        entry;
 };
 
 
@@ -1466,6 +1663,36 @@ private:
        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__
index 447ec7af5e78599f208545b0a27cb6368f7307e2..aed4fa37e6748ddfab1e6afa644fbb7d5ccb7de1 100755 (executable)
@@ -11,17 +11,17 @@ else
 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
-       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
-               echo "#error uknown architecture: $ANARCH" >> ${DERIVED_FILE_DIR}/configure.h
+               echo "#error unknown architecture: $ANARCH" >> ${DERIVED_FILE_DIR}/configure.h
        fi
 done
 
index 11455505dd5c489b34cb4e1418cbad5878d6aa7c..fdf795b2d8bc4c7af2e14b7e96f4489394d7d88b 100644 (file)
@@ -56,6 +56,11 @@ struct arm
        typedef Pointer32<LittleEndian>         P;
 };
 
+struct arm64
+{
+       typedef Pointer64<LittleEndian>         P;
+};
+
 #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*                                        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;
        
@@ -143,6 +144,7 @@ private:
        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;
@@ -192,6 +194,22 @@ HeaderAndLoadCommandsAtom<A>::HeaderAndLoadCommandsAtom(const Options& opts, ld:
                                        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();
@@ -210,6 +228,7 @@ HeaderAndLoadCommandsAtom<A>::HeaderAndLoadCommandsAtom(const Options& opts, ld:
        _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) {
@@ -394,6 +413,17 @@ uint64_t HeaderAndLoadCommandsAtom<A>::size() const
        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>);
                
@@ -465,6 +495,12 @@ uint32_t HeaderAndLoadCommandsAtom<A>::commandsCount() const
        if ( _hasDataInCodeLoadCommand )
                ++count;
 
+       if ( !_linkerOptions.empty() ) {
+               for (ld::relocatable::File::LinkerOptionsList::const_iterator it = _linkerOptions.begin(); it != _linkerOptions.end(); ++it) {
+                       ++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<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<arm64>::cpuType() const { return CPU_TYPE_ARM64; }
 
 
 
@@ -584,6 +622,12 @@ uint32_t HeaderAndLoadCommandsAtom<arm>::cpuSubType() const
        return _state.cpuSubType;
 }
 
+template <>
+uint32_t HeaderAndLoadCommandsAtom<arm64>::cpuSubType() const
+{
+       return CPU_SUBTYPE_ARM64_ALL;
+}
+
 
 
 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
@@ -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;
-       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);
@@ -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
 {
@@ -1384,7 +1471,7 @@ void HeaderAndLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
        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));
        }
 
@@ -1425,6 +1512,12 @@ void HeaderAndLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
 
        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);
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.
@@ -60,6 +61,7 @@
 #include "archive_file.h"
 #include "lto_file.h"
 #include "opaque_section_file.h"
+#include "MachOFileAbstraction.hpp"
 #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;
-                
+
+    result = mach_o::dylib::archName(p);
+    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];
-               sprintf(buf, " 0x%2x", p[i]);
+               sprintf(buf, " 0x%02X", p[i]);
                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 )
-               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) )
@@ -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.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 ) {
@@ -365,12 +373,31 @@ void InputFiles::logDylib(ld::File* file, bool indirect)
                        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);
-                       else
+                       else 
                                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
@@ -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 )
-                               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);
@@ -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);
@@ -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;
+                                       info.options.fIndirectDylib = true;
                                        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;
+               info.options.fIndirectDylib = true;
                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);
        }
-       
+}
+
+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;
@@ -539,9 +637,11 @@ void InputFiles::createIndirectDylibs()
 
 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));
+               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), 
-       _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 ) {
@@ -781,7 +883,8 @@ void InputFiles::parseWorkerThread() {
                        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
@@ -789,8 +892,9 @@ void InputFiles::parseWorkerThread() {
                                        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);
                        }
@@ -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;
-                       } else {
+                       } 
+                       else {
                                _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 )
-                       //      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
-       if ( !_allDirectDylibsLoaded ) 
+       if ( ! info.options.fIndirectDylib ) 
                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));
+       
        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 (!inputInfo->checkFileExists())
+                       if (!inputInfo->checkFileExists(_options))
                                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
 
 
-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();
@@ -986,6 +1092,8 @@ void InputFiles::forEachInitialAtom(ld::File::AtomHandler& handler)
                        {
                                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:
@@ -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 ( _options.dumpDependencyInfo() )
+                                       _options.dumpDependency(Options::depArchive, archive->path());
                        }
                                break;
                        case ld::File::Other:
@@ -1014,6 +1124,8 @@ void InputFiles::forEachInitialAtom(ld::File::AtomHandler& handler)
                file->forEachAtom(handler);
        }
 
+       markExplicitlyLinkedDylibs();
+       addLinkerOptionLibraries(state);
        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
-                        return true;
+                       return true;
                     }
                 }
                 else {
@@ -1145,7 +1257,7 @@ bool InputFiles::searchLibraries(const char* name, bool searchDylibs, bool searc
 
 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() ) {
@@ -1224,4 +1336,3 @@ void InputFiles::dylibs(ld::Internal& state)
 } // 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
-       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;
@@ -90,12 +90,15 @@ private:
        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                                            addLinkerOptionLibraries(ld::Internal& state);
+       bool                                            libraryAlreadyLoaded(const char* path);
        
        // for pipelined linking
-    void                      waitForInputFiles();
+    void                                               waitForInputFiles();
        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;
-       bool                                            _allDirectDylibsLoaded;
        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;
+       ld::File::Ordinal                       _linkerOptionOrdinal;
     
     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);
                }
+               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;
@@ -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>                           _adrpLocations;
 
 
        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::kindStoreTargetAddressX86PCRel32TLVLoad:
+               case ld::Fixup::kindStoreTargetAddressX86PCRel32TLVLoadNowLEA:
                        _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:
+               case ld::Fixup::kindStoreX86PCRel32TLVLoad:
+               case ld::Fixup::kindStoreX86PCRel32TLVLoadNowLEA:
                        _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
@@ -1201,6 +1241,14 @@ void SplitSegInfoAtom<A>::encode() const
                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");
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>);
 }
 
+#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
@@ -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; }
+#if SUPPORT_ARCH_arm64
+template <> uint32_t ExternalRelocationsAtom<arm64>::callReloc() { return ARM64_RELOC_BRANCH26; }
+#endif
+
 template <typename A> 
 uint32_t ExternalRelocationsAtom<A>::callReloc() 
 { 
@@ -1647,6 +1654,205 @@ void SectionRelocationsAtom<arm>::encodeSectionReloc(ld::Internal::FinalSection*
 }
 #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>
index 0131911afd722bb5a9363e7187a5c2f888444ca1..d916c536c120d761726c8bebe46c4b9b82794df8 100644 (file)
@@ -104,19 +104,24 @@ void throwf(const char* format, ...)
        throw t;
 }
 
-bool Options::FileInfo::checkFileExists(const char *p)
+
+bool Options::FileInfo::checkFileExists(const Options& options, const char *p)
 {
        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 ( options.dumpDependencyInfo() )
+               options.dumpDependency(Options::depNotFound, p);
     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),
@@ -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), 
-         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), 
@@ -167,9 +172,14 @@ Options::Options(int argc, const char* argv[])
          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), 
-         fSaveTempFiles(false), fSnapshotRequested(false), fPipelineFifo(NULL)
+         fSaveTempFiles(false), fSnapshotRequested(false), fPipelineFifo(NULL), 
+         fDependencyInfoPath(NULL), fDependencyFileDescriptor(-1)
 {
        this->checkForClassic(argc, argv);
        this->parsePreCommandLineEnvironmentSettings();
@@ -177,10 +187,18 @@ Options::Options(int argc, const char* argv[])
        this->parsePostCommandLineEnvironmentSettings();
        this->reconfigureDefaults();
        this->checkIllegalOptionCombinations();
+       
+       if ( this->dumpDependencyInfo() ) {
+               this->dumpDependency(depOutputFile, fOutputFile);
+               if ( fMapPath != NULL ) 
+               this->dumpDependency(depOutputFile, fMapPath);
+       }
 }
 
 Options::~Options()
 {
+  if ( fDependencyFileDescriptor != -1 )
+       ::close(fDependencyFileDescriptor);
 }
 
 bool Options::errorBecauseOfWarnings() const
@@ -246,7 +264,11 @@ bool Options::allGlobalsAreDeadStripRoots() const
        //
        switch ( fOutputKind ) {
                case Options::kDynamicExecutable:
+                       // <rdar://problem/12839986> Add the -export_dynamic flag 
+                       return fExportDynamic;
                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;
@@ -276,7 +298,6 @@ const char* Options::executablePath()
        return fExecutablePath;
 }
 
-
 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);
 }
 
+bool Options::forceCoalesce(const char* symbolName) const
+{
+       return fForceCoalesceSymbols.contains(symbolName);
+}
+
 
 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          
                                        }
-                                       if ( !fMakeCompressedDyldInfo && minOS(ld::mac10_6, ld::iOS_3_1) && !fMakeCompressedDyldInfoForceOff )
-                                               fMakeCompressedDyldInfo = true;
                                        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);
-                               #elif defined(DEFAULT_MACOSX_MIN_VERSION)
-                                               warning("-macosx_version_min not specified, assuming " DEFAULT_MACOSX_MIN_VERSION);
-                                               setMacOSXVersionMin(DEFAULT_MACOSX_MIN_VERSION);
                                #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
                                        }
-                                       if ( !fMakeCompressedDyldInfo && minOS(ld::mac10_6, ld::iOS_3_1) && !fMakeCompressedDyldInfoForceOff )
-                                               fMakeCompressedDyldInfo = true;
                                        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;
                }
        }
@@ -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);
-       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;
 }
 
 
-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) ) {
-               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;
@@ -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 ) {
-                                       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;
                                        }
-                                       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;
@@ -625,7 +653,7 @@ Options::FileInfo Options::findLibrary(const char* rootName, bool 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;
@@ -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
-                               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;
@@ -654,7 +682,7 @@ Options::FileInfo Options::findLibrary(const char* rootName, bool dylibsOnly)
        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";
@@ -670,9 +698,9 @@ Options::FileInfo Options::findFramework(const char* frameworkName)
        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?
@@ -693,7 +721,7 @@ Options::FileInfo Options::findFramework(const char* rootName, const char* suffi
                        }
                }
         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);
@@ -724,13 +752,13 @@ Options::FileInfo Options::findFile(const char* path) const
                        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
-       if ( result.checkFileExists(path) ) {
+       if ( result.checkFileExists(*this, path) ) {
                return result;
        }
 
@@ -743,7 +771,7 @@ Options::FileInfo Options::findFile(const char* path) const
                        strcpy(&addPoint[1], &path[17]);
                else
                        strcpy(newPath, &path[17]);
-               if ( result.checkFileExists(newPath) ) {
+               if ( result.checkFileExists(*this, newPath) ) {
                        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);
 }
+
+
 
 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));
+                       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));
+               if ( this->dumpDependencyInfo() )
+                       this->dumpDependency(Options::depFileList, fileOfPaths);
        }
 
        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 ( this->dumpDependencyInfo() )
+               this->dumpDependency(Options::depMisc, fileOfExports);
+
        ::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);
+       if ( this->dumpDependencyInfo() )
+               this->dumpDependency(Options::depMisc, fileOfAliases);
 
        // 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]) ) {
-               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 {
@@ -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';
+       if ( this->dumpDependencyInfo() )
+               this->dumpDependency(Options::depMisc, path);
 
        // 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];
                                        }
+                                       else {
+                                               colon = strstr(symbolStart, ".o):");
+                                               if ( colon != NULL ) {
+                                                       colon[3] = '\0';
+                                                       objFileName = symbolStart;
+                                                       symbolStart = &colon[4];
+                                               }
+                                       }
                                        // 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 ) {
-                               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]);
+                               fTargetIOSSimulator = true;
                        }
                        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);
                        }
+                       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;
                        }
@@ -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, "-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;
@@ -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(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);
                        }
@@ -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], "-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();
@@ -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);
-                       #elif defined(DEFAULT_MACOSX_MIN_VERSION)
-                                               warning("-macosx_version_min not specified, assuming " DEFAULT_MACOSX_MIN_VERSION);
-                                               setMacOSXVersionMin(DEFAULT_MACOSX_MIN_VERSION);
                        #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:
-                                       // architecture will be infered ;ater by examining .o files
+                                       // architecture will be infered later by examining .o files
                                        break;
                        }
                }
@@ -3229,6 +3369,12 @@ void Options::reconfigureDefaults()
                                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
@@ -3263,6 +3409,14 @@ void Options::reconfigureDefaults()
                                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
@@ -3475,6 +3629,7 @@ void Options::reconfigureDefaults()
        switch ( fArchitecture ) {
                case CPU_TYPE_I386:             
                case CPU_TYPE_X86_64:           
+               case CPU_TYPE_ARM64:            
                        switch ( fOutputKind ) {
                                case Options::kObjectFile:
                                case Options::kStaticExecutable:
@@ -3501,10 +3656,10 @@ void Options::reconfigureDefaults()
                        break;
        }
                
-       // only ARM main executables can be encrypted
+       // only iOS main executables should be encrypted
        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
@@ -3554,7 +3709,6 @@ void Options::reconfigureDefaults()
                        fMakeCompressedDyldInfo = false;
        }
 
-
        // 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;
 
+       // arm64 is always PIE
+       if ( (fArchitecture == CPU_TYPE_ARM64) && (fOutputKind == kDynamicExecutable) ) {
+               fPositionIndependentExecutable = true;
+       }
+
        // set fOutputSlidable
        switch ( fOutputKind ) {
                case Options::kObjectFile:
@@ -3653,13 +3812,6 @@ void Options::reconfigureDefaults()
                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;
        }
        
@@ -3699,12 +3851,7 @@ void Options::reconfigureDefaults()
                                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";
                                }
@@ -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()
@@ -3890,6 +4101,7 @@ void Options::checkIllegalOptionCombinations()
                                        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 )
@@ -3917,11 +4129,19 @@ void Options::checkIllegalOptionCombinations()
                                        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_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";
@@ -4018,6 +4238,10 @@ void Options::checkIllegalOptionCombinations()
        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) {
@@ -4028,6 +4252,7 @@ void Options::checkIllegalOptionCombinations()
                        break;
                case CPU_TYPE_X86_64:
                case CPU_TYPE_ARM:
+               case CPU_TYPE_ARM64:
                        alterObjC1ClassNamesToObjC2 = true;
                        break;
        }
@@ -4123,6 +4348,7 @@ void Options::checkIllegalOptionCombinations()
                                // 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;
@@ -4392,3 +4618,41 @@ const char* Options::demangleSymbol(const char* sym) const
        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), 
-                                               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;
+       bool            fIndirectDylib;
        // 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.
-        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; }
-};
+       };
 
        struct ExtraSection {
                const char*                             segmentName;
@@ -170,6 +172,13 @@ public:
                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();
@@ -322,25 +331,38 @@ public:
        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                                            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                                            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; }
+       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; }
-       
+       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;
@@ -372,9 +394,7 @@ private:
        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*);
@@ -441,6 +461,7 @@ private:
        SetWithWildcards                                        fForceWeakSymbols;
        SetWithWildcards                                        fForceNotWeakSymbols;
        SetWithWildcards                                        fReExportSymbols;
+       SetWithWildcards                                        fForceCoalesceSymbols;
        NameSet                                                         fRemovedExports;
        NameToOrder                                                     fExportSymbolsOrder;
        ExportMode                                                      fExportMode;
@@ -464,6 +485,7 @@ private:
        const char*                                                     fDyldInstallPath;
        const char*                                                     fTempLtoObjectPath;
        const char*                                                     fOverridePathlibLTO;
+       const char*                                                     fLtoCpu;
        uint64_t                                                        fZeroPageSize;
        uint64_t                                                        fStackSize;
        uint64_t                                                        fStackAddr;
@@ -562,6 +584,14 @@ private:
        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;
@@ -582,10 +612,13 @@ private:
        std::vector<const char*>                        fFrameworkSearchPaths;
        std::vector<const char*>                        fSDKPaths;
        std::vector<const char*>                        fDyldEnvironExtras;
+       std::vector< std::vector<const char*> > fLinkerOptions;
        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;
+                               uint32_t atomModulus = atom->alignment().modulus;
                                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:
+                                                       if ( contiguousObjCSection ) 
+                                                               break;
                                                        pagePerAtom = true;
-                                                       if ( atomAlignmentPowerOf2 < 12 )
+                                                       if ( atomAlignmentPowerOf2 < 12 ) {
                                                                atomAlignmentPowerOf2 = 12;
+                                                               atomModulus = 0;
+                                                       }
                                                        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);
-                               uint64_t requiredModulus = atom->alignment().modulus;
+                               uint64_t requiredModulus = atomModulus;
                                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); }
@@ -1023,16 +1060,18 @@ void OutputFile::applyFixUps(ld::Internal& state, uint64_t mhAddress, const ld::
                                        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;
@@ -1229,6 +1268,18 @@ void OutputFile::applyFixUps(ld::Internal& state, uint64_t mhAddress, const ld::
                                        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:
@@ -1504,6 +1555,126 @@ void OutputFile::applyFixUps(ld::Internal& state, uint64_t mhAddress, const ld::
                                        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 ) 
-                       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 )
@@ -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);
                }
+               ::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 ) {
-                               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);
@@ -1929,7 +2111,6 @@ void OutputFile::buildSymbolTable(ld::Internal& state)
                                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()) ) {
@@ -2048,9 +2229,29 @@ void OutputFile::addPreloadLinkEdit(ld::Internal& state)
                                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:
-                       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;
+#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";
@@ -2257,6 +2516,12 @@ void OutputFile::addLoadCommands(ld::Internal& state)
                        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);
@@ -2430,8 +2695,26 @@ bool OutputFile::isPcRelStore(ld::Fixup::Kind kind)
                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:
+#if SUPPORT_ARCH_arm64
+               case ld::Fixup::kindStoreTargetAddressARM64Branch26:
+#endif
                        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::kindStoreTargetAddressX86PCRel32TLVLoadNowLEA:
                case ld::Fixup::kindStoreTargetAddressX86Abs32TLVLoad:
                case ld::Fixup::kindStoreTargetAddressARMBranch24:
                case ld::Fixup::kindStoreTargetAddressThumbBranch22:
                case ld::Fixup::kindStoreTargetAddressARMLoad12:
+#if SUPPORT_ARCH_arm64
+               case ld::Fixup::kindStoreTargetAddressARM64Branch26:
+               case ld::Fixup::kindStoreTargetAddressARM64Page21:
+               case ld::Fixup::kindStoreTargetAddressARM64PageOff12:
+               case ld::Fixup::kindStoreTargetAddressARM64GOTLoadPage21:
+               case ld::Fixup::kindStoreTargetAddressARM64GOTLoadPageOff12:
+               case ld::Fixup::kindStoreTargetAddressARM64GOTLeaPage21:
+               case ld::Fixup::kindStoreTargetAddressARM64GOTLeaPageOff12:
+#endif
                        return true;
                case ld::Fixup::kindStoreX86DtraceCallSiteNop:
                case ld::Fixup::kindStoreX86DtraceIsEnableSiteClear:
                case ld::Fixup::kindStoreARMDtraceCallSiteNop:
                case ld::Fixup::kindStoreARMDtraceIsEnableSiteClear:
+               case ld::Fixup::kindStoreARM64DtraceCallSiteNop:
+               case ld::Fixup::kindStoreARM64DtraceIsEnableSiteClear:
                case ld::Fixup::kindStoreThumbDtraceCallSiteNop:
                case ld::Fixup::kindStoreThumbDtraceIsEnableSiteClear:
                        return (_options.outputKind() == Options::kObjectFile);
@@ -2590,6 +2885,7 @@ void OutputFile::generateLinkEditInfo(ld::Internal& state)
                        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;
@@ -2624,9 +2920,11 @@ void OutputFile::generateLinkEditInfo(ld::Internal& state)
                                switch ( fit->kind ) {
                                        case ld::Fixup::kindAddAddend:
                                                targetAddend = fit->u.addend;
+                                               fixupWithAddend = fit;
                                                break;
                                        case ld::Fixup::kindSubtractAddend:
                                                minusTargetAddend = fit->u.addend;
+                                               fixupWithAddend = fit;
                                                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 ) {
-                                                       this->addSectionRelocs(state, sect, atom, fixupWithTarget, fixupWithMinusTarget, fixupWithStore,
+                                                       this->addSectionRelocs(state, sect, atom, fixupWithTarget, fixupWithMinusTarget, fixupWithAddend, fixupWithStore,
                                                                                                        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 ) {
-                       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());
+                       }
                }
                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-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;
                                }
+                               // <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. "
@@ -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
                        }
                }
-               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/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 {
@@ -2873,6 +3191,9 @@ void OutputFile::addDyldInfo(ld::Internal& state,  ld::Internal::FinalSection* s
                                                needsRebase = false;
                                                needsBinding = true;
                                        }
+                                       else if ( _options.forceCoalesce(target->name()) ) {
+                                               needsWeakBinding = true;
+                                       }
                                }
                                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 ) {
@@ -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;
                }
-               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)
-                                               && (_options.outputKind() != Options::kPreload) ) {
+                                               && (_options.outputKind() != Options::kPreload) 
+                                               && (atom != target) ) {
                                                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:
+#if SUPPORT_ARCH_arm64
+               case ld::Fixup::kindStoreTargetAddressARM64Branch26:
+#endif
                        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)
 {
-       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 );
        }
        
@@ -3127,11 +3472,29 @@ bool OutputFile::useExternalSectionReloc(const ld::Atom* atom, const ld::Atom* t
        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, 
-                                                               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)
 {
@@ -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);
        
-       // 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 ( this->useSectionRelocAddend(fixupWithStore) && (fixupWithAddend != NULL) )
+                               fixupWithAddend->contentIgnoresAddend = 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::kindStoreX86PCRel32TLVLoad:
+                                       case ld::Fixup::kindStoreX86PCRel32TLVLoadNowLEA:
                                        case ld::Fixup::kindStoreTargetAddressX86PCRel32:
                                        case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoad:
                                        case ld::Fixup::kindStoreTargetAddressX86PCRel32GOTLoadNowLEA:
+                                       case ld::Fixup::kindStoreTargetAddressX86PCRel32TLVLoad:
+                                       case ld::Fixup::kindStoreTargetAddressX86PCRel32TLVLoadNowLEA:
                     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));
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, 
-                                                                                               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,  
@@ -169,6 +170,7 @@ private:
                                                                                                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);
@@ -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);
+       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);
index ad4b22dbd287eaa7c81666574f7a683ad03354a2..25d0c666d0571567a85203146decb7b5f87ad695 100644 (file)
@@ -132,6 +132,7 @@ public:
 
        void                                                                    setFinalAliasOf() const {
                                                                                                (const_cast<AliasAtom*>(this))->setAttributesFromAtom(_aliasOf);
+                                                                                               (const_cast<AliasAtom*>(this))->setScope(ld::Atom::scopeGlobal);
                                                                                        }
                                                                                                                        
 private:
@@ -281,13 +282,21 @@ void Resolver::initializeState()
                _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);
-       _inputFiles.forEachInitialAtom(*this);
+       _inputFiles.forEachInitialAtom(*this, _internal);
     
        _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 ) {
+               // 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:
@@ -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());
-                               _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;
+                               if ( _options.targetIOSSimulator() )
+                                       warning("linking ObjC for iOS Simulator, but object file (%s) was compiled for MacOSX", file.path());
                                break;
                        case ld::File::objcConstraintGC:
                                if ( _internal.objcObjectConstraint == ld::File::objcConstraintRetainRelease )
                                        throwf("%s built with incompatible Garbage Collection settings to link with previous .o files", file.path());
                                _internal.objcObjectConstraint = ld::File::objcConstraintGC;
+                               if ( _options.targetIOSSimulator() )
+                                       warning("linking ObjC for iOS Simulator, but object file (%s) was compiled for MacOSX", file.path());
+                               break;
+                       case ld::File::objcConstraintRetainReleaseForSimulator:
+                               if ( _internal.objcObjectConstraint == ld::File::objcConstraintNone ) {
+                                       if ( !_options.targetIOSSimulator() && (_options.outputKind() != Options::kObjectFile) )
+                                               warning("ObjC object file (%s) was compiled for iOS Simulator, but linking for MacOSX", file.path());
+                                       _internal.objcObjectConstraint = ld::File::objcConstraintRetainReleaseForSimulator;
+                               }
+                               else if ( _internal.objcObjectConstraint != ld::File::objcConstraintRetainReleaseForSimulator ) {
+                                       _internal.objcObjectConstraint = ld::File::objcConstraintRetainReleaseForSimulator;
+                               }
                                break;
                }
        
@@ -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());
+                               if ( _options.targetIOSSimulator() )
+                                       warning("linking ObjC for iOS Simulator, but dylib (%s) was compiled for MacOSX", file.path());
                                _internal.objcDylibConstraint = ld::File::objcConstraintRetainRelease;
                                break;
                        case ld::File::objcConstraintRetainReleaseOrGC:
                                if ( _internal.objcDylibConstraint == ld::File::objcConstraintNone )
                                        _internal.objcDylibConstraint = ld::File::objcConstraintRetainReleaseOrGC;
+                               if ( _options.targetIOSSimulator() )
+                                       warning("linking ObjC for iOS Simulator, but dylib (%s) was compiled for MacOSX", file.path());
                                break;
                        case ld::File::objcConstraintGC:
                                if ( _internal.objcDylibConstraint == ld::File::objcConstraintRetainRelease )
                                        throwf("%s built with incompatible Garbage Collection settings to link with previous dylibs", file.path());
-                               _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;
                }
        }
@@ -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::kindStoreARM64DtraceCallSiteNop:
+               case ld::Fixup::kindStoreARM64DtraceIsEnableSiteClear:
                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;
@@ -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::kindNoneGroupSubordinatePersonality:
                        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:
+#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
@@ -1338,7 +1433,10 @@ void Resolver::linkTimeOptimize()
        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.mcpu                                                     = _options.mcpuLTO();
        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                                 fillInEntryPoint();
+       void                                    fillInEntryPoint();
        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                                    doLinkerOption(const std::vector<const char*>& linkerOption, const char* fileName);
 
        typedef std::unordered_set<const char*, CStringHash, CStringEquals>  StringSet;
 
index 2ea690fa2eb1aea3dd2387f00dc404f0e5858ccb..309de8b6835fa155c00733903cdb9d79d60cdac3 100644 (file)
@@ -312,6 +312,7 @@ private:
        }
        
        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:
@@ -320,6 +321,12 @@ private:
                                                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:
@@ -334,6 +341,12 @@ private:
                        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:
index 411dbbc94d9bd40b023b4a4cfe831a73b954fcca..ecdf89897235977ae4fc57388a5299232a7af208 100644 (file)
@@ -62,9 +62,15 @@ enum {
   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,
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:
+                               // <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
-                               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;
@@ -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;
-               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;
index 7be00a3a624af6cc79a5cda5f865a42ac8e30f86..42d5aa62713136f237a5a353a501dac87343956b 100644 (file)
@@ -32,8 +32,9 @@
 #include <assert.h>
 
 #include <vector>
-#include <set>
+#include <unordered_set>
 
+#include "configure.h"
 
 namespace ld {
 
@@ -51,7 +52,9 @@ namespace ld {
 class File
 {
 public:
-       enum ObjcConstraint { objcConstraintNone, objcConstraintRetainRelease, objcConstraintRetainReleaseOrGC, objcConstraintGC };
+       enum ObjcConstraint { objcConstraintNone, objcConstraintRetainRelease, 
+                                                       objcConstraintRetainReleaseOrGC, objcConstraintGC,
+                                                       objcConstraintRetainReleaseForSimulator };
        
        class AtomHandler {
        public:
@@ -84,7 +87,7 @@ public:
                
                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);
                }
@@ -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.
-               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 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.
-               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.
-               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;
@@ -155,10 +163,10 @@ private:
 //
 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,
-                                               iOS_6_0=0x00060000, iOS_Future=0x10000000};
+                                               iOS_6_0=0x00060000, iOS_7_0=0x00070000, iOS_Future=0x10000000};
  
 namespace relocatable {
        //
@@ -189,6 +197,7 @@ namespace relocatable {
                        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) { }
@@ -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 LinkerOptionsList*                      linkerOptions() const = 0;
        };
 } // 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                                            installPathVersionSpecific() const { return false; }
        protected:
                const char*                                                     _dylibInstallPath;
                uint32_t                                                        _dylibTimeStamp;
@@ -391,10 +402,20 @@ struct Fixup
                                        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,
+                                       kindStoreARM64DtraceCallSiteNop, kindStoreARM64DtraceIsEnableSiteClear,
                                        kindStoreThumbDtraceCallSiteNop, kindStoreThumbDtraceIsEnableSiteClear,
                                        // lazy binding
                                        kindLazyTarget, kindSetLazyOffset,
@@ -421,6 +442,16 @@ struct Fixup
                                        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 {
@@ -436,52 +467,53 @@ struct Fixup
        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),  
-               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),  
-               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),  
-               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),  
-               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),  
-               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),  
-               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),  
-               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),  
-               contentAddendOnly(false), contentDetlaToAddendOnly(false) 
+               contentAddendOnly(false), contentDetlaToAddendOnly(false), contentIgnoresAddend(false) 
                        { u.addend = addend; }
                        
        bool firstInCluster() const { 
@@ -611,7 +643,7 @@ public:
                                                                                                                switch ( _combine ) {
                                                                                                                        case combineByNameAndContent:
                                                                                                                        case combineByNameAndReferences:
-                                                                                                                               assert(_symbolTableInclusion == symbolTableNotIn);
+                                                                                                                               assert(_symbolTableInclusion != symbolTableIn);
                                                                                                                                assert(_scope != scopeGlobal);
                                                                 break;
                                                             case combineByName:
@@ -692,7 +724,6 @@ protected:
                                                                                                        _combine = a._combine;
                                                                                                        _dontDeadStrip = a._dontDeadStrip;
                                                                                                        _thumb = a._thumb;
-                                                                                                       _alias = a._alias;
                                                                                                        _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:
@@ -757,6 +805,7 @@ public:
                bool                                                    hasExternalRelocs;
        };
        
+
        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;
+       CStringSet                                                                      linkerOptionLibraries;
+       CStringSet                                                                      linkerOptionFrameworks;
        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;
@@ -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<arm64>::architecture()  { return CPU_TYPE_ARM64; }
 
 
 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
 {
-       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;
-               uint16_t index;
+               uint32_t index;
                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;
+#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;
index b04582d80b18fd88a00be1e7a9bdf1bbef26ee73..c67a2372bbb30c0b0f258a5d62817056bfcc03da 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- 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@
  *
@@ -95,7 +95,8 @@ public:
        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, 
@@ -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]);
+                                                                                               
+       // 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, 
-                                                                                               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;
@@ -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));
-                       // 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;
@@ -243,34 +256,60 @@ const char* DwarfInstructions<A,R>::parseCFIs(A& addressSpace, pint_t ehSectionS
                                }
                                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 {
-                               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;
        }
-       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
 }
 
@@ -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 ) {
-                               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) {
@@ -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;
                        }
-                       pint_t functionContentAdjustStackIns = funcAddr + prolog.codeOffsetAtStackDecrement - 4;                
+                       pint_t functionContentAdjustStackIns = funcAddr + prolog.codeOffsetAtStackDecrement - 4;
+        #if __EXCEPTIONS 
                        try {
+        #endif
                                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;
                        }
+        #endif
                        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 ) {
-                               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) {
@@ -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;                
-                       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 ) {
-                               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;
@@ -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
 
index 3824d2e2f80d837ffa5613b608341354e307216a..2e4a3bbeb43cb217d71c49fe1c5e4aada26714a8 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- 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@
  *
index 7d39fd74ad9eb5b72acdaf7e4aba32425be4b585..02470665623f62a79df30e548de1ec03862adef1 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- 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@
  *
@@ -1035,9 +1035,288 @@ inline const char* Registers_ppc::getRegisterName(int regNum)
                        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 
 
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; }
+       virtual LinkerOptionsList*                                                      linkerOptions() const           { return NULL; }
+
 
        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.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
@@ -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,
@@ -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();
+       // <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) {
-               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
@@ -481,6 +501,10 @@ bool Parser::optimize(  const std::vector<const ld::Atom*>&        allAtoms,
                ::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 
@@ -775,7 +799,8 @@ void Parser::AtomSyncer::doAtom(const ld::Atom& machoAtom)
                                                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;
index 3503fa9a69a4300475bc7bb09a01bf9d5e3e51ee..4140a3ae4bc27944c6fbb8f4a9db6d02cc33e33d 100644 (file)
@@ -53,7 +53,10 @@ struct OptimizeOptions {
        bool                                                            relocatable;
        bool                                                            allowTextRelocs; 
        bool                                                            linkerDeadStripping; 
+       bool                                                            needsUnwindInfoSection; 
+       bool                                                            keepDwarfUnwind; 
        cpu_type_t                                                      arch;
+       const char*                                                     mcpu;
        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.
@@ -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, 
-                                                                                                       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() {}
 
@@ -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                                                    installPathVersionSpecific() const { return _installPathOverride; }
 
 
 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                                                                            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,
@@ -206,6 +209,7 @@ private:
        
        const ld::MacVersionMin                                         _macVersionMin;
        const ld::IOSVersionMin                                         _iOSVersionMin;
+       const bool                                                                      _allowSimToMacOSXLinking;
        const bool                                                                      _addVersionLoadCommand;
        bool                                                                            _linkingFlat;
        bool                                                                            _implicitlyLinkPublicDylibs;
@@ -225,7 +229,9 @@ private:
        bool                                                                            _hasPublicInstallName;
        mutable bool                                                            _providedAtom;
        bool                                                                            _explictReExportFound;
-
+       bool                                                                            _wrongOS;
+       bool                                                                            _installPathOverride;
+       
        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,
-                               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), 
-       _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),
@@ -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), 
-        _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();
@@ -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:
-                               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:
-                               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;
@@ -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_IS_SIMULATED  32
                                                        //
                                                        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;
+                                                               else if ( (flags & 32) == 32 )
+                                                                       _objcContraint = ld::File::objcConstraintRetainReleaseForSimulator;
                                                                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;
+                                               _installPathOverride = true;
                                                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 ( 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());
@@ -866,6 +882,7 @@ public:
        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) {
@@ -875,6 +892,7 @@ public:
                                                                                                                                                        opts.implicitlyLinkIndirectPublicDylibs(), 
                                                                                                                                                        opts.macosxVersionMin(), 
                                                                                                                                                        opts.iOSVersionMin(),
+                                                                                                                                                       opts.allowSimulatorToLinkWithMacOSX(),
                                                                                                                                                        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
 //
@@ -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;
+#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;
index ad03af1af1c9e0f5811037018f0f7331bfd55f82..4d093f139d921e3528a32e3bcb42eb74d972c2fd 100644 (file)
 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);
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 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 LinkerOptionsList*                                                      linkerOptions() const                   { return &_linkerOptions; }
        
        const uint8_t*                                                                          fileContent()                                   { return _fileContent; }
 private:
@@ -123,6 +124,7 @@ private:
        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 bool                                    ignoreLabel(const char* label) const { return false; }
        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;
        
-       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();
@@ -274,6 +277,7 @@ public:
 
        uint32_t                                count();
        void                                    parse(class Parser<A>& parser, uint32_t cnt, Info array[]);
+       static bool                             encodingMeansUseDwarf(compact_unwind_encoding_t enc);
        
        
 private:
@@ -379,16 +383,17 @@ protected:
        
        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 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>
 {
@@ -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 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;
@@ -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 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;
@@ -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 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, 
@@ -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 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;
@@ -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 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;
 };
@@ -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 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;
@@ -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 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; }
@@ -865,7 +870,8 @@ public:
                                                                                                                        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);
                                                                                                                }
 
@@ -934,7 +940,7 @@ public:
                _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);
@@ -971,9 +977,11 @@ public:
        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                                                                                    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; }
        
@@ -989,7 +997,7 @@ public:
                                                                        : 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; }
@@ -1050,8 +1058,8 @@ private:
        
 
                                                                                                        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();
@@ -1106,8 +1114,10 @@ private:
        bool                                                                            _hasLongBranchStubs;
        bool                                                                            _AppleObjc; // FSF has objc that uses different data layout
        bool                                                                            _overlappingSymbols;
-       bool                                                                            _convertUnwindInfo;
+       bool                                                                            _warnUnwindConversionProblems;
        bool                                                                            _hasDataInCodeLabels;
+       bool                                                                            _keepDwarfUnwind;
+       bool                                                                            _forceDwarfConversion;
        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, 
-                                       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),
@@ -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),
-                       _overlappingSymbols(false), _convertUnwindInfo(convertDUI), _hasDataInCodeLabels(false), 
+                       _overlappingSymbols(false), _warnUnwindConversionProblems(convertDUI), _hasDataInCodeLabels(false),
+                       _keepDwarfUnwind(keepDwarfUnwind), _forceDwarfConversion(forceDwarfConversion),
                        _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)
@@ -1222,6 +1246,18 @@ const char* Parser<arm>::fileKind(const uint8_t* fileContent)
        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)
@@ -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>
-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
@@ -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]);
-                       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 ) {
@@ -1381,7 +1419,19 @@ bool Parser<A>::LabelAndCFIBreakIterator::next(Parser<A>& parser, uint32_t sectN
                        *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;
@@ -1459,6 +1509,16 @@ bool Parser<A>::LabelAndCFIBreakIterator::next(Parser<A>& parser, uint32_t sectN
        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>
@@ -1475,7 +1535,7 @@ ld::relocatable::File* Parser<A>::parse(const ParserOptions& opts)
        if ( ! parseLoadCommands() )
                return _file;
        
-       // make array of 
+       // make array of
        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();
-       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);
+
+       // 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 
-       // 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();
-       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
-       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 ) {
-               _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;
-                       //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;
@@ -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
-       pint_t cfiStartsArray[cfiStartsCount];
+       pint_t cfiStartsArray[cfiStartsCount+cuLsdaCount];
        uint32_t countOfFDEs = 0;
+       uint32_t cfiStartsArrayCount = 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 )
-                               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 )
-                               cfiStartsArray[index++] = cfiArray[i].u.fdeInfo.lsda.targetAddress;
+                               cfiStartsArray[cfiStartsArrayCount++] = cfiArray[i].u.fdeInfo.lsda.targetAddress;
                        ++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
-               for(int i=1; i < index; ++i) {
+               for(uint32_t i=1; i < cfiStartsArrayCount; ++i) {
                        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, 
-                                                                                       cfiStartsCount, _overlappingSymbols);
+                                                                                       cfiStartsArrayCount, _overlappingSymbols);
        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, 
-                                                                                               cfiStartsCount, _overlappingSymbols);
+                                                                                               cfiStartsArrayCount, _overlappingSymbols);
        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);
+                       //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
@@ -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();
-               ui.unwindInfo = info->compactUnwindInfo;                
+               ui.unwindInfo = info->compactUnwindInfo;
                _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
@@ -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<arm64>::loadCommandSizeMask()       { return 0x07; }
 
 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";
                                }
+                               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 )
@@ -1984,7 +2089,6 @@ void Parser<A>::makeSortedSymbolsArray(uint32_t array[], const uint32_t sectionA
        }
 }
 
-
 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_IS_SIMULATED  32
                        //
                        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;
+                               else if ( (flags & 32) == 32 )
+                                       _file->_objConstraint = ld::File::objcConstraintRetainReleaseForSimulator;
                                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
-               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)) )
@@ -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;
+#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;
@@ -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);
                }
+               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());
@@ -2922,6 +3056,22 @@ bool Parser<A>::skip_form(const uint8_t ** offset, const uint8_t * end, uint64_t
       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;
     }
@@ -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;
-       if ( ! parser->convertUnwindInfo() ) 
+       if ( ! parser->warnUnwindConversionProblems() ) 
                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;
 }
 
+template <>
+bool CFISection<arm64>::needsRelocating()
+{
+       return true;
+}
+
 template <typename A>
 bool CFISection<A>::needsRelocating()
 {
@@ -3748,9 +3904,9 @@ bool CFISection<A>::needsRelocating()
 }
 
 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[], 
-                                                                       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());
@@ -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);
        
@@ -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(), 
-                                                       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);
 }
@@ -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[], 
-                                                                       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());
@@ -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(), 
-                                                       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);
 }
@@ -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[], 
-                                                                       uint32_t count)
+                                                                       uint32_t& count, const pint_t cuStarts[], uint32_t cuCount)
 {
        // 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>
@@ -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<arm64>::bigEndian() { return false; }
 
 
 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)
 {
-       // FIX ME
-       assert(0);
+       assert(0 && "addCiePersonalityFixups() not implemented for arch");
 }
 
 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)
 {
-       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)
 {
-       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 <>
+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)
@@ -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) {
@@ -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();
+                               array[entryIndex].functionStartAddress += parser.symbolFromIndex(reloc->r_symbolnum()).n_value();
                        }
                        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
@@ -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) {
-               // 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
@@ -4356,7 +4680,7 @@ uint32_t SymboledSection<A>::computeAtomCount(class Parser<A>& parser,
        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);
@@ -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, 
-                                                                                       struct Parser<A>::LabelAndCFIBreakIterator& it, 
+                                                                                       struct Parser<A>::LabelAndCFIBreakIterator& it,
                                                                                        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;
-       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 ) {
@@ -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;
-                       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));
                }
@@ -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, 
@@ -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;
+               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();
-                       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;
+                       prevIgnore = ignore;
                }
        }
        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;
-       while ( it.next(parser, sectNum, startAddr, endAddr, &foundAddr, &size, &foundLabel) ) {
+       while ( it.next(parser, *this, sectNum, startAddr, endAddr, &foundAddr, &size, &foundLabel) ) {
                if ( foundLabel != NULL ) {
+                       bool skip = false;
                        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));
+                               }
                        }
                        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) ) {
-                               //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), 
@@ -4606,11 +4957,12 @@ bool CStringSection<A>::useElementAt(Parser<A>& parser, struct Parser<A>::LabelA
 }
 
 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'); 
 }
 
+
 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;
 }
 
+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&)
@@ -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::bindingDirectlyBound:
+                       targetAtom = fit->u.target;
+                       break;
                default:
-                       assert(0);
+                       assert(0 && "unsupported reference to selector");
        }
        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();
 }
 
@@ -6054,8 +6416,314 @@ bool Section<arm>::addRelocFixup(class Parser<arm>& parser, const macho_relocati
 #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)
@@ -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;
+#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;
@@ -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) );
+               case CPU_TYPE_ARM64:
+                       return ( mach_o::relocatable::Parser<arm64>::validFile(fileContent, opts.objSubtypeMustMatch, opts.subType) );
        }
        return false;
 }
@@ -6344,6 +7020,11 @@ bool isObjectFile(const uint8_t* fileContent, cpu_type_t* result, cpu_subtype_t*
                *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;
 }                                      
 
@@ -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);
        }
+#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;
 }                              
 
index 021c3f2ff6f77340d4e2db133ce5a6e6cf64444e..a576f527afcb87e862f60887a8d5f5e86b747ae4 100644 (file)
@@ -35,7 +35,9 @@ struct ParserOptions {
        uint32_t                architecture;
        bool                    objSubtypeMustMatch;
        bool                    logAllFiles;
-       bool                    convertUnwindInfo;
+       bool                    warnUnwindConversionProblems;
+       bool                    keepDwarfUnwind;
+       bool                    forceDwarfConversion;
        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);
        
-       
        // 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);
 }
 
+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)
 {
@@ -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));
 }
 
+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)
 {
@@ -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));
 }
 
+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)
@@ -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));
 }
 
+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)
 {
@@ -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));
 }
 
+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)
 {
@@ -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));
 }
 
+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)
 {
@@ -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));
 }
 
+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;
+                                       if (_s_log) fprintf(stderr, "makeCompressedSecondLevelPage(): pageSpecificEncodings[%d]=0x%08X\n", encodingIndex, encoding); 
                                }
                                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->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));
                                }
                        }
@@ -781,6 +829,11 @@ static void makeFinalLinkedImageCompactUnwindSection(const Options& opts, ld::In
                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");
@@ -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;
+#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, 
-                               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));
@@ -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;
+#endif
+#if SUPPORT_ARCH_arm64
+               case CPU_TYPE_ARM64:
+                       state.addAtom(*new CompactUnwindAtom<arm64>(state, atom, startOffset, endOffset-startOffset, cui));
+                       break;
 #endif
        }
 }
index 74328ffbe81275ec924550930d4e137b8abcff38..6f8a5440a174f5ba3be496fae74e8c54d7b7ed50 100644 (file)
@@ -34,6 +34,7 @@
 #include <unordered_set>
 
 #include "ld.hpp"
+#include "MachOFileAbstraction.hpp"
 #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;
+       
+       // 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;
@@ -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::kindStoreARM64DtraceCallSiteNop:
                                                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:
@@ -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_ARM64:
                        storeKind = ld::Fixup::kindStoreLittleEndian32;
                        break;
                default:
index 3e6824f415af25663e82735d6046dd108c2a7427..2b9da3a9816b99b68bc388d78155f20eddc951c2 100644 (file)
 #include <vector>
 #include <map>
 
+#include "MachOFileAbstraction.hpp"
 #include "ld.hpp"
 #include "got.h"
+#include "configure.h"
 
 namespace ld {
 namespace passes {
@@ -42,17 +44,18 @@ class File; // forward reference
 
 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, 
-                                                       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(); }
-       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)                                 { }
@@ -62,6 +65,7 @@ public:
 private:
        mutable ld::Fixup                                               _fixup;
        const ld::Atom*                                                 _target;
+       bool                                                                    _is64;
        
        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:
+#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
@@ -122,6 +130,9 @@ static bool gotFixup(const Options& opts, ld::Internal& internal, const ld::Atom
                        }
                        return true;
                case ld::Fixup::kindStoreX86PCRel32GOT:
+#if SUPPORT_ARCH_arm64
+               case ld::Fixup::kindStoreARM64PCRelToGOT:
+#endif
                        *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;
-                                                       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");
@@ -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) {
-               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
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_IS_SIMULATED                        (1<<5)
 
 
 
@@ -111,6 +112,9 @@ ObjCImageInfoAtom<A>::ObjCImageInfoAtom(ld::File::ObjcConstraint objcConstraint,
                        if ( compaction ) 
                                value |= OBJC_IMAGE_SUPPORTS_COMPACTION;
                        break;
+               case ld::File::objcConstraintRetainReleaseForSimulator:
+                               value |= OBJC_IMAGE_IS_SIMULATED;
+                       break;
        }
 
        _content.version = 0;
@@ -1176,10 +1180,18 @@ void doPass(const Options& opts, ld::Internal& state)
                                                        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;
+#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");
                }       
@@ -1195,16 +1207,19 @@ void doPass(const Options& opts, ld::Internal& state)
 #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:
-                               // disable optimization until fully tested
                                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");
index b4be79fd0fc953ebeefa90d6f01d2532bc685a60..af73d66ecb4860f444964dd772704ee482bba465 100644 (file)
@@ -31,6 +31,7 @@
 
 #include <vector>
 #include <map>
+#include <set>
 #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;
-       
+
        // 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;
 
+       // 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);
@@ -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
-               bool leftIsAlias = left->isAlias();
-               bool rightIsAlias = right->isAlias();
                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;
+               //fprintf(stderr, "sorting section %s\n", sect->sectionName());
                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;
-       //              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 "ld.hpp"
 #include "MachOFileAbstraction.hpp"
+#include "ld.hpp"
 
 #include "make_stubs.h"
 
@@ -90,8 +90,9 @@ private:
 #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), 
@@ -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:
+#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 ) 
@@ -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;
+#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";
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::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;
@@ -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::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;
@@ -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));
+                       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;
@@ -1116,7 +1177,9 @@ static ld::relocatable::File* createReader(const char* path)
        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 ) {
index 766ae947696e5264b923e259b4e32d801dc6a43b..e47d482ad799b78713c904d3530e3b79fa43cb3e 100644 (file)
@@ -98,3 +98,16 @@ prune_trie(
        // 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
 
+#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), 
@@ -612,7 +632,7 @@ void DyldInfoPrinter<A>::printRebaseInfo()
                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 = "??";
@@ -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 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);
-                       if ( weakDef || threadLocal || resolver ) {
+                       if ( weakDef || threadLocal || resolver || abs ) {
                                bool needComma = false;
                                printf(" [");
                                if ( weakDef ) {
@@ -1286,6 +1307,12 @@ void DyldInfoPrinter<A>::printExportInfo()
                                        printf("per-thread");
                                        needComma = true;
                                }
+                               if ( abs ) {
+                                       if ( needComma )
+                                               printf(", ");
+                                       printf("absolute");
+                                       needComma = true;
+                               }
                                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);
+                                       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);
                                }
@@ -1467,7 +1496,12 @@ const uint8_t* DyldInfoPrinter<A>::printSharedRegionInfoForEachULEB128Address(co
                        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";
@@ -1751,7 +1785,6 @@ x86::P::uint_t DyldInfoPrinter<x86>::relocBase()
 template <>
 x86_64::P::uint_t DyldInfoPrinter<x86_64>::relocBase()
 {
-       // check for split-seg
        return fFirstWritableSegment->vmaddr();
 }
 
@@ -1766,6 +1799,13 @@ arm::P::uint_t DyldInfoPrinter<arm>::relocBase()
 }
 #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)
@@ -1818,6 +1858,16 @@ const char*      DyldInfoPrinter<arm>::relocTypeName(uint8_t r_type)
 }
 #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()
 {
@@ -2114,6 +2164,14 @@ static void dump(const char* path)
                                                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);
@@ -2137,6 +2195,11 @@ static void dump(const char* path)
                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";
@@ -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;
+#if SUPPORT_ARCH_arm64
+                                       else if ( strcmp(arch, "arm64") == 0 )
+                                               sPreferredArch = CPU_TYPE_ARM64;
+#endif
                                        else {
                                                if ( arch == NULL )
                                                        throw "-arch missing architecture name";
index bd585d139063b4aac8a577dca387371b546193ca..aec6ebe1ff88a8336173033dad0e2e7ba91b507c 100644 (file)
@@ -264,11 +264,34 @@ bool MachOChecker<arm>::validFile(const uint8_t* fileContent)
        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; }
+#if SUPPORT_ARCH_arm64
+template <> uint8_t MachOChecker<arm64>::loadCommandSizeMask() { return 0x07; }
+#endif
 
 
 template <>
@@ -301,9 +324,13 @@ arm::P::uint_t MachOChecker<arm>::getInitialStackPointer(const macho_thread_comm
        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)
@@ -335,6 +362,13 @@ arm::P::uint_t MachOChecker<arm>::getEntryPoint(const macho_thread_command<arm::
        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)
@@ -447,6 +481,7 @@ void MachOChecker<A>::checkLoadCommands()
                                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:
@@ -993,6 +1028,15 @@ arm::P::uint_t MachOChecker<arm>::relocBase()
                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)
@@ -1107,6 +1151,14 @@ void MachOChecker<arm>::checkExternalReloation(const macho_relocation_info<P>* r
 }
 #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)
@@ -1184,6 +1236,15 @@ void MachOChecker<arm>::checkLocalReloation(const macho_relocation_info<P>* relo
 }
 #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()
 {
@@ -1602,6 +1663,11 @@ static void check(const char* 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";
index 731f2a36d4600a40048deb50dce570513e5c8997..3da01c540f39391561697034d58a65b3c3e7c776 100644 (file)
@@ -35,7 +35,7 @@
 #include <set>
 #include <unordered_set>
 
-
+#include "configure.h"
 #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"; }
-
+#if SUPPORT_ARCH_arm64
+template <>     const char*    UnwindPrinter<arm64>::archName()        { return "arm64"; }
+#endif
 
 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),
@@ -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)
@@ -648,6 +748,17 @@ const char* UnwindPrinter<x86>::personalityName(const macho_relocation_info<x86:
        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)
 {
@@ -715,7 +826,6 @@ void UnwindPrinter<A>::printObjectUnwindSection(bool showFunctionNames)
                                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) : "";
-                               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);
                        }
                }
@@ -827,7 +937,7 @@ void UnwindPrinter<A>::printUnwindSection(bool showFunctionNames)
                                                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);
                        }                                       
                }
@@ -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;
+#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);
                                        }
@@ -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);
                }
+#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";
                }
@@ -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);
+#if SUPPORT_ARCH_arm64
+                                       else if ( strcmp(arch, "arm64") == 0 )
+                                               onlyArchs.insert(CPU_TYPE_ARM64);
+#endif
                                        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 SUPPORT_ARCH_arm64
+                       onlyArchs.insert(CPU_TYPE_ARM64);
+#endif
                }
                
                // process each file
index 41cf6cf51de07467ebd7314603cfcc8df55a549d..fdb62126dbe893a6deef7719d4b80648c0cfebed 100644 (file)
@@ -125,6 +125,17 @@ else
   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
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
+       ${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
-       #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:
-       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
-l$start$data$1:
+ .data_region
        nop
        nop
        nop
-l$start$jt8$2:
+ .data_region jt8
        nop
        nop
-l$start$jt16$3: 
+.data_region jt16
        nop
        nop
-l$start$code$n4:
+.data_region jt32
        nop
        nop
-       
-       
+.end_data_region
+       nop
+       nop
+
        
        .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}
 
-       # 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} 
+       ${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}
index 714540a528f1229ec79afafa631f64d324d516dd..61981fe265da2a331dc0be35bb8a1039880666c0 100644 (file)
@@ -1,4 +1,21 @@
+
+#if USE_MY
+  extern int mybar();
+#else
+  extern int bar();
+#endif
+
 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