]>
Commit | Line | Data |
---|---|---|
1 | /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-* | |
2 | * | |
3 | * Copyright (c) 2009-2011 Apple Inc. All rights reserved. | |
4 | * | |
5 | * @APPLE_LICENSE_HEADER_START@ | |
6 | * | |
7 | * This file contains Original Code and/or Modifications of Original Code | |
8 | * as defined in and that are subject to the Apple Public Source License | |
9 | * Version 2.0 (the 'License'). You may not use this file except in | |
10 | * compliance with the License. Please obtain a copy of the License at | |
11 | * http://www.opensource.apple.com/apsl/ and read it before using this | |
12 | * file. | |
13 | * | |
14 | * The Original Code and all software distributed under the License are | |
15 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
16 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, | |
17 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
18 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. | |
19 | * Please see the License for the specific language governing rights and | |
20 | * limitations under the License. | |
21 | * | |
22 | * @APPLE_LICENSE_HEADER_END@ | |
23 | */ | |
24 | ||
25 | ||
26 | #include <stdlib.h> | |
27 | #include <sys/types.h> | |
28 | #include <sys/stat.h> | |
29 | #include <sys/mman.h> | |
30 | #include <sys/sysctl.h> | |
31 | #include <fcntl.h> | |
32 | #include <errno.h> | |
33 | #include <limits.h> | |
34 | #include <unistd.h> | |
35 | #include <mach/mach_time.h> | |
36 | #include <mach/vm_statistics.h> | |
37 | #include <mach/mach_init.h> | |
38 | #include <mach/mach_host.h> | |
39 | #include <dlfcn.h> | |
40 | #include <mach-o/dyld.h> | |
41 | #include <mach-o/fat.h> | |
42 | ||
43 | #include <string> | |
44 | #include <map> | |
45 | #include <set> | |
46 | #include <string> | |
47 | #include <vector> | |
48 | #include <list> | |
49 | #include <algorithm> | |
50 | #include <ext/hash_map> | |
51 | #include <ext/hash_set> | |
52 | #include <dlfcn.h> | |
53 | #include <AvailabilityMacros.h> | |
54 | ||
55 | #include "Options.h" | |
56 | ||
57 | #include "InputFiles.h" | |
58 | #include "macho_relocatable_file.h" | |
59 | #include "macho_dylib_file.h" | |
60 | #include "archive_file.h" | |
61 | #include "lto_file.h" | |
62 | #include "opaque_section_file.h" | |
63 | ||
64 | ||
65 | namespace ld { | |
66 | namespace tool { | |
67 | ||
68 | ||
69 | ||
70 | ||
71 | class DSOHandleAtom : public ld::Atom { | |
72 | public: | |
73 | DSOHandleAtom(const char* nm, ld::Atom::Scope sc, | |
74 | ld::Atom::SymbolTableInclusion inc, bool preload=false) | |
75 | : ld::Atom(preload ? _s_section_preload : _s_section, | |
76 | ld::Atom::definitionRegular, ld::Atom::combineNever, | |
77 | sc, ld::Atom::typeUnclassified, inc, true, false, false, | |
78 | ld::Atom::Alignment(1)), _name(nm) {} | |
79 | ||
80 | virtual ld::File* file() const { return NULL; } | |
81 | virtual bool translationUnitSource(const char** dir, const char** ) const | |
82 | { return false; } | |
83 | virtual const char* name() const { return _name; } | |
84 | virtual uint64_t size() const { return 0; } | |
85 | virtual uint64_t objectAddress() const { return 0; } | |
86 | virtual void copyRawContent(uint8_t buffer[]) const | |
87 | { } | |
88 | virtual void setScope(Scope) { } | |
89 | ||
90 | virtual ~DSOHandleAtom() {} | |
91 | ||
92 | static ld::Section _s_section; | |
93 | static ld::Section _s_section_preload; | |
94 | static DSOHandleAtom _s_atomAll; | |
95 | static DSOHandleAtom _s_atomExecutable; | |
96 | static DSOHandleAtom _s_atomDylib; | |
97 | static DSOHandleAtom _s_atomBundle; | |
98 | static DSOHandleAtom _s_atomDyld; | |
99 | static DSOHandleAtom _s_atomObjectFile; | |
100 | static DSOHandleAtom _s_atomPreload; | |
101 | private: | |
102 | const char* _name; | |
103 | }; | |
104 | ld::Section DSOHandleAtom::_s_section("__TEXT", "__mach_header", ld::Section::typeMachHeader, true); | |
105 | ld::Section DSOHandleAtom::_s_section_preload("__HEADER", "__mach_header", ld::Section::typeMachHeader, true); | |
106 | DSOHandleAtom DSOHandleAtom::_s_atomAll("___dso_handle", ld::Atom::scopeLinkageUnit, ld::Atom::symbolTableNotIn); | |
107 | DSOHandleAtom DSOHandleAtom::_s_atomExecutable("__mh_execute_header", ld::Atom::scopeGlobal, ld::Atom::symbolTableInAndNeverStrip); | |
108 | DSOHandleAtom DSOHandleAtom::_s_atomDylib("__mh_dylib_header", ld::Atom::scopeLinkageUnit, ld::Atom::symbolTableNotIn); | |
109 | DSOHandleAtom DSOHandleAtom::_s_atomBundle("__mh_bundle_header", ld::Atom::scopeLinkageUnit, ld::Atom::symbolTableNotIn); | |
110 | DSOHandleAtom DSOHandleAtom::_s_atomDyld("__mh_dylinker_header", ld::Atom::scopeLinkageUnit, ld::Atom::symbolTableNotIn); | |
111 | DSOHandleAtom DSOHandleAtom::_s_atomObjectFile("__mh_object_header", ld::Atom::scopeLinkageUnit, ld::Atom::symbolTableNotIn); | |
112 | DSOHandleAtom DSOHandleAtom::_s_atomPreload("__mh_preload_header", ld::Atom::scopeLinkageUnit, ld::Atom::symbolTableNotIn, true); | |
113 | ||
114 | ||
115 | ||
116 | class PageZeroAtom : public ld::Atom { | |
117 | public: | |
118 | PageZeroAtom(uint64_t sz) | |
119 | : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever, | |
120 | ld::Atom::scopeTranslationUnit, ld::Atom::typeZeroFill, | |
121 | symbolTableNotIn, true, false, false, ld::Atom::Alignment(12)), | |
122 | _size(sz) {} | |
123 | ||
124 | virtual ld::File* file() const { return NULL; } | |
125 | virtual bool translationUnitSource(const char** dir, const char** ) const | |
126 | { return false; } | |
127 | virtual const char* name() const { return "page zero"; } | |
128 | virtual uint64_t size() const { return _size; } | |
129 | virtual uint64_t objectAddress() const { return 0; } | |
130 | virtual void copyRawContent(uint8_t buffer[]) const | |
131 | { } | |
132 | virtual void setScope(Scope) { } | |
133 | ||
134 | virtual ~PageZeroAtom() {} | |
135 | ||
136 | static ld::Section _s_section; | |
137 | static DSOHandleAtom _s_atomAll; | |
138 | private: | |
139 | uint64_t _size; | |
140 | }; | |
141 | ld::Section PageZeroAtom::_s_section("__PAGEZERO", "__pagezero", ld::Section::typePageZero, true); | |
142 | ||
143 | ||
144 | class CustomStackAtom : public ld::Atom { | |
145 | public: | |
146 | CustomStackAtom(uint64_t sz) | |
147 | : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever, | |
148 | ld::Atom::scopeTranslationUnit, ld::Atom::typeZeroFill, | |
149 | symbolTableNotIn, false, false, false, ld::Atom::Alignment(12)), | |
150 | _size(sz) {} | |
151 | ||
152 | virtual ld::File* file() const { return NULL; } | |
153 | virtual bool translationUnitSource(const char** dir, const char** ) const | |
154 | { return false; } | |
155 | virtual const char* name() const { return "custom stack"; } | |
156 | virtual uint64_t size() const { return _size; } | |
157 | virtual uint64_t objectAddress() const { return 0; } | |
158 | virtual void copyRawContent(uint8_t buffer[]) const | |
159 | { } | |
160 | virtual void setScope(Scope) { } | |
161 | ||
162 | virtual ~CustomStackAtom() {} | |
163 | ||
164 | private: | |
165 | uint64_t _size; | |
166 | static ld::Section _s_section; | |
167 | }; | |
168 | ld::Section CustomStackAtom::_s_section("__UNIXSTACK", "__stack", ld::Section::typeStack, true); | |
169 | ||
170 | ||
171 | ||
172 | const char* InputFiles::fileArch(const uint8_t* p, unsigned len) | |
173 | { | |
174 | const char* result = mach_o::relocatable::archName(p); | |
175 | if ( result != NULL ) | |
176 | return result; | |
177 | ||
178 | result = lto::archName(p, len); | |
179 | if ( result != NULL ) | |
180 | return result; | |
181 | ||
182 | if ( strncmp((const char*)p, "!<arch>\n", 8) == 0 ) | |
183 | return "archive"; | |
184 | ||
185 | return "unsupported file format"; | |
186 | } | |
187 | ||
188 | ||
189 | ld::File* InputFiles::makeFile(const Options::FileInfo& info, bool indirectDylib) | |
190 | { | |
191 | // map in whole file | |
192 | uint64_t len = info.fileLen; | |
193 | int fd = ::open(info.path, O_RDONLY, 0); | |
194 | if ( fd == -1 ) | |
195 | throwf("can't open file, errno=%d", errno); | |
196 | if ( info.fileLen < 20 ) | |
197 | throw "file too small"; | |
198 | ||
199 | uint8_t* p = (uint8_t*)::mmap(NULL, info.fileLen, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, 0); | |
200 | if ( p == (uint8_t*)(-1) ) | |
201 | throwf("can't map file, errno=%d", errno); | |
202 | ||
203 | // if fat file, skip to architecture we want | |
204 | // Note: fat header is always big-endian | |
205 | bool isFatFile = false; | |
206 | const fat_header* fh = (fat_header*)p; | |
207 | if ( fh->magic == OSSwapBigToHostInt32(FAT_MAGIC) ) { | |
208 | isFatFile = true; | |
209 | const struct fat_arch* archs = (struct fat_arch*)(p + sizeof(struct fat_header)); | |
210 | uint32_t sliceToUse; | |
211 | bool sliceFound = false; | |
212 | if ( _options.preferSubArchitecture() ) { | |
213 | // first try to find a slice that match cpu-type and cpu-sub-type | |
214 | for (uint32_t i=0; i < OSSwapBigToHostInt32(fh->nfat_arch); ++i) { | |
215 | if ( (OSSwapBigToHostInt32(archs[i].cputype) == (uint32_t)_options.architecture()) | |
216 | && (OSSwapBigToHostInt32(archs[i].cpusubtype) == (uint32_t)_options.subArchitecture()) ) { | |
217 | sliceToUse = i; | |
218 | sliceFound = true; | |
219 | break; | |
220 | } | |
221 | } | |
222 | } | |
223 | if ( !sliceFound ) { | |
224 | // look for any slice that matches just cpu-type | |
225 | for (uint32_t i=0; i < OSSwapBigToHostInt32(fh->nfat_arch); ++i) { | |
226 | if ( OSSwapBigToHostInt32(archs[i].cputype) == (uint32_t)_options.architecture() ) { | |
227 | sliceToUse = i; | |
228 | sliceFound = true; | |
229 | break; | |
230 | } | |
231 | } | |
232 | } | |
233 | if ( sliceFound ) { | |
234 | uint32_t fileOffset = OSSwapBigToHostInt32(archs[sliceToUse].offset); | |
235 | len = OSSwapBigToHostInt32(archs[sliceToUse].size); | |
236 | if ( fileOffset+len > info.fileLen ) { | |
237 | throwf("truncated fat file. Slice from %u to %llu is past end of file with length %llu", | |
238 | fileOffset, fileOffset+len, info.fileLen); | |
239 | } | |
240 | // if requested architecture is page aligned within fat file, then remap just that portion of file | |
241 | if ( (fileOffset & 0x00000FFF) == 0 ) { | |
242 | // unmap whole file | |
243 | munmap((caddr_t)p, info.fileLen); | |
244 | // re-map just part we need | |
245 | p = (uint8_t*)::mmap(NULL, len, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, fileOffset); | |
246 | if ( p == (uint8_t*)(-1) ) | |
247 | throwf("can't re-map file, errno=%d", errno); | |
248 | } | |
249 | else { | |
250 | p = &p[fileOffset]; | |
251 | } | |
252 | } | |
253 | } | |
254 | ::close(fd); | |
255 | ||
256 | // see if it is an object file | |
257 | mach_o::relocatable::ParserOptions objOpts; | |
258 | objOpts.architecture = _options.architecture(); | |
259 | objOpts.objSubtypeMustMatch = !_options.allowSubArchitectureMismatches(); | |
260 | objOpts.logAllFiles = _options.logAllFiles(); | |
261 | objOpts.convertUnwindInfo = _options.needsUnwindInfoSection(); | |
262 | objOpts.subType = _options.subArchitecture(); | |
263 | ld::relocatable::File* objResult = mach_o::relocatable::parse(p, len, info.path, info.modTime, _nextInputOrdinal, objOpts); | |
264 | if ( objResult != NULL ) | |
265 | return this->addObject(objResult, info, len); | |
266 | ||
267 | // see if it is an llvm object file | |
268 | objResult = lto::parse(p, len, info.path, info.modTime, _nextInputOrdinal, _options.architecture(), _options.subArchitecture(), _options.logAllFiles()); | |
269 | if ( objResult != NULL ) | |
270 | return this->addObject(objResult, info, len); | |
271 | ||
272 | // see if it is a dynamic library | |
273 | ld::dylib::File* dylibResult = mach_o::dylib::parse(p, len, info.path, info.modTime, _options, _nextInputOrdinal, info.options.fBundleLoader, indirectDylib); | |
274 | if ( dylibResult != NULL ) | |
275 | return this->addDylib(dylibResult, info, len); | |
276 | ||
277 | // see if it is a static library | |
278 | ::archive::ParserOptions archOpts; | |
279 | archOpts.objOpts = objOpts; | |
280 | archOpts.forceLoadThisArchive = info.options.fForceLoad; | |
281 | archOpts.forceLoadAll = _options.fullyLoadArchives(); | |
282 | archOpts.forceLoadObjC = _options.loadAllObjcObjectsFromArchives(); | |
283 | archOpts.objcABI2 = _options.objCABIVersion2POverride(); | |
284 | archOpts.verboseLoad = _options.whyLoad(); | |
285 | archOpts.logAllFiles = _options.logAllFiles(); | |
286 | ld::archive::File* archiveResult = ::archive::parse(p, len, info.path, info.modTime, _nextInputOrdinal, archOpts); | |
287 | if ( archiveResult != NULL ) { | |
288 | // <rdar://problem/9740166> force loaded archives should be in LD_TRACE | |
289 | if ( (info.options.fForceLoad || _options.fullyLoadArchives()) && _options.traceArchives() ) | |
290 | logArchive(archiveResult); | |
291 | return this->addArchive(archiveResult, info, len); | |
292 | } | |
293 | ||
294 | // does not seem to be any valid linker input file, check LTO misconfiguration problems | |
295 | if ( lto::archName((uint8_t*)p, len) != NULL ) { | |
296 | if ( lto::libLTOisLoaded() ) { | |
297 | throwf("file was built for %s which is not the architecture being linked (%s)", fileArch(p, len), _options.architectureName()); | |
298 | } | |
299 | else { | |
300 | const char* libLTO = "libLTO.dylib"; | |
301 | char ldPath[PATH_MAX]; | |
302 | char tmpPath[PATH_MAX]; | |
303 | char libLTOPath[PATH_MAX]; | |
304 | uint32_t bufSize = PATH_MAX; | |
305 | if ( _NSGetExecutablePath(ldPath, &bufSize) != -1 ) { | |
306 | if ( realpath(ldPath, tmpPath) != NULL ) { | |
307 | char* lastSlash = strrchr(tmpPath, '/'); | |
308 | if ( lastSlash != NULL ) | |
309 | strcpy(lastSlash, "/../lib/libLTO.dylib"); | |
310 | libLTO = tmpPath; | |
311 | if ( realpath(tmpPath, libLTOPath) != NULL ) | |
312 | libLTO = libLTOPath; | |
313 | } | |
314 | } | |
315 | throwf("could not process llvm bitcode object file, because %s could not be loaded", libLTO); | |
316 | } | |
317 | } | |
318 | ||
319 | // error handling | |
320 | if ( ((fat_header*)p)->magic == OSSwapBigToHostInt32(FAT_MAGIC) ) { | |
321 | throwf("missing required architecture %s in file", _options.architectureName()); | |
322 | } | |
323 | else { | |
324 | if ( isFatFile ) | |
325 | throwf("file is universal but does not contain a(n) %s slice", _options.architectureName()); | |
326 | else | |
327 | throwf("file was built for %s which is not the architecture being linked (%s)", fileArch(p, len), _options.architectureName()); | |
328 | } | |
329 | } | |
330 | ||
331 | void InputFiles::logDylib(ld::File* file, bool indirect) | |
332 | { | |
333 | if ( _options.traceDylibs() ) { | |
334 | const char* fullPath = file->path(); | |
335 | char realName[MAXPATHLEN]; | |
336 | if ( realpath(fullPath, realName) != NULL ) | |
337 | fullPath = realName; | |
338 | const ld::dylib::File* dylib = dynamic_cast<const ld::dylib::File*>(file); | |
339 | if ( (dylib != NULL ) && dylib->willBeUpwardDylib() ) { | |
340 | // don't log upward dylibs when XBS is computing dependencies | |
341 | logTraceInfo("[Logging for XBS] Used upward dynamic library: %s\n", fullPath); | |
342 | } | |
343 | else { | |
344 | if ( indirect ) | |
345 | logTraceInfo("[Logging for XBS] Used indirect dynamic library: %s\n", fullPath); | |
346 | else | |
347 | logTraceInfo("[Logging for XBS] Used dynamic library: %s\n", fullPath); | |
348 | } | |
349 | } | |
350 | } | |
351 | ||
352 | void InputFiles::logArchive(ld::File* file) const | |
353 | { | |
354 | if ( _options.traceArchives() && (_archiveFilesLogged.count(file) == 0) ) { | |
355 | // <rdar://problem/4947347> LD_TRACE_ARCHIVES should only print out when a .o is actually used from an archive | |
356 | _archiveFilesLogged.insert(file); | |
357 | const char* fullPath = file->path(); | |
358 | char realName[MAXPATHLEN]; | |
359 | if ( realpath(fullPath, realName) != NULL ) | |
360 | fullPath = realName; | |
361 | logTraceInfo("[Logging for XBS] Used static archive: %s\n", fullPath); | |
362 | } | |
363 | } | |
364 | ||
365 | ||
366 | void InputFiles::logTraceInfo(const char* format, ...) const | |
367 | { | |
368 | // one time open() of custom LD_TRACE_FILE | |
369 | static int trace_file = -1; | |
370 | if ( trace_file == -1 ) { | |
371 | const char *trace_file_path = _options.traceOutputFile(); | |
372 | if ( trace_file_path != NULL ) { | |
373 | trace_file = open(trace_file_path, O_WRONLY | O_APPEND | O_CREAT, 0666); | |
374 | if ( trace_file == -1 ) | |
375 | throwf("Could not open or create trace file: %s", trace_file_path); | |
376 | } | |
377 | else { | |
378 | trace_file = fileno(stderr); | |
379 | } | |
380 | } | |
381 | ||
382 | char trace_buffer[MAXPATHLEN * 2]; | |
383 | va_list ap; | |
384 | va_start(ap, format); | |
385 | int length = vsnprintf(trace_buffer, sizeof(trace_buffer), format, ap); | |
386 | va_end(ap); | |
387 | char* buffer_ptr = trace_buffer; | |
388 | ||
389 | while (length > 0) { | |
390 | ssize_t amount_written = write(trace_file, buffer_ptr, length); | |
391 | if(amount_written == -1) | |
392 | /* Failure to write shouldn't fail the build. */ | |
393 | return; | |
394 | buffer_ptr += amount_written; | |
395 | length -= amount_written; | |
396 | } | |
397 | } | |
398 | ||
399 | ld::dylib::File* InputFiles::findDylib(const char* installPath, const char* fromPath) | |
400 | { | |
401 | //fprintf(stderr, "findDylib(%s, %s)\n", installPath, fromPath); | |
402 | InstallNameToDylib::iterator pos = _installPathToDylibs.find(installPath); | |
403 | if ( pos != _installPathToDylibs.end() ) { | |
404 | return pos->second; | |
405 | } | |
406 | else { | |
407 | // allow -dylib_path option to override indirect library to use | |
408 | for (std::vector<Options::DylibOverride>::const_iterator dit = _options.dylibOverrides().begin(); dit != _options.dylibOverrides().end(); ++dit) { | |
409 | if ( strcmp(dit->installName,installPath) == 0 ) { | |
410 | try { | |
411 | Options::FileInfo info = _options.findFile(dit->useInstead); | |
412 | ld::File* reader = this->makeFile(info, true); | |
413 | ld::dylib::File* dylibReader = dynamic_cast<ld::dylib::File*>(reader); | |
414 | if ( dylibReader != NULL ) { | |
415 | //_installPathToDylibs[strdup(installPath)] = dylibReader; | |
416 | this->logDylib(dylibReader, true); | |
417 | return dylibReader; | |
418 | } | |
419 | else | |
420 | throwf("indirect dylib at %s is not a dylib", dit->useInstead); | |
421 | } | |
422 | catch (const char* msg) { | |
423 | warning("ignoring -dylib_file option, %s", msg); | |
424 | } | |
425 | } | |
426 | } | |
427 | char newPath[MAXPATHLEN]; | |
428 | // handle @loader_path | |
429 | if ( strncmp(installPath, "@loader_path/", 13) == 0 ) { | |
430 | strcpy(newPath, fromPath); | |
431 | char* addPoint = strrchr(newPath,'/'); | |
432 | if ( addPoint != NULL ) | |
433 | strcpy(&addPoint[1], &installPath[13]); | |
434 | else | |
435 | strcpy(newPath, &installPath[13]); | |
436 | installPath = newPath; | |
437 | } | |
438 | // note: @executable_path case is handled inside findFileUsingPaths() | |
439 | // search for dylib using -F and -L paths | |
440 | Options::FileInfo info = _options.findFileUsingPaths(installPath); | |
441 | try { | |
442 | ld::File* reader = this->makeFile(info, true); | |
443 | ld::dylib::File* dylibReader = dynamic_cast<ld::dylib::File*>(reader); | |
444 | if ( dylibReader != NULL ) { | |
445 | //assert(_installPathToDylibs.find(installPath) != _installPathToDylibs.end()); | |
446 | //_installPathToDylibs[strdup(installPath)] = dylibReader; | |
447 | this->logDylib(dylibReader, true); | |
448 | return dylibReader; | |
449 | } | |
450 | else | |
451 | throwf("indirect dylib at %s is not a dylib", info.path); | |
452 | } | |
453 | catch (const char* msg) { | |
454 | throwf("in %s, %s", info.path, msg); | |
455 | } | |
456 | } | |
457 | } | |
458 | ||
459 | ||
460 | ||
461 | void InputFiles::createIndirectDylibs() | |
462 | { | |
463 | _allDirectDylibsLoaded = true; | |
464 | ||
465 | // mark all dylibs initially specified as required and check if they can be used | |
466 | for (InstallNameToDylib::iterator it=_installPathToDylibs.begin(); it != _installPathToDylibs.end(); it++) { | |
467 | it->second->setExplicitlyLinked(); | |
468 | this->checkDylibClientRestrictions(it->second); | |
469 | } | |
470 | ||
471 | // keep processing dylibs until no more dylibs are added | |
472 | unsigned long lastMapSize = 0; | |
473 | std::set<ld::dylib::File*> dylibsProcessed; | |
474 | while ( lastMapSize != _allDylibs.size() ) { | |
475 | lastMapSize = _allDylibs.size(); | |
476 | // can't iterator _installPathToDylibs while modifying it, so use temp buffer | |
477 | std::vector<ld::dylib::File*> unprocessedDylibs; | |
478 | for (std::set<ld::dylib::File*>::iterator it=_allDylibs.begin(); it != _allDylibs.end(); it++) { | |
479 | if ( dylibsProcessed.count(*it) == 0 ) | |
480 | unprocessedDylibs.push_back(*it); | |
481 | } | |
482 | for (std::vector<ld::dylib::File*>::iterator it=unprocessedDylibs.begin(); it != unprocessedDylibs.end(); it++) { | |
483 | dylibsProcessed.insert(*it); | |
484 | (*it)->processIndirectLibraries(this, _options.implicitlyLinkIndirectPublicDylibs()); | |
485 | } | |
486 | } | |
487 | ||
488 | // go back over original dylibs and mark sub frameworks as re-exported | |
489 | if ( _options.outputKind() == Options::kDynamicLibrary ) { | |
490 | const char* myLeaf = strrchr(_options.installPath(), '/'); | |
491 | if ( myLeaf != NULL ) { | |
492 | for (std::vector<class ld::File*>::const_iterator it=_inputFiles.begin(); it != _inputFiles.end(); it++) { | |
493 | ld::dylib::File* dylibReader = dynamic_cast<ld::dylib::File*>(*it); | |
494 | if ( dylibReader != NULL ) { | |
495 | const char* childParent = dylibReader->parentUmbrella(); | |
496 | if ( childParent != NULL ) { | |
497 | if ( strcmp(childParent, &myLeaf[1]) == 0 ) { | |
498 | // mark that this dylib will be re-exported | |
499 | dylibReader->setWillBeReExported(); | |
500 | } | |
501 | } | |
502 | } | |
503 | } | |
504 | } | |
505 | } | |
506 | ||
507 | } | |
508 | ||
509 | void InputFiles::createOpaqueFileSections() | |
510 | { | |
511 | // extra command line section always at end | |
512 | for (Options::ExtraSection::const_iterator it=_options.extraSectionsBegin(); it != _options.extraSectionsEnd(); ++it) { | |
513 | _inputFiles.push_back(opaque_section::parse(it->segmentName, it->sectionName, it->path, it->data, | |
514 | it->dataLen, _nextInputOrdinal)); | |
515 | // bump ordinal | |
516 | _nextInputOrdinal++; | |
517 | } | |
518 | ||
519 | } | |
520 | ||
521 | ||
522 | void InputFiles::checkDylibClientRestrictions(ld::dylib::File* dylib) | |
523 | { | |
524 | // Check for any restrictions on who can link with this dylib | |
525 | const char* dylibParentName = dylib->parentUmbrella() ; | |
526 | const std::vector<const char*>* clients = dylib->allowableClients(); | |
527 | if ( (dylibParentName != NULL) || (clients != NULL) ) { | |
528 | // only dylibs that are in an umbrella or have a client list need verification | |
529 | const char* installName = _options.installPath(); | |
530 | const char* installNameLastSlash = strrchr(installName, '/'); | |
531 | bool isParent = false; | |
532 | bool isSibling = false; | |
533 | bool isAllowableClient = false; | |
534 | // There are three cases: | |
535 | if ( (dylibParentName != NULL) && (installNameLastSlash != NULL) ) { | |
536 | // starts after last slash | |
537 | const char* myName = &installNameLastSlash[1]; | |
538 | unsigned int myNameLen = strlen(myName); | |
539 | if ( strncmp(myName, "lib", 3) == 0 ) | |
540 | myName = &myName[3]; | |
541 | // up to first dot | |
542 | const char* firstDot = strchr(myName, '.'); | |
543 | if ( firstDot != NULL ) | |
544 | myNameLen = firstDot - myName; | |
545 | // up to first underscore | |
546 | const char* firstUnderscore = strchr(myName, '_'); | |
547 | if ( (firstUnderscore != NULL) && ((firstUnderscore - myName) < (int)myNameLen) ) | |
548 | myNameLen = firstUnderscore - myName; | |
549 | ||
550 | // case 1) The dylib has a parent umbrella, and we are creating the parent umbrella | |
551 | isParent = ( (strlen(dylibParentName) == myNameLen) && (strncmp(myName, dylibParentName, myNameLen) == 0) ); | |
552 | ||
553 | // case 2) The dylib has a parent umbrella, and we are creating a sibling with the same parent | |
554 | isSibling = ( (_options.umbrellaName() != NULL) && (strcmp(_options.umbrellaName(), dylibParentName) == 0) ); | |
555 | } | |
556 | ||
557 | if ( !isParent && !isSibling && (clients != NULL) ) { | |
558 | // case 3) the dylib has a list of allowable clients, and we are creating one of them | |
559 | const char* clientName = _options.clientName(); | |
560 | int clientNameLen = 0; | |
561 | if ( clientName != NULL ) { | |
562 | // use client name as specified on command line | |
563 | clientNameLen = strlen(clientName); | |
564 | } | |
565 | else { | |
566 | // infer client name from output path (e.g. xxx/libfoo_variant.A.dylib --> foo, Bar.framework/Bar_variant --> Bar) | |
567 | clientName = installName; | |
568 | clientNameLen = strlen(clientName); | |
569 | // starts after last slash | |
570 | if ( installNameLastSlash != NULL ) | |
571 | clientName = &installNameLastSlash[1]; | |
572 | if ( strncmp(clientName, "lib", 3) == 0 ) | |
573 | clientName = &clientName[3]; | |
574 | // up to first dot | |
575 | const char* firstDot = strchr(clientName, '.'); | |
576 | if ( firstDot != NULL ) | |
577 | clientNameLen = firstDot - clientName; | |
578 | // up to first underscore | |
579 | const char* firstUnderscore = strchr(clientName, '_'); | |
580 | if ( (firstUnderscore != NULL) && ((firstUnderscore - clientName) < clientNameLen) ) | |
581 | clientNameLen = firstUnderscore - clientName; | |
582 | } | |
583 | ||
584 | // Use clientName to check if this dylib is able to link against the allowable clients. | |
585 | for (std::vector<const char*>::const_iterator it = clients->begin(); it != clients->end(); it++) { | |
586 | if ( strncmp(*it, clientName, clientNameLen) == 0 ) | |
587 | isAllowableClient = true; | |
588 | } | |
589 | } | |
590 | ||
591 | if ( !isParent && !isSibling && !isAllowableClient ) { | |
592 | if ( dylibParentName != NULL ) { | |
593 | throwf("cannot link directly with %s. Link against the umbrella framework '%s.framework' instead.", | |
594 | dylib->path(), dylibParentName); | |
595 | } | |
596 | else { | |
597 | throwf("cannot link directly with %s", dylib->path()); | |
598 | } | |
599 | } | |
600 | } | |
601 | } | |
602 | ||
603 | ||
604 | void InputFiles::inferArchitecture(Options& opts, const char** archName) | |
605 | { | |
606 | _inferredArch = true; | |
607 | // scan all input files, looking for a thin .o file. | |
608 | // the first one found is presumably the architecture to link | |
609 | uint8_t buffer[sizeof(mach_header_64)]; | |
610 | const std::vector<Options::FileInfo>& files = opts.getInputFiles(); | |
611 | for (std::vector<Options::FileInfo>::const_iterator it = files.begin(); it != files.end(); ++it) { | |
612 | int fd = ::open(it->path, O_RDONLY, 0); | |
613 | if ( fd != -1 ) { | |
614 | ssize_t amount = read(fd, buffer, sizeof(buffer)); | |
615 | ::close(fd); | |
616 | if ( amount >= (ssize_t)sizeof(buffer) ) { | |
617 | cpu_type_t type; | |
618 | cpu_subtype_t subtype; | |
619 | if ( mach_o::relocatable::isObjectFile(buffer, &type, &subtype) ) { | |
620 | opts.setArchitecture(type, subtype); | |
621 | *archName = opts.architectureName(); | |
622 | return; | |
623 | } | |
624 | } | |
625 | } | |
626 | } | |
627 | ||
628 | // no thin .o files found, so default to same architecture this tool was built as | |
629 | warning("-arch not specified"); | |
630 | #if __i386__ | |
631 | opts.setArchitecture(CPU_TYPE_I386, CPU_SUBTYPE_X86_ALL); | |
632 | #elif __x86_64__ | |
633 | opts.setArchitecture(CPU_TYPE_X86_64, CPU_SUBTYPE_X86_64_ALL); | |
634 | #elif __arm__ | |
635 | opts.setArchitecture(CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V6); | |
636 | #else | |
637 | #error unknown default architecture | |
638 | #endif | |
639 | *archName = opts.architectureName(); | |
640 | } | |
641 | ||
642 | ||
643 | InputFiles::InputFiles(Options& opts, const char** archName) | |
644 | : _totalObjectSize(0), _totalArchiveSize(0), | |
645 | _totalObjectLoaded(0), _totalArchivesLoaded(0), _totalDylibsLoaded(0), | |
646 | _options(opts), _bundleLoader(NULL), _nextInputOrdinal(1), | |
647 | _allDirectDylibsLoaded(false), _inferredArch(false) | |
648 | { | |
649 | // fStartCreateReadersTime = mach_absolute_time(); | |
650 | if ( opts.architecture() == 0 ) { | |
651 | // command line missing -arch, so guess arch | |
652 | inferArchitecture(opts, archName); | |
653 | } | |
654 | ||
655 | const std::vector<Options::FileInfo>& files = opts.getInputFiles(); | |
656 | if ( files.size() == 0 ) | |
657 | throw "no object files specified"; | |
658 | // add all direct object, archives, and dylibs | |
659 | _inputFiles.reserve(files.size()); | |
660 | for (std::vector<Options::FileInfo>::const_iterator it = files.begin(); it != files.end(); ++it) { | |
661 | const Options::FileInfo& entry = *it; | |
662 | try { | |
663 | _inputFiles.push_back(this->makeFile(entry, false)); | |
664 | } | |
665 | catch (const char* msg) { | |
666 | if ( (strstr(msg, "architecture") != NULL) && !_options.errorOnOtherArchFiles() ) { | |
667 | if ( opts.ignoreOtherArchInputFiles() ) { | |
668 | // ignore, because this is about an architecture not in use | |
669 | } | |
670 | else { | |
671 | warning("ignoring file %s, %s", entry.path, msg); | |
672 | } | |
673 | } | |
674 | else { | |
675 | throwf("in %s, %s", entry.path, msg); | |
676 | } | |
677 | } | |
678 | } | |
679 | ||
680 | this->createIndirectDylibs(); | |
681 | this->createOpaqueFileSections(); | |
682 | } | |
683 | ||
684 | ||
685 | ||
686 | ld::File* InputFiles::addArchive(ld::File* reader, const Options::FileInfo& info, uint64_t mappedLen) | |
687 | { | |
688 | // bump ordinal | |
689 | _nextInputOrdinal += reader->subFileCount(); | |
690 | ||
691 | // update stats | |
692 | _totalArchiveSize += mappedLen; | |
693 | _totalArchivesLoaded++; | |
694 | return reader; | |
695 | } | |
696 | ||
697 | ||
698 | ld::File* InputFiles::addObject(ld::relocatable::File* file, const Options::FileInfo& info, uint64_t mappedLen) | |
699 | { | |
700 | // bump ordinal | |
701 | _nextInputOrdinal++; | |
702 | ||
703 | // update stats | |
704 | _totalObjectSize += mappedLen; | |
705 | _totalObjectLoaded++; | |
706 | return file; | |
707 | } | |
708 | ||
709 | ||
710 | ld::File* InputFiles::addDylib(ld::dylib::File* reader, const Options::FileInfo& info, uint64_t mappedLen) | |
711 | { | |
712 | _allDylibs.insert(reader); | |
713 | ||
714 | if ( (reader->installPath() == NULL) && !info.options.fBundleLoader ) { | |
715 | // this is a "blank" stub | |
716 | // silently ignore it | |
717 | return reader; | |
718 | } | |
719 | // store options about how dylib will be used in dylib itself | |
720 | if ( info.options.fWeakImport ) | |
721 | reader->setForcedWeakLinked(); | |
722 | if ( info.options.fReExport ) | |
723 | reader->setWillBeReExported(); | |
724 | if ( info.options.fUpward ) { | |
725 | if ( _options.outputKind() == Options::kDynamicLibrary ) | |
726 | reader->setWillBeUpwardDylib(); | |
727 | else | |
728 | warning("ignoring upward dylib option for %s\n", info.path); | |
729 | } | |
730 | if ( info.options.fLazyLoad ) | |
731 | reader->setWillBeLazyLoadedDylb(); | |
732 | ||
733 | // add to map of loaded dylibs | |
734 | const char* installPath = reader->installPath(); | |
735 | if ( installPath != NULL ) { | |
736 | InstallNameToDylib::iterator pos = _installPathToDylibs.find(installPath); | |
737 | if ( pos == _installPathToDylibs.end() ) { | |
738 | _installPathToDylibs[strdup(installPath)] = reader; | |
739 | } | |
740 | else { | |
741 | bool dylibOnCommandLineTwice = ( strcmp(pos->second->path(), reader->path()) == 0 ); | |
742 | bool isSymlink = false; | |
743 | // ignore if this is a symlink to a dylib we've already loaded | |
744 | if ( !dylibOnCommandLineTwice ) { | |
745 | char existingDylibPath[PATH_MAX]; | |
746 | if ( realpath(pos->second->path(), existingDylibPath) != NULL ) { | |
747 | char newDylibPath[PATH_MAX]; | |
748 | if ( realpath(reader->path(), newDylibPath) != NULL ) { | |
749 | isSymlink = ( strcmp(existingDylibPath, newDylibPath) == 0 ); | |
750 | } | |
751 | } | |
752 | } | |
753 | if ( !dylibOnCommandLineTwice && !isSymlink ) | |
754 | warning("dylibs with same install name: %s and %s", pos->second->path(), reader->path()); | |
755 | } | |
756 | } | |
757 | else if ( info.options.fBundleLoader ) | |
758 | _bundleLoader = reader; | |
759 | ||
760 | // log direct readers | |
761 | if ( !_allDirectDylibsLoaded ) | |
762 | this->logDylib(reader, false); | |
763 | ||
764 | // bump ordinal | |
765 | _nextInputOrdinal++; | |
766 | ||
767 | // update stats | |
768 | _totalDylibsLoaded++; | |
769 | ||
770 | return reader; | |
771 | } | |
772 | ||
773 | ||
774 | bool InputFiles::forEachInitialAtom(ld::File::AtomHandler& handler) const | |
775 | { | |
776 | bool didSomething = false; | |
777 | for (std::vector<ld::File*>::const_iterator it=_inputFiles.begin(); it != _inputFiles.end(); ++it) { | |
778 | didSomething |= (*it)->forEachAtom(handler); | |
779 | } | |
780 | if ( didSomething || true ) { | |
781 | switch ( _options.outputKind() ) { | |
782 | case Options::kStaticExecutable: | |
783 | case Options::kDynamicExecutable: | |
784 | // add implicit __dso_handle label | |
785 | handler.doAtom(DSOHandleAtom::_s_atomExecutable); | |
786 | handler.doAtom(DSOHandleAtom::_s_atomAll); | |
787 | if ( _options.pageZeroSize() != 0 ) | |
788 | handler.doAtom(*new PageZeroAtom(_options.pageZeroSize())); | |
789 | if ( _options.hasCustomStack() ) | |
790 | handler.doAtom(*new CustomStackAtom(_options.customStackSize())); | |
791 | break; | |
792 | case Options::kDynamicLibrary: | |
793 | // add implicit __dso_handle label | |
794 | handler.doAtom(DSOHandleAtom::_s_atomDylib); | |
795 | handler.doAtom(DSOHandleAtom::_s_atomAll); | |
796 | break; | |
797 | case Options::kDynamicBundle: | |
798 | // add implicit __dso_handle label | |
799 | handler.doAtom(DSOHandleAtom::_s_atomBundle); | |
800 | handler.doAtom(DSOHandleAtom::_s_atomAll); | |
801 | break; | |
802 | case Options::kDyld: | |
803 | // add implicit __dso_handle label | |
804 | handler.doAtom(DSOHandleAtom::_s_atomDyld); | |
805 | handler.doAtom(DSOHandleAtom::_s_atomAll); | |
806 | break; | |
807 | case Options::kPreload: | |
808 | // add implicit __mh_preload_header label | |
809 | handler.doAtom(DSOHandleAtom::_s_atomPreload); | |
810 | handler.doAtom(DSOHandleAtom::_s_atomAll); | |
811 | break; | |
812 | case Options::kObjectFile: | |
813 | handler.doAtom(DSOHandleAtom::_s_atomObjectFile); | |
814 | break; | |
815 | case Options::kKextBundle: | |
816 | // add implicit __dso_handle label | |
817 | handler.doAtom(DSOHandleAtom::_s_atomAll); | |
818 | break; | |
819 | } | |
820 | } | |
821 | return didSomething; | |
822 | } | |
823 | ||
824 | ||
825 | bool InputFiles::searchLibraries(const char* name, bool searchDylibs, bool searchArchives, bool dataSymbolOnly, ld::File::AtomHandler& handler) const | |
826 | { | |
827 | // check each input file | |
828 | for (std::vector<ld::File*>::const_iterator it=_inputFiles.begin(); it != _inputFiles.end(); ++it) { | |
829 | ld::File* file = *it; | |
830 | // if this reader is a static archive that has the symbol we need, pull in all atoms in that module | |
831 | // if this reader is a dylib that exports the symbol we need, have it synthesize an atom for us. | |
832 | ld::dylib::File* dylibFile = dynamic_cast<ld::dylib::File*>(file); | |
833 | ld::archive::File* archiveFile = dynamic_cast<ld::archive::File*>(file); | |
834 | if ( searchDylibs && (dylibFile != NULL) ) { | |
835 | //fprintf(stderr, "searchLibraries(%s), looking in linked %s\n", name, dylibFile->path() ); | |
836 | if ( dylibFile->justInTimeforEachAtom(name, handler) ) { | |
837 | // we found a definition in this dylib | |
838 | // done, unless it is a weak definition in which case we keep searching | |
839 | if ( !dylibFile->hasWeakExternals() || !dylibFile->hasWeakDefinition(name)) | |
840 | return true; | |
841 | // else continue search for a non-weak definition | |
842 | } | |
843 | } | |
844 | else if ( searchArchives && (archiveFile != NULL) ) { | |
845 | if ( dataSymbolOnly ) { | |
846 | if ( archiveFile->justInTimeDataOnlyforEachAtom(name, handler) ) { | |
847 | if ( _options.traceArchives() ) | |
848 | logArchive(file); | |
849 | // found data definition in static library, done | |
850 | return true; | |
851 | } | |
852 | } | |
853 | else { | |
854 | if ( archiveFile->justInTimeforEachAtom(name, handler) ) { | |
855 | if ( _options.traceArchives() ) | |
856 | logArchive(file); | |
857 | // found definition in static library, done | |
858 | return true; | |
859 | } | |
860 | } | |
861 | } | |
862 | } | |
863 | ||
864 | // search indirect dylibs | |
865 | if ( searchDylibs ) { | |
866 | for (InstallNameToDylib::const_iterator it=_installPathToDylibs.begin(); it != _installPathToDylibs.end(); ++it) { | |
867 | ld::dylib::File* dylibFile = it->second; | |
868 | bool searchThisDylib = false; | |
869 | if ( _options.nameSpace() == Options::kTwoLevelNameSpace ) { | |
870 | // for two level namesapce, just check all implicitly linked dylibs | |
871 | searchThisDylib = dylibFile->implicitlyLinked() && !dylibFile->explicitlyLinked(); | |
872 | } | |
873 | else { | |
874 | // for flat namespace, check all indirect dylibs | |
875 | searchThisDylib = ! dylibFile->explicitlyLinked(); | |
876 | } | |
877 | if ( searchThisDylib ) { | |
878 | //fprintf(stderr, "searchLibraries(%s), looking in implicitly linked %s\n", name, dylibFile->path() ); | |
879 | if ( dylibFile->justInTimeforEachAtom(name, handler) ) { | |
880 | // we found a definition in this dylib | |
881 | // done, unless it is a weak definition in which case we keep searching | |
882 | if ( !dylibFile->hasWeakExternals() || !dylibFile->hasWeakDefinition(name)) | |
883 | return true; | |
884 | // else continue search for a non-weak definition | |
885 | } | |
886 | } | |
887 | } | |
888 | } | |
889 | ||
890 | return false; | |
891 | } | |
892 | ||
893 | ||
894 | bool InputFiles::searchWeakDefInDylib(const char* name) const | |
895 | { | |
896 | // search all relevant dylibs to see if any of a weak-def with this name | |
897 | for (InstallNameToDylib::const_iterator it=_installPathToDylibs.begin(); it != _installPathToDylibs.end(); ++it) { | |
898 | ld::dylib::File* dylibFile = it->second; | |
899 | if ( dylibFile->implicitlyLinked() || dylibFile->explicitlyLinked() ) { | |
900 | if ( dylibFile->hasWeakExternals() && dylibFile->hasWeakDefinition(name) ) { | |
901 | return true; | |
902 | } | |
903 | } | |
904 | } | |
905 | return false; | |
906 | } | |
907 | ||
908 | void InputFiles::dylibs(ld::Internal& state) | |
909 | { | |
910 | bool dylibsOK = false; | |
911 | switch ( _options.outputKind() ) { | |
912 | case Options::kDynamicExecutable: | |
913 | case Options::kDynamicLibrary: | |
914 | case Options::kDynamicBundle: | |
915 | dylibsOK = true; | |
916 | break; | |
917 | case Options::kStaticExecutable: | |
918 | case Options::kDyld: | |
919 | case Options::kPreload: | |
920 | case Options::kObjectFile: | |
921 | case Options::kKextBundle: | |
922 | dylibsOK = false; | |
923 | break; | |
924 | } | |
925 | ||
926 | // add command line dylibs in order | |
927 | for (std::vector<ld::File*>::const_iterator it=_inputFiles.begin(); it != _inputFiles.end(); ++it) { | |
928 | ld::dylib::File* dylibFile = dynamic_cast<ld::dylib::File*>(*it); | |
929 | // only add dylibs that are not "blank" dylib stubs | |
930 | if ( (dylibFile != NULL) && ((dylibFile->installPath() != NULL) || (dylibFile == _bundleLoader)) ) { | |
931 | if ( dylibsOK ) | |
932 | state.dylibs.push_back(dylibFile); | |
933 | else | |
934 | warning("unexpected dylib (%s) on link line", dylibFile->path()); | |
935 | } | |
936 | } | |
937 | // add implicitly linked dylibs | |
938 | if ( _options.nameSpace() == Options::kTwoLevelNameSpace ) { | |
939 | for (InstallNameToDylib::const_iterator it=_installPathToDylibs.begin(); it != _installPathToDylibs.end(); ++it) { | |
940 | ld::dylib::File* dylibFile = it->second; | |
941 | if ( dylibFile->implicitlyLinked() && dylibsOK ) | |
942 | state.dylibs.push_back(dylibFile); | |
943 | } | |
944 | } | |
945 | // and -bundle_loader | |
946 | state.bundleLoader = _bundleLoader; | |
947 | } | |
948 | ||
949 | ||
950 | } // namespace tool | |
951 | } // namespace ld | |
952 |