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