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