X-Git-Url: https://git.saurik.com/apple/ld64.git/blobdiff_plain/0a8dc3df050bd5c0a70486b9ebdb9dccce439f3e..HEAD:/src/ld/InputFiles.cpp diff --git a/src/ld/InputFiles.cpp b/src/ld/InputFiles.cpp index e8e6bcc..af66ec7 100644 --- a/src/ld/InputFiles.cpp +++ b/src/ld/InputFiles.cpp @@ -177,6 +177,11 @@ 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) { @@ -209,15 +214,27 @@ const char* InputFiles::fileArch(const uint8_t* p, unsigned len) ld::File* InputFiles::makeFile(const Options::FileInfo& info, bool indirectDylib) { + // handle inlined framework first. + if (info.isInlined) { + auto interface = _options.findTAPIFile(info.path); + if (!interface) + throwf("could not find inlined dylib file: %s", info.path); + auto file = textstub::dylib::parse(info.path, interface, info.modTime, info.ordinal, _options, indirectDylib); + if (!file) + throwf("could not parse inlined dylib file: %s(%s)", interface->getInstallName().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 ) - throwf("file too small (length=%llu)", info.fileLen); - - uint8_t* p = (uint8_t*)::mmap(NULL, info.fileLen, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, 0); + if ( ::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); @@ -231,11 +248,19 @@ ld::File* InputFiles::makeFile(const Options::FileInfo& info, bool indirectDylib const struct fat_arch* archs = (struct fat_arch*)(p + sizeof(struct fat_header)); bool sliceFound = false; sliceCount = OSSwapBigToHostInt32(fh->nfat_arch); - if ( _options.preferSubArchitecture() ) { - // first try to find a slice that match cpu-type and cpu-sub-type + // first try to find a slice that match cpu-type and cpu-sub-type + for (uint32_t i=0; i < sliceCount; ++i) { + if ( (OSSwapBigToHostInt32(archs[i].cputype) == (uint32_t)_options.architecture()) + && ((OSSwapBigToHostInt32(archs[i].cpusubtype) & ~CPU_SUBTYPE_MASK) == (uint32_t)_options.subArchitecture()) ) { + sliceToUse = i; + sliceFound = true; + break; + } + } + if ( !sliceFound && _options.allowSubArchitectureMismatches() ) { + // look for any slice that matches just cpu-type for (uint32_t i=0; i < sliceCount; ++i) { - if ( (OSSwapBigToHostInt32(archs[i].cputype) == (uint32_t)_options.architecture()) - && (OSSwapBigToHostInt32(archs[i].cpusubtype) == (uint32_t)_options.subArchitecture()) ) { + if ( OSSwapBigToHostInt32(archs[i].cputype) == (uint32_t)_options.architecture() ) { sliceToUse = i; sliceFound = true; break; @@ -243,9 +268,10 @@ ld::File* InputFiles::makeFile(const Options::FileInfo& info, bool indirectDylib } } if ( !sliceFound ) { - // look for any slice that matches just cpu-type - for (uint32_t i=0; i < sliceCount; ++i) { - if ( OSSwapBigToHostInt32(archs[i].cputype) == (uint32_t)_options.architecture() ) { + // Look for a fallback slice. + for (uint32_t i = 0; i < sliceCount; ++i) { + if ( OSSwapBigToHostInt32(archs[i].cputype) == (uint32_t)_options.fallbackArchitecture() && + OSSwapBigToHostInt32(archs[i].cpusubtype) == (uint32_t)_options.fallbackSubArchitecture() ) { sliceToUse = i; sliceFound = true; break; @@ -255,23 +281,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 ) { + 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); - uint64_t newFileLen = info.fileLen; + 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, info.fileLen); + 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) ) @@ -297,9 +323,11 @@ ld::File* InputFiles::makeFile(const Options::FileInfo& info, bool indirectDylib objOpts.armUsesZeroCostExceptions = _options.armUsesZeroCostExceptions(); objOpts.simulator = _options.targetIOSSimulator(); objOpts.ignoreMismatchPlatform = ((_options.outputKind() == Options::kPreload) || (_options.outputKind() == Options::kStaticExecutable)); +#if SUPPORT_ARCH_arm64e + objOpts.supportsAuthenticatedPointers = _options.supportsAuthenticatedPointers(); +#endif objOpts.subType = _options.subArchitecture(); - objOpts.platform = _options.platform(); - objOpts.minOSVersion = _options.minOSversion(); + objOpts.platforms = _options.platforms(); objOpts.srcKind = ld::relocatable::File::kSourceObj; objOpts.treateBitcodeAsData = _options.bitcodeKind() == Options::kBitcodeAsData; objOpts.usingBitcode = _options.bundleBitcode(); @@ -355,8 +383,7 @@ ld::File* InputFiles::makeFile(const Options::FileInfo& info, bool indirectDylib 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) ) + if ( isCompilerSupportLib(info.path) ) archOpts.objOpts.srcKind = ld::relocatable::File::kSourceCompilerArchive; else archOpts.objOpts.srcKind = ld::relocatable::File::kSourceArchive; @@ -412,7 +439,7 @@ ld::File* InputFiles::makeFile(const Options::FileInfo& info, bool indirectDylib } else { if ( isFatFile ) - throwf("file is universal (%u slices) but does not contain a(n) %s slice: %s", sliceCount, _options.architectureName(), info.path); + throwf("file is universal (%u slices) but does not contain the %s architecture: %s", sliceCount, _options.architectureName(), info.path); else throwf("file was built for %s which is not the architecture being linked (%s): %s", fileArch(p, len), _options.architectureName(), info.path); } @@ -449,19 +476,19 @@ void InputFiles::logDylib(ld::File* file, bool indirect, bool speculative) if ( _options.dumpDependencyInfo() ) { const ld::dylib::File* dylib = dynamic_cast(file); if ( file == _bundleLoader ) { - _options.dumpDependency(Options::depBundleLoader, file->path()); + _options.addDependency(Options::depBundleLoader, file->path()); } else if ( (dylib != NULL ) && dylib->willBeUpwardDylib() ) { if ( indirect ) - _options.dumpDependency(Options::depUpwardIndirectDylib, file->path()); + _options.addDependency(Options::depUpwardIndirectDylib, file->path()); else - _options.dumpDependency(Options::depUpwardDirectDylib, file->path()); + _options.addDependency(Options::depUpwardDirectDylib, file->path()); } else { if ( indirect ) - _options.dumpDependency(Options::depIndirectDylib, file->path()); + _options.addDependency(Options::depIndirectDylib, file->path()); else - _options.dumpDependency(Options::depDirectDylib, file->path()); + _options.addDependency(Options::depDirectDylib, file->path()); } } } @@ -485,35 +512,12 @@ void InputFiles::logArchive(ld::File* file) const 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 (errno=%d): %s", errno, 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); } @@ -637,13 +641,14 @@ void InputFiles::addLinkerOptionLibraries(ld::Internal& state, ld::File::AtomHan for (const char* frameworkName : newFrameworks) { if ( state.linkerOptionFrameworks.count(frameworkName) ) continue; - Options::FileInfo info = _options.findFramework(frameworkName); - if ( ! this->frameworkAlreadyLoaded(info.path, frameworkName) ) { - _linkerOptionOrdinal = _linkerOptionOrdinal.nextLinkerOptionOrdinal(); - info.ordinal = _linkerOptionOrdinal; - try { + 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); @@ -652,14 +657,23 @@ void InputFiles::addLinkerOptionLibraries(ld::Internal& state, ld::File::AtomHan 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", info.path); + throwf("framework linker option at %s is not a dylib and not an archive", info.path); } } - catch (const char* msg) { - warning("Auto-Linking supplied '%s', %s", info.path, msg); - } } + catch (const char* msg) { + // only warn about missing auto-linked framework if some missing symbol error happens later + state.missingLinkerOptionFrameworks.insert(frameworkName); + } state.linkerOptionFrameworks.insert(frameworkName); } @@ -670,11 +684,11 @@ void InputFiles::addLinkerOptionLibraries(ld::Internal& state, ld::File::AtomHan for (const char* libName : newLibraries) { if ( state.linkerOptionLibraries.count(libName) ) continue; - Options::FileInfo info = _options.findLibrary(libName); - if ( ! this->libraryAlreadyLoaded(info.path) ) { - _linkerOptionOrdinal = _linkerOptionOrdinal.nextLinkerOptionOrdinal(); - info.ordinal = _linkerOptionOrdinal; - try { + 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); @@ -688,8 +702,7 @@ void InputFiles::addLinkerOptionLibraries(ld::Internal& state, ld::File::AtomHan } else if ( archiveReader != NULL ) { _searchLibraries.push_back(LibraryInfo(archiveReader)); - if ( _options.dumpDependencyInfo() ) - _options.dumpDependency(Options::depArchive, archiveReader->path()); + _options.addDependency(Options::depArchive, archiveReader->path()); // -force_load_swift_libs if (info.options.fForceLoad) { archiveReader->forEachAtom(handler); @@ -699,10 +712,11 @@ void InputFiles::addLinkerOptionLibraries(ld::Internal& state, ld::File::AtomHan throwf("linker option dylib at %s is not a dylib", info.path); } } - catch (const char* msg) { - warning("Auto-Linking supplied '%s', %s", info.path, msg); - } } + catch (const char* msg) { + // only warn about missing auto-linked library if some missing symbol error happens later + state.missingLinkerOptionLibraries.insert(libName); + } state.linkerOptionLibraries.insert(libName); } } @@ -753,8 +767,7 @@ void InputFiles::createOpaqueFileSections() // extra command line sections always at end for (Options::ExtraSection::const_iterator it=_options.extraSectionsBegin(); it != _options.extraSectionsEnd(); ++it) { _inputFiles.push_back(opaque_section::parse(it->segmentName, it->sectionName, it->path, it->data, it->dataLen)); - if ( _options.dumpDependencyInfo() ) - _options.dumpDependency(Options::depSection, it->path); + _options.addDependency(Options::depSection, it->path); } } @@ -862,9 +875,10 @@ void InputFiles::inferArchitecture(Options& opts, const char** archName) 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); + ld::Platform platform; + uint32_t minOsVersion; + if ( mach_o::relocatable::isObjectFile(buffer, &type, &subtype, &platform, &minOsVersion) ) { + opts.setArchitecture(type, subtype, platform, minOsVersion); *archName = opts.architectureName(); return; } @@ -876,11 +890,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, Options::kPlatformOSX); + opts.setArchitecture(CPU_TYPE_I386, CPU_SUBTYPE_X86_ALL, ld::kPlatform_macOS, 0); #elif __x86_64__ - opts.setArchitecture(CPU_TYPE_X86_64, CPU_SUBTYPE_X86_64_ALL, Options::kPlatformOSX); + opts.setArchitecture(CPU_TYPE_X86_64, CPU_SUBTYPE_X86_64_ALL, ld::kPlatform_macOS, 0); #elif __arm__ - opts.setArchitecture(CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V6, Options::kPlatformOSX); + opts.setArchitecture(CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V6, ld::kPlatform_macOS, 0); #else #error unknown default architecture #endif @@ -1216,8 +1230,7 @@ void InputFiles::forEachInitialAtom(ld::File::AtomHandler& handler, ld::Internal { ld::relocatable::File* reloc = (ld::relocatable::File*)file; _options.snapshot().recordObjectFile(reloc->path()); - if ( _options.dumpDependencyInfo() ) - _options.dumpDependency(Options::depObjectFile, reloc->path()); + _options.addDependency(Options::depObjectFile, reloc->path()); } break; case ld::File::Dylib: @@ -1232,9 +1245,12 @@ void InputFiles::forEachInitialAtom(ld::File::AtomHandler& handler, ld::Internal // force loaded archives should be in LD_TRACE 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)); - if ( _options.dumpDependencyInfo() ) - _options.dumpDependency(Options::depArchive, archive->path()); + _options.addDependency(Options::depArchive, archive->path()); } break; case ld::File::Other: @@ -1245,8 +1261,15 @@ void InputFiles::forEachInitialAtom(ld::File::AtomHandler& handler, ld::Internal } 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); @@ -1477,8 +1500,16 @@ void InputFiles::dylibs(ld::Internal& state) state.bundleLoader = _bundleLoader; // give an error when -nostdlib is used and libSystem is missing - if ( (state.dylibs.size() == 0) && _options.needsEntryPointLoadCommand() ) - throw "dynamic main executables must link with libSystem.dylib"; + if ( (state.dylibs.size() == 0) && _options.needsEntryPointLoadCommand() ) { + // HACK until 39514191 is fixed + bool grandfather = false; + for (const File* inFile : _inputFiles) { + if ( strstr(inFile->path(), "exit-asm.o") != NULL ) + grandfather = true; + } + if ( !grandfather ) + throw "dynamic main executables must link with libSystem.dylib"; + } } void InputFiles::archives(ld::Internal& state)