X-Git-Url: https://git.saurik.com/apple/ld64.git/blobdiff_plain/ebf6f43431fe84b7b17822014a6d1f0169516e93..f410558f5d60087e4c310119a1751b437121c3b9:/src/ld/InputFiles.cpp?ds=sidebyside diff --git a/src/ld/InputFiles.cpp b/src/ld/InputFiles.cpp index 766b17c..2a79ae2 100644 --- a/src/ld/InputFiles.cpp +++ b/src/ld/InputFiles.cpp @@ -1,3 +1,4 @@ + /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-* * * Copyright (c) 2009-2011 Apple Inc. All rights reserved. @@ -49,8 +50,6 @@ #include #include #include -#include -#include #include #include @@ -59,9 +58,11 @@ #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" +#include "MachOFileAbstraction.hpp" #include "Snapshot.h" const bool _s_logPThreads = false; @@ -80,16 +81,15 @@ public: class DSOHandleAtom : public ld::Atom { public: DSOHandleAtom(const char* nm, ld::Atom::Scope sc, - ld::Atom::SymbolTableInclusion inc, bool preload=false) - : ld::Atom(preload ? _s_section_preload : _s_section, - ld::Atom::definitionRegular, ld::Atom::combineNever, + ld::Atom::SymbolTableInclusion inc, ld::Section& sect=_s_section) + : ld::Atom(sect, ld::Atom::definitionRegular, + (sect == _s_section_text) ? ld::Atom::combineByName : ld::Atom::combineNever, + // make "weak def" so that link succeeds even if app defines __dso_handle sc, ld::Atom::typeUnclassified, inc, true, false, false, ld::Atom::Alignment(1)), _name(nm) {} virtual ld::File* file() const { return NULL; } - virtual bool translationUnitSource(const char** dir, const char** ) const - { return false; } - virtual const char* name() const { return _name; } + 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 @@ -100,6 +100,7 @@ public: static ld::Section _s_section; static ld::Section _s_section_preload; + static ld::Section _s_section_text; static DSOHandleAtom _s_atomAll; static DSOHandleAtom _s_atomExecutable; static DSOHandleAtom _s_atomDylib; @@ -107,18 +108,21 @@ public: static DSOHandleAtom _s_atomDyld; static DSOHandleAtom _s_atomObjectFile; static DSOHandleAtom _s_atomPreload; + static DSOHandleAtom _s_atomPreloadDSO; private: const char* _name; }; ld::Section DSOHandleAtom::_s_section("__TEXT", "__mach_header", ld::Section::typeMachHeader, true); ld::Section DSOHandleAtom::_s_section_preload("__HEADER", "__mach_header", ld::Section::typeMachHeader, true); +ld::Section DSOHandleAtom::_s_section_text("__TEXT", "__text", ld::Section::typeCode, false); DSOHandleAtom DSOHandleAtom::_s_atomAll("___dso_handle", ld::Atom::scopeLinkageUnit, ld::Atom::symbolTableNotIn); DSOHandleAtom DSOHandleAtom::_s_atomExecutable("__mh_execute_header", ld::Atom::scopeGlobal, ld::Atom::symbolTableInAndNeverStrip); DSOHandleAtom DSOHandleAtom::_s_atomDylib("__mh_dylib_header", ld::Atom::scopeLinkageUnit, ld::Atom::symbolTableNotIn); DSOHandleAtom DSOHandleAtom::_s_atomBundle("__mh_bundle_header", ld::Atom::scopeLinkageUnit, ld::Atom::symbolTableNotIn); DSOHandleAtom DSOHandleAtom::_s_atomDyld("__mh_dylinker_header", ld::Atom::scopeLinkageUnit, ld::Atom::symbolTableNotIn); DSOHandleAtom DSOHandleAtom::_s_atomObjectFile("__mh_object_header", ld::Atom::scopeLinkageUnit, ld::Atom::symbolTableNotIn); -DSOHandleAtom DSOHandleAtom::_s_atomPreload("__mh_preload_header", ld::Atom::scopeLinkageUnit, ld::Atom::symbolTableNotIn, true); +DSOHandleAtom DSOHandleAtom::_s_atomPreload("__mh_preload_header", ld::Atom::scopeLinkageUnit, ld::Atom::symbolTableNotIn, _s_section_preload); +DSOHandleAtom DSOHandleAtom::_s_atomPreloadDSO("___dso_handle", ld::Atom::scopeLinkageUnit, ld::Atom::symbolTableNotIn, _s_section_text); @@ -131,8 +135,6 @@ public: _size(sz) {} virtual ld::File* file() const { return NULL; } - virtual bool translationUnitSource(const char** dir, const char** ) const - { return false; } virtual const char* name() const { return "page zero"; } virtual uint64_t size() const { return _size; } virtual uint64_t objectAddress() const { return 0; } @@ -159,8 +161,6 @@ public: _size(sz) {} virtual ld::File* file() const { return NULL; } - virtual bool translationUnitSource(const char** dir, const char** ) const - { return false; } virtual const char* name() const { return "custom stack"; } virtual uint64_t size() const { return _size; } virtual uint64_t objectAddress() const { return 0; } @@ -177,13 +177,22 @@ private: ld::Section CustomStackAtom::_s_section("__UNIXSTACK", "__stack", ld::Section::typeStack, true); +static bool isCompilerSupportLib(const char* path) { + const char* libName = strrchr(path, '/'); + return ( (libName != NULL) && (strncmp(libName, "/libclang_rt", 12) == 0) ); +} + const char* InputFiles::fileArch(const uint8_t* p, unsigned len) { const char* result = mach_o::relocatable::archName(p); if ( result != NULL ) return result; - + + result = mach_o::dylib::archName(p); + if ( result != NULL ) + return result; + result = lto::archName(p, len); if ( result != NULL ) return result; @@ -195,7 +204,7 @@ const char* InputFiles::fileArch(const uint8_t* p, unsigned len) strcpy(unsupported, "unsupported file format ("); for (unsigned i=0; igetInstallName().c_str(), info.path); + return file; + } // map in whole file - uint64_t len = info.fileLen; + struct stat stat_buf; int fd = ::open(info.path, O_RDONLY, 0); if ( fd == -1 ) throwf("can't open file, errno=%d", errno); - if ( info.fileLen < 20 ) - throw "file too small"; - - uint8_t* p = (uint8_t*)::mmap(NULL, info.fileLen, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, 0); + if ( ::fstat(fd, &stat_buf) != 0 ) + throwf("fstat(%s) failed, errno=%d\n", info.path, errno); + if ( stat_buf.st_size < 20 ) + throwf("file too small (length=%llu)", stat_buf.st_size); + int64_t len = stat_buf.st_size; + uint8_t* p = (uint8_t*)::mmap(NULL, stat_buf.st_size, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, 0); if ( p == (uint8_t*)(-1) ) throwf("can't map file, errno=%d", errno); @@ -251,14 +271,23 @@ ld::File* InputFiles::makeFile(const Options::FileInfo& info, bool indirectDylib if ( sliceFound ) { 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", - fileOffset, fileOffset+len, info.fileLen); + if ( fileOffset+len > stat_buf.st_size ) { + // file size was read awhile ago. If file is being written, wait a second to see if big enough now + sleep(1); + int64_t newFileLen = stat_buf.st_size; + 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, stat_buf.st_size); + } } // if requested architecture is page aligned within fat file, then remap just that portion of file if ( (fileOffset & 0x00000FFF) == 0 ) { // unmap whole file - munmap((caddr_t)p, info.fileLen); + munmap((caddr_t)p, stat_buf.st_size); // re-map just part we need p = (uint8_t*)::mmap(NULL, len, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, fileOffset); if ( p == (uint8_t*)(-1) ) @@ -276,8 +305,22 @@ ld::File* InputFiles::makeFile(const Options::FileInfo& info, bool indirectDylib objOpts.architecture = _options.architecture(); objOpts.objSubtypeMustMatch = !_options.allowSubArchitectureMismatches(); objOpts.logAllFiles = _options.logAllFiles(); - objOpts.convertUnwindInfo = _options.needsUnwindInfoSection(); + objOpts.warnUnwindConversionProblems = _options.needsUnwindInfoSection(); + objOpts.keepDwarfUnwind = _options.keepDwarfUnwind(); + objOpts.forceDwarfConversion= (_options.outputKind() == Options::kDyld); + objOpts.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); @@ -286,17 +329,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, _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 @@ -308,8 +370,17 @@ 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 + if ( isCompilerSupportLib(info.path) ) + 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); OSAtomicIncrement32(&_totalArchivesLoaded); return archiveResult; @@ -343,6 +414,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); @@ -355,7 +433,7 @@ ld::File* InputFiles::makeFile(const Options::FileInfo& info, bool indirectDylib } } -void InputFiles::logDylib(ld::File* file, bool indirect) +void InputFiles::logDylib(ld::File* file, bool indirect, bool speculative) { if ( _options.traceDylibs() ) { const char* fullPath = file->path(); @@ -367,18 +445,45 @@ void InputFiles::logDylib(ld::File* file, bool indirect) // don't log upward dylibs when XBS is computing dependencies logTraceInfo("[Logging for XBS] Used upward dynamic library: %s\n", fullPath); } + else if ( (dylib != NULL ) && dylib->speculativelyLoaded() ) { + logTraceInfo("[Logging for XBS] Speculatively loaded dynamic library: %s\n", fullPath); + } else { - if ( indirect ) - logTraceInfo("[Logging for XBS] Used indirect dynamic library: %s\n", fullPath); - else + if ( indirect ) { + if ( speculative ) + logTraceInfo("[Logging for XBS] Speculatively loaded indirect dynamic library: %s\n", fullPath); + else + logTraceInfo("[Logging for XBS] Used indirect dynamic library: %s\n", fullPath); + } + else { logTraceInfo("[Logging for XBS] Used dynamic library: %s\n", fullPath); + } + } + } + + if ( _options.dumpDependencyInfo() ) { + const ld::dylib::File* dylib = dynamic_cast(file); + if ( file == _bundleLoader ) { + _options.addDependency(Options::depBundleLoader, file->path()); + } + else if ( (dylib != NULL ) && dylib->willBeUpwardDylib() ) { + if ( indirect ) + _options.addDependency(Options::depUpwardIndirectDylib, file->path()); + else + _options.addDependency(Options::depUpwardDirectDylib, file->path()); + } + else { + if ( indirect ) + _options.addDependency(Options::depIndirectDylib, file->path()); + else + _options.addDependency(Options::depDirectDylib, file->path()); } } } void InputFiles::logArchive(ld::File* file) const { - if ( _options.traceArchives() && (_archiveFilesLogged.count(file) == 0) ) { + if ( (_options.traceArchives() || _options.traceEmitJSON()) && (_archiveFilesLogged.count(file) == 0) ) { // LD_TRACE_ARCHIVES should only print out when a .o is actually used from an archive _archiveFilesLogged.insert(file); const char* fullPath = file->path(); @@ -386,44 +491,25 @@ void InputFiles::logArchive(ld::File* file) const if ( realpath(fullPath, realName) != NULL ) fullPath = realName; logTraceInfo("[Logging for XBS] Used static archive: %s\n", fullPath); + + std::string archivePath(fullPath); + _archiveFilePaths.push_back(archivePath); } } void InputFiles::logTraceInfo(const char* format, ...) const { - // one time open() of custom LD_TRACE_FILE - static int trace_file = -1; - if ( trace_file == -1 ) { - const char *trace_file_path = _options.traceOutputFile(); - if ( trace_file_path != NULL ) { - trace_file = open(trace_file_path, O_WRONLY | O_APPEND | O_CREAT, 0666); - if ( trace_file == -1 ) - throwf("Could not open or create trace file: %s", trace_file_path); - } - else { - trace_file = fileno(stderr); - } - } - char trace_buffer[MAXPATHLEN * 2]; va_list ap; va_start(ap, format); int length = vsnprintf(trace_buffer, sizeof(trace_buffer), format, ap); va_end(ap); - char* buffer_ptr = trace_buffer; - - while (length > 0) { - ssize_t amount_written = write(trace_file, buffer_ptr, length); - if(amount_written == -1) - /* Failure to write shouldn't fail the build. */ - return; - buffer_ptr += amount_written; - length -= amount_written; - } + _options.writeToTraceFile(trace_buffer, length); } -ld::dylib::File* InputFiles::findDylib(const char* installPath, const char* fromPath) + +ld::dylib::File* InputFiles::findDylib(const char* installPath, const ld::dylib::File* fromDylib, bool speculative) { //fprintf(stderr, "findDylib(%s, %s)\n", installPath, fromPath); InstallNameToDylib::iterator pos = _installPathToDylibs.find(installPath); @@ -438,12 +524,13 @@ ld::dylib::File* InputFiles::findDylib(const char* installPath, const char* from Options::FileInfo info = _options.findFile(dit->useInstead); _indirectDylibOrdinal = _indirectDylibOrdinal.nextIndirectDylibOrdinal(); info.ordinal = _indirectDylibOrdinal; + info.options.fIndirectDylib = true; ld::File* reader = this->makeFile(info, true); ld::dylib::File* dylibReader = dynamic_cast(reader); if ( dylibReader != NULL ) { addDylib(dylibReader, info); //_installPathToDylibs[strdup(installPath)] = dylibReader; - this->logDylib(dylibReader, true); + this->logDylib(dylibReader, true, speculative); return dylibReader; } else @@ -454,22 +541,12 @@ ld::dylib::File* InputFiles::findDylib(const char* installPath, const char* from } } } - char newPath[MAXPATHLEN]; - // handle @loader_path - if ( strncmp(installPath, "@loader_path/", 13) == 0 ) { - strcpy(newPath, fromPath); - char* addPoint = strrchr(newPath,'/'); - if ( addPoint != NULL ) - strcpy(&addPoint[1], &installPath[13]); - else - strcpy(newPath, &installPath[13]); - installPath = newPath; - } - // note: @executable_path case is handled inside findFileUsingPaths() - // search for dylib using -F and -L paths - Options::FileInfo info = _options.findFileUsingPaths(installPath); + + // search for dylib using -F and -L paths and expanding @ paths + Options::FileInfo info = _options.findIndirectDylib(installPath, fromDylib); _indirectDylibOrdinal = _indirectDylibOrdinal.nextIndirectDylibOrdinal(); info.ordinal = _indirectDylibOrdinal; + info.options.fIndirectDylib = true; try { ld::File* reader = this->makeFile(info, true); ld::dylib::File* dylibReader = dynamic_cast(reader); @@ -477,31 +554,162 @@ ld::dylib::File* InputFiles::findDylib(const char* installPath, const char* from //assert(_installPathToDylibs.find(installPath) != _installPathToDylibs.end()); //_installPathToDylibs[strdup(installPath)] = dylibReader; addDylib(dylibReader, info); - this->logDylib(dylibReader, true); + this->logDylib(dylibReader, true, speculative); return dylibReader; } else throwf("indirect dylib at %s is not a dylib", info.path); } catch (const char* msg) { - throwf("in %s, %s", info.path, msg); + throwf("in '%s', %s", info.path, msg); } } } - -void InputFiles::createIndirectDylibs() -{ - _allDirectDylibsLoaded = true; - _indirectDylibOrdinal = ld::File::Ordinal::indirectDylibBase(); - - // mark all dylibs initially specified as required and check if they can be used +// mark all dylibs initially specified as required, and check if they can be used +void InputFiles::markExplicitlyLinkedDylibs() +{ for (InstallNameToDylib::iterator it=_installPathToDylibs.begin(); it != _installPathToDylibs.end(); it++) { it->second->setExplicitlyLinked(); this->checkDylibClientRestrictions(it->second); } - +} + +bool InputFiles::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 (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; + } + + char realDylibPath[PATH_MAX]; + if ( (realpath(path, realDylibPath) != NULL) && (strcmp(path, realDylibPath) != 0) ) { + return libraryAlreadyLoaded(realDylibPath); + } + + return false; +} + + +void InputFiles::addLinkerOptionLibraries(ld::Internal& state, ld::File::AtomHandler& handler) +{ + if ( _options.outputKind() == Options::kObjectFile ) + return; + + while (! state.unprocessedLinkerOptionLibraries.empty() || ! state.unprocessedLinkerOptionFrameworks.empty()) { + + // process frameworks specified in .o linker options + CStringSet newFrameworks = std::move(state.unprocessedLinkerOptionFrameworks); + state.unprocessedLinkerOptionFrameworks.clear(); + for (const char* frameworkName : newFrameworks) { + if ( state.linkerOptionFrameworks.count(frameworkName) ) + continue; + try { + Options::FileInfo info = _options.findFramework(frameworkName); + if ( ! this->frameworkAlreadyLoaded(info.path, frameworkName) ) { + _linkerOptionOrdinal = _linkerOptionOrdinal.nextLinkerOptionOrdinal(); + info.ordinal = _linkerOptionOrdinal; + ld::File* reader = this->makeFile(info, true); + ld::dylib::File* dylibReader = dynamic_cast(reader); + ld::archive::File* archiveReader = dynamic_cast(reader); + if ( dylibReader != NULL ) { + if ( ! dylibReader->installPathVersionSpecific() ) { + dylibReader->forEachAtom(handler); + dylibReader->setImplicitlyLinked(); + dylibReader->setSpeculativelyLoaded(); + this->addDylib(dylibReader, info); + } + } + else if ( archiveReader != NULL ) { + _searchLibraries.push_back(LibraryInfo(archiveReader)); + _options.addDependency(Options::depArchive, archiveReader->path()); + // -force_load_swift_libs + if (info.options.fForceLoad) { + archiveReader->forEachAtom(handler); + } + } + else { + throwf("framework linker option at %s is not a dylib and not an archive", info.path); + } + } + } + catch (const char* msg) { + warning("Auto-Linking %s", msg); + } + state.linkerOptionFrameworks.insert(frameworkName); + } + + // process libraries specified in .o linker options + // fixme optimize with std::move? + CStringSet newLibraries = std::move(state.unprocessedLinkerOptionLibraries); + state.unprocessedLinkerOptionLibraries.clear(); + for (const char* libName : newLibraries) { + if ( state.linkerOptionLibraries.count(libName) ) + continue; + try { + Options::FileInfo info = _options.findLibrary(libName); + if ( ! this->libraryAlreadyLoaded(info.path) ) { + _linkerOptionOrdinal = _linkerOptionOrdinal.nextLinkerOptionOrdinal(); + info.ordinal = _linkerOptionOrdinal; + // -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(reader); + ld::archive::File* archiveReader = dynamic_cast(reader); + if ( dylibReader != NULL ) { + dylibReader->forEachAtom(handler); + dylibReader->setImplicitlyLinked(); + dylibReader->setSpeculativelyLoaded(); + this->addDylib(dylibReader, info); + } + else if ( archiveReader != NULL ) { + _searchLibraries.push_back(LibraryInfo(archiveReader)); + _options.addDependency(Options::depArchive, archiveReader->path()); + // -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) { + warning("Auto-Linking %s", msg); + } + state.linkerOptionLibraries.insert(libName); + } + } +} + +void InputFiles::createIndirectDylibs() +{ // keep processing dylibs until no more dylibs are added unsigned long lastMapSize = 0; std::set dylibsProcessed; @@ -542,9 +750,10 @@ void InputFiles::createIndirectDylibs() void InputFiles::createOpaqueFileSections() { - // extra command line section always at end + // extra command line sections always at end for (Options::ExtraSection::const_iterator it=_options.extraSectionsBegin(); it != _options.extraSectionsEnd(); ++it) { _inputFiles.push_back(opaque_section::parse(it->segmentName, it->sectionName, it->path, it->data, it->dataLen)); + _options.addDependency(Options::depSection, it->path); } } @@ -637,20 +846,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& files = opts.getInputFiles(); for (std::vector::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; + } } } } @@ -659,11 +875,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 @@ -675,8 +891,10 @@ InputFiles::InputFiles(Options& opts, const char** archName) : _totalObjectSize(0), _totalArchiveSize(0), _totalObjectLoaded(0), _totalArchivesLoaded(0), _totalDylibsLoaded(0), _options(opts), _bundleLoader(NULL), - _allDirectDylibsLoaded(false), _inferredArch(false), _fileMonitor(-1), - _exception(NULL) + _inferredArch(false), + _exception(NULL), + _indirectDylibOrdinal(ld::File::Ordinal::indirectDylibBase()), + _linkerOptionOrdinal(ld::File::Ordinal::linkeOptionBase()) { // fStartCreateReadersTime = mach_absolute_time(); if ( opts.architecture() == 0 ) { @@ -687,6 +905,7 @@ InputFiles::InputFiles(Options& opts, const char** archName) pthread_mutex_init(&_parseLock, NULL); pthread_cond_init(&_parseWorkReady, NULL); pthread_cond_init(&_newFileAvailable, NULL); + _neededFileSlot = -1; #endif const std::vector& files = _options.getInputFiles(); if ( files.size() == 0 ) @@ -784,7 +1003,8 @@ void InputFiles::parseWorkerThread() { if (_s_logPThreads) printf("parsing index %u\n", slot); try { file = makeFile(entry, false); - } catch (const char *msg) { + } + catch (const char *msg) { if ( (strstr(msg, "architecture") != NULL) && !_options.errorOnOtherArchFiles() ) { if ( _options.ignoreOtherArchInputFiles() ) { // ignore, because this is about an architecture not in use @@ -792,8 +1012,12 @@ void InputFiles::parseWorkerThread() { else { warning("ignoring file %s, %s", entry.path, msg); } - } else { - exception = msg; + } + else if ( strstr(msg, "ignoring unexpected") != NULL ) { + warning("%s, %s", entry.path, msg); + } + else { + asprintf((char**)&exception, "%s file '%s'", msg, entry.path); } file = new IgnoredFile(entry.path, entry.modTime, entry.ordinal, ld::File::Other); } @@ -805,7 +1029,8 @@ void InputFiles::parseWorkerThread() { // We are about to die, so set to zero to stop other threads from doing unneeded work. _remainingInputFiles = 0; _exception = exception; - } else { + } + else { _inputFiles[slot] = file; if (_neededFileSlot == slot) pthread_cond_signal(&_newFileAvailable); @@ -870,20 +1095,23 @@ ld::File* InputFiles::addDylib(ld::dylib::File* reader, const Options::FileInfo& } // remove warning for Same install name for CoreServices and CFNetwork? //if ( !dylibOnCommandLineTwice && !isSymlink ) - // warning("dylibs with same install name: %s and %s", pos->second->path(), reader->path()); + // warning("dylibs with same install name: %p %s and %p %s", pos->second, pos->second->path(), reader, reader->path()); } } else if ( info.options.fBundleLoader ) _bundleLoader = reader; // log direct readers - if ( !_allDirectDylibsLoaded ) - this->logDylib(reader, false); + if ( ! info.options.fIndirectDylib ) + this->logDylib(reader, false, false); // update stats _totalDylibsLoaded++; - _searchLibraries.push_back(LibraryInfo(reader)); + // just add direct libraries to search-first list + if ( ! info.options.fIndirectDylib ) + _searchLibraries.push_back(LibraryInfo(reader)); + return reader; } @@ -919,7 +1147,7 @@ void InputFiles::waitForInputFiles() if (it == fileMap.end()) throwf("pipelined linking error - not in file list: %s\n", path_buf); Options::FileInfo* inputInfo = (Options::FileInfo*)it->second; - if (!inputInfo->checkFileExists()) + if (!inputInfo->checkFileExists(_options)) throwf("pipelined linking error - file does not exist: %s\n", inputInfo->path); pthread_mutex_lock(&_parseLock); if (_idleWorkers) @@ -947,7 +1175,7 @@ void InputFiles::waitForInputFiles(InputFiles *inputFiles) { #endif -void InputFiles::forEachInitialAtom(ld::File::AtomHandler& handler) +void InputFiles::forEachInitialAtom(ld::File::AtomHandler& handler, ld::Internal& state) { // add all direct object, archives, and dylibs const std::vector& files = _options.getInputFiles(); @@ -987,6 +1215,7 @@ void InputFiles::forEachInitialAtom(ld::File::AtomHandler& handler) { ld::relocatable::File* reloc = (ld::relocatable::File*)file; _options.snapshot().recordObjectFile(reloc->path()); + _options.addDependency(Options::depObjectFile, reloc->path()); } break; case ld::File::Dylib: @@ -999,9 +1228,14 @@ void InputFiles::forEachInitialAtom(ld::File::AtomHandler& handler) { ld::archive::File* archive = (ld::archive::File*)file; // force loaded archives should be in LD_TRACE - if ( (info.options.fForceLoad || _options.fullyLoadArchives()) && _options.traceArchives() ) + if ( (info.options.fForceLoad || _options.fullyLoadArchives()) && (_options.traceArchives() || _options.traceEmitJSON()) ) logArchive(archive); + + if ( isCompilerSupportLib(info.path) && (info.options.fForceLoad || _options.fullyLoadArchives()) ) + state.forceLoadCompilerRT = true; + _searchLibraries.push_back(LibraryInfo(archive)); + _options.addDependency(Options::depArchive, archive->path()); } break; case ld::File::Other: @@ -1012,9 +1246,18 @@ void InputFiles::forEachInitialAtom(ld::File::AtomHandler& handler) } break; } - file->forEachAtom(handler); + try { + file->forEachAtom(handler); + } + catch (const char* msg) { + asprintf((char**)&_exception, "%s file '%s'", msg, file->path()); + } } + if (_exception) + throw _exception; + markExplicitlyLinkedDylibs(); + addLinkerOptionLibraries(state, handler); createIndirectDylibs(); createOpaqueFileSections(); @@ -1053,7 +1296,9 @@ void InputFiles::forEachInitialAtom(ld::File::AtomHandler& handler) case Options::kPreload: // add implicit __mh_preload_header label handler.doAtom(DSOHandleAtom::_s_atomPreload); - handler.doAtom(DSOHandleAtom::_s_atomAll); + // add implicit __dso_handle label, but put it in __text section because + // with -preload the mach_header is no in the address space. + handler.doAtom(DSOHandleAtom::_s_atomPreloadDSO); break; case Options::kObjectFile: handler.doAtom(DSOHandleAtom::_s_atomObjectFile); @@ -1069,11 +1314,8 @@ void InputFiles::forEachInitialAtom(ld::File::AtomHandler& handler) bool InputFiles::searchLibraries(const char* name, bool searchDylibs, bool searchArchives, bool dataSymbolOnly, ld::File::AtomHandler& handler) const { // Check each input library. - std::vector::const_iterator libIterator = _searchLibraries.begin(); - - - while (libIterator != _searchLibraries.end()) { - LibraryInfo lib = *libIterator; + for (std::vector::const_iterator it=_searchLibraries.begin(); it != _searchLibraries.end(); ++it) { + LibraryInfo lib = *it; if (lib.isDylib()) { if (searchDylibs) { ld::dylib::File *dylibFile = lib.dylib(); @@ -1093,16 +1335,17 @@ bool InputFiles::searchLibraries(const char* name, bool searchDylibs, bool searc ld::archive::File *archiveFile = lib.archive(); if ( dataSymbolOnly ) { if ( archiveFile->justInTimeDataOnlyforEachAtom(name, handler) ) { - if ( _options.traceArchives() ) + if ( _options.traceArchives() || _options.traceEmitJSON()) logArchive(archiveFile); _options.snapshot().recordArchive(archiveFile->path()); + // DALLAS _state.archives.push_back(archiveFile); // found data definition in static library, done - return true; + return true; } } else { if ( archiveFile->justInTimeforEachAtom(name, handler) ) { - if ( _options.traceArchives() ) + if ( _options.traceArchives() || _options.traceEmitJSON()) logArchive(archiveFile); _options.snapshot().recordArchive(archiveFile->path()); // found definition in static library, done @@ -1111,7 +1354,6 @@ bool InputFiles::searchLibraries(const char* name, bool searchDylibs, bool searc } } } - libIterator++; } // search indirect dylibs @@ -1148,7 +1390,7 @@ bool InputFiles::searchLibraries(const char* name, bool searchDylibs, bool searc bool InputFiles::searchWeakDefInDylib(const char* name) const { - // search all relevant dylibs to see if any of a weak-def with this name + // search all relevant dylibs to see if any have a weak-def with this name for (InstallNameToDylib::const_iterator it=_installPathToDylibs.begin(); it != _installPathToDylibs.end(); ++it) { ld::dylib::File* dylibFile = it->second; if ( dylibFile->implicitlyLinked() || dylibFile->explicitlyLinked() ) { @@ -1165,6 +1407,14 @@ static bool vectorContains(const std::vector& 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; @@ -1199,20 +1449,36 @@ void InputFiles::dylibs(ld::Internal& state) } // add implicitly linked dylibs if ( _options.nameSpace() == Options::kTwoLevelNameSpace ) { + std::vector 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); + } + } + } + // make implicit dylib order be deterministic by sorting by install_name + std::sort(implicitDylibs.begin(), implicitDylibs.end(), DylibByInstallNameSorter()); + + if ( _options.traceDylibs() ) { + for (ld::dylib::File* dylib : implicitDylibs) { + if ( dylib->speculativelyLoaded() && !dylib->explicitlyLinked() && dylib->providedExportAtom() ) { + const char* fullPath = dylib->path(); + char realName[MAXPATHLEN]; + if ( realpath(fullPath, realName) != NULL ) + fullPath = realName; + logTraceInfo("[Logging for XBS] Used dynamic library: %s\n", fullPath); } } } + state.dylibs.insert(state.dylibs.end(), implicitDylibs.begin(), implicitDylibs.end()); } //fprintf(stderr, "all dylibs:\n"); //for(std::vector::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 @@ -1223,8 +1489,15 @@ void InputFiles::dylibs(ld::Internal& state) throw "dynamic main executables must link with libSystem.dylib"; } +void InputFiles::archives(ld::Internal& state) +{ + for (const std::string path : _archiveFilePaths) { + + state.archivePaths.push_back(path); + } +} + } // namespace tool } // namespace ld -