]> git.saurik.com Git - apple/ld64.git/blob - src/ld/parsers/macho_dylib_file.cpp
ld64-409.12.tar.gz
[apple/ld64.git] / src / ld / parsers / macho_dylib_file.cpp
1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
2 *
3 * Copyright (c) 2005-2011 Apple Inc. All rights reserved.
4 *
5 * @APPLE_LICENSE_HEADER_START@
6 *
7 * This file contains Original Code and/or Modifications of Original Code
8 * as defined in and that are subject to the Apple Public Source License
9 * Version 2.0 (the 'License'). You may not use this file except in
10 * compliance with the License. Please obtain a copy of the License at
11 * http://www.opensource.apple.com/apsl/ and read it before using this
12 * file.
13 *
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
19 * Please see the License for the specific language governing rights and
20 * limitations under the License.
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24
25
26 #include <stdint.h>
27 #include <math.h>
28 #include <unistd.h>
29 #include <sys/param.h>
30 #include <sys/mman.h>
31
32
33 #include <vector>
34 #include <set>
35 #include <map>
36 #include <algorithm>
37
38 #include "Architectures.hpp"
39 #include "Bitcode.hpp"
40 #include "MachOFileAbstraction.hpp"
41 #include "MachOTrie.hpp"
42 #include "generic_dylib_file.hpp"
43 #include "macho_dylib_file.h"
44 #include "../code-sign-blobs/superblob.h"
45
46 namespace mach_o {
47 namespace dylib {
48
49 //
50 // The reader for a dylib extracts all exported symbols names from the memory-mapped
51 // dylib, builds a hash table, then unmaps the file. This is an important memory
52 // savings for large dylibs.
53 //
54 template <typename A>
55 class File final : public generic::dylib::File<A>
56 {
57 using Base = generic::dylib::File<A>;
58
59 public:
60 static bool validFile(const uint8_t* fileContent, bool executableOrDylib, bool subTypeMustMatch=false);
61 File(const uint8_t* fileContent, uint64_t fileLength, const char* path,
62 time_t mTime, ld::File::Ordinal ordinal, bool linkingFlatNamespace,
63 bool linkingMainExecutable, bool hoistImplicitPublicDylibs,
64 const ld::VersionSet& platforms, bool allowWeakImports,
65 bool allowSimToMacOSX, bool addVers, bool buildingForSimulator,
66 bool logAllFiles, const char* installPath,
67 bool indirectDylib, bool ignoreMismatchPlatform, bool usingBitcode);
68 virtual ~File() noexcept {}
69 virtual const ld::VersionSet& platforms() const { return this->_platforms; }
70
71 private:
72 using P = typename A::P;
73 using E = typename A::P::E;
74 using pint_t = typename A::P::uint_t;
75
76 void addDyldFastStub();
77 void buildExportHashTableFromExportInfo(const macho_dyld_info_command<P>* dyldInfo,
78 const uint8_t* fileContent);
79 void buildExportHashTableFromSymbolTable(const macho_dysymtab_command<P>* dynamicInfo,
80 const macho_nlist<P>* symbolTable, const char* strings,
81 const uint8_t* fileContent);
82 void addSymbol(const char* name, bool weakDef = false, bool tlv = false, pint_t address = 0);
83 static const char* objCInfoSegmentName();
84 static const char* objCInfoSectionName();
85 static bool useSimulatorVariant();
86
87
88 uint64_t _fileLength;
89 uint32_t _linkeditStartOffset;
90
91 };
92
93 template <> const char* File<x86_64>::objCInfoSegmentName() { return "__DATA"; }
94 template <> const char* File<arm>::objCInfoSegmentName() { return "__DATA"; }
95 template <typename A> const char* File<A>::objCInfoSegmentName() { return "__OBJC"; }
96
97 template <> const char* File<x86_64>::objCInfoSectionName() { return "__objc_imageinfo"; }
98 template <> const char* File<arm>::objCInfoSectionName() { return "__objc_imageinfo"; }
99 template <typename A> const char* File<A>::objCInfoSectionName() { return "__image_info"; }
100
101 template <> bool File<x86>::useSimulatorVariant() { return true; }
102 template <> bool File<x86_64>::useSimulatorVariant() { return true; }
103 template <typename A> bool File<A>::useSimulatorVariant() { return false; }
104
105 template <typename A>
106 File<A>::File(const uint8_t* fileContent, uint64_t fileLength, const char* path, time_t mTime,
107 ld::File::Ordinal ord, bool linkingFlatNamespace, bool linkingMainExecutable,
108 bool hoistImplicitPublicDylibs, const ld::VersionSet& platforms, bool allowWeakImports,
109 bool allowSimToMacOSX, bool addVers, bool buildingForSimulator, bool logAllFiles,
110 const char* targetInstallPath, bool indirectDylib, bool ignoreMismatchPlatform, bool usingBitcode)
111 : Base(strdup(path), mTime, ord, platforms, allowWeakImports, linkingFlatNamespace,
112 hoistImplicitPublicDylibs, allowSimToMacOSX, addVers), _fileLength(fileLength), _linkeditStartOffset(0)
113 {
114 const macho_header<P>* header = (const macho_header<P>*)fileContent;
115 const uint32_t cmd_count = header->ncmds();
116 const macho_load_command<P>* const cmds = (macho_load_command<P>*)((char*)header + sizeof(macho_header<P>));
117 const macho_load_command<P>* const cmdsEnd = (macho_load_command<P>*)((char*)header + sizeof(macho_header<P>) + header->sizeofcmds());
118
119 // write out path for -t option
120 if ( logAllFiles )
121 printf("%s\n", path);
122
123 // a "blank" stub has zero load commands
124 if ( (header->filetype() == MH_DYLIB_STUB) && (cmd_count == 0) ) {
125 // no further processing needed
126 munmap((caddr_t)fileContent, fileLength);
127 return;
128 }
129
130
131 // optimize the case where we know there is no reason to look at indirect dylibs
132 this->_noRexports = (header->flags() & MH_NO_REEXPORTED_DYLIBS)
133 || (header->filetype() == MH_BUNDLE)
134 || (header->filetype() == MH_EXECUTE); // bundles and exectuables can be used via -bundle_loader
135 this->_hasWeakExports = (header->flags() & MH_WEAK_DEFINES);
136 this->_deadStrippable = (header->flags() & MH_DEAD_STRIPPABLE_DYLIB);
137 this->_appExtensionSafe = (header->flags() & MH_APP_EXTENSION_SAFE);
138
139 // pass 1: get pointers, and see if this dylib uses compressed LINKEDIT format
140 const macho_dysymtab_command<P>* dynamicInfo = nullptr;
141 const macho_dyld_info_command<P>* dyldInfo = nullptr;
142 const macho_nlist<P>* symbolTable = nullptr;
143 const macho_symtab_command<P>* symtab = nullptr;
144 const char* strings = nullptr;
145 bool compressedLinkEdit = false;
146 uint32_t dependentLibCount = 0;
147 ld::VersionSet lcPlatforms;
148 const macho_load_command<P>* cmd = cmds;
149 for (uint32_t i = 0; i < cmd_count; ++i) {
150 macho_dylib_command<P>* dylibID;
151 uint32_t cmdLength = cmd->cmdsize();
152 switch (cmd->cmd()) {
153 case LC_SYMTAB:
154 symtab = (macho_symtab_command<P>*)cmd;
155 symbolTable = (const macho_nlist<P>*)((char*)header + symtab->symoff());
156 strings = (char*)header + symtab->stroff();
157 if ( (symtab->stroff() + symtab->strsize()) > fileLength )
158 throwf("mach-o string pool extends beyond end of file in %s", path);
159 break;
160 case LC_DYSYMTAB:
161 dynamicInfo = (macho_dysymtab_command<P>*)cmd;
162 break;
163 case LC_DYLD_INFO:
164 case LC_DYLD_INFO_ONLY:
165 dyldInfo = (macho_dyld_info_command<P>*)cmd;
166 compressedLinkEdit = true;
167 break;
168 case LC_ID_DYLIB:
169 dylibID = (macho_dylib_command<P>*)cmd;
170 if ( dylibID->name_offset() > cmdLength )
171 throwf("malformed mach-o: LC_ID_DYLIB load command has offset (%u) outside its size (%u)", dylibID->name_offset(), cmdLength);
172 if ( (dylibID->name_offset() + strlen(dylibID->name()) + 1) > cmdLength )
173 throwf("malformed mach-o: LC_ID_DYLIB load command string extends beyond end of load command");
174 this->_dylibInstallPath = strdup(dylibID->name());
175 this->_dylibTimeStamp = dylibID->timestamp();
176 this->_dylibCurrentVersion = dylibID->current_version();
177 this->_dylibCompatibilityVersion = dylibID->compatibility_version();
178 this->_hasPublicInstallName = this->isPublicLocation(this->_dylibInstallPath);
179 break;
180 case LC_LOAD_DYLIB:
181 case LC_LOAD_WEAK_DYLIB:
182 ++dependentLibCount;
183 break;
184 case LC_REEXPORT_DYLIB:
185 this->_explictReExportFound = true;
186 ++dependentLibCount;
187 break;
188 case LC_SUB_FRAMEWORK:
189 this->_parentUmbrella = strdup(((macho_sub_framework_command<P>*)cmd)->umbrella());
190 break;
191 case LC_SUB_CLIENT:
192 this->_allowableClients.push_back(strdup(((macho_sub_client_command<P>*)cmd)->client()));
193 // <rdar://problem/20627554> Don't hoist "public" (in /usr/lib/) dylibs that should not be directly linked
194 this->_hasPublicInstallName = false;
195 break;
196 case LC_RPATH:
197 this->_rpaths.push_back(strdup(((macho_rpath_command<P>*)cmd)->path()));
198 break;
199 case LC_VERSION_MIN_MACOSX:
200 case LC_VERSION_MIN_IPHONEOS:
201 case LC_VERSION_MIN_WATCHOS:
202 case LC_VERSION_MIN_TVOS:
203 lcPlatforms.add({Options::platformForLoadCommand(cmd->cmd(), useSimulatorVariant()), ((macho_version_min_command<P>*)cmd)->version()});
204 break;
205 case LC_BUILD_VERSION:
206 {
207 const macho_build_version_command<P>* buildVersCmd = (macho_build_version_command<P>*)cmd;
208 lcPlatforms.add({(ld::Platform)buildVersCmd->platform(), buildVersCmd->minos()});
209 }
210 break;
211 case LC_CODE_SIGNATURE:
212 break;
213 case macho_segment_command<P>::CMD:
214 // check for Objective-C info
215 if ( strncmp(((macho_segment_command<P>*)cmd)->segname(), objCInfoSegmentName(), 6) == 0 ) {
216 const macho_segment_command<P>* segment = (macho_segment_command<P>*)cmd;
217 const macho_section<P>* const sectionsStart = (macho_section<P>*)((char*)segment + sizeof(macho_segment_command<P>));
218 const macho_section<P>* const sectionsEnd = &sectionsStart[segment->nsects()];
219 for (const macho_section<P>* sect=sectionsStart; sect < sectionsEnd; ++sect) {
220 if ( strncmp(sect->sectname(), objCInfoSectionName(), strlen(objCInfoSectionName())) == 0 ) {
221 // struct objc_image_info {
222 // uint32_t version; // initially 0
223 // uint32_t flags;
224 // };
225 // #define OBJC_IMAGE_SUPPORTS_GC 2
226 // #define OBJC_IMAGE_GC_ONLY 4
227 // #define OBJC_IMAGE_IS_SIMULATED 32
228 //
229 const uint32_t* contents = (uint32_t*)(&fileContent[sect->offset()]);
230 if ( (sect->size() >= 8) && (contents[0] == 0) ) {
231 uint32_t flags = E::get32(contents[1]);
232 this->_swiftVersion = ((flags >> 8) & 0xFF);
233 }
234 else if ( sect->size() > 0 ) {
235 warning("can't parse %s/%s section in %s", objCInfoSegmentName(), objCInfoSectionName(), path);
236 }
237 }
238 }
239 }
240 // Construct bitcode if there is a bitcode bundle section in the dylib
241 // Record the size of the section because the content is not checked
242 else if ( strcmp(((macho_segment_command<P>*)cmd)->segname(), "__LLVM") == 0 ) {
243 const macho_section<P>* const sect = (macho_section<P>*)((char*)cmd + sizeof(macho_segment_command<P>));
244 if ( strncmp(sect->sectname(), "__bundle", 8) == 0 )
245 this->_bitcode = std::unique_ptr<ld::Bitcode>(new ld::Bitcode(NULL, sect->size()));
246 }
247 else if ( strcmp(((macho_segment_command<P>*)cmd)->segname(), "__LINKEDIT") == 0 ) {
248 _linkeditStartOffset = ((macho_segment_command<P>*)cmd)->fileoff();
249 }
250 }
251 cmd = (const macho_load_command<P>*)(((char*)cmd)+cmdLength);
252 if ( cmd > cmdsEnd )
253 throwf("malformed dylb, load command #%d is outside size of load commands in %s", i, path);
254 }
255 // arm/arm64 objects are default to ios platform if not set.
256 // rdar://problem/21746314
257 if (lcPlatforms.empty() &&
258 (std::is_same<A, arm>::value || std::is_same<A, arm64>::value))
259 lcPlatforms.add({ld::kPlatform_iOS, 0});
260
261 // check cross-linking
262 platforms.forEach(^(ld::Platform platform, uint32_t version, bool &stop) {
263 if (!lcPlatforms.contains(platform) ) {
264 this->_wrongOS = true;
265 if ( this->_addVersionLoadCommand && !indirectDylib && !ignoreMismatchPlatform ) {
266 if (buildingForSimulator && !this->_allowSimToMacOSXLinking) {
267 if ( usingBitcode )
268 throwf("building for %s simulator, but linking against dylib built for %s,",
269 platforms.to_str().c_str(), lcPlatforms.to_str().c_str());
270 else
271 warning("URGENT: building for %s simulator, but linking against dylib (%s) built for %s. "
272 "Note: This will be an error in the future.",
273 platforms.to_str().c_str(), path, lcPlatforms.to_str().c_str());
274 }
275 } else {
276 if ( usingBitcode )
277 throwf("building for %s, but linking against dylib built for %s,",
278 platforms.to_str().c_str(), lcPlatforms.to_str().c_str());
279 else if ( (getenv("RC_XBS") != NULL) && (getenv("RC_BUILDIT") == NULL) ) // FIXME: remove after platform bringup
280 warning("URGENT: building for %s, but linking against dylib (%s) built for %s. "
281 "Note: This will be an error in the future.",
282 platforms.to_str().c_str(), path, lcPlatforms.to_str().c_str());
283 }
284 }
285 });
286
287 // figure out if we need to examine dependent dylibs
288 // with compressed LINKEDIT format, MH_NO_REEXPORTED_DYLIBS can be trusted
289 bool processDependentLibraries = true;
290 if ( compressedLinkEdit && this->_noRexports && !linkingFlatNamespace)
291 processDependentLibraries = false;
292
293 if ( processDependentLibraries ) {
294 // pass 2 builds list of all dependent libraries
295 this->_dependentDylibs.reserve(dependentLibCount);
296 cmd = cmds;
297 unsigned int reExportDylibCount = 0;
298 for (uint32_t i = 0; i < cmd_count; ++i) {
299 uint32_t cmdLength = cmd->cmdsize();
300 const macho_dylib_command<P>* dylibCmd = (macho_dylib_command<P>*)cmd;
301 switch (cmd->cmd()) {
302 case LC_LOAD_DYLIB:
303 case LC_LOAD_WEAK_DYLIB:
304 // with new linkedit format only care about LC_REEXPORT_DYLIB
305 if ( compressedLinkEdit && !linkingFlatNamespace )
306 break;
307 case LC_REEXPORT_DYLIB:
308 ++reExportDylibCount;
309 if ( dylibCmd->name_offset() > cmdLength )
310 throwf("malformed mach-o: LC_*_DYLIB load command has offset (%u) outside its size (%u)", dylibCmd->name_offset(), cmdLength);
311 if ( (dylibCmd->name_offset() + strlen(dylibCmd->name()) + 1) > cmdLength )
312 throwf("malformed mach-o: LC_*_DYLIB load command string extends beyond end of load command");
313 const char *path = strdup(dylibCmd->name());
314 bool reExport = (cmd->cmd() == LC_REEXPORT_DYLIB);
315 if ( (targetInstallPath == nullptr) || (strcmp(targetInstallPath, path) != 0) )
316 this->_dependentDylibs.emplace_back(path, reExport);
317 break;
318 }
319 cmd = (const macho_load_command<P>*)(((char*)cmd)+cmdLength);
320 }
321 // verify MH_NO_REEXPORTED_DYLIBS bit was correct
322 if ( compressedLinkEdit && !linkingFlatNamespace ) {
323 if ( reExportDylibCount == 0 )
324 throwf("malformed dylib has MH_NO_REEXPORTED_DYLIBS flag but no LC_REEXPORT_DYLIB load commands: %s", path);
325 }
326 // pass 3 add re-export info
327 cmd = cmds;
328 for (uint32_t i = 0; i < cmd_count; ++i) {
329 const char* frameworkLeafName;
330 const char* dylibBaseName;
331 switch (cmd->cmd()) {
332 case LC_SUB_UMBRELLA:
333 frameworkLeafName = ((macho_sub_umbrella_command<P>*)cmd)->sub_umbrella();
334 for (auto &dep : this->_dependentDylibs) {
335 const char* dylibName = dep.path;
336 const char* lastSlash = strrchr(dylibName, '/');
337 if ( (lastSlash != nullptr) && (strcmp(&lastSlash[1], frameworkLeafName) == 0) )
338 dep.reExport = true;
339 }
340 break;
341 case LC_SUB_LIBRARY:
342 dylibBaseName = ((macho_sub_library_command<P>*)cmd)->sub_library();
343 for (auto &dep : this->_dependentDylibs) {
344 const char* dylibName = dep.path;
345 const char* lastSlash = strrchr(dylibName, '/');
346 const char* leafStart = &lastSlash[1];
347 if ( lastSlash == nullptr )
348 leafStart = dylibName;
349 const char* firstDot = strchr(leafStart, '.');
350 int len = strlen(leafStart);
351 if ( firstDot != nullptr )
352 len = firstDot - leafStart;
353 if ( strncmp(leafStart, dylibBaseName, len) == 0 )
354 dep.reExport = true;
355 }
356 break;
357 }
358 cmd = (const macho_load_command<P>*)(((char*)cmd)+cmd->cmdsize());
359 }
360 }
361
362 // if framework, capture framework name
363 if ( this->_dylibInstallPath != NULL ) {
364 const char* lastSlash = strrchr(this->_dylibInstallPath, '/');
365 if ( lastSlash != NULL ) {
366 const char* leafName = lastSlash+1;
367 char frname[strlen(leafName)+32];
368 strcpy(frname, leafName);
369 strcat(frname, ".framework/");
370
371 if ( strstr(this->_dylibInstallPath, frname) != NULL )
372 this->_frameworkName = leafName;
373 }
374 }
375
376 // validate minimal load commands
377 if ( (this->_dylibInstallPath == nullptr) && ((header->filetype() == MH_DYLIB) || (header->filetype() == MH_DYLIB_STUB)) )
378 throwf("dylib %s missing LC_ID_DYLIB load command", path);
379 if ( dyldInfo == nullptr ) {
380 if ( symbolTable == nullptr )
381 throw "binary missing LC_SYMTAB load command";
382 if ( dynamicInfo == nullptr )
383 throw "binary missing LC_DYSYMTAB load command";
384 }
385
386 if ( symtab != nullptr ) {
387 if ( symtab->symoff() < _linkeditStartOffset )
388 throwf("malformed mach-o, symbol table not in __LINKEDIT");
389 if ( symtab->stroff() < _linkeditStartOffset )
390 throwf("malformed mach-o, symbol table strings not in __LINKEDIT");
391 }
392
393 // if linking flat and this is a flat dylib, create one atom that references all imported symbols
394 if ( linkingFlatNamespace && linkingMainExecutable && ((header->flags() & MH_TWOLEVEL) == 0) ) {
395 std::vector<const char*> importNames;
396 importNames.reserve(dynamicInfo->nundefsym());
397 const macho_nlist<P>* start = &symbolTable[dynamicInfo->iundefsym()];
398 const macho_nlist<P>* end = &start[dynamicInfo->nundefsym()];
399 for (const macho_nlist<P>* sym=start; sym < end; ++sym) {
400 importNames.push_back(&strings[sym->n_strx()]);
401 }
402 this->_importAtom = new generic::dylib::ImportAtom<A>(*this, importNames);
403 }
404
405 // build hash table
406 if ( dyldInfo != nullptr )
407 buildExportHashTableFromExportInfo(dyldInfo, fileContent);
408 else
409 buildExportHashTableFromSymbolTable(dynamicInfo, symbolTable, strings, fileContent);
410
411 // unmap file
412 munmap((caddr_t)fileContent, fileLength);
413 }
414
415 template <typename A>
416 void File<A>::buildExportHashTableFromSymbolTable(const macho_dysymtab_command<P>* dynamicInfo,
417 const macho_nlist<P>* symbolTable,
418 const char* strings, const uint8_t* fileContent)
419 {
420 if ( dynamicInfo->tocoff() == 0 ) {
421 if ( this->_s_logHashtable )
422 fprintf(stderr, "ld: building hashtable of %u toc entries for %s\n", dynamicInfo->nextdefsym(), this->path());
423 const macho_nlist<P>* start = &symbolTable[dynamicInfo->iextdefsym()];
424 const macho_nlist<P>* end = &start[dynamicInfo->nextdefsym()];
425 this->_atoms.reserve(dynamicInfo->nextdefsym()); // set initial bucket count
426 for (const macho_nlist<P>* sym=start; sym < end; ++sym) {
427 this->addSymbol(&strings[sym->n_strx()], (sym->n_desc() & N_WEAK_DEF) != 0, false, sym->n_value());
428 }
429 }
430 else {
431 int32_t count = dynamicInfo->ntoc();
432 this->_atoms.reserve(count); // set initial bucket count
433 if ( this->_s_logHashtable )
434 fprintf(stderr, "ld: building hashtable of %u entries for %s\n", count, this->path());
435 const auto* toc = reinterpret_cast<const dylib_table_of_contents*>(fileContent + dynamicInfo->tocoff());
436 for (int32_t i = 0; i < count; ++i) {
437 const uint32_t index = E::get32(toc[i].symbol_index);
438 const macho_nlist<P>* sym = &symbolTable[index];
439 this->addSymbol(&strings[sym->n_strx()], (sym->n_desc() & N_WEAK_DEF) != 0, false, sym->n_value());
440 }
441 }
442
443 // special case old libSystem
444 if ( (this->_dylibInstallPath != nullptr) && (strcmp(this->_dylibInstallPath, "/usr/lib/libSystem.B.dylib") == 0) )
445 addDyldFastStub();
446 }
447
448
449 template <typename A>
450 void File<A>::buildExportHashTableFromExportInfo(const macho_dyld_info_command<P>* dyldInfo,
451 const uint8_t* fileContent)
452 {
453 if ( this->_s_logHashtable )
454 fprintf(stderr, "ld: building hashtable from export info in %s\n", this->path());
455 if ( dyldInfo->export_size() > 0 ) {
456 const uint8_t* start = fileContent + dyldInfo->export_off();
457 const uint8_t* end = &start[dyldInfo->export_size()];
458 if ( (dyldInfo->export_off() + dyldInfo->export_size()) > _fileLength )
459 throwf("malformed mach-o dylib, exports trie extends beyond end of file, ");
460 std::vector<mach_o::trie::Entry> list;
461 parseTrie(start, end, list);
462 for (const auto &entry : list)
463 this->addSymbol(entry.name,
464 entry.flags & EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION,
465 (entry.flags & EXPORT_SYMBOL_FLAGS_KIND_MASK) == EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL,
466 entry.address);
467 }
468 }
469
470 template <typename A>
471 void File<A>::addSymbol(const char* name, bool weakDef, bool tlv, pint_t address)
472 {
473 __block uint32_t linkMinOSVersion = 0;
474
475 this->platforms().forEach(^(ld::Platform platform, uint32_t version, bool &stop) {
476 //FIXME hack to handle symbol versioning in a zippered world.
477 //This will need to be rethought
478 if (linkMinOSVersion == 0)
479 linkMinOSVersion = version;
480 if (platform == ld::kPlatform_macOS)
481 linkMinOSVersion = version;
482 });
483
484 // symbols that start with $ld$ are meta-data to the static linker
485 // <rdar://problem/5182537> need way for ld and dyld to see different exported symbols in a dylib
486 if ( strncmp(name, "$ld$", 4) == 0 ) {
487 // $ld$ <action> $ <condition> $ <symbol-name>
488 const char* symAction = &name[4];
489 const char* symCond = strchr(symAction, '$');
490 if ( symCond != nullptr ) {
491 char curOSVers[16];
492 sprintf(curOSVers, "$os%d.%d$", (linkMinOSVersion >> 16), ((linkMinOSVersion >> 8) & 0xFF));
493 if ( strncmp(symCond, curOSVers, strlen(curOSVers)) == 0 ) {
494 const char* symName = strchr(&symCond[1], '$');
495 if ( symName != nullptr ) {
496 ++symName;
497 if ( strncmp(symAction, "hide$", 5) == 0 ) {
498 if ( this->_s_logHashtable )
499 fprintf(stderr, " adding %s to ignore set for %s\n", symName, this->path());
500 this->_ignoreExports.insert(strdup(symName));
501 return;
502 }
503 else if ( strncmp(symAction, "add$", 4) == 0 ) {
504 this->addSymbol(symName, weakDef);
505 return;
506 }
507 else if ( strncmp(symAction, "weak$", 5) == 0 ) {
508 if ( !this->_allowWeakImports )
509 this->_ignoreExports.insert(strdup(symName));
510 }
511 else if ( strncmp(symAction, "install_name$", 13) == 0 ) {
512 this->_dylibInstallPath = strdup(symName);
513 this->_installPathOverride = true;
514 // <rdar://problem/14448206> CoreGraphics redirects to ApplicationServices, but with wrong compat version
515 if ( strcmp(this->_dylibInstallPath, "/System/Library/Frameworks/ApplicationServices.framework/Versions/A/ApplicationServices") == 0 )
516 this->_dylibCompatibilityVersion = Options::parseVersionNumber32("1.0");
517 return;
518 }
519 else if ( strncmp(symAction, "compatibility_version$", 22) == 0 ) {
520 this->_dylibCompatibilityVersion = Options::parseVersionNumber32(symName);
521 return;
522 }
523 else {
524 warning("bad symbol action: %s in dylib %s", name, this->path());
525 }
526 }
527 }
528 }
529 else {
530 warning("bad symbol condition: %s in dylib %s", name, this->path());
531 }
532 }
533
534 // add symbol as possible export if we are not supposed to ignore it
535 if ( this->_ignoreExports.count(name) == 0 ) {
536 typename Base::AtomAndWeak bucket = { nullptr, weakDef, tlv, address };
537 if ( this->_s_logHashtable )
538 fprintf(stderr, " adding %s to hash table for %s\n", name, this->path());
539 this->_atoms[strdup(name)] = bucket;
540 }
541 }
542
543 template <>
544 void File<x86_64>::addDyldFastStub()
545 {
546 addSymbol("dyld_stub_binder");
547 }
548
549 template <>
550 void File<x86>::addDyldFastStub()
551 {
552 addSymbol("dyld_stub_binder");
553 }
554
555 template <typename A>
556 void File<A>::addDyldFastStub()
557 {
558 // do nothing
559 }
560
561 template <typename A>
562 class Parser
563 {
564 public:
565 using P = typename A::P;
566
567 static bool validFile(const uint8_t* fileContent, bool executableOrDyliborBundle, bool subTypeMustMatch=false, uint32_t subType=0);
568 static const char* fileKind(const uint8_t* fileContent);
569 static ld::dylib::File* parse(const uint8_t* fileContent, uint64_t fileLength, const char* path,
570 time_t mTime, ld::File::Ordinal ordinal, const Options& opts,
571 bool indirectDylib)
572 {
573 return new File<A>(fileContent, fileLength, path, mTime, ordinal, opts.flatNamespace(),
574 opts.linkingMainExecutable(), opts.implicitlyLinkIndirectPublicDylibs(),
575 opts.platforms(), opts.allowWeakImports(),
576 opts.allowSimulatorToLinkWithMacOSX(), opts.addVersionLoadCommand(),
577 opts.targetIOSSimulator(), opts.logAllFiles(), opts.installPath(),
578 indirectDylib, opts.outputKind() == Options::kPreload, opts.bundleBitcode());
579 }
580
581 };
582
583
584
585 template <>
586 bool Parser<x86>::validFile(const uint8_t* fileContent, bool executableOrDyliborBundle, bool subTypeMustMatch, uint32_t subType)
587 {
588 const auto* header = reinterpret_cast<const macho_header<P>*>(fileContent);
589 if ( header->magic() != MH_MAGIC )
590 return false;
591 if ( header->cputype() != CPU_TYPE_I386 )
592 return false;
593 switch ( header->filetype() ) {
594 case MH_DYLIB:
595 case MH_DYLIB_STUB:
596 return true;
597 case MH_BUNDLE:
598 if ( executableOrDyliborBundle )
599 return true;
600 else
601 throw "can't link with bundle (MH_BUNDLE) only dylibs (MH_DYLIB)";
602 case MH_EXECUTE:
603 if ( executableOrDyliborBundle )
604 return true;
605 else
606 throw "can't link with a main executable";
607 default:
608 return false;
609 }
610 }
611
612 template <>
613 bool Parser<x86_64>::validFile(const uint8_t* fileContent, bool executableOrDyliborBundle, bool subTypeMustMatch, uint32_t subType)
614 {
615 const auto* header = reinterpret_cast<const macho_header<P>*>(fileContent);
616 if ( header->magic() != MH_MAGIC_64 )
617 return false;
618 if ( header->cputype() != CPU_TYPE_X86_64 )
619 return false;
620 switch ( header->filetype() ) {
621 case MH_DYLIB:
622 case MH_DYLIB_STUB:
623 return true;
624 case MH_BUNDLE:
625 if ( executableOrDyliborBundle )
626 return true;
627 else
628 throw "can't link with bundle (MH_BUNDLE) only dylibs (MH_DYLIB)";
629 case MH_EXECUTE:
630 if ( executableOrDyliborBundle )
631 return true;
632 else
633 throw "can't link with a main executable";
634 default:
635 return false;
636 }
637 }
638
639 template <>
640 bool Parser<arm>::validFile(const uint8_t* fileContent, bool executableOrDyliborBundle, bool subTypeMustMatch, uint32_t subType)
641 {
642 const auto* header = reinterpret_cast<const macho_header<P>*>(fileContent);
643 if ( header->magic() != MH_MAGIC )
644 return false;
645 if ( header->cputype() != CPU_TYPE_ARM )
646 return false;
647 if ( subTypeMustMatch && (header->cpusubtype() != subType) )
648 return false;
649 switch ( header->filetype() ) {
650 case MH_DYLIB:
651 case MH_DYLIB_STUB:
652 return true;
653 case MH_BUNDLE:
654 if ( executableOrDyliborBundle )
655 return true;
656 else
657 throw "can't link with bundle (MH_BUNDLE) only dylibs (MH_DYLIB)";
658 case MH_EXECUTE:
659 if ( executableOrDyliborBundle )
660 return true;
661 else
662 throw "can't link with a main executable";
663 default:
664 return false;
665 }
666 }
667
668
669
670 template <>
671 bool Parser<arm64>::validFile(const uint8_t* fileContent, bool executableOrDyliborBundle, bool subTypeMustMatch, uint32_t subType)
672 {
673 const auto* header = reinterpret_cast<const macho_header<P>*>(fileContent);
674 if ( header->magic() != MH_MAGIC_64 )
675 return false;
676 if ( header->cputype() != CPU_TYPE_ARM64 )
677 return false;
678 switch ( header->filetype() ) {
679 case MH_DYLIB:
680 case MH_DYLIB_STUB:
681 return true;
682 case MH_BUNDLE:
683 if ( executableOrDyliborBundle )
684 return true;
685 else
686 throw "can't link with bundle (MH_BUNDLE) only dylibs (MH_DYLIB)";
687 case MH_EXECUTE:
688 if ( executableOrDyliborBundle )
689 return true;
690 else
691 throw "can't link with a main executable";
692 default:
693 return false;
694 }
695 }
696
697
698 bool isDylibFile(const uint8_t* fileContent, cpu_type_t* result, cpu_subtype_t* subResult)
699 {
700 if ( Parser<x86_64>::validFile(fileContent, false) ) {
701 *result = CPU_TYPE_X86_64;
702 const auto* header = reinterpret_cast<const macho_header<Pointer64<LittleEndian>>*>(fileContent);
703 *subResult = header->cpusubtype();
704 return true;
705 }
706 if ( Parser<x86>::validFile(fileContent, false) ) {
707 *result = CPU_TYPE_I386;
708 *subResult = CPU_SUBTYPE_X86_ALL;
709 return true;
710 }
711 if ( Parser<arm>::validFile(fileContent, false) ) {
712 *result = CPU_TYPE_ARM;
713 const auto* header = reinterpret_cast<const macho_header<Pointer32<LittleEndian>>*>(fileContent);
714 *subResult = header->cpusubtype();
715 return true;
716 }
717 if ( Parser<arm64>::validFile(fileContent, false) ) {
718 *result = CPU_TYPE_ARM64;
719 const auto* header = reinterpret_cast<const macho_header<Pointer32<LittleEndian>>*>(fileContent);
720 *subResult = header->cpusubtype();
721 return true;
722 }
723 return false;
724 }
725
726 template <>
727 const char* Parser<x86>::fileKind(const uint8_t* fileContent)
728 {
729 const auto* header = reinterpret_cast<const macho_header<P>*>(fileContent);
730 if ( header->magic() != MH_MAGIC )
731 return nullptr;
732 if ( header->cputype() != CPU_TYPE_I386 )
733 return nullptr;
734 return "i386";
735 }
736
737 template <>
738 const char* Parser<x86_64>::fileKind(const uint8_t* fileContent)
739 {
740 const auto* header = reinterpret_cast<const macho_header<P>*>(fileContent);
741 if ( header->magic() != MH_MAGIC_64 )
742 return nullptr;
743 if ( header->cputype() != CPU_TYPE_X86_64 )
744 return nullptr;
745 return "x86_64";
746 }
747
748 template <>
749 const char* Parser<arm>::fileKind(const uint8_t* fileContent)
750 {
751 const auto* header = reinterpret_cast<const macho_header<P>*>(fileContent);
752 if ( header->magic() != MH_MAGIC )
753 return nullptr;
754 if ( header->cputype() != CPU_TYPE_ARM )
755 return nullptr;
756 for (const auto* t = archInfoArray; t->archName != nullptr; ++t) {
757 if ( (t->cpuType == CPU_TYPE_ARM) && ((cpu_subtype_t)header->cpusubtype() == t->cpuSubType) ) {
758 return t->archName;
759 }
760 }
761 return "arm???";
762 }
763
764 #if SUPPORT_ARCH_arm64
765 template <>
766 const char* Parser<arm64>::fileKind(const uint8_t* fileContent)
767 {
768 const auto* header = reinterpret_cast<const macho_header<P>*>(fileContent);
769 if ( header->magic() != MH_MAGIC_64 )
770 return nullptr;
771 if ( header->cputype() != CPU_TYPE_ARM64 )
772 return nullptr;
773 return "arm64";
774 }
775 #endif
776
777
778 //
779 // used by linker is error messages to describe mismatched files
780 //
781 const char* archName(const uint8_t* fileContent)
782 {
783 if ( Parser<x86_64>::validFile(fileContent, true) ) {
784 return Parser<x86_64>::fileKind(fileContent);
785 }
786 if ( Parser<x86>::validFile(fileContent, true) ) {
787 return Parser<x86>::fileKind(fileContent);
788 }
789 if ( Parser<arm>::validFile(fileContent, true) ) {
790 return Parser<arm>::fileKind(fileContent);
791 }
792 #if SUPPORT_ARCH_arm64
793 if ( Parser<arm64>::validFile(fileContent, true) ) {
794 return Parser<arm64>::fileKind(fileContent);
795 }
796 #endif
797 return nullptr;
798 }
799
800
801 static ld::dylib::File* parseAsArchitecture(const uint8_t* fileContent, uint64_t fileLength, const char* path,
802 time_t modTime, const Options& opts, ld::File::Ordinal ordinal,
803 bool bundleLoader, bool indirectDylib,
804 cpu_type_t architecture, cpu_subtype_t subArchitecture)
805 {
806 bool subTypeMustMatch = opts.enforceDylibSubtypesMatch();
807 switch ( architecture) {
808 #if SUPPORT_ARCH_x86_64
809 case CPU_TYPE_X86_64:
810 if ( Parser<x86_64>::validFile(fileContent, bundleLoader, subTypeMustMatch, subArchitecture) )
811 return Parser<x86_64>::parse(fileContent, fileLength, path, modTime, ordinal, opts, indirectDylib);
812 break;
813 #endif
814 #if SUPPORT_ARCH_i386
815 case CPU_TYPE_I386:
816 if ( Parser<x86>::validFile(fileContent, bundleLoader, subTypeMustMatch, subArchitecture) )
817 return Parser<x86>::parse(fileContent, fileLength, path, modTime, ordinal, opts, indirectDylib);
818 break;
819 #endif
820 #if SUPPORT_ARCH_arm_any
821 case CPU_TYPE_ARM:
822 if ( Parser<arm>::validFile(fileContent, bundleLoader, subTypeMustMatch, subArchitecture) )
823 return Parser<arm>::parse(fileContent, fileLength, path, modTime, ordinal, opts, indirectDylib);
824 break;
825 #endif
826 #if SUPPORT_ARCH_arm64
827 case CPU_TYPE_ARM64:
828 if ( Parser<arm64>::validFile(fileContent, bundleLoader, subTypeMustMatch, subArchitecture) )
829 return Parser<arm64>::parse(fileContent, fileLength, path, modTime, ordinal, opts, indirectDylib);
830 break;
831 #endif
832 }
833 return nullptr;
834 }
835
836 //
837 // main function used by linker to instantiate ld::Files
838 //
839 ld::dylib::File* parse(const uint8_t* fileContent, uint64_t fileLength, const char* path,
840 time_t modtime, const Options& opts, ld::File::Ordinal ordinal,
841 bool bundleLoader, bool indirectDylib)
842 {
843 // First make sure we are even a dylib with a known arch. If we aren't then there's no point in continuing.
844 if (!archName(fileContent))
845 return nullptr;
846
847 auto file = parseAsArchitecture(fileContent, fileLength, path, modtime, opts, ordinal, bundleLoader, indirectDylib, opts.architecture(), opts.subArchitecture());
848
849 // If we've been provided with an architecture we can fall back to, try to parse the dylib as that instead.
850 if (!file && opts.fallbackArchitecture()) {
851 warning("architecture %s not present in dylib file %s, attempting fallback", opts.architectureName(), path);
852 file = parseAsArchitecture(fileContent, fileLength, path, modtime, opts, ordinal, bundleLoader, indirectDylib, opts.fallbackArchitecture(), opts.fallbackSubArchitecture());
853 }
854
855 return file;
856 }
857
858
859
860 }; // namespace dylib
861 }; // namespace mach_o