]> git.saurik.com Git - apple/ld64.git/blob - src/ld/parsers/textstub_dylib_file.cpp
fb452d8b6fcb9590234b1fb2e2aebd1c216af69b
[apple/ld64.git] / src / ld / parsers / textstub_dylib_file.cpp
1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
2 *
3 * Copyright (c) 2015 Apple Inc. All rights reserved.
4 *
5 * @APPLE_LICENSE_HEADER_START@
6 *
7 * This file contains Original Code and/or Modifications of Original Code
8 * as defined in and that are subject to the Apple Public Source License
9 * Version 2.0 (the 'License'). You may not use this file except in
10 * compliance with the License. Please obtain a copy of the License at
11 * http://www.opensource.apple.com/apsl/ and read it before using this
12 * file.
13 *
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
19 * Please see the License for the specific language governing rights and
20 * limitations under the License.
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24
25
26 #include <sys/param.h>
27 #include <sys/mman.h>
28
29 #include <vector>
30
31 #include "Architectures.hpp"
32 #include "bitcode.hpp"
33 #include "MachOFileAbstraction.hpp"
34 #include "MachOTrie.hpp"
35 #include "generic_dylib_file.hpp"
36 #include "textstub_dylib_file.hpp"
37
38 namespace {
39
40 ///
41 /// A token is a light-weight reference to the content of an nmap'ed file. It
42 /// doesn't own the data and it doesn't make a copy of it. The referenced data
43 /// is only valid as long as the file is mapped in.
44 ///
45 class Token {
46 const char* _p;
47 size_t _size;
48
49 int compareMemory(const char* lhs, const char* rhs, size_t size) const {
50 if (size == 0)
51 return 0;
52 return ::memcmp(lhs, rhs, size);
53 }
54
55 public:
56 Token() : _p(nullptr), _size(0) {}
57
58 Token(const char* p) : _p(p), _size(0) {
59 if (p)
60 _size = ::strlen(p);
61 }
62
63 Token(const char* p, size_t s) : _p(p), _size(s) {}
64
65 const char* data() const { return _p; }
66
67 size_t size() const { return _size; }
68
69 std::string str() const { return std::string(_p, _size); }
70
71 bool empty() const { return _size == 0; }
72
73 bool operator==(Token other) const {
74 if (_size != other._size)
75 return false;
76 return compareMemory(_p, other._p, _size) == 0;
77 }
78
79 bool operator!=(Token other) const {
80 return !(*this == other);
81 }
82 };
83
84 ///
85 /// Simple text-based dynamic library file tokenizer.
86 ///
87 class Tokenizer {
88 const char* _start;
89 const char* _current;
90 const char* _end;
91 Token _currentToken;
92
93 void fetchNextToken();
94 void scanToNextToken();
95 void skip(unsigned distance) {
96 _current += distance;
97 assert(_current <= _end && "Skipped past the end");
98 }
99
100 const char* skipLineBreak(const char* pos) const;
101 bool isDelimiter(const char* pos) const;
102
103 public:
104 Tokenizer(const char* data, uint64_t size) : _start(data), _current(data), _end(data + size) {}
105
106 void reset() {
107 _current = _start;
108 fetchNextToken();
109 }
110
111 Token peek() { return _currentToken; }
112 Token next() {
113 Token token = peek();
114 fetchNextToken();
115 return token;
116 }
117 };
118
119 const char* Tokenizer::skipLineBreak(const char* pos) const
120 {
121 if ( pos == _end )
122 return pos;
123
124 // Carriage return.
125 if ( *pos == 0x0D ) {
126 // line feed.
127 if ( pos + 1 != _end && *(pos + 1) == 0x0A)
128 return pos + 2;
129 return pos + 1;
130 }
131
132 // line feed.
133 if ( *pos == 0x0A )
134 return pos + 1;
135
136 return pos;
137 }
138
139 void Tokenizer::scanToNextToken() {
140 while (true) {
141 while ( isDelimiter(_current) )
142 skip(1);
143
144 const char* i = skipLineBreak(_current);
145 if ( i == _current )
146 break;
147
148 _current = i;
149 }
150 }
151
152
153 bool Tokenizer::isDelimiter(const char* pos) const {
154 if ( pos == _end )
155 return false;
156 if ( *pos == ' ' || *pos == '\t' || *pos == '\r' || *pos == '\n' || *pos == ',' || *pos == ':' || *pos == '\'' || *pos == '\"' )
157 return true;
158 return false;
159 }
160
161 void Tokenizer::fetchNextToken() {
162 scanToNextToken();
163
164 if (_current == _end) {
165 _currentToken = Token();
166 return;
167 }
168
169 auto start = _current;
170 while ( !isDelimiter(_current) ) {
171 ++_current;
172 }
173
174 _currentToken = Token(start, _current - start);
175 }
176
177 ///
178 /// Representation of a parsed text-based dynamic library file.
179 ///
180 struct DynamicLibrary {
181 Token _installName;
182 uint32_t _currentVersion;
183 uint32_t _compatibilityVersion;
184 uint8_t _swiftVersion;
185 ld::File::ObjcConstraint _objcConstraint;
186 Options::Platform _platform;
187 std::vector<Token> _allowedClients;
188 std::vector<Token> _reexportedLibraries;
189 std::vector<Token> _symbols;
190 std::vector<Token> _classes;
191 std::vector<Token> _ivars;
192 std::vector<Token> _weakDefSymbols;
193 std::vector<Token> _tlvSymbols;
194
195 DynamicLibrary() : _currentVersion(0x10000), _compatibilityVersion(0x10000), _swiftVersion(0),
196 _objcConstraint(ld::File::objcConstraintNone) {}
197 };
198
199 ///
200 /// A simple text-based dynamic library file parser.
201 ///
202 class TBDFile {
203 Tokenizer _tokenizer;
204
205 Token peek() { return _tokenizer.peek(); }
206 Token next() { return _tokenizer.next(); }
207
208 void expectToken(Token str) {
209 Token token = next();
210 if (token != str)
211 throwf("unexpected token: %s", token.str().c_str());
212 }
213
214 bool hasOptionalToken(Token str) {
215 auto token = peek();
216 if ( token == str ) {
217 next();
218 return true;
219 }
220 return false;
221 }
222
223
224 void parseFlowSequence(std::function<void (Token)> func) {
225 expectToken("[");
226
227 while ( true ) {
228 auto token = peek();
229 if ( token == "]" )
230 break;
231
232 token = next();
233 func(token);
234 }
235
236 expectToken("]");
237 }
238
239 void parseAllowedClients(DynamicLibrary& lib) {
240 if ( !hasOptionalToken("allowed-clients") )
241 return;
242 parseFlowSequence([&](Token name) {
243 lib._allowedClients.emplace_back(name);
244 });
245 }
246
247 void parseReexportedDylibs(DynamicLibrary& lib) {
248 if ( !hasOptionalToken("re-exports") )
249 return;
250 parseFlowSequence([&](Token name) {
251 lib._reexportedLibraries.emplace_back(name);
252 });
253 }
254
255 void parseSymbols(DynamicLibrary& lib) {
256 if ( hasOptionalToken("symbols") ) {
257 parseFlowSequence([&](Token name) {
258 lib._symbols.emplace_back(name);
259 });
260 }
261
262 if ( hasOptionalToken("objc-classes") ) {
263 parseFlowSequence([&](Token name) {
264 lib._classes.emplace_back(name);
265 });
266 }
267
268 if ( hasOptionalToken("objc-ivars") ) {
269 parseFlowSequence([&](Token name) {
270 lib._ivars.emplace_back(name);
271 });
272 }
273
274 if ( hasOptionalToken("weak-def-symbols") ) {
275 parseFlowSequence([&](Token name) {
276 lib._weakDefSymbols.emplace_back(name);
277 });
278 }
279
280 if ( hasOptionalToken("thread-local-symbols") ) {
281 parseFlowSequence([&](Token name) {
282 lib._tlvSymbols.emplace_back(name);
283 });
284 }
285 }
286
287 std::vector<std::string> parseArchFlowSequence() {
288 std::vector<std::string> availabledArchitectures;
289 expectToken("archs");
290 parseFlowSequence([&](Token name) {
291 availabledArchitectures.emplace_back(name.str());
292 });
293 return availabledArchitectures;
294 }
295
296 bool parseArchFlowSequence(std::string &selectedArchName) {
297 auto availabledArchitectures = parseArchFlowSequence();
298
299 for (const auto &archName : availabledArchitectures) {
300 if (archName == selectedArchName)
301 return true;
302 }
303
304 return false;
305 }
306
307 void parsePlatform(DynamicLibrary& lib) {
308 expectToken("platform");
309
310 auto token = next();
311 if (token == "macosx")
312 lib._platform = Options::kPlatformOSX;
313 else if (token == "ios")
314 lib._platform = Options::kPlatformiOS;
315 else if (token == "watchos")
316 lib._platform = Options::kPlatformWatchOS;
317 #if SUPPORT_APPLE_TV
318 else if (token == "tvos")
319 lib._platform = Options::kPlatform_tvOS;
320 #endif
321 else
322 lib._platform = Options::kPlatformUnknown;
323 }
324
325 void parseInstallName(DynamicLibrary& lib) {
326 expectToken("install-name");
327
328 lib._installName = next();
329 if ( lib._installName.empty() )
330 throwf("no install name specified");
331 }
332
333 uint32_t parseVersionNumber32(Token token) {
334 if ( token.size() >= 128 )
335 throwf("malformed version number");
336
337 // Make a null-terminated string.
338 char buffer[128];
339 ::memcpy(buffer, token.data(), token.size());
340 buffer[token.size()] = '\0';
341
342 return Options::parseVersionNumber32(buffer);
343 }
344
345 void parseCurrentVersion(DynamicLibrary& lib) {
346 if ( !hasOptionalToken("current-version") )
347 return;
348 lib._currentVersion = parseVersionNumber32(next());
349 }
350
351 void parseCompatibilityVersion(DynamicLibrary& lib) {
352 if ( !hasOptionalToken("compatibility-version") )
353 return;
354 lib._compatibilityVersion = parseVersionNumber32(next());
355 }
356
357 void parseSwiftVersion(DynamicLibrary& lib) {
358 if ( !hasOptionalToken("swift-version") )
359 return;
360 auto token = next();
361 if ( token == "1.0" )
362 lib._swiftVersion = 1;
363 else if ( token == "1.1" )
364 lib._swiftVersion = 2;
365 else if ( token == "2.0" )
366 lib._swiftVersion = 3;
367 else
368 throwf("unsupported Swift ABI version: %s", token.str().c_str());
369 }
370
371 void parseObjCConstraint(DynamicLibrary& lib) {
372 if ( !hasOptionalToken("objc-constraint") )
373 return;
374 auto token = next();
375 if ( token == "none" )
376 lib._objcConstraint = ld::File::objcConstraintNone;
377 else if ( token == "retain_release" )
378 lib._objcConstraint = ld::File::objcConstraintRetainRelease;
379 else if ( token == "retain_release_for_simulator" )
380 lib._objcConstraint = ld::File::objcConstraintRetainReleaseForSimulator;
381 else if ( token == "retain_release_or_gc" )
382 lib._objcConstraint = ld::File::objcConstraintRetainReleaseOrGC;
383 else if ( token == "gc" )
384 lib._objcConstraint = ld::File::objcConstraintGC;
385 else
386 throwf("unexpected token: %s", token.str().c_str());
387 }
388 void parseExportsBlock(DynamicLibrary& lib, std::string &selectedArchName) {
389 if ( !hasOptionalToken("exports") )
390 return;
391
392 if ( !hasOptionalToken("-") )
393 return;
394
395 while ( true ) {
396 if ( !parseArchFlowSequence(selectedArchName) ) {
397 Token token;
398 while ( true ) {
399 token = peek();
400 if ( token == "archs" || token == "..." || token.empty() )
401 break;
402 next();
403 }
404 if (token == "..." || token.empty() )
405 break;
406
407 continue;
408 }
409
410 parseAllowedClients(lib);
411 parseReexportedDylibs(lib);
412 parseSymbols(lib);
413 if ( !hasOptionalToken("-") )
414 break;
415 }
416 }
417
418 std::vector<std::string> getCompatibleArchList(std::string &requestedArchName) {
419 if (requestedArchName == "i386")
420 return {"i386"};
421 else if (requestedArchName == "x86_64" || requestedArchName == "x86_64h")
422 return {"x86_64", "x86_64h"};
423 else if (requestedArchName == "armv7" || requestedArchName == "armv7s")
424 return {"armv7", "armv7s"};
425 else if (requestedArchName == "armv7k")
426 return {"armv7k"};
427 else if (requestedArchName == "arm64")
428 return {"arm64"};
429 else
430 return {};
431 }
432
433 std::string parseAndSelectArchitecture(std::string &requestedArchName) {
434 auto availabledArchitectures = parseArchFlowSequence();
435
436 // First try to find an exact match (cpu type and sub-cpu type).
437 if (std::find(availabledArchitectures.begin(), availabledArchitectures.end(), requestedArchName)
438 != availabledArchitectures.end())
439 return requestedArchName;
440
441 // If there is no exact match, then try to find an ABI compatible slice.
442 auto compatibleArchitectures = getCompatibleArchList(requestedArchName);
443 std::vector<std::string> result;
444 std::sort(availabledArchitectures.begin(), availabledArchitectures.end());
445 std::sort(compatibleArchitectures.begin(), compatibleArchitectures.end());
446 std::set_intersection(availabledArchitectures.begin(), availabledArchitectures.end(),
447 compatibleArchitectures.begin(), compatibleArchitectures.end(),
448 std::back_inserter(result));
449
450 if (result.empty())
451 return std::string();
452 else
453 return result.front();
454 }
455
456 void parseDocument(DynamicLibrary& lib, std::string &requestedArchName) {
457 auto selectedArchName = parseAndSelectArchitecture(requestedArchName);
458 if (selectedArchName.empty())
459 throwf("invalid arch");
460
461 parsePlatform(lib);
462 parseInstallName(lib);
463 parseCurrentVersion(lib);
464 parseCompatibilityVersion(lib);
465 parseSwiftVersion(lib);
466 parseObjCConstraint(lib);
467 parseExportsBlock(lib, selectedArchName);
468 }
469
470 public:
471 TBDFile(const char* data, uint64_t size) : _tokenizer(data, size) {}
472
473 DynamicLibrary parseFileForArch(std::string requestedArchName) {
474 _tokenizer.reset();
475 DynamicLibrary lib;
476 expectToken("---");
477 parseDocument(lib, requestedArchName);
478 expectToken("...");
479 return lib;
480 }
481
482 bool validForArch(std::string requestedArchName) {
483 _tokenizer.reset();
484 auto token = next();
485 if ( token != "---" )
486 return false;
487 return !parseAndSelectArchitecture(requestedArchName).empty();
488 }
489
490 void dumpTokens() {
491 _tokenizer.reset();
492 Token token;
493 do {
494 token = next();
495 printf("token: %s\n", token.str().c_str());
496 } while ( !token.empty() );
497 }
498 };
499
500 } // end anonymous namespace
501
502 namespace textstub {
503 namespace dylib {
504
505 //
506 // The reader for a dylib extracts all exported symbols names from the memory-mapped
507 // dylib, builds a hash table, then unmaps the file. This is an important memory
508 // savings for large dylibs.
509 //
510 template <typename A>
511 class File final : public generic::dylib::File<A>
512 {
513 using Base = generic::dylib::File<A>;
514
515 public:
516 static bool validFile(const uint8_t* fileContent, bool executableOrDylib);
517 File(const uint8_t* fileContent, uint64_t fileLength, const char* path,
518 time_t mTime, ld::File::Ordinal ordinal, bool linkingFlatNamespace,
519 bool hoistImplicitPublicDylibs, Options::Platform platform,
520 cpu_type_t cpuType, const char* archName, uint32_t linkMinOSVersion,
521 bool allowSimToMacOSX, bool addVers, bool buildingForSimulator,
522 bool logAllFiles, const char* installPath, bool indirectDylib);
523 virtual ~File() noexcept {}
524
525 private:
526 void buildExportHashTable(const DynamicLibrary &lib);
527
528 cpu_type_t _cpuType;
529 };
530
531 template <typename A>
532 File<A>::File(const uint8_t* fileContent, uint64_t fileLength, const char* path, time_t mTime,
533 ld::File::Ordinal ord, bool linkingFlatNamespace, bool hoistImplicitPublicDylibs,
534 Options::Platform platform, cpu_type_t cpuType, const char* archName,
535 uint32_t linkMinOSVersion, bool allowSimToMacOSX, bool addVers,
536 bool buildingForSimulator, bool logAllFiles, const char* targetInstallPath,
537 bool indirectDylib)
538 : Base(strdup(path), mTime, ord, platform, linkMinOSVersion, linkingFlatNamespace,
539 hoistImplicitPublicDylibs, allowSimToMacOSX, addVers),
540 _cpuType(cpuType)
541 {
542 this->_bitcode = std::unique_ptr<ld::Bitcode>(new ld::Bitcode(nullptr, 0));
543 // Text stubs are implicit app extension safe.
544 this->_appExtensionSafe = true;
545
546 // write out path for -t option
547 if ( logAllFiles )
548 printf("%s\n", path);
549
550 TBDFile stub((const char*)fileContent, fileLength);
551 auto lib = stub.parseFileForArch(archName);
552
553 this->_noRexports = lib._reexportedLibraries.empty();
554 this->_hasWeakExports = !lib._weakDefSymbols.empty();
555 this->_dylibInstallPath = strdup(lib._installName.str().c_str());
556 this->_dylibCurrentVersion = lib._currentVersion;
557 this->_dylibCompatibilityVersion = lib._compatibilityVersion;
558 this->_swiftVersion = lib._swiftVersion;
559 this->_objcConstraint = lib._objcConstraint;
560 this->_hasPublicInstallName = this->isPublicLocation(this->_dylibInstallPath);
561
562 // if framework, capture framework name
563 const char* lastSlash = strrchr(this->_dylibInstallPath, '/');
564 if ( lastSlash != NULL ) {
565 const char* leafName = lastSlash+1;
566 char frname[strlen(leafName)+32];
567 strcpy(frname, leafName);
568 strcat(frname, ".framework/");
569
570 if ( strstr(this->_dylibInstallPath, frname) != NULL )
571 this->_frameworkName = leafName;
572 }
573
574 // TEMPORARY HACK BEGIN: Support ancient re-export command LC_SUB_FRAMEWORK.
575 // <rdar://problem/23614899> [TAPI] Support LC_SUB_FRAMEWORK as re-export indicator.
576 auto installName = std::string(this->_dylibInstallPath);
577
578 // All sub-frameworks of ApplicationServices use LC_SUB_FRAMEWORK.
579 if (installName.find("/System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/") == 0 &&
580 installName.find(".dylib") == std::string::npos) {
581 this->_parentUmbrella = "ApplicationServices";
582 } else if (installName.find("/System/Library/Frameworks/Carbon.framework/Versions/A/Frameworks/") == 0) {
583 this->_parentUmbrella = "Carbon";
584 } else if (installName.find("/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/") == 0 &&
585 installName.find(".dylib") == std::string::npos) {
586 this->_parentUmbrella = "CoreServices";
587 } else if (installName.find("/System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libLinearAlgebra.dylib") == 0 ||
588 installName.find("/System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libQuadrature.dylib") == 0 ||
589 installName.find("System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libSparseBLAS.dylib") == 0) {
590 this->_parentUmbrella = "vecLib";
591 } else if (installName.find("/System/Library/Frameworks/WebKit.framework/Versions/A/Frameworks/WebCore.framework/Versions/A/WebCore") == 0) {
592 this->_parentUmbrella = "WebKit";
593 } else if (installName.find("/usr/lib/system/") == 0 &&
594 installName != "/usr/lib/system/libkxld.dylib") {
595 this->_parentUmbrella = "System";
596 }
597 // TEMPORARY HACK END
598
599 for (auto &client : lib._allowedClients) {
600 if ((this->_parentUmbrella != nullptr) && (client.str() != this->_parentUmbrella))
601 this->_allowableClients.push_back(strdup(client.str().c_str()));
602 }
603
604 // <rdar://problem/20659505> [TAPI] Don't hoist "public" (in /usr/lib/) dylibs that should not be directly linked
605 if ( !this->_allowableClients.empty() )
606 this->_hasPublicInstallName = false;
607
608 if ( (lib._platform != platform) && (platform != Options::kPlatformUnknown) ) {
609 this->_wrongOS = true;
610 if ( this->_addVersionLoadCommand && !indirectDylib ) {
611 if ( buildingForSimulator ) {
612 if ( !this->_allowSimToMacOSXLinking )
613 throwf("building for %s simulator, but linking against dylib built for %s (%s).",
614 Options::platformName(platform), Options::platformName(lib._platform), path);
615 } else {
616 throwf("building for %s, but linking against dylib built for %s (%s).",
617 Options::platformName(platform), Options::platformName(lib._platform), path);
618 }
619 }
620 }
621
622 this->_dependentDylibs.reserve(lib._reexportedLibraries.size());
623 for ( const auto& reexport : lib._reexportedLibraries ) {
624 const char *path = strdup(reexport.str().c_str());
625 if ( (targetInstallPath == nullptr) || (strcmp(targetInstallPath, path) != 0) )
626 this->_dependentDylibs.emplace_back(path, true);
627 }
628
629 // build hash table
630 buildExportHashTable(lib);
631
632 munmap((caddr_t)fileContent, fileLength);
633 }
634
635 template <typename A>
636 void File<A>::buildExportHashTable(const DynamicLibrary& lib) {
637 if (this->_s_logHashtable )
638 fprintf(stderr, "ld: building hashtable from text-stub info in %s\n", this->path());
639
640 for (auto &sym : lib._symbols)
641 this->addSymbol(sym.str().c_str());
642
643 #if SUPPORT_ARCH_i386
644 if (this->_platform == Options::kPlatformOSX && _cpuType == CPU_TYPE_I386) {
645 for (auto &sym : lib._classes)
646 this->addSymbol((".objc_class_name" + sym.str()).c_str());
647 } else {
648 for (auto &sym : lib._classes) {
649 this->addSymbol(("_OBJC_CLASS_$" + sym.str()).c_str());
650 this->addSymbol(("_OBJC_METACLASS_$" + sym.str()).c_str());
651 }
652 }
653 #else
654 for (auto &sym : lib._classes) {
655 this->addSymbol(("_OBJC_CLASS_$" + sym.str()).c_str());
656 this->addSymbol(("_OBJC_METACLASS_$" + sym.str()).c_str());
657 }
658 #endif
659
660 for (auto &sym : lib._ivars)
661 this->addSymbol(("_OBJC_IVAR_$" + sym.str()).c_str());
662
663 for (auto &sym : lib._weakDefSymbols)
664 this->addSymbol(sym.str().c_str(), /*weak=*/true);
665
666 for (auto &sym : lib._tlvSymbols)
667 this->addSymbol(sym.str().c_str(), /*weak=*/false, /*tlv=*/true);
668 }
669
670 template <typename A>
671 class Parser
672 {
673 public:
674 using P = typename A::P;
675
676 static bool validFile(const uint8_t* fileContent, uint64_t fileLength,
677 const std::string &path, const char* archName);
678 static ld::dylib::File* parse(const uint8_t* fileContent, uint64_t fileLength, const char* path,
679 time_t mTime, ld::File::Ordinal ordinal, const Options& opts,
680 bool indirectDylib)
681 {
682 return new File<A>(fileContent, fileLength, path, mTime, ordinal,
683 opts.flatNamespace(),
684 opts.implicitlyLinkIndirectPublicDylibs(),
685 opts.platform(),
686 opts.architecture(),
687 opts.architectureName(),
688 opts.minOSversion(),
689 opts.allowSimulatorToLinkWithMacOSX(),
690 opts.addVersionLoadCommand(),
691 opts.targetIOSSimulator(),
692 opts.logAllFiles(),
693 opts.installPath(),
694 indirectDylib);
695 }
696 };
697
698 template <typename A>
699 bool Parser<A>::validFile(const uint8_t* fileContent, uint64_t fileLength, const std::string &path,
700 const char* archName)
701 {
702 if ( path.find(".tbd", path.size()-4) == std::string::npos )
703 return false;
704
705 TBDFile stub((const char*)fileContent, fileLength);
706 if ( !stub.validForArch(archName) )
707 throwf("missing required architecture %s in file %s", archName, path.c_str());
708
709 return true;
710 }
711
712 //
713 // main function used by linker to instantiate ld::Files
714 //
715 ld::dylib::File* parse(const uint8_t* fileContent, uint64_t fileLength, const char* path,
716 time_t modTime, const Options& opts, ld::File::Ordinal ordinal,
717 bool bundleLoader, bool indirectDylib)
718 {
719 switch ( opts.architecture() ) {
720 #if SUPPORT_ARCH_x86_64
721 case CPU_TYPE_X86_64:
722 if ( Parser<x86_64>::validFile(fileContent, fileLength, path, opts.architectureName()) )
723 return Parser<x86_64>::parse(fileContent, fileLength, path, modTime, ordinal, opts, indirectDylib);
724 break;
725 #endif
726 #if SUPPORT_ARCH_i386
727 case CPU_TYPE_I386:
728 if ( Parser<x86>::validFile(fileContent, fileLength, path, opts.architectureName()) )
729 return Parser<x86>::parse(fileContent, fileLength, path, modTime, ordinal, opts, indirectDylib);
730 break;
731 #endif
732 #if SUPPORT_ARCH_arm_any
733 case CPU_TYPE_ARM:
734 if ( Parser<arm>::validFile(fileContent, fileLength, path, opts.architectureName()) )
735 return Parser<arm>::parse(fileContent, fileLength, path, modTime, ordinal, opts, indirectDylib);
736 break;
737 #endif
738 #if SUPPORT_ARCH_arm64
739 case CPU_TYPE_ARM64:
740 if ( Parser<arm64>::validFile(fileContent, fileLength, path, opts.architectureName()) )
741 return Parser<arm64>::parse(fileContent, fileLength, path, modTime, ordinal, opts, indirectDylib);
742 break;
743 #endif
744 }
745 return nullptr;
746 }
747
748
749 } // namespace dylib
750 } // namespace textstub