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