+
/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-*
*
* Copyright (c) 2009-2011 Apple Inc. All rights reserved.
#include <vector>
#include <list>
#include <algorithm>
-#include <ext/hash_map>
-#include <ext/hash_set>
#include <dlfcn.h>
#include <AvailabilityMacros.h>
#include "InputFiles.h"
#include "macho_relocatable_file.h"
#include "macho_dylib_file.h"
+#include "textstub_dylib_file.hpp"
#include "archive_file.h"
#include "lto_file.h"
#include "opaque_section_file.h"
+#include "MachOFileAbstraction.hpp"
#include "Snapshot.h"
const bool _s_logPThreads = false;
class DSOHandleAtom : public ld::Atom {
public:
DSOHandleAtom(const char* nm, ld::Atom::Scope sc,
- ld::Atom::SymbolTableInclusion inc, bool preload=false)
- : ld::Atom(preload ? _s_section_preload : _s_section,
- ld::Atom::definitionRegular, ld::Atom::combineNever,
+ ld::Atom::SymbolTableInclusion inc, ld::Section& sect=_s_section)
+ : ld::Atom(sect, ld::Atom::definitionRegular,
+ (sect == _s_section_text) ? ld::Atom::combineByName : ld::Atom::combineNever,
+ // make "weak def" so that link succeeds even if app defines __dso_handle
sc, ld::Atom::typeUnclassified, inc, true, false, false,
ld::Atom::Alignment(1)), _name(nm) {}
virtual ld::File* file() const { return NULL; }
- virtual bool translationUnitSource(const char** dir, const char** ) const
- { return false; }
- virtual const char* name() const { return _name; }
+ virtual const char* name() const { return _name; }
virtual uint64_t size() const { return 0; }
virtual uint64_t objectAddress() const { return 0; }
virtual void copyRawContent(uint8_t buffer[]) const
static ld::Section _s_section;
static ld::Section _s_section_preload;
+ static ld::Section _s_section_text;
static DSOHandleAtom _s_atomAll;
static DSOHandleAtom _s_atomExecutable;
static DSOHandleAtom _s_atomDylib;
static DSOHandleAtom _s_atomDyld;
static DSOHandleAtom _s_atomObjectFile;
static DSOHandleAtom _s_atomPreload;
+ static DSOHandleAtom _s_atomPreloadDSO;
private:
const char* _name;
};
ld::Section DSOHandleAtom::_s_section("__TEXT", "__mach_header", ld::Section::typeMachHeader, true);
ld::Section DSOHandleAtom::_s_section_preload("__HEADER", "__mach_header", ld::Section::typeMachHeader, true);
+ld::Section DSOHandleAtom::_s_section_text("__TEXT", "__text", ld::Section::typeCode, false);
DSOHandleAtom DSOHandleAtom::_s_atomAll("___dso_handle", ld::Atom::scopeLinkageUnit, ld::Atom::symbolTableNotIn);
DSOHandleAtom DSOHandleAtom::_s_atomExecutable("__mh_execute_header", ld::Atom::scopeGlobal, ld::Atom::symbolTableInAndNeverStrip);
DSOHandleAtom DSOHandleAtom::_s_atomDylib("__mh_dylib_header", ld::Atom::scopeLinkageUnit, ld::Atom::symbolTableNotIn);
DSOHandleAtom DSOHandleAtom::_s_atomBundle("__mh_bundle_header", ld::Atom::scopeLinkageUnit, ld::Atom::symbolTableNotIn);
DSOHandleAtom DSOHandleAtom::_s_atomDyld("__mh_dylinker_header", ld::Atom::scopeLinkageUnit, ld::Atom::symbolTableNotIn);
DSOHandleAtom DSOHandleAtom::_s_atomObjectFile("__mh_object_header", ld::Atom::scopeLinkageUnit, ld::Atom::symbolTableNotIn);
-DSOHandleAtom DSOHandleAtom::_s_atomPreload("__mh_preload_header", ld::Atom::scopeLinkageUnit, ld::Atom::symbolTableNotIn, true);
+DSOHandleAtom DSOHandleAtom::_s_atomPreload("__mh_preload_header", ld::Atom::scopeLinkageUnit, ld::Atom::symbolTableNotIn, _s_section_preload);
+DSOHandleAtom DSOHandleAtom::_s_atomPreloadDSO("___dso_handle", ld::Atom::scopeLinkageUnit, ld::Atom::symbolTableNotIn, _s_section_text);
_size(sz) {}
virtual ld::File* file() const { return NULL; }
- virtual bool translationUnitSource(const char** dir, const char** ) const
- { return false; }
virtual const char* name() const { return "page zero"; }
virtual uint64_t size() const { return _size; }
virtual uint64_t objectAddress() const { return 0; }
_size(sz) {}
virtual ld::File* file() const { return NULL; }
- virtual bool translationUnitSource(const char** dir, const char** ) const
- { return false; }
virtual const char* name() const { return "custom stack"; }
virtual uint64_t size() const { return _size; }
virtual uint64_t objectAddress() const { return 0; }
ld::Section CustomStackAtom::_s_section("__UNIXSTACK", "__stack", ld::Section::typeStack, true);
+static bool isCompilerSupportLib(const char* path) {
+ const char* libName = strrchr(path, '/');
+ return ( (libName != NULL) && (strncmp(libName, "/libclang_rt", 12) == 0) );
+}
+
const char* InputFiles::fileArch(const uint8_t* p, unsigned len)
{
const char* result = mach_o::relocatable::archName(p);
if ( result != NULL )
return result;
-
+
+ result = mach_o::dylib::archName(p);
+ if ( result != NULL )
+ return result;
+
result = lto::archName(p, len);
if ( result != NULL )
return result;
strcpy(unsupported, "unsupported file format (");
for (unsigned i=0; i<len && i < 16; i++) {
char buf[8];
- sprintf(buf, " 0x%2x", p[i]);
+ sprintf(buf, " 0x%02X", p[i]);
strcat(unsupported, buf);
}
strcat(unsupported, " )");
ld::File* InputFiles::makeFile(const Options::FileInfo& info, bool indirectDylib)
{
+ // handle inlined framework first.
+ if (info.isInlined) {
+ auto interface = _options.findTAPIFile(info.path);
+ auto file = textstub::dylib::parse(info.path, std::move(interface), info.modTime, info.ordinal, _options, indirectDylib);
+ assert(file && "could not locate the inlined file");
+ if (!file)
+ throwf("could not parse inline dylib file: %s(%s)", interface->getInstallName().c_str(), info.path);
+ return file;
+ }
// map in whole file
- uint64_t len = info.fileLen;
+ struct stat stat_buf;
int fd = ::open(info.path, O_RDONLY, 0);
if ( fd == -1 )
throwf("can't open file, errno=%d", errno);
- if ( info.fileLen < 20 )
- throw "file too small";
-
- uint8_t* p = (uint8_t*)::mmap(NULL, info.fileLen, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, 0);
+ if ( ::fstat(fd, &stat_buf) != 0 )
+ throwf("fstat(%s) failed, errno=%d\n", info.path, errno);
+ if ( stat_buf.st_size < 20 )
+ throwf("file too small (length=%llu)", stat_buf.st_size);
+ int64_t len = stat_buf.st_size;
+ uint8_t* p = (uint8_t*)::mmap(NULL, stat_buf.st_size, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, 0);
if ( p == (uint8_t*)(-1) )
throwf("can't map file, errno=%d", errno);
if ( sliceFound ) {
uint32_t fileOffset = OSSwapBigToHostInt32(archs[sliceToUse].offset);
len = OSSwapBigToHostInt32(archs[sliceToUse].size);
- if ( fileOffset+len > info.fileLen ) {
- throwf("truncated fat file. Slice from %u to %llu is past end of file with length %llu",
- fileOffset, fileOffset+len, info.fileLen);
+ if ( fileOffset+len > stat_buf.st_size ) {
+ // <rdar://problem/17593430> file size was read awhile ago. If file is being written, wait a second to see if big enough now
+ sleep(1);
+ int64_t newFileLen = stat_buf.st_size;
+ struct stat statBuffer;
+ if ( stat(info.path, &statBuffer) == 0 ) {
+ newFileLen = statBuffer.st_size;
+ }
+ if ( fileOffset+len > newFileLen ) {
+ throwf("truncated fat file. Slice from %u to %llu is past end of file with length %llu",
+ fileOffset, fileOffset+len, stat_buf.st_size);
+ }
}
// if requested architecture is page aligned within fat file, then remap just that portion of file
if ( (fileOffset & 0x00000FFF) == 0 ) {
// unmap whole file
- munmap((caddr_t)p, info.fileLen);
+ munmap((caddr_t)p, stat_buf.st_size);
// re-map just part we need
p = (uint8_t*)::mmap(NULL, len, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, fileOffset);
if ( p == (uint8_t*)(-1) )
objOpts.architecture = _options.architecture();
objOpts.objSubtypeMustMatch = !_options.allowSubArchitectureMismatches();
objOpts.logAllFiles = _options.logAllFiles();
- objOpts.convertUnwindInfo = _options.needsUnwindInfoSection();
+ objOpts.warnUnwindConversionProblems = _options.needsUnwindInfoSection();
+ objOpts.keepDwarfUnwind = _options.keepDwarfUnwind();
+ objOpts.forceDwarfConversion= (_options.outputKind() == Options::kDyld);
+ objOpts.neverConvertDwarf = !_options.needsUnwindInfoSection();
+ objOpts.verboseOptimizationHints = _options.verboseOptimizationHints();
+ objOpts.armUsesZeroCostExceptions = _options.armUsesZeroCostExceptions();
+ objOpts.simulator = _options.targetIOSSimulator();
+ objOpts.ignoreMismatchPlatform = ((_options.outputKind() == Options::kPreload) || (_options.outputKind() == Options::kStaticExecutable));
objOpts.subType = _options.subArchitecture();
+ objOpts.platform = _options.platform();
+ objOpts.minOSVersion = _options.minOSversion();
+ objOpts.srcKind = ld::relocatable::File::kSourceObj;
+ objOpts.treateBitcodeAsData = _options.bitcodeKind() == Options::kBitcodeAsData;
+ objOpts.usingBitcode = _options.bundleBitcode();
+ objOpts.maxDefaultCommonAlignment = _options.maxDefaultCommonAlign();
+
ld::relocatable::File* objResult = mach_o::relocatable::parse(p, len, info.path, info.modTime, info.ordinal, objOpts);
if ( objResult != NULL ) {
OSAtomicAdd64(len, &_totalObjectSize);
}
// see if it is an llvm object file
- objResult = lto::parse(p, len, info.path, info.modTime, _options.architecture(), _options.subArchitecture(), _options.logAllFiles());
+ objResult = lto::parse(p, len, info.path, info.modTime, info.ordinal, _options.architecture(), _options.subArchitecture(), _options.logAllFiles(), _options.verboseOptimizationHints());
if ( objResult != NULL ) {
OSAtomicAdd64(len, &_totalObjectSize);
OSAtomicIncrement32(&_totalObjectLoaded);
return objResult;
}
-
- // see if it is a dynamic library
- ld::dylib::File* dylibResult = mach_o::dylib::parse(p, len, info.path, info.modTime, _options, info.ordinal, info.options.fBundleLoader, indirectDylib);
- if ( dylibResult != NULL ) {
- return dylibResult;
+
+ // see if it is a dynamic library (or text-based dynamic library)
+ ld::dylib::File* dylibResult;
+ bool dylibsNotAllowed = false;
+ switch ( _options.outputKind() ) {
+ case Options::kDynamicExecutable:
+ case Options::kDynamicLibrary:
+ case Options::kDynamicBundle:
+ dylibResult = mach_o::dylib::parse(p, len, info.path, info.modTime, _options, info.ordinal, info.options.fBundleLoader, indirectDylib);
+ if ( dylibResult != NULL ) {
+ return dylibResult;
+ }
+ dylibResult = textstub::dylib::parse(p, len, info.path, info.modTime, _options, info.ordinal, info.options.fBundleLoader, indirectDylib);
+ if ( dylibResult != NULL ) {
+ return dylibResult;
+ }
+ break;
+ case Options::kStaticExecutable:
+ case Options::kDyld:
+ case Options::kPreload:
+ case Options::kObjectFile:
+ case Options::kKextBundle:
+ dylibsNotAllowed = true;
+ break;
}
// see if it is a static library
archOpts.objcABI2 = _options.objCABIVersion2POverride();
archOpts.verboseLoad = _options.whyLoad();
archOpts.logAllFiles = _options.logAllFiles();
+ // Set ObjSource Kind, libclang_rt is compiler static library
+ if ( isCompilerSupportLib(info.path) )
+ archOpts.objOpts.srcKind = ld::relocatable::File::kSourceCompilerArchive;
+ else
+ archOpts.objOpts.srcKind = ld::relocatable::File::kSourceArchive;
+ archOpts.objOpts.treateBitcodeAsData = _options.bitcodeKind() == Options::kBitcodeAsData;
+ archOpts.objOpts.usingBitcode = _options.bundleBitcode();
+
ld::archive::File* archiveResult = ::archive::parse(p, len, info.path, info.modTime, info.ordinal, archOpts);
if ( archiveResult != NULL ) {
+
OSAtomicAdd64(len, &_totalArchiveSize);
OSAtomicIncrement32(&_totalArchivesLoaded);
return archiveResult;
}
}
+ if ( dylibsNotAllowed ) {
+ cpu_type_t dummy1;
+ cpu_type_t dummy2;
+ if ( mach_o::dylib::isDylibFile(p, &dummy1, &dummy2) )
+ throw "ignoring unexpected dylib file";
+ }
+
// error handling
if ( ((fat_header*)p)->magic == OSSwapBigToHostInt32(FAT_MAGIC) ) {
throwf("missing required architecture %s in file %s (%u slices)", _options.architectureName(), info.path, sliceCount);
}
}
-void InputFiles::logDylib(ld::File* file, bool indirect)
+void InputFiles::logDylib(ld::File* file, bool indirect, bool speculative)
{
if ( _options.traceDylibs() ) {
const char* fullPath = file->path();
// don't log upward dylibs when XBS is computing dependencies
logTraceInfo("[Logging for XBS] Used upward dynamic library: %s\n", fullPath);
}
+ else if ( (dylib != NULL ) && dylib->speculativelyLoaded() ) {
+ logTraceInfo("[Logging for XBS] Speculatively loaded dynamic library: %s\n", fullPath);
+ }
else {
- if ( indirect )
- logTraceInfo("[Logging for XBS] Used indirect dynamic library: %s\n", fullPath);
- else
+ if ( indirect ) {
+ if ( speculative )
+ logTraceInfo("[Logging for XBS] Speculatively loaded indirect dynamic library: %s\n", fullPath);
+ else
+ logTraceInfo("[Logging for XBS] Used indirect dynamic library: %s\n", fullPath);
+ }
+ else {
logTraceInfo("[Logging for XBS] Used dynamic library: %s\n", fullPath);
+ }
+ }
+ }
+
+ if ( _options.dumpDependencyInfo() ) {
+ const ld::dylib::File* dylib = dynamic_cast<const ld::dylib::File*>(file);
+ if ( file == _bundleLoader ) {
+ _options.addDependency(Options::depBundleLoader, file->path());
+ }
+ else if ( (dylib != NULL ) && dylib->willBeUpwardDylib() ) {
+ if ( indirect )
+ _options.addDependency(Options::depUpwardIndirectDylib, file->path());
+ else
+ _options.addDependency(Options::depUpwardDirectDylib, file->path());
+ }
+ else {
+ if ( indirect )
+ _options.addDependency(Options::depIndirectDylib, file->path());
+ else
+ _options.addDependency(Options::depDirectDylib, file->path());
}
}
}
void InputFiles::logArchive(ld::File* file) const
{
- if ( _options.traceArchives() && (_archiveFilesLogged.count(file) == 0) ) {
+ if ( (_options.traceArchives() || _options.traceEmitJSON()) && (_archiveFilesLogged.count(file) == 0) ) {
// <rdar://problem/4947347> LD_TRACE_ARCHIVES should only print out when a .o is actually used from an archive
_archiveFilesLogged.insert(file);
const char* fullPath = file->path();
if ( realpath(fullPath, realName) != NULL )
fullPath = realName;
logTraceInfo("[Logging for XBS] Used static archive: %s\n", fullPath);
+
+ std::string archivePath(fullPath);
+ _archiveFilePaths.push_back(archivePath);
}
}
void InputFiles::logTraceInfo(const char* format, ...) const
{
- // one time open() of custom LD_TRACE_FILE
- static int trace_file = -1;
- if ( trace_file == -1 ) {
- const char *trace_file_path = _options.traceOutputFile();
- if ( trace_file_path != NULL ) {
- trace_file = open(trace_file_path, O_WRONLY | O_APPEND | O_CREAT, 0666);
- if ( trace_file == -1 )
- throwf("Could not open or create trace file: %s", trace_file_path);
- }
- else {
- trace_file = fileno(stderr);
- }
- }
-
char trace_buffer[MAXPATHLEN * 2];
va_list ap;
va_start(ap, format);
int length = vsnprintf(trace_buffer, sizeof(trace_buffer), format, ap);
va_end(ap);
- char* buffer_ptr = trace_buffer;
-
- while (length > 0) {
- ssize_t amount_written = write(trace_file, buffer_ptr, length);
- if(amount_written == -1)
- /* Failure to write shouldn't fail the build. */
- return;
- buffer_ptr += amount_written;
- length -= amount_written;
- }
+ _options.writeToTraceFile(trace_buffer, length);
}
-ld::dylib::File* InputFiles::findDylib(const char* installPath, const char* fromPath)
+
+ld::dylib::File* InputFiles::findDylib(const char* installPath, const ld::dylib::File* fromDylib, bool speculative)
{
//fprintf(stderr, "findDylib(%s, %s)\n", installPath, fromPath);
InstallNameToDylib::iterator pos = _installPathToDylibs.find(installPath);
Options::FileInfo info = _options.findFile(dit->useInstead);
_indirectDylibOrdinal = _indirectDylibOrdinal.nextIndirectDylibOrdinal();
info.ordinal = _indirectDylibOrdinal;
+ info.options.fIndirectDylib = true;
ld::File* reader = this->makeFile(info, true);
ld::dylib::File* dylibReader = dynamic_cast<ld::dylib::File*>(reader);
if ( dylibReader != NULL ) {
addDylib(dylibReader, info);
//_installPathToDylibs[strdup(installPath)] = dylibReader;
- this->logDylib(dylibReader, true);
+ this->logDylib(dylibReader, true, speculative);
return dylibReader;
}
else
}
}
}
- char newPath[MAXPATHLEN];
- // handle @loader_path
- if ( strncmp(installPath, "@loader_path/", 13) == 0 ) {
- strcpy(newPath, fromPath);
- char* addPoint = strrchr(newPath,'/');
- if ( addPoint != NULL )
- strcpy(&addPoint[1], &installPath[13]);
- else
- strcpy(newPath, &installPath[13]);
- installPath = newPath;
- }
- // note: @executable_path case is handled inside findFileUsingPaths()
- // search for dylib using -F and -L paths
- Options::FileInfo info = _options.findFileUsingPaths(installPath);
+
+ // search for dylib using -F and -L paths and expanding @ paths
+ Options::FileInfo info = _options.findIndirectDylib(installPath, fromDylib);
_indirectDylibOrdinal = _indirectDylibOrdinal.nextIndirectDylibOrdinal();
info.ordinal = _indirectDylibOrdinal;
+ info.options.fIndirectDylib = true;
try {
ld::File* reader = this->makeFile(info, true);
ld::dylib::File* dylibReader = dynamic_cast<ld::dylib::File*>(reader);
//assert(_installPathToDylibs.find(installPath) != _installPathToDylibs.end());
//_installPathToDylibs[strdup(installPath)] = dylibReader;
addDylib(dylibReader, info);
- this->logDylib(dylibReader, true);
+ this->logDylib(dylibReader, true, speculative);
return dylibReader;
}
else
throwf("indirect dylib at %s is not a dylib", info.path);
}
catch (const char* msg) {
- throwf("in %s, %s", info.path, msg);
+ throwf("in '%s', %s", info.path, msg);
}
}
}
-
-void InputFiles::createIndirectDylibs()
-{
- _allDirectDylibsLoaded = true;
- _indirectDylibOrdinal = ld::File::Ordinal::indirectDylibBase();
-
- // mark all dylibs initially specified as required and check if they can be used
+// mark all dylibs initially specified as required, and check if they can be used
+void InputFiles::markExplicitlyLinkedDylibs()
+{
for (InstallNameToDylib::iterator it=_installPathToDylibs.begin(); it != _installPathToDylibs.end(); it++) {
it->second->setExplicitlyLinked();
this->checkDylibClientRestrictions(it->second);
}
-
+}
+
+bool InputFiles::frameworkAlreadyLoaded(const char* path, const char* frameworkName)
+{
+ for (ld::File* file : _inputFiles) {
+ if ( strcmp(path, file->path()) == 0 )
+ return true;
+ }
+ for (ld::dylib::File* dylibx : _allDylibs) {
+ const char* fname = dylibx->frameworkName();
+ if ( fname == NULL )
+ continue;
+ if ( strcmp(frameworkName, fname) == 0 )
+ return true;
+ }
+ return false;
+}
+
+bool InputFiles::libraryAlreadyLoaded(const char* path)
+{
+ for (ld::File* file : _inputFiles) {
+ if ( strcmp(path, file->path()) == 0 )
+ return true;
+ }
+ for (ld::dylib::File* dylib : _allDylibs) {
+ if ( strcmp(path, dylib->path()) == 0 )
+ return true;
+ }
+ for (const LibraryInfo& libInfo : _searchLibraries) {
+ if ( strcmp(path, libInfo.archive()->path()) == 0 )
+ return true;
+ }
+
+ char realDylibPath[PATH_MAX];
+ if ( (realpath(path, realDylibPath) != NULL) && (strcmp(path, realDylibPath) != 0) ) {
+ return libraryAlreadyLoaded(realDylibPath);
+ }
+
+ return false;
+}
+
+
+void InputFiles::addLinkerOptionLibraries(ld::Internal& state, ld::File::AtomHandler& handler)
+{
+ if ( _options.outputKind() == Options::kObjectFile )
+ return;
+
+ while (! state.unprocessedLinkerOptionLibraries.empty() || ! state.unprocessedLinkerOptionFrameworks.empty()) {
+
+ // process frameworks specified in .o linker options
+ CStringSet newFrameworks = std::move(state.unprocessedLinkerOptionFrameworks);
+ state.unprocessedLinkerOptionFrameworks.clear();
+ for (const char* frameworkName : newFrameworks) {
+ if ( state.linkerOptionFrameworks.count(frameworkName) )
+ continue;
+ try {
+ Options::FileInfo info = _options.findFramework(frameworkName);
+ if ( ! this->frameworkAlreadyLoaded(info.path, frameworkName) ) {
+ _linkerOptionOrdinal = _linkerOptionOrdinal.nextLinkerOptionOrdinal();
+ info.ordinal = _linkerOptionOrdinal;
+ ld::File* reader = this->makeFile(info, true);
+ ld::dylib::File* dylibReader = dynamic_cast<ld::dylib::File*>(reader);
+ ld::archive::File* archiveReader = dynamic_cast<ld::archive::File*>(reader);
+ if ( dylibReader != NULL ) {
+ if ( ! dylibReader->installPathVersionSpecific() ) {
+ dylibReader->forEachAtom(handler);
+ dylibReader->setImplicitlyLinked();
+ dylibReader->setSpeculativelyLoaded();
+ this->addDylib(dylibReader, info);
+ }
+ }
+ else if ( archiveReader != NULL ) {
+ _searchLibraries.push_back(LibraryInfo(archiveReader));
+ _options.addDependency(Options::depArchive, archiveReader->path());
+ //<rdar://problem/17787306> -force_load_swift_libs
+ if (info.options.fForceLoad) {
+ archiveReader->forEachAtom(handler);
+ }
+ }
+ else {
+ throwf("framework linker option at %s is not a dylib and not an archive", info.path);
+ }
+ }
+ }
+ catch (const char* msg) {
+ warning("Auto-Linking %s", msg);
+ }
+ state.linkerOptionFrameworks.insert(frameworkName);
+ }
+
+ // process libraries specified in .o linker options
+ // fixme optimize with std::move?
+ CStringSet newLibraries = std::move(state.unprocessedLinkerOptionLibraries);
+ state.unprocessedLinkerOptionLibraries.clear();
+ for (const char* libName : newLibraries) {
+ if ( state.linkerOptionLibraries.count(libName) )
+ continue;
+ try {
+ Options::FileInfo info = _options.findLibrary(libName);
+ if ( ! this->libraryAlreadyLoaded(info.path) ) {
+ _linkerOptionOrdinal = _linkerOptionOrdinal.nextLinkerOptionOrdinal();
+ info.ordinal = _linkerOptionOrdinal;
+ //<rdar://problem/17787306> -force_load_swift_libs
+ info.options.fForceLoad = _options.forceLoadSwiftLibs() && (strncmp(libName, "swift", 5) == 0);
+ ld::File* reader = this->makeFile(info, true);
+ ld::dylib::File* dylibReader = dynamic_cast<ld::dylib::File*>(reader);
+ ld::archive::File* archiveReader = dynamic_cast<ld::archive::File*>(reader);
+ if ( dylibReader != NULL ) {
+ dylibReader->forEachAtom(handler);
+ dylibReader->setImplicitlyLinked();
+ dylibReader->setSpeculativelyLoaded();
+ this->addDylib(dylibReader, info);
+ }
+ else if ( archiveReader != NULL ) {
+ _searchLibraries.push_back(LibraryInfo(archiveReader));
+ _options.addDependency(Options::depArchive, archiveReader->path());
+ //<rdar://problem/17787306> -force_load_swift_libs
+ if (info.options.fForceLoad) {
+ archiveReader->forEachAtom(handler);
+ }
+ }
+ else {
+ throwf("linker option dylib at %s is not a dylib", info.path);
+ }
+ }
+ }
+ catch (const char* msg) {
+ warning("Auto-Linking %s", msg);
+ }
+ state.linkerOptionLibraries.insert(libName);
+ }
+ }
+}
+
+void InputFiles::createIndirectDylibs()
+{
// keep processing dylibs until no more dylibs are added
unsigned long lastMapSize = 0;
std::set<ld::dylib::File*> dylibsProcessed;
void InputFiles::createOpaqueFileSections()
{
- // extra command line section always at end
+ // extra command line sections always at end
for (Options::ExtraSection::const_iterator it=_options.extraSectionsBegin(); it != _options.extraSectionsEnd(); ++it) {
_inputFiles.push_back(opaque_section::parse(it->segmentName, it->sectionName, it->path, it->data, it->dataLen));
+ _options.addDependency(Options::depSection, it->path);
}
}
_inferredArch = true;
// scan all input files, looking for a thin .o file.
// the first one found is presumably the architecture to link
- uint8_t buffer[sizeof(mach_header_64)];
+ uint8_t buffer[4096];
const std::vector<Options::FileInfo>& files = opts.getInputFiles();
for (std::vector<Options::FileInfo>::const_iterator it = files.begin(); it != files.end(); ++it) {
int fd = ::open(it->path, O_RDONLY, 0);
if ( fd != -1 ) {
- ssize_t amount = read(fd, buffer, sizeof(buffer));
- ::close(fd);
- if ( amount >= (ssize_t)sizeof(buffer) ) {
- cpu_type_t type;
- cpu_subtype_t subtype;
- if ( mach_o::relocatable::isObjectFile(buffer, &type, &subtype) ) {
- opts.setArchitecture(type, subtype);
- *archName = opts.architectureName();
- return;
+ struct stat stat_buf;
+ if ( fstat(fd, &stat_buf) != -1) {
+ ssize_t readAmount = stat_buf.st_size;
+ if ( 4096 < readAmount )
+ readAmount = 4096;
+ ssize_t amount = read(fd, buffer, readAmount);
+ ::close(fd);
+ if ( amount >= readAmount ) {
+ cpu_type_t type;
+ cpu_subtype_t subtype;
+ Options::Platform platform;
+ if ( mach_o::relocatable::isObjectFile(buffer, &type, &subtype, &platform) ) {
+ opts.setArchitecture(type, subtype, platform);
+ *archName = opts.architectureName();
+ return;
+ }
}
}
}
// no thin .o files found, so default to same architecture this tool was built as
warning("-arch not specified");
#if __i386__
- opts.setArchitecture(CPU_TYPE_I386, CPU_SUBTYPE_X86_ALL);
+ opts.setArchitecture(CPU_TYPE_I386, CPU_SUBTYPE_X86_ALL, Options::kPlatformOSX);
#elif __x86_64__
- opts.setArchitecture(CPU_TYPE_X86_64, CPU_SUBTYPE_X86_64_ALL);
+ opts.setArchitecture(CPU_TYPE_X86_64, CPU_SUBTYPE_X86_64_ALL, Options::kPlatformOSX);
#elif __arm__
- opts.setArchitecture(CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V6);
+ opts.setArchitecture(CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V6, Options::kPlatformOSX);
#else
#error unknown default architecture
#endif
: _totalObjectSize(0), _totalArchiveSize(0),
_totalObjectLoaded(0), _totalArchivesLoaded(0), _totalDylibsLoaded(0),
_options(opts), _bundleLoader(NULL),
- _allDirectDylibsLoaded(false), _inferredArch(false), _fileMonitor(-1),
- _exception(NULL)
+ _inferredArch(false),
+ _exception(NULL),
+ _indirectDylibOrdinal(ld::File::Ordinal::indirectDylibBase()),
+ _linkerOptionOrdinal(ld::File::Ordinal::linkeOptionBase())
{
// fStartCreateReadersTime = mach_absolute_time();
if ( opts.architecture() == 0 ) {
pthread_mutex_init(&_parseLock, NULL);
pthread_cond_init(&_parseWorkReady, NULL);
pthread_cond_init(&_newFileAvailable, NULL);
+ _neededFileSlot = -1;
#endif
const std::vector<Options::FileInfo>& files = _options.getInputFiles();
if ( files.size() == 0 )
if (_s_logPThreads) printf("parsing index %u\n", slot);
try {
file = makeFile(entry, false);
- } catch (const char *msg) {
+ }
+ catch (const char *msg) {
if ( (strstr(msg, "architecture") != NULL) && !_options.errorOnOtherArchFiles() ) {
if ( _options.ignoreOtherArchInputFiles() ) {
// ignore, because this is about an architecture not in use
else {
warning("ignoring file %s, %s", entry.path, msg);
}
- } else {
- exception = msg;
+ }
+ else if ( strstr(msg, "ignoring unexpected") != NULL ) {
+ warning("%s, %s", entry.path, msg);
+ }
+ else {
+ asprintf((char**)&exception, "%s file '%s'", msg, entry.path);
}
file = new IgnoredFile(entry.path, entry.modTime, entry.ordinal, ld::File::Other);
}
// We are about to die, so set to zero to stop other threads from doing unneeded work.
_remainingInputFiles = 0;
_exception = exception;
- } else {
+ }
+ else {
_inputFiles[slot] = file;
if (_neededFileSlot == slot)
pthread_cond_signal(&_newFileAvailable);
}
// remove warning for <rdar://problem/10860629> Same install name for CoreServices and CFNetwork?
//if ( !dylibOnCommandLineTwice && !isSymlink )
- // warning("dylibs with same install name: %s and %s", pos->second->path(), reader->path());
+ // warning("dylibs with same install name: %p %s and %p %s", pos->second, pos->second->path(), reader, reader->path());
}
}
else if ( info.options.fBundleLoader )
_bundleLoader = reader;
// log direct readers
- if ( !_allDirectDylibsLoaded )
- this->logDylib(reader, false);
+ if ( ! info.options.fIndirectDylib )
+ this->logDylib(reader, false, false);
// update stats
_totalDylibsLoaded++;
- _searchLibraries.push_back(LibraryInfo(reader));
+ // just add direct libraries to search-first list
+ if ( ! info.options.fIndirectDylib )
+ _searchLibraries.push_back(LibraryInfo(reader));
+
return reader;
}
if (it == fileMap.end())
throwf("pipelined linking error - not in file list: %s\n", path_buf);
Options::FileInfo* inputInfo = (Options::FileInfo*)it->second;
- if (!inputInfo->checkFileExists())
+ if (!inputInfo->checkFileExists(_options))
throwf("pipelined linking error - file does not exist: %s\n", inputInfo->path);
pthread_mutex_lock(&_parseLock);
if (_idleWorkers)
#endif
-void InputFiles::forEachInitialAtom(ld::File::AtomHandler& handler)
+void InputFiles::forEachInitialAtom(ld::File::AtomHandler& handler, ld::Internal& state)
{
// add all direct object, archives, and dylibs
const std::vector<Options::FileInfo>& files = _options.getInputFiles();
{
ld::relocatable::File* reloc = (ld::relocatable::File*)file;
_options.snapshot().recordObjectFile(reloc->path());
+ _options.addDependency(Options::depObjectFile, reloc->path());
}
break;
case ld::File::Dylib:
{
ld::archive::File* archive = (ld::archive::File*)file;
// <rdar://problem/9740166> force loaded archives should be in LD_TRACE
- if ( (info.options.fForceLoad || _options.fullyLoadArchives()) && _options.traceArchives() )
+ if ( (info.options.fForceLoad || _options.fullyLoadArchives()) && (_options.traceArchives() || _options.traceEmitJSON()) )
logArchive(archive);
+
+ if ( isCompilerSupportLib(info.path) && (info.options.fForceLoad || _options.fullyLoadArchives()) )
+ state.forceLoadCompilerRT = true;
+
_searchLibraries.push_back(LibraryInfo(archive));
+ _options.addDependency(Options::depArchive, archive->path());
}
break;
case ld::File::Other:
}
break;
}
- file->forEachAtom(handler);
+ try {
+ file->forEachAtom(handler);
+ }
+ catch (const char* msg) {
+ asprintf((char**)&_exception, "%s file '%s'", msg, file->path());
+ }
}
+ if (_exception)
+ throw _exception;
+ markExplicitlyLinkedDylibs();
+ addLinkerOptionLibraries(state, handler);
createIndirectDylibs();
createOpaqueFileSections();
case Options::kPreload:
// add implicit __mh_preload_header label
handler.doAtom(DSOHandleAtom::_s_atomPreload);
- handler.doAtom(DSOHandleAtom::_s_atomAll);
+ // add implicit __dso_handle label, but put it in __text section because
+ // with -preload the mach_header is no in the address space.
+ handler.doAtom(DSOHandleAtom::_s_atomPreloadDSO);
break;
case Options::kObjectFile:
handler.doAtom(DSOHandleAtom::_s_atomObjectFile);
bool InputFiles::searchLibraries(const char* name, bool searchDylibs, bool searchArchives, bool dataSymbolOnly, ld::File::AtomHandler& handler) const
{
// Check each input library.
- std::vector<LibraryInfo>::const_iterator libIterator = _searchLibraries.begin();
-
-
- while (libIterator != _searchLibraries.end()) {
- LibraryInfo lib = *libIterator;
+ for (std::vector<LibraryInfo>::const_iterator it=_searchLibraries.begin(); it != _searchLibraries.end(); ++it) {
+ LibraryInfo lib = *it;
if (lib.isDylib()) {
if (searchDylibs) {
ld::dylib::File *dylibFile = lib.dylib();
ld::archive::File *archiveFile = lib.archive();
if ( dataSymbolOnly ) {
if ( archiveFile->justInTimeDataOnlyforEachAtom(name, handler) ) {
- if ( _options.traceArchives() )
+ if ( _options.traceArchives() || _options.traceEmitJSON())
logArchive(archiveFile);
_options.snapshot().recordArchive(archiveFile->path());
+ // DALLAS _state.archives.push_back(archiveFile);
// found data definition in static library, done
- return true;
+ return true;
}
}
else {
if ( archiveFile->justInTimeforEachAtom(name, handler) ) {
- if ( _options.traceArchives() )
+ if ( _options.traceArchives() || _options.traceEmitJSON())
logArchive(archiveFile);
_options.snapshot().recordArchive(archiveFile->path());
// found definition in static library, done
}
}
}
- libIterator++;
}
// search indirect dylibs
bool InputFiles::searchWeakDefInDylib(const char* name) const
{
- // search all relevant dylibs to see if any of a weak-def with this name
+ // search all relevant dylibs to see if any have a weak-def with this name
for (InstallNameToDylib::const_iterator it=_installPathToDylibs.begin(); it != _installPathToDylibs.end(); ++it) {
ld::dylib::File* dylibFile = it->second;
if ( dylibFile->implicitlyLinked() || dylibFile->explicitlyLinked() ) {
return std::find(vec.begin(), vec.end(), key) != vec.end();
}
+struct DylibByInstallNameSorter
+{
+ bool operator()(const ld::dylib::File* left, const ld::dylib::File* right)
+ {
+ return (strcmp(left->installPath(), right->installPath()) < 0);
+ }
+};
+
void InputFiles::dylibs(ld::Internal& state)
{
bool dylibsOK = false;
}
// add implicitly linked dylibs
if ( _options.nameSpace() == Options::kTwoLevelNameSpace ) {
+ std::vector<ld::dylib::File*> implicitDylibs;
for (InstallNameToDylib::const_iterator it=_installPathToDylibs.begin(); it != _installPathToDylibs.end(); ++it) {
ld::dylib::File* dylibFile = it->second;
if ( dylibFile->implicitlyLinked() && dylibsOK ) {
- if ( ! vectorContains(state.dylibs, dylibFile) ) {
- state.dylibs.push_back(dylibFile);
+ if ( ! vectorContains(implicitDylibs, dylibFile) ) {
+ implicitDylibs.push_back(dylibFile);
+ }
+ }
+ }
+ // <rdar://problem/15002251> make implicit dylib order be deterministic by sorting by install_name
+ std::sort(implicitDylibs.begin(), implicitDylibs.end(), DylibByInstallNameSorter());
+
+ if ( _options.traceDylibs() ) {
+ for (ld::dylib::File* dylib : implicitDylibs) {
+ if ( dylib->speculativelyLoaded() && !dylib->explicitlyLinked() && dylib->providedExportAtom() ) {
+ const char* fullPath = dylib->path();
+ char realName[MAXPATHLEN];
+ if ( realpath(fullPath, realName) != NULL )
+ fullPath = realName;
+ logTraceInfo("[Logging for XBS] Used dynamic library: %s\n", fullPath);
}
}
}
+ state.dylibs.insert(state.dylibs.end(), implicitDylibs.begin(), implicitDylibs.end());
}
//fprintf(stderr, "all dylibs:\n");
//for(std::vector<ld::dylib::File*>::iterator it=state.dylibs.begin(); it != state.dylibs.end(); ++it) {
// const ld::dylib::File* dylib = *it;
- // fprintf(stderr, " %p %s\n", dylib, dylib->path());
+ // fprintf(stderr, " %p impl=%d %s\n", dylib, dylib->implicitlyLinked(), dylib->path());
//}
// and -bundle_loader
throw "dynamic main executables must link with libSystem.dylib";
}
+void InputFiles::archives(ld::Internal& state)
+{
+ for (const std::string path : _archiveFilePaths) {
+
+ state.archivePaths.push_back(path);
+ }
+}
+
} // namespace tool
} // namespace ld
-