]> git.saurik.com Git - apple/ld64.git/commitdiff
ld64-236.3.tar.gz developer-tools-51 v236.3
authorApple <opensource@apple.com>
Fri, 4 Apr 2014 22:42:29 +0000 (22:42 +0000)
committerApple <opensource@apple.com>
Fri, 4 Apr 2014 22:42:29 +0000 (22:42 +0000)
70 files changed:
doc/man/man1/ld.1
ld64.xcodeproj/project.pbxproj
src/abstraction/MachOFileAbstraction.hpp
src/abstraction/MachOTrie.hpp
src/create_configure
src/ld/HeaderAndLoadCommands.hpp
src/ld/InputFiles.cpp
src/ld/InputFiles.h
src/ld/LinkEdit.hpp
src/ld/Options.cpp
src/ld/Options.h
src/ld/OutputFile.cpp
src/ld/OutputFile.h
src/ld/Resolver.cpp
src/ld/Resolver.h
src/ld/SymbolTable.cpp
src/ld/SymbolTable.h
src/ld/ld.cpp
src/ld/ld.hpp
src/ld/parsers/archive_file.cpp
src/ld/parsers/libunwind/DwarfInstructions.hpp
src/ld/parsers/lto_file.cpp
src/ld/parsers/lto_file.h
src/ld/parsers/macho_dylib_file.cpp
src/ld/parsers/macho_relocatable_file.cpp
src/ld/parsers/macho_relocatable_file.h
src/ld/passes/branch_island.cpp
src/ld/passes/compact_unwind.cpp
src/ld/passes/order.cpp
src/ld/passes/stubs/stub_arm64.hpp
src/ld/passes/tlvp.cpp
src/other/ObjectDump.cpp
src/other/PruneTrie.cpp
src/other/dyldinfo.cpp
unit-tests/include/common.makefile
unit-tests/test-cases/branch-islands/Makefile
unit-tests/test-cases/branch-islands/extra.c
unit-tests/test-cases/branch-islands/hello.c
unit-tests/test-cases/branch-islands/space.s
unit-tests/test-cases/branch-long/Makefile [new file with mode: 0644]
unit-tests/test-cases/branch-long/bar.s [new file with mode: 0644]
unit-tests/test-cases/branch-long/foo.c [new file with mode: 0644]
unit-tests/test-cases/cpu-sub-types/Makefile
unit-tests/test-cases/dso_handle/Makefile
unit-tests/test-cases/eh-coalescing-r/Makefile
unit-tests/test-cases/linker-optimization-hints/AdrpAdd.s [new file with mode: 0644]
unit-tests/test-cases/linker-optimization-hints/AdrpAddLdr.s [new file with mode: 0644]
unit-tests/test-cases/linker-optimization-hints/AdrpAddStr.s [new file with mode: 0644]
unit-tests/test-cases/linker-optimization-hints/AdrpLdr.s [new file with mode: 0644]
unit-tests/test-cases/linker-optimization-hints/AdrpLdrGot.s [new file with mode: 0644]
unit-tests/test-cases/linker-optimization-hints/AdrpLdrGotLdr.s [new file with mode: 0644]
unit-tests/test-cases/linker-optimization-hints/AdrpLdrGotStr.s [new file with mode: 0644]
unit-tests/test-cases/linker-optimization-hints/Makefile [new file with mode: 0644]
unit-tests/test-cases/linker-optimization-hints/main.s [new file with mode: 0644]
unit-tests/test-cases/objc-abi/Makefile
unit-tests/test-cases/objc-abi/test.m
unit-tests/test-cases/objc-category-optimize-load/Makefile
unit-tests/test-cases/objc-category-optimize/Makefile
unit-tests/test-cases/objc-category-warning/Makefile
unit-tests/test-cases/objc-gc-checks/Makefile
unit-tests/test-cases/objc-gc-checks/bar.m
unit-tests/test-cases/objc-gc-checks/foo.m
unit-tests/test-cases/objc-literal-pointers-strip/test.m
unit-tests/test-cases/objc-properties/test.m
unit-tests/test-cases/operator-new/main.cxx
unit-tests/test-cases/relocs-literals/Makefile
unit-tests/test-cases/relocs-literals/test.c
unit-tests/test-cases/relocs-literals2/Makefile
unit-tests/test-cases/relocs-literals2/test.c
unit-tests/test-cases/relocs-objc/test.m

index aef8eb94208f4d40d7366600087f89c50b821b66..964d099e1fed6cc93b8dcdffa212d1ceebf64f45 100644 (file)
@@ -297,6 +297,10 @@ them to use no space on disk.  This option suppresses that optimization, so zero
 space on disk in a final linked image.
 .It Fl merge_zero_fill_sections
 Causes all zero-fill sections in the __DATA segment to be merged into one __zerofill section.
+.It Fl no_branch_islands
+Disables linker creation of branch islands which allows images to be created that are larger than the
+maximum branch distance. Useful with -preload when code is in multiple sections but all are within
+the branch range.
 .El
 .Ss Options when creating a dynamic library (dylib) 
 .Bl -tag
@@ -380,6 +384,8 @@ Don't turn private external (aka visibility=hidden) symbols into static symbols,
 but rather leave them as private external in the resulting object file.
 .It Fl d
 Force definition of common symbols.  That is, transform tentative definitions into real definitions.
+.It Fl rename_section Ar fromSegment fromSection toSegment toSection
+Renames section fromSegment/fromSection to toSegment/toSection.
 .El
 .Ss Options that control symbol resolution
 .Bl -tag
index 4ffd5d86c4f2ff62ace367f656833851182c2e84..250fa5e89638164a9d7b535350d75cfb6ba85841 100644 (file)
                                        "$(DEVELOPER_DIR)/usr/include",
                                );
                                INSTALL_PATH = /usr/bin;
+                               LD_RUNPATH_SEARCH_PATHS = "@executable_path/../lib/";
                                LINKER_DISPLAYS_MANGLED_NAMES = NO;
                                MACOSX_DEPLOYMENT_TARGET = "";
                                OTHER_CPLUSPLUSFLAGS = (
                                );
                                OTHER_LDFLAGS = (
                                        "-stdlib=libc++",
-                                       "@$(DERIVED_SOURCES_DIR)/LTO_option.txt",
+                                       "-Wl,-lazy_library,$(DT_TOOLCHAIN_DIR)/usr/lib/libLTO.dylib",
                                        "-Wl,-exported_symbol,__mh_execute_header",
                                );
                                PREBINDING = NO;
                                        "$(DEVELOPER_DIR)/usr/include",
                                );
                                INSTALL_PATH = /usr/bin;
+                               LD_RUNPATH_SEARCH_PATHS = "@executable_path/../lib/";
                                OTHER_CPLUSPLUSFLAGS = (
                                        "-stdlib=libc++",
                                        "$(OTHER_CPLUSPLUSFLAGS)",
                                );
                                OTHER_LDFLAGS = (
                                        "-stdlib=libc++",
-                                       "@$(DERIVED_SOURCES_DIR)/LTO_option.txt",
+                                       "-Wl,-lazy_library,$(DT_TOOLCHAIN_DIR)/usr/lib/libLTO.dylib",
                                        "-Wl,-exported_symbol,__mh_execute_header",
                                );
                                PREBINDING = NO;
                                );
                                OTHER_LDFLAGS = (
                                        "-stdlib=libc++",
-                                       "@$(DERIVED_SOURCES_DIR)/LTO_option.txt",
+                                       "-Wl,-lazy_library,$(DT_TOOLCHAIN_DIR)/usr/lib/libLTO.dylib",
                                );
                                OTHER_REZFLAGS = "";
                                PREBINDING = NO;
                                );
                                OTHER_LDFLAGS = (
                                        "-stdlib=libc++",
-                                       "@$(DERIVED_SOURCES_DIR)/LTO_option.txt",
+                                       "-Wl,-lazy_library,$(DT_TOOLCHAIN_DIR)/usr/lib/libLTO.dylib",
                                );
                                OTHER_REZFLAGS = "";
                                PREBINDING = NO;
                                        "$(DEVELOPER_DIR)/usr/include",
                                );
                                INSTALL_PATH = /usr/bin;
+                               LD_RUNPATH_SEARCH_PATHS = "@executable_path/../lib/";
                                OTHER_CPLUSPLUSFLAGS = (
                                        "-stdlib=libc++",
                                        "$(OTHER_CPLUSPLUSFLAGS)",
                                );
                                OTHER_LDFLAGS = (
                                        "-stdlib=libc++",
-                                       "@$(DERIVED_SOURCES_DIR)/LTO_option.txt",
+                                       "-Wl,-lazy_library,$(DT_TOOLCHAIN_DIR)/usr/lib/libLTO.dylib",
                                        "-Wl,-exported_symbol,__mh_execute_header",
                                );
                                PREBINDING = NO;
                                );
                                OTHER_LDFLAGS = (
                                        "-stdlib=libc++",
-                                       "@$(DERIVED_SOURCES_DIR)/LTO_option.txt",
+                                       "-Wl,-lazy_library,$(DT_TOOLCHAIN_DIR)/usr/lib/libLTO.dylib",
                                );
                                OTHER_REZFLAGS = "";
                                PREBINDING = NO;
index 60b4f10c22fecaaa02e5c3c50fd38864521e5138..92797342610bd819214b76f5a636f74798bda68b 100644 (file)
        };
 #endif
 
+#ifndef LC_LINKER_OPTIMIZATION_HINTS 
+       #define LC_LINKER_OPTIMIZATION_HINTS   0x2E
+       #define LOH_ARM64_ADRP_ADRP                             1
+       #define LOH_ARM64_ADRP_LDR                              2
+       #define LOH_ARM64_ADRP_ADD_LDR                  3
+       #define LOH_ARM64_ADRP_LDR_GOT_LDR              4
+       #define LOH_ARM64_ADRP_ADD_STR                  5
+       #define LOH_ARM64_ADRP_LDR_GOT_STR              6
+       #define LOH_ARM64_ADRP_ADD                              7
+       #define LOH_ARM64_ADRP_LDR_GOT                  8
+#endif
+
 #ifndef EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE
        #define EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE                       0x02
 #endif
        #define CPU_SUBTYPE_ARM_V7EM    ((cpu_subtype_t) 16) 
 #endif 
 
+#ifndef CPU_SUBTYPE_X86_64_H
+       #define CPU_SUBTYPE_X86_64_H    ((cpu_subtype_t) 8) 
+#endif 
 
 struct ArchInfo {
        const char*                     archName;
@@ -428,7 +443,10 @@ struct ArchInfo {
 
 static const ArchInfo archInfoArray[] = {
 #if SUPPORT_ARCH_x86_64
-       { "x86_64", CPU_TYPE_X86_64, CPU_SUBTYPE_X86_64_ALL, "x86_64-",  "", false, false },
+       { "x86_64", CPU_TYPE_X86_64, CPU_SUBTYPE_X86_64_ALL, "x86_64-",  "", true, false },
+#endif
+#if SUPPORT_ARCH_x86_64h
+       { "x86_64h", CPU_TYPE_X86_64, CPU_SUBTYPE_X86_64_H,      "x86_64h-",  "", true, false },
 #endif
 #if SUPPORT_ARCH_i386
        { "i386",   CPU_TYPE_I386,   CPU_SUBTYPE_I386_ALL,   "i386-",    "", false, false },
index 1885e482add8ab861a8bd25822a219fd39a9e138..b7c55c1d3d71150a68f9216852743a1ca6433db2 100644 (file)
@@ -329,7 +329,7 @@ static inline void processExportNode(const uint8_t* const start, const uint8_t*
 {
        if ( p >= end )
                throw "malformed trie, node past end";
-       const uint8_t terminalSize = read_uleb128(p, end);
+       const uint64_t terminalSize = read_uleb128(p, end);
        const uint8_t* children = p + terminalSize;
        if ( terminalSize != 0 ) {
                EntryWithOffset e;
index aed4fa37e6748ddfab1e6afa644fbb7d5ccb7de1..8ca92bee0f6335ff5f5b5a87e1db0660a01943e1 100755 (executable)
@@ -11,12 +11,12 @@ else
 fi
 
 if [ -z "${RC_SUPPORTED_ARCHS}" ]; then
-       RC_SUPPORTED_ARCHS="i386 x86_64 armv7 armv7s arm64"
+       RC_SUPPORTED_ARCHS="i386 x86_64 x86_64h armv6 armv7 armv7s armv7m arm64"
 fi
 
 for ANARCH in ${RC_SUPPORTED_ARCHS}
 do
-       KNOWN_ARCHS=",armv4t,armv5,armv6,armv7,armv7f,armv7k,armv7s,armv6m,armv7m,armv7em,armv8,arm64,arm64v8,i386,x86_64,"
+       KNOWN_ARCHS=",armv4t,armv5,armv6,armv7,armv7f,armv7k,armv7s,armv6m,armv7m,armv7em,armv8,arm64,arm64v8,i386,x86_64,x86_64h,"
        FOUND=`echo "$KNOWN_ARCHS" | grep ",$ANARCH,"`
        if [ $FOUND ]; then
                echo "#define SUPPORT_ARCH_$ANARCH  1" >> ${DERIVED_FILE_DIR}/configure.h
@@ -28,18 +28,5 @@ done
 echo "#define ALL_SUPPORTED_ARCHS  \"${RC_SUPPORTED_ARCHS}\"" >> ${DERIVED_FILE_DIR}/configure.h
 
 
-# <rdar://problem/10897631> ld64 hardcodes a reference to /Developer/usr/lib/libLTO.dylib
-if [ -n "${DT_TOOLCHAIN_DIR}" ]
-then
-       echo "-Wl,-lazy_library,${DT_TOOLCHAIN_DIR}/usr/lib/libLTO.dylib" > ${DERIVED_SOURCES_DIR}/LTO_option.txt
-else
-       if [ -e "/Developer/usr/lib/libLTO.dylib" ]
-       then
-               echo "-Wl,-lazy_library,/Developer/usr/lib/libLTO.dylib" > ${DERIVED_SOURCES_DIR}/LTO_option.txt
-       else
-               echo "-Wl,-lazy_library,${BUILT_PRODUCTS_DIR}/../lib/libLTO.dylib" > ${DERIVED_SOURCES_DIR}/LTO_option.txt
-       fi
-fi
-
  
 
index 35daef1de569ce2bba0da10190b3132bef5db4cd..acbdf4f3057e8ada8386b1fd9c37475af705b4b7 100644 (file)
@@ -110,6 +110,7 @@ private:
        uint8_t*                                        copyDependentDRLoadCommand(uint8_t* p) const;
        uint8_t*                                        copyDyldEnvLoadCommand(uint8_t* p, const char* env) const;
        uint8_t*                                        copyLinkerOptionsLoadCommand(uint8_t* p, const std::vector<const char*>&) const;
+       uint8_t*                                        copyOptimizationHintsLoadCommand(uint8_t* p) const;
 
        uint32_t                                        sectionFlags(ld::Internal::FinalSection* sect) const;
        bool                                            sectionTakesNoDiskSpace(ld::Internal::FinalSection* sect) const;
@@ -137,6 +138,7 @@ private:
        bool                                            _hasDataInCodeLoadCommand;
        bool                                            _hasSourceVersionLoadCommand;
        bool                                            _hasDependentDRInfo;
+       bool                                            _hasOptimizationHints;
        uint32_t                                        _dylibLoadCommmandsCount;
        uint32_t                                        _allowableClientLoadCommmandsCount;
        uint32_t                                        _dyldEnvironExrasCount;
@@ -176,6 +178,7 @@ HeaderAndLoadCommandsAtom<A>::HeaderAndLoadCommandsAtom(const Options& opts, ld:
        _hasRoutinesLoadCommand = (opts.initFunctionName() != NULL);
        _hasSymbolTableLoadCommand = true;
        _hasUUIDLoadCommand = (opts.UUIDMode() != Options::kUUIDNone);
+       _hasOptimizationHints = (_state.someObjectHasOptimizationHints && (opts.outputKind() == Options::kObjectFile));
        switch ( opts.outputKind() ) {
                case Options::kDynamicExecutable:
                case Options::kDynamicLibrary:
@@ -426,6 +429,9 @@ uint64_t HeaderAndLoadCommandsAtom<A>::size() const
        
        if ( _hasDependentDRInfo ) 
                sz += sizeof(macho_linkedit_data_command<P>);
+       
+       if ( _hasOptimizationHints )
+               sz += sizeof(macho_linkedit_data_command<P>);
                
        return sz;
 }
@@ -503,6 +509,9 @@ uint32_t HeaderAndLoadCommandsAtom<A>::commandsCount() const
 
        if ( _hasDependentDRInfo ) 
                ++count;
+       
+       if ( _hasOptimizationHints )
+               ++count;
                
        return count;
 }
@@ -561,9 +570,9 @@ uint32_t HeaderAndLoadCommandsAtom<A>::flags() const
                                        bits |= MH_FORCE_FLAT;
                                        break;
                        }
-                       if ( _writer.hasWeakExternalSymbols || _writer.overridesWeakExternalSymbols )
+                       if ( _state.hasWeakExternalSymbols || _writer.overridesWeakExternalSymbols )
                                bits |= MH_WEAK_DEFINES;
-                       if ( _writer.usesWeakExternalSymbols || _writer.hasWeakExternalSymbols )
+                       if ( _writer.usesWeakExternalSymbols || _state.hasWeakExternalSymbols )
                                bits |= MH_BINDS_TO_WEAK;
                        if ( _options.prebind() )
                                bits |= MH_PREBOUND;
@@ -578,7 +587,7 @@ uint32_t HeaderAndLoadCommandsAtom<A>::flags() const
                                bits |= MH_PIE;
                        if ( _options.markAutoDeadStripDylib() ) 
                                bits |= MH_DEAD_STRIPPABLE_DYLIB;
-                       if ( _writer.hasThreadLocalVariableDefinitions )
+                       if ( _state.hasThreadLocalVariableDefinitions )
                                bits |= MH_HAS_TLV_DESCRIPTORS;
                        if ( _options.hasNonExecutableHeap() )
                                bits |= MH_NO_HEAP_EXECUTION;
@@ -610,10 +619,10 @@ uint32_t HeaderAndLoadCommandsAtom<x86>::cpuSubType() const
 template <>
 uint32_t HeaderAndLoadCommandsAtom<x86_64>::cpuSubType() const
 {
-       if ( (_options.outputKind() == Options::kDynamicExecutable) && (_options.macosxVersionMin() >= ld::mac10_5) )
-               return (CPU_SUBTYPE_X86_64_ALL | 0x80000000);
+       if ( (_options.outputKind() == Options::kDynamicExecutable) && (_state.cpuSubType == CPU_SUBTYPE_X86_64_ALL) && (_options.macosxVersionMin() >= ld::mac10_5) )
+               return (_state.cpuSubType | 0x80000000);
        else
-               return CPU_SUBTYPE_X86_64_ALL;
+               return _state.cpuSubType;
 }
 
 template <>
@@ -1409,6 +1418,19 @@ uint8_t* HeaderAndLoadCommandsAtom<A>::copyDependentDRLoadCommand(uint8_t* p) co
 }
 
 
+
+template <typename A>
+uint8_t* HeaderAndLoadCommandsAtom<A>::copyOptimizationHintsLoadCommand(uint8_t* p) const
+{
+       macho_linkedit_data_command<P>* cmd = (macho_linkedit_data_command<P>*)p;
+       cmd->set_cmd(LC_LINKER_OPTIMIZATION_HINTS);
+       cmd->set_cmdsize(sizeof(macho_linkedit_data_command<P>));
+       cmd->set_dataoff(_writer.optimizationHintsSection->fileOffset);
+       cmd->set_datasize(_writer.optimizationHintsSection->size);
+       return p + sizeof(macho_linkedit_data_command<P>);
+}
+
+
 template <typename A>
 void HeaderAndLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
 {
@@ -1522,6 +1544,9 @@ void HeaderAndLoadCommandsAtom<A>::copyRawContent(uint8_t buffer[]) const
        if ( _hasDependentDRInfo ) 
                p = this->copyDependentDRLoadCommand(p);
  
+       if ( _hasOptimizationHints )
+               p = this->copyOptimizationHintsLoadCommand(p);
 }
 
 
index a4b256fa2b16ea3282e0179a5a5f4af6a683c7eb..f49f2e350d820c0d6364cbf0045400ce89b77dcd 100644 (file)
@@ -282,6 +282,8 @@ ld::File* InputFiles::makeFile(const Options::FileInfo& info, bool indirectDylib
        objOpts.warnUnwindConversionProblems    = _options.needsUnwindInfoSection();
        objOpts.keepDwarfUnwind         = _options.keepDwarfUnwind();
        objOpts.forceDwarfConversion= (_options.outputKind() == Options::kDyld);
+       objOpts.neverConvertDwarf   = !_options.needsUnwindInfoSection();
+       objOpts.verboseOptimizationHints = _options.verboseOptimizationHints();
        objOpts.subType                         = _options.subArchitecture();
        ld::relocatable::File* objResult = mach_o::relocatable::parse(p, len, info.path, info.modTime, info.ordinal, objOpts);
        if ( objResult != NULL ) {
@@ -291,7 +293,7 @@ ld::File* InputFiles::makeFile(const Options::FileInfo& info, bool indirectDylib
        }
 
        // see if it is an llvm object file
-       objResult = lto::parse(p, len, info.path, info.modTime, info.ordinal, _options.architecture(), _options.subArchitecture(), _options.logAllFiles());
+       objResult = lto::parse(p, len, info.path, info.modTime, info.ordinal, _options.architecture(), _options.subArchitecture(), _options.logAllFiles(), _options.verboseOptimizationHints());
        if ( objResult != NULL ) {
                OSAtomicAdd64(len, &_totalObjectSize);
                OSAtomicIncrement32(&_totalObjectLoaded);
@@ -561,7 +563,7 @@ void InputFiles::addLinkerOptionLibraries(ld::Internal& state)
                                }
                        }
                        catch (const char* msg) {
-                               throwf("in '%s', %s", info.path, msg);
+                               warning("Auto-Linking supplied '%s', %s", info.path, msg);
                        }
                }
        }
@@ -589,7 +591,7 @@ void InputFiles::addLinkerOptionLibraries(ld::Internal& state)
                                }
                        }
                        catch (const char* msg) {
-                               throwf("in '%s', %s", info.path, msg);
+                               warning("Auto-Linking supplied '%s', %s", info.path, msg);
                        }
                }
        }
index 3c55d4539336c43240225cf1c1b6c6f1830e92ff..b1e85cbf5d4ac67b58127f99ad0cbd8b02966b91 100644 (file)
@@ -74,6 +74,9 @@ public:
        
        bool                                            inferredArch() const { return _inferredArch; }
        
+       void                                            addLinkerOptionLibraries(ld::Internal& state);
+       void                                            createIndirectDylibs();
+
        // for -print_statistics
        volatile int64_t                        _totalObjectSize;
        volatile int64_t                        _totalArchiveSize;
@@ -91,10 +94,8 @@ private:
        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
index 1b41fb2c6f664c2995a28873405949a313116ce5..3420626d4d98fe51cc18edb4236e7b98b54032f2 100644 (file)
@@ -1555,6 +1555,68 @@ void DependentDRAtom<A>::encode() const
 
 
 
+template <typename A>
+class OptimizationHintsAtom : public LinkEditAtom
+{
+public:
+                                                                                               OptimizationHintsAtom(const Options& opts, ld::Internal& state, OutputFile& writer)
+                                                                                                       : LinkEditAtom(opts, state, writer, _s_section, sizeof(pint_t)) { 
+                                                                                                               assert(opts.outputKind() == Options::kObjectFile);
+                                                                                                       }
+
+       // overrides of ld::Atom
+       virtual const char*                                                     name() const            { return "linker optimization hints"; }
+       // overrides of LinkEditAtom
+       virtual void                                                            encode() const;
+
+private:
+       typedef typename A::P                                           P;
+       typedef typename A::P::E                                        E;
+       typedef typename A::P::uint_t                           pint_t;
+
+       static ld::Section                      _s_section;
+
+};
+
+template <typename A>
+ld::Section OptimizationHintsAtom<A>::_s_section("__LINKEDIT", "__opt_hints", ld::Section::typeLinkEdit, true);
+
+template <typename A>
+void OptimizationHintsAtom<A>::encode() const
+{
+       if ( _state.someObjectHasOptimizationHints ) {
+               for (std::vector<ld::Internal::FinalSection*>::iterator sit = _state.sections.begin(); sit != _state.sections.end(); ++sit) {
+                       ld::Internal::FinalSection* sect = *sit;
+                       if ( sect->type() != ld::Section::typeCode )
+                               continue;
+                       for (std::vector<const ld::Atom*>::iterator ait = sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
+                               const ld::Atom* atom = *ait;
+                               uint64_t address = atom->finalAddress();
+                               for (ld::Fixup::iterator fit = atom->fixupsBegin(); fit != atom->fixupsEnd(); ++fit) {
+                                       if ( fit->kind != ld::Fixup::kindLinkerOptimizationHint) 
+                                               continue;
+                                       ld::Fixup::LOH_arm64 extra;
+                                       extra.addend = fit->u.addend;
+                                       _encodedData.append_uleb128(extra.info.kind);
+                                       _encodedData.append_uleb128(extra.info.count+1);
+                                       _encodedData.append_uleb128((extra.info.delta1 << 2) + fit->offsetInAtom + address);
+                                       if ( extra.info.count > 0 )
+                                               _encodedData.append_uleb128((extra.info.delta2 << 2) + fit->offsetInAtom + address);
+                                       if ( extra.info.count > 1 )
+                                               _encodedData.append_uleb128((extra.info.delta3 << 2) + fit->offsetInAtom + address);
+                                       if ( extra.info.count > 2 )
+                                               _encodedData.append_uleb128((extra.info.delta4 << 2) + fit->offsetInAtom + address);
+                               }
+                       }
+               }
+                       
+               this->_encodedData.pad_to_size(sizeof(pint_t));
+       }
+       
+       this->_encoded = true;
+}
+
+
 } // namespace tool 
 } // namespace ld 
 
index d916c536c120d761726c8bebe46c4b9b82794df8..057fad996b255a41885bce60476c2c430c68b2dc 100644 (file)
@@ -175,7 +175,8 @@ Options::Options(int argc, const char* argv[])
          fTargetIOSSimulator(false), fExportDynamic(false), fAbsoluteSymbols(false),
          fAllowSimulatorToLinkWithMacOSX(false), fKeepDwarfUnwind(true),
          fKeepDwarfUnwindForcedOn(false), fKeepDwarfUnwindForcedOff(false),
-         fGenerateDtraceDOF(true),
+         fVerboseOptimizationHints(false), fIgnoreOptimizationHints(false),
+         fGenerateDtraceDOF(true), fAllowBranchIslands(true),
          fDebugInfoStripping(kDebugInfoMinimal), fTraceOutputFile(NULL), 
          fMacVersionMin(ld::macVersionUnset), fIOSVersionMin(ld::iOSVersionUnset), 
          fSaveTempFiles(false), fSnapshotRequested(false), fPipelineFifo(NULL), 
@@ -631,7 +632,21 @@ Options::FileInfo Options::findLibrary(const char* rootName, bool dylibsOnly) co
                }
        }
        else {
-               bool lookForDylibs = ( fOutputKind != Options::kDyld);
+               bool lookForDylibs = false;
+               switch ( fOutputKind ) {
+                       case Options::kDynamicExecutable:
+                       case Options::kDynamicLibrary:
+                       case Options::kDynamicBundle:
+                       case Options::kObjectFile:  // <rdar://problem/15914513> 
+                               lookForDylibs = true;
+                               break;
+                       case Options::kStaticExecutable:
+                       case Options::kDyld:
+                       case Options::kPreload:
+                       case Options::kKextBundle:
+                               lookForDylibs = false;
+                               break;
+               }
                switch ( fLibrarySearchMode ) {
                case kSearchAllDirsForDylibsThenAllDirsForArchives:
                                // first look in all directories for just for dylibs
@@ -1717,6 +1732,27 @@ void Options::addSection(const char* segment, const char* section, const char* p
        fExtraSections.push_back(info);
 }
 
+void Options::addSectionRename(const char* srcSegment, const char* srcSection, const char* dstSegment, const char* dstSection)
+{
+       if ( strlen(srcSegment) > 16 )
+               throw "-rename_section segment name max 16 chars";
+       if ( strlen(srcSection) > 16 )
+               throw "-rename_section section name max 16 chars";
+       if ( strlen(dstSegment) > 16 )
+               throw "-rename_section segment name max 16 chars";
+       if ( strlen(dstSection) > 16 )
+               throw "-rename_section section name max 16 chars";
+
+       SectionRename info;
+       info.fromSegment = srcSegment;
+       info.fromSection = srcSection;
+       info.toSegment = dstSegment;
+       info.toSection = dstSection;
+
+       fSectionRenames.push_back(info);
+}
+
+
 void Options::addSectionAlignment(const char* segment, const char* section, const char* alignmentStr)
 {
        if ( strlen(segment) > 16 )
@@ -2571,18 +2607,6 @@ void Options::parse(int argc, const char* argv[])
                 snapshotFileArgIndex = 1;
                                parseAliasFile(argv[++i]);
                        }
-                       // put this last so that it does not interfer with other options starting with 'i'
-                       else if ( strncmp(arg, "-i", 2) == 0 ) {
-                               const char* colon = strchr(arg, ':');
-                               if ( colon == NULL )
-                                       throwf("unknown option: %s", arg);
-                               Options::AliasPair pair;
-                               char* temp = new char[colon-arg];
-                               strlcpy(temp, &arg[2], colon-arg-1);
-                               pair.realName = &colon[1];
-                               pair.alias = temp;
-                               fAliases.push_back(pair);
-                       }
                        else if ( strcmp(arg, "-save-temps") == 0 ) {
                                fSaveTempFiles = true;
                        }
@@ -2923,9 +2947,36 @@ void Options::parse(int argc, const char* argv[])
                                fKeepDwarfUnwindForcedOn = false;
                                fKeepDwarfUnwindForcedOff = true;
                        }
+                       else if ( strcmp(arg, "-verbose_optimization_hints") == 0 ) {
+                               fVerboseOptimizationHints = true;
+                       }
+                       else if ( strcmp(arg, "-ignore_optimization_hints") == 0 ) {
+                               fIgnoreOptimizationHints = true;
+                       }
                        else if ( strcmp(arg, "-no_dtrace_dof") == 0 ) {
                                fGenerateDtraceDOF = false;
                        }
+                       else if ( strcmp(arg, "-rename_section") == 0 ) {
+                                if ( (argv[i+1]==NULL) || (argv[i+2]==NULL) || (argv[i+3]==NULL) || (argv[i+4]==NULL) )
+                                       throw "-rename_section missing <segment> <section> <segment> <section>";
+                               addSectionRename(argv[i+1], argv[i+2], argv[i+3], argv[i+4]);
+                               i += 4;
+                       }
+                       else if ( strcmp(arg, "-no_branch_islands") == 0 ) {
+                               fAllowBranchIslands = false;
+                       }
+                       // put this last so that it does not interfer with other options starting with 'i'
+                       else if ( strncmp(arg, "-i", 2) == 0 ) {
+                               const char* colon = strchr(arg, ':');
+                               if ( colon == NULL )
+                                       throwf("unknown option: %s", arg);
+                               Options::AliasPair pair;
+                               char* temp = new char[colon-arg];
+                               strlcpy(temp, &arg[2], colon-arg-1);
+                               pair.realName = &colon[1];
+                               pair.alias = temp;
+                               fAliases.push_back(pair);
+                       }
                        else {
                                throwf("unknown option: %s", arg);
                        }
@@ -3388,6 +3439,11 @@ void Options::reconfigureDefaults()
                                fFunctionStartsLoadCommand = true;
                        break;
                case Options::kObjectFile:
+                       if ( !fDataInCodeInfoLoadCommandForcedOff )
+                               fDataInCodeInfoLoadCommand = true;
+                       if ( fFunctionStartsForcedOn )
+                               fFunctionStartsLoadCommand = true;
+                       break;
                case Options::kDynamicExecutable:
                case Options::kDyld:
                case Options::kDynamicLibrary:
@@ -3624,7 +3680,11 @@ void Options::reconfigureDefaults()
        // <rdar://problem/5366363> -r -x implies -S
        if ( (fOutputKind == Options::kObjectFile) && (fLocalSymbolHandling == kLocalSymbolsNone) )
                fDebugInfoStripping = Options::kDebugInfoNone;                  
-               
+
+       // <rdar://problem/15252891> -r implies -no_uuid
+       if ( fOutputKind == Options::kObjectFile )
+               fUUIDMode = kUUIDNone;
+
        // choose how to process unwind info
        switch ( fArchitecture ) {
                case CPU_TYPE_I386:             
@@ -3709,9 +3769,17 @@ void Options::reconfigureDefaults()
                        fMakeCompressedDyldInfo = false;
        }
 
-       // only ARM enforces that cpu-sub-types must match
-       if ( fArchitecture != CPU_TYPE_ARM )
-               fAllowCpuSubtypeMismatches = true;
+       // only ARM and x86_64 enforces that cpu-sub-types must match
+       switch ( fArchitecture ) {
+               case CPU_TYPE_ARM:
+               case CPU_TYPE_X86_64:
+                       break;
+               case CPU_TYPE_I386:
+               case CPU_TYPE_ARM64:
+                       fAllowCpuSubtypeMismatches = true;
+                       break;
+       }
+               
                
        // only final linked images can not optimize zero fill sections
        if ( fOutputKind == Options::kObjectFile )
@@ -3794,7 +3862,10 @@ void Options::reconfigureDefaults()
        if ( fMacVersionMin >= ld::mac10_7 ) {
                fTLVSupport = true;
        }
-       
+       else if ( (fArchitecture == CPU_TYPE_ARM64) && (fIOSVersionMin >= 0x00080000) ) {
+               fTLVSupport = true;
+       }
+
        // default to adding version load command for dynamic code, static code must opt-in
        switch ( fOutputKind ) {
                case Options::kObjectFile:
@@ -4466,6 +4537,10 @@ void Options::checkIllegalOptionCombinations()
        // -dyld_env can only be used with main executables
        if ( (fOutputKind != Options::kDynamicExecutable) && (fDyldEnvironExtras.size() != 0) )
                throw "-dyld_env can only used used when created main executables";
+
+       // -rename_sections can only be used in -r mode
+       if ( (fSectionRenames.size() != 0) && (fOutputKind != Options::kObjectFile) )
+               throw "-rename_sections can only used used in -r mode";
 }      
 
 
index d3e8d3fb7223f2b15bd165d576be75c37f878bf0..019581585ded02fd10d40f80f6b07922766b6706 100644 (file)
@@ -172,6 +172,14 @@ public:
                const char*                     alias;
        };
 
+       struct SectionRename {
+               const char*                     fromSegment;
+               const char*                     fromSection;
+               const char*                     toSegment;
+               const char*                     toSection;
+       };
+
+
        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,
@@ -335,7 +343,10 @@ public:
        bool                                            objcCategoryMerging() const { return fObjcCategoryMerging; }
        bool                                            pageAlignDataAtoms() const { return fPageAlignDataAtoms; }
        bool                                            keepDwarfUnwind() const { return fKeepDwarfUnwind; }
+       bool                                            verboseOptimizationHints() const { return fVerboseOptimizationHints; }
+       bool                                            ignoreOptimizationHints() const { return fIgnoreOptimizationHints; }
        bool                                            generateDtraceDOF() const { return fGenerateDtraceDOF; }
+       bool                                            allowBranchIslands() const { return fAllowBranchIslands; }
        bool                                            hasWeakBitTweaks() const;
        bool                                            forceWeak(const char* symbolName) const;
        bool                                            forceNotWeak(const char* symbolName) const;
@@ -362,6 +373,7 @@ public:
                                                                linkerOptions() const { return fLinkerOptions; }
        FileInfo                                        findFramework(const char* frameworkName) const;
        FileInfo                                        findLibrary(const char* rootName, bool dylibsOnly=false) const;
+       const std::vector<SectionRename>& sectionRenames() const { return fSectionRenames; }
 
 private:
        typedef std::unordered_map<const char*, unsigned int, ld::CStringHash, ld::CStringEquals> NameToOrder;
@@ -424,6 +436,7 @@ private:
        void                                            warnObsolete(const char* arg);
        uint32_t                                        parseProtection(const char* prot);
        void                                            loadSymbolOrderFile(const char* fileOfExports, NameToOrder& orderMapping);
+       void                                            addSectionRename(const char* srcSegment, const char* srcSection, const char* dstSegment, const char* dstSection);
 
 
 
@@ -591,7 +604,10 @@ private:
        bool                                                            fKeepDwarfUnwind;
        bool                                                            fKeepDwarfUnwindForcedOn;
        bool                                                            fKeepDwarfUnwindForcedOff;
+       bool                                                            fVerboseOptimizationHints;
+       bool                                                            fIgnoreOptimizationHints;
        bool                                                            fGenerateDtraceDOF;
+       bool                                                            fAllowBranchIslands;
        DebugInfoStripping                                      fDebugInfoStripping;
        const char*                                                     fTraceOutputFile;
        ld::MacVersionMin                                       fMacVersionMin;
@@ -613,6 +629,7 @@ private:
        std::vector<const char*>                        fSDKPaths;
        std::vector<const char*>                        fDyldEnvironExtras;
        std::vector< std::vector<const char*> > fLinkerOptions;
+       std::vector<SectionRename>                      fSectionRenames;
        bool                                                            fSaveTempFiles;
     mutable Snapshot                                   fLinkSnapshot;
     bool                                                               fSnapshotRequested;
index 8b0be0a1398d11bbeda23e4c2ebd3d60c6635829..c7a0918b34fa99f81d3fd29946f93dfcb7752380 100644 (file)
 namespace ld {
 namespace tool {
 
+uint32_t sAdrpNA = 0;
+uint32_t sAdrpNoped = 0;
+uint32_t sAdrpNotNoped = 0;
+
 
 OutputFile::OutputFile(const Options& opts) 
        :
-               hasWeakExternalSymbols(false), usesWeakExternalSymbols(false), overridesWeakExternalSymbols(false), 
-               _noReExportedDylibs(false), hasThreadLocalVariableDefinitions(false), pieDisabled(false), hasDataInCode(false), 
+               usesWeakExternalSymbols(false), overridesWeakExternalSymbols(false), 
+               _noReExportedDylibs(false), pieDisabled(false), hasDataInCode(false), 
                headerAndLoadCommandsSection(NULL),
                rebaseSection(NULL), bindingSection(NULL), weakBindingSection(NULL), 
                lazyBindingSection(NULL), exportSection(NULL), 
                splitSegInfoSection(NULL), functionStartsSection(NULL), 
-               dataInCodeSection(NULL), dependentDRsSection(NULL), 
+               dataInCodeSection(NULL), optimizationHintsSection(NULL), dependentDRsSection(NULL), 
                symbolTableSection(NULL), stringPoolSection(NULL), 
                localRelocationsSection(NULL), externalRelocationsSection(NULL), 
                sectionRelocationsSection(NULL), 
@@ -94,6 +98,7 @@ OutputFile::OutputFile(const Options& opts)
                _hasDynamicSymbolTable(true),
                _hasLocalRelocations(!opts.makeCompressedDyldInfo()),
                _hasExternalRelocations(!opts.makeCompressedDyldInfo()),
+               _hasOptimizationHints(opts.outputKind() == Options::kObjectFile),
                _encryptedTEXTstartOffset(0),
                _encryptedTEXTendOffset(0),
                _localSymbolsStartIndex(0),
@@ -115,7 +120,8 @@ OutputFile::OutputFile(const Options& opts)
                _splitSegInfoAtom(NULL),
                _functionStartsAtom(NULL),
                _dataInCodeAtom(NULL),
-               _dependentDRInfoAtom(NULL)
+               _dependentDRInfoAtom(NULL),
+               _optimizationHintsAtom(NULL)
 {
 }
 
@@ -143,9 +149,9 @@ void OutputFile::write(ld::Internal& state)
        this->buildDylibOrdinalMapping(state);
        this->addLoadCommands(state);
        this->addLinkEdit(state);
-       this->setSectionSizesAndAlignments(state);
+       state.setSectionSizesAndAlignments();
        this->setLoadCommandsPadding(state);
-       this->assignFileOffsets(state);
+       _fileSize = state.assignFileOffsets();
        this->assignAtomAddresses(state);
        this->synthesizeDebugNotes(state);
        this->buildSymbolTable(state);
@@ -192,7 +198,6 @@ void OutputFile::assignAtomAddresses(ld::Internal& state)
                if ( log ) fprintf(stderr, "  section=%s/%s\n", sect->segmentName(), sect->sectionName());
                for (std::vector<const ld::Atom*>::iterator ait = sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
                        const ld::Atom* atom = *ait;
-                       if ( log ) fprintf(stderr, "    atom=%p, name=%s\n", atom, atom->name());
                        switch ( sect-> type() ) {
                                case ld::Section::typeImportProxies:
                                        // want finalAddress() of all proxy atoms to be zero
@@ -207,6 +212,7 @@ void OutputFile::assignAtomAddresses(ld::Internal& state)
                                        break;
                                default:
                                        (const_cast<ld::Atom*>(atom))->setSectionStartAddress(sect->address);
+                                       if ( log ) fprintf(stderr, "    atom=%p, addr=0x%08llX, name=%s\n", atom, atom->finalAddress(), atom->name());
                                        break;
                        }
                }
@@ -255,6 +261,12 @@ void OutputFile::updateLINKEDITAddresses(ld::Internal& state)
                _dataInCodeAtom->encode();
        }
        
+       if ( _hasOptimizationHints ) {
+               // build linker-optimization-hint info  
+               assert(_optimizationHintsAtom != NULL);
+               _optimizationHintsAtom->encode();
+       }
+       
        if ( _options.needsDependentDRInfo() ) {
                // build dependent dylib DR info  
                assert(_dependentDRInfoAtom != NULL);
@@ -326,94 +338,6 @@ void OutputFile::updateLINKEDITAddresses(ld::Internal& state)
        _fileSize = state.sections.back()->fileOffset + state.sections.back()->size;
 }
 
-void OutputFile::setSectionSizesAndAlignments(ld::Internal& state)
-{
-       for (std::vector<ld::Internal::FinalSection*>::iterator sit = state.sections.begin(); sit != state.sections.end(); ++sit) {
-               ld::Internal::FinalSection* sect = *sit;
-               if ( sect->type() == ld::Section::typeAbsoluteSymbols ) {
-                       // absolute symbols need their finalAddress() to their value
-                       for (std::vector<const ld::Atom*>::iterator ait = sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
-                               const ld::Atom* atom = *ait;
-                               (const_cast<ld::Atom*>(atom))->setSectionOffset(atom->objectAddress());
-                       }
-               }
-               else {
-                       uint16_t maxAlignment = 0;
-                       uint64_t offset = 0;
-                       for (std::vector<const ld::Atom*>::iterator ait = sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
-                               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 ) {
-                                                               atomAlignmentPowerOf2 = 12;
-                                                               atomModulus = 0;
-                                                       }
-                                                       break;
-                                               default:
-                                                       break;
-                                       }
-                               }
-                               if ( atomAlignmentPowerOf2 > maxAlignment )
-                                       maxAlignment = atomAlignmentPowerOf2;
-                               // calculate section offset for this atom
-                               uint64_t alignment = 1 << atomAlignmentPowerOf2;
-                               uint64_t currentModulus = (offset % alignment);
-                               uint64_t requiredModulus = atomModulus;
-                               if ( currentModulus != requiredModulus ) {
-                                       if ( requiredModulus > currentModulus )
-                                               offset += requiredModulus-currentModulus;
-                                       else
-                                               offset += requiredModulus+alignment-currentModulus;
-                               }
-                               // LINKEDIT atoms are laid out later
-                               if ( sect->type() != ld::Section::typeLinkEdit ) {
-                                       (const_cast<ld::Atom*>(atom))->setSectionOffset(offset);
-                                       offset += atom->size();
-                                       if ( pagePerAtom ) {
-                                               offset = (offset + 4095) & (-4096); // round up to end of page
-                                       }
-                               }
-                               if ( (atom->scope() == ld::Atom::scopeGlobal) 
-                                       && (atom->definition() == ld::Atom::definitionRegular) 
-                                       && (atom->combine() == ld::Atom::combineByName) 
-                                       && ((atom->symbolTableInclusion() == ld::Atom::symbolTableIn) 
-                                        || (atom->symbolTableInclusion() == ld::Atom::symbolTableInAndNeverStrip)) ) {
-                                               this->hasWeakExternalSymbols = true;
-                                               if ( _options.warnWeakExports() ) 
-                                                       warning("weak external symbol: %s", atom->name());
-                               }
-                       }
-                       sect->size = offset;
-                       // section alignment is that of a contained atom with the greatest alignment
-                       sect->alignment = maxAlignment;
-                       // unless -sectalign command line option overrides
-                       if  ( _options.hasCustomSectionAlignment(sect->segmentName(), sect->sectionName()) )
-                               sect->alignment = _options.customSectionAlignment(sect->segmentName(), sect->sectionName());
-                       // each atom in __eh_frame has zero alignment to assure they pack together,
-                       // but compilers usually make the CFIs pointer sized, so we want whole section
-                       // to start on pointer sized boundary.
-                       if ( sect->type() == ld::Section::typeCFI )
-                               sect->alignment = 3;
-                       if ( sect->type() == ld::Section::typeTLVDefs )
-                               this->hasThreadLocalVariableDefinitions = true;
-               }
-       }
-}
 
 void OutputFile::setLoadCommandsPadding(ld::Internal& state)
 {
@@ -438,13 +362,14 @@ void OutputFile::setLoadCommandsPadding(ld::Internal& state)
                default:
                        // work backwards from end of segment and lay out sections so that extra room goes to padding atom
                        uint64_t addr = 0;
+                       uint64_t textSegPageSize = _options.segPageSize("__TEXT");
                        for (std::vector<ld::Internal::FinalSection*>::reverse_iterator it = state.sections.rbegin(); it != state.sections.rend(); ++it) {
                                ld::Internal::FinalSection* sect = *it;
                                if ( strcmp(sect->segmentName(), "__TEXT") != 0 ) 
                                        continue;
                                if ( sect == headerAndLoadCommandsSection ) {
                                        addr -= headerAndLoadCommandsSection->size;
-                                       paddingSize = addr % _options.segmentAlignment();
+                                       paddingSize = addr % textSegPageSize;
                                        break;
                                }
                                addr -= sect->size;
@@ -495,192 +420,6 @@ uint64_t OutputFile::pageAlign(uint64_t addr, uint64_t pageSize)
        return ((addr+pageSize-1) & (-pageSize)); 
 }
 
-
-void OutputFile::assignFileOffsets(ld::Internal& state)
-{
-       const bool log = false;
-       const bool hiddenSectionsOccupyAddressSpace = ((_options.outputKind() != Options::kObjectFile)
-                                                                                               && (_options.outputKind() != Options::kPreload));
-       const bool segmentsArePageAligned = (_options.outputKind() != Options::kObjectFile);
-
-       uint64_t address = 0;
-       const char* lastSegName = "";
-       uint64_t floatingAddressStart = _options.baseAddress();
-       
-       // first pass, assign addresses to sections in segments with fixed start addresses
-       if ( log ) fprintf(stderr, "Fixed address segments:\n");
-       for (std::vector<ld::Internal::FinalSection*>::iterator it = state.sections.begin(); it != state.sections.end(); ++it) {
-               ld::Internal::FinalSection* sect = *it;
-               if ( ! _options.hasCustomSegmentAddress(sect->segmentName()) ) 
-                       continue;
-               if ( segmentsArePageAligned ) {
-                       if ( strcmp(lastSegName, sect->segmentName()) != 0 ) {
-                               address = _options.customSegmentAddress(sect->segmentName());
-                               lastSegName = sect->segmentName();
-                       }
-               }
-               // adjust section address based on alignment
-               uint64_t unalignedAddress = address;
-               uint64_t alignment = (1 << sect->alignment);
-               address = ( (unalignedAddress+alignment-1) & (-alignment) );
-       
-               // update section info
-               sect->address = address;
-               sect->alignmentPaddingBytes = (address - unalignedAddress);
-               
-               // sanity check size
-               if ( ((address + sect->size) > _options.maxAddress()) && (_options.outputKind() != Options::kObjectFile) 
-                                                                                                                         && (_options.outputKind() != Options::kStaticExecutable) )
-                       throwf("section %s (address=0x%08llX, size=%llu) would make the output executable exceed available address range", 
-                                               sect->sectionName(), address, sect->size);
-               
-               if ( log ) fprintf(stderr, "  address=0x%08llX, hidden=%d, alignment=%02d, section=%s,%s\n",
-                                               sect->address, sect->isSectionHidden(), sect->alignment, sect->segmentName(), sect->sectionName());
-               // update running totals
-               if ( !sect->isSectionHidden() || hiddenSectionsOccupyAddressSpace )
-                       address += sect->size;
-               
-               // if TEXT segment address is fixed, then flow other segments after it
-               if ( strcmp(sect->segmentName(), "__TEXT") == 0 ) {
-                       floatingAddressStart = address;
-               }
-       }
-       
-       // second pass, assign section address to sections in segments that are contiguous with previous segment
-       address = floatingAddressStart;
-       lastSegName = "";
-       ld::Internal::FinalSection* overlappingFixedSection = NULL;
-       ld::Internal::FinalSection* overlappingFlowSection = NULL;
-       if ( log ) fprintf(stderr, "Regular layout segments:\n");
-       for (std::vector<ld::Internal::FinalSection*>::iterator it = state.sections.begin(); it != state.sections.end(); ++it) {
-               ld::Internal::FinalSection* sect = *it;
-               if ( _options.hasCustomSegmentAddress(sect->segmentName()) ) 
-                       continue;
-               if ( (_options.outputKind() == Options::kPreload) && (sect->type() == ld::Section::typeMachHeader) ) {
-                       sect->alignmentPaddingBytes = 0;
-                       continue;
-               }
-               if ( segmentsArePageAligned ) {
-                       if ( strcmp(lastSegName, sect->segmentName()) != 0 ) {
-                               // round up size of last segment if needed
-                               if ( *lastSegName != '\0' ) {
-                                       address = pageAlign(address, _options.segPageSize(lastSegName));
-                               }
-                               // set segment address based on end of last segment
-                               address = pageAlign(address);
-                               lastSegName = sect->segmentName();
-                       }
-               }
-               // adjust section address based on alignment
-               uint64_t unalignedAddress = address;
-               uint64_t alignment = (1 << sect->alignment);
-               address = ( (unalignedAddress+alignment-1) & (-alignment) );
-       
-               // update section info
-               sect->address = address;
-               sect->alignmentPaddingBytes = (address - unalignedAddress);
-               
-               // sanity check size
-               if ( ((address + sect->size) > _options.maxAddress()) && (_options.outputKind() != Options::kObjectFile) 
-                                                                                                                         && (_options.outputKind() != Options::kStaticExecutable) )
-                               throwf("section %s (address=0x%08llX, size=%llu) would make the output executable exceed available address range", 
-                                               sect->sectionName(), address, sect->size);
-
-               // sanity check it does not overlap a fixed address segment
-               for (std::vector<ld::Internal::FinalSection*>::iterator sit = state.sections.begin(); sit != state.sections.end(); ++sit) {
-                       ld::Internal::FinalSection* otherSect = *sit;
-                       if ( ! _options.hasCustomSegmentAddress(otherSect->segmentName()) ) 
-                               continue;
-                       if ( sect->address > otherSect->address ) {
-                               if ( (otherSect->address+otherSect->size) > sect->address ) {
-                                       overlappingFixedSection = otherSect;
-                                       overlappingFlowSection = sect;
-                               }
-                       }
-                       else {
-                               if ( (sect->address+sect->size) > otherSect->address ) {
-                                       overlappingFixedSection = otherSect;
-                                       overlappingFlowSection = sect;
-                               }
-                       }
-               }
-               
-               if ( log ) fprintf(stderr, "  address=0x%08llX, size=0x%08llX, hidden=%d, alignment=%02d, padBytes=%d, section=%s,%s\n",
-                                                       sect->address, sect->size, sect->isSectionHidden(), sect->alignment, sect->alignmentPaddingBytes, 
-                                                       sect->segmentName(), sect->sectionName());
-               // update running totals
-               if ( !sect->isSectionHidden() || hiddenSectionsOccupyAddressSpace )
-                       address += sect->size;
-       }
-       if ( overlappingFixedSection != NULL ) {
-               fprintf(stderr, "Section layout:\n");
-               for (std::vector<ld::Internal::FinalSection*>::iterator it = state.sections.begin(); it != state.sections.end(); ++it) {
-                       ld::Internal::FinalSection* sect = *it;
-                       if ( sect->isSectionHidden() )
-                               continue;
-                       fprintf(stderr, "  address:0x%08llX, alignment:2^%d, size:0x%08llX, padBytes:%d, section:%s/%s\n",
-                                                       sect->address, sect->alignment, sect->size, sect->alignmentPaddingBytes, 
-                                                       sect->segmentName(), sect->sectionName());
-       
-               }
-               throwf("Section (%s/%s) overlaps fixed address section (%s/%s)", 
-                       overlappingFlowSection->segmentName(), overlappingFlowSection->sectionName(),
-                       overlappingFixedSection->segmentName(), overlappingFixedSection->sectionName());
-       }
-       
-       
-       // third pass, assign section file offsets 
-       uint64_t fileOffset = 0;
-       lastSegName = "";
-       if ( log ) fprintf(stderr, "All segments with file offsets:\n");
-       for (std::vector<ld::Internal::FinalSection*>::iterator it = state.sections.begin(); it != state.sections.end(); ++it) {
-               ld::Internal::FinalSection* sect = *it;
-               if ( hasZeroForFileOffset(sect) ) {
-                       // fileoff of zerofill sections is moot, but historically it is set to zero
-                       sect->fileOffset = 0;
-
-                       // <rdar://problem/10445047> align file offset with address layout
-                       fileOffset += sect->alignmentPaddingBytes;
-               }
-               else {
-                       // page align file offset at start of each segment
-                       if ( segmentsArePageAligned && (*lastSegName != '\0') && (strcmp(lastSegName, sect->segmentName()) != 0) ) {
-                               fileOffset = pageAlign(fileOffset, _options.segPageSize(lastSegName));
-                       }
-                       lastSegName = sect->segmentName();
-
-                       // align file offset with address layout
-                       fileOffset += sect->alignmentPaddingBytes;
-                       
-                       // update section info
-                       sect->fileOffset = fileOffset;
-                       
-                       // update running total
-                       fileOffset += sect->size;
-               }
-               
-               if ( log ) fprintf(stderr, "  fileoffset=0x%08llX, address=0x%08llX, hidden=%d, size=%lld, alignment=%02d, section=%s,%s\n",
-                               sect->fileOffset, sect->address, sect->isSectionHidden(), sect->size, sect->alignment, 
-                               sect->segmentName(), sect->sectionName());
-       }
-
-
-       // for encrypted iPhoneOS apps
-       if ( _options.makeEncryptable() ) { 
-               // remember end of __TEXT for later use by load command
-               for (std::vector<ld::Internal::FinalSection*>::iterator it = state.sections.begin(); it != state.sections.end(); ++it) {
-                       ld::Internal::FinalSection* sect = *it;
-                       if ( strcmp(sect->segmentName(), "__TEXT") == 0 ) {
-                               _encryptedTEXTendOffset = pageAlign(sect->fileOffset + sect->size);
-                       }
-               }
-       }
-
-       // remember total file size
-       _fileSize = fileOffset;
-}
-
-
 static const char* makeName(const ld::Atom& atom)
 {
        static char buffer[4096];
@@ -934,45 +673,61 @@ void OutputFile::rangeCheckARM12(int64_t displacement, ld::Internal& state, cons
        }
 }
 
+bool OutputFile::checkArmBranch24Displacement(int64_t displacement)
+{
+       return ( (displacement < 33554428LL) && (displacement > (-33554432LL)) );
+}
 
 void OutputFile::rangeCheckARMBranch24(int64_t displacement, ld::Internal& state, const ld::Atom* atom, const ld::Fixup* fixup)
 {
-       if ( (displacement > 33554428LL) || (displacement < (-33554432LL)) ) {
-               // show layout of final image
-               printSectionLayout(state);
+       if ( checkArmBranch24Displacement(displacement) )
+               return;
                
-               const ld::Atom* target; 
-               throwf("b/bl/blx ARM branch out of range (%lld max is +/-32MB): from %s (0x%08llX) to %s (0x%08llX)", 
-                               displacement, atom->name(), atom->finalAddress(), referenceTargetAtomName(state, fixup), 
-                               addressOf(state, fixup, &target));
-       }
+       // show layout of final image
+       printSectionLayout(state);
+       
+       const ld::Atom* target; 
+       throwf("b/bl/blx ARM branch out of range (%lld max is +/-32MB): from %s (0x%08llX) to %s (0x%08llX)", 
+                       displacement, atom->name(), atom->finalAddress(), referenceTargetAtomName(state, fixup), 
+                       addressOf(state, fixup, &target));
 }
 
-void OutputFile::rangeCheckThumbBranch22(int64_t displacement, ld::Internal& state, const ld::Atom* atom, const ld::Fixup* fixup)
+bool OutputFile::checkThumbBranch22Displacement(int64_t displacement)
 {
-       // thumb2 supports a larger displacement
+       // thumb2 supports  +/- 16MB displacement
        if ( _options.preferSubArchitecture() && _options.archSupportsThumb2() ) {
                if ( (displacement > 16777214LL) || (displacement < (-16777216LL)) ) {
-                       // show layout of final image
-                       printSectionLayout(state);
-                       
-                       const ld::Atom* target; 
-                       throwf("b/bl/blx thumb2 branch out of range (%lld max is +/-16MB): from %s (0x%08llX) to %s (0x%08llX)", 
-                                       displacement, atom->name(), atom->finalAddress(), referenceTargetAtomName(state, fixup), 
-                               addressOf(state, fixup, &target));
+                       return false;
                }
        }
        else {
+               // thumb1 supports +/- 4MB displacement
                if ( (displacement > 4194302LL) || (displacement < (-4194304LL)) ) {
-                       // show layout of final image
-                       printSectionLayout(state);
-                       
-                       const ld::Atom* target; 
-                       throwf("b/bl/blx thumb1 branch out of range (%lld max is +/-4MB): from %s (0x%08llX) to %s (0x%08llX)", 
-                                       displacement, atom->name(), atom->finalAddress(), referenceTargetAtomName(state, fixup), 
-                               addressOf(state, fixup, &target));
+                       return false;
                }
        }
+       return true;
+}
+
+void OutputFile::rangeCheckThumbBranch22(int64_t displacement, ld::Internal& state, const ld::Atom* atom, const ld::Fixup* fixup)
+{
+       if ( checkThumbBranch22Displacement(displacement) )
+               return;
+
+       // show layout of final image
+       printSectionLayout(state);
+
+       const ld::Atom* target; 
+       if ( _options.preferSubArchitecture() && _options.archSupportsThumb2() ) {
+               throwf("b/bl/blx thumb2 branch out of range (%lld max is +/-16MB): from %s (0x%08llX) to %s (0x%08llX)", 
+                               displacement, atom->name(), atom->finalAddress(), referenceTargetAtomName(state, fixup), 
+                               addressOf(state, fixup, &target));
+       }
+       else {
+               throwf("b/bl/blx thumb1 branch out of range (%lld max is +/-4MB): from %s (0x%08llX) to %s (0x%08llX)", 
+                               displacement, atom->name(), atom->finalAddress(), referenceTargetAtomName(state, fixup), 
+                               addressOf(state, fixup, &target));
+       }
 }
 
 
@@ -1023,6 +778,517 @@ void     OutputFile::set32BE(uint8_t* loc, uint32_t value) { BigEndian::set32(*(
 uint64_t OutputFile::get64BE(uint8_t* loc) { return BigEndian::get64(*(uint64_t*)loc); }
 void     OutputFile::set64BE(uint8_t* loc, uint64_t value) { BigEndian::set64(*(uint64_t*)loc, value); }
 
+static uint32_t makeNOP() {
+       return 0xD503201F;
+}
+
+enum SignExtension { signedNot, signed32, signed64 };
+struct LoadStoreInfo {
+       uint32_t                reg;
+       uint32_t                baseReg;
+       uint32_t                offset;         // after scaling
+       uint32_t                size;           // 1,2,4,8, or 16
+       bool                    isStore;
+       bool                    isFloat;        // if destReg is FP/SIMD
+       SignExtension   signEx;         // if load is sign extended
+};
+
+static uint32_t makeLDR_literal(const LoadStoreInfo& info, uint64_t targetAddress, uint64_t instructionAddress) 
+{
+       int64_t delta = targetAddress - instructionAddress;
+       assert(delta < 1024*1024);
+       assert(delta > -1024*1024);
+       assert((info.reg & 0xFFFFFFE0) == 0);
+       assert((targetAddress & 0x3) == 0);
+       assert((instructionAddress & 0x3) == 0);
+       assert(!info.isStore);
+       uint32_t imm19 = (delta << 3) & 0x00FFFFE0;
+       uint32_t instruction = 0;
+       switch ( info.size ) {
+               case 4:
+                       if ( info.isFloat ) {
+                               assert(info.signEx == signedNot);
+                               instruction = 0x1C000000;
+                       }
+                       else {
+                               if ( info.signEx == signed64 )
+                                       instruction = 0x98000000;
+                               else
+                                       instruction = 0x18000000;
+                       }
+                       break;
+               case 8:
+                       assert(info.signEx == signedNot);
+                       instruction = info.isFloat ? 0x5C000000 : 0x58000000;
+                       break;
+               case 16:
+                       assert(info.signEx == signedNot);
+                       instruction = 0x9C000000;
+                       break;
+               default:
+                       assert(0 && "invalid load size for literal");
+       }
+       return (instruction | imm19 | info.reg);
+}
+
+static uint32_t makeADR(uint32_t destReg, uint64_t targetAddress, uint64_t instructionAddress)
+{
+       assert((destReg & 0xFFFFFFE0) == 0);
+       assert((instructionAddress & 0x3) == 0);
+       uint32_t instruction = 0x10000000;
+       int64_t delta = targetAddress - instructionAddress;
+       assert(delta < 1024*1024);
+       assert(delta > -1024*1024);
+       uint32_t immhi = (delta & 0x001FFFFC) << 3;
+       uint32_t immlo = (delta & 0x00000003) << 29;
+       return (instruction | immhi | immlo | destReg); 
+}
+
+static uint32_t makeLoadOrStore(const LoadStoreInfo& info)
+{
+       uint32_t instruction = 0x39000000;
+       if ( info.isFloat )
+               instruction |= 0x04000000;
+       instruction |= info.reg;
+       instruction |= (info.baseReg << 5);
+       uint32_t sizeBits = 0;
+       uint32_t opcBits = 0;
+       uint32_t imm12Bits = 0;
+       switch ( info.size ) {
+               case 1:
+                       sizeBits = 0;
+                       imm12Bits = info.offset;
+                       if ( info.isStore ) {
+                               opcBits = 0;
+                       }
+                       else {
+                               switch ( info.signEx ) {
+                                       case signedNot:
+                                               opcBits = 1;
+                                               break;
+                                       case signed32:
+                                               opcBits = 3;
+                                               break;
+                                       case signed64:
+                                               opcBits = 2;
+                                               break;
+                               }
+                       }
+                       break;
+               case 2:
+                       sizeBits = 1;
+                       assert((info.offset % 2) == 0);
+                       imm12Bits = info.offset/2;
+                       if ( info.isStore ) {
+                               opcBits = 0;
+                       }
+                       else {
+                               switch ( info.signEx ) {
+                                       case signedNot:
+                                               opcBits = 1;
+                                               break;
+                                       case signed32:
+                                               opcBits = 3;
+                                               break;
+                                       case signed64:
+                                               opcBits = 2;
+                                               break;
+                               }
+                       }
+                       break;
+               case 4:
+                       sizeBits = 2;
+                       assert((info.offset % 4) == 0);
+                       imm12Bits = info.offset/4;
+                       if ( info.isStore ) {
+                               opcBits = 0;
+                       }
+                       else {
+                               switch ( info.signEx ) {
+                                       case signedNot:
+                                               opcBits = 1;
+                                               break;
+                                       case signed32:
+                                               assert(0 && "cannot use signed32 with 32-bit load/store");
+                                               break;
+                                       case signed64:
+                                               opcBits = 2;
+                                               break;
+                               }
+                       }
+                       break;
+               case 8:
+                       sizeBits = 3;
+                       assert((info.offset % 8) == 0);
+                       imm12Bits = info.offset/8;
+                       if ( info.isStore ) {
+                               opcBits = 0;
+                       }
+                       else {
+                               opcBits = 1;
+                               assert(info.signEx == signedNot);
+                       }
+                       break;
+               case 16:
+                       sizeBits = 0;
+                       assert((info.offset % 16) == 0);
+                       imm12Bits = info.offset/16;
+                       assert(info.isFloat);
+                       if ( info.isStore ) {
+                               opcBits = 2;
+                       }
+                       else {
+                               opcBits = 3;
+                       }
+                       break;
+               default:
+                       assert(0 && "bad load/store size");
+                       break;
+       }
+       assert(imm12Bits < 4096);
+       return (instruction | (sizeBits << 30) | (opcBits << 22) | (imm12Bits << 10));
+}
+
+static bool parseLoadOrStore(uint32_t instruction, LoadStoreInfo& info) 
+{
+       if ( (instruction & 0x3B000000) != 0x39000000 ) 
+               return false;
+       info.isFloat = ( (instruction & 0x04000000) != 0 );
+       info.reg = (instruction & 0x1F);
+       info.baseReg = ((instruction>>5) & 0x1F);
+       switch (instruction & 0xC0C00000) {
+               case 0x00000000:
+                       info.size = 1;
+                       info.isStore = true;
+                       info.signEx = signedNot;
+                       break;
+               case 0x00400000:
+                       info.size = 1;
+                       info.isStore = false;
+                       info.signEx = signedNot;
+                       break;
+               case 0x00800000:
+                       if ( info.isFloat ) {
+                               info.size = 16;
+                               info.isStore = true;
+                               info.signEx = signedNot;
+                       }
+                       else {
+                               info.size = 1;
+                               info.isStore = false;
+                               info.signEx = signed64;
+                       }
+                       break;
+               case 0x00C00000:
+                       if ( info.isFloat ) {
+                               info.size = 16;
+                               info.isStore = false;
+                               info.signEx = signedNot;
+                       }
+                       else {
+                               info.size = 1;
+                               info.isStore = false;
+                               info.signEx = signed32;
+                       }
+                       break;
+               case 0x40000000:
+                       info.size = 2;
+                       info.isStore = true;
+                       info.signEx = signedNot;
+                       break;
+               case 0x40400000:
+                       info.size = 2;
+                       info.isStore = false;
+                       info.signEx = signedNot;
+                       break;
+               case 0x40800000:
+                       info.size = 2;
+                       info.isStore = false;
+                       info.signEx = signed64;
+                       break;
+               case 0x40C00000:
+                       info.size = 2;
+                       info.isStore = false;
+                       info.signEx = signed32;
+                       break;
+               case 0x80000000:
+                       info.size = 4;
+                       info.isStore = true;
+                       info.signEx = signedNot;
+                       break;
+               case 0x80400000:
+                       info.size = 4;
+                       info.isStore = false;
+                       info.signEx = signedNot;
+                       break;
+               case 0x80800000:
+                       info.size = 4;
+                       info.isStore = false;
+                       info.signEx = signed64;
+                       break;
+               case 0xC0000000:
+                       info.size = 8;
+                       info.isStore = true;
+                       info.signEx = signedNot;
+                       break;
+               case 0xC0400000:
+                       info.size = 8;
+                       info.isStore = false;
+                       info.signEx = signedNot;
+                       break;
+               default:
+                       return false;
+       }
+       info.offset = ((instruction >> 10) & 0x0FFF) * info.size;
+       return true;    
+}
+
+struct AdrpInfo {
+       uint32_t        destReg;
+};
+
+static bool parseADRP(uint32_t instruction, AdrpInfo& info) 
+{
+       if ( (instruction & 0x9F000000) != 0x90000000 )
+               return false;
+       info.destReg = (instruction & 0x1F);
+       return true;
+}
+
+struct AddInfo {
+       uint32_t        destReg;
+       uint32_t        srcReg;
+       uint32_t        addend;
+};
+
+static bool parseADD(uint32_t instruction, AddInfo& info) 
+{
+       if ( (instruction & 0xFFC00000) != 0x91000000 )
+               return false;
+       info.destReg = (instruction & 0x1F);
+       info.srcReg = ((instruction>>5) & 0x1F);
+       info.addend = ((instruction>>10) & 0xFFF);
+       return true;
+}
+
+
+
+#if 0
+static uint32_t makeLDR_scaledOffset(const LoadStoreInfo& info) 
+{
+       assert((info.reg & 0xFFFFFFE0) == 0);
+       assert((info.baseReg & 0xFFFFFFE0) == 0);
+       assert(!info.isFloat || (info.signEx != signedNot));
+       uint32_t sizeBits = 0;
+       uint32_t opcBits = 1;
+       uint32_t vBit = info.isFloat;
+       switch ( info.signEx ) {
+               case signedNot:
+                       opcBits = 1;
+                       break;
+               case signed32:
+                       opcBits = 3;
+                       break;
+               case signed64:
+                       opcBits = 2;
+                       break;
+               default:
+                       assert(0 && "bad SignExtension runtime value");
+       }
+       switch ( info.size ) {
+               case 1:
+                       sizeBits = 0;
+                       break;
+               case 2:
+                       sizeBits = 1;
+                       break;
+               case 4:
+                       sizeBits = 2;
+                       break;
+               case 8:
+                       sizeBits = 3;
+                       break;
+               case 16:
+                       sizeBits = 0;
+                       vBit = 1;
+                       opcBits = 3;
+                       break;
+               default:
+                       assert(0 && "invalid load size for literal");
+       }
+       assert((info.offset % info.size) == 0);
+       uint32_t scaledOffset = info.offset/info.size;
+       assert(scaledOffset < 4096);
+       return (0x39000000 | (sizeBits<<30) | (vBit<<26) | (opcBits<<22) | (scaledOffset<<10) | (info.baseReg<<5) | info.reg);
+}
+
+static uint32_t makeLDR_literal(uint32_t destReg, uint32_t loadSize, bool isFloat, uint64_t targetAddress, uint64_t instructionAddress) 
+{
+       int64_t delta = targetAddress - instructionAddress;
+       assert(delta < 1024*1024);
+       assert(delta > -1024*1024);
+       assert((destReg & 0xFFFFFFE0) == 0);
+       assert((targetAddress & 0x3) == 0);
+       assert((instructionAddress & 0x3) == 0);
+       uint32_t imm19 = (delta << 3) & 0x00FFFFE0;
+       uint32_t instruction = 0;
+       switch ( loadSize ) {
+               case 4:
+                       instruction = isFloat ? 0x1C000000 : 0x18000000;
+                       break;
+               case 8:
+                       instruction = isFloat ? 0x5C000000 : 0x58000000;
+                       break;
+               case 16:
+                       instruction = 0x9C000000;
+                       break;
+               default:
+                       assert(0 && "invalid load size for literal");
+       }
+       return (instruction | imm19 | destReg);
+}
+
+
+static bool ldrInfo(uint32_t instruction, uint8_t* size, uint8_t* destReg, bool* v, uint32_t* scaledOffset)
+{
+       *v = ( (instruction & 0x04000000) != 0 );
+       *destReg = (instruction & 0x1F);
+       uint32_t imm12 = ((instruction >> 10) & 0x00000FFF);
+       switch ( (instruction & 0xC0000000) >> 30 ) {
+               case 0:
+                       // vector and byte LDR have same "size" bits, need to check other bits to differenciate
+                       if ( (instruction & 0x00800000) == 0 ) {
+                               *size = 1;
+                               *scaledOffset = imm12;
+                       }
+                       else {
+                               *size = 16;
+                               *scaledOffset = imm12 * 16;
+                       }
+                       break;
+               case 1:
+                       *size = 2;
+                       *scaledOffset = imm12 * 2;
+                       break;
+               case 2:
+                       *size = 4;
+                       *scaledOffset = imm12 * 4;
+                       break;
+               case 3:
+                       *size = 8;
+                       *scaledOffset = imm12 * 8;
+                       break;
+       }
+       return ((instruction & 0x3B400000) == 0x39400000);
+}
+#endif
+
+static bool withinOneMeg(uint64_t addr1, uint64_t addr2) {
+       int64_t delta = (addr2 - addr1);
+       return ( (delta < 1024*1024) && (delta > -1024*1024) );
+}
+
+void OutputFile::setInfo(ld::Internal& state, const ld::Atom* atom, uint8_t* buffer, const std::map<uint32_t, const Fixup*>& usedByHints, 
+                                               uint32_t offsetInAtom, uint32_t delta, InstructionInfo* info) 
+{
+       info->offsetInAtom = offsetInAtom + delta;
+       std::map<uint32_t, const Fixup*>::const_iterator pos = usedByHints.find(info->offsetInAtom);
+       if ( (pos != usedByHints.end()) && (pos->second != NULL) ) {
+               info->fixup = pos->second;
+               info->targetAddress = addressOf(state, info->fixup, &info->target);
+               if ( info->fixup->clusterSize != ld::Fixup::k1of1 ) {
+                       assert(info->fixup->firstInCluster());
+                       const ld::Fixup* nextFixup = info->fixup + 1;
+                       if ( nextFixup->kind == ld::Fixup::kindAddAddend ) {
+                               info->targetAddress += nextFixup->u.addend;
+                       }
+                       else {
+                               assert(0 && "expected addend");
+                       }
+               }
+       }
+       else {
+               info->fixup = NULL;
+               info->targetAddress = 0;
+               info->target = NULL;
+       }
+       info->instructionContent = &buffer[info->offsetInAtom];
+       info->instructionAddress = atom->finalAddress() + info->offsetInAtom;
+       info->instruction = get32LE(info->instructionContent);
+}      
+
+static bool isPageKind(const ld::Fixup* fixup, bool mustBeGOT=false)
+{
+       if ( fixup == NULL )
+               return false;
+       const ld::Fixup* f;
+       switch ( fixup->kind ) {
+               case ld::Fixup::kindStoreTargetAddressARM64Page21:
+                       return !mustBeGOT;
+               case ld::Fixup::kindStoreTargetAddressARM64GOTLoadPage21:
+               case ld::Fixup::kindStoreTargetAddressARM64GOTLeaPage21:
+                       return true;
+               case ld::Fixup::kindSetTargetAddress:
+                       f = fixup;
+                       do { 
+                               ++f;
+                       } while ( ! f->lastInCluster() );
+                       switch (f->kind ) {
+                               case ld::Fixup::kindStoreARM64Page21:
+                                       return !mustBeGOT;
+                               case ld::Fixup::kindStoreARM64GOTLoadPage21:
+                               case ld::Fixup::kindStoreARM64GOTLeaPage21:
+                                       return true;
+                               default:
+                                       break;
+                       }
+                       break;
+               default:
+                       break;
+       }
+       return false;
+}
+
+static bool isPageOffsetKind(const ld::Fixup* fixup, bool mustBeGOT=false)
+{
+       if ( fixup == NULL )
+               return false;
+       const ld::Fixup* f;
+       switch ( fixup->kind ) {
+               case ld::Fixup::kindStoreTargetAddressARM64PageOff12:
+                       return !mustBeGOT;
+               case ld::Fixup::kindStoreTargetAddressARM64GOTLoadPageOff12:
+               case ld::Fixup::kindStoreTargetAddressARM64GOTLeaPageOff12:
+                       return true;
+               case ld::Fixup::kindSetTargetAddress:
+                       f = fixup;
+                       do { 
+                               ++f;
+                       } while ( ! f->lastInCluster() );
+                       switch (f->kind ) {
+                               case ld::Fixup::kindStoreARM64PageOff12:
+                                       return !mustBeGOT;
+                               case ld::Fixup::kindStoreARM64GOTLoadPageOff12:
+                               case ld::Fixup::kindStoreARM64GOTLeaPageOff12:
+                                       return true;
+                               default:
+                                       break;
+                       }
+                       break;
+               default:
+                       break;
+       }
+       return false;
+}
+
+
+#define LOH_ASSERT(cond) \
+       if ( !(cond) ) { \
+               warning("ignoring linker optimzation hint at %s+0x%X because " #cond, atom->name(), fit->offsetInAtom); \
+               break; \
+       } 
+
+
 void OutputFile::applyFixUps(ld::Internal& state, uint64_t mhAddress, const ld::Atom* atom, uint8_t* buffer)
 {
        //fprintf(stderr, "applyFixUps() on %s\n", atom->name());
@@ -1036,8 +1302,10 @@ void OutputFile::applyFixUps(ld::Internal& state, uint64_t mhAddress, const ld::
        bool is_blx;
        bool is_b;
        bool thumbTarget = false;
+       std::map<uint32_t, const Fixup*> usedByHints;
        for (ld::Fixup::iterator fit = atom->fixupsBegin(), end=atom->fixupsEnd(); fit != end; ++fit) {
                uint8_t* fixUpLocation = &buffer[fit->offsetInAtom];
+               ld::Fixup::LOH_arm64 lohExtra;
                switch ( (ld::Fixup::Kind)(fit->kind) ) { 
                        case ld::Fixup::kindNone:
                        case ld::Fixup::kindNoneFollowOn:
@@ -1281,6 +1549,7 @@ void OutputFile::applyFixUps(ld::Internal& state, uint64_t mhAddress, const ld::
                                }
                                break;
                        case ld::Fixup::kindLazyTarget:
+                       case ld::Fixup::kindIslandTarget:
                                break;
                        case ld::Fixup::kindSetLazyOffset:
                                assert(fit->binding == ld::Fixup::bindingDirectlyBound);
@@ -1293,6 +1562,17 @@ void OutputFile::applyFixUps(ld::Internal& state, uint64_t mhAddress, const ld::
                        case ld::Fixup::kindDataInCodeStartJTA32:
                        case ld::Fixup::kindDataInCodeEnd:
                                break;
+                       case ld::Fixup::kindLinkerOptimizationHint:
+                               // expand table of address/offsets used by hints
+                               lohExtra.addend = fit->u.addend;
+                               usedByHints[fit->offsetInAtom + (lohExtra.info.delta1 << 2)] = NULL;
+                               if ( lohExtra.info.count > 0 )
+                                       usedByHints[fit->offsetInAtom + (lohExtra.info.delta2 << 2)] = NULL;
+                               if ( lohExtra.info.count > 1 )
+                                       usedByHints[fit->offsetInAtom + (lohExtra.info.delta3 << 2)] = NULL;
+                               if ( lohExtra.info.count > 2 )
+                                       usedByHints[fit->offsetInAtom + (lohExtra.info.delta4 << 2)] = NULL;
+                               break;
                        case ld::Fixup::kindStoreTargetAddressLittleEndian32:
                                accumulator = addressOf(state, fit, &toTarget);
                                thumbTarget = targetIsThumb(state, fit);
@@ -1377,6 +1657,22 @@ void OutputFile::applyFixUps(ld::Internal& state, uint64_t mhAddress, const ld::
                        case ld::Fixup::kindStoreTargetAddressARMBranch24:
                                accumulator = addressOf(state, fit, &toTarget);
                                thumbTarget = targetIsThumb(state, fit);
+                               if ( toTarget->contentType() == ld::Atom::typeBranchIsland ) {
+                                       // Branching to island.  If ultimate target is in range, branch there directly.
+                                       for (ld::Fixup::iterator islandfit = toTarget->fixupsBegin(), end=toTarget->fixupsEnd(); islandfit != end; ++islandfit) {
+                                               if ( islandfit->kind == ld::Fixup::kindIslandTarget ) {
+                                                       const ld::Atom* islandTarget = NULL;
+                                                       uint64_t islandTargetAddress = addressOf(state, islandfit, &islandTarget);
+                                                       delta = islandTargetAddress - (atom->finalAddress() + fit->offsetInAtom + 4);
+                                                       if ( checkArmBranch24Displacement(delta) ) {
+                                                               toTarget = islandTarget;
+                                                               accumulator = islandTargetAddress;
+                                                               thumbTarget = targetIsThumb(state, islandfit);
+                                                       }
+                                                       break;
+                                               }
+                                       }
+                               }
                                if ( thumbTarget ) 
                                        accumulator |= 1;
                                if ( fit->contentDetlaToAddendOnly )
@@ -1387,18 +1683,18 @@ void OutputFile::applyFixUps(ld::Internal& state, uint64_t mhAddress, const ld::
                                delta = accumulator - (atom->finalAddress() + fit->offsetInAtom + 8);
                                rangeCheckARMBranch24(delta, state, atom, fit);
                                instruction = get32LE(fixUpLocation);
-                               // Make sure we are calling arm with bl, thumb with blx                 
+                               // Make sure we are calling arm with bl, thumb with blx         
                                is_bl = ((instruction & 0xFF000000) == 0xEB000000);
                                is_blx = ((instruction & 0xFE000000) == 0xFA000000);
                                is_b = !is_blx && ((instruction & 0x0F000000) == 0x0A000000);
-                               if ( is_bl && thumbTarget ) {
-                                       uint32_t opcode = 0xFA000000;
+                               if ( (is_bl | is_blx) && thumbTarget ) {
+                                       uint32_t opcode = 0xFA000000;  // force to be blx
                                        uint32_t disp = (uint32_t)(delta >> 2) & 0x00FFFFFF;
                                        uint32_t h_bit = (uint32_t)(delta << 23) & 0x01000000;
                                        newInstruction = opcode | h_bit | disp;
                                } 
-                               else if ( is_blx && !thumbTarget ) {
-                                       uint32_t opcode = 0xEB000000;
+                               else if ( (is_bl | is_blx) && !thumbTarget ) {
+                                       uint32_t opcode = 0xEB000000;  // force to be bl
                                        uint32_t disp = (uint32_t)(delta >> 2) & 0x00FFFFFF;
                                        newInstruction = opcode | disp;
                                } 
@@ -1421,6 +1717,23 @@ void OutputFile::applyFixUps(ld::Internal& state, uint64_t mhAddress, const ld::
                        case ld::Fixup::kindStoreTargetAddressThumbBranch22:
                                accumulator = addressOf(state, fit, &toTarget);
                                thumbTarget = targetIsThumb(state, fit);
+                               if ( toTarget->contentType() == ld::Atom::typeBranchIsland ) {
+                                       // branching to island, so see if ultimate target is in range 
+                                       // and if so branch to ultimate target instead.
+                                       for (ld::Fixup::iterator islandfit = toTarget->fixupsBegin(), end=toTarget->fixupsEnd(); islandfit != end; ++islandfit) {
+                                               if ( islandfit->kind == ld::Fixup::kindIslandTarget ) {
+                                                       const ld::Atom* islandTarget = NULL;
+                                                       uint64_t islandTargetAddress = addressOf(state, islandfit, &islandTarget);
+                                                       delta = islandTargetAddress - (atom->finalAddress() + fit->offsetInAtom + 4);
+                                                       if ( checkThumbBranch22Displacement(delta) ) {
+                                                               toTarget = islandTarget;
+                                                               accumulator = islandTargetAddress;
+                                                               thumbTarget = targetIsThumb(state, islandfit);
+                                                       }
+                                                       break;
+                                               }
+                                       }
+                               }
                                if ( thumbTarget ) 
                                        accumulator |= 1;
                                if ( fit->contentDetlaToAddendOnly )
@@ -1572,11 +1885,14 @@ void OutputFile::applyFixUps(ld::Internal& state, uint64_t mhAddress, const ld::
                        case ld::Fixup::kindStoreTargetAddressARM64GOTLeaPage21:
                        case ld::Fixup::kindStoreTargetAddressARM64GOTLoadPage21:
                        case ld::Fixup::kindStoreTargetAddressARM64Page21:
+                       case ld::Fixup::kindStoreTargetAddressARM64TLVPLoadPage21:
+                       case ld::Fixup::kindStoreTargetAddressARM64TLVPLoadNowLeaPage21:
                                accumulator = addressOf(state, fit, &toTarget);
                                // fall into kindStoreARM64Branch26 case
                        case ld::Fixup::kindStoreARM64GOTLeaPage21:
                        case ld::Fixup::kindStoreARM64GOTLoadPage21:
                        case ld::Fixup::kindStoreARM64TLVPLoadPage21:
+                       case ld::Fixup::kindStoreARM64TLVPLoadNowLeaPage21:
                        case ld::Fixup::kindStoreARM64Page21:
                                {
                                        // the ADRP instruction adds the imm << 12 to the page that the pc is on
@@ -1594,6 +1910,7 @@ void OutputFile::applyFixUps(ld::Internal& state, uint64_t mhAddress, const ld::
                                break;
                        case ld::Fixup::kindStoreTargetAddressARM64GOTLoadPageOff12:
                        case ld::Fixup::kindStoreTargetAddressARM64PageOff12:
+                       case ld::Fixup::kindStoreTargetAddressARM64TLVPLoadPageOff12:
                                accumulator = addressOf(state, fit, &toTarget);
                                // fall into kindAddressARM64PageOff12 case
                        case ld::Fixup::kindStoreARM64TLVPLoadPageOff12:
@@ -1664,6 +1981,21 @@ void OutputFile::applyFixUps(ld::Internal& state, uint64_t mhAddress, const ld::
                                        set32LE(fixUpLocation, newInstruction);
                                }
                                break;
+                       case ld::Fixup::kindStoreTargetAddressARM64TLVPLoadNowLeaPageOff12:
+                               accumulator = addressOf(state, fit, &toTarget);
+                               // fall into kindStoreARM64TLVPLeaPageOff12 case
+                       case ld::Fixup::kindStoreARM64TLVPLoadNowLeaPageOff12:
+                               {
+                                       // TLV thunk in same linkage unit, so LEA it directly, changing LDR instruction to a ADD
+                                       instruction = get32LE(fixUpLocation);
+                                       if ( (instruction & 0xFFC00000) != 0xF9400000 )
+                                               throwf("TLV 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;
@@ -1677,6 +2009,450 @@ void OutputFile::applyFixUps(ld::Internal& state, uint64_t mhAddress, const ld::
 #endif
                }
        }
+       
+       // after all fixups are done on atom, if there are potential optimizations, do those
+       if ( (usedByHints.size() != 0) && (_options.outputKind() != Options::kObjectFile) && !_options.ignoreOptimizationHints() ) {
+               // fill in second part of usedByHints map, so we can see the target of fixups that might be optimized
+               for (ld::Fixup::iterator fit = atom->fixupsBegin(), end=atom->fixupsEnd(); fit != end; ++fit) {
+                       switch ( fit->kind ) {
+                               case ld::Fixup::kindLinkerOptimizationHint:
+                               case ld::Fixup::kindNoneFollowOn:
+                               case ld::Fixup::kindNoneGroupSubordinate:
+                               case ld::Fixup::kindNoneGroupSubordinateFDE:
+                               case ld::Fixup::kindNoneGroupSubordinateLSDA:
+                               case ld::Fixup::kindNoneGroupSubordinatePersonality:
+                                       break;
+                               default:
+                                       if ( fit->firstInCluster() ) {
+                                               std::map<uint32_t, const Fixup*>::iterator pos = usedByHints.find(fit->offsetInAtom);
+                                               if ( pos != usedByHints.end() ) {
+                                                       assert(pos->second == NULL && "two fixups in same hint location");
+                                                       pos->second = fit;
+                                                       //fprintf(stderr, "setting %s usedByHints[0x%04X], kind = %d\n",  atom->name(), fit->offsetInAtom, fit->kind);
+                                               }
+                                       }
+                       }
+               }
+               
+               // apply hints pass 1
+               for (ld::Fixup::iterator fit = atom->fixupsBegin(), end=atom->fixupsEnd(); fit != end; ++fit) {
+                       if ( fit->kind != ld::Fixup::kindLinkerOptimizationHint ) 
+                               continue;
+                       InstructionInfo infoA;
+                       InstructionInfo infoB;
+                       InstructionInfo infoC;
+                       InstructionInfo infoD;
+                       LoadStoreInfo ldrInfoB, ldrInfoC;
+                       AddInfo addInfoB;
+                       AdrpInfo adrpInfoA;
+                       bool usableSegment;
+                       bool targetFourByteAligned;
+                       bool literalableSize, isADRP, isADD, isLDR, isSTR;
+                       //uint8_t loadSize, destReg;
+                       //uint32_t scaledOffset;
+                       //uint32_t imm12;
+                       ld::Fixup::LOH_arm64 alt;
+                       alt.addend = fit->u.addend;
+                       setInfo(state, atom, buffer, usedByHints, fit->offsetInAtom, (alt.info.delta1 << 2), &infoA);
+                       if ( alt.info.count > 0 ) 
+                               setInfo(state, atom, buffer, usedByHints, fit->offsetInAtom, (alt.info.delta2 << 2), &infoB);
+                       if ( alt.info.count > 1 )
+                               setInfo(state, atom, buffer, usedByHints, fit->offsetInAtom, (alt.info.delta3 << 2), &infoC);
+                       if ( alt.info.count > 2 )
+                               setInfo(state, atom, buffer, usedByHints, fit->offsetInAtom, (alt.info.delta4 << 2), &infoD);
+                               
+                       switch ( alt.info.kind ) {
+                               case LOH_ARM64_ADRP_ADRP:
+                                       // processed in pass 2 beacuse some ADRP may have been removed
+                                       break;
+                               case LOH_ARM64_ADRP_LDR:
+                                       LOH_ASSERT(alt.info.count == 1);
+                                       LOH_ASSERT(isPageKind(infoA.fixup));
+                                       LOH_ASSERT(isPageOffsetKind(infoB.fixup));
+                                       LOH_ASSERT(infoA.target == infoB.target);
+                                       LOH_ASSERT(infoA.targetAddress == infoB.targetAddress);
+                                       usableSegment = ( !_options.sharedRegionEligible() || (strcmp(atom->section().segmentName(), infoB.target->section().segmentName()) == 0) );
+                                       isADRP = parseADRP(infoA.instruction, adrpInfoA);
+                                       LOH_ASSERT(isADRP);
+                                       isLDR = parseLoadOrStore(infoB.instruction, ldrInfoB);
+                                       LOH_ASSERT(isLDR);
+                                       LOH_ASSERT(ldrInfoB.baseReg == adrpInfoA.destReg);
+                                       LOH_ASSERT(ldrInfoB.offset == (infoA.targetAddress & 0x00000FFF));
+                                       literalableSize = ( (ldrInfoB.size != 1) && (ldrInfoB.size != 2) );
+                                       targetFourByteAligned = ( (infoA.targetAddress & 0x3) == 0 );
+                                       if ( literalableSize && usableSegment && targetFourByteAligned && withinOneMeg(infoB.instructionAddress, infoA.targetAddress) ) {
+                                               set32LE(infoA.instructionContent, makeNOP());
+                                               set32LE(infoB.instructionContent, makeLDR_literal(ldrInfoB, infoA.targetAddress, infoB.instructionAddress));
+                                               if ( _options.verboseOptimizationHints() )
+                                                       fprintf(stderr, "adrp-ldr at 0x%08llX transformed to LDR literal\n", infoB.instructionAddress);
+                                       }
+                                       else {
+                                               if ( _options.verboseOptimizationHints() )
+                                                       fprintf(stderr, "adrp-ldr at 0x%08llX not transformed, isLDR=%d, literalableSize=%d, inRange=%d, usableSegment=%d, scaledOffset=%d\n", 
+                                                               infoB.instructionAddress, isLDR, literalableSize, withinOneMeg(infoB.instructionAddress, infoA.targetAddress), usableSegment, ldrInfoB.offset);
+                                       }
+                                       break;
+                               case LOH_ARM64_ADRP_ADD_LDR:
+                                       LOH_ASSERT(alt.info.count == 2);
+                                       LOH_ASSERT(isPageKind(infoA.fixup));
+                                       LOH_ASSERT(isPageOffsetKind(infoB.fixup));
+                                       LOH_ASSERT(infoC.fixup == NULL);
+                                       LOH_ASSERT(infoA.target == infoB.target);
+                                       LOH_ASSERT(infoA.targetAddress == infoB.targetAddress);
+                                       usableSegment = ( !_options.sharedRegionEligible() || (strcmp(atom->section().segmentName(), infoB.target->section().segmentName()) == 0) );
+                                       isADRP = parseADRP(infoA.instruction, adrpInfoA);
+                                       LOH_ASSERT(isADRP);
+                                       isADD = parseADD(infoB.instruction, addInfoB);
+                                       LOH_ASSERT(isADD);
+                                       LOH_ASSERT(adrpInfoA.destReg == addInfoB.srcReg);
+                                       isLDR = parseLoadOrStore(infoC.instruction, ldrInfoC);
+                                       LOH_ASSERT(isLDR);
+                                       LOH_ASSERT(addInfoB.destReg == ldrInfoC.baseReg);
+                                       targetFourByteAligned = ( ((infoB.targetAddress+ldrInfoC.offset) & 0x3) == 0 );
+                                       literalableSize  = ( (ldrInfoC.size != 1) && (ldrInfoC.size != 2) );
+                                       if ( literalableSize && usableSegment && targetFourByteAligned && withinOneMeg(infoC.instructionAddress, infoA.targetAddress+ldrInfoC.offset) ) {
+                                               // can do T1 transformation to LDR literal
+                                               set32LE(infoA.instructionContent, makeNOP());
+                                               set32LE(infoB.instructionContent, makeNOP());
+                                               set32LE(infoC.instructionContent, makeLDR_literal(ldrInfoC, infoA.targetAddress+ldrInfoC.offset, infoC.instructionAddress));
+                                               if ( _options.verboseOptimizationHints() ) {
+                                                       fprintf(stderr, "adrp-add-ldr at 0x%08llX T1 transformed to LDR literal\n", infoC.instructionAddress);
+                                               }
+                                       }
+                                       else if ( usableSegment && withinOneMeg(infoA.instructionAddress, infoA.targetAddress+ldrInfoC.offset) ) {
+                                               // can to T4 transformation and turn ADRP/ADD into ADR
+                                               set32LE(infoA.instructionContent, makeADR(ldrInfoC.baseReg, infoA.targetAddress+ldrInfoC.offset, infoA.instructionAddress));
+                                               set32LE(infoB.instructionContent, makeNOP());   
+                                               ldrInfoC.offset = 0; // offset is now in ADR instead of ADD or LDR
+                                               set32LE(infoC.instructionContent, makeLoadOrStore(ldrInfoC));
+                                               set32LE(infoC.instructionContent, infoC.instruction & 0xFFC003FF);      
+                                               if ( _options.verboseOptimizationHints() )
+                                                       fprintf(stderr, "adrp-add-ldr at 0x%08llX T4 transformed to ADR/LDR\n", infoB.instructionAddress);                                              
+                                       }
+                                       else if ( ((infoB.targetAddress % ldrInfoC.size) == 0) && (ldrInfoC.offset == 0) ) {
+                                               // can do T2 transformation by merging ADD into LD
+                                               // Leave ADRP as-is
+                                               set32LE(infoB.instructionContent, makeNOP());   
+                                               ldrInfoC.offset += addInfoB.addend;
+                                               set32LE(infoC.instructionContent, makeLoadOrStore(ldrInfoC));
+                                               if ( _options.verboseOptimizationHints() )
+                                                       fprintf(stderr, "adrp-add-ldr at 0x%08llX T2 transformed to ADRP/LDR \n", infoC.instructionAddress);
+                                       }
+                                       else {
+                                               if ( _options.verboseOptimizationHints() )
+                                                       fprintf(stderr, "adrp-add-ldr at 0x%08llX could not be transformed, loadSize=%d, literalableSize=%d, inRange=%d, usableSegment=%d, targetFourByteAligned=%d, imm12=%d\n", 
+                                                                       infoC.instructionAddress, ldrInfoC.size, literalableSize, withinOneMeg(infoC.instructionAddress, infoA.targetAddress+ldrInfoC.offset), usableSegment, targetFourByteAligned, ldrInfoC.offset);
+                                       }
+                                       break;
+                               case LOH_ARM64_ADRP_ADD:
+                                       LOH_ASSERT(alt.info.count == 1);
+                                       LOH_ASSERT(isPageKind(infoA.fixup));
+                                       LOH_ASSERT(isPageOffsetKind(infoB.fixup));
+                                       LOH_ASSERT(infoA.target == infoB.target);
+                                       LOH_ASSERT(infoA.targetAddress == infoB.targetAddress);
+                                       isADRP = parseADRP(infoA.instruction, adrpInfoA);
+                                       LOH_ASSERT(isADRP);
+                                       isADD = parseADD(infoB.instruction, addInfoB);
+                                       LOH_ASSERT(isADD);
+                                       LOH_ASSERT(adrpInfoA.destReg == addInfoB.srcReg);
+                                       usableSegment = ( !_options.sharedRegionEligible() || (strcmp(atom->section().segmentName(), infoB.target->section().segmentName()) == 0) );
+                                       if ( usableSegment && withinOneMeg(infoA.targetAddress, infoA.instructionAddress) ) {
+                                               // can do T4 transformation and use ADR 
+                                               set32LE(infoA.instructionContent, makeADR(addInfoB.destReg, infoA.targetAddress, infoA.instructionAddress));
+                                               set32LE(infoB.instructionContent, makeNOP());   
+                                               if ( _options.verboseOptimizationHints() )
+                                                       fprintf(stderr, "adrp-add at 0x%08llX transformed to ADR\n", infoB.instructionAddress);
+                                       }
+                                       else {
+                                               if ( _options.verboseOptimizationHints() )
+                                                       fprintf(stderr, "adrp-add at 0x%08llX not transformed, isAdd=%d, inRange=%d, usableSegment=%d\n", 
+                                                               infoB.instructionAddress, isADD, withinOneMeg(infoA.targetAddress, infoA.instructionAddress), usableSegment);
+                                       }
+                                       break;
+                               case LOH_ARM64_ADRP_LDR_GOT_LDR:
+                                       LOH_ASSERT(alt.info.count == 2);
+                                       LOH_ASSERT(isPageKind(infoA.fixup, true));
+                                       LOH_ASSERT(isPageOffsetKind(infoB.fixup, true));
+                                       LOH_ASSERT(infoC.fixup == NULL);
+                                       LOH_ASSERT(infoA.target == infoB.target);
+                                       LOH_ASSERT(infoA.targetAddress == infoB.targetAddress);
+                                       isADRP = parseADRP(infoA.instruction, adrpInfoA);
+                                       LOH_ASSERT(isADRP);
+                                       isLDR = parseLoadOrStore(infoC.instruction, ldrInfoC);
+                                       LOH_ASSERT(isLDR);
+                                       LOH_ASSERT(ldrInfoC.offset == 0);
+                                       isADD = parseADD(infoB.instruction, addInfoB);
+                                       isLDR = parseLoadOrStore(infoB.instruction, ldrInfoB);
+                                       if ( isLDR ) {
+                                               // target of GOT is external
+                                               LOH_ASSERT(ldrInfoB.size == 8);
+                                               LOH_ASSERT(!ldrInfoB.isFloat);
+                                               LOH_ASSERT(ldrInfoC.baseReg == ldrInfoB.reg);
+                                               //fprintf(stderr, "infoA.target=%p, %s, infoA.targetAddress=0x%08llX\n", infoA.target, infoA.target->name(), infoA.targetAddress);
+                                               usableSegment = ( !_options.sharedRegionEligible() || (strcmp(atom->section().segmentName(), infoB.target->section().segmentName()) == 0) );
+                                               targetFourByteAligned = ( ((infoA.targetAddress) & 0x3) == 0 );
+                                               if ( usableSegment && targetFourByteAligned && withinOneMeg(infoB.instructionAddress, infoA.targetAddress) ) {
+                                                       // can do T5 transform
+                                                       set32LE(infoA.instructionContent, makeNOP());
+                                                       set32LE(infoB.instructionContent, makeLDR_literal(ldrInfoB, infoA.targetAddress, infoB.instructionAddress));
+                                                       if ( _options.verboseOptimizationHints() ) {
+                                                               fprintf(stderr, "adrp-ldr-got-ldr at 0x%08llX T5 transformed to LDR literal of GOT plus LDR\n", infoC.instructionAddress);
+                                                       }
+                                               }
+                                               else {
+                                                       if ( _options.verboseOptimizationHints() ) 
+                                                               fprintf(stderr, "adrp-ldr-got-ldr at 0x%08llX no optimization done\n", infoC.instructionAddress);
+                                               }
+                                       }
+                                       else if ( isADD ) {
+                                               // target of GOT is in same linkage unit and B instruction was changed to ADD to compute LEA of target
+                                               LOH_ASSERT(addInfoB.srcReg == adrpInfoA.destReg);
+                                               LOH_ASSERT(addInfoB.destReg == ldrInfoC.baseReg);
+                                               usableSegment = ( !_options.sharedRegionEligible() || (strcmp(atom->section().segmentName(), infoB.target->section().segmentName()) == 0) );
+                                               targetFourByteAligned = ( ((infoA.targetAddress) & 0x3) == 0 );
+                                               literalableSize  = ( (ldrInfoC.size != 1) && (ldrInfoC.size != 2) );
+                                               if ( usableSegment && literalableSize && targetFourByteAligned && withinOneMeg(infoC.instructionAddress, infoA.targetAddress) ) {
+                                                       // can do T1 transform
+                                                       set32LE(infoA.instructionContent, makeNOP());   
+                                                       set32LE(infoB.instructionContent, makeNOP());   
+                                                       set32LE(infoC.instructionContent, makeLDR_literal(ldrInfoC, infoA.targetAddress, infoC.instructionAddress));
+                                                       if ( _options.verboseOptimizationHints() ) 
+                                                               fprintf(stderr, "adrp-ldr-got-ldr at 0x%08llX T1 transformed to LDR literal\n", infoC.instructionAddress);
+                                               }
+                                               else if ( usableSegment && withinOneMeg(infoA.instructionAddress, infoA.targetAddress) ) {
+                                                       // can do T4 transform
+                                                       set32LE(infoA.instructionContent, makeADR(ldrInfoC.baseReg, infoA.targetAddress, infoA.instructionAddress));
+                                                       set32LE(infoB.instructionContent, makeNOP());   
+                                                       set32LE(infoC.instructionContent, makeLoadOrStore(ldrInfoC));
+                                                       if ( _options.verboseOptimizationHints() ) {
+                                                               fprintf(stderr, "adrp-ldr-got-ldr at 0x%08llX T4 transformed to ADR/LDR\n", infoC.instructionAddress);
+                                                       }
+                                               }
+                                               else if ( (infoA.targetAddress % ldrInfoC.size) == 0 ) {
+                                                       // can do T2 transform
+                                                       set32LE(infoB.instructionContent, makeNOP());
+                                                       ldrInfoC.baseReg = adrpInfoA.destReg;
+                                                       ldrInfoC.offset = addInfoB.addend;
+                                                       set32LE(infoC.instructionContent, makeLoadOrStore(ldrInfoC));
+                                                       if ( _options.verboseOptimizationHints() ) {
+                                                               fprintf(stderr, "adrp-ldr-got-ldr at 0x%08llX T4 transformed to ADRP/NOP/LDR\n", infoC.instructionAddress);
+                                                       }
+                                               }
+                                               else {
+                                                       // T3 transform already done by ld::passes:got:doPass()
+                                                       if ( _options.verboseOptimizationHints() ) {
+                                                               fprintf(stderr, "adrp-ldr-got-ldr at 0x%08llX T3 transformed to ADRP/ADD/LDR\n", infoC.instructionAddress);
+                                                       }
+                                               }
+                                       }
+                                       else {
+                                               if ( _options.verboseOptimizationHints() )                                                      
+                                                       fprintf(stderr, "adrp-ldr-got-ldr at 0x%08llX not ADD or LDR\n", infoC.instructionAddress);
+                                       }
+                                       break;
+                               case LOH_ARM64_ADRP_ADD_STR:
+                                       LOH_ASSERT(alt.info.count == 2);
+                                       LOH_ASSERT(isPageKind(infoA.fixup));
+                                       LOH_ASSERT(isPageOffsetKind(infoB.fixup));
+                                       LOH_ASSERT(infoC.fixup == NULL);
+                                       LOH_ASSERT(infoA.target == infoB.target);
+                                       LOH_ASSERT(infoA.targetAddress == infoB.targetAddress);
+                                       usableSegment = ( !_options.sharedRegionEligible() || (strcmp(atom->section().segmentName(), infoB.target->section().segmentName()) == 0) );
+                                       isADRP = parseADRP(infoA.instruction, adrpInfoA);
+                                       LOH_ASSERT(isADRP);
+                                       isADD = parseADD(infoB.instruction, addInfoB);
+                                       LOH_ASSERT(isADD);
+                                       LOH_ASSERT(adrpInfoA.destReg == addInfoB.srcReg);
+                                       isSTR = (parseLoadOrStore(infoC.instruction, ldrInfoC) && ldrInfoC.isStore);
+                                       LOH_ASSERT(isSTR);
+                                       LOH_ASSERT(addInfoB.destReg == ldrInfoC.baseReg);
+                                       if ( usableSegment && withinOneMeg(infoA.instructionAddress, infoA.targetAddress+ldrInfoC.offset) ) {
+                                               // can to T4 transformation and turn ADRP/ADD into ADR
+                                               set32LE(infoA.instructionContent, makeADR(ldrInfoC.baseReg, infoA.targetAddress+ldrInfoC.offset, infoA.instructionAddress));
+                                               set32LE(infoB.instructionContent, makeNOP());   
+                                               ldrInfoC.offset = 0; // offset is now in ADR instead of ADD or LDR
+                                               set32LE(infoC.instructionContent, makeLoadOrStore(ldrInfoC));
+                                               set32LE(infoC.instructionContent, infoC.instruction & 0xFFC003FF);      
+                                               if ( _options.verboseOptimizationHints() )
+                                                       fprintf(stderr, "adrp-add-str at 0x%08llX T4 transformed to ADR/STR\n", infoB.instructionAddress);                                              
+                                       }
+                                       else if ( ((infoB.targetAddress % ldrInfoC.size) == 0) && (ldrInfoC.offset == 0) ) {
+                                               // can do T2 transformation by merging ADD into STR
+                                               // Leave ADRP as-is
+                                               set32LE(infoB.instructionContent, makeNOP());   
+                                               ldrInfoC.offset += addInfoB.addend;
+                                               set32LE(infoC.instructionContent, makeLoadOrStore(ldrInfoC));
+                                               if ( _options.verboseOptimizationHints() )
+                                                       fprintf(stderr, "adrp-add-str at 0x%08llX T2 transformed to ADRP/STR \n", infoC.instructionAddress);
+                                       }
+                                       else {
+                                               if ( _options.verboseOptimizationHints() )
+                                                       fprintf(stderr, "adrp-add-str at 0x%08llX could not be transformed, loadSize=%d, inRange=%d, usableSegment=%d, imm12=%d\n", 
+                                                                       infoC.instructionAddress, ldrInfoC.size, withinOneMeg(infoC.instructionAddress, infoA.targetAddress+ldrInfoC.offset), usableSegment, ldrInfoC.offset);
+                                       }
+                                       break;
+                               case LOH_ARM64_ADRP_LDR_GOT_STR:
+                                       LOH_ASSERT(alt.info.count == 2);
+                                       LOH_ASSERT(isPageKind(infoA.fixup, true));
+                                       LOH_ASSERT(isPageOffsetKind(infoB.fixup, true));
+                                       LOH_ASSERT(infoC.fixup == NULL);
+                                       LOH_ASSERT(infoA.target == infoB.target);
+                                       LOH_ASSERT(infoA.targetAddress == infoB.targetAddress);
+                                       isADRP = parseADRP(infoA.instruction, adrpInfoA);
+                                       LOH_ASSERT(isADRP);
+                                       isSTR = (parseLoadOrStore(infoC.instruction, ldrInfoC) && ldrInfoC.isStore);
+                                       LOH_ASSERT(isSTR);
+                                       LOH_ASSERT(ldrInfoC.offset == 0);
+                                       isADD = parseADD(infoB.instruction, addInfoB);
+                                       isLDR = parseLoadOrStore(infoB.instruction, ldrInfoB);
+                                       if ( isLDR ) {
+                                               // target of GOT is external
+                                               LOH_ASSERT(ldrInfoB.size == 8);
+                                               LOH_ASSERT(!ldrInfoB.isFloat);
+                                               LOH_ASSERT(ldrInfoC.baseReg == ldrInfoB.reg);
+                                               usableSegment = ( !_options.sharedRegionEligible() || (strcmp(atom->section().segmentName(), infoB.target->section().segmentName()) == 0) );
+                                               targetFourByteAligned = ( ((infoA.targetAddress) & 0x3) == 0 );
+                                               if ( usableSegment && targetFourByteAligned && withinOneMeg(infoB.instructionAddress, infoA.targetAddress) ) {
+                                                       // can do T5 transform
+                                                       set32LE(infoA.instructionContent, makeNOP());
+                                                       set32LE(infoB.instructionContent, makeLDR_literal(ldrInfoB, infoA.targetAddress, infoB.instructionAddress));
+                                                       if ( _options.verboseOptimizationHints() ) {
+                                                               fprintf(stderr, "adrp-ldr-got-str at 0x%08llX T5 transformed to LDR literal of GOT plus STR\n", infoC.instructionAddress);
+                                                       }
+                                               }
+                                               else {
+                                                       if ( _options.verboseOptimizationHints() ) 
+                                                               fprintf(stderr, "adrp-ldr-got-str at 0x%08llX no optimization done\n", infoC.instructionAddress);
+                                               }
+                                       }
+                                       else if ( isADD ) {
+                                               // target of GOT is in same linkage unit and B instruction was changed to ADD to compute LEA of target
+                                               LOH_ASSERT(addInfoB.srcReg == adrpInfoA.destReg);
+                                               LOH_ASSERT(addInfoB.destReg == ldrInfoC.baseReg);
+                                               usableSegment = ( !_options.sharedRegionEligible() || (strcmp(atom->section().segmentName(), infoB.target->section().segmentName()) == 0) );
+                                               targetFourByteAligned = ( ((infoA.targetAddress) & 0x3) == 0 );
+                                               literalableSize  = ( (ldrInfoC.size != 1) && (ldrInfoC.size != 2) );
+                                               if ( usableSegment && withinOneMeg(infoA.instructionAddress, infoA.targetAddress) ) {
+                                                       // can do T4 transform
+                                                       set32LE(infoA.instructionContent, makeADR(ldrInfoC.baseReg, infoA.targetAddress, infoA.instructionAddress));
+                                                       set32LE(infoB.instructionContent, makeNOP());   
+                                                       set32LE(infoC.instructionContent, makeLoadOrStore(ldrInfoC));
+                                                       if ( _options.verboseOptimizationHints() ) {
+                                                               fprintf(stderr, "adrp-ldr-got-str at 0x%08llX T4 transformed to ADR/STR\n", infoC.instructionAddress);
+                                                       }
+                                               }
+                                               else if ( ((infoA.targetAddress % ldrInfoC.size) == 0) && (ldrInfoC.offset == 0) ) {
+                                                       // can do T2 transform
+                                                       set32LE(infoB.instructionContent, makeNOP());
+                                                       ldrInfoC.baseReg = adrpInfoA.destReg;
+                                                       ldrInfoC.offset = addInfoB.addend;
+                                                       set32LE(infoC.instructionContent, makeLoadOrStore(ldrInfoC));
+                                                       if ( _options.verboseOptimizationHints() ) {
+                                                               fprintf(stderr, "adrp-ldr-got-str at 0x%08llX T4 transformed to ADRP/NOP/STR\n", infoC.instructionAddress);
+                                                       }
+                                               }
+                                               else {
+                                                       // T3 transform already done by ld::passes:got:doPass()
+                                                       if ( _options.verboseOptimizationHints() ) {
+                                                               fprintf(stderr, "adrp-ldr-got-str at 0x%08llX T3 transformed to ADRP/ADD/STR\n", infoC.instructionAddress);
+                                                       }
+                                               }
+                                       }
+                                       else {
+                                               if ( _options.verboseOptimizationHints() )                                                      
+                                                       fprintf(stderr, "adrp-ldr-got-str at 0x%08llX not ADD or LDR\n", infoC.instructionAddress);
+                                       }
+                                       break;
+                               case LOH_ARM64_ADRP_LDR_GOT:
+                                       LOH_ASSERT(alt.info.count == 1);
+                                       LOH_ASSERT(isPageKind(infoA.fixup, true));
+                                       LOH_ASSERT(isPageOffsetKind(infoB.fixup, true));
+                                       LOH_ASSERT(infoA.target == infoB.target);
+                                       LOH_ASSERT(infoA.targetAddress == infoB.targetAddress);
+                                       isADRP = parseADRP(infoA.instruction, adrpInfoA);
+                                       isADD = parseADD(infoB.instruction, addInfoB);
+                                       isLDR = parseLoadOrStore(infoB.instruction, ldrInfoB);
+                                       usableSegment = ( !_options.sharedRegionEligible() || (strcmp(atom->section().segmentName(), infoB.target->section().segmentName()) == 0) );
+                                       if ( isADRP ) {
+                                               if ( isLDR ) {
+                                                       if ( usableSegment && withinOneMeg(infoB.instructionAddress, infoA.targetAddress) ) {
+                                                               // can do T5 transform (LDR literal load of GOT)
+                                                               set32LE(infoA.instructionContent, makeNOP());
+                                                               set32LE(infoB.instructionContent, makeLDR_literal(ldrInfoB, infoA.targetAddress, infoB.instructionAddress));
+                                                               if ( _options.verboseOptimizationHints() ) {
+                                                                       fprintf(stderr, "adrp-ldr-got at 0x%08llX T5 transformed to NOP/LDR\n", infoC.instructionAddress);
+                                                               }
+                                                       }
+                                               }
+                                               else if ( isADD ) {
+                                                       if ( usableSegment && withinOneMeg(infoA.instructionAddress, infoA.targetAddress) ) {
+                                                               // can do T4 transform (ADR to compute local address)
+                                                               set32LE(infoA.instructionContent, makeADR(addInfoB.destReg, infoA.targetAddress, infoA.instructionAddress));
+                                                               set32LE(infoB.instructionContent, makeNOP());
+                                                               if ( _options.verboseOptimizationHints() ) {
+                                                                       fprintf(stderr, "adrp-ldr-got at 0x%08llX T4 transformed to ADR/STR\n", infoC.instructionAddress);
+                                                               }
+                                                       }
+                                               }
+                                               else {
+                                                       if ( _options.verboseOptimizationHints() )
+                                                               fprintf(stderr, "adrp-ldr-got at 0x%08llX not LDR or ADD\n", infoB.instructionAddress);
+                                               }
+                                       }
+                                       else {
+                                               if ( _options.verboseOptimizationHints() )
+                                                       fprintf(stderr, "adrp-ldr-got at 0x%08llX not ADRP\n", infoA.instructionAddress);
+                                       }
+                                       break;
+                               default:
+                                               if ( _options.verboseOptimizationHints() )                                                      
+                                                       fprintf(stderr, "unknown hint kind %d alt.info.kind at 0x%08llX\n", alt.info.kind, infoA.instructionAddress);
+                                       break;
+                       }
+               }
+               // apply hints pass 2
+               for (ld::Fixup::iterator fit = atom->fixupsBegin(), end=atom->fixupsEnd(); fit != end; ++fit) {
+                       if ( fit->kind != ld::Fixup::kindLinkerOptimizationHint ) 
+                               continue;
+                       InstructionInfo infoA;
+                       InstructionInfo infoB;
+                       ld::Fixup::LOH_arm64 alt;
+                       alt.addend = fit->u.addend;
+                       setInfo(state, atom, buffer, usedByHints, fit->offsetInAtom, (alt.info.delta1 << 2), &infoA);
+                       if ( alt.info.count > 0 ) 
+                               setInfo(state, atom, buffer, usedByHints, fit->offsetInAtom, (alt.info.delta2 << 2), &infoB);
+
+                       switch ( alt.info.kind ) {
+                               case LOH_ARM64_ADRP_ADRP:
+                                       LOH_ASSERT(isPageKind(infoA.fixup));
+                                       LOH_ASSERT(isPageKind(infoB.fixup));
+                                       if ( (infoA.instruction & 0x9F000000) != 0x90000000 ) {
+                                               if ( _options.verboseOptimizationHints() )
+                                                       fprintf(stderr, "may-reused-adrp at 0x%08llX no longer an ADRP, now 0x%08X\n", infoA.instructionAddress, infoA.instruction);
+                                               sAdrpNA++;
+                                               break;
+                                       }
+                                       if ( (infoB.instruction & 0x9F000000) != 0x90000000 ) {
+                                               if ( _options.verboseOptimizationHints() )
+                                                       fprintf(stderr, "may-reused-adrp at 0x%08llX no longer an ADRP, now 0x%08X\n", infoB.instructionAddress, infoA.instruction);
+                                               sAdrpNA++;
+                                               break;
+                                       }
+                                       if ( (infoA.targetAddress & (-4096)) == (infoB.targetAddress & (-4096)) ) {
+                                               set32LE(infoB.instructionContent, 0xD503201F);
+                                               sAdrpNoped++;
+                                       }
+                                       else {
+                                               sAdrpNotNoped++;
+                                       }
+                                       break;
+                       }                               
+               }
+       }
+
+
+       
+
 }
 
 void OutputFile::copyNoOps(uint8_t* from, uint8_t* to, bool thumb)
@@ -1779,6 +2555,12 @@ void OutputFile::writeAtoms(ld::Internal& state, uint8_t* wholeBuffer)
                        }
                }
        }
+       
+       if ( _options.verboseOptimizationHints() ) {
+               //fprintf(stderr, "ADRP optimized away:   %d\n", sAdrpNA);
+               //fprintf(stderr, "ADRPs changed to NOPs: %d\n", sAdrpNoped);
+               //fprintf(stderr, "ADRPs unchanged:       %d\n", sAdrpNotNoped);
+       }
 }
 
 
@@ -2302,6 +3084,10 @@ void OutputFile::addLinkEdit(ld::Internal& state)
                                _dataInCodeAtom = new DataInCodeAtom<x86>(_options, state, *this);
                                dataInCodeSection = state.addAtom(*_dataInCodeAtom);
                        }
+                       if ( _hasOptimizationHints ) {
+                               _optimizationHintsAtom = new OptimizationHintsAtom<x86>(_options, state, *this);
+                               optimizationHintsSection = state.addAtom(*_optimizationHintsAtom);
+                       }
                        if ( _hasDependentDRInfo ) {
                                _dependentDRInfoAtom = new DependentDRAtom<x86>(_options, state, *this);
                                dependentDRsSection = state.addAtom(*_dependentDRInfoAtom);
@@ -2360,6 +3146,10 @@ void OutputFile::addLinkEdit(ld::Internal& state)
                                _dataInCodeAtom = new DataInCodeAtom<x86_64>(_options, state, *this);
                                dataInCodeSection = state.addAtom(*_dataInCodeAtom);
                        }
+                       if ( _hasOptimizationHints ) {
+                               _optimizationHintsAtom = new OptimizationHintsAtom<x86_64>(_options, state, *this);
+                               optimizationHintsSection = state.addAtom(*_optimizationHintsAtom);
+                       }
                        if ( _hasDependentDRInfo ) {
                                _dependentDRInfoAtom = new DependentDRAtom<x86_64>(_options, state, *this);
                                dependentDRsSection = state.addAtom(*_dependentDRInfoAtom);
@@ -2418,6 +3208,10 @@ void OutputFile::addLinkEdit(ld::Internal& state)
                                _dataInCodeAtom = new DataInCodeAtom<arm>(_options, state, *this);
                                dataInCodeSection = state.addAtom(*_dataInCodeAtom);
                        }
+                       if ( _hasOptimizationHints ) {
+                               _optimizationHintsAtom = new OptimizationHintsAtom<arm>(_options, state, *this);
+                               optimizationHintsSection = state.addAtom(*_optimizationHintsAtom);
+                       }
                        if ( _hasDependentDRInfo ) {
                                _dependentDRInfoAtom = new DependentDRAtom<arm>(_options, state, *this);
                                dependentDRsSection = state.addAtom(*_dependentDRInfoAtom);
@@ -2476,6 +3270,10 @@ void OutputFile::addLinkEdit(ld::Internal& state)
                                _dataInCodeAtom = new DataInCodeAtom<arm64>(_options, state, *this);
                                dataInCodeSection = state.addAtom(*_dataInCodeAtom);
                        }
+                       if ( _hasOptimizationHints ) {
+                               _optimizationHintsAtom = new OptimizationHintsAtom<arm64>(_options, state, *this);
+                               optimizationHintsSection = state.addAtom(*_optimizationHintsAtom);
+                       }
                        if ( _hasDependentDRInfo ) {
                                _dependentDRInfoAtom = new DependentDRAtom<arm64>(_options, state, *this);
                                dependentDRsSection = state.addAtom(*_dependentDRInfoAtom);
@@ -2857,13 +3655,14 @@ uint64_t OutputFile::lookBackAddend(ld::Fixup::iterator fit)
 }
 
 
-
-
-
 void OutputFile::generateLinkEditInfo(ld::Internal& state)
 {
        for (std::vector<ld::Internal::FinalSection*>::iterator sit = state.sections.begin(); sit != state.sections.end(); ++sit) {
                ld::Internal::FinalSection* sect = *sit;
+               // record end of last __TEXT section encrypted iPhoneOS apps.
+               if ( _options.makeEncryptable() && (strcmp(sect->segmentName(), "__TEXT") == 0) ) { 
+                       _encryptedTEXTendOffset = pageAlign(sect->fileOffset + sect->size);
+               }
                bool objc1ClassRefSection = ( (sect->type() == ld::Section::typeCStringPointer) 
                                                                        && (strcmp(sect->sectionName(), "__cls_refs") == 0)
                                                                        && (strcmp(sect->segmentName(), "__OBJC") == 0) );
@@ -3097,7 +3896,7 @@ void OutputFile::addDyldInfo(ld::Internal& state,  ld::Internal::FinalSection* s
        if ( target == NULL )
                return; 
 
-       bool inReadOnlySeg = ( strcmp(sect->segmentName(), "__TEXT") == 0 );
+       bool inReadOnlySeg = ((_options.initialSegProtection(sect->segmentName()) & VM_PROT_WRITE) == 0);
        bool needsRebase = false;
        bool needsBinding = false;
        bool needsLazyBinding = false;
index bfc89367717d2713b2ce81b0626c1fdafa5fd48e..6bb793bf951de806910865b4b783d20fad6e8283 100644 (file)
@@ -68,11 +68,9 @@ public:
        uint64_t                                        fileSize() const { return _fileSize; }
        
        
-       bool                                            hasWeakExternalSymbols;
        bool                                            usesWeakExternalSymbols;
        bool                                            overridesWeakExternalSymbols;
        bool                                            _noReExportedDylibs;
-       bool                                            hasThreadLocalVariableDefinitions;
        bool                                            pieDisabled;
        bool                                            hasDataInCode;
        ld::Internal::FinalSection*     headerAndLoadCommandsSection;
@@ -84,6 +82,7 @@ public:
        ld::Internal::FinalSection*     splitSegInfoSection;
        ld::Internal::FinalSection*     functionStartsSection;
        ld::Internal::FinalSection*     dataInCodeSection;
+       ld::Internal::FinalSection*     optimizationHintsSection;
        ld::Internal::FinalSection*     dependentDRsSection;
        ld::Internal::FinalSection*     symbolTableSection;
        ld::Internal::FinalSection*     stringPoolSection;
@@ -150,8 +149,6 @@ private:
        void                                            generateLinkEditInfo(ld::Internal& state);
        void                                            buildSymbolTable(ld::Internal& state);
        void                                            writeOutputFile(ld::Internal& state);
-       void                                            assignFileOffsets(ld::Internal& state);
-       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* fixupWithAddend,
@@ -201,6 +198,10 @@ private:
        bool                                            hasZeroForFileOffset(const ld::Section* sect);
        
        void                                            printSectionLayout(ld::Internal& state);
+       
+       bool                                            checkThumbBranch22Displacement(int64_t displacement);
+       bool                                            checkArmBranch24Displacement(int64_t displacement);
+
        void                                            rangeCheck8(int64_t delta, ld::Internal& state, const ld::Atom* atom, 
                                                                                                                                                                                        const ld::Fixup* fixup);
        void                                            rangeCheck16(int64_t delta, ld::Internal& state, const ld::Atom* atom, 
@@ -231,6 +232,19 @@ private:
        void                                            noteTextReloc(const ld::Atom* atom, const ld::Atom* target);
 
        
+       struct InstructionInfo {
+               uint32_t                        offsetInAtom;
+               const ld::Fixup*        fixup; 
+               const ld::Atom*         target; 
+               uint64_t                        targetAddress;
+               uint8_t*                        instructionContent;
+               uint64_t                        instructionAddress;
+               uint32_t                        instruction;
+       };
+
+       void setInfo(ld::Internal& state, const ld::Atom* atom, uint8_t* buffer, const std::map<uint32_t, const Fixup*>& usedHints, 
+                                               uint32_t offsetInAtom, uint32_t delta, InstructionInfo* info);
+
        static uint16_t                         get16LE(uint8_t* loc);
        static void                                     set16LE(uint8_t* loc, uint16_t value);
        static uint32_t                         get32LE(uint8_t* loc);
@@ -261,6 +275,7 @@ private:
                  bool                                                          _hasDynamicSymbolTable;
                  bool                                                          _hasLocalRelocations;
                  bool                                                          _hasExternalRelocations;
+                 bool                                                          _hasOptimizationHints;
        uint64_t                                                                _fileSize;
        std::map<uint64_t, uint32_t>                    _lazyPointerAddressToInfoOffset;
        uint32_t                                                                _encryptedTEXTstartOffset;
@@ -297,6 +312,7 @@ public:
        class LinkEditAtom*                                             _functionStartsAtom;
        class LinkEditAtom*                                             _dataInCodeAtom;
        class LinkEditAtom*                                             _dependentDRInfoAtom;
+       class LinkEditAtom*                                             _optimizationHintsAtom;
 };
 
 } // namespace tool 
index 25d0c666d0571567a85203146decb7b5f87ad695..573cad8d8de878758b140759bb7b27edcccfb717 100644 (file)
@@ -418,7 +418,16 @@ void Resolver::doFile(const ld::File& file)
                                break;
                                
                        case CPU_TYPE_X86_64:
-                               _internal.cpuSubType = CPU_SUBTYPE_X86_64_ALL;
+                               if ( _options.subArchitecture() != nextObjectSubType ) {
+                                       if ( _options.allowSubArchitectureMismatches() ) {
+                                               warning("object file %s was built for different x86_64 sub-type (%d) than link command line (%d)", 
+                                                       file.path(), nextObjectSubType, _options.subArchitecture());
+                                       }
+                                       else {
+                                               throwf("object file %s was built for different x86_64 sub-type (%d) than link command line (%d)", 
+                                                       file.path(), nextObjectSubType, _options.subArchitecture());
+                                       }
+                               }
                                break;
                }
        }
@@ -466,7 +475,9 @@ void Resolver::doFile(const ld::File& file)
 
 void Resolver::doAtom(const ld::Atom& atom)
 {
-       //fprintf(stderr, "Resolver::doAtom(%p), name=%s, sect=%s\n", &atom, atom.name(), atom.section().sectionName());
+       //fprintf(stderr, "Resolver::doAtom(%p), name=%s, sect=%s, scope=%d\n", &atom, atom.name(), atom.section().sectionName(), atom.scope());
+       if ( _ltoCodeGenFinished && (atom.contentType() == ld::Atom::typeLTOtemporary) && (atom.scope() != ld::Atom::scopeTranslationUnit) )
+               warning("'%s' is implemented in bitcode, but it was loaded too late", atom.name());
 
        // add to list of known atoms
        _atoms.push_back(&atom);
@@ -601,6 +612,8 @@ void Resolver::convertReferencesToIndirect(const ld::Atom& atom)
        const ld::Atom* dummy;
        ld::Fixup::iterator end = atom.fixupsEnd();
        for (ld::Fixup::iterator fit=atom.fixupsBegin(); fit != end; ++fit) {
+               if ( fit->kind == ld::Fixup::kindLinkerOptimizationHint )
+                       _internal.someObjectHasOptimizationHints = true;
                switch ( fit->binding ) { 
                        case ld::Fixup::bindingByNameUnbound:
                                if ( isDtraceProbe(fit->kind) && (_options.outputKind() != Options::kObjectFile ) ) {
@@ -732,8 +745,14 @@ void Resolver::resolveUndefines()
                std::vector<const char*> undefineNames;
                _symbolTable.undefines(undefineNames);
                for(std::vector<const char*>::iterator it = undefineNames.begin(); it != undefineNames.end(); ++it) {
-                       // make proxy
-                       this->doAtom(*new UndefinedProxyAtom(*it));
+                       const char* undefName = *it;
+                       // <rdar://problem/14547001> "ld -r -exported_symbol _foo" has wrong error message if _foo is undefined
+                       bool makeProxy = true;
+                       if ( (_options.outputKind() == Options::kObjectFile) && _options.hasExportMaskList() && _options.shouldExport(undefName) ) 
+                               makeProxy = false;
+                       
+                       if ( makeProxy ) 
+                               this->doAtom(*new UndefinedProxyAtom(undefName));
                }
        }
        
@@ -952,6 +971,7 @@ void Resolver::deadStripOptimize(bool force)
        if ( _haveLLVMObjs && !force ) {
                // <rdar://problem/9777977> don't remove combinable atoms, they may come back in lto output
                _atoms.erase(std::remove_if(_atoms.begin(), _atoms.end(), NotLiveLTO()), _atoms.end());
+               _symbolTable.removeDeadAtoms();
        }
        else {
                _atoms.erase(std::remove_if(_atoms.begin(), _atoms.end(), NotLive()), _atoms.end());
@@ -1420,6 +1440,9 @@ void Resolver::linkTimeOptimize()
        if ( ! _haveLLVMObjs )
                return;
 
+       // <rdar://problem/15314161> LTO: Symbol multiply defined error should specify exactly where the symbol is found
+    _symbolTable.checkDuplicateSymbols();
+
        // run LLVM lto code-gen
        lto::OptimizeOptions optOpt;
        optOpt.outputFilePath                           = _options.outputFilePath();
@@ -1443,12 +1466,12 @@ void Resolver::linkTimeOptimize()
        std::vector<const char*>                        additionalUndefines; 
        if ( ! lto::optimize(_atoms, _internal, optOpt, *this, newAtoms, additionalUndefines) )
                return; // if nothing done
-               
+       _ltoCodeGenFinished = true;
        
        // add all newly created atoms to _atoms and update symbol table
        for(std::vector<const ld::Atom*>::iterator it = newAtoms.begin(); it != newAtoms.end(); ++it)
                this->doAtom(**it);
-               
+
        // some atoms might have been optimized way (marked coalesced), remove them
        this->removeCoalescedAwayAtoms();
 
@@ -1463,6 +1486,10 @@ void Resolver::linkTimeOptimize()
                aliasAtom->setFinalAliasOf();
        }
        
+       // <rdar://problem/14609792> add any auto-link libraries requested by LTO output to dylibs to search
+       _inputFiles.addLinkerOptionLibraries(_internal);
+       _inputFiles.createIndirectDylibs();
+
        // resolve new undefines (e.g calls to _malloc and _memcpy that llvm compiler conjures up)
        for(std::vector<const char*>::iterator uit = additionalUndefines.begin(); uit != additionalUndefines.end(); ++uit) {
                const char *targetName = *uit;
@@ -1500,6 +1527,7 @@ void Resolver::linkTimeOptimize()
        }
        else {
                // last chance to check for undefines
+               this->resolveUndefines();
                this->checkUndefines(true);
 
                // check new code does not override some dylib
@@ -1540,6 +1568,14 @@ void Resolver::tweakWeakness()
        }
 }
 
+void Resolver::dumpAtoms() 
+{
+       fprintf(stderr, "Resolver all atoms:\n");
+       for (std::vector<const ld::Atom*>::const_iterator it=_atoms.begin(); it != _atoms.end(); ++it) {
+               const ld::Atom* atom = *it;
+               fprintf(stderr, "  %p name=%s, def=%d\n", atom, atom->name(), atom->definition());
+       }
+}
 
 void Resolver::resolve()
 {
index bdb4e3edfc31b1404271536ce87f50611904c361..4a3cd73011a4cac75dff3165f99744387a144729 100644 (file)
@@ -62,7 +62,8 @@ public:
                                                                : _options(opts), _inputFiles(inputs), _internal(state), 
                                                                  _symbolTable(opts, state.indirectBindingTable),
                                                                  _haveLLVMObjs(false),
-                                                                 _completedInitialObjectFiles(false) {}
+                                                                 _completedInitialObjectFiles(false),
+                                                                 _ltoCodeGenFinished(false) {}
                                                                
 
                virtual void            doAtom(const ld::Atom&);
@@ -100,6 +101,7 @@ private:
        bool                                    printReferencedBy(const char* name, SymbolTable::IndirectBindingSlot slot);
        void                                    tweakWeakness();
        void                                    doLinkerOption(const std::vector<const char*>& linkerOption, const char* fileName);
+       void                                    dumpAtoms();
 
        typedef std::unordered_set<const char*, CStringHash, CStringEquals>  StringSet;
 
@@ -127,6 +129,7 @@ private:
        SymbolTable                                             _symbolTable;
        bool                                                    _haveLLVMObjs;
        bool                                                    _completedInitialObjectFiles;
+       bool                                                    _ltoCodeGenFinished;
 };
 
 
index 309de8b6835fa155c00733903cdb9d79d60cdac3..b27125950cba5740b5b25306c1790e8d9eef104e 100644 (file)
@@ -588,6 +588,19 @@ SymbolTable::IndirectBindingSlot SymbolTable::findSlotForName(const char* name)
        return slot;
 }
 
+void SymbolTable::removeDeadAtoms()
+{
+       for (NameToSlot::iterator it=_byNameTable.begin(); it != _byNameTable.end(); ++it) {
+               IndirectBindingSlot slot = it->second;
+               const ld::Atom* atom = _indirectBindingTable[slot];
+               if ( atom != NULL ) {
+                       if ( !atom->live() && !atom->dontDeadStrip() ) {
+                               //fprintf(stderr, "removing from symbolTable[%u] %s\n", slot, atom->name());
+                               _indirectBindingTable[slot] = NULL;
+                       }
+               }
+       }
+}
 
 // find existing or create new slot
 SymbolTable::IndirectBindingSlot SymbolTable::findSlotForContent(const ld::Atom* atom, const ld::Atom** existingAtom)
index 5575f3125cd3ddbd4a18c7e0d8605f1c385edad5..14c7a9e0077f45fc983d0a117f29f55424c4d0fd 100644 (file)
@@ -120,6 +120,7 @@ public:
        unsigned int            updateCount()                                           { return _indirectBindingTable.size(); }
        void                            undefines(std::vector<const char*>& undefines);
        void                            tentativeDefs(std::vector<const char*>& undefines);
+       void                            removeDeadAtoms();
        bool                            hasName(const char* name);
        bool                            hasExternalTentativeDefinitions()       { return _hasExternalTentativeDefinitions; }
        byNameIterator          begin()                                                         { return byNameIterator(_byNameTable.begin(),_indirectBindingTable); }
index 7f7161d2abb8f9a7577a29d9b2e09426137a55a3..844f6142521eac5067be1c189bbfa12f774a17b0 100644 (file)
@@ -100,9 +100,6 @@ struct PerformanceStatistics {
 };
 
 
-
-
-
 class InternalState : public ld::Internal
 {
 public:
@@ -110,6 +107,8 @@ public:
        virtual ld::Internal::FinalSection*             addAtom(const ld::Atom& atom);
        virtual ld::Internal::FinalSection*             getFinalSection(const ld::Section&);
        
+       uint64_t                                                                assignFileOffsets();
+       void                                                                    setSectionSizesAndAlignments();
        void                                                                    sortSections();
        void                                                                    markAtomsOrdered() { _atomsOrderedInSections = true; }
        virtual                                                                 ~InternalState() {}
@@ -121,7 +120,7 @@ private:
                                                        FinalSection(const ld::Section& sect, uint32_t sectionsSeen, bool objFile);
                static int                                      sectionComparer(const void* l, const void* r);
                static const ld::Section&       outputSection(const ld::Section& sect, bool mergeZeroFill);
-               static const ld::Section&       objectOutputSection(const ld::Section& sect, bool makeTentativeDefsReal);
+               static const ld::Section&       objectOutputSection(const ld::Section& sect, const Options&);
        private:
                friend class InternalState;
                static uint32_t         sectionOrder(const ld::Section& sect, uint32_t sectionsSeen);
@@ -139,6 +138,9 @@ private:
                static ld::Section              _s_DATA_zerofill;
        };
        
+       bool hasZeroForFileOffset(const ld::Section* sect);
+       uint64_t pageAlign(uint64_t addr);
+       uint64_t pageAlign(uint64_t addr, uint64_t pageSize);
        
        struct SectionHash {
                size_t operator()(const ld::Section*) const;
@@ -243,10 +245,19 @@ const ld::Section& InternalState::FinalSection::outputSection(const ld::Section&
        return sect;
 }
 
-const ld::Section& InternalState::FinalSection::objectOutputSection(const ld::Section& sect, bool makeTentativeDefsReal)
+const ld::Section& InternalState::FinalSection::objectOutputSection(const ld::Section& sect, const Options& options)
 {
+       const std::vector<Options::SectionRename>& renames = options.sectionRenames();
+       for ( std::vector<Options::SectionRename>::const_iterator it=renames.begin(); it != renames.end(); ++it) {
+         if ( (strcmp(sect.sectionName(), it->fromSection) == 0) && (strcmp(sect.segmentName(), it->fromSegment) == 0) ) {
+               ld::Section* s = new ld::Section(it->toSegment, it->toSection, sect.type());
+               return *s;
+         }
+       }
+
+
        // in -r mode the only section that ever changes is __tenative -> __common with -d option
-       if ( (sect.type() == ld::Section::typeTentativeDefs) && makeTentativeDefsReal)
+       if ( (sect.type() == ld::Section::typeTentativeDefs) && options.makeTentativeDefinitionsReal())
                return _s_DATA_common;
        return sect;
 }
@@ -522,7 +533,7 @@ ld::Internal::FinalSection* InternalState::getFinalSection(const ld::Section& in
                        }
                        break;
                case Options::kObjectFile:
-                       baseForFinalSection = &FinalSection::objectOutputSection(inputSection, _options.makeTentativeDefinitionsReal());
+                       baseForFinalSection = &FinalSection::objectOutputSection(inputSection, _options);
                        pos = _sectionInToFinalMap.find(baseForFinalSection);
                        if ( pos != _sectionInToFinalMap.end() ) {
                                _sectionInToFinalMap[&inputSection] = pos->second;
@@ -569,6 +580,308 @@ void InternalState::sortSections()
        
 }
 
+
+bool InternalState::hasZeroForFileOffset(const ld::Section* sect)
+{
+       switch ( sect->type() ) {
+               case ld::Section::typeZeroFill:
+               case ld::Section::typeTLVZeroFill:
+                       return _options.optimizeZeroFill();
+               case ld::Section::typePageZero:
+               case ld::Section::typeStack:
+               case ld::Section::typeTentativeDefs:
+                       return true;
+               default:
+                       break;
+       }
+       return false;
+}
+
+uint64_t InternalState::pageAlign(uint64_t addr)
+{
+       const uint64_t alignment = _options.segmentAlignment();
+       return ((addr+alignment-1) & (-alignment)); 
+}
+
+uint64_t InternalState::pageAlign(uint64_t addr, uint64_t pageSize)
+{
+       return ((addr+pageSize-1) & (-pageSize)); 
+}
+
+void InternalState::setSectionSizesAndAlignments()
+{
+       for (std::vector<ld::Internal::FinalSection*>::iterator sit = sections.begin(); sit != sections.end(); ++sit) {
+               ld::Internal::FinalSection* sect = *sit;
+               if ( sect->type() == ld::Section::typeAbsoluteSymbols ) {
+                       // absolute symbols need their finalAddress() to their value
+                       for (std::vector<const ld::Atom*>::iterator ait = sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
+                               const ld::Atom* atom = *ait;
+                               (const_cast<ld::Atom*>(atom))->setSectionOffset(atom->objectAddress());
+                       }
+               }
+               else {
+                       uint16_t maxAlignment = 0;
+                       uint64_t offset = 0;
+                       for (std::vector<const ld::Atom*>::iterator ait = sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
+                               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 ) {
+                                                               atomAlignmentPowerOf2 = 12;
+                                                               atomModulus = 0;
+                                                       }
+                                                       break;
+                                               default:
+                                                       break;
+                                       }
+                               }
+                               if ( atomAlignmentPowerOf2 > maxAlignment )
+                                       maxAlignment = atomAlignmentPowerOf2;
+                               // calculate section offset for this atom
+                               uint64_t alignment = 1 << atomAlignmentPowerOf2;
+                               uint64_t currentModulus = (offset % alignment);
+                               uint64_t requiredModulus = atomModulus;
+                               if ( currentModulus != requiredModulus ) {
+                                       if ( requiredModulus > currentModulus )
+                                               offset += requiredModulus-currentModulus;
+                                       else
+                                               offset += requiredModulus+alignment-currentModulus;
+                               }
+                               // LINKEDIT atoms are laid out later
+                               if ( sect->type() != ld::Section::typeLinkEdit ) {
+                                       (const_cast<ld::Atom*>(atom))->setSectionOffset(offset);
+                                       offset += atom->size();
+                                       if ( pagePerAtom ) {
+                                               offset = (offset + 4095) & (-4096); // round up to end of page
+                                       }
+                               }
+                               if ( (atom->scope() == ld::Atom::scopeGlobal) 
+                                       && (atom->definition() == ld::Atom::definitionRegular) 
+                                       && (atom->combine() == ld::Atom::combineByName) 
+                                       && ((atom->symbolTableInclusion() == ld::Atom::symbolTableIn) 
+                                        || (atom->symbolTableInclusion() == ld::Atom::symbolTableInAndNeverStrip)) ) {
+                                               this->hasWeakExternalSymbols = true;
+                                               if ( _options.warnWeakExports() ) 
+                                                       warning("weak external symbol: %s", atom->name());
+                               }
+                       }
+                       sect->size = offset;
+                       // section alignment is that of a contained atom with the greatest alignment
+                       sect->alignment = maxAlignment;
+                       // unless -sectalign command line option overrides
+                       if  ( _options.hasCustomSectionAlignment(sect->segmentName(), sect->sectionName()) )
+                               sect->alignment = _options.customSectionAlignment(sect->segmentName(), sect->sectionName());
+                       // each atom in __eh_frame has zero alignment to assure they pack together,
+                       // but compilers usually make the CFIs pointer sized, so we want whole section
+                       // to start on pointer sized boundary.
+                       if ( sect->type() == ld::Section::typeCFI )
+                               sect->alignment = 3;
+                       if ( sect->type() == ld::Section::typeTLVDefs )
+                               this->hasThreadLocalVariableDefinitions = true;
+               }
+       }
+}
+
+uint64_t InternalState::assignFileOffsets() 
+{
+       const bool log = false;
+       const bool hiddenSectionsOccupyAddressSpace = ((_options.outputKind() != Options::kObjectFile)
+                                                                                               && (_options.outputKind() != Options::kPreload));
+       const bool segmentsArePageAligned = (_options.outputKind() != Options::kObjectFile);
+
+       uint64_t address = 0;
+       const char* lastSegName = "";
+       uint64_t floatingAddressStart = _options.baseAddress();
+       
+       // first pass, assign addresses to sections in segments with fixed start addresses
+       if ( log ) fprintf(stderr, "Fixed address segments:\n");
+       for (std::vector<ld::Internal::FinalSection*>::iterator it = sections.begin(); it != sections.end(); ++it) {
+               ld::Internal::FinalSection* sect = *it;
+               if ( ! _options.hasCustomSegmentAddress(sect->segmentName()) ) 
+                       continue;
+               if ( segmentsArePageAligned ) {
+                       if ( strcmp(lastSegName, sect->segmentName()) != 0 ) {
+                               address = _options.customSegmentAddress(sect->segmentName());
+                               lastSegName = sect->segmentName();
+                       }
+               }
+               // adjust section address based on alignment
+               uint64_t unalignedAddress = address;
+               uint64_t alignment = (1 << sect->alignment);
+               address = ( (unalignedAddress+alignment-1) & (-alignment) );
+       
+               // update section info
+               sect->address = address;
+               sect->alignmentPaddingBytes = (address - unalignedAddress);
+               
+               // sanity check size
+               if ( ((address + sect->size) > _options.maxAddress()) && (_options.outputKind() != Options::kObjectFile) 
+                                                                                                                         && (_options.outputKind() != Options::kStaticExecutable) )
+                       throwf("section %s (address=0x%08llX, size=%llu) would make the output executable exceed available address range", 
+                                               sect->sectionName(), address, sect->size);
+               
+               if ( log ) fprintf(stderr, "  address=0x%08llX, hidden=%d, alignment=%02d, section=%s,%s\n",
+                                               sect->address, sect->isSectionHidden(), sect->alignment, sect->segmentName(), sect->sectionName());
+               // update running totals
+               if ( !sect->isSectionHidden() || hiddenSectionsOccupyAddressSpace )
+                       address += sect->size;
+               
+               // if TEXT segment address is fixed, then flow other segments after it
+               if ( strcmp(sect->segmentName(), "__TEXT") == 0 ) {
+                       floatingAddressStart = address;
+               }
+       }
+       
+       // second pass, assign section address to sections in segments that are contiguous with previous segment
+       address = floatingAddressStart;
+       lastSegName = "";
+       ld::Internal::FinalSection* overlappingFixedSection = NULL;
+       ld::Internal::FinalSection* overlappingFlowSection = NULL;
+       if ( log ) fprintf(stderr, "Regular layout segments:\n");
+       for (std::vector<ld::Internal::FinalSection*>::iterator it = sections.begin(); it != sections.end(); ++it) {
+               ld::Internal::FinalSection* sect = *it;
+               if ( _options.hasCustomSegmentAddress(sect->segmentName()) ) 
+                       continue;
+               if ( (_options.outputKind() == Options::kPreload) && (sect->type() == ld::Section::typeMachHeader) ) {
+                       sect->alignmentPaddingBytes = 0;
+                       continue;
+               }
+               if ( segmentsArePageAligned ) {
+                       if ( strcmp(lastSegName, sect->segmentName()) != 0 ) {
+                               // round up size of last segment if needed
+                               if ( *lastSegName != '\0' ) {
+                                       address = pageAlign(address, _options.segPageSize(lastSegName));
+                               }
+                               // set segment address based on end of last segment
+                               address = pageAlign(address);
+                               lastSegName = sect->segmentName();
+                       }
+               }
+               // adjust section address based on alignment
+               uint64_t unalignedAddress = address;
+               uint64_t alignment = (1 << sect->alignment);
+               address = ( (unalignedAddress+alignment-1) & (-alignment) );
+       
+               // update section info
+               sect->address = address;
+               sect->alignmentPaddingBytes = (address - unalignedAddress);
+               
+               // sanity check size
+               if ( ((address + sect->size) > _options.maxAddress()) && (_options.outputKind() != Options::kObjectFile) 
+                                                                                                                         && (_options.outputKind() != Options::kStaticExecutable) )
+                               throwf("section %s (address=0x%08llX, size=%llu) would make the output executable exceed available address range", 
+                                               sect->sectionName(), address, sect->size);
+
+               // sanity check it does not overlap a fixed address segment
+               for (std::vector<ld::Internal::FinalSection*>::iterator sit = sections.begin(); sit != sections.end(); ++sit) {
+                       ld::Internal::FinalSection* otherSect = *sit;
+                       if ( ! _options.hasCustomSegmentAddress(otherSect->segmentName()) ) 
+                               continue;
+                       if ( sect->address > otherSect->address ) {
+                               if ( (otherSect->address+otherSect->size) > sect->address ) {
+                                       overlappingFixedSection = otherSect;
+                                       overlappingFlowSection = sect;
+                               }
+                       }
+                       else {
+                               if ( (sect->address+sect->size) > otherSect->address ) {
+                                       overlappingFixedSection = otherSect;
+                                       overlappingFlowSection = sect;
+                               }
+                       }
+               }
+               
+               if ( log ) fprintf(stderr, "  address=0x%08llX, size=0x%08llX, hidden=%d, alignment=%02d, padBytes=%d, section=%s,%s\n",
+                                                       sect->address, sect->size, sect->isSectionHidden(), sect->alignment, sect->alignmentPaddingBytes, 
+                                                       sect->segmentName(), sect->sectionName());
+               // update running totals
+               if ( !sect->isSectionHidden() || hiddenSectionsOccupyAddressSpace )
+                       address += sect->size;
+       }
+       if ( overlappingFixedSection != NULL ) {
+               fprintf(stderr, "Section layout:\n");
+               for (std::vector<ld::Internal::FinalSection*>::iterator it = sections.begin(); it != sections.end(); ++it) {
+                       ld::Internal::FinalSection* sect = *it;
+                       if ( sect->isSectionHidden() )
+                               continue;
+                       fprintf(stderr, "  address:0x%08llX, alignment:2^%d, size:0x%08llX, padBytes:%d, section:%s/%s\n",
+                                                       sect->address, sect->alignment, sect->size, sect->alignmentPaddingBytes, 
+                                                       sect->segmentName(), sect->sectionName());
+       
+               }
+               throwf("Section (%s/%s) overlaps fixed address section (%s/%s)", 
+                       overlappingFlowSection->segmentName(), overlappingFlowSection->sectionName(),
+                       overlappingFixedSection->segmentName(), overlappingFixedSection->sectionName());
+       }
+       
+       
+       // third pass, assign section file offsets 
+       uint64_t fileOffset = 0;
+       lastSegName = "";
+       if ( log ) fprintf(stderr, "All segments with file offsets:\n");
+       for (std::vector<ld::Internal::FinalSection*>::iterator it = sections.begin(); it != sections.end(); ++it) {
+               ld::Internal::FinalSection* sect = *it;
+               if ( hasZeroForFileOffset(sect) ) {
+                       // fileoff of zerofill sections is moot, but historically it is set to zero
+                       sect->fileOffset = 0;
+
+                       // <rdar://problem/10445047> align file offset with address layout
+                       fileOffset += sect->alignmentPaddingBytes;
+               }
+               else {
+                       // page align file offset at start of each segment
+                       if ( segmentsArePageAligned && (*lastSegName != '\0') && (strcmp(lastSegName, sect->segmentName()) != 0) ) {
+                               fileOffset = pageAlign(fileOffset, _options.segPageSize(lastSegName));
+                       }
+                       lastSegName = sect->segmentName();
+
+                       // align file offset with address layout
+                       fileOffset += sect->alignmentPaddingBytes;
+                       
+                       // update section info
+                       sect->fileOffset = fileOffset;
+                       
+                       // update running total
+                       fileOffset += sect->size;
+               }
+               
+               if ( log ) fprintf(stderr, "  fileoffset=0x%08llX, address=0x%08llX, hidden=%d, size=%lld, alignment=%02d, section=%s,%s\n",
+                               sect->fileOffset, sect->address, sect->isSectionHidden(), sect->size, sect->alignment, 
+                               sect->segmentName(), sect->sectionName());
+       }
+
+#if 0
+       // for encrypted iPhoneOS apps
+       if ( _options.makeEncryptable() ) { 
+               // remember end of __TEXT for later use by load command
+               for (std::vector<ld::Internal::FinalSection*>::iterator it = state.sections.begin(); it != state.sections.end(); ++it) {
+                       ld::Internal::FinalSection* sect = *it;
+                       if ( strcmp(sect->segmentName(), "__TEXT") == 0 ) {
+                               _encryptedTEXTendOffset = pageAlign(sect->fileOffset + sect->size);
+                       }
+               }
+       }
+#endif
+
+       // return total file size
+       return fileOffset;
+}
+
 static char* commatize(uint64_t in, char* out)
 {
        char* result = out;
index 42d5aa62713136f237a5a353a501dac87343956b..95973aa1c66c06ba9716ddcbf413ff78275bb7f2 100644 (file)
@@ -166,7 +166,8 @@ enum MacVersionMin { macVersionUnset=0, mac10_4=0x000A0400, mac10_5=0x000A0500,
                                                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_7_0=0x00070000, iOS_Future=0x10000000};
+                                               iOS_6_0=0x00060000, iOS_7_0=0x00070000,  
+                                               iOS_Future=0x10000000};
  
 namespace relocatable {
        //
@@ -409,6 +410,7 @@ struct Fixup
                                        kindStoreARM64GOTLoadPage21, kindStoreARM64GOTLoadPageOff12,
                                        kindStoreARM64GOTLeaPage21, kindStoreARM64GOTLeaPageOff12,
                                        kindStoreARM64TLVPLoadPage21, kindStoreARM64TLVPLoadPageOff12,
+                                       kindStoreARM64TLVPLoadNowLeaPage21, kindStoreARM64TLVPLoadNowLeaPageOff12,
                                        kindStoreARM64PointerToGOT, kindStoreARM64PCRelToGOT,
 #endif
                                        // dtrace probes
@@ -419,9 +421,13 @@ struct Fixup
                                        kindStoreThumbDtraceCallSiteNop, kindStoreThumbDtraceIsEnableSiteClear,
                                        // lazy binding
                                        kindLazyTarget, kindSetLazyOffset,
+                                       // islands
+                                       kindIslandTarget,
                                        // data-in-code markers
                                        kindDataInCodeStartData, kindDataInCodeStartJT8, kindDataInCodeStartJT16, 
                                        kindDataInCodeStartJT32, kindDataInCodeStartJTA32, kindDataInCodeEnd,
+                                       // linker optimzation hints
+                                       kindLinkerOptimizationHint,
                                        // pointer store combinations
                                        kindStoreTargetAddressLittleEndian32,   // kindSetTargetAddress + kindStoreLittleEndian32
                                        kindStoreTargetAddressLittleEndian64,   // kindSetTargetAddress + kindStoreLittleEndian64
@@ -451,6 +457,10 @@ struct Fixup
                                        kindStoreTargetAddressARM64GOTLoadPageOff12,// kindSetTargetAddress + kindStoreARM64GOTLoadPageOff12
                                        kindStoreTargetAddressARM64GOTLeaPage21,        // kindSetTargetAddress + kindStoreARM64GOTLeaPage21
                                        kindStoreTargetAddressARM64GOTLeaPageOff12,     // kindSetTargetAddress + kindStoreARM64GOTLeaPageOff12
+                                       kindStoreTargetAddressARM64TLVPLoadPage21,      // kindSetTargetAddress + kindStoreARM64TLVPLoadPage21
+                                       kindStoreTargetAddressARM64TLVPLoadPageOff12,// kindSetTargetAddress + kindStoreARM64TLVPLoadPageOff12
+                                       kindStoreTargetAddressARM64TLVPLoadNowLeaPage21,        // kindSetTargetAddress + kindStoreARM64TLVPLoadNowLeaPage21
+                                       kindStoreTargetAddressARM64TLVPLoadNowLeaPageOff12,     // kindSetTargetAddress + kindStoreARM64TLVPLoadNowLeaPageOff12
 #endif
                        };
 
@@ -516,6 +526,23 @@ struct Fixup
                contentAddendOnly(false), contentDetlaToAddendOnly(false), contentIgnoresAddend(false) 
                        { u.addend = addend; }
                        
+#if SUPPORT_ARCH_arm64
+       Fixup(Kind k, uint32_t lohKind, uint32_t off1, uint32_t off2) :
+               offsetInAtom(off1), kind(k), clusterSize(k1of1),  
+               weakImport(false), binding(Fixup::bindingNone), contentAddendOnly(false), 
+               contentDetlaToAddendOnly(false), contentIgnoresAddend(false) {
+                       assert(k == kindLinkerOptimizationHint);
+                       LOH_arm64 extra;
+                       extra.addend = 0;
+                       extra.info.kind = lohKind;
+                       extra.info.count = 1;
+                       extra.info.delta1 = 0;
+                       extra.info.delta2 = (off2 - off1) >> 2;
+                       u.addend = extra.addend; 
+               }
+#endif                 
+                       
+
        bool firstInCluster() const { 
                switch (clusterSize) {
                        case k1of1:
@@ -544,6 +571,20 @@ struct Fixup
                return false;
        }
        
+#if SUPPORT_ARCH_arm64
+       union LOH_arm64 {
+               uint64_t        addend;
+               struct {
+                       unsigned        kind    :  6,
+                                               count   :  2,   // 00 => 1 addr, 11 => 4 addrs
+                                               delta1 : 14,    // 16-bit delta, low 2 bits assumed zero
+                                               delta2 : 14,
+                                               delta3 : 14,
+                                               delta4 : 14;    
+               } info;
+       };
+#endif
+       
 };
 
 //
@@ -707,6 +748,7 @@ public:
                }
                return false;
        }
+       virtual void                                                    setFile(const File* f)          { }
        
        virtual UnwindInfo::iterator                    beginUnwind() const { return NULL; }
        virtual UnwindInfo::iterator                    endUnwind() const       { return NULL; }
@@ -805,7 +847,8 @@ public:
                bool                                                    hasExternalRelocs;
        };
        
-
+       virtual uint64_t                                        assignFileOffsets() = 0;
+       virtual void                                            setSectionSizesAndAlignments() = 0;
        virtual ld::Internal::FinalSection*     addAtom(const Atom&) = 0;
        virtual ld::Internal::FinalSection* getFinalSection(const ld::Section& inputSection) = 0;
        virtual                                                         ~Internal() {}
@@ -816,7 +859,10 @@ public:
                                                                                        objcDylibConstraint(ld::File::objcConstraintNone), 
                                                                                        cpuSubType(0), 
                                                                                        allObjectFilesScatterable(true), 
-                                                                                       someObjectFileHasDwarf(false), usingHugeSections(false) { }
+                                                                                       someObjectFileHasDwarf(false), usingHugeSections(false),
+                                                                                       hasThreadLocalVariableDefinitions(false),
+                                                                                       hasWeakExternalSymbols(false),
+                                                                                       someObjectHasOptimizationHints(false) { }
                                                                                
        std::vector<FinalSection*>                                      sections;
        std::vector<ld::dylib::File*>                           dylibs;
@@ -835,6 +881,9 @@ public:
        bool                                                                            allObjectFilesScatterable;
        bool                                                                            someObjectFileHasDwarf;
        bool                                                                            usingHugeSections;
+       bool                                                                            hasThreadLocalVariableDefinitions;
+       bool                                                                            hasWeakExternalSymbols;
+       bool                                                                            someObjectHasOptimizationHints;
 };
 
 
index 49240b3008b3156b0ffe2695941a067f64c8190e..900453040e4a511e6a68468173cff94b5794fa9b 100644 (file)
@@ -381,7 +381,7 @@ typename File<A>::MemberState& File<A>::makeObjectFileForMember(const Entry* mem
                // see if member is llvm bitcode file
                result = lto::parse(member->content(), member->contentSize(), 
                                                                mPath, member->modificationTime(), ordinal, 
-                                                               _objOpts.architecture, _objOpts.subType, _logAllFiles);
+                                                               _objOpts.architecture, _objOpts.subType, _logAllFiles, _objOpts.verboseOptimizationHints);
                if ( result != NULL ) {
                        MemberState state = {result, member, false, false, memberIndex};
                        _instantiatedEntries[member] = state;
index c67a2372bbb30c0b0f258a5d62817056bfcc03da..a37c8a041766ef3aca0a21c5b3fe9073d7c4a170 100644 (file)
@@ -95,7 +95,8 @@ public:
        typedef typename A::sint_t              sint_t; 
 
        static const char* parseCFIs(A& addressSpace, pint_t ehSectionStart, uint32_t sectionLength, 
-                            const pint_t cuStarts[], uint32_t cuCount, bool keepDwarfWhichHasCU, bool forceDwarfConversion,
+                            const pint_t cuStarts[], uint32_t cuCount, 
+                            bool keepDwarfWhichHasCU, bool forceDwarfConversion, bool neverConvertToCU,
                             CFI_Atom_Info<A>* infos, uint32_t& infosCount, void* ref, WarnFunc warn);
 
 
@@ -172,7 +173,8 @@ private:
 
 template <typename A, typename R>
 const char* DwarfInstructions<A,R>::parseCFIs(A& addressSpace, pint_t ehSectionStart, uint32_t sectionLength, 
-                                      const pint_t cuStarts[], uint32_t cuCount,  bool keepDwarfWhichHasCU,  bool forceDwarfConversion,
+                                      const pint_t cuStarts[], uint32_t cuCount,  
+                                      bool keepDwarfWhichHasCU,  bool forceDwarfConversion, bool neverConvertToCU,
                                       CFI_Atom_Info<A>* infos, uint32_t& infosCount, void* ref, WarnFunc warn)
 {
        typename CFI_Parser<A>::CIE_Info cieInfo;
@@ -270,7 +272,7 @@ const char* DwarfInstructions<A,R>::parseCFIs(A& addressSpace, pint_t ehSectionS
                                        ++entry;
                        }
                        else {
-                               if ( (cuCount != 0) && !forceDwarfConversion ) {
+                               if ( neverConvertToCU || ((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;
index 460dcf0b837da5d9751a7bcb76f0b06c91c073bd..3fe21f686cfb4458d1e74e718315d87c8c7e7587 100644 (file)
@@ -47,7 +47,6 @@
 #define __STDC_CONSTANT_MACROS 1
 #include "llvm-c/lto.h"
 
-
 namespace lto {
          
 
@@ -199,7 +198,8 @@ public:
        static bool                                             validFile(const uint8_t* fileContent, uint64_t fileLength, cpu_type_t architecture, cpu_subtype_t subarch);
        static const char*                              fileKind(const uint8_t* fileContent, uint64_t fileLength);
        static File*                                    parse(const uint8_t* fileContent, uint64_t fileLength, const char* path, 
-                                                                                       time_t modTime, ld::File::Ordinal ordinal, cpu_type_t architecture, cpu_subtype_t subarch, bool logAllFiles);
+                                                                                       time_t modTime, ld::File::Ordinal ordinal, cpu_type_t architecture, cpu_subtype_t subarch,
+                                                                                       bool logAllFiles, bool verboseOptimizationHints);
        static bool                                             libLTOisLoaded() { return (::lto_get_version() != NULL); }
        static bool                                             optimize(   const std::vector<const ld::Atom*>& allAtoms,
                                                                                                ld::Internal&                                           state,
@@ -213,6 +213,9 @@ public:
 private:
        static const char*                              tripletPrefixForArch(cpu_type_t arch);
        static ld::relocatable::File*   parseMachOFile(const uint8_t* p, size_t len, const OptimizeOptions& options);
+#if LTO_API_VERSION >= 7
+       static void ltoDiagnosticHandler(lto_codegen_diagnostic_severity_t, const char*, void*);
+#endif
 
        typedef std::unordered_set<const char*, ld::CStringHash, ld::CStringEquals>  CStringSet;
        typedef std::unordered_map<const char*, Atom*, ld::CStringHash, ld::CStringEquals> CStringToAtom;
@@ -276,7 +279,7 @@ const char* Parser::fileKind(const uint8_t* p, uint64_t fileLength)
 }
 
 File* Parser::parse(const uint8_t* fileContent, uint64_t fileLength, const char* path, time_t modTime, ld::File::Ordinal ordinal,
-                                                                                                       cpu_type_t architecture, cpu_subtype_t subarch, bool logAllFiles) 
+                                                                                                       cpu_type_t architecture, cpu_subtype_t subarch, bool logAllFiles, bool verboseOptimizationHints
 {
        File* f = new File(path, modTime, ordinal, fileContent, fileLength, architecture);
        _s_files.push_back(f);
@@ -295,6 +298,8 @@ ld::relocatable::File* Parser::parseMachOFile(const uint8_t* p, size_t len, cons
        objOpts.warnUnwindConversionProblems    = options.needsUnwindInfoSection;
        objOpts.keepDwarfUnwind         = options.keepDwarfUnwind;
        objOpts.forceDwarfConversion = false;
+       objOpts.neverConvertDwarf   = false;
+       objOpts.verboseOptimizationHints = options.verboseOptimizationHints;
        objOpts.subType                         = 0;
        
        // mach-o parsing is done in-memory, but need path for debug notes
@@ -461,6 +466,20 @@ struct CommandLineOrderFileSorter
 };
 
 
+#if LTO_API_VERSION >= 7
+void Parser::ltoDiagnosticHandler(lto_codegen_diagnostic_severity_t severity, const char* message, void*) 
+{
+       switch ( severity ) {
+               case LTO_DS_NOTE:
+               case LTO_DS_WARNING:
+                       warning("%s", message);
+                       break;
+               case LTO_DS_ERROR:
+                       throwf("%s", message);
+       }
+}
+#endif
+
 bool Parser::optimize(  const std::vector<const ld::Atom*>&    allAtoms,
                                                ld::Internal&                                           state,
                                                const OptimizeOptions&                          options,
@@ -483,6 +502,10 @@ bool Parser::optimize(  const std::vector<const ld::Atom*>&        allAtoms,
        
        // create optimizer and add each Reader
        lto_code_gen_t generator = ::lto_codegen_create();
+#if LTO_API_VERSION >= 7
+       lto_codegen_set_diagnostic_handler(generator, ltoDiagnosticHandler, NULL);
+#endif
+
        // <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;
@@ -529,10 +552,7 @@ bool Parser::optimize(  const std::vector<const ld::Atom*>&        allAtoms,
                                                break;
                                        case ld::Fixup::bindingsIndirectlyBound:
                                                target = state.indirectBindingTable[fit->u.bindingIndex];
-                                               if ( target == NULL )
-                                                       throwf("'%s' in %s contains undefined reference", atom->name(), atom->file()->path());
-                                               assert(target != NULL);
-                                               if ( target->contentType() == ld::Atom::typeLTOtemporary )
+                                               if ( (target != NULL) && (target->contentType() == ld::Atom::typeLTOtemporary) )
                                                        nonLLVMRefs.insert(target->name());
                                        default:
                                                break;
@@ -742,6 +762,8 @@ bool Parser::optimize(  const std::vector<const ld::Atom*>& allAtoms,
 
 void Parser::AtomSyncer::doAtom(const ld::Atom& machoAtom)
 {
+       static const ld::Atom* lastProxiedAtom = NULL;
+       static const ld::File* lastProxiedFile = NULL;
        // update proxy atoms to point to real atoms and find new atoms
        const char* name = machoAtom.name();
        if ( machoAtom.scope() >= ld::Atom::scopeLinkageUnit ) {
@@ -749,6 +771,8 @@ void Parser::AtomSyncer::doAtom(const ld::Atom& machoAtom)
                if ( pos != _llvmAtoms.end() ) {
                        // turn Atom into a proxy for this mach-o atom
                        pos->second->setCompiledAtom(machoAtom);
+                       lastProxiedAtom = &machoAtom;
+                       lastProxiedFile = pos->second->file();
                }
                else {
                        // an atom of this name was not in the allAtoms list the linker gave us
@@ -774,6 +798,11 @@ void Parser::AtomSyncer::doAtom(const ld::Atom& machoAtom)
        else {
                // ld only knew about non-static atoms, so this one must be new
                _newAtoms.push_back(&machoAtom);
+               // <rdar://problem/15469363> if new static atom in same section as previous non-static atom, assign to same file as previous
+               if ( (lastProxiedAtom != NULL) && (lastProxiedAtom->section() == machoAtom.section()) ) {
+                       ld::Atom* ma = const_cast<ld::Atom*>(&machoAtom);
+                       ma->setFile(lastProxiedFile);
+               }
        }
        
        // adjust fixups to go through proxy atoms
@@ -844,11 +873,12 @@ bool isObjectFile(const uint8_t* fileContent, uint64_t fileLength, cpu_type_t ar
 //
 ld::relocatable::File* parse(const uint8_t* fileContent, uint64_t fileLength, 
                                                                const char* path, time_t modTime, ld::File::Ordinal ordinal,
-                                                               cpu_type_t architecture, cpu_subtype_t subarch, bool logAllFiles)
+                                                               cpu_type_t architecture, cpu_subtype_t subarch, bool logAllFiles,
+                                                               bool verboseOptimizationHints)
 {
        Mutex lock;
        if ( Parser::validFile(fileContent, fileLength, architecture, subarch) )
-               return Parser::parse(fileContent, fileLength, path, modTime, ordinal, architecture, subarch, logAllFiles);
+               return Parser::parse(fileContent, fileLength, path, modTime, ordinal, architecture, subarch, logAllFiles, verboseOptimizationHints);
        else
                return NULL;
 }
index 4140a3ae4bc27944c6fbb8f4a9db6d02cc33e33d..d75aab328efddbf093b4a35b061a6f364e5a5b0c 100644 (file)
@@ -39,7 +39,8 @@ extern bool isObjectFile(const uint8_t* fileContent, uint64_t fileLength, cpu_ty
 
 extern ld::relocatable::File* parse(const uint8_t* fileContent, uint64_t fileLength, 
                                                                        const char* path, time_t modTime, ld::File::Ordinal ordinal,
-                                                                       cpu_type_t architecture, cpu_subtype_t subarch, bool logAllFiles);
+                                                                       cpu_type_t architecture, cpu_subtype_t subarch, bool logAllFiles,
+                                                                       bool verboseOptimizationHints);
 
 struct OptimizeOptions {
        const char*                                                     outputFilePath;
@@ -55,6 +56,7 @@ struct OptimizeOptions {
        bool                                                            linkerDeadStripping; 
        bool                                                            needsUnwindInfoSection; 
        bool                                                            keepDwarfUnwind; 
+       bool                                                            verboseOptimizationHints;
        cpu_type_t                                                      arch;
        const char*                                                     mcpu;
        const std::vector<const char*>*         llvmOptions;
index b30e727417a59d9a8dcf5dc3731ec76e3e5e34ec..d37098b24ee91ea43d9c36b9cbd326e24d7ec07d 100644 (file)
@@ -204,6 +204,7 @@ private:
        void                                                                            buildExportHashTableFromSymbolTable(const macho_dysymtab_command<P>* dynamicInfo, 
                                                                                                                const macho_nlist<P>* symbolTable, const char* strings,
                                                                                                                const uint8_t* fileContent);
+       static uint32_t                                                         parseVersionNumber32(const char* versionString);
        static const char*                                                      objCInfoSegmentName();
        static const char*                                                      objCInfoSectionName();
        
@@ -231,6 +232,7 @@ private:
        bool                                                                            _explictReExportFound;
        bool                                                                            _wrongOS;
        bool                                                                            _installPathOverride;
+       bool                                                                            _indirectDylibsProcessed;
        
        static bool                                                                     _s_logHashtable;
 };
@@ -260,7 +262,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), _wrongOS(false), _installPathOverride(false)
+        _providedAtom(false), _explictReExportFound(false), _wrongOS(false), _installPathOverride(false), _indirectDylibsProcessed(false)
 {
        const macho_header<P>* header = (const macho_header<P>*)fileContent;
        const uint32_t cmd_count = header->ncmds();
@@ -514,6 +516,28 @@ File<A>::File(const uint8_t* fileContent, uint64_t fileLength, const char* pth,
        munmap((caddr_t)fileContent, fileLength);
 }
 
+//
+// Parses number of form X[.Y[.Z]] into a uint32_t where the nibbles are xxxx.yy.zz
+//
+template <typename A>
+uint32_t File<A>::parseVersionNumber32(const char* versionString)
+{
+       uint32_t x = 0;
+       uint32_t y = 0;
+       uint32_t z = 0;
+       char* end;
+       x = strtoul(versionString, &end, 10);
+       if ( *end == '.' ) {
+               y = strtoul(&end[1], &end, 10);
+               if ( *end == '.' ) {
+                       z = strtoul(&end[1], &end, 10);
+               }
+       }
+       if ( (*end != '\0') || (x > 0xffff) || (y > 0xff) || (z > 0xff) )
+               throwf("malformed 32-bit x.y.z version number: %s", versionString);
+
+       return (x << 16) | ( y << 8 ) | z;
+}
 
 template <typename A>
 void File<A>::buildExportHashTableFromSymbolTable(const macho_dysymtab_command<P>* dynamicInfo, 
@@ -621,6 +645,13 @@ 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;
+                                               // <rdar://problem/14448206> CoreGraphics redirects to ApplicationServices, but with wrong compat version
+                                               if ( strcmp(_dylibInstallPath, "/System/Library/Frameworks/ApplicationServices.framework/Versions/A/ApplicationServices") == 0 )
+                                                       _dylibCompatibilityVersion = parseVersionNumber32("1.0");
+                                               return;
+                                       }
+                                       else if ( strncmp(symAction, "compatibility_version$", 22) == 0 ) {
+                                               _dylibCompatibilityVersion = parseVersionNumber32(symName);
                                                return;
                                        }
                                        else {
@@ -793,6 +824,9 @@ bool File<A>::isPublicLocation(const char* pth)
 template <typename A>
 void File<A>::processIndirectLibraries(ld::dylib::File::DylibHandler* handler, bool addImplicitDylibs)
 {
+       // only do this once
+       if ( _indirectDylibsProcessed )
+               return;
        const static bool log = false;
        if ( log ) fprintf(stderr, "processIndirectLibraries(%s)\n", this->installPath());
        if ( _linkingFlat ) {
@@ -850,6 +884,8 @@ void File<A>::processIndirectLibraries(ld::dylib::File::DylibHandler* handler, b
        chain.prev = NULL;
        chain.file = this;
        this->assertNoReExportCycles(&chain);
+       
+       _indirectDylibsProcessed = true;
 }
 
 template <typename A>
@@ -1018,7 +1054,8 @@ bool isDylibFile(const uint8_t* fileContent, cpu_type_t* result, cpu_subtype_t*
 {
        if ( Parser<x86_64>::validFile(fileContent, false) ) {
                *result = CPU_TYPE_X86_64;
-               *subResult = CPU_SUBTYPE_X86_64_ALL;
+               const macho_header<Pointer64<LittleEndian> >* header = (const macho_header<Pointer64<LittleEndian> >*)fileContent;
+               *subResult = header->cpusubtype();
                return true;
        }
        if ( Parser<x86>::validFile(fileContent, false) ) {
index c22af18c0a4a3d2f2b4628abdbf71ef59c22654c..ad5720ed1212e2b3b060c558df673658b49c5eb6 100644 (file)
@@ -170,6 +170,7 @@ protected:
 
        Atom<A>*                                                findContentAtomByAddress(pint_t addr, class Atom<A>* start, class Atom<A>* end);
        uint32_t                                                x86_64PcRelOffset(uint8_t r_type);
+       void                                                    addLOH(class Parser<A>& parser, int kind, int count, const uint64_t addrs[]);
        static const char*                              makeSegmentName(const macho_section<typename A::P>* s);
        static bool                                             readable(const macho_section<typename A::P>* s);
        static bool                                             writable(const macho_section<typename A::P>* s);
@@ -676,7 +677,7 @@ class Atom : public ld::Atom
 {
 public:
        // overrides of ld::Atom
-       virtual ld::File*                                                       file() const            { return &sect().file(); }
+       virtual const ld::File*                                         file() const;
        virtual const char*                                                     translationUnitSource() const
                                                                                                                                        { return sect().file().translationUnitSource(); }
        virtual const char*                                                     name() const            { return _name; }
@@ -694,6 +695,7 @@ public:
        virtual ld::Atom::UnwindInfo::iterator          endUnwind()     const   { return &machofile()._unwindInfos[_unwindInfoStartIndex+_unwindInfoCount];  }
        virtual ld::Atom::LineInfo::iterator            beginLineInfo() const{ return &machofile()._lineInfos[_lineInfoStartIndex]; }
        virtual ld::Atom::LineInfo::iterator            endLineInfo() const { return &machofile()._lineInfos[_lineInfoStartIndex+_lineInfoCount];  }
+       virtual void                                                            setFile(const ld::File* f);
 
 private:
 
@@ -719,7 +721,7 @@ public:
                                                                                                                                                        throwf("too may fixups in %s", name()); ++_fixupsCount; }
                        const uint8_t*                                          contentPointer() const;
                        uint32_t                                                        fixupCount() const { return _fixupsCount; }
-                       void                                                            verifyAlignment() const;
+                       void                                                            verifyAlignment(const macho_section<typename A::P>&) const;
        
        typedef typename A::P                                           P;
        typedef typename A::P::E                                        E;
@@ -753,7 +755,7 @@ public:
                                                                                                                                if ( _scope == ld::Atom::scopeGlobal && 
                                                                                                                                                (sym.n_desc() & (N_WEAK_DEF|N_WEAK_REF)) == (N_WEAK_DEF|N_WEAK_REF) )
                                                                                                                                        this->setAutoHide();
-                                                                                                                                       this->verifyAlignment();
+                                                                                                                                       this->verifyAlignment(*sct.machoSection());
                                                                                                                        }
 
 private:
@@ -773,10 +775,27 @@ private:
                                                                                                _fixupsCount                    : kFixupCountBits,
                                                                                                _lineInfoCount                  : kLineInfoCountBits,
                                                                                                _unwindInfoCount                : kUnwindInfoCountBits;
-
+                                                                                               
+       static std::map<const ld::Atom*, const ld::File*> _s_fileOverride;
 };
 
+template <typename A>
+std::map<const ld::Atom*, const ld::File*> Atom<A>::_s_fileOverride;
+
+template <typename A>
+void Atom<A>::setFile(const ld::File* f) {
+       _s_fileOverride[this] = f;
+}
 
+template <typename A>
+const ld::File* Atom<A>::file() const
+{
+       std::map<const ld::Atom*, const ld::File*>::iterator pos = _s_fileOverride.find(this);
+       if ( pos != _s_fileOverride.end() )
+               return pos->second;
+               
+       return &sect().file();
+}
 
 template <typename A>
 void Atom<A>::setFixupsRange(uint32_t startIndex, uint32_t count)
@@ -843,7 +862,7 @@ void Atom<A>::copyRawContent(uint8_t buffer[]) const
 }
 
 template <>
-void Atom<arm>::verifyAlignment() const
+void Atom<arm>::verifyAlignment(const macho_section<P>&) const
 {
        if ( (this->section().type() == ld::Section::typeCode) && ! isThumb() ) {
                if ( ((_objAddress % 4) != 0) || (this->alignment().powerOf2 < 2) )
@@ -851,8 +870,19 @@ void Atom<arm>::verifyAlignment() const
        }
 }
 
+#if SUPPORT_ARCH_arm64
+template <>
+void Atom<arm64>::verifyAlignment(const macho_section<P>& sect) const
+{
+       if ( (this->section().type() == ld::Section::typeCode) && (sect.size() != 0) ) {
+               if ( ((_objAddress % 4) != 0) || (this->alignment().powerOf2 < 2) )
+                       warning("arm64 function not 4-byte aligned: %s from %s", this->name(), this->file()->path());
+       }
+}
+#endif
+
 template <typename A>
-void Atom<A>::verifyAlignment() const
+void Atom<A>::verifyAlignment(const macho_section<P>&) const
 {
 }
 
@@ -871,7 +901,8 @@ public:
                                                                                                                         const ParserOptions& opts) {
                                                                                                                                Parser p(fileContent, fileLength, path, modTime, 
                                                                                                                                                ordinal, opts.warnUnwindConversionProblems,
-                                                                                                                                               opts.keepDwarfUnwind, opts.forceDwarfConversion);
+                                                                                                                                               opts.keepDwarfUnwind, opts.forceDwarfConversion,
+                                                                                                                                               opts.neverConvertDwarf, opts.verboseOptimizationHints);
                                                                                                                                return p.parse(opts);
                                                                                                                }
 
@@ -981,9 +1012,15 @@ public:
        bool                                                                                    hasDataInCodeLabels() { return _hasDataInCodeLabels; }
        bool                                                                                    keepDwarfUnwind() { return _keepDwarfUnwind; }
        bool                                                                                    forceDwarfConversion() { return _forceDwarfConversion; }
+       bool                                                                                    verboseOptimizationHints() { return _verboseOptimizationHints; }
+       bool                                                                                    neverConvertDwarf() { return _neverConvertDwarf; }
        
        macho_data_in_code_entry<P>*                                    dataInCodeStart() { return _dataInCodeStart; }
        macho_data_in_code_entry<P>*                                    dataInCodeEnd()   { return _dataInCodeEnd; }
+       const uint8_t*                                                                  optimizationHintsStart() { return _lohStart; }
+       const uint8_t*                                                                  optimizationHintsEnd() { return _lohEnd; }
+       bool                                                                                    hasOptimizationHints() { return _lohStart != _lohEnd; }
+
        
        void                                                    addFixups(const SourceLocation& src, ld::Fixup::Kind kind, const TargetDesc& target);
        void                                                    addFixups(const SourceLocation& src, ld::Fixup::Kind kind, const TargetDesc& target, const TargetDesc& picBase);
@@ -1059,7 +1096,8 @@ private:
 
                                                                                                        Parser(const uint8_t* fileContent, uint64_t fileLength, 
                                                                                                                        const char* path, time_t modTime, ld::File::Ordinal ordinal, 
-                                                                                                                       bool warnUnwindConversionProblems, bool keepDwarfUnwind, bool forceDwarfConversion);
+                                                                                                                       bool warnUnwindConversionProblems, bool keepDwarfUnwind,
+                                                                                                                       bool forceDwarfConversion, bool neverConvertDwarf, bool verboseOptimizationHints);
        ld::relocatable::File*                                                  parse(const ParserOptions& opts);
        uint8_t                                                                                 loadCommandSizeMask();
        bool                                                                                    parseLoadCommands();
@@ -1103,6 +1141,8 @@ private:
        bool                                                                            _hasUUID;
        macho_data_in_code_entry<P>*                            _dataInCodeStart;
        macho_data_in_code_entry<P>*                            _dataInCodeEnd;
+       const uint8_t*                                                          _lohStart;
+       const uint8_t*                                                          _lohEnd;
                
        // filled in by parse()
        CFISection<A>*                                                          _EHFrameSection;
@@ -1118,6 +1158,8 @@ private:
        bool                                                                            _hasDataInCodeLabels;
        bool                                                                            _keepDwarfUnwind;
        bool                                                                            _forceDwarfConversion;
+       bool                                                                            _neverConvertDwarf;
+       bool                                                                            _verboseOptimizationHints;
        unsigned int                                                            _stubsSectionNum;
        const macho_section<P>*                                         _stubsMachOSection;
        std::vector<const char*>                                        _dtraceProviderInfo;
@@ -1128,7 +1170,8 @@ private:
 
 template <typename A>
 Parser<A>::Parser(const uint8_t* fileContent, uint64_t fileLength, const char* path, time_t modTime, 
-                                       ld::File::Ordinal ordinal, bool convertDUI, bool keepDwarfUnwind, bool forceDwarfConversion)
+                                       ld::File::Ordinal ordinal, bool convertDUI, bool keepDwarfUnwind, bool forceDwarfConversion, 
+                                       bool neverConvertDwarf, bool verboseOptimizationHints)
                : _fileContent(fileContent), _fileLength(fileLength), _path(path), _modTime(modTime),
                        _ordinal(ordinal), _file(NULL),
                        _symbols(NULL), _symbolCount(0), _strings(NULL), _stringsSize(0),
@@ -1136,11 +1179,14 @@ Parser<A>::Parser(const uint8_t* fileContent, uint64_t fileLength, const char* p
                        _undefinedStartIndex(0), _undefinedEndIndex(0), 
                        _sectionsStart(NULL), _machOSectionsCount(0), _hasUUID(false), 
                        _dataInCodeStart(NULL), _dataInCodeEnd(NULL),
+                       _lohStart(NULL), _lohEnd(NULL),
                        _EHFrameSection(NULL), _compactUnwindSection(NULL), _absoluteSection(NULL),
                        _tentativeDefinitionCount(0), _absoluteSymbolCount(0),
                        _symbolsInSections(0), _hasLongBranchStubs(false),  _AppleObjc(false),
                        _overlappingSymbols(false), _warnUnwindConversionProblems(convertDUI), _hasDataInCodeLabels(false),
                        _keepDwarfUnwind(keepDwarfUnwind), _forceDwarfConversion(forceDwarfConversion),
+                       _neverConvertDwarf(neverConvertDwarf),
+                       _verboseOptimizationHints(verboseOptimizationHints),
                        _stubsSectionNum(0), _stubsMachOSection(NULL)
 {
 }
@@ -1843,6 +1889,15 @@ bool Parser<A>::parseLoadCommands()
                                                throw "malformed LC_LINKER_OPTION";
                                }
                                break;
+                       case LC_LINKER_OPTIMIZATION_HINTS:
+                               {
+                                       const macho_linkedit_data_command<P>* loh = (macho_linkedit_data_command<P>*)cmd;
+                                       _lohStart = _fileContent + loh->dataoff();
+                                       _lohEnd = _fileContent + loh->dataoff() + loh->datasize();
+                                       if ( _lohEnd > endOfFile )
+                                               throw "LC_LINKER_OPTIMIZATION_HINTS table extends beyond end of file";
+                               }
+                               break;
                        default:
                                if ( cmd->cmd() == macho_segment_command<P>::CMD ) {
                                        if ( segment != NULL )
@@ -2648,6 +2703,12 @@ void Parser<A>::addFixups(const SourceLocation& src, ld::Fixup::Kind setKind, co
                        case ld::Fixup::kindStoreARM64GOTLoadPageOff12:
                                firstKind = ld::Fixup::kindStoreTargetAddressARM64GOTLoadPageOff12;
                                break;
+                       case ld::Fixup::kindStoreARM64TLVPLoadPage21:
+                               firstKind = ld::Fixup::kindStoreTargetAddressARM64TLVPLoadPage21;
+                               break;
+                       case ld::Fixup::kindStoreARM64TLVPLoadPageOff12:
+                               firstKind = ld::Fixup::kindStoreTargetAddressARM64TLVPLoadPageOff12;
+                               break;
 #endif
                        default:
                                combined = false;
@@ -3552,7 +3613,7 @@ bool Parser<A>::read_comp_unit(const char ** name, const char ** comp_dir,
                return false;
 
        vers = A::P::E::get16(*(uint16_t*)di);
-       if (vers < 2 || vers > 3)
+       if (vers < 2 || vers > 4)
        /* DWARF version wrong for this code.
           Chances are we could continue anyway, but we don't know for sure.  */
                return false;
@@ -3845,7 +3906,10 @@ template <typename A>
 ld::Atom::Alignment Section<A>::alignmentForAddress(pint_t addr) 
 { 
        const uint32_t sectionAlignment = this->_machOSection->align();
-       return ld::Atom::Alignment(sectionAlignment, (addr % (1 << sectionAlignment)));
+       uint32_t modulus = (addr % (1 << sectionAlignment));
+       if ( modulus > 0xFFFF )
+               warning("alignment for symbol at address 0x%08llX in %s exceeds 2^16", (uint64_t)addr, this->file().path());
+       return ld::Atom::Alignment(sectionAlignment, modulus);
 }
 
 template <typename A>
@@ -3959,7 +4023,8 @@ 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(), 
-                                                       cuStarts, cuCount, parser.keepDwarfUnwind(), parser.forceDwarfConversion(), cfiArray, count, (void*)&parser, warnFunc);
+                                                       cuStarts, cuCount, parser.keepDwarfUnwind(), parser.forceDwarfConversion(), parser.neverConvertDwarf(), 
+                                                       cfiArray, count, (void*)&parser, warnFunc);
        if ( msg != NULL ) 
                throwf("malformed __eh_frame section: %s", msg);
 }
@@ -3976,7 +4041,8 @@ 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(), 
-                                                       cuStarts, cuCount, parser.keepDwarfUnwind(), parser.forceDwarfConversion(), cfiArray, count, (void*)&parser, warnFunc);
+                                                       cuStarts, cuCount, parser.keepDwarfUnwind(), parser.forceDwarfConversion(), parser.neverConvertDwarf(),
+                                                       cfiArray, count, (void*)&parser, warnFunc);
        if ( msg != NULL ) 
                throwf("malformed __eh_frame section: %s", msg);
 }
@@ -4052,7 +4118,7 @@ void CFISection<arm64>::cfiParse(class Parser<arm64>& parser, uint8_t* buffer,
        const char* msg;
        msg = libunwind::DwarfInstructions<OAS, libunwind::Registers_arm64>::parseCFIs(
                                                        oas, this->_machOSection->addr(), this->_machOSection->size(), 
-                                                       cuStarts, cuCount, parser.keepDwarfUnwind(), parser.forceDwarfConversion(), 
+                                                       cuStarts, cuCount, parser.keepDwarfUnwind(), parser.forceDwarfConversion(), parser.neverConvertDwarf(),
                                                        cfiArray, count, (void*)&parser, warnFunc);
        if ( msg != NULL ) 
                throwf("malformed __eh_frame section: %s", msg);
@@ -5190,7 +5256,11 @@ const uint8_t* CFStringSection<A>::targetContent(const class Atom<A>* atom, cons
                        *ct = contentUTF16;
                        *count = (targetAtom->size()+1)/2; // round up incase of buggy compiler that has only one trailing zero byte
                }
-               assert(target !=  NULL);
+               else {
+                       *ct = contentUnknown;
+                       *count = 0;
+                       return NULL;
+               }
                return target->contentPointer();
        }
        assert(0);
@@ -5220,7 +5290,8 @@ unsigned long CFStringSection<A>::contentHash(const class Atom<A>* atom, const l
                        }
                        return hash;
                case contentUnknown:
-                       return 0;
+                       // <rdar://problem/14134211> For malformed CFStrings, hash to address of atom so they have unique hashes
+                       return ULONG_MAX - (unsigned long)(atom);
        }
        return 0;
 }
@@ -5249,6 +5320,12 @@ bool CFStringSection<A>::canCoalesceWith(const class Atom<A>* atom, const ld::At
        if ( thisType != rhsType )
                return false;
 
+       if ( thisType == contentUnknown )
+               return false;
+
+       if ( rhsType == contentUnknown )
+               return false;
+
        // no need to compare content of pointers are already the same
        if ( cstringContent == rhsStringContent ) 
                return true;
@@ -6814,6 +6891,72 @@ bool Objc1ClassReferences<x86>::addRelocFixup(class Parser<x86>& parser, const m
        return PointerToCStringSection<x86>::addRelocFixup(parser, reloc);
 }
 
+#if SUPPORT_ARCH_arm64
+template <>
+void Section<arm64>::addLOH(class Parser<arm64>& parser, int kind, int count, const uint64_t addrs[]) {
+       switch (kind) {
+               case LOH_ARM64_ADRP_ADRP:
+               case LOH_ARM64_ADRP_LDR:
+               case LOH_ARM64_ADRP_ADD:
+               case LOH_ARM64_ADRP_LDR_GOT:
+                       if ( count != 2 )
+                               warning("arm64 Linker Optimiztion Hint %d has wrong number of arguments", kind);
+                       break;
+               case LOH_ARM64_ADRP_ADD_LDR:
+               case LOH_ARM64_ADRP_LDR_GOT_LDR:
+               case LOH_ARM64_ADRP_ADD_STR:
+               case LOH_ARM64_ADRP_LDR_GOT_STR:
+                       if ( count != 3 )
+                               warning("arm64 Linker Optimiztion Hint %d has wrong number of arguments", kind);
+       }
+       
+       // pick lowest address in tuple for use as offsetInAtom
+       uint64_t lowestAddress = addrs[0];
+       for(int i=1; i < count; ++i) {
+               if ( addrs[i] < lowestAddress )
+                       lowestAddress = addrs[i];
+       }
+       // verify all other address are in same atom
+       Atom<arm64>* inAtom = parser.findAtomByAddress(lowestAddress);
+       const uint64_t atomStartAddr = inAtom->objectAddress();
+       const uint64_t atomEndAddr = atomStartAddr + inAtom->size();
+       for(int i=0; i < count; ++i) {
+               if ( (addrs[i] < atomStartAddr) || (addrs[i] >= atomEndAddr) ) {
+                       warning("arm64 Linker Optimiztion Hint addresses are not in same atom: 0x%08llX and 0x%08llX",
+                               lowestAddress, addrs[i]);
+                       return; // skip this LOH
+               }
+               if ( (addrs[i] & 0x3) != 0 ) {
+                       warning("arm64 Linker Optimiztion Hint address is not 4-byte aligned: 0x%08llX", addrs[i]);
+                       return; // skip this LOH
+               }
+               if ( (addrs[i] - lowestAddress) > 0xFFFF ) {
+                       if ( parser.verboseOptimizationHints() ) {
+                               warning("arm64 Linker Optimiztion Hint addresses are too far apart: 0x%08llX and 0x%08llX",
+                                       lowestAddress, addrs[i]);
+                       }
+                       return; // skip this LOH
+               }
+       }
+       
+       // encoded kind, count, and address deltas in 64-bit addend 
+       ld::Fixup::LOH_arm64 extra;
+       extra.addend = 0;
+       extra.info.kind = kind;
+       extra.info.count = count-1;
+       extra.info.delta1 = (addrs[0] - lowestAddress) >> 2;
+       extra.info.delta2 = (count > 1) ? ((addrs[1] - lowestAddress) >> 2) : 0;
+       extra.info.delta3 = (count > 2) ? ((addrs[2] - lowestAddress) >> 2) : 0;
+       extra.info.delta4 = (count > 3) ? ((addrs[3] - lowestAddress) >> 2) : 0;
+       typename Parser<arm64>::SourceLocation src(inAtom, lowestAddress- inAtom->objectAddress());
+       parser.addFixup(src, ld::Fixup::k1of1, ld::Fixup::kindLinkerOptimizationHint, extra.addend);
+}
+#endif
+
+template <typename A>
+void Section<A>::addLOH(class Parser<A>& parser, int kind, int count, const uint64_t addrs[]) {
+
+}
 
 template <typename A>
 void Section<A>::makeFixups(class Parser<A>& parser, const struct Parser<A>::CFI_CU_InfoArrays&)
@@ -6929,6 +7072,42 @@ void Section<A>::makeFixups(class Parser<A>& parser, const struct Parser<A>::CFI
                }
        }
        
+       // <rdar://problem/11945700> convert linker optimization hints into internal format
+       if ( this->type() == ld::Section::typeCode && parser.hasOptimizationHints() ) {
+               const pint_t startAddr = this->_machOSection->addr();
+               const pint_t endAddr = startAddr + this->_machOSection->size();
+               for (const uint8_t* p = parser.optimizationHintsStart(); p < parser.optimizationHintsEnd(); ) {
+                       uint64_t addrs[4];
+                       int32_t kind = read_uleb128(&p, parser.optimizationHintsEnd());
+                       if ( kind == 0 ) // padding at end of loh buffer
+                               break;
+                       if ( kind == -1 ) {
+                               warning("malformed uleb128 kind in LC_LINKER_OPTIMIZATION_HINTS");
+                               break;
+                       }
+                       int32_t count = read_uleb128(&p, parser.optimizationHintsEnd());
+                       if ( count == -1 ) {
+                               warning("malformed uleb128 count in LC_LINKER_OPTIMIZATION_HINTS");
+                               break;
+                       }
+                       if ( count > 3 ) {
+                               warning("address count > 3 in LC_LINKER_OPTIMIZATION_HINTS");
+                               break;
+                       }
+                       for (int32_t i=0; i < count; ++i) {
+                               addrs[i] = read_uleb128(&p, parser.optimizationHintsEnd());
+                       }
+                       if ( (startAddr <= addrs[0]) && (addrs[0] < endAddr) ) {
+                               this->addLOH(parser, kind, count, addrs);
+                               //fprintf(stderr, "kind=%d", kind);
+                               //for (int32_t i=0; i < count; ++i) {
+                               //      fprintf(stderr, ", addr=0x%08llX", addrs[i]);
+                               //}
+                               //fprintf(stderr, "\n");
+                       }
+               }
+       }
+       
        
        // add follow-on fixups for aliases
        if ( _hasAliases ) {
@@ -7006,7 +7185,8 @@ bool isObjectFile(const uint8_t* fileContent, cpu_type_t* result, cpu_subtype_t*
 {
        if ( mach_o::relocatable::Parser<x86_64>::validFile(fileContent) ) {
                *result = CPU_TYPE_X86_64;
-               *subResult = CPU_SUBTYPE_X86_64_ALL;
+               const macho_header<Pointer64<LittleEndian> >* header = (const macho_header<Pointer64<LittleEndian> >*)fileContent;
+               *subResult = header->cpusubtype();
                return true;
        }
        if ( mach_o::relocatable::Parser<x86>::validFile(fileContent) ) {
index a576f527afcb87e862f60887a8d5f5e86b747ae4..6d20847fcd02d2b244bd23f56376ef3539749b14 100644 (file)
@@ -38,6 +38,8 @@ struct ParserOptions {
        bool                    warnUnwindConversionProblems;
        bool                    keepDwarfUnwind;
        bool                    forceDwarfConversion;
+       bool                    neverConvertDwarf;
+       bool                    verboseOptimizationHints;
        uint32_t                subType;
 };
 
index 96b6d35c59c218f1eec991ca13b37b2eca3ac80b..5f5612ccac3e5824b74dd38da8837368b3d75477 100644 (file)
@@ -41,6 +41,7 @@ namespace passes {
 namespace branch_island {
 
 
+static std::map<const Atom*, uint64_t> sAtomToAddress;
 
 
 struct TargetAndOffset { const ld::Atom* atom; uint32_t offset; };
@@ -68,43 +69,27 @@ public:
                                                        ld::Atom::scopeLinkageUnit, ld::Atom::typeBranchIsland, 
                                                        ld::Atom::symbolTableIn, false, false, false, ld::Atom::Alignment(2)), 
                                _name(nm),
-                               _target(target),
-                               _finalTarget(finalTarget) { }
+                               _fixup1(0, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressARMBranch24, target),
+                               _fixup2(0, ld::Fixup::k1of1, ld::Fixup::kindIslandTarget, finalTarget.atom) {
+                                       if (_s_log) fprintf(stderr, "%s: ARM jump instruction branch island to final target %s\n", 
+                                                                               target->name(), finalTarget.atom->name());
+                               }
 
        virtual const ld::File*                                 file() const                                    { return NULL; }
        virtual const char*                                             name() const                                    { return _name; }
        virtual uint64_t                                                size() const                                    { return 4; }
        virtual uint64_t                                                objectAddress() const                   { return 0; }
        virtual void                                                    copyRawContent(uint8_t buffer[]) const {
-               int64_t displacement = _target->finalAddress() - this->finalAddress() - 8;
-               if ( _target->contentType() == ld::Atom::typeBranchIsland ) {
-                       // an ARM branch can branch farther than a thumb branch.  The branch
-                       // island generation was conservative and put islands every thumb
-                       // branch distance apart.  Check to see if this is a an island
-                       // hopping branch that could be optimized to go directly to target.
-                       int64_t skipToFinalDisplacement = _finalTarget.atom->finalAddress() + _finalTarget.offset - this->finalAddress() - 8;
-                       if ( (skipToFinalDisplacement < 33554428LL) && (skipToFinalDisplacement > (-33554432LL)) ) {
-                               // can skip branch island and jump straight to target
-                               if (_s_log) fprintf(stderr, "%s: optimized jump to final target at 0x%08llX, thisAddr=0x%08llX\n", 
-                                                                                       _target->name(), _finalTarget.atom->finalAddress(), this->finalAddress());
-                               displacement = skipToFinalDisplacement;
-                       }
-                       else {
-                               // ultimate target is too far, jump to island
-                               if (_s_log) fprintf(stderr, "%s: jump to branch island at 0x%08llX\n", 
-                                                                                       _target->name(), _finalTarget.atom->finalAddress());
-                       }
-               }
-               uint32_t imm24 = (displacement >> 2) & 0x00FFFFFF;
-               int32_t branchInstruction = 0xEA000000 | imm24;
-               OSWriteLittleInt32(buffer, 0, branchInstruction);
+               OSWriteLittleInt32(buffer, 0, 0xEA000000);
        }
        virtual void                                                    setScope(Scope)                                 { }
+       virtual ld::Fixup::iterator                             fixupsBegin() const                             { return (ld::Fixup*)&_fixup1; }
+       virtual ld::Fixup::iterator                             fixupsEnd()     const                           { return &((ld::Fixup*)&_fixup2)[1]; }
 
 private:
        const char*                                                             _name;
-       const ld::Atom*                                                 _target;
-       TargetAndOffset                                                 _finalTarget;
+       ld::Fixup                                                               _fixup1;
+       ld::Fixup                                                               _fixup2;
 };
 
 
@@ -154,62 +139,68 @@ public:
                                                        ld::Atom::scopeLinkageUnit, ld::Atom::typeBranchIsland, 
                                                        ld::Atom::symbolTableIn, false, true, false, ld::Atom::Alignment(1)), 
                                _name(nm),
-                               _target(target),
-                               _finalTarget(finalTarget) { }
+                               _fixup1(0, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressThumbBranch22, target),
+                               _fixup2(0, ld::Fixup::k1of1, ld::Fixup::kindIslandTarget, finalTarget.atom)             { 
+                                       if (_s_log) fprintf(stderr, "%s: Thumb jump instruction branch island to final target %s\n", 
+                                                                               target->name(), finalTarget.atom->name());
+                                       }
 
        virtual const ld::File*                                 file() const                                    { return NULL; }
        virtual const char*                                             name() const                                    { return _name; }
        virtual uint64_t                                                size() const                                    { return 4; }
        virtual uint64_t                                                objectAddress() const                   { return 0; }
        virtual void                                                    copyRawContent(uint8_t buffer[]) const {
-               int64_t displacement = _target->finalAddress() - this->finalAddress() - 4;
-               if ( _target->contentType() == ld::Atom::typeBranchIsland ) {
-                       // an ARM branch can branch farther than a thumb branch.  The branch
-                       // island generation was conservative and put islands every thumb
-                       // branch distance apart.  Check to see if this is a an island
-                       // hopping branch that could be optimized to go directly to target.
-                       int64_t skipToFinalDisplacement = _finalTarget.atom->finalAddress() + _finalTarget.offset - this->finalAddress() - 4;
-                       if ( (skipToFinalDisplacement < 16777214) && (skipToFinalDisplacement > (-16777216LL)) ) {
-                               // can skip branch island and jump straight to target
-                               if (_s_log) fprintf(stderr, "%s: optimized jump to final target at 0x%08llX, thisAddr=0x%08llX\n", 
-                                                                                       _target->name(), _finalTarget.atom->finalAddress(), this->finalAddress());
-                               displacement = skipToFinalDisplacement;
-                       }
-                       else {
-                               // ultimate target is too far for thumb2 branch, jump to island
-                               if (_s_log) fprintf(stderr, "%s: jump to branch island at 0x%08llX\n", 
-                                                                                       _target->name(), _finalTarget.atom->finalAddress());
-                       }
-               }
-               // The instruction is really two instructions:
-               // The lower 16 bits are the first instruction, which contains the high
-               //   11 bits of the displacement.
-               // The upper 16 bits are the second instruction, which contains the low
-               //   11 bits of the displacement, as well as differentiating bl and blx.
-               uint32_t s = (uint32_t)(displacement >> 24) & 0x1;
-               uint32_t i1 = (uint32_t)(displacement >> 23) & 0x1;
-               uint32_t i2 = (uint32_t)(displacement >> 22) & 0x1;
-               uint32_t imm10 = (uint32_t)(displacement >> 12) & 0x3FF;
-               uint32_t imm11 = (uint32_t)(displacement >> 1) & 0x7FF;
-               uint32_t j1 = (i1 == s);
-               uint32_t j2 = (i2 == s);
-               uint32_t opcode = 0x9000F000;
-               uint32_t nextDisp = (j1 << 13) | (j2 << 11) | imm11;
-               uint32_t firstDisp = (s << 10) | imm10;
-               uint32_t newInstruction = opcode | (nextDisp << 16) | firstDisp;
-               //warning("s=%d, j1=%d, j2=%d, imm10=0x%0X, imm11=0x%0X, opcode=0x%08X, first=0x%04X, next=0x%04X, new=0x%08X, disp=0x%llX for %s to %s\n",
-               //      s, j1, j2, imm10, imm11, opcode, firstDisp, nextDisp, newInstruction, displacement, inAtom->getDisplayName(), ref->getTarget().getDisplayName());
-               OSWriteLittleInt32(buffer, 0, newInstruction);
+               OSWriteLittleInt32(buffer, 0, 0xf0008000);
        }
        virtual void                                                    setScope(Scope)                                 { }
+       virtual ld::Fixup::iterator                             fixupsBegin() const                             { return (ld::Fixup*)&_fixup1; }
+       virtual ld::Fixup::iterator                             fixupsEnd()     const                           { return &((ld::Fixup*)&_fixup2)[1]; }
 
 private:
        const char*                                                             _name;
-       const ld::Atom*                                                 _target;
-       TargetAndOffset                                                 _finalTarget;
+       ld::Fixup                                                               _fixup1;
+       ld::Fixup                                                               _fixup2;
+};
+
+
+
+class Thumb2toThumbBranchAbsoluteIslandAtom : public ld::Atom {
+public:
+                                                                                       Thumb2toThumbBranchAbsoluteIslandAtom(const char* nm, const ld::Section& inSect, TargetAndOffset finalTarget)
+                               : ld::Atom(inSect, ld::Atom::definitionRegular, ld::Atom::combineNever,
+                                                       ld::Atom::scopeLinkageUnit, ld::Atom::typeBranchIsland, 
+                                                       ld::Atom::symbolTableIn, false, true, false, ld::Atom::Alignment(1)), 
+                               _name(nm),
+                               _fixup1(0, ld::Fixup::k1of2, ld::Fixup::kindSetTargetAddress, finalTarget.atom),
+                               _fixup2(0, ld::Fixup::k2of2, ld::Fixup::kindStoreThumbLow16),
+                               _fixup3(4, ld::Fixup::k1of2, ld::Fixup::kindSetTargetAddress, finalTarget.atom),
+                               _fixup4(4, ld::Fixup::k2of2, ld::Fixup::kindStoreThumbHigh16),
+                               _fixup5(0, ld::Fixup::k1of1, ld::Fixup::kindIslandTarget, finalTarget.atom) { } 
+
+       virtual const ld::File*                                 file() const                                    { return NULL; }
+       virtual const char*                                             name() const                                    { return _name; }
+       virtual uint64_t                                                size() const                                    { return 10; }
+       virtual uint64_t                                                objectAddress() const                   { return 0; }
+       virtual void                                                    copyRawContent(uint8_t buffer[]) const {
+               OSWriteLittleInt32(&buffer[0], 0, 0x0c00f240);  //      movw    r12, #0x5678
+               OSWriteLittleInt32(&buffer[4], 0, 0x0c00f2c0);  //      movt    r12, #0x1234
+               OSWriteLittleInt16(&buffer[8], 0, 0x4760);              //      bx              r12
+       }
+       virtual void                                                    setScope(Scope)                                 { }
+       virtual ld::Fixup::iterator                             fixupsBegin() const                             { return (ld::Fixup*)&_fixup1; }
+       virtual ld::Fixup::iterator                             fixupsEnd()     const                           { return &((ld::Fixup*)&_fixup5)[1]; }
+
+private:
+       const char*                                                             _name;
+       ld::Fixup                                                               _fixup1;
+       ld::Fixup                                                               _fixup2;
+       ld::Fixup                                                               _fixup3;
+       ld::Fixup                                                               _fixup4;
+       ld::Fixup                                                               _fixup5;
 };
 
 
+
 class NoPicARMtoThumbMBranchIslandAtom : public ld::Atom {
 public:
                                                                                        NoPicARMtoThumbMBranchIslandAtom(const char* nm, const ld::Atom* target, TargetAndOffset finalTarget)
@@ -245,7 +236,8 @@ private:
 };
 
 
-static ld::Atom* makeBranchIsland(const Options& opts, ld::Fixup::Kind kind, int islandRegion, const ld::Atom* nextTarget, TargetAndOffset finalTarget)
+static ld::Atom* makeBranchIsland(const Options& opts, ld::Fixup::Kind kind, int islandRegion, const ld::Atom* nextTarget, 
+                                                                       TargetAndOffset finalTarget, const ld::Section& inSect, bool crossSectionBranch)
 {
        char* name;
        if ( finalTarget.offset == 0 ) {
@@ -263,7 +255,10 @@ static ld::Atom* makeBranchIsland(const Options& opts, ld::Fixup::Kind kind, int
                case ld::Fixup::kindStoreThumbBranch22:
                case ld::Fixup::kindStoreTargetAddressARMBranch24:
                case ld::Fixup::kindStoreTargetAddressThumbBranch22:
-                       if ( finalTarget.atom->isThumb() ) {
+                       if ( crossSectionBranch && opts.preferSubArchitecture() && opts.archSupportsThumb2() ) {
+                               return new Thumb2toThumbBranchAbsoluteIslandAtom(name, inSect, finalTarget);
+                       }
+                       else if ( finalTarget.atom->isThumb() ) {
                                if ( opts.preferSubArchitecture() && opts.archSupportsThumb2() ) {
                                        return new Thumb2toThumbBranchIslandAtom(name, nextTarget, finalTarget);
                                }
@@ -343,47 +338,51 @@ static uint64_t maxDistanceBetweenIslands(const Options& opts, bool seenThumbBra
 // before any branches could be pushed out of range.
 //
 
-void doPass(const Options& opts, ld::Internal& state)
-{      
-       // only make branch islands in final linked images
-       if ( opts.outputKind() == Options::kObjectFile )
-               return;
 
-       // only ARM needs branch islands
-       switch ( opts.architecture() ) {
-               case CPU_TYPE_ARM:
-                       break;
-               default:
-                       return;
-       }
-       
-       // scan to find __text section
-       ld::Internal::FinalSection* textSection = NULL;
-       for (std::vector<ld::Internal::FinalSection*>::iterator sit=state.sections.begin(); sit != state.sections.end(); ++sit) {
-               ld::Internal::FinalSection* sect = *sit;
-               if ( strcmp(sect->sectionName(), "__text") == 0 )
-                       textSection = sect;
-       }
-       if ( textSection == NULL )
-               return;
-       
+static void makeIslandsForSection(const Options& opts, ld::Internal& state, ld::Internal::FinalSection* textSection)
+{
        // assign section offsets to each atom in __text section, watch for thumb branches, and find total size
-       const bool isARM = (opts.architecture() == CPU_TYPE_ARM);
        bool hasThumbBranches = false;
+       bool haveCrossSectionBranches = false;
+       const bool preload = (opts.outputKind() == Options::kPreload);
        uint64_t offset = 0;
        for (std::vector<const ld::Atom*>::iterator ait=textSection->atoms.begin();  ait != textSection->atoms.end(); ++ait) {
                const ld::Atom* atom = *ait;
-               // check for thumb branches
-               if ( isARM && ~hasThumbBranches ) {
-                       for (ld::Fixup::iterator fit = atom->fixupsBegin(), end=atom->fixupsEnd(); fit != end; ++fit) {
-                               switch ( fit->kind ) {
-                                       case ld::Fixup::kindStoreThumbBranch22:
-                                       case ld::Fixup::kindStoreTargetAddressThumbBranch22:
-                                               hasThumbBranches = true;
-                                               break;
-                                       default:
-                                               break;
-                               }
+               // check for thumb branches and cross section branches
+               const ld::Atom* target = NULL;
+               for (ld::Fixup::iterator fit = atom->fixupsBegin(), end=atom->fixupsEnd(); fit != end; ++fit) {
+                       if ( fit->firstInCluster() ) {
+                               target = NULL;
+                       }
+                       switch ( fit->binding ) {
+                               case ld::Fixup::bindingNone:
+                               case ld::Fixup::bindingByNameUnbound:
+                                       break;
+                               case ld::Fixup::bindingByContentBound:
+                               case ld::Fixup::bindingDirectlyBound:
+                                       target = fit->u.target;
+                                       break;
+                               case ld::Fixup::bindingsIndirectlyBound:
+                                       target = state.indirectBindingTable[fit->u.bindingIndex];
+                                       break;
+                       }
+                       bool haveBranch = false;
+                       switch (fit->kind) {
+                               case ld::Fixup::kindStoreThumbBranch22:
+                               case ld::Fixup::kindStoreTargetAddressThumbBranch22:
+                                       hasThumbBranches = true;
+                                       // fall into arm branch case
+                               case ld::Fixup::kindStoreARMBranch24:
+                               case ld::Fixup::kindStoreTargetAddressARMBranch24:
+                                       haveBranch = true;
+                                       break;
+                default:
+                    break;   
+                       }
+                       if ( haveBranch && (target->contentType() != ld::Atom::typeStub) ) {
+                               // <rdar://problem/14792124> haveCrossSectionBranches only applies to -preload builds
+                               if ( preload && (atom->section() != target->section()) )
+                                       haveCrossSectionBranches = true;
                        }
                }
                // align atom
@@ -400,9 +399,9 @@ void doPass(const Options& opts, ld::Internal& state)
                offset += atom->size();
        }
        uint64_t totalTextSize = offset;
-       if ( totalTextSize < textSizeWhenMightNeedBranchIslands(opts, hasThumbBranches) )
+       if ( (totalTextSize < textSizeWhenMightNeedBranchIslands(opts, hasThumbBranches)) && !haveCrossSectionBranches )
                return;
-       if (_s_log) fprintf(stderr, "ld:  __text section size=%llu, might need branch islands\n", totalTextSize);
+       if (_s_log) fprintf(stderr, "ld: section %s size=%llu, might need branch islands\n", textSection->sectionName(), totalTextSize);
        
        // Figure out how many regions of branch islands will be needed, and their locations.
        // Construct a vector containing the atoms after which branch islands will be inserted,
@@ -410,12 +409,12 @@ void doPass(const Options& opts, ld::Internal& state)
        const uint64_t kBetweenRegions = maxDistanceBetweenIslands(opts, hasThumbBranches); // place regions of islands every 14MB in __text section
        std::vector<const ld::Atom*> branchIslandInsertionPoints; // atoms in the atom list after which branch islands will be inserted
        uint64_t previousIslandEndAddr = 0;
-       const ld::Atom *insertionPoint;
+       const ld::Atom *insertionPoint = NULL;
        branchIslandInsertionPoints.reserve(totalTextSize/kBetweenRegions*2);
        for (std::vector<const ld::Atom*>::iterator it=textSection->atoms.begin(); it != textSection->atoms.end(); it++) {
                const ld::Atom* atom = *it;
                // if we move past the next atom, will the run length exceed kBetweenRegions?
-               if ( atom->sectionOffset() + atom->size() - previousIslandEndAddr > kBetweenRegions ) {
+               if ( atom->sectionOffset() + atom->size() > previousIslandEndAddr + kBetweenRegions ) {
                        // yes. Add the last known good location (atom) for inserting a branch island.
                        if ( insertionPoint == NULL )
                                throwf("Unable to insert branch island. No insertion point available.");
@@ -427,28 +426,24 @@ void doPass(const Options& opts, ld::Internal& state)
                if ( !atom->hasFixupsOfKind(ld::Fixup::kindNoneFollowOn) )
                        insertionPoint = atom;
        }
-       // add one more island after the last atom
-       if (insertionPoint != NULL)
+       // add one more island after the last atom if close to limit
+       if ( (insertionPoint != NULL) && (insertionPoint->sectionOffset() + insertionPoint->size() > previousIslandEndAddr + (kBetweenRegions-0x100000)) )
                branchIslandInsertionPoints.push_back(insertionPoint);
-       const int kIslandRegionsCount = branchIslandInsertionPoints.size();
-       if (_s_log) {
-               fprintf(stderr, "ld: will use %u branch island regions\n", kIslandRegionsCount);
-               for (std::vector<const ld::Atom*>::iterator it = branchIslandInsertionPoints.begin(); it != branchIslandInsertionPoints.end(); ++it) {
-                       const ld::Atom* atom = *it;
-                       const ld::File *file = atom->file();
-                       fprintf(stderr, "ld: branch island will be inserted at 0x%llx after %s", atom->sectionOffset()+atom->size(), atom->name());
-                       if (file) fprintf(stderr, " (%s)", atom->file()->path());
-                       fprintf(stderr, "\n");
-               }
+       if ( haveCrossSectionBranches && branchIslandInsertionPoints.empty() ) {
+               branchIslandInsertionPoints.push_back(textSection->atoms.back());
        }
+       const int kIslandRegionsCount = branchIslandInsertionPoints.size();
 
-
+       if (_s_log) fprintf(stderr, "ld: will use %u branch island regions\n", kIslandRegionsCount);
        typedef std::map<TargetAndOffset,const ld::Atom*, TargetAndOffsetComparor> AtomToIsland;
     AtomToIsland* regionsMap[kIslandRegionsCount];
+       uint64_t regionAddresses[kIslandRegionsCount];
        std::vector<const ld::Atom*>* regionsIslands[kIslandRegionsCount];
        for(int i=0; i < kIslandRegionsCount; ++i) {
                regionsMap[i] = new AtomToIsland();
                regionsIslands[i] = new std::vector<const ld::Atom*>();
+               regionAddresses[i] = branchIslandInsertionPoints[i]->sectionOffset() + branchIslandInsertionPoints[i]->size();
+               if (_s_log) fprintf(stderr, "ld: branch islands will be inserted at 0x%08llX after %s\n", regionAddresses[i], branchIslandInsertionPoints[i]->name());
        }
        unsigned int islandCount = 0;
        
@@ -493,25 +488,51 @@ void doPass(const Options& opts, ld::Internal& state)
                     break;   
                        }
                        if ( haveBranch ) {
+                               bool crossSectionBranch = ( preload && (atom->section() != target->section()) );
                                int64_t srcAddr = atom->sectionOffset() + fit->offsetInAtom;
                                int64_t dstAddr = target->sectionOffset() + addend;
+                               if ( preload ) {
+                                       srcAddr = sAtomToAddress[atom] + fit->offsetInAtom;
+                                       dstAddr = sAtomToAddress[target] + addend;
+                               }
                                if ( target->section().type() == ld::Section::typeStub )
                                        dstAddr = totalTextSize;
                                int64_t displacement = dstAddr - srcAddr;
                                TargetAndOffset finalTargetAndOffset = { target, addend };
                                const int64_t kBranchLimit = kBetweenRegions;
-                               if ( displacement > kBranchLimit ) {
+                               if ( crossSectionBranch && ((displacement > kBranchLimit) || (displacement < (-kBranchLimit))) ) {
+                                       const ld::Atom* island;
+                                       AtomToIsland* region = regionsMap[0];
+                                       AtomToIsland::iterator pos = region->find(finalTargetAndOffset);
+                                       if ( pos == region->end() ) {
+                                               island = makeBranchIsland(opts, fit->kind, 0, target, finalTargetAndOffset, atom->section(), true);
+                                               (*region)[finalTargetAndOffset] = island;
+                                               if (_s_log) fprintf(stderr, "added absolute branching island %p %s, displacement=%lld\n", 
+                                                                                               island, island->name(), displacement);
+                                               ++islandCount;
+                                               regionsIslands[0]->push_back(island);
+                                       }
+                                       else {
+                                               island = pos->second;
+                                       }
+                                       if (_s_log) fprintf(stderr, "using island %p %s for branch to %s from %s\n", island, island->name(), target->name(), atom->name());
+                                       fixupWithTarget->u.target = island;
+                                       fixupWithTarget->binding = ld::Fixup::bindingDirectlyBound;
+                               }
+                               else if ( displacement > kBranchLimit ) {
                                        // create forward branch chain
                                        const ld::Atom* nextTarget = target;
+                                       if (_s_log) fprintf(stderr, "need forward branching island srcAdr=0x%08llX, dstAdr=0x%08llX, target=%s\n",
+                                                                                                               srcAddr, dstAddr, target->name());
                                        for (int i=kIslandRegionsCount-1; i >=0 ; --i) {
                                                AtomToIsland* region = regionsMap[i];
-                                               int64_t islandRegionAddr = kBetweenRegions * (i+1);
-                                               if ( (srcAddr < islandRegionAddr) && (islandRegionAddr <= dstAddr) ) { 
+                                               int64_t islandRegionAddr = regionAddresses[i];
+                                               if ( (srcAddr < islandRegionAddr) && ((islandRegionAddr <= dstAddr)) ) { 
                                                        AtomToIsland::iterator pos = region->find(finalTargetAndOffset);
                                                        if ( pos == region->end() ) {
-                                                               ld::Atom* island = makeBranchIsland(opts, fit->kind, i, nextTarget, finalTargetAndOffset);
+                                                               ld::Atom* island = makeBranchIsland(opts, fit->kind, i, nextTarget, finalTargetAndOffset, atom->section(), false);
                                                                (*region)[finalTargetAndOffset] = island;
-                                                               if (_s_log) fprintf(stderr, "added island %s to region %d for %s\n", island->name(), i, atom->name());
+                                                               if (_s_log) fprintf(stderr, "added forward branching island %p %s to region %d for %s\n", island, island->name(), i, atom->name());
                                                                regionsIslands[i]->push_back(island);
                                                                ++islandCount;
                                                                nextTarget = island;
@@ -521,7 +542,7 @@ void doPass(const Options& opts, ld::Internal& state)
                                                        }
                                                }
                                        }
-                                       if (_s_log) fprintf(stderr, "using island %s for branch to %s from %s\n", nextTarget->name(), target->name(), atom->name());
+                                       if (_s_log) fprintf(stderr, "using island %p %s for branch to %s from %s\n", nextTarget, nextTarget->name(), target->name(), atom->name());
                                        fixupWithTarget->u.target = nextTarget;
                                        fixupWithTarget->binding = ld::Fixup::bindingDirectlyBound;
                                }
@@ -530,13 +551,14 @@ void doPass(const Options& opts, ld::Internal& state)
                                        const ld::Atom* prevTarget = target;
                                        for (int i=0; i < kIslandRegionsCount ; ++i) {
                                                AtomToIsland* region = regionsMap[i];
-                                               int64_t islandRegionAddr = kBetweenRegions * (i+1);
-                                               if ( (dstAddr <= islandRegionAddr) && (islandRegionAddr < srcAddr) ) {
+                                               int64_t islandRegionAddr = regionAddresses[i];
+                                               if ( (dstAddr < islandRegionAddr) && (islandRegionAddr <= srcAddr) ) {
+                                                       if (_s_log) fprintf(stderr, "need backward branching island srcAdr=0x%08llX, dstAdr=0x%08llX, target=%s\n", srcAddr, dstAddr, target->name());
                                                        AtomToIsland::iterator pos = region->find(finalTargetAndOffset);
                                                        if ( pos == region->end() ) {
-                                                               ld::Atom* island = makeBranchIsland(opts, fit->kind, i, prevTarget, finalTargetAndOffset);
+                                                               ld::Atom* island = makeBranchIsland(opts, fit->kind, i, prevTarget, finalTargetAndOffset, atom->section(), false);
                                                                (*region)[finalTargetAndOffset] = island;
-                                                               if (_s_log) fprintf(stderr, "added back island %s to region %d for %s\n", island->name(), i, atom->name());
+                                                               if (_s_log) fprintf(stderr, "added back branching island %p %s to region %d for %s\n", island, island->name(), i, atom->name());
                                                                regionsIslands[i]->push_back(island);
                                                                ++islandCount;
                                                                prevTarget = island;
@@ -546,7 +568,7 @@ void doPass(const Options& opts, ld::Internal& state)
                                                        }
                                                }
                                        }
-                                       if (_s_log) fprintf(stderr, "using back island %s for %s\n", prevTarget->name(), atom->name());
+                                       if (_s_log) fprintf(stderr, "using back island %p %s for %s\n", prevTarget, prevTarget->name(), atom->name());
                                        fixupWithTarget->u.target = prevTarget;
                                        fixupWithTarget->binding = ld::Fixup::bindingDirectlyBound;
                                }
@@ -561,24 +583,15 @@ void doPass(const Options& opts, ld::Internal& state)
                std::vector<const ld::Atom*> newAtomList;
                newAtomList.reserve(textSection->atoms.size()+islandCount);
                
-               uint64_t regionIndex = 0;
+               int regionIndex = 0;
                for (std::vector<const ld::Atom*>::iterator ait=textSection->atoms.begin(); ait != textSection->atoms.end(); ait++) {
-                       newAtomList.push_back(*ait);
-                       // copy over atoms until we find an island insertion point
-                       // Note that the last insertion point is the last atom, so this loop never moves the iterator to atoms.end().
-                       while (*ait != branchIslandInsertionPoints[regionIndex]) {
-                               ait++;
-                               newAtomList.push_back(*ait);
+                       const ld::Atom* atom = *ait;
+                       newAtomList.push_back(atom);
+                       if ( (regionIndex < kIslandRegionsCount) && (atom == branchIslandInsertionPoints[regionIndex]) ) {
+                               std::vector<const ld::Atom*>* islands = regionsIslands[regionIndex];
+                               newAtomList.insert(newAtomList.end(), islands->begin(), islands->end());
+                               ++regionIndex;
                        }
-                       
-                       // insert the branch island atoms after the insertion point atom
-                       std::vector<const ld::Atom*>* regionIslands = regionsIslands[regionIndex];
-                       for (std::vector<const ld::Atom*>::iterator rit=regionIslands->begin(); rit != regionIslands->end(); rit++) {
-                               const ld::Atom* islandAtom = *rit;
-                               newAtomList.push_back(islandAtom);
-                               if ( _s_log ) fprintf(stderr, "inserting island %s into __text section\n", islandAtom->name());
-                       }
-                       regionIndex++;
                }
                // swap in new list of atoms for __text section
                textSection->atoms.clear();
@@ -588,6 +601,77 @@ void doPass(const Options& opts, ld::Internal& state)
 }
 
 
+static void buildAddressMap(const Options& opts, ld::Internal& state) {
+       // Assign addresses to sections
+       state.setSectionSizesAndAlignments();
+       state.assignFileOffsets();
+       
+       // Assign addresses to atoms in a side table
+       const bool log = false;
+       if ( log ) fprintf(stderr, "buildAddressMap()\n");
+       for (std::vector<ld::Internal::FinalSection*>::iterator sit = state.sections.begin(); sit != state.sections.end(); ++sit) {
+               ld::Internal::FinalSection* sect = *sit;
+               uint16_t maxAlignment = 0;
+               uint64_t offset = 0;
+               if ( log ) fprintf(stderr, "  section=%s/%s, address=0x%08llX\n", sect->segmentName(), sect->sectionName(), sect->address);
+               for (std::vector<const ld::Atom*>::iterator ait = sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
+                       const ld::Atom* atom = *ait;
+                       uint32_t atomAlignmentPowerOf2 = atom->alignment().powerOf2;
+                       uint32_t atomModulus = atom->alignment().modulus;
+                       if ( atomAlignmentPowerOf2 > maxAlignment )
+                               maxAlignment = atomAlignmentPowerOf2;
+                       // calculate section offset for this atom
+                       uint64_t alignment = 1 << atomAlignmentPowerOf2;
+                       uint64_t currentModulus = (offset % alignment);
+                       uint64_t requiredModulus = atomModulus;
+                       if ( currentModulus != requiredModulus ) {
+                               if ( requiredModulus > currentModulus )
+                                       offset += requiredModulus-currentModulus;
+                               else
+                                       offset += requiredModulus+alignment-currentModulus;
+                       }
+                       
+                       if ( log ) fprintf(stderr, "    0x%08llX atom=%p, name=%s\n", sect->address+offset, atom, atom->name());
+                       sAtomToAddress[atom] = sect->address + offset;
+                       
+                       offset += atom->size();
+               }
+       }
+
+       
+}
+
+void doPass(const Options& opts, ld::Internal& state)
+{      
+       // only make branch islands in final linked images
+       if ( opts.outputKind() == Options::kObjectFile )
+               return;
+       
+       // Allow user to disable branch island generation
+       if ( !opts.allowBranchIslands() )
+               return;
+       
+       // only ARM needs branch islands
+       switch ( opts.architecture() ) {
+               case CPU_TYPE_ARM:
+                       break;
+               default:
+                       return;
+       }
+       
+       if ( opts.outputKind() == Options::kPreload ) {
+               buildAddressMap(opts, state);
+       }
+       
+       // scan sections and add island to each code section
+       for (std::vector<ld::Internal::FinalSection*>::iterator sit=state.sections.begin(); sit != state.sections.end(); ++sit) {
+               ld::Internal::FinalSection* sect = *sit;
+               if ( sect->type() == ld::Section::typeCode ) 
+                       makeIslandsForSection(opts, state, sect);
+       }
+}
+
+
 } // namespace branch_island
 } // namespace passes 
 } // namespace ld 
index 8b4a6bf190794a665fb991955e35fc6e8a6c40c3..ad8a504fde004a7f5d7764ec97fcd542d4d7259e 100644 (file)
@@ -159,7 +159,7 @@ UnwindInfoAtom<A>::UnwindInfoAtom(const std::vector<UnwindEntry>& entries, uint6
        // 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);
-       const unsigned int pageCount = ((uniqueEntries.size() - 1)/entriesPerRegularPage) + 1;
+       const unsigned int pageCount = ((uniqueEntries.size() - 1)/entriesPerRegularPage) + 2;
        _pagesForDelete = (uint8_t*)calloc(pageCount,4096);
        if ( _pagesForDelete == NULL ) {
                warning("could not allocate space for compact unwind info");
@@ -186,7 +186,11 @@ UnwindInfoAtom<A>::UnwindInfoAtom(const std::vector<UnwindEntry>& entries, uint6
                secondLevelPagesStarts[secondLevelPageCount] = pageEnd;
                secondLevelFirstFuncs[secondLevelPageCount] = uniqueEntries[endIndex].func;
                ++secondLevelPageCount;
-               pageSize = 4096;  // last page can be odd size, make rest up to 4096 bytes in size
+               // if this requires more than one page, align so that next starts on page boundary
+               if ( (pageSize != 4096) && (endIndex > 0) ) {
+                       pageEnd = (uint8_t*)((uintptr_t)(pageEnd) & -4096);
+                       pageSize = 4096;  // last page can be odd size, make rest up to 4096 bytes in size
+               }
        }
        _pages = pageEnd;
        _pagesSize = &_pagesForDelete[pageCount*4096] - pageEnd;
index af73d66ecb4860f444964dd772704ee482bba465..684cb795d17519a1ff95e23fcbebbfae92f607bc 100644 (file)
@@ -531,22 +531,32 @@ void Layout::buildOrdinalOverrideMap()
                warning("only %u out of %lu order_file symbols were applicable", matchCount, _options.orderedSymbolsCount() );
        }
 
-
        // <rdar://problem/8612550> When order file used on data, turn ordered zero fill symbols into zeroed data
        if ( ! moveToData.empty() ) {
+               // <rdar://problem/14919139> only move zero fill symbols to __data if there is a __data section
+               ld::Internal::FinalSection* dataSect = NULL;
                for (std::vector<ld::Internal::FinalSection*>::iterator sit=_state.sections.begin(); sit != _state.sections.end(); ++sit) {
                        ld::Internal::FinalSection* sect = *sit;
-                       switch ( sect->type() ) {
-                               case ld::Section::typeZeroFill:
-                               case ld::Section::typeTentativeDefs:
-                                       sect->atoms.erase(std::remove_if(sect->atoms.begin(), sect->atoms.end(), InSet(moveToData)), sect->atoms.end());
-                                       break;
-                               case ld::Section::typeUnclassified:
-                                       if ( (strcmp(sect->sectionName(), "__data") == 0) && (strcmp(sect->segmentName(), "__DATA") == 0) )
-                                               sect->atoms.insert(sect->atoms.end(), moveToData.begin(), moveToData.end());
-                                       break;
-                               default:
-                                       break;
+                       if ( sect->type() == ld::Section::typeUnclassified ) {
+                               if ( (strcmp(sect->sectionName(), "__data") == 0) && (strcmp(sect->segmentName(), "__DATA") == 0) )
+                                       dataSect = sect;
+                       }
+               }
+
+               if ( dataSect != NULL ) {
+                       // add atoms to __data
+                       dataSect->atoms.insert(dataSect->atoms.end(), moveToData.begin(), moveToData.end());
+                       // remove atoms from original sections
+                       for (std::vector<ld::Internal::FinalSection*>::iterator sit=_state.sections.begin(); sit != _state.sections.end(); ++sit) {
+                               ld::Internal::FinalSection* sect = *sit;
+                               switch ( sect->type() ) {
+                                       case ld::Section::typeZeroFill:
+                                       case ld::Section::typeTentativeDefs:
+                                               sect->atoms.erase(std::remove_if(sect->atoms.begin(), sect->atoms.end(), InSet(moveToData)), sect->atoms.end());
+                                               break;
+                                       default:
+                                               break;
+                               }
                        }
                }
        }
index cb1ceb33cb51d516bcb00c218df9ef82f02e2a22..63382e58fa9022c6e7ad53e7839da1135e6ff67a 100644 (file)
@@ -95,7 +95,9 @@ public:
                                _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)) 
+                               _fixup4(16, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressARM64PageOff12, compressedFastBinder(pass)), 
+                               _fixup5(ld::Fixup::kindLinkerOptimizationHint, LOH_ARM64_ADRP_ADD, 0, 4), 
+                               _fixup6(ld::Fixup::kindLinkerOptimizationHint, LOH_ARM64_ADRP_LDR, 12, 16) 
                                        { pass.addAtom(*this); }
 
        virtual ld::File*                                               file() const                                    { return NULL; }
@@ -112,7 +114,7 @@ public:
        }
        virtual void                                                    setScope(Scope)                                 { }
        virtual ld::Fixup::iterator                             fixupsBegin() const                             { return &_fixup1; }
-       virtual ld::Fixup::iterator                             fixupsEnd()     const                           { return &((ld::Fixup*)&_fixup4)[1]; }
+       virtual ld::Fixup::iterator                             fixupsEnd()     const                           { return &((ld::Fixup*)&_fixup6)[1]; }
 
 private:
        static ld::Atom* compressedImageCache(ld::passes::stubs::Pass& pass) {
@@ -130,6 +132,8 @@ private:
        ld::Fixup                                                               _fixup2;
        ld::Fixup                                                               _fixup3;
        ld::Fixup                                                               _fixup4;
+       ld::Fixup                                                               _fixup5;
+       ld::Fixup                                                               _fixup6;
        
        static ld::Section                                              _s_section;
 };
@@ -287,8 +291,9 @@ public:
                                _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); }
+                               _fixup2(4, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressARM64PageOff12, &_lazyPointer),
+                               _fixup3(ld::Fixup::kindLinkerOptimizationHint, LOH_ARM64_ADRP_LDR, 0, 4) 
+                                       { pass.addAtom(*this);  }
 
        virtual const ld::File*                                 file() const                                    { return _stubTo.file(); }
        virtual const char*                                             name() const                                    { return _stubTo.name(); }
@@ -301,13 +306,14 @@ public:
        }
        virtual void                                                    setScope(Scope)                                 { }
        virtual ld::Fixup::iterator                             fixupsBegin() const                             { return &_fixup1; }
-       virtual ld::Fixup::iterator                             fixupsEnd()     const                           { return &((ld::Fixup*)&_fixup2)[1]; }
+       virtual ld::Fixup::iterator                             fixupsEnd()     const                           { return &((ld::Fixup*)&_fixup3)[1]; }
 
 private:
        const ld::Atom&                                                 _stubTo;
        LazyPointerAtom                                                 _lazyPointer;
        mutable ld::Fixup                                               _fixup1;
        mutable ld::Fixup                                               _fixup2;
+       mutable ld::Fixup                                               _fixup3;
        
        static ld::Section                                              _s_section;
 };
index 6a58fdf1cec5213492b08f97c721497c2552a89d..e84fc25b8f710c09db737cdc517a13339a6607ed 100644 (file)
@@ -142,6 +142,10 @@ void doPass(const Options& opts, ld::Internal& internal)
                                        case ld::Fixup::kindStoreTargetAddressX86Abs32TLVLoad:
                                        case ld::Fixup::kindStoreX86PCRel32TLVLoad:
                                        case ld::Fixup::kindStoreX86Abs32TLVLoad:
+#if SUPPORT_ARCH_arm64
+                                       case ld::Fixup::kindStoreTargetAddressARM64TLVPLoadPage21:
+                                       case ld::Fixup::kindStoreTargetAddressARM64TLVPLoadPageOff12:
+#endif
                                                ref.fixupWithTLVStore = fit;
                                                break;
                                        default:
@@ -230,6 +234,14 @@ void doPass(const Options& opts, ld::Internal& internal)
                                case ld::Fixup::kindStoreX86Abs32TLVLoad:
                                        it->fixupWithTLVStore->kind = ld::Fixup::kindStoreX86Abs32TLVLoadNowLEA;
                                        break;
+#if SUPPORT_ARCH_arm64
+                               case ld::Fixup::kindStoreTargetAddressARM64TLVPLoadPage21:
+                                       it->fixupWithTLVStore->kind = ld::Fixup::kindStoreARM64TLVPLoadNowLeaPage21;
+                                       break;
+                               case ld::Fixup::kindStoreTargetAddressARM64TLVPLoadPageOff12:
+                                       it->fixupWithTLVStore->kind = ld::Fixup::kindStoreTargetAddressARM64TLVPLoadNowLeaPageOff12;
+                                       break;
+#endif
                                default:
                                        assert(0 && "bad store kind for TLV optimization");
                        }
index 36fcce9f9f312c54ff67922c478845642f455411..c9eb46c4774fcbb8a8148d31e0b6a4843621e6a8 100644 (file)
@@ -870,6 +870,9 @@ void dumper::dumpFixup(const ld::Fixup* ref)
                case ld::Fixup::kindSetLazyOffset:
                        printf("offset of lazy binding info for %s", referenceTargetAtomName(ref));
                        break;
+               case ld::Fixup::kindIslandTarget:
+                       printf("ultimate target of island %s", referenceTargetAtomName(ref));
+                       break;
                case ld::Fixup::kindDataInCodeStartData:
                        printf("start of data in code");
                        break;
@@ -888,6 +891,46 @@ void dumper::dumpFixup(const ld::Fixup* ref)
                case ld::Fixup::kindDataInCodeEnd:
                        printf("end of data in code");
                        break;
+               case ld::Fixup::kindLinkerOptimizationHint:
+#if SUPPORT_ARCH_arm64
+                       ld::Fixup::LOH_arm64 extra;
+                       extra.addend = ref->u.addend;
+                       printf("ARM64 hint: ");
+                       switch(extra.info.kind) {
+                               case LOH_ARM64_ADRP_ADRP:
+                                       printf("ADRP-ADRP");
+                                       break;
+                               case LOH_ARM64_ADRP_LDR:
+                                       printf("ADRP-LDR");
+                                       break;
+                               case LOH_ARM64_ADRP_ADD_LDR:
+                                       printf("ADRP-ADD-LDR");
+                                       break;
+                               case LOH_ARM64_ADRP_LDR_GOT_LDR:
+                                       printf("ADRP-LDR-GOT-LDR");
+                                       break;
+                               case LOH_ARM64_ADRP_ADD_STR:
+                                       printf("ADRP-ADD-STR");
+                                       break;
+                               case LOH_ARM64_ADRP_LDR_GOT_STR:
+                                       printf("ADRP-LDR-GOT-STR");
+                                       break;
+                               case LOH_ARM64_ADRP_ADD:
+                                       printf("ADRP-ADD");
+                                       break;
+                               default:
+                                       printf("kind=%d", extra.info.kind);
+                                       break;
+                       }
+                       printf(", offset1=0x%X", (extra.info.delta1 << 2)  + ref->offsetInAtom);
+                       if ( extra.info.count > 0 )
+                               printf(", offset2=0x%X", (extra.info.delta2 << 2) + ref->offsetInAtom);
+                       if ( extra.info.count > 1 )
+                               printf(", offset3=0x%X", (extra.info.delta3 << 2)  + ref->offsetInAtom);
+                       if ( extra.info.count > 2 )
+                               printf(", offset4=0x%X", (extra.info.delta4 << 2)  + ref->offsetInAtom);
+#endif                 
+                       break;
                case ld::Fixup::kindStoreTargetAddressLittleEndian32:
                        printf("store 32-bit little endian address of %s", referenceTargetAtomName(ref));
                        break;
@@ -947,6 +990,12 @@ void dumper::dumpFixup(const ld::Fixup* ref)
                case ld::Fixup::kindStoreTargetAddressARM64PageOff12:
                        printf("ARM64 store 12-bit page offset of %s", referenceTargetAtomName(ref));
                        break;
+               case ld::Fixup::kindStoreTargetAddressARM64TLVPage21:
+                       printf("ARM64 store 21-bit pcrel ADRP to TLV for %s", referenceTargetAtomName(ref));
+                       break;
+               case ld::Fixup::kindStoreTargetAddressARM64TLVPageOff12:
+                       printf("ARM64 store 12-bit page offset of TLV of %s", referenceTargetAtomName(ref));
+                       break;
                case ld::Fixup::kindStoreTargetAddressARM64GOTLoadPage21:
                        printf("ARM64 store 21-bit pcrel ADRP to GOT for %s", referenceTargetAtomName(ref));
                        break;
@@ -1180,6 +1229,7 @@ static ld::relocatable::File* createReader(const char* path)
        objOpts.warnUnwindConversionProblems    = true;
        objOpts.keepDwarfUnwind         = false;
        objOpts.forceDwarfConversion = false;
+       objOpts.verboseOptimizationHints = true;
        objOpts.subType                         = sPreferredSubArch;
 #if 1
        if ( ! foundFatSlice ) {
@@ -1196,7 +1246,7 @@ static ld::relocatable::File* createReader(const char* path)
                return objResult;
 
        // see if it is an llvm object file
-       objResult = lto::parse(p, fileLen, path, stat_buf.st_mtime, ld::File::Ordinal::NullOrdinal(), sPreferredArch, sPreferredSubArch, false);
+       objResult = lto::parse(p, fileLen, path, stat_buf.st_mtime, ld::File::Ordinal::NullOrdinal(), sPreferredArch, sPreferredSubArch, false, true);
        if ( objResult != NULL ) 
                return objResult;
 
index e47d482ad799b78713c904d3530e3b79fa43cb3e..766ae947696e5264b923e259b4e32d801dc6a43b 100644 (file)
@@ -98,16 +98,3 @@ 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 b43ff3fc73a71b957a0490bdc9e5b6aa115563f8..6ac33119a0240262fce67521747a6fca0b06d3b0 100644 (file)
@@ -1339,7 +1339,7 @@ void DyldInfoPrinter<A>::processExportGraphNode(const uint8_t* const start, cons
                                                                                        char* cummulativeString, int curStrOffset) 
 {
        const uint8_t* const me = p;
-       const uint8_t terminalSize = read_uleb128(p, end);
+       const uint64_t terminalSize = read_uleb128(p, end);
        const uint8_t* children = p + terminalSize;
        if ( terminalSize != 0 ) {
                uint32_t flags = read_uleb128(p, end);
index fdb62126dbe893a6deef7719d4b80648c0cfebed..3f4647d9b0d491556b750a5e64495fa0316c8f6e 100644 (file)
@@ -13,7 +13,7 @@ MYDIR=$(shell cd ../../bin;pwd)
 LD                     = ld
 OBJECTDUMP     = ObjectDump
 MACHOCHECK     = machocheck
-OTOOL          = otool
+OTOOL =   /Applications/Xcode.app/Contents/Developer/Toolchains/iOS7.0.xctoolchain/usr/bin/otool
 REBASE         = rebase
 DYLDINFO       = dyldinfo
 
@@ -65,7 +65,7 @@ LD_NEW_LINKEDIT = -macosx_version_min 10.6
 CXX              = $(shell xcrun -find clang++) -arch ${ARCH} ${SDKExtra}
 CXXFLAGS = -Wall -stdlib=libc++ 
 
-IOS_SDK = $(shell xcodebuild -sdk iphoneos7.0.internal -version Path)
+IOS_SDK = $(shell xcodebuild -sdk iphoneos7.0.internal -version Path  2>/dev/null)
 
 ifeq ($(ARCH),armv6)
   LDFLAGS := -syslibroot $(IOS_SDK)
@@ -127,12 +127,16 @@ 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)
+  CC = /Applications/Xcode.app/Contents/Developer/Toolchains/iOS7.1.xctoolchain/usr/bin/clang -arch ${ARCH} -ccc-install-dir ${LD_PATH} -miphoneos-version-min=7.0 -isysroot $(IOS_SDK)
+  #CC = $(shell xcrun --sdk iphoneos.internal -find clang) -arch ${ARCH} -ccc-install-dir ${LD_PATH} -miphoneos-version-min=7.0 -isysroot $(IOS_SDK)
+  #CC =  /Applications/Xcode.app/Contents/Developer/Toolchains/iOS7.0.xctoolchain/usr/bin/clang-loh -arch ${ARCH} -ccc-install-dir ${LD_PATH} -miphoneos-version-min=7.0 -isysroot $(IOS_SDK)
   CXX = $(shell xcrun --sdk iphoneos.internal -find clang++) -arch ${ARCH} -ccc-install-dir ${LD_PATH} -miphoneos-version-min=7.0 -isysroot $(IOS_SDK)
   VERSION_NEW_LINKEDIT = -miphoneos-version-min=7.0
   VERSION_OLD_LINKEDIT = -miphoneos-version-min=3.0
   LD_SYSROOT = -syslibroot $(IOS_SDK)
   LD_NEW_LINKEDIT = -ios_version_min 7.0
+  OTOOL =   /Applications/Xcode.app/Contents/Developer/Toolchains/iOS7.1.xctoolchain/usr/bin/otool
+  #OTOOL =  $(shell xcrun --sdk iphoneos.internal -find otool)
 else
   FILEARCH = $(ARCH)
 endif
index 8e1870b7c1575c740fdb8cc1d2797f0c4c36f504..9d30491088b4bdbb76e2cff2377688770e624428 100644 (file)
@@ -33,9 +33,9 @@ run: all
 
 all:
        # Verify that we fail if there is no valid place to insert branch islands.
-       ${CC} ${CCFLAGS} hello.c atomic_space.s extra.c -o hello ${ARCH_FLAGS} 2>&1 | grep "Unable to insert branch island. No insertion point available." | ${PASS_IFF_STDIN}
+       #${CC} ${CCFLAGS} hello.c atomic_space.s extra.c -o hello ${ARCH_FLAGS} 2>&1 | grep "Unable to insert branch island. No insertion point available." | ${PASS_IFF_STDIN}
 
-       ${CC} ${CCFLAGS} hello.c space.s extra.c -o hello ${ARCH_FLAGS}
+       ${CC} ${CCFLAGS} hello.c space.s extra.c -Os -o hello ${ARCH_FLAGS}
        ${PASS_IFF_GOOD_MACHO} hello
 
 
index a1991fe9f4930dd4856e4a239ad4bcaf6690196f..3f433922164243a015cb9899b2ff8cdf3679c48d 100644 (file)
@@ -1,8 +1,10 @@
 #include <stdio.h>
 
+extern void back();
 
 void foo()
 {
        fprintf(stdout, "foo\n");
+  back();
 }
 
index 3037663f2113bc1e9886919432cd900792f43dcb..0738f0e859e55d97b39f4b16660ca9558e346839 100644 (file)
@@ -5,7 +5,10 @@ extern void foo();
 int main()
 {
        fprintf(stdout, "hello\n");
-    foo();
+  foo();
        return 0;
 }
 
+void back()
+{
+}
\ No newline at end of file
index 0218beae2370b6fe5aa302617e261587ae4378dc..a15a2c2bd87323fa38b5b3824a75f2fb87a7d8e5 100644 (file)
@@ -35,11 +35,11 @@ _prejunk:
 #if __thumb2__
        // thumb2 branches are +/- 16MB
 _space1:
-    .space 14*1024*1024
+    .space 13*1024*1024
 _space2:
-    .space 14*1024*1024
+    .space 13*1024*1024
 _space3:
-    .space 14*1024*1024
+    .space 13*1024*1024
 
 
 #elif __thumb__
diff --git a/unit-tests/test-cases/branch-long/Makefile b/unit-tests/test-cases/branch-long/Makefile
new file mode 100644 (file)
index 0000000..9b41703
--- /dev/null
@@ -0,0 +1,59 @@
+##
+# 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 thumb2 branch ranges
+#
+
+run: all
+
+all:   all-${ARCH}
+
+all-i386:
+       ${PASS_IFF} true
+
+all-x86_64:
+       ${PASS_IFF} true
+
+all-armv7:
+       ${CC} ${CCFLAGS} -static foo.c -c 
+       ${CC} ${CCFLAGS} bar.s -c 
+       # verify islands are created and used
+       ${CC} ${CCFLAGS} foo.o bar.o -e _foo -o foobar -nostdlib -Wl,-preload -segaddr __MY 0x3000000
+       ${OTOOL} -s __MY __text -V foobar | grep '_myweak1.island:' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -s __MY __text -V foobar | grep '_foo2.island:' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -s __MY __text -V foobar | grep '_foo.island:' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -s __MY __text -V foobar | grep "bl\t_foo.island" | ${FAIL_IF_EMPTY}
+       # verify that is close enough islands are bypassed and target called directly
+       ${CC} ${CCFLAGS} foo.o bar.o -e _foo -o foobar2 -nostdlib -Wl,-preload -segaddr __MY 0x30000
+       ${OTOOL} -s __MY __text -V foobar2 | grep 'bl\t_foo' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -s __MY __text -V foobar2 | grep 'bl\t_foo2' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -s __MY __text -V foobar2 | grep 'bl\t_myweak1' | ${FAIL_IF_EMPTY}
+       ${PASS_IFF} true
+
+clean:
+       rm  *.o foobar*
diff --git a/unit-tests/test-cases/branch-long/bar.s b/unit-tests/test-cases/branch-long/bar.s
new file mode 100644 (file)
index 0000000..528512a
--- /dev/null
@@ -0,0 +1,24 @@
+
+#if __arm__
+
+  .section __MY,__text,regular,pure_instructions
+       .align 4
+
+#if __thumb__
+       .thumb_func _bar
+       .code 16
+#endif 
+       .globl _bar
+_bar:
+    nop
+    bl         _foo
+    blx                _foo2
+    bl         _myweak1
+
+
+#endif // __arm__
+
+
+
+    .subsections_via_symbols
+    
\ No newline at end of file
diff --git a/unit-tests/test-cases/branch-long/foo.c b/unit-tests/test-cases/branch-long/foo.c
new file mode 100644 (file)
index 0000000..60e96d2
--- /dev/null
@@ -0,0 +1,25 @@
+
+int x = 1;
+int y = 2;
+
+__attribute__((weak))
+void myweak1()
+{
+}
+
+int foo()
+{
+  myweak1();
+  return 1;
+}
+
+int foo1()
+{
+  return x;
+}
+
+int foo2()
+{
+  return y;
+}
+
index f773c1100033cd7a8cb2c940ce7c046304892e27..78a24845a293ec3b381aadb35e03f45cf891e72c 100644 (file)
@@ -27,6 +27,8 @@ include ${TESTROOT}/include/common.makefile
 # Validate cpu subtypes processing
 #
 
+CC_ARM = $(shell xcrun -find clang)  -miphoneos-version-min=5.0 -isysroot ${IOS_SDK}
+
 test: test-${ARCH}
 
 test-ppc64:
@@ -42,31 +44,31 @@ test-armv6: test-arm
 test-armv7: test-arm
 
 test-arm:
-       clang  foo.c -arch armv4t -c -o foo-v4.o
+       ${CC_ARM}  foo.c -arch armv4t -c -o foo-v4.o
        ${FAIL_IF_BAD_OBJ} foo-v4.o
-       clang  foo.c -arch armv5  -c -o foo-v5.o
+       ${CC_ARM}  foo.c -arch armv5  -c -o foo-v5.o
        ${FAIL_IF_BAD_OBJ} foo-v5.o
-       clang  foo.c -arch armv6  -c -o foo-v6.o
+       ${CC_ARM}  foo.c -arch armv6  -c -o foo-v6.o
        ${FAIL_IF_BAD_OBJ} foo-v6.o
-       clang  foo.c -arch armv7  -c -o foo-v7.o
+       ${CC_ARM}  foo.c -arch armv7  -c -o foo-v7.o
        ${FAIL_IF_BAD_OBJ} foo-v7.o
-       clang  foo.c -arch xscale  -c -o foo-xscale.o
+       ${CC_ARM}  foo.c -arch xscale  -c -o foo-xscale.o
        ${FAIL_IF_BAD_OBJ} foo-xscale.o
-       clang  main.c -arch armv4t  -c -o main-v4.o
+       ${CC_ARM}  main.c -arch armv4t  -c -o main-v4.o
        ${FAIL_IF_BAD_OBJ} main-v4.o
-       clang  main.c -arch armv5  -c -o main-v5.o
+       ${CC_ARM}  main.c -arch armv5  -c -o main-v5.o
        ${FAIL_IF_BAD_OBJ} main-v5.o
-       clang  main.c -arch armv6  -c -o main-v6.o
+       ${CC_ARM}  main.c -arch armv6  -c -o main-v6.o
        ${FAIL_IF_BAD_OBJ} main-v6.o
-       clang  main.c -arch xscale  -c -o main-xscale.o
+       ${CC_ARM}  main.c -arch xscale  -c -o main-xscale.o
        ${FAIL_IF_BAD_OBJ} main-xscale.o
-       clang  main.c -arch armv7  -c -o main-v7.o
+       ${CC_ARM}  main.c -arch armv7  -c -o main-v7.o
        ${FAIL_IF_BAD_OBJ} main-v7.o
 
        # check V4+V4 -> V4
-       ${LD} -r main-v4.o foo-v4.o -o all.o
-       ${FAIL_IF_BAD_OBJ} all.o
-       otool -hv all.o | grep V4T | ${FAIL_IF_EMPTY}
+#      ${LD} -r main-v4.o foo-v4.o -o all.o
+#      ${FAIL_IF_BAD_OBJ} all.o
+#      otool -hv all.o | grep V4T | ${FAIL_IF_EMPTY}
 
        # check V4+V5 -> V5
        #${LD} -r main-v4.o foo-v5.o -o all.o
@@ -84,9 +86,9 @@ test-arm:
        #otool -hv all.o | grep XSCALE | ${FAIL_IF_EMPTY}
 
        # check V5+V5 -> V5
-       ${LD} -r main-v5.o foo-v5.o -o all.o
-       ${FAIL_IF_BAD_OBJ} all.o
-       otool -hv all.o | grep V5 | ${FAIL_IF_EMPTY}
+#      ${LD} -r main-v5.o foo-v5.o -o all.o
+#      ${FAIL_IF_BAD_OBJ} all.o
+#      otool -hv all.o | grep V5 | ${FAIL_IF_EMPTY}
 
        # check V5+V6 -> V6
        #${LD} -r main-v5.o foo-v6.o -o all.o
index f6c40e425ac047517390797b614b753a979fd96f..d91d17f2134d7f076955ae146016d1dfaf6cd628 100644 (file)
@@ -15,7 +15,7 @@ all:
        ${FAIL_IF_BAD_MACHO} test
        ${CC} ${CCFLAGS} test.c -DDSO_DEF=1 -o test-def 2>warnings.txt
        ${FAIL_IF_BAD_MACHO} test-def
-       ${CC} ${CCFLAGS} test.c -DDSO_TENT=1 -o test-tent
+       ${CC} ${CCFLAGS} test.c -DDSO_TENT=1 -o test-tent -Wl,-w
        ${PASS_IFF_GOOD_MACHO} test-tent
 
 
index 3fb8a254c467746d03ec54904a3ca8ab49b8aabf..e40cc53dbf03c99b6a280d0138669753213f8ab5 100644 (file)
@@ -31,13 +31,12 @@ SHELL = bash # use bash shell so we can redirect just stderr
 #
 #   <rdar://problem/5726215> comdat warnings in ld -r
 #
-#  also use -falign-functions to force an out of order coalesing  
 #
 run: all
 
 all:
        ${CXX} ${CCXXFLAGS} foo.cxx -c -o foo.o
-       ${CXX} ${CCXXFLAGS} bar.cxx -c -o bar.o -falign-functions=32
+       ${CXX} ${CCXXFLAGS} bar.cxx -c -o bar.o
        ${CXX} ${CCXXFLAGS} baz.cxx -c -o baz.o
        ${LD} -r foo.o bar.o baz.o -o foobarbaz.o 2> warnings.log
        grep warning warnings.log | ${PASS_IFF_EMPTY}
diff --git a/unit-tests/test-cases/linker-optimization-hints/AdrpAdd.s b/unit-tests/test-cases/linker-optimization-hints/AdrpAdd.s
new file mode 100644 (file)
index 0000000..b99221b
--- /dev/null
@@ -0,0 +1,27 @@
+
+
+      .text
+      .align 2
+_test:
+      nop
+L1:   adrp     x0, _foo@PAGE
+L2:   add   x0, x0, _foo@PAGEOFF
+      nop
+  
+    .loh AdrpAdd L1, L2
+    
+#if PADDING
+_pad:
+      .space 1100000
+#endif 
+  
+#if FOO_AS_CONST
+    .const
+#endif
+
+#if FOO_AS_DATA
+    .data
+#endif
+
+_foo: .long 0
+
diff --git a/unit-tests/test-cases/linker-optimization-hints/AdrpAddLdr.s b/unit-tests/test-cases/linker-optimization-hints/AdrpAddLdr.s
new file mode 100644 (file)
index 0000000..cdcaba9
--- /dev/null
@@ -0,0 +1,55 @@
+
+#ifndef ADDEND
+ #define ADDEND 0
+#endif
+
+      .text
+      .align 2
+_test:
+      nop
+L1:   adrp     x0, _foo@PAGE
+L2:   add   x0, x0, _foo@PAGEOFF
+#if LOAD_GPR_8
+L3:   ldr   b1, [x0, #ADDEND]
+#elif LOAD_GPR_16
+L3:   ldr   h1, [x0, #ADDEND]
+#elif LOAD_GPR_32
+L3:   ldr   w1, [x0, #ADDEND]
+#elif LOAD_GPR_64
+L3:   ldr   x1, [x0, #ADDEND]
+#elif LOAD_FPR_32
+L3:   ldr   s1, [x0, #ADDEND]
+#elif LOAD_FPR_64
+L3:   ldr   d1, [x0, #ADDEND]
+#elif LOAD_VEC_128
+L3:   ldr   q1, [x0, #ADDEND]
+#endif
+      nop
+  
+    .loh AdrpAddLdr L1, L2, L3
+    
+#if PADDING
+_pad:
+      .space 1100000
+#endif 
+
+#if FOO_AS_CONSTANT
+    .literal4
+#endif
+
+#if FOO_AS_DATA
+    .data
+_makePageOffsetNonZero: .long 0,0,0,0
+#endif
+
+#if MISALIGN_DATA
+_junk: .byte 0
+#endif
+
+_foo:     .long 0
+          .long 0
+_8foo8:   .long 0
+          .long 0
+_16foo16: .long 0
+
+
diff --git a/unit-tests/test-cases/linker-optimization-hints/AdrpAddStr.s b/unit-tests/test-cases/linker-optimization-hints/AdrpAddStr.s
new file mode 100644 (file)
index 0000000..3e3252a
--- /dev/null
@@ -0,0 +1,44 @@
+
+#ifndef ADDEND
+ #define ADDEND 0
+#endif
+
+      .text
+      .align 2
+_test:
+      nop
+L1:   adrp     x0, _foo@PAGE
+L2:   add   x0, x0, _foo@PAGEOFF
+#if LOAD_GPR_8
+L3:   str   b1, [x0, #ADDEND]
+#elif LOAD_GPR_16
+L3:   str   h1, [x0, #ADDEND]
+#elif LOAD_GPR_32
+L3:   str   w1, [x0, #ADDEND]
+#elif LOAD_GPR_64
+L3:   str   x1, [x0, #ADDEND]
+#elif LOAD_FPR_32
+L3:   str   s1, [x0, #ADDEND]
+#elif LOAD_FPR_64
+L3:   str   d1, [x0, #ADDEND]
+#elif LOAD_VEC_128
+L3:   str   q1, [x0, #ADDEND]
+#endif
+      nop
+  
+    .loh AdrpAddStr L1, L2, L3
+
+    .data
+_makePageOffsetNonZero: .long 0,0,0,0
+
+#if MISALIGN_DATA
+_junk: .byte 0
+#endif
+
+_foo:     .long 0
+          .long 0
+_8foo8:   .long 0
+          .long 0
+_16foo16: .long 0
+
+
diff --git a/unit-tests/test-cases/linker-optimization-hints/AdrpLdr.s b/unit-tests/test-cases/linker-optimization-hints/AdrpLdr.s
new file mode 100644 (file)
index 0000000..c91fa06
--- /dev/null
@@ -0,0 +1,64 @@
+
+#ifndef ADDEND
+ #define ADDEND  
+#endif
+
+      .text
+      .align 2
+_test:
+      nop
+L1:   adrp     x0, _foo ADDEND@PAGE
+#if LOAD_GPR_8
+L3:   ldr   b1, [x0,  _foo ADDEND@PAGEOFF]
+#elif LOAD_GPR_16
+L3:   ldr   h1, [x0,  _foo ADDEND@PAGEOFF]
+#elif LOAD_GPR_32
+L3:   ldr   w1, [x0,  _foo ADDEND@PAGEOFF]
+#elif LOAD_GPR_32_S16
+L3:   ldrsh w1, [x0,  _foo ADDEND@PAGEOFF]
+#elif LOAD_GPR_32_S8
+L3:   ldrsb w1, [x0,  _foo ADDEND@PAGEOFF]
+#elif LOAD_GPR_64
+L3:   ldr   x1, [x0,  _foo ADDEND@PAGEOFF]
+#elif LOAD_GPR_64_S32
+L3:   ldrsw x1, [x0,  _foo ADDEND@PAGEOFF]
+#elif LOAD_GPR_64_S16
+L3:   ldrsh x1, [x0,  _foo ADDEND@PAGEOFF]
+#elif LOAD_GPR_64_S8
+L3:   ldrsb x1, [x0,  _foo ADDEND@PAGEOFF]
+#elif LOAD_FPR_32
+L3:   ldr   s1, [x0,  _foo ADDEND@PAGEOFF]
+#elif LOAD_FPR_64
+L3:   ldr   d1, [x0,  _foo ADDEND@PAGEOFF]
+#elif LOAD_VEC_128
+L3:   ldr   q1, [x0,  _foo ADDEND@PAGEOFF]
+#endif
+      nop
+  
+    .loh AdrpLdr L1, L3
+    
+#if PADDING
+_pad:
+      .space 1100000
+#endif 
+
+#if FOO_AS_CONSTANT
+    .literal4
+#endif
+
+#if FOO_AS_DATA
+    .data
+_makePageOffsetNonZero: .long 0,0,0,0
+#endif
+
+#if MISALIGN_DATA
+_junk: .byte 0
+#endif
+
+_foo:     .long 0
+          .long 0
+_8foo8:   .long 0
+          .long 0
+_16foo16: .long 0
+
+
diff --git a/unit-tests/test-cases/linker-optimization-hints/AdrpLdrGot.s b/unit-tests/test-cases/linker-optimization-hints/AdrpLdrGot.s
new file mode 100644 (file)
index 0000000..40bc180
--- /dev/null
@@ -0,0 +1,30 @@
+
+#ifndef TARGET
+ #define TARGET _malloc
+#endif
+
+      .text
+      .align 2
+_test:
+      nop
+L1:   adrp     x0, TARGET@GOTPAGE
+L2:   ldr   x1, [x0, #TARGET@GOTPAGEOFF]
+      nop
+  
+    .loh AdrpLdrGot L1, L2
+
+#if PADDING
+_pad:
+      .space 1100000
+#endif 
+    
+_fooCode:
+      nop
+  
+
+    .data
+_makePageOffsetNonZero: .long 0,0,0,0
+
+_fooData:     .long 0
+
+
diff --git a/unit-tests/test-cases/linker-optimization-hints/AdrpLdrGotLdr.s b/unit-tests/test-cases/linker-optimization-hints/AdrpLdrGotLdr.s
new file mode 100644 (file)
index 0000000..0f90ff8
--- /dev/null
@@ -0,0 +1,56 @@
+
+#ifndef TARGET
+ #define TARGET _foo
+#endif
+
+      .text
+      .align 2
+_test:
+      nop
+L1:   adrp     x0, TARGET@GOTPAGE
+L2:   ldr   x1, [x0, #TARGET@GOTPAGEOFF]
+#if LOAD_GPR_8
+L3:   ldr   b2, [x1]
+#elif LOAD_GPR_16
+L3:   ldr   h2, [x1]
+#elif LOAD_GPR_32
+L3:   ldr   w2, [x1]
+#elif LOAD_GPR_64
+L3:   ldr   x2, [x1]
+#elif LOAD_FPR_32
+L3:   ldr   s2, [x1]
+#elif LOAD_FPR_64
+L3:   ldr   d2, [x1]
+#elif LOAD_VEC_128
+L3:   ldr   q2, [x1]
+#endif
+      nop
+  
+    .loh AdrpLdrGotLdr L1, L2, L3
+    
+#if PADDING
+_pad:
+      .space 1100000
+#endif 
+
+#if FOO_AS_CONST
+    .const
+    .align 4
+#endif
+
+#if FOO_AS_DATA
+    .data
+_makePageOffsetNonZero: .long 0,0,0,0
+#endif
+
+#if MISALIGN_DATA
+_junk: .byte 0
+#endif
+
+_foo:     .long 0
+          .long 0
+_8foo8:   .long 0
+          .long 0
+_16foo16: .long 0
+
+
diff --git a/unit-tests/test-cases/linker-optimization-hints/AdrpLdrGotStr.s b/unit-tests/test-cases/linker-optimization-hints/AdrpLdrGotStr.s
new file mode 100644 (file)
index 0000000..d3fed03
--- /dev/null
@@ -0,0 +1,49 @@
+
+#ifndef TARGET
+ #define TARGET _foo
+#endif
+
+      .text
+      .align 2
+_test:
+      nop
+L1:   adrp     x0, TARGET@GOTPAGE
+L2:   ldr   x1, [x0, #TARGET@GOTPAGEOFF]
+#if LOAD_GPR_8
+L3:   str   b2, [x1]
+#elif LOAD_GPR_16
+L3:   str   h2, [x1]
+#elif LOAD_GPR_32
+L3:   str   w2, [x1]
+#elif LOAD_GPR_64
+L3:   str   x2, [x1]
+#elif LOAD_FPR_32
+L3:   str   s2, [x1]
+#elif LOAD_FPR_64
+L3:   str   d2, [x1]
+#elif LOAD_VEC_128
+L3:   str   q2, [x1]
+#endif
+      nop
+  
+    .loh AdrpLdrGotStr L1, L2, L3
+    
+#if PADDING
+_pad:
+      .space 1100000
+#endif 
+    
+    .data
+_makePageOffsetNonZero: .long 0,0,0,0
+
+#if MISALIGN_DATA
+_junk: .byte 0
+#endif
+
+_foo:     .long 0
+          .long 0
+_8foo8:   .long 0
+          .long 0
+_16foo16: .long 0
+
+
diff --git a/unit-tests/test-cases/linker-optimization-hints/Makefile b/unit-tests/test-cases/linker-optimization-hints/Makefile
new file mode 100644 (file)
index 0000000..de5da0d
--- /dev/null
@@ -0,0 +1,1418 @@
+##
+# 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 that linker does/doesnot apply optimization hints
+#
+
+all: all-${ARCH}
+
+all-i386: skip
+all-x86_64: skip
+all-armv6: skip 
+all-armv7: skip
+
+all-arm64: AdrpAdd AdrpAddLdr AdrpLdr AdrpLdrGotLdr AdrpAddStr AdrpLdrGotStr AdrpLdrGot
+
+main.o:
+       ${CC} ${CCFLAGS} main.s -c -o main.o
+       
+AdrpAdd:       main.o
+       # test ADRP/ADD -> ADR when target is in __TEXT
+       ${CC} ${CCFLAGS} AdrpAdd.s -c -o AdrpAdd1.o -DFOO_AS_CONST=1
+       ${CC} ${CCFLAGS} AdrpAdd1.o main.o -o AdrpAdd1.exe
+       ${OTOOL} -tV AdrpAdd1.exe | grep 'adr   x0' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpAdd1.exe | grep 'adrp  x0' | ${FAIL_IF_STDIN}
+       ${OTOOL} -tV AdrpAdd1.exe | grep 'add   x0' | ${FAIL_IF_STDIN}
+       # test ADRP/ADD -> ADR when target is in __DATA and main executable
+       ${CC} ${CCFLAGS} AdrpAdd.s -c -o AdrpAdd2.o -DFOO_AS_DATA=1
+       ${CC} ${CCFLAGS} AdrpAdd2.o main.o -o AdrpAdd2.exe
+       ${OTOOL} -tV AdrpAdd2.exe | grep 'adr   x0' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpAdd2.exe | grep 'adrp  x0' | ${FAIL_IF_STDIN}
+       ${OTOOL} -tV AdrpAdd2.exe | grep 'add   x0' | ${FAIL_IF_STDIN}
+       # test ADRP/ADD -> ADR when target is in __DATA and dylib
+       ${CC} ${CCFLAGS} AdrpAdd.s -c -o AdrpAdd3.o -DFOO_AS_DATA=1
+       ${CC} ${CCFLAGS} AdrpAdd3.o -dynamiclib -o AdrpAdd3.dylib
+       ${OTOOL} -tV AdrpAdd3.dylib | grep 'adr x0' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpAdd3.dylib | grep 'adrp        x0' | ${FAIL_IF_STDIN}
+       ${OTOOL} -tV AdrpAdd3.dylib | grep 'add x0' | ${FAIL_IF_STDIN}
+       # test ADRP/ADD !->  when target is in __DATA and dylib in shared region
+       ${CC} ${CCFLAGS} AdrpAdd.s -c -o AdrpAdd4.o -DFOO_AS_DATA=1
+       ${CC} ${CCFLAGS} AdrpAdd4.o -dynamiclib -o AdrpAdd4.dylib -install_name /usr/lib/libjunk.dylib
+       ${OTOOL} -tV AdrpAdd4.dylib | grep 'adrp        x0' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpAdd4.dylib | grep 'add x0' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpAdd4.dylib | grep 'adr x0' | ${FAIL_IF_STDIN}
+       # test ADRP/ADD !->  when target is in __TEXT but too far
+       ${CC} ${CCFLAGS} AdrpAdd.s -c -o AdrpAdd5.o -DFOO_AS_CONST=1 -DPADDING
+       ${CC} ${CCFLAGS} AdrpAdd5.o main.o -o AdrpAdd5.exe
+       ${OTOOL} -tV AdrpAdd5.exe | grep 'adrp  x0' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpAdd5.exe | grep 'add   x0' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpAdd5.exe | grep 'adr   x0' | ${FAIL_IF_STDIN}
+       
+
+
+AdrpAddLdr: AdrpAddLdr-ldr AdrpAddLdr-far AdrpAddLdr-seg AdrpAddLdr-align AdrpAddLdr-addend
+       true
+
+AdrpAddLdr-ldr: main.o
+       # test ADRP/ADD/LD -> ADR/LDR when target is in __TEXT for 8-bit load
+       ${CC} ${CCFLAGS} AdrpAddLdr.s -c -o AdrpAddLdr-ldr-g8.o -DFOO_AS_CONST -DLOAD_GPR_8 
+       ${CC} ${CCFLAGS} AdrpAddLdr-ldr-g8.o main.o -o AdrpAddLdr-ldr-g8.exe 
+       ${OTOOL} -tV AdrpAddLdr-ldr-g8.exe | grep 'adr  x0' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpAddLdr-ldr-g8.exe | grep 'ldr\tb1, \[x0\]' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpAddLdr-ldr-g8.exe | grep 'add  x0' | ${FAIL_IF_STDIN}
+       
+       # test ADRP/ADD/LD -> ADR/LDR when target is in __TEXT for 16-bit load
+       ${CC} ${CCFLAGS} AdrpAddLdr.s -c -o AdrpAddLdr-ldr-g16.o -DFOO_AS_CONST -DLOAD_GPR_16
+       ${CC} ${CCFLAGS} AdrpAddLdr-ldr-g16.o main.o -o AdrpAddLdr-ldr-g16.exe
+       ${OTOOL} -tV AdrpAddLdr-ldr-g16.exe | grep 'adr x0' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpAddLdr-ldr-g16.exe | grep 'ldr\th1, \[x0\]' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpAddLdr-ldr-g16.exe | grep 'add x0' | ${FAIL_IF_STDIN}
+       
+       # test ADRP/ADD/LD -> LDR when target is in __TEXT for 32-bit load
+       ${CC} ${CCFLAGS} AdrpAddLdr.s -c -o AdrpAddLdr-ldr-g32.o -DFOO_AS_CONST -DLOAD_GPR_32
+       ${CC} ${CCFLAGS} AdrpAddLdr-ldr-g32.o main.o -o AdrpAddLdr-ldr-g32.exe
+       ${OTOOL} -tV AdrpAddLdr-ldr-g32.exe | grep 'ldr w1, _foo' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpAddLdr-ldr-g32.exe | grep 'adrp        x0' | ${FAIL_IF_STDIN}
+       ${OTOOL} -tV AdrpAddLdr-ldr-g32.exe | grep 'add x0' | ${FAIL_IF_STDIN}
+
+       # test ADRP/ADD/LD -> LDR when target is in __TEXT for 64-bit load
+       ${CC} ${CCFLAGS} AdrpAddLdr.s -c -o AdrpAddLdr-ldr-g64.o -DFOO_AS_CONST -DLOAD_GPR_64
+       ${CC} ${CCFLAGS} AdrpAddLdr-ldr-g64.o main.o -o AdrpAddLdr-ldr-g64.exe
+       ${OTOOL} -tV AdrpAddLdr-ldr-g64.exe | grep 'ldr x1, _foo' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpAddLdr-ldr-g64.exe | grep 'adrp        x0' | ${FAIL_IF_STDIN}
+       ${OTOOL} -tV AdrpAddLdr-ldr-g64.exe | grep 'add x0' | ${FAIL_IF_STDIN}
+
+       # test ADRP/ADD/LD -> LDR when target is in __TEXT for 32-bit fp load
+       ${CC} ${CCFLAGS} AdrpAddLdr.s -c -o AdrpAddLdr-ldr-f32.o -DFOO_AS_CONST -DLOAD_FPR_32
+       ${CC} ${CCFLAGS} AdrpAddLdr-ldr-f32.o main.o -o AdrpAddLdr-ldr-f32.exe
+       ${OTOOL} -tV AdrpAddLdr-ldr-f32.exe | grep 'ldr s1, _foo' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpAddLdr-ldr-f32.exe | grep 'adrp        x0' | ${FAIL_IF_STDIN}
+       ${OTOOL} -tV AdrpAddLdr-ldr-f32.exe | grep 'add x0' | ${FAIL_IF_STDIN}
+
+       # test ADRP/ADD/LD -> LDR when target is in __TEXT for 64-bit fp load
+       ${CC} ${CCFLAGS} AdrpAddLdr.s -c -o AdrpAddLdr-ldr-f64.o -DFOO_AS_CONST -DLOAD_FPR_64
+       ${CC} ${CCFLAGS} AdrpAddLdr-ldr-f64.o main.o -o AdrpAddLdr-ldr-f64.exe
+       ${OTOOL} -tV AdrpAddLdr-ldr-f64.exe | grep 'ldr d1, _foo' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpAddLdr-ldr-f64.exe | grep 'adrp        x0' | ${FAIL_IF_STDIN}
+       ${OTOOL} -tV AdrpAddLdr-ldr-f64.exe | grep 'add x0' | ${FAIL_IF_STDIN}
+       
+       # test ADRP/ADD/LD -> LDR when target is in __TEXT for 128-bit vec load
+       ${CC} ${CCFLAGS} AdrpAddLdr.s -c -o AdrpAddLdr-ldr-v128.o -DFOO_AS_CONST -DLOAD_VEC_128
+       ${CC} ${CCFLAGS} AdrpAddLdr-ldr-v128.o main.o -o AdrpAddLdr-ldr-v128.exe
+       ${OTOOL} -tV AdrpAddLdr-ldr-v128.exe | grep 'ldr        q1, _foo' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpAddLdr-ldr-v128.exe | grep 'adrp       x0' | ${FAIL_IF_STDIN}
+       ${OTOOL} -tV AdrpAddLdr-ldr-v128.exe | grep 'add        x0' | ${FAIL_IF_STDIN}
+
+
+AdrpAddLdr-far: main.o
+       # test ADRP/ADD/LD -> ADRP/LD when target is far for 8-bit load
+       ${CC} ${CCFLAGS} AdrpAddLdr.s -c -o AdrpAddLdr-far-g8.o -DFOO_AS_CONST -DLOAD_GPR_8  -DPADDING
+       ${CC} ${CCFLAGS} AdrpAddLdr-far-g8.o main.o -o AdrpAddLdr-far-g8.exe
+       ${OTOOL} -tV AdrpAddLdr-far-g8.exe | grep 'ldr  b1, \[x0, ' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpAddLdr-far-g8.exe | grep 'add  x0' | ${FAIL_IF_STDIN}
+       
+       # test ADRP/ADD/LD -> ADRP/LD when target is far for 16-bit load
+       ${CC} ${CCFLAGS} AdrpAddLdr.s -c -o AdrpAddLdr-far-g16.o -DFOO_AS_CONST -DLOAD_GPR_16 -DPADDING
+       ${CC} ${CCFLAGS} AdrpAddLdr-far-g16.o main.o -o AdrpAddLdr-far-g16.exe
+       ${OTOOL} -tV AdrpAddLdr-far-g16.exe | grep 'ldr h1, \[x0, ' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpAddLdr-far-g16.exe | grep 'add x0' | ${FAIL_IF_STDIN}
+       
+       # test ADRP/ADD/LD -> ADRP/LD when target is far for 32-bit load
+       ${CC} ${CCFLAGS} AdrpAddLdr.s -c -o AdrpAddLdr-far-g32.o -DFOO_AS_CONST -DLOAD_GPR_32 -DPADDING
+       ${CC} ${CCFLAGS} AdrpAddLdr-far-g32.o main.o -o AdrpAddLdr-far-g32.exe
+       ${OTOOL} -tV AdrpAddLdr-far-g32.exe | grep 'ldr w1, \[x0, ' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpAddLdr-far-g32.exe | grep 'add x0' | ${FAIL_IF_STDIN}
+
+       # test ADRP/ADD/LD -> ADRP/LD when target is far for 64-bit load
+       ${CC} ${CCFLAGS} AdrpAddLdr.s -c -o AdrpAddLdr-far-g64.o -DFOO_AS_CONST -DLOAD_GPR_64 -DPADDING
+       ${CC} ${CCFLAGS} AdrpAddLdr-far-g64.o main.o -o AdrpAddLdr-far-g64.exe
+       ${OTOOL} -tV AdrpAddLdr-far-g64.exe | grep 'ldr x1, \[x0, ' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpAddLdr-far-g64.exe | grep 'add x0' | ${FAIL_IF_STDIN}
+
+       # test ADRP/ADD/LD -> ADRP/LD when target is far for 32-bit fp load
+       ${CC} ${CCFLAGS} AdrpAddLdr.s -c -o AdrpAddLdr-far-f32.o -DFOO_AS_CONST -DLOAD_FPR_32 -DPADDING
+       ${CC} ${CCFLAGS} AdrpAddLdr-far-f32.o main.o -o AdrpAddLdr-far-f32.exe
+       ${OTOOL} -tV AdrpAddLdr-far-f32.exe | grep 'ldr s1, \[x0, ' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpAddLdr-far-f32.exe | grep 'add x0' | ${FAIL_IF_STDIN}
+
+       # test ADRP/ADD/LD -> ADRP/LD when target is far for 64-bit fp load
+       ${CC} ${CCFLAGS} AdrpAddLdr.s -c -o AdrpAddLdr-far-f64.o -DFOO_AS_CONST -DLOAD_FPR_64 -DPADDING
+       ${CC} ${CCFLAGS} AdrpAddLdr-far-f64.o main.o -o AdrpAddLdr-far-f64.exe
+       ${OTOOL} -tV AdrpAddLdr-far-f64.exe | grep 'ldr d1, \[x0, ' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpAddLdr-far-f64.exe | grep 'add x0' | ${FAIL_IF_STDIN}
+       
+       # test ADRP/ADD/LD -> ADRP/LD when target is far for 128-bit vec load
+       ${CC} ${CCFLAGS} AdrpAddLdr.s -c -o AdrpAddLdr-far-v128.o -DFOO_AS_CONST -DLOAD_VEC_128 -DPADDING
+       ${CC} ${CCFLAGS} AdrpAddLdr-far-v128.o main.o -o AdrpAddLdr-far-v128.exe
+       ${OTOOL} -tV AdrpAddLdr-far-v128.exe | grep 'ldr        q1, \[x0, ' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpAddLdr-far-v128.exe | grep 'add        x0' | ${FAIL_IF_STDIN}
+
+
+
+AdrpAddLdr-align: main.o
+       # test ADRP/ADD/LD -> ADR/LD when target is for 8-bit load
+       ${CC} ${CCFLAGS} AdrpAddLdr.s -c -o AdrpAddLdr-align-g8.o -DFOO_AS_DATA -DLOAD_GPR_8 -DMISALIGN_DATA
+       ${CC} ${CCFLAGS} AdrpAddLdr-align-g8.o main.o -o AdrpAddLdr-align-g8.exe
+       ${OTOOL} -tV AdrpAddLdr-align-g8.exe | grep 'adr        x0,' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpAddLdr-align-g8.exe | grep 'ldr\tb1, \[x0\]' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpAddLdr-align-g8.exe | grep 'add        x0' | ${FAIL_IF_STDIN}
+       
+       # test ADRP/ADD/LD -> ADR/LD when target is not aligned for 16-bit load
+       ${CC} ${CCFLAGS} AdrpAddLdr.s -c -o AdrpAddLdr-align-g16.o -DFOO_AS_DATA -DLOAD_GPR_16 -DMISALIGN_DATA
+       ${CC} ${CCFLAGS} AdrpAddLdr-align-g16.o main.o -o AdrpAddLdr-align-g16.exe
+       ${OTOOL} -tV AdrpAddLdr-align-g16.exe | grep 'adr       x0,' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpAddLdr-align-g16.exe | grep 'ldr       h1, \[x0\]' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpAddLdr-align-g16.exe | grep 'add       x0' | ${FAIL_IF_STDIN}
+       
+       # test ADRP/ADD/LD -> ADR/LD  when target is not aligned for 32-bit load
+       ${CC} ${CCFLAGS} AdrpAddLdr.s -c -o AdrpAddLdr-align-g32.o -DFOO_AS_DATA -DLOAD_GPR_32 -DMISALIGN_DATA
+       ${CC} ${CCFLAGS} AdrpAddLdr-align-g32.o main.o -o AdrpAddLdr-align-g32.exe
+       ${OTOOL} -tV AdrpAddLdr-align-g32.exe | grep 'adr       x0' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpAddLdr-align-g32.exe | grep 'add       x0' | ${FAIL_IF_STDIN}
+       ${OTOOL} -tV AdrpAddLdr-align-g32.exe | grep 'ldr       w1, \[x0\]' | ${FAIL_IF_EMPTY}
+
+       # test ADRP/ADD/LD -> ADR/LD  when target is not aligned for 64-bit load
+       ${CC} ${CCFLAGS} AdrpAddLdr.s -c -o AdrpAddLdr-align-g64.o -DFOO_AS_DATA -DLOAD_GPR_64 -DMISALIGN_DATA
+       ${CC} ${CCFLAGS} AdrpAddLdr-align-g64.o main.o -o AdrpAddLdr-align-g64.exe
+       ${OTOOL} -tV AdrpAddLdr-align-g64.exe | grep 'adr       x0' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpAddLdr-align-g64.exe | grep 'add       x0' | ${FAIL_IF_STDIN}
+       ${OTOOL} -tV AdrpAddLdr-align-g64.exe | grep 'ldr       x1, \[x0\]' | ${FAIL_IF_EMPTY}
+
+       # test ADRP/ADD/LD -> ADR/LD  when target is not aligned for 32-bit fp load
+       ${CC} ${CCFLAGS} AdrpAddLdr.s -c -o AdrpAddLdr-align-f32.o -DFOO_AS_DATA -DLOAD_FPR_32 -DMISALIGN_DATA
+       ${CC} ${CCFLAGS} AdrpAddLdr-align-f32.o main.o -o AdrpAddLdr-align-f32.exe
+       ${OTOOL} -tV AdrpAddLdr-align-f32.exe | grep 'adr       x0' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpAddLdr-align-f32.exe | grep 'add       x0' | ${FAIL_IF_STDIN}
+       ${OTOOL} -tV AdrpAddLdr-align-f32.exe | grep 'ldr       s1, \[x0\]' | ${FAIL_IF_EMPTY}
+
+       # test ADRP/ADD/LD -> ADR/LD  when target is not aligned for 64-bit fp load
+       ${CC} ${CCFLAGS} AdrpAddLdr.s -c -o AdrpAddLdr-align-f64.o -DFOO_AS_DATA -DLOAD_FPR_64 -DMISALIGN_DATA
+       ${CC} ${CCFLAGS} AdrpAddLdr-align-f64.o main.o -o AdrpAddLdr-align-f64.exe
+       ${OTOOL} -tV AdrpAddLdr-align-f64.exe | grep 'adr       x0' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpAddLdr-align-f64.exe | grep 'add       x0' | ${FAIL_IF_STDIN}
+       ${OTOOL} -tV AdrpAddLdr-align-f64.exe | grep 'ldr       d1, \[x0\]' | ${FAIL_IF_EMPTY}
+       
+       # test ADRP/ADD/LD -> ADR/LD  when target is not aligned for 128-bit vec load
+       ${CC} ${CCFLAGS} AdrpAddLdr.s -c -o AdrpAddLdr-align-v128.o -DFOO_AS_DATA -DLOAD_VEC_128 -DMISALIGN_DATA
+       ${CC} ${CCFLAGS} AdrpAddLdr-align-v128.o main.o -o AdrpAddLdr-align-v128.exe
+       ${OTOOL} -tV AdrpAddLdr-align-v128.exe | grep 'adr      x0' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpAddLdr-align-v128.exe | grep 'add      x0' | ${FAIL_IF_STDIN}
+       ${OTOOL} -tV AdrpAddLdr-align-v128.exe | grep 'ldr      q1, \[x0\]' | ${FAIL_IF_EMPTY}
+
+
+       
+AdrpAddLdr-seg:        
+       # test ADRP/ADD/LD -> ADRP/LD when target is in movable segment for 8-bit load
+       ${CC} ${CCFLAGS} AdrpAddLdr.s -c -o AdrpAddLdr-seg-g8.o -DFOO_AS_DATA -DLOAD_GPR_8 
+       ${CC} ${CCFLAGS} AdrpAddLdr-seg-g8.o -dynamiclib -o AdrpAddLdr-seg-g8.dylib -install_name /usr/lib/libjunk.dylib
+       ${OTOOL} -tV AdrpAddLdr-seg-g8.dylib | grep 'adrp       x0' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpAddLdr-seg-g8.dylib | grep 'add        x0' | ${FAIL_IF_STDIN}
+       ${OTOOL} -tV AdrpAddLdr-seg-g8.dylib | grep 'ldr        b1, \[x0,' | ${FAIL_IF_EMPTY}
+       
+       # test ADRP/ADD/LD -> ADRP/LD when target is in movable segment for 16-bit load
+       ${CC} ${CCFLAGS} AdrpAddLdr.s -c -o AdrpAddLdr-seg-g16.o -DFOO_AS_DATA -DLOAD_GPR_16 
+       ${CC} ${CCFLAGS} AdrpAddLdr-seg-g16.o -dynamiclib -o AdrpAddLdr-seg-g16.dylib -install_name /usr/lib/libjunk.dylib
+       ${OTOOL} -tV AdrpAddLdr-seg-g16.dylib | grep 'adrp      x0' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpAddLdr-seg-g16.dylib | grep 'add       x0' | ${FAIL_IF_STDIN}
+       ${OTOOL} -tV AdrpAddLdr-seg-g16.dylib | grep 'ldr       h1, \[x0,' | ${FAIL_IF_EMPTY}
+       
+       # test ADRP/ADD/LD -> ADRP/LD  when target is in movable segment for 32-bit load
+       ${CC} ${CCFLAGS} AdrpAddLdr.s -c -o AdrpAddLdr-seg-g32.o -DFOO_AS_DATA -DLOAD_GPR_32 
+       ${CC} ${CCFLAGS} AdrpAddLdr-seg-g32.o -dynamiclib -o AdrpAddLdr-seg-g32.dylib -install_name /usr/lib/libjunk.dylib
+       ${OTOOL} -tV AdrpAddLdr-seg-g32.dylib | grep 'adrp      x0' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpAddLdr-seg-g32.dylib | grep 'add       x0' | ${FAIL_IF_STDIN}
+       ${OTOOL} -tV AdrpAddLdr-seg-g32.dylib | grep 'ldr       w1, \[x0,' | ${FAIL_IF_EMPTY}
+
+       # test ADRP/ADD/LD -> ADRP/LD  when target is in movable segment for 64-bit load
+       ${CC} ${CCFLAGS} AdrpAddLdr.s -c -o AdrpAddLdr-seg-g64.o -DFOO_AS_DATA -DLOAD_GPR_64 
+       ${CC} ${CCFLAGS} AdrpAddLdr-seg-g64.o -dynamiclib -o AdrpAddLdr-seg-g64.dylib -install_name /usr/lib/libjunk.dylib
+       ${OTOOL} -tV AdrpAddLdr-seg-g64.dylib | grep 'adrp      x0' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpAddLdr-seg-g64.dylib | grep 'add       x0' | ${FAIL_IF_STDIN}
+       ${OTOOL} -tV AdrpAddLdr-seg-g64.dylib | grep 'ldr       x1, \[x0,' | ${FAIL_IF_EMPTY}
+
+       # test ADRP/ADD/LD -> ADRP/LD  when target is in movable segment for 32-bit fp load
+       ${CC} ${CCFLAGS} AdrpAddLdr.s -c -o AdrpAddLdr-seg-f32.o -DFOO_AS_DATA -DLOAD_FPR_32 
+       ${CC} ${CCFLAGS} AdrpAddLdr-seg-f32.o -dynamiclib -o AdrpAddLdr-seg-f32.dylib -install_name /usr/lib/libjunk.dylib
+       ${OTOOL} -tV AdrpAddLdr-seg-f32.dylib | grep 'adrp      x0' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpAddLdr-seg-f32.dylib | grep 'add       x0' | ${FAIL_IF_STDIN}
+       ${OTOOL} -tV AdrpAddLdr-seg-f32.dylib | grep 'ldr       s1, \[x0,' | ${FAIL_IF_EMPTY}
+
+       # test ADRP/ADD/LD -> ADRP/LD  when target is in movable segment for 64-bit fp load
+       ${CC} ${CCFLAGS} AdrpAddLdr.s -c -o AdrpAddLdr-seg-f64.o -DFOO_AS_DATA -DLOAD_FPR_64 
+       ${CC} ${CCFLAGS} AdrpAddLdr-seg-f64.o -dynamiclib -o AdrpAddLdr-seg-f64.dylib -install_name /usr/lib/libjunk.dylib
+       ${OTOOL} -tV AdrpAddLdr-seg-f64.dylib | grep 'adrp      x0' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpAddLdr-seg-f64.dylib | grep 'add       x0' | ${FAIL_IF_STDIN}
+       ${OTOOL} -tV AdrpAddLdr-seg-f64.dylib | grep 'ldr       d1, \[x0,' | ${FAIL_IF_EMPTY}
+       
+       # test ADRP/ADD/LD -> ADRP/LD  when target is in movable segmentfor 128-bit vec load
+       ${CC} ${CCFLAGS} AdrpAddLdr.s -c -o AdrpAddLdr-seg-v128.o -DFOO_AS_DATA -DLOAD_VEC_128 
+       ${CC} ${CCFLAGS} AdrpAddLdr-seg-v128.o -dynamiclib -o AdrpAddLdr-seg-v128.dylib -install_name /usr/lib/libjunk.dylib
+       ${OTOOL} -tV AdrpAddLdr-seg-v128.dylib | grep 'adrp     x0' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpAddLdr-seg-v128.dylib | grep 'add      x0' | ${FAIL_IF_STDIN}
+       ${OTOOL} -tV AdrpAddLdr-seg-v128.dylib | grep 'ldr      q1, \[x0,' | ${FAIL_IF_EMPTY}
+
+
+
+AdrpAddLdr-addend:     
+       # test ADRP/ADD/LD -> ADRP/LD when target is in __TEXT for 8-bit load
+       ${CC} ${CCFLAGS} AdrpAddLdr.s -c -o AdrpAddLdr-addend-g8.o -DFOO_AS_CONST -DLOAD_GPR_8 -DADDEND=8
+       ${CC} ${CCFLAGS} AdrpAddLdr-addend-g8.o main.o -o AdrpAddLdr-addend-g8.exe
+       ${OTOOL} -tV AdrpAddLdr-addend-g8.exe | grep 'adr       x0' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpAddLdr-addend-g8.exe | grep 'ldr\tb1, \[x0\]' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpAddLdr-addend-g8.exe | grep 'add       x0' | ${FAIL_IF_STDIN}
+       
+       # test ADRP/ADD/LD -> ADRP/LD when target is in __TEXT for 16-bit load
+       ${CC} ${CCFLAGS} AdrpAddLdr.s -c -o AdrpAddLdr-addend-g16.o -DFOO_AS_CONST -DLOAD_GPR_16 -DADDEND=8
+       ${CC} ${CCFLAGS} AdrpAddLdr-addend-g16.o main.o -o AdrpAddLdr-addend-g16.exe
+       ${OTOOL} -tV AdrpAddLdr-addend-g16.exe | grep 'adr      x0' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpAddLdr-addend-g16.exe | grep 'ldr\th1, \[x0\]' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpAddLdr-addend-g16.exe | grep 'add      x0' | ${FAIL_IF_STDIN}
+       
+       # test ADRP/ADD/LD -> LDR when target is in __TEXT for 32-bit load
+       ${CC} ${CCFLAGS} AdrpAddLdr.s -c -o AdrpAddLdr-addend-g32.o -DFOO_AS_CONST -DLOAD_GPR_32 -DADDEND=8
+       ${CC} ${CCFLAGS} AdrpAddLdr-addend-g32.o main.o -o AdrpAddLdr-addend-g32.exe
+       ${OTOOL} -tV AdrpAddLdr-addend-g32.exe | grep 'ldr      w1, _8foo8' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpAddLdr-addend-g32.exe | grep 'adrp     x0' | ${FAIL_IF_STDIN}
+       ${OTOOL} -tV AdrpAddLdr-addend-g32.exe | grep 'add      x0' | ${FAIL_IF_STDIN}
+
+       # test ADRP/ADD/LD -> LDR when target is in __TEXT for 64-bit load
+       ${CC} ${CCFLAGS} AdrpAddLdr.s -c -o AdrpAddLdr-addend-g64.o -DFOO_AS_CONST -DLOAD_GPR_64 -DADDEND=8
+       ${CC} ${CCFLAGS} AdrpAddLdr-addend-g64.o main.o -o AdrpAddLdr-addend-g64.exe
+       ${OTOOL} -tV AdrpAddLdr-addend-g64.exe | grep 'ldr      x1, _8foo8' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpAddLdr-addend-g64.exe | grep 'adrp     x0' | ${FAIL_IF_STDIN}
+       ${OTOOL} -tV AdrpAddLdr-addend-g64.exe | grep 'add      x0' | ${FAIL_IF_STDIN}
+
+       # test ADRP/ADD/LD -> LDR when target is in __TEXT for 32-bit fp load
+       ${CC} ${CCFLAGS} AdrpAddLdr.s -c -o AdrpAddLdr-addend-f32.o -DFOO_AS_CONST -DLOAD_FPR_32 -DADDEND=8
+       ${CC} ${CCFLAGS} AdrpAddLdr-addend-f32.o main.o -o AdrpAddLdr-addend-f32.exe
+       ${OTOOL} -tV AdrpAddLdr-addend-f32.exe | grep 'ldr      s1, _8foo8' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpAddLdr-addend-f32.exe | grep 'adrp     x0' | ${FAIL_IF_STDIN}
+       ${OTOOL} -tV AdrpAddLdr-addend-f32.exe | grep 'add      x0' | ${FAIL_IF_STDIN}
+
+       # test ADRP/ADD/LD -> LDR when target is in __TEXT for 64-bit fp load
+       ${CC} ${CCFLAGS} AdrpAddLdr.s -c -o AdrpAddLdr-addend-f64.o -DFOO_AS_CONST -DLOAD_FPR_64 -DADDEND=8
+       ${CC} ${CCFLAGS} AdrpAddLdr-addend-f64.o main.o -o AdrpAddLdr-addend-f64.exe
+       ${OTOOL} -tV AdrpAddLdr-addend-f64.exe | grep 'ldr      d1, _8foo8' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpAddLdr-addend-f64.exe | grep 'adrp     x0' | ${FAIL_IF_STDIN}
+       ${OTOOL} -tV AdrpAddLdr-addend-f64.exe | grep 'add      x0' | ${FAIL_IF_STDIN}
+       
+       # test ADRP/ADD/LD -> LDR when target is in __TEXT for 128-bit vec load
+       ${CC} ${CCFLAGS} AdrpAddLdr.s -c -o AdrpAddLdr-addend-v128.o -DFOO_AS_CONST -DLOAD_VEC_128 -DADDEND=16
+       ${CC} ${CCFLAGS} AdrpAddLdr-addend-v128.o main.o -o AdrpAddLdr-addend-v128.exe 
+       ${OTOOL} -tV AdrpAddLdr-addend-v128.exe | grep 'ldr     q1, _16foo16' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpAddLdr-addend-v128.exe | grep 'adrp    x0' | ${FAIL_IF_STDIN}
+       ${OTOOL} -tV AdrpAddLdr-addend-v128.exe | grep 'add     x0' | ${FAIL_IF_STDIN}
+
+
+
+
+AdrpLdr: AdrpLdr-ldr AdrpLdr-seg AdrpLdr-addend
+       true
+
+AdrpLdr-ldr: main.o
+       # test ADRP/LDR left untouched when target is in __TEXT for 8-bit load
+       ${CC} ${CCFLAGS} AdrpLdr.s -c -o AdrpLdr-ldr-g8.o -DFOO_AS_CONST -DLOAD_GPR_8 
+       ${CC} ${CCFLAGS} AdrpLdr-ldr-g8.o main.o -o AdrpLdr-ldr-g8.exe 
+       ${OTOOL} -tV AdrpLdr-ldr-g8.exe | grep 'adrp\tx0,' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdr-ldr-g8.exe | grep 'ldr\tb1, \[x0,' | ${FAIL_IF_EMPTY}
+       
+       # test ADRP/LDR left untouched when target is in __TEXT for 16-bit load
+       ${CC} ${CCFLAGS} AdrpLdr.s -c -o AdrpLdr-ldr-g16.o -DFOO_AS_CONST -DLOAD_GPR_16
+       ${CC} ${CCFLAGS} AdrpLdr-ldr-g16.o main.o -o AdrpLdr-ldr-g16.exe
+       ${OTOOL} -tV AdrpLdr-ldr-g16.exe | grep 'adrp\tx0,' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdr-ldr-g16.exe | grep 'ldr\th1, \[x0,' | ${FAIL_IF_EMPTY}
+       
+       # test ADRP/LDR -> LDR when target is in __TEXT for 32-bit load
+       ${CC} ${CCFLAGS} AdrpLdr.s -c -o AdrpLdr-ldr-g32.o -DFOO_AS_CONST -DLOAD_GPR_32
+       ${CC} ${CCFLAGS} AdrpLdr-ldr-g32.o main.o -o AdrpLdr-ldr-g32.exe
+       ${OTOOL} -tV AdrpLdr-ldr-g32.exe | grep 'ldr    w1, _foo' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdr-ldr-g32.exe | grep 'adrp   x0' | ${FAIL_IF_STDIN}
+       ${OTOOL} -tV AdrpLdr-ldr-g32.exe | grep 'add    x0' | ${FAIL_IF_STDIN}
+
+       # test ADRP/LDR left untouched when target is in __TEXT for 32-bit load from signed 8-bit value
+       ${CC} ${CCFLAGS} AdrpLdr.s -c -o AdrpLdr-ldr-g32s8.o -DFOO_AS_CONST -DLOAD_GPR_32_S8
+       ${CC} ${CCFLAGS} AdrpLdr-ldr-g32s8.o main.o -o AdrpLdr-ldr-g32s8.exe
+       ${OTOOL} -tV AdrpLdr-ldr-g32s8.exe | grep 'adrp\tx0,' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdr-ldr-g32s8.exe | grep 'ldrsb\tw1, \[x0,' | ${FAIL_IF_EMPTY}
+
+       # test ADRP/LDR -> LDR when target is in __TEXT for 32-bit load from signed 16-bit value
+       ${CC} ${CCFLAGS} AdrpLdr.s -c -o AdrpLdr-ldr-g32s16.o -DFOO_AS_CONST -DLOAD_GPR_32_S16
+       ${CC} ${CCFLAGS} AdrpLdr-ldr-g32s16.o main.o -o AdrpLdr-ldr-g32s16.exe
+       ${OTOOL} -tV AdrpLdr-ldr-g32s16.exe | grep 'adrp\tx0,' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdr-ldr-g32s16.exe | grep 'ldrsh\tw1, \[x0,' | ${FAIL_IF_EMPTY}
+
+       # test ADRP/LDR -> LDR when target is in __TEXT for 64-bit load
+       ${CC} ${CCFLAGS} AdrpLdr.s -c -o AdrpLdr-ldr-g64.o -DFOO_AS_CONST -DLOAD_GPR_64
+       ${CC} ${CCFLAGS} AdrpLdr-ldr-g64.o main.o -o AdrpLdr-ldr-g64.exe
+       ${OTOOL} -tV AdrpLdr-ldr-g64.exe | grep 'ldr    x1, _foo' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdr-ldr-g64.exe | grep 'adrp   x0' | ${FAIL_IF_STDIN}
+       ${OTOOL} -tV AdrpLdr-ldr-g64.exe | grep 'add    x0' | ${FAIL_IF_STDIN}
+
+       # test ADRP/LDR left untouched when target is in __TEXT for 64-bit load from signed 8-bit value
+       ${CC} ${CCFLAGS} AdrpLdr.s -c -o AdrpLdr-ldr-g64s8.o -DFOO_AS_CONST -DLOAD_GPR_64_S8
+       ${CC} ${CCFLAGS} AdrpLdr-ldr-g64s8.o main.o -o AdrpLdr-ldr-g64s8.exe
+       ${OTOOL} -tV AdrpLdr-ldr-g64s8.exe | grep 'adrp\tx0,' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdr-ldr-g64s8.exe | grep 'ldrsb\tx1, \[x0,' | ${FAIL_IF_EMPTY}
+
+       # test ADRP/LDR left untouched when target is in __TEXT for 64-bit load from signed 16-bit value
+       ${CC} ${CCFLAGS} AdrpLdr.s -c -o AdrpLdr-ldr-g64s16.o -DFOO_AS_CONST -DLOAD_GPR_64_S16
+       ${CC} ${CCFLAGS} AdrpLdr-ldr-g64s16.o main.o -o AdrpLdr-ldr-g64s16.exe
+       ${OTOOL} -tV AdrpLdr-ldr-g64s16.exe | grep 'adrp\tx0,' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdr-ldr-g64s16.exe | grep 'ldrsh\tx1, \[x0,' | ${FAIL_IF_EMPTY}
+
+       # test ADRP/LDR -> LDR when target is in __TEXT for 64-bit load from signed 32-bit value
+       ${CC} ${CCFLAGS} AdrpLdr.s -c -o AdrpLdr-ldr-g64s32.o -DFOO_AS_CONST -DLOAD_GPR_64_S32
+       ${CC} ${CCFLAGS} AdrpLdr-ldr-g64s32.o main.o -o AdrpLdr-ldr-g64s32.exe
+       ${OTOOL} -tV AdrpLdr-ldr-g64s32.exe | grep 'ldrsw       x1, _foo' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdr-ldr-g64s32.exe | grep 'adrp        x0' | ${FAIL_IF_STDIN}
+       ${OTOOL} -tV AdrpLdr-ldr-g64s32.exe | grep 'add x0' | ${FAIL_IF_STDIN}
+
+       # test ADRP/LDR -> LDR when target is in __TEXT for 32-bit fp load
+       ${CC} ${CCFLAGS} AdrpLdr.s -c -o AdrpLdr-ldr-f32.o -DFOO_AS_CONST -DLOAD_FPR_32
+       ${CC} ${CCFLAGS} AdrpLdr-ldr-f32.o main.o -o AdrpLdr-ldr-f32.exe
+       ${OTOOL} -tV AdrpLdr-ldr-f32.exe | grep 'ldr    s1, _foo' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdr-ldr-f32.exe | grep 'adrp   x0' | ${FAIL_IF_STDIN}
+       ${OTOOL} -tV AdrpLdr-ldr-f32.exe | grep 'add    x0' | ${FAIL_IF_STDIN}
+
+       # test ADRP/LDR -> LDR when target is in __TEXT for 64-bit fp load
+       ${CC} ${CCFLAGS} AdrpLdr.s -c -o AdrpLdr-ldr-f64.o -DFOO_AS_CONST -DLOAD_FPR_64
+       ${CC} ${CCFLAGS} AdrpLdr-ldr-f64.o main.o -o AdrpLdr-ldr-f64.exe
+       ${OTOOL} -tV AdrpLdr-ldr-f64.exe | grep 'ldr    d1, _foo' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdr-ldr-f64.exe | grep 'adrp   x0' | ${FAIL_IF_STDIN}
+       ${OTOOL} -tV AdrpLdr-ldr-f64.exe | grep 'add    x0' | ${FAIL_IF_STDIN}
+       
+       # test ADRP/LDR -> LDR when target is in __TEXT for 128-bit vec load
+       ${CC} ${CCFLAGS} AdrpLdr.s -c -o AdrpLdr-ldr-v128.o -DFOO_AS_CONST -DLOAD_VEC_128
+       ${CC} ${CCFLAGS} AdrpLdr-ldr-v128.o main.o -o AdrpLdr-ldr-v128.exe
+       ${OTOOL} -tV AdrpLdr-ldr-v128.exe | grep 'ldr   q1, _foo' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdr-ldr-v128.exe | grep 'adrp  x0' | ${FAIL_IF_STDIN}
+       ${OTOOL} -tV AdrpLdr-ldr-v128.exe | grep 'add   x0' | ${FAIL_IF_STDIN}
+
+AdrpLdr-seg: 
+       # test ADRP/LDR left untouched when target is in __TEXT for 8-bit load
+       ${CC} ${CCFLAGS} AdrpLdr.s -c -o AdrpLdr-seg-g8.o -DFOO_AS_DATA -DLOAD_GPR_8 
+       ${CC} ${CCFLAGS} AdrpLdr-seg-g8.o  -dynamiclib -o AdrpLdr-seg-g8.dylib -install_name /usr/lib/libjunk.dylib
+       ${OTOOL} -tV AdrpLdr-seg-g8.dylib | grep 'adrp\tx0,' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdr-seg-g8.dylib | grep 'ldr\tb1, \[x0,' | ${FAIL_IF_EMPTY}
+       
+       # test ADRP/LDR left untouched when target is in __TEXT for 16-bit load
+       ${CC} ${CCFLAGS} AdrpLdr.s -c -o AdrpLdr-seg-g16.o -DFOO_AS_DATA -DLOAD_GPR_16
+       ${CC} ${CCFLAGS} AdrpLdr-seg-g16.o  -dynamiclib -o AdrpLdr-seg-g16.dylib -install_name /usr/lib/libjunk.dylib
+       ${OTOOL} -tV AdrpLdr-seg-g16.dylib | grep 'adrp\tx0,' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdr-seg-g16.dylib | grep 'ldr\th1, \[x0,' | ${FAIL_IF_EMPTY}
+       
+       # test ADRP/LDR -> LDR when target is in __TEXT for 32-bit load
+       ${CC} ${CCFLAGS} AdrpLdr.s -c -o AdrpLdr-seg-g32.o -DFOO_AS_DATA -DLOAD_GPR_32
+       ${CC} ${CCFLAGS} AdrpLdr-seg-g32.o  -dynamiclib -o AdrpLdr-seg-g32.dylib -install_name /usr/lib/libjunk.dylib
+       ${OTOOL} -tV AdrpLdr-seg-g32.dylib | grep 'adrp\tx0,' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdr-seg-g32.dylib | grep 'ldr\tw1, \[x0,' | ${FAIL_IF_EMPTY}
+
+       # test ADRP/LDR -> LDR when target is in __TEXT for 64-bit load
+       ${CC} ${CCFLAGS} AdrpLdr.s -c -o AdrpLdr-seg-g64.o -DFOO_AS_DATA -DLOAD_GPR_64
+       ${CC} ${CCFLAGS} AdrpLdr-seg-g64.o  -dynamiclib -o AdrpLdr-seg-g64.dylib -install_name /usr/lib/libjunk.dylib
+       ${OTOOL} -tV AdrpLdr-seg-g64.dylib | grep 'adrp\tx0,' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdr-seg-g64.dylib | grep 'ldr\tx1, \[x0,' | ${FAIL_IF_EMPTY}
+
+       # test ADRP/LDR -> LDR when target is in __TEXT for 32-bit fp load
+       ${CC} ${CCFLAGS} AdrpLdr.s -c -o AdrpLdr-seg-f32.o -DFOO_AS_DATA -DLOAD_FPR_32
+       ${CC} ${CCFLAGS} AdrpLdr-seg-f32.o  -dynamiclib -o AdrpLdr-seg-f32.dylib -install_name /usr/lib/libjunk.dylib
+       ${OTOOL} -tV AdrpLdr-seg-f32.dylib | grep 'adrp\tx0,' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdr-seg-f32.dylib | grep 'ldr\ts1, \[x0,' | ${FAIL_IF_EMPTY}
+
+       # test ADRP/LDR -> LDR when target is in __TEXT for 64-bit fp load
+       ${CC} ${CCFLAGS} AdrpLdr.s -c -o AdrpLdr-seg-f64.o -DFOO_AS_DATA -DLOAD_FPR_64
+       ${CC} ${CCFLAGS} AdrpLdr-seg-f64.o  -dynamiclib -o AdrpLdr-seg-f64.dylib -install_name /usr/lib/libjunk.dylib
+       ${OTOOL} -tV AdrpLdr-seg-f64.dylib | grep 'adrp\tx0,' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdr-seg-f64.dylib | grep 'ldr\td1, \[x0,' | ${FAIL_IF_EMPTY}
+       
+       # test ADRP/LDR -> LDR when target is in __TEXT for 128-bit vec load
+       ${CC} ${CCFLAGS} AdrpLdr.s -c -o AdrpLdr-seg-v128.o -DFOO_AS_DATA -DLOAD_VEC_128
+       ${CC} ${CCFLAGS} AdrpLdr-seg-v128.o  -dynamiclib -o AdrpLdr-seg-v128.dylib -install_name /usr/lib/libjunk.dylib
+       ${OTOOL} -tV AdrpLdr-seg-v128.dylib | grep 'adrp\tx0,' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdr-seg-v128.dylib | grep 'ldr\tq1, \[x0,' | ${FAIL_IF_EMPTY}
+
+AdrpLdr-addend: main.o
+       # test ADRP/LDR left untouched when target is in __TEXT for 8-bit load
+       ${CC} ${CCFLAGS} AdrpLdr.s -c -o AdrpLdr-addend-g8.o -DFOO_AS_DATA -DLOAD_GPR_8 -DADDEND=+8
+       ${CC} ${CCFLAGS} AdrpLdr-addend-g8.o main.o  -o AdrpLdr-addend-g8.exe 
+       ${OTOOL} -tV AdrpLdr-addend-g8.exe | grep 'adrp\tx0,' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdr-addend-g8.exe | grep 'ldr\tb1, \[x0,' | ${FAIL_IF_EMPTY}
+       
+       # test ADRP/LDR left untouched when target is in __TEXT for 16-bit load
+       ${CC} ${CCFLAGS} AdrpLdr.s -c -o AdrpLdr-addend-g16.o -DFOO_AS_DATA -DLOAD_GPR_16 -DADDEND=+8
+       ${CC} ${CCFLAGS} AdrpLdr-addend-g16.o main.o  -o AdrpLdr-addend-g16.exe 
+       ${OTOOL} -tV AdrpLdr-addend-g16.exe | grep 'adrp\tx0,' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdr-addend-g16.exe | grep 'ldr\th1, \[x0,' | ${FAIL_IF_EMPTY}
+       
+       # test ADRP/LDR -> LDR when target is in __TEXT for 32-bit load
+       ${CC} ${CCFLAGS} AdrpLdr.s -c -o AdrpLdr-addend-g32.o -DFOO_AS_DATA -DLOAD_GPR_32 -DADDEND=+8
+       ${CC} ${CCFLAGS} AdrpLdr-addend-g32.o main.o -o AdrpLdr-addend-g32.exe
+       ${OTOOL} -tV AdrpLdr-addend-g32.exe | grep 'ldr w1, _8foo8' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdr-addend-g32.exe | grep 'adrp        x0' | ${FAIL_IF_STDIN}
+       ${OTOOL} -tV AdrpLdr-addend-g32.exe | grep 'add x0' | ${FAIL_IF_STDIN}
+
+       # test ADRP/LDR -> LDR when target is in __TEXT for 64-bit load
+       ${CC} ${CCFLAGS} AdrpLdr.s -c -o AdrpLdr-addend-g64.o -DFOO_AS_DATA -DLOAD_GPR_64 -DADDEND=+8
+       ${CC} ${CCFLAGS} AdrpLdr-addend-g64.o main.o -o AdrpLdr-addend-g64.exe
+       ${OTOOL} -tV AdrpLdr-addend-g64.exe | grep 'ldr x1, _8foo8' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdr-addend-g64.exe | grep 'adrp        x0' | ${FAIL_IF_STDIN}
+       ${OTOOL} -tV AdrpLdr-addend-g64.exe | grep 'add x0' | ${FAIL_IF_STDIN}
+
+       # test ADRP/LDR -> LDR when target is in __TEXT for 32-bit fp load
+       ${CC} ${CCFLAGS} AdrpLdr.s -c -o AdrpLdr-addend-f32.o -DFOO_AS_DATA -DLOAD_FPR_32 -DADDEND=+8
+       ${CC} ${CCFLAGS} AdrpLdr-addend-f32.o main.o -o AdrpLdr-addend-f32.exe
+       ${OTOOL} -tV AdrpLdr-addend-f32.exe | grep 'ldr s1, _8foo8' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdr-addend-f32.exe | grep 'adrp        x0' | ${FAIL_IF_STDIN}
+       ${OTOOL} -tV AdrpLdr-addend-f32.exe | grep 'add x0' | ${FAIL_IF_STDIN}
+
+       # test ADRP/LDR -> LDR when target is in __TEXT for 64-bit fp load
+       ${CC} ${CCFLAGS} AdrpLdr.s -c -o AdrpLdr-addend-f64.o -DFOO_AS_DATA -DLOAD_FPR_64 -DADDEND=+8
+       ${CC} ${CCFLAGS} AdrpLdr-addend-f64.o main.o -o AdrpLdr-addend-f64.exe
+       ${OTOOL} -tV AdrpLdr-addend-f64.exe | grep 'ldr d1, _8foo8' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdr-addend-f64.exe | grep 'adrp        x0' | ${FAIL_IF_STDIN}
+       ${OTOOL} -tV AdrpLdr-addend-f64.exe | grep 'add x0' | ${FAIL_IF_STDIN}
+       
+       # test ADRP/LDR -> LDR when target is in __TEXT for 128-bit vec load
+       ${CC} ${CCFLAGS} AdrpLdr.s -c -o AdrpLdr-addend-v128.o -DFOO_AS_DATA -DLOAD_VEC_128 -DADDEND=+16
+       ${CC} ${CCFLAGS} AdrpLdr-addend-v128.o main.o -o AdrpLdr-addend-v128.exe
+       ${OTOOL} -tV AdrpLdr-addend-v128.exe | grep 'ldr        q1, _16foo16' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdr-addend-v128.exe | grep 'adrp       x0' | ${FAIL_IF_STDIN}
+       ${OTOOL} -tV AdrpLdr-addend-v128.exe | grep 'add        x0' | ${FAIL_IF_STDIN}
+
+
+AdrpLdrGotLdr: AdrpLdrGotLdr-extern AdrpLdrGotLdr-externfargot AdrpLdrGotLdr-near AdrpLdrGotLdr-far AdrpLdrGotLdr-nearunaligned AdrpLdrGotLdr-farunaligned
+       true
+
+AdrpLdrGotLdr-extern: main.o
+       # test ADRP/LDR/LDR -> LDR/LDR when GOT slot is close  for 8-bit load
+       ${CC} ${CCFLAGS} AdrpLdrGotLdr.s -c -o AdrpLdrGotLdr-extern-g8.o -DFOO_AS_CONST -DLOAD_GPR_8 -DTARGET=_malloc
+       ${CC} ${CCFLAGS} AdrpLdrGotLdr-extern-g8.o main.o -o AdrpLdrGotLdr-extern-g8.exe 
+       ${OTOOL} -tV AdrpLdrGotLdr-extern-g8.exe | grep 'adrp' | ${FAIL_IF_STDIN}
+       ${OTOOL} -tV AdrpLdrGotLdr-extern-g8.exe | grep 'ldr\tx1,' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdrGotLdr-extern-g8.exe | grep 'ldr\tb2, \[x1\]' | ${FAIL_IF_EMPTY}
+       
+       # test ADRP/LDR/LDR -> LDR/LDR when GOT slot is close  for 16-bit load
+       ${CC} ${CCFLAGS} AdrpLdrGotLdr.s -c -o AdrpLdrGotLdr-extern-g16.o -DFOO_AS_CONST -DLOAD_GPR_16 -DTARGET=_malloc
+       ${CC} ${CCFLAGS} AdrpLdrGotLdr-extern-g16.o main.o -o AdrpLdrGotLdr-extern-g16.exe 
+       ${OTOOL} -tV AdrpLdrGotLdr-extern-g16.exe | grep 'adrp' | ${FAIL_IF_STDIN}
+       ${OTOOL} -tV AdrpLdrGotLdr-extern-g16.exe | grep 'ldr\tx1,' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdrGotLdr-extern-g16.exe | grep 'ldr\th2, \[x1\]' | ${FAIL_IF_EMPTY}
+       
+       # test ADRP/LDR/LDR -> LDR/LDR when GOT slot is close for 32-bit load
+       ${CC} ${CCFLAGS} AdrpLdrGotLdr.s -c -o AdrpLdrGotLdr-extern-g32.o -DFOO_AS_CONST -DLOAD_GPR_32 -DTARGET=_malloc
+       ${CC} ${CCFLAGS} AdrpLdrGotLdr-extern-g32.o main.o -o AdrpLdrGotLdr-extern-g32.exe 
+       ${OTOOL} -tV AdrpLdrGotLdr-extern-g32.exe | grep 'adrp' | ${FAIL_IF_STDIN}
+       ${OTOOL} -tV AdrpLdrGotLdr-extern-g32.exe | grep 'ldr\tx1,' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdrGotLdr-extern-g32.exe | grep 'ldr\tw2, \[x1\]' | ${FAIL_IF_EMPTY}
+
+       # test ADRP/LDR/LDR -> LDR/LDR when GOT slot is close for 64-bit load
+       ${CC} ${CCFLAGS} AdrpLdrGotLdr.s -c -o AdrpLdrGotLdr-extern-g64.o -DFOO_AS_CONST -DLOAD_GPR_64 -DTARGET=_malloc
+       ${CC} ${CCFLAGS} AdrpLdrGotLdr-extern-g64.o main.o -o AdrpLdrGotLdr-extern-g64.exe 
+       ${OTOOL} -tV AdrpLdrGotLdr-extern-g64.exe | grep 'adrp' | ${FAIL_IF_STDIN}
+       ${OTOOL} -tV AdrpLdrGotLdr-extern-g64.exe | grep 'ldr\tx1,' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdrGotLdr-extern-g64.exe | grep 'ldr\tx2, \[x1\]' | ${FAIL_IF_EMPTY}
+
+       # test ADRP/LDR/LDR -> LDR/LDR when GOT slot is close for 32-bit fp load
+       ${CC} ${CCFLAGS} AdrpLdrGotLdr.s -c -o AdrpLdrGotLdr-extern-f32.o -DFOO_AS_CONST -DLOAD_FPR_32 -DTARGET=_malloc
+       ${CC} ${CCFLAGS} AdrpLdrGotLdr-extern-f32.o main.o -o AdrpLdrGotLdr-extern-f32.exe 
+       ${OTOOL} -tV AdrpLdrGotLdr-extern-f32.exe | grep 'adrp' | ${FAIL_IF_STDIN}
+       ${OTOOL} -tV AdrpLdrGotLdr-extern-f32.exe | grep 'ldr\tx1,' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdrGotLdr-extern-f32.exe | grep 'ldr\ts2, \[x1\]' | ${FAIL_IF_EMPTY}
+
+       # test ADRP/LDR/LDR -> LDR/LDR when GOT slot is close for 64-bit fp load
+       ${CC} ${CCFLAGS} AdrpLdrGotLdr.s -c -o AdrpLdrGotLdr-extern-f64.o -DFOO_AS_CONST -DLOAD_FPR_64 -DTARGET=_malloc
+       ${CC} ${CCFLAGS} AdrpLdrGotLdr-extern-f64.o main.o -o AdrpLdrGotLdr-extern-f64.exe 
+       ${OTOOL} -tV AdrpLdrGotLdr-extern-f64.exe | grep 'adrp' | ${FAIL_IF_STDIN}
+       ${OTOOL} -tV AdrpLdrGotLdr-extern-f64.exe | grep 'ldr\tx1,' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdrGotLdr-extern-f64.exe | grep 'ldr\td2, \[x1\]' | ${FAIL_IF_EMPTY}
+       
+       # test ADRP/LDR/LDR -> LDR/LDR when GOT slot is close for 128-bit vec load
+       ${CC} ${CCFLAGS} AdrpLdrGotLdr.s -c -o AdrpLdrGotLdr-extern-v128.o -DFOO_AS_CONST -DLOAD_VEC_128 -DTARGET=_malloc
+       ${CC} ${CCFLAGS} AdrpLdrGotLdr-extern-v128.o main.o -o AdrpLdrGotLdr-extern-v128.exe 
+       ${OTOOL} -tV AdrpLdrGotLdr-extern-v128.exe | grep 'adrp' | ${FAIL_IF_STDIN}
+       ${OTOOL} -tV AdrpLdrGotLdr-extern-v128.exe | grep 'ldr\tx1,' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdrGotLdr-extern-v128.exe | grep 'ldr\tq2, \[x1\]' | ${FAIL_IF_EMPTY}
+
+
+AdrpLdrGotLdr-externfargot: main.o
+       # test ADRP/LDR/LDR left untouched when target is external and GOT slot far for 8-bit load
+       ${CC} ${CCFLAGS} AdrpLdrGotLdr.s -c -o AdrpLdrGotLdr-externfargot-g8.o -DFOO_AS_CONST -DLOAD_GPR_8 -DTARGET=_malloc -DPADDING
+       ${CC} ${CCFLAGS} AdrpLdrGotLdr-externfargot-g8.o main.o -o AdrpLdrGotLdr-externfargot-g8.exe 
+       ${OTOOL} -tV AdrpLdrGotLdr-externfargot-g8.exe | grep 'adrp' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdrGotLdr-externfargot-g8.exe | grep 'ldr\tx1, \[x0' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdrGotLdr-externfargot-g8.exe | grep 'ldr\tb2, \[x1\]' | ${FAIL_IF_EMPTY}
+       
+       # test ADRP/LDR/LDR left untouched when target is external and GOT slot far for 16-bit load
+       ${CC} ${CCFLAGS} AdrpLdrGotLdr.s -c -o AdrpLdrGotLdr-externfargot-g16.o -DFOO_AS_CONST -DLOAD_GPR_16 -DTARGET=_malloc -DPADDING
+       ${CC} ${CCFLAGS} AdrpLdrGotLdr-externfargot-g16.o main.o -o AdrpLdrGotLdr-externfargot-g16.exe 
+       ${OTOOL} -tV AdrpLdrGotLdr-externfargot-g16.exe | grep 'adrp' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdrGotLdr-externfargot-g16.exe | grep 'ldr\tx1, \[x0' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdrGotLdr-externfargot-g16.exe | grep 'ldr\th2, \[x1\]' | ${FAIL_IF_EMPTY}
+       
+       # test ADRP/LDR/LDR left untouched when target is external and GOT slot farfor 32-bit load
+       ${CC} ${CCFLAGS} AdrpLdrGotLdr.s -c -o AdrpLdrGotLdr-externfargot-g32.o -DFOO_AS_CONST -DLOAD_GPR_32 -DTARGET=_malloc -DPADDING
+       ${CC} ${CCFLAGS} AdrpLdrGotLdr-externfargot-g32.o main.o -o AdrpLdrGotLdr-externfargot-g32.exe 
+       ${OTOOL} -tV AdrpLdrGotLdr-externfargot-g32.exe | grep 'adrp' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdrGotLdr-externfargot-g32.exe | grep 'ldr\tx1, \[x0' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdrGotLdr-externfargot-g32.exe | grep 'ldr\tw2, \[x1\]' | ${FAIL_IF_EMPTY}
+
+       # test ADRP/LDR/LDR left untouched when target is external and GOT slot far for 64-bit load
+       ${CC} ${CCFLAGS} AdrpLdrGotLdr.s -c -o AdrpLdrGotLdr-externfargot-g64.o -DFOO_AS_CONST -DLOAD_GPR_64 -DTARGET=_malloc -DPADDING
+       ${CC} ${CCFLAGS} AdrpLdrGotLdr-externfargot-g64.o main.o -o AdrpLdrGotLdr-externfargot-g64.exe 
+       ${OTOOL} -tV AdrpLdrGotLdr-externfargot-g64.exe | grep 'adrp' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdrGotLdr-externfargot-g64.exe | grep 'ldr\tx1, \[x0' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdrGotLdr-externfargot-g64.exe | grep 'ldr\tx2, \[x1\]' | ${FAIL_IF_EMPTY}
+
+       # test ADRP/LDR/LDR left untouched when target is external and GOT slot far for 32-bit fp load
+       ${CC} ${CCFLAGS} AdrpLdrGotLdr.s -c -o AdrpLdrGotLdr-externfargot-f32.o -DFOO_AS_CONST -DLOAD_FPR_32 -DTARGET=_malloc -DPADDING
+       ${CC} ${CCFLAGS} AdrpLdrGotLdr-externfargot-f32.o main.o -o AdrpLdrGotLdr-externfargot-f32.exe 
+       ${OTOOL} -tV AdrpLdrGotLdr-externfargot-f32.exe | grep 'adrp' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdrGotLdr-externfargot-f32.exe | grep 'ldr\tx1, \[x0' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdrGotLdr-externfargot-f32.exe | grep 'ldr\ts2, \[x1\]' | ${FAIL_IF_EMPTY}
+
+       # test ADRP/LDR/LDR left untouched when target is external and GOT slot far for 64-bit fp load
+       ${CC} ${CCFLAGS} AdrpLdrGotLdr.s -c -o AdrpLdrGotLdr-externfargot-f64.o -DFOO_AS_CONST -DLOAD_FPR_64 -DTARGET=_malloc -DPADDING
+       ${CC} ${CCFLAGS} AdrpLdrGotLdr-externfargot-f64.o main.o -o AdrpLdrGotLdr-externfargot-f64.exe 
+       ${OTOOL} -tV AdrpLdrGotLdr-externfargot-f64.exe | grep 'adrp' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdrGotLdr-externfargot-f64.exe | grep 'ldr\tx1, \[x0' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdrGotLdr-externfargot-f64.exe | grep 'ldr\td2, \[x1\]' | ${FAIL_IF_EMPTY}
+       
+       # test ADRP/LDR/LDR -left untouched when target is external and GOT slot far for 128-bit vec load
+       ${CC} ${CCFLAGS} AdrpLdrGotLdr.s -c -o AdrpLdrGotLdr-externfargot-v128.o -DFOO_AS_CONST -DLOAD_VEC_128 -DTARGET=_malloc -DPADDING
+       ${CC} ${CCFLAGS} AdrpLdrGotLdr-externfargot-v128.o main.o -o AdrpLdrGotLdr-externfargot-v128.exe 
+       ${OTOOL} -tV AdrpLdrGotLdr-externfargot-v128.exe | grep 'adrp' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdrGotLdr-externfargot-v128.exe | grep 'ldr\tx1, \[x0' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdrGotLdr-externfargot-v128.exe | grep 'ldr\tq2, \[x1\]' | ${FAIL_IF_EMPTY}
+
+
+AdrpLdrGotLdr-near: main.o 
+       # test ADRP/LDR left untouched when target is in __TEXT for 8-bit load
+       ${CC} ${CCFLAGS} AdrpLdrGotLdr.s -c -o AdrpLdrGotLdr-near-g8.o -DFOO_AS_CONST -DLOAD_GPR_8 
+       ${CC} ${CCFLAGS} AdrpLdrGotLdr-near-g8.o main.o -o AdrpLdrGotLdr-near-g8.exe 
+       ${OTOOL} -tV AdrpLdrGotLdr-near-g8.exe | grep 'adrp' | ${FAIL_IF_STDIN}
+       ${OTOOL} -tV AdrpLdrGotLdr-near-g8.exe | grep 'adr\tx1,' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdrGotLdr-near-g8.exe | grep 'ldr\tb2, \[x1\]' | ${FAIL_IF_EMPTY}
+
+       # test ADRP/LDR/LDR left untouched when target is external and GOT slot far for 16-bit load
+       ${CC} ${CCFLAGS} AdrpLdrGotLdr.s -c -o AdrpLdrGotLdr-near-g16.o -DFOO_AS_CONST -DLOAD_GPR_16 
+       ${CC} ${CCFLAGS} AdrpLdrGotLdr-near-g16.o main.o -o AdrpLdrGotLdr-near-g16.exe 
+       ${OTOOL} -tV AdrpLdrGotLdr-near-g16.exe | grep 'adrp' | ${FAIL_IF_STDIN}
+       ${OTOOL} -tV AdrpLdrGotLdr-near-g16.exe | grep 'adr\tx1,' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdrGotLdr-near-g16.exe | grep 'ldr\th2, \[x1\]' | ${FAIL_IF_EMPTY}
+       
+       # test ADRP/LDR/LDR -> LDR literal when target close for 32-bit load
+       ${CC} ${CCFLAGS} AdrpLdrGotLdr.s -c -o AdrpLdrGotLdr-near-g32.o -DFOO_AS_CONST -DLOAD_GPR_32 
+       ${CC} ${CCFLAGS} AdrpLdrGotLdr-near-g32.o main.o -o AdrpLdrGotLdr-near-g32.exe 
+       ${OTOOL} -tV AdrpLdrGotLdr-near-g32.exe | grep 'adrp' | ${FAIL_IF_STDIN}
+       ${OTOOL} -tV AdrpLdrGotLdr-near-g32.exe | grep 'ldr\tx1, \[x0' | ${FAIL_IF_STDIN}
+       ${OTOOL} -tV AdrpLdrGotLdr-near-g32.exe | grep 'ldr\tw2, _foo' | ${FAIL_IF_EMPTY}
+
+       # test ADRP/LDR/LDR left untouched when target is external and GOT slot far for 64-bit load
+       ${CC} ${CCFLAGS} AdrpLdrGotLdr.s -c -o AdrpLdrGotLdr-near-g64.o -DFOO_AS_CONST -DLOAD_GPR_64 
+       ${CC} ${CCFLAGS} AdrpLdrGotLdr-near-g64.o main.o -o AdrpLdrGotLdr-near-g64.exe 
+       ${OTOOL} -tV AdrpLdrGotLdr-near-g64.exe | grep 'adrp' | ${FAIL_IF_STDIN}
+       ${OTOOL} -tV AdrpLdrGotLdr-near-g64.exe | grep 'ldr\tx1, \[x0' | ${FAIL_IF_STDIN}
+       ${OTOOL} -tV AdrpLdrGotLdr-near-g64.exe | grep 'ldr\tx2, _foo' | ${FAIL_IF_EMPTY}
+
+       # test ADRP/LDR/LDR left untouched when target is external and GOT slot far for 32-bit fp load
+       ${CC} ${CCFLAGS} AdrpLdrGotLdr.s -c -o AdrpLdrGotLdr-near-f32.o -DFOO_AS_CONST -DLOAD_FPR_32 
+       ${CC} ${CCFLAGS} AdrpLdrGotLdr-near-f32.o main.o -o AdrpLdrGotLdr-near-f32.exe 
+       ${OTOOL} -tV AdrpLdrGotLdr-near-f32.exe | grep 'adrp' | ${FAIL_IF_STDIN}
+       ${OTOOL} -tV AdrpLdrGotLdr-near-f32.exe | grep 'ldr\tx1, \[x0' | ${FAIL_IF_STDIN}
+       ${OTOOL} -tV AdrpLdrGotLdr-near-f32.exe | grep 'ldr\ts2, _foo' | ${FAIL_IF_EMPTY}
+
+       # test ADRP/LDR/LDR left untouched when target is external and GOT slot far for 64-bit fp load
+       ${CC} ${CCFLAGS} AdrpLdrGotLdr.s -c -o AdrpLdrGotLdr-near-f64.o -DFOO_AS_CONST -DLOAD_FPR_64 
+       ${CC} ${CCFLAGS} AdrpLdrGotLdr-near-f64.o main.o -o AdrpLdrGotLdr-near-f64.exe 
+       ${OTOOL} -tV AdrpLdrGotLdr-near-f64.exe | grep 'adrp' | ${FAIL_IF_STDIN}
+       ${OTOOL} -tV AdrpLdrGotLdr-near-f64.exe | grep 'ldr\tx1, \[x0' | ${FAIL_IF_STDIN}
+       ${OTOOL} -tV AdrpLdrGotLdr-near-f64.exe | grep 'ldr\td2, _foo' | ${FAIL_IF_EMPTY}
+       
+       # test ADRP/LDR/LDR -left untouched when target is external and GOT slot far for 128-bit vec load
+       ${CC} ${CCFLAGS} AdrpLdrGotLdr.s -c -o AdrpLdrGotLdr-near-v128.o -DFOO_AS_CONST -DLOAD_VEC_128 
+       ${CC} ${CCFLAGS} AdrpLdrGotLdr-near-v128.o main.o -o AdrpLdrGotLdr-near-v128.exe 
+       ${OTOOL} -tV AdrpLdrGotLdr-near-v128.exe | grep 'adrp' | ${FAIL_IF_STDIN}
+       ${OTOOL} -tV AdrpLdrGotLdr-near-v128.exe | grep 'ldr\tx1, \[x0' | ${FAIL_IF_STDIN}
+       ${OTOOL} -tV AdrpLdrGotLdr-near-v128.exe | grep 'ldr\tq2, _foo' | ${FAIL_IF_EMPTY}
+
+
+AdrpLdrGotLdr-nearunaligned: main.o 
+       # test ADRP/LDR left untouched when target is in __TEXT for 8-bit load
+       ${CC} ${CCFLAGS} AdrpLdrGotLdr.s -c -o AdrpLdrGotLdr-nearunaligned-g8.o -DFOO_AS_CONST -DLOAD_GPR_8 -DMISALIGN_DATA
+       ${CC} ${CCFLAGS} AdrpLdrGotLdr-nearunaligned-g8.o main.o -o AdrpLdrGotLdr-nearunaligned-g8.exe 
+       ${OTOOL} -tV AdrpLdrGotLdr-nearunaligned-g8.exe | grep 'adrp' | ${FAIL_IF_STDIN}
+       ${OTOOL} -tV AdrpLdrGotLdr-nearunaligned-g8.exe | grep 'adr\tx1,' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdrGotLdr-nearunaligned-g8.exe | grep 'ldr\tb2, \[x1\]' | ${FAIL_IF_EMPTY}
+
+       # test ADRP/LDR/LDR left untouched when target is external and GOT slot far for 16-bit load
+       ${CC} ${CCFLAGS} AdrpLdrGotLdr.s -c -o AdrpLdrGotLdr-nearunaligned-g16.o -DFOO_AS_CONST -DLOAD_GPR_16 -DMISALIGN_DATA
+       ${CC} ${CCFLAGS} AdrpLdrGotLdr-nearunaligned-g16.o main.o -o AdrpLdrGotLdr-nearunaligned-g16.exe 
+       ${OTOOL} -tV AdrpLdrGotLdr-nearunaligned-g16.exe | grep 'adrp' | ${FAIL_IF_STDIN}
+       ${OTOOL} -tV AdrpLdrGotLdr-nearunaligned-g16.exe | grep 'adr\tx1,' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdrGotLdr-nearunaligned-g16.exe | grep 'ldr\th2, \[x1\]' | ${FAIL_IF_EMPTY}
+       
+       # test ADRP/LDR/LDR -> LDR literal when target close for 32-bit load
+       ${CC} ${CCFLAGS} AdrpLdrGotLdr.s -c -o AdrpLdrGotLdr-nearunaligned-g32.o -DFOO_AS_CONST -DLOAD_GPR_32 -DMISALIGN_DATA
+       ${CC} ${CCFLAGS} AdrpLdrGotLdr-nearunaligned-g32.o main.o -o AdrpLdrGotLdr-nearunaligned-g32.exe 
+       ${OTOOL} -tV AdrpLdrGotLdr-nearunaligned-g32.exe | grep 'adrp' | ${FAIL_IF_STDIN}
+       ${OTOOL} -tV AdrpLdrGotLdr-nearunaligned-g32.exe | grep 'adr\tx1,' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdrGotLdr-nearunaligned-g32.exe | grep 'ldr\tw2, \[x1\]' | ${FAIL_IF_EMPTY}
+
+       # test ADRP/LDR/LDR left untouched when target is external and GOT slot far for 64-bit load
+       ${CC} ${CCFLAGS} AdrpLdrGotLdr.s -c -o AdrpLdrGotLdr-nearunaligned-g64.o -DFOO_AS_CONST -DLOAD_GPR_64 -DMISALIGN_DATA
+       ${CC} ${CCFLAGS} AdrpLdrGotLdr-nearunaligned-g64.o main.o -o AdrpLdrGotLdr-nearunaligned-g64.exe 
+       ${OTOOL} -tV AdrpLdrGotLdr-nearunaligned-g64.exe | grep 'adrp' | ${FAIL_IF_STDIN}
+       ${OTOOL} -tV AdrpLdrGotLdr-nearunaligned-g64.exe | grep 'adr\tx1,' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdrGotLdr-nearunaligned-g64.exe | grep 'ldr\tx2, \[x1\]' | ${FAIL_IF_EMPTY}
+
+       # test ADRP/LDR/LDR left untouched when target is external and GOT slot far for 32-bit fp load
+       ${CC} ${CCFLAGS} AdrpLdrGotLdr.s -c -o AdrpLdrGotLdr-nearunaligned-f32.o -DFOO_AS_CONST -DLOAD_FPR_32 -DMISALIGN_DATA
+       ${CC} ${CCFLAGS} AdrpLdrGotLdr-nearunaligned-f32.o main.o -o AdrpLdrGotLdr-nearunaligned-f32.exe 
+       ${OTOOL} -tV AdrpLdrGotLdr-nearunaligned-f32.exe | grep 'adrp' | ${FAIL_IF_STDIN}
+       ${OTOOL} -tV AdrpLdrGotLdr-nearunaligned-f32.exe | grep 'adr\tx1,' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdrGotLdr-nearunaligned-f32.exe | grep 'ldr\ts2, \[x1\]' | ${FAIL_IF_EMPTY}
+
+       # test ADRP/LDR/LDR left untouched when target is external and GOT slot far for 64-bit fp load
+       ${CC} ${CCFLAGS} AdrpLdrGotLdr.s -c -o AdrpLdrGotLdr-nearunaligned-f64.o -DFOO_AS_CONST -DLOAD_FPR_64 -DMISALIGN_DATA
+       ${CC} ${CCFLAGS} AdrpLdrGotLdr-nearunaligned-f64.o main.o -o AdrpLdrGotLdr-nearunaligned-f64.exe 
+       ${OTOOL} -tV AdrpLdrGotLdr-nearunaligned-f64.exe | grep 'adrp' | ${FAIL_IF_STDIN}
+       ${OTOOL} -tV AdrpLdrGotLdr-nearunaligned-f64.exe | grep 'adr\tx1,' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdrGotLdr-nearunaligned-f64.exe | grep 'ldr\td2, \[x1\]' | ${FAIL_IF_EMPTY}
+       
+       # test ADRP/LDR/LDR -left untouched when target is external and GOT slot far for 128-bit vec load
+       ${CC} ${CCFLAGS} AdrpLdrGotLdr.s -c -o AdrpLdrGotLdr-nearunaligned-v128.o -DFOO_AS_CONST -DLOAD_VEC_128 -DMISALIGN_DATA
+       ${CC} ${CCFLAGS} AdrpLdrGotLdr-nearunaligned-v128.o main.o -o AdrpLdrGotLdr-nearunaligned-v128.exe 
+       ${OTOOL} -tV AdrpLdrGotLdr-nearunaligned-v128.exe | grep 'adrp' | ${FAIL_IF_STDIN}
+       ${OTOOL} -tV AdrpLdrGotLdr-nearunaligned-v128.exe | grep 'adr\tx1,' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdrGotLdr-nearunaligned-v128.exe | grep 'ldr\tq2, \[x1\]' | ${FAIL_IF_EMPTY}
+
+
+AdrpLdrGotLdr-far: main.o 
+       # test ADRP/LDR left untouched when target is in __TEXT for 8-bit load
+       ${CC} ${CCFLAGS} AdrpLdrGotLdr.s -c -o AdrpLdrGotLdr-far-g8.o -DFOO_AS_CONST -DLOAD_GPR_8 -DPADDING
+       ${CC} ${CCFLAGS} AdrpLdrGotLdr-far-g8.o main.o -o AdrpLdrGotLdr-far-g8.exe 
+       ${OTOOL} -tV AdrpLdrGotLdr-far-g8.exe | grep 'adrp\tx0' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdrGotLdr-far-g8.exe | grep 'add\t' | ${FAIL_IF_STDIN}
+       ${OTOOL} -tV AdrpLdrGotLdr-far-g8.exe | grep 'ldr\tb2, \[x0,' | ${FAIL_IF_EMPTY}
+
+       # test ADRP/LDR/LDR left untouched when target is external and GOT slot far for 16-bit load
+       ${CC} ${CCFLAGS} AdrpLdrGotLdr.s -c -o AdrpLdrGotLdr-far-g16.o -DFOO_AS_CONST -DLOAD_GPR_16 -DPADDING
+       ${CC} ${CCFLAGS} AdrpLdrGotLdr-far-g16.o main.o -o AdrpLdrGotLdr-far-g16.exe  
+       ${OTOOL} -tV AdrpLdrGotLdr-far-g16.exe | grep 'adrp\tx0' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdrGotLdr-far-g16.exe | grep 'add\t' | ${FAIL_IF_STDIN}
+       ${OTOOL} -tV AdrpLdrGotLdr-far-g16.exe | grep 'ldr\th2, \[x0,' | ${FAIL_IF_EMPTY}
+       
+       # test ADRP/LDR/LDR -> LDR literal when target close for 32-bit load
+       ${CC} ${CCFLAGS} AdrpLdrGotLdr.s -c -o AdrpLdrGotLdr-far-g32.o -DFOO_AS_CONST -DLOAD_GPR_32 -DPADDING 
+       ${CC} ${CCFLAGS} AdrpLdrGotLdr-far-g32.o main.o -o AdrpLdrGotLdr-far-g32.exe  
+       ${OTOOL} -tV AdrpLdrGotLdr-far-g32.exe | grep 'adrp\tx0' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdrGotLdr-far-g32.exe | grep 'add\t' | ${FAIL_IF_STDIN}
+       ${OTOOL} -tV AdrpLdrGotLdr-far-g32.exe | grep 'ldr\tw2, \[x0,' | ${FAIL_IF_EMPTY}
+
+       # test ADRP/LDR/LDR left untouched when target is external and GOT slot far for 64-bit load
+       ${CC} ${CCFLAGS} AdrpLdrGotLdr.s -c -o AdrpLdrGotLdr-far-g64.o -DFOO_AS_CONST -DLOAD_GPR_64 -DPADDING 
+       ${CC} ${CCFLAGS} AdrpLdrGotLdr-far-g64.o main.o -o AdrpLdrGotLdr-far-g64.exe  
+       ${OTOOL} -tV AdrpLdrGotLdr-far-g64.exe | grep 'adrp\tx0' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdrGotLdr-far-g64.exe | grep 'add\t' | ${FAIL_IF_STDIN}
+       ${OTOOL} -tV AdrpLdrGotLdr-far-g64.exe | grep 'ldr\tx2, \[x0,' | ${FAIL_IF_EMPTY}
+
+       # test ADRP/LDR/LDR left untouched when target is external and GOT slot far for 32-bit fp load
+       ${CC} ${CCFLAGS} AdrpLdrGotLdr.s -c -o AdrpLdrGotLdr-far-f32.o -DFOO_AS_CONST -DLOAD_FPR_32 -DPADDING 
+       ${CC} ${CCFLAGS} AdrpLdrGotLdr-far-f32.o main.o -o AdrpLdrGotLdr-far-f32.exe  
+       ${OTOOL} -tV AdrpLdrGotLdr-far-f32.exe | grep 'adrp\tx0' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdrGotLdr-far-f32.exe | grep 'add\t' | ${FAIL_IF_STDIN}
+       ${OTOOL} -tV AdrpLdrGotLdr-far-f32.exe | grep 'ldr\ts2, \[x0,' | ${FAIL_IF_EMPTY}
+
+       # test ADRP/LDR/LDR left untouched when target is external and GOT slot far for 64-bit fp load
+       ${CC} ${CCFLAGS} AdrpLdrGotLdr.s -c -o AdrpLdrGotLdr-far-f64.o -DFOO_AS_CONST -DLOAD_FPR_64 -DPADDING 
+       ${CC} ${CCFLAGS} AdrpLdrGotLdr-far-f64.o main.o -o AdrpLdrGotLdr-far-f64.exe  
+       ${OTOOL} -tV AdrpLdrGotLdr-far-f64.exe | grep 'adrp\tx0' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdrGotLdr-far-f64.exe | grep 'add\t' | ${FAIL_IF_STDIN}
+       ${OTOOL} -tV AdrpLdrGotLdr-far-f64.exe | grep 'ldr\td2, \[x0,' | ${FAIL_IF_EMPTY}
+       
+       # test ADRP/LDR/LDR -left untouched when target is external and GOT slot far for 128-bit vec load
+       ${CC} ${CCFLAGS} AdrpLdrGotLdr.s -c -o AdrpLdrGotLdr-far-v128.o -DFOO_AS_CONST -DLOAD_VEC_128 -DPADDING 
+       ${CC} ${CCFLAGS} AdrpLdrGotLdr-far-v128.o main.o -o AdrpLdrGotLdr-far-v128.exe  
+       ${OTOOL} -tV AdrpLdrGotLdr-far-v128.exe | grep 'adrp\tx0' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdrGotLdr-far-v128.exe | grep 'add\t' | ${FAIL_IF_STDIN}
+       ${OTOOL} -tV AdrpLdrGotLdr-far-v128.exe | grep 'ldr\tq2, \[x0,' | ${FAIL_IF_EMPTY}
+
+
+AdrpLdrGotLdr-farunaligned: main.o 
+       # test ADRP/LDR left untouched when target is in __TEXT for 8-bit load
+       ${CC} ${CCFLAGS} AdrpLdrGotLdr.s -c -o AdrpLdrGotLdr-farunaligned-g8.o -DFOO_AS_CONST -DLOAD_GPR_8 -DMISALIGN_DATA -DPADDING
+       ${CC} ${CCFLAGS} AdrpLdrGotLdr-farunaligned-g8.o main.o -o AdrpLdrGotLdr-farunaligned-g8.exe 
+       ${OTOOL} -tV AdrpLdrGotLdr-farunaligned-g8.exe | grep 'adrp' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdrGotLdr-farunaligned-g8.exe | grep 'add\t' | ${FAIL_IF_STDIN}
+       ${OTOOL} -tV AdrpLdrGotLdr-farunaligned-g8.exe | grep 'ldr\tb2, \[x0,' | ${FAIL_IF_EMPTY}
+
+       # test ADRP/LDR/LDR left untouched when target is external and GOT slot far for 16-bit load
+       ${CC} ${CCFLAGS} AdrpLdrGotLdr.s -c -o AdrpLdrGotLdr-farunaligned-g16.o -DFOO_AS_CONST -DLOAD_GPR_16 -DMISALIGN_DATA -DPADDING
+       ${CC} ${CCFLAGS} AdrpLdrGotLdr-farunaligned-g16.o main.o -o AdrpLdrGotLdr-farunaligned-g16.exe 
+       ${OTOOL} -tV AdrpLdrGotLdr-farunaligned-g16.exe | grep 'adrp' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdrGotLdr-farunaligned-g16.exe | grep 'add\t' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdrGotLdr-farunaligned-g16.exe | grep 'ldr\th2, \[x1\]' | ${FAIL_IF_EMPTY}
+       
+       # test ADRP/LDR/LDR -> LDR literal when target close for 32-bit load
+       ${CC} ${CCFLAGS} AdrpLdrGotLdr.s -c -o AdrpLdrGotLdr-farunaligned-g32.o -DFOO_AS_CONST -DLOAD_GPR_32 -DMISALIGN_DATA -DPADDING
+       ${CC} ${CCFLAGS} AdrpLdrGotLdr-farunaligned-g32.o main.o -o AdrpLdrGotLdr-farunaligned-g32.exe 
+       ${OTOOL} -tV AdrpLdrGotLdr-farunaligned-g32.exe | grep 'adrp' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdrGotLdr-farunaligned-g32.exe | grep 'add\t' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdrGotLdr-farunaligned-g32.exe | grep 'ldr\tw2, \[x1\]' | ${FAIL_IF_EMPTY}
+
+       # test ADRP/LDR/LDR left untouched when target is external and GOT slot far for 64-bit load
+       ${CC} ${CCFLAGS} AdrpLdrGotLdr.s -c -o AdrpLdrGotLdr-farunaligned-g64.o -DFOO_AS_CONST -DLOAD_GPR_64 -DMISALIGN_DATA -DPADDING
+       ${CC} ${CCFLAGS} AdrpLdrGotLdr-farunaligned-g64.o main.o -o AdrpLdrGotLdr-farunaligned-g64.exe 
+       ${OTOOL} -tV AdrpLdrGotLdr-farunaligned-g64.exe | grep 'adrp' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdrGotLdr-farunaligned-g64.exe | grep 'add\t' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdrGotLdr-farunaligned-g64.exe | grep 'ldr\tx2, \[x1\]' | ${FAIL_IF_EMPTY}
+
+       # test ADRP/LDR/LDR left untouched when target is external and GOT slot far for 32-bit fp load
+       ${CC} ${CCFLAGS} AdrpLdrGotLdr.s -c -o AdrpLdrGotLdr-farunaligned-f32.o -DFOO_AS_CONST -DLOAD_FPR_32 -DMISALIGN_DATA -DPADDING
+       ${CC} ${CCFLAGS} AdrpLdrGotLdr-farunaligned-f32.o main.o -o AdrpLdrGotLdr-farunaligned-f32.exe 
+       ${OTOOL} -tV AdrpLdrGotLdr-farunaligned-f32.exe | grep 'adrp' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdrGotLdr-farunaligned-f32.exe | grep 'add\t' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdrGotLdr-farunaligned-f32.exe | grep 'ldr\ts2, \[x1\]' | ${FAIL_IF_EMPTY}
+
+       # test ADRP/LDR/LDR left untouched when target is external and GOT slot far for 64-bit fp load
+       ${CC} ${CCFLAGS} AdrpLdrGotLdr.s -c -o AdrpLdrGotLdr-farunaligned-f64.o -DFOO_AS_CONST -DLOAD_FPR_64 -DMISALIGN_DATA -DPADDING
+       ${CC} ${CCFLAGS} AdrpLdrGotLdr-farunaligned-f64.o main.o -o AdrpLdrGotLdr-farunaligned-f64.exe 
+       ${OTOOL} -tV AdrpLdrGotLdr-farunaligned-f64.exe | grep 'adrp' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdrGotLdr-farunaligned-f64.exe | grep 'add\t' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdrGotLdr-farunaligned-f64.exe | grep 'ldr\td2, \[x1\]' | ${FAIL_IF_EMPTY}
+       
+       # test ADRP/LDR/LDR -left untouched when target is external and GOT slot far for 128-bit vec load
+       ${CC} ${CCFLAGS} AdrpLdrGotLdr.s -c -o AdrpLdrGotLdr-farunaligned-v128.o -DFOO_AS_CONST -DLOAD_VEC_128 -DMISALIGN_DATA -DPADDING
+       ${CC} ${CCFLAGS} AdrpLdrGotLdr-farunaligned-v128.o main.o -o AdrpLdrGotLdr-farunaligned-v128.exe 
+       ${OTOOL} -tV AdrpLdrGotLdr-farunaligned-v128.exe | grep 'adrp' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdrGotLdr-farunaligned-v128.exe | grep 'add\t' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdrGotLdr-farunaligned-v128.exe | grep 'ldr\tq2, \[x1\]' | ${FAIL_IF_EMPTY}
+
+
+AdrpAddStr: AdrpAddStr-base AdrpAddStr-seg AdrpAddStr-align AdrpAddStr-addend AdrpAddStr-faraddend
+       true
+
+AdrpAddStr-base: main.o
+       # test ADRP/ADD/STR -> ADR/STR for 8-bit store
+       ${CC} ${CCFLAGS} AdrpAddStr.s -c -o AdrpAddStr-base-g8.o  -DLOAD_GPR_8 
+       ${CC} ${CCFLAGS} AdrpAddStr-base-g8.o main.o -o AdrpAddStr-base-g8.exe 
+       ${OTOOL} -tV AdrpAddStr-base-g8.exe | grep 'adr x0' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpAddStr-base-g8.exe | grep 'str\tb1, \[x0\]' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpAddStr-base-g8.exe | grep 'add x0' | ${FAIL_IF_STDIN}
+       
+       # test ADRP/ADD/STR -> ADR/STR for 16-bit store
+       ${CC} ${CCFLAGS} AdrpAddStr.s -c -o AdrpAddStr-base-g16.o  -DLOAD_GPR_16
+       ${CC} ${CCFLAGS} AdrpAddStr-base-g16.o main.o -o AdrpAddStr-base-g16.exe
+       ${OTOOL} -tV AdrpAddStr-base-g16.exe | grep 'adr        x0' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpAddStr-base-g16.exe | grep 'str\th1, \[x0\]' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpAddStr-base-g16.exe | grep 'add        x0' | ${FAIL_IF_STDIN}
+       
+       # test ADRP/ADD/STR -> ADR/STR  for 32-bit store
+       ${CC} ${CCFLAGS} AdrpAddStr.s -c -o AdrpAddStr-base-g32.o  -DLOAD_GPR_32
+       ${CC} ${CCFLAGS} AdrpAddStr-base-g32.o main.o -o AdrpAddStr-base-g32.exe
+       ${OTOOL} -tV AdrpAddStr-base-g32.exe | grep 'adr        x0' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpAddStr-base-g32.exe | grep 'str\tw1, \[x0\]' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpAddStr-base-g32.exe | grep 'add        x0' | ${FAIL_IF_STDIN}
+
+       # test ADRP/ADD/STR -> ADR/STR  for 64-bit store
+       ${CC} ${CCFLAGS} AdrpAddStr.s -c -o AdrpAddStr-base-g64.o  -DLOAD_GPR_64
+       ${CC} ${CCFLAGS} AdrpAddStr-base-g64.o main.o -o AdrpAddStr-base-g64.exe
+       ${OTOOL} -tV AdrpAddStr-base-g64.exe | grep 'adr        x0' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpAddStr-base-g64.exe | grep 'str\tx1, \[x0\]' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpAddStr-base-g64.exe | grep 'add        x0' | ${FAIL_IF_STDIN}
+
+       # test ADRP/ADD/STR -> ADR/STR  for 32-bit fp store
+       ${CC} ${CCFLAGS} AdrpAddStr.s -c -o AdrpAddStr-base-f32.o  -DLOAD_FPR_32
+       ${CC} ${CCFLAGS} AdrpAddStr-base-f32.o main.o -o AdrpAddStr-base-f32.exe
+       ${OTOOL} -tV AdrpAddStr-base-f32.exe | grep 'adr        x0' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpAddStr-base-f32.exe | grep 'str\ts1, \[x0\]' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpAddStr-base-f32.exe | grep 'add        x0' | ${FAIL_IF_STDIN}
+
+       # test ADRP/ADD/STR -> ADR/STR  for 64-bit fp store
+       ${CC} ${CCFLAGS} AdrpAddStr.s -c -o AdrpAddStr-base-f64.o  -DLOAD_FPR_64
+       ${CC} ${CCFLAGS} AdrpAddStr-base-f64.o main.o -o AdrpAddStr-base-f64.exe
+       ${OTOOL} -tV AdrpAddStr-base-f64.exe | grep 'adr        x0' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpAddStr-base-f64.exe | grep 'str\td1, \[x0\]' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpAddStr-base-f64.exe | grep 'add        x0' | ${FAIL_IF_STDIN}
+       
+       # test ADRP/ADD/STR -> ADR/STR  for 128-bit vec store
+       ${CC} ${CCFLAGS} AdrpAddStr.s -c -o AdrpAddStr-base-v128.o  -DLOAD_VEC_128
+       ${CC} ${CCFLAGS} AdrpAddStr-base-v128.o main.o -o AdrpAddStr-base-v128.exe
+       ${OTOOL} -tV AdrpAddStr-base-v128.exe | grep 'adr       x0' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpAddStr-base-v128.exe | grep 'str\tq1, \[x0\]' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpAddStr-base-v128.exe | grep 'add       x0' | ${FAIL_IF_STDIN}
+
+
+AdrpAddStr-seg: main.o
+       # test ADRP/ADD/STR -> ADRP/STR for 8-bit store
+       ${CC} ${CCFLAGS} AdrpAddStr.s -c -o AdrpAddStr-seg-g8.o  -DLOAD_GPR_8 
+       ${CC} ${CCFLAGS} AdrpAddStr-seg-g8.o -o AdrpAddStr-seg-g8.dylib -dynamiclib -install_name /usr/lib/libjunk.dylib
+       ${OTOOL} -tV AdrpAddStr-seg-g8.dylib | grep 'adrp       x0' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpAddStr-seg-g8.dylib | grep 'str\tb1, \[x0' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpAddStr-seg-g8.dylib | grep 'add        x0' | ${FAIL_IF_STDIN}
+       
+       # test ADRP/ADD/STR -> ADRP/STR for 16-bit v
+       ${CC} ${CCFLAGS} AdrpAddStr.s -c -o AdrpAddStr-seg-g16.o  -DLOAD_GPR_16
+       ${CC} ${CCFLAGS} AdrpAddStr-seg-g16.o -o AdrpAddStr-seg-g16.dylib -dynamiclib -install_name /usr/lib/libjunk.dylib
+       ${OTOOL} -tV AdrpAddStr-seg-g16.dylib | grep 'adrp      x0' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpAddStr-seg-g16.dylib | grep 'str\th1, \[x0' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpAddStr-seg-g16.dylib | grep 'add       x0' | ${FAIL_IF_STDIN}
+       
+       # test ADRP/ADD/STR -> ADRP/STR for 32-bit store
+       ${CC} ${CCFLAGS} AdrpAddStr.s -c -o AdrpAddStr-seg-g32.o  -DLOAD_GPR_32
+       ${CC} ${CCFLAGS} AdrpAddStr-seg-g32.o -o AdrpAddStr-seg-g32.dylib -dynamiclib -install_name /usr/lib/libjunk.dylib
+       ${OTOOL} -tV AdrpAddStr-seg-g32.dylib | grep 'adrp      x0' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpAddStr-seg-g32.dylib | grep 'str\tw1, \[x0' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpAddStr-seg-g32.dylib | grep 'add       x0' | ${FAIL_IF_STDIN}
+       
+       # test ADRP/ADD/STR -> ADRP/STR  for 64-bit store
+       ${CC} ${CCFLAGS} AdrpAddStr.s -c -o AdrpAddStr-seg-g64.o  -DLOAD_GPR_64
+       ${CC} ${CCFLAGS} AdrpAddStr-seg-g64.o -o AdrpAddStr-seg-g64.dylib -dynamiclib -install_name /usr/lib/libjunk.dylib
+       ${OTOOL} -tV AdrpAddStr-seg-g64.dylib | grep 'adrp      x0' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpAddStr-seg-g64.dylib | grep 'str\tx1, \[x0' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpAddStr-seg-g64.dylib | grep 'add       x0' | ${FAIL_IF_STDIN}
+
+       # test ADRP/ADD/STR -> ADRP/STR  for 32-bit fp store
+       ${CC} ${CCFLAGS} AdrpAddStr.s -c -o AdrpAddStr-seg-f32.o  -DLOAD_FPR_32
+       ${CC} ${CCFLAGS} AdrpAddStr-seg-f32.o -o AdrpAddStr-seg-f32.dylib -dynamiclib -install_name /usr/lib/libjunk.dylib
+       ${OTOOL} -tV AdrpAddStr-seg-f32.dylib | grep 'adrp      x0' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpAddStr-seg-f32.dylib | grep 'str\ts1, \[x0' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpAddStr-seg-f32.dylib | grep 'add       x0' | ${FAIL_IF_STDIN}
+
+       # test ADRP/ADD/STR -> ADRP/STR  for 64-bit fp store
+       ${CC} ${CCFLAGS} AdrpAddStr.s -c -o AdrpAddStr-seg-f64.o  -DLOAD_FPR_64
+       ${CC} ${CCFLAGS} AdrpAddStr-seg-f64.o -o AdrpAddStr-seg-f64.dylib -dynamiclib -install_name /usr/lib/libjunk.dylib
+       ${OTOOL} -tV AdrpAddStr-seg-f64.dylib | grep 'adrp      x0' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpAddStr-seg-f64.dylib | grep 'str\td1, \[x0' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpAddStr-seg-f64.dylib | grep 'add       x0' | ${FAIL_IF_STDIN}
+       
+       # test ADRP/ADD/STR -> ADRP/STR  for 128-bit vec store
+       ${CC} ${CCFLAGS} AdrpAddStr.s -c -o AdrpAddStr-seg-v128.o  -DLOAD_VEC_128
+       ${CC} ${CCFLAGS} AdrpAddStr-seg-v128.o -o AdrpAddStr-seg-v128.dylib -dynamiclib -install_name /usr/lib/libjunk.dylib
+       ${OTOOL} -tV AdrpAddStr-seg-v128.dylib | grep 'adrp     x0' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpAddStr-seg-v128.dylib | grep 'str\tq1, \[x0' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpAddStr-seg-v128.dylib | grep 'add      x0' | ${FAIL_IF_STDIN}
+
+
+AdrpAddStr-align: main.o
+       # test ADRP/ADD/STR -> ADR/STR when target is for 8-bit load
+       ${CC} ${CCFLAGS} AdrpAddStr.s -c -o AdrpAddStr-align-g8.o  -DLOAD_GPR_8 -DMISALIGN_DATA
+       ${CC} ${CCFLAGS} AdrpAddStr-align-g8.o main.o -o AdrpAddStr-align-g8.exe
+       ${OTOOL} -tV AdrpAddStr-align-g8.exe | grep 'adr        x0,' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpAddStr-align-g8.exe | grep 'str\tb1, \[x0\]' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpAddStr-align-g8.exe | grep 'add        x0' | ${FAIL_IF_STDIN}
+       
+       # test ADRP/ADD/STR -> ADR/STR when target is not aligned for 16-bit load
+       ${CC} ${CCFLAGS} AdrpAddStr.s -c -o AdrpAddStr-align-g16.o  -DLOAD_GPR_16 -DMISALIGN_DATA
+       ${CC} ${CCFLAGS} AdrpAddStr-align-g16.o main.o -o AdrpAddStr-align-g16.exe
+       ${OTOOL} -tV AdrpAddStr-align-g16.exe | grep 'adr       x0,' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpAddStr-align-g16.exe | grep 'str       h1, \[x0\]' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpAddStr-align-g16.exe | grep 'add       x0' | ${FAIL_IF_STDIN}
+       
+       # test ADRP/ADD/STR -> ADR/STR when target is not aligned for 32-bit load
+       ${CC} ${CCFLAGS} AdrpAddStr.s -c -o AdrpAddStr-align-g32.o  -DLOAD_GPR_32 -DMISALIGN_DATA
+       ${CC} ${CCFLAGS} AdrpAddStr-align-g32.o main.o -o AdrpAddStr-align-g32.exe
+       ${OTOOL} -tV AdrpAddStr-align-g32.exe | grep 'adr       x0,' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpAddStr-align-g32.exe | grep 'str       w1, \[x0\]' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpAddStr-align-g32.exe | grep 'add       x0' | ${FAIL_IF_STDIN}
+
+       # test ADRP/ADD/STR -> ADR/STR  when target is not aligned for 64-bit load
+       ${CC} ${CCFLAGS} AdrpAddStr.s -c -o AdrpAddStr-align-g64.o  -DLOAD_GPR_64 -DMISALIGN_DATA
+       ${CC} ${CCFLAGS} AdrpAddStr-align-g64.o main.o -o AdrpAddStr-align-g64.exe
+       ${OTOOL} -tV AdrpAddStr-align-g64.exe | grep 'adr       x0,' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpAddStr-align-g64.exe | grep 'str       x1, \[x0\]' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpAddStr-align-g64.exe | grep 'add       x0' | ${FAIL_IF_STDIN}
+
+       # test ADRP/ADD/STR -> ADR/STR  when target is not aligned for 32-bit fp load
+       ${CC} ${CCFLAGS} AdrpAddStr.s -c -o AdrpAddStr-align-f32.o  -DLOAD_FPR_32 -DMISALIGN_DATA
+       ${CC} ${CCFLAGS} AdrpAddStr-align-f32.o main.o -o AdrpAddStr-align-f32.exe
+       ${OTOOL} -tV AdrpAddStr-align-f32.exe | grep 'adr       x0,' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpAddStr-align-f32.exe | grep 'str       s1, \[x0\]' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpAddStr-align-f32.exe | grep 'add       x0' | ${FAIL_IF_STDIN}
+
+       # test ADRP/ADD/STR -> ADR/STR  when target is not aligned for 64-bit fp load
+       ${CC} ${CCFLAGS} AdrpAddStr.s -c -o AdrpAddStr-align-f64.o  -DLOAD_FPR_64 -DMISALIGN_DATA
+       ${CC} ${CCFLAGS} AdrpAddStr-align-f64.o main.o -o AdrpAddStr-align-f64.exe
+       ${OTOOL} -tV AdrpAddStr-align-f64.exe | grep 'adr       x0,' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpAddStr-align-f64.exe | grep 'str       d1, \[x0\]' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpAddStr-align-f64.exe | grep 'add       x0' | ${FAIL_IF_STDIN}
+       
+       # test ADRP/ADD/STR -> ADR/STR  when target is not aligned for 128-bit vec load
+       ${CC} ${CCFLAGS} AdrpAddStr.s -c -o AdrpAddStr-align-v128.o  -DLOAD_VEC_128 -DMISALIGN_DATA
+       ${CC} ${CCFLAGS} AdrpAddStr-align-v128.o main.o -o AdrpAddStr-align-v128.exe
+       ${OTOOL} -tV AdrpAddStr-align-v128.exe | grep 'adr      x0,' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpAddStr-align-v128.exe | grep 'str      q1, \[x0\]' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpAddStr-align-v128.exe | grep 'add      x0' | ${FAIL_IF_STDIN}
+
+
+
+AdrpAddStr-addend:     
+       # test ADRP/ADD/STR -> ADRP/LD when target is in __TEXT for 8-bit load
+       ${CC} ${CCFLAGS} AdrpAddStr.s -c -o AdrpAddStr-addend-g8.o  -DLOAD_GPR_8 -DADDEND=8
+       ${CC} ${CCFLAGS} AdrpAddStr-addend-g8.o main.o -o AdrpAddStr-addend-g8.exe
+       ${OTOOL} -tV AdrpAddStr-addend-g8.exe | grep 'adr       x0' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpAddStr-addend-g8.exe | grep 'str\tb1, \[x0\]' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpAddStr-addend-g8.exe | grep 'add       x0' | ${FAIL_IF_STDIN}
+       
+       # test ADRP/ADD/STR -> ADRP/LD when target is in __TEXT for 16-bit load
+       ${CC} ${CCFLAGS} AdrpAddStr.s -c -o AdrpAddStr-addend-g16.o  -DLOAD_GPR_16 -DADDEND=8
+       ${CC} ${CCFLAGS} AdrpAddStr-addend-g16.o main.o -o AdrpAddStr-addend-g16.exe
+       ${OTOOL} -tV AdrpAddStr-addend-g16.exe | grep 'adr      x0' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpAddStr-addend-g16.exe | grep 'str\th1, \[x0\]' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpAddStr-addend-g16.exe | grep 'add      x0' | ${FAIL_IF_STDIN}
+       
+       # test ADRP/ADD/STR -> LDR when target is in __TEXT for 32-bit load
+       ${CC} ${CCFLAGS} AdrpAddStr.s -c -o AdrpAddStr-addend-g32.o  -DLOAD_GPR_32 -DADDEND=8
+       ${CC} ${CCFLAGS} AdrpAddStr-addend-g32.o main.o -o AdrpAddStr-addend-g32.exe
+       ${OTOOL} -tV AdrpAddStr-addend-g32.exe | grep 'adr      x0' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpAddStr-addend-g32.exe | grep 'str\tw1, \[x0\]' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpAddStr-addend-g32.exe | grep 'add      x0' | ${FAIL_IF_STDIN}
+
+       # test ADRP/ADD/STR -> LDR when target is in __TEXT for 64-bit load
+       ${CC} ${CCFLAGS} AdrpAddStr.s -c -o AdrpAddStr-addend-g64.o  -DLOAD_GPR_64 -DADDEND=8
+       ${CC} ${CCFLAGS} AdrpAddStr-addend-g64.o main.o -o AdrpAddStr-addend-g64.exe
+       ${OTOOL} -tV AdrpAddStr-addend-g64.exe | grep 'adr      x0' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpAddStr-addend-g64.exe | grep 'str\tx1, \[x0\]' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpAddStr-addend-g64.exe | grep 'add      x0' | ${FAIL_IF_STDIN}
+
+       # test ADRP/ADD/STR -> LDR when target is in __TEXT for 32-bit fp load
+       ${CC} ${CCFLAGS} AdrpAddStr.s -c -o AdrpAddStr-addend-f32.o  -DLOAD_FPR_32 -DADDEND=8
+       ${CC} ${CCFLAGS} AdrpAddStr-addend-f32.o main.o -o AdrpAddStr-addend-f32.exe
+       ${OTOOL} -tV AdrpAddStr-addend-f32.exe | grep 'adr      x0' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpAddStr-addend-f32.exe | grep 'str\ts1, \[x0\]' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpAddStr-addend-f32.exe | grep 'add      x0' | ${FAIL_IF_STDIN}
+
+       # test ADRP/ADD/STR -> LDR when target is in __TEXT for 64-bit fp load
+       ${CC} ${CCFLAGS} AdrpAddStr.s -c -o AdrpAddStr-addend-f64.o  -DLOAD_FPR_64 -DADDEND=8
+       ${CC} ${CCFLAGS} AdrpAddStr-addend-f64.o main.o -o AdrpAddStr-addend-f64.exe
+       ${OTOOL} -tV AdrpAddStr-addend-f64.exe | grep 'adr      x0' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpAddStr-addend-f64.exe | grep 'str\td1, \[x0\]' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpAddStr-addend-f64.exe | grep 'add      x0' | ${FAIL_IF_STDIN}
+       
+       # test ADRP/ADD/STR -> LDR when target is in __TEXT for 128-bit vec load
+       ${CC} ${CCFLAGS} AdrpAddStr.s -c -o AdrpAddStr-addend-v128.o  -DLOAD_VEC_128 -DADDEND=16
+       ${CC} ${CCFLAGS} AdrpAddStr-addend-v128.o main.o -o AdrpAddStr-addend-v128.exe 
+       ${OTOOL} -tV AdrpAddStr-addend-v128.exe | grep 'adr     x0' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpAddStr-addend-v128.exe | grep 'str\tq1, \[x0\]' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpAddStr-addend-v128.exe | grep 'add     x0' | ${FAIL_IF_STDIN}
+
+
+AdrpAddStr-faraddend:  
+       # test ADRP/ADD/STR -> ADRP/LD when target is in __TEXT for 8-bit load
+       ${CC} ${CCFLAGS} AdrpAddStr.s -c -o AdrpAddStr-faraddend-g8.o  -DLOAD_GPR_8 -DADDEND=8
+       ${CC} ${CCFLAGS} AdrpAddStr-faraddend-g8.o -o AdrpAddStr-faraddend-g8.dylib -dynamiclib -install_name /usr/lib/libjunk.dylib
+       ${OTOOL} -tV AdrpAddStr-faraddend-g8.dylib | grep 'adrp x0' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpAddStr-faraddend-g8.dylib | grep 'add  x0' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpAddStr-faraddend-g8.dylib | grep 'str\tb1, \[x0' | ${FAIL_IF_EMPTY}
+       
+       # test ADRP/ADD/STR -> ADRP/LD when target is in __TEXT for 16-bit load
+       ${CC} ${CCFLAGS} AdrpAddStr.s -c -o AdrpAddStr-faraddend-g16.o  -DLOAD_GPR_16 -DADDEND=8
+       ${CC} ${CCFLAGS} AdrpAddStr-faraddend-g16.o -o AdrpAddStr-faraddend-g16.dylib -dynamiclib -install_name /usr/lib/libjunk.dylib
+       ${OTOOL} -tV AdrpAddStr-faraddend-g16.dylib | grep 'adrp        x0' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpAddStr-faraddend-g16.dylib | grep 'add x0' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpAddStr-faraddend-g16.dylib | grep 'str\th1, \[x0' | ${FAIL_IF_EMPTY}
+       
+       # test ADRP/ADD/STR -> LDR when target is in __TEXT for 32-bit load
+       ${CC} ${CCFLAGS} AdrpAddStr.s -c -o AdrpAddStr-faraddend-g32.o  -DLOAD_GPR_32 -DADDEND=8
+       ${CC} ${CCFLAGS} AdrpAddStr-faraddend-g32.o -o AdrpAddStr-faraddend-g32.dylib -dynamiclib -install_name /usr/lib/libjunk.dylib
+       ${OTOOL} -tV AdrpAddStr-faraddend-g32.dylib | grep 'adrp        x0' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpAddStr-faraddend-g32.dylib | grep 'add x0' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpAddStr-faraddend-g32.dylib | grep 'str\tw1, \[x0' | ${FAIL_IF_EMPTY}
+
+       # test ADRP/ADD/STR -> LDR when target is in __TEXT for 64-bit load
+       ${CC} ${CCFLAGS} AdrpAddStr.s -c -o AdrpAddStr-faraddend-g64.o  -DLOAD_GPR_64 -DADDEND=8
+       ${CC} ${CCFLAGS} AdrpAddStr-faraddend-g64.o -o AdrpAddStr-faraddend-g64.dylib -dynamiclib -install_name /usr/lib/libjunk.dylib
+       ${OTOOL} -tV AdrpAddStr-faraddend-g64.dylib | grep 'adrp        x0' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpAddStr-faraddend-g64.dylib | grep 'add x0' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpAddStr-faraddend-g64.dylib | grep 'str\tx1, \[x0' | ${FAIL_IF_EMPTY}
+
+       # test ADRP/ADD/STR -> LDR when target is in __TEXT for 32-bit fp load
+       ${CC} ${CCFLAGS} AdrpAddStr.s -c -o AdrpAddStr-faraddend-f32.o  -DLOAD_FPR_32 -DADDEND=8
+       ${CC} ${CCFLAGS} AdrpAddStr-faraddend-f32.o -o AdrpAddStr-faraddend-f32.dylib -dynamiclib -install_name /usr/lib/libjunk.dylib
+       ${OTOOL} -tV AdrpAddStr-faraddend-f32.dylib | grep 'adrp        x0' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpAddStr-faraddend-f32.dylib | grep 'add x0' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpAddStr-faraddend-f32.dylib | grep 'str\ts1, \[x0' | ${FAIL_IF_EMPTY}
+
+       # test ADRP/ADD/STR -> LDR when target is in __TEXT for 64-bit fp load
+       ${CC} ${CCFLAGS} AdrpAddStr.s -c -o AdrpAddStr-faraddend-f64.o  -DLOAD_FPR_64 -DADDEND=8
+       ${CC} ${CCFLAGS} AdrpAddStr-faraddend-f64.o -o AdrpAddStr-faraddend-f64.dylib -dynamiclib -install_name /usr/lib/libjunk.dylib
+       ${OTOOL} -tV AdrpAddStr-faraddend-f64.dylib | grep 'adrp        x0' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpAddStr-faraddend-f64.dylib | grep 'add x0' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpAddStr-faraddend-f64.dylib | grep 'str\td1, \[x0' | ${FAIL_IF_EMPTY}
+       
+       # test ADRP/ADD/STR -> LDR when target is in __TEXT for 128-bit vec load
+       ${CC} ${CCFLAGS} AdrpAddStr.s -c -o AdrpAddStr-faraddend-v128.o  -DLOAD_VEC_128 -DADDEND=16
+       ${CC} ${CCFLAGS} AdrpAddStr-faraddend-v128.o -o AdrpAddStr-faraddend-v128.dylib -dynamiclib -install_name /usr/lib/libjunk.dylib 
+       ${OTOOL} -tV AdrpAddStr-faraddend-v128.dylib | grep 'adrp       x0' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpAddStr-faraddend-v128.dylib | grep 'add        x0' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpAddStr-faraddend-v128.dylib | grep 'str\tq1, \[x0' | ${FAIL_IF_EMPTY}
+
+
+
+AdrpLdrGotStr: AdrpLdrGotStr-extern AdrpLdrGotStr-externfargot AdrpLdrGotStr-near AdrpLdrGotStr-far AdrpLdrGotStr-nearunaligned AdrpLdrGotStr-farunaligned
+       true
+
+AdrpLdrGotStr-extern: main.o
+       # test ADRP/LDR/LDR -> LDR/STR when GOT slot is close  for 8-bit load
+       ${CC} ${CCFLAGS} AdrpLdrGotStr.s -c -o AdrpLdrGotStr-extern-g8.o -DFOO_AS_CONST -DLOAD_GPR_8 -DTARGET=_malloc
+       ${CC} ${CCFLAGS} AdrpLdrGotStr-extern-g8.o main.o -o AdrpLdrGotStr-extern-g8.exe 
+       ${OTOOL} -tV AdrpLdrGotStr-extern-g8.exe | grep 'adrp' | ${FAIL_IF_STDIN}
+       ${OTOOL} -tV AdrpLdrGotStr-extern-g8.exe | grep 'ldr\tx1,' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdrGotStr-extern-g8.exe | grep 'str\tb2, \[x1\]' | ${FAIL_IF_EMPTY}
+       
+       # test ADRP/LDR/LDR -> LDR/STR when GOT slot is close  for 16-bit load
+       ${CC} ${CCFLAGS} AdrpLdrGotStr.s -c -o AdrpLdrGotStr-extern-g16.o -DFOO_AS_CONST -DLOAD_GPR_16 -DTARGET=_malloc
+       ${CC} ${CCFLAGS} AdrpLdrGotStr-extern-g16.o main.o -o AdrpLdrGotStr-extern-g16.exe 
+       ${OTOOL} -tV AdrpLdrGotStr-extern-g16.exe | grep 'adrp' | ${FAIL_IF_STDIN}
+       ${OTOOL} -tV AdrpLdrGotStr-extern-g16.exe | grep 'ldr\tx1,' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdrGotStr-extern-g16.exe | grep 'str\th2, \[x1\]' | ${FAIL_IF_EMPTY}
+       
+       # test ADRP/LDR/LDR -> LDR/STR when GOT slot is close for 32-bit load
+       ${CC} ${CCFLAGS} AdrpLdrGotStr.s -c -o AdrpLdrGotStr-extern-g32.o -DFOO_AS_CONST -DLOAD_GPR_32 -DTARGET=_malloc
+       ${CC} ${CCFLAGS} AdrpLdrGotStr-extern-g32.o main.o -o AdrpLdrGotStr-extern-g32.exe 
+       ${OTOOL} -tV AdrpLdrGotStr-extern-g32.exe | grep 'adrp' | ${FAIL_IF_STDIN}
+       ${OTOOL} -tV AdrpLdrGotStr-extern-g32.exe | grep 'ldr\tx1,' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdrGotStr-extern-g32.exe | grep 'str\tw2, \[x1\]' | ${FAIL_IF_EMPTY}
+
+       # test ADRP/LDR/LDR -> LDR/STR when GOT slot is close for 64-bit load
+       ${CC} ${CCFLAGS} AdrpLdrGotStr.s -c -o AdrpLdrGotStr-extern-g64.o -DFOO_AS_CONST -DLOAD_GPR_64 -DTARGET=_malloc
+       ${CC} ${CCFLAGS} AdrpLdrGotStr-extern-g64.o main.o -o AdrpLdrGotStr-extern-g64.exe 
+       ${OTOOL} -tV AdrpLdrGotStr-extern-g64.exe | grep 'adrp' | ${FAIL_IF_STDIN}
+       ${OTOOL} -tV AdrpLdrGotStr-extern-g64.exe | grep 'ldr\tx1,' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdrGotStr-extern-g64.exe | grep 'str\tx2, \[x1\]' | ${FAIL_IF_EMPTY}
+
+       # test ADRP/LDR/LDR -> LDR/STR when GOT slot is close for 32-bit fp load
+       ${CC} ${CCFLAGS} AdrpLdrGotStr.s -c -o AdrpLdrGotStr-extern-f32.o -DFOO_AS_CONST -DLOAD_FPR_32 -DTARGET=_malloc
+       ${CC} ${CCFLAGS} AdrpLdrGotStr-extern-f32.o main.o -o AdrpLdrGotStr-extern-f32.exe 
+       ${OTOOL} -tV AdrpLdrGotStr-extern-f32.exe | grep 'adrp' | ${FAIL_IF_STDIN}
+       ${OTOOL} -tV AdrpLdrGotStr-extern-f32.exe | grep 'ldr\tx1,' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdrGotStr-extern-f32.exe | grep 'str\ts2, \[x1\]' | ${FAIL_IF_EMPTY}
+
+       # test ADRP/LDR/LDR -> LDR/STR when GOT slot is close for 64-bit fp load
+       ${CC} ${CCFLAGS} AdrpLdrGotStr.s -c -o AdrpLdrGotStr-extern-f64.o -DFOO_AS_CONST -DLOAD_FPR_64 -DTARGET=_malloc
+       ${CC} ${CCFLAGS} AdrpLdrGotStr-extern-f64.o main.o -o AdrpLdrGotStr-extern-f64.exe 
+       ${OTOOL} -tV AdrpLdrGotStr-extern-f64.exe | grep 'adrp' | ${FAIL_IF_STDIN}
+       ${OTOOL} -tV AdrpLdrGotStr-extern-f64.exe | grep 'ldr\tx1,' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdrGotStr-extern-f64.exe | grep 'str\td2, \[x1\]' | ${FAIL_IF_EMPTY}
+       
+       # test ADRP/LDR/LDR -> LDR/STR when GOT slot is close for 128-bit vec load
+       ${CC} ${CCFLAGS} AdrpLdrGotStr.s -c -o AdrpLdrGotStr-extern-v128.o -DFOO_AS_CONST -DLOAD_VEC_128 -DTARGET=_malloc
+       ${CC} ${CCFLAGS} AdrpLdrGotStr-extern-v128.o main.o -o AdrpLdrGotStr-extern-v128.exe 
+       ${OTOOL} -tV AdrpLdrGotStr-extern-v128.exe | grep 'adrp' | ${FAIL_IF_STDIN}
+       ${OTOOL} -tV AdrpLdrGotStr-extern-v128.exe | grep 'ldr\tx1,' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdrGotStr-extern-v128.exe | grep 'str\tq2, \[x1\]' | ${FAIL_IF_EMPTY}
+
+
+AdrpLdrGotStr-externfargot: main.o
+       # test ADRP/LDR/STR left untouched when target is external and GOT slot far for 8-bit load
+       ${CC} ${CCFLAGS} AdrpLdrGotStr.s -c -o AdrpLdrGotStr-externfargot-g8.o -DFOO_AS_CONST -DLOAD_GPR_8 -DTARGET=_malloc -DPADDING
+       ${CC} ${CCFLAGS} AdrpLdrGotStr-externfargot-g8.o main.o -o AdrpLdrGotStr-externfargot-g8.exe 
+       ${OTOOL} -tV AdrpLdrGotStr-externfargot-g8.exe | grep 'adrp' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdrGotStr-externfargot-g8.exe | grep 'ldr\tx1, \[x0' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdrGotStr-externfargot-g8.exe | grep 'str\tb2, \[x1\]' | ${FAIL_IF_EMPTY}
+       
+       # test ADRP/LDR/STR left untouched when target is external and GOT slot far for 16-bit load
+       ${CC} ${CCFLAGS} AdrpLdrGotStr.s -c -o AdrpLdrGotStr-externfargot-g16.o -DFOO_AS_CONST -DLOAD_GPR_16 -DTARGET=_malloc -DPADDING
+       ${CC} ${CCFLAGS} AdrpLdrGotStr-externfargot-g16.o main.o -o AdrpLdrGotStr-externfargot-g16.exe 
+       ${OTOOL} -tV AdrpLdrGotStr-externfargot-g16.exe | grep 'adrp' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdrGotStr-externfargot-g16.exe | grep 'ldr\tx1, \[x0' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdrGotStr-externfargot-g16.exe | grep 'str\th2, \[x1\]' | ${FAIL_IF_EMPTY}
+       
+       # test ADRP/LDR/STR left untouched when target is external and GOT slot farfor 32-bit load
+       ${CC} ${CCFLAGS} AdrpLdrGotStr.s -c -o AdrpLdrGotStr-externfargot-g32.o -DFOO_AS_CONST -DLOAD_GPR_32 -DTARGET=_malloc -DPADDING
+       ${CC} ${CCFLAGS} AdrpLdrGotStr-externfargot-g32.o main.o -o AdrpLdrGotStr-externfargot-g32.exe 
+       ${OTOOL} -tV AdrpLdrGotStr-externfargot-g32.exe | grep 'adrp' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdrGotStr-externfargot-g32.exe | grep 'ldr\tx1, \[x0' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdrGotStr-externfargot-g32.exe | grep 'str\tw2, \[x1\]' | ${FAIL_IF_EMPTY}
+
+       # test ADRP/LDR/STR left untouched when target is external and GOT slot far for 64-bit load
+       ${CC} ${CCFLAGS} AdrpLdrGotStr.s -c -o AdrpLdrGotStr-externfargot-g64.o -DFOO_AS_CONST -DLOAD_GPR_64 -DTARGET=_malloc -DPADDING
+       ${CC} ${CCFLAGS} AdrpLdrGotStr-externfargot-g64.o main.o -o AdrpLdrGotStr-externfargot-g64.exe 
+       ${OTOOL} -tV AdrpLdrGotStr-externfargot-g64.exe | grep 'adrp' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdrGotStr-externfargot-g64.exe | grep 'ldr\tx1, \[x0' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdrGotStr-externfargot-g64.exe | grep 'str\tx2, \[x1\]' | ${FAIL_IF_EMPTY}
+
+       # test ADRP/LDR/STR left untouched when target is external and GOT slot far for 32-bit fp load
+       ${CC} ${CCFLAGS} AdrpLdrGotStr.s -c -o AdrpLdrGotStr-externfargot-f32.o -DFOO_AS_CONST -DLOAD_FPR_32 -DTARGET=_malloc -DPADDING
+       ${CC} ${CCFLAGS} AdrpLdrGotStr-externfargot-f32.o main.o -o AdrpLdrGotStr-externfargot-f32.exe 
+       ${OTOOL} -tV AdrpLdrGotStr-externfargot-f32.exe | grep 'adrp' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdrGotStr-externfargot-f32.exe | grep 'ldr\tx1, \[x0' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdrGotStr-externfargot-f32.exe | grep 'str\ts2, \[x1\]' | ${FAIL_IF_EMPTY}
+
+       # test ADRP/LDR/STR left untouched when target is external and GOT slot far for 64-bit fp load
+       ${CC} ${CCFLAGS} AdrpLdrGotStr.s -c -o AdrpLdrGotStr-externfargot-f64.o -DFOO_AS_CONST -DLOAD_FPR_64 -DTARGET=_malloc -DPADDING
+       ${CC} ${CCFLAGS} AdrpLdrGotStr-externfargot-f64.o main.o -o AdrpLdrGotStr-externfargot-f64.exe 
+       ${OTOOL} -tV AdrpLdrGotStr-externfargot-f64.exe | grep 'adrp' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdrGotStr-externfargot-f64.exe | grep 'ldr\tx1, \[x0' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdrGotStr-externfargot-f64.exe | grep 'str\td2, \[x1\]' | ${FAIL_IF_EMPTY}
+       
+       # test ADRP/LDR/STR -left untouched when target is external and GOT slot far for 128-bit vec load
+       ${CC} ${CCFLAGS} AdrpLdrGotStr.s -c -o AdrpLdrGotStr-externfargot-v128.o -DFOO_AS_CONST -DLOAD_VEC_128 -DTARGET=_malloc -DPADDING
+       ${CC} ${CCFLAGS} AdrpLdrGotStr-externfargot-v128.o main.o -o AdrpLdrGotStr-externfargot-v128.exe 
+       ${OTOOL} -tV AdrpLdrGotStr-externfargot-v128.exe | grep 'adrp' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdrGotStr-externfargot-v128.exe | grep 'ldr\tx1, \[x0' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdrGotStr-externfargot-v128.exe | grep 'str\tq2, \[x1\]' | ${FAIL_IF_EMPTY}
+
+
+AdrpLdrGotStr-near: main.o 
+       # test ADRP/LDR/STR -> ADR/STR when target close for 8-bit load
+       ${CC} ${CCFLAGS} AdrpLdrGotStr.s -c -o AdrpLdrGotStr-near-g8.o -DLOAD_GPR_8 
+       ${CC} ${CCFLAGS} AdrpLdrGotStr-near-g8.o main.o -o AdrpLdrGotStr-near-g8.exe 
+       ${OTOOL} -tV AdrpLdrGotStr-near-g8.exe | grep 'adrp' | ${FAIL_IF_STDIN}
+       ${OTOOL} -tV AdrpLdrGotStr-near-g8.exe | grep 'adr\tx1,' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdrGotStr-near-g8.exe | grep 'str\tb2, \[x1\]' | ${FAIL_IF_EMPTY}
+
+       # test ADRP/LDR/STR -> ADR/STR when target close for 16-bit load
+       ${CC} ${CCFLAGS} AdrpLdrGotStr.s -c -o AdrpLdrGotStr-near-g16.o -DLOAD_GPR_16 
+       ${CC} ${CCFLAGS} AdrpLdrGotStr-near-g16.o main.o -o AdrpLdrGotStr-near-g16.exe 
+       ${OTOOL} -tV AdrpLdrGotStr-near-g16.exe | grep 'adrp' | ${FAIL_IF_STDIN}
+       ${OTOOL} -tV AdrpLdrGotStr-near-g16.exe | grep 'adr\tx1,' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdrGotStr-near-g16.exe | grep 'str\th2, \[x1\]' | ${FAIL_IF_EMPTY}
+       
+       # test ADRP/LDR/STR -> ADR/STR when target close for 32-bit load
+       ${CC} ${CCFLAGS} AdrpLdrGotStr.s -c -o AdrpLdrGotStr-near-g32.o -DLOAD_GPR_32 
+       ${CC} ${CCFLAGS} AdrpLdrGotStr-near-g32.o main.o -o AdrpLdrGotStr-near-g32.exe 
+       ${OTOOL} -tV AdrpLdrGotStr-near-g32.exe | grep 'adrp' | ${FAIL_IF_STDIN}
+       ${OTOOL} -tV AdrpLdrGotStr-near-g32.exe | grep 'ldr\tx1, \[x0' | ${FAIL_IF_STDIN}
+       ${OTOOL} -tV AdrpLdrGotStr-near-g32.exe | grep 'str\tw2, \[x1\]' | ${FAIL_IF_EMPTY}
+
+       # test ADRP/LDR/STR -> ADR/STR when target close for 64-bit load
+       ${CC} ${CCFLAGS} AdrpLdrGotStr.s -c -o AdrpLdrGotStr-near-g64.o -DLOAD_GPR_64 
+       ${CC} ${CCFLAGS} AdrpLdrGotStr-near-g64.o main.o -o AdrpLdrGotStr-near-g64.exe 
+       ${OTOOL} -tV AdrpLdrGotStr-near-g64.exe | grep 'adrp' | ${FAIL_IF_STDIN}
+       ${OTOOL} -tV AdrpLdrGotStr-near-g64.exe | grep 'ldr\tx1, \[x0' | ${FAIL_IF_STDIN}
+       ${OTOOL} -tV AdrpLdrGotStr-near-g64.exe | grep 'str\tx2, \[x1\]' | ${FAIL_IF_EMPTY}
+
+       # test ADRP/LDR/STR -> ADR/STR when target close for 32-bit fp load
+       ${CC} ${CCFLAGS} AdrpLdrGotStr.s -c -o AdrpLdrGotStr-near-f32.o -DLOAD_FPR_32 
+       ${CC} ${CCFLAGS} AdrpLdrGotStr-near-f32.o main.o -o AdrpLdrGotStr-near-f32.exe 
+       ${OTOOL} -tV AdrpLdrGotStr-near-f32.exe | grep 'adrp' | ${FAIL_IF_STDIN}
+       ${OTOOL} -tV AdrpLdrGotStr-near-f32.exe | grep 'ldr\tx1, \[x0' | ${FAIL_IF_STDIN}
+       ${OTOOL} -tV AdrpLdrGotStr-near-f32.exe | grep 'str\ts2, \[x1\]' | ${FAIL_IF_EMPTY}
+
+       # test ADRP/LDR/STR -> ADR/STR when target close for 64-bit fp load
+       ${CC} ${CCFLAGS} AdrpLdrGotStr.s -c -o AdrpLdrGotStr-near-f64.o -DLOAD_FPR_64 
+       ${CC} ${CCFLAGS} AdrpLdrGotStr-near-f64.o main.o -o AdrpLdrGotStr-near-f64.exe 
+       ${OTOOL} -tV AdrpLdrGotStr-near-f64.exe | grep 'adrp' | ${FAIL_IF_STDIN}
+       ${OTOOL} -tV AdrpLdrGotStr-near-f64.exe | grep 'ldr\tx1, \[x0' | ${FAIL_IF_STDIN}
+       ${OTOOL} -tV AdrpLdrGotStr-near-f64.exe | grep 'str\td2, \[x1\]' | ${FAIL_IF_EMPTY}
+       
+       # test ADRP/LDR/STR -> ADR/STR when target close for 128-bit vec load
+       ${CC} ${CCFLAGS} AdrpLdrGotStr.s -c -o AdrpLdrGotStr-near-v128.o -DLOAD_VEC_128 
+       ${CC} ${CCFLAGS} AdrpLdrGotStr-near-v128.o main.o -o AdrpLdrGotStr-near-v128.exe 
+       ${OTOOL} -tV AdrpLdrGotStr-near-v128.exe | grep 'adrp' | ${FAIL_IF_STDIN}
+       ${OTOOL} -tV AdrpLdrGotStr-near-v128.exe | grep 'ldr\tx1, \[x0' | ${FAIL_IF_STDIN}
+       ${OTOOL} -tV AdrpLdrGotStr-near-v128.exe | grep 'str\tq2, \[x1\]' | ${FAIL_IF_EMPTY}
+
+
+AdrpLdrGotStr-nearunaligned: main.o 
+       # test ADRP/LDR left untouched when target is in __TEXT for 8-bit load
+       ${CC} ${CCFLAGS} AdrpLdrGotStr.s -c -o AdrpLdrGotStr-nearunaligned-g8.o  -DLOAD_GPR_8 -DMISALIGN_DATA
+       ${CC} ${CCFLAGS} AdrpLdrGotStr-nearunaligned-g8.o main.o -o AdrpLdrGotStr-nearunaligned-g8.exe 
+       ${OTOOL} -tV AdrpLdrGotStr-nearunaligned-g8.exe | grep 'adrp' | ${FAIL_IF_STDIN}
+       ${OTOOL} -tV AdrpLdrGotStr-nearunaligned-g8.exe | grep 'adr\tx1,' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdrGotStr-nearunaligned-g8.exe | grep 'str\tb2, \[x1\]' | ${FAIL_IF_EMPTY}
+
+       # test ADRP/LDR/LDR left untouched when target is external and GOT slot far for 16-bit load
+       ${CC} ${CCFLAGS} AdrpLdrGotStr.s -c -o AdrpLdrGotStr-nearunaligned-g16.o  -DLOAD_GPR_16 -DMISALIGN_DATA
+       ${CC} ${CCFLAGS} AdrpLdrGotStr-nearunaligned-g16.o main.o -o AdrpLdrGotStr-nearunaligned-g16.exe 
+       ${OTOOL} -tV AdrpLdrGotStr-nearunaligned-g16.exe | grep 'adrp' | ${FAIL_IF_STDIN}
+       ${OTOOL} -tV AdrpLdrGotStr-nearunaligned-g16.exe | grep 'adr\tx1,' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdrGotStr-nearunaligned-g16.exe | grep 'str\th2, \[x1\]' | ${FAIL_IF_EMPTY}
+       
+       # test ADRP/LDR/LDR -> LDR literal when target close for 32-bit load
+       ${CC} ${CCFLAGS} AdrpLdrGotStr.s -c -o AdrpLdrGotStr-nearunaligned-g32.o  -DLOAD_GPR_32 -DMISALIGN_DATA
+       ${CC} ${CCFLAGS} AdrpLdrGotStr-nearunaligned-g32.o main.o -o AdrpLdrGotStr-nearunaligned-g32.exe 
+       ${OTOOL} -tV AdrpLdrGotStr-nearunaligned-g32.exe | grep 'adrp' | ${FAIL_IF_STDIN}
+       ${OTOOL} -tV AdrpLdrGotStr-nearunaligned-g32.exe | grep 'adr\tx1,' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdrGotStr-nearunaligned-g32.exe | grep 'str\tw2, \[x1\]' | ${FAIL_IF_EMPTY}
+
+       # test ADRP/LDR/LDR left untouched when target is external and GOT slot far for 64-bit load
+       ${CC} ${CCFLAGS} AdrpLdrGotStr.s -c -o AdrpLdrGotStr-nearunaligned-g64.o  -DLOAD_GPR_64 -DMISALIGN_DATA
+       ${CC} ${CCFLAGS} AdrpLdrGotStr-nearunaligned-g64.o main.o -o AdrpLdrGotStr-nearunaligned-g64.exe 
+       ${OTOOL} -tV AdrpLdrGotStr-nearunaligned-g64.exe | grep 'adrp' | ${FAIL_IF_STDIN}
+       ${OTOOL} -tV AdrpLdrGotStr-nearunaligned-g64.exe | grep 'adr\tx1,' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdrGotStr-nearunaligned-g64.exe | grep 'str\tx2, \[x1\]' | ${FAIL_IF_EMPTY}
+
+       # test ADRP/LDR/LDR left untouched when target is external and GOT slot far for 32-bit fp load
+       ${CC} ${CCFLAGS} AdrpLdrGotStr.s -c -o AdrpLdrGotStr-nearunaligned-f32.o  -DLOAD_FPR_32 -DMISALIGN_DATA
+       ${CC} ${CCFLAGS} AdrpLdrGotStr-nearunaligned-f32.o main.o -o AdrpLdrGotStr-nearunaligned-f32.exe 
+       ${OTOOL} -tV AdrpLdrGotStr-nearunaligned-f32.exe | grep 'adrp' | ${FAIL_IF_STDIN}
+       ${OTOOL} -tV AdrpLdrGotStr-nearunaligned-f32.exe | grep 'adr\tx1,' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdrGotStr-nearunaligned-f32.exe | grep 'str\ts2, \[x1\]' | ${FAIL_IF_EMPTY}
+
+       # test ADRP/LDR/LDR left untouched when target is external and GOT slot far for 64-bit fp load
+       ${CC} ${CCFLAGS} AdrpLdrGotStr.s -c -o AdrpLdrGotStr-nearunaligned-f64.o  -DLOAD_FPR_64 -DMISALIGN_DATA
+       ${CC} ${CCFLAGS} AdrpLdrGotStr-nearunaligned-f64.o main.o -o AdrpLdrGotStr-nearunaligned-f64.exe 
+       ${OTOOL} -tV AdrpLdrGotStr-nearunaligned-f64.exe | grep 'adrp' | ${FAIL_IF_STDIN}
+       ${OTOOL} -tV AdrpLdrGotStr-nearunaligned-f64.exe | grep 'adr\tx1,' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdrGotStr-nearunaligned-f64.exe | grep 'str\td2, \[x1\]' | ${FAIL_IF_EMPTY}
+       
+       # test ADRP/LDR/LDR -left untouched when target is external and GOT slot far for 128-bit vec load
+       ${CC} ${CCFLAGS} AdrpLdrGotStr.s -c -o AdrpLdrGotStr-nearunaligned-v128.o  -DLOAD_VEC_128 -DMISALIGN_DATA
+       ${CC} ${CCFLAGS} AdrpLdrGotStr-nearunaligned-v128.o main.o -o AdrpLdrGotStr-nearunaligned-v128.exe 
+       ${OTOOL} -tV AdrpLdrGotStr-nearunaligned-v128.exe | grep 'adrp' | ${FAIL_IF_STDIN}
+       ${OTOOL} -tV AdrpLdrGotStr-nearunaligned-v128.exe | grep 'adr\tx1,' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdrGotStr-nearunaligned-v128.exe | grep 'str\tq2, \[x1\]' | ${FAIL_IF_EMPTY}
+
+
+AdrpLdrGotStr-far: main.o 
+       # test ADRP/LDR left untouched when target is in __TEXT for 8-bit load
+       ${CC} ${CCFLAGS} AdrpLdrGotStr.s -c -o AdrpLdrGotStr-far-g8.o -DFOO_AS_CONST -DLOAD_GPR_8 -DPADDING
+       ${CC} ${CCFLAGS} AdrpLdrGotStr-far-g8.o main.o -o AdrpLdrGotStr-far-g8.exe 
+       ${OTOOL} -tV AdrpLdrGotStr-far-g8.exe | grep 'adrp\tx0' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdrGotStr-far-g8.exe | grep 'add\t' | ${FAIL_IF_STDIN}
+       ${OTOOL} -tV AdrpLdrGotStr-far-g8.exe | grep 'str\tb2, \[x0,' | ${FAIL_IF_EMPTY}
+
+       # test ADRP/LDR/LDR left untouched when target is external and GOT slot far for 16-bit load
+       ${CC} ${CCFLAGS} AdrpLdrGotStr.s -c -o AdrpLdrGotStr-far-g16.o -DFOO_AS_CONST -DLOAD_GPR_16 -DPADDING
+       ${CC} ${CCFLAGS} AdrpLdrGotStr-far-g16.o main.o -o AdrpLdrGotStr-far-g16.exe  
+       ${OTOOL} -tV AdrpLdrGotStr-far-g16.exe | grep 'adrp\tx0' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdrGotStr-far-g16.exe | grep 'add\t' | ${FAIL_IF_STDIN}
+       ${OTOOL} -tV AdrpLdrGotStr-far-g16.exe | grep 'str\th2, \[x0,' | ${FAIL_IF_EMPTY}
+       
+       # test ADRP/LDR/LDR -> LDR literal when target close for 32-bit load
+       ${CC} ${CCFLAGS} AdrpLdrGotStr.s -c -o AdrpLdrGotStr-far-g32.o -DFOO_AS_CONST -DLOAD_GPR_32 -DPADDING 
+       ${CC} ${CCFLAGS} AdrpLdrGotStr-far-g32.o main.o -o AdrpLdrGotStr-far-g32.exe  
+       ${OTOOL} -tV AdrpLdrGotStr-far-g32.exe | grep 'adrp\tx0' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdrGotStr-far-g32.exe | grep 'add\t' | ${FAIL_IF_STDIN}
+       ${OTOOL} -tV AdrpLdrGotStr-far-g32.exe | grep 'str\tw2, \[x0,' | ${FAIL_IF_EMPTY}
+
+       # test ADRP/LDR/LDR left untouched when target is external and GOT slot far for 64-bit load
+       ${CC} ${CCFLAGS} AdrpLdrGotStr.s -c -o AdrpLdrGotStr-far-g64.o -DFOO_AS_CONST -DLOAD_GPR_64 -DPADDING 
+       ${CC} ${CCFLAGS} AdrpLdrGotStr-far-g64.o main.o -o AdrpLdrGotStr-far-g64.exe  
+       ${OTOOL} -tV AdrpLdrGotStr-far-g64.exe | grep 'adrp\tx0' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdrGotStr-far-g64.exe | grep 'add\t' | ${FAIL_IF_STDIN}
+       ${OTOOL} -tV AdrpLdrGotStr-far-g64.exe | grep 'str\tx2, \[x0,' | ${FAIL_IF_EMPTY}
+
+       # test ADRP/LDR/LDR left untouched when target is external and GOT slot far for 32-bit fp load
+       ${CC} ${CCFLAGS} AdrpLdrGotStr.s -c -o AdrpLdrGotStr-far-f32.o -DFOO_AS_CONST -DLOAD_FPR_32 -DPADDING 
+       ${CC} ${CCFLAGS} AdrpLdrGotStr-far-f32.o main.o -o AdrpLdrGotStr-far-f32.exe  
+       ${OTOOL} -tV AdrpLdrGotStr-far-f32.exe | grep 'adrp\tx0' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdrGotStr-far-f32.exe | grep 'add\t' | ${FAIL_IF_STDIN}
+       ${OTOOL} -tV AdrpLdrGotStr-far-f32.exe | grep 'str\ts2, \[x0,' | ${FAIL_IF_EMPTY}
+
+       # test ADRP/LDR/LDR left untouched when target is external and GOT slot far for 64-bit fp load
+       ${CC} ${CCFLAGS} AdrpLdrGotStr.s -c -o AdrpLdrGotStr-far-f64.o -DFOO_AS_CONST -DLOAD_FPR_64 -DPADDING 
+       ${CC} ${CCFLAGS} AdrpLdrGotStr-far-f64.o main.o -o AdrpLdrGotStr-far-f64.exe  
+       ${OTOOL} -tV AdrpLdrGotStr-far-f64.exe | grep 'adrp\tx0' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdrGotStr-far-f64.exe | grep 'add\t' | ${FAIL_IF_STDIN}
+       ${OTOOL} -tV AdrpLdrGotStr-far-f64.exe | grep 'str\td2, \[x0,' | ${FAIL_IF_EMPTY}
+       
+       # test ADRP/LDR/LDR -left untouched when target is external and GOT slot far for 128-bit vec load
+       ${CC} ${CCFLAGS} AdrpLdrGotStr.s -c -o AdrpLdrGotStr-far-v128.o -DFOO_AS_CONST -DLOAD_VEC_128 -DPADDING 
+       ${CC} ${CCFLAGS} AdrpLdrGotStr-far-v128.o main.o -o AdrpLdrGotStr-far-v128.exe  
+       ${OTOOL} -tV AdrpLdrGotStr-far-v128.exe | grep 'adrp\tx0' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdrGotStr-far-v128.exe | grep 'add\t' | ${FAIL_IF_STDIN}
+       ${OTOOL} -tV AdrpLdrGotStr-far-v128.exe | grep 'str\tq2, \[x0,' | ${FAIL_IF_EMPTY}
+
+
+AdrpLdrGotStr-farunaligned: main.o 
+       # test ADRP/LDR left untouched when target is in __TEXT for 8-bit load
+       ${CC} ${CCFLAGS} AdrpLdrGotStr.s -c -o AdrpLdrGotStr-farunaligned-g8.o  -DLOAD_GPR_8 -DMISALIGN_DATA -DPADDING
+       ${CC} ${CCFLAGS} AdrpLdrGotStr-farunaligned-g8.o main.o -o AdrpLdrGotStr-farunaligned-g8.exe 
+       ${OTOOL} -tV AdrpLdrGotStr-farunaligned-g8.exe | grep 'adrp' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdrGotStr-farunaligned-g8.exe | grep 'add\t' | ${FAIL_IF_STDIN}
+       ${OTOOL} -tV AdrpLdrGotStr-farunaligned-g8.exe | grep 'str\tb2, \[x0,' | ${FAIL_IF_EMPTY}
+
+       # test ADRP/LDR/LDR left untouched when target is external and GOT slot far for 16-bit load
+       ${CC} ${CCFLAGS} AdrpLdrGotStr.s -c -o AdrpLdrGotStr-farunaligned-g16.o  -DLOAD_GPR_16 -DMISALIGN_DATA -DPADDING
+       ${CC} ${CCFLAGS} AdrpLdrGotStr-farunaligned-g16.o main.o -o AdrpLdrGotStr-farunaligned-g16.exe 
+       ${OTOOL} -tV AdrpLdrGotStr-farunaligned-g16.exe | grep 'adrp' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdrGotStr-farunaligned-g16.exe | grep 'add\t' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdrGotStr-farunaligned-g16.exe | grep 'str\th2, \[x1\]' | ${FAIL_IF_EMPTY}
+       
+       # test ADRP/LDR/LDR -> LDR literal when target close for 32-bit load
+       ${CC} ${CCFLAGS} AdrpLdrGotStr.s -c -o AdrpLdrGotStr-farunaligned-g32.o  -DLOAD_GPR_32 -DMISALIGN_DATA -DPADDING
+       ${CC} ${CCFLAGS} AdrpLdrGotStr-farunaligned-g32.o main.o -o AdrpLdrGotStr-farunaligned-g32.exe 
+       ${OTOOL} -tV AdrpLdrGotStr-farunaligned-g32.exe | grep 'adrp' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdrGotStr-farunaligned-g32.exe | grep 'add\t' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdrGotStr-farunaligned-g32.exe | grep 'str\tw2, \[x1\]' | ${FAIL_IF_EMPTY}
+
+       # test ADRP/LDR/LDR left untouched when target is external and GOT slot far for 64-bit load
+       ${CC} ${CCFLAGS} AdrpLdrGotStr.s -c -o AdrpLdrGotStr-farunaligned-g64.o  -DLOAD_GPR_64 -DMISALIGN_DATA -DPADDING
+       ${CC} ${CCFLAGS} AdrpLdrGotStr-farunaligned-g64.o main.o -o AdrpLdrGotStr-farunaligned-g64.exe 
+       ${OTOOL} -tV AdrpLdrGotStr-farunaligned-g64.exe | grep 'adrp' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdrGotStr-farunaligned-g64.exe | grep 'add\t' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdrGotStr-farunaligned-g64.exe | grep 'str\tx2, \[x1\]' | ${FAIL_IF_EMPTY}
+
+       # test ADRP/LDR/LDR left untouched when target is external and GOT slot far for 32-bit fp load
+       ${CC} ${CCFLAGS} AdrpLdrGotStr.s -c -o AdrpLdrGotStr-farunaligned-f32.o  -DLOAD_FPR_32 -DMISALIGN_DATA -DPADDING
+       ${CC} ${CCFLAGS} AdrpLdrGotStr-farunaligned-f32.o main.o -o AdrpLdrGotStr-farunaligned-f32.exe 
+       ${OTOOL} -tV AdrpLdrGotStr-farunaligned-f32.exe | grep 'adrp' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdrGotStr-farunaligned-f32.exe | grep 'add\t' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdrGotStr-farunaligned-f32.exe | grep 'str\ts2, \[x1\]' | ${FAIL_IF_EMPTY}
+
+       # test ADRP/LDR/LDR left untouched when target is external and GOT slot far for 64-bit fp load
+       ${CC} ${CCFLAGS} AdrpLdrGotStr.s -c -o AdrpLdrGotStr-farunaligned-f64.o  -DLOAD_FPR_64 -DMISALIGN_DATA -DPADDING
+       ${CC} ${CCFLAGS} AdrpLdrGotStr-farunaligned-f64.o main.o -o AdrpLdrGotStr-farunaligned-f64.exe 
+       ${OTOOL} -tV AdrpLdrGotStr-farunaligned-f64.exe | grep 'adrp' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdrGotStr-farunaligned-f64.exe | grep 'add\t' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdrGotStr-farunaligned-f64.exe | grep 'str\td2, \[x1\]' | ${FAIL_IF_EMPTY}
+       
+       # test ADRP/LDR/LDR -left untouched when target is external and GOT slot far for 128-bit vec load
+       ${CC} ${CCFLAGS} AdrpLdrGotStr.s -c -o AdrpLdrGotStr-farunaligned-v128.o  -DLOAD_VEC_128 -DMISALIGN_DATA -DPADDING
+       ${CC} ${CCFLAGS} AdrpLdrGotStr-farunaligned-v128.o main.o -o AdrpLdrGotStr-farunaligned-v128.exe 
+       ${OTOOL} -tV AdrpLdrGotStr-farunaligned-v128.exe | grep 'adrp' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdrGotStr-farunaligned-v128.exe | grep 'add\t' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdrGotStr-farunaligned-v128.exe | grep 'str\tq2, \[x1\]' | ${FAIL_IF_EMPTY}
+
+
+AdrpLdrGot:  main.o
+       # test ADRP/LDR left untouched when target is extern and GOT is far
+       ${CC} ${CCFLAGS} AdrpLdrGot.s -c -o AdrpLdrGot-externfar.o -DPADDING
+       ${CC} ${CCFLAGS} AdrpLdrGot-externfar.o main.o -o AdrpLdrGot-externfar.exe
+       ${OTOOL} -tV AdrpLdrGot-externfar.exe | grep 'adrp' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdrGot-externfar.exe | grep 'ldr\tx1, \[x0' | ${FAIL_IF_EMPTY}
+       
+       # test ADRP/LDR -> NOP/LDR literal when target is exern and GOT is near
+       ${CC} ${CCFLAGS} AdrpLdrGot.s -c -o AdrpLdrGot-externnear.o
+       ${CC} ${CCFLAGS} AdrpLdrGot-externnear.o main.o -o AdrpLdrGot-externnear.exe
+       ${OTOOL} -tV AdrpLdrGot-externnear.exe | grep 'adrp' | ${FAIL_IF_STDIN}
+       ${OTOOL} -tV AdrpLdrGot-externnear.exe | grep 'ldr\tx1' | ${FAIL_IF_EMPTY}
+       
+       # test ADRP/LDR -> ADR when target is local, near code 
+       ${CC} ${CCFLAGS} AdrpLdrGot.s -c -o AdrpLdrGot-localnear.o -DTARGET=_fooCode
+       ${CC} ${CCFLAGS} AdrpLdrGot-localnear.o main.o -o AdrpLdrGot-localnear.exe
+       ${OTOOL} -tV AdrpLdrGot-localnear.exe | grep 'adrp' | ${FAIL_IF_STDIN}
+       ${OTOOL} -tV AdrpLdrGot-localnear.exe | grep 'adr\tx1' | ${FAIL_IF_EMPTY}
+       
+       # test ADRP/LDR -> ADR when target is local, near data 
+       ${CC} ${CCFLAGS} AdrpLdrGot.s -c -o AdrpLdrGot-localnear2.o -DTARGET=_fooData
+       ${CC} ${CCFLAGS} AdrpLdrGot-localnear2.o main.o -o AdrpLdrGot-localnear2.exe
+       ${OTOOL} -tV AdrpLdrGot-localnear2.exe | grep 'adrp' | ${FAIL_IF_STDIN}
+       ${OTOOL} -tV AdrpLdrGot-localnear2.exe | grep 'adr\tx1' | ${FAIL_IF_EMPTY}
+       
+       # test ADRP/LDR -> ADR when target is local, far code 
+       ${CC} ${CCFLAGS} AdrpLdrGot.s -c -o AdrpLdrGot-localfar.o -DTARGET=_fooCode -DPADDING=1
+       ${CC} ${CCFLAGS} AdrpLdrGot-localfar.o main.o -o AdrpLdrGot-localfar.exe
+       ${OTOOL} -tV AdrpLdrGot-localfar.exe | grep 'adrp\tx1' | ${FAIL_IF_EMPTY}
+       ${OTOOL} -tV AdrpLdrGot-localfar.exe | grep 'add\tx1' | ${FAIL_IF_EMPTY}
+       
+
+
+clean:
+       rm -f *.o   *.exe   *.dylib
diff --git a/unit-tests/test-cases/linker-optimization-hints/main.s b/unit-tests/test-cases/linker-optimization-hints/main.s
new file mode 100644 (file)
index 0000000..762b4e4
--- /dev/null
@@ -0,0 +1,6 @@
+
+       .text
+  .align 2
+       .globl _main
+_main: ret     lr
+
index d7eb66053a5bd140da28235d7ca77c876ae743ff..d563cd969f67f50949605fb7f5d11fb65a002f8b 100644 (file)
@@ -35,12 +35,12 @@ endif
 run: ${ALL}
 
 all:
-       ${PASS_IFF_GOOD_MACHO} /usr/bin/true
+       ${PASS_IFF} /usr/bin/true
 
 all-i386:
-       ${CC} ${CCFLAGS} test.m -framework Foundation -o test1
+       ${CC} ${CCFLAGS} test.m -framework Foundation -o test1 -Wno-objc-root-class
        size -l test1 | grep __image_info | ${FAIL_IF_EMPTY}
-       ${CC} ${CCFLAGS} test.m -fobjc-abi-version=2 -Wl,-objc_abi_version,2 -framework Foundation -o test2
+       ${CC} ${CCFLAGS} test.m -Wno-objc-root-class -fobjc-abi-version=2 -Wl,-objc_abi_version,2 -framework Foundation -o test2
        size -l test2 | grep __objc_imageinfo | ${FAIL_IF_EMPTY}
        ${PASS_IFF_GOOD_MACHO} test2
        
index 8b4a29577d35e2bf574c8240cf92088dd95e3e56..292c456a19a22c34764389847cdbb2f25241b1a9 100644 (file)
@@ -1,5 +1,5 @@
 
-@interface Foo 
+@interface Foo
 @end
 
 @implementation Foo
index 2bbc5dd525ce396db69d23a8a3cf7df05b0225e6..7dcafac4b90fa208881767e642f0d2cbc06cb4eb 100644 (file)
@@ -29,7 +29,7 @@ include ${TESTROOT}/include/common.makefile
 OPTIONS = 
 
 ifeq ($(ARCH),i386)
-       OPTIONS = -fobjc-abi-version=2 -Wl,-objc_abi_version,2 -isysroot /Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator5.0.sdk -fobjc-legacy-dispatch
+       OPTIONS = -mios-simulator-version-min=6.0 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator7.0.sdk/
 endif
 
 all:   all-${ARCH}
index c395988affbf667939f4e86105e9e612d9a42505..de4ea0cc1293e72d452ed7451193133367e835a3 100644 (file)
@@ -29,7 +29,7 @@ include ${TESTROOT}/include/common.makefile
 OPTIONS = 
 
 ifeq ($(ARCH),i386)
-       OPTIONS = -fobjc-abi-version=2 -Wl,-objc_abi_version,2 -isysroot /Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator5.0.sdk -fobjc-legacy-dispatch
+       OPTIONS = -mios-simulator-version-min=6.0 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator7.0.sdk/
 endif
 
 ifeq ($(ARCH),arm)
index 5481ba0957ddeacff0748f03f16c9759479615ad..31d841b40fb0d0eb471d606ffe68a6400e3e9580 100644 (file)
@@ -30,7 +30,7 @@ SHELL = bash # use bash shell so we can redirect just stderr
 OPTIONS = 
 
 ifeq ($(ARCH),i386)
-       OPTIONS = -fobjc-abi-version=2 -Wl,-objc_abi_version,2 -isysroot /Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator5.0.sdk -fobjc-legacy-dispatch
+       OPTIONS = -mios-simulator-version-min=6.0 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator7.0.sdk/
 endif
 
 all:   all-${FILEARCH}
index 67e04a3c7ecc594463aa8f40cece3552cccb7246..13d17432bfb0e2c395624c5393be59d13916010d 100644 (file)
@@ -63,70 +63,70 @@ test-macosx:
        ${FAIL_IF_BAD_OBJ} bar-gc-only.o
 
        # check RR + RR -> RR
-       ${CC} ${CCFLAGS} foo.o bar.o runtime.c -dynamiclib -o libfoobar.dylib 
+       ${CC} ${CCFLAGS} foo.o bar.o runtime.c -dynamiclib -o libfoobar.dylib -framework Foundation
        ${FAIL_IF_BAD_MACHO} libfoobar.dylib
 
        # check GC/RR + GC/RR -> GC/RR
-       ${CC} ${CCFLAGS} foo-gc.o bar-gc.o runtime.c -dynamiclib -o libfoobar.dylib 
+       ${CC} ${CCFLAGS} foo-gc.o bar-gc.o runtime.c -dynamiclib -o libfoobar.dylib  -framework Foundation
        ${FAIL_IF_BAD_MACHO} libfoobar.dylib
        otool -o libfoobar.dylib | grep -A4 _image | grep flags | grep 0x2  | ${FAIL_IF_EMPTY}
 
        # check GC + GC -> GC
-       ${CC} ${CCFLAGS} foo-gc-only.o bar-gc-only.o runtime.c -dynamiclib -o libfoobar.dylib 
+       ${CC} ${CCFLAGS} foo-gc-only.o bar-gc-only.o runtime.c -dynamiclib -o libfoobar.dylib  -framework Foundation
        ${FAIL_IF_BAD_MACHO} libfoobar.dylib
        otool -o libfoobar.dylib | grep -A4 _image | grep flags | grep 0x6  | ${FAIL_IF_EMPTY}
 
        # check RR + GC/RR -> RR
-       ${CC} ${CCFLAGS} foo.o bar-gc.o runtime.c -dynamiclib -o libfoobar.dylib 
+       ${CC} ${CCFLAGS} foo.o bar-gc.o runtime.c -dynamiclib -o libfoobar.dylib  -framework Foundation
        ${FAIL_IF_BAD_MACHO} libfoobar.dylib
        otool -o libfoobar.dylib | grep -A4 _image | grep flags | grep 0x[26]  | ${FAIL_IF_STDIN}
 
        # check GC/RR + RR -> RR
-       ${CC} ${CCFLAGS} bar-gc.o foo.o runtime.c -dynamiclib -o libfoobar.dylib 
+       ${CC} ${CCFLAGS} bar-gc.o foo.o runtime.c -dynamiclib -o libfoobar.dylib  -framework Foundation
        ${FAIL_IF_BAD_MACHO} libfoobar.dylib
        otool -o libfoobar.dylib | grep -A4 _image | grep flags | grep 0x[26]  | ${FAIL_IF_STDIN}
 
        # check GC + GC/RR -> GC
-       ${CC} ${CCFLAGS} foo-gc-only.o bar-gc.o runtime.c -dynamiclib -o libfoobar.dylib  
+       ${CC} ${CCFLAGS} foo-gc-only.o bar-gc.o runtime.c -dynamiclib -o libfoobar.dylib   -framework Foundation
        ${FAIL_IF_BAD_MACHO} libfoobar.dylib
        otool -o libfoobar.dylib | grep -A4 _image | grep flags | grep 0x6  | ${FAIL_IF_EMPTY}
 
        # check RR + GC -> error
-       ${FAIL_IF_SUCCESS} ${CC} ${CCFLAGS} foo.o bar-gc-only.o runtime.c -dynamiclib -o libfoobar.dylib 2> fail.log
+       ${FAIL_IF_SUCCESS} ${CC} ${CCFLAGS} foo.o bar-gc-only.o runtime.c -dynamiclib -o libfoobar.dylib  -framework Foundation 2> fail.log
 
        # check cmd line GC/RR, GC/RR + RR -> error
-       ${FAIL_IF_SUCCESS} ${CC} ${CCFLAGS} foo-gc.o foo.o runtime.c -dynamiclib -o libfoobar.dylib -Wl,-objc_gc 2> fail.log
+       ${FAIL_IF_SUCCESS} ${CC} ${CCFLAGS} foo-gc.o foo.o runtime.c -dynamiclib -o libfoobar.dylib -Wl,-objc_gc  -framework Foundation 2> fail.log
        
        # check GC/RR + compaction
-       ${CC} ${CCFLAGS} foo-gc.o bar-gc.o runtime.c -dynamiclib -Wl,-objc_gc_compaction -o libfoobar.dylib 
+       ${CC} ${CCFLAGS} foo-gc.o bar-gc.o runtime.c -dynamiclib -Wl,-objc_gc_compaction -o libfoobar.dylib  -framework Foundation
        otool -o libfoobar.dylib | grep -A4 _image | grep flags | grep 0x12  | ${FAIL_IF_EMPTY}
 
        # check GC + compaction
-       ${CC} ${CCFLAGS} foo-gc-only.o bar-gc-only.o runtime.c -dynamiclib -Wl,-objc_gc_compaction -o libfoobar.dylib 
+       ${CC} ${CCFLAGS} foo-gc-only.o bar-gc-only.o runtime.c -dynamiclib -Wl,-objc_gc_compaction -o libfoobar.dylib  -framework Foundation
        otool -o libfoobar.dylib | grep -A4 _image | grep flags | grep 0x16  | ${FAIL_IF_EMPTY}
 
        # none + GC/RR-dylib -> none
-       ${CC} ${CCFLAGS} foo-gc.o runtime.c -dynamiclib -o libfoo.dylib 
-       ${CC} ${CCFLAGS} none.c libfoo.dylib -dynamiclib -o libnone.dylib
+       ${CC} ${CCFLAGS} foo-gc.o runtime.c -dynamiclib -o libfoo.dylib  -framework Foundation
+       ${CC} ${CCFLAGS} none.c libfoo.dylib -dynamiclib -o libnone.dylib -framework Foundation
        size -l libnone.dylib | grep ${IMAGE_INFO} | ${FAIL_IF_STDIN}
 
        # none + GC-dylib -> none
-       ${CC} ${CCFLAGS} foo-gc-only.o runtime.c -dynamiclib -o libfoo.dylib 
-       ${CC} ${CCFLAGS} none.c libfoo.dylib -dynamiclib -o libnone.dylib
+       ${CC} ${CCFLAGS} foo-gc-only.o runtime.c -dynamiclib -o libfoo.dylib  -framework Foundation
+       ${CC} ${CCFLAGS} none.c libfoo.dylib -dynamiclib -o libnone.dylib -framework Foundation
        size -l libnone.dylib | grep ${IMAGE_INFO} | ${FAIL_IF_STDIN}
 
        # none + RR-dylib -> none
-       ${CC} ${CCFLAGS} foo.o runtime.c -dynamiclib -o libfoo.dylib 
-       ${CC} ${CCFLAGS} none.c libfoo.dylib -dynamiclib -o libnone.dylib
+       ${CC} ${CCFLAGS} foo.o runtime.c -dynamiclib -o libfoo.dylib  -framework Foundation
+       ${CC} ${CCFLAGS} none.c libfoo.dylib -dynamiclib -o libnone.dylib -framework Foundation
        size -l libnone.dylib | grep ${IMAGE_INFO} | ${FAIL_IF_STDIN}
 
        # check RR + GC-dylib -> error
-       ${CC} ${CCFLAGS} foo-gc-only.o runtime.c -dynamiclib -o libfoo.dylib 
-       ${FAIL_IF_SUCCESS} ${CC} ${CCFLAGS} bar.o runtime.c -dynamiclib libfoo.dylib -o libbar.dylib 2> fail.log
+       ${CC} ${CCFLAGS} foo-gc-only.o runtime.c -dynamiclib -o libfoo.dylib  -framework Foundation
+       ${FAIL_IF_SUCCESS} ${CC} ${CCFLAGS} bar.o runtime.c -dynamiclib libfoo.dylib -o libbar.dylib  -framework Foundation 2> fail.log
 
        # check GC + RR-dylib -> error
-       ${CC} ${CCFLAGS} foo.o runtime.c -dynamiclib -o libfoo.dylib 
-       ${FAIL_IF_SUCCESS} ${CC} ${CCFLAGS} bar-gc-only.o runtime.c -dynamiclib libfoo.dylib -o libbar.dylib 2> fail.log
+       ${CC} ${CCFLAGS} foo.o runtime.c -dynamiclib -o libfoo.dylib  -framework Foundation
+       ${FAIL_IF_SUCCESS} ${CC} ${CCFLAGS} bar-gc-only.o runtime.c -dynamiclib libfoo.dylib -o libbar.dylib  -framework Foundation 2> fail.log
 
        ${PASS_IFF} true
 
index 5c98709873c1891eded40e371e41f34372030af9..f66df5006b3e703ce45deabb19317bb7c952abd3 100644 (file)
@@ -1,5 +1,6 @@
+#include <Foundation/Foundation.h>
 
-@interface Bar  {
+@interface Bar : NSObject {
        int f;
 }
 - (void) doit;
index e13367edc05eb2928a0187d1cf28fcfb57637e55..819049d636a1a76b8d66f87989f994ad4bf79f94 100644 (file)
@@ -1,5 +1,6 @@
+#include <Foundation/Foundation.h>
 
-@interface Foo  {
+@interface Foo : NSObject  {
        int f;
 }
 - (void) doit;
index 4837911f1724580b7031c6d00ee225b74199fa8a..3ead0e66f134ccfbe749e2c6661db09b638bc1d0 100644 (file)
 
 #include <stdio.h>
 #include <stdlib.h>
+#include <Foundation/Foundation.h>
 
-@interface Foo @end
+@interface Foo : NSObject
+@end
 @implementation Foo
 +(void)initialize { }
 +(void)foo {
index 25ca8c8bba6d18079e2b1c533cb7e337e49b45d9..4a568ae7492be86c5810e389540588ea22b18bd7 100644 (file)
@@ -24,7 +24,7 @@
  
 #include <Foundation/Foundation.h>
 
-@interface Test
+@interface Test : NSObject
 {
        BOOL            one;
        NSString*       two;                    
index 7d1ef815bc94aadd6bc84127f0a3b23e2eaf12d2..862e46e6447d4e6b87b0a259176484fa6988dbcb 100644 (file)
@@ -48,7 +48,7 @@ public:
 };
 
 void Foo::print() {
-       printf("%d\n", a);
+       printf("%d %d\n", a, b);
 }
 
 
index a9ca5ef1875a92d41326eab5f607ed24e808eae1..d62de340e42a3e56efc01ccb3ac5cd83921db518 100644 (file)
@@ -35,7 +35,7 @@ include ${TESTROOT}/include/common.makefile
 run: all
 
 all:
-       ${CC} ${CCFLAGS} -Os $(MDYNAMIC_NO_PIC) test.c -c -o test.${ARCH}.o
+       ${CC} ${CCFLAGS} -Os $(MDYNAMIC_NO_PIC) test.c -c -o test.${ARCH}.o -Wno-array-bounds
        ${FAIL_IF_ERROR} ${OBJECTDUMP} -no_content test.${ARCH}.o > test.${ARCH}.o.dump
 
        ${LD} -arch ${ARCH} -r -keep_private_externs test.${ARCH}.o -o test-r.${ARCH}.o
index 2d199d08a793e2a07ef652560013f5e864841553..5939ef42300f5098a535695f83506052674ddc92 100644 (file)
@@ -48,7 +48,7 @@ long double getLongDouble() { return 3.0; }
 
 // rdar://problem/4732996
 const char* stringFutz(int x) {
-       return "hello" + 0x1000 + x;
+       return &"hello"[0x1000 + x];
 }
 
-const char*    usesAddend = "teststr" + 0x2000;
+const char*    usesAddend = &"teststr"[0x2000];
index 23e4a828276e63b0511382dc03d9a5ca41ec5ea3..b1820f09801777f885bb40d5fa40af30fdd23707 100644 (file)
@@ -38,7 +38,7 @@ endif
 run: all
 
 all:
-       ${CC} ${CCFLAGS} -Os $(PIC) test.c -c -o test.${ARCH}.o
+       ${CC} ${CCFLAGS} -Os $(PIC) test.c -c -o test.${ARCH}.o -Wno-array-bounds
        ${FAIL_IF_ERROR} ${OBJECTDUMP} -no_content test.${ARCH}.o > test.${ARCH}.o.dump
 
        ${LD} -arch ${ARCH} -r -keep_private_externs test.${ARCH}.o -o test-r.${ARCH}.o
index 2d199d08a793e2a07ef652560013f5e864841553..5939ef42300f5098a535695f83506052674ddc92 100644 (file)
@@ -48,7 +48,7 @@ long double getLongDouble() { return 3.0; }
 
 // rdar://problem/4732996
 const char* stringFutz(int x) {
-       return "hello" + 0x1000 + x;
+       return &"hello"[0x1000 + x];
 }
 
-const char*    usesAddend = "teststr" + 0x2000;
+const char*    usesAddend = &"teststr"[0x2000];
index 1ca215766d2decd553edaea196e4c7afa9841109..2b2bf9c910d38aba6f7afdc878b6fc0fcc5f7bdd 100644 (file)
@@ -48,7 +48,7 @@
 
 
 
-@interface Base
+@interface Base : NSObject
 @end