1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
3 * Copyright (c) 2005-2009 Apple Inc. All rights reserved.
5 * @APPLE_LICENSE_HEADER_START@
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
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.
22 * @APPLE_LICENSE_HEADER_END@
29 #include <sys/param.h>
36 #include <ext/hash_map>
37 #include <ext/hash_set>
39 #include "Architectures.hpp"
40 #include "MachOFileAbstraction.hpp"
41 #include "MachOTrie.hpp"
42 #include "macho_dylib_file.h"
50 template <typename A
> class File
;
54 // An ExportAtom has no content. It exists so that the linker can track which imported
55 // symbols came from which dynamic libraries.
58 class ExportAtom
: public ld::Atom
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
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
) { }
80 typedef typename
A::P P
;
81 typedef typename
A::P::uint_t pint_t
;
83 virtual ~ExportAtom() {}
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
97 class ImportAtom
: public ld::Atom
100 ImportAtom(File
<A
>& f
, std::vector
<const char*>& imports
);
102 // overrides of ld::Atom
103 virtual ld::File
* file() const { return &_file
; }
104 virtual bool translationUnitSource(const char** dir
, const char** nm
) const
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()]; }
115 typedef typename
A::P P
;
117 virtual ~ImportAtom() {}
121 mutable std::vector
<ld::Fixup
> _undefs
;
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
)
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
)));
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.
141 template <typename A
>
142 class File
: public ld::dylib::File
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
,
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
; }
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;
171 struct ReExportChain
{ ReExportChain
* prev
; File
<A
>* file
; };
173 void assertNoReExportCycles(ReExportChain
*);
176 typedef typename
A::P P
;
177 typedef typename
A::P::E E
;
178 typedef typename
A::P::uint_t pint_t
;
180 friend class ExportAtom
<A
>;
181 friend class ImportAtom
<A
>;
186 bool operator()(const char* left
, const char* right
) const { return (strcmp(left
, right
) == 0); }
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
;
192 struct Dependent
{ const char* path
; File
<A
>* dylib
; bool reExport
; };
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();
206 const ld::MacVersionMin _macVersionMin
;
207 const ld::IPhoneVersionMin _iPhoneVersionMin
;
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
;
220 bool _hasWeakExports
;
221 bool _deadStrippable
;
222 bool _hasPublicInstallName
;
223 mutable bool _providedAtom
;
224 bool _explictReExportFound
;
226 static bool _s_logHashtable
;
229 template <typename A
>
230 bool File
<A
>::_s_logHashtable
= false;
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"; }
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"; }
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)
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());
259 // write out path for -t option
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
);
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
);
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()) {
291 symtab
= (macho_symtab_command
<P
>*)cmd
;
292 symbolTable
= (const macho_nlist
<P
>*)((char*)header
+ symtab
->symoff());
293 strings
= (char*)header
+ symtab
->stroff();
296 dynamicInfo
= (macho_dysymtab_command
<P
>*)cmd
;
299 case LC_DYLD_INFO_ONLY
:
300 dyldInfo
= (macho_dyld_info_command
<P
>*)cmd
;
301 compressedLinkEdit
= true;
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
);
312 case LC_LOAD_WEAK_DYLIB
:
315 case LC_REEXPORT_DYLIB
:
316 _explictReExportFound
= true;
319 case LC_SUB_FRAMEWORK
:
320 _parentUmbrella
= strdup(((macho_sub_framework_command
<P
>*)cmd
)->umbrella());
323 _allowableClients
.push_back(strdup(((macho_sub_client_command
<P
>*)cmd
)->client()));
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
= §ionsStart
[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
337 // #define OBJC_IMAGE_SUPPORTS_GC 2
338 // #define OBJC_IMAGE_GC_ONLY 4
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
;
348 _objcContraint
= ld::File::objcConstraintRetainRelease
;
350 else if ( sect
->size() > 0 ) {
351 warning("can't parse %s/%s section in %s", objCInfoSegmentName(), objCInfoSectionName(), this->path());
357 cmd
= (const macho_load_command
<P
>*)(((char*)cmd
)+cmd
->cmdsize());
359 throwf("malformed dylb, load command #%d is outside size of load commands in %s", i
, pth
);
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;
368 if ( processDependentLibraries
) {
369 // pass 2 builds list of all dependent libraries
370 _dependentDylibs
.reserve(dependentLibCount
);
372 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
373 switch (cmd
->cmd()) {
375 case LC_LOAD_WEAK_DYLIB
:
376 // with new linkedit format only care about LC_REEXPORT_DYLIB
377 if ( compressedLinkEdit
&& !linkingFlatNamespace
)
379 case LC_REEXPORT_DYLIB
:
381 entry
.path
= strdup(((macho_dylib_command
<P
>*)cmd
)->name());
383 entry
.reExport
= (cmd
->cmd() == LC_REEXPORT_DYLIB
);
384 _dependentDylibs
.push_back(entry
);
387 cmd
= (const macho_load_command
<P
>*)(((char*)cmd
)+cmd
->cmdsize());
389 // verify MH_NO_REEXPORTED_DYLIBS bit was correct
390 if ( compressedLinkEdit
&& !linkingFlatNamespace
) {
391 assert(_dependentDylibs
.size() != 0);
393 // pass 3 add re-export info
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) )
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 )
425 cmd
= (const macho_load_command
<P
>*)(((char*)cmd
)+cmd
->cmdsize());
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";
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()]);
448 _importAtom
= new ImportAtom
<A
>(*this, importNames
);
452 if ( dyldInfo
!= NULL
)
453 buildExportHashTableFromExportInfo(dyldInfo
, fileContent
);
455 buildExportHashTableFromSymbolTable(dynamicInfo
, symbolTable
, strings
, fileContent
);
458 munmap((caddr_t
)fileContent
, fileLength
);
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
)
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());
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());
488 // special case old libSystem
489 if ( (_dylibInstallPath
!= NULL
) && (strcmp(_dylibInstallPath
, "/usr/lib/libSystem.B.dylib") == 0) )
494 template <typename A
>
495 void File
<A
>::buildExportHashTableFromExportInfo(const macho_dyld_info_command
<P
>* dyldInfo
,
496 const uint8_t* fileContent
)
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
,
514 void File
<x86_64
>::addDyldFastStub()
516 addSymbol("dyld_stub_binder", false, false, 0);
520 void File
<x86
>::addDyldFastStub()
522 addSymbol("dyld_stub_binder", false, false, 0);
525 template <typename A
>
526 void File
<A
>::addDyldFastStub()
531 template <typename A
>
532 void File
<A
>::addSymbol(const char* name
, bool weakDef
, bool tlv
, pint_t address
)
535 assert(_hasWeakExports
);
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
) {
546 if ( _macVersionMin
!= ld::macVersionUnset
) {
547 sprintf(curOSVers
, "$os%d.%d$", (_macVersionMin
>> 16), ((_macVersionMin
>> 8) & 0xFF));
549 else if ( _iPhoneVersionMin
!= ld::iPhoneVersionUnset
) {
550 sprintf(curOSVers
, "$os%d.%d$", (_iPhoneVersionMin
>> 16), ((_iPhoneVersionMin
>> 8) & 0xFF));
553 assert(0 && "targeting neither macosx nor iphoneos");
555 if ( strncmp(symCond
, curOSVers
, strlen(curOSVers
)) == 0 ) {
556 const char* symName
= strchr(&symCond
[1], '$');
557 if ( symName
!= NULL
) {
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
));
564 else if ( strncmp(symAction
, "add$", 4) == 0 ) {
565 this->addSymbol(symName
, weakDef
, false, 0);
569 warning("bad symbol action: %s in dylib %s", name
, this->path());
575 warning("bad symbol condition: %s in dylib %s", name
, this->path());
579 // add symbol as possible export if we are not supposed to ignore it
580 if ( _ignoreExports
.count(name
) == 0 ) {
583 bucket
.weak
= weakDef
;
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
;
592 template <typename A
>
593 bool File
<A
>::forEachAtom(ld::File::AtomHandler
& handler
) const
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
);
605 template <typename A
>
606 bool File
<A
>::hasWeakDefinition(const char* name
) const
608 // if supposed to ignore this export, then pretend I don't have it
609 if ( _ignoreExports
.count(name
) != 0 )
612 typename
NameToAtomMap::const_iterator pos
= _atoms
.find(name
);
613 if ( pos
!= _atoms
.end() ) {
614 return pos
->second
.weak
;
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
;
630 template <typename A
>
631 bool File
<A
>::containsOrReExports(const char* name
, bool* weakDef
, bool* tlv
, pint_t
* defAddress
) const
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
;
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
) )
654 template <typename A
>
655 bool File
<A
>::justInTimeforEachAtom(const char* name
, ld::File::AtomHandler
& handler
) const
657 // if supposed to ignore this export, then pretend I don't have it
658 if ( _ignoreExports
.count(name
) != 0 )
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
);
678 template <typename A
>
679 bool File
<A
>::isPublicLocation(const char* pth
)
681 // -no_implicit_dylibs disables this optimization
682 if ( ! _implicitlyLinkPublicDylibs
)
685 // /usr/lib is a public location
686 if ( (strncmp(pth
, "/usr/lib/", 9) == 0) && (strchr(&pth
[9], '/') == NULL
) )
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 )
707 template <typename A
>
708 void File
<A
>::processIndirectLibraries(ld::dylib::File::DylibHandler
* handler
, bool addImplicitDylibs
)
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());
717 else if ( _noRexports
) {
718 // MH_NO_REEXPORTED_DYLIBS bit set, then nothing to do
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();
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");
737 if ( log
) fprintf(stderr
, "processIndirectLibraries() parent is not directly linked, so parent=%s will re-export child=%s\n", this->installPath(), it
->path
);
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
);
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
755 if ( log
) fprintf(stderr
, "processIndirectLibraries() umbrella=%s will re-export child=%s\n", this->installPath(), it
->path
);
762 // check for re-export cycles
766 this->assertNoReExportCycles(&chain
);
769 template <typename A
>
770 void File
<A
>::assertNoReExportCycles(ReExportChain
* prev
)
772 // recursively check my re-exported dylibs
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());
785 if ( it
->dylib
!= NULL
)
786 it
->dylib
->assertNoReExportCycles(&chain
);
792 struct ParserOptions
{
795 bool addImplictDylibs
;
796 ld::MacVersionMin macOSMin
;
797 ld::IPhoneVersionMin iphoneOSMin
;
801 template <typename A
>
805 typedef typename
A::P P
;
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(),
825 bool Parser
<ppc
>::validFile(const uint8_t* fileContent
, bool executableOrDyliborBundle
)
827 const macho_header
<P
>* header
= (const macho_header
<P
>*)fileContent
;
828 if ( header
->magic() != MH_MAGIC
)
830 if ( header
->cputype() != CPU_TYPE_POWERPC
)
832 switch ( header
->filetype() ) {
837 if ( executableOrDyliborBundle
)
840 throw "can't link with bundle (MH_BUNDLE) only dylibs (MH_DYLIB)";
842 if ( executableOrDyliborBundle
)
845 throw "can't link with a main executable";
852 bool Parser
<ppc64
>::validFile(const uint8_t* fileContent
, bool executableOrDyliborBundle
)
854 const macho_header
<P
>* header
= (const macho_header
<P
>*)fileContent
;
855 if ( header
->magic() != MH_MAGIC_64
)
857 if ( header
->cputype() != CPU_TYPE_POWERPC64
)
859 switch ( header
->filetype() ) {
864 if ( executableOrDyliborBundle
)
867 throw "can't link with bundle (MH_BUNDLE) only dylibs (MH_DYLIB)";
869 if ( executableOrDyliborBundle
)
872 throw "can't link with a main executable";
879 bool Parser
<x86
>::validFile(const uint8_t* fileContent
, bool executableOrDyliborBundle
)
881 const macho_header
<P
>* header
= (const macho_header
<P
>*)fileContent
;
882 if ( header
->magic() != MH_MAGIC
)
884 if ( header
->cputype() != CPU_TYPE_I386
)
886 switch ( header
->filetype() ) {
891 if ( executableOrDyliborBundle
)
894 throw "can't link with bundle (MH_BUNDLE) only dylibs (MH_DYLIB)";
896 if ( executableOrDyliborBundle
)
899 throw "can't link with a main executable";
906 bool Parser
<x86_64
>::validFile(const uint8_t* fileContent
, bool executableOrDyliborBundle
)
908 const macho_header
<P
>* header
= (const macho_header
<P
>*)fileContent
;
909 if ( header
->magic() != MH_MAGIC_64
)
911 if ( header
->cputype() != CPU_TYPE_X86_64
)
913 switch ( header
->filetype() ) {
918 if ( executableOrDyliborBundle
)
921 throw "can't link with bundle (MH_BUNDLE) only dylibs (MH_DYLIB)";
923 if ( executableOrDyliborBundle
)
926 throw "can't link with a main executable";
933 bool Parser
<arm
>::validFile(const uint8_t* fileContent
, bool executableOrDyliborBundle
)
935 const macho_header
<P
>* header
= (const macho_header
<P
>*)fileContent
;
936 if ( header
->magic() != MH_MAGIC
)
938 if ( header
->cputype() != CPU_TYPE_ARM
)
940 switch ( header
->filetype() ) {
945 if ( executableOrDyliborBundle
)
948 throw "can't link with bundle (MH_BUNDLE) only dylibs (MH_DYLIB)";
950 if ( executableOrDyliborBundle
)
953 throw "can't link with a main executable";
962 // main function used by linker to instantiate ld::Files
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
)
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
);
973 if ( Parser
<x86
>::validFile(fileContent
, bundleLoader
) )
974 return Parser
<x86
>::parse(fileContent
, fileLength
, path
, modTime
, ordinal
, opts
);
977 if ( Parser
<arm
>::validFile(fileContent
, bundleLoader
) )
978 return Parser
<arm
>::parse(fileContent
, fileLength
, path
, modTime
, ordinal
, opts
);
980 case CPU_TYPE_POWERPC
:
981 if ( Parser
<ppc
>::validFile(fileContent
, bundleLoader
) )
982 return Parser
<ppc
>::parse(fileContent
, fileLength
, path
, modTime
, ordinal
, opts
);
984 case CPU_TYPE_POWERPC64
:
985 if ( Parser
<ppc64
>::validFile(fileContent
, bundleLoader
) )
986 return Parser
<ppc64
>::parse(fileContent
, fileLength
, path
, modTime
, ordinal
, opts
);
993 }; // namespace dylib
994 }; // namespace mach_o