]>
Commit | Line | Data |
---|---|---|
a645023d A |
1 | /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- |
2 | * | |
afe874b1 | 3 | * Copyright (c) 2005-2011 Apple Inc. All rights reserved. |
a645023d A |
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 <algorithm> | |
36 | #include <ext/hash_map> | |
37 | #include <ext/hash_set> | |
38 | ||
39 | #include "Architectures.hpp" | |
40 | #include "MachOFileAbstraction.hpp" | |
41 | #include "MachOTrie.hpp" | |
42 | #include "macho_dylib_file.h" | |
ebf6f434 | 43 | #include "../code-sign-blobs/superblob.h" |
a645023d A |
44 | |
45 | namespace mach_o { | |
46 | namespace dylib { | |
47 | ||
48 | ||
49 | // forward reference | |
50 | template <typename A> class File; | |
51 | ||
52 | ||
53 | // | |
54 | // An ExportAtom has no content. It exists so that the linker can track which imported | |
55 | // symbols came from which dynamic libraries. | |
56 | // | |
57 | template <typename A> | |
58 | class ExportAtom : public ld::Atom | |
59 | { | |
60 | public: | |
61 | ExportAtom(const File<A>& f, const char* nm, bool weakDef, | |
62 | bool tlv, typename A::P::uint_t address) | |
63 | : ld::Atom(f._importProxySection, ld::Atom::definitionProxy, | |
64 | (weakDef? ld::Atom::combineByName : ld::Atom::combineNever), | |
65 | ld::Atom::scopeLinkageUnit, | |
66 | (tlv ? ld::Atom::typeTLV : ld::Atom::typeUnclassified), | |
67 | symbolTableNotIn, false, false, false, ld::Atom::Alignment(0)), | |
68 | _file(f), _name(nm), _address(address) {} | |
69 | // overrides of ld::Atom | |
70 | virtual const ld::File* file() const { return &_file; } | |
a645023d A |
71 | virtual const char* name() const { return _name; } |
72 | virtual uint64_t size() const { return 0; } | |
73 | virtual uint64_t objectAddress() const { return _address; } | |
74 | virtual void copyRawContent(uint8_t buffer[]) const { } | |
75 | virtual void setScope(Scope) { } | |
76 | ||
77 | protected: | |
78 | typedef typename A::P P; | |
79 | typedef typename A::P::uint_t pint_t; | |
80 | ||
81 | virtual ~ExportAtom() {} | |
82 | ||
83 | const File<A>& _file; | |
84 | const char* _name; | |
85 | pint_t _address; | |
86 | }; | |
87 | ||
88 | ||
89 | ||
90 | // | |
91 | // An ImportAtom has no content. It exists so that when linking a main executable flat-namespace | |
92 | // the imports of all flat dylibs are checked | |
93 | // | |
94 | template <typename A> | |
95 | class ImportAtom : public ld::Atom | |
96 | { | |
97 | public: | |
98 | ImportAtom(File<A>& f, std::vector<const char*>& imports); | |
99 | ||
100 | // overrides of ld::Atom | |
101 | virtual ld::File* file() const { return &_file; } | |
a645023d A |
102 | virtual const char* name() const { return "import-atom"; } |
103 | virtual uint64_t size() const { return 0; } | |
104 | virtual uint64_t objectAddress() const { return 0; } | |
105 | virtual void copyRawContent(uint8_t buffer[]) const { } | |
106 | virtual void setScope(Scope) { } | |
107 | virtual ld::Fixup::iterator fixupsBegin() const { return &_undefs[0]; } | |
108 | virtual ld::Fixup::iterator fixupsEnd() const { return &_undefs[_undefs.size()]; } | |
109 | ||
110 | protected: | |
111 | typedef typename A::P P; | |
112 | ||
113 | virtual ~ImportAtom() {} | |
114 | ||
115 | ||
116 | File<A>& _file; | |
117 | mutable std::vector<ld::Fixup> _undefs; | |
118 | }; | |
119 | ||
120 | template <typename A> | |
121 | ImportAtom<A>::ImportAtom(File<A>& f, std::vector<const char*>& imports) | |
122 | : ld::Atom(f._flatDummySection, ld::Atom::definitionRegular, ld::Atom::combineNever, ld::Atom::scopeTranslationUnit, | |
123 | ld::Atom::typeUnclassified, symbolTableNotIn, false, false, false, ld::Atom::Alignment(0)), _file(f) | |
124 | { | |
125 | for(std::vector<const char*>::iterator it=imports.begin(); it != imports.end(); ++it) { | |
126 | _undefs.push_back(ld::Fixup(0, ld::Fixup::k1of1, ld::Fixup::kindNone, false, strdup(*it))); | |
127 | } | |
128 | } | |
129 | ||
130 | ||
131 | ||
132 | // | |
133 | // The reader for a dylib extracts all exported symbols names from the memory-mapped | |
134 | // dylib, builds a hash table, then unmaps the file. This is an important memory | |
135 | // savings for large dylibs. | |
136 | // | |
137 | template <typename A> | |
138 | class File : public ld::dylib::File | |
139 | { | |
140 | public: | |
141 | static bool validFile(const uint8_t* fileContent, bool executableOrDylib); | |
142 | File(const uint8_t* fileContent, uint64_t fileLength, const char* path, | |
ebf6f434 | 143 | time_t mTime, ld::File::Ordinal ordinal, bool linkingFlatNamespace, |
a645023d | 144 | bool linkingMainExecutable, bool hoistImplicitPublicDylibs, |
afe874b1 A |
145 | ld::MacVersionMin macMin, ld::IOSVersionMin iPhoneMin, bool addVers, |
146 | bool logAllFiles, const char* installPath, bool indirectDylib); | |
a645023d A |
147 | virtual ~File() {} |
148 | ||
149 | // overrides of ld::File | |
150 | virtual bool forEachAtom(ld::File::AtomHandler&) const; | |
151 | virtual bool justInTimeforEachAtom(const char* name, ld::File::AtomHandler&) const; | |
152 | virtual ld::File::ObjcConstraint objCConstraint() const { return _objcContraint; } | |
153 | ||
154 | // overrides of ld::dylib::File | |
155 | virtual void processIndirectLibraries(ld::dylib::File::DylibHandler*, bool); | |
156 | virtual bool providedExportAtom() const { return _providedAtom; } | |
157 | virtual const char* parentUmbrella() const { return _parentUmbrella; } | |
158 | virtual const std::vector<const char*>* allowableClients() const { return _allowableClients.size() != 0 ? &_allowableClients : NULL; } | |
159 | virtual bool hasWeakExternals() const { return _hasWeakExports; } | |
160 | virtual bool deadStrippable() const { return _deadStrippable; } | |
161 | virtual bool hasPublicInstallName() const{ return _hasPublicInstallName; } | |
162 | virtual bool hasWeakDefinition(const char* name) const; | |
afe874b1 | 163 | virtual bool allSymbolsAreWeakImported() const; |
ebf6f434 | 164 | virtual const void* codeSignatureDR() const { return _codeSignatureDR; } |
a645023d A |
165 | |
166 | ||
167 | protected: | |
168 | ||
169 | struct ReExportChain { ReExportChain* prev; File<A>* file; }; | |
170 | ||
171 | void assertNoReExportCycles(ReExportChain*); | |
172 | ||
173 | private: | |
174 | typedef typename A::P P; | |
175 | typedef typename A::P::E E; | |
176 | typedef typename A::P::uint_t pint_t; | |
177 | ||
178 | friend class ExportAtom<A>; | |
179 | friend class ImportAtom<A>; | |
180 | ||
181 | class CStringEquals | |
182 | { | |
183 | public: | |
184 | bool operator()(const char* left, const char* right) const { return (strcmp(left, right) == 0); } | |
185 | }; | |
afe874b1 | 186 | struct AtomAndWeak { ld::Atom* atom; bool weakDef; bool tlv; pint_t address; }; |
a645023d A |
187 | typedef __gnu_cxx::hash_map<const char*, AtomAndWeak, __gnu_cxx::hash<const char*>, CStringEquals> NameToAtomMap; |
188 | typedef __gnu_cxx::hash_set<const char*, __gnu_cxx::hash<const char*>, CStringEquals> NameSet; | |
189 | ||
190 | struct Dependent { const char* path; File<A>* dylib; bool reExport; }; | |
191 | ||
192 | bool containsOrReExports(const char* name, bool* weakDef, bool* tlv, pint_t* defAddress) const; | |
193 | bool isPublicLocation(const char* pth); | |
194 | void addSymbol(const char* name, bool weak, bool tlv, pint_t address); | |
195 | void addDyldFastStub(); | |
196 | void buildExportHashTableFromExportInfo(const macho_dyld_info_command<P>* dyldInfo, | |
197 | const uint8_t* fileContent); | |
198 | void buildExportHashTableFromSymbolTable(const macho_dysymtab_command<P>* dynamicInfo, | |
199 | const macho_nlist<P>* symbolTable, const char* strings, | |
200 | const uint8_t* fileContent); | |
201 | static const char* objCInfoSegmentName(); | |
202 | static const char* objCInfoSectionName(); | |
203 | ||
204 | const ld::MacVersionMin _macVersionMin; | |
afe874b1 A |
205 | const ld::IOSVersionMin _iOSVersionMin; |
206 | const bool _addVersionLoadCommand; | |
a645023d A |
207 | bool _linkingFlat; |
208 | bool _implicitlyLinkPublicDylibs; | |
209 | ld::File::ObjcConstraint _objcContraint; | |
210 | ld::Section _importProxySection; | |
211 | ld::Section _flatDummySection; | |
212 | std::vector<Dependent> _dependentDylibs; | |
213 | std::vector<const char*> _allowableClients; | |
214 | mutable NameToAtomMap _atoms; | |
215 | NameSet _ignoreExports; | |
216 | const char* _parentUmbrella; | |
217 | ImportAtom<A>* _importAtom; | |
ebf6f434 | 218 | const void* _codeSignatureDR; |
a645023d A |
219 | bool _noRexports; |
220 | bool _hasWeakExports; | |
221 | bool _deadStrippable; | |
222 | bool _hasPublicInstallName; | |
223 | mutable bool _providedAtom; | |
224 | bool _explictReExportFound; | |
225 | ||
226 | static bool _s_logHashtable; | |
227 | }; | |
228 | ||
229 | template <typename A> | |
230 | bool File<A>::_s_logHashtable = false; | |
231 | ||
232 | template <> const char* File<x86_64>::objCInfoSegmentName() { return "__DATA"; } | |
233 | template <> const char* File<arm>::objCInfoSegmentName() { return "__DATA"; } | |
234 | template <typename A> const char* File<A>::objCInfoSegmentName() { return "__OBJC"; } | |
235 | ||
236 | template <> const char* File<x86_64>::objCInfoSectionName() { return "__objc_imageinfo"; } | |
237 | template <> const char* File<arm>::objCInfoSectionName() { return "__objc_imageinfo"; } | |
238 | template <typename A> const char* File<A>::objCInfoSectionName() { return "__image_info"; } | |
239 | ||
240 | template <typename A> | |
ebf6f434 | 241 | File<A>::File(const uint8_t* fileContent, uint64_t fileLength, const char* pth, time_t mTime, ld::File::Ordinal ord, |
a645023d | 242 | bool linkingFlatNamespace, bool linkingMainExecutable, bool hoistImplicitPublicDylibs, |
afe874b1 A |
243 | ld::MacVersionMin macMin, ld::IOSVersionMin iOSMin, bool addVers, |
244 | bool logAllFiles, const char* targetInstallPath, bool indirectDylib) | |
a645023d | 245 | : ld::dylib::File(strdup(pth), mTime, ord), |
afe874b1 | 246 | _macVersionMin(macMin), _iOSVersionMin(iOSMin), _addVersionLoadCommand(addVers), |
a645023d A |
247 | _linkingFlat(linkingFlatNamespace), _implicitlyLinkPublicDylibs(hoistImplicitPublicDylibs), |
248 | _objcContraint(ld::File::objcConstraintNone), | |
249 | _importProxySection("__TEXT", "__import", ld::Section::typeImportProxies, true), | |
250 | _flatDummySection("__LINKEDIT", "__flat_dummy", ld::Section::typeLinkEdit, true), | |
ebf6f434 A |
251 | _parentUmbrella(NULL), _importAtom(NULL), _codeSignatureDR(NULL), |
252 | _noRexports(false), _hasWeakExports(false), | |
a645023d A |
253 | _deadStrippable(false), _hasPublicInstallName(false), |
254 | _providedAtom(false), _explictReExportFound(false) | |
255 | { | |
256 | const macho_header<P>* header = (const macho_header<P>*)fileContent; | |
257 | const uint32_t cmd_count = header->ncmds(); | |
258 | const macho_load_command<P>* const cmds = (macho_load_command<P>*)((char*)header + sizeof(macho_header<P>)); | |
259 | const macho_load_command<P>* const cmdsEnd = (macho_load_command<P>*)((char*)header + sizeof(macho_header<P>) + header->sizeofcmds()); | |
260 | ||
261 | // write out path for -t option | |
262 | if ( logAllFiles ) | |
263 | printf("%s\n", pth); | |
264 | ||
265 | // a "blank" stub has zero load commands | |
266 | if ( (header->filetype() == MH_DYLIB_STUB) && (cmd_count == 0) ) { | |
267 | // no further processing needed | |
268 | munmap((caddr_t)fileContent, fileLength); | |
269 | return; | |
270 | } | |
271 | ||
272 | ||
273 | // optimize the case where we know there is no reason to look at indirect dylibs | |
274 | _noRexports = (header->flags() & MH_NO_REEXPORTED_DYLIBS) | |
275 | || (header->filetype() == MH_BUNDLE) | |
276 | || (header->filetype() == MH_EXECUTE); // bundles and exectuables can be used via -bundle_loader | |
277 | _hasWeakExports = (header->flags() & MH_WEAK_DEFINES); | |
278 | _deadStrippable = (header->flags() & MH_DEAD_STRIPPABLE_DYLIB); | |
279 | ||
280 | // pass 1: get pointers, and see if this dylib uses compressed LINKEDIT format | |
281 | const macho_dysymtab_command<P>* dynamicInfo = NULL; | |
282 | const macho_dyld_info_command<P>* dyldInfo = NULL; | |
ebf6f434 | 283 | const macho_linkedit_data_command<P>* codeSignature = NULL; |
a645023d A |
284 | const macho_nlist<P>* symbolTable = NULL; |
285 | const char* strings = NULL; | |
286 | bool compressedLinkEdit = false; | |
287 | uint32_t dependentLibCount = 0; | |
288 | const macho_load_command<P>* cmd = cmds; | |
289 | for (uint32_t i = 0; i < cmd_count; ++i) { | |
290 | macho_dylib_command<P>* dylibID; | |
291 | const macho_symtab_command<P>* symtab; | |
292 | switch (cmd->cmd()) { | |
293 | case LC_SYMTAB: | |
294 | symtab = (macho_symtab_command<P>*)cmd; | |
295 | symbolTable = (const macho_nlist<P>*)((char*)header + symtab->symoff()); | |
296 | strings = (char*)header + symtab->stroff(); | |
ebf6f434 A |
297 | if ( (symtab->stroff() + symtab->strsize()) > fileLength ) |
298 | throwf("mach-o string pool extends beyond end of file in %s", pth); | |
a645023d A |
299 | break; |
300 | case LC_DYSYMTAB: | |
301 | dynamicInfo = (macho_dysymtab_command<P>*)cmd; | |
302 | break; | |
303 | case LC_DYLD_INFO: | |
304 | case LC_DYLD_INFO_ONLY: | |
305 | dyldInfo = (macho_dyld_info_command<P>*)cmd; | |
306 | compressedLinkEdit = true; | |
307 | break; | |
308 | case LC_ID_DYLIB: | |
309 | dylibID = (macho_dylib_command<P>*)cmd; | |
310 | _dylibInstallPath = strdup(dylibID->name()); | |
311 | _dylibTimeStamp = dylibID->timestamp(); | |
312 | _dylibCurrentVersion = dylibID->current_version(); | |
313 | _dylibCompatibilityVersion = dylibID->compatibility_version(); | |
314 | _hasPublicInstallName = isPublicLocation(_dylibInstallPath); | |
315 | break; | |
316 | case LC_LOAD_DYLIB: | |
317 | case LC_LOAD_WEAK_DYLIB: | |
318 | ++dependentLibCount; | |
319 | break; | |
320 | case LC_REEXPORT_DYLIB: | |
321 | _explictReExportFound = true; | |
322 | ++dependentLibCount; | |
323 | break; | |
324 | case LC_SUB_FRAMEWORK: | |
325 | _parentUmbrella = strdup(((macho_sub_framework_command<P>*)cmd)->umbrella()); | |
326 | break; | |
327 | case LC_SUB_CLIENT: | |
328 | _allowableClients.push_back(strdup(((macho_sub_client_command<P>*)cmd)->client())); | |
329 | break; | |
afe874b1 A |
330 | case LC_VERSION_MIN_MACOSX: |
331 | if ( _addVersionLoadCommand && !indirectDylib && (_iOSVersionMin != ld::iOSVersionUnset) ) | |
332 | warning("building for iOS, but linking against dylib built for MacOSX: %s", pth); | |
333 | break; | |
334 | case LC_VERSION_MIN_IPHONEOS: | |
335 | if ( _addVersionLoadCommand && !indirectDylib && (_macVersionMin != ld::macVersionUnset) ) | |
336 | warning("building for MacOSX, but linking against dylib built for iOS: %s", pth); | |
337 | break; | |
ebf6f434 A |
338 | case LC_CODE_SIGNATURE: |
339 | codeSignature = (macho_linkedit_data_command<P>* )cmd; | |
340 | break; | |
a645023d A |
341 | case macho_segment_command<P>::CMD: |
342 | // check for Objective-C info | |
343 | if ( strcmp(((macho_segment_command<P>*)cmd)->segname(), objCInfoSegmentName()) == 0 ) { | |
344 | const macho_segment_command<P>* segment = (macho_segment_command<P>*)cmd; | |
345 | const macho_section<P>* const sectionsStart = (macho_section<P>*)((char*)segment + sizeof(macho_segment_command<P>)); | |
346 | const macho_section<P>* const sectionsEnd = §ionsStart[segment->nsects()]; | |
347 | for (const macho_section<P>* sect=sectionsStart; sect < sectionsEnd; ++sect) { | |
348 | if ( strncmp(sect->sectname(), objCInfoSectionName(), strlen(objCInfoSectionName())) == 0 ) { | |
349 | // struct objc_image_info { | |
350 | // uint32_t version; // initially 0 | |
351 | // uint32_t flags; | |
352 | // }; | |
353 | // #define OBJC_IMAGE_SUPPORTS_GC 2 | |
354 | // #define OBJC_IMAGE_GC_ONLY 4 | |
355 | // | |
356 | const uint32_t* contents = (uint32_t*)(&fileContent[sect->offset()]); | |
357 | if ( (sect->size() >= 8) && (contents[0] == 0) ) { | |
358 | uint32_t flags = E::get32(contents[1]); | |
359 | if ( (flags & 4) == 4 ) | |
360 | _objcContraint = ld::File::objcConstraintGC; | |
361 | else if ( (flags & 2) == 2 ) | |
362 | _objcContraint = ld::File::objcConstraintRetainReleaseOrGC; | |
363 | else | |
364 | _objcContraint = ld::File::objcConstraintRetainRelease; | |
365 | } | |
366 | else if ( sect->size() > 0 ) { | |
367 | warning("can't parse %s/%s section in %s", objCInfoSegmentName(), objCInfoSectionName(), this->path()); | |
368 | } | |
369 | } | |
370 | } | |
371 | } | |
372 | } | |
373 | cmd = (const macho_load_command<P>*)(((char*)cmd)+cmd->cmdsize()); | |
374 | if ( cmd > cmdsEnd ) | |
375 | throwf("malformed dylb, load command #%d is outside size of load commands in %s", i, pth); | |
376 | } | |
377 | ||
378 | // figure out if we need to examine dependent dylibs | |
379 | // with compressed LINKEDIT format, MH_NO_REEXPORTED_DYLIBS can be trusted | |
380 | bool processDependentLibraries = true; | |
381 | if ( compressedLinkEdit && _noRexports && !linkingFlatNamespace) | |
382 | processDependentLibraries = false; | |
383 | ||
384 | if ( processDependentLibraries ) { | |
385 | // pass 2 builds list of all dependent libraries | |
386 | _dependentDylibs.reserve(dependentLibCount); | |
387 | cmd = cmds; | |
b1f7435d | 388 | unsigned int reExportDylibCount = 0; |
a645023d A |
389 | for (uint32_t i = 0; i < cmd_count; ++i) { |
390 | switch (cmd->cmd()) { | |
391 | case LC_LOAD_DYLIB: | |
392 | case LC_LOAD_WEAK_DYLIB: | |
393 | // with new linkedit format only care about LC_REEXPORT_DYLIB | |
394 | if ( compressedLinkEdit && !linkingFlatNamespace ) | |
395 | break; | |
396 | case LC_REEXPORT_DYLIB: | |
b1f7435d | 397 | ++reExportDylibCount; |
a645023d A |
398 | Dependent entry; |
399 | entry.path = strdup(((macho_dylib_command<P>*)cmd)->name()); | |
400 | entry.dylib = NULL; | |
401 | entry.reExport = (cmd->cmd() == LC_REEXPORT_DYLIB); | |
afe874b1 A |
402 | if ( (targetInstallPath == NULL) || (strcmp(targetInstallPath, entry.path) != 0) ) |
403 | _dependentDylibs.push_back(entry); | |
a645023d A |
404 | break; |
405 | } | |
406 | cmd = (const macho_load_command<P>*)(((char*)cmd)+cmd->cmdsize()); | |
407 | } | |
408 | // verify MH_NO_REEXPORTED_DYLIBS bit was correct | |
409 | if ( compressedLinkEdit && !linkingFlatNamespace ) { | |
b1f7435d | 410 | assert(reExportDylibCount != 0); |
a645023d A |
411 | } |
412 | // pass 3 add re-export info | |
413 | cmd = cmds; | |
414 | for (uint32_t i = 0; i < cmd_count; ++i) { | |
415 | const char* frameworkLeafName; | |
416 | const char* dylibBaseName; | |
417 | switch (cmd->cmd()) { | |
418 | case LC_SUB_UMBRELLA: | |
419 | frameworkLeafName = ((macho_sub_umbrella_command<P>*)cmd)->sub_umbrella(); | |
420 | for (typename std::vector<Dependent>::iterator it = _dependentDylibs.begin(); it != _dependentDylibs.end(); ++it) { | |
421 | const char* dylibName = it->path; | |
422 | const char* lastSlash = strrchr(dylibName, '/'); | |
423 | if ( (lastSlash != NULL) && (strcmp(&lastSlash[1], frameworkLeafName) == 0) ) | |
424 | it->reExport = true; | |
425 | } | |
426 | break; | |
427 | case LC_SUB_LIBRARY: | |
428 | dylibBaseName = ((macho_sub_library_command<P>*)cmd)->sub_library(); | |
429 | for (typename std::vector<Dependent>::iterator it = _dependentDylibs.begin(); it != _dependentDylibs.end(); ++it) { | |
430 | const char* dylibName = it->path; | |
431 | const char* lastSlash = strrchr(dylibName, '/'); | |
432 | const char* leafStart = &lastSlash[1]; | |
433 | if ( lastSlash == NULL ) | |
434 | leafStart = dylibName; | |
435 | const char* firstDot = strchr(leafStart, '.'); | |
436 | int len = strlen(leafStart); | |
437 | if ( firstDot != NULL ) | |
438 | len = firstDot - leafStart; | |
439 | if ( strncmp(leafStart, dylibBaseName, len) == 0 ) | |
440 | it->reExport = true; | |
441 | } | |
442 | break; | |
443 | } | |
444 | cmd = (const macho_load_command<P>*)(((char*)cmd)+cmd->cmdsize()); | |
445 | } | |
446 | } | |
447 | ||
448 | // validate minimal load commands | |
449 | if ( (_dylibInstallPath == NULL) && ((header->filetype() == MH_DYLIB) || (header->filetype() == MH_DYLIB_STUB)) ) | |
450 | throwf("dylib %s missing LC_ID_DYLIB load command", pth); | |
451 | if ( dyldInfo == NULL ) { | |
452 | if ( symbolTable == NULL ) | |
453 | throw "binary missing LC_SYMTAB load command"; | |
454 | if ( dynamicInfo == NULL ) | |
455 | throw "binary missing LC_DYSYMTAB load command"; | |
456 | } | |
457 | ||
458 | // if linking flat and this is a flat dylib, create one atom that references all imported symbols | |
459 | if ( linkingFlatNamespace && linkingMainExecutable && ((header->flags() & MH_TWOLEVEL) == 0) ) { | |
460 | std::vector<const char*> importNames; | |
461 | importNames.reserve(dynamicInfo->nundefsym()); | |
462 | const macho_nlist<P>* start = &symbolTable[dynamicInfo->iundefsym()]; | |
463 | const macho_nlist<P>* end = &start[dynamicInfo->nundefsym()]; | |
464 | for (const macho_nlist<P>* sym=start; sym < end; ++sym) { | |
465 | importNames.push_back(&strings[sym->n_strx()]); | |
466 | } | |
467 | _importAtom = new ImportAtom<A>(*this, importNames); | |
468 | } | |
469 | ||
ebf6f434 A |
470 | // if the dylib is code signed, look for its Designated Requirement |
471 | if ( codeSignature != NULL ) { | |
472 | const Security::BlobCore* overallSignature = (Security::BlobCore*)((char*)header + codeSignature->dataoff()); | |
473 | typedef Security::SuperBlob<Security::kSecCodeMagicEmbeddedSignature> EmbeddedSignatureBlob; | |
474 | typedef Security::SuperBlob<Security::kSecCodeMagicRequirementSet> InternalRequirementsBlob; | |
475 | const EmbeddedSignatureBlob* signature = EmbeddedSignatureBlob::specific(overallSignature); | |
476 | if ( signature->validateBlob(codeSignature->datasize()) ) { | |
477 | const InternalRequirementsBlob* ireq = signature->find<InternalRequirementsBlob>(Security::cdRequirementsSlot); | |
478 | if ( (ireq != NULL) && ireq->validateBlob() ) { | |
479 | const Security::BlobCore* dr = ireq->find(Security::kSecDesignatedRequirementType); | |
480 | if ( (dr != NULL) && dr->validateBlob(Security::kSecCodeMagicRequirement) ) { | |
481 | // <rdar://problem/10968461> make copy because mapped file is about to be unmapped | |
482 | _codeSignatureDR = ::malloc(dr->length()); | |
483 | ::memcpy((void*)_codeSignatureDR, dr, dr->length()); | |
484 | } | |
485 | } | |
486 | } | |
487 | } | |
488 | ||
a645023d A |
489 | // build hash table |
490 | if ( dyldInfo != NULL ) | |
491 | buildExportHashTableFromExportInfo(dyldInfo, fileContent); | |
492 | else | |
493 | buildExportHashTableFromSymbolTable(dynamicInfo, symbolTable, strings, fileContent); | |
494 | ||
495 | // unmap file | |
496 | munmap((caddr_t)fileContent, fileLength); | |
497 | } | |
498 | ||
499 | ||
500 | template <typename A> | |
501 | void File<A>::buildExportHashTableFromSymbolTable(const macho_dysymtab_command<P>* dynamicInfo, | |
502 | const macho_nlist<P>* symbolTable, const char* strings, | |
503 | const uint8_t* fileContent) | |
504 | { | |
505 | if ( dynamicInfo->tocoff() == 0 ) { | |
506 | if ( _s_logHashtable ) fprintf(stderr, "ld: building hashtable of %u toc entries for %s\n", dynamicInfo->nextdefsym(), this->path()); | |
507 | const macho_nlist<P>* start = &symbolTable[dynamicInfo->iextdefsym()]; | |
508 | const macho_nlist<P>* end = &start[dynamicInfo->nextdefsym()]; | |
509 | _atoms.resize(dynamicInfo->nextdefsym()); // set initial bucket count | |
510 | for (const macho_nlist<P>* sym=start; sym < end; ++sym) { | |
511 | this->addSymbol(&strings[sym->n_strx()], (sym->n_desc() & N_WEAK_DEF) != 0, false, sym->n_value()); | |
512 | } | |
513 | } | |
514 | else { | |
515 | int32_t count = dynamicInfo->ntoc(); | |
516 | _atoms.resize(count); // set initial bucket count | |
517 | if ( _s_logHashtable ) fprintf(stderr, "ld: building hashtable of %u entries for %s\n", count, this->path()); | |
518 | const struct dylib_table_of_contents* toc = (dylib_table_of_contents*)(fileContent + dynamicInfo->tocoff()); | |
519 | for (int32_t i = 0; i < count; ++i) { | |
520 | const uint32_t index = E::get32(toc[i].symbol_index); | |
521 | const macho_nlist<P>* sym = &symbolTable[index]; | |
522 | this->addSymbol(&strings[sym->n_strx()], (sym->n_desc() & N_WEAK_DEF) != 0, false, sym->n_value()); | |
523 | } | |
524 | } | |
525 | ||
526 | // special case old libSystem | |
527 | if ( (_dylibInstallPath != NULL) && (strcmp(_dylibInstallPath, "/usr/lib/libSystem.B.dylib") == 0) ) | |
528 | addDyldFastStub(); | |
529 | } | |
530 | ||
531 | ||
532 | template <typename A> | |
533 | void File<A>::buildExportHashTableFromExportInfo(const macho_dyld_info_command<P>* dyldInfo, | |
534 | const uint8_t* fileContent) | |
535 | { | |
536 | if ( _s_logHashtable ) fprintf(stderr, "ld: building hashtable from export info in %s\n", this->path()); | |
537 | if ( dyldInfo->export_size() > 0 ) { | |
538 | const uint8_t* start = fileContent + dyldInfo->export_off(); | |
539 | const uint8_t* end = &start[dyldInfo->export_size()]; | |
540 | std::vector<mach_o::trie::Entry> list; | |
541 | parseTrie(start, end, list); | |
542 | for (std::vector<mach_o::trie::Entry>::iterator it=list.begin(); it != list.end(); ++it) | |
543 | this->addSymbol(it->name, | |
544 | it->flags & EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION, | |
545 | (it->flags & EXPORT_SYMBOL_FLAGS_KIND_MASK) == EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL, | |
546 | it->address); | |
547 | } | |
548 | } | |
549 | ||
550 | ||
551 | template <> | |
552 | void File<x86_64>::addDyldFastStub() | |
553 | { | |
554 | addSymbol("dyld_stub_binder", false, false, 0); | |
555 | } | |
556 | ||
557 | template <> | |
558 | void File<x86>::addDyldFastStub() | |
559 | { | |
560 | addSymbol("dyld_stub_binder", false, false, 0); | |
561 | } | |
562 | ||
563 | template <typename A> | |
564 | void File<A>::addDyldFastStub() | |
565 | { | |
566 | // do nothing | |
567 | } | |
568 | ||
569 | template <typename A> | |
570 | void File<A>::addSymbol(const char* name, bool weakDef, bool tlv, pint_t address) | |
571 | { | |
572 | if ( weakDef ) { | |
573 | assert(_hasWeakExports); | |
574 | } | |
575 | //fprintf(stderr, "addSymbol() %s\n", name); | |
576 | // symbols that start with $ld$ are meta-data to the static linker | |
577 | // <rdar://problem/5182537> need way for ld and dyld to see different exported symbols in a dylib | |
578 | if ( strncmp(name, "$ld$", 4) == 0 ) { | |
579 | // $ld$ <action> $ <condition> $ <symbol-name> | |
580 | const char* symAction = &name[4]; | |
581 | const char* symCond = strchr(symAction, '$'); | |
582 | if ( symCond != NULL ) { | |
583 | char curOSVers[16]; | |
584 | if ( _macVersionMin != ld::macVersionUnset ) { | |
585 | sprintf(curOSVers, "$os%d.%d$", (_macVersionMin >> 16), ((_macVersionMin >> 8) & 0xFF)); | |
586 | } | |
afe874b1 A |
587 | else if ( _iOSVersionMin != ld::iOSVersionUnset ) { |
588 | sprintf(curOSVers, "$os%d.%d$", (_iOSVersionMin >> 16), ((_iOSVersionMin >> 8) & 0xFF)); | |
a645023d A |
589 | } |
590 | else { | |
591 | assert(0 && "targeting neither macosx nor iphoneos"); | |
592 | } | |
593 | if ( strncmp(symCond, curOSVers, strlen(curOSVers)) == 0 ) { | |
594 | const char* symName = strchr(&symCond[1], '$'); | |
595 | if ( symName != NULL ) { | |
596 | ++symName; | |
597 | if ( strncmp(symAction, "hide$", 5) == 0 ) { | |
598 | if ( _s_logHashtable ) fprintf(stderr, " adding %s to ignore set for %s\n", symName, this->path()); | |
599 | _ignoreExports.insert(strdup(symName)); | |
600 | return; | |
601 | } | |
602 | else if ( strncmp(symAction, "add$", 4) == 0 ) { | |
603 | this->addSymbol(symName, weakDef, false, 0); | |
604 | return; | |
605 | } | |
ebf6f434 A |
606 | else if ( strncmp(symAction, "install_name$", 13) == 0 ) { |
607 | _dylibInstallPath = symName; | |
608 | return; | |
609 | } | |
a645023d A |
610 | else { |
611 | warning("bad symbol action: %s in dylib %s", name, this->path()); | |
612 | } | |
613 | } | |
614 | } | |
615 | } | |
616 | else { | |
617 | warning("bad symbol condition: %s in dylib %s", name, this->path()); | |
618 | } | |
619 | } | |
620 | ||
621 | // add symbol as possible export if we are not supposed to ignore it | |
622 | if ( _ignoreExports.count(name) == 0 ) { | |
623 | AtomAndWeak bucket; | |
624 | bucket.atom = NULL; | |
afe874b1 | 625 | bucket.weakDef = weakDef; |
a645023d A |
626 | bucket.tlv = tlv; |
627 | bucket.address = address; | |
628 | if ( _s_logHashtable ) fprintf(stderr, " adding %s to hash table for %s\n", name, this->path()); | |
629 | _atoms[strdup(name)] = bucket; | |
630 | } | |
631 | } | |
632 | ||
633 | ||
634 | template <typename A> | |
635 | bool File<A>::forEachAtom(ld::File::AtomHandler& handler) const | |
636 | { | |
637 | handler.doFile(*this); | |
638 | // if doing flatnamespace and need all this dylib's imports resolve | |
639 | // add atom which references alls undefines in this dylib | |
640 | if ( _importAtom != NULL ) { | |
641 | handler.doAtom(*_importAtom); | |
642 | return true; | |
643 | } | |
644 | return false; | |
645 | } | |
646 | ||
647 | template <typename A> | |
648 | bool File<A>::hasWeakDefinition(const char* name) const | |
649 | { | |
650 | // if supposed to ignore this export, then pretend I don't have it | |
651 | if ( _ignoreExports.count(name) != 0 ) | |
652 | return false; | |
653 | ||
654 | typename NameToAtomMap::const_iterator pos = _atoms.find(name); | |
655 | if ( pos != _atoms.end() ) { | |
afe874b1 | 656 | return pos->second.weakDef; |
a645023d A |
657 | } |
658 | else { | |
659 | // look in children that I re-export | |
660 | for (typename std::vector<Dependent>::const_iterator it = _dependentDylibs.begin(); it != _dependentDylibs.end(); ++it) { | |
661 | if ( it->reExport ) { | |
662 | //fprintf(stderr, "getJustInTimeAtomsFor: %s NOT found in %s, looking in child %s\n", name, this->path(), (*it)->getInstallPath()); | |
663 | typename NameToAtomMap::iterator cpos = it->dylib->_atoms.find(name); | |
664 | if ( cpos != it->dylib->_atoms.end() ) | |
afe874b1 | 665 | return cpos->second.weakDef; |
a645023d A |
666 | } |
667 | } | |
668 | } | |
669 | return false; | |
670 | } | |
671 | ||
afe874b1 A |
672 | |
673 | // <rdar://problem/5529626> If only weak_import symbols are used, linker should use LD_LOAD_WEAK_DYLIB | |
674 | template <typename A> | |
675 | bool File<A>::allSymbolsAreWeakImported() const | |
676 | { | |
677 | bool foundNonWeakImport = false; | |
678 | bool foundWeakImport = false; | |
679 | //fprintf(stderr, "%s:\n", this->path()); | |
680 | for (typename NameToAtomMap::const_iterator it = _atoms.begin(); it != _atoms.end(); ++it) { | |
681 | const ld::Atom* atom = it->second.atom; | |
682 | if ( atom != NULL ) { | |
683 | if ( atom->weakImported() ) | |
684 | foundWeakImport = true; | |
685 | else | |
686 | foundNonWeakImport = true; | |
687 | //fprintf(stderr, " weak_import=%d, name=%s\n", atom->weakImported(), it->first); | |
688 | } | |
689 | } | |
690 | ||
691 | // don't automatically weak link dylib with no imports | |
692 | // so at least one weak import symbol and no non-weak-imported symbols must be found | |
693 | return foundWeakImport && !foundNonWeakImport; | |
694 | } | |
695 | ||
696 | ||
a645023d A |
697 | template <typename A> |
698 | bool File<A>::containsOrReExports(const char* name, bool* weakDef, bool* tlv, pint_t* defAddress) const | |
699 | { | |
afe874b1 A |
700 | if ( _ignoreExports.count(name) != 0 ) |
701 | return false; | |
702 | ||
703 | // check myself | |
a645023d A |
704 | typename NameToAtomMap::iterator pos = _atoms.find(name); |
705 | if ( pos != _atoms.end() ) { | |
afe874b1 | 706 | *weakDef = pos->second.weakDef; |
a645023d A |
707 | *tlv = pos->second.tlv; |
708 | *defAddress = pos->second.address; | |
709 | return true; | |
710 | } | |
711 | ||
712 | // check dylibs I re-export | |
713 | for (typename std::vector<Dependent>::const_iterator it = _dependentDylibs.begin(); it != _dependentDylibs.end(); ++it) { | |
714 | if ( it->reExport && !it->dylib->implicitlyLinked() ) { | |
715 | if ( it->dylib->containsOrReExports(name, weakDef, tlv, defAddress) ) | |
716 | return true; | |
717 | } | |
718 | } | |
719 | ||
720 | return false; | |
721 | } | |
722 | ||
723 | ||
724 | template <typename A> | |
725 | bool File<A>::justInTimeforEachAtom(const char* name, ld::File::AtomHandler& handler) const | |
726 | { | |
727 | // if supposed to ignore this export, then pretend I don't have it | |
728 | if ( _ignoreExports.count(name) != 0 ) | |
729 | return false; | |
730 | ||
731 | ||
732 | AtomAndWeak bucket; | |
afe874b1 A |
733 | if ( this->containsOrReExports(name, &bucket.weakDef, &bucket.tlv, &bucket.address) ) { |
734 | bucket.atom = new ExportAtom<A>(*this, name, bucket.weakDef, bucket.tlv, bucket.address); | |
a645023d A |
735 | _atoms[name] = bucket; |
736 | _providedAtom = true; | |
737 | if ( _s_logHashtable ) fprintf(stderr, "getJustInTimeAtomsFor: %s found in %s\n", name, this->path()); | |
738 | // call handler with new export atom | |
739 | handler.doAtom(*bucket.atom); | |
740 | return true; | |
741 | } | |
742 | ||
743 | return false; | |
744 | } | |
745 | ||
746 | ||
747 | ||
748 | template <typename A> | |
749 | bool File<A>::isPublicLocation(const char* pth) | |
750 | { | |
751 | // -no_implicit_dylibs disables this optimization | |
752 | if ( ! _implicitlyLinkPublicDylibs ) | |
753 | return false; | |
754 | ||
755 | // /usr/lib is a public location | |
756 | if ( (strncmp(pth, "/usr/lib/", 9) == 0) && (strchr(&pth[9], '/') == NULL) ) | |
757 | return true; | |
758 | ||
759 | // /System/Library/Frameworks/ is a public location | |
760 | if ( strncmp(pth, "/System/Library/Frameworks/", 27) == 0 ) { | |
761 | const char* frameworkDot = strchr(&pth[27], '.'); | |
762 | // but only top level framework | |
763 | // /System/Library/Frameworks/Foo.framework/Versions/A/Foo ==> true | |
764 | // /System/Library/Frameworks/Foo.framework/Resources/libBar.dylib ==> false | |
765 | // /System/Library/Frameworks/Foo.framework/Frameworks/Bar.framework/Bar ==> false | |
766 | // /System/Library/Frameworks/Foo.framework/Frameworks/Xfoo.framework/XFoo ==> false | |
767 | if ( frameworkDot != NULL ) { | |
768 | int frameworkNameLen = frameworkDot - &pth[27]; | |
769 | if ( strncmp(&pth[strlen(pth)-frameworkNameLen-1], &pth[26], frameworkNameLen+1) == 0 ) | |
770 | return true; | |
771 | } | |
772 | } | |
773 | ||
774 | return false; | |
775 | } | |
776 | ||
777 | template <typename A> | |
778 | void File<A>::processIndirectLibraries(ld::dylib::File::DylibHandler* handler, bool addImplicitDylibs) | |
779 | { | |
780 | const static bool log = false; | |
781 | if ( log ) fprintf(stderr, "processIndirectLibraries(%s)\n", this->installPath()); | |
782 | if ( _linkingFlat ) { | |
783 | for (typename std::vector<Dependent>::iterator it = _dependentDylibs.begin(); it != _dependentDylibs.end(); it++) { | |
784 | it->dylib = (File<A>*)handler->findDylib(it->path, this->path()); | |
785 | } | |
786 | } | |
787 | else if ( _noRexports ) { | |
788 | // MH_NO_REEXPORTED_DYLIBS bit set, then nothing to do | |
789 | } | |
790 | else { | |
791 | // two-level, might have re-exports | |
792 | for (typename std::vector<Dependent>::iterator it = _dependentDylibs.begin(); it != _dependentDylibs.end(); it++) { | |
793 | if ( it->reExport ) { | |
794 | if ( log ) fprintf(stderr, "processIndirectLibraries() parent=%s, child=%s\n", this->installPath(), it->path); | |
795 | // a LC_REEXPORT_DYLIB, LC_SUB_UMBRELLA or LC_SUB_LIBRARY says we re-export this child | |
796 | it->dylib = (File<A>*)handler->findDylib(it->path, this->path()); | |
797 | if ( it->dylib->hasPublicInstallName() ) { | |
798 | // promote this child to be automatically added as a direct dependent if this already is | |
799 | if ( (this->explicitlyLinked() || this->implicitlyLinked()) && (strcmp(it->path,it->dylib->installPath()) == 0) ) { | |
800 | if ( log ) fprintf(stderr, "processIndirectLibraries() implicitly linking %s\n", it->dylib->installPath()); | |
801 | it->dylib->setImplicitlyLinked(); | |
802 | } | |
803 | else if ( it->dylib->explicitlyLinked() || it->dylib->implicitlyLinked() ) { | |
804 | if ( log ) fprintf(stderr, "processIndirectLibraries() parent is not directly linked, but child is, so no need to re-export child\n"); | |
805 | } | |
806 | else { | |
807 | if ( log ) fprintf(stderr, "processIndirectLibraries() parent is not directly linked, so parent=%s will re-export child=%s\n", this->installPath(), it->path); | |
808 | } | |
809 | } | |
810 | else { | |
811 | // add all child's symbols to me | |
812 | if ( log ) fprintf(stderr, "processIndirectLibraries() child is not public, so parent=%s will re-export child=%s\n", this->installPath(), it->path); | |
813 | } | |
814 | } | |
815 | else if ( !_explictReExportFound ) { | |
816 | // see if child contains LC_SUB_FRAMEWORK with my name | |
817 | it->dylib = (File<A>*)handler->findDylib(it->path, this->path()); | |
818 | const char* parentUmbrellaName = it->dylib->parentUmbrella(); | |
819 | if ( parentUmbrellaName != NULL ) { | |
820 | const char* parentName = this->path(); | |
821 | const char* lastSlash = strrchr(parentName, '/'); | |
822 | if ( (lastSlash != NULL) && (strcmp(&lastSlash[1], parentUmbrellaName) == 0) ) { | |
823 | // add all child's symbols to me | |
824 | it->reExport = true; | |
825 | if ( log ) fprintf(stderr, "processIndirectLibraries() umbrella=%s will re-export child=%s\n", this->installPath(), it->path); | |
826 | } | |
827 | } | |
828 | } | |
829 | } | |
830 | } | |
831 | ||
832 | // check for re-export cycles | |
833 | ReExportChain chain; | |
834 | chain.prev = NULL; | |
835 | chain.file = this; | |
836 | this->assertNoReExportCycles(&chain); | |
837 | } | |
838 | ||
839 | template <typename A> | |
840 | void File<A>::assertNoReExportCycles(ReExportChain* prev) | |
841 | { | |
842 | // recursively check my re-exported dylibs | |
843 | ReExportChain chain; | |
844 | chain.prev = prev; | |
845 | chain.file = this; | |
846 | for (typename std::vector<Dependent>::iterator it = _dependentDylibs.begin(); it != _dependentDylibs.end(); it++) { | |
847 | if ( it->reExport ) { | |
848 | ld::File* child = it->dylib; | |
849 | // check child is not already in chain | |
850 | for (ReExportChain* p = prev; p != NULL; p = p->prev) { | |
851 | if ( p->file == child ) { | |
852 | throwf("cycle in dylib re-exports with %s and %s", child->path(), this->path()); | |
853 | } | |
854 | } | |
855 | if ( it->dylib != NULL ) | |
856 | it->dylib->assertNoReExportCycles(&chain); | |
857 | } | |
858 | } | |
859 | } | |
860 | ||
861 | ||
a645023d A |
862 | template <typename A> |
863 | class Parser | |
864 | { | |
865 | public: | |
866 | typedef typename A::P P; | |
867 | ||
868 | static bool validFile(const uint8_t* fileContent, bool executableOrDyliborBundle); | |
869 | static ld::dylib::File* parse(const uint8_t* fileContent, uint64_t fileLength, | |
870 | const char* path, time_t mTime, | |
ebf6f434 A |
871 | ld::File::Ordinal ordinal, const Options& opts, bool indirectDylib) { |
872 | return new File<A>(fileContent, fileLength, path, mTime, | |
a645023d A |
873 | ordinal, opts.flatNamespace(), |
874 | opts.linkingMainExecutable(), | |
875 | opts.implicitlyLinkIndirectPublicDylibs(), | |
876 | opts.macosxVersionMin(), | |
afe874b1 A |
877 | opts.iOSVersionMin(), |
878 | opts.addVersionLoadCommand(), | |
879 | opts.logAllFiles(), | |
880 | opts.installPath(), | |
881 | indirectDylib); | |
a645023d A |
882 | } |
883 | ||
884 | }; | |
885 | ||
886 | ||
887 | ||
a645023d A |
888 | template <> |
889 | bool Parser<x86>::validFile(const uint8_t* fileContent, bool executableOrDyliborBundle) | |
890 | { | |
891 | const macho_header<P>* header = (const macho_header<P>*)fileContent; | |
892 | if ( header->magic() != MH_MAGIC ) | |
893 | return false; | |
894 | if ( header->cputype() != CPU_TYPE_I386 ) | |
895 | return false; | |
896 | switch ( header->filetype() ) { | |
897 | case MH_DYLIB: | |
898 | case MH_DYLIB_STUB: | |
899 | return true; | |
900 | case MH_BUNDLE: | |
901 | if ( executableOrDyliborBundle ) | |
902 | return true; | |
903 | else | |
904 | throw "can't link with bundle (MH_BUNDLE) only dylibs (MH_DYLIB)"; | |
905 | case MH_EXECUTE: | |
906 | if ( executableOrDyliborBundle ) | |
907 | return true; | |
908 | else | |
909 | throw "can't link with a main executable"; | |
910 | default: | |
911 | return false; | |
912 | } | |
913 | } | |
914 | ||
915 | template <> | |
916 | bool Parser<x86_64>::validFile(const uint8_t* fileContent, bool executableOrDyliborBundle) | |
917 | { | |
918 | const macho_header<P>* header = (const macho_header<P>*)fileContent; | |
919 | if ( header->magic() != MH_MAGIC_64 ) | |
920 | return false; | |
921 | if ( header->cputype() != CPU_TYPE_X86_64 ) | |
922 | return false; | |
923 | switch ( header->filetype() ) { | |
924 | case MH_DYLIB: | |
925 | case MH_DYLIB_STUB: | |
926 | return true; | |
927 | case MH_BUNDLE: | |
928 | if ( executableOrDyliborBundle ) | |
929 | return true; | |
930 | else | |
931 | throw "can't link with bundle (MH_BUNDLE) only dylibs (MH_DYLIB)"; | |
932 | case MH_EXECUTE: | |
933 | if ( executableOrDyliborBundle ) | |
934 | return true; | |
935 | else | |
936 | throw "can't link with a main executable"; | |
937 | default: | |
938 | return false; | |
939 | } | |
940 | } | |
941 | ||
942 | template <> | |
943 | bool Parser<arm>::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_ARM ) | |
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 | ||
970 | ||
971 | // | |
972 | // main function used by linker to instantiate ld::Files | |
973 | // | |
974 | ld::dylib::File* parse(const uint8_t* fileContent, uint64_t fileLength, | |
ebf6f434 | 975 | const char* path, time_t modTime, const Options& opts, ld::File::Ordinal ordinal, |
afe874b1 | 976 | bool bundleLoader, bool indirectDylib) |
a645023d A |
977 | { |
978 | switch ( opts.architecture() ) { | |
ebf6f434 | 979 | #if SUPPORT_ARCH_x86_64 |
a645023d A |
980 | case CPU_TYPE_X86_64: |
981 | if ( Parser<x86_64>::validFile(fileContent, bundleLoader) ) | |
afe874b1 | 982 | return Parser<x86_64>::parse(fileContent, fileLength, path, modTime, ordinal, opts, indirectDylib); |
a645023d | 983 | break; |
ebf6f434 A |
984 | #endif |
985 | #if SUPPORT_ARCH_i386 | |
a645023d A |
986 | case CPU_TYPE_I386: |
987 | if ( Parser<x86>::validFile(fileContent, bundleLoader) ) | |
afe874b1 | 988 | return Parser<x86>::parse(fileContent, fileLength, path, modTime, ordinal, opts, indirectDylib); |
a645023d | 989 | break; |
ebf6f434 A |
990 | #endif |
991 | #if SUPPORT_ARCH_arm_any | |
a645023d A |
992 | case CPU_TYPE_ARM: |
993 | if ( Parser<arm>::validFile(fileContent, bundleLoader) ) | |
afe874b1 | 994 | return Parser<arm>::parse(fileContent, fileLength, path, modTime, ordinal, opts, indirectDylib); |
a645023d | 995 | break; |
ebf6f434 | 996 | #endif |
a645023d A |
997 | } |
998 | return NULL; | |
999 | } | |
1000 | ||
1001 | ||
1002 | }; // namespace dylib | |
1003 | }; // namespace mach_o | |
1004 | ||
1005 |