]> git.saurik.com Git - apple/ld64.git/commitdiff
ld64-241.9.tar.gz developer-tools-60 developer-tools-61 developer-tools-62 v241.9
authorApple <opensource@apple.com>
Mon, 3 Nov 2014 23:59:51 +0000 (23:59 +0000)
committerApple <opensource@apple.com>
Mon, 3 Nov 2014 23:59:51 +0000 (23:59 +0000)
73 files changed:
doc/man/man1/ld.1
ld64.xcodeproj/project.pbxproj
src/abstraction/MachOFileAbstraction.hpp
src/ld/HeaderAndLoadCommands.hpp
src/ld/InputFiles.cpp
src/ld/InputFiles.h
src/ld/LinkEditClassic.hpp
src/ld/Options.cpp
src/ld/Options.h
src/ld/OutputFile.cpp
src/ld/Resolver.cpp
src/ld/Resolver.h
src/ld/SymbolTable.cpp
src/ld/ld.cpp
src/ld/ld.hpp
src/ld/parsers/libunwind/DwarfInstructions.hpp
src/ld/parsers/libunwind/DwarfParser.hpp
src/ld/parsers/libunwind/Registers.hpp
src/ld/parsers/lto_file.cpp
src/ld/parsers/lto_file.h
src/ld/parsers/macho_dylib_file.cpp
src/ld/parsers/macho_relocatable_file.cpp
src/ld/passes/branch_island.cpp
src/ld/passes/compact_unwind.cpp
src/ld/passes/objc.cpp
src/ld/passes/order.cpp
src/other/ObjectDump.cpp
src/other/unwinddump.cpp
unit-tests/include/common.makefile
unit-tests/test-cases/alias-basic/Makefile [new file with mode: 0644]
unit-tests/test-cases/alias-basic/aliases.s [new file with mode: 0644]
unit-tests/test-cases/alias-basic/main.c [new file with mode: 0644]
unit-tests/test-cases/alias-objects/Makefile
unit-tests/test-cases/alias-objects/aliases.s
unit-tests/test-cases/alt-entry/Makefile [new file with mode: 0644]
unit-tests/test-cases/alt-entry/foo.c [new file with mode: 0644]
unit-tests/test-cases/alt-entry/main.c [new file with mode: 0644]
unit-tests/test-cases/lto-r/Makefile [new file with mode: 0644]
unit-tests/test-cases/lto-r/bar.c [new file with mode: 0644]
unit-tests/test-cases/lto-r/foo.c [new file with mode: 0644]
unit-tests/test-cases/lto-r/main.c [new file with mode: 0644]
unit-tests/test-cases/lto-rename_section/Makefile [new file with mode: 0644]
unit-tests/test-cases/lto-rename_section/a.c [new file with mode: 0644]
unit-tests/test-cases/lto-rename_section/b.c [new file with mode: 0644]
unit-tests/test-cases/lto-rename_section/main.c [new file with mode: 0644]
unit-tests/test-cases/lto-rename_segment/Makefile [new file with mode: 0644]
unit-tests/test-cases/lto-rename_segment/a.c [new file with mode: 0644]
unit-tests/test-cases/lto-rename_segment/b.c [new file with mode: 0644]
unit-tests/test-cases/lto-rename_segment/main.c [new file with mode: 0644]
unit-tests/test-cases/lto-symbol-section-move/Makefile [new file with mode: 0644]
unit-tests/test-cases/lto-symbol-section-move/foo.c [new file with mode: 0644]
unit-tests/test-cases/lto-symbol-section-move/main.c [new file with mode: 0644]
unit-tests/test-cases/lto-symbol-section-move/other.c [new file with mode: 0644]
unit-tests/test-cases/lto-symbol-section-move/ram1.symbols [new file with mode: 0644]
unit-tests/test-cases/lto-symbol-section-move/rom1.symbols [new file with mode: 0644]
unit-tests/test-cases/preload-section_order/Makefile [new file with mode: 0644]
unit-tests/test-cases/preload-section_order/extra.s [new file with mode: 0644]
unit-tests/test-cases/preload-section_order/main.c [new file with mode: 0644]
unit-tests/test-cases/preload-section_order/main1.expected [new file with mode: 0644]
unit-tests/test-cases/preload-section_order/main2.expected [new file with mode: 0644]
unit-tests/test-cases/preload-section_order/more.s [new file with mode: 0644]
unit-tests/test-cases/preload-segment_order/Makefile [new file with mode: 0644]
unit-tests/test-cases/preload-segment_order/a.c [new file with mode: 0644]
unit-tests/test-cases/preload-segment_order/b.c [new file with mode: 0644]
unit-tests/test-cases/preload-segment_order/main-segs.expected [new file with mode: 0644]
unit-tests/test-cases/preload-segment_order/main.c [new file with mode: 0644]
unit-tests/test-cases/section-labels/main.c
unit-tests/test-cases/symbol-section-move/Makefile [new file with mode: 0644]
unit-tests/test-cases/symbol-section-move/main.c [new file with mode: 0644]
unit-tests/test-cases/symbol-section-move/other.c [new file with mode: 0644]
unit-tests/test-cases/symbol-section-move/ram1.symbols [new file with mode: 0644]
unit-tests/test-cases/symbol-section-move/rom1.symbols [new file with mode: 0644]
unit-tests/test-cases/weak_import-undefined/Makefile

index 964d099e1fed6cc93b8dcdffa212d1ceebf64f45..df4b5a4b17a79b7860930fbbdc075c0979b038a6 100644 (file)
@@ -384,8 +384,6 @@ 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
@@ -521,10 +519,49 @@ of wildcards.
 .Bl -tag
 .It Fl v
 Prints the version of the linker.
+.It Fl move_to_rw_segment Ar segment_name Ar filename
+Moves data symbols to another segment.  The command line option specifies the
+target segment name and a path to a file containing a list of symbols to move.
+Comments can be added to the symbol file by starting a line with a #.
+If there are multiple instances of a symbol name (for instance a "static int foo=5;" in multiple files)
+the symbol name in the symbol list file can be prefixed with the object file name 
+(e.g. "init.o:_foo") to move a specific instance.
+.It Fl move_to_ro_section Ar segment_name Ar section_name Ar filename
+Moves code symbols to another segment.  The command line option specifies the
+target segment name and a path to a file containing a list of symbols to move.
+Comments can be added to the symbol file by starting a line with a #.
+If there are multiple instances of a symbol name (for instance a "static int foo() {}" in multiple files)
+the symbol name in the symbol list file can be prefixed with the object file name 
+(e.g. "init.o:_foo") to move a specific instance.
+.It Fl rename_section Ar orgSegment orgSection newSegment newSection
+Renames section orgSegment/orgSection to newSegment/newSection.
+.It Fl rename_segment Ar orgSegment newSegment 
+Renames all sections with orgSegment segment name to have newSegment segment name.
+.It Fl trace_symbol_layout
+For using in debugging -rename_section, -rename_segment, -move_to_ro_segment, and -move_to_rw_segment.
+This option prints out a line show where and why each symbol was moved.
+Note: These options do not chain.  For each symbol, the linker first checks
+-move_to_ro_segment and -move_to_rw_segment.  If the symbol is not moved,
+it checks for an applicable -rename_section.  Only if the symbol still has
+not been moved, does the linker look for an applicable -rename_segment option.
+.It Fl section_order Ar segname Ar colon_separated_section_list
+Only for use with -preload.  Specifies the order that sections with the specified segment should be layout out.
+For example: "-section_order __ROM __text:__const:__cstring". 
+.It Fl segment_order Ar colon_separated_segment_list
+Only for use with -preload.  Specifies the order segments should be layout out.
+For example: "-segment_order __ROM:__ROM2:__RAM". 
 .It Fl allow_heap_execute
 Normally i386 main executables will be marked so that the Mac OS X 10.7 and later kernel 
 will only allow pages with the x-bit to execute instructions. This option overrides that
 behavior and allows instructions on any page to be executed.
+.It Fl application_extension
+Specifies that the code is being linked for use in an application extension.  The linker
+will then validiate that any dynamic libraries linked against are safe for use in
+application extensions.
+.It Fl no_application_extension
+Specifies that the code is being linked is not safe for use in an application extension. 
+For instance, can be used when creating a framework that should not be used in
+an application extension.
 .It Fl fatal_warnings
 Causes the linker to exit with a non-zero value if any warnings were emitted.
 .It Fl no_eh_labels
index 250fa5e89638164a9d7b535350d75cfb6ba85841..854356efcb5c3cf9fc8cd45ed1a19ce6a7563c73 100644 (file)
                B3B672441406D44300A376BB /* Snapshot.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.h; name = Snapshot.h; path = src/ld/Snapshot.h; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
                B3C7A09914295B9C005FC714 /* compile_stubs */ = {isa = PBXFileReference; lastKnownFileType = text.script.csh; path = compile_stubs; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
                F9023C3906D5A23E001BBF46 /* ld */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = ld; sourceTree = BUILT_PRODUCTS_DIR; };
-               F9023C3F06D5A254001BBF46 /* ld.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = ld.cpp; path = src/ld/ld.cpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+               F9023C3F06D5A254001BBF46 /* ld.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ld.cpp; path = src/ld/ld.cpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
+               F91B7B0318987D5F0099486F /* AddressSpace.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = AddressSpace.hpp; sourceTree = "<group>"; };
+               F91B7B0418987D5F0099486F /* DwarfInstructions.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = DwarfInstructions.hpp; sourceTree = "<group>"; };
+               F91B7B0518987D5F0099486F /* DwarfParser.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = DwarfParser.hpp; sourceTree = "<group>"; };
+               F91B7B0618987D5F0099486F /* InternalMacros.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InternalMacros.h; sourceTree = "<group>"; };
+               F91B7B0718987D5F0099486F /* Registers.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Registers.hpp; sourceTree = "<group>"; };
                F92D9C2710657AAB00FF369B /* stub_x86_64_classic.hpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.cpp.h; path = stub_x86_64_classic.hpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
                F933D9460929277C0083EAC8 /* FileAbstraction.hpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = FileAbstraction.hpp; path = src/abstraction/FileAbstraction.hpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
                F933D9470929277C0083EAC8 /* MachOFileAbstraction.hpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 4; lastKnownFileType = sourcecode.cpp.h; name = MachOFileAbstraction.hpp; path = src/abstraction/MachOFileAbstraction.hpp; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
                        name = Products;
                        sourceTree = "<group>";
                };
+               F91B7B0218987D5F0099486F /* libunwind */ = {
+                       isa = PBXGroup;
+                       children = (
+                               F91B7B0318987D5F0099486F /* AddressSpace.hpp */,
+                               F91B7B0418987D5F0099486F /* DwarfInstructions.hpp */,
+                               F91B7B0518987D5F0099486F /* DwarfParser.hpp */,
+                               F91B7B0618987D5F0099486F /* InternalMacros.h */,
+                               F91B7B0718987D5F0099486F /* Registers.hpp */,
+                       );
+                       path = libunwind;
+                       sourceTree = "<group>";
+               };
                F9AA650B1051BD2B003E3539 /* passes */ = {
                        isa = PBXGroup;
                        children = (
                F9AA65861051E750003E3539 /* parsers */ = {
                        isa = PBXGroup;
                        children = (
+                               F91B7B0218987D5F0099486F /* libunwind */,
                                F9AA6784105700C2003E3539 /* opaque_section_file.cpp */,
                                F9AA6785105700C2003E3539 /* opaque_section_file.h */,
                                F9AA65D71051EC4A003E3539 /* archive_file.cpp */,
index 92797342610bd819214b76f5a636f74798bda68b..8b58efd2357e3d6b7f83012634bf8914fcb3dec7 100644 (file)
        #define N_SYMBOL_RESOLVER 0x100
 #endif
 
+#ifndef N_AST
+       #define N_AST 0x32
+#endif
+
 #ifndef LC_FUNCTION_STARTS
        #define LC_FUNCTION_STARTS      0x26
 #endif
   };
 #endif
 
+#ifndef MH_APP_EXTENSION_SAFE
+       #define MH_APP_EXTENSION_SAFE 0x02000000
+#endif
 
+#ifndef N_ALT_ENTRY
+       #define N_ALT_ENTRY 0x0200
+#endif
 
 #ifndef CPU_SUBTYPE_ARM_V7F
   #define CPU_SUBTYPE_ARM_V7F    ((cpu_subtype_t) 10)
 
 #define UNWIND_ARM64_DWARF_SECTION_OFFSET               0x00FFFFFF
 
+
 #ifndef LC_SOURCE_VERSION
        #define LC_SOURCE_VERSION 0x2A
        struct source_version_command {
        #define CPU_SUBTYPE_X86_64_H    ((cpu_subtype_t) 8) 
 #endif 
 
+
 struct ArchInfo {
        const char*                     archName;
        cpu_type_t                      cpuType;
index acbdf4f3057e8ada8386b1fd9c37475af705b4b7..3629af5ac3f9de32f4b7292eabea2e0dd13b8ade 100644 (file)
@@ -591,6 +591,8 @@ uint32_t HeaderAndLoadCommandsAtom<A>::flags() const
                                bits |= MH_HAS_TLV_DESCRIPTORS;
                        if ( _options.hasNonExecutableHeap() )
                                bits |= MH_NO_HEAP_EXECUTION;
+                       if ( _options.markAppExtensionSafe() && (_options.outputKind() == Options::kDynamicLibrary) )
+                               bits |= MH_APP_EXTENSION_SAFE;
                }
                if ( _options.hasExecutableStack() )
                        bits |= MH_ALLOW_STACK_EXECUTION;
@@ -750,6 +752,9 @@ uint32_t HeaderAndLoadCommandsAtom<A>::sectionFlags(ld::Internal::FinalSection*
                case ld::Section::typeTempLTO:
                        assert(0 && "typeTempLTO should not make it to final linked image");
                        return S_REGULAR;
+               case ld::Section::typeTempAlias:
+                       assert(0 && "typeAlias should not make it to final linked image");
+                       return S_REGULAR;
                case ld::Section::typeAbsoluteSymbols:
                        assert(0 && "typeAbsoluteSymbols should not make it to final linked image");
                        return S_REGULAR;
index f49f2e350d820c0d6364cbf0045400ce89b77dcd..595b5d19cdc7d53fa500324914584c39536e6a64 100644 (file)
@@ -255,8 +255,17 @@ ld::File* InputFiles::makeFile(const Options::FileInfo& info, bool indirectDylib
                        uint32_t fileOffset = OSSwapBigToHostInt32(archs[sliceToUse].offset);
                        len = OSSwapBigToHostInt32(archs[sliceToUse].size);
                        if ( fileOffset+len > info.fileLen ) {
-                               throwf("truncated fat file. Slice from %u to %llu is past end of file with length %llu", 
+                               // <rdar://problem/17593430> file size was read awhile ago.  If file is being written, wait a second to see if big enough now
+                               sleep(1);
+                               uint64_t newFileLen = info.fileLen;
+                               struct stat statBuffer;
+                               if ( stat(info.path, &statBuffer) == 0 ) {
+                                       newFileLen = statBuffer.st_size;
+                               }
+                               if ( fileOffset+len > newFileLen ) {
+                                       throwf("truncated fat file. Slice from %u to %llu is past end of file with length %llu", 
                                                fileOffset, fileOffset+len, info.fileLen);
+                               }
                        }
                        // if requested architecture is page aligned within fat file, then remap just that portion of file
                        if ( (fileOffset & 0x00000FFF) == 0 ) {
@@ -301,11 +310,27 @@ ld::File* InputFiles::makeFile(const Options::FileInfo& info, bool indirectDylib
        }
        
        // see if it is a dynamic library
-       ld::dylib::File* dylibResult = mach_o::dylib::parse(p, len, info.path, info.modTime, _options, info.ordinal, info.options.fBundleLoader, indirectDylib);
-       if ( dylibResult != NULL ) {
-               return dylibResult;
+       ld::dylib::File* dylibResult;
+       bool dylibsNotAllowed = false;
+       switch ( _options.outputKind() ) {
+               case Options::kDynamicExecutable:
+               case Options::kDynamicLibrary:
+               case Options::kDynamicBundle:   
+                       dylibResult = mach_o::dylib::parse(p, len, info.path, info.modTime, _options, info.ordinal, info.options.fBundleLoader, indirectDylib);
+                       if ( dylibResult != NULL ) {
+                               return dylibResult;
+                       }
+                       break;
+               case Options::kStaticExecutable:
+               case Options::kDyld:
+               case Options::kPreload:
+               case Options::kObjectFile:
+               case Options::kKextBundle:
+                       dylibsNotAllowed = true;
+                       break;
        }
 
+
        // see if it is a static library
        ::archive::ParserOptions archOpts;
        archOpts.objOpts                                = objOpts;
@@ -350,6 +375,13 @@ ld::File* InputFiles::makeFile(const Options::FileInfo& info, bool indirectDylib
                }
        }
 
+       if ( dylibsNotAllowed ) {
+               cpu_type_t dummy1;
+               cpu_type_t dummy2;
+               if ( mach_o::dylib::isDylibFile(p, &dummy1, &dummy2) )
+                       throw "ignoring unexpected dylib file";
+       }
+
        // error handling
        if ( ((fat_header*)p)->magic == OSSwapBigToHostInt32(FAT_MAGIC) ) {
                throwf("missing required architecture %s in file %s (%u slices)", _options.architectureName(), info.path, sliceCount);
@@ -538,7 +570,7 @@ bool InputFiles::libraryAlreadyLoaded(const char* path)
 }
 
 
-void InputFiles::addLinkerOptionLibraries(ld::Internal& state)
+void InputFiles::addLinkerOptionLibraries(ld::Internal& state, ld::File::AtomHandler& handler)
 {      
     if ( _options.outputKind() == Options::kObjectFile ) 
                return;
@@ -554,6 +586,7 @@ void InputFiles::addLinkerOptionLibraries(ld::Internal& state)
                                ld::dylib::File* dylibReader = dynamic_cast<ld::dylib::File*>(reader);
                                if ( dylibReader != NULL ) {
                                        if ( ! dylibReader->installPathVersionSpecific() ) {
+                                               dylibReader->forEachAtom(handler);
                                                dylibReader->setImplicitlyLinked();
                                                this->addDylib(dylibReader, info);
                                        }
@@ -574,10 +607,13 @@ void InputFiles::addLinkerOptionLibraries(ld::Internal& state)
                if ( ! this->libraryAlreadyLoaded(info.path) ) {
                        info.ordinal = _linkerOptionOrdinal.nextLinkerOptionOrdinal();
                        try {
+                               //<rdar://problem/17787306> -force_load_swift_libs
+                               info.options.fForceLoad = _options.forceLoadSwiftLibs() && (strncmp(libName, "swift", 5) == 0);
                                ld::File* reader = this->makeFile(info, true);
                                ld::dylib::File* dylibReader = dynamic_cast<ld::dylib::File*>(reader);
                                ld::archive::File* archiveReader = dynamic_cast<ld::archive::File*>(reader);
                                if ( dylibReader != NULL ) {
+                                       dylibReader->forEachAtom(handler);
                                        dylibReader->setImplicitlyLinked();
                                        this->addDylib(dylibReader, info);
                                }
@@ -585,6 +621,10 @@ void InputFiles::addLinkerOptionLibraries(ld::Internal& state)
                                        _searchLibraries.push_back(LibraryInfo(archiveReader));
                                        if ( _options.dumpDependencyInfo() )
                                                _options.dumpDependency(Options::depArchive, archiveReader->path());
+                                       //<rdar://problem/17787306> -force_load_swift_libs
+                                       if (info.options.fForceLoad) {
+                                               archiveReader->forEachAtom(handler);
+                                       }
                                }
                                else {
                                        throwf("linker option dylib at %s is not a dylib", info.path);
@@ -895,6 +935,9 @@ void InputFiles::parseWorkerThread() {
                                                warning("ignoring file %s, %s", entry.path, msg);
                                        }
                                } 
+                               else if ( strstr(msg, "ignoring unexpected") != NULL ) {
+                                       warning("%s, %s", entry.path, msg);
+                               }
                                else {
                                        asprintf((char**)&exception, "%s file '%s'", msg, entry.path);
                                }
@@ -1127,7 +1170,7 @@ void InputFiles::forEachInitialAtom(ld::File::AtomHandler& handler, ld::Internal
        }
 
        markExplicitlyLinkedDylibs();
-       addLinkerOptionLibraries(state);
+       addLinkerOptionLibraries(state, handler);
        createIndirectDylibs();
        createOpaqueFileSections();
        
@@ -1276,6 +1319,14 @@ static bool vectorContains(const std::vector<ld::dylib::File*>& vec, ld::dylib::
        return std::find(vec.begin(), vec.end(), key) != vec.end();
 }
 
+struct DylibByInstallNameSorter
+{      
+        bool operator()(const ld::dylib::File* left, const ld::dylib::File* right)
+        {
+          return (strcmp(left->installPath(), right->installPath()) < 0);
+        }
+};
+
 void InputFiles::dylibs(ld::Internal& state)
 {
        bool dylibsOK = false;
@@ -1310,14 +1361,18 @@ void InputFiles::dylibs(ld::Internal& state)
        }
        // add implicitly linked dylibs
        if ( _options.nameSpace() == Options::kTwoLevelNameSpace ) {
+               std::vector<ld::dylib::File*> implicitDylibs;
                for (InstallNameToDylib::const_iterator it=_installPathToDylibs.begin(); it != _installPathToDylibs.end(); ++it) {
                        ld::dylib::File* dylibFile = it->second;
                        if ( dylibFile->implicitlyLinked() && dylibsOK ) {
-                               if ( ! vectorContains(state.dylibs, dylibFile) ) {
-                                       state.dylibs.push_back(dylibFile);
+                               if ( ! vectorContains(implicitDylibs, dylibFile) ) {
+                                       implicitDylibs.push_back(dylibFile);
                                }
                        }
                }
+               // <rdar://problem/15002251> make implicit dylib order be deterministic by sorting by install_name
+               std::sort(implicitDylibs.begin(), implicitDylibs.end(), DylibByInstallNameSorter());
+               state.dylibs.insert(state.dylibs.end(), implicitDylibs.begin(), implicitDylibs.end());
        }
 
        //fprintf(stderr, "all dylibs:\n");
index b1e85cbf5d4ac67b58127f99ad0cbd8b02966b91..608ce39f41f20349a0ec035a1a2eea7a26851219 100644 (file)
@@ -74,7 +74,7 @@ public:
        
        bool                                            inferredArch() const { return _inferredArch; }
        
-       void                                            addLinkerOptionLibraries(ld::Internal& state);
+       void                                            addLinkerOptionLibraries(ld::Internal& state, ld::File::AtomHandler& handler);
        void                                            createIndirectDylibs();
 
        // for -print_statistics
index b9b12156b5960355de378806cc3707218ce07e47..3389f5ce69e4c8cc440377aa455e7c2859827c17 100644 (file)
@@ -224,7 +224,7 @@ private:
        uint32_t                                                stringOffsetForStab(const ld::relocatable::File::Stab& stab, StringPoolAtom* pool);
        uint64_t                                                valueForStab(const ld::relocatable::File::Stab& stab);
        uint8_t                                                 sectionIndexForStab(const ld::relocatable::File::Stab& stab);
-       
+       bool                                                    isAltEntry(const ld::Atom* atom);
 
        mutable std::vector<macho_nlist<P> >    _globals;
        mutable std::vector<macho_nlist<P> >    _locals;
@@ -247,6 +247,29 @@ template <typename A>
 int     SymbolTableAtom<A>::_s_anonNameIndex = 1;
 
 
+template <typename A>
+bool SymbolTableAtom<A>::isAltEntry(const ld::Atom* atom) 
+{
+       // alt entries have a group subordinate reference to the previous atom
+       for (ld::Fixup::iterator fit = atom->fixupsBegin(); fit != atom->fixupsEnd(); ++fit) {
+               if ( fit->kind == ld::Fixup::kindNoneGroupSubordinate ) {
+                       if ( fit->binding == Fixup::bindingDirectlyBound ) {
+                               const Atom* prevAtom = fit->u.target;
+                               assert(prevAtom != NULL);
+                               for (ld::Fixup::iterator fit2 = prevAtom->fixupsBegin(); fit2 != prevAtom->fixupsEnd(); ++fit2) {
+                                       if ( fit2->kind == ld::Fixup::kindNoneFollowOn ) {
+                                               if ( fit2->binding == Fixup::bindingDirectlyBound ) {
+                                                       if ( fit2->u.target == atom )
+                                                               return true;
+                                               }
+                                       }
+                               }
+                       }
+               }
+       }
+       return false;
+}
+
 template <typename A>
 bool SymbolTableAtom<A>::addLocal(const ld::Atom* atom, StringPoolAtom* pool) 
 {
@@ -312,6 +335,8 @@ bool SymbolTableAtom<A>::addLocal(const ld::Atom* atom, StringPoolAtom* pool)
                desc |= N_WEAK_DEF;
        if ( atom->isThumb() )
                desc |= N_ARM_THUMB_DEF;
+    if ( (this->_options.outputKind() == Options::kObjectFile) && this->_state.allObjectFilesScatterable && isAltEntry(atom) )
+        desc |= N_ALT_ENTRY;
        entry.set_n_desc(desc);
 
        // set n_value ( address this symbol will be at if this executable is loaded at it preferred address )
@@ -387,6 +412,8 @@ void SymbolTableAtom<A>::addGlobal(const ld::Atom* atom, StringPoolAtom* pool)
         desc |= N_SYMBOL_RESOLVER;
     if ( atom->dontDeadStrip() && (this->_options.outputKind() == Options::kObjectFile) )
         desc |= N_NO_DEAD_STRIP;
+    if ( (this->_options.outputKind() == Options::kObjectFile) && this->_state.allObjectFilesScatterable && isAltEntry(atom) )
+        desc |= N_ALT_ENTRY;
        if ( (atom->definition() == ld::Atom::definitionRegular) && (atom->combine() == ld::Atom::combineByName) ) {
                desc |= N_WEAK_DEF;
                // <rdar://problem/6783167> support auto hidden weak symbols: .weak_def_can_be_hidden
@@ -451,7 +478,13 @@ void SymbolTableAtom<A>::addImport(const ld::Atom* atom, StringPoolAtom* pool)
 
        // set n_type
        if ( this->_options.outputKind() == Options::kObjectFile ) {
-               if ( (atom->scope() == ld::Atom::scopeLinkageUnit) 
+               if ( atom->section().type() == ld::Section::typeTempAlias ) {
+                       if ( atom->scope() == ld::Atom::scopeLinkageUnit )
+                               entry.set_n_type(N_INDR | N_EXT | N_PEXT);
+                       else
+                               entry.set_n_type(N_INDR | N_EXT);
+               }
+               else if ( (atom->scope() == ld::Atom::scopeLinkageUnit) 
                                && (atom->definition() == ld::Atom::definitionTentative) )
                        entry.set_n_type(N_UNDF | N_EXT | N_PEXT);
                else 
@@ -500,8 +533,24 @@ void SymbolTableAtom<A>::addImport(const ld::Atom* atom, StringPoolAtom* pool)
        // set n_value, zero for import proxy and size for tentative definition
        if ( atom->definition() == ld::Atom::definitionTentative )
                entry.set_n_value(atom->size());
-       else
+       else if ( atom->section().type() != ld::Section::typeTempAlias )
                entry.set_n_value(0);
+       else {
+               assert(atom->fixupsBegin() != atom->fixupsEnd());
+               for (ld::Fixup::iterator fit = atom->fixupsBegin(); fit != atom->fixupsEnd(); ++fit) {
+                       assert(fit->kind == ld::Fixup::kindNoneFollowOn);
+                       switch ( fit->binding ) {
+                               case ld::Fixup::bindingByNameUnbound:
+                                       entry.set_n_value(pool->add(fit->u.name));
+                                       break;
+                               case ld::Fixup::bindingsIndirectlyBound:
+                                       entry.set_n_value(pool->add((_state.indirectBindingTable[fit->u.bindingIndex])->name()));
+                                       break;
+                               default:
+                                       assert(0 && "internal error: unexpected alias binding");
+                       }
+               }
+       }
        
        // add to array
        _imports.push_back(entry);
@@ -775,13 +824,13 @@ uint64_t LocalRelocationsAtom<x86_64>::relocBaseAddress(ld::Internal& state)
                // for kext bundles the reloc base address starts at __TEXT segment
                return _options.baseAddress();
        }
-       // for all other kinds, the x86_64 reloc base address starts at __DATA segment
+       // for all other kinds, the x86_64 reloc base address starts at first writable segment (usually __DATA)
        for (std::vector<ld::Internal::FinalSection*>::iterator sit = state.sections.begin(); sit != state.sections.end(); ++sit) {
                ld::Internal::FinalSection* sect = *sit;
-               if ( strcmp(sect->segmentName(), "__DATA") == 0 )
+               if ( !sect->isSectionHidden() && _options.initialSegProtection(sect->segmentName()) & VM_PROT_WRITE )
                        return sect->address;
        }
-       throw "__DATA segment not found";
+       throw "writable (__DATA) segment not found";
 }
 
 template <typename A>
@@ -892,10 +941,10 @@ uint64_t ExternalRelocationsAtom<x86_64>::relocBaseAddress(ld::Internal& state)
        // for x86_64 the reloc base address starts at __DATA segment
        for (std::vector<ld::Internal::FinalSection*>::iterator sit = state.sections.begin(); sit != state.sections.end(); ++sit) {
                ld::Internal::FinalSection* sect = *sit;
-               if ( strcmp(sect->segmentName(), "__DATA") == 0 )
+               if ( !sect->isSectionHidden() && _options.initialSegProtection(sect->segmentName()) & VM_PROT_WRITE )
                        return sect->address;
        }
-       throw "__DATA segment not found";
+       throw "writable (__DATA) segment not found";
 }
 
 template <typename A>
index 057fad996b255a41885bce60476c2c430c68b2dc..aa4f6ee85205f7c62c05704ae1916ca3e98805fb 100644 (file)
@@ -127,7 +127,7 @@ Options::Options(int argc, const char* argv[])
          fHasPreferredSubType(false), fArchSupportsThumb2(false), fPrebind(false), fBindAtLoad(false), fKeepPrivateExterns(false),
          fNeedsModuleTable(false), fIgnoreOtherArchFiles(false), fErrorOnOtherArchFiles(false), fForceSubtypeAll(false), 
          fInterposeMode(kInterposeNone), fDeadStrip(false), fNameSpace(kTwoLevelNameSpace),
-         fDylibCompatVersion(0), fDylibCurrentVersion(0), fDylibInstallName(NULL), fFinalName(NULL), fEntryName("start"), 
+         fDylibCompatVersion(0), fDylibCurrentVersion(0), fDylibInstallName(NULL), fFinalName(NULL), fEntryName(NULL), 
          fBaseAddress(0), fMaxAddress(0x7FFFFFFFFFFFFFFFLL), 
          fBaseWritableAddress(0), fSplitSegs(false),
          fExportMode(kExportDefault), fLibrarySearchMode(kSearchDylibAndArchiveInEachDir),
@@ -176,7 +176,8 @@ Options::Options(int argc, const char* argv[])
          fAllowSimulatorToLinkWithMacOSX(false), fKeepDwarfUnwind(true),
          fKeepDwarfUnwindForcedOn(false), fKeepDwarfUnwindForcedOff(false),
          fVerboseOptimizationHints(false), fIgnoreOptimizationHints(false),
-         fGenerateDtraceDOF(true), fAllowBranchIslands(true),
+         fGenerateDtraceDOF(true), fAllowBranchIslands(true), fTraceSymbolLayout(false), 
+         fMarkAppExtensionSafe(false), fCheckAppExtensionSafe(false), fForceLoadSwiftLibs(false), 
          fDebugInfoStripping(kDebugInfoMinimal), fTraceOutputFile(NULL), 
          fMacVersionMin(ld::macVersionUnset), fIOSVersionMin(ld::iOSVersionUnset), 
          fSaveTempFiles(false), fSnapshotRequested(false), fPipelineFifo(NULL), 
@@ -539,6 +540,17 @@ bool Options::keepLocalSymbol(const char* symbolName) const
        throw "internal error";
 }
 
+const std::vector<const char*>* Options::sectionOrder(const char* segName) const
+{ 
+       for (std::vector<SectionOrderList>::const_iterator it=fSectionOrder.begin(); it != fSectionOrder.end(); ++it) {
+               if ( strcmp(it->segmentName, segName) == 0 )
+                       return &it->sectionOrder;
+       }
+       return NULL;
+}
+
+
+
 void Options::setArchitecture(cpu_type_t type, cpu_subtype_t subtype)
 {
        for (const ArchInfo* t=archInfoArray; t->archName != NULL; ++t) {
@@ -1012,19 +1024,40 @@ void Options::SetWithWildcards::insert(const char* symbol)
                fRegular.insert(symbol);
 }
 
-bool Options::SetWithWildcards::contains(const char* symbol) const
+bool Options::SetWithWildcards::contains(const char* symbol, bool* matchBecauseOfWildcard) const
 {
+       if ( matchBecauseOfWildcard != NULL )
+               *matchBecauseOfWildcard = false;
        // first look at hash table on non-wildcard symbols
        if ( fRegular.find(symbol) != fRegular.end() )
                return true;
        // next walk list of wild card symbols looking for a match
        for(std::vector<const char*>::const_iterator it = fWildCard.begin(); it != fWildCard.end(); ++it) {
-               if ( wildCardMatch(*it, symbol) )
+               if ( wildCardMatch(*it, symbol) ) {
+                       if ( matchBecauseOfWildcard != NULL )
+                               *matchBecauseOfWildcard = true;
                        return true;
+               }
        }
        return false;
 }
 
+// Support "foo.o:_bar" to mean symbol _bar in file foo.o
+bool Options::SetWithWildcards::containsWithPrefix(const char* symbol, const char* file, bool& wildCardMatch) const
+{
+       wildCardMatch = false;
+       if ( contains(symbol, &wildCardMatch) )
+               return true;
+       if ( file == NULL )
+               return false;
+       const char* s = strrchr(file, '/');
+       if ( s != NULL )
+               file = s+1;
+       char buff[strlen(file)+strlen(symbol)+2];
+       sprintf(buff, "%s:%s", file, symbol);
+       return contains(buff, &wildCardMatch);
+}
+
 bool Options::SetWithWildcards::containsNonWildcard(const char* symbol) const
 {
        // look at hash table on non-wildcard symbols
@@ -1753,6 +1786,59 @@ void Options::addSectionRename(const char* srcSegment, const char* srcSection, c
 }
 
 
+void Options::addSegmentRename(const char* srcSegment, const char* dstSegment)
+{
+       if ( strlen(srcSegment) > 16 )
+               throw "-rename_segment segment name max 16 chars";
+       if ( strlen(dstSegment) > 16 )
+               throw "-rename_segment segment name max 16 chars";
+
+       SegmentRename info;
+       info.fromSegment = srcSegment;
+       info.toSegment = dstSegment;
+
+       fSegmentRenames.push_back(info);
+}
+
+
+
+void Options::addSymbolMove(const char* dstSegment, const char* symbolList,
+                                                       std::vector<SymbolsMove>& list, const char* optionName)
+{
+       if ( strlen(dstSegment) > 16 )
+               throwf("%s segment name max 16 chars", optionName);
+       
+       SymbolsMove tmp;
+       list.push_back(tmp);
+       SymbolsMove& info = list.back();
+       info.toSegment = dstSegment;
+       loadExportFile(symbolList, optionName, info.symbols);
+}
+               
+bool Options::moveRwSymbol(const char* symName, const char* filePath, const char*& seg, bool& wildCardMatch) const
+{
+       for (std::vector<SymbolsMove>::const_iterator it=fSymbolsMovesData.begin(); it != fSymbolsMovesData.end(); ++it) {
+               const SymbolsMove& info = *it;
+               if ( info.symbols.containsWithPrefix(symName, filePath, wildCardMatch)) {
+                       seg  = info.toSegment;
+                       return true;
+               }
+       }
+       return false;
+}
+
+bool Options::moveRoSymbol(const char* symName, const char* filePath, const char*& seg, bool& wildCardMatch) const
+{
+       for (std::vector<SymbolsMove>::const_iterator it=fSymbolsMovesCode.begin(); it != fSymbolsMovesCode.end(); ++it) {
+               const SymbolsMove& info = *it;
+               if ( info.symbols.containsWithPrefix(symName, filePath, wildCardMatch)) {
+                       seg  = info.toSegment;
+                       return true;
+               }
+       }
+       return false;
+}
+
 void Options::addSectionAlignment(const char* segment, const char* section, const char* alignmentStr)
 {
        if ( strlen(segment) > 16 )
@@ -2904,6 +2990,7 @@ void Options::parse(int argc, const char* argv[])
                                fKextsUseStubs = true;
                        }
                        else if ( strcmp(argv[i], "-dependency_info") == 0 ) {
+                snapshotArgCount = 0;
                                ++i;
                                // previously handled by buildSearchPaths()
                        }
@@ -2962,9 +3049,96 @@ void Options::parse(int argc, const char* argv[])
                                addSectionRename(argv[i+1], argv[i+2], argv[i+3], argv[i+4]);
                                i += 4;
                        }
+                       else if ( strcmp(arg, "-rename_segment") == 0 ) {
+                                if ( (argv[i+1]==NULL) || (argv[i+2]==NULL) )
+                                       throw "-rename_segment missing <existing-segment> <new-segment>";
+                               addSegmentRename(argv[i+1], argv[i+2]);
+                               i += 2;
+                       }
+                       else if ( strcmp(arg, "-move_to_ro_segment") == 0 ) {
+                                if ( (argv[i+1]==NULL) || (argv[i+2]==NULL) )
+                                       throw "-move_to_ro_segment missing <segment> <symbol-list-file>";
+                               addSymbolMove(argv[i+1], argv[i+2], fSymbolsMovesCode, "-move_to_ro_segment");
+                               i += 2;
+                       }
+                       else if ( strcmp(arg, "-move_to_rw_segment") == 0 ) {
+                                if ( (argv[i+1]==NULL) || (argv[i+2]==NULL) )
+                                       throw "-move_to_rw_segment missing <segment> <symbol-list-file>";
+                               addSymbolMove(argv[i+1], argv[i+2], fSymbolsMovesData, "-move_to_rw_segment");
+                               i += 2;
+                       }
+                       else if ( strcmp(arg, "-trace_symbol_layout") == 0 ) {
+                               fTraceSymbolLayout = true;
+                       }
                        else if ( strcmp(arg, "-no_branch_islands") == 0 ) {
                                fAllowBranchIslands = false;
                        }
+                       else if ( strcmp(arg, "-segment_order") == 0 ) {
+                               // ex: -segment_order __TEXT:__DATA:__JUNK
+                               const char* optString = argv[++i];
+                               if ( optString == NULL )
+                                       throw "-segment_order missing colon separated <segment-list>";
+                               if ( !fSegmentOrder.empty() )
+                                       throw "-segment_order used more than once";
+                               // break up into list of tokens at colon
+                               char* buffer = strdup(optString);
+                               char* start = buffer;
+                               for (char* s = buffer; ; ++s) {
+                                       if ( *s == ':'  ) {
+                                               *s = '\0';
+                                               fSegmentOrder.push_back(start);
+                                               start = s+1;
+                                       }
+                                       else if ( *s == '\0' ) {
+                                               fSegmentOrder.push_back(start);
+                                               break;
+                                       }
+                               }
+                       }
+                       else if ( strcmp(arg, "-section_order") == 0 ) {
+                               // ex: -section_order __DATA  __data:__const:__nl_pointers
+                                if ( (argv[i+1]==NULL) || (argv[i+2]==NULL) )
+                                       throw "-section_order missing <segment> <section-list>";
+                               const char* segName = argv[++i];
+                               const char* optString = argv[++i];
+                               if ( sectionOrder(segName) != NULL )
+                                       throwf("-section_order %s ... used more than once", segName);
+                               SectionOrderList dummy;
+                               fSectionOrder.push_back(dummy);
+                               SectionOrderList& entry = fSectionOrder.back();
+                               entry.segmentName = segName;
+                               // break up into list of tokens at colon
+                               char* buffer = strdup(optString);
+                               char* start = buffer;
+                               for (char* s = buffer; ; ++s) {
+                                       if ( *s == ':'  ) {
+                                               *s = '\0';
+                                               entry.sectionOrder.push_back(start);
+                                               start = s+1;
+                                       }
+                                       else if ( *s == '\0' ) {
+                                               entry.sectionOrder.push_back(start);
+                                               break;
+                                       }
+                               }
+                       }                       
+                       else if ( strcmp(arg, "-application_extension") == 0 ) {
+                               fMarkAppExtensionSafe = true;
+                               fCheckAppExtensionSafe = true;
+                       }
+                       else if ( strcmp(arg, "-no_application_extension") == 0 ) {
+                               fMarkAppExtensionSafe = false;
+                               fCheckAppExtensionSafe = false;
+                       }
+                       else if ( strcmp(arg, "-add_ast_path") == 0 ) {
+                               const char* path = argv[++i];
+                               if ( path == NULL )
+                                       throw "-add_ast_path missing <option>";
+                               fASTFilePaths.push_back(path);
+                       }
+                       else if ( strcmp(arg, "-force_load_swift_libs") == 0 ) {
+                               fForceLoadSwiftLibs = true;
+                       }
                        // 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, ':');
@@ -3253,8 +3427,16 @@ void Options::parsePreCommandLineEnvironmentSettings()
        if (getenv("LD_SPLITSEGS_NEW_LIBRARIES") != NULL)
                fSplitSegs = true;
                
-       if (getenv("LD_NO_ENCRYPT") != NULL)
+       if (getenv("LD_NO_ENCRYPT") != NULL) {
                fEncryptable = false;
+               fMarkAppExtensionSafe = true; // temporary
+               fCheckAppExtensionSafe = false;
+       }
+
+       if (getenv("LD_APPLICATION_EXTENSION_SAFE") != NULL) {
+               fMarkAppExtensionSafe = true;
+               fCheckAppExtensionSafe = false;
+       }
        
        if (getenv("LD_ALLOW_CPU_SUBTYPE_MISMATCHES") != NULL)
                fAllowCpuSubtypeMismatches = true;
@@ -3716,9 +3898,24 @@ void Options::reconfigureDefaults()
                        break;
        }
                
-       // only iOS main executables should be encrypted
-       if ( fOutputKind != Options::kDynamicExecutable )
-               fEncryptable = false;
+       // only iOS executables should be encryptable
+       switch ( fOutputKind ) {
+               case Options::kObjectFile:
+               case Options::kDyld:
+               case Options::kStaticExecutable:
+               case Options::kPreload:
+               case Options::kKextBundle:
+                       fEncryptable = false;
+                       break;
+               case Options::kDynamicExecutable:
+                       break;
+               case Options::kDynamicLibrary:
+               case Options::kDynamicBundle:
+                       // <rdar://problem/16293398> Add LC_ENCRYPTION_INFO load command to bundled frameworks
+                       if ( fIOSVersionMin < ld::iOS_8_0 )
+                               fEncryptable = false;
+                       break;
+       }
        if ( (fArchitecture != CPU_TYPE_ARM) && (fArchitecture != CPU_TYPE_ARM64) )
                fEncryptable = false;
 
@@ -3829,6 +4026,10 @@ void Options::reconfigureDefaults()
                        fPositionIndependentExecutable = true;
        }
 
+       // Simulator defaults to PIE
+       if ( fTargetIOSSimulator && (fOutputKind == kDynamicExecutable) )
+               fPositionIndependentExecutable = true;
+
        // -no_pie anywhere on command line disable PIE
        if ( fDisablePositionIndependentExecutable )
                fPositionIndependentExecutable = false;
@@ -3862,7 +4063,7 @@ void Options::reconfigureDefaults()
        if ( fMacVersionMin >= ld::mac10_7 ) {
                fTLVSupport = true;
        }
-       else if ( (fArchitecture == CPU_TYPE_ARM64) && (fIOSVersionMin >= 0x00080000) ) {
+       else if ( (fArchitecture == CPU_TYPE_ARM64) && (fIOSVersionMin >= ld::iOS_8_0) ) {
                fTLVSupport = true;
        }
 
@@ -3916,18 +4117,30 @@ void Options::reconfigureDefaults()
                case Options::kDynamicExecutable:
                        if ( fEntryPointLoadCommandForceOn ) {
                                fEntryPointLoadCommand = true;
-                               fEntryName = "_main";
+                               if ( fEntryName == NULL ) 
+                                       fEntryName = "_main";
                        }
                        else if ( fEntryPointLoadCommandForceOff ) {
                                fNeedsThreadLoadCommand = true;
+                               if ( fEntryName == NULL ) 
+                                       fEntryName = "start";
                        }
                        else {
-                               if ( minOS(ld::mac10_8, ld::iOS_6_0) ) {
+                               // <rdar://problem/16310363> Linker should look for "_main" not "start" when building for sim regardless of min OS
+                               if ( minOS(ld::mac10_8, ld::iOS_6_0) || fTargetIOSSimulator ) {
                                        fEntryPointLoadCommand = true;
-                                       fEntryName = "_main";
-                               }
-                               else
+                                       if ( fEntryName == NULL ) 
+                                               fEntryName = "_main";
+                                       if ( strcmp(fEntryName, "start") == 0 ) {
+                                               warning("Ignoring '-e start' because entry point 'start' is not used for the targeted OS version");
+                                               fEntryName = "_main";
+                                       }
+                               } 
+                               else {
                                        fNeedsThreadLoadCommand = true;
+                                       if ( fEntryName == NULL ) 
+                                               fEntryName = "start";
+                               }
                        }
                        break;
                case Options::kObjectFile:
@@ -3940,6 +4153,8 @@ void Options::reconfigureDefaults()
                case Options::kPreload:
                case Options::kDyld:
                        fNeedsThreadLoadCommand = true;
+                       if ( fEntryName == NULL ) 
+                               fEntryName = "start";  // Perhaps these should have no default and require -e
                        break;
        }
        
@@ -4053,8 +4268,11 @@ void Options::reconfigureDefaults()
        }
   
        // <rdar://problem/12258065> ARM64 needs 16KB page size for user land code
-       if ( fArchitecture == CPU_TYPE_ARM64 ) {
-               if ( fSegmentAlignment == 4096 ) {
+       // <rdar://problem/15974532> make armv7[s] use 16KB pages in user land code for iOS 8 or later
+       if ( fSegmentAlignment == 4096 ) {
+               if ( (fArchitecture == CPU_TYPE_ARM64) 
+               || ((fArchitecture == CPU_TYPE_ARM) && (fIOSVersionMin >= ld::iOS_8_0) && 
+                       ((fSubArchitecture == CPU_SUBTYPE_ARM_V7S) || (fSubArchitecture == CPU_SUBTYPE_ARM_V7))) ) {
                        switch ( fOutputKind ) {
                                case Options::kDynamicExecutable:
                                case Options::kDynamicLibrary:
@@ -4070,7 +4288,7 @@ void Options::reconfigureDefaults()
                        }
                }
        }
-       
+
        // <rdar://problem/13624134> linker should not convert dwarf unwind if .o file has compact unwind section
        switch ( fOutputKind ) {
                case Options::kDynamicExecutable:
@@ -4538,9 +4756,15 @@ void Options::checkIllegalOptionCombinations()
        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";
+       // -segment_order can only be used with -preload
+       if ( !fSegmentOrder.empty() && (fOutputKind != Options::kPreload) )
+               throw "-segment_order can only used used with -preload output";
+
+       // <rdar://problem/17598404> warn if building an embedded iOS dylib for pre-iOS 8
+       if ( (fOutputKind == Options::kDynamicLibrary) && (fIOSVersionMin != ld::iOSVersionUnset) && (fDylibInstallName != NULL) ) {
+               if ( (fIOSVersionMin < ld::iOS_8_0) && (fDylibInstallName[0] == '@') ) 
+                       warning("embedded dylibs/frameworks only run on iOS 8 or later");
+       }
 }      
 
 
index 019581585ded02fd10d40f80f6b07922766b6706..8395fc90057d27fc9304da64cd73173181822af4 100644 (file)
@@ -140,6 +140,11 @@ public:
                uint8_t                                 alignment;
        };
 
+       struct SectionOrderList {
+               const char*                                     segmentName;
+               std::vector<const char*>        sectionOrder;
+       };
+
        struct OrderedSymbol {
                const char*                             symbolName;
                const char*                             objectFileName;
@@ -179,6 +184,10 @@ public:
                const char*                     toSection;
        };
 
+       struct SegmentRename {
+               const char*                     fromSegment;
+               const char*                     toSegment;
+       };
 
        enum { depLinkerVersion=0x00, depObjectFile=0x10, depDirectDylib=0x10, depIndirectDylib=0x10, 
                  depUpwardDirectDylib=0x10, depUpwardIndirectDylib=0x10, depArchive=0x10,
@@ -248,6 +257,7 @@ public:
        bool                                            hasNonExecutableHeap() const { return fNonExecutableHeap; }
        UndefinesIterator                       initialUndefinesBegin() const { return &fInitialUndefines[0]; }
        UndefinesIterator                       initialUndefinesEnd() const { return &fInitialUndefines[fInitialUndefines.size()]; }
+       const std::vector<const char*>& initialUndefines() const { return fInitialUndefines; }
        bool                                            printWhyLive(const char* name) const;
        uint32_t                                        minimumHeaderPad() const { return fMinimumHeaderPad; }
        bool                                            maxMminimumHeaderPad() const { return fMaxMinimumHeaderPad; }
@@ -300,7 +310,10 @@ public:
        bool                                            makeEncryptable() const { return fEncryptable; }
        bool                                            needsUnwindInfoSection() const { return fAddCompactUnwindEncoding; }
        const std::vector<const char*>& llvmOptions() const{ return fLLVMOptions; }
+       const std::vector<const char*>& segmentOrder() const{ return fSegmentOrder; }
+       const std::vector<const char*>* sectionOrder(const char* segName) const;
        const std::vector<const char*>& dyldEnvironExtras() const{ return fDyldEnvironExtras; }
+       const std::vector<const char*>& astFilePaths() const{ return fASTFilePaths; }
        bool                                            makeCompressedDyldInfo() const { return fMakeCompressedDyldInfo; }
        bool                                            hasExportedSymbolOrder();
        bool                                            exportedSymbolOrder(const char* sym, unsigned int* order) const;
@@ -347,6 +360,10 @@ public:
        bool                                            ignoreOptimizationHints() const { return fIgnoreOptimizationHints; }
        bool                                            generateDtraceDOF() const { return fGenerateDtraceDOF; }
        bool                                            allowBranchIslands() const { return fAllowBranchIslands; }
+       bool                                            traceSymbolLayout() const { return fTraceSymbolLayout; }
+       bool                                            markAppExtensionSafe() const { return fMarkAppExtensionSafe; }
+       bool                                            checkDylibsAreAppExtensionSafe() const { return fCheckAppExtensionSafe; }
+       bool                                            forceLoadSwiftLibs() const { return fForceLoadSwiftLibs; }
        bool                                            hasWeakBitTweaks() const;
        bool                                            forceWeak(const char* symbolName) const;
        bool                                            forceNotWeak(const char* symbolName) const;
@@ -374,6 +391,9 @@ public:
        FileInfo                                        findFramework(const char* frameworkName) const;
        FileInfo                                        findLibrary(const char* rootName, bool dylibsOnly=false) const;
        const std::vector<SectionRename>& sectionRenames() const { return fSectionRenames; }
+       const std::vector<SegmentRename>& segmentRenames() const { return fSegmentRenames; }
+       bool                                            moveRoSymbol(const char* symName, const char* filePath, const char*& seg, bool& wildCardMatch) const;
+       bool                                            moveRwSymbol(const char* symName, const char* filePath, const char*& seg, bool& wildCardMatch) const;
 
 private:
        typedef std::unordered_map<const char*, unsigned int, ld::CStringHash, ld::CStringEquals> NameToOrder;
@@ -385,7 +405,8 @@ private:
        class SetWithWildcards {
        public:
                void                                    insert(const char*);
-               bool                                    contains(const char*) const;
+               bool                                    contains(const char*, bool* wildCardMatch=NULL) const;
+               bool                                    containsWithPrefix(const char* symbol, const char* file, bool& wildCardMatch) const;
                bool                                    containsNonWildcard(const char*) const;
                bool                                    empty() const                   { return fRegular.empty() && fWildCard.empty(); }
                bool                                    hasWildCards() const    { return !fWildCard.empty(); }
@@ -401,6 +422,10 @@ private:
                std::vector<const char*>                fWildCard;
        };
 
+       struct SymbolsMove {
+               const char*                     toSegment;
+               SetWithWildcards        symbols;
+       };
 
        void                                            parse(int argc, const char* argv[]);
        void                                            checkIllegalOptionCombinations();
@@ -437,7 +462,8 @@ private:
        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);
-
+       void                                            addSegmentRename(const char* srcSegment, const char* dstSegment);
+       void                                            addSymbolMove(const char* dstSegment, const char* symbolList, std::vector<SymbolsMove>& list, const char* optionName);
 
 
 //     ObjectFile::ReaderOptions                       fReaderOptions;
@@ -608,6 +634,10 @@ private:
        bool                                                            fIgnoreOptimizationHints;
        bool                                                            fGenerateDtraceDOF;
        bool                                                            fAllowBranchIslands;
+       bool                                                            fTraceSymbolLayout;
+       bool                                                            fMarkAppExtensionSafe;
+       bool                                                            fCheckAppExtensionSafe;
+       bool                                                            fForceLoadSwiftLibs;
        DebugInfoStripping                                      fDebugInfoStripping;
        const char*                                                     fTraceOutputFile;
        ld::MacVersionMin                                       fMacVersionMin;
@@ -628,8 +658,15 @@ private:
        std::vector<const char*>                        fFrameworkSearchPaths;
        std::vector<const char*>                        fSDKPaths;
        std::vector<const char*>                        fDyldEnvironExtras;
+       std::vector<const char*>                        fSegmentOrder;
+       std::vector<const char*>                        fASTFilePaths;
+       std::vector<SectionOrderList>           fSectionOrder;
        std::vector< std::vector<const char*> > fLinkerOptions;
        std::vector<SectionRename>                      fSectionRenames;
+       std::vector<SegmentRename>                      fSegmentRenames;
+       std::vector<SymbolsMove>                        fSymbolsMovesData;
+       std::vector<SymbolsMove>                        fSymbolsMovesCode;
+       std::vector<SymbolsMove>                        fSymbolsMovesZeroFill;
        bool                                                            fSaveTempFiles;
     mutable Snapshot                                   fLinkSnapshot;
     bool                                                               fSnapshotRequested;
index c7a0918b34fa99f81d3fd29946f93dfcb7752380..1680ade089e8c8fa6221d187327a8924c9239cb8 100644 (file)
@@ -363,6 +363,8 @@ void OutputFile::setLoadCommandsPadding(ld::Internal& state)
                        // work backwards from end of segment and lay out sections so that extra room goes to padding atom
                        uint64_t addr = 0;
                        uint64_t textSegPageSize = _options.segPageSize("__TEXT");
+                       if ( _options.sharedRegionEligible() && (_options.iOSVersionMin() >= ld::iOS_8_0) && (textSegPageSize == 0x4000) )
+                               textSegPageSize = 0x1000;
                        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 ) 
@@ -778,6 +780,8 @@ 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); }
 
+#if SUPPORT_ARCH_arm64
+
 static uint32_t makeNOP() {
        return 0xD503201F;
 }
@@ -1187,6 +1191,7 @@ static bool withinOneMeg(uint64_t addr1, uint64_t addr2) {
        int64_t delta = (addr2 - addr1);
        return ( (delta < 1024*1024) && (delta > -1024*1024) );
 }
+#endif // SUPPORT_ARCH_arm64
 
 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) 
@@ -1217,6 +1222,7 @@ void OutputFile::setInfo(ld::Internal& state, const ld::Atom* atom, uint8_t* buf
        info->instruction = get32LE(info->instructionContent);
 }      
 
+#if SUPPORT_ARCH_arm64
 static bool isPageKind(const ld::Fixup* fixup, bool mustBeGOT=false)
 {
        if ( fixup == NULL )
@@ -1280,6 +1286,7 @@ static bool isPageOffsetKind(const ld::Fixup* fixup, bool mustBeGOT=false)
        }
        return false;
 }
+#endif // SUPPORT_ARCH_arm64
 
 
 #define LOH_ASSERT(cond) \
@@ -1346,6 +1353,9 @@ void OutputFile::applyFixUps(ld::Internal& state, uint64_t mhAddress, const ld::
                                break;
                        case ld::Fixup::kindSetTargetImageOffset:
                                accumulator = addressOf(state, fit, &toTarget) - mhAddress;
+                               thumbTarget = targetIsThumb(state, fit);
+                               if ( thumbTarget ) 
+                                       accumulator |= 1;
                                break;
                        case ld::Fixup::kindSetTargetSectionOffset:
                                accumulator = sectionOffsetOf(state, fit);
@@ -1724,6 +1734,21 @@ void OutputFile::applyFixUps(ld::Internal& state, uint64_t mhAddress, const ld::
                                                if ( islandfit->kind == ld::Fixup::kindIslandTarget ) {
                                                        const ld::Atom* islandTarget = NULL;
                                                        uint64_t islandTargetAddress = addressOf(state, islandfit, &islandTarget);
+                                                       if ( !fit->contentDetlaToAddendOnly ) {
+                                                               if ( targetIsThumb(state, islandfit) ) {
+                                                                       // Thumb to thumb branch, we will be generating a bl instruction.
+                                                                       // Delta is always even, so mask out thumb bit in target.
+                                                                       islandTargetAddress &= -2ULL;
+                                                               }
+                                                               else {
+                                                                       // Target is not thumb, we will be generating a blx instruction
+                                                                       // Since blx cannot have the low bit set, set bit[1] of the target to
+                                                                       // bit[1] of the base address, so that the difference is a multiple of
+                                                                       // 4 bytes.
+                                                                       islandTargetAddress &= -3ULL;
+                                                                       islandTargetAddress |= ((atom->finalAddress() + fit->offsetInAtom ) & 2LL);
+                                                               }
+                                                       }
                                                        delta = islandTargetAddress - (atom->finalAddress() + fit->offsetInAtom + 4);
                                                        if ( checkThumbBranch22Displacement(delta) ) {
                                                                toTarget = islandTarget;
@@ -1744,16 +1769,28 @@ void OutputFile::applyFixUps(ld::Internal& state, uint64_t mhAddress, const ld::
                                is_bl = ((instruction & 0xD000F800) == 0xD000F000);
                                is_blx = ((instruction & 0xD000F800) == 0xC000F000);
                                is_b = ((instruction & 0xD000F800) == 0x9000F000);
-                               // If the target is not thumb, we will be generating a blx instruction
-                               // Since blx cannot have the low bit set, set bit[1] of the target to
-                               // bit[1] of the base address, so that the difference is a multiple of
-                               // 4 bytes.
-                               if ( !thumbTarget && !fit->contentDetlaToAddendOnly ) {
-                                 accumulator &= -3ULL;
-                                 accumulator |= ((atom->finalAddress() + fit->offsetInAtom ) & 2LL);
+                               if ( !fit->contentDetlaToAddendOnly ) {
+                                       if ( thumbTarget ) {
+                                               // Thumb to thumb branch, we will be generating a bl instruction.
+                                               // Delta is always even, so mask out thumb bit in target.
+                                               accumulator &= -2ULL;
+                                       }
+                                       else {
+                                               // Target is not thumb, we will be generating a blx instruction
+                                               // Since blx cannot have the low bit set, set bit[1] of the target to
+                                               // bit[1] of the base address, so that the difference is a multiple of
+                                               // 4 bytes.
+                                               accumulator &= -3ULL;
+                                               accumulator |= ((atom->finalAddress() + fit->offsetInAtom ) & 2LL);
+                                       }
                                }
                                // The pc added will be +4 from the pc
                                delta = accumulator - (atom->finalAddress() + fit->offsetInAtom + 4);
+                               // <rdar://problem/16652542> support bl in very large .o files
+                               if ( fit->contentDetlaToAddendOnly ) {
+                                       while ( delta < (-16777216LL) ) 
+                                               delta += 0x2000000;
+                               }
                                rangeCheckThumbBranch22(delta, state, atom, fit);
                                if ( _options.preferSubArchitecture() && _options.archSupportsThumb2() ) {
                                        // The instruction is really two instructions:
@@ -2010,6 +2047,7 @@ void OutputFile::applyFixUps(ld::Internal& state, uint64_t mhAddress, const ld::
                }
        }
        
+#if SUPPORT_ARCH_arm64
        // 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
@@ -2449,9 +2487,7 @@ void OutputFile::applyFixUps(ld::Internal& state, uint64_t mhAddress, const ld::
                        }                               
                }
        }
-
-
-       
+#endif // SUPPORT_ARCH_arm64
 
 }
 
@@ -2815,6 +2851,11 @@ void OutputFile::buildSymbolTable(ld::Internal& state)
                                        else
                                                (const_cast<ld::Atom*>(atom))->setSymbolTableInclusion(ld::Atom::symbolTableIn);
                                }
+                               else if ( sect->type() == ld::Section::typeTempAlias ) {
+                                       assert(_options.outputKind() == Options::kObjectFile);
+                                       _importedAtoms.push_back(atom);
+                                       continue;
+                               }
                                if ( atom->symbolTableInclusion() == ld::Atom::symbolTableNotInFinalLinkedImages )
                                        (const_cast<ld::Atom*>(atom))->setSymbolTableInclusion(ld::Atom::symbolTableIn);
                        }
@@ -4540,8 +4581,8 @@ void OutputFile::writeMapFile(ld::Internal& state)
                                        else if ( (atom->contentType() == ld::Atom::typeCFI) && (strcmp(name, "FDE") == 0) ) {
                                                for (ld::Fixup::iterator fit = atom->fixupsBegin(); fit != atom->fixupsEnd(); ++fit) {
                                                        if ( (fit->kind == ld::Fixup::kindSetTargetAddress) && (fit->clusterSize == ld::Fixup::k1of4) ) {
-                                                               assert(fit->binding == ld::Fixup::bindingDirectlyBound);
-                                                               if ( fit->u.target->section().type() == ld::Section::typeCode) {
+                                                               if ( (fit->binding == ld::Fixup::bindingDirectlyBound)
+                                                                &&  (fit->u.target->section().type() == ld::Section::typeCode) ) {
                                                                        strcpy(buffer, "FDE for: ");
                                                                        strlcat(buffer, fit->u.target->name(), 4096);
                                                                        name = buffer;
@@ -4612,6 +4653,15 @@ const char* OutputFile::assureFullPath(const char* path)
        return path;
 }
 
+static time_t fileModTime(const char* path) {
+       struct stat statBuffer;
+       if ( stat(path, &statBuffer) == 0 ) {
+               return statBuffer.st_mtime;
+       }
+       return 0;
+}
+
+
 void OutputFile::synthesizeDebugNotes(ld::Internal& state)
 {
        // -S means don't synthesize debug map
@@ -4678,6 +4728,21 @@ void OutputFile::synthesizeDebugNotes(ld::Internal& state)
        // sort by file ordinal then atom ordinal
        std::sort(atomsNeedingDebugNotes.begin(), atomsNeedingDebugNotes.end(), DebugNoteSorter());
 
+       // <rdar://problem/17689030> Add -add_ast_path option to linker which add N_AST stab entry to output
+       const std::vector<const char*>& astPaths = _options.astFilePaths();
+       for (std::vector<const char*>::const_iterator it=astPaths.begin(); it != astPaths.end(); it++) {
+               const char* path = *it;
+               //  emit N_AST
+               ld::relocatable::File::Stab astStab;
+               astStab.atom    = NULL;
+               astStab.type    = N_AST;
+               astStab.other   = 0;
+               astStab.desc    = 0;
+               astStab.value   = fileModTime(path);
+               astStab.string  = path;
+               state.stabs.push_back(astStab);
+       }
+       
        // synthesize "debug notes" and add them to master stabs vector
        const char* dirPath = NULL;
        const char* filename = NULL;
@@ -4689,20 +4754,20 @@ void OutputFile::synthesizeDebugNotes(ld::Internal& state)
                const ld::File* atomFile = atom->file();
                const ld::relocatable::File* atomObjFile = dynamic_cast<const ld::relocatable::File*>(atomFile);
                //fprintf(stderr, "debug note for %s\n", atom->name());
-    const char* newPath = atom->translationUnitSource();
-    if ( newPath != NULL ) {
-      const char* newDirPath;
-      const char* newFilename;
-      const char* lastSlash = strrchr(newPath, '/');
-      if ( lastSlash == NULL ) 
-        continue;
-      newFilename = lastSlash+1;
-      char* temp = strdup(newPath);
-      newDirPath = temp;
-      // gdb like directory SO's to end in '/', but dwarf DW_AT_comp_dir usually does not have trailing '/'
-      temp[lastSlash-newPath+1] = '\0';
+               const char* newPath = atom->translationUnitSource();
+               if ( newPath != NULL ) {
+                       const char* newDirPath;
+                       const char* newFilename;
+                       const char* lastSlash = strrchr(newPath, '/');
+                       if ( lastSlash == NULL ) 
+                               continue;
+                       newFilename = lastSlash+1;
+                       char* temp = strdup(newPath);
+                       newDirPath = temp;
+                       // gdb like directory SO's to end in '/', but dwarf DW_AT_comp_dir usually does not have trailing '/'
+                       temp[lastSlash-newPath+1] = '\0';
                        // need SO's whenever the translation unit source file changes
-                       if ( (filename == NULL) || (strcmp(newFilename,filename) != 0) ) {
+                       if ( (filename == NULL) || (strcmp(newFilename,filename) != 0) || (strcmp(newDirPath,dirPath) != 0)) {
                                if ( filename != NULL ) {
                                        // translation unit change, emit ending SO
                                        ld::relocatable::File::Stab endFileStab;
@@ -4875,7 +4940,7 @@ void OutputFile::synthesizeDebugNotes(ld::Internal& state)
                        }
                }
        }
-       
+
 }
 
 
index 573cad8d8de878758b140759bb7b27edcccfb717..a5405a9951057673fb0cdf1cd9c5a629acebdec2 100644 (file)
@@ -330,6 +330,20 @@ void Resolver::doLinkerOption(const std::vector<const char*>& linkerOption, cons
        }
 }
 
+static void userReadableSwiftVersion(uint8_t value, char versionString[64])
+{
+       switch (value) {
+               case 1:
+                       strcpy(versionString, "1.0");
+                       break;
+               case 2:
+                       strcpy(versionString, "1.1");
+                       break;
+               default:
+                       sprintf(versionString, "unknown ABI version 0x%02X", value);
+       }
+}
+
 void Resolver::doFile(const ld::File& file)
 {
        const ld::relocatable::File* objFile = dynamic_cast<const ld::relocatable::File*>(&file);
@@ -383,6 +397,27 @@ void Resolver::doFile(const ld::File& file)
                                break;
                }
        
+               // verify all files use same version of Swift language
+               if ( file.swiftVersion() != 0 ) {
+                       if ( _internal.swiftVersion == 0 ) {
+                               _internal.swiftVersion = file.swiftVersion();
+                       }
+                       else if ( file.swiftVersion() != _internal.swiftVersion ) {
+                               char fileVersion[64];
+                               char otherVersion[64];
+                               userReadableSwiftVersion(file.swiftVersion(), fileVersion);
+                               userReadableSwiftVersion(_internal.swiftVersion, otherVersion);
+                               if ( file.swiftVersion() > _internal.swiftVersion ) {
+                                       throwf("%s compiled with newer version of Swift language (%s) than previous files (%s)", 
+                                                  file.path(), fileVersion, otherVersion);
+                               }
+                               else {
+                                       throwf("%s compiled with older version of Swift language (%s) than previous files (%s)", 
+                                              file.path(), fileVersion, otherVersion);
+                               }
+                       }
+               }
+               
                // in -r mode, if any .o files have dwarf then add UUID to output .o file
                if ( objFile->debugInfo() == ld::relocatable::File::kDebugInfoDwarf )
                        _internal.someObjectFileHasDwarf = true;
@@ -469,6 +504,27 @@ void Resolver::doFile(const ld::File& file)
                                }
                                break;
                }
+               if ( _options.checkDylibsAreAppExtensionSafe() && !dylibFile->appExtensionSafe() ) {
+                       warning("linking against dylib not safe for use in application extensions: %s", file.path());
+               }
+               const char* depInstallName = dylibFile->installPath();
+               // <rdar://problem/17229513> embedded frameworks are only supported on iOS 8 and later
+               if ( (depInstallName != NULL) && (depInstallName[0] != '/') ) {
+                       if ( (_options.iOSVersionMin() != iOSVersionUnset) && (_options.iOSVersionMin() < iOS_8_0) ) {
+                               // <rdar://problem/17598404> only warn about linking against embedded dylib if it is built for iOS 8 or later
+                               if ( dylibFile->iOSMinVersion() >= iOS_8_0 )
+                                       throwf("embedded dylibs/frameworks are only supported on iOS 8.0 and later (%s)", depInstallName);
+                       }
+               }
+               if ( _options.sharedRegionEligible() ) {
+                       assert(depInstallName != NULL);
+                       if ( depInstallName[0] == '@' )
+                               warning("invalid -install_name (%s) in dependent dylib (%s). Dylibs/frameworks which might go in dyld shared cache "
+                                               "cannot link with dylib that uses @rpath, @loaderpath, etc.", depInstallName, dylibFile->path());
+                       if ( (strncmp(depInstallName, "/usr/lib/", 9) != 0) && (strncmp(depInstallName, "/System/Library/", 16) != 0) )
+                               warning("invalid -install_name (%s) in dependent dylib (%s). Dylibs/frameworks which might go in dyld shared cache "
+                                               "cannot link with dylibs that won't be in the shared cache", depInstallName, dylibFile->path());
+               }
        }
 
 }
@@ -569,7 +625,11 @@ void Resolver::doAtom(const ld::Atom& atom)
        // remember if any atoms are proxies that require LTO
        if ( atom.contentType() == ld::Atom::typeLTOtemporary )
                _haveLLVMObjs = true;
-               
+       
+       // remember if any atoms are aliases
+       if ( atom.section().type() == ld::Section::typeTempAlias )
+               _haveAliases = true;
+       
        if ( _options.deadCodeStrip() ) {
                // add to set of dead-strip-roots, all symbols that the compiler marks as don't strip
                if ( atom.dontDeadStrip() )
@@ -726,7 +786,7 @@ void Resolver::resolveUndefines()
                }
        }
        
-       // Use linker options to resolve an remaining undefined symbols
+       // Use linker options to resolve any remaining undefined symbols
        if ( !_internal.linkerOptionLibraries.empty() || !_internal.linkerOptionFrameworks.empty() ) {
                std::vector<const char*> undefineNames;
                _symbolTable.undefines(undefineNames);
@@ -1417,7 +1477,38 @@ void Resolver::fillInEntryPoint()
        _internal.entryPoint = this->entryPoint(true);
 }
 
-
+void Resolver::syncAliases()
+{
+       if ( !_haveAliases || (_options.outputKind() == Options::kObjectFile) )
+               return;
+       
+       // Set attributes of alias to match its found target
+       for (std::vector<const ld::Atom*>::iterator it = _atoms.begin(); it != _atoms.end(); ++it) {
+               const ld::Atom* atom = *it;
+               if ( atom->section().type() == ld::Section::typeTempAlias ) {
+                       assert(atom->fixupsBegin() != atom->fixupsEnd());
+                       for (ld::Fixup::iterator fit = atom->fixupsBegin(); fit != atom->fixupsEnd(); ++fit) {
+                               const ld::Atom* target;
+                               ld::Atom::Scope scope;
+                               assert(fit->kind == ld::Fixup::kindNoneFollowOn);
+                               switch ( fit->binding ) {
+                                       case ld::Fixup::bindingByNameUnbound:
+                                               break;
+                                       case ld::Fixup::bindingsIndirectlyBound:
+                                               target = _internal.indirectBindingTable[fit->u.bindingIndex];
+                                               assert(target != NULL);
+                                               scope = atom->scope();
+                                               (const_cast<Atom*>(atom))->setAttributesFromAtom(*target);
+                                               // alias has same attributes as target, except for scope
+                                               (const_cast<Atom*>(atom))->setScope(scope);
+                                               break;
+                                       default:
+                                               assert(0 && "internal error: unexpected alias binding");
+                               }
+                       }
+               }
+       }
+}
 
 void Resolver::removeCoalescedAwayAtoms()
 {
@@ -1458,9 +1549,11 @@ void Resolver::linkTimeOptimize()
        optOpt.linkerDeadStripping                      = _options.deadCodeStrip();
        optOpt.needsUnwindInfoSection           = _options.needsUnwindInfoSection();
        optOpt.keepDwarfUnwind                          = _options.keepDwarfUnwind();
+       optOpt.verboseOptimizationHints     = _options.verboseOptimizationHints();
        optOpt.arch                                                     = _options.architecture();
        optOpt.mcpu                                                     = _options.mcpuLTO();
        optOpt.llvmOptions                                      = &_options.llvmOptions();
+       optOpt.initialUndefines                         = &_options.initialUndefines();
        
        std::vector<const ld::Atom*>            newAtoms;
        std::vector<const char*>                        additionalUndefines; 
@@ -1487,7 +1580,7 @@ void Resolver::linkTimeOptimize()
        }
        
        // <rdar://problem/14609792> add any auto-link libraries requested by LTO output to dylibs to search
-       _inputFiles.addLinkerOptionLibraries(_internal);
+       _inputFiles.addLinkerOptionLibraries(_internal, *this);
        _inputFiles.createIndirectDylibs();
 
        // resolve new undefines (e.g calls to _malloc and _memcpy that llvm compiler conjures up)
@@ -1587,6 +1680,7 @@ void Resolver::resolve()
        this->deadStripOptimize();
        this->checkUndefines();
        this->checkDylibSymbolCollisions();
+       this->syncAliases();
        this->removeCoalescedAwayAtoms();
        this->fillInEntryPoint();
        this->linkTimeOptimize();
index 4a3cd73011a4cac75dff3165f99744387a144729..975772be72d8e7287088704c3ba2eb7f941ade73 100644 (file)
@@ -63,7 +63,8 @@ public:
                                                                  _symbolTable(opts, state.indirectBindingTable),
                                                                  _haveLLVMObjs(false),
                                                                  _completedInitialObjectFiles(false),
-                                                                 _ltoCodeGenFinished(false) {}
+                                                                 _ltoCodeGenFinished(false),
+                                                                 _haveAliases(false) {}
                                                                
 
                virtual void            doAtom(const ld::Atom&);
@@ -90,6 +91,7 @@ private:
        void                                    fillInInternalState();
        void                                    fillInHelpersInInternalState();
        void                                    removeCoalescedAwayAtoms();
+       void                                    syncAliases();
        void                                    fillInEntryPoint();
        void                                    linkTimeOptimize();
        void                                    convertReferencesToIndirect(const ld::Atom& atom);
@@ -130,6 +132,7 @@ private:
        bool                                                    _haveLLVMObjs;
        bool                                                    _completedInitialObjectFiles;
        bool                                                    _ltoCodeGenFinished;
+       bool                                                    _haveAliases;
 };
 
 
index b27125950cba5740b5b25306c1790e8d9eef104e..ea552f4c5da20cae41fb3913fb76f17a447c0f44 100644 (file)
@@ -590,6 +590,8 @@ SymbolTable::IndirectBindingSlot SymbolTable::findSlotForName(const char* name)
 
 void SymbolTable::removeDeadAtoms()
 {
+       // remove dead atoms from: _byNameTable, _byNameReverseTable, and _indirectBindingTable
+       std::vector<const char*> namesToRemove;
        for (NameToSlot::iterator it=_byNameTable.begin(); it != _byNameTable.end(); ++it) {
                IndirectBindingSlot slot = it->second;
                const ld::Atom* atom = _indirectBindingTable[slot];
@@ -597,11 +599,89 @@ void SymbolTable::removeDeadAtoms()
                        if ( !atom->live() && !atom->dontDeadStrip() ) {
                                //fprintf(stderr, "removing from symbolTable[%u] %s\n", slot, atom->name());
                                _indirectBindingTable[slot] = NULL;
+                               // <rdar://problem/16025786> need to completely remove dead atoms from symbol table
+                               _byNameReverseTable.erase(slot);
+                               // can't remove while iterating, do it after iteration
+                               namesToRemove.push_back(it->first);
                        }
                }
        }
+       for (std::vector<const char*>::iterator it = namesToRemove.begin(); it != namesToRemove.end(); ++it) {
+               _byNameTable.erase(*it);
+       }
+
+       // remove dead atoms from _nonLazyPointerTable
+       for (ReferencesToSlot::iterator it=_nonLazyPointerTable.begin(); it != _nonLazyPointerTable.end(); ) {
+               const ld::Atom* atom = it->first;
+               assert(atom != NULL);
+               if ( !atom->live() && !atom->dontDeadStrip() )
+                       it = _nonLazyPointerTable.erase(it);
+               else
+                       ++it;
+       }
+
+       // remove dead atoms from _cstringTable
+       for (CStringToSlot::iterator it=_cstringTable.begin(); it != _cstringTable.end(); ) {
+               const ld::Atom* atom = it->first;
+               assert(atom != NULL);
+               if ( !atom->live() && !atom->dontDeadStrip() )
+                       it = _cstringTable.erase(it);
+               else
+                       ++it;
+       }
+
+       // remove dead atoms from _utf16Table
+       for (UTF16StringToSlot::iterator it=_utf16Table.begin(); it != _utf16Table.end(); ) {
+               const ld::Atom* atom = it->first;
+               assert(atom != NULL);
+               if ( !atom->live() && !atom->dontDeadStrip() )
+                       it = _utf16Table.erase(it);
+               else
+                       ++it;
+       }
+
+       // remove dead atoms from _cfStringTable
+       for (ReferencesToSlot::iterator it=_cfStringTable.begin(); it != _cfStringTable.end(); ) {
+               const ld::Atom* atom = it->first;
+               assert(atom != NULL);
+               if ( !atom->live() && !atom->dontDeadStrip() )
+                       it = _cfStringTable.erase(it);
+               else
+                       ++it;
+       }
+
+       // remove dead atoms from _literal4Table
+       for (ContentToSlot::iterator it=_literal4Table.begin(); it != _literal4Table.end(); ) {
+               const ld::Atom* atom = it->first;
+               assert(atom != NULL);
+               if ( !atom->live() && !atom->dontDeadStrip() )
+                       it = _literal4Table.erase(it);
+               else
+                       ++it;
+       }
+
+       // remove dead atoms from _literal8Table
+       for (ContentToSlot::iterator it=_literal8Table.begin(); it != _literal8Table.end(); ) {
+               const ld::Atom* atom = it->first;
+               assert(atom != NULL);
+               if ( !atom->live() && !atom->dontDeadStrip() )
+                       it = _literal8Table.erase(it);
+               else
+                       ++it;
+       }
+
+       // remove dead atoms from _literal16Table
+       for (ContentToSlot::iterator it=_literal16Table.begin(); it != _literal16Table.end(); ) {
+               const ld::Atom* atom = it->first;
+               assert(atom != NULL);
+               if ( !atom->live() && !atom->dontDeadStrip() )
+                       it = _literal16Table.erase(it);
+               else
+                       ++it;
+       }
 }
 
+
 // find existing or create new slot
 SymbolTable::IndirectBindingSlot SymbolTable::findSlotForContent(const ld::Atom* atom, const ld::Atom** existingAtom)
 {
index 844f6142521eac5067be1c189bbfa12f774a17b0..4ef1f146177526c4865791bf44df728cf1e91ba6 100644 (file)
@@ -106,6 +106,7 @@ public:
                                                                                        InternalState(const Options& opts) : _options(opts), _atomsOrderedInSections(false) { }
        virtual ld::Internal::FinalSection*             addAtom(const ld::Atom& atom);
        virtual ld::Internal::FinalSection*             getFinalSection(const ld::Section&);
+                       ld::Internal::FinalSection*     getFinalSection(const char* seg, const char* sect, ld::Section::Type type);
        
        uint64_t                                                                assignFileOffsets();
        void                                                                    setSectionSizesAndAlignments();
@@ -117,14 +118,14 @@ private:
        class FinalSection : public ld::Internal::FinalSection 
        {
        public:
-                                                       FinalSection(const ld::Section& sect, uint32_t sectionsSeen, bool objFile);
+                                                                       FinalSection(const ld::Section& sect, uint32_t sectionsSeen, const Options&);
                static int                                      sectionComparer(const void* l, const void* r);
                static const ld::Section&       outputSection(const ld::Section& sect, bool mergeZeroFill);
                static const ld::Section&       objectOutputSection(const ld::Section& sect, const Options&);
        private:
                friend class InternalState;
-               static uint32_t         sectionOrder(const ld::Section& sect, uint32_t sectionsSeen);
-               static uint32_t         segmentOrder(const ld::Section& sect, bool objFile);
+               static uint32_t         sectionOrder(const ld::Section& sect, uint32_t sectionsSeen, const Options& options);
+               static uint32_t         segmentOrder(const ld::Section& sect, const Options& options);
                uint32_t                        _segmentOrder;
                uint32_t                        _sectionOrder;
 
@@ -181,10 +182,10 @@ bool InternalState::SectionEquals::operator()(const ld::Section* left, const ld:
 }
 
 
-InternalState::FinalSection::FinalSection(const ld::Section& sect, uint32_t sectionsSeen, bool objFile)
+InternalState::FinalSection::FinalSection(const ld::Section& sect, uint32_t sectionsSeen, const Options& opts)
        : ld::Internal::FinalSection(sect), 
-         _segmentOrder(segmentOrder(sect, objFile)),
-         _sectionOrder(sectionOrder(sect, sectionsSeen))
+         _segmentOrder(segmentOrder(sect, opts)),
+         _sectionOrder(sectionOrder(sect, sectionsSeen, opts))
 {
        //fprintf(stderr, "FinalSection(%s, %s) _segmentOrder=%d, _sectionOrder=%d\n", 
        //              this->segmentName(), this->sectionName(), _segmentOrder, _sectionOrder);
@@ -197,7 +198,9 @@ const ld::Section& InternalState::FinalSection::outputSection(const ld::Section&
                case ld::Section::typeLiteral4:
                case ld::Section::typeLiteral8:
                case ld::Section::typeLiteral16:
-                       return _s_TEXT_const;
+                       if ( strcmp(sect.segmentName(), "__TEXT") == 0 )
+                               return _s_TEXT_const;
+                       break;
                case ld::Section::typeUnclassified:
                        if ( strcmp(sect.segmentName(), "__DATA") == 0 ) {
                                if ( strcmp(sect.sectionName(), "__datacoal_nt") == 0 )
@@ -233,10 +236,12 @@ const ld::Section& InternalState::FinalSection::outputSection(const ld::Section&
                        }
                        break;
                case ld::Section::typeTentativeDefs:
-                       if ( mergeZeroFill )
-                               return _s_DATA_zerofill;
-                       else
-                               return _s_DATA_common;
+                       if ( (strcmp(sect.segmentName(), "__DATA") == 0) && (strcmp(sect.sectionName(), "__comm/tent") == 0) ) {
+                               if ( mergeZeroFill )
+                                       return _s_DATA_zerofill;
+                               else
+                                       return _s_DATA_common;
+                       }
                        break;
                        // FIX ME: more 
                default:
@@ -247,47 +252,50 @@ const ld::Section& InternalState::FinalSection::outputSection(const ld::Section&
 
 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) && options.makeTentativeDefinitionsReal())
                return _s_DATA_common;
        return sect;
 }
 
-uint32_t InternalState::FinalSection::segmentOrder(const ld::Section& sect, bool objFile)
+uint32_t InternalState::FinalSection::segmentOrder(const ld::Section& sect, const Options& options)
 {
-       if ( strcmp(sect.segmentName(), "__PAGEZERO") == 0 ) 
-               return 0;
-       if ( strcmp(sect.segmentName(), "__HEADER") == 0 ) // only used with -preload
-               return 0;
-       if ( strcmp(sect.segmentName(), "__TEXT") == 0 ) 
-               return 1;
-       // in -r mode, want __DATA  last so zerofill sections are at end
-       if ( strcmp(sect.segmentName(), "__DATA") == 0 ) 
-               return (objFile ? 5 : 2);
-       if ( strcmp(sect.segmentName(), "__OBJC") == 0 ) 
-               return 3;
-       if ( strcmp(sect.segmentName(), "__IMPORT") == 0 ) 
-               return 4;
-       
-       // layout non-standard segments in order seen (+10 to shift beyond standard segments)
+       if ( options.outputKind() == Options::kPreload ) {
+               if ( strcmp(sect.segmentName(), "__HEADER") == 0 ) 
+                       return 0;
+               const std::vector<const char*>& order = options.segmentOrder();
+               for (size_t i=0; i != order.size(); ++i) {
+                       if ( strcmp(sect.segmentName(), order[i]) == 0 ) 
+                               return i+1;
+               }
+               if ( strcmp(sect.segmentName(), "__TEXT") == 0 ) 
+                       return order.size()+1;
+               if ( strcmp(sect.segmentName(), "__DATA") == 0 ) 
+                       return order.size()+2;
+       }
+       else {
+               if ( strcmp(sect.segmentName(), "__PAGEZERO") == 0 ) 
+                       return 0;
+               if ( strcmp(sect.segmentName(), "__TEXT") == 0 ) 
+                       return 1;
+               // in -r mode, want __DATA  last so zerofill sections are at end
+               if ( strcmp(sect.segmentName(), "__DATA") == 0 ) 
+                       return (options.outputKind() == Options::kObjectFile) ? 5 : 2;
+               if ( strcmp(sect.segmentName(), "__OBJC") == 0 ) 
+                       return 3;
+               if ( strcmp(sect.segmentName(), "__IMPORT") == 0 ) 
+                       return 4;
+       }
+       // layout non-standard segments in order seen (+100 to shift beyond standard segments)
        for (uint32_t i=0; i < _s_segmentsSeen.size(); ++i) {
                if ( strcmp(_s_segmentsSeen[i], sect.segmentName()) == 0 )
-                       return i+10;
+                       return i+100;
        }
        _s_segmentsSeen.push_back(sect.segmentName());
-       return _s_segmentsSeen.size()-1+10;
+       return _s_segmentsSeen.size()-1+100;
 }
 
-uint32_t InternalState::FinalSection::sectionOrder(const ld::Section& sect, uint32_t sectionsSeen)
+uint32_t InternalState::FinalSection::sectionOrder(const ld::Section& sect, uint32_t sectionsSeen, const Options& options)
 {
        if ( sect.type() == ld::Section::typeFirstSection )
                return 0;
@@ -295,6 +303,14 @@ uint32_t InternalState::FinalSection::sectionOrder(const ld::Section& sect, uint
                return 1;
        if ( sect.type() == ld::Section::typeLastSection )
                return INT_MAX;
+       const std::vector<const char*>* sectionList = options.sectionOrder(sect.segmentName());
+       if ( (options.outputKind() == Options::kPreload) && (sectionList != NULL) ) {
+               uint32_t count = 10;
+               for (std::vector<const char*>::const_iterator it=sectionList->begin(); it != sectionList->end(); ++it, ++count) {
+                       if ( strcmp(*it, sect.sectionName()) == 0 ) 
+                               return count;
+               }
+       }
        if ( strcmp(sect.segmentName(), "__TEXT") == 0 ) {
                switch ( sect.type() ) {
                        case ld::Section::typeCode:
@@ -347,6 +363,9 @@ uint32_t InternalState::FinalSection::sectionOrder(const ld::Section& sect, uint
                                // <rdar://problem/14348664> __DATA,__const section should be near __mod_init_func not __data
                                if ( strcmp(sect.sectionName(), "__const") == 0 )
                                        return 14;
+                               // <rdar://problem/17125893> Linker should put __cfstring near __const
+                               if ( strcmp(sect.sectionName(), "__cfstring") == 0 )
+                                       return 15;
                                // <rdar://problem/7435296> Reorder sections to reduce page faults in object files
                                else if ( strcmp(sect.sectionName(), "__objc_classlist") == 0 ) 
                                        return 20;
@@ -354,24 +373,28 @@ uint32_t InternalState::FinalSection::sectionOrder(const ld::Section& sect, uint
                                        return 21;
                                else if ( strcmp(sect.sectionName(), "__objc_catlist") == 0 ) 
                                        return 22;
-                               else if ( strcmp(sect.sectionName(), "__objc_protolist") == 0 ) 
+                               else if ( strcmp(sect.sectionName(), "__objc_nlcatlist") == 0 ) 
                                        return 23;
-                               else if ( strcmp(sect.sectionName(), "__objc_imageinfo") == 0 ) 
+                               else if ( strcmp(sect.sectionName(), "__objc_protolist") == 0 ) 
                                        return 24;
-                               else if ( strcmp(sect.sectionName(), "__objc_const") == 0 ) 
+                               else if ( strcmp(sect.sectionName(), "__objc_imageinfo") == 0 ) 
                                        return 25;
-                               else if ( strcmp(sect.sectionName(), "__objc_selrefs") == 0 ) 
+                               else if ( strcmp(sect.sectionName(), "__objc_const") == 0 ) 
                                        return 26;
-                               else if ( strcmp(sect.sectionName(), "__objc_msgrefs") == 0 ) 
+                               else if ( strcmp(sect.sectionName(), "__objc_selrefs") == 0 ) 
                                        return 27;
-                               else if ( strcmp(sect.sectionName(), "__objc_protorefs") == 0 ) 
+                               else if ( strcmp(sect.sectionName(), "__objc_msgrefs") == 0 ) 
                                        return 28;
-                               else if ( strcmp(sect.sectionName(), "__objc_classrefs") == 0 ) 
+                               else if ( strcmp(sect.sectionName(), "__objc_protorefs") == 0 ) 
                                        return 29;
-                               else if ( strcmp(sect.sectionName(), "__objc_superrefs") == 0 ) 
+                               else if ( strcmp(sect.sectionName(), "__objc_classrefs") == 0 ) 
                                        return 30;
-                               else if ( strcmp(sect.sectionName(), "__objc_data") == 0 ) 
+                               else if ( strcmp(sect.sectionName(), "__objc_superrefs") == 0 ) 
                                        return 31;
+                               else if ( strcmp(sect.sectionName(), "__objc_ivar") == 0 ) 
+                                       return 32;
+                               else if ( strcmp(sect.sectionName(), "__objc_data") == 0 ) 
+                                       return 33;
                                else
                                        return sectionsSeen+40;
                }
@@ -471,7 +494,79 @@ static void validateFixups(const ld::Atom& atom)
 
 ld::Internal::FinalSection* InternalState::addAtom(const ld::Atom& atom)
 {
-       ld::Internal::FinalSection* fs = this->getFinalSection(atom.section());
+       ld::Internal::FinalSection* fs = NULL;
+       const char* sectName = atom.section().sectionName();
+       ld::Section::Type sectType = atom.section().type();
+       const ld::File* f = atom.file();
+       const char* path = (f != NULL) ? f->path() : NULL;
+       if ( atom.section().type() == ld::Section::typeTentativeDefs ) {
+               // tentative defintions don't have a real section name yet
+               sectType = ld::Section::typeZeroFill;
+               if ( _options.mergeZeroFill() )
+                       sectName = FinalSection::_s_DATA_zerofill.sectionName();
+               else
+                       sectName = FinalSection::_s_DATA_common.sectionName();
+       }
+       // Support for -move_to_r._segment
+       if ( atom.symbolTableInclusion() == ld::Atom::symbolTableIn ) {
+               const char* dstSeg;
+               //fprintf(stderr, "%s\n", atom.name());
+               bool wildCardMatch;
+               if ( _options.moveRwSymbol(atom.name(), path, dstSeg, wildCardMatch) ) {
+                       if ( (sectType != ld::Section::typeZeroFill) 
+                         && (sectType != ld::Section::typeUnclassified) 
+                         && (sectType != ld::Section::typeTentativeDefs) ) {
+                               if ( !wildCardMatch )
+                                       warning("cannot move symbol '%s' from file %s to segment '%s' because symbol is not data (is %d)", atom.name(), path, dstSeg, sectType);
+                       }
+                       else {
+                               if ( _options.traceSymbolLayout() )
+                                       printf("symbol '%s', -move_to_rw_segment mapped it to %s/%s\n", atom.name(), dstSeg, sectName);
+                               fs = this->getFinalSection(dstSeg, sectName, sectType);
+                       }
+               }
+               if ( (fs == NULL) && _options.moveRoSymbol(atom.name(), path, dstSeg, wildCardMatch) ) {
+                       if ( atom.section().type() != ld::Section::typeCode ) {
+                               if ( !wildCardMatch )
+                                       warning("cannot move symbol '%s' from file %s to segment '%s' because symbol is not code (is %d)", atom.name(), path, dstSeg, sectType);
+                       }
+                       else {
+                               if ( _options.traceSymbolLayout() )
+                                       printf("symbol '%s', -move_to_ro_segment mapped it to %s/%s\n", atom.name(), dstSeg, sectName);
+                               fs = this->getFinalSection(dstSeg, sectName, ld::Section::typeCode);
+                       }
+               }
+       }
+       // support for -rename_section and -rename_segment
+       if ( fs == NULL ) {
+               const std::vector<Options::SectionRename>& sectRenames = _options.sectionRenames();
+               const std::vector<Options::SegmentRename>& segRenames = _options.segmentRenames();
+               for ( std::vector<Options::SectionRename>::const_iterator it=sectRenames.begin(); it != sectRenames.end(); ++it) {
+                       if ( (strcmp(sectName, it->fromSection) == 0) && (strcmp(atom.section().segmentName(), it->fromSegment) == 0) ) {
+                               if ( _options.traceSymbolLayout() )
+                                       printf("symbol '%s', -rename_section mapped it to %s/%s\n", atom.name(), it->toSegment, it->toSection);
+                               fs = this->getFinalSection(it->toSegment, it->toSection, sectType);
+                       }
+               }
+               if ( fs == NULL ) {
+                       for ( std::vector<Options::SegmentRename>::const_iterator it=segRenames.begin(); it != segRenames.end(); ++it) {
+                               if ( strcmp(atom.section().segmentName(), it->fromSegment) == 0 ) {
+                                       if ( _options.traceSymbolLayout() )
+                                               printf("symbol '%s', -rename_segment mapped it to %s/%s\n", atom.name(), it->toSegment, sectName);
+                                       fs = this->getFinalSection(it->toSegment, sectName, sectType);
+                               }
+                       }
+               }
+       }
+       
+       
+       // if no override, use default location
+       if ( fs == NULL ) {
+               fs = this->getFinalSection(atom.section());
+               if ( _options.traceSymbolLayout() && (atom.symbolTableInclusion() == ld::Atom::symbolTableIn) )
+                       printf("symbol '%s', use default mapping to %s/%s\n", atom.name(), fs->segmentName(), fs->sectionName());
+       }
+
        //fprintf(stderr, "InternalState::doAtom(%p), name=%s, sect=%s, finalsect=%p\n", &atom, atom.name(), atom.section().sectionName(), fs);
 #ifndef NDEBUG
        validateFixups(atom);
@@ -497,6 +592,17 @@ ld::Internal::FinalSection* InternalState::addAtom(const ld::Atom& atom)
        return fs;
 }
 
+
+
+ld::Internal::FinalSection* InternalState::getFinalSection(const char* seg, const char* sect, ld::Section::Type type)
+{      
+       for (std::vector<ld::Internal::FinalSection*>::iterator it=sections.begin(); it != sections.end(); ++it) {
+               if ( (strcmp((*it)->segmentName(),seg) == 0) && (strcmp((*it)->sectionName(),sect) == 0) )
+                       return *it;
+       }
+       return this->getFinalSection(*new ld::Section(seg, sect, type, false));
+}
+
 ld::Internal::FinalSection* InternalState::getFinalSection(const ld::Section& inputSection)
 {      
        const ld::Section* baseForFinalSection = &inputSection;
@@ -508,7 +614,6 @@ ld::Internal::FinalSection* InternalState::getFinalSection(const ld::Section& in
        }
 
        // otherwise, create a new final section
-       bool objFile = false;
        switch ( _options.outputKind() ) {
                case Options::kStaticExecutable:
                case Options::kDynamicExecutable:
@@ -540,14 +645,13 @@ ld::Internal::FinalSection* InternalState::getFinalSection(const ld::Section& in
                                //fprintf(stderr, "_sectionInToFinalMap[%p] = %p\n", &inputSection, pos->second);
                                return pos->second;
                        }
-                       objFile = true;
                        break;
        }
 
        InternalState::FinalSection* result = new InternalState::FinalSection(*baseForFinalSection, 
-                                                                                                                                       _sectionInToFinalMap.size(), objFile);
+                                                                                                                                       _sectionInToFinalMap.size(), _options);
        _sectionInToFinalMap[baseForFinalSection] = result;
-       //fprintf(stderr, "_sectionInToFinalMap[%p] = %p\n", baseForFinalSection, result);
+       //fprintf(stderr, "_sectionInToFinalMap[%p(%s)] = %p\n", baseForFinalSection, baseForFinalSection->sectionName(), result);
        sections.push_back(result);
        return result;
 }
@@ -792,6 +896,10 @@ uint64_t InternalState::assignFileOffsets()
                        ld::Internal::FinalSection* otherSect = *sit;
                        if ( ! _options.hasCustomSegmentAddress(otherSect->segmentName()) ) 
                                continue;
+                       if ( otherSect->size == 0 )
+                               continue;
+                       if ( sect->size == 0 )
+                               continue;
                        if ( sect->address > otherSect->address ) {
                                if ( (otherSect->address+otherSect->size) > sect->address ) {
                                        overlappingFixedSection = otherSect;
@@ -817,8 +925,8 @@ uint64_t InternalState::assignFileOffsets()
                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;
+                       //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());
index 95973aa1c66c06ba9716ddcbf413ff78275bb7f2..8c3de4f19b0b6b5bd0bdebdcb56d70f76966bcd1 100644 (file)
@@ -146,6 +146,7 @@ public:
        virtual bool                                            forEachAtom(AtomHandler&) const = 0;
        virtual bool                                            justInTimeforEachAtom(const char* name, AtomHandler&) const = 0;
        virtual ObjcConstraint                          objCConstraint() const                  { return objcConstraintNone; }
+       virtual uint8_t                                         swiftVersion() const                    { return 0; }
        virtual uint32_t                                        cpuSubType() const              { return 0; }
        virtual uint32_t                                        subFileCount() const    { return 1; }
     bool                                                               fileExists() const     { return _modTime != 0; }
@@ -166,7 +167,7 @@ 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_6_0=0x00060000, iOS_7_0=0x00070000, iOS_8_0=0x00080000,
                                                iOS_Future=0x10000000};
  
 namespace relocatable {
@@ -270,6 +271,10 @@ namespace dylib {
                virtual bool                                            allSymbolsAreWeakImported() const = 0;
                virtual const void*                                     codeSignatureDR() const = 0;
                virtual bool                                            installPathVersionSpecific() const { return false; }
+               virtual bool                                            appExtensionSafe() const = 0;
+               virtual MacVersionMin                           macMinVersion() const { return macVersionUnset; }
+               virtual IOSVersionMin                           iOSMinVersion() const { return iOSVersionUnset; }
+
        protected:
                const char*                                                     _dylibInstallPath;
                uint32_t                                                        _dylibTimeStamp;
@@ -310,7 +315,7 @@ class Section
 {
 public:
        enum Type { typeUnclassified, typeCode, typePageZero, typeImportProxies, typeLinkEdit, typeMachHeader, typeStack,
-                               typeLiteral4, typeLiteral8, typeLiteral16, typeConstants, typeTempLTO, 
+                               typeLiteral4, typeLiteral8, typeLiteral16, typeConstants, typeTempLTO, typeTempAlias,
                                typeCString, typeNonStdCString, typeCStringPointer, typeUTF16Strings, typeCFString, typeObjC1Classes,
                                typeCFI, typeLSDA, typeDtraceDOF, typeUnwindInfo, typeObjCClassRefs, typeObjC2CategoryList,
                                typeZeroFill, typeTentativeDefs, typeLazyPointer, typeStub, typeNonLazyPointer, typeDyldInfo, 
@@ -526,7 +531,6 @@ 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), 
@@ -540,7 +544,6 @@ struct Fixup
                        extra.info.delta2 = (off2 - off1) >> 2;
                        u.addend = extra.addend; 
                }
-#endif                 
                        
 
        bool firstInCluster() const { 
@@ -571,7 +574,6 @@ struct Fixup
                return false;
        }
        
-#if SUPPORT_ARCH_arm64
        union LOH_arm64 {
                uint64_t        addend;
                struct {
@@ -583,7 +585,6 @@ struct Fixup
                                                delta4 : 14;    
                } info;
        };
-#endif
        
 };
 
@@ -755,9 +756,6 @@ public:
        virtual LineInfo::iterator                              beginLineInfo() const { return NULL; }
        virtual LineInfo::iterator                              endLineInfo() const { return NULL; }
                                                                                        
-protected:
-       enum AddressMode { modeSectionOffset, modeFinalAddress };
-
                                                                                        void setAttributesFromAtom(const Atom& a) { 
                                                                                                        _section = a._section; 
                                                                                                        _alignmentModulus = a._alignmentModulus;
@@ -776,6 +774,9 @@ protected:
                                                                                                        _weakImportState = a._weakImportState;
                                                                                                }
 
+protected:
+       enum AddressMode { modeSectionOffset, modeFinalAddress };
+
        const Section *                                         _section;
        uint64_t                                                        _address;
        uint16_t                                                        _alignmentModulus;
@@ -857,7 +858,7 @@ public:
                                                                                        lazyBindingHelper(NULL), compressedFastBinderProxy(NULL),
                                                                                        objcObjectConstraint(ld::File::objcConstraintNone), 
                                                                                        objcDylibConstraint(ld::File::objcConstraintNone), 
-                                                                                       cpuSubType(0), 
+                                                                                       swiftVersion(0), cpuSubType(0), 
                                                                                        allObjectFilesScatterable(true), 
                                                                                        someObjectFileHasDwarf(false), usingHugeSections(false),
                                                                                        hasThreadLocalVariableDefinitions(false),
@@ -877,6 +878,7 @@ public:
        const Atom*                                                                     compressedFastBinderProxy;
        ld::File::ObjcConstraint                                        objcObjectConstraint;
        ld::File::ObjcConstraint                                        objcDylibConstraint;
+       uint8_t                                                                         swiftVersion;
        uint32_t                                                                        cpuSubType;
        bool                                                                            allObjectFilesScatterable;
        bool                                                                            someObjectFileHasDwarf;
index a37c8a041766ef3aca0a21c5b3fe9073d7c4a170..18355404b5ffeddf6147da587dc8ba19c87e06c2 100644 (file)
@@ -51,6 +51,7 @@
 
 #define CFI_INVALID_ADDRESS ((pint_t)(-1))
 
+
 namespace libunwind {
 
 ///
@@ -1960,6 +1961,7 @@ compact_unwind_encoding_t DwarfInstructions<A,R>::createCompactEncodingFromProlo
   return encoding;
 }
 
+
 } // namespace libunwind
 
 
index 2e4a3bbeb43cb217d71c49fe1c5e4aada26714a8..9463390cc6685eef86d14e75e81fc2993ebe6e0c 100644 (file)
@@ -109,7 +109,7 @@ public:
        /// Information about a frame layout and registers saved determined 
        /// by "running" the dwarf FDE "instructions"
        ///  
-       enum { kMaxRegisterNumber = 120 };
+       enum { kMaxRegisterNumber = 300 };
        enum RegisterSavedWhere { kRegisterUnused, kRegisterInCFA, kRegisterOffsetFromCFA,
                                                        kRegisterInRegister, kRegisterAtExpression, kRegisterIsExpression } ;
        struct RegisterLocation {
index 02470665623f62a79df30e548de1ec03862adef1..66e66cce0c5b60dbb456af7dd9f38a1ddf69e543 100644 (file)
@@ -1317,6 +1317,38 @@ inline void Registers_arm64::setVectorRegister(int regNum, v128 value)
 }
 
 
+///
+/// Registers_arm holds the register state of a thread in a 32-bit arm process.  
+///
+class Registers_arm {
+public:
+                Registers_arm();
+
+    bool        validRegister(int num) const;
+    uint32_t    getRegister(int num) const;
+    void        setRegister(int num, uint32_t value);
+    bool        validFloatRegister(int num) const;
+    unw_fpreg_t getFloatRegister(int num) const;
+    void        setFloatRegister(int num, unw_fpreg_t value);
+    bool        validVectorRegister(int num) const;
+    v128        getVectorRegister(int num) const;
+    void        setVectorRegister(int num, v128 value);
+    const char *getRegisterName(int num);
+    void        jumpto();
+
+    uint32_t    getSP() const         { return _registers[13]; }
+    void        setSP(uint32_t value) { _registers[13] = value; }
+    uint32_t    getIP() const         { return _registers[15]; }
+    void        setIP(uint32_t value) { _registers[15] = value; }
+
+private:
+  uint32_t    _registers[16];
+};
+
+inline Registers_arm::Registers_arm() {
+  bzero(&_registers, sizeof(_registers));
+}
+
 
 } // namespace libunwind 
 
index 3fe21f686cfb4458d1e74e718315d87c8c7e7587..f2cb8ca364980c1c0c654bd64f71f69930b0f685 100644 (file)
@@ -74,7 +74,7 @@ public:
        // for adding references to symbols outside bitcode file
        void                                                                            addReference(const char* nm)
                                                                                                                                        { _undefs.push_back(ld::Fixup(0, ld::Fixup::k1of1, 
-                                                                                                                                                               ld::Fixup::kindNone, false, nm)); }
+                                                                                                                                                               ld::Fixup::kindNone, false, strdup(nm))); }
 private:
 
        ld::File&                                                                       _file;
@@ -108,6 +108,7 @@ public:
        virtual LinkerOptionsList*                                                      linkerOptions() const           { return NULL; }
 
 
+       void                                                                                            release();
        lto_module_t                                                                            module()                                        { return _module; }
        class InternalAtom&                                                                     internalAtom()                          { return _internalAtom; }
        void                                                                                            setDebugInfo(ld::relocatable::File::DebugInfoKind k,
@@ -228,6 +229,7 @@ private:
                virtual void            doAtom(const class ld::Atom&);
                virtual void            doFile(const class ld::File&) { }
                
+
                const OptimizeOptions&                  _options;
                std::vector<const char*>&               _additionalUndefines;
                std::vector<const ld::Atom*>&   _newAtoms;
@@ -300,6 +302,7 @@ ld::relocatable::File* Parser::parseMachOFile(const uint8_t* p, size_t len, cons
        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
@@ -330,6 +333,10 @@ File::File(const char* pth, time_t mTime, ld::File::Ordinal ordinal, const uint8
        const bool log = false;
        
        // create llvm module
+#if LTO_API_VERSION >= 9
+       _module = ::lto_module_create_from_memory_with_path(content, contentLength, pth);
+       if ( _module == NULL )
+#endif
        _module = ::lto_module_create_from_memory(content, contentLength);
     if ( _module == NULL )
                throwf("could not parse object file %s: '%s', using libLTO version '%s'", pth, ::lto_get_error_message(), ::lto_get_version());
@@ -412,9 +419,15 @@ File::File(const char* pth, time_t mTime, ld::File::Ordinal ordinal, const uint8
 }
 
 File::~File()
+{
+       this->release();
+}
+
+void File::release()
 {
        if ( _module != NULL )
                ::lto_module_dispose(_module);
+       _module = NULL;
 }
 
 bool File::forEachAtom(ld::File::AtomHandler& handler) const
@@ -437,7 +450,7 @@ Atom::Atom(File& f, const char* nm, ld::Atom::Scope s, ld::Atom::Definition d, l
                        ld::Atom::Alignment a, bool ah)
        : ld::Atom(f._section, d, c, s, ld::Atom::typeLTOtemporary, 
                                ld::Atom::symbolTableIn, false, false, false, a),
-               _file(f), _name(nm), _compiledAtom(NULL)
+               _file(f), _name(strdup(nm)), _compiledAtom(NULL)
 {
        if ( ah )
                this->setAutoHide();
@@ -470,6 +483,11 @@ struct CommandLineOrderFileSorter
 void Parser::ltoDiagnosticHandler(lto_codegen_diagnostic_severity_t severity, const char* message, void*) 
 {
        switch ( severity ) {
+#if LTO_API_VERSION >= 10
+               case LTO_DS_REMARK:
+                       fprintf(stderr, "ld: LTO remark: %s\n", message);
+                       break;
+#endif
                case LTO_DS_NOTE:
                case LTO_DS_WARNING:
                        warning("%s", message);
@@ -515,6 +533,8 @@ bool Parser::optimize(  const std::vector<const ld::Atom*>& allAtoms,
                if ( logBitcodeFiles ) fprintf(stderr, "lto_codegen_add_module(%s)\n", f->path());
                if ( ::lto_codegen_add_module(generator, f->module()) )
                        throwf("lto: could not merge in %s because '%s', using libLTO version '%s'", f->path(), ::lto_get_error_message(), ::lto_get_version());
+               // <rdar://problem/15471128> linker should release module as soon as possible
+               f->release();
                lastOrdinal = f->ordinal();
        }
 
@@ -559,7 +579,7 @@ bool Parser::optimize(  const std::vector<const ld::Atom*>& allAtoms,
                                }
                        }
                }
-               else {
+               else if ( atom->scope() >= ld::Atom::scopeLinkageUnit ) {
                        llvmAtoms[atom->name()] = (Atom*)atom;
                }
        }
@@ -619,8 +639,19 @@ bool Parser::optimize(  const std::vector<const ld::Atom*>&        allAtoms,
                        if ( logMustPreserve ) fprintf(stderr, "lto_codegen_add_must_preserve_symbol(%s) because referenced by a mach-o atom\n", name);
                        ::lto_codegen_add_must_preserve_symbol(generator, name);
                }
+               else if ( options.relocatable && hasNonllvmAtoms ) {
+                       // <rdar://problem/14334895> ld -r mode but merging in some mach-o files, so need to keep libLTO from optimizing away anything
+                       if ( logMustPreserve ) fprintf(stderr, "lto_codegen_add_must_preserve_symbol(%s) because -r mode disable LTO dead stripping\n", name);
+                       ::lto_codegen_add_must_preserve_symbol(generator, name);
+               }
        }
        
+       // <rdar://problem/16165191> tell code generator to preserve initial undefines
+       for( std::vector<const char*>::const_iterator it=options.initialUndefines->begin(); it != options.initialUndefines->end(); ++it) {
+               if ( logMustPreserve ) fprintf(stderr, "lto_codegen_add_must_preserve_symbol(%s) because it is an initial undefine\n", *it);
+               ::lto_codegen_add_must_preserve_symbol(generator, *it);
+       }
+
     // special case running ld -r on all bitcode files to produce another bitcode file (instead of mach-o)
     if ( options.relocatable && !hasNonllvmAtoms ) {
                if ( ! ::lto_codegen_write_merged_modules(generator, options.outputFilePath) ) {
@@ -721,14 +752,14 @@ bool Parser::optimize(  const std::vector<const ld::Atom*>&       allAtoms,
                fprintf(stderr, "llvmAtoms:\n");
                for (CStringToAtom::iterator it = llvmAtoms.begin(); it != llvmAtoms.end(); ++it) {
                        const char* name = it->first;
-                       //Atom* atom = it->second;
-                       fprintf(stderr, "\t%s\n", name);
+                       Atom* atom = it->second;
+                       fprintf(stderr, "\t%p\t%s\n", atom, name);
                }
                fprintf(stderr, "deadllvmAtoms:\n");
                for (CStringToAtom::iterator it = deadllvmAtoms.begin(); it != deadllvmAtoms.end(); ++it) {
                        const char* name = it->first;
-                       //Atom* atom = it->second;
-                       fprintf(stderr, "\t%s\n", name);
+                       Atom* atom = it->second;
+                       fprintf(stderr, "\t%p\t%s\n", atom, name);
                }
        }
        AtomSyncer syncer(additionalUndefines, newAtoms, llvmAtoms, deadllvmAtoms, options);
@@ -762,51 +793,50 @@ bool Parser::optimize(  const std::vector<const ld::Atom*>&       allAtoms,
 
 void Parser::AtomSyncer::doAtom(const ld::Atom& machoAtom)
 {
+       static const bool log = false;
        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 ) {
-               CStringToAtom::iterator pos = _llvmAtoms.find(name);
-               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
-                       if ( _deadllvmAtoms.find(name) != _deadllvmAtoms.end() ) {
-                               // this corresponding to an atom that the linker coalesced away or marked not-live
-                               if ( _options.linkerDeadStripping ) {
-                                       // llvm seems to want this atom and -dead_strip is enabled, so it will be deleted if not needed, so add back
-                                       Atom* llvmAtom = _deadllvmAtoms[name];
-                                       llvmAtom->setCompiledAtom(machoAtom);
-                                       _newAtoms.push_back(&machoAtom);
-                               }
-                               else {
-                                       // Don't pass it back as a new atom
-                               } 
-                       }
-                       else
-                       {
-                               // this is something new that lto conjured up, tell ld its new
+       CStringToAtom::iterator pos = _llvmAtoms.find(name);
+       if ( pos != _llvmAtoms.end() ) {
+               // turn Atom into a proxy for this mach-o atom
+               pos->second->setCompiledAtom(machoAtom);
+               lastProxiedAtom = &machoAtom;
+               lastProxiedFile = pos->second->file();
+               if (log) fprintf(stderr, "AtomSyncer, mach-o atom %p synced to lto atom %p (name=%s)\n", &machoAtom, pos->second, machoAtom.name());
+       }
+       else {
+               // an atom of this name was not in the allAtoms list the linker gave us
+               if ( _deadllvmAtoms.find(name) != _deadllvmAtoms.end() ) {
+                       // this corresponding to an atom that the linker coalesced away or marked not-live
+                       if ( _options.linkerDeadStripping ) {
+                               // llvm seems to want this atom and -dead_strip is enabled, so it will be deleted if not needed, so add back
+                               Atom* llvmAtom = _deadllvmAtoms[name];
+                               llvmAtom->setCompiledAtom(machoAtom);
                                _newAtoms.push_back(&machoAtom);
+                               if (log) fprintf(stderr, "AtomSyncer, mach-o atom %p matches dead lto atom %p but adding back (name=%s)\n", &machoAtom, llvmAtom, machoAtom.name());
                        }
+                       else {
+                               // Don't pass it back as a new atom
+                               if (log) fprintf(stderr, "AtomSyncer, mach-o atom %p matches dead lto atom %p (name=%s)\n", &machoAtom, _deadllvmAtoms[name], machoAtom.name());
+                       } 
                }
-       }
-       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);
+               else
+               {
+                       // this is something new that lto conjured up, tell ld its 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);
+                       }
+                       if (log) fprintf(stderr, "AtomSyncer, mach-o atom %p is totally new (name=%s)\n", &machoAtom, machoAtom.name());
                }
        }
        
        // adjust fixups to go through proxy atoms
-       //fprintf(stderr, "adjusting fixups in atom: %s\n", machoAtom.name());
+       if (log) fprintf(stderr, "  adjusting fixups in atom: %s\n", machoAtom.name());
        for (ld::Fixup::iterator fit=machoAtom.fixupsBegin(); fit != machoAtom.fixupsEnd(); ++fit) {
                switch ( fit->binding ) {
                        case ld::Fixup::bindingNone:
@@ -815,17 +845,19 @@ void Parser::AtomSyncer::doAtom(const ld::Atom& machoAtom)
                                // don't know if this target has been seen by linker before or if it is new
                                // be conservative and tell linker it is new
                                _additionalUndefines.push_back(fit->u.name);
-                               //fprintf(stderr, "    by name ref to: %s\n", fit->u.name);
+                               if (log) fprintf(stderr, "    adding by-name symbol %s\n", fit->u.name);
                                break;
                        case ld::Fixup::bindingDirectlyBound:
                                // If mach-o atom is referencing another mach-o atom then 
                                // reference is not going through Atom proxy. Fix it here to ensure that all
                                // llvm symbol references always go through Atom proxy.
-                               if (  fit->u.target->scope() != ld::Atom::scopeTranslationUnit ) {
+                               {
                                        const char* targetName = fit->u.target->name();
-                                       CStringToAtom::iterator pos = _llvmAtoms.find(targetName);
-                                       if ( pos != _llvmAtoms.end() ) {
-                                               fit->u.target = pos->second;
+                                       CStringToAtom::iterator post = _llvmAtoms.find(targetName);
+                                       if ( post != _llvmAtoms.end() ) {
+                                               const ld::Atom* t = post->second;
+                                               if (log) fprintf(stderr, "    updating direct reference to %p to be ref to %p: %s\n", fit->u.target, t, targetName);
+                                               fit->u.target = t;
                                        }
                                        else {
                                                // <rdar://problem/12859831> Don't unbind follow-on reference into by-name reference 
index d75aab328efddbf093b4a35b061a6f364e5a5b0c..332215d5d706b852e41a9a29bfdb3581e8e9215c 100644 (file)
@@ -60,6 +60,7 @@ struct OptimizeOptions {
        cpu_type_t                                                      arch;
        const char*                                                     mcpu;
        const std::vector<const char*>*         llvmOptions;
+       const std::vector<const char*>*         initialUndefines;
 };
 
 extern bool    optimize(   const std::vector<const ld::Atom*>& allAtoms,
index d37098b24ee91ea43d9c36b9cbd326e24d7ec07d..a3c14562e4baa3d32031db990404f6c6ae59f973 100644 (file)
@@ -151,6 +151,7 @@ public:
        virtual bool                                                    forEachAtom(ld::File::AtomHandler&) const;
        virtual bool                                                    justInTimeforEachAtom(const char* name, ld::File::AtomHandler&) const;
        virtual ld::File::ObjcConstraint                objCConstraint() const          { return _objcContraint; }
+       virtual uint8_t                                                 swiftVersion() const            { return _swiftVersion; }
        
        // overrides of ld::dylib::File
        virtual void                                                    processIndirectLibraries(ld::dylib::File::DylibHandler*, bool);
@@ -164,6 +165,9 @@ public:
        virtual bool                                                    allSymbolsAreWeakImported() const;
        virtual const void*                                             codeSignatureDR() const         { return _codeSignatureDR; }
        virtual bool                                                    installPathVersionSpecific() const { return _installPathOverride; }
+       virtual bool                                                    appExtensionSafe() const        { return _appExtensionSafe; };
+       virtual ld::MacVersionMin                               macMinVersion() const           { return _macMinVersionInDylib; }
+       virtual ld::IOSVersionMin                               iOSMinVersion() const           { return _iOSMinVersionInDylib; }
 
 
 protected:
@@ -215,6 +219,7 @@ private:
        bool                                                                            _linkingFlat;
        bool                                                                            _implicitlyLinkPublicDylibs;
        ld::File::ObjcConstraint                                        _objcContraint;
+       uint8_t                                                                         _swiftVersion;
        ld::Section                                                                     _importProxySection;
        ld::Section                                                                     _flatDummySection;
        std::vector<Dependent>                                          _dependentDylibs;
@@ -233,6 +238,9 @@ private:
        bool                                                                            _wrongOS;
        bool                                                                            _installPathOverride;
        bool                                                                            _indirectDylibsProcessed;
+       bool                                                                            _appExtensionSafe;
+       ld::MacVersionMin                                                       _macMinVersionInDylib;
+       ld::IOSVersionMin                                                       _iOSMinVersionInDylib;
        
        static bool                                                                     _s_logHashtable;
 };
@@ -256,13 +264,15 @@ File<A>::File(const uint8_t* fileContent, uint64_t fileLength, const char* pth,
        : ld::dylib::File(strdup(pth), mTime, ord), 
        _macVersionMin(macMin), _iOSVersionMin(iOSMin), _allowSimToMacOSXLinking(allowSimToMacOSX), _addVersionLoadCommand(addVers), 
        _linkingFlat(linkingFlatNamespace), _implicitlyLinkPublicDylibs(hoistImplicitPublicDylibs),
-       _objcContraint(ld::File::objcConstraintNone),
+       _objcContraint(ld::File::objcConstraintNone), _swiftVersion(0),
        _importProxySection("__TEXT", "__import", ld::Section::typeImportProxies, true),
        _flatDummySection("__LINKEDIT", "__flat_dummy", ld::Section::typeLinkEdit, true),
        _parentUmbrella(NULL), _importAtom(NULL), _codeSignatureDR(NULL), 
        _noRexports(false), _hasWeakExports(false), 
        _deadStrippable(false), _hasPublicInstallName(false), 
-        _providedAtom(false), _explictReExportFound(false), _wrongOS(false), _installPathOverride(false), _indirectDylibsProcessed(false)
+        _providedAtom(false), _explictReExportFound(false), _wrongOS(false), _installPathOverride(false), 
+       _indirectDylibsProcessed(false), _appExtensionSafe(false),
+       _macMinVersionInDylib(ld::macVersionUnset), _iOSMinVersionInDylib(ld::iOSVersionUnset)
 {
        const macho_header<P>* header = (const macho_header<P>*)fileContent;
        const uint32_t cmd_count = header->ncmds();
@@ -287,6 +297,7 @@ File<A>::File(const uint8_t* fileContent, uint64_t fileLength, const char* pth,
                                        || (header->filetype() == MH_EXECUTE);  // bundles and exectuables can be used via -bundle_loader
        _hasWeakExports = (header->flags() & MH_WEAK_DEFINES);
        _deadStrippable = (header->flags() & MH_DEAD_STRIPPABLE_DYLIB);
+       _appExtensionSafe = (header->flags() & MH_APP_EXTENSION_SAFE);
        
        // pass 1: get pointers, and see if this dylib uses compressed LINKEDIT format
        const macho_dysymtab_command<P>* dynamicInfo = NULL;
@@ -344,6 +355,7 @@ File<A>::File(const uint8_t* fileContent, uint64_t fileLength, const char* pth,
                                        if ( _addVersionLoadCommand && !indirectDylib )
                                                throw "building for iOS Simulator, but linking against dylib built for MacOSX";
                                }
+                               _macMinVersionInDylib = (ld::MacVersionMin)((macho_version_min_command<P>*)cmd)->version();
                                break;
                        case LC_VERSION_MIN_IPHONEOS:
                                if ( _macVersionMin != ld::macVersionUnset ) {
@@ -351,6 +363,7 @@ File<A>::File(const uint8_t* fileContent, uint64_t fileLength, const char* pth,
                                        if ( _addVersionLoadCommand && !indirectDylib )
                                                throw "building for MacOSX, but linking against dylib built for iOS Simulator";
                                }
+                               _iOSMinVersionInDylib = (ld::IOSVersionMin)((macho_version_min_command<P>*)cmd)->version();
                                break;
                        case LC_CODE_SIGNATURE:
                                codeSignature = (macho_linkedit_data_command<P>* )cmd;
@@ -382,6 +395,7 @@ File<A>::File(const uint8_t* fileContent, uint64_t fileLength, const char* pth,
                                                                        _objcContraint = ld::File::objcConstraintRetainReleaseForSimulator;
                                                                else
                                                                        _objcContraint = ld::File::objcConstraintRetainRelease;
+                                                               _swiftVersion = ((flags >> 8) & 0xFF);
                                                        }
                                                        else if ( sect->size() > 0 ) {
                                                                warning("can't parse %s/%s section in %s", objCInfoSegmentName(), objCInfoSectionName(), this->path());
@@ -1074,17 +1088,6 @@ bool isDylibFile(const uint8_t* fileContent, cpu_type_t* result, cpu_subtype_t*
                *subResult = CPU_SUBTYPE_ARM64_ALL;
                return true;
        }
-       if ( Parser<ppc>::validFile(fileContent, false) ) {
-               *result = CPU_TYPE_POWERPC;
-               const macho_header<Pointer32<BigEndian> >* header = (const macho_header<Pointer32<BigEndian> >*)fileContent;
-               *subResult = header->cpusubtype();
-               return true;
-       }
-       if ( Parser<ppc64>::validFile(fileContent, false) ) {
-               *result = CPU_TYPE_POWERPC64;
-               *subResult = CPU_SUBTYPE_POWERPC_ALL;
-               return true;
-       }
        return false;
 }
 
index ad5720ed1212e2b3b060c558df673658b49c5eb6..d3990e371b816eeff5787253d714244198f0470d 100644 (file)
@@ -79,6 +79,7 @@ public:
                                                                                                _dwarfDebugInfoSect(NULL), _dwarfDebugAbbrevSect(NULL), 
                                                                                                _dwarfDebugLineSect(NULL), _dwarfDebugStringSect(NULL), 
                                                                                                _objConstraint(ld::File::objcConstraintNone),
+                                                                                               _swiftVersion(0),
                                                                                                _cpuSubType(0),
                                                                                                _canScatterAtoms(false) {}
        virtual                                                                 ~File();
@@ -96,6 +97,7 @@ public:
        virtual bool                                                                            canScatterAtoms() const                 { return _canScatterAtoms; }
        virtual const char*                                                                     translationUnitSource() const;
        virtual LinkerOptionsList*                                                      linkerOptions() const                   { return &_linkerOptions; }
+       virtual uint8_t                                                                         swiftVersion() const                    { return _swiftVersion; }
        
        const uint8_t*                                                                          fileContent()                                   { return _fileContent; }
 private:
@@ -109,8 +111,10 @@ private:
        const uint8_t*                                                  _fileContent;
        Section<A>**                                                    _sectionsArray;
        uint8_t*                                                                _atomsArray;
+       uint8_t*                                                                _aliasAtomsArray;
        uint32_t                                                                _sectionsArrayCount;
        uint32_t                                                                _atomsArrayCount;
+       uint32_t                                                                _aliasAtomsArrayCount;
        std::vector<ld::Fixup>                                  _fixups;
        std::vector<ld::Atom::UnwindInfo>               _unwindInfos;
        std::vector<ld::Atom::LineInfo>                 _lineInfos;
@@ -122,6 +126,7 @@ private:
        const macho_section<P>*                                 _dwarfDebugLineSect;
        const macho_section<P>*                                 _dwarfDebugStringSect;
        ld::File::ObjcConstraint                                _objConstraint;
+       uint8_t                                                                 _swiftVersion;
        uint32_t                                                                _cpuSubType;
        bool                                                                    _canScatterAtoms;
        std::vector<std::vector<const char*> >  _linkerOptions;
@@ -182,6 +187,7 @@ protected:
        class Atom<A>*                                  _beginAtoms;
        class Atom<A>*                                  _endAtoms;
        bool                                                    _hasAliases;
+       std::set<const class Atom<A>*>  _altEntries;
 };
 
 
@@ -191,7 +197,7 @@ class CFISection : public Section<A>
 public:
                                                CFISection(Parser<A>& parser, File<A>& f, const macho_section<typename A::P>* s)
                                                        : Section<A>(f, s) { }
-       uint32_t                        cfiCount();
+       uint32_t                        cfiCount(Parser<A>& parser);
 
        virtual ld::Atom::ContentType   contentType()           { return ld::Atom::typeCFI; }
        virtual uint32_t        computeAtomCount(class Parser<A>& parser, struct Parser<A>::LabelAndCFIBreakIterator& it, const struct Parser<A>::CFI_CU_InfoArrays&);
@@ -887,6 +893,39 @@ void Atom<A>::verifyAlignment(const macho_section<P>&) const
 }
 
 
+class AliasAtom : public ld::Atom
+{
+public:
+                                                                               AliasAtom(const char* name, bool hidden, const ld::File* file, const char* aliasOfName) : 
+                                                                                       ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
+                                                                                                       (hidden ? ld::Atom::scopeLinkageUnit : ld::Atom::scopeGlobal), 
+                                                                                                       ld::Atom::typeUnclassified, ld::Atom::symbolTableIn, 
+                                                                                                       false, false, true, 0),
+                                                                                       _file(file),
+                                                                                       _name(name), 
+                                                                                       _fixup(0, ld::Fixup::k1of1, ld::Fixup::kindNoneFollowOn, ld::Fixup::bindingByNameUnbound, aliasOfName) { }
+
+       virtual const ld::File*                         file() const            { return _file; }
+       virtual const char*                                     translationUnitSource() const
+                                                                                                                       { return NULL; }
+       virtual const char*                                     name() const            { return _name; }
+       virtual uint64_t                                        size() const            { return 0; }
+       virtual uint64_t                                        objectAddress() const { return 0; }
+       virtual void                                            copyRawContent(uint8_t buffer[]) const { }
+       virtual ld::Fixup::iterator                     fixupsBegin() const     { return &((ld::Fixup*)&_fixup)[0]; }
+       virtual ld::Fixup::iterator                     fixupsEnd()     const   { return &((ld::Fixup*)&_fixup)[1]; }
+
+private:
+       static ld::Section                                      _s_section;
+
+       const ld::File*                                         _file;
+       const char*                                                     _name;
+       ld::Fixup                                                       _fixup;
+};
+
+ld::Section AliasAtom::_s_section("__LD", "__aliases", ld::Section::typeTempAlias, true);
+
+
 template <typename A>
 class Parser 
 {
@@ -984,6 +1023,7 @@ public:
        static bool                                                                             isThumbFromSymbol(const macho_nlist<P>& sym);
        static bool                                                                             weakImportFromSymbol(const macho_nlist<P>& sym);
        static bool                                                                             resolverFromSymbol(const macho_nlist<P>& sym);
+       static bool                                                                             altEntryFromSymbol(const macho_nlist<P>& sym);
        uint32_t                                                                                symbolIndexFromIndirectSectionAddress(pint_t,const macho_section<P>*);
        const macho_section<P>*                                                 firstMachOSection() { return _sectionsStart; }
        const macho_section<P>*                                                 machOSectionFromSectionIndex(uint32_t index);
@@ -1014,7 +1054,7 @@ public:
        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; }
@@ -1111,10 +1151,13 @@ private:
 
        void                                                                                    parseDebugInfo();
        void                                                                                    parseStabs();
+       void                                                                                    appendAliasAtoms(uint8_t* atomBuffer);
        static bool                                                                             isConstFunStabs(const char *stabStr);
        bool                                                                                    read_comp_unit(const char ** name, const char ** comp_dir,
                                                                                                                                                                                                uint64_t *stmt_list);
-       const char*                                                                             getDwarfString(uint64_t form, const uint8_t* p);
+       pint_t                                                                                  realAddr(pint_t addr);
+       const char*                                                                             getDwarfString(uint64_t form, const uint8_t*& p);
+       uint64_t                                                                                getDwarfOffset(uint64_t form, const uint8_t*& di, bool dwarf64);
        bool                                                                                    skip_form(const uint8_t ** offset, const uint8_t * end, 
                                                                                                                                uint64_t form, uint8_t addr_size, bool dwarf64);
        
@@ -1130,6 +1173,7 @@ private:
        File<A>*                                                                        _file;
        const macho_nlist<P>*                                           _symbols;
        uint32_t                                                                        _symbolCount;
+       uint32_t                                                                        _indirectSymbolCount;
        const char*                                                                     _strings;
        uint32_t                                                                        _stringsSize;
        const uint32_t*                                                         _indirectTable;
@@ -1174,7 +1218,7 @@ Parser<A>::Parser(const uint8_t* fileContent, uint64_t fileLength, const char* p
                                        bool neverConvertDwarf, bool verboseOptimizationHints)
                : _fileContent(fileContent), _fileLength(fileLength), _path(path), _modTime(modTime),
                        _ordinal(ordinal), _file(NULL),
-                       _symbols(NULL), _symbolCount(0), _strings(NULL), _stringsSize(0),
+                       _symbols(NULL), _symbolCount(0), _indirectSymbolCount(0), _strings(NULL), _stringsSize(0),
                        _indirectTable(NULL), _indirectTableCount(0), 
                        _undefinedStartIndex(0), _undefinedEndIndex(0), 
                        _sectionsStart(NULL), _machOSectionsCount(0), _hasUUID(false), 
@@ -1555,6 +1599,18 @@ bool Parser<A>::LabelAndCFIBreakIterator::next(Parser<A>& parser, const Section<
        return false;
 }
 
+template <>
+typename arm::P::uint_t Parser<arm>::realAddr(typename arm::P::uint_t addr)
+{
+       return addr & (-2);
+}
+
+template <typename A>
+typename A::P::uint_t Parser<A>::realAddr(typename A::P::uint_t addr)
+{
+       return addr;
+}
+
 #define STACK_ALLOC_IF_SMALL(_type, _name, _actual_count, _maxCount) \
        _type*  _name = NULL;   \
        uint32_t _name##_count = 1; \
@@ -1619,7 +1675,7 @@ ld::relocatable::File* Parser<A>::parse(const ParserOptions& opts)
        // stack allocate (if not too large) array of CFI_Atom_Info
        uint32_t countOfCFIs = 0;
        if ( _EHFrameSection != NULL )
-               countOfCFIs = _EHFrameSection->cfiCount();
+               countOfCFIs = _EHFrameSection->cfiCount(*this);
        STACK_ALLOC_IF_SMALL(typename CFISection<A>::CFI_Atom_Info, cfiArray, countOfCFIs, 1024);
        
        // stack allocate (if not too large) a copy of __eh_frame to apply relocations to
@@ -1655,7 +1711,7 @@ ld::relocatable::File* Parser<A>::parse(const ParserOptions& opts)
                        if ( cfiArray[i].isCIE )
                                continue;
                        if ( cfiArray[i].u.fdeInfo.function.targetAddress != CFI_INVALID_ADDRESS )
-                               cfiStartsArray[cfiStartsArrayCount++] = cfiArray[i].u.fdeInfo.function.targetAddress;
+                               cfiStartsArray[cfiStartsArrayCount++] = realAddr(cfiArray[i].u.fdeInfo.function.targetAddress);
                        if ( cfiArray[i].u.fdeInfo.lsda.targetAddress != CFI_INVALID_ADDRESS )
                                cfiStartsArray[cfiStartsArrayCount++] = cfiArray[i].u.fdeInfo.lsda.targetAddress;
                        ++countOfFDEs;
@@ -1792,6 +1848,16 @@ ld::relocatable::File* Parser<A>::parse(const ParserOptions& opts)
                }
        }
        
+       // process indirect symbols which become AliasAtoms
+       _file->_aliasAtomsArray = NULL;
+       _file->_aliasAtomsArrayCount = 0;
+       if ( _indirectSymbolCount != 0 ) {
+               _file->_aliasAtomsArrayCount = _indirectSymbolCount;
+               _file->_aliasAtomsArray = new uint8_t[_file->_aliasAtomsArrayCount*sizeof(AliasAtom)];
+               this->appendAliasAtoms(_file->_aliasAtomsArray);
+       }
+       
+       
        // parse dwarf debug info to get line info
        this->parseDebugInfo();
 
@@ -1799,7 +1865,6 @@ ld::relocatable::File* Parser<A>::parse(const ParserOptions& opts)
 }
 
 
-
 template <> uint8_t Parser<x86>::loadCommandSizeMask()         { return 0x03; }
 template <> uint8_t Parser<x86_64>::loadCommandSizeMask()      { return 0x07; }
 template <> uint8_t Parser<arm>::loadCommandSizeMask()         { return 0x03; }
@@ -1950,7 +2015,11 @@ void Parser<A>::prescanSymbolTable()
                        }
                        continue;
                }
-                                               
+               else if ( ((sym.n_type() & N_TYPE) == N_INDR) && ((sym.n_type() & N_EXT) != 0) ) {
+                       _indirectSymbolCount++;
+                       continue;
+               }
+
                // count absolute symbols
                if ( (sym.n_type() & N_TYPE) == N_ABS ) {
                        const char* absName = this->nameFromSymbol(sym);
@@ -1987,6 +2056,34 @@ void Parser<A>::prescanSymbolTable()
        }
 }
 
+template <typename A>
+void Parser<A>::appendAliasAtoms(uint8_t* p)
+{
+       for (uint32_t i=0; i < this->_symbolCount; ++i) {
+               const macho_nlist<P>& sym =     symbolFromIndex(i);
+               // ignore stabs
+               if ( (sym.n_type() & N_STAB) != 0 )
+                       continue;
+
+               // only look at N_INDR symbols
+               if ( (sym.n_type() & N_TYPE) != N_INDR ) 
+                       continue;
+
+               // skip non-external aliases
+               if ( (sym.n_type() & N_EXT) == 0 ) 
+                       continue;
+
+               const char* symbolName = this->nameFromSymbol(sym);
+               const char* aliasOfName = &_strings[sym.n_value()];
+               bool isHiddenVisibility = (sym.n_type() & N_PEXT);
+               AliasAtom* allocatedSpace = (AliasAtom*)p;
+               new (allocatedSpace) AliasAtom(symbolName, isHiddenVisibility, _file, aliasOfName);
+               p += sizeof(AliasAtom);
+       }
+}
+
+
+
 template <typename A>
 int Parser<A>::sectionIndexSorter(void* extra, const void* l, const void* r)
 {
@@ -2206,6 +2303,7 @@ void Parser<A>::makeSections()
                                        _file->_objConstraint = ld::File::objcConstraintRetainReleaseForSimulator;
                                else
                                        _file->_objConstraint = ld::File::objcConstraintRetainRelease;
+                               _file->_swiftVersion = ((flags >> 8) & 0xFF);
                                if ( sect->size() > 8 ) {
                                        warning("section %s/%s has unexpectedly large size %llu in %s", 
                                                        sect->segname(), Section<A>::makeSectionName(sect), sect->size(), _file->path());
@@ -3011,6 +3109,12 @@ bool Parser<A>::resolverFromSymbol(const macho_nlist<P>& sym)
        return ( sym.n_desc() & N_SYMBOL_RESOLVER );
 }
 
+template <typename A>
+bool Parser<A>::altEntryFromSymbol(const macho_nlist<P>& sym)
+{
+       return ( sym.n_desc() & N_ALT_ENTRY );
+}
+
 
 /* Skip over a LEB128 value (signed or unsigned).  */
 static void
@@ -3144,21 +3248,51 @@ bool Parser<A>::skip_form(const uint8_t ** offset, const uint8_t * end, uint64_t
 
 
 template <typename A>
-const char* Parser<A>::getDwarfString(uint64_t form, const uint8_t* p)
+const char* Parser<A>::getDwarfString(uint64_t form, const uint8_t*& di)
 {
-       if ( form == DW_FORM_string )
-               return (const char*)p;
-       else if ( form == DW_FORM_strp ) {
-               uint32_t offset = E::get32(*((uint32_t*)p));
-               const char* dwarfStrings = (char*)_file->fileContent() + _file->_dwarfDebugStringSect->offset();
-               if ( offset > _file->_dwarfDebugStringSect->size() ) {
-                       warning("unknown dwarf DW_FORM_strp (offset=0x%08X) is too big in %s\n", offset, this->_path);
-                       return NULL;
-               }
-               return &dwarfStrings[offset];
+       uint32_t offset;
+       const char* dwarfStrings;
+       const char* result = NULL;
+       switch (form) {
+               case DW_FORM_string:
+                       result = (const char*)di;
+                       di += strlen(result) + 1;
+                       break;
+               case DW_FORM_strp:
+                       offset = E::get32(*((uint32_t*)di));
+                       dwarfStrings = (char*)_file->fileContent() + _file->_dwarfDebugStringSect->offset();
+                       if ( offset < _file->_dwarfDebugStringSect->size() )
+                               result = &dwarfStrings[offset];
+                       else
+                               warning("dwarf DW_FORM_strp (offset=0x%08X) is too big in %s", offset, this->_path);
+                       di += 4;
+                       break;
+               default:
+                       warning("unknown dwarf string encoding (form=%lld) in %s", form, this->_path);
+                       break;
        }
-       warning("unknown dwarf string encoding (form=%lld) in %s\n", form, this->_path);
-       return NULL;
+       return result;
+}
+
+template <typename A>
+uint64_t Parser<A>::getDwarfOffset(uint64_t form, const uint8_t*& di, bool dwarf64)
+{
+       if ( form == DW_FORM_sec_offset ) 
+               form = (dwarf64 ? DW_FORM_data8 : DW_FORM_data4);
+       uint64_t result = -1;
+       switch (form) {
+               case DW_FORM_data4:
+                       result = A::P::E::get32(*(uint32_t*)di);
+                       di += 4;
+                       break;
+               case DW_FORM_data8:
+                       result = A::P::E::get64(*(uint64_t*)di);
+                       di += 8;
+                       break;
+               default:
+                       warning("unknown dwarf DW_FORM_ for DW_AT_stmt_list in %s", this->_path);
+       }
+       return result;
 }
 
 
@@ -3400,6 +3534,7 @@ void Parser<A>::parseStabs()
                                                case N_LSYM:
                                                case N_RSYM:
                                                case N_PSYM:
+                                               case N_AST:
                                                        // not associated with an atom, just copy
                                                        stab.string = symString;
                                                        break;
@@ -3676,20 +3811,23 @@ bool Parser<A>::read_comp_unit(const char ** name, const char ** comp_dir,
                        return false;
                else if (attr == 0)
                        return true;
-
                if (form == DW_FORM_indirect)
                        form = read_uleb128 (&di, end);
 
-               if (attr == DW_AT_name)
-                       *name = getDwarfString(form, di);
-               else if (attr == DW_AT_comp_dir)
-                       *comp_dir = getDwarfString(form, di);
-               else if (attr == DW_AT_stmt_list && form == DW_FORM_data4)
-                       *stmt_list = A::P::E::get32(*(uint32_t*)di);
-               else if (attr == DW_AT_stmt_list && form == DW_FORM_data8)
-                       *stmt_list = A::P::E::get64(*(uint64_t*)di);
-               if (! skip_form (&di, end, form, address_size, dwarf64))
-                       return false;
+               switch (attr) {
+                       case DW_AT_name:
+                               *name = getDwarfString(form, di);
+                               break;
+                       case DW_AT_comp_dir:
+                               *comp_dir = getDwarfString(form, di);
+                               break;
+                       case DW_AT_stmt_list:
+                               *stmt_list = getDwarfOffset(form, di, dwarf64);
+                               break;
+                       default:
+                               if (! skip_form (&di, end, form, address_size, dwarf64))
+                                       return false;
+               }
        }
 }
 
@@ -3708,7 +3846,7 @@ const char* File<A>::translationUnitSource() const
        return _dwarfTranslationUnitPath;
 }
 
-       
+
 
 template <typename A>
 bool File<A>::forEachAtom(ld::File::AtomHandler& handler) const
@@ -3719,7 +3857,13 @@ bool File<A>::forEachAtom(ld::File::AtomHandler& handler) const
                handler.doAtom(*((Atom<A>*)p));
                p += sizeof(Atom<A>);
        }
-       return (_atomsArrayCount != 0);
+       p = _aliasAtomsArray;
+       for(int i=_aliasAtomsArrayCount; i > 0; --i) {
+               handler.doAtom(*((AliasAtom*)p));
+               p += sizeof(AliasAtom);
+       }
+       
+       return (_atomsArrayCount != 0) || (_aliasAtomsArrayCount != 0);
 }
 
 template <typename A>
@@ -3922,10 +4066,14 @@ uint32_t Section<A>::sectionNum(class Parser<A>& parser) const
 }
 
 // arm does not have zero cost exceptions
-template <> uint32_t CFISection<arm>::cfiCount() { return 0; }
+template <> 
+uint32_t CFISection<arm>::cfiCount(Parser<arm>& parser) 
+{
+       return 0; 
+}
 
 template <typename A>
-uint32_t CFISection<A>::cfiCount()
+uint32_t CFISection<A>::cfiCount(Parser<A>& parser)
 {
        // create ObjectAddressSpace object for use by libunwind
        OAS oas(*this, (uint8_t*)this->file().fileContent()+this->_machOSection->offset());
@@ -4059,6 +4207,9 @@ void CFISection<arm>::cfiParse(class Parser<arm>& parser, uint8_t* buffer,
        assert(count == 0);
 }
 
+
+
+
 template <>
 void CFISection<arm64>::cfiParse(class Parser<arm64>& parser, uint8_t* buffer, 
                                                                        libunwind::CFI_Atom_Info<CFISection<arm64>::OAS>::CFI_Atom_Info cfiArray[], 
@@ -4209,8 +4360,6 @@ void CFISection<x86>::addCiePersonalityFixups(class Parser<x86>& parser, const C
        }
 }
 
-
-
 #if SUPPORT_ARCH_arm64
 template <>
 void CFISection<arm64>::addCiePersonalityFixups(class Parser<arm64>& parser, const CFI_Atom_Info* cieInfo)
@@ -4236,6 +4385,7 @@ void CFISection<arm64>::addCiePersonalityFixups(class Parser<arm64>& parser, con
 }
 #endif
 
+
 template <typename A>
 void CFISection<A>::addCiePersonalityFixups(class Parser<A>& parser, const CFI_Atom_Info* cieInfo)
 {
@@ -4481,8 +4631,7 @@ const char* CUSection<x86_64>::personalityName(class Parser<x86_64>& parser, con
        else {
                const pint_t* content = (pint_t*)(this->file().fileContent() + this->_machOSection->offset() + reloc->r_address());
                pint_t personalityAddr = *content;
-               Section<x86_64>* personalitySection = parser.sectionForAddress(personalityAddr);
-               assert((personalitySection->type() == ld::Section::typeCode) && "personality column in __compact_unwind section is not pointer to function");
+               assert((parser.sectionForAddress(personalityAddr)->type() == ld::Section::typeCode) && "personality column in __compact_unwind section is not pointer to function");
                // atoms may not be constructed yet, so scan symbol table for labels
                const char* name = parser.scanSymbolTableForAddress(personalityAddr);
                return name;
@@ -4537,6 +4686,7 @@ const char* CUSection<arm64>::personalityName(class Parser<arm64>& parser, const
 }
 #endif
 
+
 template <typename A>
 const char* CUSection<A>::personalityName(class Parser<A>& parser, const macho_relocation_info<P>* reloc)
 {
@@ -4780,6 +4930,8 @@ uint32_t SymboledSection<A>::appendAtoms(class Parser<A>& parser, uint8_t* p,
                        new (allocatedSpace) Atom<A>(*this, parser, *label, size, isAlias);
                        if ( isAlias )
                                this->_hasAliases = true;
+                       if ( parser.altEntryFromSymbol(*label) )
+                               this->_altEntries.insert(allocatedSpace);
                }
                else {
                        ld::Atom::SymbolTableInclusion inclusion = ld::Atom::symbolTableNotIn;
@@ -6085,7 +6237,12 @@ bool Section<arm>::addRelocFixup(class Parser<arm>& parser, const macho_relocati
                                if ((instruction & 0xFE000000) == 0xFA000000)
                                        displacement += ((instruction & 0x01000000) >> 23);
                                if ( reloc->r_extern() ) {
-                                       target.addend = srcAddr + displacement;
+                                       dstAddr = srcAddr + displacement;
+                                       // <rdar://problem/16652542> support large .o files
+                                       if ( srcAddr > 0x2000000 ) {
+                                               dstAddr -= ((srcAddr + 0x1FFFFFF) & 0xFC000000);
+                                       }
+                                       target.addend = dstAddr;
                                        if ( externSymbolIsThumbDef )
                                                target.addend &= -2; // remove thumb bit
                                }
@@ -6132,7 +6289,11 @@ bool Section<arm>::addRelocFixup(class Parser<arm>& parser, const macho_relocati
                                        dstAddr &= 0xFFFFFFFC;
 
                                if ( reloc->r_extern() ) {
-                                       target.addend = dstAddr;
+                                       // <rdar://problem/16652542> support large .o files
+                                       if ( srcAddr > 0x1000000 ) {
+                                               dstAddr -= ((srcAddr + 0xFFFFFF) & 0xFE000000);
+                                       }
+                                       target.addend = (int64_t)(int32_t)dstAddr;
                                }
                                else {
                                        parser.findTargetFromAddressAndSectionNum(dstAddr, reloc->r_symbolnum(), target);
@@ -6994,6 +7155,21 @@ void Section<A>::makeFixups(class Parser<A>& parser, const struct Parser<A>::CFI
                        }
                }
        }
+       if ( !this->_altEntries.empty() && !this->addFollowOnFixups() ) {
+               if ( _altEntries.count(_beginAtoms) != 0 ) 
+                       warning("N_ALT_ENTRY bit set on first atom in section %s/%s", sect->segname(), Section<A>::makeSectionName(sect));
+
+               Atom<A>* end = &_endAtoms[-1];
+               for(Atom<A>* p = _beginAtoms; p < end; ++p) {
+                       Atom<A>* nextAtom = &p[1];
+                       if ( _altEntries.count(nextAtom) != 0 ) {
+                               typename Parser<A>::SourceLocation src(p, 0);
+                               parser.addFixup(src, ld::Fixup::k1of1, ld::Fixup::kindNoneFollowOn, nextAtom);
+                               typename Parser<A>::SourceLocation src2(nextAtom, 0);
+                               parser.addFixup(src2, ld::Fixup::k1of1, ld::Fixup::kindNoneGroupSubordinate, p);
+                       }
+               }
+       }
        
        // <rdar://problem/9218847> track data-in-code
        if ( parser.hasDataInCodeLabels() && (this->type() == ld::Section::typeCode) ) {
index 5f5612ccac3e5824b74dd38da8837368b3d75477..8efd10aaa0884fb06c9eda5e4b53403c28d6bf8d 100644 (file)
@@ -71,8 +71,8 @@ public:
                                _name(nm),
                                _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());
+                                       if (_s_log) fprintf(stderr, "%p: ARM-to-ARM branch island to final target %s\n", 
+                                                                               this, finalTarget.atom->name());
                                }
 
        virtual const ld::File*                                 file() const                                    { return NULL; }
@@ -101,8 +101,10 @@ public:
                                                        ld::Atom::scopeLinkageUnit, ld::Atom::typeBranchIsland, 
                                                        ld::Atom::symbolTableIn, false, false, false, ld::Atom::Alignment(2)), 
                                _name(nm),
-                               _target(target),
-                               _finalTarget(finalTarget) { }
+                               _finalTarget(finalTarget) {
+                                       if (_s_log) fprintf(stderr, "%p: ARM-to-thumb1 branch island to final target %s\n", 
+                                                                               this, finalTarget.atom->name());
+                               }
 
        virtual const ld::File*                                 file() const                                    { return NULL; }
        virtual const char*                                             name() const                                    { return _name; }
@@ -115,8 +117,6 @@ public:
                int64_t displacement = _finalTarget.atom->finalAddress() + _finalTarget.offset - (this->finalAddress() + 12);
                if ( _finalTarget.atom->isThumb() )
                        displacement |= 1;
-               if (_s_log) fprintf(stderr, "%s: 4 ARM instruction jump to final target at 0x%08llX\n", 
-                                                                               _target->name(), _finalTarget.atom->finalAddress());
                OSWriteLittleInt32(&buffer[ 0], 0, 0xe59fc004); //      ldr  ip, pc + 4
                OSWriteLittleInt32(&buffer[ 4], 0, 0xe08fc00c); //      add      ip, pc, ip
                OSWriteLittleInt32(&buffer[ 8], 0, 0xe12fff1c); //      bx       ip
@@ -126,7 +126,6 @@ public:
 
 private:
        const char*                                                             _name;
-       const ld::Atom*                                                 _target;
        TargetAndOffset                                                 _finalTarget;
 };
 
@@ -141,8 +140,8 @@ public:
                                _name(nm),
                                _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());
+                                       if (_s_log) fprintf(stderr, "%p: Thumb-to-thumb branch island to final target %s\n", 
+                                                                               this, finalTarget.atom->name());
                                        }
 
        virtual const ld::File*                                 file() const                                    { return NULL; }
@@ -175,7 +174,10 @@ public:
                                _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) { } 
+                               _fixup5(0, ld::Fixup::k1of1, ld::Fixup::kindIslandTarget, finalTarget.atom) {
+                                       if (_s_log) fprintf(stderr, "%p: Thumb-to-thumb absolute branch island to final target %s\n", 
+                                                                               this, finalTarget.atom->name());
+                                       }
 
        virtual const ld::File*                                 file() const                                    { return NULL; }
        virtual const char*                                             name() const                                    { return _name; }
@@ -208,8 +210,10 @@ public:
                                                        ld::Atom::scopeLinkageUnit, ld::Atom::typeBranchIsland, 
                                                        ld::Atom::symbolTableIn, false, false, false, ld::Atom::Alignment(2)), 
                                _name(nm),
-                               _target(target),
-                               _finalTarget(finalTarget) { }
+                               _finalTarget(finalTarget) {
+                                       if (_s_log) fprintf(stderr, "%p: NoPIC ARM-to-Thumb branch island to final target %s\n", 
+                                                                               this, finalTarget.atom->name());
+                                       }
 
        virtual const ld::File*                                 file() const                                    { return NULL; }
        virtual const char*                                             name() const                                    { return _name; }
@@ -222,8 +226,6 @@ public:
                uint32_t targetAddr = _finalTarget.atom->finalAddress();
                if ( _finalTarget.atom->isThumb() )
                        targetAddr |= 1;
-               if (_s_log) fprintf(stderr, "%s: 2 ARM instruction jump to final target at 0x%08llX\n",
-                                                                       _target->name(), _finalTarget.atom->finalAddress());
                OSWriteLittleInt32(&buffer[0], 0, 0xe51ff004);  //      ldr     pc, [pc, #-4]
                OSWriteLittleInt32(&buffer[4], 0, targetAddr);  //      .long target-this               
        }
@@ -231,7 +233,6 @@ public:
 
 private:
        const char*                                                             _name;
-       const ld::Atom*                                                 _target;
        TargetAndOffset                                                 _finalTarget;
 };
 
index ad8a504fde004a7f5d7764ec97fcd542d4d7259e..3ddd9b8b9e520641fcff14d5130dd893ee69d319 100644 (file)
@@ -108,6 +108,7 @@ private:
        void                                            addImageOffsetFixupPlusAddend(uint32_t offset, const ld::Atom* targ, uint32_t addend);
 
        uint8_t*                                                                _pagesForDelete;
+       uint8_t*                                                                _pageAlignedPages;
        uint8_t*                                                                _pages;
        uint64_t                                                                _pagesSize;
        uint8_t*                                                                _header;
@@ -129,8 +130,8 @@ template <typename A>
 UnwindInfoAtom<A>::UnwindInfoAtom(const std::vector<UnwindEntry>& entries, uint64_t ehFrameSize)
        : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
                                ld::Atom::scopeLinkageUnit, ld::Atom::typeUnclassified, 
-                               symbolTableNotIn, false, false, false, ld::Atom::Alignment(0)),
-               _pagesForDelete(NULL), _pages(NULL), _pagesSize(0), _header(NULL), _headerSize(0)
+                               symbolTableNotIn, false, false, false, ld::Atom::Alignment(2)),
+               _pagesForDelete(NULL), _pageAlignedPages(NULL), _pages(NULL), _pagesSize(0), _header(NULL), _headerSize(0)
 {
        // build new compressed list by removing entries where next function has same encoding 
        std::vector<UnwindEntry> uniqueEntries;
@@ -160,11 +161,12 @@ UnwindInfoAtom<A>::UnwindInfoAtom(const std::vector<UnwindEntry>& entries, uint6
        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) + 2;
-       _pagesForDelete = (uint8_t*)calloc(pageCount,4096);
+       _pagesForDelete = (uint8_t*)calloc(pageCount+1,4096);
        if ( _pagesForDelete == NULL ) {
                warning("could not allocate space for compact unwind info");
                return;
        }
+       _pageAlignedPages = (uint8_t*)((((uintptr_t)_pagesForDelete) + 4095) & -4096);
        
        // make last second level page smaller so that all other second level pages can be page aligned
        uint32_t maxLastPageSize = 4096 - (ehFrameSize % 4096);
@@ -179,7 +181,7 @@ UnwindInfoAtom<A>::UnwindInfoAtom(const std::vector<UnwindEntry>& entries, uint6
        uint8_t* secondLevelPagesStarts[pageCount*3];
        unsigned int endIndex = uniqueEntries.size();
        unsigned int secondLevelPageCount = 0;
-       uint8_t* pageEnd = &_pagesForDelete[pageCount*4096];
+       uint8_t* pageEnd = &_pageAlignedPages[pageCount*4096];
        uint32_t pageSize = maxLastPageSize;
        while ( endIndex > 0 ) {
                endIndex = makeCompressedSecondLevelPage(uniqueEntries, commonEncodings, pageSize, endIndex, pageEnd);
@@ -193,9 +195,8 @@ UnwindInfoAtom<A>::UnwindInfoAtom(const std::vector<UnwindEntry>& entries, uint6
                }
        }
        _pages = pageEnd;
-       _pagesSize = &_pagesForDelete[pageCount*4096] - pageEnd;
-       
-       
+       _pagesSize = &_pageAlignedPages[pageCount*4096] - pageEnd;
+
        // calculate section layout
        const uint32_t commonEncodingsArraySectionOffset = sizeof(macho_unwind_info_section_header<P>);
        const uint32_t commonEncodingsArrayCount = commonEncodings.size();
@@ -212,7 +213,7 @@ UnwindInfoAtom<A>::UnwindInfoAtom(const std::vector<UnwindEntry>& entries, uint6
        const uint32_t headerEndSectionOffset = lsdaIndexArraySectionOffset + lsdaIndexArraySize;
 
        // now that we know the size of the header, slide all existing fixups on the pages
-       const int32_t fixupSlide = headerEndSectionOffset + (_pagesForDelete - _pages);
+       const int32_t fixupSlide = headerEndSectionOffset + (_pageAlignedPages - _pages);
        for(std::vector<ld::Fixup>::iterator it = _fixups.begin(); it != _fixups.end(); ++it) {
                it->offsetInAtom += fixupSlide;
        }
@@ -547,11 +548,11 @@ unsigned int UnwindInfoAtom<A>::makeRegularSecondLevelPage(const std::vector<Unw
                entryTable[i].set_functionOffset(0);
                entryTable[i].set_encoding(info.encoding);
                // add fixup for address part of entry
-               uint32_t offset = (uint8_t*)(&entryTable[i]) - _pagesForDelete;
+               uint32_t offset = (uint8_t*)(&entryTable[i]) - _pageAlignedPages;
                this->addRegularAddressFixup(offset, info.func);
                if ( encodingMeansUseDwarf(info.encoding) ) {
                        // add fixup for dwarf offset part of page specific encoding
-                       uint32_t encOffset = (uint8_t*)(&entryTable[i]) - _pagesForDelete;
+                       uint32_t encOffset = (uint8_t*)(&entryTable[i]) - _pageAlignedPages;
                        this->addRegularFDEOffsetFixup(encOffset, info.fde);
                }
        }
@@ -678,11 +679,11 @@ unsigned int UnwindInfoAtom<A>::makeCompressedSecondLevelPage(const std::vector<
                uint32_t entryIndex = i - endIndex + entryCount;
                E::set32(entiresArray[entryIndex], encodingIndex << 24);
                // add fixup for address part of entry
-               uint32_t offset = (uint8_t*)(&entiresArray[entryIndex]) - _pagesForDelete;
+               uint32_t offset = (uint8_t*)(&entiresArray[entryIndex]) - _pageAlignedPages;
                this->addCompressedAddressOffsetFixup(offset, info.func, firstFunc);
                if ( encodingMeansUseDwarf(info.encoding) ) {
                        // add fixup for dwarf offset part of page specific encoding
-                       uint32_t encOffset = (uint8_t*)(&encodingsArray[encodingIndex-commonEncodings.size()]) - _pagesForDelete;
+                       uint32_t encOffset = (uint8_t*)(&encodingsArray[encodingIndex-commonEncodings.size()]) - _pageAlignedPages;
                        this->addCompressedEncodingFixup(encOffset, info.fde);
                }
        }
index d921a64fb515100d69668828fa22fc6c6b0721a6..2bbf54a61ead25d474a8c83fcf25e5b671d59b61 100644 (file)
@@ -65,7 +65,7 @@ template <typename A>
 class ObjCImageInfoAtom : public ld::Atom {
 public:
                                                                                        ObjCImageInfoAtom(ld::File::ObjcConstraint objcConstraint, 
-                                                                                                                       bool compaction, bool abi2);
+                                                                                                                       bool compaction, bool abi2, uint8_t swiftVersion);
 
        virtual const ld::File*                                 file() const                                    { return NULL; }
        virtual const char*                                             name() const                                    { return "objc image info"; }
@@ -89,7 +89,7 @@ template <typename A> ld::Section ObjCImageInfoAtom<A>::_s_sectionABI2("__DATA",
 
 template <typename A>
 ObjCImageInfoAtom<A>::ObjCImageInfoAtom(ld::File::ObjcConstraint objcConstraint, bool compaction, 
-                                                                               bool abi2)
+                                                                               bool abi2, uint8_t swiftVersion)
        : ld::Atom(abi2 ? _s_sectionABI2 : _s_sectionABI1, ld::Atom::definitionRegular, ld::Atom::combineNever,
                                                        ld::Atom::scopeLinkageUnit, ld::Atom::typeUnclassified, 
                                                        symbolTableNotIn, false, false, false, ld::Atom::Alignment(2))
@@ -117,6 +117,9 @@ ObjCImageInfoAtom<A>::ObjCImageInfoAtom(ld::File::ObjcConstraint objcConstraint,
                        break;
        }
 
+       // provide swift language version in final binary for runtime to inspect
+       value |= (swiftVersion << 8);
+
        _content.version = 0;
        A::P::E::set32(_content.flags, value);
 }
@@ -362,7 +365,7 @@ void ObjCData<A>::setPointerInContent(ld::Internal& state, const ld::Atom* conte
 template <typename A>
 class Category : public ObjCData<A> {
 public:
-       static const ld::Atom*  getClass(ld::Internal& state, const ld::Atom* contentAtom);
+       static const ld::Atom*  getClass(ld::Internal& state, const ld::Atom* contentAtom, bool& hasAddend);
        static const ld::Atom*  getInstanceMethods(ld::Internal& state, const ld::Atom* contentAtom);
        static const ld::Atom*  getClassMethods(ld::Internal& state, const ld::Atom* contentAtom);
        static const ld::Atom*  getProtocols(ld::Internal& state, const ld::Atom* contentAtom);
@@ -374,9 +377,9 @@ private:
 
 
 template <typename A>
-const ld::Atom*        Category<A>::getClass(ld::Internal& state, const ld::Atom* contentAtom)
+const ld::Atom*        Category<A>::getClass(ld::Internal& state, const ld::Atom* contentAtom, bool& hasAddend)
 {
-       return ObjCData<A>::getPointerInContent(state, contentAtom, sizeof(pint_t)); // category_t.cls
+       return ObjCData<A>::getPointerInContent(state, contentAtom, sizeof(pint_t), &hasAddend); // category_t.cls
 }
 
 template <typename A>
@@ -838,10 +841,17 @@ void OptimizeCategories<A>::doit(const Options& opts, ld::Internal& state)
                                // ignore categories also in __objc_nlcatlist
                                if ( nlcatListAtoms.count(categoryAtom) != 0 )
                                        continue;
-                               const ld::Atom* categoryOnClassAtom = Category<A>::getClass(state, categoryAtom); 
+                               const ld::Atom* categoryOnClassAtom = Category<A>::getClass(state, categoryAtom, hasAddend); 
                                assert(categoryOnClassAtom != NULL);
+                               // only look at classes defined in this image
                                if ( categoryOnClassAtom->definition() != ld::Atom::definitionProxy ) {
-                                       // only look at classes defined in this image
+                                       // <rdar://problem/16107696> for now, back off optimization on new style classes
+                                       if ( hasAddend != 0 )
+                                               continue;
+                                       // <rdar://problem/17249777> don't apply categories to swift classes
+                                       if ( categoryOnClassAtom->hasFixupsOfKind(ld::Fixup::kindNoneGroupSubordinate) )
+                                               continue;
+
                                        CatMap::iterator pos = classToCategories.find(categoryOnClassAtom);
                                        if ( pos == classToCategories.end() ) {
                                                classToCategories[categoryOnClassAtom] = new std::vector<const ld::Atom*>();
@@ -1171,25 +1181,25 @@ void doPass(const Options& opts, ld::Internal& state)
 #if SUPPORT_ARCH_x86_64
                        case CPU_TYPE_X86_64:
                                state.addAtom(*new ObjCImageInfoAtom<x86_64>(state.objcObjectConstraint, compaction, 
-                                                               true));
+                                                         true, state.swiftVersion));
                                break;
 #endif
 #if SUPPORT_ARCH_i386
                        case CPU_TYPE_I386:
                                state.addAtom(*new ObjCImageInfoAtom<x86>(state.objcObjectConstraint, compaction, 
-                                                       opts.objCABIVersion2POverride() ? true : false));
+                                                         opts.objCABIVersion2POverride() ? true : false, state.swiftVersion));
                                break;
 #endif
 #if SUPPORT_ARCH_arm_any
                        case CPU_TYPE_ARM:
                                state.addAtom(*new ObjCImageInfoAtom<arm>(state.objcObjectConstraint, compaction, 
-                                                       true));
+                                                         true, state.swiftVersion));
                                break;
 #endif
 #if SUPPORT_ARCH_arm64
                        case CPU_TYPE_ARM64:
                                state.addAtom(*new ObjCImageInfoAtom<arm64>(state.objcObjectConstraint, compaction, 
-                                                       true));
+                                                         true, state.swiftVersion));
                                break;
 #endif
                        default:
index 684cb795d17519a1ff95e23fcbebbfae92f607bc..139e761d08cf57f8fccffbf8b3d1a8fa3047e335 100644 (file)
@@ -78,10 +78,11 @@ private:
 
        class Comparer {
        public:
-                                       Comparer(const Layout& l) : _layout(l) {}
+                                       Comparer(const Layout& l, ld::Internal& s) : _layout(l), _state(s) {}
                bool            operator()(const ld::Atom* left, const ld::Atom* right);
        private:
                const Layout&   _layout;
+               ld::Internal&   _state;
        };
                                
        typedef std::unordered_map<const char*, const ld::Atom*, CStringHash, CStringEquals> NameToAtom;
@@ -114,7 +115,7 @@ private:
 bool Layout::_s_log = false;
 
 Layout::Layout(const Options& opts, ld::Internal& state)
-       : _options(opts), _state(state), _comparer(*this), _haveOrderFile(opts.orderedSymbolsCount() != 0)
+       : _options(opts), _state(state), _comparer(*this, state), _haveOrderFile(opts.orderedSymbolsCount() != 0)
 {
 }
 
@@ -167,11 +168,21 @@ bool Layout::Comparer::operator()(const ld::Atom* left, const ld::Atom* right)
        bool leftIsAlias = left->isAlias();
        if ( leftIsAlias ) {
                for (ld::Fixup::iterator fit=left->fixupsBegin(); fit != left->fixupsEnd(); ++fit) {
+                       const ld::Atom* target = NULL;
                        if ( fit->kind == ld::Fixup::kindNoneFollowOn ) {
-                               assert(fit->binding == ld::Fixup::bindingDirectlyBound);
-                           if ( fit->u.target == right )
+                               switch ( fit->binding ) {
+                                       case ld::Fixup::bindingsIndirectlyBound:
+                                               target = _state.indirectBindingTable[fit->u.bindingIndex];
+                                               break;
+                                       case ld::Fixup::bindingDirectlyBound:
+                                               target = fit->u.target;
+                                               break;
+                    default:
+                        break;   
+                               }
+                           if ( target == right )
                                        return true; // left already before right
-                               left = fit->u.target; // sort as if alias was its target
+                               left = target; // sort as if alias was its target
                                break;
                    }
                }
@@ -179,11 +190,21 @@ bool Layout::Comparer::operator()(const ld::Atom* left, const ld::Atom* right)
        bool rightIsAlias = right->isAlias();
     if ( rightIsAlias ) {
         for (ld::Fixup::iterator fit=right->fixupsBegin(); fit != right->fixupsEnd(); ++fit) {
+                       const ld::Atom* target = NULL;
                        if ( fit->kind == ld::Fixup::kindNoneFollowOn ) {
-                               assert(fit->binding == ld::Fixup::bindingDirectlyBound);
-                if ( fit->u.target == left )
+                               switch ( fit->binding ) {
+                                       case ld::Fixup::bindingsIndirectlyBound:
+                                               target = _state.indirectBindingTable[fit->u.bindingIndex];
+                                               break;
+                                       case ld::Fixup::bindingDirectlyBound:
+                                               target = fit->u.target;
+                                               break;
+                    default:
+                        break;   
+                               }
+                           if ( target == left )
                     return false; // need to swap, alias is after target
-                               right = fit->u.target; // continue with sort as if right was target
+                               right = target; // continue with sort as if right was target
                 break;
                        }       
                }
@@ -565,6 +586,18 @@ void Layout::buildOrdinalOverrideMap()
 
 void Layout::doPass()
 {
+       const bool log = false;
+       if ( log ) {
+               fprintf(stderr, "Unordered atoms:\n");
+               for (std::vector<ld::Internal::FinalSection*>::iterator sit=_state.sections.begin(); sit != _state.sections.end(); ++sit) {
+                       ld::Internal::FinalSection* sect = *sit;
+                       for (std::vector<const ld::Atom*>::iterator ait=sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
+                               const ld::Atom* atom = *ait;
+                               fprintf(stderr, "\t%p\t%s\t%s\n", atom, sect->sectionName(), atom->name());
+                       }
+               }
+       }
+       
        // handle .o files that cannot have their atoms rearranged
        this->buildFollowOnTables();
 
@@ -574,19 +607,22 @@ void Layout::doPass()
        // sort atoms in each section
        for (std::vector<ld::Internal::FinalSection*>::iterator sit=_state.sections.begin(); sit != _state.sections.end(); ++sit) {
                ld::Internal::FinalSection* sect = *sit;
-               //fprintf(stderr, "sorting section %s\n", sect->sectionName());
+               if ( sect->type() ==  ld::Section::typeTempAlias )
+                       continue;
+               if ( log ) fprintf(stderr, "sorting section %s\n", sect->sectionName());
                std::sort(sect->atoms.begin(), sect->atoms.end(), _comparer);
        }
 
-       //fprintf(stderr, "Sorted atoms:\n");
-       //for (std::vector<ld::Internal::FinalSection*>::iterator sit=_state.sections.begin(); sit != _state.sections.end(); ++sit) {
-       //      ld::Internal::FinalSection* sect = *sit;
-       //      for (std::vector<const ld::Atom*>::iterator ait=sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
-       //              const ld::Atom* atom = *ait;
-       //              fprintf(stderr, "\t%p\t%s\t%s\n", atom, sect->sectionName(), atom->name());
-       //      }
-       //}
-
+       if ( log ) {
+               fprintf(stderr, "Sorted atoms:\n");
+               for (std::vector<ld::Internal::FinalSection*>::iterator sit=_state.sections.begin(); sit != _state.sections.end(); ++sit) {
+                       ld::Internal::FinalSection* sect = *sit;
+                       for (std::vector<const ld::Atom*>::iterator ait=sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
+                               const ld::Atom* atom = *ait;
+                               fprintf(stderr, "\t%p\t%s\t%s\n", atom, sect->sectionName(), atom->name());
+                       }
+               }
+       }
 }
 
 
index c9eb46c4774fcbb8a8148d31e0b6a4843621e6a8..e957e2b52b3342b100c1d8dae35cc5b89b19b892 100644 (file)
@@ -831,6 +831,12 @@ void dumper::dumpFixup(const ld::Fixup* ref)
                case ld::Fixup::kindStoreARM64TLVPLoadPageOff12:
                        printf(", then store as ARM64 12-bit page offset of TLVP");
                        break;
+               case ld::Fixup::kindStoreARM64TLVPLoadNowLeaPage21:
+                       printf(", then store as ARM64 21-bit pcrel ADRP of lea of TLVP");
+                       break;
+               case ld::Fixup::kindStoreARM64TLVPLoadNowLeaPageOff12:
+                       printf(", then store as ARM64 12-bit page offset of lea of TLVP");
+                       break;
                case ld::Fixup::kindStoreARM64PointerToGOT:
                        printf(", then store as 64-bit pointer to GOT entry");
                        break;
@@ -990,12 +996,6 @@ 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;
@@ -1003,10 +1003,22 @@ void dumper::dumpFixup(const ld::Fixup* ref)
                        printf("ARM64 store 12-bit page offset of GOT of %s", referenceTargetAtomName(ref));
                        break;
                case ld::Fixup::kindStoreTargetAddressARM64GOTLeaPage21:
-                       printf("ARM64 store 21-bit pcrel ADRP for lea of %s", referenceTargetAtomName(ref));
+                       printf("ARM64 store 21-bit pcrel ADRP to GOT lea for %s", referenceTargetAtomName(ref));
                        break;
                case ld::Fixup::kindStoreTargetAddressARM64GOTLeaPageOff12:
-                       printf("ARM64 store 12-bit page offset of lea of %s", referenceTargetAtomName(ref));
+                       printf("ARM64 store 12-bit page offset of GOT lea of %s", referenceTargetAtomName(ref));
+                       break;
+               case ld::Fixup::kindStoreTargetAddressARM64TLVPLoadPage21:
+                       printf("ARM64 store 21-bit pcrel ADRP to TLV for %s", referenceTargetAtomName(ref));
+                       break;
+               case ld::Fixup::kindStoreTargetAddressARM64TLVPLoadPageOff12:
+                       printf("ARM64 store 12-bit page offset of TLV of %s", referenceTargetAtomName(ref));
+                       break;
+               case ld::Fixup::kindStoreTargetAddressARM64TLVPLoadNowLeaPage21:
+                       printf("ARM64 store 21-bit pcrel ADRP to lea for TLV for %s", referenceTargetAtomName(ref));
+                       break;
+               case ld::Fixup::kindStoreTargetAddressARM64TLVPLoadNowLeaPageOff12:
+                       printf("ARM64 store 12-bit page offset of lea for TLV of %s", referenceTargetAtomName(ref));
                        break;
                //default:
                //      printf("unknown fixup");
index 3da01c540f39391561697034d58a65b3c3e7c776..effd09ba08e14c2826bae276b3781b952f471e9b 100644 (file)
@@ -221,7 +221,14 @@ const char* UnwindPrinter<A>::functionName(pint_t addr, uint32_t* offset)
        for (uint32_t i=0; i < fSymbolCount; ++i) {
                uint8_t type = fSymbols[i].n_type();
                if ( ((type & N_STAB) == 0) && ((type & N_TYPE) == N_SECT) ) {
-                       if ( fSymbols[i].n_value() == addr ) {
+                       uint32_t value = fSymbols[i].n_value();
+                       if ( value == addr ) {
+                               const char* r = &fStrings[fSymbols[i].n_strx()];
+                               return r;
+                       }
+                       if ( fSymbols[i].n_desc() & N_ARM_THUMB_DEF ) 
+                               value |= 1;
+                       if ( value == addr ) {
                                const char* r = &fStrings[fSymbols[i].n_strx()];
                                //fprintf(stderr, "addr=0x%08llX, i=%u, n_type=0x%0X, r=%s\n", (long long)(fSymbols[i].n_value()), i,  fSymbols[i].n_type(), r);
                                return r;
@@ -730,6 +737,8 @@ void UnwindPrinter<arm64>::decode(uint32_t encoding, const uint8_t* funcStart, c
 }
 #endif
 
+
+
 template <>
 const char* UnwindPrinter<x86_64>::personalityName(const macho_relocation_info<x86_64::P>* reloc)
 {
@@ -759,6 +768,7 @@ const char* UnwindPrinter<arm64>::personalityName(const macho_relocation_info<ar
 }
 #endif
 
+
 template <typename A>
 bool UnwindPrinter<A>::hasExernReloc(uint64_t sectionOffset, const char** personalityStr, pint_t* addr)
 {
@@ -795,6 +805,7 @@ void UnwindPrinter<A>::printObjectUnwindSection(bool showFunctionNames)
                }
                else {
                        functionNameStr = this->functionName(entry->codeStart(), &offsetInFunction);
+                       funcAddress = entry->codeStart();
                }
                if ( offsetInFunction == 0 )
                        printf("  start:        0x%08llX   %s\n", (uint64_t)funcAddress, functionNameStr);
@@ -990,7 +1001,7 @@ static void dump(const char* path, const std::set<cpu_type_t>& onlyArchs, bool s
                                                if ( UnwindPrinter<arm64>::validFile(p + offset) )
                                                        UnwindPrinter<arm64>::make(p + offset, size, path, showFunctionNames);
                                                else
-                                                       throw "in universal file, arm64 slice does not contain arm mach-o";
+                                                       throw "in universal file, arm64 slice does not contain arm64 mach-o";
                                                break;
 #endif
                                        default:
@@ -1062,6 +1073,7 @@ int main(int argc, const char* argv[])
 #if SUPPORT_ARCH_arm64
                        onlyArchs.insert(CPU_TYPE_ARM64);
 #endif
+                       onlyArchs.insert(CPU_TYPE_ARM);
                }
                
                // process each file
index 3f4647d9b0d491556b750a5e64495fa0316c8f6e..545b4a7714321de8a68211042bd2f6b7334f4004 100644 (file)
@@ -13,7 +13,7 @@ MYDIR=$(shell cd ../../bin;pwd)
 LD                     = ld
 OBJECTDUMP     = ObjectDump
 MACHOCHECK     = machocheck
-OTOOL =   /Applications/Xcode.app/Contents/Developer/Toolchains/iOS7.0.xctoolchain/usr/bin/otool
+OTOOL =   xcrun 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  2>/dev/null)
+IOS_SDK = $(shell xcodebuild -sdk iphoneos8.0.internal -version Path  2>/dev/null)
 
 ifeq ($(ARCH),armv6)
   LDFLAGS := -syslibroot $(IOS_SDK)
diff --git a/unit-tests/test-cases/alias-basic/Makefile b/unit-tests/test-cases/alias-basic/Makefile
new file mode 100644 (file)
index 0000000..e457aeb
--- /dev/null
@@ -0,0 +1,47 @@
+##
+# Copyright (c) 2014 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+# 
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+# 
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+# 
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Verify that code and data references can be redirected via aliases. 
+#
+
+CC=/Volumes/my/src/puzzlebox/build/Debug+Asserts/bin/clang
+
+run: all
+
+all:
+       # verify aliases can redirect references to code and data
+       ${CC} -arch ${ARCH} ${CCFLAGS} main.c -c -o main.o
+       ${CC} -arch ${ARCH} ${ASMFLAGS} aliases.s -c -o aliases.o
+       ${CC} -arch ${ARCH} main.o aliases.o -o main.exe
+       nm -nm main.exe | grep _barHidden | grep " external " | ${FAIL_IF_STDIN}
+       # verify dead stripping can remove unused and undefined alias
+       ${CC} -arch ${ARCH} ${ASMFLAGS} aliases.s -c -o aliases2.o -DUNUSED_ALIAS=1
+       ${CC} -arch ${ARCH} main.o aliases2.o -dead_strip -o main2.exe 
+       nm -nm main2.exe | grep _barAlt | ${FAIL_IF_STDIN}      
+       ${PASS_IFF_GOOD_MACHO} main2.exe
+
+clean:
+       rm -rf *.o *.dump *.exe
diff --git a/unit-tests/test-cases/alias-basic/aliases.s b/unit-tests/test-cases/alias-basic/aliases.s
new file mode 100644 (file)
index 0000000..90c1149
--- /dev/null
@@ -0,0 +1,26 @@
+
+  .globl _main
+_main = _mymain
+
+  .globl _bar
+_bar = _mybar
+
+  .globl _barAlt
+_barAlt = _mybar
+
+  .private_extern _barHidden
+_barHidden = _mybar
+
+  .globl _barExtra
+_barExtra = _barAlt
+
+  .globl _result
+_result = _myresult
+
+  .globl _resultHidden
+_resultHidden = _myresult
+
+#if UNUSED_ALIAS
+  .globl _unusedAlias
+_unusedAlias = _unusedUndefined
+#endif
diff --git a/unit-tests/test-cases/alias-basic/main.c b/unit-tests/test-cases/alias-basic/main.c
new file mode 100644 (file)
index 0000000..d89f421
--- /dev/null
@@ -0,0 +1,16 @@
+extern void bar();
+extern int result;
+
+int myresult = 1;
+
+int mymain()
+{
+  bar();
+  return result;
+}
+
+void mybar()
+{
+
+}
+
index f4bfdc854ed1b5c5f4fa716e434ef3c22544140b..7b7667d1de7a3bda2870a75ccf2da5f9429ed624 100644 (file)
@@ -1,5 +1,5 @@
 ##
-# Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+# Copyright (c) 2006-2014 Apple Computer, Inc. All rights reserved.
 #
 # @APPLE_LICENSE_HEADER_START@
 # 
@@ -31,14 +31,16 @@ include ${TESTROOT}/include/common.makefile
 # No differences means this test passes
 #
 
+CC=/Volumes/my/src/puzzlebox/build/Debug+Asserts/bin/clang
+
 run: all
 
 all:
-       ${CC} ${ASMFLAGS} aliases.s -c -o aliases.${ARCH}.o
-       ${LD} -arch ${ARCH} -r -keep_private_externs aliases.${ARCH}.o -o aliases-r.${ARCH}.o
-       ${FAIL_IF_ERROR} ${OBJECTDUMP} -no_content -no_sort aliases.${ARCH}.o > aliases.${ARCH}.o.dump
-       ${FAIL_IF_ERROR} ${OBJECTDUMP} -no_content -no_sort aliases-r.${ARCH}.o > aliases-r.${ARCH}.o.dump
-       ${PASS_IFF} diff aliases.${ARCH}.o.dump aliases-r.${ARCH}.o.dump
+       ${CC} -arch ${ARCH} ${ASMFLAGS} aliases.s -c -o aliases.o
+       ${LD} -arch ${ARCH} -r -keep_private_externs aliases.o -o aliases-r.o
+       ${FAIL_IF_ERROR} ${OBJECTDUMP} -no_content -no_sort aliases.o > aliases.o.dump
+       ${FAIL_IF_ERROR} ${OBJECTDUMP} -no_content -no_sort aliases-r.o > aliases-r.o.dump
+       ${PASS_IFF} diff aliases.o.dump aliases-r.o.dump
 
 clean:
        rm -rf *.o *.dump
index 5e92d8d41c9d0cb22c9361e6725f0d3aee7ed0eb..b669233c2e6e8d3f4cf93c885bb50ef1622a513a 100644 (file)
@@ -31,14 +31,23 @@ _temp:      nop
 _foo:  nop
                nop
 
+/* this should make an alias "_fooalt" for "_foo" */
                .globl _fooalt
                .globl _fooalt2
-/* this should make an alias "_fooalt" for "_foo" */
 _fooalt = _foo 
 _fooalt2 = _foo        
 
+    .global _myAlias
+_myAlias  = _myBase
+
+    .global _myHiddenAlias
+    .private_extern _myHiddenAlias
+_myHiddenAlias  = _myHiddenBase
+
+
+
 _bar:  nop
                nop
                
                
-               .subsections_via_symbols
\ No newline at end of file
+               .subsections_via_symbols
diff --git a/unit-tests/test-cases/alt-entry/Makefile b/unit-tests/test-cases/alt-entry/Makefile
new file mode 100644 (file)
index 0000000..292be81
--- /dev/null
@@ -0,0 +1,40 @@
+##
+# Copyright (c) 2014 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+# 
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+# 
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+# 
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Check that -e works for dynamic executables.
+#
+
+run: all
+
+all:
+       ${CC} ${CCFLAGS} main.c -e _mymain -o main1
+       ${CC} ${CCFLAGS} foo.c -dynamiclib -o libfoo.dylib
+       ${CC} ${CCFLAGS} main.c -e _foo libfoo.dylib -o main2 
+
+       ${PASS_IFF_GOOD_MACHO} main1
+
+clean:
+       rm -f main1 main2 libfoo.dylib
diff --git a/unit-tests/test-cases/alt-entry/foo.c b/unit-tests/test-cases/alt-entry/foo.c
new file mode 100644 (file)
index 0000000..1b1d09b
--- /dev/null
@@ -0,0 +1,7 @@
+#include <stdio.h>
+
+int foo()
+{
+       fprintf(stdout, "hello foo\n");
+       return 0;
+}
\ No newline at end of file
diff --git a/unit-tests/test-cases/alt-entry/main.c b/unit-tests/test-cases/alt-entry/main.c
new file mode 100644 (file)
index 0000000..8af852a
--- /dev/null
@@ -0,0 +1,7 @@
+#include <stdio.h>
+
+int mymain()
+{
+       fprintf(stdout, "hello mymain\n");
+       return 0;
+}
\ No newline at end of file
diff --git a/unit-tests/test-cases/lto-r/Makefile b/unit-tests/test-cases/lto-r/Makefile
new file mode 100644 (file)
index 0000000..49e0b68
--- /dev/null
@@ -0,0 +1,53 @@
+##
+# Copyright (c) 2014 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+# 
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+# 
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+# 
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Check that -r mode preserves symbols with LTO
+#
+
+
+run: all
+
+all:
+       ${CC} ${CCFLAGS} -flto foo.c -c -o foo.o
+       ${CC} ${CCFLAGS} bar.c -c -o bar.o
+       ${LD} -arch ${ARCH} -r foo.o bar.o -o foobar.o 
+       nm -nm foobar.o | grep _foo_hidden | grep non-external | ${FAIL_IF_EMPTY}
+       nm -nm foobar.o | grep _foo_static | grep non-external | ${FAIL_IF_EMPTY}
+       nm -nm foobar.o | grep _foo_weak_hidden | grep non-external | ${FAIL_IF_EMPTY}
+       nm -nm foobar.o | grep _foo_weak_global | grep "weak external " | ${FAIL_IF_EMPTY}
+       nm -nm foobar.o | grep _foo_global | grep " external " | ${FAIL_IF_EMPTY}
+       nm -nm foobar.o | grep _bar | grep " external " | ${FAIL_IF_EMPTY}
+       ${LD} -arch ${ARCH} -r -keep_private_externs foo.o bar.o -o foobar2.o 
+       nm -nm foobar2.o | grep _foo_hidden | grep "private external" | ${FAIL_IF_EMPTY}
+       nm -nm foobar2.o | grep _foo_static | grep non-external | ${FAIL_IF_EMPTY}
+       nm -nm foobar2.o | grep _foo_weak_hidden | grep "weak private external" | ${FAIL_IF_EMPTY}
+       nm -nm foobar2.o | grep _foo_weak_global | grep "weak external " | ${FAIL_IF_EMPTY}
+       nm -nm foobar2.o | grep _foo_global | grep " external " | ${FAIL_IF_EMPTY}
+       nm -nm foobar2.o | grep _bar | grep " external " | ${FAIL_IF_EMPTY}
+       ${PASS_IFF} true
+
+clean:
+       rm -f foo.o bar.o foobar.o foobar2.o
diff --git a/unit-tests/test-cases/lto-r/bar.c b/unit-tests/test-cases/lto-r/bar.c
new file mode 100644 (file)
index 0000000..e425999
--- /dev/null
@@ -0,0 +1 @@
+void bar() {}
diff --git a/unit-tests/test-cases/lto-r/foo.c b/unit-tests/test-cases/lto-r/foo.c
new file mode 100644 (file)
index 0000000..2918f9b
--- /dev/null
@@ -0,0 +1,38 @@
+static int var_static = 3;
+
+__attribute__((visibility("hidden")))
+int var_hidden = 4;
+
+int var_global = 5;
+
+
+__attribute__((visibility("hidden"), weak))
+int var_weak_hidden = 4;
+
+__attribute__((weak))
+int var_weak_global = 5;
+
+
+
+
+static int* foo_static() { return &var_static; }
+
+__attribute__((visibility("hidden")))
+int* foo_hidden() { return &var_hidden; }
+
+
+int* foo_global() { return &var_global; }
+
+
+__attribute__((visibility("hidden"),weak))
+int* foo_weak_hidden() { return &var_weak_hidden; }
+
+
+__attribute__((weak))
+int* foo_weak_global() { return &var_weak_global; }
+
+
+__attribute__((visibility("hidden")))
+void* keep[] = { &foo_static };
+
+
diff --git a/unit-tests/test-cases/lto-r/main.c b/unit-tests/test-cases/lto-r/main.c
new file mode 100644 (file)
index 0000000..578d24b
--- /dev/null
@@ -0,0 +1,15 @@
+
+#include <stdio.h>
+
+
+void foo(int x)
+{
+       printf("hello, world %d\n", x);
+}
+
+int main()
+{
+       foo(10);
+       return 0;
+}
+
diff --git a/unit-tests/test-cases/lto-rename_section/Makefile b/unit-tests/test-cases/lto-rename_section/Makefile
new file mode 100644 (file)
index 0000000..17ba9c3
--- /dev/null
@@ -0,0 +1,52 @@
+##
+# Copyright (c) 2014 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+# 
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+# 
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+# 
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# verify -rename_sectione works with LTO 
+#
+
+run: all
+
+all:
+       ${CC} ${CCFLAGS} -flto a.c -c -o a.o
+       ${CC} ${CCFLAGS} -flto b.c -c -o b.o
+       ${CC} ${CCFLAGS} -flto main.c -c -o main.o
+       ${CC} ${CCFLAGS} main.o a.o b.o -Wl,-preload -o main.preload \
+               -e _entry -nostdlib -Wl,-segalign,0x20 -Wl,-seg1addr,0x200 \
+               -Wl,-rename_section,__DATA,__data,__RAM,__vars \
+               -Wl,-rename_section,__TEXT,__text,__ROM,__code \
+               -Wl,-rename_section,__TEXT,__eh_frame,__ROM,__eh_frame \
+               -Wl,-rename_section,__TEXT,__cstring,__ROM,__const 
+       size -l main.preload | grep __TEXT  | ${FAIL_IF_STDIN}
+       size -l main.preload | grep __DATA  | ${FAIL_IF_STDIN}
+       nm -m main.preload  | grep __ROM | grep __code | grep _entry | ${FAIL_IF_EMPTY}
+       nm -m main.preload  | grep __RAM | grep __vars | grep _mystring | ${FAIL_IF_EMPTY}
+       size -l main.preload | grep __ROM  | ${PASS_IFF_STDIN}
+
+
+
+       
+clean:
+       rm  -f a.o b.o main.o main.preload
diff --git a/unit-tests/test-cases/lto-rename_section/a.c b/unit-tests/test-cases/lto-rename_section/a.c
new file mode 100644 (file)
index 0000000..c17b3e3
--- /dev/null
@@ -0,0 +1,4 @@
+
+extern const char* mystring;
+
+const char** myp = &mystring;
diff --git a/unit-tests/test-cases/lto-rename_section/b.c b/unit-tests/test-cases/lto-rename_section/b.c
new file mode 100644 (file)
index 0000000..b7ad5e1
--- /dev/null
@@ -0,0 +1 @@
+ const char* mystring = "hello";
diff --git a/unit-tests/test-cases/lto-rename_section/main.c b/unit-tests/test-cases/lto-rename_section/main.c
new file mode 100644 (file)
index 0000000..8c9c61e
--- /dev/null
@@ -0,0 +1,11 @@
+
+extern const char** myp;
+
+
+const char** entry(int i) { 
+       if ( i ) {
+               *myp = "help";
+       }
+       return myp;
+}
+
diff --git a/unit-tests/test-cases/lto-rename_segment/Makefile b/unit-tests/test-cases/lto-rename_segment/Makefile
new file mode 100644 (file)
index 0000000..2f3286c
--- /dev/null
@@ -0,0 +1,52 @@
+##
+# Copyright (c) 2014 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+# 
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+# 
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+# 
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# verify -rename_segment and -rename_section works with LTO 
+#
+
+run: all
+
+all:
+       ${CC} ${CCFLAGS} -flto a.c -c -o a.o
+       ${CC} ${CCFLAGS} -flto b.c -c -o b.o
+       ${CC} ${CCFLAGS} -flto main.c -c -o main.o
+       ${CC} ${CCFLAGS} main.o a.o b.o -Wl,-preload -o main.preload \
+               -e _entry -nostdlib -Wl,-segalign,0x20 -Wl,-seg1addr,0x200 \
+               -Wl,-rename_segment,__TEXT,__ROM \
+               -Wl,-rename_segment,__DATA,__RAM \
+               -Wl,-rename_section,__DATA,__data_extra,__RAM2,__data \
+               -Wl,-exported_symbol,_get
+       size -l main.preload | grep __TEXT  | ${FAIL_IF_STDIN}
+       size -l main.preload | grep __DATA  | ${FAIL_IF_STDIN}
+       nm -m main.preload  | grep __ROM | grep __text | grep _entry | ${FAIL_IF_EMPTY}
+       nm -m main.preload  | grep __ROM | grep __text | grep _get | ${FAIL_IF_EMPTY}
+       nm -m main.preload  | grep __RAM | grep __data | grep _mystring | ${FAIL_IF_EMPTY}
+       nm -m main.preload  | grep __RAM2 | grep __data | grep _param | ${FAIL_IF_EMPTY}
+       size -l main.preload | grep __ROM  | ${PASS_IFF_STDIN}
+
+
+clean:
+       rm  -f a.o b.o main.o main.preload
diff --git a/unit-tests/test-cases/lto-rename_segment/a.c b/unit-tests/test-cases/lto-rename_segment/a.c
new file mode 100644 (file)
index 0000000..c17b3e3
--- /dev/null
@@ -0,0 +1,4 @@
+
+extern const char* mystring;
+
+const char** myp = &mystring;
diff --git a/unit-tests/test-cases/lto-rename_segment/b.c b/unit-tests/test-cases/lto-rename_segment/b.c
new file mode 100644 (file)
index 0000000..b7ad5e1
--- /dev/null
@@ -0,0 +1 @@
+ const char* mystring = "hello";
diff --git a/unit-tests/test-cases/lto-rename_segment/main.c b/unit-tests/test-cases/lto-rename_segment/main.c
new file mode 100644 (file)
index 0000000..c219503
--- /dev/null
@@ -0,0 +1,18 @@
+
+extern const char** myp;
+extern const char* mystring;
+
+
+__attribute__((section("__DATA,__data_extra")))
+int param = 0;
+
+
+const char** entry(int i) { 
+       if ( i ) {
+               *myp = "help";
+       }
+  param = i;
+       return myp;
+}
+
+int get() { return param; }
\ No newline at end of file
diff --git a/unit-tests/test-cases/lto-symbol-section-move/Makefile b/unit-tests/test-cases/lto-symbol-section-move/Makefile
new file mode 100644 (file)
index 0000000..018087d
--- /dev/null
@@ -0,0 +1,60 @@
+##
+# Copyright (c) 2014 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+# 
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+# 
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+# 
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Check interaction of -section_rename, -segment_rename, and -move_to_r._segment
+#
+
+run: all
+
+all:
+       ${CC} ${CCFLAGS} main.c -c -o main.o -flto
+       ${CC} ${CCFLAGS} foo.c -c -o foo.o -flto
+       ${CC} ${CCFLAGS} other.c -c -o other.o -flto
+       ${LD} -arch ${ARCH} main.o foo.o other.o -preload -o main.preload \
+               -e _foo -trace_symbol_layout \
+               -move_to_ro_segment __ROM1 rom1.symbols \
+               -move_to_rw_segment __RAM1 ram1.symbols 
+       nm -m main.preload | grep _mainget | grep __ROM1 | grep __text | ${FAIL_IF_EMPTY}
+       nm -m main.preload | grep _getpi | grep __ROM1 | grep __text | ${FAIL_IF_EMPTY}
+       nm -m main.preload | grep _bar | grep __ROM1 | grep __text | ${FAIL_IF_EMPTY}
+       nm -m main.preload | grep _foo | grep __ROM1 | grep __text | ${FAIL_IF_EMPTY}
+       nm -m main.preload | grep _def | grep __RAM1  | grep __data | ${FAIL_IF_EMPTY}
+       nm -m main.preload | grep _ghi | grep __RAM1  | grep __data | ${FAIL_IF_EMPTY}
+       nm -m main.preload | grep _com | grep __RAM1  | grep __bss | ${FAIL_IF_EMPTY}
+       nm -m main.preload | grep _abc | grep __RAM1  | grep __data | ${FAIL_IF_EMPTY}
+       nm -m main.preload | grep _com4 | grep __RAM1  | grep __bss | ${FAIL_IF_EMPTY}
+       nm -m main.preload | grep _main | grep __TEXT | grep __text | ${FAIL_IF_EMPTY}
+       nm -m main.preload | grep _version | grep __TEXT | grep __text | ${FAIL_IF_EMPTY}
+       nm -m main.preload | grep _otherget | grep __TEXT | grep __text | ${FAIL_IF_EMPTY}
+       nm -m main.preload | grep _mylocal | grep __TEXT | grep __text | ${FAIL_IF_EMPTY}
+       nm -m main.preload | grep _x | grep __DATA | grep __data | ${FAIL_IF_EMPTY}
+       nm -m main.preload | grep _all | grep __DATA | grep __data | ${FAIL_IF_EMPTY}
+       nm -m main.preload | grep _x | grep __DATA | grep __data | ${FAIL_IF_EMPTY}
+       nm -m main.preload | grep _com5 | grep __DATA | grep __bss | ${FAIL_IF_EMPTY}
+       ${PASS_IFF} true
+
+clean:
+       rm  -f main.preload main.o other.o foo.o
diff --git a/unit-tests/test-cases/lto-symbol-section-move/foo.c b/unit-tests/test-cases/lto-symbol-section-move/foo.c
new file mode 100644 (file)
index 0000000..9360585
--- /dev/null
@@ -0,0 +1,38 @@
+extern void* otherget();
+extern int main();
+extern const char* version();
+extern void* mainget();
+
+extern int def;
+extern int ghi;
+extern int com;
+
+double getpi() { return 3.1415926535; }
+
+void bar() 
+{  
+}
+
+
+
+extern void* __dso_handle;
+void* x = &__dso_handle;
+
+int abc = 10;
+
+
+int com3;
+int com4;
+int com5;
+
+extern void* foo();
+
+void* all[] = { &main, &version, &mainget, &getpi, &otherget, 
+                &bar, &foo, &x, &abc, &def, &ghi, &com, &com3, &com4, &com5 };
+                
+                
+void* foo() 
+{
+  return all;
+}
+
diff --git a/unit-tests/test-cases/lto-symbol-section-move/main.c b/unit-tests/test-cases/lto-symbol-section-move/main.c
new file mode 100644 (file)
index 0000000..ce97d92
--- /dev/null
@@ -0,0 +1,37 @@
+extern void* otherget();
+
+void mm() 
+{
+}
+
+static void s1() {
+  mm();
+}
+
+static void s2() {
+  mm();
+}
+
+int main()
+{
+  s1();
+  s2();
+       return 0;
+}
+
+const char* version() { return "1.0"; }
+
+static int mylocal()
+{
+  return 0;
+}
+
+void* mainget() { return mylocal; }
+
+
+int def = 20;
+
+int ghi = 30;
+
+int com;
+
diff --git a/unit-tests/test-cases/lto-symbol-section-move/other.c b/unit-tests/test-cases/lto-symbol-section-move/other.c
new file mode 100644 (file)
index 0000000..37d5047
--- /dev/null
@@ -0,0 +1,9 @@
+
+static int mylocal()
+{
+  return 1;
+}
+
+void* otherget() { return mylocal; }
+
+
diff --git a/unit-tests/test-cases/lto-symbol-section-move/ram1.symbols b/unit-tests/test-cases/lto-symbol-section-move/ram1.symbols
new file mode 100644 (file)
index 0000000..ac26378
--- /dev/null
@@ -0,0 +1,5 @@
+main.o:*
+_abc
+_com4
+
+
diff --git a/unit-tests/test-cases/lto-symbol-section-move/rom1.symbols b/unit-tests/test-cases/lto-symbol-section-move/rom1.symbols
new file mode 100644 (file)
index 0000000..ce8e335
--- /dev/null
@@ -0,0 +1,6 @@
+foo.o:*
+_mainget
+
+
+
+
diff --git a/unit-tests/test-cases/preload-section_order/Makefile b/unit-tests/test-cases/preload-section_order/Makefile
new file mode 100644 (file)
index 0000000..653ccf7
--- /dev/null
@@ -0,0 +1,54 @@
+##
+# Copyright (c) 2014 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+# 
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+# 
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+# 
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# verify -section_order works
+#
+
+run: all
+
+all:
+       ${CC} ${CCFLAGS} extra.s -c -o extra.o 
+       ${CC} ${CCFLAGS} more.s -c -o more.o 
+       ${CC} ${CCFLAGS} main.c -c -o main.o
+       # test basic re-order of sections from different files
+       ${CC} ${CCFLAGS} main.o more.o extra.o -Wl,-preload -Wl,-pie -o main1.preload \
+               -e _entry -nostdlib -Wl,-segalign,0x20 -Wl,-seg1addr,0x200 \
+               -Wl,-section_order,__MYSEG,__my_yyy:__my_ccc:__my_aaa
+       ${OTOOL} -l main1.preload | grep "sectname __my_" > main1.found
+       ${FAIL_IF_ERROR} diff main1.found main1.expected
+       # test renaming and re-ordering
+       ${CC} ${CCFLAGS} main.o more.o extra.o -Wl,-preload -Wl,-pie -o main2.preload \
+               -e _entry -nostdlib -Wl,-segalign,0x20 -Wl,-seg1addr,0x200 \
+               -Wl,-rename_section,__MYSEG,__my_yyy,__MYSEG,__my_iii \
+               -Wl,-rename_section,__MYSEG,__my_ccc,__MYSEG,__my_jjj \
+               -Wl,-section_order,__MYSEG,__my_iii:__my_aaa:__my_jjj
+       ${OTOOL} -l main2.preload | grep "sectname __my_" > main2.found
+       ${PASS_IFF} diff main1.found main1.expected
+       
+       
+       
+clean:
+       rm  extra.o more.o main.o main1.preload main1.found main2.preload main2.found
diff --git a/unit-tests/test-cases/preload-section_order/extra.s b/unit-tests/test-cases/preload-section_order/extra.s
new file mode 100644 (file)
index 0000000..9e07959
--- /dev/null
@@ -0,0 +1,15 @@
+
+
+
+  .section __MYSEG,__my_xxx
+_x: .long 0
+
+
+  .section __MYSEG,__my_yyy
+_y: .long 0
+
+
+  .section __MYSEG,__my_zzz
+_z: .long 0
+
+
diff --git a/unit-tests/test-cases/preload-section_order/main.c b/unit-tests/test-cases/preload-section_order/main.c
new file mode 100644 (file)
index 0000000..a9a516f
--- /dev/null
@@ -0,0 +1,5 @@
+
+
+void entry() { 
+}
+
diff --git a/unit-tests/test-cases/preload-section_order/main1.expected b/unit-tests/test-cases/preload-section_order/main1.expected
new file mode 100644 (file)
index 0000000..06f643b
--- /dev/null
@@ -0,0 +1,7 @@
+  sectname __my_yyy
+  sectname __my_ccc
+  sectname __my_aaa
+  sectname __my_bbb
+  sectname __my_ddd
+  sectname __my_xxx
+  sectname __my_zzz
diff --git a/unit-tests/test-cases/preload-section_order/main2.expected b/unit-tests/test-cases/preload-section_order/main2.expected
new file mode 100644 (file)
index 0000000..6ac3c0e
--- /dev/null
@@ -0,0 +1,7 @@
+  sectname __my_iii
+  sectname __my_aaa
+  sectname __my_jjj
+  sectname __my_bbb
+  sectname __my_ddd
+  sectname __my_xxx
+  sectname __my_zzz
diff --git a/unit-tests/test-cases/preload-section_order/more.s b/unit-tests/test-cases/preload-section_order/more.s
new file mode 100644 (file)
index 0000000..6db305b
--- /dev/null
@@ -0,0 +1,19 @@
+
+
+  .section __MYSEG,__my_aaa
+_a: .long 0
+
+
+  .section __MYSEG,__my_bbb
+_b: .long 0
+
+
+  .section __MYSEG,__my_ccc
+_c: .long 0
+
+
+
+  .section __MYSEG,__my_ddd
+_d: .long 0
+
+
diff --git a/unit-tests/test-cases/preload-segment_order/Makefile b/unit-tests/test-cases/preload-segment_order/Makefile
new file mode 100644 (file)
index 0000000..b5b4994
--- /dev/null
@@ -0,0 +1,50 @@
+##
+# Copyright (c) 2014 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+# 
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+# 
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+# 
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# verify -segment_order works
+#
+
+run: all
+
+all:
+       ${CC} ${CCFLAGS} a.c -c -o a.o -static
+       ${CC} ${CCFLAGS} b.c -c -o b.o -static
+       ${CC} ${CCFLAGS} main.c -c -o main.o -static
+       ${CC} ${CCFLAGS} main.o a.o b.o -Wl,-preload -Wl,-pie -o main.preload \
+               -e _entry -nostdlib -Wl,-segalign,0x20 -Wl,-seg1addr,0x200 \
+               -Wl,-rename_section,__TEXT,__text,__ROM,__code \
+               -Wl,-rename_section,__TEXT,__eh_frame,__ROM,__eh_frame \
+               -Wl,-rename_section,__TEXT,__cstring,__ROM2,__strings \
+               -Wl,-rename_section,__DATA,__data,__RAM,__inited \
+               -Wl,-rename_section,__DATA,__common,__ZF,__zf \
+               -Wl,-segment_order,__ROM2:__ROM:__RAM:__ZF 
+       ${OTOOL} -l main.preload | grep -A2 LC_SEGMENT | grep segname > main-segs.found
+       ${PASS_IFF} diff main-segs.found main-segs.expected
+
+
+       
+clean:
+       rm  a.o b.o main.o main.preload main-segs.found
diff --git a/unit-tests/test-cases/preload-segment_order/a.c b/unit-tests/test-cases/preload-segment_order/a.c
new file mode 100644 (file)
index 0000000..b07e94c
--- /dev/null
@@ -0,0 +1,13 @@
+
+extern const char* mystring;
+
+const char** myp = &mystring;
+
+int com;
+
+const char* inc() {
+  ++com;
+  return "";
+}
+
+
diff --git a/unit-tests/test-cases/preload-segment_order/b.c b/unit-tests/test-cases/preload-segment_order/b.c
new file mode 100644 (file)
index 0000000..89db6f1
--- /dev/null
@@ -0,0 +1,9 @@
+const char* mystring = "hello";
+
+int var = 10;
+
+const char* incget() {
+  ++var;
+  return mystring;
+}
+
diff --git a/unit-tests/test-cases/preload-segment_order/main-segs.expected b/unit-tests/test-cases/preload-segment_order/main-segs.expected
new file mode 100644 (file)
index 0000000..c378179
--- /dev/null
@@ -0,0 +1,4 @@
+  segname __ROM2
+  segname __ROM
+  segname __RAM
+  segname __ZF
diff --git a/unit-tests/test-cases/preload-segment_order/main.c b/unit-tests/test-cases/preload-segment_order/main.c
new file mode 100644 (file)
index 0000000..8c9c61e
--- /dev/null
@@ -0,0 +1,11 @@
+
+extern const char** myp;
+
+
+const char** entry(int i) { 
+       if ( i ) {
+               *myp = "help";
+       }
+       return myp;
+}
+
index a8c4bfa8ffaf0d058ccb6d155de0f06951fba0cd..c7c456469db7454916ec5ba1a3fe309485cd3085 100644 (file)
@@ -28,14 +28,14 @@ struct stuff { int a; int b; };
 struct stuff stuff1 __attribute__ ((section ("__DATA,__my"))) = { 1, 2};
 struct stuff stuff2 __attribute__ ((section ("__DATA,__my"))) = { 3 ,4 };
 
-extern struct stuff*  stuff_start  __asm("section$start$__DATA$__my");
-extern struct stuff*  stuff_end    __asm("section$end$__DATA$__my");
+extern struct stuff  stuff_start  __asm("section$start$__DATA$__my");
+extern struct stuff  stuff_end    __asm("section$end$__DATA$__my");
 
 
 int main()
 {
        struct stuff* p;
-       for (p = stuff_start; p < stuff_end; ++p) {
+       for (p = &stuff_start; p < &stuff_end; ++p) {
                p->a = 0;
        }
        return 0;
diff --git a/unit-tests/test-cases/symbol-section-move/Makefile b/unit-tests/test-cases/symbol-section-move/Makefile
new file mode 100644 (file)
index 0000000..32a24b4
--- /dev/null
@@ -0,0 +1,60 @@
+##
+# Copyright (c) 2014 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+# 
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+# 
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+# 
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# Check interaction of -section_rename, -segment_rename, and -move_to_r._segment
+#
+
+run: all
+
+all:
+       ${CC} ${CCFLAGS} main.c -c -o main.o
+       ${CC} ${CCFLAGS} other.c -c -o other.o
+       ${LD} -arch ${ARCH} main.o other.o -preload -o main.preload \
+               -e _foo -trace_symbol_layout \
+               -move_to_ro_segment __ROM1 rom1.symbols \
+               -rename_section __TEXT __cstring __ROM2 mycstrings \
+               -rename_segment __TEXT __ROM3 \
+               -move_to_rw_segment __RAM1 ram1.symbols \
+               -rename_section __DATA __data __RAM2 mydata \
+               -rename_segment __DATA __RAM3 \
+               -segment_order __ROM1:__ROM2:__ROM3:__RAM1:__RAM2:__RAM3
+       nm -m main.preload | grep _foo | grep __ROM1 | grep __text | ${FAIL_IF_EMPTY}
+       nm -m main.preload | grep _s1  | grep __ROM1 | grep __text | ${FAIL_IF_EMPTY}
+       nm -m main.preload | grep _mylocal | grep __ROM1 | grep __text | ${FAIL_IF_EMPTY}
+       size -l main.preload | grep __cstring |  ${FAIL_IF_STDIN}
+       size -l main.preload | grep mycstrings |  ${FAIL_IF_EMPTY}
+       size -l main.preload | grep __TEXT |  ${FAIL_IF_STDIN}
+       nm -m main.preload | grep _mm | grep __ROM3 | grep __text | ${FAIL_IF_EMPTY}
+       nm -m main.preload | grep _main | grep __ROM3 | grep __text | ${FAIL_IF_EMPTY}
+       nm -m main.preload | grep _abc | grep __RAM1  | ${FAIL_IF_EMPTY}
+       nm -m main.preload | grep _com | grep __RAM1  | ${FAIL_IF_EMPTY}
+       size -l main.preload | grep __DATA |  ${FAIL_IF_STDIN}
+       nm -m main.preload | grep _def | grep __RAM2 | grep mydata | ${FAIL_IF_EMPTY}
+       nm -m main.preload | grep _ghi | grep __RAM2 | grep mydata | ${FAIL_IF_EMPTY}
+       ${PASS_IFF} true
+
+clean:
+       rm  -f main.preload main.o other.o
diff --git a/unit-tests/test-cases/symbol-section-move/main.c b/unit-tests/test-cases/symbol-section-move/main.c
new file mode 100644 (file)
index 0000000..407d4ad
--- /dev/null
@@ -0,0 +1,54 @@
+
+void mm() 
+{
+}
+
+static void s1() {
+  mm();
+}
+
+static void s2() {
+  mm();
+}
+
+int main()
+{
+  s1();
+  s2();
+       return 0;
+}
+
+const char* version() { return "1.0"; }
+
+static int mylocal()
+{
+  return 0;
+}
+
+void* mainget() { return mylocal; }
+
+double getpi() { return 3.1415926535; }
+
+void foo() 
+{
+}
+
+void bar() 
+{
+}
+
+extern void* __dso_handle;
+void* x = &__dso_handle;
+
+int abc = 10;
+
+int def = 20;
+
+int ghi = 30;
+
+int com;
+
+int com3;
+int com4;
+int com5;
+
diff --git a/unit-tests/test-cases/symbol-section-move/other.c b/unit-tests/test-cases/symbol-section-move/other.c
new file mode 100644 (file)
index 0000000..37d5047
--- /dev/null
@@ -0,0 +1,9 @@
+
+static int mylocal()
+{
+  return 1;
+}
+
+void* otherget() { return mylocal; }
+
+
diff --git a/unit-tests/test-cases/symbol-section-move/ram1.symbols b/unit-tests/test-cases/symbol-section-move/ram1.symbols
new file mode 100644 (file)
index 0000000..4b641d7
--- /dev/null
@@ -0,0 +1,3 @@
+_com
+_abc
+
diff --git a/unit-tests/test-cases/symbol-section-move/rom1.symbols b/unit-tests/test-cases/symbol-section-move/rom1.symbols
new file mode 100644 (file)
index 0000000..1d50eda
--- /dev/null
@@ -0,0 +1,6 @@
+_foo
+_s1
+main.o:_mylocal
+
+
+
index 56e888ffa95dd221bcbe42c3f0c8ff8081e7e7dc..1d5fbbab39859503c9feff56112914b6e27b23b1 100644 (file)
@@ -37,4 +37,4 @@ all:
        ${PASS_IFF_GOOD_MACHO}  weak
        
 clean:
-       rm -rf main
+       rm -rf weak