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