]> git.saurik.com Git - apple/ld64.git/blobdiff - src/ld/InputFiles.cpp
ld64-264.3.102.tar.gz
[apple/ld64.git] / src / ld / InputFiles.cpp
index a4b256fa2b16ea3282e0179a5a5f4af6a683c7eb..ab31d4acab07ffe72a8e69cfde6a37cbf064fffc 100644 (file)
@@ -58,6 +58,7 @@
 #include "InputFiles.h"
 #include "macho_relocatable_file.h"
 #include "macho_dylib_file.h"
+#include "textstub_dylib_file.hpp"
 #include "archive_file.h"
 #include "lto_file.h"
 #include "opaque_section_file.h"
@@ -255,8 +256,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 ) {
@@ -282,7 +292,19 @@ ld::File* InputFiles::makeFile(const Options::FileInfo& info, bool indirectDylib
        objOpts.warnUnwindConversionProblems    = _options.needsUnwindInfoSection();
        objOpts.keepDwarfUnwind         = _options.keepDwarfUnwind();
        objOpts.forceDwarfConversion= (_options.outputKind() == Options::kDyld);
+       objOpts.neverConvertDwarf   = !_options.needsUnwindInfoSection();
+       objOpts.verboseOptimizationHints = _options.verboseOptimizationHints();
+       objOpts.armUsesZeroCostExceptions = _options.armUsesZeroCostExceptions();
+       objOpts.simulator                       = _options.targetIOSSimulator();
+       objOpts.ignoreMismatchPlatform = ((_options.outputKind() == Options::kPreload) || (_options.outputKind() == Options::kStaticExecutable));
        objOpts.subType                         = _options.subArchitecture();
+       objOpts.platform                        = _options.platform();
+       objOpts.minOSVersion            = _options.minOSversion();
+       objOpts.srcKind                         = ld::relocatable::File::kSourceObj;
+       objOpts.treateBitcodeAsData     = _options.bitcodeKind() == Options::kBitcodeAsData;
+       objOpts.usingBitcode            = _options.bundleBitcode();
+       objOpts.maxDefaultCommonAlignment = _options.maxDefaultCommonAlign();
+
        ld::relocatable::File* objResult = mach_o::relocatable::parse(p, len, info.path, info.modTime, info.ordinal, objOpts);
        if ( objResult != NULL ) {
                OSAtomicAdd64(len, &_totalObjectSize);
@@ -291,17 +313,36 @@ ld::File* InputFiles::makeFile(const Options::FileInfo& info, bool indirectDylib
        }
 
        // see if it is an llvm object file
-       objResult = lto::parse(p, len, info.path, info.modTime, info.ordinal, _options.architecture(), _options.subArchitecture(), _options.logAllFiles());
+       objResult = lto::parse(p, len, info.path, info.modTime, info.ordinal, _options.architecture(), _options.subArchitecture(), _options.logAllFiles(), _options.verboseOptimizationHints());
        if ( objResult != NULL ) {
                OSAtomicAdd64(len, &_totalObjectSize);
                OSAtomicIncrement32(&_totalObjectLoaded);
                return objResult;
        }
-       
-       // 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;
+
+       // see if it is a dynamic library (or text-based dynamic library)
+       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;
+                       }
+                       dylibResult = textstub::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
@@ -313,6 +354,15 @@ ld::File* InputFiles::makeFile(const Options::FileInfo& info, bool indirectDylib
        archOpts.objcABI2                               = _options.objCABIVersion2POverride();
        archOpts.verboseLoad                    = _options.whyLoad();
        archOpts.logAllFiles                    = _options.logAllFiles();
+       // Set ObjSource Kind, libclang_rt is compiler static library
+       const char* libName = strrchr(info.path, '/');
+       if ( (libName != NULL) && (strncmp(libName, "/libclang_rt", 12) == 0) )
+               archOpts.objOpts.srcKind = ld::relocatable::File::kSourceCompilerArchive;
+       else
+               archOpts.objOpts.srcKind = ld::relocatable::File::kSourceArchive;
+       archOpts.objOpts.treateBitcodeAsData = _options.bitcodeKind() == Options::kBitcodeAsData;
+       archOpts.objOpts.usingBitcode = _options.bundleBitcode();
+
        ld::archive::File* archiveResult = ::archive::parse(p, len, info.path, info.modTime, info.ordinal, archOpts);
        if ( archiveResult != NULL ) {
                OSAtomicAdd64(len, &_totalArchiveSize);
@@ -348,6 +398,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);
@@ -526,17 +583,42 @@ void InputFiles::markExplicitlyLinkedDylibs()
        }
 }
 
-bool InputFiles::libraryAlreadyLoaded(const char* path) 
+bool InputFiles::frameworkAlreadyLoaded(const char* path, const char* frameworkName)
+{
+       for (ld::File* file : _inputFiles) {
+               if ( strcmp(path, file->path()) == 0 )
+                       return true;
+       }
+       for (ld::dylib::File* dylibx : _allDylibs) {
+               const char* fname = dylibx->frameworkName();
+               if ( fname == NULL )
+                       continue;
+               if ( strcmp(frameworkName, fname) == 0 )
+                       return true;
+       }
+       return false;
+}
+
+bool InputFiles::libraryAlreadyLoaded(const char* path)
 {
-       for (std::vector<ld::File*>::const_iterator it = _inputFiles.begin(); it != _inputFiles.end(); ++it) {
-               if ( strcmp(path, (*it)->path()) == 0 )
+       for (ld::File* file : _inputFiles) {
+               if ( strcmp(path, file->path()) == 0 )
+                       return true;
+       }
+       for (ld::dylib::File* dylib : _allDylibs) {
+               if ( strcmp(path, dylib->path()) == 0 )
+                       return true;
+       }
+       for (const LibraryInfo& libInfo : _searchLibraries) {
+               if ( strcmp(path, libInfo.archive()->path()) == 0 )
                        return true;
        }
+
        return false;
 }
 
 
-void InputFiles::addLinkerOptionLibraries(ld::Internal& state)
+void InputFiles::addLinkerOptionLibraries(ld::Internal& state, ld::File::AtomHandler& handler)
 {      
     if ( _options.outputKind() == Options::kObjectFile ) 
                return;
@@ -544,14 +626,17 @@ void InputFiles::addLinkerOptionLibraries(ld::Internal& state)
        // process frameworks specified in .o linker options
        for (CStringSet::const_iterator it = state.linkerOptionFrameworks.begin(); it != state.linkerOptionFrameworks.end(); ++it) {
                const char* frameworkName = *it;
+               if ( state.linkerOptionFrameworksProcessed.count(frameworkName) )
+                       continue;
                Options::FileInfo info = _options.findFramework(frameworkName);
-               if ( ! this->libraryAlreadyLoaded(info.path) ) {
+               if ( ! this->frameworkAlreadyLoaded(info.path, frameworkName) ) {
                        info.ordinal = _linkerOptionOrdinal.nextLinkerOptionOrdinal();
                        try {
                                ld::File* reader = this->makeFile(info, true);
                                ld::dylib::File* dylibReader = dynamic_cast<ld::dylib::File*>(reader);
                                if ( dylibReader != NULL ) {
                                        if ( ! dylibReader->installPathVersionSpecific() ) {
+                                               dylibReader->forEachAtom(handler);
                                                dylibReader->setImplicitlyLinked();
                                                this->addDylib(dylibReader, info);
                                        }
@@ -561,21 +646,27 @@ void InputFiles::addLinkerOptionLibraries(ld::Internal& state)
                                }
                        }
                        catch (const char* msg) {
-                               throwf("in '%s', %s", info.path, msg);
+                               warning("Auto-Linking supplied '%s', %s", info.path, msg);
                        }
                }
+               state.linkerOptionFrameworksProcessed.insert(frameworkName);
        }
        // process libraries specified in .o linker options
        for (CStringSet::const_iterator it = state.linkerOptionLibraries.begin(); it != state.linkerOptionLibraries.end(); ++it) {
                const char* libName = *it;
+               if ( state.linkerOptionLibrariesProcessed.count(libName) )
+                       continue;
                Options::FileInfo info = _options.findLibrary(libName);
                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);
                                }
@@ -583,15 +674,20 @@ 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);
                                }
                        }
                        catch (const char* msg) {
-                               throwf("in '%s', %s", info.path, msg);
+                               warning("Auto-Linking supplied '%s', %s", info.path, msg);
                        }
                }
+               state.linkerOptionLibrariesProcessed.insert(libName);
        }
 }
 
@@ -734,20 +830,27 @@ void InputFiles::inferArchitecture(Options& opts, const char** archName)
        _inferredArch = true;
        // scan all input files, looking for a thin .o file.
        // the first one found is presumably the architecture to link
-       uint8_t buffer[sizeof(mach_header_64)];
+       uint8_t buffer[4096];
        const std::vector<Options::FileInfo>& files = opts.getInputFiles();
        for (std::vector<Options::FileInfo>::const_iterator it = files.begin(); it != files.end(); ++it) {
                int fd = ::open(it->path, O_RDONLY, 0);
                if ( fd != -1 ) {
-                       ssize_t amount = read(fd, buffer, sizeof(buffer));
-                       ::close(fd);
-                       if ( amount >= (ssize_t)sizeof(buffer) ) {
-                               cpu_type_t type;
-                               cpu_subtype_t subtype;
-                               if ( mach_o::relocatable::isObjectFile(buffer, &type, &subtype) ) {
-                                       opts.setArchitecture(type, subtype);
-                                       *archName = opts.architectureName();
-                                       return;
+                       struct stat stat_buf;
+                       if ( fstat(fd, &stat_buf) != -1) {
+                               ssize_t readAmount = stat_buf.st_size;
+                               if ( 4096 < readAmount )
+                                       readAmount = 4096;
+                               ssize_t amount = read(fd, buffer, readAmount);
+                               ::close(fd);
+                               if ( amount >= readAmount ) {
+                                       cpu_type_t type;
+                                       cpu_subtype_t subtype;
+                                       Options::Platform platform;
+                                       if ( mach_o::relocatable::isObjectFile(buffer, &type, &subtype, &platform) ) {
+                                               opts.setArchitecture(type, subtype, platform);
+                                               *archName = opts.architectureName();
+                                               return;
+                                       }
                                }
                        }
                }
@@ -756,11 +859,11 @@ void InputFiles::inferArchitecture(Options& opts, const char** archName)
        // no thin .o files found, so default to same architecture this tool was built as
        warning("-arch not specified");
 #if __i386__
-       opts.setArchitecture(CPU_TYPE_I386, CPU_SUBTYPE_X86_ALL);
+       opts.setArchitecture(CPU_TYPE_I386, CPU_SUBTYPE_X86_ALL, Options::kPlatformOSX);
 #elif __x86_64__
-       opts.setArchitecture(CPU_TYPE_X86_64, CPU_SUBTYPE_X86_64_ALL);
+       opts.setArchitecture(CPU_TYPE_X86_64, CPU_SUBTYPE_X86_64_ALL, Options::kPlatformOSX);
 #elif __arm__
-       opts.setArchitecture(CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V6);
+       opts.setArchitecture(CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V6, Options::kPlatformOSX);
 #else
        #error unknown default architecture
 #endif
@@ -893,6 +996,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);
                                }
@@ -1125,7 +1231,7 @@ void InputFiles::forEachInitialAtom(ld::File::AtomHandler& handler, ld::Internal
        }
 
        markExplicitlyLinkedDylibs();
-       addLinkerOptionLibraries(state);
+       addLinkerOptionLibraries(state, handler);
        createIndirectDylibs();
        createOpaqueFileSections();
        
@@ -1274,6 +1380,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;
@@ -1308,20 +1422,24 @@ 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");
        //for(std::vector<ld::dylib::File*>::iterator it=state.dylibs.begin(); it != state.dylibs.end(); ++it) {
        //      const ld::dylib::File* dylib = *it;
-       //      fprintf(stderr, "    %p %s\n", dylib, dylib->path());
+       //      fprintf(stderr, "    %p impl=%d %s\n", dylib, dylib->implicitlyLinked(), dylib->path());
        //}
        
        // and -bundle_loader