X-Git-Url: https://git.saurik.com/apple/ld64.git/blobdiff_plain/b1f7435d66a93f03b77932b3a9ad8a83ce5e1ebc..9543cb2f21e50a417dc8cf37eb7173f353536979:/src/ld/Options.cpp diff --git a/src/ld/Options.cpp b/src/ld/Options.cpp index 543a348..057fad9 100644 --- a/src/ld/Options.cpp +++ b/src/ld/Options.cpp @@ -104,19 +104,24 @@ void throwf(const char* format, ...) throw t; } -bool Options::FileInfo::checkFileExists(const char *p) + +bool Options::FileInfo::checkFileExists(const Options& options, const char *p) { struct stat statBuffer; - if (p == NULL) p = path; + if (p == NULL) + p = path; if ( stat(p, &statBuffer) == 0 ) { if (p != path) path = strdup(p); fileLen = statBuffer.st_size; modTime = statBuffer.st_mtime; return true; } + if ( options.dumpDependencyInfo() ) + options.dumpDependency(Options::depNotFound, p); return false; } + Options::Options(int argc, const char* argv[]) : fOutputFile("a.out"), fArchitecture(0), fSubArchitecture(0), fArchitectureName("unknown"), fOutputKind(kDynamicExecutable), fHasPreferredSubType(false), fArchSupportsThumb2(false), fPrebind(false), fBindAtLoad(false), fKeepPrivateExterns(false), @@ -131,7 +136,7 @@ Options::Options(int argc, const char* argv[]) fClientName(NULL), fUmbrellaName(NULL), fInitFunctionName(NULL), fDotOutputFile(NULL), fExecutablePath(NULL), fBundleLoader(NULL), fDtraceScriptName(NULL), fSegAddrTablePath(NULL), fMapPath(NULL), - fDyldInstallPath("/usr/lib/dyld"), fTempLtoObjectPath(NULL), fOverridePathlibLTO(NULL), + fDyldInstallPath("/usr/lib/dyld"), fTempLtoObjectPath(NULL), fOverridePathlibLTO(NULL), fLtoCpu(NULL), fZeroPageSize(ULLONG_MAX), fStackSize(0), fStackAddr(0), fSourceVersion(0), fSDKVersion(0), fExecutableStack(false), fNonExecutableHeap(false), fDisableNonExecutableHeap(false), fMinimumHeaderPad(32), fSegmentAlignment(4096), @@ -167,9 +172,15 @@ Options::Options(int argc, const char* argv[]) fSourceVersionLoadCommand(false), fSourceVersionLoadCommandForceOn(false), fSourceVersionLoadCommandForceOff(false), fDependentDRInfo(false), fDependentDRInfoForcedOn(false), fDependentDRInfoForcedOff(false), + fTargetIOSSimulator(false), fExportDynamic(false), fAbsoluteSymbols(false), + fAllowSimulatorToLinkWithMacOSX(false), fKeepDwarfUnwind(true), + fKeepDwarfUnwindForcedOn(false), fKeepDwarfUnwindForcedOff(false), + fVerboseOptimizationHints(false), fIgnoreOptimizationHints(false), + fGenerateDtraceDOF(true), fAllowBranchIslands(true), fDebugInfoStripping(kDebugInfoMinimal), fTraceOutputFile(NULL), fMacVersionMin(ld::macVersionUnset), fIOSVersionMin(ld::iOSVersionUnset), - fSaveTempFiles(false), fSnapshotRequested(false), fPipelineFifo(NULL) + fSaveTempFiles(false), fSnapshotRequested(false), fPipelineFifo(NULL), + fDependencyInfoPath(NULL), fDependencyFileDescriptor(-1) { this->checkForClassic(argc, argv); this->parsePreCommandLineEnvironmentSettings(); @@ -177,10 +188,18 @@ Options::Options(int argc, const char* argv[]) this->parsePostCommandLineEnvironmentSettings(); this->reconfigureDefaults(); this->checkIllegalOptionCombinations(); + + if ( this->dumpDependencyInfo() ) { + this->dumpDependency(depOutputFile, fOutputFile); + if ( fMapPath != NULL ) + this->dumpDependency(depOutputFile, fMapPath); + } } Options::~Options() { + if ( fDependencyFileDescriptor != -1 ) + ::close(fDependencyFileDescriptor); } bool Options::errorBecauseOfWarnings() const @@ -246,7 +265,11 @@ bool Options::allGlobalsAreDeadStripRoots() const // switch ( fOutputKind ) { case Options::kDynamicExecutable: + // Add the -export_dynamic flag + return fExportDynamic; case Options::kStaticExecutable: + // Support the -export_dynamic flag for xnu + return fExportDynamic; case Options::kPreload: // by default unused globals in a main executable are stripped return false; @@ -276,7 +299,6 @@ const char* Options::executablePath() return fExecutablePath; } - uint32_t Options::initialSegProtection(const char* segName) const { for(std::vector::const_iterator it = fCustomSegmentProtections.begin(); it != fCustomSegmentProtections.end(); ++it) { @@ -404,7 +426,7 @@ void Options::loadSymbolOrderFile(const char* fileOfExports, NameToOrder& orderM ::close(fd); - // parse into symbols and add to hash_set + // parse into symbols and add to unordered_set unsigned int count = 0; char * const end = &p[stat_buf.st_size]; enum { lineStart, inSymbol, inComment } state = lineStart; @@ -478,6 +500,11 @@ bool Options::forceNotWeakNonWildcard(const char* symbolName) const return fForceNotWeakSymbols.containsNonWildcard(symbolName); } +bool Options::forceCoalesce(const char* symbolName) const +{ + return fForceCoalesceSymbols.contains(symbolName); +} + bool Options::shouldExport(const char* symbolName) const { @@ -533,27 +560,29 @@ void Options::setArchitecture(cpu_type_t type, cpu_subtype_t subtype) fMacVersionMin = ld::mac10_6; #endif } - if ( !fMakeCompressedDyldInfo && minOS(ld::mac10_6, ld::iOS_3_1) && !fMakeCompressedDyldInfoForceOff ) - fMakeCompressedDyldInfo = true; break; case CPU_TYPE_ARM: + case CPU_TYPE_ARM64: if ( (fMacVersionMin == ld::macVersionUnset) && (fIOSVersionMin == ld::iOSVersionUnset) && (fOutputKind != Options::kObjectFile) ) { #if defined(DEFAULT_IPHONEOS_MIN_VERSION) warning("-ios_version_min not specified, assuming " DEFAULT_IPHONEOS_MIN_VERSION); setIOSVersionMin(DEFAULT_IPHONEOS_MIN_VERSION); - #elif defined(DEFAULT_MACOSX_MIN_VERSION) - warning("-macosx_version_min not specified, assuming " DEFAULT_MACOSX_MIN_VERSION); - setMacOSXVersionMin(DEFAULT_MACOSX_MIN_VERSION); #else - warning("-macosx_version_min not specified, assuming 10.6"); - fMacVersionMin = ld::mac10_6; + warning("-ios_version_min not specified, assuming 6.0"); + setIOSVersionMin("6.0"); #endif } - if ( !fMakeCompressedDyldInfo && minOS(ld::mac10_6, ld::iOS_3_1) && !fMakeCompressedDyldInfoForceOff ) - fMakeCompressedDyldInfo = true; break; } fLinkSnapshot.recordArch(fArchitectureName); + // only use compressed LINKEDIT for: + // Mac OS X 10.6 or later + // iOS 3.1 or later + if ( !fMakeCompressedDyldInfo && minOS(ld::mac10_6, ld::iOS_3_1) && !fMakeCompressedDyldInfoForceOff ) + fMakeCompressedDyldInfo = true; + // Mac OS X 10.5 and iPhoneOS 2.0 support LC_REEXPORT_DYLIB + if ( minOS(ld::mac10_5, ld::iOS_2_0) ) + fUseSimplifiedDylibReExports = true; return; } } @@ -581,20 +610,20 @@ bool Options::checkForFile(const char* format, const char* dir, const char* root { char possiblePath[strlen(dir)+strlen(rootName)+strlen(format)+8]; sprintf(possiblePath, format, dir, rootName); - bool found = result.checkFileExists(possiblePath); + bool found = result.checkFileExists(*this, possiblePath); if ( fTraceDylibSearching ) printf("[Logging for XBS]%sfound library: '%s'\n", (found ? " " : " not "), possiblePath); return found; } -Options::FileInfo Options::findLibrary(const char* rootName, bool dylibsOnly) +Options::FileInfo Options::findLibrary(const char* rootName, bool dylibsOnly) const { FileInfo result; const int rootNameLen = strlen(rootName); // if rootName ends in .o there is no .a vs .dylib choice if ( (rootNameLen > 3) && (strcmp(&rootName[rootNameLen-2], ".o") == 0) ) { - for (std::vector::iterator it = fLibrarySearchPaths.begin(); + for (std::vector::const_iterator it = fLibrarySearchPaths.begin(); it != fLibrarySearchPaths.end(); it++) { const char* dir = *it; @@ -603,19 +632,33 @@ Options::FileInfo Options::findLibrary(const char* rootName, bool dylibsOnly) } } else { - bool lookForDylibs = ( fOutputKind != Options::kDyld); + bool lookForDylibs = false; + switch ( fOutputKind ) { + case Options::kDynamicExecutable: + case Options::kDynamicLibrary: + case Options::kDynamicBundle: + case Options::kObjectFile: // + lookForDylibs = true; + break; + case Options::kStaticExecutable: + case Options::kDyld: + case Options::kPreload: + case Options::kKextBundle: + lookForDylibs = false; + break; + } switch ( fLibrarySearchMode ) { case kSearchAllDirsForDylibsThenAllDirsForArchives: // first look in all directories for just for dylibs if ( lookForDylibs ) { - for (std::vector::iterator it = fLibrarySearchPaths.begin(); + for (std::vector::const_iterator it = fLibrarySearchPaths.begin(); it != fLibrarySearchPaths.end(); it++) { const char* dir = *it; if ( checkForFile("%s/lib%s.dylib", dir, rootName, result) ) return result; } - for (std::vector::iterator it = fLibrarySearchPaths.begin(); + for (std::vector::const_iterator it = fLibrarySearchPaths.begin(); it != fLibrarySearchPaths.end(); it++) { const char* dir = *it; @@ -625,7 +668,7 @@ Options::FileInfo Options::findLibrary(const char* rootName, bool dylibsOnly) } // next look in all directories for just for archives if ( !dylibsOnly ) { - for (std::vector::iterator it = fLibrarySearchPaths.begin(); + for (std::vector::const_iterator it = fLibrarySearchPaths.begin(); it != fLibrarySearchPaths.end(); it++) { const char* dir = *it; @@ -637,7 +680,7 @@ Options::FileInfo Options::findLibrary(const char* rootName, bool dylibsOnly) case kSearchDylibAndArchiveInEachDir: // look in each directory for just for a dylib then for an archive - for (std::vector::iterator it = fLibrarySearchPaths.begin(); + for (std::vector::const_iterator it = fLibrarySearchPaths.begin(); it != fLibrarySearchPaths.end(); it++) { const char* dir = *it; @@ -654,7 +697,7 @@ Options::FileInfo Options::findLibrary(const char* rootName, bool dylibsOnly) throwf("library not found for -l%s", rootName); } -Options::FileInfo Options::findFramework(const char* frameworkName) +Options::FileInfo Options::findFramework(const char* frameworkName) const { if ( frameworkName == NULL ) throw "-framework missing next argument"; @@ -670,9 +713,9 @@ Options::FileInfo Options::findFramework(const char* frameworkName) return findFramework(name, suffix); } -Options::FileInfo Options::findFramework(const char* rootName, const char* suffix) +Options::FileInfo Options::findFramework(const char* rootName, const char* suffix) const { - for (std::vector::iterator it = fFrameworkSearchPaths.begin(); + for (std::vector::const_iterator it = fFrameworkSearchPaths.begin(); it != fFrameworkSearchPaths.end(); it++) { // ??? Shouldn't we be using String here and just initializing it? @@ -693,7 +736,7 @@ Options::FileInfo Options::findFramework(const char* rootName, const char* suffi } } FileInfo result; - bool found = result.checkFileExists(possiblePath); + bool found = result.checkFileExists(*this, possiblePath); if ( fTraceDylibSearching ) printf("[Logging for XBS]%sfound framework: '%s'\n", (found ? " " : " not "), possiblePath); @@ -724,13 +767,13 @@ Options::FileInfo Options::findFile(const char* path) const if ( possiblePath[sdkPathDirLen-1] == '/' ) possiblePath[sdkPathDirLen-1] = '\0'; strcat(possiblePath, path); - if ( result.checkFileExists(possiblePath) ) { + if ( result.checkFileExists(*this, possiblePath) ) { return result; } } } // try raw path - if ( result.checkFileExists(path) ) { + if ( result.checkFileExists(*this, path) ) { return result; } @@ -743,7 +786,7 @@ Options::FileInfo Options::findFile(const char* path) const strcpy(&addPoint[1], &path[17]); else strcpy(newPath, &path[17]); - if ( result.checkFileExists(newPath) ) { + if ( result.checkFileExists(*this, newPath) ) { return result; } } @@ -815,7 +858,8 @@ Options::FileInfo Options::findFileUsingPaths(const char* path) const // If we didn't find it fall back to findFile. return findFile(path); } - + + void Options::parseSegAddrTable(const char* segAddrPath, const char* installPth) { @@ -886,12 +930,16 @@ void Options::loadFileList(const char* fileOfPaths, ld::File::Ordinal baseOrdina file = fopen(realFileOfPaths, "r"); if ( file == NULL ) throwf("-filelist file '%s' could not be opened, errno=%d (%s)\n", realFileOfPaths, errno, strerror(errno)); + if ( this->dumpDependencyInfo() ) + this->dumpDependency(Options::depFileList, realFileOfPaths); } } else { file = fopen(fileOfPaths, "r"); if ( file == NULL ) throwf("-filelist file '%s' could not be opened, errno=%d (%s)\n", fileOfPaths, errno, strerror(errno)); + if ( this->dumpDependencyInfo() ) + this->dumpDependency(Options::depFileList, fileOfPaths); } char path[PATH_MAX]; @@ -1064,9 +1112,12 @@ void Options::loadExportFile(const char* fileOfExports, const char* option, SetW if ( read(fd, p, stat_buf.st_size) != stat_buf.st_size ) throwf("can't read %s file: %s", option, fileOfExports); + if ( this->dumpDependencyInfo() ) + this->dumpDependency(Options::depMisc, fileOfExports); + ::close(fd); - // parse into symbols and add to hash_set + // parse into symbols and add to unordered_set char * const end = &p[stat_buf.st_size]; enum { lineStart, inSymbol, inComment } state = lineStart; char* symbolStart = NULL; @@ -1135,6 +1186,8 @@ void Options::parseAliasFile(const char* fileOfAliases) throwf("can't read alias file: %s", fileOfAliases); p[stat_buf.st_size] = '\n'; ::close(fd); + if ( this->dumpDependencyInfo() ) + this->dumpDependency(Options::depMisc, fileOfAliases); // parse into symbols and add to fAliases AliasPair pair; @@ -1248,7 +1301,14 @@ void Options::setMacOSXVersionMin(const char* version) throw "-macosx_version_min argument missing"; if ( (strncmp(version, "10.", 3) == 0) && isdigit(version[3]) ) { - unsigned int minorVersion = version[3] - '0'; + unsigned int minorVersion = 0; + for (int i=3; isdigit(version[i]); ++i) { + minorVersion = minorVersion*10 + (version[i] - '0'); + } + if ( minorVersion > 255 ) { + warning("Mac OS X minor version > 255 in '%s'", version); + minorVersion = 255; + } fMacVersionMin = (ld::MacVersionMin)(0x000A0000 | (minorVersion << 8)); } else { @@ -1533,6 +1593,8 @@ void Options::parseOrderFile(const char* path, bool cstring) throwf("can't read order file: %s", path); ::close(fd); p[stat_buf.st_size] = '\n'; + if ( this->dumpDependencyInfo() ) + this->dumpDependency(Options::depMisc, path); // parse into vector of pairs char * const end = &p[stat_buf.st_size+1]; @@ -1592,6 +1654,14 @@ void Options::parseOrderFile(const char* path, bool cstring) objFileName = symbolStart; symbolStart = &colon[3]; } + else { + colon = strstr(symbolStart, ".o):"); + if ( colon != NULL ) { + colon[3] = '\0'; + objFileName = symbolStart; + symbolStart = &colon[4]; + } + } // trim leading spaces while ( isspace(*symbolStart) ) ++symbolStart; @@ -1662,6 +1732,27 @@ void Options::addSection(const char* segment, const char* section, const char* p fExtraSections.push_back(info); } +void Options::addSectionRename(const char* srcSegment, const char* srcSection, const char* dstSegment, const char* dstSection) +{ + if ( strlen(srcSegment) > 16 ) + throw "-rename_section segment name max 16 chars"; + if ( strlen(srcSection) > 16 ) + throw "-rename_section section name max 16 chars"; + if ( strlen(dstSegment) > 16 ) + throw "-rename_section segment name max 16 chars"; + if ( strlen(dstSection) > 16 ) + throw "-rename_section section name max 16 chars"; + + SectionRename info; + info.fromSegment = srcSegment; + info.fromSection = srcSection; + info.toSegment = dstSegment; + info.toSection = dstSection; + + fSectionRenames.push_back(info); +} + + void Options::addSectionAlignment(const char* segment, const char* section, const char* alignmentStr) { if ( strlen(segment) > 16 ) @@ -2264,13 +2355,34 @@ void Options::parse(int argc, const char* argv[]) } // Use this flag to set default behavior for deployement targets. else if ( strcmp(arg, "-macosx_version_min") == 0 ) { - setMacOSXVersionMin(argv[++i]); + const char* macVers = argv[++i]; + const char* envMacVers = getenv("MACOSX_DEPLOYMENT_TARGET"); + const char* enviPhoneVers = getenv("IPHONEOS_DEPLOYMENT_TARGET"); + if ( (envMacVers != NULL) && (enviPhoneVers != NULL) ) { + // when conflicting deployments set, break tie by looking at syslibroot + warning("both MACOSX_DEPLOYMENT_TARGET and IPHONEOS_DEPLOYMENT_TARGET are set"); + if ( !fSDKPaths.empty() ) { + const char* sysrootPath = fSDKPaths.back(); + const char* lastSlash = strrchr(sysrootPath, '/'); + if ( strstr(lastSlash, "Simulator") != NULL ) + setIOSVersionMin(enviPhoneVers); + else + setMacOSXVersionMin(macVers); + } + else { + setMacOSXVersionMin(macVers); + } + } + else { + setMacOSXVersionMin(macVers); + } } else if ( (strcmp(arg, "-ios_version_min") == 0) || (strcmp(arg, "-iphoneos_version_min") == 0) ) { setIOSVersionMin(argv[++i]); } else if ( strcmp(arg, "-ios_simulator_version_min") == 0 ) { setIOSVersionMin(argv[++i]); + fTargetIOSSimulator = true; } else if ( strcmp(arg, "-multiply_defined") == 0 ) { //warnObsolete(arg); @@ -2495,18 +2607,6 @@ void Options::parse(int argc, const char* argv[]) snapshotFileArgIndex = 1; parseAliasFile(argv[++i]); } - // put this last so that it does not interfer with other options starting with 'i' - else if ( strncmp(arg, "-i", 2) == 0 ) { - const char* colon = strchr(arg, ':'); - if ( colon == NULL ) - throwf("unknown option: %s", arg); - Options::AliasPair pair; - char* temp = new char[colon-arg]; - strlcpy(temp, &arg[2], colon-arg-1); - pair.realName = &colon[1]; - pair.alias = temp; - fAliases.push_back(pair); - } else if ( strcmp(arg, "-save-temps") == 0 ) { fSaveTempFiles = true; } @@ -2603,6 +2703,12 @@ void Options::parse(int argc, const char* argv[]) throw "missing argument to -mllvm"; fLLVMOptions.push_back(opts); } + else if ( strcmp(arg, "-mcpu") == 0 ) { + const char* cpu = argv[++i]; + if ( cpu == NULL ) + throw "missing argument to -mcpu"; + fLtoCpu = cpu; + } else if ( strcmp(arg, "-no_order_inits") == 0 ) { fAutoOrderInitializers = false; } @@ -2755,6 +2861,14 @@ void Options::parse(int argc, const char* argv[]) else if (strcmp(arg, "-debug_snapshot") == 0) { fLinkSnapshot.setSnapshotMode(Snapshot::SNAPSHOT_DEBUG); fSnapshotRequested = true; + } + else if (strcmp(arg, "-snapshot_dir") == 0) { + const char* path = argv[++i]; + if ( path == NULL ) + throw "-snapshot_dir missing path"; + fLinkSnapshot.setSnapshotMode(Snapshot::SNAPSHOT_DEBUG); + fLinkSnapshot.setSnapshotPath(path); + fSnapshotRequested = true; } else if ( strcmp(arg, "-new_main") == 0 ) { fEntryPointLoadCommandForceOn = true; @@ -2789,6 +2903,80 @@ void Options::parse(int argc, const char* argv[]) else if ( strcmp(arg, "-kexts_use_stubs") == 0 ) { fKextsUseStubs = true; } + else if ( strcmp(argv[i], "-dependency_info") == 0 ) { + ++i; + // previously handled by buildSearchPaths() + } + else if ( strcmp(arg, "-export_dynamic") == 0 ) { + fExportDynamic = true; + } + else if ( strcmp(arg, "-force_symbols_coalesce_list") == 0 ) { + snapshotFileArgIndex = 1; + loadExportFile(argv[++i], "-force_symbols_coalesce_list", fForceCoalesceSymbols); + } + else if ( strcmp(arg, "-add_linker_option") == 0 ) { + // ex: -add_linker_option '-framework Foundation' + const char* optString = argv[++i]; + if ( optString == NULL ) + throw "-add_linker_option missing