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