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