#include <spawn.h>
#include <cxxabi.h>
#include <Availability.h>
+#include <tapi/tapi.h>
#include <vector>
+#include <map>
+#include <sstream>
+#include "ld.hpp"
#include "Options.h"
#include "Architectures.hpp"
#include "MachOFileAbstraction.hpp"
#include "Snapshot.h"
+// from FunctionNameDemangle.h
+extern "C" size_t fnd_get_demangled_name(const char *mangledName, char *outputBuffer, size_t length);
+
+
// upward dependency on lto::version()
namespace lto {
extern const char* version();
+ extern unsigned static_api_version();
+ extern unsigned runtime_api_version();
}
// magic to place command line in crash reports
bool Options::FileInfo::checkFileExists(const Options& options, const char *p)
{
+ if (isInlined) {
+ modTime = 0;
+ return true;
+ }
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;
}
- if ( options.dumpDependencyInfo() )
- options.dumpDependency(Options::depNotFound, p);
+ options.addDependency(Options::depNotFound, p);
+// fprintf(stderr, "not found: %s\n", 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),
- fNeedsModuleTable(false), fIgnoreOtherArchFiles(false), fErrorOnOtherArchFiles(false), fForceSubtypeAll(false),
+ : fOutputFile("a.out"), fArchitecture(0), fSubArchitecture(0),
+ fFallbackArchitecture(0), fFallbackSubArchitecture(0), fArchitectureName("unknown"), fOutputKind(kDynamicExecutable),
+ fHasPreferredSubType(false), fArchSupportsThumb2(false), fBindAtLoad(false), fKeepPrivateExterns(false),
+ fIgnoreOtherArchFiles(false), fErrorOnOtherArchFiles(false), fForceSubtypeAll(false),
fInterposeMode(kInterposeNone), fDeadStrip(false), fNameSpace(kTwoLevelNameSpace),
- fDylibCompatVersion(0), fDylibCurrentVersion(0), fDylibInstallName(NULL), fFinalName(NULL), fEntryName("start"),
- fBaseAddress(0), fMaxAddress(0x7FFFFFFFFFFFFFFFLL),
- fBaseWritableAddress(0), fSplitSegs(false),
+ fDylibCompatVersion(0), fDylibCurrentVersion(0), fDylibInstallName(NULL), fFinalName(NULL), fEntryName(NULL),
+ fBaseAddress(0), fMaxAddress(0xFFFFFFFFFFFFFFFFULL),
+ fBaseWritableAddress(0),
fExportMode(kExportDefault), fLibrarySearchMode(kSearchDylibAndArchiveInEachDir),
fUndefinedTreatment(kUndefinedError), fMessagesPrefixedWithArchitecture(true),
fWeakReferenceMismatchTreatment(kWeakReferenceMismatchNonWeak),
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), fLtoCpu(NULL),
+ fBundleLoader(NULL), fDtraceScriptName(NULL), fMapPath(NULL),
+ fDyldInstallPath("/usr/lib/dyld"), fLtoCachePath(NULL), fTempLtoObjectPath(NULL), fOverridePathlibLTO(NULL), fLtoCpu(NULL),
+ fKextObjectsEnable(-1),fKextObjectsDirPath(NULL),fToolchainPath(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),
fVerbose(false), fKeepRelocations(false), fWarnStabs(false),
fTraceDylibSearching(false), fPause(false), fStatistics(false), fPrintOptions(false),
- fSharedRegionEligible(false), fPrintOrderFileStatistics(false),
+ fSharedRegionEligible(false), fSharedRegionEligibleForceOff(false), fPrintOrderFileStatistics(false),
fReadOnlyx86Stubs(false), fPositionIndependentExecutable(false), fPIEOnCommandLine(false),
fDisablePositionIndependentExecutable(false), fMaxMinimumHeaderPad(false),
fDeadStripDylibs(false), fAllowTextRelocs(false), fWarnTextRelocs(false), fKextsUseStubs(false),
- fUsingLazyDylibLinking(false), fEncryptable(true),
+ fUsingLazyDylibLinking(false), fEncryptable(true), fEncryptableForceOn(false), fEncryptableForceOff(false),
fOrderData(true), fMarkDeadStrippableDylib(false),
- fMakeCompressedDyldInfo(true), fMakeCompressedDyldInfoForceOff(false), fNoEHLabels(false),
- fAllowCpuSubtypeMismatches(false), fUseSimplifiedDylibReExports(false),
+ fMakeCompressedDyldInfo(true), fMakeCompressedDyldInfoForceOff(false),
+ fMakeThreadedStartsSection(false), fNoEHLabels(false),
+ fAllowCpuSubtypeMismatches(false), fEnforceDylibSubtypesMatch(false),
+ fWarnOnSwiftABIVersionMismatches(false), fUseSimplifiedDylibReExports(false),
fObjCABIVersion2Override(false), fObjCABIVersion1Override(false), fCanUseUpwardDylib(false),
fFullyLoadArchives(false), fLoadAllObjcObjectsFromArchives(false), fFlatNamespace(false),
fLinkingMainExecutable(false), fForFinalLinkedImage(false), fForStatic(false),
fSetuidSafe(false), fImplicitlyLinkPublicDylibs(true), fAddCompactUnwindEncoding(true),
fWarnCompactUnwind(false), fRemoveDwarfUnwindIfCompactExists(false),
fAutoOrderInitializers(true), fOptimizeZeroFill(true), fMergeZeroFill(false), fLogObjectFiles(false),
- fLogAllFiles(false), fTraceDylibs(false), fTraceIndirectDylibs(false), fTraceArchives(false),
- fOutputSlidable(false), fWarnWeakExports(false),
+ fLogAllFiles(false), fTraceDylibs(false), fTraceIndirectDylibs(false), fTraceArchives(false), fTraceEmitJSON(false),
+ fOutputSlidable(false), fWarnWeakExports(false), fNoWeakExports(false),
fObjcGcCompaction(false), fObjCGc(false), fObjCGcOnly(false),
fDemangle(false), fTLVSupport(false),
fVersionLoadCommand(false), fVersionLoadCommandForcedOn(false),
fDataInCodeInfoLoadCommand(false), fDataInCodeInfoLoadCommandForcedOn(false), fDataInCodeInfoLoadCommandForcedOff(false),
fCanReExportSymbols(false), fObjcCategoryMerging(true), fPageAlignDataAtoms(false),
fNeedsThreadLoadCommand(false), fEntryPointLoadCommand(false),
- fEntryPointLoadCommandForceOn(false), fEntryPointLoadCommandForceOff(false),
- fSourceVersionLoadCommand(false),
+ fSourceVersionLoadCommand(false),
fSourceVersionLoadCommandForceOn(false), fSourceVersionLoadCommandForceOff(false),
- fDependentDRInfo(false), fDependentDRInfoForcedOn(false), fDependentDRInfoForcedOff(false),
- fTargetIOSSimulator(false), fExportDynamic(false), fAbsoluteSymbols(false),
+ fExportDynamic(false), fAbsoluteSymbols(false),
fAllowSimulatorToLinkWithMacOSX(false), fKeepDwarfUnwind(true),
fKeepDwarfUnwindForcedOn(false), fKeepDwarfUnwindForcedOff(false),
- fGenerateDtraceDOF(true),
- fDebugInfoStripping(kDebugInfoMinimal), fTraceOutputFile(NULL),
- fMacVersionMin(ld::macVersionUnset), fIOSVersionMin(ld::iOSVersionUnset),
- fSaveTempFiles(false), fSnapshotRequested(false), fPipelineFifo(NULL),
- fDependencyInfoPath(NULL), fDependencyFileDescriptor(-1)
+ fVerboseOptimizationHints(false), fIgnoreOptimizationHints(false),
+ fGenerateDtraceDOF(true), fAllowBranchIslands(true), fTraceSymbolLayout(false),
+ fMarkAppExtensionSafe(false), fCheckAppExtensionSafe(false), fForceLoadSwiftLibs(false),
+ fSharedRegionEncodingV2(false), fUseDataConstSegment(false),
+ fUseDataConstSegmentForceOn(false), fUseDataConstSegmentForceOff(false), fUseTextExecSegment(false),
+ fBundleBitcode(false), fHideSymbols(false), fVerifyBitcode(false),
+ fReverseMapUUIDRename(false), fDeDupe(true), fVerboseDeDupe(false),
+ fUseLinkedListBinding(false), fNoLazyBinding(false), fDebugVariant(false),
+ fReverseMapPath(NULL), fLTOCodegenOnly(false),
+ fIgnoreAutoLink(false), fAllowDeadDups(false), fAllowWeakImports(true), fInitializersTreatment(Options::kInvalid),
+ fZeroModTimeInDebugMap(false), fBitcodeKind(kBitcodeProcess),
+ fDebugInfoStripping(kDebugInfoMinimal), fTraceOutputFile(NULL),
+ fSaveTempFiles(false), fLinkSnapshot(this), fSnapshotRequested(false), fPipelineFifo(NULL),
+ fDependencyInfoPath(NULL), fBuildContextName(NULL), fTraceFileDescriptor(-1), fMaxDefaultCommonAlign(0),
+ fUnalignedPointerTreatment(kUnalignedPointerIgnore)
{
this->checkForClassic(argc, argv);
this->parsePreCommandLineEnvironmentSettings();
this->reconfigureDefaults();
this->checkIllegalOptionCombinations();
- if ( this->dumpDependencyInfo() ) {
- this->dumpDependency(depOutputFile, fOutputFile);
- if ( fMapPath != NULL )
- this->dumpDependency(depOutputFile, fMapPath);
- }
+ this->addDependency(depOutputFile, fOutputFile);
+ if ( fMapPath != NULL )
+ this->addDependency(depOutputFile, fMapPath);
}
Options::~Options()
{
- if ( fDependencyFileDescriptor != -1 )
- ::close(fDependencyFileDescriptor);
+ if ( fTraceFileDescriptor != -1 )
+ ::close(fTraceFileDescriptor);
}
bool Options::errorBecauseOfWarnings() const
bool Options::printWhyLive(const char* symbolName) const
{
- return ( fWhyLive.find(symbolName) != fWhyLive.end() );
+ return fWhyLive.contains(symbolName);
}
return it->init;
}
}
- if ( strcmp(segName, "__PAGEZERO") == 0 ) {
- return 0;
+ if ( strcmp(segName, "__TEXT") == 0 ) {
+ return ( fUseTextExecSegment ? VM_PROT_READ : (VM_PROT_READ | VM_PROT_EXECUTE) );
}
- else if ( strcmp(segName, "__TEXT") == 0 ) {
+ else if ( strcmp(segName, "__TEXT_EXEC") == 0 ) {
return VM_PROT_READ | VM_PROT_EXECUTE;
}
+ else if ( strcmp(segName, "__PAGEZERO") == 0 ) {
+ return 0;
+ }
else if ( strcmp(segName, "__LINKEDIT") == 0 ) {
return VM_PROT_READ;
}
{
// iPhoneOS always uses same protection for max and initial
// <rdar://problem/11663436> simulator apps need to use MacOSX max-prot
- if ( (fIOSVersionMin != ld::iOSVersionUnset) && (fArchitecture != CPU_TYPE_I386) )
+ if ( (platforms().contains(ld::kPlatform_macOS) == 0) && !targetIOSSimulator() )
return initialSegProtection(segName);
for(std::vector<Options::SegmentProtect>::const_iterator it = fCustomSegmentProtections.begin(); it != fCustomSegmentProtections.end(); ++it) {
if ( (strcmp(it->segmentName, segName) == 0) && (strcmp(it->sectionName, sectName) == 0) )
return true;
}
+ if ( fEncryptable && (strcmp(sectName, "__oslogstring") == 0) && (strcmp(segName, "__TEXT") == 0) )
+ return true;
+
return false;
}
if ( (strcmp(it->segmentName, segName) == 0) && (strcmp(it->sectionName, sectName) == 0) )
return it->alignment;
}
+ if ( fEncryptable && (strcmp(sectName, "__oslogstring") == 0) && (strcmp(segName, "__TEXT") == 0) )
+ return __builtin_ctz(fSegmentAlignment);
+
return 0;
}
+bool Options::segmentOrderAfterFixedAddressSegment(const char* segName) const
+{
+ bool nowPinned = false;
+ for (std::vector<const char*>::const_iterator it=fSegmentOrder.begin(); it != fSegmentOrder.end(); ++it) {
+ if ( strcmp(*it, segName) == 0 )
+ return nowPinned;
+ if ( hasCustomSegmentAddress(*it) )
+ nowPinned = true;
+ }
+ return false;
+}
bool Options::hasExportedSymbolOrder()
{
throw "internal error";
}
-void Options::setArchitecture(cpu_type_t type, cpu_subtype_t subtype)
+const std::vector<const char*>* Options::sectionOrder(const char* segName) const
+{
+ for (std::vector<SectionOrderList>::const_iterator it=fSectionOrder.begin(); it != fSectionOrder.end(); ++it) {
+ if ( strcmp(it->segmentName, segName) == 0 )
+ return &it->sectionOrder;
+ }
+ return NULL;
+}
+
+void Options::setArchitecture(cpu_type_t type, cpu_subtype_t subtype, ld::Platform platform, uint32_t minOsVers)
{
for (const ArchInfo* t=archInfoArray; t->archName != NULL; ++t) {
if ( (type == t->cpuType) && (subtype == t->cpuSubType) ) {
fArchitectureName = t->archName;
fHasPreferredSubType = t->isSubType;
fArchSupportsThumb2 = t->supportsThumb2;
+ if ( platforms().empty() && (platform != ld::kPlatform_unknown) )
+ fPlatforms.add({platform, minOsVers});
switch ( type ) {
case CPU_TYPE_I386:
case CPU_TYPE_X86_64:
- if ( (fMacVersionMin == ld::macVersionUnset) && (fIOSVersionMin == ld::iOSVersionUnset) && (fOutputKind != Options::kObjectFile) ) {
+ if ( platforms().contains(ld::kPlatform_macOS) && (fOutputKind != Options::kObjectFile) && (platforms().minOS(ld::kPlatform_macOS) == 0) ) {
#ifdef DEFAULT_MACOSX_MIN_VERSION
warning("-macosx_version_min not specified, assuming " DEFAULT_MACOSX_MIN_VERSION);
- setMacOSXVersionMin(DEFAULT_MACOSX_MIN_VERSION);
+ setVersionMin(ld::kPlatform_macOS, DEFAULT_MACOSX_MIN_VERSION);
#else
warning("-macosx_version_min not specified, assuming 10.6");
- fMacVersionMin = ld::mac10_6;
- #endif
+ setVersionMin(ld::kPlatform_macOS, "10.6");
+ #endif
}
break;
case CPU_TYPE_ARM:
case CPU_TYPE_ARM64:
- if ( (fMacVersionMin == ld::macVersionUnset) && (fIOSVersionMin == ld::iOSVersionUnset) && (fOutputKind != Options::kObjectFile) ) {
+ if ( platforms().contains(ld::kPlatform_iOS) && (platforms().minOS(ld::kPlatform_iOS) == 0) && (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);
+ setVersionMin(ld::kPlatformiOS, DEFAULT_IPHONEOS_MIN_VERSION);
#else
warning("-ios_version_min not specified, assuming 6.0");
- setIOSVersionMin("6.0");
+ setVersionMin(ld::kPlatform_iOS, "6.0");
#endif
}
+#if SUPPORT_ARCH_arm64e
+ if ( (fArchitecture == CPU_TYPE_ARM64) && (fSubArchitecture == CPU_SUBTYPE_ARM64_E) ) {
+ fSupportsAuthenticatedPointers = true;
+ }
+#endif
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 )
+ if ( !fMakeCompressedDyldInfo && platforms().minOS(ld::version2009) && !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) )
+ if ( platforms().minOS(ld::version2008) )
fUseSimplifiedDylibReExports = true;
return;
}
fArchitectureName = "unknown architecture";
}
+bool Options::armUsesZeroCostExceptions() const
+{
+ return ( (fArchitecture == CPU_TYPE_ARM) && (fSubArchitecture == CPU_SUBTYPE_ARM_V7K) );
+}
+
+void Options::selectFallbackArch(const char *arch)
+{
+ // Should have the format "desired_arch:fallback_arch", for example "arm64_32:armv7k" to allow an armv7k
+ // slice to substitute for arm64_32 if the latter isn't present.
+ if (const char* fallbackEnv = getenv("LD_DYLIB_ARCH_FALLBACK") ) {
+ std::string fallback(fallbackEnv);
+ auto delimPos = fallback.find(':');
+
+ // Check we've got a potentially valid fallback string and that it's this architecture we're falling back from.
+ if ( delimPos == std::string::npos || fallback.substr(0, delimPos) != arch )
+ return;
+
+ std::string fallbackTo = fallback.substr(delimPos + 1);
+ for (const ArchInfo *t = archInfoArray; t->archName != nullptr; ++t) {
+ if ( fallbackTo == t->archName ) {
+ fFallbackArchitecture = t->cpuType;
+ fFallbackSubArchitecture = t->cpuSubType;
+ }
+ }
+ }
+ else {
+ // <rdar://problem/39797337> let x86_64h fallback and use x86_64 slice
+ if ( (fArchitecture == CPU_TYPE_X86_64) && (fSubArchitecture == CPU_SUBTYPE_X86_64_H) ) {
+ fFallbackArchitecture = CPU_TYPE_X86_64;
+ fFallbackSubArchitecture = CPU_SUBTYPE_X86_ALL;
+ }
+ }
+}
+
void Options::parseArch(const char* arch)
{
if ( arch == NULL )
fSubArchitecture = t->cpuSubType;
fHasPreferredSubType = t->isSubType;
fArchSupportsThumb2 = t->supportsThumb2;
+ selectFallbackArch(arch);
return;
}
}
}
}
else {
- bool lookForDylibs = ( fOutputKind != Options::kDyld);
+ bool lookForDylibs = false;
+ switch ( fOutputKind ) {
+ case Options::kDynamicExecutable:
+ case Options::kDynamicLibrary:
+ case Options::kDynamicBundle:
+ case Options::kObjectFile: // <rdar://problem/15914513>
+ 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
it != fLibrarySearchPaths.end();
it++) {
const char* dir = *it;
- if ( checkForFile("%s/lib%s.dylib", dir, rootName, result) )
+ auto path = std::string(dir) + "/lib" + rootName + ".dylib";
+ if ( findFile(path, {".tbd"}, result) )
return result;
}
for (std::vector<const char*>::const_iterator it = fLibrarySearchPaths.begin();
it != fLibrarySearchPaths.end();
it++) {
const char* dir = *it;
- if ( lookForDylibs && checkForFile("%s/lib%s.dylib", dir, rootName, result) )
+ auto path = std::string(dir) + "/lib" + rootName + ".dylib";
+ if ( lookForDylibs && findFile(path, {".tbd"}, result) )
return result;
if ( lookForDylibs && checkForFile("%s/lib%s.so", dir, rootName, result) )
return result;
Options::FileInfo Options::findFramework(const char* rootName, const char* suffix) const
{
- for (std::vector<const char*>::const_iterator it = fFrameworkSearchPaths.begin();
- it != fFrameworkSearchPaths.end();
- it++) {
- // ??? Shouldn't we be using String here and just initializing it?
- // ??? Use str.c_str () to pull out the string for the stat call.
- const char* dir = *it;
- char possiblePath[PATH_MAX];
- strcpy(possiblePath, dir);
- strcat(possiblePath, "/");
- strcat(possiblePath, rootName);
- strcat(possiblePath, ".framework/");
- strcat(possiblePath, rootName);
- if ( suffix != NULL ) {
+ for (const auto* path : fFrameworkSearchPaths) {
+ auto possiblePath = std::string(path).append("/").append(rootName).append(".framework/").append(rootName);
+ if ( suffix != nullptr ) {
char realPath[PATH_MAX];
// no symlink in framework to suffix variants, so follow main symlink
- if ( realpath(possiblePath, realPath) != NULL ) {
- strcpy(possiblePath, realPath);
- strcat(possiblePath, suffix);
- }
+ if ( realpath(possiblePath.c_str(), realPath) != nullptr )
+ possiblePath = std::string(realPath).append(suffix);
}
FileInfo result;
- bool found = result.checkFileExists(*this, possiblePath);
- if ( fTraceDylibSearching )
- printf("[Logging for XBS]%sfound framework: '%s'\n",
- (found ? " " : " not "), possiblePath);
- if ( found ) {
+ if ( findFile(possiblePath, {".tbd"}, result) )
return result;
- }
}
// try without suffix
if ( suffix != NULL )
throwf("framework not found %s", rootName);
}
-Options::FileInfo Options::findFile(const char* path) const
+static std::string replace_extension(const std::string &path, const std::string &ext)
+{
+ auto result = path;
+ auto lastSlashIdx = result.find_last_of('/');
+ auto lastDotIdx = result.find_last_of('.');
+ if (lastDotIdx != std::string::npos && lastDotIdx > lastSlashIdx)
+ result.erase(lastDotIdx, std::string::npos);
+ if ( ext.size() > 0 && ext[0] == '.' )
+ result.append(ext);
+ else
+ result.append('.' + ext);
+ return result;
+}
+
+void Options::addTAPIInterface(tapi::LinkerInterfaceFile* interface, const char *path) const {
+#if ((TAPI_API_VERSION_MAJOR == 1 && TAPI_API_VERSION_MINOR >= 3) || (TAPI_API_VERSION_MAJOR > 1))
+ if (tapi::APIVersion::isAtLeast(1, 3)) {
+ for (auto &name : interface->inlinedFrameworkNames()) {
+ fTAPIFiles.emplace_back(interface, path, name.c_str());
+ }
+ }
+#endif
+}
+
+bool Options::findFile(const std::string &path, const std::vector<std::string> &tbdExtensions, FileInfo& result) const
+{
+ FileInfo tbdInfo;
+ for ( const auto &ext : tbdExtensions ) {
+ auto newPath = replace_extension(path, ext);
+ bool found = tbdInfo.checkFileExists(*this, newPath.c_str());
+ if ( fTraceDylibSearching )
+ printf("[Logging for XBS]%sfound library: '%s'\n", (found ? " " : " not "), newPath.c_str());
+ if ( found )
+ break;
+ }
+
+ FileInfo dylibInfo;
+ {
+ bool found = dylibInfo.checkFileExists(*this, path.c_str());
+ if ( fTraceDylibSearching )
+ printf("[Logging for XBS]%sfound library: '%s'\n", (found ? " " : " not "), path.c_str());
+ }
+
+ // There is only a text-based stub file or a dynamic library file.
+ if ( tbdInfo.missing() != dylibInfo.missing() ) {
+ result = tbdInfo.missing() ? dylibInfo : tbdInfo;
+ }
+ // There are both - a text-based stub file and a dynamic library file.
+ else if ( !tbdInfo.missing() && !dylibInfo.missing() ) {
+ // Check if we should prefer the text-based stub file (installapi).
+ if (tapi::LinkerInterfaceFile::shouldPreferTextBasedStubFile(tbdInfo.path)) {
+ result = tbdInfo;
+ }
+ // If the files are still in sync we can use and should use the text-based stub file.
+ else if (tapi::LinkerInterfaceFile::areEquivalent(tbdInfo.path, dylibInfo.path)) {
+ result = tbdInfo;
+ }
+ // Otherwise issue a warning and fall-back to the dynamic library file.
+ else {
+ warning("text-based stub file %s and library file %s are out of sync. Falling back to library file for linking.", tbdInfo.path, dylibInfo.path);
+ result = dylibInfo;
+ }
+ } else {
+ return false;
+ }
+
+ return true;
+}
+
+static bool startsWith(const std::string& str, const std::string& prefix)
+{
+ return (str.compare(0, prefix.length(), prefix) == 0);
+}
+
+static std::string getDirPath(const std::string& path)
+{
+ std::string::size_type lastSlashPos = path.find_last_of('/');
+ if ( lastSlashPos == std::string::npos )
+ return "./";
+ else
+ return path.substr(0, lastSlashPos+1);
+}
+
+Options::FileInfo Options::findFile(const std::string &path, const ld::dylib::File* fromDylib) const
{
FileInfo result;
- // if absolute path and not a .o file, the use SDK prefix
- if ( (path[0] == '/') && (strcmp(&path[strlen(path)-2], ".o") != 0) ) {
- const int pathLen = strlen(path);
- for (std::vector<const char*>::const_iterator it = fSDKPaths.begin(); it != fSDKPaths.end(); it++) {
- // ??? Shouldn't we be using String here?
- const char* sdkPathDir = *it;
- const int sdkPathDirLen = strlen(sdkPathDir);
- char possiblePath[sdkPathDirLen+pathLen+4];
- strcpy(possiblePath, sdkPathDir);
- if ( possiblePath[sdkPathDirLen-1] == '/' )
- possiblePath[sdkPathDirLen-1] = '\0';
- strcat(possiblePath, path);
- if ( result.checkFileExists(*this, possiblePath) ) {
+ // if absolute path and not a .o file, then use SDK prefix
+ if ( (path[0] == '/') && (strcmp(&path[path.size()-2], ".o") != 0) ) {
+ for (const auto* sdkPathDir : fSDKPaths) {
+ auto possiblePath = std::string(sdkPathDir) + path;
+ if ( findFile(possiblePath, {".tbd"}, result) )
+ return result;
+ }
+ }
+
+ // expand @ variables
+ if ( path[0] == '@' ) {
+ if ( startsWith(path, "@executable_path/") && (fExecutablePath != nullptr) ) {
+ std::string exeBasedPath = getDirPath(fExecutablePath) + &path[17];
+ if ( findFile(exeBasedPath, {".tbd"}, result) )
return result;
+ }
+ else if ( startsWith(path, "@loader_path/") && (fromDylib != nullptr) ) {
+ char absPath[PATH_MAX];
+ if ( realpath(fromDylib->path(), absPath) != NULL ) {
+ std::string loaderBasedPath = getDirPath(fromDylib->path()) + &path[13];
+ if ( findFile(loaderBasedPath, {".tbd"}, result) )
+ return result;
+ }
+ }
+ else if ( startsWith(path, "@rpath/") ) {
+ // first search any LC_RPATH supplied by dyld that re-exports dylib to be found
+ if ( fromDylib != nullptr ) {
+ for (const char* rp : fromDylib->rpaths() ) {
+ std::string rpath = rp;
+ // handle dylib that has LC_RPATH = @loader_path/blah
+ if ( startsWith(rpath, "@loader_path/") ) {
+ char absPath[PATH_MAX];
+ if ( realpath(fromDylib->path(), absPath) != NULL )
+ rpath = getDirPath(absPath) + &rpath[13];
+ else
+ rpath = getDirPath(fromDylib->path()) + &rpath[13];
+ }
+ std::string rpathBasedPath = rpath + "/" + &path[6];
+ if ( findFile(rpathBasedPath, {".tbd"}, result) )
+ return result;
+ }
}
}
}
+
+ // find inlined TBD file before raw path.
+ // rdar://problem/35864452
+ if (hasInlinedTAPIFile(path)) {
+ FileInfo inlinedFile(path.c_str());
+ inlinedFile.isInlined = true;
+ return inlinedFile;
+ }
+
// try raw path
- if ( result.checkFileExists(*this, path) ) {
+ if ( findFile(path, {".tbd"}, result) )
return result;
+
+ // not found
+ throwf("file not found: %s", path.c_str());
+}
+
+bool Options::hasInlinedTAPIFile(const std::string &path) const {
+ for (const auto &dylib : fTAPIFiles) {
+ if (dylib.getInstallName() == path)
+ return true;
}
+ return false;
+}
- // try @executable_path substitution
- if ( (strncmp(path, "@executable_path/", 17) == 0) && (fExecutablePath != NULL) ) {
- char newPath[strlen(fExecutablePath) + strlen(path)];
- strcpy(newPath, fExecutablePath);
- char* addPoint = strrchr(newPath,'/');
- if ( addPoint != NULL )
- strcpy(&addPoint[1], &path[17]);
- else
- strcpy(newPath, &path[17]);
- if ( result.checkFileExists(*this, newPath) ) {
- return result;
+tapi::LinkerInterfaceFile* Options::findTAPIFile(const std::string &path) const
+{
+#if ((TAPI_API_VERSION_MAJOR == 1 && TAPI_API_VERSION_MINOR >= 3) || (TAPI_API_VERSION_MAJOR > 1))
+ tapi::LinkerInterfaceFile* interface = nullptr;
+ std::string TBDPath;
+
+ // create parsing options.
+ tapi::ParsingFlags flags = tapi::ParsingFlags::None;
+ if (enforceDylibSubtypesMatch())
+ flags |= tapi::ParsingFlags::ExactCpuSubType;
+
+ if (!allowWeakImports())
+ flags |= tapi::ParsingFlags::DisallowWeakImports;
+
+ __block uint32_t linkMinOSVersion = 0;
+ //FIXME handle this correctly once we have multi-platform TAPI.
+ platforms().forEach(^(ld::Platform platform, uint32_t version, bool &stop) {
+ if (linkMinOSVersion == 0)
+ linkMinOSVersion = version;
+ if (platform == ld::kPlatform_macOS)
+ linkMinOSVersion = version;
+ });
+
+ // Search through all the inlined framework.
+ for (const auto &dylib : fTAPIFiles) {
+ if (dylib.getInstallName() == path) {
+ // If the install name matches, parse the framework.
+ std::string errorMessage;
+ auto file = dylib.getInterfaceFile()->getInlinedFramework(path.c_str(), architecture(), subArchitecture(),
+ flags, tapi::PackedVersion32(linkMinOSVersion), errorMessage);
+ if (!file)
+ throw strdup(errorMessage.c_str());
+
+ if (!interface) {
+ // If this is the first inlined framework found, record the information.
+ interface = file;
+ TBDPath = dylib.getTAPIFilePath();
+ } else {
+ // If we found other inlined framework already, check to see if their versions are the same.
+ // If not the same, emit an warning and record the newer one. Otherwise, just use the current one.
+ if (interface->getCurrentVersion() == file->getCurrentVersion())
+ continue;
+ warning("Inlined framework/dylib mismatch: %s (%s and %s)", path.c_str(),
+ TBDPath.c_str(), dylib.getTAPIFilePath().c_str());
+ if (interface->getCurrentVersion() < file->getCurrentVersion()) {
+ interface = file;
+ TBDPath = dylib.getTAPIFilePath();
+ }
+ }
}
}
-
- // not found
- throwf("file not found: %s", path);
+ return interface;
+#else
+ return nullptr;
+#endif
}
-Options::FileInfo Options::findFileUsingPaths(const char* path) const
+// search for indirect dylib first using -F and -L paths first
+Options::FileInfo Options::findIndirectDylib(const std::string& installName, const ld::dylib::File* fromDylib) const
{
FileInfo result;
- const char* lastSlash = strrchr(path, '/');
- const char* leafName = (lastSlash == NULL) ? path : &lastSlash[1];
+ auto lastSlashPos = installName.find_last_of('/');
+ auto pos = ( lastSlashPos != std::string::npos ) ? lastSlashPos + 1 : 0;
+ auto leafName = installName.substr(pos);
// Is this in a framework?
// /path/Foo.framework/Foo ==> true (Foo)
// /path/Foo.framework/Frameworks/Bar.framework/Bar ==> true (Bar)
// /path/Foo.framework/Resources/Bar ==> false
bool isFramework = false;
- if ( lastSlash != NULL ) {
- char frameworkDir[strlen(leafName) + 20];
- strcpy(frameworkDir, "/");
- strcat(frameworkDir, leafName);
- strcat(frameworkDir, ".framework/");
- if ( strstr(path, frameworkDir) != NULL )
+ if ( lastSlashPos != std::string::npos ) {
+ auto frameworkDir = std::string("/").append(leafName).append(".framework/");
+ if ( installName.rfind(frameworkDir) != std::string::npos )
isFramework = true;
}
// don't need to try variations, just paths. We do need to add the additional bits
// onto the framework path though.
if ( isFramework ) {
- for (std::vector<const char*>::const_iterator it = fFrameworkSearchPaths.begin();
- it != fFrameworkSearchPaths.end();
- it++) {
- const char* dir = *it;
- char possiblePath[PATH_MAX];
- strcpy(possiblePath, dir);
- strcat(possiblePath, "/");
- strcat(possiblePath, leafName);
- strcat(possiblePath, ".framework");
-
- //fprintf(stderr,"Finding Framework: %s/%s, leafName=%s\n", possiblePath, leafName, leafName);
- if ( checkForFile("%s/%s", possiblePath, leafName, result) )
+ auto endPos = installName.rfind(".framework");
+ auto beginPos = installName.find_last_of('/', endPos);
+ auto leafPath = installName.substr(beginPos);
+ for (const auto* dir : fFrameworkSearchPaths) {
+ auto possiblePath = dir + leafPath;
+ if ( findFile(possiblePath, {".tbd"}, result) )
return result;
}
- }
- else {
+ } else {
// if this is a .dylib inside a framework, do not search -L paths
- // <rdar://problem/5427952> ld64's re-export cycle detection logic prevents use of X11 libGL on Leopard
- int leafLen = strlen(leafName);
- bool embeddedDylib = ( (leafLen > 6)
- && (strcmp(&leafName[leafLen-6], ".dylib") == 0)
- && (strstr(path, ".framework/") != NULL) );
+ // <rdar://problem/5427952> ld64's re-export cycle detection logic prevents use of X11 libGL on Leopard
+ bool embeddedDylib = ( (leafName.size() > 6)
+ && (leafName.find(".dylib", leafName.size()-6) != std::string::npos)
+ && (installName.find(".framework/") != std::string::npos) );
if ( !embeddedDylib ) {
- for (std::vector<const char*>::const_iterator it = fLibrarySearchPaths.begin();
- it != fLibrarySearchPaths.end();
- it++) {
- const char* dir = *it;
+ for (const auto* dir : fLibrarySearchPaths) {
//fprintf(stderr,"Finding Library: %s/%s\n", dir, leafName);
- if ( checkForFile("%s/%s", dir, leafName, result) )
+ std::string possiblePath = dir + std::string("/") + leafName;
+ if ( findFile(possiblePath, {".tbd"}, result) )
return result;
}
}
}
// If we didn't find it fall back to findFile.
- return findFile(path);
-}
-
-
-
-void Options::parseSegAddrTable(const char* segAddrPath, const char* installPth)
-{
- FILE* file = fopen(segAddrPath, "r");
- if ( file == NULL ) {
- warning("-seg_addr_table file cannot be read: %s", segAddrPath);
- return;
- }
-
- char path[PATH_MAX];
- uint64_t firstColumAddress = 0;
- uint64_t secondColumAddress = 0;
- bool hasSecondColumn = false;
- while ( fgets(path, PATH_MAX, file) != NULL ) {
- path[PATH_MAX-1] = '\0';
- char* eol = strchr(path, '\n');
- if ( eol != NULL )
- *eol = '\0';
- // ignore lines not starting with 0x number
- if ( (path[0] == '0') && (path[1] == 'x') ) {
- char* p;
- firstColumAddress = strtoull(path, &p, 16);
- while ( isspace(*p) )
- ++p;
- // see if second column is a number
- if ( (p[0] == '0') && (p[1] == 'x') ) {
- secondColumAddress = strtoull(p, &p, 16);
- hasSecondColumn = true;
- while ( isspace(*p) )
- ++p;
- }
- while ( isspace(*p) )
- ++p;
- if ( p[0] == '/' ) {
- // remove any trailing whitespace
- for(char* end = eol-1; (end > p) && isspace(*end); --end)
- *end = '\0';
- // see if this line is for the dylib being linked
- if ( strcmp(p, installPth) == 0 ) {
- fBaseAddress = firstColumAddress;
- if ( hasSecondColumn ) {
- fBaseWritableAddress = secondColumAddress;
- fSplitSegs = true;
- }
- break; // out of while loop
- }
- }
- }
- }
-
- fclose(file);
+ return findFile(installName, fromDylib);
}
void Options::loadFileList(const char* fileOfPaths, ld::File::Ordinal baseOrdinal)
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);
+ this->addDependency(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);
+ this->addDependency(Options::depFileList, fileOfPaths);
}
char path[PATH_MAX];
fRegular.insert(symbol);
}
-bool Options::SetWithWildcards::contains(const char* symbol) const
+bool Options::SetWithWildcards::contains(const char* symbol, bool* matchBecauseOfWildcard) const
{
+ if ( matchBecauseOfWildcard != NULL )
+ *matchBecauseOfWildcard = false;
// first look at hash table on non-wildcard symbols
if ( fRegular.find(symbol) != fRegular.end() )
return true;
// next walk list of wild card symbols looking for a match
for(std::vector<const char*>::const_iterator it = fWildCard.begin(); it != fWildCard.end(); ++it) {
- if ( wildCardMatch(*it, symbol) )
+ if ( wildCardMatch(*it, symbol) ) {
+ if ( matchBecauseOfWildcard != NULL )
+ *matchBecauseOfWildcard = true;
return true;
+ }
}
return false;
}
+// Support "foo.o:_bar" to mean symbol _bar in file foo.o
+bool Options::SetWithWildcards::containsWithPrefix(const char* symbol, const char* file, bool& wildCardMatch) const
+{
+ wildCardMatch = false;
+ if ( contains(symbol, &wildCardMatch) )
+ return true;
+ if ( file == NULL )
+ return false;
+ const char* s = strrchr(file, '/');
+ if ( s != NULL )
+ file = s+1;
+ char buff[strlen(file)+strlen(symbol)+2];
+ sprintf(buff, "%s:%s", file, symbol);
+ return contains(buff, &wildCardMatch);
+}
+
bool Options::SetWithWildcards::containsNonWildcard(const char* symbol) const
{
// look at hash table on non-wildcard symbols
}
+std::vector<const char*> Options::exportsData() const
+{
+ return fExportSymbols.data();
+}
+
+
+std::vector<const char*> Options::SetWithWildcards::data() const
+{
+ std::vector<const char*> data;
+ for (NameSet::iterator it=regularBegin(); it != regularEnd(); ++it) {
+ data.push_back(*it);
+ }
+ for (std::vector<const char*>::const_iterator it=fWildCard.begin(); it != fWildCard.end(); ++it) {
+ data.push_back(*it);
+ }
+ return data;
+}
bool Options::SetWithWildcards::inCharRange(const char*& p, unsigned char c) const
{
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);
+ this->addDependency(Options::depMisc, fileOfExports);
::close(fd);
throwf("can't read alias file: %s", fileOfAliases);
p[stat_buf.st_size] = '\n';
::close(fd);
- if ( this->dumpDependencyInfo() )
- this->dumpDependency(Options::depMisc, fileOfAliases);
+ this->addDependency(Options::depMisc, fileOfAliases);
// parse into symbols and add to fAliases
AliasPair pair;
return kInvalid;
}
-void Options::setMacOSXVersionMin(const char* version)
-{
- if ( version == NULL )
- throw "-macosx_version_min argument missing";
-
- if ( (strncmp(version, "10.", 3) == 0) && isdigit(version[3]) ) {
- 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;
+void Options::setVersionMin(const ld::Platform& platform, const char *version) {
+ auto checkAndParse = [&](const char *errorFlag) {
+ if ( version == NULL )
+ throwf("%s missing version argument", errorFlag);
+ uint32_t value;
+ if ( !parsePackedVersion32(version, value) ) {
+ throwf("%s value malformed: '%s'", errorFlag, version);
}
- fMacVersionMin = (ld::MacVersionMin)(0x000A0000 | (minorVersion << 8));
- }
- else {
- warning("unknown option to -macosx_version_min, not 10.x");
- }
-}
-
-void Options::setIOSVersionMin(const char* version)
-{
- if ( version == NULL )
- throw "-ios_version_min argument missing";
- if ( ! isdigit(version[0]) )
- throw "-ios_version_min argument is not a number";
- if ( version[1] != '.' )
- throw "-ios_version_min argument is missing period as second character";
- if ( ! isdigit(version[2]) )
- throw "-ios_version_min argument is not a number";
-
- unsigned int majorVersion = version[0] - '0';
- unsigned int minorVersion = version[2] - '0';
- fIOSVersionMin = (ld::IOSVersionMin)((majorVersion << 16) | (minorVersion << 8));
-}
-
-bool Options::minOS(ld::MacVersionMin requiredMacMin, ld::IOSVersionMin requirediPhoneOSMin)
-{
- if ( fMacVersionMin != ld::macVersionUnset ) {
- return ( fMacVersionMin >= requiredMacMin );
- }
- else {
- return ( fIOSVersionMin >= requirediPhoneOSMin);
- }
+ fPlatforms.add({platform, value});
+ };
+
+ switch(platform) {
+ case ld::kPlatform_macOS: checkAndParse("-macosx_version_min"); break;
+ case ld::kPlatform_iOS: checkAndParse("-ios_version_min"); break;
+ case ld::kPlatform_tvOS: checkAndParse("-tvos_version_min"); break;
+ case ld::kPlatform_watchOS: checkAndParse("-watchos_version_min"); break;
+ case ld::kPlatform_bridgeOS: checkAndParse("-bridgeos_version_min"); break;
+ case ld::kPlatform_iOSSimulator: checkAndParse("-ios_simulator_version_min"); break;
+ case ld::kPlatform_tvOSSimulator: checkAndParse("-tvos_simulator_version_min"); break;
+ case ld::kPlatform_watchOSSimulator: checkAndParse("-watchos_simulator_version_min"); break;
+ case ld::kPlatform_unknown: throw "kPlatformUnknown is an invalid argument to setVersionMin()";
+ case ld::kPlatform_iOSMac: checkAndParse("-iosmac_version_min"); break;
+ };
}
-
void Options::setWeakReferenceMismatchTreatment(const char* treatment)
{
if ( treatment == NULL )
// order files override auto-ordering
fAutoOrderInitializers = false;
+ // <rdar://problem/24856050> ld64 should prefer OrderFiles from the SDK over the ones in /
+ for (const char* sdkPath : fSDKPaths) {
+ char fullPath[PATH_MAX];
+ strlcpy(fullPath, sdkPath, PATH_MAX);
+ strlcat(fullPath, "/", PATH_MAX);
+ strlcat(fullPath, path, PATH_MAX);
+ struct stat statBuffer;
+ if ( stat(fullPath, &statBuffer) == 0 ) {
+ path = strdup(fullPath);
+ break;
+ }
+ }
+
// read in whole file
int fd = ::open(path, O_RDONLY, 0);
if ( fd == -1 )
throwf("can't read order file: %s", path);
::close(fd);
p[stat_buf.st_size] = '\n';
- if ( this->dumpDependencyInfo() )
- this->dumpDependency(Options::depMisc, path);
+ this->addDependency(Options::depMisc, path);
// parse into vector of pairs
char * const end = &p[stat_buf.st_size+1];
else
symbolStart = NULL;
}
+ else if ( strncmp(symbolStart, "arm64:", 6) == 0 ) {
+ if ( fArchitecture == CPU_TYPE_ARM64 )
+ symbolStart = &symbolStart[6];
+ else
+ symbolStart = NULL;
+ }
if ( symbolStart != NULL ) {
char* objFileName = NULL;
char* colon = strstr(symbolStart, ".o:");
::close(fd);
// record section to create
- ExtraSection info = { segment, section, path, (uint8_t*)p, stat_buf.st_size };
+ ExtraSection info = { segment, section, path, (uint8_t*)p, (uint64_t)stat_buf.st_size };
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::addSegmentRename(const char* srcSegment, const char* dstSegment)
+{
+ if ( strlen(srcSegment) > 16 )
+ throw "-rename_segment segment name max 16 chars";
+ if ( strlen(dstSegment) > 16 )
+ throw "-rename_segment segment name max 16 chars";
+
+ SegmentRename info;
+ info.fromSegment = srcSegment;
+ info.toSegment = dstSegment;
+
+ fSegmentRenames.push_back(info);
+}
+
+
+
+void Options::addSymbolMove(const char* dstSegment, const char* symbolList,
+ std::vector<SymbolsMove>& list, const char* optionName)
+{
+ if ( strlen(dstSegment) > 16 )
+ throwf("%s segment name max 16 chars", optionName);
+
+ SymbolsMove tmp;
+ list.push_back(tmp);
+ SymbolsMove& info = list.back();
+ info.toSegment = dstSegment;
+ loadExportFile(symbolList, optionName, info.symbols);
+}
+
+bool Options::moveRwSymbol(const char* symName, const char* filePath, const char*& seg, bool& wildCardMatch) const
+{
+ for (std::vector<SymbolsMove>::const_iterator it=fSymbolsMovesData.begin(); it != fSymbolsMovesData.end(); ++it) {
+ const SymbolsMove& info = *it;
+ if ( info.symbols.containsWithPrefix(symName, filePath, wildCardMatch)) {
+ seg = info.toSegment;
+ return true;
+ }
+ }
+ return false;
+}
+
+bool Options::moveAXMethodList(const char* className) const
+{
+ for (const SymbolsMove& sm : fSymbolsMovesAXMethodLists) {
+ bool wildcard;
+ if ( sm.symbols.containsWithPrefix(className, NULL, wildcard) )
+ return true;
+ }
+ return false;
+}
+
+bool Options::moveRoSymbol(const char* symName, const char* filePath, const char*& seg, bool& wildCardMatch) const
+{
+ for (std::vector<SymbolsMove>::const_iterator it=fSymbolsMovesCode.begin(); it != fSymbolsMovesCode.end(); ++it) {
+ const SymbolsMove& info = *it;
+ if ( info.symbols.containsWithPrefix(symName, filePath, wildCardMatch)) {
+ seg = info.toSegment;
+ return true;
+ }
+ }
+ return false;
+}
+
void Options::addSectionAlignment(const char* segment, const char* section, const char* alignmentStr)
{
if ( strlen(segment) > 16 )
}
+void Options::cannotBeUsedWithBitcode(const char* arg)
+{
+ if ( fBundleBitcode )
+ throwf("%s and -bitcode_bundle (Xcode setting ENABLE_BITCODE=YES) cannot be used together", arg);
+}
+std::string Options::getVersionString32(uint32_t ver) const
+{
+ if (ver == 0 || ver >= 0x10000000)
+ return "0.0.0";
+
+ unsigned microVersion = ver & 0xFF;
+ unsigned minorVersion = (ver >> 8) & 0xFF;
+ unsigned majorVersion = (ver >> 16) & 0xFF;
+ std::stringstream versionString;
+ versionString << majorVersion << "." << minorVersion << "." << microVersion;
+ return versionString.str();
+}
-//
-// Process all command line arguments.
-//
-// The only error checking done here is that each option is valid and if it has arguments
-// that they too are valid.
-//
-// The general rule is "last option wins", i.e. if both -bundle and -dylib are specified,
-// whichever was last on the command line is used.
-//
-// Error check for invalid combinations of options is done in checkIllegalOptionCombinations()
-//
-void Options::parse(int argc, const char* argv[])
+std::string Options::getVersionString64(uint64_t ver) const
{
- // 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);
+ uint64_t a = (ver >> 40) & 0xFFFFFF;
+ uint64_t b = (ver >> 30) & 0x3FF;
+ uint64_t c = (ver >> 20) & 0x3FF;
+ uint64_t d = (ver >> 10) & 0x3FF;
+ uint64_t e = ver & 0x3FF;
+ std::stringstream versionString;
+ versionString << a << "." << b << "." << c << "." << d << "." << e;
+ return versionString.str();
+}
- // reduce re-allocations
- fInputFiles.reserve(32);
+// Convert X.Y[.Z] to 32-bit value xxxxyyzz
+bool Options::parsePackedVersion32(const std::string& versionStr, uint32_t &result)
+{
+ result = 0;
- // pass two parse all other options
- for(int i=1; i < argc; ++i) {
- const char* arg = argv[i];
+ if ( versionStr.empty() )
+ return false;
- 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
+ size_t pos = versionStr.find('.');
+ if ( pos == std::string::npos )
+ return false;
- // 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);
+ std::string majorStr = versionStr.substr(0, pos);
+ std::string rest = versionStr.substr(pos+1);
- if ( (arg[1] == 'L') || (arg[1] == 'F') ) {
- snapshotArgCount = 0; // stripped out of link snapshot
- if (arg[2] == '\0')
+ try {
+ size_t majorEnd;
+ int majorValue = std::stoi(majorStr, &majorEnd);
+ if ( majorEnd != majorStr.size() )
+ return false;
+ if ( majorValue < 0 )
+ return false;
+ if ( majorValue > 65535 )
+ return false;
+
+ std::string minorStr;
+ std::string microStr;
+ pos = rest.find('.');
+ if ( pos == std::string::npos ) {
+ minorStr = rest;
+ }
+ else {
+ minorStr = rest.substr(0, pos);
+ microStr = rest.substr(pos+1);
+ }
+
+ size_t minorEnd;
+ int minorValue = std::stoi(minorStr, &minorEnd);
+ if ( minorEnd != minorStr.size() )
+ return false;
+ if ( minorValue < 0 )
+ return false;
+ if ( minorValue > 255 )
+ return false;
+
+ int microValue = 0;
+ if ( !microStr.empty() ) {
+ size_t microEnd;
+ microValue = std::stoi(microStr, µEnd);
+ if ( microEnd != microStr.size() )
+ return false;
+ if ( microValue < 0 )
+ return false;
+ if ( microValue > 255 )
+ return false;
+ }
+
+ result = (uint32_t)((majorValue << 16) | (minorValue << 8) | microValue);
+
+ return true;
+ }
+ catch (...) {
+ // std::stoi() throws exception on malformed input
+ return false;
+ }
+}
+
+std::string Options::getSDKVersionStr() const
+{
+ return getVersionString32(fSDKVersion);
+}
+
+std::vector<std::string> Options::writeBitcodeLinkOptions() const
+{
+ __block std::vector<std::string> linkCommand;
+ switch ( fOutputKind ) {
+ case Options::kDynamicLibrary:
+ linkCommand.push_back("-dylib");
+ linkCommand.push_back("-compatibility_version");
+ if ( fDylibCompatVersion != 0 ) {
+ linkCommand.push_back(getVersionString32(fDylibCompatVersion));
+ } else {
+ linkCommand.push_back(getVersionString32(currentVersion32()));
+ }
+ if ( fDylibCurrentVersion != 0 ) {
+ linkCommand.push_back("-current_version");
+ linkCommand.push_back(getVersionString64(fDylibCurrentVersion));
+ }
+ linkCommand.push_back("-install_name");
+ linkCommand.push_back(installPath());
+ break;
+ case Options::kDynamicExecutable:
+ linkCommand.push_back("-execute");
+ break;
+ case Options::kObjectFile:
+ linkCommand.push_back("-r");
+ break;
+ default:
+ throwf("could not write bitcode options file output kind\n");
+ }
+
+ if (!fImplicitlyLinkPublicDylibs)
+ linkCommand.push_back("-no_implicit_dylibs");
+
+ // Add deployment target.
+ // Platform is allowed to be unknown for "ld -r".
+
+ platforms().forEach(^(ld::Platform platform, uint32_t version, bool &stop) {
+ switch (platform) {
+ case ld::kPlatform_macOS:
+ linkCommand.push_back("-macosx_version_min");
+ linkCommand.push_back(getVersionString32(version));
+ break;
+ case ld::kPlatform_iOS:
+ linkCommand.push_back("-ios_version_min");
+ linkCommand.push_back(getVersionString32(version));
+ break;
+ case ld::kPlatform_iOSSimulator:
+ linkCommand.push_back("-ios_simulator_version_min");
+ linkCommand.push_back(getVersionString32(version));
+ break;
+ case ld::kPlatform_watchOS:
+ linkCommand.push_back("-watchos_version_min");
+ linkCommand.push_back(getVersionString32(version));
+ break;
+ case ld::kPlatform_watchOSSimulator:
+ linkCommand.push_back("-watchos_simulator_version_min");
+ linkCommand.push_back(getVersionString32(version));
+ break;
+ case ld::kPlatform_tvOS:
+ linkCommand.push_back("-tvos_version_min");
+ linkCommand.push_back(getVersionString32(version));
+ break;
+ case ld::kPlatform_tvOSSimulator:
+ linkCommand.push_back("-tvos_simulator_version_min");
+ linkCommand.push_back(getVersionString32(version));
+ break;
+ case ld::kPlatform_bridgeOS:
+ linkCommand.push_back("-bridgeos_version_min");
+ linkCommand.push_back(getVersionString32(version));
+ break;
+ case ld::kPlatform_iOSMac:
+ linkCommand.push_back("-iosmac_version_min");
+ linkCommand.push_back(getVersionString32(version));
+ break;
+ case ld::kPlatform_unknown:
+ if ( fOutputKind != Options::kObjectFile ) {
+ throwf("platform is unknown for final bitcode bundle,"
+ "deployment target and min version is required for -bitcode_bundle");
+ }
+ break;
+ }
+ });
+
+
+ // entry name
+ if ( fEntryName ) {
+ linkCommand.push_back("-e");
+ linkCommand.push_back(fEntryName);
+ }
+
+ // Write rpaths
+ if (!fRPaths.empty()) {
+ for (std::vector<const char*>::const_iterator it=fRPaths.begin(); it != fRPaths.end(); ++it) {
+ linkCommand.push_back("-rpath");
+ linkCommand.push_back(*it);
+ }
+ }
+
+ // Other bitcode compatiable options
+ if ( fObjCABIVersion1Override ) {
+ linkCommand.push_back("-objc_abi_version");
+ linkCommand.push_back("1");
+ } else if ( fObjCABIVersion2Override ) {
+ linkCommand.push_back("-objc_abi_version");
+ linkCommand.push_back("2");
+ }
+ if ( fExecutablePath ) {
+ linkCommand.push_back("-executable_path");
+ linkCommand.push_back(fExecutablePath);
+ }
+ if ( fDeadStrip )
+ linkCommand.push_back("-dead_strip");
+ if ( fExportDynamic )
+ linkCommand.push_back("-export_dynamic");
+ if ( fMarkAppExtensionSafe && fCheckAppExtensionSafe )
+ linkCommand.push_back("-application_extension");
+
+ if ( fSourceVersionLoadCommandForceOn )
+ linkCommand.push_back("-add_source_version");
+ if ( fSourceVersion != 0 ) {
+ linkCommand.push_back("-source_version");
+ linkCommand.push_back(getVersionString64(fSourceVersion));
+ }
+
+ // linker flag added by swift driver
+ // rdar://problem/20108072
+ if ( !fObjcCategoryMerging )
+ linkCommand.push_back("-no_objc_category_merging");
+
+ return linkCommand;
+}
+
+const char* Options::checkForNullArgument(const char* argument_name, const char* arg) const
+{
+ if ( arg == NULL )
+ throwf("missing argument for %s", argument_name);
+ return arg;
+}
+
+const char* Options::checkForNullVersionArgument(const char* argument_name, const char* arg) const
+{
+ if ( arg == NULL )
+ throwf("%s missing version argument", argument_name);
+ return arg;
+}
+
+//
+// Process all command line arguments.
+//
+// The only error checking done here is that each option is valid and if it has arguments
+// that they too are valid.
+//
+// The general rule is "last option wins", i.e. if both -bundle and -dylib are specified,
+// whichever was last on the command line is used.
+//
+// Error check for invalid combinations of options is done in checkIllegalOptionCombinations()
+//
+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);
+
+ // reduce re-allocations
+ fInputFiles.reserve(32);
+
+ // pass two parse all other options
+ for(int i=1; i < argc; ++i) {
+ 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()
}
exit (0);
}
else if ( strcmp(arg, "-arch") == 0 ) {
- parseArch(argv[++i]);
+ const char* arch = argv[++i];
+ parseArch(arch);
+ fLinkSnapshot.recordArch(arch);
}
else if ( strcmp(arg, "-dynamic") == 0 ) {
// default
if ( (fOutputKind != kObjectFile) && (fOutputKind != kKextBundle) ) {
fOutputKind = kStaticExecutable;
}
+ cannotBeUsedWithBitcode(arg);
}
else if ( strcmp(arg, "-dylib") == 0 ) {
fOutputKind = kDynamicLibrary;
}
else if ( strcmp(arg, "-bundle") == 0 ) {
fOutputKind = kDynamicBundle;
+ cannotBeUsedWithBitcode(arg);
}
else if ( strcmp(arg, "-dylinker") == 0 ) {
fOutputKind = kDyld;
+ cannotBeUsedWithBitcode(arg);
}
else if ( strcmp(arg, "-execute") == 0 ) {
if ( fOutputKind != kStaticExecutable )
}
else if ( strcmp(arg, "-preload") == 0 ) {
fOutputKind = kPreload;
+ cannotBeUsedWithBitcode(arg);
}
else if ( strcmp(arg, "-r") == 0 ) {
fOutputKind = kObjectFile;
}
else if ( strcmp(arg, "-kext") == 0 ) {
fOutputKind = kKextBundle;
+ cannotBeUsedWithBitcode(arg);
+ }
+ else if ( strcmp(arg, "-kext_objects_dir") == 0 ) {
+ fKextObjectsDirPath = argv[++i];
+ if ( fKextObjectsDirPath == NULL )
+ throw "missing argument to -kext_objects_dir";
+ fKextObjectsEnable = 1;
+ }
+ else if ( strcmp(arg, "-no_kext_objects") == 0 ) {
+ fKextObjectsEnable = 0;
}
else if ( strcmp(arg, "-o") == 0 ) {
- snapshotArgCount = 0;
- fOutputFile = argv[++i];
- fLinkSnapshot.setSnapshotName(fOutputFile);
+ snapshotArgCount = 0;
+ fOutputFile = checkForNullArgument(arg, argv[++i]);
+ fLinkSnapshot.setOutputPath(fOutputFile);
}
else if ( strncmp(arg, "-lazy-l", 7) == 0 ) {
snapshotArgCount = 0;
info.ordinal = ld::File::Ordinal::makeArgOrdinal((uint16_t)i);
addLibrary(info);
fUsingLazyDylibLinking = true;
+ cannotBeUsedWithBitcode(arg);
}
else if ( strcmp(arg, "-lto_library") == 0 ) {
snapshotFileArgIndex = 1;
if ( fOverridePathlibLTO == NULL )
throw "missing argument to -lto_library";
}
+ else if ( strcmp(arg, "-cache_path_lto") == 0 ) {
+ fLtoCachePath = argv[++i];
+ if ( fLtoCachePath == NULL )
+ throw "missing argument to -cache_path_lto";
+ }
+ else if ( strcmp(arg, "-prune_interval_lto") == 0 ) {
+ const char* value = argv[++i];
+ if ( value == NULL )
+ throw "missing argument to -prune_interval_lto";
+ char* endptr;
+ fLtoPruneIntervalOverwrite = true;
+ fLtoPruneInterval = strtoul(value, &endptr, 10);
+ if ( *endptr != '\0')
+ throw "invalid argument for -prune_interval_lto";
+ }
+ else if ( strcmp(arg, "-prune_after_lto") == 0 ) {
+ const char* value = argv[++i];
+ if ( value == NULL )
+ throw "missing argument to -prune_after_lto";
+ char* endptr;
+ fLtoPruneAfter = strtoul(value, &endptr, 10);
+ if ( *endptr != '\0')
+ throw "invalid argument for -prune_after_lto";
+ }
+ else if ( strcmp(arg, "-max_relative_cache_size_lto") == 0 ) {
+ const char* value = argv[++i];
+ if ( value == NULL )
+ throw "missing argument to -max_relative_cache_size_lto";
+ char* endptr;
+ fLtoMaxCacheSize = strtoul(value, &endptr, 10);
+ if ( *endptr != '\0')
+ throw "invalid argument for -max_relative_cache_size_lto";
+ if (fLtoMaxCacheSize > 100)
+ throw "Expect a value between 0 and 100 for -max_relative_cache_size_lto";
+ }
else if ( (arg[1] == 'l') && (strncmp(arg,"-lazy_",6) !=0) ) {
snapshotArgCount = 0;
FileInfo info = findLibrary(&arg[2]);
// Avoid lazy binding.
else if ( strcmp(arg, "-bind_at_load") == 0 ) {
fBindAtLoad = true;
+ cannotBeUsedWithBitcode(arg);
}
else if ( strcmp(arg, "-twolevel_namespace") == 0 ) {
fNameSpace = kTwoLevelNameSpace;
}
else if ( strcmp(arg, "-flat_namespace") == 0 ) {
fNameSpace = kFlatNameSpace;
+ cannotBeUsedWithBitcode(arg);
}
// Also sets a bit to ensure dyld causes everything
// in the namespace to be flat.
// ??? Deprecate
else if ( strcmp(arg, "-force_flat_namespace") == 0 ) {
fNameSpace = kForceFlatNameSpace;
+ cannotBeUsedWithBitcode(arg);
}
// Similar to --whole-archive.
else if ( strcmp(arg, "-all_load") == 0 ) {
}
// Similar to -all_load, but for the following archive only.
else if ( strcmp(arg, "-force_load") == 0 ) {
- FileInfo info = findFile(argv[++i]);
+ const char* path = checkForNullArgument(arg, argv[++i]);
+ FileInfo info = findFile(path);
info.options.fForceLoad = true;
info.ordinal = ld::File::Ordinal::makeArgOrdinal((uint16_t)i);
addLibrary(info);
snapshotFileArgIndex = 3;
parseSectionOrderFile(argv[i+1], argv[i+2], argv[i+3]);
i += 3;
+ cannotBeUsedWithBitcode(arg);
}
else if ( strcmp(arg, "-order_file") == 0 ) {
snapshotFileArgIndex = 1;
}
else if ( strcmp(arg, "-order_file_statistics") == 0 ) {
fPrintOrderFileStatistics = true;
+ cannotBeUsedWithBitcode(arg);
}
// ??? Deprecate segcreate.
// -sectcreate puts whole files into a section in the output.
warning("-seg1addr not %lld byte aligned, rounding up", fSegmentAlignment);
fBaseAddress = temp;
}
+ cannotBeUsedWithBitcode(arg);
}
else if ( strcmp(arg, "-e") == 0 ) {
fEntryName = argv[++i];
loadFileList(path, baseOrdinal);
}
else if ( strcmp(arg, "-keep_private_externs") == 0 ) {
- fKeepPrivateExterns = true;
+ cannotBeUsedWithBitcode(arg);
+ fKeepPrivateExterns = true;
}
else if ( strcmp(arg, "-final_output") == 0 ) {
fFinalName = argv[++i];
// do nothing, -interposable_list overrides -interposable"
break;
}
+ cannotBeUsedWithBitcode(arg);
}
else if ( strcmp(arg, "-interposable_list") == 0 ) {
snapshotFileArgIndex = 1;
fInterposeMode = kInterposeSome;
loadExportFile(argv[++i], "-interposable_list", fInterposeList);
+ cannotBeUsedWithBitcode(arg);
}
// Default for -interposable/-multi_module/-single_module.
else if ( strcmp(arg, "-single_module") == 0 ) {
if ( fExportMode == kDontExportSome )
throw "can't use -exported_symbol and -unexported_symbols";
fExportMode = kExportSome;
- fExportSymbols.insert(argv[++i]);
+ const char* symbol = checkForNullArgument(arg, argv[++i]);
+ fExportSymbols.insert(symbol);
}
else if ( strcmp(arg, "-unexported_symbol") == 0 ) {
if ( fExportMode == kExportSome )
throw "can't use -unexported_symbol and -exported_symbol";
fExportMode = kDontExportSome;
- fDontExportSymbols.insert(argv[++i]);
+ const char* symbol = checkForNullArgument(arg, argv[++i]);
+ fDontExportSymbols.insert(symbol);
}
else if ( strcmp(arg, "-non_global_symbols_no_strip_list") == 0 ) {
snapshotFileArgIndex = 1;
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);
+ cannotBeUsedWithBitcode(arg);
}
else if ( strcmp(arg, "-non_global_symbols_strip_list") == 0 ) {
snapshotFileArgIndex = 1;
throw "can't use -non_global_symbols_no_strip_list and -non_global_symbols_strip_list";
fLocalSymbolHandling = kLocalSymbolsSelectiveExclude;
loadExportFile(argv[++i], "-non_global_symbols_strip_list", fLocalSymbolsExcluded);
+ cannotBeUsedWithBitcode(arg);
}
// ??? Deprecate
else if ( strcmp(arg, "-no_arch_warnings") == 0 ) {
else if ( strcmp(arg, "-force_cpusubtype_ALL") == 0 ) {
fForceSubtypeAll = true;
fAllowCpuSubtypeMismatches = true;
+ cannotBeUsedWithBitcode(arg);
}
// 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]);
+ const char* path = checkForNullArgument(arg, argv[++i]);
+ FileInfo info = findFile(path);
info.options.fWeakImport = true;
info.ordinal = ld::File::Ordinal::makeArgOrdinal((uint16_t)i);
addLibrary(info);
+ cannotBeUsedWithBitcode(arg);
}
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]);
+ const char* path = checkForNullArgument(arg, argv[++i]);
+ FileInfo info = findFile(path);
info.options.fLazyLoad = true;
info.ordinal = ld::File::Ordinal::makeArgOrdinal((uint16_t)i);
addLibrary(info);
fUsingLazyDylibLinking = true;
+ cannotBeUsedWithBitcode(arg);
}
else if ( strcmp(arg, "-framework") == 0 ) {
snapshotArgCount = 0;
info.ordinal = ld::File::Ordinal::makeArgOrdinal((uint16_t)i);
addLibrary(info);
fUsingLazyDylibLinking = true;
+ cannotBeUsedWithBitcode(arg);
}
else if ( strcmp(arg, "-search_paths_first") == 0 ) {
// previously handled by buildSearchPaths()
}
else if ( strcmp(arg, "-undefined") == 0 ) {
setUndefinedTreatment(argv[++i]);
+ cannotBeUsedWithBitcode(arg);
}
// Debugging output flag.
else if ( strcmp(arg, "-arch_multiple") == 0 ) {
case kWarning:
fWarnTextRelocs = true;
fAllowTextRelocs = true;
+ cannotBeUsedWithBitcode(arg);
break;
case kSuppress:
fWarnTextRelocs = false;
fAllowTextRelocs = true;
+ cannotBeUsedWithBitcode(arg);
break;
case kError:
fWarnTextRelocs = false;
// are prebound. This can then be fixed up by update_prebinding
// later. Prebinding is less useful on 10.4 and greater.
else if ( strcmp(arg, "-prebind") == 0 ) {
- fPrebind = true;
+ warnObsolete(arg);
+ cannotBeUsedWithBitcode(arg);
}
else if ( strcmp(arg, "-noprebind") == 0 ) {
warnObsolete(arg);
- fPrebind = false;
}
else if ( strcmp(arg, "-prebind_allow_overlap") == 0 ) {
warnObsolete(arg);
// ignore for snapshot because a stub dylib will be created in the snapshot
snapshotArgCount = 0;
addDylibOverride(argv[++i]);
+ cannotBeUsedWithBitcode(arg);
}
// What to expand @executable_path to if found in dependent dylibs
else if ( strcmp(arg, "-executable_path") == 0 ) {
warning("alignment for -segalign %s is not a power of two, using 0x%X", size, p2aligned);
fSegmentAlignment = p2aligned;
}
+ cannotBeUsedWithBitcode(arg);
}
// Puts a specified segment at a particular address that must
// be a multiple of the segment alignment.
if ( seg.address != temp )
warning("-segaddr %s not %lld byte aligned", seg.name, fSegmentAlignment);
fCustomSegmentAddresses.push_back(seg);
+ cannotBeUsedWithBitcode(arg);
}
// ??? Deprecate when we deprecate split-seg.
else if ( strcmp(arg, "-segs_read_only_addr") == 0 ) {
- fBaseAddress = parseAddress(argv[++i]);
+ warnObsolete(arg);
+ ++i;
+ cannotBeUsedWithBitcode(arg);
}
// ??? Deprecate when we deprecate split-seg.
else if ( strcmp(arg, "-segs_read_write_addr") == 0 ) {
- fBaseWritableAddress = parseAddress(argv[++i]);
- fSplitSegs = true;
+ warnObsolete(arg);
+ ++i;
+ cannotBeUsedWithBitcode(arg);
}
// ??? Deprecate when we get rid of basing at build time.
else if ( strcmp(arg, "-seg_addr_table") == 0 ) {
+ warnObsolete(arg);
snapshotFileArgIndex = 1;
const char* name = argv[++i];
if ( name == NULL )
throw "-seg_addr_table missing argument";
- fSegAddrTablePath = name;
+ cannotBeUsedWithBitcode(arg);
}
else if ( strcmp(arg, "-seg_addr_table_filename") == 0 ) {
warnObsolete(arg);
throw "-segprot missing segName max-prot init-prot";
seg.max = parseProtection(argv[++i]);
seg.init = parseProtection(argv[++i]);
- fCustomSegmentProtections.push_back(seg);
+ if ( strcmp(seg.name, "__LINKEDIT") == 0 )
+ warning("-segprot cannot be used to modify __LINKEDIT protections");
+ else
+ fCustomSegmentProtections.push_back(seg);
+ cannotBeUsedWithBitcode(arg);
}
else if ( strcmp(arg, "-pagezero_size") == 0 ) {
const char* size = argv[++i];
if ( (fZeroPageSize != temp) )
warning("-pagezero_size not page aligned, rounding down");
fZeroPageSize = temp;
+ cannotBeUsedWithBitcode(arg);
}
else if ( strcmp(arg, "-stack_addr") == 0 ) {
const char* address = argv[++i];
if ( address == NULL )
throw "-stack_addr missing <address>";
fStackAddr = parseAddress(address);
+ cannotBeUsedWithBitcode(arg);
}
else if ( strcmp(arg, "-stack_size") == 0 ) {
const char* size = argv[++i];
if ( size == NULL )
throw "-stack_size missing <address>";
fStackSize = parseAddress(size);
- uint64_t temp = fStackSize & (-4096); // page align
- if ( (fStackSize != temp) )
- warning("-stack_size not page aligned, rounding down");
}
else if ( strcmp(arg, "-allow_stack_execute") == 0 ) {
fExecutableStack = true;
+ cannotBeUsedWithBitcode(arg);
}
else if ( strcmp(arg, "-allow_heap_execute") == 0 ) {
fDisableNonExecutableHeap = true;
+ cannotBeUsedWithBitcode(arg);
}
else if ( strcmp(arg, "-sectalign") == 0 ) {
if ( (argv[i+1]==NULL) || (argv[i+2]==NULL) || (argv[i+3]==NULL) )
throw "-sectalign missing <segment> <section> <file-path>";
addSectionAlignment(argv[i+1], argv[i+2], argv[i+3]);
i += 3;
+ cannotBeUsedWithBitcode(arg);
}
else if ( strcmp(arg, "-sectorder_detail") == 0 ) {
warnObsolete(arg);
}
// Use this flag to set default behavior for deployement targets.
else if ( strcmp(arg, "-macosx_version_min") == 0 ) {
- const char* macVers = argv[++i];
+ const char* macVers = checkForNullVersionArgument(arg, argv[++i]);
const char* envMacVers = getenv("MACOSX_DEPLOYMENT_TARGET");
const char* enviPhoneVers = getenv("IPHONEOS_DEPLOYMENT_TARGET");
if ( (envMacVers != NULL) && (enviPhoneVers != NULL) ) {
const char* sysrootPath = fSDKPaths.back();
const char* lastSlash = strrchr(sysrootPath, '/');
if ( strstr(lastSlash, "Simulator") != NULL )
- setIOSVersionMin(enviPhoneVers);
+ setVersionMin(ld::kPlatform_iOS, enviPhoneVers);
else
- setMacOSXVersionMin(macVers);
+ setVersionMin(ld::kPlatform_macOS, macVers);
}
else {
- setMacOSXVersionMin(macVers);
+ setVersionMin(ld::kPlatform_macOS, macVers);
}
}
else {
- setMacOSXVersionMin(macVers);
+ setVersionMin(ld::kPlatform_macOS, macVers);
}
}
else if ( (strcmp(arg, "-ios_version_min") == 0) || (strcmp(arg, "-iphoneos_version_min") == 0) ) {
- setIOSVersionMin(argv[++i]);
+ const char* vers = checkForNullVersionArgument(arg, argv[++i]);
+ setVersionMin(ld::kPlatform_iOS, vers);
}
else if ( strcmp(arg, "-ios_simulator_version_min") == 0 ) {
- setIOSVersionMin(argv[++i]);
- fTargetIOSSimulator = true;
+ const char* vers = checkForNullVersionArgument(arg, argv[++i]);
+ setVersionMin(ld::kPlatform_iOSSimulator, vers);
+ }
+ else if ( strcmp(arg, "-watchos_version_min") == 0 ) {
+ const char* vers = checkForNullVersionArgument(arg, argv[++i]);
+ setVersionMin(ld::kPlatform_watchOS, vers);
+ }
+ else if ( strcmp(arg, "-watchos_simulator_version_min") == 0 ) {
+ const char* vers = checkForNullVersionArgument(arg, argv[++i]);
+ setVersionMin(ld::kPlatform_watchOSSimulator, vers);
+ }
+ else if ( strcmp(arg, "-tvos_version_min") == 0 ) {
+ const char* vers = checkForNullVersionArgument(arg, argv[++i]);
+ setVersionMin(ld::kPlatform_tvOS, vers);
+ }
+ else if ( strcmp(arg, "-tvos_simulator_version_min") == 0 ) {
+ const char* vers = checkForNullVersionArgument(arg, argv[++i]);
+ setVersionMin(ld::kPlatform_tvOSSimulator, vers);
+ }
+ else if ( strcmp(arg, "-bridgeos_version_min") == 0 ) {
+ const char* vers = checkForNullVersionArgument(arg, argv[++i]);
+ setVersionMin(ld::kPlatform_bridgeOS, vers);
+ }
+ else if ( strcmp(arg, "-iosmac_version_min") == 0 ) {
+ const char* vers = checkForNullVersionArgument(arg, argv[++i]);
+ setVersionMin(ld::kPlatform_iOSMac, vers);
}
else if ( strcmp(arg, "-multiply_defined") == 0 ) {
//warnObsolete(arg);
if ( name == NULL )
throw "-u missing argument";
fInitialUndefines.push_back(name);
+ cannotBeUsedWithBitcode(arg);
}
else if ( strcmp(arg, "-U") == 0 ) {
const char* name = argv[++i];
if ( name == NULL )
throw "-U missing argument";
fAllowedUndefined.insert(name);
+ cannotBeUsedWithBitcode(arg);
}
else if ( strcmp(arg, "-s") == 0 ) {
warnObsolete(arg);
if ( size == NULL )
throw "-headerpad missing argument";
fMinimumHeaderPad = parseAddress(size);
+ cannotBeUsedWithBitcode(arg);
}
else if ( strcmp(arg, "-headerpad_max_install_names") == 0 ) {
- fMaxMinimumHeaderPad = true;
+ // ignore -headerpad_max_install_names when compiling with bitcode
+ // rdar://problem/20748962
+ if ( fBundleBitcode )
+ warning("-headerpad_max_install_names is ignored when used with -bitcode_bundle (Xcode setting ENABLE_BITCODE=YES)");
+ else
+ fMaxMinimumHeaderPad = true;
}
else if ( strcmp(arg, "-t") == 0 ) {
fLogAllFiles = true;
if ( name == NULL )
throw "-umbrella missing argument";
fUmbrellaName = name;
+ cannotBeUsedWithBitcode(arg);
}
else if ( strcmp(arg, "-allowable_client") == 0 ) {
const char* name = argv[++i];
throw "-allowable_client missing argument";
fAllowableClients.push_back(name);
+ cannotBeUsedWithBitcode(arg);
}
else if ( strcmp(arg, "-client_name") == 0 ) {
const char* name = argv[++i];
throw "-client_name missing argument";
fClientName = name;
+ cannotBeUsedWithBitcode(arg);
}
else if ( strcmp(arg, "-sub_umbrella") == 0 ) {
const char* name = argv[++i];
if ( name == NULL )
throw "-sub_umbrella missing argument";
fSubUmbellas.push_back(name);
+ cannotBeUsedWithBitcode(arg);
}
else if ( strcmp(arg, "-sub_library") == 0 ) {
const char* name = argv[++i];
if ( name == NULL )
throw "-sub_library missing argument";
fSubLibraries.push_back(name);
+ cannotBeUsedWithBitcode(arg);
}
else if ( strcmp(arg, "-init") == 0 ) {
const char* name = argv[++i];
if ( name == NULL )
throw "-init missing argument";
fInitFunctionName = name;
+ cannotBeUsedWithBitcode(arg);
}
else if ( strcmp(arg, "-dot") == 0 ) {
const char* name = argv[++i];
if ( name == NULL )
throw "-dot missing argument";
fDotOutputFile = name;
+ cannotBeUsedWithBitcode(arg);
}
else if ( strcmp(arg, "-warn_commons") == 0 ) {
fWarnCommons = true;
++i;
// previously handled by buildSearchPaths()
}
+ else if ( strcmp(arg, "-bitcode_bundle") == 0 ) {
+ snapshotArgCount = 0;
+ // previously handled by buildSearchPaths()
+ }
else if ( strcmp(arg, "-no_uuid") == 0 ) {
fUUIDMode = kUUIDNone;
+ cannotBeUsedWithBitcode(arg);
}
else if ( strcmp(arg, "-random_uuid") == 0 ) {
fUUIDMode = kUUIDRandom;
+ cannotBeUsedWithBitcode(arg);
}
else if ( strcmp(arg, "-dtrace") == 0 ) {
snapshotFileArgIndex = 1;
if ( name == NULL )
throw "-dtrace missing argument";
fDtraceScriptName = name;
+ cannotBeUsedWithBitcode(arg);
}
else if ( strcmp(arg, "-root_safe") == 0 ) {
fRootSafe = true;
}
else if ( strcmp(arg, "-alias") == 0 ) {
Options::AliasPair pair;
- pair.realName = argv[++i];
- if ( pair.realName == NULL )
- throw "missing argument to -alias";
- pair.alias = argv[++i];
- if ( pair.alias == NULL )
- throw "missing argument to -alias";
+ pair.realName = checkForNullArgument(arg, argv[++i]);
+ pair.alias = checkForNullArgument(arg, argv[++i]);
fAliases.push_back(pair);
+ cannotBeUsedWithBitcode(arg);
}
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'
- 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);
+ cannotBeUsedWithBitcode(arg);
}
else if ( strcmp(arg, "-save-temps") == 0 ) {
fSaveTempFiles = true;
}
+ else if ( strcmp(arg, "-bitcode_hide_symbols") == 0 ) {
+ fHideSymbols = true;
+ }
+ else if ( strcmp(arg, "-bitcode_verify") == 0 ) {
+ fVerifyBitcode = true;
+ }
+ else if ( strcmp(arg, "-bitcode_symbol_map") == 0) {
+ fReverseMapPath = checkForNullArgument(arg, argv[++i]);
+ struct stat statbuf;
+ int ret = ::stat(fReverseMapPath, &statbuf);
+ if ( ret == 0 && S_ISDIR(statbuf.st_mode)) {
+ char tempPath[PATH_MAX];
+ sprintf(tempPath, "%s/XXXXXX", fReverseMapPath);
+ int tempFile = ::mkstemp(tempPath);
+ if (tempFile == -1)
+ throwf("could not write file to symbol map directory: %s", fReverseMapPath);
+ ::close(tempFile);
+ fReverseMapTempPath = std::string(tempPath);
+ fReverseMapUUIDRename = true;
+ } else
+ fReverseMapTempPath = std::string(fReverseMapPath);
+ }
+ else if ( strcmp(arg, "-flto-codegen-only") == 0) {
+ fLTOCodegenOnly = true;
+ }
+ else if ( strcmp(arg, "-ignore_auto_link") == 0) {
+ fIgnoreAutoLink = true;
+ }
+ else if ( strcmp(arg, "-allow_dead_duplicates") == 0) {
+ fAllowDeadDups = true;
+ }
+ else if ( strcmp(arg, "-bitcode_process_mode") == 0 ) {
+ const char* bitcode_type = checkForNullArgument(arg, argv[++i]);
+ if ( strcmp(bitcode_type, "strip") == 0 )
+ fBitcodeKind = kBitcodeStrip;
+ else if ( strcmp(bitcode_type, "marker") == 0 )
+ fBitcodeKind = kBitcodeMarker;
+ else if ( strcmp(bitcode_type, "data") == 0 )
+ fBitcodeKind = kBitcodeAsData;
+ else if ( strcmp(bitcode_type, "bitcode") == 0 )
+ fBitcodeKind = kBitcodeProcess;
+ else
+ throw "unknown argument to -bitcode_process_mode {strip,marker,data,bitcode}";
+ }
else if ( strcmp(arg, "-rpath") == 0 ) {
- const char* path = argv[++i];
- if ( path == NULL )
- throw "missing argument to -rpath";
+ const char* path = checkForNullArgument(arg, argv[++i]);
fRPaths.push_back(path);
}
else if ( strcmp(arg, "-read_only_stubs") == 0 ) {
warnObsolete(arg);
}
else if ( strcmp(arg, "-map") == 0 ) {
- fMapPath = argv[++i];
- if ( fMapPath == NULL )
- throw "missing argument to -map";
+ fMapPath = checkForNullArgument(arg, argv[++i]);
}
else if ( strcmp(arg, "-pie") == 0 ) {
fPositionIndependentExecutable = true;
}
else if ( strcmp(arg, "-no_pie") == 0 ) {
fDisablePositionIndependentExecutable = true;
+ cannotBeUsedWithBitcode(arg);
}
else if ( strncmp(arg, "-reexport-l", 11) == 0 ) {
// SNAPSHOT FIXME: what should we do for link snapshots? (ignore for now)
info.options.fReExport = true;
info.ordinal = ld::File::Ordinal::makeArgOrdinal((uint16_t)i);
addLibrary(info);
+ cannotBeUsedWithBitcode(arg);
}
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]);
+ const char* path = checkForNullArgument(arg, argv[++i]);
+ FileInfo info = findFile(path);
info.options.fReExport = true;
info.ordinal = ld::File::Ordinal::makeArgOrdinal((uint16_t)i);
addLibrary(info);
+ cannotBeUsedWithBitcode(arg);
}
else if ( strcmp(arg, "-reexport_framework") == 0 ) {
// SNAPSHOT FIXME: what should we do for link snapshots? (ignore for now)
info.options.fReExport = true;
info.ordinal = ld::File::Ordinal::makeArgOrdinal((uint16_t)i);
addLibrary(info);
+ cannotBeUsedWithBitcode(arg);
}
else if ( strncmp(arg, "-upward-l", 9) == 0 ) {
// SNAPSHOT FIXME: what should we do for link snapshots? (ignore for now)
info.options.fUpward = true;
info.ordinal = ld::File::Ordinal::makeArgOrdinal((uint16_t)i);
addLibrary(info);
+ cannotBeUsedWithBitcode(arg);
}
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]);
+ const char* path = checkForNullArgument(arg, argv[++i]);
+ FileInfo info = findFile(path);
info.options.fUpward = true;
info.ordinal = ld::File::Ordinal::makeArgOrdinal((uint16_t)i);
addLibrary(info);
+ cannotBeUsedWithBitcode(arg);
}
else if ( strcmp(arg, "-upward_framework") == 0 ) {
// SNAPSHOT FIXME: what should we do for link snapshots? (ignore for now)
info.options.fUpward = true;
info.ordinal = ld::File::Ordinal::makeArgOrdinal((uint16_t)i);
addLibrary(info);
+ cannotBeUsedWithBitcode(arg);
}
else if ( strcmp(arg, "-dead_strip_dylibs") == 0 ) {
fDeadStripDylibs = true;
+ cannotBeUsedWithBitcode(arg);
}
else if ( strcmp(arg, "-no_implicit_dylibs") == 0 ) {
fImplicitlyLinkPublicDylibs = false;
// ignore
}
else if ( strcmp(arg, "-no_encryption") == 0 ) {
- fEncryptable = false;
+ fEncryptableForceOff = true;
+ cannotBeUsedWithBitcode(arg);
+ }
+ else if ( strcmp(arg, "-encryptable") == 0 ) {
+ fEncryptableForceOn = true;
+ cannotBeUsedWithBitcode(arg);
}
else if ( strcmp(arg, "-no_compact_unwind") == 0 ) {
fAddCompactUnwindEncoding = false;
+ cannotBeUsedWithBitcode(arg);
}
else if ( strcmp(arg, "-mllvm") == 0 ) {
- const char* opts = argv[++i];
- if ( opts == NULL )
- throw "missing argument to -mllvm";
+ const char* opts = checkForNullArgument(arg, argv[++i]);
fLLVMOptions.push_back(opts);
+ cannotBeUsedWithBitcode(arg);
}
else if ( strcmp(arg, "-mcpu") == 0 ) {
- const char* cpu = argv[++i];
- if ( cpu == NULL )
- throw "missing argument to -mcpu";
+ const char* cpu = checkForNullArgument(arg, argv[++i]);
fLtoCpu = cpu;
+ cannotBeUsedWithBitcode(arg);
}
else if ( strcmp(arg, "-no_order_inits") == 0 ) {
fAutoOrderInitializers = false;
+ cannotBeUsedWithBitcode(arg);
}
else if ( strcmp(arg, "-no_order_data") == 0 ) {
fOrderData = false;
+ cannotBeUsedWithBitcode(arg);
}
else if ( strcmp(arg, "-seg_page_size") == 0 ) {
SegmentSize seg;
if ( (seg.size != temp) )
warning("-seg_page_size %s not 4K aligned, rounding down", seg.name);
fCustomSegmentSizes.push_back(seg);
+ cannotBeUsedWithBitcode(arg);
}
else if ( strcmp(arg, "-mark_dead_strippable_dylib") == 0 ) {
fMarkDeadStrippableDylib = true;
+ cannotBeUsedWithBitcode(arg);
}
else if ( strcmp(arg, "-exported_symbols_order") == 0 ) {
snapshotFileArgIndex = 1;
loadSymbolOrderFile(argv[++i], fExportSymbolsOrder);
+ cannotBeUsedWithBitcode(arg);
}
else if ( strcmp(arg, "-no_compact_linkedit") == 0 ) {
warnObsolete("-no_compact_linkedit");
}
else if ( strcmp(arg, "-no_eh_labels") == 0 ) {
fNoEHLabels = true;
+ cannotBeUsedWithBitcode(arg);
}
else if ( strcmp(arg, "-warn_compact_unwind") == 0 ) {
fWarnCompactUnwind = true;
}
else if ( strcmp(arg, "-allow_sub_type_mismatches") == 0 ) {
fAllowCpuSubtypeMismatches = true;
+ cannotBeUsedWithBitcode(arg);
}
else if ( strcmp(arg, "-no_zero_fill_sections") == 0 ) {
fOptimizeZeroFill = false;
+ cannotBeUsedWithBitcode(arg);
}
else if ( strcmp(arg, "-merge_zero_fill_sections") == 0 ) {
fMergeZeroFill = true;
+ cannotBeUsedWithBitcode(arg);
}
else if ( strcmp(arg, "-objc_abi_version") == 0 ) {
- const char* version = argv[++i];
- if ( version == NULL )
- throw "-objc_abi_version missing version number";
+ const char* version = checkForNullVersionArgument(arg, argv[++i]);
if ( strcmp(version, "2") == 0 ) {
fObjCABIVersion1Override = false;
fObjCABIVersion2Override = true;
else if ( strcmp(arg, "-warn_weak_exports") == 0 ) {
fWarnWeakExports = true;
}
+ else if ( strcmp(arg, "-no_weak_exports") == 0 ) {
+ fNoWeakExports = true;
+ }
else if ( strcmp(arg, "-objc_gc_compaction") == 0 ) {
fObjcGcCompaction = true;
+ cannotBeUsedWithBitcode(arg);
}
else if ( strcmp(arg, "-objc_gc") == 0 ) {
fObjCGc = true;
- if ( fObjCGcOnly ) {
+ if ( fObjCGcOnly ) {
warning("-objc_gc overriding -objc_gc_only");
- fObjCGcOnly = false;
+ fObjCGcOnly = false;
}
+ cannotBeUsedWithBitcode(arg);
}
else if ( strcmp(arg, "-objc_gc_only") == 0 ) {
fObjCGcOnly = true;
- if ( fObjCGc ) {
+ if ( fObjCGc ) {
warning("-objc_gc_only overriding -objc_gc");
- fObjCGc = false;
+ fObjCGc = false;
}
+ cannotBeUsedWithBitcode(arg);
}
else if ( strcmp(arg, "-demangle") == 0 ) {
fDemangle = true;
fVersionLoadCommandForcedOn = true;
fVersionLoadCommandForcedOff = false;
}
- else if ( strcmp(arg, "-no_version_load_command") == 0 ) {
- fVersionLoadCommandForcedOff = true;
- fVersionLoadCommandForcedOn = false;
- }
else if ( strcmp(arg, "-function_starts") == 0 ) {
fFunctionStartsForcedOn = true;
fFunctionStartsForcedOff = false;
else if ( strcmp(arg, "-no_function_starts") == 0 ) {
fFunctionStartsForcedOff = true;
fFunctionStartsForcedOn = false;
+ cannotBeUsedWithBitcode(arg);
}
else if ( strcmp(arg, "-no_data_in_code_info") == 0 ) {
fDataInCodeInfoLoadCommandForcedOff = true;
fDataInCodeInfoLoadCommandForcedOn = false;
+ cannotBeUsedWithBitcode(arg);
}
else if ( strcmp(arg, "-data_in_code_info") == 0 ) {
fDataInCodeInfoLoadCommandForcedOn = true;
fDataInCodeInfoLoadCommandForcedOff = false;
}
else if ( strcmp(arg, "-object_path_lto") == 0 ) {
- fTempLtoObjectPath = argv[++i];
- if ( fTempLtoObjectPath == NULL )
- throw "missing argument to -object_path_lto";
+ fTempLtoObjectPath = checkForNullArgument(arg, argv[++i]);
}
else if ( strcmp(arg, "-no_objc_category_merging") == 0 ) {
fObjcCategoryMerging = false;
else if ( strcmp(arg, "-force_symbols_weak_list") == 0 ) {
snapshotFileArgIndex = 1;
loadExportFile(argv[++i], "-force_symbols_weak_list", fForceWeakSymbols);
+ cannotBeUsedWithBitcode(arg);
}
else if ( strcmp(arg, "-force_symbols_not_weak_list") == 0 ) {
snapshotFileArgIndex = 1;
loadExportFile(argv[++i], "-force_symbols_not_weak_list", fForceNotWeakSymbols);
+ cannotBeUsedWithBitcode(arg);
}
else if ( strcmp(arg, "-force_symbol_weak") == 0 ) {
const char* symbol = argv[++i];
if ( symbol == NULL )
throw "-force_symbol_weak missing <symbol>";
fForceWeakSymbols.insert(symbol);
+ cannotBeUsedWithBitcode(arg);
}
else if ( strcmp(arg, "-force_symbol_not_weak") == 0 ) {
const char* symbol = argv[++i];
if ( symbol == NULL )
throw "-force_symbol_not_weak missing <symbol>";
fForceNotWeakSymbols.insert(symbol);
+ cannotBeUsedWithBitcode(arg);
}
else if ( strcmp(arg, "-reexported_symbols_list") == 0 ) {
snapshotFileArgIndex = 1;
if ( strchr(envarg, '=') == NULL )
throw "-dyld_env missing ENV=VALUE";
fDyldEnvironExtras.push_back(envarg);
+ cannotBeUsedWithBitcode(arg);
}
else if ( strcmp(arg, "-page_align_data_atoms") == 0 ) {
fPageAlignDataAtoms = true;
+ cannotBeUsedWithBitcode(arg);
}
else if (strcmp(arg, "-debug_snapshot") == 0) {
fLinkSnapshot.setSnapshotMode(Snapshot::SNAPSHOT_DEBUG);
fSnapshotRequested = true;
+ cannotBeUsedWithBitcode(arg);
}
else if (strcmp(arg, "-snapshot_dir") == 0) {
const char* path = argv[++i];
fLinkSnapshot.setSnapshotMode(Snapshot::SNAPSHOT_DEBUG);
fLinkSnapshot.setSnapshotPath(path);
fSnapshotRequested = true;
+ cannotBeUsedWithBitcode(arg);
}
- 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 )
}
else if ( strcmp(arg, "-no_source_version") == 0 ) {
fSourceVersionLoadCommandForceOff = true;
+ cannotBeUsedWithBitcode(arg);
}
else if ( strcmp(arg, "-sdk_version") == 0 ) {
const char* vers = argv[++i];
fSDKVersion = parseVersionNumber32(vers);
}
else if ( strcmp(arg, "-dependent_dr_info") == 0 ) {
- fDependentDRInfoForcedOn = true;
+ warnObsolete(arg);
}
else if ( strcmp(arg, "-no_dependent_dr_info") == 0 ) {
- fDependentDRInfoForcedOff = true;
+ warnObsolete(arg);
}
else if ( strcmp(arg, "-kexts_use_stubs") == 0 ) {
fKextsUseStubs = true;
+ cannotBeUsedWithBitcode(arg);
}
- else if ( strcmp(argv[i], "-dependency_info") == 0 ) {
+ else if ( strcmp(arg, "-dependency_info") == 0 ) {
+ snapshotArgCount = 0;
++i;
// previously handled by buildSearchPaths()
}
}
}
fLinkerOptions.push_back(opts);
+ cannotBeUsedWithBitcode(arg);
}
else if ( strcmp(arg, "-allow_simulator_linking_to_macosx_dylibs") == 0 ) {
fAllowSimulatorToLinkWithMacOSX = true;
+ cannotBeUsedWithBitcode(arg);
}
else if ( strcmp(arg, "-keep_dwarf_unwind") == 0 ) {
fKeepDwarfUnwindForcedOn = true;
fKeepDwarfUnwindForcedOff = false;
+ cannotBeUsedWithBitcode(arg);
}
else if ( strcmp(arg, "-no_keep_dwarf_unwind") == 0 ) {
fKeepDwarfUnwindForcedOn = false;
fKeepDwarfUnwindForcedOff = true;
+ cannotBeUsedWithBitcode(arg);
+ }
+ else if ( strcmp(arg, "-verbose_optimization_hints") == 0 ) {
+ fVerboseOptimizationHints = true;
+ }
+ else if ( strcmp(arg, "-ignore_optimization_hints") == 0 ) {
+ fIgnoreOptimizationHints = true;
+ cannotBeUsedWithBitcode(arg);
}
else if ( strcmp(arg, "-no_dtrace_dof") == 0 ) {
fGenerateDtraceDOF = false;
}
+ else if ( strcmp(arg, "-rename_section") == 0 ) {
+ if ( (argv[i+1]==NULL) || (argv[i+2]==NULL) || (argv[i+3]==NULL) || (argv[i+4]==NULL) )
+ throw "-rename_section missing <segment> <section> <segment> <section>";
+ addSectionRename(argv[i+1], argv[i+2], argv[i+3], argv[i+4]);
+ i += 4;
+ cannotBeUsedWithBitcode(arg);
+ }
+ else if ( strcmp(arg, "-rename_segment") == 0 ) {
+ if ( (argv[i+1]==NULL) || (argv[i+2]==NULL) )
+ throw "-rename_segment missing <existing-segment> <new-segment>";
+ addSegmentRename(argv[i+1], argv[i+2]);
+ i += 2;
+ cannotBeUsedWithBitcode(arg);
+ }
+ else if ( strcmp(arg, "-move_to_ro_segment") == 0 ) {
+ if ( (argv[i+1]==NULL) || (argv[i+2]==NULL) )
+ throw "-move_to_ro_segment missing <segment> <symbol-list-file>";
+ addSymbolMove(argv[i+1], argv[i+2], fSymbolsMovesCode, "-move_to_ro_segment");
+ i += 2;
+ cannotBeUsedWithBitcode(arg);
+ }
+ else if ( strcmp(arg, "-move_to_rw_segment") == 0 ) {
+ if ( (argv[i+1]==NULL) || (argv[i+2]==NULL) )
+ throw "-move_to_rw_segment missing <segment> <symbol-list-file>";
+ addSymbolMove(argv[i+1], argv[i+2], fSymbolsMovesData, "-move_to_rw_segment");
+ i += 2;
+ cannotBeUsedWithBitcode(arg);
+ }
+ else if ( strcmp(arg, "-trace_symbol_layout") == 0 ) {
+ fTraceSymbolLayout = true;
+ }
+ else if ( strcmp(arg, "-no_branch_islands") == 0 ) {
+ fAllowBranchIslands = false;
+ cannotBeUsedWithBitcode(arg);
+ }
+ else if ( strcmp(arg, "-segment_order") == 0 ) {
+ // ex: -segment_order __TEXT:__DATA:__JUNK
+ const char* optString = argv[++i];
+ if ( optString == NULL )
+ throw "-segment_order missing colon separated <segment-list>";
+ if ( !fSegmentOrder.empty() )
+ throw "-segment_order used more than once";
+ // break up into list of tokens at colon
+ char* buffer = strdup(optString);
+ char* start = buffer;
+ for (char* s = buffer; ; ++s) {
+ if ( *s == ':' ) {
+ *s = '\0';
+ fSegmentOrder.push_back(start);
+ start = s+1;
+ }
+ else if ( *s == '\0' ) {
+ fSegmentOrder.push_back(start);
+ break;
+ }
+ }
+ cannotBeUsedWithBitcode(arg);
+ }
+ else if ( strcmp(arg, "-section_order") == 0 ) {
+ // ex: -section_order __DATA __data:__const:__nl_pointers
+ if ( (argv[i+1]==NULL) || (argv[i+2]==NULL) )
+ throw "-section_order missing <segment> <section-list>";
+ const char* segName = argv[++i];
+ const char* optString = argv[++i];
+ if ( sectionOrder(segName) != NULL )
+ throwf("-section_order %s ... used more than once", segName);
+ SectionOrderList dummy;
+ fSectionOrder.push_back(dummy);
+ SectionOrderList& entry = fSectionOrder.back();
+ entry.segmentName = segName;
+ // break up into list of tokens at colon
+ char* buffer = strdup(optString);
+ char* start = buffer;
+ for (char* s = buffer; ; ++s) {
+ if ( *s == ':' ) {
+ *s = '\0';
+ entry.sectionOrder.push_back(start);
+ start = s+1;
+ }
+ else if ( *s == '\0' ) {
+ entry.sectionOrder.push_back(start);
+ break;
+ }
+ }
+ cannotBeUsedWithBitcode(arg);
+ }
+ else if ( strcmp(arg, "-application_extension") == 0 ) {
+ fMarkAppExtensionSafe = true;
+ fCheckAppExtensionSafe = true;
+ }
+ else if ( strcmp(arg, "-no_application_extension") == 0 ) {
+ fMarkAppExtensionSafe = false;
+ fCheckAppExtensionSafe = false;
+ }
+ else if ( strcmp(arg, "-add_ast_path") == 0 ) {
+ const char* path = argv[++i];
+ if ( path == NULL )
+ throw "-add_ast_path missing <option>";
+ fASTFilePaths.push_back(path);
+ }
+ else if ( strcmp(arg, "-force_load_swift_libs") == 0 ) {
+ fForceLoadSwiftLibs = true;
+ }
+ else if ( strcmp(arg, "-not_for_dyld_shared_cache") == 0 ) {
+ fSharedRegionEligibleForceOff = true;
+ cannotBeUsedWithBitcode(arg);
+ }
+ else if ( strcmp(arg, "-dirty_data_list") == 0 ) {
+ if ( argv[i+1] == NULL )
+ throw "-dirty_data_list missing <symbol-list-file>";
+ addSymbolMove("__DATA_DIRTY", argv[i+1], fSymbolsMovesData, "-dirty_data_list");
+ ++i;
+ cannotBeUsedWithBitcode(arg);
+ }
+ else if ( strcmp(arg, "-data_const") == 0 ) {
+ fUseDataConstSegmentForceOn = true;
+ cannotBeUsedWithBitcode(arg);
+ }
+ else if ( strcmp(arg, "-no_data_const") == 0 ) {
+ fUseDataConstSegmentForceOff = true;
+ cannotBeUsedWithBitcode(arg);
+ }
+ else if ( strcmp(arg, "-text_exec") == 0 ) {
+ fUseTextExecSegment = true;
+ cannotBeUsedWithBitcode(arg);
+ }
+ else if ( strcmp(arg, "-add_split_seg_info") == 0) {
+ fSharedRegionEligible = true;
+ cannotBeUsedWithBitcode(arg);
+ }
+ else if ( strcmp(arg, "-no_deduplicate") == 0 ) {
+ fDeDupe = false;
+ }
+ else if ( strcmp(arg, "-verbose_deduplicate") == 0 ) {
+ fVerboseDeDupe = true;
+ }
+ else if ( strcmp(arg, "-max_default_common_align") == 0 ) {
+ const char* alignStr = argv[++i];
+ if ( alignStr == NULL )
+ throw "-max_default_common_align missing <align-value>";
+ // argument is a hexadecimal number
+ char* endptr;
+ unsigned long value = strtoul(alignStr, &endptr, 16);
+ if ( *endptr != '\0')
+ throw "argument for -max_default_common_align is not a hexadecimal number";
+ if ( value > 0x8000 )
+ throw "argument for -max_default_common_align must be less than or equal to 0x8000";
+ if ( value == 0 ) {
+ warning("zero is not a valid -max_default_common_align");
+ value = 1;
+ }
+ // alignment is power of 2
+ uint8_t alignment = (uint8_t)__builtin_ctz(value);
+ if ( (unsigned long)(1 << alignment) != value ) {
+ warning("alignment for -max_default_common_align is not a power of two, using 0x%X", 1 << alignment);
+ }
+ fMaxDefaultCommonAlign = alignment;
+ }
+ else if ( strcmp(arg, "-no_weak_imports") == 0 ) {
+ fAllowWeakImports = false;
+ }
+ else if ( strcmp(arg, "-no_inits") == 0 ) {
+ fInitializersTreatment = Options::kError;
+ }
+ else if ( strcmp(arg, "-no_warn_inits") == 0 ) {
+ fInitializersTreatment = Options::kSuppress;
+ }
+ else if ( strcmp(arg, "-threaded_starts_section") == 0 ) {
+ fMakeThreadedStartsSection = true;
+ }
+ else if (strcmp(arg, "-debug_variant") == 0) {
+ fDebugVariant = true;
+ }
+ else if (strcmp(arg, "-no_new_main") == 0) {
+ // HACK until 39514191 is fixed
+ }
+ // 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 {
throwf("unknown option: %s", arg);
}
if (fSnapshotRequested)
fLinkSnapshot.createSnapshot();
-}
-
+ if ( kKextBundle == fOutputKind ) {
+ if ( fKextObjectsEnable < 0 )
+ fKextObjectsEnable = ((fArchitecture == CPU_TYPE_ARM64) || (fArchitecture == CPU_TYPE_ARM));
+
+ if (fKextObjectsEnable > 0) {
+ if ( !fKextObjectsDirPath ) {
+ const char* dstroot;
+ const char* objdir = getenv("LD_KEXT_OBJECTS_DIR");
+ if ( objdir )
+ fKextObjectsDirPath = strdup(objdir);
+ else if ( (dstroot = getenv("DSTROOT")) )
+ asprintf((char **)&fKextObjectsDirPath, "%s/AppleInternal/KextObjects", dstroot);
+ }
+ fLinkSnapshot.setSnapshotMode(Snapshot::SNAPSHOT_KEXT);
+ fLinkSnapshot.createSnapshot();
+ }
+ }
+}
//
// -syslibroot <path> is used for SDK support.
}
if ( libSearchDir[0] == '\0' )
throw "-L must be immediately followed by a directory path (no space)";
- struct stat statbuf;
- if ( stat(libSearchDir, &statbuf) == 0 ) {
- if ( statbuf.st_mode & S_IFDIR )
- libraryPaths.push_back(libSearchDir);
- else
- warning("path '%s' following -L not a directory", libSearchDir);
- }
- else {
- warning("directory not found for option '-L%s'", libSearchDir);
- }
+ libraryPaths.push_back(libSearchDir);
}
else if ( (argv[i][0] == '-') && (argv[i][1] == 'F') ) {
const char* frameworkSearchDir = &argv[i][2];
}
if ( frameworkSearchDir[0] == '\0' )
throw "-F must be immediately followed by a directory path (no space)";
- struct stat statbuf;
- if ( stat(frameworkSearchDir, &statbuf) == 0 ) {
- if ( statbuf.st_mode & S_IFDIR )
- frameworkPaths.push_back(frameworkSearchDir);
- else
- warning("path '%s' following -F not a directory", frameworkSearchDir);
- }
- else {
- warning("directory not found for option '-F%s'", frameworkSearchDir);
- }
+ frameworkPaths.push_back(frameworkSearchDir);
}
else if ( strcmp(argv[i], "-Z") == 0 )
addStandardLibraryDirectories = false;
fVerbose = true;
extern const char ldVersionString[];
fprintf(stderr, "%s", ldVersionString);
+ fprintf(stderr, "BUILD " __TIME__ " " __DATE__"\n");
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, "LTO support using: %s\n", ltoVers);
+ fprintf(stderr, "LTO support using: %s (static support for %d, runtime is %d)\n",
+ ltoVers, lto::static_api_version(), lto::runtime_api_version());
+ fprintf(stderr, "TAPI support using: %s\n", tapi::Version::getFullVersionAsString().c_str());
exit(0);
}
}
throw "-dependency_info missing <path>";
fDependencyInfoPath = path;
}
+ else if ( strcmp(argv[i], "-bitcode_bundle") == 0 ) {
+ fBundleBitcode = true;
+ }
}
int standardLibraryPathsStartIndex = libraryPaths.size();
int standardFrameworkPathsStartIndex = frameworkPaths.size();
strcat(newPath, libDir);
struct stat statBuffer;
if ( stat(newPath, &statBuffer) == 0 ) {
- fLibrarySearchPaths.push_back(strdup(newPath));
- sdkOverride = true;
+ if ( (statBuffer.st_mode & S_IFDIR) == 0 ) {
+ warning("-syslibroot and -L combined path '%s' is not a directory", newPath);
+ }
+ else {
+ fLibrarySearchPaths.push_back(strdup(newPath));
+ sdkOverride = true;
+ }
}
}
}
// if one SDK is specified and a standard library path is not in the SDK, don't use it
}
else {
- fLibrarySearchPaths.push_back(libDir);
+ struct stat statBuffer;
+ if ( stat(libDir, &statBuffer) == 0 ) {
+ if ( (statBuffer.st_mode & S_IFDIR) == 0 )
+ warning("-L path '%s' is not a directory", libDir);
+ else
+ fLibrarySearchPaths.push_back(libDir);
+ }
+ else if ( !addStandardLibraryDirectories || (strcmp(libDir, "/usr/local/lib") != 0) ) {
+ warning("directory not found for option '-L%s'", libDir);
+ }
}
}
}
+
// now merge sdk and framework paths to make real search paths
fFrameworkSearchPaths.reserve(frameworkPaths.size()*(fSDKPaths.size()+1));
int frameIndex = 0;
strcat(newPath, frameworkDir);
struct stat statBuffer;
if ( stat(newPath, &statBuffer) == 0 ) {
- fFrameworkSearchPaths.push_back(strdup(newPath));
- sdkOverride = true;
+ if ( (statBuffer.st_mode & S_IFDIR) == 0 ) {
+ warning("-syslibroot and -F combined path '%s' is not a directory", newPath);
+ }
+ else {
+ fFrameworkSearchPaths.push_back(strdup(newPath));
+ sdkOverride = true;
+ }
}
}
}
// if one SDK is specified and a standard library path is not in the SDK, don't use it
}
else {
- fFrameworkSearchPaths.push_back(frameworkDir);
+ struct stat statBuffer;
+ if ( stat(frameworkDir, &statBuffer) == 0 ) {
+ if ( (statBuffer.st_mode & S_IFDIR) == 0 )
+ warning("-F path '%s' is not a directory", frameworkDir);
+ else
+ fFrameworkSearchPaths.push_back(frameworkDir);
+ }
+ else if ( !addStandardLibraryDirectories || (strcmp(frameworkDir, "/Library/Frameworks/") != 0) ) {
+ warning("directory not found for option '-F%s'", frameworkDir);
+ }
}
}
}
fTraceDylibs = true;
fTraceIndirectDylibs = true;
}
+
+ if ((getenv("LD_TRACE_DEPENDENTS") != NULL)) {
+
+ fTraceEmitJSON = true;
+ }
if (getenv("RC_TRACE_DYLIB_SEARCHING") != NULL) {
fTraceDylibSearching = true;
if (getenv("LD_PRINT_OPTIONS") != NULL)
fPrintOptions = true;
- if (fTraceDylibs || fTraceArchives)
+ if (fTraceDylibs || fTraceArchives || fTraceEmitJSON)
fTraceOutputFile = getenv("LD_TRACE_FILE");
if (getenv("LD_PRINT_ORDER_FILE_STATISTICS") != NULL)
fPrintOrderFileStatistics = true;
- if (getenv("LD_SPLITSEGS_NEW_LIBRARIES") != NULL)
- fSplitSegs = true;
-
- if (getenv("LD_NO_ENCRYPT") != NULL)
+ if (getenv("LD_NO_ENCRYPT") != NULL) {
fEncryptable = false;
+ fMarkAppExtensionSafe = true; // temporary
+ fCheckAppExtensionSafe = false;
+ }
+
+ if (getenv("LD_APPLICATION_EXTENSION_SAFE") != NULL) {
+ fMarkAppExtensionSafe = true;
+ fCheckAppExtensionSafe = false;
+ }
if (getenv("LD_ALLOW_CPU_SUBTYPE_MISMATCHES") != NULL)
fAllowCpuSubtypeMismatches = true;
+ if (getenv("LD_DYLIB_CPU_SUBTYPES_MUST_MATCH") != NULL)
+ fEnforceDylibSubtypesMatch = true;
+
+ if (getenv("LD_WARN_ON_SWIFT_ABI_VERSION_MISMATCHES") != NULL)
+ fWarnOnSwiftABIVersionMismatches = true;
+
sWarningsSideFilePath = getenv("LD_WARN_FILE");
const char* customDyldPath = getenv("LD_DYLD_PATH");
if (pipeFdString != NULL) {
fPipelineFifo = pipeFdString;
}
+
+ // <rdar://problem/30746905> [Reproducible Builds] If env ZERO_AR_DATE is set, zero out timestamp in N_OSO stab
+ if ( getenv("ZERO_AR_DATE") != NULL )
+ fZeroModTimeInDebugMap = true;
+
+ char rawPath[PATH_MAX];
+ char path[PATH_MAX];
+ char *base;
+ uint32_t bufSize = PATH_MAX;
+ if ( _NSGetExecutablePath(rawPath, &bufSize) != -1 ) {
+ if ( realpath(rawPath, path) != NULL ) {
+#define TOOLCHAINBASEPATH "/Developer/Toolchains/"
+ if ( (base = strstr(path, TOOLCHAINBASEPATH)) )
+ fToolchainPath = strndup(path, base - path + strlen(TOOLCHAINBASEPATH));
+ }
+ }
+
+ // <rdar://problem/38679559> ld64 should consider RC_RELEASE when calculating a binary's UUID
+ fBuildContextName = getenv("RC_RELEASE");
}
fExecutablePath = fOutputFile;
}
- // allow build system to set default seg_addr_table
- if ( fSegAddrTablePath == NULL )
- fSegAddrTablePath = getenv("LD_SEG_ADDR_TABLE");
-
- // allow build system to turn on prebinding
- if ( !fPrebind ) {
- fPrebind = ( getenv("LD_PREBIND") != NULL );
- }
-
// allow build system to force on dead-code-stripping
if ( !fDeadStrip ) {
if ( getenv("LD_DEAD_STRIP") != NULL ) {
}
+
+static bool sharedCacheEligiblePath(const char* path)
+{
+ return ( (strncmp(path, "/usr/lib/", 9) == 0) || (strncmp(path, "/System/Library/", 16) == 0) );
+}
+
void Options::reconfigureDefaults()
{
// sync reader options
}
// set default min OS version
- if ( (fMacVersionMin == ld::macVersionUnset)
- && (fIOSVersionMin == ld::iOSVersionUnset) ) {
+ if ( platforms().empty() ) {
// if neither -macosx_version_min nor -iphoneos_version_min used, try environment variables
+ if ( (fOutputKind != Options::kObjectFile) && (fOutputKind != Options::kPreload) )
+ warning("No version-min specified on command line");
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);
+ const char* wOSVers = getenv("WATCHOS_DEPLOYMENT_TARGET");
+ if ( macVers != NULL )
+ setVersionMin(ld::kPlatform_macOS, macVers);
else if ( iPhoneVers != NULL )
- setIOSVersionMin(iPhoneVers);
+ setVersionMin(ld::kPlatform_iOS, iPhoneVers);
else if ( iOSVers != NULL )
- setIOSVersionMin(iOSVers);
- else if ( iOSSimulatorVers != NULL )
- setIOSVersionMin(iOSSimulatorVers);
+ setVersionMin(ld::kPlatform_iOS, iOSVers);
+ else if ( wOSVers != NULL )
+ setVersionMin(ld::kPlatform_watchOS, wOSVers);
else {
// if still nothing, set default based on architecture
switch ( fArchitecture ) {
if ( (fOutputKind != Options::kObjectFile) && (fOutputKind != Options::kPreload) ) {
#ifdef DEFAULT_MACOSX_MIN_VERSION
warning("-macosx_version_min not specified, assuming " DEFAULT_MACOSX_MIN_VERSION);
- setMacOSXVersionMin(DEFAULT_MACOSX_MIN_VERSION);
+ setVersionMin(ld::kPlatform_macOS, DEFAULT_MACOSX_MIN_VERSION);
#else
warning("-macosx_version_min not specified, assuming 10.6");
- fMacVersionMin = ld::mac10_6;
- #endif
+ setVersionMin(ld::kPlatform_macOS, "10.6");
+ #endif
}
break;
case CPU_TYPE_ARM:
if ( (fOutputKind != Options::kObjectFile) && (fOutputKind != Options::kPreload) ) {
#if defined(DEFAULT_IPHONEOS_MIN_VERSION)
warning("-ios_version_min not specified, assuming " DEFAULT_IPHONEOS_MIN_VERSION);
- setIOSVersionMin(DEFAULT_IPHONEOS_MIN_VERSION);
+ setVersionMin(ld::kPlatformiOS, DEFAULT_IPHONEOS_MIN_VERSION);
#else
- warning("-ios_version_min not specified, assuming 6.0");
- setIOSVersionMin("6.0");
+ if ( fSubArchitecture == CPU_SUBTYPE_ARM_V7K ) {
+ warning("-watchos_version_min not specified, assuming 2.0");
+ setVersionMin(ld::kPlatform_watchOS, "2.0");
+ }
+ else {
+ warning("-ios_version_min not specified, assuming 6.0");
+ setVersionMin(ld::kPlatform_iOS, "6.0");
+ }
#endif
}
break;
}
}
-
+ __block ld::VersionSet platformOverrides;
// adjust min based on architecture
- switch ( fArchitecture ) {
- case CPU_TYPE_I386:
- 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_X86_64:
- 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;
- }
- break;
- case CPU_TYPE_ARM64:
- if ( fIOSVersionMin < ld::iOS_7_0 ) {
- //warning("-mios_version_min should be 7.0 or later for arm64");
- fIOSVersionMin = ld::iOS_7_0;
- }
- break;
- }
-
+ platforms().forEach(^(ld::Platform platform, uint32_t version, bool &stop) {
+ if ( (fArchitecture == CPU_TYPE_I386 || fArchitecture == CPU_TYPE_X86_64)
+ && platform == ld::kPlatform_macOS && !platforms().minOS(ld::mac10_4) ) {
+ platformOverrides.add(ld::mac10_4);
+ } else if (fArchitecture == CPU_TYPE_ARM64 && platform == ld::kPlatform_iOS
+ && !platforms().minOS(ld::iOS_7_0)) {
+ platformOverrides.add(ld::iOS_7_0);
+ }
+ });
+
+ // Insert the overrides into fPlatfroms
+ platformOverrides.forEach(^(ld::Platform platform, uint32_t version, bool &stop) {
+ fPlatforms.add({platform, version});
+ });
+
// default to adding functions start for dynamic code, static code must opt-in
switch ( fOutputKind ) {
case Options::kPreload:
fFunctionStartsLoadCommand = true;
break;
case Options::kObjectFile:
+ if ( !fDataInCodeInfoLoadCommandForcedOff )
+ fDataInCodeInfoLoadCommand = true;
+ if ( fFunctionStartsForcedOn )
+ fFunctionStartsLoadCommand = true;
+ break;
case Options::kDynamicExecutable:
case Options::kDyld:
case Options::kDynamicLibrary:
fUndefinedTreatment = kUndefinedDynamicLookup;
break;
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
+ fMakeCompressedDyldInfo = false;
+ fMakeCompressedDyldInfoForceOff = true;
+ fAllowTextRelocs = false;
+ fKextsUseStubs = !fAllowTextRelocs;
+ fUndefinedTreatment = kUndefinedDynamicLookup;
+ break;
case CPU_TYPE_I386:
// use .o files
fOutputKind = kObjectFile;
// disable implicit dylibs when targeting 10.3
// <rdar://problem/5451987> add option to disable implicit load commands for indirectly used public dylibs
- if ( !minOS(ld::mac10_4, ld::iOS_2_0) )
+ if ( !platforms().minOS(ld::version2007) )
fImplicitlyLinkPublicDylibs = false;
-
- // allow build system to force linker to ignore -prebind
- if ( getenv("LD_FORCE_NO_PREBIND") != NULL )
- fPrebind = false;
-
- // allow build system to force linker to ignore -seg_addr_table
- if ( getenv("LD_FORCE_NO_SEG_ADDR_TABLE") != NULL )
- fSegAddrTablePath = NULL;
-
- // check for base address specified externally
- if ( (fSegAddrTablePath != NULL) && (fOutputKind == Options::kDynamicLibrary) ) {
- parseSegAddrTable(fSegAddrTablePath, this->installPath());
- // HACK to support seg_addr_table entries that are physical paths instead of install paths
- if ( fBaseAddress == 0 ) {
- if ( strcmp(this->installPath(), "/usr/lib/libstdc++.6.dylib") == 0 ) {
- parseSegAddrTable(fSegAddrTablePath, "/usr/lib/libstdc++.6.0.4.dylib");
- if ( fBaseAddress == 0 )
- parseSegAddrTable(fSegAddrTablePath, "/usr/lib/libstdc++.6.0.9.dylib");
- }
-
- else if ( strcmp(this->installPath(), "/usr/lib/libz.1.dylib") == 0 )
- parseSegAddrTable(fSegAddrTablePath, "/usr/lib/libz.1.2.3.dylib");
-
- else if ( strcmp(this->installPath(), "/usr/lib/libutil.dylib") == 0 )
- parseSegAddrTable(fSegAddrTablePath, "/usr/lib/libutil1.0.dylib");
- }
- }
-
- // split segs only allowed for dylibs
- if ( fSplitSegs ) {
- // split seg only supported for i386, and arm.
- switch ( fArchitecture ) {
- case CPU_TYPE_I386:
- if ( fOutputKind != Options::kDynamicLibrary )
- fSplitSegs = false;
- // make sure read and write segments are proper distance apart
- if ( fSplitSegs && (fBaseWritableAddress-fBaseAddress != 0x10000000) )
- fBaseWritableAddress = fBaseAddress + 0x10000000;
- break;
- case CPU_TYPE_ARM:
- if ( fOutputKind != Options::kDynamicLibrary ) {
- fSplitSegs = false;
- }
- else {
- // make sure read and write segments are proper distance apart
- if ( fSplitSegs && (fBaseWritableAddress-fBaseAddress != 0x08000000) )
- fBaseWritableAddress = fBaseAddress + 0x08000000;
- }
- break;
- default:
- fSplitSegs = false;
- fBaseAddress = 0;
- fBaseWritableAddress = 0;
- }
- }
-
// set too-large size
switch ( fArchitecture ) {
case CPU_TYPE_I386:
break;
}
- // <rdar://problem/6138961> -r implies no prebinding for all architectures
- if ( fOutputKind == Options::kObjectFile )
- fPrebind = false;
-
- // disable prebinding depending on arch and min OS version
- if ( fPrebind ) {
- switch ( fArchitecture ) {
- case CPU_TYPE_I386:
- if ( fMacVersionMin == ld::mac10_4 ) {
- // in 10.4 only split seg dylibs are prebound
- if ( (fOutputKind != Options::kDynamicLibrary) || ! fSplitSegs )
- fPrebind = false;
- }
- else if ( fMacVersionMin >= ld::mac10_5 ) {
- // 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 ) {
- case Options::kDynamicExecutable:
- case Options::kDynamicLibrary:
- // only main executables and dylibs can be prebound
- break;
- case Options::kStaticExecutable:
- case Options::kDynamicBundle:
- case Options::kObjectFile:
- case Options::kDyld:
- case Options::kPreload:
- case Options::kKextBundle:
- // disable prebinding for everything else
- fPrebind = false;
- break;
- }
- }
- break;
- case CPU_TYPE_X86_64:
- fPrebind = false;
- break;
- case CPU_TYPE_ARM:
- switch ( fOutputKind ) {
- case Options::kDynamicExecutable:
- case Options::kDynamicLibrary:
- // only main executables and dylibs can be prebound
- break;
- case Options::kStaticExecutable:
- case Options::kDynamicBundle:
- case Options::kObjectFile:
- case Options::kDyld:
- case Options::kPreload:
- case Options::kKextBundle:
- // disable prebinding for everything else
- fPrebind = false;
- break;
- }
- break;
- }
- }
-
- // only prebound images can be split-seg
- if ( fSplitSegs && !fPrebind )
- fSplitSegs = false;
-
// determine if info for shared region should be added
if ( fOutputKind == Options::kDynamicLibrary ) {
- 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) )
+ if ( platforms().minOS(ld::version2008Fall) )
+ if ( !fSharedRegionEligibleForceOff )
+ if ( sharedCacheEligiblePath(this->installPath()) )
fSharedRegionEligible = true;
}
else if ( fOutputKind == Options::kDyld ) {
// <rdar://problem/10111122> 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_I386:
- if ( fIOSVersionMin != ld::iOSVersionUnset ) // simulator never needs modules
+
+ // automatically use __DATA_CONST in dylibs on all platforms except macOS
+ if ( fSharedRegionEligible && !fUseDataConstSegmentForceOff
+ && !platforms().contains(ld::kPlatform_macOS) && !targetIOSSimulator()) {
+ fUseDataConstSegment = true;
+ }
+ if ( fUseDataConstSegmentForceOn ) {
+ fUseDataConstSegment = true;
+ }
+ // A -kext for iOS 10 ==> -data_const, -text_exec, -add_split_seg_info
+ if ( (fOutputKind == Options::kKextBundle) && (fArchitecture == CPU_TYPE_ARM64) ) {
+ fUseDataConstSegment = true;
+ fUseTextExecSegment = true;
+ fSharedRegionEligible = true;
+ }
+ if ( fUseDataConstSegment ) {
+ addSectionRename("__DATA", "__got", "__DATA_CONST", "__got");
+
+#if SUPPORT_ARCH_arm64e
+ addSectionRename("__DATA", "__auth_got", "__DATA_CONST", "__auth_got");
+#endif
+ addSectionRename("__DATA", "__la_symbol_ptr", "__DATA_CONST", "__la_symbol_ptr");
+ addSectionRename("__DATA", "__nl_symbol_ptr", "__DATA_CONST", "__nl_symbol_ptr");
+ addSectionRename("__DATA", "__const", "__DATA_CONST", "__const");
+ addSectionRename("__DATA", "__cfstring", "__DATA_CONST", "__cfstring");
+ addSectionRename("__DATA", "__mod_init_func", "__DATA_CONST", "__mod_init_func");
+ addSectionRename("__DATA", "__mod_term_func", "__DATA_CONST", "__mod_term_func");
+ addSectionRename("__DATA", "__objc_classlist", "__DATA_CONST", "__objc_classlist");
+ addSectionRename("__DATA", "__objc_nlclslist", "__DATA_CONST", "__objc_nlclslist");
+ addSectionRename("__DATA", "__objc_catlist", "__DATA_CONST", "__objc_catlist");
+ addSectionRename("__DATA", "__objc_nlcatlist", "__DATA_CONST", "__objc_nlcatlist");
+ addSectionRename("__DATA", "__objc_protolist", "__DATA_CONST", "__objc_protolist");
+ addSectionRename("__DATA", "__objc_imageinfo", "__DATA_CONST", "__objc_imageinfo");
+ addSectionRename("__DATA", "__objc_const", "__DATA_CONST", "__objc_const");
+ }
+ if ( fUseTextExecSegment ) {
+ addSectionRename("__TEXT", "__text", "__TEXT_EXEC", "__text");
+ addSectionRename("__TEXT", "__stubs", "__TEXT_EXEC", "__stubs");
+ }
+
+ // Use V2 shared cache info when targetting newer OSs
+ if ( fSharedRegionEligible && platforms().minOS(ld::supportsSplitSegV2)) {
+ fSharedRegionEncodingV2 = true;
+ if ( platforms().contains(ld::kPlatform_macOS) ) {
+ fSharedRegionEncodingV2 = false;
+ // <rdar://problem/24772435> only use v2 for Swift dylibs on Mac OS X
+ if ( strncmp(this->installPath(), "/System/Library/PrivateFrameworks/Swift/", 40) == 0 )
+ fSharedRegionEncodingV2 = true;
+ // <rdar://problem/32525720> use v2 for ABI stable Swift dylibs on macOS
+ if ( strncmp(this->installPath(), "/System/Library/Frameworks/Swift/", 33) == 0 )
+ fSharedRegionEncodingV2 = true;
+ // <rdar://problem/31428120> an other OS frameworks that use swift need v2
+ for (const char* searchPath : fLibrarySearchPaths ) {
+ if ( strstr(searchPath, "xctoolchain/usr/lib/swift/macos") != NULL ) {
+ fSharedRegionEncodingV2 = true;
break;
- case CPU_TYPE_ARM:
- if ( fPrebind )
- fNeedsModuleTable = true; // redo_prebinding requires a module table
- break;
+ }
+ }
}
+ fIgnoreOptimizationHints = true;
}
-
+
// <rdar://problem/5366363> -r -x implies -S
if ( (fOutputKind == Options::kObjectFile) && (fLocalSymbolHandling == kLocalSymbolsNone) )
fDebugInfoStripping = Options::kDebugInfoNone;
-
+
+ // <rdar://problem/15252891> -r implies -no_uuid
+ if ( fOutputKind == Options::kObjectFile )
+ fUUIDMode = kUUIDNone;
+
// choose how to process unwind info
switch ( fArchitecture ) {
case CPU_TYPE_I386:
}
break;
case CPU_TYPE_ARM:
- fAddCompactUnwindEncoding = false;
- fRemoveDwarfUnwindIfCompactExists = false;
+ if ( armUsesZeroCostExceptions() ) {
+ switch ( fOutputKind ) {
+ case Options::kObjectFile:
+ case Options::kStaticExecutable:
+ case Options::kPreload:
+ case Options::kKextBundle:
+ fAddCompactUnwindEncoding = false;
+ break;
+ case Options::kDyld:
+ case Options::kDynamicLibrary:
+ case Options::kDynamicBundle:
+ case Options::kDynamicExecutable:
+ fAddCompactUnwindEncoding = true;
+ break;
+ }
+ }
+ else {
+ fAddCompactUnwindEncoding = false;
+ fRemoveDwarfUnwindIfCompactExists = false;
+ }
break;
case 0:
// if -arch is missing, assume we don't want compact unwind info
break;
}
- // only iOS main executables should be encrypted
- if ( fOutputKind != Options::kDynamicExecutable )
+ // only iOS executables should be encryptable
+ switch ( fOutputKind ) {
+ case Options::kObjectFile:
+ case Options::kDyld:
+ case Options::kStaticExecutable:
+ case Options::kPreload:
+ case Options::kKextBundle:
+ fEncryptable = false;
+ break;
+ case Options::kDynamicExecutable:
+ break;
+ case Options::kDynamicLibrary:
+ case Options::kDynamicBundle:
+ // <rdar://problem/16293398> Add LC_ENCRYPTION_INFO load command to bundled frameworks
+ if ( !platforms().minOS(ld::version2013) )
+ fEncryptable = false;
+ break;
+ }
+ if ( (fArchitecture != CPU_TYPE_ARM) && (fArchitecture != CPU_TYPE_ARM64)
+ )
fEncryptable = false;
- if ( (fArchitecture != CPU_TYPE_ARM) && (fArchitecture != CPU_TYPE_ARM64) )
+ if ( fEncryptableForceOn )
+ fEncryptable = true;
+ else if ( fEncryptableForceOff )
fEncryptable = false;
// don't move inits in dyld because dyld wants certain
case Options::kDynamicLibrary:
case Options::kDynamicBundle:
break;
+ case Options::kDyld:
+ // arm64e has support for compressed LINKEDIT.
+ if ( (fArchitecture == CPU_TYPE_ARM64) && (fSubArchitecture == CPU_SUBTYPE_ARM64_E) )
+ break;
case Options::kPreload:
case Options::kStaticExecutable:
case Options::kObjectFile:
- case Options::kDyld:
case Options::kKextBundle:
fMakeCompressedDyldInfoForceOff = true;
break;
}
- if ( fMakeCompressedDyldInfoForceOff )
+
+ // only use legacy LINKEDIT if compressed LINKEDIT is forced off of:
+ // macOS before 10.6
+ // iOS before 3.1
+ if ( fMakeCompressedDyldInfoForceOff || !platforms().minOS(ld::version2009) )
fMakeCompressedDyldInfo = false;
-
- // only use compressed LINKEDIT for:
- // Mac OS X 10.6 or later
- // iOS 3.1 or later
- if ( fMakeCompressedDyldInfo ) {
- if ( !minOS(ld::mac10_6, ld::iOS_3_1) )
- fMakeCompressedDyldInfo = false;
+ // only ARM and x86_64 enforces that cpu-sub-types must match
+ switch ( fArchitecture ) {
+ case CPU_TYPE_ARM:
+ case CPU_TYPE_ARM64:
+ break;
+ case CPU_TYPE_X86_64:
+ fEnforceDylibSubtypesMatch = false;
+ break;
+ case CPU_TYPE_I386:
+ fEnforceDylibSubtypesMatch = false;
+ break;
}
-
- // only ARM enforces that cpu-sub-types must match
- if ( fArchitecture != CPU_TYPE_ARM )
- fAllowCpuSubtypeMismatches = true;
+
// only final linked images can not optimize zero fill sections
if ( fOutputKind == Options::kObjectFile )
}
// Mac OS X 10.5 and iPhoneOS 2.0 support LC_REEXPORT_DYLIB
- if ( minOS(ld::mac10_5, ld::iOS_2_0) )
+ if ( platforms().minOS(ld::version2008) )
fUseSimplifiedDylibReExports = true;
// Mac OS X 10.7 and iOS 4.2 support LC_LOAD_UPWARD_DYLIB
- if ( minOS(ld::mac10_7, ld::iOS_4_2) && (fOutputKind == kDynamicLibrary) )
+ if ( platforms().minOS(ld::version2010) && (fOutputKind == kDynamicLibrary) )
fCanUseUpwardDylib = true;
-
+
+ if (fArchitecture == CPU_TYPE_ARM64) {
+#if SUPPORT_ARCH_arm64e
+ if (fSubArchitecture == CPU_SUBTYPE_ARM64_E)
+ {
+ // FIXME: Move some of these to arm64
+ fNoLazyBinding = true;
+ switch ( fOutputKind ) {
+ case Options::kDynamicExecutable:
+ case Options::kDynamicLibrary:
+ case Options::kDynamicBundle:
+ case Options::kDyld:
+ fUseLinkedListBinding = true;
+ fUseAuthenticatedStubs = true;
+ break;
+ case Options::kPreload:
+ case Options::kStaticExecutable:
+ case Options::kObjectFile:
+ case Options::kKextBundle:
+ break;
+ }
+ switch ( fOutputKind ) {
+ case Options::kDynamicExecutable:
+ case Options::kDyld:
+ case Options::kDynamicLibrary:
+ case Options::kObjectFile:
+ case Options::kDynamicBundle:
+ case Options::kKextBundle:
+ fSupportsAuthenticatedPointers = true;
+ break;
+ case Options::kStaticExecutable:
+ case Options::kPreload:
+ fSupportsAuthenticatedPointers = false;
+ break;
+ }
+ }
+#endif
+ }
+
+ if ( fMakeThreadedStartsSection && (fArchitecture != CPU_TYPE_ARM64) ) {
+ // Threaded starts isn't valid here so ignore it.
+ warning("-threaded_starts_section ignored ignored for non-arm64");
+ fMakeThreadedStartsSection = false;
+ }
+
+ if (fMakeThreadedStartsSection) {
+ switch ( fOutputKind ) {
+ case Options::kDynamicExecutable:
+ case Options::kDyld:
+ case Options::kDynamicLibrary:
+ case Options::kObjectFile:
+ case Options::kDynamicBundle:
+ case Options::kKextBundle:
+ // Threaded starts isn't valid here so ignore it.
+ warning("-threaded_starts_section ignored for binaries other than -static or -preload");
+ fMakeThreadedStartsSection = false;
+ break;
+ case Options::kStaticExecutable:
+ case Options::kPreload:
+ fUseLinkedListBinding = true;
+ fNoLazyBinding = true;
+#if SUPPORT_ARCH_arm64e
+ if ( (fArchitecture == CPU_TYPE_ARM64) && (fSubArchitecture == CPU_SUBTYPE_ARM64_E) )
+ fSupportsAuthenticatedPointers = true;
+#endif
+ break;
+ }
+ }
+
+ // Weak binding requires that if we want to use linked list binding, we must
+ // also be using no lazy binding.
+ if ( fUseLinkedListBinding )
+ assert(fNoLazyBinding);
+
// MacOSX 10.7 defaults to PIE
- if ( ((fArchitecture == CPU_TYPE_X86_64) || (fArchitecture == CPU_TYPE_I386))
+ if ( (fArchitecture == CPU_TYPE_I386)
&& (fOutputKind == kDynamicExecutable)
- && (fMacVersionMin >= ld::mac10_7) ) {
+ && platforms().minOS(ld::mac10_7) ) {
fPositionIndependentExecutable = true;
}
// armv7 for iOS4.3 defaults to PIE
if ( (fArchitecture == CPU_TYPE_ARM)
&& fArchSupportsThumb2
- && (fOutputKind == kDynamicExecutable)
- && (fIOSVersionMin >= ld::iOS_4_3) ) {
+ && (fOutputKind == kDynamicExecutable)
+ && (platforms().contains(ld::kPlatform_watchOS) || platforms().minOS(ld::iOS_4_3)) ) {
fPositionIndependentExecutable = true;
}
+ // <rdar://problem/24535196> x86_64 defaults PIE (for 10.6 and later)
+ if ( (fArchitecture == CPU_TYPE_X86_64) && (fOutputKind == kDynamicExecutable) && (platforms().minOS(ld::mac10_6) || platforms().contains(ld::kPlatform_iOSMac)) )
+ fPositionIndependentExecutable = true;
+
+ // Simulator defaults to PIE
+ if ( targetIOSSimulator() && (fOutputKind == kDynamicExecutable) )
+ fPositionIndependentExecutable = true;
+
// -no_pie anywhere on command line disable PIE
if ( fDisablePositionIndependentExecutable )
fPositionIndependentExecutable = false;
// arm64 is always PIE
- if ( (fArchitecture == CPU_TYPE_ARM64) && (fOutputKind == kDynamicExecutable) ) {
+ if ( ((fArchitecture == CPU_TYPE_ARM64)
+ )
+ && (fOutputKind == kDynamicExecutable) ) {
fPositionIndependentExecutable = true;
+ if ( fDisablePositionIndependentExecutable )
+ warning("-no_pie ignored for arm64");
}
// set fOutputSlidable
break;
}
- // let linker know if thread local variables are supported
- if ( fMacVersionMin >= ld::mac10_7 ) {
+ // Let linker know if thread local variables are supported
+ // This is more complex than normal version checks since
+ // runtime support varies by architecture
+ if (platforms().minOS(ld::supportsTLV)
+ || ((fArchitecture == CPU_TYPE_ARM64) && platforms().minOS(ld::iOS_8_0))
+ || ((fArchitecture == CPU_TYPE_X86_64) && platforms().minOS(ld::iOS_9_0))) {
fTLVSupport = true;
}
-
+
// default to adding version load command for dynamic code, static code must opt-in
switch ( fOutputKind ) {
case Options::kObjectFile:
}
// support re-export of individual symbols in MacOSX 10.7 and iOS 4.2
- if ( (fOutputKind == kDynamicLibrary) && minOS(ld::mac10_7, ld::iOS_4_2) )
+ if ( (fOutputKind == kDynamicLibrary) && platforms().minOS(ld::version2010) )
fCanReExportSymbols = true;
// ObjC optimization is only in dynamic final linked images
// Use LC_MAIN instead of LC_UNIXTHREAD for newer OSs
switch ( fOutputKind ) {
case Options::kDynamicExecutable:
- if ( fEntryPointLoadCommandForceOn ) {
+ // <rdar://problem/16310363> Linker should look for "_main" not "start" when building for sim regardless of min OS
+ if ( platforms().minOS(ld::version2012) ) {
fEntryPointLoadCommand = true;
- fEntryName = "_main";
- }
- else if ( fEntryPointLoadCommandForceOff ) {
- fNeedsThreadLoadCommand = true;
- }
- else {
- if ( minOS(ld::mac10_8, ld::iOS_6_0) ) {
- fEntryPointLoadCommand = true;
+ if ( fEntryName == NULL )
+ fEntryName = "_main";
+ if ( strcmp(fEntryName, "start") == 0 ) {
+ warning("Ignoring '-e start' because entry point 'start' is not used for the targeted OS version");
fEntryName = "_main";
}
- else
- fNeedsThreadLoadCommand = true;
+ }
+ else {
+ fNeedsThreadLoadCommand = true;
+ if ( fEntryName == NULL )
+ fEntryName = "start";
}
break;
case Options::kObjectFile:
case Options::kPreload:
case Options::kDyld:
fNeedsThreadLoadCommand = true;
+ if ( fEntryName == NULL )
+ fEntryName = "start"; // Perhaps these should have no default and require -e
break;
}
fSourceVersionLoadCommand = false;
}
else {
- if ( minOS(ld::mac10_8, ld::iOS_6_0) ) {
+ if ( platforms().minOS(ld::version2012) ) {
fSourceVersionLoadCommand = true;
}
else
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();
fSDKVersion = parseVersionNumber32(sdkVersionStr);
}
}
-
+
// if -sdk_version and -syslibroot not used, but targeting MacOSX, use current OS version
- if ( (fSDKVersion == 0) && (fMacVersionMin != ld::macVersionUnset) ) {
+ if ( (fSDKVersion == 0) && platforms().contains(ld::kPlatform_macOS) ) {
// 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;
+ fSDKVersion = platforms().minOS(ld::kPlatform_macOS);
}
else {
int mib[2] = { CTL_KERN, KERN_OSRELEASE };
// allow trie based absolute symbols if targeting new enough OS
if ( fMakeCompressedDyldInfo ) {
- if ( minOS(ld::mac10_9, ld::iOS_7_0) ) {
- // <rdar://problem/13179029> Allow absolute symbols in export trie for device but not simulator
- if ( !fTargetIOSSimulator )
- fAbsoluteSymbols = true;
+ if ( platforms().minOS(ld::version2013) ) {
+ fAbsoluteSymbols = true;
}
}
-
- // <rdar://problem/12959510> iOS main executables now default to 16KB page size
- if ( (fIOSVersionMin != ld::iOSVersionUnset) && (fOutputKind == Options::kDynamicExecutable) ) {
- // <rdar://problem/13070042> Only third party apps should have 16KB page segments by default
- if ( fEncryptable ) {
- if ( fSegmentAlignment == 4096 )
- fSegmentAlignment = 4096*4;
- }
+
+ // <rdar://problem/13070042> Only third party apps should have 16KB page segments by default
+ if ( fEncryptable ) {
+ if ( fSegmentAlignment == 4096 )
+ fSegmentAlignment = 4096*4;
}
// <rdar://problem/12258065> ARM64 needs 16KB page size for user land code
- if ( fArchitecture == CPU_TYPE_ARM64 ) {
- if ( fSegmentAlignment == 4096 ) {
- switch ( fOutputKind ) {
- case Options::kDynamicExecutable:
- case Options::kDynamicLibrary:
- case Options::kDynamicBundle:
- case Options::kDyld:
+ // <rdar://problem/15974532> make armv7[s] use 16KB pages in user land code for iOS 8 or later
+ if ( fSegmentAlignment == 4096 ) {
+ switch ( fOutputKind ) {
+ case Options::kDynamicExecutable:
+ case Options::kDynamicLibrary:
+ case Options::kDynamicBundle:
+ case Options::kDyld:
+ // <rdar://problem/14676611> 16KB segments for arm64 kexts
+ if ( (fArchitecture == CPU_TYPE_ARM64)
+ || (fArchitecture == CPU_TYPE_ARM) ) {
fSegmentAlignment = 4096*4;
- break;
- case Options::kStaticExecutable:
- case Options::kKextBundle:
- case Options::kObjectFile:
- case Options::kPreload:
- break;
- }
+ }
+ break;
+ case Options::kStaticExecutable:
+ case Options::kKextBundle:
+ // <rdar://problem/14676611> 16KB segments for arm64 kexts
+ if ( (fArchitecture == CPU_TYPE_ARM64)
+ ) {
+ fSegmentAlignment = 4096*4;
+ }
+ break;
+ case Options::kObjectFile:
+ case Options::kPreload:
+ break;
}
}
-
+
+
+
// <rdar://problem/13624134> linker should not convert dwarf unwind if .o file has compact unwind section
switch ( fOutputKind ) {
case Options::kDynamicExecutable:
fKeepDwarfUnwind = false;
}
else {
- if ( minOS(ld::mac10_9, ld::iOS_7_0) )
+ if ( platforms().minOS(ld::version2013) )
fKeepDwarfUnwind = false;
else
fKeepDwarfUnwind = true;
break;
}
+ // Make sure -image_base matches alignment
+ uint64_t alignedBaseAddress = (fBaseAddress+fSegmentAlignment-1) & (-fSegmentAlignment);
+ if ( alignedBaseAddress != fBaseAddress ) {
+ warning("base address 0x%llX is not properly aligned. Changing it to 0x%llX", fBaseAddress, alignedBaseAddress);
+ fBaseAddress = alignedBaseAddress;
+ }
+
+ // If -dirty_data_list not specified, look in $SDKROOT/AppleInternal/DirtyDataFiles/<dylib>.dirty for dirty data list
+ if ( fSymbolsMovesData.empty() && fUseDataConstSegment && ( fDylibInstallName != NULL) && !fSDKPaths.empty() ) {
+ const char* dylibLeaf = strrchr(fDylibInstallName, '/');
+ if ( dylibLeaf ) {
+ char path[PATH_MAX];
+ strlcpy(path , fSDKPaths.front(), sizeof(path));
+ strlcat(path , "/AppleInternal/DirtyDataFiles", sizeof(path));
+ strlcat(path , dylibLeaf, sizeof(path));
+ strlcat(path , ".dirty", sizeof(path));
+ FileInfo info;
+ if ( info.checkFileExists(*this, path) )
+ addSymbolMove("__DATA_DIRTY", path, fSymbolsMovesData, "-dirty_data_list");
+ }
+ }
+
+
+ // Look in $SDKROOT/AppleInternal/AccessibilityLinkerSymbols/<dylib>.axsymbols for objc-class names
+ if ( fUseDataConstSegment && (fDylibInstallName != NULL) && !fSDKPaths.empty() ) {
+ const char* dylibLeaf = strrchr(fDylibInstallName, '/');
+ if ( dylibLeaf ) {
+ char path[PATH_MAX];
+ strlcpy(path , fSDKPaths.front(), sizeof(path));
+ strlcat(path , "/AppleInternal/AccessibilityLinkerSymbols", sizeof(path));
+ strlcat(path , dylibLeaf, sizeof(path));
+ strlcat(path , ".axsymbols", sizeof(path));
+ FileInfo info;
+ if ( info.checkFileExists(*this, path) ) {
+ SymbolsMove tmp;
+ fSymbolsMovesAXMethodLists.push_back(tmp);
+ loadExportFile(path, ".axsymbols", fSymbolsMovesAXMethodLists.back().symbols);
+ }
+ }
+ }
+
+ // <rdar://problem/32138080> Automatically use OrderFiles found in the AppleInternal SDK
+ if ( (fFinalName != NULL) && fOrderedSymbols.empty() && !fSDKPaths.empty() ) {
+ char path[PATH_MAX];
+ strlcpy(path , fSDKPaths.front(), sizeof(path));
+ strlcat(path , "/AppleInternal/OrderFiles/", sizeof(path));
+ strlcat(path , fFinalName, sizeof(path));
+ strlcat(path , ".order", sizeof(path));
+ FileInfo info;
+ if ( info.checkFileExists(*this, path) )
+ parseOrderFile(path, false);
+ }
+
+ // <rdar://problem/20503811> Reduce the default alignment of structures/arrays to save memory in embedded systems
+ if ( fMaxDefaultCommonAlign == 0 ) {
+ if ( fOutputKind == Options::kPreload )
+ fMaxDefaultCommonAlign = 8;
+ else
+ fMaxDefaultCommonAlign = 15;
+ }
+
+ // Add warnings for issues likely to cause OS verification issues
+ if ( fSharedRegionEligible && !fRPaths.empty() && !fDebugVariant ) {
+ // <rdar://problem/18719327> warn if -rpath is used with OS dylibs
+ warning("OS dylibs should not add rpaths (linker option: -rpath) (Xcode build setting: LD_RUNPATH_SEARCH_PATHS)");
+ }
+ if ( (fOutputKind == Options::kDynamicLibrary) && (fDylibInstallName != NULL) && (fFinalName != NULL) && sharedCacheEligiblePath(fFinalName) && !fDebugVariant ) {
+ if ( strncmp(fDylibInstallName, "@rpath", 6) == 0 )
+ warning("OS dylibs should not use @rpath for -install_name. Use absolute path instead");
+ if ( strcmp(fDylibInstallName, fFinalName) != 0 ) {
+ bool different = true;
+ // some projects end up with double slash in -final_output path
+ if ( strstr(fFinalName, "//") != NULL ) {
+ char fixedPath[strlen(fFinalName)+1];
+ char* t = fixedPath;
+ bool lastWasSlash = false;
+ for (const char* s=fFinalName; *s != '\0'; ++s) {
+ if ( *s == '/' ) {
+ if ( !lastWasSlash )
+ *t++ = *s;
+ lastWasSlash = true;
+ }
+ else {
+ *t++ = *s;
+ lastWasSlash = false;
+ }
+ }
+ *t = '\0';
+ different = (strcmp(fDylibInstallName, fixedPath) != 0);
+ }
+ if ( different )
+ warning("OS dylibs -install_name should match its real absolute path");
+ }
+ }
+
+ // set if unaligned pointers are warnings or errors
+ if ( platforms().minOS(ld::mac10_12) ) {
+ // ignore unaligned pointers when targeting older macOS versions
+ if ( fSharedRegionEligible )
+ fUnalignedPointerTreatment = Options::kUnalignedPointerWarning;
+ else
+ fUnalignedPointerTreatment = Options::kUnalignedPointerIgnore;
+ }
+ else if ( platforms().minOS(ld::iOS_10_0) ) {
+#if SUPPORT_ARCH_arm64e
+ if ( (fArchitecture == CPU_TYPE_ARM64) && (fSubArchitecture == CPU_SUBTYPE_ARM64_E) ) {
+ fUnalignedPointerTreatment = Options::kUnalignedPointerError;
+ } else
+#endif
+ fUnalignedPointerTreatment = Options::kUnalignedPointerWarning;
+ }
+ else {
+ fUnalignedPointerTreatment = Options::kUnalignedPointerIgnore;
+ }
+
+ // warn by default for OS dylibs
+ if ( fInitializersTreatment == Options::kInvalid ) {
+ if ( fSharedRegionEligible && (fOutputKind == Options::kDynamicLibrary) && !fDebugVariant ) {
+ fInitializersTreatment = Options::kWarning;
+ }
+ else
+ fInitializersTreatment = Options::kSuppress;
+ }
+
}
void Options::checkIllegalOptionCombinations()
// check -undefined setting
switch ( fUndefinedTreatment ) {
case kUndefinedError:
- case kUndefinedDynamicLookup:
// always legal
break;
+ case kUndefinedDynamicLookup: {
+ platforms().forEach(^(ld::Platform platform, uint32_t version, bool &stop) {
+ switch (platform) {
+ case ld::kPlatform_macOS:
+ case ld::kPlatform_iOSMac:
+ case ld::kPlatform_unknown:
+ break;
+ case ld::kPlatform_iOS:
+ case ld::kPlatform_iOSSimulator:
+ case ld::kPlatform_watchOS:
+ case ld::kPlatform_watchOSSimulator:
+ case ld::kPlatform_bridgeOS:
+ case ld::kPlatform_tvOS:
+ case ld::kPlatform_tvOSSimulator:
+ if ( fOutputKind != kKextBundle )
+ warning("-undefined dynamic_lookup is deprecated on %s", platformName(platform));
+ break;
+ }
+ });
+ } break;
case kUndefinedWarning:
case kUndefinedSuppress:
// requires flat namespace
const char* lastSlash = strrchr(info.path, '/');
if ( lastSlash == NULL )
lastSlash = info.path - 1;
- if ( strcmp(&lastSlash[1], subUmbrella) == 0 ) {
+ std::string path(&lastSlash[1]);
+ auto idx = path.find(".tbd", path.size() - 4);
+ if (idx != std::string::npos)
+ path.erase(idx);
+ if ( path == subUmbrella ) {
info.options.fReExport = true;
found = true;
fLinkSnapshot.recordSubUmbrella(info.path);
}
// sync reader options
- if ( fNameSpace != kTwoLevelNameSpace )
+ if ( fNameSpace != kTwoLevelNameSpace ) {
fFlatNamespace = true;
+ platforms().forEach(^(ld::Platform platform, uint32_t version, bool &stop) {
+ switch (platform) {
+ case ld::kPlatform_unknown:
+ case ld::kPlatform_macOS:
+ case ld::kPlatform_iOSMac:
+ break;
+ case ld::kPlatform_iOS:
+ case ld::kPlatform_iOSSimulator:
+ case ld::kPlatform_watchOS:
+ case ld::kPlatform_watchOSSimulator:
+ case ld::kPlatform_bridgeOS:
+ case ld::kPlatform_tvOS:
+ case ld::kPlatform_tvOSSimulator:
+ warning("-flat_namespace is deprecated on %s", platformName(platform));
+ break;
+ }
+ });
+
+ }
+
// check -stack_addr
if ( fStackAddr != 0 ) {
if ( fStackSize != 0 ) {
switch (fArchitecture) {
case CPU_TYPE_I386:
- if ( fStackSize > 0xFFFFFFFF )
- throw "-stack_size must be < 4G for 32-bit processes";
- if ( fStackAddr == 0 ) {
- fStackAddr = 0xC0000000;
+ if ( platforms().contains(ld::kPlatform_macOS) ) {
+ if ( fStackSize > 0xFFFFFFFF )
+ throw "-stack_size must be < 4GB for 32-bit processes";
+ if ( fStackAddr == 0 )
+ fStackAddr = 0xC0000000;
+ if ( (fStackAddr > 0xB0000000) && ((fStackAddr-fStackSize) < 0xB0000000) )
+ warning("custom stack placement overlaps and will disable shared region");
+ }
+ else {
+ if ( fStackSize > 0x1F000000 )
+ throw "-stack_size must be < 496MB";
+ if ( fStackAddr == 0 )
+ fStackAddr = 0xC0000000;
}
- if ( (fStackAddr > 0xB0000000) && ((fStackAddr-fStackSize) < 0xB0000000) )
- warning("custom stack placement overlaps and will disable shared region");
break;
case CPU_TYPE_ARM:
- if ( fStackSize > 0x2F000000 )
- throw "-stack_size must be < 752MB";
+ if ( fStackSize > 0x1F000000 )
+ throw "-stack_size must be < 496MB";
if ( fStackAddr == 0 )
- fStackAddr = 0x2F000000;
- if ( fStackAddr > 0x30000000)
- throw "-stack_addr must be < 0x30000000 for arm";
+ fStackAddr = 0x1F000000;
+ if ( fStackAddr > 0x20000000)
+ throw "-stack_addr must be < 0x20000000 for arm";
break;
case CPU_TYPE_X86_64:
- if ( fStackAddr == 0 ) {
- fStackAddr = 0x00007FFF5C000000LL;
+ if ( platforms().contains(ld::kPlatform_macOS) ) {
+ if ( fStackSize > 0x10000000000 )
+ throw "-stack_size must be <= 1TB";
+ if ( fStackAddr == 0 ) {
+ fStackAddr = 0x00007FFF5C000000LL;
+ }
+ }
+ else {
+ if ( fStackSize > 0x20000000 )
+ throw "-stack_size must be <= 512MB";
+ if ( fStackAddr == 0 ) {
+ fStackAddr = 0x120000000;
}
break;
case CPU_TYPE_ARM64:
if ( fStackSize > 0x20000000 )
- throw "-stack_size must be < 512MB";
- if ( fStackAddr == 0 ) {
+ throw "-stack_size must be <= 512MB";
+ if ( fStackAddr == 0 )
fStackAddr = 0x120000000;
}
break;
}
- if ( (fStackSize & -4096) != fStackSize )
- throw "-stack_size must be multiples of 4K";
+ if ( (fStackSize & (-fSegmentAlignment)) != fStackSize )
+ throwf("-stack_size must be multiple of segment alignment (%lldKB)", fSegmentAlignment/1024);
switch ( fOutputKind ) {
case Options::kDynamicExecutable:
case Options::kStaticExecutable:
throw "-setuid_safe cannot be used with -r";
// <rdar://problem/12781832> compiler driver no longer uses -objc_abi_version, it uses -ios_simulator_version_min instead
- if ( !fObjCABIVersion1Override && !fObjCABIVersion2Override && fTargetIOSSimulator )
+ if ( !fObjCABIVersion1Override && !fObjCABIVersion2Override && targetIOSSimulator() )
fObjCABIVersion2Override = true;
// rdar://problem/4718189 map ObjC class names to new runtime names
// zero page size not specified on command line, set default
switch (fArchitecture) {
case CPU_TYPE_I386:
- case CPU_TYPE_ARM:
+ case CPU_TYPE_ARM:
// first 4KB for 32-bit architectures
fZeroPageSize = 0x1000;
break;
// can't use -rpath unless targeting 10.5 or later
if ( fRPaths.size() > 0 ) {
- if ( !minOS(ld::mac10_5, ld::iOS_2_0) )
+ if ( !platforms().minOS(ld::version2008) )
throw "-rpath can only be used when targeting Mac OS X 10.5 or later";
switch ( fOutputKind ) {
case Options::kDynamicExecutable:
switch ( fOutputKind ) {
case Options::kDynamicExecutable:
// 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";
+ if ( !platforms().minOS(ld::supportsPIE) ) {
+ throw "-pie requires targetting a newer minimum version";
}
break;
case Options::kStaticExecutable:
}
}
- // check -read_only_relocs is not used with x86_64
+ // check -read_only_relocs is not used with x86_64 or arm64
if ( fAllowTextRelocs ) {
if ( (fArchitecture == CPU_TYPE_X86_64) && (fOutputKind != kKextBundle) ) {
warning("-read_only_relocs cannot be used with x86_64");
fAllowTextRelocs = false;
}
+ else if ( fArchitecture == CPU_TYPE_ARM64 ) {
+ warning("-read_only_relocs cannot be used with arm64");
+ }
}
// check -mark_auto_dead_strip is only used with dylibs
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::iOS_4_2) )
+ if ( !platforms().minOS(ld::version2010) )
throw "targeted OS version does not support -reexported_symbols_list";
}
// -dyld_env can only be used with main executables
if ( (fOutputKind != Options::kDynamicExecutable) && (fDyldEnvironExtras.size() != 0) )
throw "-dyld_env can only used used when created main executables";
-}
+
+ // -segment_order can only be used with -preload or -static
+ if ( !fSegmentOrder.empty() && ((fOutputKind != Options::kPreload) && (fOutputKind != kStaticExecutable)) )
+ throw "-segment_order can only used used with -preload output";
+
+ // warn about bitcode option combinations
+ if ( !fBundleBitcode ) {
+ if ( fVerifyBitcode )
+ warning("-bitcode_verify is ignored without -bitcode_bundle");
+ else if ( fHideSymbols )
+ warning("-bitcode_hide_symbols is ignored without -bitcode_bundle");
+ }
+ if ( fReverseMapPath != NULL && !fHideSymbols ) {
+ throw "-bitcode_symbol_map can only be used with -bitcode_hide_symbols";
+ }
+ // auto fix up the process type for strip -S.
+ // when there is only one input and output type is object file, downgrade kBitcodeProcess to kBitcodeAsData.
+ if ( fOutputKind == Options::kObjectFile && fInputFiles.size() == 1 && fBitcodeKind == Options::kBitcodeProcess )
+ fBitcodeKind = Options::kBitcodeAsData;
+
+ // <rdar://problem/17598404> warn if building an embedded iOS dylib for pre-iOS 8
+ // <rdar://problem/18935714> How can we suppress "ld: warning: embedded dylibs/frameworks only run on iOS 8 or later" when building XCTest?
+ if ( (fOutputKind == Options::kDynamicLibrary) && (fDylibInstallName != NULL) ) {
+ if ( platforms().contains(ld::kPlatform_iOS) && !platforms().minOS(ld::iOS_8_0) && (fDylibInstallName[0] == '@') && !fEncryptableForceOff )
+ warning("embedded dylibs/frameworks only run on iOS 8 or later");
+ }
+
+ // produce nicer error when no input
+ if ( fInputFiles.empty() ) {
+ throw "no object files specified";
+ }
+
+ // Check zippered combinations.
+ if (platforms().count() > 2) {
+ throw "Illegal platform count. Only 2 platforms at a maximum can be specified";
+ }
+
+ // Convert from -ios_version_min to -ios_simulator_version_min for now until clang has been updated
+ if (architecture() == CPU_TYPE_X86_64 || architecture() == CPU_TYPE_X86) {
+ if (platforms().contains(ld::kPlatform_iOS)) {
+ uint32_t version = platforms().minOS(ld::kPlatform_iOS);
+ fPlatforms.erase(ld::kPlatform_iOS);
+ // HACK infer the build environment from the SDK path
+ bool macOSSDK = false;
+ for (const auto& sdkPath : fSDKPaths) {
+ if (strstr(sdkPath, "MacOSX10") != 0) {
+ macOSSDK = true;
+ break;
+ }
+ }
+ if (macOSSDK) {
+ fPlatforms.add({ ld::kPlatform_iOSMac, version });
+ warning("URGENT: -ios_version_min is invalid for architecture x86/x86_64, inferring -iosmac_version_min. "
+ "This will be an error in the future.");
+ } else {
+ fPlatforms.add({ ld::kPlatform_iOSSimulator, version });
+ warning("URGENT: -ios_version_min is invalid for architecture x86/x86_64, inferring -ios_simulator_version_min. "
+ "This will be an error in the future.");
+ }
+ }
+ }
+
+ if (platforms().count() == 2) {
+ if (!platforms().minOS(ld::mac10_14))
+ throw "Zippered macOS version platform must be at least 10.14";
+ if (!platforms().minOS(ld::iOS_12_0))
+ throw "Zippered iosmac version platform must be at least 12.0";
+ }
+
+ if (platforms().contains(ld::kPlatform_iOSMac) && !platforms().minOS(ld::iOS_12_0)) {
+ throw "iosmac platform version must be at least 12.0";
+ }
+
+ // <rdar://problem/38155581> ld64 shouldn't allow final executables to have more than one version load command
+ if ( platforms().contains(ld::kPlatform_iOSMac) && platforms().contains(ld::kPlatform_macOS) ) {
+ if ( (fOutputKind != Options::kDynamicLibrary) && (fOutputKind != Options::kDynamicBundle) ) {
+ warning("Only dylibs and bundles can be zippered, changing output to be macOS only.");
+ fPlatforms.erase(ld::kPlatform_iOSMac);
+ }
+ }
+
+ // <rdar://problem/39095109> Linker warning for i386 macOS binaries
+ if ( (architecture() == CPU_TYPE_I386) && platforms().contains(ld::kPlatform_macOS) ) {
+ bool internalSDK = false;
+ for (const char* sdkPath : fSDKPaths) {
+ std::string possiblePath = std::string(sdkPath) + "/AppleInternal/";
+ struct stat statBuffer;
+ if ( stat(possiblePath.c_str(), &statBuffer) == 0 ) {
+ internalSDK = true;
+ break;
+ }
+ }
+ if ( !internalSDK )
+ warning("The i386 architecture is deprecated for macOS (remove from the Xcode build setting: ARCHS)");
+ }
+}
void Options::checkForClassic(int argc, const char* argv[])
if ( !fDemangle )
return sym;
+ static size_t size = 1024;
+ static char* buff = (char*)malloc(size);
+
+#if DEMANGLE_SWIFT
+ // only try to demangle symbols that look like Swift symbols
+ if ( strncmp(sym, "_$", 2) == 0 ) {
+ size_t demangledSize = fnd_get_demangled_name(&sym[1], buff, size);
+ if ( demangledSize > size ) {
+ size = demangledSize+2;
+ buff = (char*)realloc(buff, size);
+ demangledSize = fnd_get_demangled_name(&sym[1], buff, size);
+ }
+ if ( demangledSize != 0 )
+ return buff;
+ }
+#endif
+
// 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
}
-void Options::dumpDependency(uint8_t opcode, const char* path) const
+void Options::writeDependencyInfo() const
{
- if ( !this->dumpDependencyInfo() )
+ // do nothing if -dependency_info not used
+ if ( !dumpDependencyInfo() )
return;
+ // <rdar://problem/30750137> sort entries for build reproducibility
+ std::sort(fDependencies.begin(), fDependencies.end(), [](const DependencyEntry& a, const DependencyEntry& b) -> bool {
+ if ( a.opcode != b.opcode )
+ return (a.opcode < b.opcode);
+ return (a.path < b.path);
+ });
+
// one time open() of -dependency_info file
- if ( fDependencyFileDescriptor == -1 ) {
- fDependencyFileDescriptor = open(this->dependencyInfoPath(), O_WRONLY | O_TRUNC | O_CREAT, 0666);
- if ( fDependencyFileDescriptor == -1 )
- throwf("Could not open or create -dependency_info file: %s", this->dependencyInfoPath());
-
- // write header
- uint8_t version = depLinkerVersion;
- if ( write(fDependencyFileDescriptor, &version, 1) == -1 )
+ int fd = open(this->dependencyInfoPath(), O_WRONLY | O_TRUNC | O_CREAT, 0666);
+ if ( fd == -1 )
+ throwf("Could not open or create -dependency_info file: %s", this->dependencyInfoPath());
+
+ // write header
+ uint8_t version = depLinkerVersion;
+ if ( write(fd, &version, 1) == -1 )
+ throwf("write() to -dependency_info failed, errno=%d", errno);
+ extern const char ldVersionString[];
+ if ( write(fd, ldVersionString, strlen(ldVersionString)+1) == -1 )
+ throwf("write() to -dependency_info failed, errno=%d", errno);
+
+ // write each dependency
+ for (const auto& entry: fDependencies) {
+ //printf("%d %s\n", entry.opcode, entry.path.c_str());
+ if ( write(fd, &entry.opcode, 1) == -1 )
throwf("write() to -dependency_info failed, errno=%d", errno);
- extern const char ldVersionString[];
- if ( write(fDependencyFileDescriptor, ldVersionString, strlen(ldVersionString)+1) == -1 )
+ if ( write(fd, entry.path.c_str(), entry.path.size()+1) == -1 )
throwf("write() to -dependency_info failed, errno=%d", errno);
}
+ ::close(fd);
+}
+
+
+void Options::addDependency(uint8_t opcode, const char* path) const
+{
+ if ( !this->dumpDependencyInfo() )
+ return;
+
char realPath[PATH_MAX];
if ( path[0] != '/' ) {
if ( realpath(path, realPath) != NULL ) {
}
}
- if ( write(fDependencyFileDescriptor, &opcode, 1) == -1 )
- throwf("write() to -dependency_info failed, errno=%d", errno);
- if ( write(fDependencyFileDescriptor, path, strlen(path)+1) == -1 )
- throwf("write() to -dependency_info failed, errno=%d", errno);
-
- //fprintf(stderr, "0x%02X %s\n", opcode, path);
+ DependencyEntry entry;
+ entry.opcode = opcode;
+ entry.path = path;
+ fDependencies.push_back(entry);
}
+void Options::writeToTraceFile(const char* buffer, size_t len) const
+{
+ // one time open() of custom LD_TRACE_FILE
+ if ( fTraceFileDescriptor == -1 ) {
+ if ( fTraceOutputFile != NULL ) {
+ fTraceFileDescriptor = open(fTraceOutputFile, O_WRONLY | O_APPEND | O_CREAT, 0666);
+ if ( fTraceFileDescriptor == -1 )
+ throwf("Could not open or create trace file (errno=%d): %s", errno, fTraceOutputFile);
+ }
+ else {
+ fTraceFileDescriptor = fileno(stderr);
+ }
+ }
+
+ while (len > 0) {
+ ssize_t amountWritten = write(fTraceFileDescriptor, buffer, len);
+ if ( amountWritten == -1 )
+ /* Failure to write shouldn't fail the build. */
+ return;
+ buffer += amountWritten;
+ len -= amountWritten;
+ }
+}
+