]> git.saurik.com Git - apple/ld64.git/blob - src/ld/parsers/macho_dylib_file.cpp
ld64-123.2.tar.gz
[apple/ld64.git] / src / ld / parsers / macho_dylib_file.cpp
1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
2 *
3 * Copyright (c) 2005-2009 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 <stdint.h>
27 #include <math.h>
28 #include <unistd.h>
29 #include <sys/param.h>
30 #include <sys/mman.h>
31
32
33 #include <vector>
34 #include <set>
35 #include <algorithm>
36 #include <ext/hash_map>
37 #include <ext/hash_set>
38
39 #include "Architectures.hpp"
40 #include "MachOFileAbstraction.hpp"
41 #include "MachOTrie.hpp"
42 #include "macho_dylib_file.h"
43
44
45 namespace mach_o {
46 namespace dylib {
47
48
49 // forward reference
50 template <typename A> class File;
51
52
53 //
54 // An ExportAtom has no content. It exists so that the linker can track which imported
55 // symbols came from which dynamic libraries.
56 //
57 template <typename A>
58 class ExportAtom : public ld::Atom
59 {
60 public:
61 ExportAtom(const File<A>& f, const char* nm, bool weakDef,
62 bool tlv, typename A::P::uint_t address)
63 : ld::Atom(f._importProxySection, ld::Atom::definitionProxy,
64 (weakDef? ld::Atom::combineByName : ld::Atom::combineNever),
65 ld::Atom::scopeLinkageUnit,
66 (tlv ? ld::Atom::typeTLV : ld::Atom::typeUnclassified),
67 symbolTableNotIn, false, false, false, ld::Atom::Alignment(0)),
68 _file(f), _name(nm), _address(address) {}
69 // overrides of ld::Atom
70 virtual const ld::File* file() const { return &_file; }
71 virtual bool translationUnitSource(const char** dir, const char** nm) const
72 { return false; }
73 virtual const char* name() const { return _name; }
74 virtual uint64_t size() const { return 0; }
75 virtual uint64_t objectAddress() const { return _address; }
76 virtual void copyRawContent(uint8_t buffer[]) const { }
77 virtual void setScope(Scope) { }
78
79 protected:
80 typedef typename A::P P;
81 typedef typename A::P::uint_t pint_t;
82
83 virtual ~ExportAtom() {}
84
85 const File<A>& _file;
86 const char* _name;
87 pint_t _address;
88 };
89
90
91
92 //
93 // An ImportAtom has no content. It exists so that when linking a main executable flat-namespace
94 // the imports of all flat dylibs are checked
95 //
96 template <typename A>
97 class ImportAtom : public ld::Atom
98 {
99 public:
100 ImportAtom(File<A>& f, std::vector<const char*>& imports);
101
102 // overrides of ld::Atom
103 virtual ld::File* file() const { return &_file; }
104 virtual bool translationUnitSource(const char** dir, const char** nm) const
105 { return false; }
106 virtual const char* name() const { return "import-atom"; }
107 virtual uint64_t size() const { return 0; }
108 virtual uint64_t objectAddress() const { return 0; }
109 virtual void copyRawContent(uint8_t buffer[]) const { }
110 virtual void setScope(Scope) { }
111 virtual ld::Fixup::iterator fixupsBegin() const { return &_undefs[0]; }
112 virtual ld::Fixup::iterator fixupsEnd() const { return &_undefs[_undefs.size()]; }
113
114 protected:
115 typedef typename A::P P;
116
117 virtual ~ImportAtom() {}
118
119
120 File<A>& _file;
121 mutable std::vector<ld::Fixup> _undefs;
122 };
123
124 template <typename A>
125 ImportAtom<A>::ImportAtom(File<A>& f, std::vector<const char*>& imports)
126 : ld::Atom(f._flatDummySection, ld::Atom::definitionRegular, ld::Atom::combineNever, ld::Atom::scopeTranslationUnit,
127 ld::Atom::typeUnclassified, symbolTableNotIn, false, false, false, ld::Atom::Alignment(0)), _file(f)
128 {
129 for(std::vector<const char*>::iterator it=imports.begin(); it != imports.end(); ++it) {
130 _undefs.push_back(ld::Fixup(0, ld::Fixup::k1of1, ld::Fixup::kindNone, false, strdup(*it)));
131 }
132 }
133
134
135
136 //
137 // The reader for a dylib extracts all exported symbols names from the memory-mapped
138 // dylib, builds a hash table, then unmaps the file. This is an important memory
139 // savings for large dylibs.
140 //
141 template <typename A>
142 class File : public ld::dylib::File
143 {
144 public:
145 static bool validFile(const uint8_t* fileContent, bool executableOrDylib);
146 File(const uint8_t* fileContent, uint64_t fileLength, const char* path,
147 time_t mTime, uint32_t ordinal, bool linkingFlatNamespace,
148 bool linkingMainExecutable, bool hoistImplicitPublicDylibs,
149 ld::MacVersionMin macMin, ld::IPhoneVersionMin iPhoneMin,
150 bool logAllFiles);
151 virtual ~File() {}
152
153 // overrides of ld::File
154 virtual bool forEachAtom(ld::File::AtomHandler&) const;
155 virtual bool justInTimeforEachAtom(const char* name, ld::File::AtomHandler&) const;
156 virtual ld::File::ObjcConstraint objCConstraint() const { return _objcContraint; }
157
158 // overrides of ld::dylib::File
159 virtual void processIndirectLibraries(ld::dylib::File::DylibHandler*, bool);
160 virtual bool providedExportAtom() const { return _providedAtom; }
161 virtual const char* parentUmbrella() const { return _parentUmbrella; }
162 virtual const std::vector<const char*>* allowableClients() const { return _allowableClients.size() != 0 ? &_allowableClients : NULL; }
163 virtual bool hasWeakExternals() const { return _hasWeakExports; }
164 virtual bool deadStrippable() const { return _deadStrippable; }
165 virtual bool hasPublicInstallName() const{ return _hasPublicInstallName; }
166 virtual bool hasWeakDefinition(const char* name) const;
167
168
169 protected:
170
171 struct ReExportChain { ReExportChain* prev; File<A>* file; };
172
173 void assertNoReExportCycles(ReExportChain*);
174
175 private:
176 typedef typename A::P P;
177 typedef typename A::P::E E;
178 typedef typename A::P::uint_t pint_t;
179
180 friend class ExportAtom<A>;
181 friend class ImportAtom<A>;
182
183 class CStringEquals
184 {
185 public:
186 bool operator()(const char* left, const char* right) const { return (strcmp(left, right) == 0); }
187 };
188 struct AtomAndWeak { ld::Atom* atom; bool weak; bool tlv; pint_t address; };
189 typedef __gnu_cxx::hash_map<const char*, AtomAndWeak, __gnu_cxx::hash<const char*>, CStringEquals> NameToAtomMap;
190 typedef __gnu_cxx::hash_set<const char*, __gnu_cxx::hash<const char*>, CStringEquals> NameSet;
191
192 struct Dependent { const char* path; File<A>* dylib; bool reExport; };
193
194 bool containsOrReExports(const char* name, bool* weakDef, bool* tlv, pint_t* defAddress) const;
195 bool isPublicLocation(const char* pth);
196 void addSymbol(const char* name, bool weak, bool tlv, pint_t address);
197 void addDyldFastStub();
198 void buildExportHashTableFromExportInfo(const macho_dyld_info_command<P>* dyldInfo,
199 const uint8_t* fileContent);
200 void buildExportHashTableFromSymbolTable(const macho_dysymtab_command<P>* dynamicInfo,
201 const macho_nlist<P>* symbolTable, const char* strings,
202 const uint8_t* fileContent);
203 static const char* objCInfoSegmentName();
204 static const char* objCInfoSectionName();
205
206 const ld::MacVersionMin _macVersionMin;
207 const ld::IPhoneVersionMin _iPhoneVersionMin;
208 bool _linkingFlat;
209 bool _implicitlyLinkPublicDylibs;
210 ld::File::ObjcConstraint _objcContraint;
211 ld::Section _importProxySection;
212 ld::Section _flatDummySection;
213 std::vector<Dependent> _dependentDylibs;
214 std::vector<const char*> _allowableClients;
215 mutable NameToAtomMap _atoms;
216 NameSet _ignoreExports;
217 const char* _parentUmbrella;
218 ImportAtom<A>* _importAtom;
219 bool _noRexports;
220 bool _hasWeakExports;
221 bool _deadStrippable;
222 bool _hasPublicInstallName;
223 mutable bool _providedAtom;
224 bool _explictReExportFound;
225
226 static bool _s_logHashtable;
227 };
228
229 template <typename A>
230 bool File<A>::_s_logHashtable = false;
231
232 template <> const char* File<x86_64>::objCInfoSegmentName() { return "__DATA"; }
233 template <> const char* File<arm>::objCInfoSegmentName() { return "__DATA"; }
234 template <typename A> const char* File<A>::objCInfoSegmentName() { return "__OBJC"; }
235
236 template <> const char* File<x86_64>::objCInfoSectionName() { return "__objc_imageinfo"; }
237 template <> const char* File<arm>::objCInfoSectionName() { return "__objc_imageinfo"; }
238 template <typename A> const char* File<A>::objCInfoSectionName() { return "__image_info"; }
239
240 template <typename A>
241 File<A>::File(const uint8_t* fileContent, uint64_t fileLength, const char* pth, time_t mTime, uint32_t ord,
242 bool linkingFlatNamespace, bool linkingMainExecutable, bool hoistImplicitPublicDylibs,
243 ld::MacVersionMin macMin, ld::IPhoneVersionMin iPhoneMin, bool logAllFiles)
244 : ld::dylib::File(strdup(pth), mTime, ord),
245 _macVersionMin(macMin), _iPhoneVersionMin(iPhoneMin),
246 _linkingFlat(linkingFlatNamespace), _implicitlyLinkPublicDylibs(hoistImplicitPublicDylibs),
247 _objcContraint(ld::File::objcConstraintNone),
248 _importProxySection("__TEXT", "__import", ld::Section::typeImportProxies, true),
249 _flatDummySection("__LINKEDIT", "__flat_dummy", ld::Section::typeLinkEdit, true),
250 _parentUmbrella(NULL), _importAtom(NULL), _noRexports(false), _hasWeakExports(false),
251 _deadStrippable(false), _hasPublicInstallName(false),
252 _providedAtom(false), _explictReExportFound(false)
253 {
254 const macho_header<P>* header = (const macho_header<P>*)fileContent;
255 const uint32_t cmd_count = header->ncmds();
256 const macho_load_command<P>* const cmds = (macho_load_command<P>*)((char*)header + sizeof(macho_header<P>));
257 const macho_load_command<P>* const cmdsEnd = (macho_load_command<P>*)((char*)header + sizeof(macho_header<P>) + header->sizeofcmds());
258
259 // write out path for -t option
260 if ( logAllFiles )
261 printf("%s\n", pth);
262
263 // a "blank" stub has zero load commands
264 if ( (header->filetype() == MH_DYLIB_STUB) && (cmd_count == 0) ) {
265 // no further processing needed
266 munmap((caddr_t)fileContent, fileLength);
267 return;
268 }
269
270
271 // optimize the case where we know there is no reason to look at indirect dylibs
272 _noRexports = (header->flags() & MH_NO_REEXPORTED_DYLIBS)
273 || (header->filetype() == MH_BUNDLE)
274 || (header->filetype() == MH_EXECUTE); // bundles and exectuables can be used via -bundle_loader
275 _hasWeakExports = (header->flags() & MH_WEAK_DEFINES);
276 _deadStrippable = (header->flags() & MH_DEAD_STRIPPABLE_DYLIB);
277
278 // pass 1: get pointers, and see if this dylib uses compressed LINKEDIT format
279 const macho_dysymtab_command<P>* dynamicInfo = NULL;
280 const macho_dyld_info_command<P>* dyldInfo = NULL;
281 const macho_nlist<P>* symbolTable = NULL;
282 const char* strings = NULL;
283 bool compressedLinkEdit = false;
284 uint32_t dependentLibCount = 0;
285 const macho_load_command<P>* cmd = cmds;
286 for (uint32_t i = 0; i < cmd_count; ++i) {
287 macho_dylib_command<P>* dylibID;
288 const macho_symtab_command<P>* symtab;
289 switch (cmd->cmd()) {
290 case LC_SYMTAB:
291 symtab = (macho_symtab_command<P>*)cmd;
292 symbolTable = (const macho_nlist<P>*)((char*)header + symtab->symoff());
293 strings = (char*)header + symtab->stroff();
294 break;
295 case LC_DYSYMTAB:
296 dynamicInfo = (macho_dysymtab_command<P>*)cmd;
297 break;
298 case LC_DYLD_INFO:
299 case LC_DYLD_INFO_ONLY:
300 dyldInfo = (macho_dyld_info_command<P>*)cmd;
301 compressedLinkEdit = true;
302 break;
303 case LC_ID_DYLIB:
304 dylibID = (macho_dylib_command<P>*)cmd;
305 _dylibInstallPath = strdup(dylibID->name());
306 _dylibTimeStamp = dylibID->timestamp();
307 _dylibCurrentVersion = dylibID->current_version();
308 _dylibCompatibilityVersion = dylibID->compatibility_version();
309 _hasPublicInstallName = isPublicLocation(_dylibInstallPath);
310 break;
311 case LC_LOAD_DYLIB:
312 case LC_LOAD_WEAK_DYLIB:
313 ++dependentLibCount;
314 break;
315 case LC_REEXPORT_DYLIB:
316 _explictReExportFound = true;
317 ++dependentLibCount;
318 break;
319 case LC_SUB_FRAMEWORK:
320 _parentUmbrella = strdup(((macho_sub_framework_command<P>*)cmd)->umbrella());
321 break;
322 case LC_SUB_CLIENT:
323 _allowableClients.push_back(strdup(((macho_sub_client_command<P>*)cmd)->client()));
324 break;
325 case macho_segment_command<P>::CMD:
326 // check for Objective-C info
327 if ( strcmp(((macho_segment_command<P>*)cmd)->segname(), objCInfoSegmentName()) == 0 ) {
328 const macho_segment_command<P>* segment = (macho_segment_command<P>*)cmd;
329 const macho_section<P>* const sectionsStart = (macho_section<P>*)((char*)segment + sizeof(macho_segment_command<P>));
330 const macho_section<P>* const sectionsEnd = &sectionsStart[segment->nsects()];
331 for (const macho_section<P>* sect=sectionsStart; sect < sectionsEnd; ++sect) {
332 if ( strncmp(sect->sectname(), objCInfoSectionName(), strlen(objCInfoSectionName())) == 0 ) {
333 // struct objc_image_info {
334 // uint32_t version; // initially 0
335 // uint32_t flags;
336 // };
337 // #define OBJC_IMAGE_SUPPORTS_GC 2
338 // #define OBJC_IMAGE_GC_ONLY 4
339 //
340 const uint32_t* contents = (uint32_t*)(&fileContent[sect->offset()]);
341 if ( (sect->size() >= 8) && (contents[0] == 0) ) {
342 uint32_t flags = E::get32(contents[1]);
343 if ( (flags & 4) == 4 )
344 _objcContraint = ld::File::objcConstraintGC;
345 else if ( (flags & 2) == 2 )
346 _objcContraint = ld::File::objcConstraintRetainReleaseOrGC;
347 else
348 _objcContraint = ld::File::objcConstraintRetainRelease;
349 }
350 else if ( sect->size() > 0 ) {
351 warning("can't parse %s/%s section in %s", objCInfoSegmentName(), objCInfoSectionName(), this->path());
352 }
353 }
354 }
355 }
356 }
357 cmd = (const macho_load_command<P>*)(((char*)cmd)+cmd->cmdsize());
358 if ( cmd > cmdsEnd )
359 throwf("malformed dylb, load command #%d is outside size of load commands in %s", i, pth);
360 }
361
362 // figure out if we need to examine dependent dylibs
363 // with compressed LINKEDIT format, MH_NO_REEXPORTED_DYLIBS can be trusted
364 bool processDependentLibraries = true;
365 if ( compressedLinkEdit && _noRexports && !linkingFlatNamespace)
366 processDependentLibraries = false;
367
368 if ( processDependentLibraries ) {
369 // pass 2 builds list of all dependent libraries
370 _dependentDylibs.reserve(dependentLibCount);
371 cmd = cmds;
372 for (uint32_t i = 0; i < cmd_count; ++i) {
373 switch (cmd->cmd()) {
374 case LC_LOAD_DYLIB:
375 case LC_LOAD_WEAK_DYLIB:
376 // with new linkedit format only care about LC_REEXPORT_DYLIB
377 if ( compressedLinkEdit && !linkingFlatNamespace )
378 break;
379 case LC_REEXPORT_DYLIB:
380 Dependent entry;
381 entry.path = strdup(((macho_dylib_command<P>*)cmd)->name());
382 entry.dylib = NULL;
383 entry.reExport = (cmd->cmd() == LC_REEXPORT_DYLIB);
384 _dependentDylibs.push_back(entry);
385 break;
386 }
387 cmd = (const macho_load_command<P>*)(((char*)cmd)+cmd->cmdsize());
388 }
389 // verify MH_NO_REEXPORTED_DYLIBS bit was correct
390 if ( compressedLinkEdit && !linkingFlatNamespace ) {
391 assert(_dependentDylibs.size() != 0);
392 }
393 // pass 3 add re-export info
394 cmd = cmds;
395 for (uint32_t i = 0; i < cmd_count; ++i) {
396 const char* frameworkLeafName;
397 const char* dylibBaseName;
398 switch (cmd->cmd()) {
399 case LC_SUB_UMBRELLA:
400 frameworkLeafName = ((macho_sub_umbrella_command<P>*)cmd)->sub_umbrella();
401 for (typename std::vector<Dependent>::iterator it = _dependentDylibs.begin(); it != _dependentDylibs.end(); ++it) {
402 const char* dylibName = it->path;
403 const char* lastSlash = strrchr(dylibName, '/');
404 if ( (lastSlash != NULL) && (strcmp(&lastSlash[1], frameworkLeafName) == 0) )
405 it->reExport = true;
406 }
407 break;
408 case LC_SUB_LIBRARY:
409 dylibBaseName = ((macho_sub_library_command<P>*)cmd)->sub_library();
410 for (typename std::vector<Dependent>::iterator it = _dependentDylibs.begin(); it != _dependentDylibs.end(); ++it) {
411 const char* dylibName = it->path;
412 const char* lastSlash = strrchr(dylibName, '/');
413 const char* leafStart = &lastSlash[1];
414 if ( lastSlash == NULL )
415 leafStart = dylibName;
416 const char* firstDot = strchr(leafStart, '.');
417 int len = strlen(leafStart);
418 if ( firstDot != NULL )
419 len = firstDot - leafStart;
420 if ( strncmp(leafStart, dylibBaseName, len) == 0 )
421 it->reExport = true;
422 }
423 break;
424 }
425 cmd = (const macho_load_command<P>*)(((char*)cmd)+cmd->cmdsize());
426 }
427 }
428
429 // validate minimal load commands
430 if ( (_dylibInstallPath == NULL) && ((header->filetype() == MH_DYLIB) || (header->filetype() == MH_DYLIB_STUB)) )
431 throwf("dylib %s missing LC_ID_DYLIB load command", pth);
432 if ( dyldInfo == NULL ) {
433 if ( symbolTable == NULL )
434 throw "binary missing LC_SYMTAB load command";
435 if ( dynamicInfo == NULL )
436 throw "binary missing LC_DYSYMTAB load command";
437 }
438
439 // if linking flat and this is a flat dylib, create one atom that references all imported symbols
440 if ( linkingFlatNamespace && linkingMainExecutable && ((header->flags() & MH_TWOLEVEL) == 0) ) {
441 std::vector<const char*> importNames;
442 importNames.reserve(dynamicInfo->nundefsym());
443 const macho_nlist<P>* start = &symbolTable[dynamicInfo->iundefsym()];
444 const macho_nlist<P>* end = &start[dynamicInfo->nundefsym()];
445 for (const macho_nlist<P>* sym=start; sym < end; ++sym) {
446 importNames.push_back(&strings[sym->n_strx()]);
447 }
448 _importAtom = new ImportAtom<A>(*this, importNames);
449 }
450
451 // build hash table
452 if ( dyldInfo != NULL )
453 buildExportHashTableFromExportInfo(dyldInfo, fileContent);
454 else
455 buildExportHashTableFromSymbolTable(dynamicInfo, symbolTable, strings, fileContent);
456
457 // unmap file
458 munmap((caddr_t)fileContent, fileLength);
459 }
460
461
462 template <typename A>
463 void File<A>::buildExportHashTableFromSymbolTable(const macho_dysymtab_command<P>* dynamicInfo,
464 const macho_nlist<P>* symbolTable, const char* strings,
465 const uint8_t* fileContent)
466 {
467 if ( dynamicInfo->tocoff() == 0 ) {
468 if ( _s_logHashtable ) fprintf(stderr, "ld: building hashtable of %u toc entries for %s\n", dynamicInfo->nextdefsym(), this->path());
469 const macho_nlist<P>* start = &symbolTable[dynamicInfo->iextdefsym()];
470 const macho_nlist<P>* end = &start[dynamicInfo->nextdefsym()];
471 _atoms.resize(dynamicInfo->nextdefsym()); // set initial bucket count
472 for (const macho_nlist<P>* sym=start; sym < end; ++sym) {
473 this->addSymbol(&strings[sym->n_strx()], (sym->n_desc() & N_WEAK_DEF) != 0, false, sym->n_value());
474 }
475 }
476 else {
477 int32_t count = dynamicInfo->ntoc();
478 _atoms.resize(count); // set initial bucket count
479 if ( _s_logHashtable ) fprintf(stderr, "ld: building hashtable of %u entries for %s\n", count, this->path());
480 const struct dylib_table_of_contents* toc = (dylib_table_of_contents*)(fileContent + dynamicInfo->tocoff());
481 for (int32_t i = 0; i < count; ++i) {
482 const uint32_t index = E::get32(toc[i].symbol_index);
483 const macho_nlist<P>* sym = &symbolTable[index];
484 this->addSymbol(&strings[sym->n_strx()], (sym->n_desc() & N_WEAK_DEF) != 0, false, sym->n_value());
485 }
486 }
487
488 // special case old libSystem
489 if ( (_dylibInstallPath != NULL) && (strcmp(_dylibInstallPath, "/usr/lib/libSystem.B.dylib") == 0) )
490 addDyldFastStub();
491 }
492
493
494 template <typename A>
495 void File<A>::buildExportHashTableFromExportInfo(const macho_dyld_info_command<P>* dyldInfo,
496 const uint8_t* fileContent)
497 {
498 if ( _s_logHashtable ) fprintf(stderr, "ld: building hashtable from export info in %s\n", this->path());
499 if ( dyldInfo->export_size() > 0 ) {
500 const uint8_t* start = fileContent + dyldInfo->export_off();
501 const uint8_t* end = &start[dyldInfo->export_size()];
502 std::vector<mach_o::trie::Entry> list;
503 parseTrie(start, end, list);
504 for (std::vector<mach_o::trie::Entry>::iterator it=list.begin(); it != list.end(); ++it)
505 this->addSymbol(it->name,
506 it->flags & EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION,
507 (it->flags & EXPORT_SYMBOL_FLAGS_KIND_MASK) == EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL,
508 it->address);
509 }
510 }
511
512
513 template <>
514 void File<x86_64>::addDyldFastStub()
515 {
516 addSymbol("dyld_stub_binder", false, false, 0);
517 }
518
519 template <>
520 void File<x86>::addDyldFastStub()
521 {
522 addSymbol("dyld_stub_binder", false, false, 0);
523 }
524
525 template <typename A>
526 void File<A>::addDyldFastStub()
527 {
528 // do nothing
529 }
530
531 template <typename A>
532 void File<A>::addSymbol(const char* name, bool weakDef, bool tlv, pint_t address)
533 {
534 if ( weakDef ) {
535 assert(_hasWeakExports);
536 }
537 //fprintf(stderr, "addSymbol() %s\n", name);
538 // symbols that start with $ld$ are meta-data to the static linker
539 // <rdar://problem/5182537> need way for ld and dyld to see different exported symbols in a dylib
540 if ( strncmp(name, "$ld$", 4) == 0 ) {
541 // $ld$ <action> $ <condition> $ <symbol-name>
542 const char* symAction = &name[4];
543 const char* symCond = strchr(symAction, '$');
544 if ( symCond != NULL ) {
545 char curOSVers[16];
546 if ( _macVersionMin != ld::macVersionUnset ) {
547 sprintf(curOSVers, "$os%d.%d$", (_macVersionMin >> 16), ((_macVersionMin >> 8) & 0xFF));
548 }
549 else if ( _iPhoneVersionMin != ld::iPhoneVersionUnset ) {
550 sprintf(curOSVers, "$os%d.%d$", (_iPhoneVersionMin >> 16), ((_iPhoneVersionMin >> 8) & 0xFF));
551 }
552 else {
553 assert(0 && "targeting neither macosx nor iphoneos");
554 }
555 if ( strncmp(symCond, curOSVers, strlen(curOSVers)) == 0 ) {
556 const char* symName = strchr(&symCond[1], '$');
557 if ( symName != NULL ) {
558 ++symName;
559 if ( strncmp(symAction, "hide$", 5) == 0 ) {
560 if ( _s_logHashtable ) fprintf(stderr, " adding %s to ignore set for %s\n", symName, this->path());
561 _ignoreExports.insert(strdup(symName));
562 return;
563 }
564 else if ( strncmp(symAction, "add$", 4) == 0 ) {
565 this->addSymbol(symName, weakDef, false, 0);
566 return;
567 }
568 else {
569 warning("bad symbol action: %s in dylib %s", name, this->path());
570 }
571 }
572 }
573 }
574 else {
575 warning("bad symbol condition: %s in dylib %s", name, this->path());
576 }
577 }
578
579 // add symbol as possible export if we are not supposed to ignore it
580 if ( _ignoreExports.count(name) == 0 ) {
581 AtomAndWeak bucket;
582 bucket.atom = NULL;
583 bucket.weak = weakDef;
584 bucket.tlv = tlv;
585 bucket.address = address;
586 if ( _s_logHashtable ) fprintf(stderr, " adding %s to hash table for %s\n", name, this->path());
587 _atoms[strdup(name)] = bucket;
588 }
589 }
590
591
592 template <typename A>
593 bool File<A>::forEachAtom(ld::File::AtomHandler& handler) const
594 {
595 handler.doFile(*this);
596 // if doing flatnamespace and need all this dylib's imports resolve
597 // add atom which references alls undefines in this dylib
598 if ( _importAtom != NULL ) {
599 handler.doAtom(*_importAtom);
600 return true;
601 }
602 return false;
603 }
604
605 template <typename A>
606 bool File<A>::hasWeakDefinition(const char* name) const
607 {
608 // if supposed to ignore this export, then pretend I don't have it
609 if ( _ignoreExports.count(name) != 0 )
610 return false;
611
612 typename NameToAtomMap::const_iterator pos = _atoms.find(name);
613 if ( pos != _atoms.end() ) {
614 return pos->second.weak;
615 }
616 else {
617 // look in children that I re-export
618 for (typename std::vector<Dependent>::const_iterator it = _dependentDylibs.begin(); it != _dependentDylibs.end(); ++it) {
619 if ( it->reExport ) {
620 //fprintf(stderr, "getJustInTimeAtomsFor: %s NOT found in %s, looking in child %s\n", name, this->path(), (*it)->getInstallPath());
621 typename NameToAtomMap::iterator cpos = it->dylib->_atoms.find(name);
622 if ( cpos != it->dylib->_atoms.end() )
623 return cpos->second.weak;
624 }
625 }
626 }
627 return false;
628 }
629
630 template <typename A>
631 bool File<A>::containsOrReExports(const char* name, bool* weakDef, bool* tlv, pint_t* defAddress) const
632 {
633 // check myself
634 typename NameToAtomMap::iterator pos = _atoms.find(name);
635 if ( pos != _atoms.end() ) {
636 *weakDef = pos->second.weak;
637 *tlv = pos->second.tlv;
638 *defAddress = pos->second.address;
639 return true;
640 }
641
642 // check dylibs I re-export
643 for (typename std::vector<Dependent>::const_iterator it = _dependentDylibs.begin(); it != _dependentDylibs.end(); ++it) {
644 if ( it->reExport && !it->dylib->implicitlyLinked() ) {
645 if ( it->dylib->containsOrReExports(name, weakDef, tlv, defAddress) )
646 return true;
647 }
648 }
649
650 return false;
651 }
652
653
654 template <typename A>
655 bool File<A>::justInTimeforEachAtom(const char* name, ld::File::AtomHandler& handler) const
656 {
657 // if supposed to ignore this export, then pretend I don't have it
658 if ( _ignoreExports.count(name) != 0 )
659 return false;
660
661
662 AtomAndWeak bucket;
663 if ( this->containsOrReExports(name, &bucket.weak, &bucket.tlv, &bucket.address) ) {
664 bucket.atom = new ExportAtom<A>(*this, name, bucket.weak, bucket.tlv, bucket.address);
665 _atoms[name] = bucket;
666 _providedAtom = true;
667 if ( _s_logHashtable ) fprintf(stderr, "getJustInTimeAtomsFor: %s found in %s\n", name, this->path());
668 // call handler with new export atom
669 handler.doAtom(*bucket.atom);
670 return true;
671 }
672
673 return false;
674 }
675
676
677
678 template <typename A>
679 bool File<A>::isPublicLocation(const char* pth)
680 {
681 // -no_implicit_dylibs disables this optimization
682 if ( ! _implicitlyLinkPublicDylibs )
683 return false;
684
685 // /usr/lib is a public location
686 if ( (strncmp(pth, "/usr/lib/", 9) == 0) && (strchr(&pth[9], '/') == NULL) )
687 return true;
688
689 // /System/Library/Frameworks/ is a public location
690 if ( strncmp(pth, "/System/Library/Frameworks/", 27) == 0 ) {
691 const char* frameworkDot = strchr(&pth[27], '.');
692 // but only top level framework
693 // /System/Library/Frameworks/Foo.framework/Versions/A/Foo ==> true
694 // /System/Library/Frameworks/Foo.framework/Resources/libBar.dylib ==> false
695 // /System/Library/Frameworks/Foo.framework/Frameworks/Bar.framework/Bar ==> false
696 // /System/Library/Frameworks/Foo.framework/Frameworks/Xfoo.framework/XFoo ==> false
697 if ( frameworkDot != NULL ) {
698 int frameworkNameLen = frameworkDot - &pth[27];
699 if ( strncmp(&pth[strlen(pth)-frameworkNameLen-1], &pth[26], frameworkNameLen+1) == 0 )
700 return true;
701 }
702 }
703
704 return false;
705 }
706
707 template <typename A>
708 void File<A>::processIndirectLibraries(ld::dylib::File::DylibHandler* handler, bool addImplicitDylibs)
709 {
710 const static bool log = false;
711 if ( log ) fprintf(stderr, "processIndirectLibraries(%s)\n", this->installPath());
712 if ( _linkingFlat ) {
713 for (typename std::vector<Dependent>::iterator it = _dependentDylibs.begin(); it != _dependentDylibs.end(); it++) {
714 it->dylib = (File<A>*)handler->findDylib(it->path, this->path());
715 }
716 }
717 else if ( _noRexports ) {
718 // MH_NO_REEXPORTED_DYLIBS bit set, then nothing to do
719 }
720 else {
721 // two-level, might have re-exports
722 for (typename std::vector<Dependent>::iterator it = _dependentDylibs.begin(); it != _dependentDylibs.end(); it++) {
723 if ( it->reExport ) {
724 if ( log ) fprintf(stderr, "processIndirectLibraries() parent=%s, child=%s\n", this->installPath(), it->path);
725 // a LC_REEXPORT_DYLIB, LC_SUB_UMBRELLA or LC_SUB_LIBRARY says we re-export this child
726 it->dylib = (File<A>*)handler->findDylib(it->path, this->path());
727 if ( it->dylib->hasPublicInstallName() ) {
728 // promote this child to be automatically added as a direct dependent if this already is
729 if ( (this->explicitlyLinked() || this->implicitlyLinked()) && (strcmp(it->path,it->dylib->installPath()) == 0) ) {
730 if ( log ) fprintf(stderr, "processIndirectLibraries() implicitly linking %s\n", it->dylib->installPath());
731 it->dylib->setImplicitlyLinked();
732 }
733 else if ( it->dylib->explicitlyLinked() || it->dylib->implicitlyLinked() ) {
734 if ( log ) fprintf(stderr, "processIndirectLibraries() parent is not directly linked, but child is, so no need to re-export child\n");
735 }
736 else {
737 if ( log ) fprintf(stderr, "processIndirectLibraries() parent is not directly linked, so parent=%s will re-export child=%s\n", this->installPath(), it->path);
738 }
739 }
740 else {
741 // add all child's symbols to me
742 if ( log ) fprintf(stderr, "processIndirectLibraries() child is not public, so parent=%s will re-export child=%s\n", this->installPath(), it->path);
743 }
744 }
745 else if ( !_explictReExportFound ) {
746 // see if child contains LC_SUB_FRAMEWORK with my name
747 it->dylib = (File<A>*)handler->findDylib(it->path, this->path());
748 const char* parentUmbrellaName = it->dylib->parentUmbrella();
749 if ( parentUmbrellaName != NULL ) {
750 const char* parentName = this->path();
751 const char* lastSlash = strrchr(parentName, '/');
752 if ( (lastSlash != NULL) && (strcmp(&lastSlash[1], parentUmbrellaName) == 0) ) {
753 // add all child's symbols to me
754 it->reExport = true;
755 if ( log ) fprintf(stderr, "processIndirectLibraries() umbrella=%s will re-export child=%s\n", this->installPath(), it->path);
756 }
757 }
758 }
759 }
760 }
761
762 // check for re-export cycles
763 ReExportChain chain;
764 chain.prev = NULL;
765 chain.file = this;
766 this->assertNoReExportCycles(&chain);
767 }
768
769 template <typename A>
770 void File<A>::assertNoReExportCycles(ReExportChain* prev)
771 {
772 // recursively check my re-exported dylibs
773 ReExportChain chain;
774 chain.prev = prev;
775 chain.file = this;
776 for (typename std::vector<Dependent>::iterator it = _dependentDylibs.begin(); it != _dependentDylibs.end(); it++) {
777 if ( it->reExport ) {
778 ld::File* child = it->dylib;
779 // check child is not already in chain
780 for (ReExportChain* p = prev; p != NULL; p = p->prev) {
781 if ( p->file == child ) {
782 throwf("cycle in dylib re-exports with %s and %s", child->path(), this->path());
783 }
784 }
785 if ( it->dylib != NULL )
786 it->dylib->assertNoReExportCycles(&chain);
787 }
788 }
789 }
790
791
792 struct ParserOptions {
793 bool linkingFlat;
794 bool linkingMain;
795 bool addImplictDylibs;
796 ld::MacVersionMin macOSMin;
797 ld::IPhoneVersionMin iphoneOSMin;
798 };
799
800
801 template <typename A>
802 class Parser
803 {
804 public:
805 typedef typename A::P P;
806
807 static bool validFile(const uint8_t* fileContent, bool executableOrDyliborBundle);
808 static ld::dylib::File* parse(const uint8_t* fileContent, uint64_t fileLength,
809 const char* path, time_t mTime,
810 uint32_t ordinal, const Options& opts) {
811 return new File<A>(fileContent, fileLength, path, mTime,
812 ordinal, opts.flatNamespace(),
813 opts.linkingMainExecutable(),
814 opts.implicitlyLinkIndirectPublicDylibs(),
815 opts.macosxVersionMin(),
816 opts.iphoneOSVersionMin(),
817 opts.logAllFiles());
818 }
819
820 };
821
822
823
824 template <>
825 bool Parser<ppc>::validFile(const uint8_t* fileContent, bool executableOrDyliborBundle)
826 {
827 const macho_header<P>* header = (const macho_header<P>*)fileContent;
828 if ( header->magic() != MH_MAGIC )
829 return false;
830 if ( header->cputype() != CPU_TYPE_POWERPC )
831 return false;
832 switch ( header->filetype() ) {
833 case MH_DYLIB:
834 case MH_DYLIB_STUB:
835 return true;
836 case MH_BUNDLE:
837 if ( executableOrDyliborBundle )
838 return true;
839 else
840 throw "can't link with bundle (MH_BUNDLE) only dylibs (MH_DYLIB)";
841 case MH_EXECUTE:
842 if ( executableOrDyliborBundle )
843 return true;
844 else
845 throw "can't link with a main executable";
846 default:
847 return false;
848 }
849 }
850
851 template <>
852 bool Parser<ppc64>::validFile(const uint8_t* fileContent, bool executableOrDyliborBundle)
853 {
854 const macho_header<P>* header = (const macho_header<P>*)fileContent;
855 if ( header->magic() != MH_MAGIC_64 )
856 return false;
857 if ( header->cputype() != CPU_TYPE_POWERPC64 )
858 return false;
859 switch ( header->filetype() ) {
860 case MH_DYLIB:
861 case MH_DYLIB_STUB:
862 return true;
863 case MH_BUNDLE:
864 if ( executableOrDyliborBundle )
865 return true;
866 else
867 throw "can't link with bundle (MH_BUNDLE) only dylibs (MH_DYLIB)";
868 case MH_EXECUTE:
869 if ( executableOrDyliborBundle )
870 return true;
871 else
872 throw "can't link with a main executable";
873 default:
874 return false;
875 }
876 }
877
878 template <>
879 bool Parser<x86>::validFile(const uint8_t* fileContent, bool executableOrDyliborBundle)
880 {
881 const macho_header<P>* header = (const macho_header<P>*)fileContent;
882 if ( header->magic() != MH_MAGIC )
883 return false;
884 if ( header->cputype() != CPU_TYPE_I386 )
885 return false;
886 switch ( header->filetype() ) {
887 case MH_DYLIB:
888 case MH_DYLIB_STUB:
889 return true;
890 case MH_BUNDLE:
891 if ( executableOrDyliborBundle )
892 return true;
893 else
894 throw "can't link with bundle (MH_BUNDLE) only dylibs (MH_DYLIB)";
895 case MH_EXECUTE:
896 if ( executableOrDyliborBundle )
897 return true;
898 else
899 throw "can't link with a main executable";
900 default:
901 return false;
902 }
903 }
904
905 template <>
906 bool Parser<x86_64>::validFile(const uint8_t* fileContent, bool executableOrDyliborBundle)
907 {
908 const macho_header<P>* header = (const macho_header<P>*)fileContent;
909 if ( header->magic() != MH_MAGIC_64 )
910 return false;
911 if ( header->cputype() != CPU_TYPE_X86_64 )
912 return false;
913 switch ( header->filetype() ) {
914 case MH_DYLIB:
915 case MH_DYLIB_STUB:
916 return true;
917 case MH_BUNDLE:
918 if ( executableOrDyliborBundle )
919 return true;
920 else
921 throw "can't link with bundle (MH_BUNDLE) only dylibs (MH_DYLIB)";
922 case MH_EXECUTE:
923 if ( executableOrDyliborBundle )
924 return true;
925 else
926 throw "can't link with a main executable";
927 default:
928 return false;
929 }
930 }
931
932 template <>
933 bool Parser<arm>::validFile(const uint8_t* fileContent, bool executableOrDyliborBundle)
934 {
935 const macho_header<P>* header = (const macho_header<P>*)fileContent;
936 if ( header->magic() != MH_MAGIC )
937 return false;
938 if ( header->cputype() != CPU_TYPE_ARM )
939 return false;
940 switch ( header->filetype() ) {
941 case MH_DYLIB:
942 case MH_DYLIB_STUB:
943 return true;
944 case MH_BUNDLE:
945 if ( executableOrDyliborBundle )
946 return true;
947 else
948 throw "can't link with bundle (MH_BUNDLE) only dylibs (MH_DYLIB)";
949 case MH_EXECUTE:
950 if ( executableOrDyliborBundle )
951 return true;
952 else
953 throw "can't link with a main executable";
954 default:
955 return false;
956 }
957 }
958
959
960
961 //
962 // main function used by linker to instantiate ld::Files
963 //
964 ld::dylib::File* parse(const uint8_t* fileContent, uint64_t fileLength,
965 const char* path, time_t modTime, const Options& opts, uint32_t ordinal, bool bundleLoader)
966 {
967 switch ( opts.architecture() ) {
968 case CPU_TYPE_X86_64:
969 if ( Parser<x86_64>::validFile(fileContent, bundleLoader) )
970 return Parser<x86_64>::parse(fileContent, fileLength, path, modTime, ordinal, opts);
971 break;
972 case CPU_TYPE_I386:
973 if ( Parser<x86>::validFile(fileContent, bundleLoader) )
974 return Parser<x86>::parse(fileContent, fileLength, path, modTime, ordinal, opts);
975 break;
976 case CPU_TYPE_ARM:
977 if ( Parser<arm>::validFile(fileContent, bundleLoader) )
978 return Parser<arm>::parse(fileContent, fileLength, path, modTime, ordinal, opts);
979 break;
980 case CPU_TYPE_POWERPC:
981 if ( Parser<ppc>::validFile(fileContent, bundleLoader) )
982 return Parser<ppc>::parse(fileContent, fileLength, path, modTime, ordinal, opts);
983 break;
984 case CPU_TYPE_POWERPC64:
985 if ( Parser<ppc64>::validFile(fileContent, bundleLoader) )
986 return Parser<ppc64>::parse(fileContent, fileLength, path, modTime, ordinal, opts);
987 break;
988 }
989 return NULL;
990 }
991
992
993 }; // namespace dylib
994 }; // namespace mach_o
995
996