X-Git-Url: https://git.saurik.com/apple/ld64.git/blobdiff_plain/a645023da60d22e86be13f7b4d97adeff8bc6665..b1f7435d66a93f03b77932b3a9ad8a83ce5e1ebc:/src/ld/Options.cpp diff --git a/src/ld/Options.cpp b/src/ld/Options.cpp index 1de3379..543a348 100644 --- a/src/ld/Options.cpp +++ b/src/ld/Options.cpp @@ -1,6 +1,6 @@ /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- * - * Copyright (c) 2005-2010 Apple Inc. All rights reserved. + * Copyright (c) 2005-2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -26,15 +26,21 @@ #include #include #include +#include #include #include +#include +#include +#include +#include +#include #include -#include "configure.h" #include "Options.h" #include "Architectures.hpp" #include "MachOFileAbstraction.hpp" +#include "Snapshot.h" // upward dependency on lto::version() namespace lto { @@ -43,16 +49,29 @@ namespace lto { // magic to place command line in crash reports const int crashreporterBufferSize = 2000; -extern "C" char* __crashreporter_info__; static char crashreporterBuffer[crashreporterBufferSize]; -char* __crashreporter_info__ = crashreporterBuffer; +#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070 + #include + // hack until ld does not need to build on 10.6 anymore + struct crashreporter_annotations_t gCRAnnotations + __attribute__((section("__DATA," CRASHREPORTER_ANNOTATIONS_SECTION))) + = { CRASHREPORTER_ANNOTATIONS_VERSION, 0, 0, 0, 0, 0, 0 }; +#else + extern "C" char* __crashreporter_info__; + __attribute__((used)) + char* __crashreporter_info__ = crashreporterBuffer; +#endif + static bool sEmitWarnings = true; +static bool sFatalWarnings = false; static const char* sWarningsSideFilePath = NULL; static FILE* sWarningsSideFile = NULL; +static int sWarningsCount = 0; void warning(const char* format, ...) { + ++sWarningsCount; if ( sEmitWarnings ) { va_list list; if ( sWarningsSideFilePath != NULL ) { @@ -85,9 +104,22 @@ void throwf(const char* format, ...) throw t; } +bool Options::FileInfo::checkFileExists(const char *p) +{ + struct stat statBuffer; + 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; + } + return false; +} + Options::Options(int argc, const char* argv[]) : fOutputFile("a.out"), fArchitecture(0), fSubArchitecture(0), fArchitectureName("unknown"), fOutputKind(kDynamicExecutable), - fHasPreferredSubType(false), fPrebind(false), fBindAtLoad(false), fKeepPrivateExterns(false), + 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"), @@ -99,8 +131,8 @@ 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), - fZeroPageSize(ULLONG_MAX), fStackSize(0), fStackAddr(0), fExecutableStack(false), + fDyldInstallPath("/usr/lib/dyld"), fTempLtoObjectPath(NULL), fOverridePathlibLTO(NULL), + fZeroPageSize(ULLONG_MAX), fStackSize(0), fStackAddr(0), fSourceVersion(0), fSDKVersion(0), fExecutableStack(false), fNonExecutableHeap(false), fDisableNonExecutableHeap(false), fMinimumHeaderPad(32), fSegmentAlignment(4096), fCommonsMode(kCommonsIgnoreDylibs), fUUIDMode(kUUIDContent), fLocalSymbolHandling(kLocalSymbolsAll), fWarnCommons(false), @@ -109,7 +141,7 @@ Options::Options(int argc, const char* argv[]) fSharedRegionEligible(false), fPrintOrderFileStatistics(false), fReadOnlyx86Stubs(false), fPositionIndependentExecutable(false), fPIEOnCommandLine(false), fDisablePositionIndependentExecutable(false), fMaxMinimumHeaderPad(false), - fDeadStripDylibs(false), fAllowTextRelocs(false), fWarnTextRelocs(false), + fDeadStripDylibs(false), fAllowTextRelocs(false), fWarnTextRelocs(false), fKextsUseStubs(false), fUsingLazyDylibLinking(false), fEncryptable(true), fOrderData(true), fMarkDeadStrippableDylib(false), fMakeCompressedDyldInfo(true), fMakeCompressedDyldInfoForceOff(false), fNoEHLabels(false), @@ -120,20 +152,24 @@ Options::Options(int argc, const char* argv[]) fForDyld(false), fMakeTentativeDefinitionsReal(false), fWhyLoad(false), fRootSafe(false), fSetuidSafe(false), fImplicitlyLinkPublicDylibs(true), fAddCompactUnwindEncoding(true), fWarnCompactUnwind(false), fRemoveDwarfUnwindIfCompactExists(false), - fAutoOrderInitializers(true), fOptimizeZeroFill(true), fLogObjectFiles(false), + fAutoOrderInitializers(true), fOptimizeZeroFill(true), fMergeZeroFill(false), fLogObjectFiles(false), fLogAllFiles(false), fTraceDylibs(false), fTraceIndirectDylibs(false), fTraceArchives(false), fOutputSlidable(false), fWarnWeakExports(false), fObjcGcCompaction(false), fObjCGc(false), fObjCGcOnly(false), fDemangle(false), fTLVSupport(false), -#if __MAC_OS_X_VERSION_MIN_REQUIRED < 1070 - fVersionLoadCommand(false), fFunctionStartsLoadCommand(false), -#else - fVersionLoadCommand(true), fFunctionStartsLoadCommand(true), -#endif - fCanReExportSymbols(false), fObjcCategoryMerging(true), + fVersionLoadCommand(false), fVersionLoadCommandForcedOn(false), + fVersionLoadCommandForcedOff(false), fFunctionStartsLoadCommand(false), + fFunctionStartsForcedOn(false), fFunctionStartsForcedOff(false), + fDataInCodeInfoLoadCommand(false), fDataInCodeInfoLoadCommandForcedOn(false), fDataInCodeInfoLoadCommandForcedOff(false), + fCanReExportSymbols(false), fObjcCategoryMerging(true), fPageAlignDataAtoms(false), + fNeedsThreadLoadCommand(false), fEntryPointLoadCommand(false), + fEntryPointLoadCommandForceOn(false), fEntryPointLoadCommandForceOff(false), + fSourceVersionLoadCommand(false), + fSourceVersionLoadCommandForceOn(false), fSourceVersionLoadCommandForceOff(false), + fDependentDRInfo(false), fDependentDRInfoForcedOn(false), fDependentDRInfoForcedOff(false), fDebugInfoStripping(kDebugInfoMinimal), fTraceOutputFile(NULL), - fMacVersionMin(ld::macVersionUnset), fIPhoneVersionMin(ld::iPhoneVersionUnset), - fSaveTempFiles(false) + fMacVersionMin(ld::macVersionUnset), fIOSVersionMin(ld::iOSVersionUnset), + fSaveTempFiles(false), fSnapshotRequested(false), fPipelineFifo(NULL) { this->checkForClassic(argc, argv); this->parsePreCommandLineEnvironmentSettings(); @@ -147,7 +183,10 @@ Options::~Options() { } - +bool Options::errorBecauseOfWarnings() const +{ + return (sFatalWarnings && (sWarningsCount > 0)); +} const char* Options::installPath() const @@ -175,8 +214,6 @@ bool Options::interposable(const char* name) const } - - bool Options::printWhyLive(const char* symbolName) const { return ( fWhyLive.find(symbolName) != fWhyLive.end() ); @@ -264,7 +301,8 @@ uint32_t Options::initialSegProtection(const char* segName) const uint32_t Options::maxSegProtection(const char* segName) const { // iPhoneOS always uses same protection for max and initial - if ( fIPhoneVersionMin != ld::iPhoneVersionUnset ) + // simulator apps need to use MacOSX max-prot + if ( (fIOSVersionMin != ld::iOSVersionUnset) && (fArchitecture != CPU_TYPE_I386) ) return initialSegProtection(segName); for(std::vector::const_iterator it = fCustomSegmentProtections.begin(); it != fCustomSegmentProtections.end(); ++it) { @@ -474,218 +512,79 @@ bool Options::keepLocalSymbol(const char* symbolName) const throw "internal error"; } - void Options::setArchitecture(cpu_type_t type, cpu_subtype_t subtype) { - fArchitecture = type; - fSubArchitecture = subtype; - switch ( type ) { - case CPU_TYPE_POWERPC: - switch ( subtype ) { - case CPU_SUBTYPE_POWERPC_750: - fArchitectureName = "ppc750"; - fHasPreferredSubType = true; - break; - case CPU_SUBTYPE_POWERPC_7400: - fArchitectureName = "ppc7400"; - fHasPreferredSubType = true; - break; - case CPU_SUBTYPE_POWERPC_7450: - fArchitectureName = "ppc7450"; - fHasPreferredSubType = true; - break; - case CPU_SUBTYPE_POWERPC_970: - fArchitectureName = "ppc970"; - fHasPreferredSubType = true; - break; - case CPU_SUBTYPE_POWERPC_ALL: - fArchitectureName = "ppc"; - fHasPreferredSubType = false; - break; - default: - assert(0 && "unknown ppc subtype"); - fArchitectureName = "ppc"; - break; - } - if ( (fMacVersionMin == ld::macVersionUnset) && (fOutputKind != Options::kObjectFile) ) { - #ifdef DEFAULT_MACOSX_MIN_VERSION - warning("-macosx_version_min not specificed, assuming " DEFAULT_MACOSX_MIN_VERSION); - setMacOSXVersionMin(DEFAULT_MACOSX_MIN_VERSION); - #else - warning("-macosx_version_min not specificed, assuming 10.6"); - fMacVersionMin = ld::mac10_6; - #endif - } - break; - case CPU_TYPE_POWERPC64: - fArchitectureName = "ppc64"; - if ( (fMacVersionMin == ld::macVersionUnset) && (fOutputKind != Options::kObjectFile) ) { - warning("-macosx_version_min not specificed, assuming 10.5"); - fMacVersionMin = ld::mac10_5; - } - break; - case CPU_TYPE_I386: - fArchitectureName = "i386"; - if ( (fMacVersionMin == ld::macVersionUnset) && (fOutputKind != Options::kObjectFile) ) { - #ifdef DEFAULT_MACOSX_MIN_VERSION - warning("-macosx_version_min not specificed, assuming " DEFAULT_MACOSX_MIN_VERSION); - setMacOSXVersionMin(DEFAULT_MACOSX_MIN_VERSION); - #else - warning("-macosx_version_min not specificed, assuming 10.6"); - fMacVersionMin = ld::mac10_6; - #endif - } - if ( !fMakeCompressedDyldInfo && (fMacVersionMin >= ld::mac10_6) && !fMakeCompressedDyldInfoForceOff ) - fMakeCompressedDyldInfo = true; - break; - case CPU_TYPE_X86_64: - fArchitectureName = "x86_64"; - if ( (fMacVersionMin == ld::macVersionUnset) && (fOutputKind != Options::kObjectFile) ) { - #ifdef DEFAULT_MACOSX_MIN_VERSION - warning("-macosx_version_min not specificed, assuming " DEFAULT_MACOSX_MIN_VERSION); - setMacOSXVersionMin(DEFAULT_MACOSX_MIN_VERSION); - #else - warning("-macosx_version_min not specificed, assuming 10.6"); - fMacVersionMin = ld::mac10_6; - #endif - } - if ( !fMakeCompressedDyldInfo && (fMacVersionMin >= ld::mac10_6) && !fMakeCompressedDyldInfoForceOff ) - fMakeCompressedDyldInfo = true; - break; - case CPU_TYPE_ARM: - switch ( subtype ) { - case CPU_SUBTYPE_ARM_V4T: - fArchitectureName = "armv4t"; - fHasPreferredSubType = true; - break; - case CPU_SUBTYPE_ARM_V5TEJ: - fArchitectureName = "armv5"; - fHasPreferredSubType = true; - break; - case CPU_SUBTYPE_ARM_V6: - fArchitectureName = "armv6"; - fHasPreferredSubType = true; - break; - case CPU_SUBTYPE_ARM_V7: - fArchitectureName = "armv7"; - fHasPreferredSubType = true; - break; - default: - assert(0 && "unknown arm subtype"); - fArchitectureName = "arm"; - break; - } - if ( (fMacVersionMin == ld::macVersionUnset) && (fIPhoneVersionMin == ld::iPhoneVersionUnset) && (fOutputKind != Options::kObjectFile) ) { -#if defined(DEFAULT_IPHONEOS_MIN_VERSION) - warning("-ios_version_min not specificed, assuming " DEFAULT_IPHONEOS_MIN_VERSION); - setIPhoneVersionMin(DEFAULT_IPHONEOS_MIN_VERSION); -#elif defined(DEFAULT_MACOSX_MIN_VERSION) - warning("-macosx_version_min not specificed, assuming " DEFAULT_MACOSX_MIN_VERSION); - setMacOSXVersionMin(DEFAULT_MACOSX_MIN_VERSION); -#else - warning("-macosx_version_min not specificed, assuming 10.6"); - fMacVersionMin = ld::mac10_6; -#endif + for (const ArchInfo* t=archInfoArray; t->archName != NULL; ++t) { + if ( (type == t->cpuType) && (subtype == t->cpuSubType) ) { + fArchitecture = type; + fSubArchitecture = subtype; + fArchitectureName = t->archName; + fHasPreferredSubType = t->isSubType; + fArchSupportsThumb2 = t->supportsThumb2; + switch ( type ) { + case CPU_TYPE_I386: + case CPU_TYPE_X86_64: + if ( (fMacVersionMin == ld::macVersionUnset) && (fIOSVersionMin == ld::iOSVersionUnset) && (fOutputKind != Options::kObjectFile) ) { + #ifdef 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; + #endif + } + if ( !fMakeCompressedDyldInfo && minOS(ld::mac10_6, ld::iOS_3_1) && !fMakeCompressedDyldInfoForceOff ) + fMakeCompressedDyldInfo = true; + break; + case CPU_TYPE_ARM: + 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; + #endif + } + if ( !fMakeCompressedDyldInfo && minOS(ld::mac10_6, ld::iOS_3_1) && !fMakeCompressedDyldInfoForceOff ) + fMakeCompressedDyldInfo = true; + break; + } + fLinkSnapshot.recordArch(fArchitectureName); + return; } - if ( !fMakeCompressedDyldInfo && minOS(ld::mac10_6, ld::iPhone3_1) && !fMakeCompressedDyldInfoForceOff ) - fMakeCompressedDyldInfo = true; - break; - default: - fArchitectureName = "unknown architecture"; - break; } + fArchitectureName = "unknown architecture"; } void Options::parseArch(const char* arch) { if ( arch == NULL ) throw "-arch must be followed by an architecture string"; - fArchitectureName = arch; - if ( strcmp(arch, "ppc") == 0 ) { - fArchitecture = CPU_TYPE_POWERPC; - fSubArchitecture = CPU_SUBTYPE_POWERPC_ALL; - } - else if ( strcmp(arch, "ppc64") == 0 ) { - fArchitecture = CPU_TYPE_POWERPC64; - fSubArchitecture = CPU_SUBTYPE_POWERPC_ALL; - } - else if ( strcmp(arch, "i386") == 0 ) { - fArchitecture = CPU_TYPE_I386; - fSubArchitecture = CPU_SUBTYPE_I386_ALL; - } - else if ( strcmp(arch, "x86_64") == 0 ) { - fArchitecture = CPU_TYPE_X86_64; - fSubArchitecture = CPU_SUBTYPE_X86_64_ALL; - } - else if ( strcmp(arch, "arm") == 0 ) { - fArchitecture = CPU_TYPE_ARM; - fSubArchitecture = CPU_SUBTYPE_ARM_ALL; - } - // compatibility support for cpu-sub-types - else if ( strcmp(arch, "ppc750") == 0 ) { - fArchitecture = CPU_TYPE_POWERPC; - fSubArchitecture = CPU_SUBTYPE_POWERPC_750; - fHasPreferredSubType = true; - } - else if ( strcmp(arch, "ppc7400") == 0 ) { - fArchitecture = CPU_TYPE_POWERPC; - fSubArchitecture = CPU_SUBTYPE_POWERPC_7400; - fHasPreferredSubType = true; - } - else if ( strcmp(arch, "ppc7450") == 0 ) { - fArchitecture = CPU_TYPE_POWERPC; - fSubArchitecture = CPU_SUBTYPE_POWERPC_7450; - fHasPreferredSubType = true; - } - else if ( strcmp(arch, "ppc970") == 0 ) { - fArchitecture = CPU_TYPE_POWERPC; - fSubArchitecture = CPU_SUBTYPE_POWERPC_970; - fHasPreferredSubType = true; - } - else if ( strcmp(arch, "armv6") == 0 ) { - fArchitecture = CPU_TYPE_ARM; - fSubArchitecture = CPU_SUBTYPE_ARM_V6; - fHasPreferredSubType = true; - } - else if ( strcmp(arch, "armv5") == 0 ) { - fArchitecture = CPU_TYPE_ARM; - fSubArchitecture = CPU_SUBTYPE_ARM_V5TEJ; - fHasPreferredSubType = true; - } - else if ( strcmp(arch, "armv4t") == 0 ) { - fArchitecture = CPU_TYPE_ARM; - fSubArchitecture = CPU_SUBTYPE_ARM_V4T; - fHasPreferredSubType = true; - } - else if ( strcmp(arch, "xscale") == 0 ) { - fArchitecture = CPU_TYPE_ARM; - fSubArchitecture = CPU_SUBTYPE_ARM_XSCALE; - fHasPreferredSubType = true; - } - else if ( strcmp(arch, "armv7") == 0 ) { - fArchitecture = CPU_TYPE_ARM; - fSubArchitecture = CPU_SUBTYPE_ARM_V7; - fHasPreferredSubType = true; + for (const ArchInfo* t=archInfoArray; t->archName != NULL; ++t) { + if ( strcmp(t->archName,arch) == 0 ) { + fArchitectureName = arch; + fArchitecture = t->cpuType; + fSubArchitecture = t->cpuSubType; + fHasPreferredSubType = t->isSubType; + fArchSupportsThumb2 = t->supportsThumb2; + return; + } } - else - throwf("unknown/unsupported architecture name for: -arch %s", arch); + throwf("unknown/unsupported architecture name for: -arch %s", arch); } bool Options::checkForFile(const char* format, const char* dir, const char* rootName, FileInfo& result) const { - struct stat statBuffer; char possiblePath[strlen(dir)+strlen(rootName)+strlen(format)+8]; sprintf(possiblePath, format, dir, rootName); - bool found = (stat(possiblePath, &statBuffer) == 0); + bool found = result.checkFileExists(possiblePath); if ( fTraceDylibSearching ) printf("[Logging for XBS]%sfound library: '%s'\n", (found ? " " : " not "), possiblePath); - if ( found ) { - result.path = strdup(possiblePath); - result.fileLen = statBuffer.st_size; - result.modTime = statBuffer.st_mtime; - return true; - } - return false; + return found; } @@ -773,7 +672,6 @@ Options::FileInfo Options::findFramework(const char* frameworkName) Options::FileInfo Options::findFramework(const char* rootName, const char* suffix) { - struct stat statBuffer; for (std::vector::iterator it = fFrameworkSearchPaths.begin(); it != fFrameworkSearchPaths.end(); it++) { @@ -794,15 +692,12 @@ Options::FileInfo Options::findFramework(const char* rootName, const char* suffi strcat(possiblePath, suffix); } } - bool found = (stat(possiblePath, &statBuffer) == 0); + FileInfo result; + bool found = result.checkFileExists(possiblePath); if ( fTraceDylibSearching ) printf("[Logging for XBS]%sfound framework: '%s'\n", (found ? " " : " not "), possiblePath); if ( found ) { - FileInfo result; - result.path = strdup(possiblePath); - result.fileLen = statBuffer.st_size; - result.modTime = statBuffer.st_mtime; return result; } } @@ -816,7 +711,6 @@ Options::FileInfo Options::findFramework(const char* rootName, const char* suffi Options::FileInfo Options::findFile(const char* path) const { FileInfo result; - struct stat statBuffer; // if absolute path and not a .o file, the use SDK prefix if ( (path[0] == '/') && (strcmp(&path[strlen(path)-2], ".o") != 0) ) { @@ -830,19 +724,13 @@ Options::FileInfo Options::findFile(const char* path) const if ( possiblePath[sdkPathDirLen-1] == '/' ) possiblePath[sdkPathDirLen-1] = '\0'; strcat(possiblePath, path); - if ( stat(possiblePath, &statBuffer) == 0 ) { - result.path = strdup(possiblePath); - result.fileLen = statBuffer.st_size; - result.modTime = statBuffer.st_mtime; + if ( result.checkFileExists(possiblePath) ) { return result; } } } // try raw path - if ( stat(path, &statBuffer) == 0 ) { - result.path = strdup(path); - result.fileLen = statBuffer.st_size; - result.modTime = statBuffer.st_mtime; + if ( result.checkFileExists(path) ) { return result; } @@ -855,10 +743,7 @@ Options::FileInfo Options::findFile(const char* path) const strcpy(&addPoint[1], &path[17]); else strcpy(newPath, &path[17]); - if ( stat(newPath, &statBuffer) == 0 ) { - result.path = strdup(newPath); - result.fileLen = statBuffer.st_size; - result.modTime = statBuffer.st_mtime; + if ( result.checkFileExists(newPath) ) { return result; } } @@ -984,7 +869,7 @@ void Options::parseSegAddrTable(const char* segAddrPath, const char* installPth) fclose(file); } -void Options::loadFileList(const char* fileOfPaths) +void Options::loadFileList(const char* fileOfPaths, ld::File::Ordinal baseOrdinal) { FILE* file; const char* comma = strrchr(fileOfPaths, ','); @@ -1000,16 +885,17 @@ void Options::loadFileList(const char* fileOfPaths) realFileOfPaths[realFileOfPathsLen] = '\0'; file = fopen(realFileOfPaths, "r"); if ( file == NULL ) - throwf("-filelist file not found: %s\n", realFileOfPaths); + throwf("-filelist file '%s' could not be opened, errno=%d (%s)\n", realFileOfPaths, errno, strerror(errno)); } } else { file = fopen(fileOfPaths, "r"); if ( file == NULL ) - throwf("-filelist file not found: %s\n", fileOfPaths); + throwf("-filelist file '%s' could not be opened, errno=%d (%s)\n", fileOfPaths, errno, strerror(errno)); } char path[PATH_MAX]; + ld::File::Ordinal previousOrdinal = baseOrdinal; while ( fgets(path, PATH_MAX, file) != NULL ) { path[PATH_MAX-1] = '\0'; char* eol = strchr(path, '\n'); @@ -1020,10 +906,34 @@ void Options::loadFileList(const char* fileOfPaths) strcpy(builtPath, prefix); strcat(builtPath, "/"); strcat(builtPath, path); - fInputFiles.push_back(findFile(builtPath)); + if (fPipelineFifo != NULL) { + FileInfo info = FileInfo(builtPath); + info.ordinal = previousOrdinal.nextFileListOrdinal(); + previousOrdinal = info.ordinal; + info.fromFileList = true; + fInputFiles.push_back(info); + } else { + FileInfo info = findFile(builtPath); + info.ordinal = previousOrdinal.nextFileListOrdinal(); + previousOrdinal = info.ordinal; + info.fromFileList = true; + fInputFiles.push_back(info); + } } else { - fInputFiles.push_back(findFile(path)); + if (fPipelineFifo != NULL) { + FileInfo info = FileInfo(path); + info.ordinal = previousOrdinal.nextFileListOrdinal(); + previousOrdinal = info.ordinal; + info.fromFileList = true; + fInputFiles.push_back(info); + } else { + FileInfo info = findFile(path); + info.ordinal = previousOrdinal.nextFileListOrdinal(); + previousOrdinal = info.ordinal; + info.fromFileList = true; + fInputFiles.push_back(info); + } } } fclose(file); @@ -1346,7 +1256,7 @@ void Options::setMacOSXVersionMin(const char* version) } } -void Options::setIPhoneVersionMin(const char* version) +void Options::setIOSVersionMin(const char* version) { if ( version == NULL ) throw "-ios_version_min argument missing"; @@ -1359,16 +1269,16 @@ void Options::setIPhoneVersionMin(const char* version) unsigned int majorVersion = version[0] - '0'; unsigned int minorVersion = version[2] - '0'; - fIPhoneVersionMin = (ld::IPhoneVersionMin)((majorVersion << 16) | (minorVersion << 8)); + fIOSVersionMin = (ld::IOSVersionMin)((majorVersion << 16) | (minorVersion << 8)); } -bool Options::minOS(ld::MacVersionMin requiredMacMin, ld::IPhoneVersionMin requirediPhoneOSMin) +bool Options::minOS(ld::MacVersionMin requiredMacMin, ld::IOSVersionMin requirediPhoneOSMin) { if ( fMacVersionMin != ld::macVersionUnset ) { return ( fMacVersionMin >= requiredMacMin ); } else { - return ( fIPhoneVersionMin >= requirediPhoneOSMin); + return ( fIOSVersionMin >= requirediPhoneOSMin); } } @@ -1451,16 +1361,67 @@ uint32_t Options::parseProtection(const char* prot) } +// +// Parses number of form A[.B[.B[.D[.E]]]] into a uint64_t where the bits are a24.b10.c10.d10.e10 +// +uint64_t Options::parseVersionNumber64(const char* versionString) +{ + uint64_t a = 0; + uint64_t b = 0; + uint64_t c = 0; + uint64_t d = 0; + uint64_t e = 0; + char* end; + a = strtoul(versionString, &end, 10); + if ( *end == '.' ) { + b = strtoul(&end[1], &end, 10); + if ( *end == '.' ) { + c = strtoul(&end[1], &end, 10); + if ( *end == '.' ) { + d = strtoul(&end[1], &end, 10); + if ( *end == '.' ) { + e = strtoul(&end[1], &end, 10); + } + } + } + } + if ( (*end != '\0') || (a > 0xFFFFFF) || (b > 0x3FF) || (c > 0x3FF) || (d > 0x3FF) || (e > 0x3FF) ) + throwf("malformed 64-bit a.b.c.d.e version number: %s", versionString); + + return (a << 40) | ( b << 30 ) | ( c << 20 ) | ( d << 10 ) | e; +} + + +uint32_t Options::currentVersion32() const +{ + // warn if it does not fit into 32 bit vers number + uint32_t a = (fDylibCurrentVersion >> 40) & 0xFFFF; + uint32_t b = (fDylibCurrentVersion >> 30) & 0xFF; + uint32_t c = (fDylibCurrentVersion >> 20) & 0xFF; + uint64_t rep32 = ((uint64_t)a << 40) | ((uint64_t)b << 30) | ((uint64_t)c << 20); + if ( rep32 != fDylibCurrentVersion ) { + warning("truncating -current_version to fit in 32-bit space used by old mach-o format"); + a = (fDylibCurrentVersion >> 40) & 0xFFFFFF; + if ( a > 0xFFFF ) + a = 0xFFFF; + b = (fDylibCurrentVersion >> 30) & 0x3FF; + if ( b > 0xFF ) + b = 0xFF; + c = (fDylibCurrentVersion >> 20) & 0x3FF; + if ( c > 0xFF ) + c = 0xFF; + } + return (a << 16) | ( b << 8 ) | c; +} // // Parses number of form X[.Y[.Z]] into a uint32_t where the nibbles are xxxx.yy.zz // -// -uint32_t Options::parseVersionNumber(const char* versionString) +uint32_t Options::parseVersionNumber32(const char* versionString) { - unsigned long x = 0; - unsigned long y = 0; - unsigned long z = 0; + uint32_t x = 0; + uint32_t y = 0; + uint32_t z = 0; char* end; x = strtoul(versionString, &end, 10); if ( *end == '.' ) { @@ -1470,7 +1431,7 @@ uint32_t Options::parseVersionNumber(const char* versionString) } } if ( (*end != '\0') || (x > 0xffff) || (y > 0xff) || (z > 0xff) ) - throwf("malformed version number: %s", versionString); + throwf("malformed 32-bit x.y.z version number: %s", versionString); return (x << 16) | ( y << 8 ) | z; } @@ -1598,18 +1559,12 @@ void Options::parseOrderFile(const char* path, bool cstring) *last = '\0'; --last; } + // if there is an architecture prefix, only use this symbol it if matches current arch if ( strncmp(symbolStart, "ppc:", 4) == 0 ) { - if ( fArchitecture == CPU_TYPE_POWERPC ) - symbolStart = &symbolStart[4]; - else - symbolStart = NULL; + symbolStart = NULL; } - // if there is an architecture prefix, only use this symbol it if matches current arch else if ( strncmp(symbolStart, "ppc64:", 6) == 0 ) { - if ( fArchitecture == CPU_TYPE_POWERPC64 ) - symbolStart = &symbolStart[6]; - else - symbolStart = NULL; + symbolStart = NULL; } else if ( strncmp(symbolStart, "i386:", 5) == 0 ) { if ( fArchitecture == CPU_TYPE_I386 ) @@ -1773,6 +1728,9 @@ void Options::warnObsolete(const char* arg) // void Options::parse(int argc, const char* argv[]) { + // Store the original args in the link snapshot. + fLinkSnapshot.recordRawArgs(argc, argv); + // pass one builds search list from -L and -F options this->buildSearchPaths(argc, argv); @@ -1784,12 +1742,17 @@ void Options::parse(int argc, const char* argv[]) const char* arg = argv[i]; if ( arg[0] == '-' ) { + // by default, copy one arg to the snapshot link command, and do no file copying + int snapshotArgIndex = i; + int snapshotArgCount = -1; // -1 means compute count based on change in index + int snapshotFileArgIndex = -1; // -1 means no data file parameter to arg // Since we don't care about the files passed, just the option names, we do this here. if (fPrintOptions) fprintf (stderr, "[Logging ld64 options]\t%s\n", arg); if ( (arg[1] == 'L') || (arg[1] == 'F') ) { + snapshotArgCount = 0; // stripped out of link snapshot if (arg[2] == '\0') ++i; // previously handled by buildSearchPaths() @@ -1836,22 +1799,38 @@ void Options::parse(int argc, const char* argv[]) fOutputKind = kKextBundle; } else if ( strcmp(arg, "-o") == 0 ) { + snapshotArgCount = 0; fOutputFile = argv[++i]; + fLinkSnapshot.setSnapshotName(fOutputFile); } else if ( strncmp(arg, "-lazy-l", 7) == 0 ) { + snapshotArgCount = 0; FileInfo info = findLibrary(&arg[7], true); info.options.fLazyLoad = true; + info.ordinal = ld::File::Ordinal::makeArgOrdinal((uint16_t)i); addLibrary(info); fUsingLazyDylibLinking = true; } + else if ( strcmp(arg, "-lto_library") == 0 ) { + snapshotFileArgIndex = 1; + fOverridePathlibLTO = argv[++i]; + if ( fOverridePathlibLTO == NULL ) + throw "missing argument to -lto_library"; + } else if ( (arg[1] == 'l') && (strncmp(arg,"-lazy_",6) !=0) ) { - addLibrary(findLibrary(&arg[2])); + snapshotArgCount = 0; + FileInfo info = findLibrary(&arg[2]); + info.ordinal = ld::File::Ordinal::makeArgOrdinal((uint16_t)i); + addLibrary(info); } // This causes a dylib to be weakly bound at // link time. This corresponds to weak_import. else if ( strncmp(arg, "-weak-l", 7) == 0 ) { + // SNAPSHOT FIXME: what should we do for link snapshots? (ignore for now) + snapshotArgCount = 0; FileInfo info = findLibrary(&arg[7]); info.options.fWeakImport = true; + info.ordinal = ld::File::Ordinal::makeArgOrdinal((uint16_t)i); addLibrary(info); } // Avoid lazy binding. @@ -1885,6 +1864,7 @@ void Options::parse(int argc, const char* argv[]) else if ( strcmp(arg, "-force_load") == 0 ) { FileInfo info = findFile(argv[++i]); info.options.fForceLoad = true; + info.ordinal = ld::File::Ordinal::makeArgOrdinal((uint16_t)i); addLibrary(info); } // Library versioning. @@ -1893,22 +1873,24 @@ void Options::parse(int argc, const char* argv[]) const char* vers = argv[++i]; if ( vers == NULL ) throw "-dylib_compatibility_version missing "; - fDylibCompatVersion = parseVersionNumber(vers); + fDylibCompatVersion = parseVersionNumber32(vers); } else if ( (strcmp(arg, "-dylib_current_version") == 0) || (strcmp(arg, "-current_version") == 0)) { const char* vers = argv[++i]; if ( vers == NULL ) throw "-dylib_current_version missing "; - fDylibCurrentVersion = parseVersionNumber(vers); + fDylibCurrentVersion = parseVersionNumber64(vers); } else if ( strcmp(arg, "-sectorder") == 0 ) { if ( (argv[i+1]==NULL) || (argv[i+2]==NULL) || (argv[i+3]==NULL) ) throw "-sectorder missing
"; + snapshotFileArgIndex = 3; parseSectionOrderFile(argv[i+1], argv[i+2], argv[i+3]); i += 3; } else if ( strcmp(arg, "-order_file") == 0 ) { + snapshotFileArgIndex = 1; parseOrderFile(argv[++i], false); } else if ( strcmp(arg, "-order_file_statistics") == 0 ) { @@ -1919,6 +1901,7 @@ void Options::parse(int argc, const char* argv[]) else if ( (strcmp(arg, "-sectcreate") == 0) || (strcmp(arg, "-segcreate") == 0) ) { if ( (argv[i+1]==NULL) || (argv[i+2]==NULL) || (argv[i+3]==NULL) ) throw "-sectcreate missing
"; + snapshotFileArgIndex = 3; addSection(argv[i+1], argv[i+2], argv[i+3]); i += 3; } @@ -1927,7 +1910,7 @@ void Options::parse(int argc, const char* argv[]) || (strcmp(arg, "-dylinker_install_name") == 0) || (strcmp(arg, "-install_name") == 0)) { fDylibInstallName = argv[++i]; - if ( fDylibInstallName == NULL ) + if ( fDylibInstallName == NULL ) throw "-install_name missing "; } // Sets the base address of the output. @@ -1947,10 +1930,12 @@ void Options::parse(int argc, const char* argv[]) } // Same as -@ from the FSF linker. else if ( strcmp(arg, "-filelist") == 0 ) { + snapshotArgCount = 0; const char* path = argv[++i]; if ( (path == NULL) || (path[0] == '-') ) throw "-filelist missing "; - loadFileList(path); + ld::File::Ordinal baseOrdinal = ld::File::Ordinal::makeArgOrdinal((uint16_t)i); + loadFileList(path, baseOrdinal); } else if ( strcmp(arg, "-keep_private_externs") == 0 ) { fKeepPrivateExterns = true; @@ -1972,6 +1957,7 @@ void Options::parse(int argc, const char* argv[]) } } else if ( strcmp(arg, "-interposable_list") == 0 ) { + snapshotFileArgIndex = 1; fInterposeMode = kInterposeSome; loadExportFile(argv[++i], "-interposable_list", fInterposeList); } @@ -1980,12 +1966,14 @@ void Options::parse(int argc, const char* argv[]) fInterposeMode = kInterposeNone; } else if ( strcmp(arg, "-exported_symbols_list") == 0 ) { + snapshotFileArgIndex = 1; if ( fExportMode == kDontExportSome ) throw "can't use -exported_symbols_list and -unexported_symbols_list"; fExportMode = kExportSome; loadExportFile(argv[++i], "-exported_symbols_list", fExportSymbols); } else if ( strcmp(arg, "-unexported_symbols_list") == 0 ) { + snapshotFileArgIndex = 1; if ( fExportMode == kExportSome ) throw "can't use -unexported_symbols_list and -exported_symbols_list"; fExportMode = kDontExportSome; @@ -2004,12 +1992,14 @@ void Options::parse(int argc, const char* argv[]) fDontExportSymbols.insert(argv[++i]); } else if ( strcmp(arg, "-non_global_symbols_no_strip_list") == 0 ) { + snapshotFileArgIndex = 1; if ( fLocalSymbolHandling == kLocalSymbolsSelectiveExclude ) throw "can't use -non_global_symbols_no_strip_list and -non_global_symbols_strip_list"; fLocalSymbolHandling = kLocalSymbolsSelectiveInclude; loadExportFile(argv[++i], "-non_global_symbols_no_strip_list", fLocalSymbolsIncluded); } else if ( strcmp(arg, "-non_global_symbols_strip_list") == 0 ) { + snapshotFileArgIndex = 1; if ( fLocalSymbolHandling == kLocalSymbolsSelectiveInclude ) throw "can't use -non_global_symbols_no_strip_list and -non_global_symbols_strip_list"; fLocalSymbolHandling = kLocalSymbolsSelectiveExclude; @@ -2020,31 +2010,47 @@ void Options::parse(int argc, const char* argv[]) fIgnoreOtherArchFiles = true; } else if ( strcmp(arg, "-force_cpusubtype_ALL") == 0 ) { - fForceSubtypeAll = true; + fForceSubtypeAll = true; + fAllowCpuSubtypeMismatches = true; } // Similar to -weak-l but uses the absolute path name to the library. else if ( strcmp(arg, "-weak_library") == 0 ) { + // SNAPSHOT FIXME: what should we do for link snapshots? (ignore for now) + snapshotArgCount = 0; FileInfo info = findFile(argv[++i]); info.options.fWeakImport = true; + info.ordinal = ld::File::Ordinal::makeArgOrdinal((uint16_t)i); addLibrary(info); } else if ( strcmp(arg, "-lazy_library") == 0 ) { + // SNAPSHOT FIXME: what should we do for link snapshots? (ignore for now) + snapshotArgCount = 0; FileInfo info = findFile(argv[++i]); info.options.fLazyLoad = true; + info.ordinal = ld::File::Ordinal::makeArgOrdinal((uint16_t)i); addLibrary(info); fUsingLazyDylibLinking = true; } else if ( strcmp(arg, "-framework") == 0 ) { - addLibrary(findFramework(argv[++i])); + snapshotArgCount = 0; + FileInfo info = findFramework(argv[++i]); + info.ordinal = ld::File::Ordinal::makeArgOrdinal((uint16_t)i); + addLibrary(info); } else if ( strcmp(arg, "-weak_framework") == 0 ) { + // SNAPSHOT FIXME: what should we do for link snapshots? (ignore for now) + snapshotArgCount = 0; FileInfo info = findFramework(argv[++i]); info.options.fWeakImport = true; + info.ordinal = ld::File::Ordinal::makeArgOrdinal((uint16_t)i); addLibrary(info); } else if ( strcmp(arg, "-lazy_framework") == 0 ) { + // SNAPSHOT FIXME: what should we do for link snapshots? (ignore for now) + snapshotArgCount = 0; FileInfo info = findFramework(argv[++i]); info.options.fLazyLoad = true; + info.ordinal = ld::File::Ordinal::makeArgOrdinal((uint16_t)i); addLibrary(info); fUsingLazyDylibLinking = true; } @@ -2055,7 +2061,7 @@ void Options::parse(int argc, const char* argv[]) // previously handled by buildSearchPaths() } else if ( strcmp(arg, "-undefined") == 0 ) { - setUndefinedTreatment(argv[++i]); + setUndefinedTreatment(argv[++i]); } // Debugging output flag. else if ( strcmp(arg, "-arch_multiple") == 0 ) { @@ -2091,7 +2097,7 @@ void Options::parse(int argc, const char* argv[]) // Warn, error or make strong a mismatch between weak // and non-weak references. else if ( strcmp(arg, "-weak_reference_mismatches") == 0 ) { - setWeakReferenceMismatchTreatment(argv[++i]); + setWeakReferenceMismatchTreatment(argv[++i]); } // For a deployment target of 10.3 and earlier ld64 will // prebind an executable with 0s in all addresses that @@ -2119,6 +2125,8 @@ void Options::parse(int argc, const char* argv[]) // This should probably be deprecated when we respect -L and -F // when searching for libraries. else if ( strcmp(arg, "-dylib_file") == 0 ) { + // ignore for snapshot because a stub dylib will be created in the snapshot + snapshotArgCount = 0; addDylibOverride(argv[++i]); } // What to expand @executable_path to if found in dependent dylibs @@ -2159,9 +2167,9 @@ void Options::parse(int argc, const char* argv[]) if ( (seg.name == NULL) || (argv[i+1] == NULL) ) throw "-segaddr missing segName Adddress"; seg.address = parseAddress(argv[++i]); - uint64_t temp = seg.address & (-4096); // page align - if ( (seg.address != temp) ) - warning("-segaddr %s not page aligned, rounding down", seg.name); + uint64_t temp = ((seg.address+fSegmentAlignment-1) & (-fSegmentAlignment)); + if ( seg.address != temp ) + warning("-segaddr %s not %lld byte aligned", seg.name, fSegmentAlignment); fCustomSegmentAddresses.push_back(seg); } // ??? Deprecate when we deprecate split-seg. @@ -2175,6 +2183,7 @@ void Options::parse(int argc, const char* argv[]) } // ??? Deprecate when we get rid of basing at build time. else if ( strcmp(arg, "-seg_addr_table") == 0 ) { + snapshotFileArgIndex = 1; const char* name = argv[++i]; if ( name == NULL ) throw "-seg_addr_table missing argument"; @@ -2238,10 +2247,12 @@ void Options::parse(int argc, const char* argv[]) i += 2; } else if ( strcmp(arg, "-bundle_loader") == 0 ) { + snapshotFileArgIndex = 1; fBundleLoader = argv[++i]; if ( (fBundleLoader == NULL) || (fBundleLoader[0] == '-') ) throw "-bundle_loader missing "; FileInfo info = findFile(fBundleLoader); + info.ordinal = ld::File::Ordinal::makeArgOrdinal((uint16_t)i); info.options.fBundleLoader = true; fInputFiles.push_back(info); } @@ -2255,8 +2266,11 @@ void Options::parse(int argc, const char* argv[]) else if ( strcmp(arg, "-macosx_version_min") == 0 ) { setMacOSXVersionMin(argv[++i]); } - else if ( (strcmp(arg, "-iphoneos_version_min") == 0) || (strcmp(arg, "-ios_version_min") == 0) ) { - setIPhoneVersionMin(argv[++i]); + 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]); } else if ( strcmp(arg, "-multiply_defined") == 0 ) { //warnObsolete(arg); @@ -2342,6 +2356,9 @@ void Options::parse(int argc, const char* argv[]) else if ( strcmp(arg, "-w") == 0 ) { // previously handled by buildSearchPaths() } + else if ( strcmp(arg, "-fatal_warnings") == 0 ) { + // previously handled by buildSearchPaths() + } else if ( strcmp(arg, "-arch_errors_fatal") == 0 ) { fErrorOnOtherArchFiles = true; } @@ -2441,6 +2458,7 @@ void Options::parse(int argc, const char* argv[]) // previously handled by buildSearchPaths() } else if ( strcmp(arg, "-syslibroot") == 0 ) { + snapshotArgCount = 0; ++i; // previously handled by buildSearchPaths() } @@ -2451,6 +2469,7 @@ void Options::parse(int argc, const char* argv[]) fUUIDMode = kUUIDRandom; } else if ( strcmp(arg, "-dtrace") == 0 ) { + snapshotFileArgIndex = 1; const char* name = argv[++i]; if ( name == NULL ) throw "-dtrace missing argument"; @@ -2473,6 +2492,7 @@ void Options::parse(int argc, const char* argv[]) fAliases.push_back(pair); } else if ( strcmp(arg, "-alias_list") == 0 ) { + snapshotFileArgIndex = 1; parseAliasFile(argv[++i]); } // put this last so that it does not interfer with other options starting with 'i' @@ -2515,33 +2535,51 @@ void Options::parse(int argc, const char* argv[]) fDisablePositionIndependentExecutable = true; } else if ( strncmp(arg, "-reexport-l", 11) == 0 ) { + // SNAPSHOT FIXME: what should we do for link snapshots? (ignore for now) + snapshotArgCount = 0; FileInfo info = findLibrary(&arg[11], true); info.options.fReExport = true; + info.ordinal = ld::File::Ordinal::makeArgOrdinal((uint16_t)i); addLibrary(info); } else if ( strcmp(arg, "-reexport_library") == 0 ) { + // SNAPSHOT FIXME: what should we do for link snapshots? (ignore for now) + snapshotArgCount = 0; FileInfo info = findFile(argv[++i]); info.options.fReExport = true; + info.ordinal = ld::File::Ordinal::makeArgOrdinal((uint16_t)i); addLibrary(info); } else if ( strcmp(arg, "-reexport_framework") == 0 ) { + // SNAPSHOT FIXME: what should we do for link snapshots? (ignore for now) + snapshotArgCount = 0; FileInfo info = findFramework(argv[++i]); info.options.fReExport = true; + info.ordinal = ld::File::Ordinal::makeArgOrdinal((uint16_t)i); addLibrary(info); } else if ( strncmp(arg, "-upward-l", 9) == 0 ) { + // SNAPSHOT FIXME: what should we do for link snapshots? (ignore for now) + snapshotArgCount = 0; FileInfo info = findLibrary(&arg[9], true); info.options.fUpward = true; + info.ordinal = ld::File::Ordinal::makeArgOrdinal((uint16_t)i); addLibrary(info); } else if ( strcmp(arg, "-upward_library") == 0 ) { + // SNAPSHOT FIXME: what should we do for link snapshots? (ignore for now) + snapshotArgCount = 0; FileInfo info = findFile(argv[++i]); info.options.fUpward = true; + info.ordinal = ld::File::Ordinal::makeArgOrdinal((uint16_t)i); addLibrary(info); } else if ( strcmp(arg, "-upward_framework") == 0 ) { + // SNAPSHOT FIXME: what should we do for link snapshots? (ignore for now) + snapshotArgCount = 0; FileInfo info = findFramework(argv[++i]); info.options.fUpward = true; + info.ordinal = ld::File::Ordinal::makeArgOrdinal((uint16_t)i); addLibrary(info); } else if ( strcmp(arg, "-dead_strip_dylibs") == 0 ) { @@ -2586,11 +2624,11 @@ void Options::parse(int argc, const char* argv[]) fMarkDeadStrippableDylib = true; } else if ( strcmp(arg, "-exported_symbols_order") == 0 ) { + snapshotFileArgIndex = 1; loadSymbolOrderFile(argv[++i], fExportSymbolsOrder); } else if ( strcmp(arg, "-no_compact_linkedit") == 0 ) { - fMakeCompressedDyldInfo = false; - fMakeCompressedDyldInfoForceOff = true; + warnObsolete("-no_compact_linkedit"); } else if ( strcmp(arg, "-no_eh_labels") == 0 ) { fNoEHLabels = true; @@ -2604,6 +2642,9 @@ void Options::parse(int argc, const char* argv[]) else if ( strcmp(arg, "-no_zero_fill_sections") == 0 ) { fOptimizeZeroFill = false; } + else if ( strcmp(arg, "-merge_zero_fill_sections") == 0 ) { + fMergeZeroFill = true; + } else if ( strcmp(arg, "-objc_abi_version") == 0 ) { const char* version = argv[++i]; if ( version == NULL ) @@ -2643,16 +2684,28 @@ void Options::parse(int argc, const char* argv[]) fDemangle = true; } else if ( strcmp(arg, "-version_load_command") == 0 ) { - fVersionLoadCommand = true; + fVersionLoadCommandForcedOn = true; + fVersionLoadCommandForcedOff = false; } else if ( strcmp(arg, "-no_version_load_command") == 0 ) { - fVersionLoadCommand = false; + fVersionLoadCommandForcedOff = true; + fVersionLoadCommandForcedOn = false; } else if ( strcmp(arg, "-function_starts") == 0 ) { - fFunctionStartsLoadCommand = true; + fFunctionStartsForcedOn = true; + fFunctionStartsForcedOff = false; } else if ( strcmp(arg, "-no_function_starts") == 0 ) { - fFunctionStartsLoadCommand = false; + fFunctionStartsForcedOff = true; + fFunctionStartsForcedOn = false; + } + else if ( strcmp(arg, "-no_data_in_code_info") == 0 ) { + fDataInCodeInfoLoadCommandForcedOff = true; + fDataInCodeInfoLoadCommandForcedOn = false; + } + else if ( strcmp(arg, "-data_in_code_info") == 0 ) { + fDataInCodeInfoLoadCommandForcedOn = true; + fDataInCodeInfoLoadCommandForcedOff = false; } else if ( strcmp(arg, "-object_path_lto") == 0 ) { fTempLtoObjectPath = argv[++i]; @@ -2663,9 +2716,11 @@ void Options::parse(int argc, const char* argv[]) fObjcCategoryMerging = false; } else if ( strcmp(arg, "-force_symbols_weak_list") == 0 ) { + snapshotFileArgIndex = 1; loadExportFile(argv[++i], "-force_symbols_weak_list", fForceWeakSymbols); } else if ( strcmp(arg, "-force_symbols_not_weak_list") == 0 ) { + snapshotFileArgIndex = 1; loadExportFile(argv[++i], "-force_symbols_not_weak_list", fForceNotWeakSymbols); } else if ( strcmp(arg, "-force_symbol_weak") == 0 ) { @@ -2681,6 +2736,7 @@ void Options::parse(int argc, const char* argv[]) fForceNotWeakSymbols.insert(symbol); } else if ( strcmp(arg, "-reexported_symbols_list") == 0 ) { + snapshotFileArgIndex = 1; if ( fExportMode == kExportSome ) throw "can't use -exported_symbols_list and -reexported_symbols_list"; loadExportFile(argv[++i], "-reexported_symbols_list", fReExportSymbols); @@ -2693,12 +2749,58 @@ void Options::parse(int argc, const char* argv[]) throw "-dyld_env missing ENV=VALUE"; fDyldEnvironExtras.push_back(envarg); } + else if ( strcmp(arg, "-page_align_data_atoms") == 0 ) { + fPageAlignDataAtoms = true; + } + else if (strcmp(arg, "-debug_snapshot") == 0) { + fLinkSnapshot.setSnapshotMode(Snapshot::SNAPSHOT_DEBUG); + fSnapshotRequested = true; + } + else if ( strcmp(arg, "-new_main") == 0 ) { + fEntryPointLoadCommandForceOn = true; + } + else if ( strcmp(arg, "-no_new_main") == 0 ) { + fEntryPointLoadCommandForceOff = true; + } + else if ( strcmp(arg, "-source_version") == 0 ) { + const char* vers = argv[++i]; + if ( vers == NULL ) + throw "-source_version missing "; + fSourceVersion = parseVersionNumber64(vers); + } + else if ( strcmp(arg, "-add_source_version") == 0 ) { + fSourceVersionLoadCommandForceOn = true; + } + else if ( strcmp(arg, "-no_source_version") == 0 ) { + fSourceVersionLoadCommandForceOff = true; + } + else if ( strcmp(arg, "-sdk_version") == 0 ) { + const char* vers = argv[++i]; + if ( vers == NULL ) + throw "-sdk_version missing "; + fSDKVersion = parseVersionNumber32(vers); + } + else if ( strcmp(arg, "-dependent_dr_info") == 0 ) { + fDependentDRInfoForcedOn = true; + } + else if ( strcmp(arg, "-no_dependent_dr_info") == 0 ) { + fDependentDRInfoForcedOff = true; + } + else if ( strcmp(arg, "-kexts_use_stubs") == 0 ) { + fKextsUseStubs = true; + } else { throwf("unknown option: %s", arg); } + + if (snapshotArgCount == -1) + snapshotArgCount = i-snapshotArgIndex+1; + if (snapshotArgCount > 0) + fLinkSnapshot.addSnapshotLinkArg(snapshotArgIndex, snapshotArgCount, snapshotFileArgIndex); } else { FileInfo info = findFile(arg); + info.ordinal = ld::File::Ordinal::makeArgOrdinal((uint16_t)i); if ( strcmp(&info.path[strlen(info.path)-2], ".a") == 0 ) addLibrary(info); else @@ -2708,8 +2810,13 @@ void Options::parse(int argc, const char* argv[]) // if a -lazy option was used, implicitly link in lazydylib1.o if ( fUsingLazyDylibLinking ) { - addLibrary(findLibrary("lazydylib1.o")); + FileInfo info = findLibrary("lazydylib1.o"); + info.ordinal = ld::File::Ordinal::makeArgOrdinal((uint16_t)argc); + addLibrary(info); } + + if (fSnapshotRequested) + fLinkSnapshot.createSnapshot(); } @@ -2784,11 +2891,12 @@ void Options::buildSearchPaths(int argc, const char* argv[]) fVerbose = true; extern const char ldVersionString[]; fprintf(stderr, "%s", ldVersionString); + fprintf(stderr, "configured to support archs: %s\n", ALL_SUPPORTED_ARCHS); // if only -v specified, exit cleanly if ( argc == 2 ) { const char* ltoVers = lto::version(); if ( ltoVers != NULL ) - fprintf(stderr, "%s\n", ltoVers); + fprintf(stderr, "LTO support using: %s\n", ltoVers); exit(0); } } @@ -2807,6 +2915,9 @@ void Options::buildSearchPaths(int argc, const char* argv[]) else if ( strcmp(argv[i], "-w") == 0 ) { sEmitWarnings = false; } + else if ( strcmp(argv[i], "-fatal_warnings") == 0 ) { + sFatalWarnings = true; + } } int standardLibraryPathsStartIndex = libraryPaths.size(); int standardFrameworkPathsStartIndex = frameworkPaths.size(); @@ -2954,17 +3065,24 @@ void Options::parsePreCommandLineEnvironmentSettings() if (getenv("LD_ALLOW_CPU_SUBTYPE_MISMATCHES") != NULL) fAllowCpuSubtypeMismatches = true; - // for now disable compressed linkedit functionality - if ( getenv("LD_NO_COMPACT_LINKEDIT") != NULL ) { - fMakeCompressedDyldInfo = false; - fMakeCompressedDyldInfoForceOff = true; - } - sWarningsSideFilePath = getenv("LD_WARN_FILE"); const char* customDyldPath = getenv("LD_DYLD_PATH"); if ( customDyldPath != NULL ) fDyldInstallPath = customDyldPath; + + const char* debugArchivePath = getenv("LD_DEBUG_SNAPSHOT"); + if (debugArchivePath != NULL) { + fLinkSnapshot.setSnapshotMode(Snapshot::SNAPSHOT_DEBUG); + if (strlen(debugArchivePath) > 0) + fLinkSnapshot.setSnapshotPath(debugArchivePath); + fSnapshotRequested = true; + } + + const char* pipeFdString = getenv("LD_PIPELINE_FIFO"); + if (pipeFdString != NULL) { + fPipelineFifo = pipeFdString; + } } @@ -3007,6 +3125,13 @@ void Options::parsePostCommandLineEnvironmentSettings() // allow build system to force on -warn_commons if ( getenv("LD_WARN_COMMONS") != NULL ) fWarnCommons = true; + + // allow B&I to set default -source_version + if ( fSourceVersion == 0 ) { + const char* vers = getenv("RC_ProjectSourceVersion"); + if ( vers != NULL ) + fSourceVersion = parseVersionNumber64(vers); + } } @@ -3039,29 +3164,31 @@ void Options::reconfigureDefaults() // set default min OS version if ( (fMacVersionMin == ld::macVersionUnset) - && (fIPhoneVersionMin == ld::iPhoneVersionUnset) ) { + && (fIOSVersionMin == ld::iOSVersionUnset) ) { // if neither -macosx_version_min nor -iphoneos_version_min used, try environment variables const char* macVers = getenv("MACOSX_DEPLOYMENT_TARGET"); const char* iPhoneVers = getenv("IPHONEOS_DEPLOYMENT_TARGET"); const char* iOSVers = getenv("IOS_DEPLOYMENT_TARGET"); + const char* iOSSimulatorVers = getenv("IOS_SIMULATOR_DEPLOYMENT_TARGET"); if ( macVers != NULL ) setMacOSXVersionMin(macVers); else if ( iPhoneVers != NULL ) - setIPhoneVersionMin(iPhoneVers); + setIOSVersionMin(iPhoneVers); else if ( iOSVers != NULL ) - setIPhoneVersionMin(iOSVers); + setIOSVersionMin(iOSVers); + else if ( iOSSimulatorVers != NULL ) + setIOSVersionMin(iOSSimulatorVers); else { // if still nothing, set default based on architecture switch ( fArchitecture ) { case CPU_TYPE_I386: case CPU_TYPE_X86_64: - case CPU_TYPE_POWERPC: if ( (fOutputKind != Options::kObjectFile) && (fOutputKind != Options::kPreload) ) { #ifdef DEFAULT_MACOSX_MIN_VERSION - warning("-macosx_version_min not specificed, assuming " 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 specificed, assuming 10.6"); + warning("-macosx_version_min not specified, assuming 10.6"); fMacVersionMin = ld::mac10_6; #endif } @@ -3069,13 +3196,13 @@ void Options::reconfigureDefaults() case CPU_TYPE_ARM: if ( (fOutputKind != Options::kObjectFile) && (fOutputKind != Options::kPreload) ) { #if defined(DEFAULT_IPHONEOS_MIN_VERSION) - warning("-ios_version_min not specificed, assuming " DEFAULT_IPHONEOS_MIN_VERSION); - setIPhoneVersionMin(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 specificed, assuming " 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 specificed, assuming 10.6"); + warning("-macosx_version_min not specified, assuming 10.6"); fMacVersionMin = ld::mac10_6; #endif } @@ -3091,19 +3218,13 @@ void Options::reconfigureDefaults() // adjust min based on architecture switch ( fArchitecture ) { case CPU_TYPE_I386: - if ( (fMacVersionMin < ld::mac10_4) && (fIPhoneVersionMin == ld::iPhoneVersionUnset) ) { + if ( (fMacVersionMin < ld::mac10_4) && (fIOSVersionMin == ld::iOSVersionUnset) ) { //warning("-macosx_version_min should be 10.4 or later for i386"); fMacVersionMin = ld::mac10_4; } break; - case CPU_TYPE_POWERPC64: - if ( fMacVersionMin < ld::mac10_4 ) { - //warning("-macosx_version_min should be 10.4 or later for ppc64"); - fMacVersionMin = ld::mac10_4; - } - break; case CPU_TYPE_X86_64: - if ( fMacVersionMin < ld::mac10_4 ) { + if ( (fMacVersionMin < ld::mac10_4) && (fIOSVersionMin == ld::iOSVersionUnset) ) { //warning("-macosx_version_min should be 10.4 or later for x86_64"); fMacVersionMin = ld::mac10_4; } @@ -3120,9 +3241,19 @@ void Options::reconfigureDefaults() fAllowTextRelocs = true; fUndefinedTreatment = kUndefinedDynamicLookup; break; - case CPU_TYPE_POWERPC: - case CPU_TYPE_I386: case CPU_TYPE_ARM: + if ( fIOSVersionMin >= ld::iOS_5_0 ) { + // iOS 5.0 and later use new MH_KEXT_BUNDLE type + fMakeCompressedDyldInfo = false; + fMakeCompressedDyldInfoForceOff = true; + // kexts are PIC in iOS 6.0 and later + fAllowTextRelocs = (fIOSVersionMin < ld::iOS_6_0); + fKextsUseStubs = !fAllowTextRelocs; + fUndefinedTreatment = kUndefinedDynamicLookup; + break; + } + // else use object file + case CPU_TYPE_I386: // use .o files fOutputKind = kObjectFile; break; @@ -3131,7 +3262,7 @@ void Options::reconfigureDefaults() // disable implicit dylibs when targeting 10.3 // add option to disable implicit load commands for indirectly used public dylibs - if ( !minOS(ld::mac10_4, ld::iPhone2_0) ) + if ( !minOS(ld::mac10_4, ld::iOS_2_0) ) fImplicitlyLinkPublicDylibs = false; @@ -3164,9 +3295,8 @@ void Options::reconfigureDefaults() // split segs only allowed for dylibs if ( fSplitSegs ) { - // split seg only supported for ppc, i386, and arm. + // split seg only supported for i386, and arm. switch ( fArchitecture ) { - case CPU_TYPE_POWERPC: case CPU_TYPE_I386: if ( fOutputKind != Options::kDynamicLibrary ) fSplitSegs = false; @@ -3193,11 +3323,9 @@ void Options::reconfigureDefaults() // set too-large size switch ( fArchitecture ) { - case CPU_TYPE_POWERPC: case CPU_TYPE_I386: fMaxAddress = 0xFFFFFFFF; break; - case CPU_TYPE_POWERPC64: case CPU_TYPE_X86_64: break; case CPU_TYPE_ARM: @@ -3231,7 +3359,6 @@ void Options::reconfigureDefaults() // disable prebinding depending on arch and min OS version if ( fPrebind ) { switch ( fArchitecture ) { - case CPU_TYPE_POWERPC: case CPU_TYPE_I386: if ( fMacVersionMin == ld::mac10_4 ) { // in 10.4 only split seg dylibs are prebound @@ -3242,6 +3369,10 @@ void Options::reconfigureDefaults() // in 10.5 nothing is prebound fPrebind = false; } + else if ( fIOSVersionMin != ld::iOSVersionUnset ) { + // nothing in simulator is prebound + fPrebind = false; + } else { // in 10.3 and earlier only dylibs and main executables could be prebound switch ( fOutputKind ) { @@ -3261,7 +3392,6 @@ void Options::reconfigureDefaults() } } break; - case CPU_TYPE_POWERPC64: case CPU_TYPE_X86_64: fPrebind = false; break; @@ -3291,21 +3421,23 @@ void Options::reconfigureDefaults() // determine if info for shared region should be added if ( fOutputKind == Options::kDynamicLibrary ) { - if ( minOS(ld::mac10_5, ld::iPhone3_1) ) + if ( minOS(ld::mac10_5, ld::iOS_3_1) ) if ( !fPrebind ) if ( (strncmp(this->installPath(), "/usr/lib/", 9) == 0) || (strncmp(this->installPath(), "/System/Library/", 16) == 0) ) fSharedRegionEligible = true; } - + else if ( fOutputKind == Options::kDyld ) { + // Enable dyld to be put into the dyld shared cache + fSharedRegionEligible = true; + } + // figure out if module table is needed for compatibility with old ld/dyld if ( fOutputKind == Options::kDynamicLibrary ) { switch ( fArchitecture ) { - case CPU_TYPE_POWERPC: // 10.3 and earlier dyld requires a module table - case CPU_TYPE_I386: // ld_classic for 10.4.x requires a module table - if ( fMacVersionMin <= ld::mac10_5 ) - fNeedsModuleTable = true; - break; + case CPU_TYPE_I386: + if ( fIOSVersionMin != ld::iOSVersionUnset ) // simulator never needs modules + break; case CPU_TYPE_ARM: if ( fPrebind ) fNeedsModuleTable = true; // redo_prebinding requires a module table @@ -3337,8 +3469,6 @@ void Options::reconfigureDefaults() break; } break; - case CPU_TYPE_POWERPC: - case CPU_TYPE_POWERPC64: case CPU_TYPE_ARM: fAddCompactUnwindEncoding = false; fRemoveDwarfUnwindIfCompactExists = false; @@ -3395,27 +3525,14 @@ void Options::reconfigureDefaults() // only use compressed LINKEDIT for: - // x86_64 and i386 on Mac OS X 10.6 or later - // arm on iPhoneOS 3.1 or later + // Mac OS X 10.6 or later + // iOS 3.1 or later if ( fMakeCompressedDyldInfo ) { - switch (fArchitecture) { - case CPU_TYPE_I386: - case CPU_TYPE_X86_64: - if ( fMacVersionMin < ld::mac10_6 ) - fMakeCompressedDyldInfo = false; - break; - case CPU_TYPE_ARM: - if ( !minOS(ld::mac10_6, ld::iPhone3_1) ) - fMakeCompressedDyldInfo = false; - break; - case CPU_TYPE_POWERPC: - case CPU_TYPE_POWERPC64: - default: - fMakeCompressedDyldInfo = false; - } + if ( !minOS(ld::mac10_6, ld::iOS_3_1) ) + fMakeCompressedDyldInfo = false; } - + // only ARM enforces that cpu-sub-types must match if ( fArchitecture != CPU_TYPE_ARM ) fAllowCpuSubtypeMismatches = true; @@ -3446,23 +3563,25 @@ void Options::reconfigureDefaults() } // Mac OS X 10.5 and iPhoneOS 2.0 support LC_REEXPORT_DYLIB - if ( minOS(ld::mac10_5, ld::iPhone2_0) ) + if ( minOS(ld::mac10_5, ld::iOS_2_0) ) fUseSimplifiedDylibReExports = true; // Mac OS X 10.7 and iOS 4.2 support LC_LOAD_UPWARD_DYLIB - if ( minOS(ld::mac10_7, ld::iPhone4_2) && (fOutputKind == kDynamicLibrary) ) + if ( minOS(ld::mac10_7, ld::iOS_4_2) && (fOutputKind == kDynamicLibrary) ) fCanUseUpwardDylib = true; - // x86_64 for MacOSX 10.7 defaults to PIE - if ( (fArchitecture == CPU_TYPE_X86_64) && (fOutputKind == kDynamicExecutable) && (fMacVersionMin >= ld::mac10_7) ) { - fPositionIndependentExecutable = true; + // MacOSX 10.7 defaults to PIE + if ( ((fArchitecture == CPU_TYPE_X86_64) || (fArchitecture == CPU_TYPE_I386)) + && (fOutputKind == kDynamicExecutable) + && (fMacVersionMin >= ld::mac10_7) ) { + fPositionIndependentExecutable = true; } // armv7 for iOS4.3 defaults to PIE if ( (fArchitecture == CPU_TYPE_ARM) - && (fSubArchitecture == CPU_SUBTYPE_ARM_V7) + && fArchSupportsThumb2 && (fOutputKind == kDynamicExecutable) - && (fIPhoneVersionMin >= ld::iPhone4_3) ) { + && (fIOSVersionMin >= ld::iOS_4_3) ) { fPositionIndependentExecutable = true; } @@ -3473,9 +3592,9 @@ void Options::reconfigureDefaults() // set fOutputSlidable switch ( fOutputKind ) { case Options::kObjectFile: - case Options::kStaticExecutable: fOutputSlidable = false; break; + case Options::kStaticExecutable: case Options::kDynamicExecutable: fOutputSlidable = fPositionIndependentExecutable; break; @@ -3495,24 +3614,57 @@ void Options::reconfigureDefaults() fTLVSupport = true; } - // version load command is only in some kinds of output files + // default to adding version load command for dynamic code, static code must opt-in switch ( fOutputKind ) { case Options::kObjectFile: + fVersionLoadCommand = false; + break; case Options::kStaticExecutable: case Options::kPreload: case Options::kKextBundle: - fVersionLoadCommand = false; - fFunctionStartsLoadCommand = false; + if ( fVersionLoadCommandForcedOn ) + fVersionLoadCommand = true; break; case Options::kDynamicExecutable: case Options::kDyld: case Options::kDynamicLibrary: case Options::kDynamicBundle: + if ( !fVersionLoadCommandForcedOff ) + fVersionLoadCommand = true; + // for now, don't create version load commands for iOS simulator builds + if ( fVersionLoadCommand && (fArchitecture == CPU_TYPE_I386) ) { + for (std::vector::iterator sdkit = fSDKPaths.begin(); sdkit != fSDKPaths.end(); sdkit++) { + if ( strstr(*sdkit, "/iPhoneSimulator.platform/") != NULL ) + fVersionLoadCommand = false; + } + } break; } + // default to adding functions start for dynamic code, static code must opt-in + switch ( fOutputKind ) { + case Options::kPreload: + case Options::kStaticExecutable: + case Options::kKextBundle: + if ( fDataInCodeInfoLoadCommandForcedOn ) + fDataInCodeInfoLoadCommand = true; + if ( fFunctionStartsForcedOn ) + fFunctionStartsLoadCommand = true; + break; + case Options::kObjectFile: + case Options::kDynamicExecutable: + case Options::kDyld: + case Options::kDynamicLibrary: + case Options::kDynamicBundle: + if ( !fDataInCodeInfoLoadCommandForcedOff ) + fDataInCodeInfoLoadCommand = true; + if ( !fFunctionStartsForcedOff ) + fFunctionStartsLoadCommand = true; + break; + } + // support re-export of individual symbols in MacOSX 10.7 and iOS 4.2 - if ( (fOutputKind == kDynamicLibrary) && minOS(ld::mac10_7, ld::iPhone4_2) ) + if ( (fOutputKind == kDynamicLibrary) && minOS(ld::mac10_7, ld::iOS_4_2) ) fCanReExportSymbols = true; // ObjC optimization is only in dynamic final linked images @@ -3535,6 +3687,135 @@ void Options::reconfigureDefaults() // on the command line if ( (fArchitecture == CPU_TYPE_I386) && (fOutputKind == kDynamicExecutable) && !fDisableNonExecutableHeap) fNonExecutableHeap = true; + + // Use LC_MAIN instead of LC_UNIXTHREAD for newer OSs + switch ( fOutputKind ) { + case Options::kDynamicExecutable: + if ( fEntryPointLoadCommandForceOn ) { + fEntryPointLoadCommand = true; + fEntryName = "_main"; + } + else if ( fEntryPointLoadCommandForceOff ) { + fNeedsThreadLoadCommand = true; + } + else { + if ( (fIOSVersionMin != ld::iOSVersionUnset) && (fArchitecture == CPU_TYPE_I386) ) { + // don't use LC_MAIN for simulator until min host OS is 10.8 for simulator + fNeedsThreadLoadCommand = true; + fEntryPointLoadCommand = false; + } + else if ( minOS(ld::mac10_8, ld::iOS_6_0) ) { + fEntryPointLoadCommand = true; + fEntryName = "_main"; + } + else + fNeedsThreadLoadCommand = true; + } + break; + case Options::kObjectFile: + case Options::kKextBundle: + case Options::kDynamicLibrary: + case Options::kDynamicBundle: + break; + + case Options::kStaticExecutable: + case Options::kPreload: + case Options::kDyld: + fNeedsThreadLoadCommand = true; + break; + } + + // add LC_SOURCE_VERSION + switch ( fOutputKind ) { + case Options::kDynamicExecutable: + case Options::kKextBundle: + case Options::kDynamicLibrary: + case Options::kDynamicBundle: + case Options::kDyld: + case Options::kStaticExecutable: + if ( fSourceVersionLoadCommandForceOn ) { + fSourceVersionLoadCommand = true; + } + else if ( fSourceVersionLoadCommandForceOff ) { + fSourceVersionLoadCommand = false; + } + else { + if ( minOS(ld::mac10_8, ld::iOS_6_0) ) { + fSourceVersionLoadCommand = true; + } + else + fSourceVersionLoadCommand = false; + } + break; + case Options::kObjectFile: + case Options::kPreload: + fSourceVersionLoadCommand = false; + break; + } + + + // add LC_DYLIB_CODE_SIGN_DRS + switch ( fOutputKind ) { + case Options::kDynamicExecutable: + case Options::kDynamicLibrary: + case Options::kDynamicBundle: + if ( fDependentDRInfoForcedOn ) { + fDependentDRInfo = true; + } + else if ( fDependentDRInfoForcedOff ) { + fDependentDRInfo = false; + } + else { + if ( minOS(ld::mac10_8, ld::iOS_6_0) ) + fDependentDRInfo = true; + else + fDependentDRInfo = false; + } + break; + case Options::kKextBundle: + case Options::kDyld: + case Options::kStaticExecutable: + case Options::kObjectFile: + case Options::kPreload: + fDependentDRInfo = false; + break; + } + + // if -sdk_version not on command line, infer from -syslibroot + if ( (fSDKVersion == 0) && (fSDKPaths.size() > 0) ) { + const char* sdkPath = fSDKPaths.front(); + const char* end = &sdkPath[strlen(sdkPath)-1]; + while ( !isdigit(*end) && (end > sdkPath) ) + --end; + const char* start = end-1; + while ( (isdigit(*start) || (*start == '.')) && (start > sdkPath)) + --start; + char sdkVersionStr[32]; + int len = end-start+1; + if ( len > 2 ) { + strlcpy(sdkVersionStr, start+1, len); + fSDKVersion = parseVersionNumber32(sdkVersionStr); + } + } + + // if -sdk_version and -syslibroot not used, but targeting MacOSX, use current OS version + if ( (fSDKVersion == 0) && (fMacVersionMin != ld::macVersionUnset) ) { + // special case if RC_ProjectName and MACOSX_DEPLOYMENT_TARGET are both set that sdkversion=minos + if ( getenv("RC_ProjectName") && getenv("MACOSX_DEPLOYMENT_TARGET") ) { + fSDKVersion = fMacVersionMin; + } + else { + int mib[2] = { CTL_KERN, KERN_OSRELEASE }; + char kernVersStr[100]; + size_t strlen = sizeof(kernVersStr); + if ( sysctl(mib, 2, kernVersStr, &strlen, NULL, 0) != -1 ) { + uint32_t kernVers = parseVersionNumber32(kernVersStr); + int minor = (kernVers >> 16) - 4; // kernel major version is 4 ahead of x in 10.x + fSDKVersion = 0x000A0000 + (minor << 8); + } + } + } + } void Options::checkIllegalOptionCombinations() @@ -3565,6 +3846,7 @@ void Options::checkIllegalOptionCombinations() if ( strcmp(&lastSlash[1], subUmbrella) == 0 ) { info.options.fReExport = true; found = true; + fLinkSnapshot.recordSubUmbrella(info.path); break; } } @@ -3587,6 +3869,7 @@ void Options::checkIllegalOptionCombinations() if ( strncmp(&lastSlash[1], subLibrary, dot-lastSlash-1) == 0 ) { info.options.fReExport = true; found = true; + fLinkSnapshot.recordSubLibrary(info.path); break; } } @@ -3602,12 +3885,10 @@ void Options::checkIllegalOptionCombinations() if ( fStackAddr != 0 ) { switch (fArchitecture) { case CPU_TYPE_I386: - case CPU_TYPE_POWERPC: case CPU_TYPE_ARM: if ( fStackAddr > 0xFFFFFFFF ) throw "-stack_addr must be < 4G for 32-bit processes"; break; - case CPU_TYPE_POWERPC64: case CPU_TYPE_X86_64: break; } @@ -3621,7 +3902,6 @@ void Options::checkIllegalOptionCombinations() if ( fStackSize != 0 ) { switch (fArchitecture) { case CPU_TYPE_I386: - case CPU_TYPE_POWERPC: if ( fStackSize > 0xFFFFFFFF ) throw "-stack_size must be < 4G for 32-bit processes"; if ( fStackAddr == 0 ) { @@ -3637,7 +3917,6 @@ void Options::checkIllegalOptionCombinations() fStackAddr = 0x2F000000; if ( fStackAddr > 0x30000000) throw "-stack_addr must be < 0x30000000 for arm"; - case CPU_TYPE_POWERPC64: case CPU_TYPE_X86_64: if ( fStackAddr == 0 ) { fStackAddr = 0x00007FFF5C000000LL; @@ -3747,7 +4026,6 @@ void Options::checkIllegalOptionCombinations() if ( fObjCABIVersion2Override ) alterObjC1ClassNamesToObjC2 = true; break; - case CPU_TYPE_POWERPC64: case CPU_TYPE_X86_64: case CPU_TYPE_ARM: alterObjC1ClassNamesToObjC2 = true; @@ -3792,10 +4070,25 @@ void Options::checkIllegalOptionCombinations() fInitialUndefines.push_back(*it); } - // make sure that -init symbol exist + // make sure that -init symbol exists if ( fInitFunctionName != NULL ) fInitialUndefines.push_back(fInitFunctionName); + // make sure that entry symbol exists + switch ( fOutputKind ) { + case Options::kDynamicExecutable: + case Options::kStaticExecutable: + case Options::kDyld: + case Options::kPreload: + fInitialUndefines.push_back(fEntryName); + break; + case Options::kDynamicLibrary: + case Options::kDynamicBundle: + case Options::kObjectFile: + case Options::kKextBundle: + break; + } + // make sure every alias base exists for (std::vector::iterator it=fAliases.begin(); it != fAliases.end(); ++it) { fInitialUndefines.push_back(it->realName); @@ -3826,18 +4119,10 @@ void Options::checkIllegalOptionCombinations() // zero page size not specified on command line, set default switch (fArchitecture) { case CPU_TYPE_I386: - case CPU_TYPE_POWERPC: case CPU_TYPE_ARM: // first 4KB for 32-bit architectures fZeroPageSize = 0x1000; break; - case CPU_TYPE_POWERPC64: - // first 4GB for ppc64 on 10.5 - if ( fMacVersionMin >= ld::mac10_5 ) - fZeroPageSize = 0x100000000ULL; - else - fZeroPageSize = 0x1000; // 10.4 dyld may not be able to handle >4GB zero page - break; case CPU_TYPE_X86_64: // first 4GB for x86_64 on all OS's fZeroPageSize = 0x100000000ULL; @@ -3878,7 +4163,7 @@ void Options::checkIllegalOptionCombinations() // can't use -rpath unless targeting 10.5 or later if ( fRPaths.size() > 0 ) { - if ( !minOS(ld::mac10_5, ld::iPhone2_0) ) + if ( !minOS(ld::mac10_5, ld::iOS_2_0) ) throw "-rpath can only be used when targeting Mac OS X 10.5 or later"; switch ( fOutputKind ) { case Options::kDynamicExecutable: @@ -3894,25 +4179,26 @@ void Options::checkIllegalOptionCombinations() } } - // check -pie is only used when building a dynamic main executable for 10.5 if ( fPositionIndependentExecutable ) { switch ( fOutputKind ) { case Options::kDynamicExecutable: - if ( !minOS(ld::mac10_5, ld::iPhone4_2) ) { - if ( fIPhoneVersionMin == ld::iPhoneVersionUnset ) + // check -pie is only used when building a dynamic main executable for 10.5 + if ( !minOS(ld::mac10_5, ld::iOS_4_2) ) { + if ( fIOSVersionMin == ld::iOSVersionUnset ) throw "-pie can only be used when targeting Mac OS X 10.5 or later"; else throw "-pie can only be used when targeting iOS 4.2 or later"; } break; + case Options::kStaticExecutable: case Options::kPreload: + // -pie is ok with -static or -preload break; case Options::kDynamicLibrary: case Options::kDynamicBundle: warning("-pie being ignored. It is only used when linking a main executable"); fPositionIndependentExecutable = false; break; - case Options::kStaticExecutable: case Options::kObjectFile: case Options::kDyld: case Options::kKextBundle: @@ -3947,7 +4233,7 @@ void Options::checkIllegalOptionCombinations() if ( !fReExportSymbols.empty() ) { if ( fOutputKind != Options::kDynamicLibrary ) throw "-reexported_symbols_list can only used used when created dynamic libraries"; - if ( !minOS(ld::mac10_7, ld::iPhone4_2) ) + if ( !minOS(ld::mac10_7, ld::iOS_4_2) ) throw "targeted OS version does not support -reexported_symbols_list"; } @@ -3969,6 +4255,9 @@ void Options::checkForClassic(int argc, const char* argv[]) bool newLinker = false; // build command line buffer in case ld crashes +#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070 + CRSetCrashLogMessage(crashreporterBuffer); +#endif const char* srcRoot = getenv("SRCROOT"); if ( srcRoot != NULL ) { strlcpy(crashreporterBuffer, "SRCROOT=", crashreporterBufferSize); @@ -4011,6 +4300,7 @@ void Options::checkForClassic(int argc, const char* argv[]) // ld_classic does not understand this option, so remove it for(int j=i; j < argc; ++j) argv[j] = argv[j+1]; + warning("using ld_classic"); this->gotoClassicLinker(argc-1, argv); } else if ( strcmp(arg, "-o") == 0 ) { @@ -4020,59 +4310,32 @@ void Options::checkForClassic(int argc, const char* argv[]) } } } - - // -dtrace only supported by new linker - if( dtraceFound ) - return; - - if( archFound ) { - switch ( fArchitecture ) { - case CPU_TYPE_I386: - case CPU_TYPE_POWERPC: - case CPU_TYPE_ARM: - if ( (staticFound || kextFound) && !newLinker ) { - // this environment variable will disable use of ld_classic for -static links - if ( getenv("LD_NO_CLASSIC_LINKER_STATIC") == NULL ) { - // ld_classic does not support -iphoneos_version_min, so change - for(int j=0; j < argc; ++j) { - if ( (strcmp(argv[j], "-iphoneos_version_min") == 0) || (strcmp(argv[j], "-ios_version_min") == 0) ) { - argv[j] = "-macosx_version_min"; - if ( j < argc-1 ) - argv[j+1] = "10.5"; - break; - } - } - // ld classic does not understand -kext (change to -static -r) - if ( kextFound ) { - for(int j=0; j < argc; ++j) { - if ( strcmp(argv[j], "-kext") == 0) - argv[j] = "-r"; - else if ( strcmp(argv[j], "-dynamic") == 0) - argv[j] = "-static"; - } - } - // ld classic does not understand -demangle - for(int j=0; j < argc; ++j) { - if ( strcmp(argv[j], "-demangle") == 0) - argv[j] = "-noprebind"; - } - this->gotoClassicLinker(argc, argv); - } - } - break; - } - } - else { - // work around for VSPTool - if ( staticFound ) - this->gotoClassicLinker(argc, argv); - } - } void Options::gotoClassicLinker(int argc, const char* argv[]) { argv[0] = "ld_classic"; + // ld_classic does not support -iphoneos_version_min, so change + for(int j=0; j < argc; ++j) { + if ( (strcmp(argv[j], "-iphoneos_version_min") == 0) || (strcmp(argv[j], "-ios_version_min") == 0) ) { + argv[j] = "-macosx_version_min"; + if ( j < argc-1 ) + argv[j+1] = "10.5"; + break; + } + } + // ld classic does not understand -kext (change to -static -r) + for(int j=0; j < argc; ++j) { + if ( strcmp(argv[j], "-kext") == 0) + argv[j] = "-r"; + else if ( strcmp(argv[j], "-dynamic") == 0) + argv[j] = "-static"; + } + // ld classic does not understand -demangle + for(int j=0; j < argc; ++j) { + if ( strcmp(argv[j], "-demangle") == 0) + argv[j] = "-noprebind"; + } // in -v mode, print command line passed to ld_classic for(int i=0; i < argc; ++i) { if ( strcmp(argv[i], "-v") == 0 ) { @@ -4100,3 +4363,32 @@ void Options::gotoClassicLinker(int argc, const char* argv[]) fprintf(stderr, "can't exec ld_classic\n"); exit(1); } + + +// Note, returned string buffer is own by this function. +// It should not be freed +// It will be reused, so clients need to strdup() if they want +// to use it long term. +const char* Options::demangleSymbol(const char* sym) const +{ + // only try to demangle symbols if -demangle on command line + if ( !fDemangle ) + return sym; + + // only try to demangle symbols that look like C++ symbols + if ( strncmp(sym, "__Z", 3) != 0 ) + return sym; + + static size_t size = 1024; + static char* buff = (char*)malloc(size); + int status; + + char* result = abi::__cxa_demangle(&sym[1], buff, &size, &status); + if ( result != NULL ) { + // if demangling successful, keep buffer for next demangle + buff = result; + return buff; + } + return sym; +} +