]>
Commit | Line | Data |
---|---|---|
f80fe69f | 1 | |
a645023d A |
2 | /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-* |
3 | * | |
afe874b1 | 4 | * Copyright (c) 2009-2011 Apple Inc. All rights reserved. |
a645023d A |
5 | * |
6 | * @APPLE_LICENSE_HEADER_START@ | |
7 | * | |
8 | * This file contains Original Code and/or Modifications of Original Code | |
9 | * as defined in and that are subject to the Apple Public Source License | |
10 | * Version 2.0 (the 'License'). You may not use this file except in | |
11 | * compliance with the License. Please obtain a copy of the License at | |
12 | * http://www.opensource.apple.com/apsl/ and read it before using this | |
13 | * file. | |
14 | * | |
15 | * The Original Code and all software distributed under the License are | |
16 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
17 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, | |
18 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
19 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. | |
20 | * Please see the License for the specific language governing rights and | |
21 | * limitations under the License. | |
22 | * | |
23 | * @APPLE_LICENSE_HEADER_END@ | |
24 | */ | |
25 | ||
26 | ||
27 | #include <stdlib.h> | |
28 | #include <sys/types.h> | |
29 | #include <sys/stat.h> | |
30 | #include <sys/mman.h> | |
31 | #include <sys/sysctl.h> | |
32 | #include <fcntl.h> | |
33 | #include <errno.h> | |
34 | #include <limits.h> | |
35 | #include <unistd.h> | |
36 | #include <mach/mach_time.h> | |
37 | #include <mach/vm_statistics.h> | |
38 | #include <mach/mach_init.h> | |
39 | #include <mach/mach_host.h> | |
40 | #include <dlfcn.h> | |
41 | #include <mach-o/dyld.h> | |
42 | #include <mach-o/fat.h> | |
ebf6f434 A |
43 | #include <sys/sysctl.h> |
44 | #include <libkern/OSAtomic.h> | |
a645023d A |
45 | |
46 | #include <string> | |
47 | #include <map> | |
48 | #include <set> | |
49 | #include <string> | |
50 | #include <vector> | |
51 | #include <list> | |
52 | #include <algorithm> | |
a645023d A |
53 | #include <dlfcn.h> |
54 | #include <AvailabilityMacros.h> | |
55 | ||
56 | #include "Options.h" | |
57 | ||
58 | #include "InputFiles.h" | |
59 | #include "macho_relocatable_file.h" | |
60 | #include "macho_dylib_file.h" | |
61 | #include "archive_file.h" | |
62 | #include "lto_file.h" | |
63 | #include "opaque_section_file.h" | |
f80fe69f | 64 | #include "MachOFileAbstraction.hpp" |
ebf6f434 | 65 | #include "Snapshot.h" |
a645023d | 66 | |
ebf6f434 | 67 | const bool _s_logPThreads = false; |
a645023d A |
68 | |
69 | namespace ld { | |
70 | namespace tool { | |
71 | ||
ebf6f434 A |
72 | class IgnoredFile : public ld::File { |
73 | public: | |
74 | IgnoredFile(const char* pth, time_t modTime, Ordinal ord, Type type) : ld::File(pth, modTime, ord, type) {}; | |
75 | virtual bool forEachAtom(AtomHandler&) const { return false; }; | |
76 | virtual bool justInTimeforEachAtom(const char* name, AtomHandler&) const { return false; }; | |
77 | }; | |
a645023d A |
78 | |
79 | ||
80 | class DSOHandleAtom : public ld::Atom { | |
81 | public: | |
82 | DSOHandleAtom(const char* nm, ld::Atom::Scope sc, | |
b1f7435d A |
83 | ld::Atom::SymbolTableInclusion inc, ld::Section& sect=_s_section) |
84 | : ld::Atom(sect, ld::Atom::definitionRegular, | |
85 | (sect == _s_section_text) ? ld::Atom::combineByName : ld::Atom::combineNever, | |
86 | // make "weak def" so that link succeeds even if app defines __dso_handle | |
a645023d A |
87 | sc, ld::Atom::typeUnclassified, inc, true, false, false, |
88 | ld::Atom::Alignment(1)), _name(nm) {} | |
89 | ||
90 | virtual ld::File* file() const { return NULL; } | |
b1f7435d | 91 | virtual const char* name() const { return _name; } |
a645023d A |
92 | virtual uint64_t size() const { return 0; } |
93 | virtual uint64_t objectAddress() const { return 0; } | |
94 | virtual void copyRawContent(uint8_t buffer[]) const | |
95 | { } | |
96 | virtual void setScope(Scope) { } | |
97 | ||
98 | virtual ~DSOHandleAtom() {} | |
99 | ||
100 | static ld::Section _s_section; | |
101 | static ld::Section _s_section_preload; | |
b1f7435d | 102 | static ld::Section _s_section_text; |
a645023d A |
103 | static DSOHandleAtom _s_atomAll; |
104 | static DSOHandleAtom _s_atomExecutable; | |
105 | static DSOHandleAtom _s_atomDylib; | |
106 | static DSOHandleAtom _s_atomBundle; | |
107 | static DSOHandleAtom _s_atomDyld; | |
108 | static DSOHandleAtom _s_atomObjectFile; | |
109 | static DSOHandleAtom _s_atomPreload; | |
b1f7435d | 110 | static DSOHandleAtom _s_atomPreloadDSO; |
a645023d A |
111 | private: |
112 | const char* _name; | |
113 | }; | |
114 | ld::Section DSOHandleAtom::_s_section("__TEXT", "__mach_header", ld::Section::typeMachHeader, true); | |
115 | ld::Section DSOHandleAtom::_s_section_preload("__HEADER", "__mach_header", ld::Section::typeMachHeader, true); | |
b1f7435d | 116 | ld::Section DSOHandleAtom::_s_section_text("__TEXT", "__text", ld::Section::typeCode, false); |
a645023d A |
117 | DSOHandleAtom DSOHandleAtom::_s_atomAll("___dso_handle", ld::Atom::scopeLinkageUnit, ld::Atom::symbolTableNotIn); |
118 | DSOHandleAtom DSOHandleAtom::_s_atomExecutable("__mh_execute_header", ld::Atom::scopeGlobal, ld::Atom::symbolTableInAndNeverStrip); | |
119 | DSOHandleAtom DSOHandleAtom::_s_atomDylib("__mh_dylib_header", ld::Atom::scopeLinkageUnit, ld::Atom::symbolTableNotIn); | |
120 | DSOHandleAtom DSOHandleAtom::_s_atomBundle("__mh_bundle_header", ld::Atom::scopeLinkageUnit, ld::Atom::symbolTableNotIn); | |
121 | DSOHandleAtom DSOHandleAtom::_s_atomDyld("__mh_dylinker_header", ld::Atom::scopeLinkageUnit, ld::Atom::symbolTableNotIn); | |
122 | DSOHandleAtom DSOHandleAtom::_s_atomObjectFile("__mh_object_header", ld::Atom::scopeLinkageUnit, ld::Atom::symbolTableNotIn); | |
b1f7435d A |
123 | DSOHandleAtom DSOHandleAtom::_s_atomPreload("__mh_preload_header", ld::Atom::scopeLinkageUnit, ld::Atom::symbolTableNotIn, _s_section_preload); |
124 | DSOHandleAtom DSOHandleAtom::_s_atomPreloadDSO("___dso_handle", ld::Atom::scopeLinkageUnit, ld::Atom::symbolTableNotIn, _s_section_text); | |
a645023d A |
125 | |
126 | ||
127 | ||
128 | class PageZeroAtom : public ld::Atom { | |
129 | public: | |
130 | PageZeroAtom(uint64_t sz) | |
131 | : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever, | |
132 | ld::Atom::scopeTranslationUnit, ld::Atom::typeZeroFill, | |
133 | symbolTableNotIn, true, false, false, ld::Atom::Alignment(12)), | |
134 | _size(sz) {} | |
135 | ||
136 | virtual ld::File* file() const { return NULL; } | |
a645023d A |
137 | virtual const char* name() const { return "page zero"; } |
138 | virtual uint64_t size() const { return _size; } | |
139 | virtual uint64_t objectAddress() const { return 0; } | |
140 | virtual void copyRawContent(uint8_t buffer[]) const | |
141 | { } | |
142 | virtual void setScope(Scope) { } | |
143 | ||
144 | virtual ~PageZeroAtom() {} | |
145 | ||
146 | static ld::Section _s_section; | |
147 | static DSOHandleAtom _s_atomAll; | |
148 | private: | |
149 | uint64_t _size; | |
150 | }; | |
151 | ld::Section PageZeroAtom::_s_section("__PAGEZERO", "__pagezero", ld::Section::typePageZero, true); | |
152 | ||
153 | ||
154 | class CustomStackAtom : public ld::Atom { | |
155 | public: | |
156 | CustomStackAtom(uint64_t sz) | |
157 | : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever, | |
158 | ld::Atom::scopeTranslationUnit, ld::Atom::typeZeroFill, | |
159 | symbolTableNotIn, false, false, false, ld::Atom::Alignment(12)), | |
160 | _size(sz) {} | |
161 | ||
162 | virtual ld::File* file() const { return NULL; } | |
a645023d A |
163 | virtual const char* name() const { return "custom stack"; } |
164 | virtual uint64_t size() const { return _size; } | |
165 | virtual uint64_t objectAddress() const { return 0; } | |
166 | virtual void copyRawContent(uint8_t buffer[]) const | |
167 | { } | |
168 | virtual void setScope(Scope) { } | |
169 | ||
170 | virtual ~CustomStackAtom() {} | |
171 | ||
172 | private: | |
173 | uint64_t _size; | |
174 | static ld::Section _s_section; | |
175 | }; | |
176 | ld::Section CustomStackAtom::_s_section("__UNIXSTACK", "__stack", ld::Section::typeStack, true); | |
177 | ||
178 | ||
179 | ||
180 | const char* InputFiles::fileArch(const uint8_t* p, unsigned len) | |
181 | { | |
182 | const char* result = mach_o::relocatable::archName(p); | |
183 | if ( result != NULL ) | |
184 | return result; | |
f80fe69f A |
185 | |
186 | result = mach_o::dylib::archName(p); | |
187 | if ( result != NULL ) | |
188 | return result; | |
189 | ||
a645023d A |
190 | result = lto::archName(p, len); |
191 | if ( result != NULL ) | |
192 | return result; | |
193 | ||
194 | if ( strncmp((const char*)p, "!<arch>\n", 8) == 0 ) | |
195 | return "archive"; | |
196 | ||
ebf6f434 A |
197 | char *unsupported = (char *)malloc(128); |
198 | strcpy(unsupported, "unsupported file format ("); | |
199 | for (unsigned i=0; i<len && i < 16; i++) { | |
200 | char buf[8]; | |
f80fe69f | 201 | sprintf(buf, " 0x%02X", p[i]); |
ebf6f434 A |
202 | strcat(unsupported, buf); |
203 | } | |
204 | strcat(unsupported, " )"); | |
205 | return unsupported; | |
a645023d A |
206 | } |
207 | ||
208 | ||
afe874b1 | 209 | ld::File* InputFiles::makeFile(const Options::FileInfo& info, bool indirectDylib) |
a645023d A |
210 | { |
211 | // map in whole file | |
212 | uint64_t len = info.fileLen; | |
213 | int fd = ::open(info.path, O_RDONLY, 0); | |
214 | if ( fd == -1 ) | |
215 | throwf("can't open file, errno=%d", errno); | |
216 | if ( info.fileLen < 20 ) | |
f80fe69f | 217 | throwf("file too small (length=%llu)", info.fileLen); |
a645023d A |
218 | |
219 | uint8_t* p = (uint8_t*)::mmap(NULL, info.fileLen, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, 0); | |
220 | if ( p == (uint8_t*)(-1) ) | |
221 | throwf("can't map file, errno=%d", errno); | |
222 | ||
223 | // if fat file, skip to architecture we want | |
224 | // Note: fat header is always big-endian | |
225 | bool isFatFile = false; | |
ebf6f434 | 226 | uint32_t sliceToUse, sliceCount; |
a645023d A |
227 | const fat_header* fh = (fat_header*)p; |
228 | if ( fh->magic == OSSwapBigToHostInt32(FAT_MAGIC) ) { | |
229 | isFatFile = true; | |
230 | const struct fat_arch* archs = (struct fat_arch*)(p + sizeof(struct fat_header)); | |
a645023d | 231 | bool sliceFound = false; |
ebf6f434 | 232 | sliceCount = OSSwapBigToHostInt32(fh->nfat_arch); |
a645023d A |
233 | if ( _options.preferSubArchitecture() ) { |
234 | // first try to find a slice that match cpu-type and cpu-sub-type | |
ebf6f434 | 235 | for (uint32_t i=0; i < sliceCount; ++i) { |
a645023d A |
236 | if ( (OSSwapBigToHostInt32(archs[i].cputype) == (uint32_t)_options.architecture()) |
237 | && (OSSwapBigToHostInt32(archs[i].cpusubtype) == (uint32_t)_options.subArchitecture()) ) { | |
238 | sliceToUse = i; | |
239 | sliceFound = true; | |
240 | break; | |
241 | } | |
242 | } | |
243 | } | |
244 | if ( !sliceFound ) { | |
245 | // look for any slice that matches just cpu-type | |
ebf6f434 | 246 | for (uint32_t i=0; i < sliceCount; ++i) { |
a645023d A |
247 | if ( OSSwapBigToHostInt32(archs[i].cputype) == (uint32_t)_options.architecture() ) { |
248 | sliceToUse = i; | |
249 | sliceFound = true; | |
250 | break; | |
251 | } | |
252 | } | |
253 | } | |
254 | if ( sliceFound ) { | |
255 | uint32_t fileOffset = OSSwapBigToHostInt32(archs[sliceToUse].offset); | |
256 | len = OSSwapBigToHostInt32(archs[sliceToUse].size); | |
257 | if ( fileOffset+len > info.fileLen ) { | |
599556ff A |
258 | // <rdar://problem/17593430> file size was read awhile ago. If file is being written, wait a second to see if big enough now |
259 | sleep(1); | |
260 | uint64_t newFileLen = info.fileLen; | |
261 | struct stat statBuffer; | |
262 | if ( stat(info.path, &statBuffer) == 0 ) { | |
263 | newFileLen = statBuffer.st_size; | |
264 | } | |
265 | if ( fileOffset+len > newFileLen ) { | |
266 | throwf("truncated fat file. Slice from %u to %llu is past end of file with length %llu", | |
a645023d | 267 | fileOffset, fileOffset+len, info.fileLen); |
599556ff | 268 | } |
a645023d A |
269 | } |
270 | // if requested architecture is page aligned within fat file, then remap just that portion of file | |
271 | if ( (fileOffset & 0x00000FFF) == 0 ) { | |
272 | // unmap whole file | |
273 | munmap((caddr_t)p, info.fileLen); | |
274 | // re-map just part we need | |
275 | p = (uint8_t*)::mmap(NULL, len, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, fileOffset); | |
276 | if ( p == (uint8_t*)(-1) ) | |
277 | throwf("can't re-map file, errno=%d", errno); | |
278 | } | |
279 | else { | |
280 | p = &p[fileOffset]; | |
281 | } | |
282 | } | |
283 | } | |
284 | ::close(fd); | |
285 | ||
286 | // see if it is an object file | |
287 | mach_o::relocatable::ParserOptions objOpts; | |
288 | objOpts.architecture = _options.architecture(); | |
afe874b1 | 289 | objOpts.objSubtypeMustMatch = !_options.allowSubArchitectureMismatches(); |
a645023d | 290 | objOpts.logAllFiles = _options.logAllFiles(); |
f80fe69f A |
291 | objOpts.warnUnwindConversionProblems = _options.needsUnwindInfoSection(); |
292 | objOpts.keepDwarfUnwind = _options.keepDwarfUnwind(); | |
293 | objOpts.forceDwarfConversion= (_options.outputKind() == Options::kDyld); | |
9543cb2f A |
294 | objOpts.neverConvertDwarf = !_options.needsUnwindInfoSection(); |
295 | objOpts.verboseOptimizationHints = _options.verboseOptimizationHints(); | |
ba348e21 | 296 | objOpts.armUsesZeroCostExceptions = _options.armUsesZeroCostExceptions(); |
a645023d | 297 | objOpts.subType = _options.subArchitecture(); |
ebf6f434 A |
298 | ld::relocatable::File* objResult = mach_o::relocatable::parse(p, len, info.path, info.modTime, info.ordinal, objOpts); |
299 | if ( objResult != NULL ) { | |
300 | OSAtomicAdd64(len, &_totalObjectSize); | |
301 | OSAtomicIncrement32(&_totalObjectLoaded); | |
302 | return objResult; | |
303 | } | |
a645023d A |
304 | |
305 | // see if it is an llvm object file | |
9543cb2f | 306 | objResult = lto::parse(p, len, info.path, info.modTime, info.ordinal, _options.architecture(), _options.subArchitecture(), _options.logAllFiles(), _options.verboseOptimizationHints()); |
ebf6f434 A |
307 | if ( objResult != NULL ) { |
308 | OSAtomicAdd64(len, &_totalObjectSize); | |
309 | OSAtomicIncrement32(&_totalObjectLoaded); | |
310 | return objResult; | |
311 | } | |
312 | ||
a645023d | 313 | // see if it is a dynamic library |
599556ff A |
314 | ld::dylib::File* dylibResult; |
315 | bool dylibsNotAllowed = false; | |
316 | switch ( _options.outputKind() ) { | |
317 | case Options::kDynamicExecutable: | |
318 | case Options::kDynamicLibrary: | |
319 | case Options::kDynamicBundle: | |
320 | dylibResult = mach_o::dylib::parse(p, len, info.path, info.modTime, _options, info.ordinal, info.options.fBundleLoader, indirectDylib); | |
321 | if ( dylibResult != NULL ) { | |
322 | return dylibResult; | |
323 | } | |
324 | break; | |
325 | case Options::kStaticExecutable: | |
326 | case Options::kDyld: | |
327 | case Options::kPreload: | |
328 | case Options::kObjectFile: | |
329 | case Options::kKextBundle: | |
330 | dylibsNotAllowed = true; | |
331 | break; | |
ebf6f434 | 332 | } |
a645023d | 333 | |
599556ff | 334 | |
a645023d | 335 | // see if it is a static library |
afe874b1 | 336 | ::archive::ParserOptions archOpts; |
a645023d A |
337 | archOpts.objOpts = objOpts; |
338 | archOpts.forceLoadThisArchive = info.options.fForceLoad; | |
339 | archOpts.forceLoadAll = _options.fullyLoadArchives(); | |
340 | archOpts.forceLoadObjC = _options.loadAllObjcObjectsFromArchives(); | |
afe874b1 | 341 | archOpts.objcABI2 = _options.objCABIVersion2POverride(); |
a645023d A |
342 | archOpts.verboseLoad = _options.whyLoad(); |
343 | archOpts.logAllFiles = _options.logAllFiles(); | |
ebf6f434 | 344 | ld::archive::File* archiveResult = ::archive::parse(p, len, info.path, info.modTime, info.ordinal, archOpts); |
afe874b1 | 345 | if ( archiveResult != NULL ) { |
ebf6f434 A |
346 | OSAtomicAdd64(len, &_totalArchiveSize); |
347 | OSAtomicIncrement32(&_totalArchivesLoaded); | |
348 | return archiveResult; | |
afe874b1 A |
349 | } |
350 | ||
a645023d A |
351 | // does not seem to be any valid linker input file, check LTO misconfiguration problems |
352 | if ( lto::archName((uint8_t*)p, len) != NULL ) { | |
353 | if ( lto::libLTOisLoaded() ) { | |
ebf6f434 | 354 | throwf("lto file was built for %s which is not the architecture being linked (%s): %s", fileArch(p, len), _options.architectureName(), info.path); |
a645023d A |
355 | } |
356 | else { | |
357 | const char* libLTO = "libLTO.dylib"; | |
358 | char ldPath[PATH_MAX]; | |
359 | char tmpPath[PATH_MAX]; | |
360 | char libLTOPath[PATH_MAX]; | |
361 | uint32_t bufSize = PATH_MAX; | |
ebf6f434 A |
362 | if ( _options.overridePathlibLTO() != NULL ) { |
363 | libLTO = _options.overridePathlibLTO(); | |
364 | } | |
365 | else if ( _NSGetExecutablePath(ldPath, &bufSize) != -1 ) { | |
a645023d A |
366 | if ( realpath(ldPath, tmpPath) != NULL ) { |
367 | char* lastSlash = strrchr(tmpPath, '/'); | |
368 | if ( lastSlash != NULL ) | |
369 | strcpy(lastSlash, "/../lib/libLTO.dylib"); | |
370 | libLTO = tmpPath; | |
371 | if ( realpath(tmpPath, libLTOPath) != NULL ) | |
372 | libLTO = libLTOPath; | |
373 | } | |
374 | } | |
375 | throwf("could not process llvm bitcode object file, because %s could not be loaded", libLTO); | |
376 | } | |
377 | } | |
378 | ||
599556ff A |
379 | if ( dylibsNotAllowed ) { |
380 | cpu_type_t dummy1; | |
381 | cpu_type_t dummy2; | |
382 | if ( mach_o::dylib::isDylibFile(p, &dummy1, &dummy2) ) | |
383 | throw "ignoring unexpected dylib file"; | |
384 | } | |
385 | ||
a645023d A |
386 | // error handling |
387 | if ( ((fat_header*)p)->magic == OSSwapBigToHostInt32(FAT_MAGIC) ) { | |
ebf6f434 | 388 | throwf("missing required architecture %s in file %s (%u slices)", _options.architectureName(), info.path, sliceCount); |
a645023d A |
389 | } |
390 | else { | |
391 | if ( isFatFile ) | |
ebf6f434 | 392 | throwf("file is universal (%u slices) but does not contain a(n) %s slice: %s", sliceCount, _options.architectureName(), info.path); |
a645023d | 393 | else |
ebf6f434 | 394 | throwf("file was built for %s which is not the architecture being linked (%s): %s", fileArch(p, len), _options.architectureName(), info.path); |
a645023d A |
395 | } |
396 | } | |
397 | ||
398 | void InputFiles::logDylib(ld::File* file, bool indirect) | |
399 | { | |
400 | if ( _options.traceDylibs() ) { | |
401 | const char* fullPath = file->path(); | |
402 | char realName[MAXPATHLEN]; | |
403 | if ( realpath(fullPath, realName) != NULL ) | |
404 | fullPath = realName; | |
405 | const ld::dylib::File* dylib = dynamic_cast<const ld::dylib::File*>(file); | |
406 | if ( (dylib != NULL ) && dylib->willBeUpwardDylib() ) { | |
407 | // don't log upward dylibs when XBS is computing dependencies | |
408 | logTraceInfo("[Logging for XBS] Used upward dynamic library: %s\n", fullPath); | |
409 | } | |
410 | else { | |
f80fe69f | 411 | if ( indirect ) |
a645023d | 412 | logTraceInfo("[Logging for XBS] Used indirect dynamic library: %s\n", fullPath); |
f80fe69f | 413 | else |
a645023d A |
414 | logTraceInfo("[Logging for XBS] Used dynamic library: %s\n", fullPath); |
415 | } | |
416 | } | |
f80fe69f A |
417 | |
418 | if ( _options.dumpDependencyInfo() ) { | |
419 | const ld::dylib::File* dylib = dynamic_cast<const ld::dylib::File*>(file); | |
420 | if ( file == _bundleLoader ) { | |
421 | _options.dumpDependency(Options::depBundleLoader, file->path()); | |
422 | } | |
423 | else if ( (dylib != NULL ) && dylib->willBeUpwardDylib() ) { | |
424 | if ( indirect ) | |
425 | _options.dumpDependency(Options::depUpwardIndirectDylib, file->path()); | |
426 | else | |
427 | _options.dumpDependency(Options::depUpwardDirectDylib, file->path()); | |
428 | } | |
429 | else { | |
430 | if ( indirect ) | |
431 | _options.dumpDependency(Options::depIndirectDylib, file->path()); | |
432 | else | |
433 | _options.dumpDependency(Options::depDirectDylib, file->path()); | |
434 | } | |
435 | } | |
a645023d A |
436 | } |
437 | ||
438 | void InputFiles::logArchive(ld::File* file) const | |
439 | { | |
440 | if ( _options.traceArchives() && (_archiveFilesLogged.count(file) == 0) ) { | |
441 | // <rdar://problem/4947347> LD_TRACE_ARCHIVES should only print out when a .o is actually used from an archive | |
442 | _archiveFilesLogged.insert(file); | |
443 | const char* fullPath = file->path(); | |
444 | char realName[MAXPATHLEN]; | |
445 | if ( realpath(fullPath, realName) != NULL ) | |
446 | fullPath = realName; | |
447 | logTraceInfo("[Logging for XBS] Used static archive: %s\n", fullPath); | |
448 | } | |
449 | } | |
450 | ||
451 | ||
452 | void InputFiles::logTraceInfo(const char* format, ...) const | |
453 | { | |
454 | // one time open() of custom LD_TRACE_FILE | |
455 | static int trace_file = -1; | |
456 | if ( trace_file == -1 ) { | |
457 | const char *trace_file_path = _options.traceOutputFile(); | |
458 | if ( trace_file_path != NULL ) { | |
459 | trace_file = open(trace_file_path, O_WRONLY | O_APPEND | O_CREAT, 0666); | |
460 | if ( trace_file == -1 ) | |
f80fe69f | 461 | throwf("Could not open or create trace file (errno=%d): %s", errno, trace_file_path); |
a645023d A |
462 | } |
463 | else { | |
464 | trace_file = fileno(stderr); | |
465 | } | |
466 | } | |
467 | ||
468 | char trace_buffer[MAXPATHLEN * 2]; | |
469 | va_list ap; | |
470 | va_start(ap, format); | |
471 | int length = vsnprintf(trace_buffer, sizeof(trace_buffer), format, ap); | |
472 | va_end(ap); | |
473 | char* buffer_ptr = trace_buffer; | |
474 | ||
475 | while (length > 0) { | |
476 | ssize_t amount_written = write(trace_file, buffer_ptr, length); | |
477 | if(amount_written == -1) | |
478 | /* Failure to write shouldn't fail the build. */ | |
479 | return; | |
480 | buffer_ptr += amount_written; | |
481 | length -= amount_written; | |
482 | } | |
483 | } | |
484 | ||
f80fe69f | 485 | |
a645023d A |
486 | ld::dylib::File* InputFiles::findDylib(const char* installPath, const char* fromPath) |
487 | { | |
488 | //fprintf(stderr, "findDylib(%s, %s)\n", installPath, fromPath); | |
489 | InstallNameToDylib::iterator pos = _installPathToDylibs.find(installPath); | |
490 | if ( pos != _installPathToDylibs.end() ) { | |
491 | return pos->second; | |
492 | } | |
493 | else { | |
494 | // allow -dylib_path option to override indirect library to use | |
495 | for (std::vector<Options::DylibOverride>::const_iterator dit = _options.dylibOverrides().begin(); dit != _options.dylibOverrides().end(); ++dit) { | |
496 | if ( strcmp(dit->installName,installPath) == 0 ) { | |
497 | try { | |
498 | Options::FileInfo info = _options.findFile(dit->useInstead); | |
ebf6f434 A |
499 | _indirectDylibOrdinal = _indirectDylibOrdinal.nextIndirectDylibOrdinal(); |
500 | info.ordinal = _indirectDylibOrdinal; | |
f80fe69f | 501 | info.options.fIndirectDylib = true; |
afe874b1 | 502 | ld::File* reader = this->makeFile(info, true); |
a645023d A |
503 | ld::dylib::File* dylibReader = dynamic_cast<ld::dylib::File*>(reader); |
504 | if ( dylibReader != NULL ) { | |
ebf6f434 | 505 | addDylib(dylibReader, info); |
a645023d A |
506 | //_installPathToDylibs[strdup(installPath)] = dylibReader; |
507 | this->logDylib(dylibReader, true); | |
508 | return dylibReader; | |
509 | } | |
510 | else | |
511 | throwf("indirect dylib at %s is not a dylib", dit->useInstead); | |
512 | } | |
513 | catch (const char* msg) { | |
514 | warning("ignoring -dylib_file option, %s", msg); | |
515 | } | |
516 | } | |
517 | } | |
518 | char newPath[MAXPATHLEN]; | |
519 | // handle @loader_path | |
520 | if ( strncmp(installPath, "@loader_path/", 13) == 0 ) { | |
521 | strcpy(newPath, fromPath); | |
522 | char* addPoint = strrchr(newPath,'/'); | |
523 | if ( addPoint != NULL ) | |
524 | strcpy(&addPoint[1], &installPath[13]); | |
525 | else | |
526 | strcpy(newPath, &installPath[13]); | |
527 | installPath = newPath; | |
528 | } | |
529 | // note: @executable_path case is handled inside findFileUsingPaths() | |
530 | // search for dylib using -F and -L paths | |
531 | Options::FileInfo info = _options.findFileUsingPaths(installPath); | |
ebf6f434 A |
532 | _indirectDylibOrdinal = _indirectDylibOrdinal.nextIndirectDylibOrdinal(); |
533 | info.ordinal = _indirectDylibOrdinal; | |
f80fe69f | 534 | info.options.fIndirectDylib = true; |
a645023d | 535 | try { |
afe874b1 | 536 | ld::File* reader = this->makeFile(info, true); |
a645023d A |
537 | ld::dylib::File* dylibReader = dynamic_cast<ld::dylib::File*>(reader); |
538 | if ( dylibReader != NULL ) { | |
539 | //assert(_installPathToDylibs.find(installPath) != _installPathToDylibs.end()); | |
540 | //_installPathToDylibs[strdup(installPath)] = dylibReader; | |
ebf6f434 | 541 | addDylib(dylibReader, info); |
a645023d A |
542 | this->logDylib(dylibReader, true); |
543 | return dylibReader; | |
544 | } | |
545 | else | |
546 | throwf("indirect dylib at %s is not a dylib", info.path); | |
547 | } | |
548 | catch (const char* msg) { | |
d425e388 | 549 | throwf("in '%s', %s", info.path, msg); |
a645023d A |
550 | } |
551 | } | |
552 | } | |
553 | ||
554 | ||
f80fe69f A |
555 | // mark all dylibs initially specified as required, and check if they can be used |
556 | void InputFiles::markExplicitlyLinkedDylibs() | |
557 | { | |
a645023d A |
558 | for (InstallNameToDylib::iterator it=_installPathToDylibs.begin(); it != _installPathToDylibs.end(); it++) { |
559 | it->second->setExplicitlyLinked(); | |
560 | this->checkDylibClientRestrictions(it->second); | |
561 | } | |
f80fe69f A |
562 | } |
563 | ||
564 | bool InputFiles::libraryAlreadyLoaded(const char* path) | |
565 | { | |
566 | for (std::vector<ld::File*>::const_iterator it = _inputFiles.begin(); it != _inputFiles.end(); ++it) { | |
567 | if ( strcmp(path, (*it)->path()) == 0 ) | |
568 | return true; | |
569 | } | |
570 | return false; | |
571 | } | |
572 | ||
573 | ||
599556ff | 574 | void InputFiles::addLinkerOptionLibraries(ld::Internal& state, ld::File::AtomHandler& handler) |
f80fe69f A |
575 | { |
576 | if ( _options.outputKind() == Options::kObjectFile ) | |
577 | return; | |
578 | ||
579 | // process frameworks specified in .o linker options | |
580 | for (CStringSet::const_iterator it = state.linkerOptionFrameworks.begin(); it != state.linkerOptionFrameworks.end(); ++it) { | |
581 | const char* frameworkName = *it; | |
582 | Options::FileInfo info = _options.findFramework(frameworkName); | |
583 | if ( ! this->libraryAlreadyLoaded(info.path) ) { | |
584 | info.ordinal = _linkerOptionOrdinal.nextLinkerOptionOrdinal(); | |
585 | try { | |
586 | ld::File* reader = this->makeFile(info, true); | |
587 | ld::dylib::File* dylibReader = dynamic_cast<ld::dylib::File*>(reader); | |
588 | if ( dylibReader != NULL ) { | |
589 | if ( ! dylibReader->installPathVersionSpecific() ) { | |
590 | dylibReader->setImplicitlyLinked(); | |
591 | this->addDylib(dylibReader, info); | |
592 | } | |
593 | } | |
594 | else { | |
595 | throwf("framework linker option at %s is not a dylib", info.path); | |
596 | } | |
597 | } | |
598 | catch (const char* msg) { | |
9543cb2f | 599 | warning("Auto-Linking supplied '%s', %s", info.path, msg); |
f80fe69f A |
600 | } |
601 | } | |
602 | } | |
603 | // process libraries specified in .o linker options | |
604 | for (CStringSet::const_iterator it = state.linkerOptionLibraries.begin(); it != state.linkerOptionLibraries.end(); ++it) { | |
605 | const char* libName = *it; | |
606 | Options::FileInfo info = _options.findLibrary(libName); | |
607 | if ( ! this->libraryAlreadyLoaded(info.path) ) { | |
608 | info.ordinal = _linkerOptionOrdinal.nextLinkerOptionOrdinal(); | |
609 | try { | |
599556ff A |
610 | //<rdar://problem/17787306> -force_load_swift_libs |
611 | info.options.fForceLoad = _options.forceLoadSwiftLibs() && (strncmp(libName, "swift", 5) == 0); | |
f80fe69f A |
612 | ld::File* reader = this->makeFile(info, true); |
613 | ld::dylib::File* dylibReader = dynamic_cast<ld::dylib::File*>(reader); | |
614 | ld::archive::File* archiveReader = dynamic_cast<ld::archive::File*>(reader); | |
615 | if ( dylibReader != NULL ) { | |
616 | dylibReader->setImplicitlyLinked(); | |
617 | this->addDylib(dylibReader, info); | |
618 | } | |
619 | else if ( archiveReader != NULL ) { | |
620 | _searchLibraries.push_back(LibraryInfo(archiveReader)); | |
621 | if ( _options.dumpDependencyInfo() ) | |
622 | _options.dumpDependency(Options::depArchive, archiveReader->path()); | |
599556ff A |
623 | //<rdar://problem/17787306> -force_load_swift_libs |
624 | if (info.options.fForceLoad) { | |
625 | archiveReader->forEachAtom(handler); | |
626 | } | |
f80fe69f A |
627 | } |
628 | else { | |
629 | throwf("linker option dylib at %s is not a dylib", info.path); | |
630 | } | |
631 | } | |
632 | catch (const char* msg) { | |
9543cb2f | 633 | warning("Auto-Linking supplied '%s', %s", info.path, msg); |
f80fe69f A |
634 | } |
635 | } | |
636 | } | |
637 | } | |
638 | ||
639 | void InputFiles::createIndirectDylibs() | |
640 | { | |
a645023d A |
641 | // keep processing dylibs until no more dylibs are added |
642 | unsigned long lastMapSize = 0; | |
afe874b1 | 643 | std::set<ld::dylib::File*> dylibsProcessed; |
a645023d A |
644 | while ( lastMapSize != _allDylibs.size() ) { |
645 | lastMapSize = _allDylibs.size(); | |
646 | // can't iterator _installPathToDylibs while modifying it, so use temp buffer | |
647 | std::vector<ld::dylib::File*> unprocessedDylibs; | |
648 | for (std::set<ld::dylib::File*>::iterator it=_allDylibs.begin(); it != _allDylibs.end(); it++) { | |
649 | if ( dylibsProcessed.count(*it) == 0 ) | |
650 | unprocessedDylibs.push_back(*it); | |
651 | } | |
652 | for (std::vector<ld::dylib::File*>::iterator it=unprocessedDylibs.begin(); it != unprocessedDylibs.end(); it++) { | |
653 | dylibsProcessed.insert(*it); | |
654 | (*it)->processIndirectLibraries(this, _options.implicitlyLinkIndirectPublicDylibs()); | |
655 | } | |
656 | } | |
657 | ||
658 | // go back over original dylibs and mark sub frameworks as re-exported | |
659 | if ( _options.outputKind() == Options::kDynamicLibrary ) { | |
660 | const char* myLeaf = strrchr(_options.installPath(), '/'); | |
661 | if ( myLeaf != NULL ) { | |
662 | for (std::vector<class ld::File*>::const_iterator it=_inputFiles.begin(); it != _inputFiles.end(); it++) { | |
663 | ld::dylib::File* dylibReader = dynamic_cast<ld::dylib::File*>(*it); | |
664 | if ( dylibReader != NULL ) { | |
665 | const char* childParent = dylibReader->parentUmbrella(); | |
666 | if ( childParent != NULL ) { | |
667 | if ( strcmp(childParent, &myLeaf[1]) == 0 ) { | |
668 | // mark that this dylib will be re-exported | |
669 | dylibReader->setWillBeReExported(); | |
670 | } | |
671 | } | |
672 | } | |
673 | } | |
674 | } | |
675 | } | |
676 | ||
677 | } | |
678 | ||
679 | void InputFiles::createOpaqueFileSections() | |
680 | { | |
f80fe69f | 681 | // extra command line sections always at end |
a645023d | 682 | for (Options::ExtraSection::const_iterator it=_options.extraSectionsBegin(); it != _options.extraSectionsEnd(); ++it) { |
ebf6f434 | 683 | _inputFiles.push_back(opaque_section::parse(it->segmentName, it->sectionName, it->path, it->data, it->dataLen)); |
f80fe69f A |
684 | if ( _options.dumpDependencyInfo() ) |
685 | _options.dumpDependency(Options::depSection, it->path); | |
a645023d A |
686 | } |
687 | ||
688 | } | |
689 | ||
690 | ||
691 | void InputFiles::checkDylibClientRestrictions(ld::dylib::File* dylib) | |
692 | { | |
693 | // Check for any restrictions on who can link with this dylib | |
694 | const char* dylibParentName = dylib->parentUmbrella() ; | |
695 | const std::vector<const char*>* clients = dylib->allowableClients(); | |
696 | if ( (dylibParentName != NULL) || (clients != NULL) ) { | |
697 | // only dylibs that are in an umbrella or have a client list need verification | |
698 | const char* installName = _options.installPath(); | |
699 | const char* installNameLastSlash = strrchr(installName, '/'); | |
700 | bool isParent = false; | |
701 | bool isSibling = false; | |
702 | bool isAllowableClient = false; | |
703 | // There are three cases: | |
704 | if ( (dylibParentName != NULL) && (installNameLastSlash != NULL) ) { | |
705 | // starts after last slash | |
706 | const char* myName = &installNameLastSlash[1]; | |
707 | unsigned int myNameLen = strlen(myName); | |
708 | if ( strncmp(myName, "lib", 3) == 0 ) | |
709 | myName = &myName[3]; | |
710 | // up to first dot | |
711 | const char* firstDot = strchr(myName, '.'); | |
712 | if ( firstDot != NULL ) | |
713 | myNameLen = firstDot - myName; | |
714 | // up to first underscore | |
715 | const char* firstUnderscore = strchr(myName, '_'); | |
716 | if ( (firstUnderscore != NULL) && ((firstUnderscore - myName) < (int)myNameLen) ) | |
717 | myNameLen = firstUnderscore - myName; | |
718 | ||
719 | // case 1) The dylib has a parent umbrella, and we are creating the parent umbrella | |
720 | isParent = ( (strlen(dylibParentName) == myNameLen) && (strncmp(myName, dylibParentName, myNameLen) == 0) ); | |
721 | ||
722 | // case 2) The dylib has a parent umbrella, and we are creating a sibling with the same parent | |
723 | isSibling = ( (_options.umbrellaName() != NULL) && (strcmp(_options.umbrellaName(), dylibParentName) == 0) ); | |
724 | } | |
725 | ||
726 | if ( !isParent && !isSibling && (clients != NULL) ) { | |
727 | // case 3) the dylib has a list of allowable clients, and we are creating one of them | |
728 | const char* clientName = _options.clientName(); | |
729 | int clientNameLen = 0; | |
730 | if ( clientName != NULL ) { | |
731 | // use client name as specified on command line | |
732 | clientNameLen = strlen(clientName); | |
733 | } | |
734 | else { | |
735 | // infer client name from output path (e.g. xxx/libfoo_variant.A.dylib --> foo, Bar.framework/Bar_variant --> Bar) | |
736 | clientName = installName; | |
737 | clientNameLen = strlen(clientName); | |
738 | // starts after last slash | |
739 | if ( installNameLastSlash != NULL ) | |
740 | clientName = &installNameLastSlash[1]; | |
741 | if ( strncmp(clientName, "lib", 3) == 0 ) | |
742 | clientName = &clientName[3]; | |
743 | // up to first dot | |
744 | const char* firstDot = strchr(clientName, '.'); | |
745 | if ( firstDot != NULL ) | |
746 | clientNameLen = firstDot - clientName; | |
747 | // up to first underscore | |
748 | const char* firstUnderscore = strchr(clientName, '_'); | |
749 | if ( (firstUnderscore != NULL) && ((firstUnderscore - clientName) < clientNameLen) ) | |
750 | clientNameLen = firstUnderscore - clientName; | |
751 | } | |
752 | ||
753 | // Use clientName to check if this dylib is able to link against the allowable clients. | |
754 | for (std::vector<const char*>::const_iterator it = clients->begin(); it != clients->end(); it++) { | |
755 | if ( strncmp(*it, clientName, clientNameLen) == 0 ) | |
756 | isAllowableClient = true; | |
757 | } | |
758 | } | |
759 | ||
760 | if ( !isParent && !isSibling && !isAllowableClient ) { | |
761 | if ( dylibParentName != NULL ) { | |
762 | throwf("cannot link directly with %s. Link against the umbrella framework '%s.framework' instead.", | |
763 | dylib->path(), dylibParentName); | |
764 | } | |
765 | else { | |
766 | throwf("cannot link directly with %s", dylib->path()); | |
767 | } | |
768 | } | |
769 | } | |
770 | } | |
771 | ||
772 | ||
773 | void InputFiles::inferArchitecture(Options& opts, const char** archName) | |
774 | { | |
775 | _inferredArch = true; | |
776 | // scan all input files, looking for a thin .o file. | |
777 | // the first one found is presumably the architecture to link | |
778 | uint8_t buffer[sizeof(mach_header_64)]; | |
779 | const std::vector<Options::FileInfo>& files = opts.getInputFiles(); | |
780 | for (std::vector<Options::FileInfo>::const_iterator it = files.begin(); it != files.end(); ++it) { | |
781 | int fd = ::open(it->path, O_RDONLY, 0); | |
782 | if ( fd != -1 ) { | |
783 | ssize_t amount = read(fd, buffer, sizeof(buffer)); | |
784 | ::close(fd); | |
785 | if ( amount >= (ssize_t)sizeof(buffer) ) { | |
786 | cpu_type_t type; | |
787 | cpu_subtype_t subtype; | |
788 | if ( mach_o::relocatable::isObjectFile(buffer, &type, &subtype) ) { | |
789 | opts.setArchitecture(type, subtype); | |
790 | *archName = opts.architectureName(); | |
791 | return; | |
792 | } | |
793 | } | |
794 | } | |
795 | } | |
796 | ||
797 | // no thin .o files found, so default to same architecture this tool was built as | |
798 | warning("-arch not specified"); | |
b2fa67a8 | 799 | #if __i386__ |
a645023d | 800 | opts.setArchitecture(CPU_TYPE_I386, CPU_SUBTYPE_X86_ALL); |
a645023d A |
801 | #elif __x86_64__ |
802 | opts.setArchitecture(CPU_TYPE_X86_64, CPU_SUBTYPE_X86_64_ALL); | |
803 | #elif __arm__ | |
804 | opts.setArchitecture(CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V6); | |
805 | #else | |
806 | #error unknown default architecture | |
807 | #endif | |
808 | *archName = opts.architectureName(); | |
809 | } | |
810 | ||
811 | ||
812 | InputFiles::InputFiles(Options& opts, const char** archName) | |
813 | : _totalObjectSize(0), _totalArchiveSize(0), | |
814 | _totalObjectLoaded(0), _totalArchivesLoaded(0), _totalDylibsLoaded(0), | |
ebf6f434 | 815 | _options(opts), _bundleLoader(NULL), |
f80fe69f A |
816 | _inferredArch(false), |
817 | _exception(NULL), | |
818 | _indirectDylibOrdinal(ld::File::Ordinal::indirectDylibBase()), | |
819 | _linkerOptionOrdinal(ld::File::Ordinal::linkeOptionBase()) | |
a645023d A |
820 | { |
821 | // fStartCreateReadersTime = mach_absolute_time(); | |
822 | if ( opts.architecture() == 0 ) { | |
823 | // command line missing -arch, so guess arch | |
824 | inferArchitecture(opts, archName); | |
825 | } | |
ebf6f434 A |
826 | #if HAVE_PTHREADS |
827 | pthread_mutex_init(&_parseLock, NULL); | |
828 | pthread_cond_init(&_parseWorkReady, NULL); | |
829 | pthread_cond_init(&_newFileAvailable, NULL); | |
830 | #endif | |
831 | const std::vector<Options::FileInfo>& files = _options.getInputFiles(); | |
a645023d A |
832 | if ( files.size() == 0 ) |
833 | throw "no object files specified"; | |
ebf6f434 | 834 | |
a645023d | 835 | _inputFiles.reserve(files.size()); |
ebf6f434 A |
836 | #if HAVE_PTHREADS |
837 | unsigned int inputFileSlot = 0; | |
838 | _availableInputFiles = 0; | |
839 | _parseCursor = 0; | |
840 | #endif | |
841 | Options::FileInfo* entry; | |
a645023d | 842 | for (std::vector<Options::FileInfo>::const_iterator it = files.begin(); it != files.end(); ++it) { |
ebf6f434 A |
843 | entry = (Options::FileInfo*)&(*it); |
844 | #if HAVE_PTHREADS | |
845 | // Assign input file slots to all the FileInfos. | |
846 | // Also chain all FileInfos into one big list to set up for worker threads to do parsing. | |
847 | entry->inputFileSlot = inputFileSlot; | |
848 | entry->readyToParse = !entry->fromFileList || !_options.pipelineEnabled(); | |
849 | if (entry->readyToParse) | |
850 | _availableInputFiles++; | |
851 | _inputFiles.push_back(NULL); | |
852 | inputFileSlot++; | |
853 | #else | |
854 | // In the non-threaded case just parse the file now. | |
855 | _inputFiles.push_back(makeFile(*entry, false)); | |
856 | #endif | |
857 | } | |
858 | ||
859 | #if HAVE_PTHREADS | |
860 | _remainingInputFiles = files.size(); | |
861 | ||
862 | // initialize info for parsing input files on worker threads | |
863 | unsigned int ncpus; | |
864 | int mib[2]; | |
865 | size_t len = sizeof(ncpus); | |
866 | mib[0] = CTL_HW; | |
867 | mib[1] = HW_NCPU; | |
868 | if (sysctl(mib, 2, &ncpus, &len, NULL, 0) != 0) { | |
869 | ncpus = 1; | |
870 | } | |
871 | _availableWorkers = MIN(ncpus, files.size()); // max # workers we permit | |
872 | _idleWorkers = 0; | |
873 | ||
874 | if (_options.pipelineEnabled()) { | |
875 | // start up a thread to listen for available input files | |
876 | startThread(InputFiles::waitForInputFiles); | |
a645023d A |
877 | } |
878 | ||
ebf6f434 A |
879 | // Start up one parser thread. More start on demand as parsed input files get consumed. |
880 | startThread(InputFiles::parseWorkerThread); | |
881 | _availableWorkers--; | |
882 | #else | |
883 | if (_options.pipelineEnabled()) { | |
884 | throwf("pipelined linking not supported on this platform"); | |
885 | } | |
886 | #endif | |
a645023d A |
887 | } |
888 | ||
889 | ||
ebf6f434 A |
890 | #if HAVE_PTHREADS |
891 | void InputFiles::startThread(void (*threadFunc)(InputFiles *)) const { | |
892 | pthread_t thread; | |
893 | pthread_attr_t attr; | |
894 | pthread_attr_init(&attr); | |
895 | // set a nice big stack (same as main thread) because some code uses potentially large stack buffers | |
896 | pthread_attr_setstacksize(&attr, 8 * 1024 * 1024); | |
897 | pthread_create(&thread, &attr, (void *(*)(void*))threadFunc, (void *)this); | |
898 | pthread_detach(thread); | |
899 | pthread_attr_destroy(&attr); | |
a645023d A |
900 | } |
901 | ||
ebf6f434 A |
902 | // Work loop for input file parsing threads |
903 | void InputFiles::parseWorkerThread() { | |
904 | ld::File *file; | |
905 | const char *exception = NULL; | |
906 | pthread_mutex_lock(&_parseLock); | |
907 | const std::vector<Options::FileInfo>& files = _options.getInputFiles(); | |
908 | if (_s_logPThreads) printf("worker starting\n"); | |
909 | do { | |
910 | if (_availableInputFiles == 0) { | |
911 | _idleWorkers++; | |
912 | pthread_cond_wait(&_parseWorkReady, &_parseLock); | |
913 | _idleWorkers--; | |
914 | } else { | |
915 | int slot = _parseCursor; | |
916 | while (slot < (int)files.size() && (_inputFiles[slot] != NULL || !files[slot].readyToParse)) | |
917 | slot++; | |
918 | assert(slot < (int)files.size()); | |
919 | Options::FileInfo& entry = (Options::FileInfo&)files[slot]; | |
920 | _parseCursor = slot+1; | |
921 | _availableInputFiles--; | |
922 | entry.readyToParse = false; // to avoid multiple threads finding this file | |
923 | pthread_mutex_unlock(&_parseLock); | |
924 | if (_s_logPThreads) printf("parsing index %u\n", slot); | |
925 | try { | |
926 | file = makeFile(entry, false); | |
f80fe69f A |
927 | } |
928 | catch (const char *msg) { | |
ebf6f434 A |
929 | if ( (strstr(msg, "architecture") != NULL) && !_options.errorOnOtherArchFiles() ) { |
930 | if ( _options.ignoreOtherArchInputFiles() ) { | |
931 | // ignore, because this is about an architecture not in use | |
932 | } | |
933 | else { | |
934 | warning("ignoring file %s, %s", entry.path, msg); | |
935 | } | |
f80fe69f | 936 | } |
599556ff A |
937 | else if ( strstr(msg, "ignoring unexpected") != NULL ) { |
938 | warning("%s, %s", entry.path, msg); | |
939 | } | |
f80fe69f A |
940 | else { |
941 | asprintf((char**)&exception, "%s file '%s'", msg, entry.path); | |
ebf6f434 A |
942 | } |
943 | file = new IgnoredFile(entry.path, entry.modTime, entry.ordinal, ld::File::Other); | |
944 | } | |
945 | pthread_mutex_lock(&_parseLock); | |
946 | if (_remainingInputFiles > 0) | |
947 | _remainingInputFiles--; | |
948 | if (_s_logPThreads) printf("done with index %u, %d remaining\n", slot, _remainingInputFiles); | |
949 | if (exception) { | |
950 | // We are about to die, so set to zero to stop other threads from doing unneeded work. | |
951 | _remainingInputFiles = 0; | |
952 | _exception = exception; | |
f80fe69f A |
953 | } |
954 | else { | |
ebf6f434 A |
955 | _inputFiles[slot] = file; |
956 | if (_neededFileSlot == slot) | |
957 | pthread_cond_signal(&_newFileAvailable); | |
958 | } | |
959 | } | |
960 | } while (_remainingInputFiles); | |
961 | if (_s_logPThreads) printf("worker exiting\n"); | |
962 | pthread_cond_broadcast(&_parseWorkReady); | |
963 | pthread_cond_signal(&_newFileAvailable); | |
964 | pthread_mutex_unlock(&_parseLock); | |
965 | } | |
a645023d | 966 | |
a645023d | 967 | |
ebf6f434 A |
968 | void InputFiles::parseWorkerThread(InputFiles *inputFiles) { |
969 | inputFiles->parseWorkerThread(); | |
a645023d | 970 | } |
ebf6f434 | 971 | #endif |
a645023d A |
972 | |
973 | ||
ebf6f434 | 974 | ld::File* InputFiles::addDylib(ld::dylib::File* reader, const Options::FileInfo& info) |
a645023d A |
975 | { |
976 | _allDylibs.insert(reader); | |
977 | ||
978 | if ( (reader->installPath() == NULL) && !info.options.fBundleLoader ) { | |
979 | // this is a "blank" stub | |
980 | // silently ignore it | |
981 | return reader; | |
982 | } | |
983 | // store options about how dylib will be used in dylib itself | |
984 | if ( info.options.fWeakImport ) | |
afe874b1 | 985 | reader->setForcedWeakLinked(); |
a645023d A |
986 | if ( info.options.fReExport ) |
987 | reader->setWillBeReExported(); | |
988 | if ( info.options.fUpward ) { | |
989 | if ( _options.outputKind() == Options::kDynamicLibrary ) | |
990 | reader->setWillBeUpwardDylib(); | |
991 | else | |
992 | warning("ignoring upward dylib option for %s\n", info.path); | |
993 | } | |
994 | if ( info.options.fLazyLoad ) | |
995 | reader->setWillBeLazyLoadedDylb(); | |
996 | ||
997 | // add to map of loaded dylibs | |
998 | const char* installPath = reader->installPath(); | |
999 | if ( installPath != NULL ) { | |
1000 | InstallNameToDylib::iterator pos = _installPathToDylibs.find(installPath); | |
1001 | if ( pos == _installPathToDylibs.end() ) { | |
1002 | _installPathToDylibs[strdup(installPath)] = reader; | |
1003 | } | |
1004 | else { | |
1005 | bool dylibOnCommandLineTwice = ( strcmp(pos->second->path(), reader->path()) == 0 ); | |
1006 | bool isSymlink = false; | |
1007 | // ignore if this is a symlink to a dylib we've already loaded | |
1008 | if ( !dylibOnCommandLineTwice ) { | |
1009 | char existingDylibPath[PATH_MAX]; | |
1010 | if ( realpath(pos->second->path(), existingDylibPath) != NULL ) { | |
1011 | char newDylibPath[PATH_MAX]; | |
1012 | if ( realpath(reader->path(), newDylibPath) != NULL ) { | |
1013 | isSymlink = ( strcmp(existingDylibPath, newDylibPath) == 0 ); | |
1014 | } | |
1015 | } | |
1016 | } | |
ebf6f434 A |
1017 | // remove warning for <rdar://problem/10860629> Same install name for CoreServices and CFNetwork? |
1018 | //if ( !dylibOnCommandLineTwice && !isSymlink ) | |
f80fe69f | 1019 | // warning("dylibs with same install name: %p %s and %p %s", pos->second, pos->second->path(), reader, reader->path()); |
a645023d A |
1020 | } |
1021 | } | |
1022 | else if ( info.options.fBundleLoader ) | |
1023 | _bundleLoader = reader; | |
1024 | ||
1025 | // log direct readers | |
f80fe69f | 1026 | if ( ! info.options.fIndirectDylib ) |
a645023d A |
1027 | this->logDylib(reader, false); |
1028 | ||
a645023d A |
1029 | // update stats |
1030 | _totalDylibsLoaded++; | |
1031 | ||
d425e388 | 1032 | // just add direct libraries to search-first list |
f80fe69f | 1033 | if ( ! info.options.fIndirectDylib ) |
d425e388 | 1034 | _searchLibraries.push_back(LibraryInfo(reader)); |
f80fe69f | 1035 | |
a645023d A |
1036 | return reader; |
1037 | } | |
1038 | ||
1039 | ||
ebf6f434 A |
1040 | #if HAVE_PTHREADS |
1041 | // Called during pipelined linking to listen for available input files. | |
1042 | // Available files are enqueued for parsing. | |
1043 | void InputFiles::waitForInputFiles() | |
a645023d | 1044 | { |
ebf6f434 A |
1045 | if (_s_logPThreads) printf("starting pipeline listener\n"); |
1046 | try { | |
1047 | const char *fifo = _options.pipelineFifo(); | |
1048 | assert(fifo); | |
1049 | std::map<const char *, const Options::FileInfo*, strcompclass> fileMap; | |
1050 | const std::vector<Options::FileInfo>& files = _options.getInputFiles(); | |
1051 | for (std::vector<Options::FileInfo>::const_iterator it = files.begin(); it != files.end(); ++it) { | |
1052 | const Options::FileInfo& entry = *it; | |
1053 | if (entry.fromFileList) { | |
1054 | fileMap[entry.path] = &entry; | |
1055 | } | |
1056 | } | |
1057 | FILE *fileStream = fopen(fifo, "r"); | |
1058 | if (!fileStream) | |
1059 | throwf("pipelined linking error - failed to open stream. fopen() returns %s for \"%s\"\n", strerror(errno), fifo); | |
1060 | while (fileMap.size() > 0) { | |
1061 | char path_buf[PATH_MAX+1]; | |
1062 | if (fgets(path_buf, PATH_MAX, fileStream) == NULL) | |
1063 | throwf("pipelined linking error - %lu missing input files", fileMap.size()); | |
1064 | int len = strlen(path_buf); | |
1065 | if (path_buf[len-1] == '\n') | |
1066 | path_buf[len-1] = 0; | |
1067 | std::map<const char *, const Options::FileInfo*, strcompclass>::iterator it = fileMap.find(path_buf); | |
1068 | if (it == fileMap.end()) | |
1069 | throwf("pipelined linking error - not in file list: %s\n", path_buf); | |
1070 | Options::FileInfo* inputInfo = (Options::FileInfo*)it->second; | |
f80fe69f | 1071 | if (!inputInfo->checkFileExists(_options)) |
ebf6f434 A |
1072 | throwf("pipelined linking error - file does not exist: %s\n", inputInfo->path); |
1073 | pthread_mutex_lock(&_parseLock); | |
1074 | if (_idleWorkers) | |
1075 | pthread_cond_signal(&_parseWorkReady); | |
1076 | inputInfo->readyToParse = true; | |
1077 | if (_parseCursor > inputInfo->inputFileSlot) | |
1078 | _parseCursor = inputInfo->inputFileSlot; | |
1079 | _availableInputFiles++; | |
1080 | if (_s_logPThreads) printf("pipeline listener: %s slot=%d, _parseCursor=%d, _availableInputFiles = %d remaining = %ld\n", path_buf, inputInfo->inputFileSlot, _parseCursor, _availableInputFiles, fileMap.size()-1); | |
1081 | pthread_mutex_unlock(&_parseLock); | |
1082 | fileMap.erase(it); | |
a645023d | 1083 | } |
ebf6f434 A |
1084 | } catch (const char *msg) { |
1085 | pthread_mutex_lock(&_parseLock); | |
1086 | _exception = msg; | |
1087 | pthread_cond_signal(&_newFileAvailable); | |
1088 | pthread_mutex_unlock(&_parseLock); | |
a645023d | 1089 | } |
a645023d A |
1090 | } |
1091 | ||
1092 | ||
ebf6f434 A |
1093 | void InputFiles::waitForInputFiles(InputFiles *inputFiles) { |
1094 | inputFiles->waitForInputFiles(); | |
1095 | } | |
1096 | #endif | |
1097 | ||
1098 | ||
f80fe69f | 1099 | void InputFiles::forEachInitialAtom(ld::File::AtomHandler& handler, ld::Internal& state) |
a645023d | 1100 | { |
ebf6f434 A |
1101 | // add all direct object, archives, and dylibs |
1102 | const std::vector<Options::FileInfo>& files = _options.getInputFiles(); | |
1103 | size_t fileIndex; | |
1104 | for (fileIndex=0; fileIndex<_inputFiles.size(); fileIndex++) { | |
1105 | ld::File *file; | |
1106 | #if HAVE_PTHREADS | |
1107 | pthread_mutex_lock(&_parseLock); | |
1108 | ||
1109 | // this loop waits for the needed file to be ready (parsed by worker thread) | |
1110 | while (_inputFiles[fileIndex] == NULL && _exception == NULL) { | |
1111 | // We are starved for input. If there are still files to parse and we have | |
1112 | // not maxed out the worker thread count start a new worker thread. | |
1113 | if (_availableInputFiles > 0 && _availableWorkers > 0) { | |
1114 | if (_s_logPThreads) printf("starting worker\n"); | |
1115 | startThread(InputFiles::parseWorkerThread); | |
1116 | _availableWorkers--; | |
a645023d | 1117 | } |
ebf6f434 A |
1118 | _neededFileSlot = fileIndex; |
1119 | if (_s_logPThreads) printf("consumer blocking for %lu: %s\n", fileIndex, files[fileIndex].path); | |
1120 | pthread_cond_wait(&_newFileAvailable, &_parseLock); | |
a645023d | 1121 | } |
ebf6f434 A |
1122 | |
1123 | if (_exception) | |
1124 | throw _exception; | |
1125 | ||
1126 | // The input file is parsed. Assimilate it and call its atom iterator. | |
1127 | if (_s_logPThreads) printf("consuming slot %lu\n", fileIndex); | |
1128 | file = _inputFiles[fileIndex]; | |
1129 | pthread_mutex_unlock(&_parseLock); | |
1130 | #else | |
1131 | file = _inputFiles[fileIndex]; | |
1132 | #endif | |
1133 | const Options::FileInfo& info = files[fileIndex]; | |
1134 | switch (file->type()) { | |
1135 | case ld::File::Reloc: | |
1136 | { | |
1137 | ld::relocatable::File* reloc = (ld::relocatable::File*)file; | |
1138 | _options.snapshot().recordObjectFile(reloc->path()); | |
f80fe69f A |
1139 | if ( _options.dumpDependencyInfo() ) |
1140 | _options.dumpDependency(Options::depObjectFile, reloc->path()); | |
afe874b1 | 1141 | } |
ebf6f434 A |
1142 | break; |
1143 | case ld::File::Dylib: | |
1144 | { | |
1145 | ld::dylib::File* dylib = (ld::dylib::File*)file; | |
1146 | addDylib(dylib, info); | |
a645023d | 1147 | } |
ebf6f434 A |
1148 | break; |
1149 | case ld::File::Archive: | |
1150 | { | |
1151 | ld::archive::File* archive = (ld::archive::File*)file; | |
1152 | // <rdar://problem/9740166> force loaded archives should be in LD_TRACE | |
1153 | if ( (info.options.fForceLoad || _options.fullyLoadArchives()) && _options.traceArchives() ) | |
1154 | logArchive(archive); | |
1155 | _searchLibraries.push_back(LibraryInfo(archive)); | |
f80fe69f A |
1156 | if ( _options.dumpDependencyInfo() ) |
1157 | _options.dumpDependency(Options::depArchive, archive->path()); | |
ebf6f434 A |
1158 | } |
1159 | break; | |
1160 | case ld::File::Other: | |
1161 | break; | |
1162 | default: | |
1163 | { | |
1164 | throwf("Unknown file type for %s", file->path()); | |
1165 | } | |
1166 | break; | |
a645023d | 1167 | } |
ebf6f434 | 1168 | file->forEachAtom(handler); |
a645023d A |
1169 | } |
1170 | ||
f80fe69f | 1171 | markExplicitlyLinkedDylibs(); |
599556ff | 1172 | addLinkerOptionLibraries(state, handler); |
ebf6f434 A |
1173 | createIndirectDylibs(); |
1174 | createOpaqueFileSections(); | |
1175 | ||
1176 | while (fileIndex < _inputFiles.size()) { | |
1177 | ld::File *file = _inputFiles[fileIndex]; | |
1178 | file->forEachAtom(handler); | |
1179 | fileIndex++; | |
1180 | } | |
1181 | ||
1182 | switch ( _options.outputKind() ) { | |
1183 | case Options::kStaticExecutable: | |
1184 | case Options::kDynamicExecutable: | |
1185 | // add implicit __dso_handle label | |
1186 | handler.doAtom(DSOHandleAtom::_s_atomExecutable); | |
1187 | handler.doAtom(DSOHandleAtom::_s_atomAll); | |
1188 | if ( _options.pageZeroSize() != 0 ) | |
1189 | handler.doAtom(*new PageZeroAtom(_options.pageZeroSize())); | |
1190 | if ( _options.hasCustomStack() && !_options.needsEntryPointLoadCommand() ) | |
1191 | handler.doAtom(*new CustomStackAtom(_options.customStackSize())); | |
1192 | break; | |
1193 | case Options::kDynamicLibrary: | |
1194 | // add implicit __dso_handle label | |
1195 | handler.doAtom(DSOHandleAtom::_s_atomDylib); | |
1196 | handler.doAtom(DSOHandleAtom::_s_atomAll); | |
1197 | break; | |
1198 | case Options::kDynamicBundle: | |
1199 | // add implicit __dso_handle label | |
1200 | handler.doAtom(DSOHandleAtom::_s_atomBundle); | |
1201 | handler.doAtom(DSOHandleAtom::_s_atomAll); | |
1202 | break; | |
1203 | case Options::kDyld: | |
1204 | // add implicit __dso_handle label | |
1205 | handler.doAtom(DSOHandleAtom::_s_atomDyld); | |
1206 | handler.doAtom(DSOHandleAtom::_s_atomAll); | |
1207 | break; | |
1208 | case Options::kPreload: | |
1209 | // add implicit __mh_preload_header label | |
1210 | handler.doAtom(DSOHandleAtom::_s_atomPreload); | |
b1f7435d A |
1211 | // add implicit __dso_handle label, but put it in __text section because |
1212 | // with -preload the mach_header is no in the address space. | |
1213 | handler.doAtom(DSOHandleAtom::_s_atomPreloadDSO); | |
ebf6f434 A |
1214 | break; |
1215 | case Options::kObjectFile: | |
1216 | handler.doAtom(DSOHandleAtom::_s_atomObjectFile); | |
1217 | break; | |
1218 | case Options::kKextBundle: | |
1219 | // add implicit __dso_handle label | |
1220 | handler.doAtom(DSOHandleAtom::_s_atomAll); | |
1221 | break; | |
1222 | } | |
1223 | } | |
1224 | ||
1225 | ||
1226 | bool InputFiles::searchLibraries(const char* name, bool searchDylibs, bool searchArchives, bool dataSymbolOnly, ld::File::AtomHandler& handler) const | |
1227 | { | |
1228 | // Check each input library. | |
d425e388 A |
1229 | for (std::vector<LibraryInfo>::const_iterator it=_searchLibraries.begin(); it != _searchLibraries.end(); ++it) { |
1230 | LibraryInfo lib = *it; | |
ebf6f434 A |
1231 | if (lib.isDylib()) { |
1232 | if (searchDylibs) { | |
1233 | ld::dylib::File *dylibFile = lib.dylib(); | |
1234 | //fprintf(stderr, "searchLibraries(%s), looking in linked %s\n", name, dylibFile->path() ); | |
1235 | if ( dylibFile->justInTimeforEachAtom(name, handler) ) { | |
1236 | // we found a definition in this dylib | |
1237 | // done, unless it is a weak definition in which case we keep searching | |
1238 | _options.snapshot().recordDylibSymbol(dylibFile, name); | |
1239 | if ( !dylibFile->hasWeakExternals() || !dylibFile->hasWeakDefinition(name)) { | |
1240 | return true; | |
1241 | } | |
1242 | // else continue search for a non-weak definition | |
1243 | } | |
1244 | } | |
1245 | } else { | |
1246 | if (searchArchives) { | |
1247 | ld::archive::File *archiveFile = lib.archive(); | |
1248 | if ( dataSymbolOnly ) { | |
1249 | if ( archiveFile->justInTimeDataOnlyforEachAtom(name, handler) ) { | |
1250 | if ( _options.traceArchives() ) | |
1251 | logArchive(archiveFile); | |
1252 | _options.snapshot().recordArchive(archiveFile->path()); | |
1253 | // found data definition in static library, done | |
f80fe69f | 1254 | return true; |
ebf6f434 A |
1255 | } |
1256 | } | |
1257 | else { | |
1258 | if ( archiveFile->justInTimeforEachAtom(name, handler) ) { | |
1259 | if ( _options.traceArchives() ) | |
1260 | logArchive(archiveFile); | |
1261 | _options.snapshot().recordArchive(archiveFile->path()); | |
1262 | // found definition in static library, done | |
1263 | return true; | |
1264 | } | |
1265 | } | |
1266 | } | |
1267 | } | |
ebf6f434 A |
1268 | } |
1269 | ||
a645023d A |
1270 | // search indirect dylibs |
1271 | if ( searchDylibs ) { | |
1272 | for (InstallNameToDylib::const_iterator it=_installPathToDylibs.begin(); it != _installPathToDylibs.end(); ++it) { | |
1273 | ld::dylib::File* dylibFile = it->second; | |
1274 | bool searchThisDylib = false; | |
1275 | if ( _options.nameSpace() == Options::kTwoLevelNameSpace ) { | |
1276 | // for two level namesapce, just check all implicitly linked dylibs | |
1277 | searchThisDylib = dylibFile->implicitlyLinked() && !dylibFile->explicitlyLinked(); | |
1278 | } | |
1279 | else { | |
1280 | // for flat namespace, check all indirect dylibs | |
1281 | searchThisDylib = ! dylibFile->explicitlyLinked(); | |
1282 | } | |
1283 | if ( searchThisDylib ) { | |
1284 | //fprintf(stderr, "searchLibraries(%s), looking in implicitly linked %s\n", name, dylibFile->path() ); | |
1285 | if ( dylibFile->justInTimeforEachAtom(name, handler) ) { | |
1286 | // we found a definition in this dylib | |
1287 | // done, unless it is a weak definition in which case we keep searching | |
ebf6f434 A |
1288 | _options.snapshot().recordDylibSymbol(dylibFile, name); |
1289 | if ( !dylibFile->hasWeakExternals() || !dylibFile->hasWeakDefinition(name)) { | |
a645023d | 1290 | return true; |
ebf6f434 | 1291 | } |
a645023d A |
1292 | // else continue search for a non-weak definition |
1293 | } | |
1294 | } | |
1295 | } | |
1296 | } | |
1297 | ||
1298 | return false; | |
1299 | } | |
1300 | ||
1301 | ||
1302 | bool InputFiles::searchWeakDefInDylib(const char* name) const | |
1303 | { | |
f80fe69f | 1304 | // search all relevant dylibs to see if any have a weak-def with this name |
a645023d A |
1305 | for (InstallNameToDylib::const_iterator it=_installPathToDylibs.begin(); it != _installPathToDylibs.end(); ++it) { |
1306 | ld::dylib::File* dylibFile = it->second; | |
1307 | if ( dylibFile->implicitlyLinked() || dylibFile->explicitlyLinked() ) { | |
1308 | if ( dylibFile->hasWeakExternals() && dylibFile->hasWeakDefinition(name) ) { | |
1309 | return true; | |
1310 | } | |
1311 | } | |
1312 | } | |
1313 | return false; | |
1314 | } | |
ebf6f434 A |
1315 | |
1316 | static bool vectorContains(const std::vector<ld::dylib::File*>& vec, ld::dylib::File* key) | |
1317 | { | |
1318 | return std::find(vec.begin(), vec.end(), key) != vec.end(); | |
1319 | } | |
a645023d | 1320 | |
599556ff A |
1321 | struct DylibByInstallNameSorter |
1322 | { | |
1323 | bool operator()(const ld::dylib::File* left, const ld::dylib::File* right) | |
1324 | { | |
1325 | return (strcmp(left->installPath(), right->installPath()) < 0); | |
1326 | } | |
1327 | }; | |
1328 | ||
a645023d A |
1329 | void InputFiles::dylibs(ld::Internal& state) |
1330 | { | |
afe874b1 | 1331 | bool dylibsOK = false; |
a645023d A |
1332 | switch ( _options.outputKind() ) { |
1333 | case Options::kDynamicExecutable: | |
1334 | case Options::kDynamicLibrary: | |
1335 | case Options::kDynamicBundle: | |
1336 | dylibsOK = true; | |
1337 | break; | |
1338 | case Options::kStaticExecutable: | |
1339 | case Options::kDyld: | |
1340 | case Options::kPreload: | |
1341 | case Options::kObjectFile: | |
1342 | case Options::kKextBundle: | |
1343 | dylibsOK = false; | |
1344 | break; | |
1345 | } | |
1346 | ||
1347 | // add command line dylibs in order | |
1348 | for (std::vector<ld::File*>::const_iterator it=_inputFiles.begin(); it != _inputFiles.end(); ++it) { | |
1349 | ld::dylib::File* dylibFile = dynamic_cast<ld::dylib::File*>(*it); | |
1350 | // only add dylibs that are not "blank" dylib stubs | |
1351 | if ( (dylibFile != NULL) && ((dylibFile->installPath() != NULL) || (dylibFile == _bundleLoader)) ) { | |
ebf6f434 A |
1352 | if ( dylibsOK ) { |
1353 | if ( ! vectorContains(state.dylibs, dylibFile) ) { | |
1354 | state.dylibs.push_back(dylibFile); | |
1355 | } | |
1356 | } | |
a645023d A |
1357 | else |
1358 | warning("unexpected dylib (%s) on link line", dylibFile->path()); | |
1359 | } | |
1360 | } | |
1361 | // add implicitly linked dylibs | |
1362 | if ( _options.nameSpace() == Options::kTwoLevelNameSpace ) { | |
599556ff | 1363 | std::vector<ld::dylib::File*> implicitDylibs; |
a645023d A |
1364 | for (InstallNameToDylib::const_iterator it=_installPathToDylibs.begin(); it != _installPathToDylibs.end(); ++it) { |
1365 | ld::dylib::File* dylibFile = it->second; | |
ebf6f434 | 1366 | if ( dylibFile->implicitlyLinked() && dylibsOK ) { |
599556ff A |
1367 | if ( ! vectorContains(implicitDylibs, dylibFile) ) { |
1368 | implicitDylibs.push_back(dylibFile); | |
ebf6f434 A |
1369 | } |
1370 | } | |
a645023d | 1371 | } |
599556ff A |
1372 | // <rdar://problem/15002251> make implicit dylib order be deterministic by sorting by install_name |
1373 | std::sort(implicitDylibs.begin(), implicitDylibs.end(), DylibByInstallNameSorter()); | |
1374 | state.dylibs.insert(state.dylibs.end(), implicitDylibs.begin(), implicitDylibs.end()); | |
a645023d | 1375 | } |
ebf6f434 A |
1376 | |
1377 | //fprintf(stderr, "all dylibs:\n"); | |
1378 | //for(std::vector<ld::dylib::File*>::iterator it=state.dylibs.begin(); it != state.dylibs.end(); ++it) { | |
1379 | // const ld::dylib::File* dylib = *it; | |
1380 | // fprintf(stderr, " %p %s\n", dylib, dylib->path()); | |
1381 | //} | |
1382 | ||
a645023d A |
1383 | // and -bundle_loader |
1384 | state.bundleLoader = _bundleLoader; | |
ebf6f434 A |
1385 | |
1386 | // <rdar://problem/10807040> give an error when -nostdlib is used and libSystem is missing | |
1387 | if ( (state.dylibs.size() == 0) && _options.needsEntryPointLoadCommand() ) | |
1388 | throw "dynamic main executables must link with libSystem.dylib"; | |
a645023d A |
1389 | } |
1390 | ||
1391 | ||
1392 | } // namespace tool | |
1393 | } // namespace ld | |
1394 |