#include <vector>
#include <list>
#include <algorithm>
-#include <ext/hash_map>
-#include <ext/hash_set>
#include <dlfcn.h>
#include <AvailabilityMacros.h>
#include "Options.h"
-
#include "ld.hpp"
+#include "Bitcode.hpp"
#include "InputFiles.h"
#include "SymbolTable.h"
#include "Resolver.h"
#include "parsers/lto_file.h"
+#include "configure.h"
+
+#define VAL(x) #x
+#define STRINGIFY(x) VAL(x)
namespace ld {
namespace tool {
_name(nm) {}
// overrides of ld::Atom
virtual const ld::File* file() const { return NULL; }
- virtual bool translationUnitSource(const char** dir, const char** nm) const
- { return false; }
virtual const char* name() const { return _name; }
virtual uint64_t size() const { return 0; }
virtual uint64_t objectAddress() const { return 0; }
// overrides of ld::Atom
virtual const ld::File* file() const { return _aliasOf.file(); }
- virtual bool translationUnitSource(const char** dir, const char** nm) const
- { return _aliasOf.translationUnitSource(dir, nm); }
+ virtual const char* translationUnitSource() const
+ { return _aliasOf.translationUnitSource(); }
virtual const char* name() const { return _name; }
virtual uint64_t size() const { return 0; }
virtual uint64_t objectAddress() const { return _aliasOf.objectAddress(); }
virtual ld::Atom::UnwindInfo::iterator endUnwind() const { return NULL; }
virtual ld::Atom::LineInfo::iterator beginLineInfo() const { return NULL; }
virtual ld::Atom::LineInfo::iterator endLineInfo() const { return NULL; }
+
+ void setFinalAliasOf() const {
+ (const_cast<AliasAtom*>(this))->setAttributesFromAtom(_aliasOf);
+ (const_cast<AliasAtom*>(this))->setScope(ld::Atom::scopeGlobal);
+ }
private:
const char* _name;
static SectionBoundaryAtom* makeOldSectionBoundaryAtom(const char* name, bool start);
// overrides of ld::Atom
- virtual bool translationUnitSource(const char** dir, const char** nm) const
- { return false; }
virtual const ld::File* file() const { return NULL; }
virtual const char* name() const { return _name; }
virtual uint64_t size() const { return 0; }
SectionBoundaryAtom* SectionBoundaryAtom::makeSectionBoundaryAtom(const char* name, bool start, const char* segSectName)
{
-
+
const char* segSectDividor = strrchr(segSectName, '$');
if ( segSectDividor == NULL )
throwf("malformed section$ symbol name: %s", name);
throwf("malformed section$ symbol name: %s", name);
char segName[18];
strlcpy(segName, segSectName, segNameLen+1);
-
- const ld::Section* section = new ld::Section(strdup(segName), sectionName, ld::Section::typeUnclassified);
+
+ ld::Section::Type sectType = ld::Section::typeUnclassified;
+ if (!strcmp(segName, "__TEXT") && !strcmp(sectionName, "__thread_starts"))
+ sectType = ld::Section::typeThreadStarts;
+
+ const ld::Section* section = new ld::Section(strdup(segName), sectionName, sectType);
return new SectionBoundaryAtom(name, *section, (start ? ld::Atom::typeSectionStart : typeSectionEnd));
}
static SegmentBoundaryAtom* makeOldSegmentBoundaryAtom(const char* name, bool start);
// overrides of ld::Atom
- virtual bool translationUnitSource(const char** dir, const char** nm) const
- { return false; }
virtual const ld::File* file() const { return NULL; }
virtual const char* name() const { return _name; }
virtual uint64_t size() const { return 0; }
void Resolver::initializeState()
{
- // set initial objc constraint based on command line options
- if ( _options.objcGc() )
- _internal.objcObjectConstraint = ld::File::objcConstraintRetainReleaseOrGC;
- else if ( _options.objcGcOnly() )
- _internal.objcObjectConstraint = ld::File::objcConstraintGC;
-
_internal.cpuSubType = _options.subArchitecture();
+
+ // In -r mode, look for -linker_option additions
+ if ( _options.outputKind() == Options::kObjectFile ) {
+ ld::relocatable::File::LinkerOptionsList lo = _options.linkerOptions();
+ for (relocatable::File::LinkerOptionsList::const_iterator it=lo.begin(); it != lo.end(); ++it) {
+ doLinkerOption(*it, "command line");
+ }
+ }
+#ifdef LD64_VERSION_NUM
+ uint32_t packedNum = Options::parseVersionNumber32(STRINGIFY(LD64_VERSION_NUM));
+ uint64_t combined = (uint64_t)TOOL_LD << 32 | packedNum;
+ _internal.toolsVersions.insert(combined);
+#endif
}
void Resolver::buildAtomList()
{
// each input files contributes initial atoms
_atoms.reserve(1024);
- _inputFiles.forEachInitialAtom(*this);
+ _inputFiles.forEachInitialAtom(*this, _internal);
+
_completedInitialObjectFiles = true;
//_symbolTable.printStatistics();
}
-unsigned int Resolver::ppcSubTypeIndex(uint32_t subtype)
+
+void Resolver::doLinkerOption(const std::vector<const char*>& linkerOption, const char* fileName)
{
- switch ( subtype ) {
- case CPU_SUBTYPE_POWERPC_ALL:
- return 0;
- case CPU_SUBTYPE_POWERPC_750:
- // G3
- return 1;
- case CPU_SUBTYPE_POWERPC_7400:
- case CPU_SUBTYPE_POWERPC_7450:
- // G4
- return 2;
- case CPU_SUBTYPE_POWERPC_970:
- // G5 can run everything
- return 3;
- default:
- throw "Unhandled PPC cpu subtype!";
- break;
+ if ( linkerOption.size() == 1 ) {
+ const char* lo1 = linkerOption.front();
+ if ( strncmp(lo1, "-l", 2) == 0) {
+ if (_internal.linkerOptionLibraries.count(&lo1[2]) == 0) {
+ _internal.unprocessedLinkerOptionLibraries.insert(&lo1[2]);
+ }
+ }
+ else {
+ warning("unknown linker option from object file ignored: '%s' in %s", lo1, fileName);
+ }
+ }
+ else if ( linkerOption.size() == 2 ) {
+ const char* lo2a = linkerOption[0];
+ const char* lo2b = linkerOption[1];
+ if ( strcmp(lo2a, "-framework") == 0) {
+ if (_internal.linkerOptionFrameworks.count(lo2b) == 0) {
+ _internal.unprocessedLinkerOptionFrameworks.insert(lo2b);
+ }
+ }
+ else {
+ warning("unknown linker option from object file ignored: '%s' '%s' from %s", lo2a, lo2b, fileName);
+ }
+ }
+ else {
+ warning("unknown linker option from object file ignored, starting with: '%s' from %s", linkerOption.front(), fileName);
}
}
+
void Resolver::doFile(const ld::File& file)
{
const ld::relocatable::File* objFile = dynamic_cast<const ld::relocatable::File*>(&file);
const ld::dylib::File* dylibFile = dynamic_cast<const ld::dylib::File*>(&file);
if ( objFile != NULL ) {
+ // if file has linker options, process them
+ ld::relocatable::File::LinkerOptionsList* lo = objFile->linkerOptions();
+ if ( lo != NULL && !_options.ignoreAutoLink() ) {
+ for (relocatable::File::LinkerOptionsList::const_iterator it=lo->begin(); it != lo->end(); ++it) {
+ this->doLinkerOption(*it, file.path());
+ }
+ // <rdar://problem/23053404> process any additional linker-options introduced by this new archive member being loaded
+ if ( _completedInitialObjectFiles ) {
+ _inputFiles.addLinkerOptionLibraries(_internal, *this);
+ _inputFiles.createIndirectDylibs();
+ }
+ }
// update which form of ObjC is being used
- switch ( file.objCConstraint() ) {
- case ld::File::objcConstraintNone:
- break;
- case ld::File::objcConstraintRetainRelease:
- if ( _internal.objcObjectConstraint == ld::File::objcConstraintGC )
- throwf("%s built with incompatible Garbage Collection settings to link with previous .o files", file.path());
- if ( _options.objcGcOnly() )
- throwf("command line specified -objc_gc_only, but file is retain/release based: %s", file.path());
- if ( _options.objcGc() )
- throwf("command line specified -objc_gc, but file is retain/release based: %s", file.path());
- _internal.objcObjectConstraint = ld::File::objcConstraintRetainRelease;
- break;
- case ld::File::objcConstraintRetainReleaseOrGC:
- if ( _internal.objcObjectConstraint == ld::File::objcConstraintNone )
- _internal.objcObjectConstraint = ld::File::objcConstraintRetainReleaseOrGC;
- break;
- case ld::File::objcConstraintGC:
- if ( _internal.objcObjectConstraint == ld::File::objcConstraintRetainRelease )
- throwf("%s built with incompatible Garbage Collection settings to link with previous .o files", file.path());
- _internal.objcObjectConstraint = ld::File::objcConstraintGC;
- break;
+ if ( objFile->hasObjC() )
+ _internal.hasObjC = true;
+
+ // Resolve bitcode section in the object file
+ if ( _options.bundleBitcode() ) {
+ if ( objFile->getBitcode() == NULL ) {
+ // Handle the special case for compiler_rt objects. Add the file to the list to be process.
+ if ( objFile->sourceKind() == ld::relocatable::File::kSourceCompilerArchive ) {
+ _internal.filesFromCompilerRT.push_back(objFile);
+ } else if (objFile->sourceKind() != ld::relocatable::File::kSourceLTO ) {
+ // No bitcode section, figure out if the object file comes from LTO/compiler static library
+ _options.platforms().forEach(^(ld::Platform platform, uint32_t version, bool &stop) {
+ switch ( platform ) {
+ case ld::kPlatform_macOS:
+ case ld::kPlatform_bridgeOS:
+ case ld::kPlatform_iOSMac:
+ case ld::kPlatform_unknown:
+ warning("all bitcode will be dropped because '%s' was built without bitcode. "
+ "You must rebuild it with bitcode enabled (Xcode setting ENABLE_BITCODE), obtain an updated library from the vendor, or disable bitcode for this target. ", file.path());
+ _internal.filesWithBitcode.clear();
+ _internal.dropAllBitcode = true;
+ break;
+ case ld::kPlatform_iOS:
+ case ld::kPlatform_iOSSimulator:
+ throwf("'%s' does not contain bitcode. "
+ "You must rebuild it with bitcode enabled (Xcode setting ENABLE_BITCODE), obtain an updated library from the vendor, or disable bitcode for this target.", file.path());
+ break;
+ case ld::kPlatform_watchOS:
+ case ld::kPlatform_watchOSSimulator:
+ case ld::kPlatform_tvOS:
+ case ld::kPlatform_tvOSSimulator:
+ throwf("'%s' does not contain bitcode. "
+ "You must rebuild it with bitcode enabled (Xcode setting ENABLE_BITCODE) or obtain an updated library from the vendor", file.path());
+ break;
+ }
+ });
+ }
+ } else {
+ // contains bitcode, check if it is just a marker
+ if ( objFile->getBitcode()->isMarker() ) {
+ // if -bitcode_verify_bundle is used, check if all the object files participate in the linking have full bitcode embedded.
+ // error on any marker encountered.
+ if ( _options.verifyBitcode() )
+ throwf("bitcode bundle could not be generated because '%s' was built without full bitcode. "
+ "All object files and libraries for bitcode must be generated from Xcode Archive or Install build",
+ objFile->path());
+ // update the internal state that marker is encountered.
+ _internal.embedMarkerOnly = true;
+ _internal.filesWithBitcode.clear();
+ _internal.dropAllBitcode = true;
+ } else if ( !_internal.dropAllBitcode )
+ _internal.filesWithBitcode.push_back(objFile);
+ }
}
-
+
+ // verify all files use same version of Swift language
+ if ( file.swiftVersion() != 0 ) {
+ _internal.someObjectFileHasSwift = true;
+ if ( _internal.swiftVersion == 0 ) {
+ _internal.swiftVersion = file.swiftVersion();
+ }
+ else if ( file.swiftVersion() != _internal.swiftVersion ) {
+ char fileVersion[64];
+ char otherVersion[64];
+ Options::userReadableSwiftVersion(file.swiftVersion(), fileVersion);
+ Options::userReadableSwiftVersion(_internal.swiftVersion, otherVersion);
+ if ( file.swiftVersion() > _internal.swiftVersion ) {
+ if ( _options.warnOnSwiftABIVersionMismatches() ) {
+ warning("%s compiled with newer version of Swift language (%s) than previous files (%s)",
+ file.path(), fileVersion, otherVersion);
+ } else {
+ throwf("%s compiled with newer version of Swift language (%s) than previous files (%s)",
+ file.path(), fileVersion, otherVersion);
+ }
+ }
+ else {
+ if ( _options.warnOnSwiftABIVersionMismatches() ) {
+ warning("%s compiled with older version of Swift language (%s) than previous files (%s)",
+ file.path(), fileVersion, otherVersion);
+ } else {
+ throwf("%s compiled with older version of Swift language (%s) than previous files (%s)",
+ file.path(), fileVersion, otherVersion);
+ }
+ }
+ }
+ }
+
// in -r mode, if any .o files have dwarf then add UUID to output .o file
if ( objFile->debugInfo() == ld::relocatable::File::kDebugInfoDwarf )
_internal.someObjectFileHasDwarf = true;
- // remember if any objc classes built for fix-and-continue
- if ( objFile->objcReplacementClasses() )
- _internal.hasObjcReplacementClasses = true;
-
// remember if any .o file did not have MH_SUBSECTIONS_VIA_SYMBOLS bit set
if ( ! objFile->canScatterAtoms() )
_internal.allObjectFilesScatterable = false;
-
+
+ // remember if building for profiling (so we don't warn about initializers)
+ if ( objFile->hasllvmProfiling() )
+ _havellvmProfiling = true;
+
+#if MULTI
+ // update minOSVersion off all .o files
+ uint32_t objMinOS = objFile->minOSVersion();
+ if ( !objMinOS )
+ _internal.objectFileFoundWithNoVersion = true;
+ if ( (_options.outputKind() == Options::kObjectFile) && (objMinOS > _internal.minOSVersion) )
+ _internal.minOSVersion = objMinOS;
+#endif
+
+ auto objPlatforms = objFile->platforms();
+ if ( (!objPlatforms.empty()) && (_options.outputKind() == Options::kObjectFile) && (_internal.derivedPlatforms.empty()) )
+ _internal.derivedPlatforms = objPlatforms;
+ // update set of known tools used
+ for (const std::pair<uint32_t,uint32_t>& entry : objFile->toolVersions()) {
+ uint64_t combined = (uint64_t)entry.first << 32 | entry.second;
+ _internal.toolsVersions.insert(combined);
+ }
+
// update cpu-sub-type
cpu_subtype_t nextObjectSubType = file.cpuSubType();
switch ( _options.architecture() ) {
- case CPU_TYPE_POWERPC:
- // no checking when -force_cpusubtype_ALL is used
- if ( _options.forceCpuSubtypeAll() )
- return;
- if ( _options.preferSubArchitecture() ) {
- // warn if some .o file is not compatible with desired output sub-type
- if ( _options.subArchitecture() != nextObjectSubType ) {
- if ( ppcSubTypeIndex(nextObjectSubType) > ppcSubTypeIndex(_options.subArchitecture()) ) {
- if ( !_inputFiles.inferredArch() )
- warning("cpu-sub-type of %s is not compatible with command line cpu-sub-type", file.path());
- _internal.cpuSubType = nextObjectSubType;
- }
- }
- }
- else {
- // command line to linker just had -arch ppc
- // figure out final sub-type based on sub-type of all .o files
- if ( ppcSubTypeIndex(nextObjectSubType) > ppcSubTypeIndex(_internal.cpuSubType) ) {
- _internal.cpuSubType = nextObjectSubType;
- }
- }
- break;
-
case CPU_TYPE_ARM:
if ( _options.subArchitecture() != nextObjectSubType ) {
if ( (_options.subArchitecture() == CPU_SUBTYPE_ARM_ALL) && _options.forceCpuSubtypeAll() ) {
}
break;
- case CPU_TYPE_POWERPC64:
+ case CPU_TYPE_ARM64:
+ if ( _options.subArchitecture() != nextObjectSubType ) {
+ if ( _options.allowSubArchitectureMismatches() ) {
+ warning("object file %s was built for different arm64 sub-type (%d) than link command line (%d)",
+ file.path(), nextObjectSubType, _options.subArchitecture());
+ }
+ else {
+ throwf("object file %s was built for different arm64 sub-type (%d) than link command line (%d)",
+ file.path(), nextObjectSubType, _options.subArchitecture());
+ }
+ }
break;
-
+
case CPU_TYPE_I386:
_internal.cpuSubType = CPU_SUBTYPE_I386_ALL;
break;
case CPU_TYPE_X86_64:
- _internal.cpuSubType = CPU_SUBTYPE_X86_64_ALL;
+ if ( _options.subArchitecture() != nextObjectSubType ) {
+ if ( _options.allowSubArchitectureMismatches() ) {
+ warning("object file %s was built for different x86_64 sub-type (%d) than link command line (%d)",
+ file.path(), nextObjectSubType, _options.subArchitecture());
+ }
+ else {
+ throwf("object file %s was built for different x86_64 sub-type (%d) than link command line (%d)",
+ file.path(), nextObjectSubType, _options.subArchitecture());
+ }
+ }
break;
}
}
if ( dylibFile != NULL ) {
- // update which form of ObjC dylibs are being linked
- switch ( dylibFile->objCConstraint() ) {
- case ld::File::objcConstraintNone:
- break;
- case ld::File::objcConstraintRetainRelease:
- if ( _internal.objcDylibConstraint == ld::File::objcConstraintGC )
- throwf("%s built with incompatible Garbage Collection settings to link with previous dylibs", file.path());
- if ( _options.objcGcOnly() )
- throwf("command line specified -objc_gc_only, but dylib is retain/release based: %s", file.path());
- if ( _options.objcGc() )
- throwf("command line specified -objc_gc, but dylib is retain/release based: %s", file.path());
- _internal.objcDylibConstraint = ld::File::objcConstraintRetainRelease;
- break;
- case ld::File::objcConstraintRetainReleaseOrGC:
- if ( _internal.objcDylibConstraint == ld::File::objcConstraintNone )
- _internal.objcDylibConstraint = ld::File::objcConstraintRetainReleaseOrGC;
- break;
- case ld::File::objcConstraintGC:
- if ( _internal.objcDylibConstraint == ld::File::objcConstraintRetainRelease )
- throwf("%s built with incompatible Garbage Collection settings to link with previous dylibs", file.path());
- _internal.objcDylibConstraint = ld::File::objcConstraintGC;
- break;
+ // Check dylib for bitcode, if the library install path is relative path or @rpath, it has to contain bitcode
+ if ( _options.bundleBitcode() ) {
+ bool isSystemFramework = ( dylibFile->installPath() != NULL ) && ( dylibFile->installPath()[0] == '/' );
+ if ( dylibFile->getBitcode() == NULL && !isSystemFramework ) {
+ // Check if the dylib is from toolchain by checking the path
+ char tcLibPath[PATH_MAX];
+ char ldPath[PATH_MAX];
+ char tempPath[PATH_MAX];
+ uint32_t bufSize = PATH_MAX;
+ // toolchain library path should pointed to *.xctoolchain/usr/lib
+ if ( _NSGetExecutablePath(ldPath, &bufSize) != -1 ) {
+ if ( realpath(ldPath, tempPath) != NULL ) {
+ char* lastSlash = strrchr(tempPath, '/');
+ if ( lastSlash != NULL )
+ strcpy(lastSlash, "/../lib");
+ }
+ }
+ // Compare toolchain library path to the dylib path
+ if ( realpath(tempPath, tcLibPath) == NULL ||
+ realpath(dylibFile->path(), tempPath) == NULL ||
+ strncmp(tcLibPath, tempPath, strlen(tcLibPath)) != 0 ) {
+ _options.platforms().forEach(^(ld::Platform platform, uint32_t version, bool &stop) {
+ switch ( platform ) {
+ case ld::kPlatform_macOS:
+ case ld::kPlatform_bridgeOS:
+ case ld::kPlatform_iOSMac:
+ case ld::kPlatform_unknown:
+ warning("all bitcode will be dropped because '%s' was built without bitcode. "
+ "You must rebuild it with bitcode enabled (Xcode setting ENABLE_BITCODE), obtain an updated library from the vendor, or disable bitcode for this target.", file.path());
+ _internal.filesWithBitcode.clear();
+ _internal.dropAllBitcode = true;
+ break;
+ case ld::kPlatform_iOS:
+ case ld::kPlatform_iOSSimulator:
+ throwf("'%s' does not contain bitcode. "
+ "You must rebuild it with bitcode enabled (Xcode setting ENABLE_BITCODE), obtain an updated library from the vendor, or disable bitcode for this target.", file.path());
+ break;
+ case ld::kPlatform_watchOS:
+ case ld::kPlatform_watchOSSimulator:
+ case ld::kPlatform_tvOS:
+ case ld::kPlatform_tvOSSimulator:
+ throwf("'%s' does not contain bitcode. "
+ "You must rebuild it with bitcode enabled (Xcode setting ENABLE_BITCODE) or obtain an updated library from the vendor", file.path());
+ break;
+ }
+ });
+ }
+ }
+ // Error on bitcode marker in non-system frameworks if -bitcode_verify is used
+ if ( _options.verifyBitcode() && !isSystemFramework &&
+ dylibFile->getBitcode() != NULL && dylibFile->getBitcode()->isMarker() )
+ throwf("bitcode bundle could not be generated because '%s' was built without full bitcode. "
+ "All frameworks and dylibs for bitcode must be generated from Xcode Archive or Install build",
+ dylibFile->path());
+ }
+
+ // Don't allow swift frameworks to link other swift frameworks.
+ if ( !_internal.firstSwiftDylibFile && _options.outputKind() == Options::kDynamicLibrary
+ && file.swiftVersion() != 0 && getenv("LD_DISALLOW_SWIFT_LINKING_SWIFT")) {
+ // Check that we aren't a whitelisted path.
+ bool inWhiteList = false;
+ const char *whitelistedPaths[] = { "/System/Library/PrivateFrameworks/Swift" };
+ for (auto whitelistedPath : whitelistedPaths) {
+ if (!strncmp(whitelistedPath, dylibFile->installPath(), strlen(whitelistedPath))) {
+ inWhiteList = true;
+ break;
+ }
+ }
+ if (!inWhiteList) {
+ _internal.firstSwiftDylibFile = dylibFile;
+ }
+ }
+
+ // <rdar://problem/25680358> verify dylibs use same version of Swift language
+ if ( file.swiftVersion() != 0 ) {
+ if ( _internal.swiftVersion == 0 ) {
+ _internal.swiftVersion = file.swiftVersion();
+ }
+ else if ( file.swiftVersion() != _internal.swiftVersion ) {
+ char fileVersion[64];
+ char otherVersion[64];
+ Options::userReadableSwiftVersion(file.swiftVersion(), fileVersion);
+ Options::userReadableSwiftVersion(_internal.swiftVersion, otherVersion);
+ if ( file.swiftVersion() > _internal.swiftVersion ) {
+ if ( _options.warnOnSwiftABIVersionMismatches() ) {
+ warning("%s compiled with newer version of Swift language (%s) than previous files (%s)",
+ file.path(), fileVersion, otherVersion);
+ } else {
+ throwf("%s compiled with newer version of Swift language (%s) than previous files (%s)",
+ file.path(), fileVersion, otherVersion);
+ }
+ }
+ else {
+ if ( _options.warnOnSwiftABIVersionMismatches() ) {
+ warning("%s compiled with older version of Swift language (%s) than previous files (%s)",
+ file.path(), fileVersion, otherVersion);
+ } else {
+ throwf("%s compiled with older version of Swift language (%s) than previous files (%s)",
+ file.path(), fileVersion, otherVersion);
+ }
+ }
+ }
}
- }
+ if ( _options.checkDylibsAreAppExtensionSafe() && !dylibFile->appExtensionSafe() ) {
+ warning("linking against a dylib which is not safe for use in application extensions: %s", file.path());
+ }
+ const char* depInstallName = dylibFile->installPath();
+ // <rdar://problem/17229513> embedded frameworks are only supported on iOS 8 and later
+ if ( (depInstallName != NULL) && (depInstallName[0] != '/') ) {
+ if ( _options.platforms().contains(ld::kPlatform_iOS) && !_options.platforms().minOS(iOS_8_0) ) {
+ // <rdar://problem/17598404> only warn about linking against embedded dylib if it is built for iOS 8 or later
+ if ( dylibFile->platforms().minOS(ld::iOS_8_0) )
+ throwf("embedded dylibs/frameworks are only supported on iOS 8.0 and later (%s)", depInstallName);
+ }
+ }
+ if ( _options.sharedRegionEligible() ) {
+ assert(depInstallName != NULL);
+ if ( depInstallName[0] == '@' ) {
+ warning("invalid -install_name (%s) in dependent dylib (%s). Dylibs/frameworks which might go in dyld shared cache "
+ "cannot link with dylib that uses @rpath, @loader_path, etc.", depInstallName, dylibFile->path());
+ } else if ( (strncmp(depInstallName, "/usr/lib/", 9) != 0) && (strncmp(depInstallName, "/System/Library/", 16) != 0) ) {
+ warning("invalid -install_name (%s) in dependent dylib (%s). Dylibs/frameworks which might go in dyld shared cache "
+ "cannot link with dylibs that won't be in the shared cache", depInstallName, dylibFile->path());
+ }
+ }
+ }
}
void Resolver::doAtom(const ld::Atom& atom)
{
- //fprintf(stderr, "Resolver::doAtom(%p), name=%s, sect=%s\n", &atom, atom.name(), atom.section().sectionName());
+ //fprintf(stderr, "Resolver::doAtom(%p), name=%s, sect=%s, scope=%d\n", &atom, atom.name(), atom.section().sectionName(), atom.scope());
+ if ( _ltoCodeGenFinished && (atom.contentType() == ld::Atom::typeLTOtemporary) && (atom.scope() != ld::Atom::scopeTranslationUnit) )
+ warning("'%s' is implemented in bitcode, but it was loaded too late", atom.name());
// add to list of known atoms
_atoms.push_back(&atom);
}
else if ( _options.outputKind() == Options::kDynamicLibrary ) {
if ( atom.file() != NULL )
- warning("target OS does not support re-exporting symbol %s from %s\n", SymbolTable::demangle(name), atom.file()->path());
+ warning("target OS does not support re-exporting symbol %s from %s\n", _options.demangleSymbol(name), atom.safeFilePath());
else
- warning("target OS does not support re-exporting symbol %s\n", SymbolTable::demangle(name));
+ warning("target OS does not support re-exporting symbol %s\n", _options.demangleSymbol(name));
}
}
else {
if ( atom.file() != NULL )
- warning("cannot export hidden symbol %s from %s", SymbolTable::demangle(name), atom.file()->path());
+ warning("cannot export hidden symbol %s from %s", _options.demangleSymbol(name), atom.safeFilePath());
else
- warning("cannot export hidden symbol %s", SymbolTable::demangle(name));
+ warning("cannot export hidden symbol %s", _options.demangleSymbol(name));
}
}
}
(const_cast<ld::Atom*>(&atom))->setScope(ld::Atom::scopeGlobal);
}
else {
- throwf("requested re-export symbol %s is not from a dylib, but from %s\n", SymbolTable::demangle(name), atom.file()->path());
+ throwf("requested re-export symbol %s is not from a dylib, but from %s\n", _options.demangleSymbol(name), atom.safeFilePath());
}
}
break;
//fprintf(stderr, "demote %s to hidden\n", name);
}
if ( _options.canReExportSymbols() && _options.shouldReExport(name) ) {
- throwf("requested re-export symbol %s is not from a dylib, but from %s\n", SymbolTable::demangle(name), atom.file()->path());
+ throwf("requested re-export symbol %s is not from a dylib, but from %s\n", _options.demangleSymbol(name), atom.safeFilePath());
}
break;
}
// work around for kernel that uses 'l' labels in assembly code
if ( (atom.symbolTableInclusion() == ld::Atom::symbolTableNotInFinalLinkedImages)
- && (atom.name()[0] == 'l') && (_options.outputKind() == Options::kStaticExecutable) )
+ && (atom.name()[0] == 'l') && (_options.outputKind() == Options::kStaticExecutable)
+ && (strncmp(atom.name(), "ltmp", 4) != 0) )
(const_cast<ld::Atom*>(&atom))->setSymbolTableInclusion(ld::Atom::symbolTableIn);
// tell symbol table about non-static atoms
if ( atom.scope() != ld::Atom::scopeTranslationUnit ) {
- _symbolTable.add(atom, _options.deadCodeStrip() && _completedInitialObjectFiles);
+ _symbolTable.add(atom, _options.deadCodeStrip() && (_completedInitialObjectFiles || _options.allowDeadDuplicates()));
// add symbol aliases defined on the command line
if ( _options.haveCmdLineAliases() ) {
const std::vector<Options::AliasPair>& aliases = _options.cmdLineAliases();
for (std::vector<Options::AliasPair>::const_iterator it=aliases.begin(); it != aliases.end(); ++it) {
if ( strcmp(it->realName, atom.name()) == 0 ) {
- const ld::Atom* alias = new AliasAtom(atom, it->alias);
- this->doAtom(*alias);
+ if ( strcmp(it->realName, it->alias) == 0 ) {
+ warning("ignoring alias of itself '%s'", it->realName);
+ }
+ else {
+ const AliasAtom* alias = new AliasAtom(atom, it->alias);
+ _aliasesFromCmdLine.push_back(alias);
+ this->doAtom(*alias);
+ }
}
}
}
if ( atom.contentType() == ld::Atom::typeLTOtemporary )
_haveLLVMObjs = true;
- // if we've already partitioned into final sections, and lto needs a symbol very late, add it
- if ( _addToFinalSection )
- _internal.addAtom(atom);
+ // remember if any atoms are aliases
+ if ( atom.section().type() == ld::Section::typeTempAlias )
+ _haveAliases = true;
+
+ // error or warn about initializers
+ if ( (atom.section().type() == ld::Section::typeInitializerPointers) && !_havellvmProfiling ) {
+ switch ( _options.initializersTreatment() ) {
+ case Options::kError:
+ throwf("static initializer found in '%s'",atom.safeFilePath());
+ case Options::kWarning:
+ warning("static initializer found in '%s'. Use -no_inits to make this an error. Use -no_warn_inits to suppress warning",atom.safeFilePath());
+ break;
+ default:
+ break;
+ }
+ }
if ( _options.deadCodeStrip() ) {
// add to set of dead-strip-roots, all symbols that the compiler marks as don't strip
if ( atom.dontDeadStrip() )
_deadStripRoots.insert(&atom);
+ else if ( atom.dontDeadStripIfReferencesLive() )
+ _dontDeadStripIfReferencesLive.push_back(&atom);
if ( atom.scope() == ld::Atom::scopeGlobal ) {
// <rdar://problem/5524973> -exported_symbols_list that has wildcards and -dead_strip
case ld::Fixup::kindStoreX86DtraceIsEnableSiteClear:
case ld::Fixup::kindStoreARMDtraceCallSiteNop:
case ld::Fixup::kindStoreARMDtraceIsEnableSiteClear:
+ case ld::Fixup::kindStoreARM64DtraceCallSiteNop:
+ case ld::Fixup::kindStoreARM64DtraceIsEnableSiteClear:
case ld::Fixup::kindStoreThumbDtraceCallSiteNop:
case ld::Fixup::kindStoreThumbDtraceIsEnableSiteClear:
- case ld::Fixup::kindStorePPCDtraceCallSiteNop:
- case ld::Fixup::kindStorePPCDtraceIsEnableSiteClear:
case ld::Fixup::kindDtraceExtra:
return true;
default:
const ld::Atom* dummy;
ld::Fixup::iterator end = atom.fixupsEnd();
for (ld::Fixup::iterator fit=atom.fixupsBegin(); fit != end; ++fit) {
+ if ( fit->kind == ld::Fixup::kindLinkerOptimizationHint )
+ _internal.someObjectHasOptimizationHints = true;
switch ( fit->binding ) {
case ld::Fixup::bindingByNameUnbound:
if ( isDtraceProbe(fit->kind) && (_options.outputKind() != Options::kObjectFile ) ) {
}
}
}
-
+
+ // Use linker options to resolve any remaining undefined symbols
+ if ( !_internal.linkerOptionLibraries.empty() || !_internal.linkerOptionFrameworks.empty() ) {
+ std::vector<const char*> undefineNames;
+ _symbolTable.undefines(undefineNames);
+ if ( undefineNames.size() != 0 ) {
+ for (std::vector<const char*>::iterator it = undefineNames.begin(); it != undefineNames.end(); ++it) {
+ const char* undef = *it;
+ if ( ! _symbolTable.hasName(undef) ) {
+ _inputFiles.searchLibraries(undef, true, true, false, *this);
+ }
+ }
+ }
+ }
+
// create proxies as needed for undefined symbols
if ( (_options.undefinedTreatment() != Options::kUndefinedError) || (_options.outputKind() == Options::kObjectFile) ) {
std::vector<const char*> undefineNames;
_symbolTable.undefines(undefineNames);
for(std::vector<const char*>::iterator it = undefineNames.begin(); it != undefineNames.end(); ++it) {
- // make proxy
- this->doAtom(*new UndefinedProxyAtom(*it));
+ const char* undefName = *it;
+ // <rdar://problem/14547001> "ld -r -exported_symbol _foo" has wrong error message if _foo is undefined
+ bool makeProxy = true;
+ if ( (_options.outputKind() == Options::kObjectFile) && _options.hasExportMaskList() && _options.shouldExport(undefName) )
+ makeProxy = false;
+
+ if ( makeProxy )
+ this->doAtom(*new UndefinedProxyAtom(undefName));
}
}
}
}
+ // After resolving all the undefs within the linkageUnit, record all the remaining undefs and all the proxies.
+ if (_options.bundleBitcode() && _options.hideSymbols())
+ _symbolTable.mustPreserveForBitcode(_internal.allUndefProxies);
+
}
//fprintf(stderr, "markLive(%p) %s\n", &atom, atom.name());
// if -why_live cares about this symbol, then dump chain
if ( (previous->referer != NULL) && _options.printWhyLive(atom.name()) ) {
- fprintf(stderr, "%s from %s\n", atom.name(), atom.file()->path());
+ fprintf(stderr, "%s from %s\n", atom.name(), atom.safeFilePath());
int depth = 1;
for(WhyLiveBackChain* p = previous; p != NULL; p = p->previous, ++depth) {
for(int i=depth; i > 0; --i)
fprintf(stderr, " ");
- fprintf(stderr, "%s from %s\n", p->referer->name(), p->referer->file()->path());
+ fprintf(stderr, "%s from %s\n", p->referer->name(), p->referer->safeFilePath());
}
}
case ld::Fixup::kindNoneGroupSubordinate:
case ld::Fixup::kindNoneGroupSubordinateFDE:
case ld::Fixup::kindNoneGroupSubordinateLSDA:
+ case ld::Fixup::kindNoneGroupSubordinatePersonality:
case ld::Fixup::kindSetTargetAddress:
case ld::Fixup::kindSubtractTargetAddress:
case ld::Fixup::kindStoreTargetAddressLittleEndian32:
case ld::Fixup::kindStoreTargetAddressLittleEndian64:
+#if SUPPORT_ARCH_arm64e
+ case ld::Fixup::kindStoreTargetAddressLittleEndianAuth64:
+#endif
case ld::Fixup::kindStoreTargetAddressBigEndian32:
case ld::Fixup::kindStoreTargetAddressBigEndian64:
case ld::Fixup::kindStoreTargetAddressX86PCRel32:
case ld::Fixup::kindStoreTargetAddressX86Abs32TLVLoadNowLEA:
case ld::Fixup::kindStoreTargetAddressARMBranch24:
case ld::Fixup::kindStoreTargetAddressThumbBranch22:
- case ld::Fixup::kindStoreTargetAddressPPCBranch24:
+#if SUPPORT_ARCH_arm64
+ case ld::Fixup::kindStoreTargetAddressARM64Branch26:
+ case ld::Fixup::kindStoreTargetAddressARM64Page21:
+ case ld::Fixup::kindStoreTargetAddressARM64GOTLoadPage21:
+ case ld::Fixup::kindStoreTargetAddressARM64GOTLeaPage21:
+ case ld::Fixup::kindStoreTargetAddressARM64TLVPLoadPage21:
+ case ld::Fixup::kindStoreTargetAddressARM64TLVPLoadNowLeaPage21:
+#endif
if ( fit->binding == ld::Fixup::bindingByContentBound ) {
// normally this was done in convertReferencesToIndirect()
// but a archive loaded .o file may have a forward reference
}
};
-void Resolver::deadStripOptimize()
+void Resolver::deadStripOptimize(bool force)
{
// only do this optimization with -dead_strip
if ( ! _options.deadCodeStrip() )
this->markLive(**it, &rootChain);
}
+ // special case atoms that need to be live if they reference something live
+ if ( ! _dontDeadStripIfReferencesLive.empty() ) {
+ for (std::vector<const ld::Atom*>::iterator it=_dontDeadStripIfReferencesLive.begin(); it != _dontDeadStripIfReferencesLive.end(); ++it) {
+ const Atom* liveIfRefLiveAtom = *it;
+ //fprintf(stderr, "live-if-live atom: %s\n", liveIfRefLiveAtom->name());
+ if ( liveIfRefLiveAtom->live() )
+ continue;
+ bool hasLiveRef = false;
+ for (ld::Fixup::iterator fit=liveIfRefLiveAtom->fixupsBegin(); fit != liveIfRefLiveAtom->fixupsEnd(); ++fit) {
+ const Atom* target = NULL;
+ switch ( fit->binding ) {
+ case ld::Fixup::bindingDirectlyBound:
+ target = fit->u.target;
+ break;
+ case ld::Fixup::bindingsIndirectlyBound:
+ target = _internal.indirectBindingTable[fit->u.bindingIndex];
+ break;
+ default:
+ break;
+ }
+ if ( (target != NULL) && target->live() )
+ hasLiveRef = true;
+ }
+ if ( hasLiveRef ) {
+ WhyLiveBackChain rootChain;
+ rootChain.previous = NULL;
+ rootChain.referer = liveIfRefLiveAtom;
+ this->markLive(*liveIfRefLiveAtom, &rootChain);
+ }
+ }
+ }
+
// now remove all non-live atoms from _atoms
const bool log = false;
if ( log ) {
- fprintf(stderr, "deadStripOptimize() all atoms with liveness:\n");
+ fprintf(stderr, "deadStripOptimize() all %ld atoms with liveness:\n", _atoms.size());
for (std::vector<const ld::Atom*>::const_iterator it=_atoms.begin(); it != _atoms.end(); ++it) {
- fprintf(stderr, " live=%d name=%s\n", (*it)->live(), (*it)->name());
+ const ld::File* file = (*it)->file();
+ fprintf(stderr, " live=%d atom=%p name=%s from=%s\n", (*it)->live(), *it, (*it)->name(), (file ? file->path() : "<internal>"));
}
}
- if ( _haveLLVMObjs ) {
+ if ( _haveLLVMObjs && !force ) {
+ std::copy_if(_atoms.begin(), _atoms.end(), std::back_inserter(_internal.deadAtoms), NotLiveLTO() );
// <rdar://problem/9777977> don't remove combinable atoms, they may come back in lto output
_atoms.erase(std::remove_if(_atoms.begin(), _atoms.end(), NotLiveLTO()), _atoms.end());
+ _symbolTable.removeDeadAtoms();
}
else {
+ std::copy_if(_atoms.begin(), _atoms.end(), std::back_inserter(_internal.deadAtoms), NotLive() );
_atoms.erase(std::remove_if(_atoms.begin(), _atoms.end(), NotLive()), _atoms.end());
}
+
+ if ( log ) {
+ fprintf(stderr, "deadStripOptimize() %ld remaining atoms\n", _atoms.size());
+ for (std::vector<const ld::Atom*>::const_iterator it=_atoms.begin(); it != _atoms.end(); ++it) {
+ fprintf(stderr, " live=%d atom=%p name=%s\n", (*it)->live(), *it, (*it)->name());
+ }
+ }
}
+// This is called when LTO is used but -dead_strip is not used.
+// Some undefines were eliminated by LTO, but others were not.
+void Resolver::remainingUndefines(std::vector<const char*>& undefs)
+{
+ StringSet undefSet;
+ // search all atoms for references that are unbound
+ for (std::vector<const ld::Atom*>::const_iterator it=_atoms.begin(); it != _atoms.end(); ++it) {
+ const ld::Atom* atom = *it;
+ for (ld::Fixup::iterator fit=atom->fixupsBegin(); fit != atom->fixupsEnd(); ++fit) {
+ switch ( (ld::Fixup::TargetBinding)fit->binding ) {
+ case ld::Fixup::bindingByNameUnbound:
+ assert(0 && "should not be by-name this late");
+ undefSet.insert(fit->u.name);
+ break;
+ case ld::Fixup::bindingsIndirectlyBound:
+ if ( _internal.indirectBindingTable[fit->u.bindingIndex] == NULL ) {
+ undefSet.insert(_symbolTable.indirectName(fit->u.bindingIndex));
+ }
+ break;
+ case ld::Fixup::bindingByContentBound:
+ case ld::Fixup::bindingNone:
+ case ld::Fixup::bindingDirectlyBound:
+ break;
+ }
+ }
+ }
+ // look for any initial undefines that are still undefined
+ for (Options::UndefinesIterator uit=_options.initialUndefinesBegin(); uit != _options.initialUndefinesEnd(); ++uit) {
+ if ( ! _symbolTable.hasName(*uit) ) {
+ undefSet.insert(*uit);
+ }
+ }
+
+ // copy set to vector
+ for (StringSet::const_iterator it=undefSet.begin(); it != undefSet.end(); ++it) {
+ fprintf(stderr, "undef: %s\n", *it);
+ undefs.push_back(*it);
+ }
+}
+
void Resolver::liveUndefines(std::vector<const char*>& undefs)
{
StringSet undefSet;
++foundReferenceCount;
}
else if ( atom->contentType() == ld::Atom::typeCFI ) {
- fprintf(stderr, " Dwarf Exception Unwind Info (__eh_frame) in %s\n", pathLeafName(atom->file()->path()));
+ fprintf(stderr, " Dwarf Exception Unwind Info (__eh_frame) in %s\n", pathLeafName(atom->safeFilePath()));
++foundReferenceCount;
}
else {
- fprintf(stderr, " %s in %s\n", SymbolTable::demangle(atom->name()), pathLeafName(atom->file()->path()));
+ fprintf(stderr, " %s in %s\n", _options.demangleSymbol(atom->name()), pathLeafName(atom->safeFilePath()));
++foundReferenceCount;
break; // if undefined used twice in a function, only show first
}
break;
}
std::vector<const char*> unresolvableUndefines;
- if ( _options.deadCodeStrip() )
+ if ( _options.deadCodeStrip() )
this->liveUndefines(unresolvableUndefines);
+ else if( _haveLLVMObjs )
+ this->remainingUndefines(unresolvableUndefines); // <rdar://problem/10052396> LTO may have eliminated need for some undefines
else
_symbolTable.undefines(unresolvableUndefines);
int unresolvableExportsCount = 0;
if ( unresolvableCount != 0 ) {
if ( doPrint ) {
+ for (const auto& lib : _internal.missingLinkerOptionLibraries)
+ warning("Could not find auto-linked library '%s'", lib);
+ for (const auto& frm : _internal.missingLinkerOptionFrameworks)
+ warning("Could not find auto-linked framework '%s'", frm);
if ( _options.printArchPrefix() )
fprintf(stderr, "Undefined symbols for architecture %s:\n", _options.architectureName());
else
for (int i=0; i < unresolvableCount; ++i) {
const char* name = unresolvableUndefines[i];
unsigned int slot = _symbolTable.findSlotForName(name);
- fprintf(stderr, " \"%s\", referenced from:\n", SymbolTable::demangle(name));
+ fprintf(stderr, " \"%s\", referenced from:\n", _options.demangleSymbol(name));
// scan all atoms for references
bool foundAtomReference = printReferencedBy(name, slot);
// scan command line options
else if ( _options.hasReExportList() && _options.shouldReExport(name) ) {
fprintf(stderr, " -reexported_symbols_list command line option\n");
}
+ else if ( (_options.outputKind() == Options::kDynamicExecutable)
+ && (_options.entryName() != NULL) && (strcmp(name, _options.entryName()) == 0) ) {
+ fprintf(stderr, " implicit entry/start for main executable\n");
+ }
else {
bool isInitialUndefine = false;
for (Options::UndefinesIterator uit=_options.initialUndefinesBegin(); uit != _options.initialUndefinesEnd(); ++uit) {
else if ( _internal.indirectBindingTable[slot]->definition() == ld::Atom::definitionProxy ) {
if ( makingDylib )
throwf("-init function (%s) found in linked dylib, must be in dylib being linked", symbolName);
- else
- throwf("entry point (%s) found in linked dylib, must be in executable being linked", symbolName);
}
return _internal.indirectBindingTable[slot];
}
}
_internal.classicBindingHelper = NULL;
+ // FIXME: What about fMakeThreadedStartsSection?
if ( needsStubHelper && !_options.makeCompressedDyldInfo() ) {
// "dyld_stub_binding_helper" comes from .o file, so should already exist in symbol table
if ( _symbolTable.hasName("dyld_stub_binding_helper") ) {
}
_internal.compressedFastBinderProxy = NULL;
+ // FIXME: What about fMakeThreadedStartsSection?
if ( needsStubHelper && _options.makeCompressedDyldInfo() ) {
// "dyld_stub_binder" comes from libSystem.dylib so will need to manually resolve
if ( !_symbolTable.hasName("dyld_stub_binder") ) {
// <rdar://problem/7783918> make sure there is a __text section so that codesigning works
if ( (_options.outputKind() == Options::kDynamicLibrary) || (_options.outputKind() == Options::kDynamicBundle) )
- _internal.getFinalSection(ld::Section("__TEXT", "__text", ld::Section::typeCode));
+ _internal.getFinalSection(*new ld::Section("__TEXT", "__text", ld::Section::typeCode));
- // add entry point
- _internal.entryPoint = this->entryPoint(true);
+ // Don't allow swift frameworks to link other swift frameworks.
+ if ( _internal.someObjectFileHasSwift && _internal.firstSwiftDylibFile != nullptr )
+ throwf("linking swift frameworks against other swift frameworks (%s) is not permitted",
+ _internal.firstSwiftDylibFile->path());
}
+void Resolver::fillInEntryPoint()
+{
+ _internal.entryPoint = this->entryPoint(true);
+}
+void Resolver::syncAliases()
+{
+ if ( !_haveAliases || (_options.outputKind() == Options::kObjectFile) )
+ return;
+
+ // Set attributes of alias to match its found target
+ for (std::vector<const ld::Atom*>::iterator it = _atoms.begin(); it != _atoms.end(); ++it) {
+ const ld::Atom* atom = *it;
+ if ( atom->section().type() == ld::Section::typeTempAlias ) {
+ assert(atom->fixupsBegin() != atom->fixupsEnd());
+ for (ld::Fixup::iterator fit = atom->fixupsBegin(); fit != atom->fixupsEnd(); ++fit) {
+ const ld::Atom* target;
+ ld::Atom::Scope scope;
+ assert(fit->kind == ld::Fixup::kindNoneFollowOn);
+ switch ( fit->binding ) {
+ case ld::Fixup::bindingByNameUnbound:
+ break;
+ case ld::Fixup::bindingsIndirectlyBound:
+ target = _internal.indirectBindingTable[fit->u.bindingIndex];
+ assert(target != NULL);
+ scope = atom->scope();
+ (const_cast<Atom*>(atom))->setAttributesFromAtom(*target);
+ // alias has same attributes as target, except for scope
+ (const_cast<Atom*>(atom))->setScope(scope);
+ break;
+ default:
+ assert(0 && "internal error: unexpected alias binding");
+ }
+ }
+ }
+ }
+}
void Resolver::removeCoalescedAwayAtoms()
{
+ const bool log = false;
+ if ( log ) {
+ fprintf(stderr, "removeCoalescedAwayAtoms() starts with %lu atoms\n", _atoms.size());
+ }
_atoms.erase(std::remove_if(_atoms.begin(), _atoms.end(), AtomCoalescedAway()), _atoms.end());
+ if ( log ) {
+ fprintf(stderr, "removeCoalescedAwayAtoms() after removing coalesced atoms, %lu remain\n", _atoms.size());
+ for (std::vector<const ld::Atom*>::const_iterator it=_atoms.begin(); it != _atoms.end(); ++it) {
+ fprintf(stderr, " atom=%p %s\n", *it, (*it)->name());
+ }
+ }
}
void Resolver::linkTimeOptimize()
// only do work here if some llvm obj files where loaded
if ( ! _haveLLVMObjs )
return;
-
+
+ // <rdar://problem/15314161> LTO: Symbol multiply defined error should specify exactly where the symbol is found
+ _symbolTable.checkDuplicateSymbols();
+
// run LLVM lto code-gen
lto::OptimizeOptions optOpt;
optOpt.outputFilePath = _options.outputFilePath();
optOpt.tmpObjectFilePath = _options.tempLtoObjectPath();
- optOpt.allGlobalsAReDeadStripRoots = _options.allGlobalsAreDeadStripRoots();
+ optOpt.ltoCachePath = _options.ltoCachePath();
+ optOpt.ltoPruneIntervalOverwrite = _options.ltoPruneIntervalOverwrite();
+ optOpt.ltoPruneInterval = _options.ltoPruneInterval();
+ optOpt.ltoPruneAfter = _options.ltoPruneAfter();
+ optOpt.ltoMaxCacheSize = _options.ltoMaxCacheSize();
+ optOpt.preserveAllGlobals = _options.allGlobalsAreDeadStripRoots() || _options.hasExportRestrictList();
optOpt.verbose = _options.verbose();
optOpt.saveTemps = _options.saveTempFiles();
+ optOpt.ltoCodegenOnly = _options.ltoCodegenOnly();
optOpt.pie = _options.positionIndependentExecutable();
optOpt.mainExecutable = _options.linkingMainExecutable();;
optOpt.staticExecutable = (_options.outputKind() == Options::kStaticExecutable);
+ optOpt.preload = (_options.outputKind() == Options::kPreload);
optOpt.relocatable = (_options.outputKind() == Options::kObjectFile);
optOpt.allowTextRelocs = _options.allowTextRelocs();
optOpt.linkerDeadStripping = _options.deadCodeStrip();
+ optOpt.needsUnwindInfoSection = _options.needsUnwindInfoSection();
+ optOpt.keepDwarfUnwind = _options.keepDwarfUnwind();
+ optOpt.verboseOptimizationHints = _options.verboseOptimizationHints();
+ optOpt.armUsesZeroCostExceptions = _options.armUsesZeroCostExceptions();
+ optOpt.simulator = _options.targetIOSSimulator();
+ optOpt.ignoreMismatchPlatform = ((_options.outputKind() == Options::kPreload) || (_options.outputKind() == Options::kStaticExecutable));
+#if SUPPORT_ARCH_arm64e
+ optOpt.supportsAuthenticatedPointers = _options.supportsAuthenticatedPointers();
+#endif
+ optOpt.bitcodeBundle = (_options.bundleBitcode() && (_options.bitcodeKind() != Options::kBitcodeMarker));
+ optOpt.maxDefaultCommonAlignment = _options.maxDefaultCommonAlign();
optOpt.arch = _options.architecture();
+ optOpt.mcpu = _options.mcpuLTO();
+ optOpt.platforms = _options.platforms();
optOpt.llvmOptions = &_options.llvmOptions();
+ optOpt.initialUndefines = &_options.initialUndefines();
std::vector<const ld::Atom*> newAtoms;
std::vector<const char*> additionalUndefines;
- if ( ! lto::optimize(_atoms, _internal, _inputFiles.nextInputOrdinal(), optOpt, *this, newAtoms, additionalUndefines) )
+ if ( ! lto::optimize(_atoms, _internal, optOpt, *this, newAtoms, additionalUndefines) )
return; // if nothing done
-
+ _ltoCodeGenFinished = true;
// add all newly created atoms to _atoms and update symbol table
for(std::vector<const ld::Atom*>::iterator it = newAtoms.begin(); it != newAtoms.end(); ++it)
this->doAtom(**it);
-
+
// some atoms might have been optimized way (marked coalesced), remove them
this->removeCoalescedAwayAtoms();
-
- // add new atoms into their final section
- for (std::vector<const ld::Atom*>::iterator it = newAtoms.begin(); it != newAtoms.end(); ++it) {
- _internal.addAtom(**it);
- }
- // remove temp lto section and move all of its atoms to their final section
- ld::Internal::FinalSection* tempLTOsection = NULL;
- for (std::vector<ld::Internal::FinalSection*>::iterator sit=_internal.sections.begin(); sit != _internal.sections.end(); ++sit) {
- ld::Internal::FinalSection* sect = *sit;
- if ( sect->type() == ld::Section::typeTempLTO ) {
- tempLTOsection = sect;
- // remove temp lto section from final image
- _internal.sections.erase(sit);
- break;
- }
- }
- // lto atoms now have proper section info, so add to final section
- if ( tempLTOsection != NULL ) {
- for (std::vector<const ld::Atom*>::iterator ait=tempLTOsection->atoms.begin(); ait != tempLTOsection->atoms.end(); ++ait) {
- const ld::Atom* atom = *ait;
- if ( ! atom->coalescedAway() ) {
- this->convertReferencesToIndirect(*atom);
- _internal.addAtom(*atom);
- }
- }
+ // run through all atoms again and make sure newly codegened atoms have references bound
+ for (std::vector<const ld::Atom*>::const_iterator it=_atoms.begin(); it != _atoms.end(); ++it)
+ this->convertReferencesToIndirect(**it);
+
+ // adjust section of any new
+ for (std::vector<const AliasAtom*>::const_iterator it=_aliasesFromCmdLine.begin(); it != _aliasesFromCmdLine.end(); ++it) {
+ const AliasAtom* aliasAtom = *it;
+ // update fields in AliasAtom to match newly constructed mach-o atom
+ aliasAtom->setFinalAliasOf();
}
+ // <rdar://problem/14609792> add any auto-link libraries requested by LTO output to dylibs to search
+ _inputFiles.addLinkerOptionLibraries(_internal, *this);
+ _inputFiles.createIndirectDylibs();
+
// resolve new undefines (e.g calls to _malloc and _memcpy that llvm compiler conjures up)
- _addToFinalSection = true;
for(std::vector<const char*>::iterator uit = additionalUndefines.begin(); uit != additionalUndefines.end(); ++uit) {
const char *targetName = *uit;
// these symbols may or may not already be in linker's symbol table
_inputFiles.searchLibraries(targetName, true, true, false, *this);
}
}
- _addToFinalSection = false;
// if -dead_strip on command line
if ( _options.deadCodeStrip() ) {
- // clear liveness bit
+ // run through all atoms again and make live_section LTO atoms are preserved from dead_stripping if needed
+ _dontDeadStripIfReferencesLive.clear();
for (std::vector<const ld::Atom*>::const_iterator it=_atoms.begin(); it != _atoms.end(); ++it) {
+ const ld::Atom* atom = *it;
+ if ( atom->dontDeadStripIfReferencesLive() ) {
+ _dontDeadStripIfReferencesLive.push_back(atom);
+ }
+
+ // clear liveness bit
(const_cast<ld::Atom*>(*it))->setLive((*it)->dontDeadStrip());
}
// and re-compute dead code
- this->deadStripOptimize();
+ this->deadStripOptimize(true);
+ }
- // remove newly dead atoms from each section
- for (std::vector<ld::Internal::FinalSection*>::iterator sit=_internal.sections.begin(); sit != _internal.sections.end(); ++sit) {
- ld::Internal::FinalSection* sect = *sit;
- sect->atoms.erase(std::remove_if(sect->atoms.begin(), sect->atoms.end(), NotLive()), sect->atoms.end());
+ // <rdar://problem/12386559> if -exported_symbols_list on command line, re-force scope
+ if ( _options.hasExportMaskList() ) {
+ for (std::vector<const ld::Atom*>::const_iterator it=_atoms.begin(); it != _atoms.end(); ++it) {
+ const ld::Atom* atom = *it;
+ if ( atom->scope() == ld::Atom::scopeGlobal ) {
+ if ( !_options.shouldExport(atom->name()) ) {
+ (const_cast<ld::Atom*>(atom))->setScope(ld::Atom::scopeLinkageUnit);
+ }
+ }
}
}
if ( _options.outputKind() == Options::kObjectFile ) {
// if -r mode, add proxies for new undefines (e.g. ___stack_chk_fail)
- _addToFinalSection = true;
this->resolveUndefines();
- _addToFinalSection = false;
}
else {
// last chance to check for undefines
+ this->resolveUndefines();
this->checkUndefines(true);
// check new code does not override some dylib
this->checkDylibSymbolCollisions();
+
+ // <rdar://problem/33853815> remove undefs from LTO objects that gets optimized away
+ std::unordered_set<const ld::Atom*> mustPreserve;
+ if ( _internal.classicBindingHelper != NULL )
+ mustPreserve.insert(_internal.classicBindingHelper);
+ if ( _internal.compressedFastBinderProxy != NULL )
+ mustPreserve.insert(_internal.compressedFastBinderProxy);
+ if ( _internal.lazyBindingHelper != NULL )
+ mustPreserve.insert(_internal.lazyBindingHelper);
+ if ( const ld::Atom* entry = this->entryPoint(true) )
+ mustPreserve.insert(entry);
+ for (Options::UndefinesIterator uit=_options.initialUndefinesBegin(); uit != _options.initialUndefinesEnd(); ++uit) {
+ SymbolTable::IndirectBindingSlot slot = _symbolTable.findSlotForName(*uit);
+ if ( _internal.indirectBindingTable[slot] != NULL )
+ mustPreserve.insert(_internal.indirectBindingTable[slot]);
+ }
+ _symbolTable.removeDeadUndefs(_atoms, mustPreserve);
}
}
+void Resolver::tweakWeakness()
+{
+ // <rdar://problem/7977374> Add command line options to control symbol weak-def bit on exported symbols
+ if ( _options.hasWeakBitTweaks() ) {
+ for (std::vector<ld::Internal::FinalSection*>::iterator sit = _internal.sections.begin(); sit != _internal.sections.end(); ++sit) {
+ ld::Internal::FinalSection* sect = *sit;
+ for (std::vector<const ld::Atom*>::iterator ait = sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
+ const ld::Atom* atom = *ait;
+ if ( atom->definition() != ld::Atom::definitionRegular )
+ continue;
+ const char* name = atom->name();
+ if ( atom->scope() == ld::Atom::scopeGlobal ) {
+ if ( atom->combine() == ld::Atom::combineNever ) {
+ if ( _options.forceWeak(name) )
+ (const_cast<ld::Atom*>(atom))->setCombine(ld::Atom::combineByName);
+ }
+ else if ( atom->combine() == ld::Atom::combineByName ) {
+ if ( _options.forceNotWeak(name) )
+ (const_cast<ld::Atom*>(atom))->setCombine(ld::Atom::combineNever);
+ }
+ }
+ else {
+ if ( _options.forceWeakNonWildCard(name) )
+ warning("cannot force to be weak, non-external symbol %s", name);
+ else if ( _options.forceNotWeakNonWildcard(name) )
+ warning("cannot force to be not-weak, non-external symbol %s", name);
+ }
+ }
+ }
+ }
+}
+
+void Resolver::buildArchivesList()
+{
+ // Determine which archives were linked and update the internal state.
+ _inputFiles.archives(_internal);
+}
+
+void Resolver::dumpAtoms()
+{
+ fprintf(stderr, "Resolver all atoms:\n");
+ for (std::vector<const ld::Atom*>::const_iterator it=_atoms.begin(); it != _atoms.end(); ++it) {
+ const ld::Atom* atom = *it;
+ fprintf(stderr, " %p name=%s, def=%d\n", atom, atom->name(), atom->definition());
+ }
+}
+
void Resolver::resolve()
{
this->initializeState();
this->deadStripOptimize();
this->checkUndefines();
this->checkDylibSymbolCollisions();
+ this->syncAliases();
this->removeCoalescedAwayAtoms();
- this->fillInInternalState();
+ this->fillInEntryPoint();
this->linkTimeOptimize();
+ this->fillInInternalState();
+ this->tweakWeakness();
+ _symbolTable.checkDuplicateSymbols();
+ this->buildArchivesList();
}