]>
Commit | Line | Data |
---|---|---|
a645023d A |
1 | /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-* |
2 | * | |
3 | * Copyright (c) 2009-2010 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) | |
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.preferSubArchitecture(); | |
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); | |
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.verboseLoad = _options.whyLoad(); | |
284 | archOpts.logAllFiles = _options.logAllFiles(); | |
285 | ld::File* archiveResult = archive::parse(p, len, info.path, info.modTime, _nextInputOrdinal, archOpts); | |
286 | if ( archiveResult != NULL ) | |
287 | return this->addArchive(archiveResult, info, len); | |
288 | ||
289 | // does not seem to be any valid linker input file, check LTO misconfiguration problems | |
290 | if ( lto::archName((uint8_t*)p, len) != NULL ) { | |
291 | if ( lto::libLTOisLoaded() ) { | |
292 | throwf("file was built for %s which is not the architecture being linked (%s)", fileArch(p, len), _options.architectureName()); | |
293 | } | |
294 | else { | |
295 | const char* libLTO = "libLTO.dylib"; | |
296 | char ldPath[PATH_MAX]; | |
297 | char tmpPath[PATH_MAX]; | |
298 | char libLTOPath[PATH_MAX]; | |
299 | uint32_t bufSize = PATH_MAX; | |
300 | if ( _NSGetExecutablePath(ldPath, &bufSize) != -1 ) { | |
301 | if ( realpath(ldPath, tmpPath) != NULL ) { | |
302 | char* lastSlash = strrchr(tmpPath, '/'); | |
303 | if ( lastSlash != NULL ) | |
304 | strcpy(lastSlash, "/../lib/libLTO.dylib"); | |
305 | libLTO = tmpPath; | |
306 | if ( realpath(tmpPath, libLTOPath) != NULL ) | |
307 | libLTO = libLTOPath; | |
308 | } | |
309 | } | |
310 | throwf("could not process llvm bitcode object file, because %s could not be loaded", libLTO); | |
311 | } | |
312 | } | |
313 | ||
314 | // error handling | |
315 | if ( ((fat_header*)p)->magic == OSSwapBigToHostInt32(FAT_MAGIC) ) { | |
316 | throwf("missing required architecture %s in file", _options.architectureName()); | |
317 | } | |
318 | else { | |
319 | if ( isFatFile ) | |
320 | throwf("file is universal but does not contain a(n) %s slice", _options.architectureName()); | |
321 | else | |
322 | throwf("file was built for %s which is not the architecture being linked (%s)", fileArch(p, len), _options.architectureName()); | |
323 | } | |
324 | } | |
325 | ||
326 | void InputFiles::logDylib(ld::File* file, bool indirect) | |
327 | { | |
328 | if ( _options.traceDylibs() ) { | |
329 | const char* fullPath = file->path(); | |
330 | char realName[MAXPATHLEN]; | |
331 | if ( realpath(fullPath, realName) != NULL ) | |
332 | fullPath = realName; | |
333 | const ld::dylib::File* dylib = dynamic_cast<const ld::dylib::File*>(file); | |
334 | if ( (dylib != NULL ) && dylib->willBeUpwardDylib() ) { | |
335 | // don't log upward dylibs when XBS is computing dependencies | |
336 | logTraceInfo("[Logging for XBS] Used upward dynamic library: %s\n", fullPath); | |
337 | } | |
338 | else { | |
339 | if ( indirect ) | |
340 | logTraceInfo("[Logging for XBS] Used indirect dynamic library: %s\n", fullPath); | |
341 | else | |
342 | logTraceInfo("[Logging for XBS] Used dynamic library: %s\n", fullPath); | |
343 | } | |
344 | } | |
345 | } | |
346 | ||
347 | void InputFiles::logArchive(ld::File* file) const | |
348 | { | |
349 | if ( _options.traceArchives() && (_archiveFilesLogged.count(file) == 0) ) { | |
350 | // <rdar://problem/4947347> LD_TRACE_ARCHIVES should only print out when a .o is actually used from an archive | |
351 | _archiveFilesLogged.insert(file); | |
352 | const char* fullPath = file->path(); | |
353 | char realName[MAXPATHLEN]; | |
354 | if ( realpath(fullPath, realName) != NULL ) | |
355 | fullPath = realName; | |
356 | logTraceInfo("[Logging for XBS] Used static archive: %s\n", fullPath); | |
357 | } | |
358 | } | |
359 | ||
360 | ||
361 | void InputFiles::logTraceInfo(const char* format, ...) const | |
362 | { | |
363 | // one time open() of custom LD_TRACE_FILE | |
364 | static int trace_file = -1; | |
365 | if ( trace_file == -1 ) { | |
366 | const char *trace_file_path = _options.traceOutputFile(); | |
367 | if ( trace_file_path != NULL ) { | |
368 | trace_file = open(trace_file_path, O_WRONLY | O_APPEND | O_CREAT, 0666); | |
369 | if ( trace_file == -1 ) | |
370 | throwf("Could not open or create trace file: %s", trace_file_path); | |
371 | } | |
372 | else { | |
373 | trace_file = fileno(stderr); | |
374 | } | |
375 | } | |
376 | ||
377 | char trace_buffer[MAXPATHLEN * 2]; | |
378 | va_list ap; | |
379 | va_start(ap, format); | |
380 | int length = vsnprintf(trace_buffer, sizeof(trace_buffer), format, ap); | |
381 | va_end(ap); | |
382 | char* buffer_ptr = trace_buffer; | |
383 | ||
384 | while (length > 0) { | |
385 | ssize_t amount_written = write(trace_file, buffer_ptr, length); | |
386 | if(amount_written == -1) | |
387 | /* Failure to write shouldn't fail the build. */ | |
388 | return; | |
389 | buffer_ptr += amount_written; | |
390 | length -= amount_written; | |
391 | } | |
392 | } | |
393 | ||
394 | ld::dylib::File* InputFiles::findDylib(const char* installPath, const char* fromPath) | |
395 | { | |
396 | //fprintf(stderr, "findDylib(%s, %s)\n", installPath, fromPath); | |
397 | InstallNameToDylib::iterator pos = _installPathToDylibs.find(installPath); | |
398 | if ( pos != _installPathToDylibs.end() ) { | |
399 | return pos->second; | |
400 | } | |
401 | else { | |
402 | // allow -dylib_path option to override indirect library to use | |
403 | for (std::vector<Options::DylibOverride>::const_iterator dit = _options.dylibOverrides().begin(); dit != _options.dylibOverrides().end(); ++dit) { | |
404 | if ( strcmp(dit->installName,installPath) == 0 ) { | |
405 | try { | |
406 | Options::FileInfo info = _options.findFile(dit->useInstead); | |
407 | ld::File* reader = this->makeFile(info); | |
408 | ld::dylib::File* dylibReader = dynamic_cast<ld::dylib::File*>(reader); | |
409 | if ( dylibReader != NULL ) { | |
410 | //_installPathToDylibs[strdup(installPath)] = dylibReader; | |
411 | this->logDylib(dylibReader, true); | |
412 | return dylibReader; | |
413 | } | |
414 | else | |
415 | throwf("indirect dylib at %s is not a dylib", dit->useInstead); | |
416 | } | |
417 | catch (const char* msg) { | |
418 | warning("ignoring -dylib_file option, %s", msg); | |
419 | } | |
420 | } | |
421 | } | |
422 | char newPath[MAXPATHLEN]; | |
423 | // handle @loader_path | |
424 | if ( strncmp(installPath, "@loader_path/", 13) == 0 ) { | |
425 | strcpy(newPath, fromPath); | |
426 | char* addPoint = strrchr(newPath,'/'); | |
427 | if ( addPoint != NULL ) | |
428 | strcpy(&addPoint[1], &installPath[13]); | |
429 | else | |
430 | strcpy(newPath, &installPath[13]); | |
431 | installPath = newPath; | |
432 | } | |
433 | // note: @executable_path case is handled inside findFileUsingPaths() | |
434 | // search for dylib using -F and -L paths | |
435 | Options::FileInfo info = _options.findFileUsingPaths(installPath); | |
436 | try { | |
437 | ld::File* reader = this->makeFile(info); | |
438 | ld::dylib::File* dylibReader = dynamic_cast<ld::dylib::File*>(reader); | |
439 | if ( dylibReader != NULL ) { | |
440 | //assert(_installPathToDylibs.find(installPath) != _installPathToDylibs.end()); | |
441 | //_installPathToDylibs[strdup(installPath)] = dylibReader; | |
442 | this->logDylib(dylibReader, true); | |
443 | return dylibReader; | |
444 | } | |
445 | else | |
446 | throwf("indirect dylib at %s is not a dylib", info.path); | |
447 | } | |
448 | catch (const char* msg) { | |
449 | throwf("in %s, %s", info.path, msg); | |
450 | } | |
451 | } | |
452 | } | |
453 | ||
454 | ||
455 | ||
456 | void InputFiles::createIndirectDylibs() | |
457 | { | |
458 | _allDirectDylibsLoaded = true; | |
459 | ||
460 | // mark all dylibs initially specified as required and check if they can be used | |
461 | for (InstallNameToDylib::iterator it=_installPathToDylibs.begin(); it != _installPathToDylibs.end(); it++) { | |
462 | it->second->setExplicitlyLinked(); | |
463 | this->checkDylibClientRestrictions(it->second); | |
464 | } | |
465 | ||
466 | // keep processing dylibs until no more dylibs are added | |
467 | unsigned long lastMapSize = 0; | |
468 | std::set<ld::dylib::File*> dylibsProcessed; | |
469 | while ( lastMapSize != _allDylibs.size() ) { | |
470 | lastMapSize = _allDylibs.size(); | |
471 | // can't iterator _installPathToDylibs while modifying it, so use temp buffer | |
472 | std::vector<ld::dylib::File*> unprocessedDylibs; | |
473 | for (std::set<ld::dylib::File*>::iterator it=_allDylibs.begin(); it != _allDylibs.end(); it++) { | |
474 | if ( dylibsProcessed.count(*it) == 0 ) | |
475 | unprocessedDylibs.push_back(*it); | |
476 | } | |
477 | for (std::vector<ld::dylib::File*>::iterator it=unprocessedDylibs.begin(); it != unprocessedDylibs.end(); it++) { | |
478 | dylibsProcessed.insert(*it); | |
479 | (*it)->processIndirectLibraries(this, _options.implicitlyLinkIndirectPublicDylibs()); | |
480 | } | |
481 | } | |
482 | ||
483 | // go back over original dylibs and mark sub frameworks as re-exported | |
484 | if ( _options.outputKind() == Options::kDynamicLibrary ) { | |
485 | const char* myLeaf = strrchr(_options.installPath(), '/'); | |
486 | if ( myLeaf != NULL ) { | |
487 | for (std::vector<class ld::File*>::const_iterator it=_inputFiles.begin(); it != _inputFiles.end(); it++) { | |
488 | ld::dylib::File* dylibReader = dynamic_cast<ld::dylib::File*>(*it); | |
489 | if ( dylibReader != NULL ) { | |
490 | const char* childParent = dylibReader->parentUmbrella(); | |
491 | if ( childParent != NULL ) { | |
492 | if ( strcmp(childParent, &myLeaf[1]) == 0 ) { | |
493 | // mark that this dylib will be re-exported | |
494 | dylibReader->setWillBeReExported(); | |
495 | } | |
496 | } | |
497 | } | |
498 | } | |
499 | } | |
500 | } | |
501 | ||
502 | } | |
503 | ||
504 | void InputFiles::createOpaqueFileSections() | |
505 | { | |
506 | // extra command line section always at end | |
507 | for (Options::ExtraSection::const_iterator it=_options.extraSectionsBegin(); it != _options.extraSectionsEnd(); ++it) { | |
508 | _inputFiles.push_back(opaque_section::parse(it->segmentName, it->sectionName, it->path, it->data, | |
509 | it->dataLen, _nextInputOrdinal)); | |
510 | // bump ordinal | |
511 | _nextInputOrdinal++; | |
512 | } | |
513 | ||
514 | } | |
515 | ||
516 | ||
517 | void InputFiles::checkDylibClientRestrictions(ld::dylib::File* dylib) | |
518 | { | |
519 | // Check for any restrictions on who can link with this dylib | |
520 | const char* dylibParentName = dylib->parentUmbrella() ; | |
521 | const std::vector<const char*>* clients = dylib->allowableClients(); | |
522 | if ( (dylibParentName != NULL) || (clients != NULL) ) { | |
523 | // only dylibs that are in an umbrella or have a client list need verification | |
524 | const char* installName = _options.installPath(); | |
525 | const char* installNameLastSlash = strrchr(installName, '/'); | |
526 | bool isParent = false; | |
527 | bool isSibling = false; | |
528 | bool isAllowableClient = false; | |
529 | // There are three cases: | |
530 | if ( (dylibParentName != NULL) && (installNameLastSlash != NULL) ) { | |
531 | // starts after last slash | |
532 | const char* myName = &installNameLastSlash[1]; | |
533 | unsigned int myNameLen = strlen(myName); | |
534 | if ( strncmp(myName, "lib", 3) == 0 ) | |
535 | myName = &myName[3]; | |
536 | // up to first dot | |
537 | const char* firstDot = strchr(myName, '.'); | |
538 | if ( firstDot != NULL ) | |
539 | myNameLen = firstDot - myName; | |
540 | // up to first underscore | |
541 | const char* firstUnderscore = strchr(myName, '_'); | |
542 | if ( (firstUnderscore != NULL) && ((firstUnderscore - myName) < (int)myNameLen) ) | |
543 | myNameLen = firstUnderscore - myName; | |
544 | ||
545 | // case 1) The dylib has a parent umbrella, and we are creating the parent umbrella | |
546 | isParent = ( (strlen(dylibParentName) == myNameLen) && (strncmp(myName, dylibParentName, myNameLen) == 0) ); | |
547 | ||
548 | // case 2) The dylib has a parent umbrella, and we are creating a sibling with the same parent | |
549 | isSibling = ( (_options.umbrellaName() != NULL) && (strcmp(_options.umbrellaName(), dylibParentName) == 0) ); | |
550 | } | |
551 | ||
552 | if ( !isParent && !isSibling && (clients != NULL) ) { | |
553 | // case 3) the dylib has a list of allowable clients, and we are creating one of them | |
554 | const char* clientName = _options.clientName(); | |
555 | int clientNameLen = 0; | |
556 | if ( clientName != NULL ) { | |
557 | // use client name as specified on command line | |
558 | clientNameLen = strlen(clientName); | |
559 | } | |
560 | else { | |
561 | // infer client name from output path (e.g. xxx/libfoo_variant.A.dylib --> foo, Bar.framework/Bar_variant --> Bar) | |
562 | clientName = installName; | |
563 | clientNameLen = strlen(clientName); | |
564 | // starts after last slash | |
565 | if ( installNameLastSlash != NULL ) | |
566 | clientName = &installNameLastSlash[1]; | |
567 | if ( strncmp(clientName, "lib", 3) == 0 ) | |
568 | clientName = &clientName[3]; | |
569 | // up to first dot | |
570 | const char* firstDot = strchr(clientName, '.'); | |
571 | if ( firstDot != NULL ) | |
572 | clientNameLen = firstDot - clientName; | |
573 | // up to first underscore | |
574 | const char* firstUnderscore = strchr(clientName, '_'); | |
575 | if ( (firstUnderscore != NULL) && ((firstUnderscore - clientName) < clientNameLen) ) | |
576 | clientNameLen = firstUnderscore - clientName; | |
577 | } | |
578 | ||
579 | // Use clientName to check if this dylib is able to link against the allowable clients. | |
580 | for (std::vector<const char*>::const_iterator it = clients->begin(); it != clients->end(); it++) { | |
581 | if ( strncmp(*it, clientName, clientNameLen) == 0 ) | |
582 | isAllowableClient = true; | |
583 | } | |
584 | } | |
585 | ||
586 | if ( !isParent && !isSibling && !isAllowableClient ) { | |
587 | if ( dylibParentName != NULL ) { | |
588 | throwf("cannot link directly with %s. Link against the umbrella framework '%s.framework' instead.", | |
589 | dylib->path(), dylibParentName); | |
590 | } | |
591 | else { | |
592 | throwf("cannot link directly with %s", dylib->path()); | |
593 | } | |
594 | } | |
595 | } | |
596 | } | |
597 | ||
598 | ||
599 | void InputFiles::inferArchitecture(Options& opts, const char** archName) | |
600 | { | |
601 | _inferredArch = true; | |
602 | // scan all input files, looking for a thin .o file. | |
603 | // the first one found is presumably the architecture to link | |
604 | uint8_t buffer[sizeof(mach_header_64)]; | |
605 | const std::vector<Options::FileInfo>& files = opts.getInputFiles(); | |
606 | for (std::vector<Options::FileInfo>::const_iterator it = files.begin(); it != files.end(); ++it) { | |
607 | int fd = ::open(it->path, O_RDONLY, 0); | |
608 | if ( fd != -1 ) { | |
609 | ssize_t amount = read(fd, buffer, sizeof(buffer)); | |
610 | ::close(fd); | |
611 | if ( amount >= (ssize_t)sizeof(buffer) ) { | |
612 | cpu_type_t type; | |
613 | cpu_subtype_t subtype; | |
614 | if ( mach_o::relocatable::isObjectFile(buffer, &type, &subtype) ) { | |
615 | opts.setArchitecture(type, subtype); | |
616 | *archName = opts.architectureName(); | |
617 | return; | |
618 | } | |
619 | } | |
620 | } | |
621 | } | |
622 | ||
623 | // no thin .o files found, so default to same architecture this tool was built as | |
624 | warning("-arch not specified"); | |
625 | #if __ppc__ | |
626 | opts.setArchitecture(CPU_TYPE_POWERPC, CPU_SUBTYPE_POWERPC_ALL); | |
627 | #elif __i386__ | |
628 | opts.setArchitecture(CPU_TYPE_I386, CPU_SUBTYPE_X86_ALL); | |
629 | #elif __ppc64__ | |
630 | opts.setArchitecture(CPU_TYPE_POWERPC64, CPU_SUBTYPE_POWERPC_ALL); | |
631 | #elif __x86_64__ | |
632 | opts.setArchitecture(CPU_TYPE_X86_64, CPU_SUBTYPE_X86_64_ALL); | |
633 | #elif __arm__ | |
634 | opts.setArchitecture(CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V6); | |
635 | #else | |
636 | #error unknown default architecture | |
637 | #endif | |
638 | *archName = opts.architectureName(); | |
639 | } | |
640 | ||
641 | ||
642 | InputFiles::InputFiles(Options& opts, const char** archName) | |
643 | : _totalObjectSize(0), _totalArchiveSize(0), | |
644 | _totalObjectLoaded(0), _totalArchivesLoaded(0), _totalDylibsLoaded(0), | |
645 | _options(opts), _bundleLoader(NULL), _nextInputOrdinal(1), | |
646 | _allDirectDylibsLoaded(false), _inferredArch(false) | |
647 | { | |
648 | // fStartCreateReadersTime = mach_absolute_time(); | |
649 | if ( opts.architecture() == 0 ) { | |
650 | // command line missing -arch, so guess arch | |
651 | inferArchitecture(opts, archName); | |
652 | } | |
653 | ||
654 | const std::vector<Options::FileInfo>& files = opts.getInputFiles(); | |
655 | if ( files.size() == 0 ) | |
656 | throw "no object files specified"; | |
657 | // add all direct object, archives, and dylibs | |
658 | _inputFiles.reserve(files.size()); | |
659 | for (std::vector<Options::FileInfo>::const_iterator it = files.begin(); it != files.end(); ++it) { | |
660 | const Options::FileInfo& entry = *it; | |
661 | try { | |
662 | _inputFiles.push_back(this->makeFile(entry)); | |
663 | } | |
664 | catch (const char* msg) { | |
665 | if ( (strstr(msg, "architecture") != NULL) && !_options.errorOnOtherArchFiles() ) { | |
666 | if ( opts.ignoreOtherArchInputFiles() ) { | |
667 | // ignore, because this is about an architecture not in use | |
668 | } | |
669 | else { | |
670 | warning("ignoring file %s, %s", entry.path, msg); | |
671 | } | |
672 | } | |
673 | else { | |
674 | throwf("in %s, %s", entry.path, msg); | |
675 | } | |
676 | } | |
677 | } | |
678 | ||
679 | this->createIndirectDylibs(); | |
680 | this->createOpaqueFileSections(); | |
681 | } | |
682 | ||
683 | ||
684 | ||
685 | ld::File* InputFiles::addArchive(ld::File* reader, const Options::FileInfo& info, uint64_t mappedLen) | |
686 | { | |
687 | // bump ordinal | |
688 | _nextInputOrdinal += reader->subFileCount(); | |
689 | ||
690 | // update stats | |
691 | _totalArchiveSize += mappedLen; | |
692 | _totalArchivesLoaded++; | |
693 | return reader; | |
694 | } | |
695 | ||
696 | ||
697 | ld::File* InputFiles::addObject(ld::relocatable::File* file, const Options::FileInfo& info, uint64_t mappedLen) | |
698 | { | |
699 | // bump ordinal | |
700 | _nextInputOrdinal++; | |
701 | ||
702 | // update stats | |
703 | _totalObjectSize += mappedLen; | |
704 | _totalObjectLoaded++; | |
705 | return file; | |
706 | } | |
707 | ||
708 | ||
709 | ld::File* InputFiles::addDylib(ld::dylib::File* reader, const Options::FileInfo& info, uint64_t mappedLen) | |
710 | { | |
711 | _allDylibs.insert(reader); | |
712 | ||
713 | if ( (reader->installPath() == NULL) && !info.options.fBundleLoader ) { | |
714 | // this is a "blank" stub | |
715 | // silently ignore it | |
716 | return reader; | |
717 | } | |
718 | // store options about how dylib will be used in dylib itself | |
719 | if ( info.options.fWeakImport ) | |
720 | reader->setWillBeWeakLinked(); | |
721 | if ( info.options.fReExport ) | |
722 | reader->setWillBeReExported(); | |
723 | if ( info.options.fUpward ) { | |
724 | if ( _options.outputKind() == Options::kDynamicLibrary ) | |
725 | reader->setWillBeUpwardDylib(); | |
726 | else | |
727 | warning("ignoring upward dylib option for %s\n", info.path); | |
728 | } | |
729 | if ( info.options.fLazyLoad ) | |
730 | reader->setWillBeLazyLoadedDylb(); | |
731 | ||
732 | // add to map of loaded dylibs | |
733 | const char* installPath = reader->installPath(); | |
734 | if ( installPath != NULL ) { | |
735 | InstallNameToDylib::iterator pos = _installPathToDylibs.find(installPath); | |
736 | if ( pos == _installPathToDylibs.end() ) { | |
737 | _installPathToDylibs[strdup(installPath)] = reader; | |
738 | } | |
739 | else { | |
740 | bool dylibOnCommandLineTwice = ( strcmp(pos->second->path(), reader->path()) == 0 ); | |
741 | bool isSymlink = false; | |
742 | // ignore if this is a symlink to a dylib we've already loaded | |
743 | if ( !dylibOnCommandLineTwice ) { | |
744 | char existingDylibPath[PATH_MAX]; | |
745 | if ( realpath(pos->second->path(), existingDylibPath) != NULL ) { | |
746 | char newDylibPath[PATH_MAX]; | |
747 | if ( realpath(reader->path(), newDylibPath) != NULL ) { | |
748 | isSymlink = ( strcmp(existingDylibPath, newDylibPath) == 0 ); | |
749 | } | |
750 | } | |
751 | } | |
752 | if ( !dylibOnCommandLineTwice && !isSymlink ) | |
753 | warning("dylibs with same install name: %s and %s", pos->second->path(), reader->path()); | |
754 | } | |
755 | } | |
756 | else if ( info.options.fBundleLoader ) | |
757 | _bundleLoader = reader; | |
758 | ||
759 | // log direct readers | |
760 | if ( !_allDirectDylibsLoaded ) | |
761 | this->logDylib(reader, false); | |
762 | ||
763 | // bump ordinal | |
764 | _nextInputOrdinal++; | |
765 | ||
766 | // update stats | |
767 | _totalDylibsLoaded++; | |
768 | ||
769 | return reader; | |
770 | } | |
771 | ||
772 | ||
773 | bool InputFiles::forEachInitialAtom(ld::File::AtomHandler& handler) const | |
774 | { | |
775 | bool didSomething = false; | |
776 | for (std::vector<ld::File*>::const_iterator it=_inputFiles.begin(); it != _inputFiles.end(); ++it) { | |
777 | didSomething |= (*it)->forEachAtom(handler); | |
778 | } | |
779 | if ( didSomething || true ) { | |
780 | switch ( _options.outputKind() ) { | |
781 | case Options::kDynamicExecutable: | |
782 | // add implicit __dso_handle label | |
783 | handler.doAtom(DSOHandleAtom::_s_atomExecutable); | |
784 | handler.doAtom(DSOHandleAtom::_s_atomAll); | |
785 | if ( _options.pageZeroSize() != 0 ) | |
786 | handler.doAtom(*new PageZeroAtom(_options.pageZeroSize())); | |
787 | if ( _options.hasCustomStack() ) | |
788 | handler.doAtom(*new CustomStackAtom(_options.customStackSize())); | |
789 | break; | |
790 | case Options::kDynamicLibrary: | |
791 | // add implicit __dso_handle label | |
792 | handler.doAtom(DSOHandleAtom::_s_atomDylib); | |
793 | handler.doAtom(DSOHandleAtom::_s_atomAll); | |
794 | break; | |
795 | case Options::kDynamicBundle: | |
796 | // add implicit __dso_handle label | |
797 | handler.doAtom(DSOHandleAtom::_s_atomBundle); | |
798 | handler.doAtom(DSOHandleAtom::_s_atomAll); | |
799 | break; | |
800 | case Options::kDyld: | |
801 | // add implicit __dso_handle label | |
802 | handler.doAtom(DSOHandleAtom::_s_atomDyld); | |
803 | handler.doAtom(DSOHandleAtom::_s_atomAll); | |
804 | break; | |
805 | case Options::kStaticExecutable: | |
806 | // add implicit __dso_handle label | |
807 | handler.doAtom(DSOHandleAtom::_s_atomExecutable); | |
808 | handler.doAtom(DSOHandleAtom::_s_atomAll); | |
809 | break; | |
810 | case Options::kPreload: | |
811 | // add implicit __mh_preload_header label | |
812 | handler.doAtom(DSOHandleAtom::_s_atomPreload); | |
813 | break; | |
814 | case Options::kObjectFile: | |
815 | handler.doAtom(DSOHandleAtom::_s_atomObjectFile); | |
816 | break; | |
817 | case Options::kKextBundle: | |
818 | // add implicit __dso_handle label | |
819 | handler.doAtom(DSOHandleAtom::_s_atomAll); | |
820 | break; | |
821 | } | |
822 | } | |
823 | return didSomething; | |
824 | } | |
825 | ||
826 | ||
827 | bool InputFiles::searchLibraries(const char* name, bool searchDylibs, bool searchArchives, ld::File::AtomHandler& handler) const | |
828 | { | |
829 | // check each input file | |
830 | for (std::vector<ld::File*>::const_iterator it=_inputFiles.begin(); it != _inputFiles.end(); ++it) { | |
831 | ld::File* file = *it; | |
832 | // if this reader is a static archive that has the symbol we need, pull in all atoms in that module | |
833 | // if this reader is a dylib that exports the symbol we need, have it synthesize an atom for us. | |
834 | ld::dylib::File* dylibFile = dynamic_cast<ld::dylib::File*>(file); | |
835 | if ( searchDylibs && (dylibFile != NULL) ) { | |
836 | //fprintf(stderr, "searchLibraries(%s), looking in linked %s\n", name, dylibFile->path() ); | |
837 | if ( dylibFile->justInTimeforEachAtom(name, handler) ) { | |
838 | // we found a definition in this dylib | |
839 | // done, unless it is a weak definition in which case we keep searching | |
840 | if ( !dylibFile->hasWeakExternals() || !dylibFile->hasWeakDefinition(name)) | |
841 | return true; | |
842 | // else continue search for a non-weak definition | |
843 | } | |
844 | } | |
845 | else if ( searchArchives && (dylibFile == NULL) ) { | |
846 | if ( file->justInTimeforEachAtom(name, handler) ) { | |
847 | if ( _options.traceArchives() ) | |
848 | logArchive(file); | |
849 | // found definition in static library, done | |
850 | return true; | |
851 | } | |
852 | } | |
853 | } | |
854 | ||
855 | // search indirect dylibs | |
856 | if ( searchDylibs ) { | |
857 | for (InstallNameToDylib::const_iterator it=_installPathToDylibs.begin(); it != _installPathToDylibs.end(); ++it) { | |
858 | ld::dylib::File* dylibFile = it->second; | |
859 | bool searchThisDylib = false; | |
860 | if ( _options.nameSpace() == Options::kTwoLevelNameSpace ) { | |
861 | // for two level namesapce, just check all implicitly linked dylibs | |
862 | searchThisDylib = dylibFile->implicitlyLinked() && !dylibFile->explicitlyLinked(); | |
863 | } | |
864 | else { | |
865 | // for flat namespace, check all indirect dylibs | |
866 | searchThisDylib = ! dylibFile->explicitlyLinked(); | |
867 | } | |
868 | if ( searchThisDylib ) { | |
869 | //fprintf(stderr, "searchLibraries(%s), looking in implicitly linked %s\n", name, dylibFile->path() ); | |
870 | if ( dylibFile->justInTimeforEachAtom(name, handler) ) { | |
871 | // we found a definition in this dylib | |
872 | // done, unless it is a weak definition in which case we keep searching | |
873 | if ( !dylibFile->hasWeakExternals() || !dylibFile->hasWeakDefinition(name)) | |
874 | return true; | |
875 | // else continue search for a non-weak definition | |
876 | } | |
877 | } | |
878 | } | |
879 | } | |
880 | ||
881 | return false; | |
882 | } | |
883 | ||
884 | ||
885 | bool InputFiles::searchWeakDefInDylib(const char* name) const | |
886 | { | |
887 | // search all relevant dylibs to see if any of a weak-def with this name | |
888 | for (InstallNameToDylib::const_iterator it=_installPathToDylibs.begin(); it != _installPathToDylibs.end(); ++it) { | |
889 | ld::dylib::File* dylibFile = it->second; | |
890 | if ( dylibFile->implicitlyLinked() || dylibFile->explicitlyLinked() ) { | |
891 | if ( dylibFile->hasWeakExternals() && dylibFile->hasWeakDefinition(name) ) { | |
892 | return true; | |
893 | } | |
894 | } | |
895 | } | |
896 | return false; | |
897 | } | |
898 | ||
899 | void InputFiles::dylibs(ld::Internal& state) | |
900 | { | |
901 | bool dylibsOK; | |
902 | switch ( _options.outputKind() ) { | |
903 | case Options::kDynamicExecutable: | |
904 | case Options::kDynamicLibrary: | |
905 | case Options::kDynamicBundle: | |
906 | dylibsOK = true; | |
907 | break; | |
908 | case Options::kStaticExecutable: | |
909 | case Options::kDyld: | |
910 | case Options::kPreload: | |
911 | case Options::kObjectFile: | |
912 | case Options::kKextBundle: | |
913 | dylibsOK = false; | |
914 | break; | |
915 | } | |
916 | ||
917 | // add command line dylibs in order | |
918 | for (std::vector<ld::File*>::const_iterator it=_inputFiles.begin(); it != _inputFiles.end(); ++it) { | |
919 | ld::dylib::File* dylibFile = dynamic_cast<ld::dylib::File*>(*it); | |
920 | // only add dylibs that are not "blank" dylib stubs | |
921 | if ( (dylibFile != NULL) && ((dylibFile->installPath() != NULL) || (dylibFile == _bundleLoader)) ) { | |
922 | if ( dylibsOK ) | |
923 | state.dylibs.push_back(dylibFile); | |
924 | else | |
925 | warning("unexpected dylib (%s) on link line", dylibFile->path()); | |
926 | } | |
927 | } | |
928 | // add implicitly linked dylibs | |
929 | if ( _options.nameSpace() == Options::kTwoLevelNameSpace ) { | |
930 | for (InstallNameToDylib::const_iterator it=_installPathToDylibs.begin(); it != _installPathToDylibs.end(); ++it) { | |
931 | ld::dylib::File* dylibFile = it->second; | |
932 | if ( dylibFile->implicitlyLinked() && dylibsOK ) | |
933 | state.dylibs.push_back(dylibFile); | |
934 | } | |
935 | } | |
936 | // and -bundle_loader | |
937 | state.bundleLoader = _bundleLoader; | |
938 | } | |
939 | ||
940 | ||
941 | } // namespace tool | |
942 | } // namespace ld | |
943 |