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