1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
3 * Copyright (c) 2005-2011 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>
38 #include "Architectures.hpp"
39 #include "Bitcode.hpp"
40 #include "MachOFileAbstraction.hpp"
41 #include "MachOTrie.hpp"
42 #include "generic_dylib_file.hpp"
43 #include "macho_dylib_file.h"
44 #include "../code-sign-blobs/superblob.h"
50 // The reader for a dylib extracts all exported symbols names from the memory-mapped
51 // dylib, builds a hash table, then unmaps the file. This is an important memory
52 // savings for large dylibs.
55 class File final
: public generic::dylib::File
<A
>
57 using Base
= generic::dylib::File
<A
>;
60 static bool validFile(const uint8_t* fileContent
, bool executableOrDylib
, bool subTypeMustMatch
=false);
61 File(const uint8_t* fileContent
, uint64_t fileLength
, const char* path
,
62 time_t mTime
, ld::File::Ordinal ordinal
, bool linkingFlatNamespace
,
63 bool linkingMainExecutable
, bool hoistImplicitPublicDylibs
,
64 const ld::VersionSet
& platforms
, bool allowWeakImports
,
65 bool allowSimToMacOSX
, bool addVers
, bool buildingForSimulator
,
66 bool logAllFiles
, const char* installPath
,
67 bool indirectDylib
, bool ignoreMismatchPlatform
, bool usingBitcode
);
68 virtual ~File() noexcept {}
69 virtual const ld::VersionSet
& platforms() const { return this->_platforms
; }
72 using P
= typename
A::P
;
73 using E
= typename
A::P::E
;
74 using pint_t
= typename
A::P::uint_t
;
76 void addDyldFastStub();
77 void buildExportHashTableFromExportInfo(const macho_dyld_info_command
<P
>* dyldInfo
,
78 const uint8_t* fileContent
);
79 void buildExportHashTableFromSymbolTable(const macho_dysymtab_command
<P
>* dynamicInfo
,
80 const macho_nlist
<P
>* symbolTable
, const char* strings
,
81 const uint8_t* fileContent
);
82 void addSymbol(const char* name
, bool weakDef
= false, bool tlv
= false, pint_t address
= 0);
83 static const char* objCInfoSegmentName();
84 static const char* objCInfoSectionName();
85 static bool useSimulatorVariant();
89 uint32_t _linkeditStartOffset
;
93 template <> const char* File
<x86_64
>::objCInfoSegmentName() { return "__DATA"; }
94 template <> const char* File
<arm
>::objCInfoSegmentName() { return "__DATA"; }
95 template <typename A
> const char* File
<A
>::objCInfoSegmentName() { return "__OBJC"; }
97 template <> const char* File
<x86_64
>::objCInfoSectionName() { return "__objc_imageinfo"; }
98 template <> const char* File
<arm
>::objCInfoSectionName() { return "__objc_imageinfo"; }
99 template <typename A
> const char* File
<A
>::objCInfoSectionName() { return "__image_info"; }
101 template <> bool File
<x86
>::useSimulatorVariant() { return true; }
102 template <> bool File
<x86_64
>::useSimulatorVariant() { return true; }
103 template <typename A
> bool File
<A
>::useSimulatorVariant() { return false; }
105 template <typename A
>
106 File
<A
>::File(const uint8_t* fileContent
, uint64_t fileLength
, const char* path
, time_t mTime
,
107 ld::File::Ordinal ord
, bool linkingFlatNamespace
, bool linkingMainExecutable
,
108 bool hoistImplicitPublicDylibs
, const ld::VersionSet
& platforms
, bool allowWeakImports
,
109 bool allowSimToMacOSX
, bool addVers
, bool buildingForSimulator
, bool logAllFiles
,
110 const char* targetInstallPath
, bool indirectDylib
, bool ignoreMismatchPlatform
, bool usingBitcode
)
111 : Base(strdup(path
), mTime
, ord
, platforms
, allowWeakImports
, linkingFlatNamespace
,
112 hoistImplicitPublicDylibs
, allowSimToMacOSX
, addVers
), _fileLength(fileLength
), _linkeditStartOffset(0)
114 const macho_header
<P
>* header
= (const macho_header
<P
>*)fileContent
;
115 const uint32_t cmd_count
= header
->ncmds();
116 const macho_load_command
<P
>* const cmds
= (macho_load_command
<P
>*)((char*)header
+ sizeof(macho_header
<P
>));
117 const macho_load_command
<P
>* const cmdsEnd
= (macho_load_command
<P
>*)((char*)header
+ sizeof(macho_header
<P
>) + header
->sizeofcmds());
119 // write out path for -t option
121 printf("%s\n", path
);
123 // a "blank" stub has zero load commands
124 if ( (header
->filetype() == MH_DYLIB_STUB
) && (cmd_count
== 0) ) {
125 // no further processing needed
126 munmap((caddr_t
)fileContent
, fileLength
);
131 // optimize the case where we know there is no reason to look at indirect dylibs
132 this->_noRexports
= (header
->flags() & MH_NO_REEXPORTED_DYLIBS
)
133 || (header
->filetype() == MH_BUNDLE
)
134 || (header
->filetype() == MH_EXECUTE
); // bundles and exectuables can be used via -bundle_loader
135 this->_hasWeakExports
= (header
->flags() & MH_WEAK_DEFINES
);
136 this->_deadStrippable
= (header
->flags() & MH_DEAD_STRIPPABLE_DYLIB
);
137 this->_appExtensionSafe
= (header
->flags() & MH_APP_EXTENSION_SAFE
);
139 // pass 1: get pointers, and see if this dylib uses compressed LINKEDIT format
140 const macho_dysymtab_command
<P
>* dynamicInfo
= nullptr;
141 const macho_dyld_info_command
<P
>* dyldInfo
= nullptr;
142 const macho_nlist
<P
>* symbolTable
= nullptr;
143 const macho_symtab_command
<P
>* symtab
= nullptr;
144 const char* strings
= nullptr;
145 bool compressedLinkEdit
= false;
146 uint32_t dependentLibCount
= 0;
147 ld::VersionSet lcPlatforms
;
148 const macho_load_command
<P
>* cmd
= cmds
;
149 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
150 macho_dylib_command
<P
>* dylibID
;
151 uint32_t cmdLength
= cmd
->cmdsize();
152 switch (cmd
->cmd()) {
154 symtab
= (macho_symtab_command
<P
>*)cmd
;
155 symbolTable
= (const macho_nlist
<P
>*)((char*)header
+ symtab
->symoff());
156 strings
= (char*)header
+ symtab
->stroff();
157 if ( (symtab
->stroff() + symtab
->strsize()) > fileLength
)
158 throwf("mach-o string pool extends beyond end of file in %s", path
);
161 dynamicInfo
= (macho_dysymtab_command
<P
>*)cmd
;
164 case LC_DYLD_INFO_ONLY
:
165 dyldInfo
= (macho_dyld_info_command
<P
>*)cmd
;
166 compressedLinkEdit
= true;
169 dylibID
= (macho_dylib_command
<P
>*)cmd
;
170 if ( dylibID
->name_offset() > cmdLength
)
171 throwf("malformed mach-o: LC_ID_DYLIB load command has offset (%u) outside its size (%u)", dylibID
->name_offset(), cmdLength
);
172 if ( (dylibID
->name_offset() + strlen(dylibID
->name()) + 1) > cmdLength
)
173 throwf("malformed mach-o: LC_ID_DYLIB load command string extends beyond end of load command");
174 this->_dylibInstallPath
= strdup(dylibID
->name());
175 this->_dylibTimeStamp
= dylibID
->timestamp();
176 this->_dylibCurrentVersion
= dylibID
->current_version();
177 this->_dylibCompatibilityVersion
= dylibID
->compatibility_version();
178 this->_hasPublicInstallName
= this->isPublicLocation(this->_dylibInstallPath
);
181 case LC_LOAD_WEAK_DYLIB
:
184 case LC_REEXPORT_DYLIB
:
185 this->_explictReExportFound
= true;
188 case LC_SUB_FRAMEWORK
:
189 this->_parentUmbrella
= strdup(((macho_sub_framework_command
<P
>*)cmd
)->umbrella());
192 this->_allowableClients
.push_back(strdup(((macho_sub_client_command
<P
>*)cmd
)->client()));
193 // <rdar://problem/20627554> Don't hoist "public" (in /usr/lib/) dylibs that should not be directly linked
194 this->_hasPublicInstallName
= false;
197 this->_rpaths
.push_back(strdup(((macho_rpath_command
<P
>*)cmd
)->path()));
199 case LC_VERSION_MIN_MACOSX
:
200 case LC_VERSION_MIN_IPHONEOS
:
201 case LC_VERSION_MIN_WATCHOS
:
202 case LC_VERSION_MIN_TVOS
:
203 lcPlatforms
.add({Options::platformForLoadCommand(cmd
->cmd(), useSimulatorVariant()), ((macho_version_min_command
<P
>*)cmd
)->version()});
205 case LC_BUILD_VERSION
:
207 const macho_build_version_command
<P
>* buildVersCmd
= (macho_build_version_command
<P
>*)cmd
;
208 lcPlatforms
.add({(ld::Platform
)buildVersCmd
->platform(), buildVersCmd
->minos()});
211 case LC_CODE_SIGNATURE
:
213 case macho_segment_command
<P
>::CMD
:
214 // check for Objective-C info
215 if ( strncmp(((macho_segment_command
<P
>*)cmd
)->segname(), objCInfoSegmentName(), 6) == 0 ) {
216 const macho_segment_command
<P
>* segment
= (macho_segment_command
<P
>*)cmd
;
217 const macho_section
<P
>* const sectionsStart
= (macho_section
<P
>*)((char*)segment
+ sizeof(macho_segment_command
<P
>));
218 const macho_section
<P
>* const sectionsEnd
= §ionsStart
[segment
->nsects()];
219 for (const macho_section
<P
>* sect
=sectionsStart
; sect
< sectionsEnd
; ++sect
) {
220 if ( strncmp(sect
->sectname(), objCInfoSectionName(), strlen(objCInfoSectionName())) == 0 ) {
221 // struct objc_image_info {
222 // uint32_t version; // initially 0
225 // #define OBJC_IMAGE_SUPPORTS_GC 2
226 // #define OBJC_IMAGE_GC_ONLY 4
227 // #define OBJC_IMAGE_IS_SIMULATED 32
229 const uint32_t* contents
= (uint32_t*)(&fileContent
[sect
->offset()]);
230 if ( (sect
->size() >= 8) && (contents
[0] == 0) ) {
231 uint32_t flags
= E::get32(contents
[1]);
232 this->_swiftVersion
= ((flags
>> 8) & 0xFF);
234 else if ( sect
->size() > 0 ) {
235 warning("can't parse %s/%s section in %s", objCInfoSegmentName(), objCInfoSectionName(), path
);
240 // Construct bitcode if there is a bitcode bundle section in the dylib
241 // Record the size of the section because the content is not checked
242 else if ( strcmp(((macho_segment_command
<P
>*)cmd
)->segname(), "__LLVM") == 0 ) {
243 const macho_section
<P
>* const sect
= (macho_section
<P
>*)((char*)cmd
+ sizeof(macho_segment_command
<P
>));
244 if ( strncmp(sect
->sectname(), "__bundle", 8) == 0 )
245 this->_bitcode
= std::unique_ptr
<ld::Bitcode
>(new ld::Bitcode(NULL
, sect
->size()));
247 else if ( strcmp(((macho_segment_command
<P
>*)cmd
)->segname(), "__LINKEDIT") == 0 ) {
248 _linkeditStartOffset
= ((macho_segment_command
<P
>*)cmd
)->fileoff();
251 cmd
= (const macho_load_command
<P
>*)(((char*)cmd
)+cmdLength
);
253 throwf("malformed dylb, load command #%d is outside size of load commands in %s", i
, path
);
255 // arm/arm64 objects are default to ios platform if not set.
256 // rdar://problem/21746314
257 if (lcPlatforms
.empty() &&
258 (std::is_same
<A
, arm
>::value
|| std::is_same
<A
, arm64
>::value
))
259 lcPlatforms
.add({ld::kPlatform_iOS
, 0});
261 // check cross-linking
262 platforms
.forEach(^(ld::Platform platform
, uint32_t version
, bool &stop
) {
263 if (!lcPlatforms
.contains(platform
) ) {
264 this->_wrongOS
= true;
265 if ( this->_addVersionLoadCommand
&& !indirectDylib
&& !ignoreMismatchPlatform
) {
266 if (buildingForSimulator
&& !this->_allowSimToMacOSXLinking
) {
268 throwf("building for %s simulator, but linking against dylib built for %s,",
269 platforms
.to_str().c_str(), lcPlatforms
.to_str().c_str());
271 warning("URGENT: building for %s simulator, but linking against dylib (%s) built for %s. "
272 "Note: This will be an error in the future.",
273 platforms
.to_str().c_str(), path
, lcPlatforms
.to_str().c_str());
277 throwf("building for %s, but linking against dylib built for %s,",
278 platforms
.to_str().c_str(), lcPlatforms
.to_str().c_str());
279 else if ( (getenv("RC_XBS") != NULL
) && (getenv("RC_BUILDIT") == NULL
) ) // FIXME: remove after platform bringup
280 warning("URGENT: building for %s, but linking against dylib (%s) built for %s. "
281 "Note: This will be an error in the future.",
282 platforms
.to_str().c_str(), path
, lcPlatforms
.to_str().c_str());
287 // figure out if we need to examine dependent dylibs
288 // with compressed LINKEDIT format, MH_NO_REEXPORTED_DYLIBS can be trusted
289 bool processDependentLibraries
= true;
290 if ( compressedLinkEdit
&& this->_noRexports
&& !linkingFlatNamespace
)
291 processDependentLibraries
= false;
293 if ( processDependentLibraries
) {
294 // pass 2 builds list of all dependent libraries
295 this->_dependentDylibs
.reserve(dependentLibCount
);
297 unsigned int reExportDylibCount
= 0;
298 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
299 uint32_t cmdLength
= cmd
->cmdsize();
300 const macho_dylib_command
<P
>* dylibCmd
= (macho_dylib_command
<P
>*)cmd
;
301 switch (cmd
->cmd()) {
303 case LC_LOAD_WEAK_DYLIB
:
304 // with new linkedit format only care about LC_REEXPORT_DYLIB
305 if ( compressedLinkEdit
&& !linkingFlatNamespace
)
307 case LC_REEXPORT_DYLIB
:
308 ++reExportDylibCount
;
309 if ( dylibCmd
->name_offset() > cmdLength
)
310 throwf("malformed mach-o: LC_*_DYLIB load command has offset (%u) outside its size (%u)", dylibCmd
->name_offset(), cmdLength
);
311 if ( (dylibCmd
->name_offset() + strlen(dylibCmd
->name()) + 1) > cmdLength
)
312 throwf("malformed mach-o: LC_*_DYLIB load command string extends beyond end of load command");
313 const char *path
= strdup(dylibCmd
->name());
314 bool reExport
= (cmd
->cmd() == LC_REEXPORT_DYLIB
);
315 if ( (targetInstallPath
== nullptr) || (strcmp(targetInstallPath
, path
) != 0) )
316 this->_dependentDylibs
.emplace_back(path
, reExport
);
319 cmd
= (const macho_load_command
<P
>*)(((char*)cmd
)+cmdLength
);
321 // verify MH_NO_REEXPORTED_DYLIBS bit was correct
322 if ( compressedLinkEdit
&& !linkingFlatNamespace
) {
323 if ( reExportDylibCount
== 0 )
324 throwf("malformed dylib has MH_NO_REEXPORTED_DYLIBS flag but no LC_REEXPORT_DYLIB load commands: %s", path
);
326 // pass 3 add re-export info
328 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
329 const char* frameworkLeafName
;
330 const char* dylibBaseName
;
331 switch (cmd
->cmd()) {
332 case LC_SUB_UMBRELLA
:
333 frameworkLeafName
= ((macho_sub_umbrella_command
<P
>*)cmd
)->sub_umbrella();
334 for (auto &dep
: this->_dependentDylibs
) {
335 const char* dylibName
= dep
.path
;
336 const char* lastSlash
= strrchr(dylibName
, '/');
337 if ( (lastSlash
!= nullptr) && (strcmp(&lastSlash
[1], frameworkLeafName
) == 0) )
342 dylibBaseName
= ((macho_sub_library_command
<P
>*)cmd
)->sub_library();
343 for (auto &dep
: this->_dependentDylibs
) {
344 const char* dylibName
= dep
.path
;
345 const char* lastSlash
= strrchr(dylibName
, '/');
346 const char* leafStart
= &lastSlash
[1];
347 if ( lastSlash
== nullptr )
348 leafStart
= dylibName
;
349 const char* firstDot
= strchr(leafStart
, '.');
350 int len
= strlen(leafStart
);
351 if ( firstDot
!= nullptr )
352 len
= firstDot
- leafStart
;
353 if ( strncmp(leafStart
, dylibBaseName
, len
) == 0 )
358 cmd
= (const macho_load_command
<P
>*)(((char*)cmd
)+cmd
->cmdsize());
362 // if framework, capture framework name
363 if ( this->_dylibInstallPath
!= NULL
) {
364 const char* lastSlash
= strrchr(this->_dylibInstallPath
, '/');
365 if ( lastSlash
!= NULL
) {
366 const char* leafName
= lastSlash
+1;
367 char frname
[strlen(leafName
)+32];
368 strcpy(frname
, leafName
);
369 strcat(frname
, ".framework/");
371 if ( strstr(this->_dylibInstallPath
, frname
) != NULL
)
372 this->_frameworkName
= leafName
;
376 // validate minimal load commands
377 if ( (this->_dylibInstallPath
== nullptr) && ((header
->filetype() == MH_DYLIB
) || (header
->filetype() == MH_DYLIB_STUB
)) )
378 throwf("dylib %s missing LC_ID_DYLIB load command", path
);
379 if ( dyldInfo
== nullptr ) {
380 if ( symbolTable
== nullptr )
381 throw "binary missing LC_SYMTAB load command";
382 if ( dynamicInfo
== nullptr )
383 throw "binary missing LC_DYSYMTAB load command";
386 if ( symtab
!= nullptr ) {
387 if ( symtab
->symoff() < _linkeditStartOffset
)
388 throwf("malformed mach-o, symbol table not in __LINKEDIT");
389 if ( symtab
->stroff() < _linkeditStartOffset
)
390 throwf("malformed mach-o, symbol table strings not in __LINKEDIT");
393 // if linking flat and this is a flat dylib, create one atom that references all imported symbols
394 if ( linkingFlatNamespace
&& linkingMainExecutable
&& ((header
->flags() & MH_TWOLEVEL
) == 0) ) {
395 std::vector
<const char*> importNames
;
396 importNames
.reserve(dynamicInfo
->nundefsym());
397 const macho_nlist
<P
>* start
= &symbolTable
[dynamicInfo
->iundefsym()];
398 const macho_nlist
<P
>* end
= &start
[dynamicInfo
->nundefsym()];
399 for (const macho_nlist
<P
>* sym
=start
; sym
< end
; ++sym
) {
400 importNames
.push_back(&strings
[sym
->n_strx()]);
402 this->_importAtom
= new generic::dylib::ImportAtom
<A
>(*this, importNames
);
406 if ( dyldInfo
!= nullptr )
407 buildExportHashTableFromExportInfo(dyldInfo
, fileContent
);
409 buildExportHashTableFromSymbolTable(dynamicInfo
, symbolTable
, strings
, fileContent
);
412 munmap((caddr_t
)fileContent
, fileLength
);
415 template <typename A
>
416 void File
<A
>::buildExportHashTableFromSymbolTable(const macho_dysymtab_command
<P
>* dynamicInfo
,
417 const macho_nlist
<P
>* symbolTable
,
418 const char* strings
, const uint8_t* fileContent
)
420 if ( dynamicInfo
->tocoff() == 0 ) {
421 if ( this->_s_logHashtable
)
422 fprintf(stderr
, "ld: building hashtable of %u toc entries for %s\n", dynamicInfo
->nextdefsym(), this->path());
423 const macho_nlist
<P
>* start
= &symbolTable
[dynamicInfo
->iextdefsym()];
424 const macho_nlist
<P
>* end
= &start
[dynamicInfo
->nextdefsym()];
425 this->_atoms
.reserve(dynamicInfo
->nextdefsym()); // set initial bucket count
426 for (const macho_nlist
<P
>* sym
=start
; sym
< end
; ++sym
) {
427 this->addSymbol(&strings
[sym
->n_strx()], (sym
->n_desc() & N_WEAK_DEF
) != 0, false, sym
->n_value());
431 int32_t count
= dynamicInfo
->ntoc();
432 this->_atoms
.reserve(count
); // set initial bucket count
433 if ( this->_s_logHashtable
)
434 fprintf(stderr
, "ld: building hashtable of %u entries for %s\n", count
, this->path());
435 const auto* toc
= reinterpret_cast<const dylib_table_of_contents
*>(fileContent
+ dynamicInfo
->tocoff());
436 for (int32_t i
= 0; i
< count
; ++i
) {
437 const uint32_t index
= E::get32(toc
[i
].symbol_index
);
438 const macho_nlist
<P
>* sym
= &symbolTable
[index
];
439 this->addSymbol(&strings
[sym
->n_strx()], (sym
->n_desc() & N_WEAK_DEF
) != 0, false, sym
->n_value());
443 // special case old libSystem
444 if ( (this->_dylibInstallPath
!= nullptr) && (strcmp(this->_dylibInstallPath
, "/usr/lib/libSystem.B.dylib") == 0) )
449 template <typename A
>
450 void File
<A
>::buildExportHashTableFromExportInfo(const macho_dyld_info_command
<P
>* dyldInfo
,
451 const uint8_t* fileContent
)
453 if ( this->_s_logHashtable
)
454 fprintf(stderr
, "ld: building hashtable from export info in %s\n", this->path());
455 if ( dyldInfo
->export_size() > 0 ) {
456 const uint8_t* start
= fileContent
+ dyldInfo
->export_off();
457 const uint8_t* end
= &start
[dyldInfo
->export_size()];
458 if ( (dyldInfo
->export_off() + dyldInfo
->export_size()) > _fileLength
)
459 throwf("malformed mach-o dylib, exports trie extends beyond end of file, ");
460 std::vector
<mach_o::trie::Entry
> list
;
461 parseTrie(start
, end
, list
);
462 for (const auto &entry
: list
)
463 this->addSymbol(entry
.name
,
464 entry
.flags
& EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION
,
465 (entry
.flags
& EXPORT_SYMBOL_FLAGS_KIND_MASK
) == EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL
,
470 template <typename A
>
471 void File
<A
>::addSymbol(const char* name
, bool weakDef
, bool tlv
, pint_t address
)
473 __block
uint32_t linkMinOSVersion
= 0;
475 this->platforms().forEach(^(ld::Platform platform
, uint32_t version
, bool &stop
) {
476 //FIXME hack to handle symbol versioning in a zippered world.
477 //This will need to be rethought
478 if (linkMinOSVersion
== 0)
479 linkMinOSVersion
= version
;
480 if (platform
== ld::kPlatform_macOS
)
481 linkMinOSVersion
= version
;
484 // symbols that start with $ld$ are meta-data to the static linker
485 // <rdar://problem/5182537> need way for ld and dyld to see different exported symbols in a dylib
486 if ( strncmp(name
, "$ld$", 4) == 0 ) {
487 // $ld$ <action> $ <condition> $ <symbol-name>
488 const char* symAction
= &name
[4];
489 const char* symCond
= strchr(symAction
, '$');
490 if ( symCond
!= nullptr ) {
492 sprintf(curOSVers
, "$os%d.%d$", (linkMinOSVersion
>> 16), ((linkMinOSVersion
>> 8) & 0xFF));
493 if ( strncmp(symCond
, curOSVers
, strlen(curOSVers
)) == 0 ) {
494 const char* symName
= strchr(&symCond
[1], '$');
495 if ( symName
!= nullptr ) {
497 if ( strncmp(symAction
, "hide$", 5) == 0 ) {
498 if ( this->_s_logHashtable
)
499 fprintf(stderr
, " adding %s to ignore set for %s\n", symName
, this->path());
500 this->_ignoreExports
.insert(strdup(symName
));
503 else if ( strncmp(symAction
, "add$", 4) == 0 ) {
504 this->addSymbol(symName
, weakDef
);
507 else if ( strncmp(symAction
, "weak$", 5) == 0 ) {
508 if ( !this->_allowWeakImports
)
509 this->_ignoreExports
.insert(strdup(symName
));
511 else if ( strncmp(symAction
, "install_name$", 13) == 0 ) {
512 this->_dylibInstallPath
= strdup(symName
);
513 this->_installPathOverride
= true;
514 // <rdar://problem/14448206> CoreGraphics redirects to ApplicationServices, but with wrong compat version
515 if ( strcmp(this->_dylibInstallPath
, "/System/Library/Frameworks/ApplicationServices.framework/Versions/A/ApplicationServices") == 0 )
516 this->_dylibCompatibilityVersion
= Options::parseVersionNumber32("1.0");
519 else if ( strncmp(symAction
, "compatibility_version$", 22) == 0 ) {
520 this->_dylibCompatibilityVersion
= Options::parseVersionNumber32(symName
);
524 warning("bad symbol action: %s in dylib %s", name
, this->path());
530 warning("bad symbol condition: %s in dylib %s", name
, this->path());
534 // add symbol as possible export if we are not supposed to ignore it
535 if ( this->_ignoreExports
.count(name
) == 0 ) {
536 typename
Base::AtomAndWeak bucket
= { nullptr, weakDef
, tlv
, address
};
537 if ( this->_s_logHashtable
)
538 fprintf(stderr
, " adding %s to hash table for %s\n", name
, this->path());
539 this->_atoms
[strdup(name
)] = bucket
;
544 void File
<x86_64
>::addDyldFastStub()
546 addSymbol("dyld_stub_binder");
550 void File
<x86
>::addDyldFastStub()
552 addSymbol("dyld_stub_binder");
555 template <typename A
>
556 void File
<A
>::addDyldFastStub()
561 template <typename A
>
565 using P
= typename
A::P
;
567 static bool validFile(const uint8_t* fileContent
, bool executableOrDyliborBundle
, bool subTypeMustMatch
=false, uint32_t subType
=0);
568 static const char* fileKind(const uint8_t* fileContent
);
569 static ld::dylib::File
* parse(const uint8_t* fileContent
, uint64_t fileLength
, const char* path
,
570 time_t mTime
, ld::File::Ordinal ordinal
, const Options
& opts
,
573 return new File
<A
>(fileContent
, fileLength
, path
, mTime
, ordinal
, opts
.flatNamespace(),
574 opts
.linkingMainExecutable(), opts
.implicitlyLinkIndirectPublicDylibs(),
575 opts
.platforms(), opts
.allowWeakImports(),
576 opts
.allowSimulatorToLinkWithMacOSX(), opts
.addVersionLoadCommand(),
577 opts
.targetIOSSimulator(), opts
.logAllFiles(), opts
.installPath(),
578 indirectDylib
, opts
.outputKind() == Options::kPreload
, opts
.bundleBitcode());
586 bool Parser
<x86
>::validFile(const uint8_t* fileContent
, bool executableOrDyliborBundle
, bool subTypeMustMatch
, uint32_t subType
)
588 const auto* header
= reinterpret_cast<const macho_header
<P
>*>(fileContent
);
589 if ( header
->magic() != MH_MAGIC
)
591 if ( header
->cputype() != CPU_TYPE_I386
)
593 switch ( header
->filetype() ) {
598 if ( executableOrDyliborBundle
)
601 throw "can't link with bundle (MH_BUNDLE) only dylibs (MH_DYLIB)";
603 if ( executableOrDyliborBundle
)
606 throw "can't link with a main executable";
613 bool Parser
<x86_64
>::validFile(const uint8_t* fileContent
, bool executableOrDyliborBundle
, bool subTypeMustMatch
, uint32_t subType
)
615 const auto* header
= reinterpret_cast<const macho_header
<P
>*>(fileContent
);
616 if ( header
->magic() != MH_MAGIC_64
)
618 if ( header
->cputype() != CPU_TYPE_X86_64
)
620 switch ( header
->filetype() ) {
625 if ( executableOrDyliborBundle
)
628 throw "can't link with bundle (MH_BUNDLE) only dylibs (MH_DYLIB)";
630 if ( executableOrDyliborBundle
)
633 throw "can't link with a main executable";
640 bool Parser
<arm
>::validFile(const uint8_t* fileContent
, bool executableOrDyliborBundle
, bool subTypeMustMatch
, uint32_t subType
)
642 const auto* header
= reinterpret_cast<const macho_header
<P
>*>(fileContent
);
643 if ( header
->magic() != MH_MAGIC
)
645 if ( header
->cputype() != CPU_TYPE_ARM
)
647 if ( subTypeMustMatch
&& (header
->cpusubtype() != subType
) )
649 switch ( header
->filetype() ) {
654 if ( executableOrDyliborBundle
)
657 throw "can't link with bundle (MH_BUNDLE) only dylibs (MH_DYLIB)";
659 if ( executableOrDyliborBundle
)
662 throw "can't link with a main executable";
671 bool Parser
<arm64
>::validFile(const uint8_t* fileContent
, bool executableOrDyliborBundle
, bool subTypeMustMatch
, uint32_t subType
)
673 const auto* header
= reinterpret_cast<const macho_header
<P
>*>(fileContent
);
674 if ( header
->magic() != MH_MAGIC_64
)
676 if ( header
->cputype() != CPU_TYPE_ARM64
)
678 switch ( header
->filetype() ) {
683 if ( executableOrDyliborBundle
)
686 throw "can't link with bundle (MH_BUNDLE) only dylibs (MH_DYLIB)";
688 if ( executableOrDyliborBundle
)
691 throw "can't link with a main executable";
698 bool isDylibFile(const uint8_t* fileContent
, cpu_type_t
* result
, cpu_subtype_t
* subResult
)
700 if ( Parser
<x86_64
>::validFile(fileContent
, false) ) {
701 *result
= CPU_TYPE_X86_64
;
702 const auto* header
= reinterpret_cast<const macho_header
<Pointer64
<LittleEndian
>>*>(fileContent
);
703 *subResult
= header
->cpusubtype();
706 if ( Parser
<x86
>::validFile(fileContent
, false) ) {
707 *result
= CPU_TYPE_I386
;
708 *subResult
= CPU_SUBTYPE_X86_ALL
;
711 if ( Parser
<arm
>::validFile(fileContent
, false) ) {
712 *result
= CPU_TYPE_ARM
;
713 const auto* header
= reinterpret_cast<const macho_header
<Pointer32
<LittleEndian
>>*>(fileContent
);
714 *subResult
= header
->cpusubtype();
717 if ( Parser
<arm64
>::validFile(fileContent
, false) ) {
718 *result
= CPU_TYPE_ARM64
;
719 const auto* header
= reinterpret_cast<const macho_header
<Pointer32
<LittleEndian
>>*>(fileContent
);
720 *subResult
= header
->cpusubtype();
727 const char* Parser
<x86
>::fileKind(const uint8_t* fileContent
)
729 const auto* header
= reinterpret_cast<const macho_header
<P
>*>(fileContent
);
730 if ( header
->magic() != MH_MAGIC
)
732 if ( header
->cputype() != CPU_TYPE_I386
)
738 const char* Parser
<x86_64
>::fileKind(const uint8_t* fileContent
)
740 const auto* header
= reinterpret_cast<const macho_header
<P
>*>(fileContent
);
741 if ( header
->magic() != MH_MAGIC_64
)
743 if ( header
->cputype() != CPU_TYPE_X86_64
)
749 const char* Parser
<arm
>::fileKind(const uint8_t* fileContent
)
751 const auto* header
= reinterpret_cast<const macho_header
<P
>*>(fileContent
);
752 if ( header
->magic() != MH_MAGIC
)
754 if ( header
->cputype() != CPU_TYPE_ARM
)
756 for (const auto* t
= archInfoArray
; t
->archName
!= nullptr; ++t
) {
757 if ( (t
->cpuType
== CPU_TYPE_ARM
) && ((cpu_subtype_t
)header
->cpusubtype() == t
->cpuSubType
) ) {
764 #if SUPPORT_ARCH_arm64
766 const char* Parser
<arm64
>::fileKind(const uint8_t* fileContent
)
768 const auto* header
= reinterpret_cast<const macho_header
<P
>*>(fileContent
);
769 if ( header
->magic() != MH_MAGIC_64
)
771 if ( header
->cputype() != CPU_TYPE_ARM64
)
779 // used by linker is error messages to describe mismatched files
781 const char* archName(const uint8_t* fileContent
)
783 if ( Parser
<x86_64
>::validFile(fileContent
, true) ) {
784 return Parser
<x86_64
>::fileKind(fileContent
);
786 if ( Parser
<x86
>::validFile(fileContent
, true) ) {
787 return Parser
<x86
>::fileKind(fileContent
);
789 if ( Parser
<arm
>::validFile(fileContent
, true) ) {
790 return Parser
<arm
>::fileKind(fileContent
);
792 #if SUPPORT_ARCH_arm64
793 if ( Parser
<arm64
>::validFile(fileContent
, true) ) {
794 return Parser
<arm64
>::fileKind(fileContent
);
801 static ld::dylib::File
* parseAsArchitecture(const uint8_t* fileContent
, uint64_t fileLength
, const char* path
,
802 time_t modTime
, const Options
& opts
, ld::File::Ordinal ordinal
,
803 bool bundleLoader
, bool indirectDylib
,
804 cpu_type_t architecture
, cpu_subtype_t subArchitecture
)
806 bool subTypeMustMatch
= opts
.enforceDylibSubtypesMatch();
807 switch ( architecture
) {
808 #if SUPPORT_ARCH_x86_64
809 case CPU_TYPE_X86_64
:
810 if ( Parser
<x86_64
>::validFile(fileContent
, bundleLoader
, subTypeMustMatch
, subArchitecture
) )
811 return Parser
<x86_64
>::parse(fileContent
, fileLength
, path
, modTime
, ordinal
, opts
, indirectDylib
);
814 #if SUPPORT_ARCH_i386
816 if ( Parser
<x86
>::validFile(fileContent
, bundleLoader
, subTypeMustMatch
, subArchitecture
) )
817 return Parser
<x86
>::parse(fileContent
, fileLength
, path
, modTime
, ordinal
, opts
, indirectDylib
);
820 #if SUPPORT_ARCH_arm_any
822 if ( Parser
<arm
>::validFile(fileContent
, bundleLoader
, subTypeMustMatch
, subArchitecture
) )
823 return Parser
<arm
>::parse(fileContent
, fileLength
, path
, modTime
, ordinal
, opts
, indirectDylib
);
826 #if SUPPORT_ARCH_arm64
828 if ( Parser
<arm64
>::validFile(fileContent
, bundleLoader
, subTypeMustMatch
, subArchitecture
) )
829 return Parser
<arm64
>::parse(fileContent
, fileLength
, path
, modTime
, ordinal
, opts
, indirectDylib
);
837 // main function used by linker to instantiate ld::Files
839 ld::dylib::File
* parse(const uint8_t* fileContent
, uint64_t fileLength
, const char* path
,
840 time_t modtime
, const Options
& opts
, ld::File::Ordinal ordinal
,
841 bool bundleLoader
, bool indirectDylib
)
843 // First make sure we are even a dylib with a known arch. If we aren't then there's no point in continuing.
844 if (!archName(fileContent
))
847 auto file
= parseAsArchitecture(fileContent
, fileLength
, path
, modtime
, opts
, ordinal
, bundleLoader
, indirectDylib
, opts
.architecture(), opts
.subArchitecture());
849 // If we've been provided with an architecture we can fall back to, try to parse the dylib as that instead.
850 if (!file
&& opts
.fallbackArchitecture()) {
851 warning("architecture %s not present in dylib file %s, attempting fallback", opts
.architectureName(), path
);
852 file
= parseAsArchitecture(fileContent
, fileLength
, path
, modtime
, opts
, ordinal
, bundleLoader
, indirectDylib
, opts
.fallbackArchitecture(), opts
.fallbackSubArchitecture());
860 }; // namespace dylib
861 }; // namespace mach_o