#include <spawn.h>
#include <cxxabi.h>
#include <Availability.h>
+#include <tapi/tapi.h>
#include <vector>
#include <map>
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);
+// fprintf(stderr, "not found: %s\n", p);
return false;
}
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),
+ fDyldInstallPath("/usr/lib/dyld"), fLtoCachePath(NULL), fTempLtoObjectPath(NULL), fOverridePathlibLTO(NULL), fLtoCpu(NULL),
fZeroPageSize(ULLONG_MAX), fStackSize(0), fStackAddr(0), fSourceVersion(0), fSDKVersion(0), fExecutableStack(false),
fNonExecutableHeap(false), fDisableNonExecutableHeap(false),
fMinimumHeaderPad(32), fSegmentAlignment(4096),
fUsingLazyDylibLinking(false), fEncryptable(true), fEncryptableForceOn(false), fEncryptableForceOff(false),
fOrderData(true), fMarkDeadStrippableDylib(false),
fMakeCompressedDyldInfo(true), fMakeCompressedDyldInfoForceOff(false), fNoEHLabels(false),
- fAllowCpuSubtypeMismatches(false), fUseSimplifiedDylibReExports(false),
+ fAllowCpuSubtypeMismatches(false), fEnforceDylibSubtypesMatch(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),
+ fLogAllFiles(false), fTraceDylibs(false), fTraceIndirectDylibs(false), fTraceArchives(false), fTraceEmitJSON(false),
fOutputSlidable(false), fWarnWeakExports(false),
fObjcGcCompaction(false), fObjCGc(false), fObjCGcOnly(false),
fDemangle(false), fTLVSupport(false),
fGenerateDtraceDOF(true), fAllowBranchIslands(true), fTraceSymbolLayout(false),
fMarkAppExtensionSafe(false), fCheckAppExtensionSafe(false), fForceLoadSwiftLibs(false),
fSharedRegionEncodingV2(false), fUseDataConstSegment(false),
- fUseDataConstSegmentForceOn(false), fUseDataConstSegmentForceOff(false),
+ fUseDataConstSegmentForceOn(false), fUseDataConstSegmentForceOff(false), fUseTextExecSegment(false),
fBundleBitcode(false), fHideSymbols(false), fVerifyBitcode(false),
- fReverseMapUUIDRename(false), fReverseMapPath(NULL), fLTOCodegenOnly(false),
- fIgnoreAutoLink(false), fAllowDeadDups(false), fBitcodeKind(kBitcodeProcess),
+ fReverseMapUUIDRename(false), fDeDupe(true), fVerboseDeDupe(false),
+ fReverseMapPath(NULL), fLTOCodegenOnly(false),
+ fIgnoreAutoLink(false), fAllowDeadDups(false), fAllowWeakImports(true), fBitcodeKind(kBitcodeProcess),
fPlatform(kPlatformUnknown), fDebugInfoStripping(kDebugInfoMinimal), fTraceOutputFile(NULL),
- fMacVersionMin(ld::macVersionUnset), fIOSVersionMin(ld::iOSVersionUnset),
+ fMacVersionMin(ld::macVersionUnset), fIOSVersionMin(ld::iOSVersionUnset), fWatchOSVersionMin(ld::wOSVersionUnset),
fSaveTempFiles(false), fSnapshotRequested(false), fPipelineFifo(NULL),
- fDependencyInfoPath(NULL), fDependencyFileDescriptor(-1)
+ fDependencyInfoPath(NULL), fDependencyFileDescriptor(-1), fTraceFileDescriptor(-1), fMaxDefaultCommonAlign(0)
{
this->checkForClassic(argc, argv);
this->parsePreCommandLineEnvironmentSettings();
Options::~Options()
{
- if ( fDependencyFileDescriptor != -1 )
- ::close(fDependencyFileDescriptor);
+ if ( fDependencyFileDescriptor != -1 )
+ ::close(fDependencyFileDescriptor);
+
+ if ( fTraceFileDescriptor != -1 )
+ ::close(fTraceFileDescriptor);
}
bool Options::errorBecauseOfWarnings() const
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;
}
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;
}
switch ( type ) {
case CPU_TYPE_I386:
case CPU_TYPE_X86_64:
- if ( (fPlatform == kPlatformOSX) && (fOutputKind != Options::kObjectFile) ) {
+ if ( (fPlatform == kPlatformOSX) && (fOutputKind != Options::kObjectFile) && (fMacVersionMin == ld::macVersionUnset) ) {
#ifdef DEFAULT_MACOSX_MIN_VERSION
warning("-macosx_version_min not specified, assuming " DEFAULT_MACOSX_MIN_VERSION);
setMacOSXVersionMin(DEFAULT_MACOSX_MIN_VERSION);
break;
case CPU_TYPE_ARM:
case CPU_TYPE_ARM64:
- if ( (fPlatform == kPlatformiOS) && (fOutputKind != Options::kObjectFile) ) {
+ if ( (fMacVersionMin == ld::macVersionUnset) && (fIOSVersionMin == ld::iOSVersionUnset) && (fOutputKind != Options::kObjectFile) ) {
#if defined(DEFAULT_IPHONEOS_MIN_VERSION)
warning("-ios_version_min not specified, assuming " DEFAULT_IPHONEOS_MIN_VERSION);
setIOSVersionMin(DEFAULT_IPHONEOS_MIN_VERSION);
it != fLibrarySearchPaths.end();
it++) {
const char* dir = *it;
- if ( checkForFile("%s/lib%s.tbd", dir, rootName, result) )
- return result;
- 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.tbd", dir, rootName, result) )
- return result;
- 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;
possiblePath = std::string(realPath).append(suffix);
}
FileInfo result;
- bool found = result.checkFileExists(*this, (possiblePath + ".tbd").c_str());
- if ( !found )
- found = result.checkFileExists(*this, possiblePath.c_str());
- if ( fTraceDylibSearching )
- printf("[Logging for XBS]%sfound framework: '%s'\n",
- (found ? " " : " not "), possiblePath.c_str());
- 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 std::string &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;
+}
+
+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, then use SDK prefix
if ( (path[0] == '/') && (strcmp(&path[path.size()-2], ".o") != 0) ) {
- auto tbdFile = path;
- auto lastSlashIdx = tbdFile.find_last_of('/');
- auto lastDotIdx = tbdFile.find_last_of('.');
- if (lastDotIdx != std::string::npos && lastDotIdx > lastSlashIdx)
- tbdFile.erase(lastDotIdx, std::string::npos);
- tbdFile.append(".tbd");
-
for (const auto* sdkPathDir : fSDKPaths) {
- auto possiblePath = std::string(sdkPathDir) + tbdFile;
- if ( result.checkFileExists(*this, possiblePath.c_str()) )
- return result;
- possiblePath = std::string(sdkPathDir) + path;
- if ( result.checkFileExists(*this, possiblePath.c_str()) )
+ auto possiblePath = std::string(sdkPathDir) + path;
+ if ( findFile(possiblePath, {".tbd"}, result) )
return result;
}
}
- // try raw path
- {
- std::string file = path;
- auto lastDotIdx = file.find_last_of('.');
- if (lastDotIdx != std::string::npos)
- file.erase(lastDotIdx, std::string::npos);
- if ( result.checkFileExists(*this, file.append(".tbd").c_str()) )
- return result;
- }
- if ( result.checkFileExists(*this, path.c_str()) ) {
- return result;
- }
-
- // try @executable_path substitution
- if ( (path.find("@executable_path/") == 0) && (fExecutablePath != nullptr) ) {
- char newPath[strlen(fExecutablePath) + path.size()];
- strcpy(newPath, fExecutablePath);
- char* addPoint = strrchr(newPath,'/');
- if ( addPoint != nullptr )
- strcpy(&addPoint[1], &path[17]);
- else
- strcpy(newPath, &path[17]);
-
- std::string file = newPath;
- auto lastDotIdx = file.find_last_of('.');
- if (lastDotIdx != std::string::npos)
- file.erase(lastDotIdx, std::string::npos);
- if ( result.checkFileExists(*this, file.append(".tbd").c_str()) ) {
- 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;
}
- if ( result.checkFileExists(*this, newPath) ) {
- 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;
+ }
+ }
}
}
+ // try raw path
+ if ( findFile(path, {".tbd"}, result) )
+ return result;
+
// not found
throwf("file not found: %s", path.c_str());
}
-Options::FileInfo Options::findFileUsingPaths(const std::string &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;
- auto lastSlashPos = path.find_last_of('/');
+ auto lastSlashPos = installName.find_last_of('/');
auto pos = ( lastSlashPos != std::string::npos ) ? lastSlashPos + 1 : 0;
- auto leafName = path.substr(pos);
+ auto leafName = installName.substr(pos);
// Is this in a framework?
// /path/Foo.framework/Foo ==> true (Foo)
bool isFramework = false;
if ( lastSlashPos != std::string::npos ) {
auto frameworkDir = std::string("/").append(leafName).append(".framework/");
- if ( path.rfind(frameworkDir) != std::string::npos )
+ 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 ) {
- auto endPos = path.rfind(".framework");
- auto beginPos = path.find_last_of('/', endPos);
- auto leafPath = path.substr(beginPos);
+ 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 ( checkForFile("%s.%s", possiblePath.c_str(), "tbd", result) )
- return result;
- if ( checkForFile("%s", possiblePath.c_str(), "", result) )
+ if ( findFile(possiblePath, {".tbd"}, result) )
return result;
}
} else {
// <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)
- && (path.find(".framework/") != std::string::npos) );
+ && (installName.find(".framework/") != std::string::npos) );
if ( !embeddedDylib ) {
for (const auto* dir : fLibrarySearchPaths) {
//fprintf(stderr,"Finding Library: %s/%s\n", dir, leafName);
- if ( checkForFile("%s/%s", dir, std::string(leafName).append(".tbd").c_str(), result) )
- return result;
- if ( checkForFile("%s/%s", dir, leafName.c_str(), 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);
+ return findFile(installName, fromDylib);
}
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;
- }
- fMacVersionMin = (ld::MacVersionMin)(0x000A0000 | (minorVersion << 8));
- fPlatform = kPlatformOSX;
- }
- else {
- warning("unknown option to -macosx_version_min, not 10.x");
+ uint32_t value;
+ if ( !parsePackedVersion32(version, value) ) {
+ throwf("-macosx_version_min value malformed: '%s'", version);
}
+ fMacVersionMin = (ld::MacVersionMin)value;
+ fPlatform = kPlatformOSX;
}
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));
+ uint32_t value;
+ if ( !parsePackedVersion32(version, value) ) {
+ throwf("-ios_version_min value malformed: '%s'", version);
+ }
+ fIOSVersionMin = (ld::IOSVersionMin)value;
fPlatform = kPlatformiOS;
}
void Options::setWatchOSVersionMin(const char* version)
{
- if ( version == NULL )
- throw "-watchos_version_min argument missing";
- if ( ! isdigit(version[0]) )
- throw "-watchos_version_min argument is not a number";
- if ( version[1] != '.' )
- throw "-watchos_version_min argument is missing period as second character";
- if ( ! isdigit(version[2]) )
- throw "-watchos_version_min argument is not a number";
-
- unsigned int majorVersion = version[0] - '0';
- unsigned int minorVersion = version[2] - '0';
- fWatchOSVersionMin = (ld::WatchOSVersionMin)((majorVersion << 16) | (minorVersion << 8));
+ uint32_t value;
+ if ( !parsePackedVersion32(version, value) ) {
+ throwf("-watchos_version_min value malformed: '%s'", version);
+ }
+ fWatchOSVersionMin = (ld::WatchOSVersionMin)value;
fPlatform = kPlatformWatchOS;
}
// 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 )
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:");
return versionString.str();
}
+// Convert X.Y[.Z] to 32-bit value xxxxyyzz
+bool Options::parsePackedVersion32(const std::string& versionStr, uint32_t &result)
+{
+ result = 0;
+
+ if ( versionStr.empty() )
+ return false;
+
+ size_t pos = versionStr.find('.');
+ if ( pos == std::string::npos )
+ return false;
+
+ std::string majorStr = versionStr.substr(0, pos);
+ std::string rest = versionStr.substr(pos+1);
+
+ 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 = (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);
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;
+ 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]);
else if ( strcmp(arg, "-order_file") == 0 ) {
snapshotFileArgIndex = 1;
parseOrderFile(argv[++i], false);
- cannotBeUsedWithBitcode(arg);
}
else if ( strcmp(arg, "-order_file_statistics") == 0 ) {
fPrintOrderFileStatistics = true;
throw "can't use -unexported_symbols_list and -exported_symbols_list";
fExportMode = kDontExportSome;
loadExportFile(argv[++i], "-unexported_symbols_list", fDontExportSymbols);
- cannotBeUsedWithBitcode(arg);
}
else if ( strcmp(arg, "-exported_symbol") == 0 ) {
if ( fExportMode == kDontExportSome )
throw "can't use -unexported_symbol and -exported_symbol";
fExportMode = kDontExportSome;
fDontExportSymbols.insert(argv[++i]);
- cannotBeUsedWithBitcode(arg);
}
else if ( strcmp(arg, "-non_global_symbols_no_strip_list") == 0 ) {
snapshotFileArgIndex = 1;
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 ) {
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;
// Use this flag to set default behavior for deployement targets.
else if ( strcmp(arg, "-macosx_version_min") == 0 ) {
const char* macVers = argv[++i];
+ if ( macVers == NULL )
+ throw "-macosx_version_min missing version argument";
const char* envMacVers = getenv("MACOSX_DEPLOYMENT_TARGET");
const char* enviPhoneVers = getenv("IPHONEOS_DEPLOYMENT_TARGET");
if ( (envMacVers != NULL) && (enviPhoneVers != NULL) ) {
}
}
else if ( (strcmp(arg, "-ios_version_min") == 0) || (strcmp(arg, "-iphoneos_version_min") == 0) ) {
- setIOSVersionMin(argv[++i]);
+ const char* vers = argv[++i];
+ if ( vers == NULL )
+ throw "-ios_version_min missing version argument";
+ setIOSVersionMin(vers);
}
else if ( strcmp(arg, "-ios_simulator_version_min") == 0 ) {
- setIOSVersionMin(argv[++i]);
+ const char* vers = argv[++i];
+ if ( vers == NULL )
+ throw "-ios_simulator_version_min missing version argument";
+ setIOSVersionMin(vers);
fTargetIOSSimulator = true;
}
else if ( strcmp(arg, "-watchos_version_min") == 0 ) {
- setWatchOSVersionMin(argv[++i]);
+ const char* vers = argv[++i];
+ if ( vers == NULL )
+ throw "-watchos_version_min missing version argument";
+ setWatchOSVersionMin(vers);
}
else if ( strcmp(arg, "-watchos_simulator_version_min") == 0 ) {
- setWatchOSVersionMin(argv[++i]);
+ const char* vers = argv[++i];
+ if ( vers == NULL )
+ throw "-watchos_simulator_version_min missing version argument";
+ setWatchOSVersionMin(vers);
fTargetIOSSimulator = true;
}
#if SUPPORT_APPLE_TV
else if ( strcmp(arg, "-tvos_version_min") == 0 ) {
- setIOSVersionMin(argv[++i]);
+ const char* vers = argv[++i];
+ if ( vers == NULL )
+ throw "-tvos_version_min missing version argument";
+ setIOSVersionMin(vers);
fPlatform = kPlatform_tvOS;
}
else if ( strcmp(arg, "-tvos_simulator_version_min") == 0 ) {
- setIOSVersionMin(argv[++i]);
+ const char* vers = argv[++i];
+ if ( vers == NULL )
+ throw "-tvos_simulator_version_min missing version argument";
+ setIOSVersionMin(vers);
fPlatform = kPlatform_tvOS;
fTargetIOSSimulator = true;
}
}
else if ( strcmp(arg, "-bitcode_hide_symbols") == 0 ) {
fHideSymbols = true;
- if ( !fBundleBitcode )
- warning("-bitcode_hide_symbols is ignored without -bitcode_bundle");
}
else if ( strcmp(arg, "-bitcode_verify") == 0 ) {
fVerifyBitcode = true;
- if ( !fBundleBitcode )
- warning("-bitcode_verify is ignored without -bitcode_bundle");
}
else if ( strcmp(arg, "-bitcode_symbol_map") == 0) {
fReverseMapPath = argv[++i];
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(argv[i], "-no_weak_imports") == 0 ) {
+ fAllowWeakImports = false;
+ }
// 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 ( 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;
const char* ltoVers = lto::version();
if ( ltoVers != NULL )
fprintf(stderr, "LTO support using: %s\n", ltoVers);
+ fprintf(stderr, "TAPI support using: %s\n", tapi::Version::getFullVersionAsString().c_str());
exit(0);
}
}
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)
if (getenv("LD_ALLOW_CPU_SUBTYPE_MISMATCHES") != NULL)
fAllowCpuSubtypeMismatches = true;
+ if (getenv("LD_DYLIB_CPU_SUBTYPES_MUST_MATCH") != NULL)
+ fEnforceDylibSubtypesMatch = true;
+
sWarningsSideFilePath = getenv("LD_WARN_FILE");
const char* customDyldPath = getenv("LD_DYLD_PATH");
// determine if info for shared region should be added
if ( fOutputKind == Options::kDynamicLibrary ) {
- if ( minOS(ld::mac10_5, ld::iOS_3_1) )
+ if ( minOS(ld::mac10_5, ld::iOS_3_1) && !fTargetIOSSimulator )
if ( !fPrebind && !fSharedRegionEligibleForceOff )
if ( (strncmp(this->installPath(), "/usr/lib/", 9) == 0)
|| (strncmp(this->installPath(), "/System/Library/", 16) == 0) )
if ( fUseDataConstSegmentForceOn ) {
fUseDataConstSegment = true;
}
+ // A -kext for iOS 10 ==> -data_const, -text_exec, -add_split_seg_info
+ if ( (fOutputKind == Options::kKextBundle) && minOS(ld::mac10_Future, ld::iOS_10_0) && (fArchitecture == CPU_TYPE_ARM64) ) {
+ fUseDataConstSegment = true;
+ fUseTextExecSegment = true;
+ fSharedRegionEligible = true;
+ }
if ( fUseDataConstSegment ) {
addSectionRename("__DATA", "__got", "__DATA_CONST", "__got");
addSectionRename("__DATA", "__la_symbol_ptr", "__DATA_CONST", "__la_symbol_ptr");
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 && minOS(ld::mac10_Future, ld::iOS_9_0)) {
+ if ( fSharedRegionEligible && minOS(ld::mac10_12, ld::iOS_9_0)) {
fSharedRegionEncodingV2 = true;
+ // <rdar://problem/24772435> only use v2 for Swift dylibs on Mac OS X
+ if ( (fPlatform == kPlatformOSX) && (strncmp(this->installPath(), "/System/Library/PrivateFrameworks/Swift/", 40) != 0) )
+ fSharedRegionEncodingV2 = false;
fIgnoreOptimizationHints = true;
}
fEncryptable = false;
break;
}
- if ( (fArchitecture != CPU_TYPE_ARM) && (fArchitecture != CPU_TYPE_ARM64) )
+ if ( (fArchitecture != CPU_TYPE_ARM) && (fArchitecture != CPU_TYPE_ARM64)
+ )
fEncryptable = false;
if ( fEncryptableForceOn )
fEncryptable = true;
// only ARM and x86_64 enforces that cpu-sub-types must match
switch ( fArchitecture ) {
case CPU_TYPE_ARM:
+ break;
case CPU_TYPE_X86_64:
+ fEnforceDylibSubtypesMatch = false;
break;
case CPU_TYPE_I386:
case CPU_TYPE_ARM64:
- fAllowCpuSubtypeMismatches = true;
+ fEnforceDylibSubtypesMatch = false;
break;
}
fCanUseUpwardDylib = true;
// 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) ) {
fPositionIndependentExecutable = true;
fPositionIndependentExecutable = true;
}
+ // <rdar://problem/24535196> x86_64 defaults PIE (regardless of minOS version)
+ if ( (fArchitecture == CPU_TYPE_X86_64) && (fOutputKind == kDynamicExecutable) && (fMacVersionMin >= ld::mac10_6) )
+ fPositionIndependentExecutable = true;
+
// Simulator defaults to PIE
if ( fTargetIOSSimulator && (fOutputKind == kDynamicExecutable) )
fPositionIndependentExecutable = true;
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
if ( fMacVersionMin >= ld::mac10_7 ) {
fTLVSupport = true;
}
- else if ( (fArchitecture == CPU_TYPE_ARM64) && min_iOS(ld::iOS_8_0) ) {
+ else if ( ((fArchitecture == CPU_TYPE_ARM64)
+ )
+ && min_iOS(ld::iOS_8_0) ) {
fTLVSupport = true;
}
else if ( (fArchitecture == CPU_TYPE_ARM) && min_iOS(ld::iOS_9_0) ) {
fTLVSupport = true;
}
+ else if ( fTargetIOSSimulator && (fArchitecture == CPU_TYPE_X86_64) && min_iOS(ld::iOS_8_0) ) {
+ fTLVSupport = true;
+ }
+ else if ( fTargetIOSSimulator && (fArchitecture == CPU_TYPE_I386) && min_iOS(ld::iOS_9_0) ) {
+ fTLVSupport = true;
+ }
// default to adding version load command for dynamic code, static code must opt-in
switch ( fOutputKind ) {
case Options::kDynamicLibrary:
case Options::kDynamicBundle:
case Options::kDyld:
- if ( (fArchitecture == CPU_TYPE_ARM64)
+ if ( ((fArchitecture == CPU_TYPE_ARM64)
+ )
|| ((fArchitecture == CPU_TYPE_ARM) && min_iOS(ld::iOS_7_0)) ) {
fSegmentAlignment = 4096*4;
}
case Options::kStaticExecutable:
case Options::kKextBundle:
// <rdar://problem/14676611> 16KB segments for arm64 kexts
- if ( (fArchitecture == CPU_TYPE_ARM64) && min_iOS(ld::iOS_9_0) ) {
+ if ( ((fArchitecture == CPU_TYPE_ARM64)
+ )
+ && min_iOS(ld::iOS_9_0) ) {
fSegmentAlignment = 4096*4;
}
break;
}
}
+ // <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;
+ }
}
void Options::checkIllegalOptionCombinations()
// check -undefined setting
switch ( fUndefinedTreatment ) {
case kUndefinedError:
- case kUndefinedDynamicLookup:
// always legal
break;
+ case kUndefinedDynamicLookup:
+ switch (fPlatform) {
+ case kPlatformOSX:
+ break;
+ case kPlatformiOS:
+ case kPlatformWatchOS:
+ #if SUPPORT_APPLE_TV
+ case kPlatform_tvOS:
+ #endif
+ if ( fOutputKind != kKextBundle )
+ warning("-undefined dynamic_lookup is deprecated on %s", platformName(fPlatform));
+ break;
+ default:
+ 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;
+ switch (fPlatform) {
+ case kPlatformOSX:
+ break;
+ case kPlatformiOS:
+ case kPlatformWatchOS:
+ #if SUPPORT_APPLE_TV
+ case Options::kPlatform_tvOS:
+ #endif
+ warning("-flat_namespace is deprecated on %s", platformName(fPlatform));
+ break;
+ default:
+ 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 ( fPlatform == kPlatformOSX ) {
+ 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 ( fPlatform == kPlatformOSX ) {
+ 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:
// 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;
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
- if ( !fSegmentOrder.empty() && (fOutputKind != Options::kPreload) )
+ // -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";
- if ( fBitcodeKind != kBitcodeProcess &&
- fOutputKind != Options::kObjectFile ) {
- throw "-bitcode_process_mode can only be used together with -r";
+ // 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.
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?
+ // <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) && (fIOSVersionMin != ld::iOSVersionUnset) && (fDylibInstallName != NULL) ) {
if ( !min_iOS(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";
+ }
}
}
+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;
+ }
+}
+