]> git.saurik.com Git - apple/ld64.git/blob - src/ld/parsers/macho_dylib_file.cpp
0ba962cf36d98b52df86aef6401028a70eac279c
[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-2011 Apple Inc. All rights reserved.
4 *
5 * @APPLE_LICENSE_HEADER_START@
6 *
7 * This file contains Original Code and/or Modifications of Original Code
8 * as defined in and that are subject to the Apple Public Source License
9 * Version 2.0 (the 'License'). You may not use this file except in
10 * compliance with the License. Please obtain a copy of the License at
11 * http://www.opensource.apple.com/apsl/ and read it before using this
12 * file.
13 *
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
19 * Please see the License for the specific language governing rights and
20 * limitations under the License.
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24
25
26 #include <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 <map>
36 #include <algorithm>
37 #include <unordered_map>
38 #include <unordered_set>
39
40 #include "Architectures.hpp"
41 #include "Bitcode.hpp"
42 #include "MachOFileAbstraction.hpp"
43 #include "MachOTrie.hpp"
44 #include "macho_dylib_file.h"
45 #include "../code-sign-blobs/superblob.h"
46
47 namespace mach_o {
48 namespace dylib {
49
50
51 // forward reference
52 template <typename A> class File;
53
54
55 //
56 // An ExportAtom has no content. It exists so that the linker can track which imported
57 // symbols came from which dynamic libraries.
58 //
59 template <typename A>
60 class ExportAtom : public ld::Atom
61 {
62 public:
63 ExportAtom(const File<A>& f, const char* nm, bool weakDef,
64 bool tlv, typename A::P::uint_t address)
65 : ld::Atom(f._importProxySection, ld::Atom::definitionProxy,
66 (weakDef? ld::Atom::combineByName : ld::Atom::combineNever),
67 ld::Atom::scopeLinkageUnit,
68 (tlv ? ld::Atom::typeTLV : ld::Atom::typeUnclassified),
69 symbolTableNotIn, false, false, false, ld::Atom::Alignment(0)),
70 _file(f), _name(nm), _address(address) {}
71 // overrides of ld::Atom
72 virtual const ld::File* file() const { return &_file; }
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 const char* name() const { return "import-atom"; }
105 virtual uint64_t size() const { return 0; }
106 virtual uint64_t objectAddress() const { return 0; }
107 virtual void copyRawContent(uint8_t buffer[]) const { }
108 virtual void setScope(Scope) { }
109 virtual ld::Fixup::iterator fixupsBegin() const { return &_undefs[0]; }
110 virtual ld::Fixup::iterator fixupsEnd() const { return &_undefs[_undefs.size()]; }
111
112 protected:
113 typedef typename A::P P;
114
115 virtual ~ImportAtom() {}
116
117
118 File<A>& _file;
119 mutable std::vector<ld::Fixup> _undefs;
120 };
121
122 template <typename A>
123 ImportAtom<A>::ImportAtom(File<A>& f, std::vector<const char*>& imports)
124 : ld::Atom(f._flatDummySection, ld::Atom::definitionRegular, ld::Atom::combineNever, ld::Atom::scopeTranslationUnit,
125 ld::Atom::typeUnclassified, symbolTableNotIn, false, false, false, ld::Atom::Alignment(0)), _file(f)
126 {
127 for(std::vector<const char*>::iterator it=imports.begin(); it != imports.end(); ++it) {
128 _undefs.push_back(ld::Fixup(0, ld::Fixup::k1of1, ld::Fixup::kindNone, false, strdup(*it)));
129 }
130 }
131
132
133
134 //
135 // The reader for a dylib extracts all exported symbols names from the memory-mapped
136 // dylib, builds a hash table, then unmaps the file. This is an important memory
137 // savings for large dylibs.
138 //
139 template <typename A>
140 class File : public ld::dylib::File
141 {
142 public:
143 static bool validFile(const uint8_t* fileContent, bool executableOrDylib);
144 File(const uint8_t* fileContent, uint64_t fileLength, const char* path,
145 time_t mTime, ld::File::Ordinal ordinal, bool linkingFlatNamespace,
146 bool linkingMainExecutable, bool hoistImplicitPublicDylibs,
147 Options::Platform platform, uint32_t linkMinOSVersion, bool allowSimToMacOSX,
148 bool addVers, bool buildingForSimulator,
149 bool logAllFiles, const char* installPath,
150 bool indirectDylib, bool ignoreMismatchPlatform);
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 virtual uint8_t swiftVersion() const { return _swiftVersion; }
158 virtual uint32_t minOSVersion() const { return _minVersionInDylib; }
159 virtual uint32_t platformLoadCommand() const { return _platformInDylib; }
160
161 // overrides of ld::dylib::File
162 virtual void processIndirectLibraries(ld::dylib::File::DylibHandler*, bool);
163 virtual bool providedExportAtom() const { return _providedAtom; }
164 virtual const char* parentUmbrella() const { return _parentUmbrella; }
165 virtual const std::vector<const char*>* allowableClients() const { return _allowableClients.size() != 0 ? &_allowableClients : NULL; }
166 virtual bool hasWeakExternals() const { return _hasWeakExports; }
167 virtual bool deadStrippable() const { return _deadStrippable; }
168 virtual bool hasPublicInstallName() const{ return _hasPublicInstallName; }
169 virtual bool hasWeakDefinition(const char* name) const;
170 virtual bool allSymbolsAreWeakImported() const;
171 virtual bool installPathVersionSpecific() const { return _installPathOverride; }
172 virtual bool appExtensionSafe() const { return _appExtensionSafe; };
173 virtual ld::Bitcode* getBitcode() const { return _bitcode.get(); }
174
175 protected:
176 virtual void assertNoReExportCycles(ReExportChain*) const;
177
178 private:
179 typedef typename A::P P;
180 typedef typename A::P::E E;
181 typedef typename A::P::uint_t pint_t;
182
183 friend class ExportAtom<A>;
184 friend class ImportAtom<A>;
185
186 struct CStringHash {
187 std::size_t operator()(const char* __s) const {
188 unsigned long __h = 0;
189 for ( ; *__s; ++__s)
190 __h = 5 * __h + *__s;
191 return size_t(__h);
192 };
193 };
194 struct AtomAndWeak { ld::Atom* atom; bool weakDef; bool tlv; uint64_t address; };
195 typedef std::unordered_map<const char*, AtomAndWeak, ld::CStringHash, ld::CStringEquals> NameToAtomMap;
196 typedef std::unordered_set<const char*, CStringHash, ld::CStringEquals> NameSet;
197
198 struct Dependent { const char* path; File<A>* dylib; bool reExport; };
199
200 virtual std::pair<bool, bool> hasWeakDefinitionImpl(const char* name) const;
201 virtual bool containsOrReExports(const char* name, bool& weakDef, bool& tlv, uint64_t& defAddress) const;
202 bool isPublicLocation(const char* pth);
203 bool wrongOS() { return _wrongOS; }
204 void addSymbol(const char* name, bool weak, bool tlv, pint_t address);
205 void addDyldFastStub();
206 void buildExportHashTableFromExportInfo(const macho_dyld_info_command<P>* dyldInfo,
207 const uint8_t* fileContent);
208 void buildExportHashTableFromSymbolTable(const macho_dysymtab_command<P>* dynamicInfo,
209 const macho_nlist<P>* symbolTable, const char* strings,
210 const uint8_t* fileContent);
211 static uint32_t parseVersionNumber32(const char* versionString);
212 static const char* objCInfoSegmentName();
213 static const char* objCInfoSectionName();
214
215 const Options::Platform _platform;
216 const uint32_t _linkMinOSVersion;
217 const bool _allowSimToMacOSXLinking;
218 const bool _addVersionLoadCommand;
219 bool _linkingFlat;
220 bool _implicitlyLinkPublicDylibs;
221 ld::File::ObjcConstraint _objcContraint;
222 uint8_t _swiftVersion;
223 ld::Section _importProxySection;
224 ld::Section _flatDummySection;
225 std::vector<Dependent> _dependentDylibs;
226 std::vector<const char*> _allowableClients;
227 mutable NameToAtomMap _atoms;
228 NameSet _ignoreExports;
229 const char* _parentUmbrella;
230 ImportAtom<A>* _importAtom;
231 bool _noRexports;
232 bool _hasWeakExports;
233 bool _deadStrippable;
234 bool _hasPublicInstallName;
235 mutable bool _providedAtom;
236 bool _explictReExportFound;
237 bool _wrongOS;
238 bool _installPathOverride;
239 bool _indirectDylibsProcessed;
240 bool _appExtensionSafe;
241 uint32_t _minVersionInDylib;
242 uint32_t _platformInDylib;
243 std::unique_ptr<ld::Bitcode> _bitcode;
244
245 static bool _s_logHashtable;
246 };
247
248 template <typename A>
249 bool File<A>::_s_logHashtable = false;
250
251 template <> const char* File<x86_64>::objCInfoSegmentName() { return "__DATA"; }
252 template <> const char* File<arm>::objCInfoSegmentName() { return "__DATA"; }
253 template <typename A> const char* File<A>::objCInfoSegmentName() { return "__OBJC"; }
254
255 template <> const char* File<x86_64>::objCInfoSectionName() { return "__objc_imageinfo"; }
256 template <> const char* File<arm>::objCInfoSectionName() { return "__objc_imageinfo"; }
257 template <typename A> const char* File<A>::objCInfoSectionName() { return "__image_info"; }
258
259 template <typename A>
260 File<A>::File(const uint8_t* fileContent, uint64_t fileLength, const char* pth, time_t mTime, ld::File::Ordinal ord,
261 bool linkingFlatNamespace, bool linkingMainExecutable, bool hoistImplicitPublicDylibs,
262 Options::Platform platform, uint32_t linkMinOSVersion, bool allowSimToMacOSX, bool addVers, bool buildingForSimulator,
263 bool logAllFiles, const char* targetInstallPath, bool indirectDylib, bool ignoreMismatchPlatform)
264 : ld::dylib::File(strdup(pth), mTime, ord),
265 _platform(platform), _linkMinOSVersion(linkMinOSVersion), _allowSimToMacOSXLinking(allowSimToMacOSX), _addVersionLoadCommand(addVers),
266 _linkingFlat(linkingFlatNamespace), _implicitlyLinkPublicDylibs(hoistImplicitPublicDylibs),
267 _objcContraint(ld::File::objcConstraintNone), _swiftVersion(0),
268 _importProxySection("__TEXT", "__import", ld::Section::typeImportProxies, true),
269 _flatDummySection("__LINKEDIT", "__flat_dummy", ld::Section::typeLinkEdit, true),
270 _parentUmbrella(NULL), _importAtom(NULL),
271 _noRexports(false), _hasWeakExports(false),
272 _deadStrippable(false), _hasPublicInstallName(false),
273 _providedAtom(false), _explictReExportFound(false), _wrongOS(false), _installPathOverride(false),
274 _indirectDylibsProcessed(false), _appExtensionSafe(false),
275 _minVersionInDylib(0), _platformInDylib(Options::kPlatformUnknown)
276 {
277 const macho_header<P>* header = (const macho_header<P>*)fileContent;
278 const uint32_t cmd_count = header->ncmds();
279 const macho_load_command<P>* const cmds = (macho_load_command<P>*)((char*)header + sizeof(macho_header<P>));
280 const macho_load_command<P>* const cmdsEnd = (macho_load_command<P>*)((char*)header + sizeof(macho_header<P>) + header->sizeofcmds());
281
282 // write out path for -t option
283 if ( logAllFiles )
284 printf("%s\n", pth);
285
286 // a "blank" stub has zero load commands
287 if ( (header->filetype() == MH_DYLIB_STUB) && (cmd_count == 0) ) {
288 // no further processing needed
289 munmap((caddr_t)fileContent, fileLength);
290 return;
291 }
292
293
294 // optimize the case where we know there is no reason to look at indirect dylibs
295 _noRexports = (header->flags() & MH_NO_REEXPORTED_DYLIBS)
296 || (header->filetype() == MH_BUNDLE)
297 || (header->filetype() == MH_EXECUTE); // bundles and exectuables can be used via -bundle_loader
298 _hasWeakExports = (header->flags() & MH_WEAK_DEFINES);
299 _deadStrippable = (header->flags() & MH_DEAD_STRIPPABLE_DYLIB);
300 _appExtensionSafe = (header->flags() & MH_APP_EXTENSION_SAFE);
301
302 // pass 1: get pointers, and see if this dylib uses compressed LINKEDIT format
303 const macho_dysymtab_command<P>* dynamicInfo = NULL;
304 const macho_dyld_info_command<P>* dyldInfo = NULL;
305 const macho_nlist<P>* symbolTable = NULL;
306 const char* strings = NULL;
307 bool compressedLinkEdit = false;
308 uint32_t dependentLibCount = 0;
309 Options::Platform lcPlatform = Options::kPlatformUnknown;
310 const macho_load_command<P>* cmd = cmds;
311 for (uint32_t i = 0; i < cmd_count; ++i) {
312 macho_dylib_command<P>* dylibID;
313 const macho_symtab_command<P>* symtab;
314 switch (cmd->cmd()) {
315 case LC_SYMTAB:
316 symtab = (macho_symtab_command<P>*)cmd;
317 symbolTable = (const macho_nlist<P>*)((char*)header + symtab->symoff());
318 strings = (char*)header + symtab->stroff();
319 if ( (symtab->stroff() + symtab->strsize()) > fileLength )
320 throwf("mach-o string pool extends beyond end of file in %s", pth);
321 break;
322 case LC_DYSYMTAB:
323 dynamicInfo = (macho_dysymtab_command<P>*)cmd;
324 break;
325 case LC_DYLD_INFO:
326 case LC_DYLD_INFO_ONLY:
327 dyldInfo = (macho_dyld_info_command<P>*)cmd;
328 compressedLinkEdit = true;
329 break;
330 case LC_ID_DYLIB:
331 dylibID = (macho_dylib_command<P>*)cmd;
332 _dylibInstallPath = strdup(dylibID->name());
333 _dylibTimeStamp = dylibID->timestamp();
334 _dylibCurrentVersion = dylibID->current_version();
335 _dylibCompatibilityVersion = dylibID->compatibility_version();
336 _hasPublicInstallName = isPublicLocation(_dylibInstallPath);
337 break;
338 case LC_LOAD_DYLIB:
339 case LC_LOAD_WEAK_DYLIB:
340 ++dependentLibCount;
341 break;
342 case LC_REEXPORT_DYLIB:
343 _explictReExportFound = true;
344 ++dependentLibCount;
345 break;
346 case LC_SUB_FRAMEWORK:
347 _parentUmbrella = strdup(((macho_sub_framework_command<P>*)cmd)->umbrella());
348 break;
349 case LC_SUB_CLIENT:
350 _allowableClients.push_back(strdup(((macho_sub_client_command<P>*)cmd)->client()));
351 // <rdar://problem/20627554> Don't hoist "public" (in /usr/lib/) dylibs that should not be directly linked
352 _hasPublicInstallName = false;
353 break;
354 case LC_VERSION_MIN_MACOSX:
355 case LC_VERSION_MIN_IPHONEOS:
356 case LC_VERSION_MIN_WATCHOS:
357 #if SUPPORT_APPLE_TV
358 case LC_VERSION_MIN_TVOS:
359 #endif
360 _minVersionInDylib = (ld::MacVersionMin)((macho_version_min_command<P>*)cmd)->version();
361 _platformInDylib = cmd->cmd();
362 lcPlatform = Options::platformForLoadCommand(_platformInDylib);
363 break;
364 case LC_CODE_SIGNATURE:
365 break;
366 case macho_segment_command<P>::CMD:
367 // check for Objective-C info
368 if ( strncmp(((macho_segment_command<P>*)cmd)->segname(), objCInfoSegmentName(), 6) == 0 ) {
369 const macho_segment_command<P>* segment = (macho_segment_command<P>*)cmd;
370 const macho_section<P>* const sectionsStart = (macho_section<P>*)((char*)segment + sizeof(macho_segment_command<P>));
371 const macho_section<P>* const sectionsEnd = &sectionsStart[segment->nsects()];
372 for (const macho_section<P>* sect=sectionsStart; sect < sectionsEnd; ++sect) {
373 if ( strncmp(sect->sectname(), objCInfoSectionName(), strlen(objCInfoSectionName())) == 0 ) {
374 // struct objc_image_info {
375 // uint32_t version; // initially 0
376 // uint32_t flags;
377 // };
378 // #define OBJC_IMAGE_SUPPORTS_GC 2
379 // #define OBJC_IMAGE_GC_ONLY 4
380 // #define OBJC_IMAGE_IS_SIMULATED 32
381 //
382 const uint32_t* contents = (uint32_t*)(&fileContent[sect->offset()]);
383 if ( (sect->size() >= 8) && (contents[0] == 0) ) {
384 uint32_t flags = E::get32(contents[1]);
385 if ( (flags & 4) == 4 )
386 _objcContraint = ld::File::objcConstraintGC;
387 else if ( (flags & 2) == 2 )
388 _objcContraint = ld::File::objcConstraintRetainReleaseOrGC;
389 else if ( (flags & 32) == 32 )
390 _objcContraint = ld::File::objcConstraintRetainReleaseForSimulator;
391 else
392 _objcContraint = ld::File::objcConstraintRetainRelease;
393 _swiftVersion = ((flags >> 8) & 0xFF);
394 }
395 else if ( sect->size() > 0 ) {
396 warning("can't parse %s/%s section in %s", objCInfoSegmentName(), objCInfoSectionName(), this->path());
397 }
398 }
399 }
400 }
401 // Construct bitcode if there is a bitcode bundle section in the dylib
402 // Record the size of the section because the content is not checked
403 else if ( strcmp(((macho_segment_command<P>*)cmd)->segname(), "__LLVM") == 0 ) {
404 const macho_section<P>* const sect = (macho_section<P>*)((char*)cmd + sizeof(macho_segment_command<P>));
405 if ( strncmp(sect->sectname(), "__bundle", 8) == 0 )
406 _bitcode = std::unique_ptr<ld::Bitcode>(new ld::Bitcode(NULL, sect->size()));
407 }
408 }
409 cmd = (const macho_load_command<P>*)(((char*)cmd)+cmd->cmdsize());
410 if ( cmd > cmdsEnd )
411 throwf("malformed dylb, load command #%d is outside size of load commands in %s", i, pth);
412 }
413 // arm/arm64 objects are default to ios platform if not set.
414 // rdar://problem/21746314
415 if (lcPlatform == Options::kPlatformUnknown &&
416 (std::is_same<A, arm>::value || std::is_same<A, arm64>::value))
417 lcPlatform = Options::kPlatformiOS;
418
419 // check cross-linking
420 if ( lcPlatform != platform ) {
421 _wrongOS = true;
422 if ( _addVersionLoadCommand && !indirectDylib && !ignoreMismatchPlatform ) {
423 if ( buildingForSimulator ) {
424 if ( !_allowSimToMacOSXLinking ) {
425 switch (platform) {
426 case Options::kPlatformOSX:
427 case Options::kPlatformiOS:
428 if ( lcPlatform == Options::kPlatformUnknown )
429 break;
430 // fall through if the Platform is not Unknown
431 case Options::kPlatformWatchOS:
432 // WatchOS errors on cross-linking all the time.
433 throwf("building for %s simulator, but linking against dylib built for %s,",
434 Options::platformName(platform),
435 Options::platformName(lcPlatform));
436 break;
437 #if SUPPORT_APPLE_TV
438 case Options::kPlatform_tvOS:
439 // tvOS is a warning temporarily. rdar://problem/21746965
440 if (platform == Options::kPlatform_tvOS)
441 warning("URGENT: building for %s simulator, but linking against dylib (%s) built for %s. "
442 "Note: This will be an error in the future.",
443 Options::platformName(platform), path(),
444 Options::platformName(lcPlatform));
445 break;
446 #endif
447 case Options::kPlatformUnknown:
448 // skip if the target platform is unknown
449 break;
450 }
451 }
452 }
453 else {
454 switch (platform) {
455 case Options::kPlatformOSX:
456 case Options::kPlatformiOS:
457 if ( lcPlatform == Options::kPlatformUnknown )
458 break;
459 // fall through if the Platform is not Unknown
460 case Options::kPlatformWatchOS:
461 // WatchOS errors on cross-linking all the time.
462 throwf("building for %s, but linking against dylib built for %s,",
463 Options::platformName(platform),
464 Options::platformName(lcPlatform));
465 break;
466 #if SUPPORT_APPLE_TV
467 case Options::kPlatform_tvOS:
468 // tvOS is a warning temporarily. rdar://problem/21746965
469 if (platform == Options::kPlatform_tvOS)
470 warning("URGENT: building for %s, but linking against dylib (%s) built for %s. "
471 "Note: This will be an error in the future.",
472 Options::platformName(platform), path(),
473 Options::platformName(lcPlatform));
474 break;
475 #endif
476 case Options::kPlatformUnknown:
477 // skip if the target platform is unknown
478 break;
479 }
480 }
481 }
482 }
483
484 // figure out if we need to examine dependent dylibs
485 // with compressed LINKEDIT format, MH_NO_REEXPORTED_DYLIBS can be trusted
486 bool processDependentLibraries = true;
487 if ( compressedLinkEdit && _noRexports && !linkingFlatNamespace)
488 processDependentLibraries = false;
489
490 if ( processDependentLibraries ) {
491 // pass 2 builds list of all dependent libraries
492 _dependentDylibs.reserve(dependentLibCount);
493 cmd = cmds;
494 unsigned int reExportDylibCount = 0;
495 for (uint32_t i = 0; i < cmd_count; ++i) {
496 switch (cmd->cmd()) {
497 case LC_LOAD_DYLIB:
498 case LC_LOAD_WEAK_DYLIB:
499 // with new linkedit format only care about LC_REEXPORT_DYLIB
500 if ( compressedLinkEdit && !linkingFlatNamespace )
501 break;
502 case LC_REEXPORT_DYLIB:
503 ++reExportDylibCount;
504 Dependent entry;
505 entry.path = strdup(((macho_dylib_command<P>*)cmd)->name());
506 entry.dylib = NULL;
507 entry.reExport = (cmd->cmd() == LC_REEXPORT_DYLIB);
508 if ( (targetInstallPath == NULL) || (strcmp(targetInstallPath, entry.path) != 0) )
509 _dependentDylibs.push_back(entry);
510 break;
511 }
512 cmd = (const macho_load_command<P>*)(((char*)cmd)+cmd->cmdsize());
513 }
514 // verify MH_NO_REEXPORTED_DYLIBS bit was correct
515 if ( compressedLinkEdit && !linkingFlatNamespace ) {
516 if ( reExportDylibCount == 0 )
517 throwf("malformed dylib has MH_NO_REEXPORTED_DYLIBS flag but no LC_REEXPORT_DYLIB load commands: %s", pth);
518 }
519 // pass 3 add re-export info
520 cmd = cmds;
521 for (uint32_t i = 0; i < cmd_count; ++i) {
522 const char* frameworkLeafName;
523 const char* dylibBaseName;
524 switch (cmd->cmd()) {
525 case LC_SUB_UMBRELLA:
526 frameworkLeafName = ((macho_sub_umbrella_command<P>*)cmd)->sub_umbrella();
527 for (typename std::vector<Dependent>::iterator it = _dependentDylibs.begin(); it != _dependentDylibs.end(); ++it) {
528 const char* dylibName = it->path;
529 const char* lastSlash = strrchr(dylibName, '/');
530 if ( (lastSlash != NULL) && (strcmp(&lastSlash[1], frameworkLeafName) == 0) )
531 it->reExport = true;
532 }
533 break;
534 case LC_SUB_LIBRARY:
535 dylibBaseName = ((macho_sub_library_command<P>*)cmd)->sub_library();
536 for (typename std::vector<Dependent>::iterator it = _dependentDylibs.begin(); it != _dependentDylibs.end(); ++it) {
537 const char* dylibName = it->path;
538 const char* lastSlash = strrchr(dylibName, '/');
539 const char* leafStart = &lastSlash[1];
540 if ( lastSlash == NULL )
541 leafStart = dylibName;
542 const char* firstDot = strchr(leafStart, '.');
543 int len = strlen(leafStart);
544 if ( firstDot != NULL )
545 len = firstDot - leafStart;
546 if ( strncmp(leafStart, dylibBaseName, len) == 0 )
547 it->reExport = true;
548 }
549 break;
550 }
551 cmd = (const macho_load_command<P>*)(((char*)cmd)+cmd->cmdsize());
552 }
553 }
554
555 // validate minimal load commands
556 if ( (_dylibInstallPath == NULL) && ((header->filetype() == MH_DYLIB) || (header->filetype() == MH_DYLIB_STUB)) )
557 throwf("dylib %s missing LC_ID_DYLIB load command", pth);
558 if ( dyldInfo == NULL ) {
559 if ( symbolTable == NULL )
560 throw "binary missing LC_SYMTAB load command";
561 if ( dynamicInfo == NULL )
562 throw "binary missing LC_DYSYMTAB load command";
563 }
564
565 // if linking flat and this is a flat dylib, create one atom that references all imported symbols
566 if ( linkingFlatNamespace && linkingMainExecutable && ((header->flags() & MH_TWOLEVEL) == 0) ) {
567 std::vector<const char*> importNames;
568 importNames.reserve(dynamicInfo->nundefsym());
569 const macho_nlist<P>* start = &symbolTable[dynamicInfo->iundefsym()];
570 const macho_nlist<P>* end = &start[dynamicInfo->nundefsym()];
571 for (const macho_nlist<P>* sym=start; sym < end; ++sym) {
572 importNames.push_back(&strings[sym->n_strx()]);
573 }
574 _importAtom = new ImportAtom<A>(*this, importNames);
575 }
576
577 // build hash table
578 if ( dyldInfo != NULL )
579 buildExportHashTableFromExportInfo(dyldInfo, fileContent);
580 else
581 buildExportHashTableFromSymbolTable(dynamicInfo, symbolTable, strings, fileContent);
582
583 // unmap file
584 munmap((caddr_t)fileContent, fileLength);
585 }
586
587
588 //
589 // Parses number of form X[.Y[.Z]] into a uint32_t where the nibbles are xxxx.yy.zz
590 //
591 template <typename A>
592 uint32_t File<A>::parseVersionNumber32(const char* versionString)
593 {
594 uint32_t x = 0;
595 uint32_t y = 0;
596 uint32_t z = 0;
597 char* end;
598 x = strtoul(versionString, &end, 10);
599 if ( *end == '.' ) {
600 y = strtoul(&end[1], &end, 10);
601 if ( *end == '.' ) {
602 z = strtoul(&end[1], &end, 10);
603 }
604 }
605 if ( (*end != '\0') || (x > 0xffff) || (y > 0xff) || (z > 0xff) )
606 throwf("malformed 32-bit x.y.z version number: %s", versionString);
607
608 return (x << 16) | ( y << 8 ) | z;
609 }
610
611 template <typename A>
612 void File<A>::buildExportHashTableFromSymbolTable(const macho_dysymtab_command<P>* dynamicInfo,
613 const macho_nlist<P>* symbolTable, const char* strings,
614 const uint8_t* fileContent)
615 {
616 if ( dynamicInfo->tocoff() == 0 ) {
617 if ( _s_logHashtable ) fprintf(stderr, "ld: building hashtable of %u toc entries for %s\n", dynamicInfo->nextdefsym(), this->path());
618 const macho_nlist<P>* start = &symbolTable[dynamicInfo->iextdefsym()];
619 const macho_nlist<P>* end = &start[dynamicInfo->nextdefsym()];
620 _atoms.reserve(dynamicInfo->nextdefsym()); // set initial bucket count
621 for (const macho_nlist<P>* sym=start; sym < end; ++sym) {
622 this->addSymbol(&strings[sym->n_strx()], (sym->n_desc() & N_WEAK_DEF) != 0, false, sym->n_value());
623 }
624 }
625 else {
626 int32_t count = dynamicInfo->ntoc();
627 _atoms.reserve(count); // set initial bucket count
628 if ( _s_logHashtable ) fprintf(stderr, "ld: building hashtable of %u entries for %s\n", count, this->path());
629 const struct dylib_table_of_contents* toc = (dylib_table_of_contents*)(fileContent + dynamicInfo->tocoff());
630 for (int32_t i = 0; i < count; ++i) {
631 const uint32_t index = E::get32(toc[i].symbol_index);
632 const macho_nlist<P>* sym = &symbolTable[index];
633 this->addSymbol(&strings[sym->n_strx()], (sym->n_desc() & N_WEAK_DEF) != 0, false, sym->n_value());
634 }
635 }
636
637 // special case old libSystem
638 if ( (_dylibInstallPath != NULL) && (strcmp(_dylibInstallPath, "/usr/lib/libSystem.B.dylib") == 0) )
639 addDyldFastStub();
640 }
641
642
643 template <typename A>
644 void File<A>::buildExportHashTableFromExportInfo(const macho_dyld_info_command<P>* dyldInfo,
645 const uint8_t* fileContent)
646 {
647 if ( _s_logHashtable ) fprintf(stderr, "ld: building hashtable from export info in %s\n", this->path());
648 if ( dyldInfo->export_size() > 0 ) {
649 const uint8_t* start = fileContent + dyldInfo->export_off();
650 const uint8_t* end = &start[dyldInfo->export_size()];
651 std::vector<mach_o::trie::Entry> list;
652 parseTrie(start, end, list);
653 for (std::vector<mach_o::trie::Entry>::iterator it=list.begin(); it != list.end(); ++it)
654 this->addSymbol(it->name,
655 it->flags & EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION,
656 (it->flags & EXPORT_SYMBOL_FLAGS_KIND_MASK) == EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL,
657 it->address);
658 }
659 }
660
661
662 template <>
663 void File<x86_64>::addDyldFastStub()
664 {
665 addSymbol("dyld_stub_binder", false, false, 0);
666 }
667
668 template <>
669 void File<x86>::addDyldFastStub()
670 {
671 addSymbol("dyld_stub_binder", false, false, 0);
672 }
673
674 template <typename A>
675 void File<A>::addDyldFastStub()
676 {
677 // do nothing
678 }
679
680 template <typename A>
681 void File<A>::addSymbol(const char* name, bool weakDef, bool tlv, pint_t address)
682 {
683 //fprintf(stderr, "addSymbol() %s\n", name);
684 // symbols that start with $ld$ are meta-data to the static linker
685 // <rdar://problem/5182537> need way for ld and dyld to see different exported symbols in a dylib
686 if ( strncmp(name, "$ld$", 4) == 0 ) {
687 // $ld$ <action> $ <condition> $ <symbol-name>
688 const char* symAction = &name[4];
689 const char* symCond = strchr(symAction, '$');
690 if ( symCond != NULL ) {
691 char curOSVers[16];
692 sprintf(curOSVers, "$os%d.%d$", (_linkMinOSVersion >> 16), ((_linkMinOSVersion >> 8) & 0xFF));
693 if ( strncmp(symCond, curOSVers, strlen(curOSVers)) == 0 ) {
694 const char* symName = strchr(&symCond[1], '$');
695 if ( symName != NULL ) {
696 ++symName;
697 if ( strncmp(symAction, "hide$", 5) == 0 ) {
698 if ( _s_logHashtable ) fprintf(stderr, " adding %s to ignore set for %s\n", symName, this->path());
699 _ignoreExports.insert(strdup(symName));
700 return;
701 }
702 else if ( strncmp(symAction, "add$", 4) == 0 ) {
703 this->addSymbol(symName, weakDef, false, 0);
704 return;
705 }
706 else if ( strncmp(symAction, "install_name$", 13) == 0 ) {
707 _dylibInstallPath = symName;
708 _installPathOverride = true;
709 // <rdar://problem/14448206> CoreGraphics redirects to ApplicationServices, but with wrong compat version
710 if ( strcmp(_dylibInstallPath, "/System/Library/Frameworks/ApplicationServices.framework/Versions/A/ApplicationServices") == 0 )
711 _dylibCompatibilityVersion = parseVersionNumber32("1.0");
712 return;
713 }
714 else if ( strncmp(symAction, "compatibility_version$", 22) == 0 ) {
715 _dylibCompatibilityVersion = parseVersionNumber32(symName);
716 return;
717 }
718 else {
719 warning("bad symbol action: %s in dylib %s", name, this->path());
720 }
721 }
722 }
723 }
724 else {
725 warning("bad symbol condition: %s in dylib %s", name, this->path());
726 }
727 }
728
729 // add symbol as possible export if we are not supposed to ignore it
730 if ( _ignoreExports.count(name) == 0 ) {
731 AtomAndWeak bucket;
732 bucket.atom = NULL;
733 bucket.weakDef = weakDef;
734 bucket.tlv = tlv;
735 bucket.address = address;
736 if ( _s_logHashtable ) fprintf(stderr, " adding %s to hash table for %s\n", name, this->path());
737 _atoms[strdup(name)] = bucket;
738 }
739 }
740
741
742 template <typename A>
743 bool File<A>::forEachAtom(ld::File::AtomHandler& handler) const
744 {
745 handler.doFile(*this);
746 // if doing flatnamespace and need all this dylib's imports resolve
747 // add atom which references alls undefines in this dylib
748 if ( _importAtom != NULL ) {
749 handler.doAtom(*_importAtom);
750 return true;
751 }
752 return false;
753 }
754
755
756 template <typename A>
757 std::pair<bool, bool> File<A>::hasWeakDefinitionImpl(const char* name) const
758 {
759 const auto pos = _atoms.find(name);
760 if ( pos != _atoms.end() )
761 return std::make_pair(true, pos->second.weakDef);
762
763 // look in children that I re-export
764 for (const auto &dep : _dependentDylibs) {
765 if ( dep.reExport ) {
766 auto ret = dep.dylib->hasWeakDefinitionImpl(name);
767 if ( ret.first )
768 return ret;
769 }
770 }
771 return std::make_pair(false, false);
772 }
773
774
775 template <typename A>
776 bool File<A>::hasWeakDefinition(const char* name) const
777 {
778 // if supposed to ignore this export, then pretend I don't have it
779 if ( _ignoreExports.count(name) != 0 )
780 return false;
781
782 return hasWeakDefinitionImpl(name).second;
783 }
784
785
786 // <rdar://problem/5529626> If only weak_import symbols are used, linker should use LD_LOAD_WEAK_DYLIB
787 template <typename A>
788 bool File<A>::allSymbolsAreWeakImported() const
789 {
790 bool foundNonWeakImport = false;
791 bool foundWeakImport = false;
792 //fprintf(stderr, "%s:\n", this->path());
793 for (typename NameToAtomMap::const_iterator it = _atoms.begin(); it != _atoms.end(); ++it) {
794 const ld::Atom* atom = it->second.atom;
795 if ( atom != NULL ) {
796 if ( atom->weakImported() )
797 foundWeakImport = true;
798 else
799 foundNonWeakImport = true;
800 //fprintf(stderr, " weak_import=%d, name=%s\n", atom->weakImported(), it->first);
801 }
802 }
803
804 // don't automatically weak link dylib with no imports
805 // so at least one weak import symbol and no non-weak-imported symbols must be found
806 return foundWeakImport && !foundNonWeakImport;
807 }
808
809
810 template <typename A>
811 bool File<A>::containsOrReExports(const char* name, bool& weakDef, bool& tlv, uint64_t& defAddress) const
812 {
813 if ( _ignoreExports.count(name) != 0 )
814 return false;
815
816 // check myself
817 const auto pos = _atoms.find(name);
818 if ( pos != _atoms.end() ) {
819 weakDef = pos->second.weakDef;
820 tlv = pos->second.tlv;
821 defAddress = pos->second.address;
822 return true;
823 }
824
825 // check dylibs I re-export
826 for (const auto &dep : _dependentDylibs) {
827 if ( dep.reExport && !dep.dylib->implicitlyLinked() ) {
828 if ( dep.dylib->containsOrReExports(name, weakDef, tlv, defAddress) )
829 return true;
830 }
831 }
832
833 return false;
834 }
835
836
837 template <typename A>
838 bool File<A>::justInTimeforEachAtom(const char* name, ld::File::AtomHandler& handler) const
839 {
840 // if supposed to ignore this export, then pretend I don't have it
841 if ( _ignoreExports.count(name) != 0 )
842 return false;
843
844
845 AtomAndWeak bucket;
846 if ( this->containsOrReExports(name, bucket.weakDef, bucket.tlv, bucket.address) ) {
847 bucket.atom = new ExportAtom<A>(*this, name, bucket.weakDef, bucket.tlv, bucket.address);
848 _atoms[name] = bucket;
849 _providedAtom = true;
850 if ( _s_logHashtable ) fprintf(stderr, "getJustInTimeAtomsFor: %s found in %s\n", name, this->path());
851 // call handler with new export atom
852 handler.doAtom(*bucket.atom);
853 return true;
854 }
855
856 return false;
857 }
858
859
860
861 template <typename A>
862 bool File<A>::isPublicLocation(const char* pth)
863 {
864 // -no_implicit_dylibs disables this optimization
865 if ( ! _implicitlyLinkPublicDylibs )
866 return false;
867
868 // /usr/lib is a public location
869 if ( (strncmp(pth, "/usr/lib/", 9) == 0) && (strchr(&pth[9], '/') == NULL) )
870 return true;
871
872 // /System/Library/Frameworks/ is a public location
873 if ( strncmp(pth, "/System/Library/Frameworks/", 27) == 0 ) {
874 const char* frameworkDot = strchr(&pth[27], '.');
875 // but only top level framework
876 // /System/Library/Frameworks/Foo.framework/Versions/A/Foo ==> true
877 // /System/Library/Frameworks/Foo.framework/Resources/libBar.dylib ==> false
878 // /System/Library/Frameworks/Foo.framework/Frameworks/Bar.framework/Bar ==> false
879 // /System/Library/Frameworks/Foo.framework/Frameworks/Xfoo.framework/XFoo ==> false
880 if ( frameworkDot != NULL ) {
881 int frameworkNameLen = frameworkDot - &pth[27];
882 if ( strncmp(&pth[strlen(pth)-frameworkNameLen-1], &pth[26], frameworkNameLen+1) == 0 )
883 return true;
884 }
885 }
886
887 return false;
888 }
889
890 template <typename A>
891 void File<A>::processIndirectLibraries(ld::dylib::File::DylibHandler* handler, bool addImplicitDylibs)
892 {
893 // only do this once
894 if ( _indirectDylibsProcessed )
895 return;
896 const static bool log = false;
897 if ( log ) fprintf(stderr, "processIndirectLibraries(%s)\n", this->installPath());
898 if ( _linkingFlat ) {
899 for (typename std::vector<Dependent>::iterator it = _dependentDylibs.begin(); it != _dependentDylibs.end(); it++) {
900 it->dylib = (File<A>*)handler->findDylib(it->path, this->path());
901 }
902 }
903 else if ( _noRexports ) {
904 // MH_NO_REEXPORTED_DYLIBS bit set, then nothing to do
905 }
906 else {
907 // two-level, might have re-exports
908 for (typename std::vector<Dependent>::iterator it = _dependentDylibs.begin(); it != _dependentDylibs.end(); it++) {
909 if ( it->reExport ) {
910 if ( log ) fprintf(stderr, "processIndirectLibraries() parent=%s, child=%s\n", this->installPath(), it->path);
911 // a LC_REEXPORT_DYLIB, LC_SUB_UMBRELLA or LC_SUB_LIBRARY says we re-export this child
912 it->dylib = (File<A>*)handler->findDylib(it->path, this->path());
913 if ( it->dylib->hasPublicInstallName() && !it->dylib->wrongOS() ) {
914 // promote this child to be automatically added as a direct dependent if this already is
915 if ( (this->explicitlyLinked() || this->implicitlyLinked()) && (strcmp(it->path,it->dylib->installPath()) == 0) ) {
916 if ( log ) fprintf(stderr, "processIndirectLibraries() implicitly linking %s\n", it->dylib->installPath());
917 it->dylib->setImplicitlyLinked();
918 }
919 else if ( it->dylib->explicitlyLinked() || it->dylib->implicitlyLinked() ) {
920 if ( log ) fprintf(stderr, "processIndirectLibraries() parent is not directly linked, but child is, so no need to re-export child\n");
921 }
922 else {
923 if ( log ) fprintf(stderr, "processIndirectLibraries() parent is not directly linked, so parent=%s will re-export child=%s\n", this->installPath(), it->path);
924 }
925 }
926 else {
927 // add all child's symbols to me
928 if ( log ) fprintf(stderr, "processIndirectLibraries() child is not public, so parent=%s will re-export child=%s\n", this->installPath(), it->path);
929 }
930 }
931 else if ( !_explictReExportFound ) {
932 // see if child contains LC_SUB_FRAMEWORK with my name
933 it->dylib = (File<A>*)handler->findDylib(it->path, this->path());
934 const char* parentUmbrellaName = it->dylib->parentUmbrella();
935 if ( parentUmbrellaName != NULL ) {
936 const char* parentName = this->path();
937 const char* lastSlash = strrchr(parentName, '/');
938 if ( (lastSlash != NULL) && (strcmp(&lastSlash[1], parentUmbrellaName) == 0) ) {
939 // add all child's symbols to me
940 it->reExport = true;
941 if ( log ) fprintf(stderr, "processIndirectLibraries() umbrella=%s will re-export child=%s\n", this->installPath(), it->path);
942 }
943 }
944 }
945 }
946 }
947
948 // check for re-export cycles
949 ReExportChain chain;
950 chain.prev = NULL;
951 chain.file = this;
952 this->assertNoReExportCycles(&chain);
953
954 _indirectDylibsProcessed = true;
955 }
956
957 template <typename A>
958 void File<A>::assertNoReExportCycles(ReExportChain* prev) const
959 {
960 // recursively check my re-exported dylibs
961 ReExportChain chain;
962 chain.prev = prev;
963 chain.file = this;
964 for (const auto &dep : _dependentDylibs) {
965 if ( dep.reExport ) {
966 ld::File* child = dep.dylib;
967 // check child is not already in chain
968 for (ReExportChain* p = prev; p != nullptr; p = p->prev) {
969 if ( p->file == child ) {
970 throwf("cycle in dylib re-exports with %s and %s", child->path(), this->path());
971 }
972 }
973 if ( dep.dylib != nullptr )
974 dep.dylib->assertNoReExportCycles(&chain);
975 }
976 }
977 }
978
979
980 template <typename A>
981 class Parser
982 {
983 public:
984 typedef typename A::P P;
985
986 static bool validFile(const uint8_t* fileContent, bool executableOrDyliborBundle);
987 static const char* fileKind(const uint8_t* fileContent);
988 static ld::dylib::File* parse(const uint8_t* fileContent, uint64_t fileLength,
989 const char* path, time_t mTime,
990 ld::File::Ordinal ordinal, const Options& opts, bool indirectDylib) {
991 return new File<A>(fileContent, fileLength, path, mTime,
992 ordinal, opts.flatNamespace(),
993 opts.linkingMainExecutable(),
994 opts.implicitlyLinkIndirectPublicDylibs(),
995 opts.platform(),
996 opts.minOSversion(),
997 opts.allowSimulatorToLinkWithMacOSX(),
998 opts.addVersionLoadCommand(),
999 opts.targetIOSSimulator(),
1000 opts.logAllFiles(),
1001 opts.installPath(),
1002 indirectDylib,
1003 opts.outputKind() == Options::kPreload);
1004 }
1005
1006 };
1007
1008
1009
1010 template <>
1011 bool Parser<x86>::validFile(const uint8_t* fileContent, bool executableOrDyliborBundle)
1012 {
1013 const macho_header<P>* header = (const macho_header<P>*)fileContent;
1014 if ( header->magic() != MH_MAGIC )
1015 return false;
1016 if ( header->cputype() != CPU_TYPE_I386 )
1017 return false;
1018 switch ( header->filetype() ) {
1019 case MH_DYLIB:
1020 case MH_DYLIB_STUB:
1021 return true;
1022 case MH_BUNDLE:
1023 if ( executableOrDyliborBundle )
1024 return true;
1025 else
1026 throw "can't link with bundle (MH_BUNDLE) only dylibs (MH_DYLIB)";
1027 case MH_EXECUTE:
1028 if ( executableOrDyliborBundle )
1029 return true;
1030 else
1031 throw "can't link with a main executable";
1032 default:
1033 return false;
1034 }
1035 }
1036
1037 template <>
1038 bool Parser<x86_64>::validFile(const uint8_t* fileContent, bool executableOrDyliborBundle)
1039 {
1040 const macho_header<P>* header = (const macho_header<P>*)fileContent;
1041 if ( header->magic() != MH_MAGIC_64 )
1042 return false;
1043 if ( header->cputype() != CPU_TYPE_X86_64 )
1044 return false;
1045 switch ( header->filetype() ) {
1046 case MH_DYLIB:
1047 case MH_DYLIB_STUB:
1048 return true;
1049 case MH_BUNDLE:
1050 if ( executableOrDyliborBundle )
1051 return true;
1052 else
1053 throw "can't link with bundle (MH_BUNDLE) only dylibs (MH_DYLIB)";
1054 case MH_EXECUTE:
1055 if ( executableOrDyliborBundle )
1056 return true;
1057 else
1058 throw "can't link with a main executable";
1059 default:
1060 return false;
1061 }
1062 }
1063
1064 template <>
1065 bool Parser<arm>::validFile(const uint8_t* fileContent, bool executableOrDyliborBundle)
1066 {
1067 const macho_header<P>* header = (const macho_header<P>*)fileContent;
1068 if ( header->magic() != MH_MAGIC )
1069 return false;
1070 if ( header->cputype() != CPU_TYPE_ARM )
1071 return false;
1072 switch ( header->filetype() ) {
1073 case MH_DYLIB:
1074 case MH_DYLIB_STUB:
1075 return true;
1076 case MH_BUNDLE:
1077 if ( executableOrDyliborBundle )
1078 return true;
1079 else
1080 throw "can't link with bundle (MH_BUNDLE) only dylibs (MH_DYLIB)";
1081 case MH_EXECUTE:
1082 if ( executableOrDyliborBundle )
1083 return true;
1084 else
1085 throw "can't link with a main executable";
1086 default:
1087 return false;
1088 }
1089 }
1090
1091
1092
1093 template <>
1094 bool Parser<arm64>::validFile(const uint8_t* fileContent, bool executableOrDyliborBundle)
1095 {
1096 const macho_header<P>* header = (const macho_header<P>*)fileContent;
1097 if ( header->magic() != MH_MAGIC_64 )
1098 return false;
1099 if ( header->cputype() != CPU_TYPE_ARM64 )
1100 return false;
1101 switch ( header->filetype() ) {
1102 case MH_DYLIB:
1103 case MH_DYLIB_STUB:
1104 return true;
1105 case MH_BUNDLE:
1106 if ( executableOrDyliborBundle )
1107 return true;
1108 else
1109 throw "can't link with bundle (MH_BUNDLE) only dylibs (MH_DYLIB)";
1110 case MH_EXECUTE:
1111 if ( executableOrDyliborBundle )
1112 return true;
1113 else
1114 throw "can't link with a main executable";
1115 default:
1116 return false;
1117 }
1118 }
1119
1120
1121 bool isDylibFile(const uint8_t* fileContent, cpu_type_t* result, cpu_subtype_t* subResult)
1122 {
1123 if ( Parser<x86_64>::validFile(fileContent, false) ) {
1124 *result = CPU_TYPE_X86_64;
1125 const macho_header<Pointer64<LittleEndian> >* header = (const macho_header<Pointer64<LittleEndian> >*)fileContent;
1126 *subResult = header->cpusubtype();
1127 return true;
1128 }
1129 if ( Parser<x86>::validFile(fileContent, false) ) {
1130 *result = CPU_TYPE_I386;
1131 *subResult = CPU_SUBTYPE_X86_ALL;
1132 return true;
1133 }
1134 if ( Parser<arm>::validFile(fileContent, false) ) {
1135 *result = CPU_TYPE_ARM;
1136 const macho_header<Pointer32<LittleEndian> >* header = (const macho_header<Pointer32<LittleEndian> >*)fileContent;
1137 *subResult = header->cpusubtype();
1138 return true;
1139 }
1140 if ( Parser<arm64>::validFile(fileContent, false) ) {
1141 *result = CPU_TYPE_ARM64;
1142 *subResult = CPU_SUBTYPE_ARM64_ALL;
1143 return true;
1144 }
1145 return false;
1146 }
1147
1148 template <>
1149 const char* Parser<x86>::fileKind(const uint8_t* fileContent)
1150 {
1151 const macho_header<P>* header = (const macho_header<P>*)fileContent;
1152 if ( header->magic() != MH_MAGIC )
1153 return NULL;
1154 if ( header->cputype() != CPU_TYPE_I386 )
1155 return NULL;
1156 return "i386";
1157 }
1158
1159 template <>
1160 const char* Parser<x86_64>::fileKind(const uint8_t* fileContent)
1161 {
1162 const macho_header<P>* header = (const macho_header<P>*)fileContent;
1163 if ( header->magic() != MH_MAGIC_64 )
1164 return NULL;
1165 if ( header->cputype() != CPU_TYPE_X86_64 )
1166 return NULL;
1167 return "x86_64";
1168 }
1169
1170 template <>
1171 const char* Parser<arm>::fileKind(const uint8_t* fileContent)
1172 {
1173 const macho_header<P>* header = (const macho_header<P>*)fileContent;
1174 if ( header->magic() != MH_MAGIC )
1175 return NULL;
1176 if ( header->cputype() != CPU_TYPE_ARM )
1177 return NULL;
1178 for (const ArchInfo* t=archInfoArray; t->archName != NULL; ++t) {
1179 if ( (t->cpuType == CPU_TYPE_ARM) && ((cpu_subtype_t)header->cpusubtype() == t->cpuSubType) ) {
1180 return t->archName;
1181 }
1182 }
1183 return "arm???";
1184 }
1185
1186 #if SUPPORT_ARCH_arm64
1187 template <>
1188 const char* Parser<arm64>::fileKind(const uint8_t* fileContent)
1189 {
1190 const macho_header<P>* header = (const macho_header<P>*)fileContent;
1191 if ( header->magic() != MH_MAGIC_64 )
1192 return NULL;
1193 if ( header->cputype() != CPU_TYPE_ARM64 )
1194 return NULL;
1195 return "arm64";
1196 }
1197 #endif
1198
1199 //
1200 // used by linker is error messages to describe mismatched files
1201 //
1202 const char* archName(const uint8_t* fileContent)
1203 {
1204 if ( Parser<x86_64>::validFile(fileContent, true) ) {
1205 return Parser<x86_64>::fileKind(fileContent);
1206 }
1207 if ( Parser<x86>::validFile(fileContent, true) ) {
1208 return Parser<x86>::fileKind(fileContent);
1209 }
1210 if ( Parser<arm>::validFile(fileContent, true) ) {
1211 return Parser<arm>::fileKind(fileContent);
1212 }
1213 #if SUPPORT_ARCH_arm64
1214 if ( Parser<arm64>::validFile(fileContent, false) ) {
1215 return Parser<arm64>::fileKind(fileContent);
1216 }
1217 #endif
1218 return NULL;
1219 }
1220
1221
1222 //
1223 // main function used by linker to instantiate ld::Files
1224 //
1225 ld::dylib::File* parse(const uint8_t* fileContent, uint64_t fileLength,
1226 const char* path, time_t modTime, const Options& opts, ld::File::Ordinal ordinal,
1227 bool bundleLoader, bool indirectDylib)
1228 {
1229 switch ( opts.architecture() ) {
1230 #if SUPPORT_ARCH_x86_64
1231 case CPU_TYPE_X86_64:
1232 if ( Parser<x86_64>::validFile(fileContent, bundleLoader) )
1233 return Parser<x86_64>::parse(fileContent, fileLength, path, modTime, ordinal, opts, indirectDylib);
1234 break;
1235 #endif
1236 #if SUPPORT_ARCH_i386
1237 case CPU_TYPE_I386:
1238 if ( Parser<x86>::validFile(fileContent, bundleLoader) )
1239 return Parser<x86>::parse(fileContent, fileLength, path, modTime, ordinal, opts, indirectDylib);
1240 break;
1241 #endif
1242 #if SUPPORT_ARCH_arm_any
1243 case CPU_TYPE_ARM:
1244 if ( Parser<arm>::validFile(fileContent, bundleLoader) )
1245 return Parser<arm>::parse(fileContent, fileLength, path, modTime, ordinal, opts, indirectDylib);
1246 break;
1247 #endif
1248 #if SUPPORT_ARCH_arm64
1249 case CPU_TYPE_ARM64:
1250 if ( Parser<arm64>::validFile(fileContent, bundleLoader) )
1251 return Parser<arm64>::parse(fileContent, fileLength, path, modTime, ordinal, opts, indirectDylib);
1252 break;
1253 #endif
1254 }
1255 return NULL;
1256 }
1257
1258
1259 }; // namespace dylib
1260 }; // namespace mach_o
1261
1262