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)
{
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 )
- throwf("file too small (length=%llu)", info.fileLen);
-
- 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 ) {
+ 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);
- uint64_t newFileLen = info.fileLen;
+ 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, info.fileLen);
+ 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) )
archOpts.verboseLoad = _options.whyLoad();
archOpts.logAllFiles = _options.logAllFiles();
// Set ObjSource Kind, libclang_rt is compiler static library
- const char* libName = strrchr(info.path, '/');
- if ( (libName != NULL) && (strncmp(libName, "/libclang_rt", 12) == 0) )
+ if ( isCompilerSupportLib(info.path) )
archOpts.objOpts.srcKind = ld::relocatable::File::kSourceCompilerArchive;
else
archOpts.objOpts.srcKind = ld::relocatable::File::kSourceArchive;
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;
}
}
-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.dumpDependency(Options::depBundleLoader, file->path());
+ _options.addDependency(Options::depBundleLoader, file->path());
}
else if ( (dylib != NULL ) && dylib->willBeUpwardDylib() ) {
if ( indirect )
- _options.dumpDependency(Options::depUpwardIndirectDylib, file->path());
+ _options.addDependency(Options::depUpwardIndirectDylib, file->path());
else
- _options.dumpDependency(Options::depUpwardDirectDylib, file->path());
+ _options.addDependency(Options::depUpwardDirectDylib, file->path());
}
else {
if ( indirect )
- _options.dumpDependency(Options::depIndirectDylib, file->path());
+ _options.addDependency(Options::depIndirectDylib, file->path());
else
- _options.dumpDependency(Options::depDirectDylib, file->path());
+ _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 (errno=%d): %s", errno, 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);
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;
//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
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;
-
- // process frameworks specified in .o linker options
- for (CStringSet::const_iterator it = state.linkerOptionFrameworks.begin(); it != state.linkerOptionFrameworks.end(); ++it) {
- const char* frameworkName = *it;
- if ( state.linkerOptionFrameworksProcessed.count(frameworkName) )
- continue;
- Options::FileInfo info = _options.findFramework(frameworkName);
- if ( ! this->frameworkAlreadyLoaded(info.path, frameworkName) ) {
- info.ordinal = _linkerOptionOrdinal.nextLinkerOptionOrdinal();
+ 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 {
- ld::File* reader = this->makeFile(info, true);
- ld::dylib::File* dylibReader = dynamic_cast<ld::dylib::File*>(reader);
- if ( dylibReader != NULL ) {
- if ( ! dylibReader->installPathVersionSpecific() ) {
- dylibReader->forEachAtom(handler);
- dylibReader->setImplicitlyLinked();
- this->addDylib(dylibReader, info);
+ 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 {
- throwf("framework linker option at %s is not a dylib", info.path);
- }
- }
+ 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 supplied '%s', %s", info.path, msg);
+ warning("Auto-Linking %s", msg);
}
- }
- state.linkerOptionFrameworksProcessed.insert(frameworkName);
- }
- // process libraries specified in .o linker options
- for (CStringSet::const_iterator it = state.linkerOptionLibraries.begin(); it != state.linkerOptionLibraries.end(); ++it) {
- const char* libName = *it;
- if ( state.linkerOptionLibrariesProcessed.count(libName) )
- continue;
- Options::FileInfo info = _options.findLibrary(libName);
- if ( ! this->libraryAlreadyLoaded(info.path) ) {
- info.ordinal = _linkerOptionOrdinal.nextLinkerOptionOrdinal();
+ 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 {
- //<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();
- this->addDylib(dylibReader, info);
- }
- else if ( archiveReader != NULL ) {
- _searchLibraries.push_back(LibraryInfo(archiveReader));
- if ( _options.dumpDependencyInfo() )
- _options.dumpDependency(Options::depArchive, archiveReader->path());
- //<rdar://problem/17787306> -force_load_swift_libs
- if (info.options.fForceLoad) {
- archiveReader->forEachAtom(handler);
+ 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 {
- throwf("linker option dylib at %s is not a dylib", info.path);
- }
- }
+ 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 supplied '%s', %s", info.path, msg);
+ warning("Auto-Linking %s", msg);
}
+ state.linkerOptionLibraries.insert(libName);
}
- state.linkerOptionLibrariesProcessed.insert(libName);
}
}
// 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));
- if ( _options.dumpDependencyInfo() )
- _options.dumpDependency(Options::depSection, it->path);
+ _options.addDependency(Options::depSection, it->path);
}
}
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) {
if ( (strstr(msg, "architecture") != NULL) && !_options.errorOnOtherArchFiles() ) {
if ( _options.ignoreOtherArchInputFiles() ) {
// log direct readers
if ( ! info.options.fIndirectDylib )
- this->logDylib(reader, false);
+ this->logDylib(reader, false, false);
// update stats
_totalDylibsLoaded++;
{
ld::relocatable::File* reloc = (ld::relocatable::File*)file;
_options.snapshot().recordObjectFile(reloc->path());
- if ( _options.dumpDependencyInfo() )
- _options.dumpDependency(Options::depObjectFile, 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));
- if ( _options.dumpDependencyInfo() )
- _options.dumpDependency(Options::depArchive, archive->path());
+ _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);
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;
}
}
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
}
// <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());
}
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