]>
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> |
d425e388 A |
37 | #include <unordered_map> |
38 | #include <unordered_set> | |
a645023d A |
39 | |
40 | #include "Architectures.hpp" | |
eaf282aa | 41 | #include "Bitcode.hpp" |
a645023d A |
42 | #include "MachOFileAbstraction.hpp" |
43 | #include "MachOTrie.hpp" | |
44 | #include "macho_dylib_file.h" | |
ebf6f434 | 45 | #include "../code-sign-blobs/superblob.h" |
a645023d A |
46 | |
47 | namespace mach_o { | |
48 | namespace dylib { | |
49 | ||
50 | ||
51 | // forward reference | |
52 | template <typename A> class File; | |
53 | ||
54 | ||
55 | // | |
56 | // An ExportAtom has no content. It exists so that the linker can track which imported | |
57 | // symbols came from which dynamic libraries. | |
58 | // | |
59 | template <typename A> | |
60 | class ExportAtom : public ld::Atom | |
61 | { | |
62 | public: | |
63 | ExportAtom(const File<A>& f, const char* nm, bool weakDef, | |
64 | bool tlv, typename A::P::uint_t address) | |
65 | : ld::Atom(f._importProxySection, ld::Atom::definitionProxy, | |
66 | (weakDef? ld::Atom::combineByName : ld::Atom::combineNever), | |
67 | ld::Atom::scopeLinkageUnit, | |
68 | (tlv ? ld::Atom::typeTLV : ld::Atom::typeUnclassified), | |
69 | symbolTableNotIn, false, false, false, ld::Atom::Alignment(0)), | |
70 | _file(f), _name(nm), _address(address) {} | |
71 | // overrides of ld::Atom | |
72 | virtual const ld::File* file() const { return &_file; } | |
a645023d A |
73 | virtual const char* name() const { return _name; } |
74 | virtual uint64_t size() const { return 0; } | |
75 | virtual uint64_t objectAddress() const { return _address; } | |
76 | virtual void copyRawContent(uint8_t buffer[]) const { } | |
77 | virtual void setScope(Scope) { } | |
78 | ||
79 | protected: | |
80 | typedef typename A::P P; | |
81 | typedef typename A::P::uint_t pint_t; | |
82 | ||
83 | virtual ~ExportAtom() {} | |
84 | ||
85 | const File<A>& _file; | |
86 | const char* _name; | |
87 | pint_t _address; | |
88 | }; | |
89 | ||
90 | ||
91 | ||
92 | // | |
93 | // An ImportAtom has no content. It exists so that when linking a main executable flat-namespace | |
94 | // the imports of all flat dylibs are checked | |
95 | // | |
96 | template <typename A> | |
97 | class ImportAtom : public ld::Atom | |
98 | { | |
99 | public: | |
100 | ImportAtom(File<A>& f, std::vector<const char*>& imports); | |
101 | ||
102 | // overrides of ld::Atom | |
103 | virtual ld::File* file() const { return &_file; } | |
a645023d A |
104 | virtual const char* name() const { return "import-atom"; } |
105 | virtual uint64_t size() const { return 0; } | |
106 | virtual uint64_t objectAddress() const { return 0; } | |
107 | virtual void copyRawContent(uint8_t buffer[]) const { } | |
108 | virtual void setScope(Scope) { } | |
109 | virtual ld::Fixup::iterator fixupsBegin() const { return &_undefs[0]; } | |
110 | virtual ld::Fixup::iterator fixupsEnd() const { return &_undefs[_undefs.size()]; } | |
111 | ||
112 | protected: | |
113 | typedef typename A::P P; | |
114 | ||
115 | virtual ~ImportAtom() {} | |
116 | ||
117 | ||
118 | File<A>& _file; | |
119 | mutable std::vector<ld::Fixup> _undefs; | |
120 | }; | |
121 | ||
122 | template <typename A> | |
123 | ImportAtom<A>::ImportAtom(File<A>& f, std::vector<const char*>& imports) | |
124 | : ld::Atom(f._flatDummySection, ld::Atom::definitionRegular, ld::Atom::combineNever, ld::Atom::scopeTranslationUnit, | |
125 | ld::Atom::typeUnclassified, symbolTableNotIn, false, false, false, ld::Atom::Alignment(0)), _file(f) | |
126 | { | |
127 | for(std::vector<const char*>::iterator it=imports.begin(); it != imports.end(); ++it) { | |
128 | _undefs.push_back(ld::Fixup(0, ld::Fixup::k1of1, ld::Fixup::kindNone, false, strdup(*it))); | |
129 | } | |
130 | } | |
131 | ||
132 | ||
133 | ||
134 | // | |
135 | // The reader for a dylib extracts all exported symbols names from the memory-mapped | |
136 | // dylib, builds a hash table, then unmaps the file. This is an important memory | |
137 | // savings for large dylibs. | |
138 | // | |
139 | template <typename A> | |
140 | class File : public ld::dylib::File | |
141 | { | |
142 | public: | |
143 | static bool validFile(const uint8_t* fileContent, bool executableOrDylib); | |
144 | File(const uint8_t* fileContent, uint64_t fileLength, const char* path, | |
ebf6f434 | 145 | time_t mTime, ld::File::Ordinal ordinal, bool linkingFlatNamespace, |
a645023d | 146 | bool linkingMainExecutable, bool hoistImplicitPublicDylibs, |
eaf282aa A |
147 | Options::Platform platform, uint32_t linkMinOSVersion, bool allowSimToMacOSX, |
148 | bool addVers, bool buildingForSimulator, | |
149 | bool logAllFiles, const char* installPath, | |
dd9e569f | 150 | bool indirectDylib, bool ignoreMismatchPlatform, bool usingBitcode); |
a645023d A |
151 | virtual ~File() {} |
152 | ||
153 | // overrides of ld::File | |
154 | virtual bool forEachAtom(ld::File::AtomHandler&) const; | |
155 | virtual bool justInTimeforEachAtom(const char* name, ld::File::AtomHandler&) const; | |
156 | virtual ld::File::ObjcConstraint objCConstraint() const { return _objcContraint; } | |
599556ff | 157 | virtual uint8_t swiftVersion() const { return _swiftVersion; } |
eaf282aa A |
158 | virtual uint32_t minOSVersion() const { return _minVersionInDylib; } |
159 | virtual uint32_t platformLoadCommand() const { return _platformInDylib; } | |
160 | ||
a645023d A |
161 | // overrides of ld::dylib::File |
162 | virtual void processIndirectLibraries(ld::dylib::File::DylibHandler*, bool); | |
163 | virtual bool providedExportAtom() const { return _providedAtom; } | |
164 | virtual const char* parentUmbrella() const { return _parentUmbrella; } | |
165 | virtual const std::vector<const char*>* allowableClients() const { return _allowableClients.size() != 0 ? &_allowableClients : NULL; } | |
166 | virtual bool hasWeakExternals() const { return _hasWeakExports; } | |
167 | virtual bool deadStrippable() const { return _deadStrippable; } | |
168 | virtual bool hasPublicInstallName() const{ return _hasPublicInstallName; } | |
169 | virtual bool hasWeakDefinition(const char* name) const; | |
afe874b1 | 170 | virtual bool allSymbolsAreWeakImported() const; |
f80fe69f | 171 | virtual bool installPathVersionSpecific() const { return _installPathOverride; } |
599556ff | 172 | virtual bool appExtensionSafe() const { return _appExtensionSafe; }; |
eaf282aa | 173 | virtual ld::Bitcode* getBitcode() const { return _bitcode.get(); } |
a645023d A |
174 | |
175 | protected: | |
eaf282aa | 176 | virtual void assertNoReExportCycles(ReExportChain*) const; |
a645023d A |
177 | |
178 | private: | |
179 | typedef typename A::P P; | |
180 | typedef typename A::P::E E; | |
181 | typedef typename A::P::uint_t pint_t; | |
182 | ||
183 | friend class ExportAtom<A>; | |
184 | friend class ImportAtom<A>; | |
185 | ||
d425e388 A |
186 | struct CStringHash { |
187 | std::size_t operator()(const char* __s) const { | |
188 | unsigned long __h = 0; | |
189 | for ( ; *__s; ++__s) | |
190 | __h = 5 * __h + *__s; | |
191 | return size_t(__h); | |
192 | }; | |
a645023d | 193 | }; |
eaf282aa | 194 | struct AtomAndWeak { ld::Atom* atom; bool weakDef; bool tlv; uint64_t address; }; |
d425e388 A |
195 | typedef std::unordered_map<const char*, AtomAndWeak, ld::CStringHash, ld::CStringEquals> NameToAtomMap; |
196 | typedef std::unordered_set<const char*, CStringHash, ld::CStringEquals> NameSet; | |
a645023d A |
197 | |
198 | struct Dependent { const char* path; File<A>* dylib; bool reExport; }; | |
199 | ||
eaf282aa A |
200 | virtual std::pair<bool, bool> hasWeakDefinitionImpl(const char* name) const; |
201 | virtual bool containsOrReExports(const char* name, bool& weakDef, bool& tlv, uint64_t& defAddress) const; | |
a645023d | 202 | bool isPublicLocation(const char* pth); |
f80fe69f | 203 | bool wrongOS() { return _wrongOS; } |
a645023d A |
204 | void addSymbol(const char* name, bool weak, bool tlv, pint_t address); |
205 | void addDyldFastStub(); | |
206 | void buildExportHashTableFromExportInfo(const macho_dyld_info_command<P>* dyldInfo, | |
207 | const uint8_t* fileContent); | |
208 | void buildExportHashTableFromSymbolTable(const macho_dysymtab_command<P>* dynamicInfo, | |
209 | const macho_nlist<P>* symbolTable, const char* strings, | |
210 | const uint8_t* fileContent); | |
9543cb2f | 211 | static uint32_t parseVersionNumber32(const char* versionString); |
a645023d A |
212 | static const char* objCInfoSegmentName(); |
213 | static const char* objCInfoSectionName(); | |
eaf282aa A |
214 | |
215 | const Options::Platform _platform; | |
216 | const uint32_t _linkMinOSVersion; | |
f80fe69f | 217 | const bool _allowSimToMacOSXLinking; |
afe874b1 | 218 | const bool _addVersionLoadCommand; |
a645023d A |
219 | bool _linkingFlat; |
220 | bool _implicitlyLinkPublicDylibs; | |
221 | ld::File::ObjcConstraint _objcContraint; | |
599556ff | 222 | uint8_t _swiftVersion; |
a645023d A |
223 | ld::Section _importProxySection; |
224 | ld::Section _flatDummySection; | |
225 | std::vector<Dependent> _dependentDylibs; | |
226 | std::vector<const char*> _allowableClients; | |
227 | mutable NameToAtomMap _atoms; | |
228 | NameSet _ignoreExports; | |
229 | const char* _parentUmbrella; | |
230 | ImportAtom<A>* _importAtom; | |
231 | bool _noRexports; | |
232 | bool _hasWeakExports; | |
233 | bool _deadStrippable; | |
234 | bool _hasPublicInstallName; | |
235 | mutable bool _providedAtom; | |
236 | bool _explictReExportFound; | |
f80fe69f A |
237 | bool _wrongOS; |
238 | bool _installPathOverride; | |
9543cb2f | 239 | bool _indirectDylibsProcessed; |
599556ff | 240 | bool _appExtensionSafe; |
dd9e569f | 241 | bool _usingBitcode; |
eaf282aa A |
242 | uint32_t _minVersionInDylib; |
243 | uint32_t _platformInDylib; | |
244 | std::unique_ptr<ld::Bitcode> _bitcode; | |
f80fe69f | 245 | |
a645023d A |
246 | static bool _s_logHashtable; |
247 | }; | |
248 | ||
249 | template <typename A> | |
250 | bool File<A>::_s_logHashtable = false; | |
251 | ||
252 | template <> const char* File<x86_64>::objCInfoSegmentName() { return "__DATA"; } | |
253 | template <> const char* File<arm>::objCInfoSegmentName() { return "__DATA"; } | |
254 | template <typename A> const char* File<A>::objCInfoSegmentName() { return "__OBJC"; } | |
255 | ||
256 | template <> const char* File<x86_64>::objCInfoSectionName() { return "__objc_imageinfo"; } | |
257 | template <> const char* File<arm>::objCInfoSectionName() { return "__objc_imageinfo"; } | |
258 | template <typename A> const char* File<A>::objCInfoSectionName() { return "__image_info"; } | |
259 | ||
260 | template <typename A> | |
ebf6f434 | 261 | File<A>::File(const uint8_t* fileContent, uint64_t fileLength, const char* pth, time_t mTime, ld::File::Ordinal ord, |
a645023d | 262 | bool linkingFlatNamespace, bool linkingMainExecutable, bool hoistImplicitPublicDylibs, |
eaf282aa | 263 | Options::Platform platform, uint32_t linkMinOSVersion, bool allowSimToMacOSX, bool addVers, bool buildingForSimulator, |
dd9e569f | 264 | bool logAllFiles, const char* targetInstallPath, bool indirectDylib, bool ignoreMismatchPlatform, bool usingBitcode) |
a645023d | 265 | : ld::dylib::File(strdup(pth), mTime, ord), |
eaf282aa | 266 | _platform(platform), _linkMinOSVersion(linkMinOSVersion), _allowSimToMacOSXLinking(allowSimToMacOSX), _addVersionLoadCommand(addVers), |
a645023d | 267 | _linkingFlat(linkingFlatNamespace), _implicitlyLinkPublicDylibs(hoistImplicitPublicDylibs), |
599556ff | 268 | _objcContraint(ld::File::objcConstraintNone), _swiftVersion(0), |
a645023d A |
269 | _importProxySection("__TEXT", "__import", ld::Section::typeImportProxies, true), |
270 | _flatDummySection("__LINKEDIT", "__flat_dummy", ld::Section::typeLinkEdit, true), | |
eaf282aa | 271 | _parentUmbrella(NULL), _importAtom(NULL), |
ebf6f434 | 272 | _noRexports(false), _hasWeakExports(false), |
a645023d | 273 | _deadStrippable(false), _hasPublicInstallName(false), |
599556ff | 274 | _providedAtom(false), _explictReExportFound(false), _wrongOS(false), _installPathOverride(false), |
dd9e569f | 275 | _indirectDylibsProcessed(false), _appExtensionSafe(false), _usingBitcode(usingBitcode), |
eaf282aa | 276 | _minVersionInDylib(0), _platformInDylib(Options::kPlatformUnknown) |
a645023d A |
277 | { |
278 | const macho_header<P>* header = (const macho_header<P>*)fileContent; | |
279 | const uint32_t cmd_count = header->ncmds(); | |
280 | const macho_load_command<P>* const cmds = (macho_load_command<P>*)((char*)header + sizeof(macho_header<P>)); | |
281 | const macho_load_command<P>* const cmdsEnd = (macho_load_command<P>*)((char*)header + sizeof(macho_header<P>) + header->sizeofcmds()); | |
282 | ||
283 | // write out path for -t option | |
284 | if ( logAllFiles ) | |
285 | printf("%s\n", pth); | |
286 | ||
287 | // a "blank" stub has zero load commands | |
288 | if ( (header->filetype() == MH_DYLIB_STUB) && (cmd_count == 0) ) { | |
289 | // no further processing needed | |
290 | munmap((caddr_t)fileContent, fileLength); | |
291 | return; | |
292 | } | |
293 | ||
294 | ||
295 | // optimize the case where we know there is no reason to look at indirect dylibs | |
296 | _noRexports = (header->flags() & MH_NO_REEXPORTED_DYLIBS) | |
297 | || (header->filetype() == MH_BUNDLE) | |
298 | || (header->filetype() == MH_EXECUTE); // bundles and exectuables can be used via -bundle_loader | |
299 | _hasWeakExports = (header->flags() & MH_WEAK_DEFINES); | |
300 | _deadStrippable = (header->flags() & MH_DEAD_STRIPPABLE_DYLIB); | |
599556ff | 301 | _appExtensionSafe = (header->flags() & MH_APP_EXTENSION_SAFE); |
a645023d A |
302 | |
303 | // pass 1: get pointers, and see if this dylib uses compressed LINKEDIT format | |
304 | const macho_dysymtab_command<P>* dynamicInfo = NULL; | |
305 | const macho_dyld_info_command<P>* dyldInfo = NULL; | |
306 | const macho_nlist<P>* symbolTable = NULL; | |
307 | const char* strings = NULL; | |
308 | bool compressedLinkEdit = false; | |
309 | uint32_t dependentLibCount = 0; | |
eaf282aa | 310 | Options::Platform lcPlatform = Options::kPlatformUnknown; |
a645023d A |
311 | const macho_load_command<P>* cmd = cmds; |
312 | for (uint32_t i = 0; i < cmd_count; ++i) { | |
313 | macho_dylib_command<P>* dylibID; | |
314 | const macho_symtab_command<P>* symtab; | |
315 | switch (cmd->cmd()) { | |
316 | case LC_SYMTAB: | |
317 | symtab = (macho_symtab_command<P>*)cmd; | |
318 | symbolTable = (const macho_nlist<P>*)((char*)header + symtab->symoff()); | |
319 | strings = (char*)header + symtab->stroff(); | |
ebf6f434 A |
320 | if ( (symtab->stroff() + symtab->strsize()) > fileLength ) |
321 | throwf("mach-o string pool extends beyond end of file in %s", pth); | |
a645023d A |
322 | break; |
323 | case LC_DYSYMTAB: | |
324 | dynamicInfo = (macho_dysymtab_command<P>*)cmd; | |
325 | break; | |
326 | case LC_DYLD_INFO: | |
327 | case LC_DYLD_INFO_ONLY: | |
328 | dyldInfo = (macho_dyld_info_command<P>*)cmd; | |
329 | compressedLinkEdit = true; | |
330 | break; | |
331 | case LC_ID_DYLIB: | |
332 | dylibID = (macho_dylib_command<P>*)cmd; | |
333 | _dylibInstallPath = strdup(dylibID->name()); | |
334 | _dylibTimeStamp = dylibID->timestamp(); | |
335 | _dylibCurrentVersion = dylibID->current_version(); | |
336 | _dylibCompatibilityVersion = dylibID->compatibility_version(); | |
337 | _hasPublicInstallName = isPublicLocation(_dylibInstallPath); | |
338 | break; | |
339 | case LC_LOAD_DYLIB: | |
340 | case LC_LOAD_WEAK_DYLIB: | |
341 | ++dependentLibCount; | |
342 | break; | |
343 | case LC_REEXPORT_DYLIB: | |
344 | _explictReExportFound = true; | |
345 | ++dependentLibCount; | |
346 | break; | |
347 | case LC_SUB_FRAMEWORK: | |
348 | _parentUmbrella = strdup(((macho_sub_framework_command<P>*)cmd)->umbrella()); | |
349 | break; | |
350 | case LC_SUB_CLIENT: | |
351 | _allowableClients.push_back(strdup(((macho_sub_client_command<P>*)cmd)->client())); | |
eaf282aa A |
352 | // <rdar://problem/20627554> Don't hoist "public" (in /usr/lib/) dylibs that should not be directly linked |
353 | _hasPublicInstallName = false; | |
a645023d | 354 | break; |
afe874b1 | 355 | case LC_VERSION_MIN_MACOSX: |
afe874b1 | 356 | case LC_VERSION_MIN_IPHONEOS: |
eaf282aa A |
357 | case LC_VERSION_MIN_WATCHOS: |
358 | #if SUPPORT_APPLE_TV | |
359 | case LC_VERSION_MIN_TVOS: | |
360 | #endif | |
361 | _minVersionInDylib = (ld::MacVersionMin)((macho_version_min_command<P>*)cmd)->version(); | |
362 | _platformInDylib = cmd->cmd(); | |
363 | lcPlatform = Options::platformForLoadCommand(_platformInDylib); | |
afe874b1 | 364 | break; |
ebf6f434 | 365 | case LC_CODE_SIGNATURE: |
ebf6f434 | 366 | break; |
a645023d A |
367 | case macho_segment_command<P>::CMD: |
368 | // check for Objective-C info | |
eaf282aa | 369 | if ( strncmp(((macho_segment_command<P>*)cmd)->segname(), objCInfoSegmentName(), 6) == 0 ) { |
a645023d A |
370 | const macho_segment_command<P>* segment = (macho_segment_command<P>*)cmd; |
371 | const macho_section<P>* const sectionsStart = (macho_section<P>*)((char*)segment + sizeof(macho_segment_command<P>)); | |
372 | const macho_section<P>* const sectionsEnd = §ionsStart[segment->nsects()]; | |
373 | for (const macho_section<P>* sect=sectionsStart; sect < sectionsEnd; ++sect) { | |
374 | if ( strncmp(sect->sectname(), objCInfoSectionName(), strlen(objCInfoSectionName())) == 0 ) { | |
375 | // struct objc_image_info { | |
376 | // uint32_t version; // initially 0 | |
377 | // uint32_t flags; | |
378 | // }; | |
379 | // #define OBJC_IMAGE_SUPPORTS_GC 2 | |
380 | // #define OBJC_IMAGE_GC_ONLY 4 | |
f80fe69f | 381 | // #define OBJC_IMAGE_IS_SIMULATED 32 |
a645023d A |
382 | // |
383 | const uint32_t* contents = (uint32_t*)(&fileContent[sect->offset()]); | |
384 | if ( (sect->size() >= 8) && (contents[0] == 0) ) { | |
385 | uint32_t flags = E::get32(contents[1]); | |
386 | if ( (flags & 4) == 4 ) | |
387 | _objcContraint = ld::File::objcConstraintGC; | |
388 | else if ( (flags & 2) == 2 ) | |
389 | _objcContraint = ld::File::objcConstraintRetainReleaseOrGC; | |
f80fe69f A |
390 | else if ( (flags & 32) == 32 ) |
391 | _objcContraint = ld::File::objcConstraintRetainReleaseForSimulator; | |
a645023d A |
392 | else |
393 | _objcContraint = ld::File::objcConstraintRetainRelease; | |
599556ff | 394 | _swiftVersion = ((flags >> 8) & 0xFF); |
a645023d A |
395 | } |
396 | else if ( sect->size() > 0 ) { | |
397 | warning("can't parse %s/%s section in %s", objCInfoSegmentName(), objCInfoSectionName(), this->path()); | |
398 | } | |
399 | } | |
400 | } | |
401 | } | |
eaf282aa A |
402 | // Construct bitcode if there is a bitcode bundle section in the dylib |
403 | // Record the size of the section because the content is not checked | |
404 | else if ( strcmp(((macho_segment_command<P>*)cmd)->segname(), "__LLVM") == 0 ) { | |
405 | const macho_section<P>* const sect = (macho_section<P>*)((char*)cmd + sizeof(macho_segment_command<P>)); | |
406 | if ( strncmp(sect->sectname(), "__bundle", 8) == 0 ) | |
407 | _bitcode = std::unique_ptr<ld::Bitcode>(new ld::Bitcode(NULL, sect->size())); | |
408 | } | |
a645023d A |
409 | } |
410 | cmd = (const macho_load_command<P>*)(((char*)cmd)+cmd->cmdsize()); | |
411 | if ( cmd > cmdsEnd ) | |
412 | throwf("malformed dylb, load command #%d is outside size of load commands in %s", i, pth); | |
413 | } | |
eaf282aa A |
414 | // arm/arm64 objects are default to ios platform if not set. |
415 | // rdar://problem/21746314 | |
416 | if (lcPlatform == Options::kPlatformUnknown && | |
417 | (std::is_same<A, arm>::value || std::is_same<A, arm64>::value)) | |
418 | lcPlatform = Options::kPlatformiOS; | |
419 | ||
420 | // check cross-linking | |
421 | if ( lcPlatform != platform ) { | |
422 | _wrongOS = true; | |
423 | if ( _addVersionLoadCommand && !indirectDylib && !ignoreMismatchPlatform ) { | |
424 | if ( buildingForSimulator ) { | |
425 | if ( !_allowSimToMacOSXLinking ) { | |
426 | switch (platform) { | |
427 | case Options::kPlatformOSX: | |
428 | case Options::kPlatformiOS: | |
429 | if ( lcPlatform == Options::kPlatformUnknown ) | |
430 | break; | |
431 | // fall through if the Platform is not Unknown | |
432 | case Options::kPlatformWatchOS: | |
433 | // WatchOS errors on cross-linking all the time. | |
434 | throwf("building for %s simulator, but linking against dylib built for %s,", | |
435 | Options::platformName(platform), | |
436 | Options::platformName(lcPlatform)); | |
437 | break; | |
438 | #if SUPPORT_APPLE_TV | |
439 | case Options::kPlatform_tvOS: | |
440 | // tvOS is a warning temporarily. rdar://problem/21746965 | |
dd9e569f A |
441 | if ( usingBitcode ) |
442 | throwf("building for %s simulator, but linking against dylib built for %s,", | |
443 | Options::platformName(platform), | |
444 | Options::platformName(lcPlatform)); | |
445 | else | |
eaf282aa A |
446 | warning("URGENT: building for %s simulator, but linking against dylib (%s) built for %s. " |
447 | "Note: This will be an error in the future.", | |
448 | Options::platformName(platform), path(), | |
449 | Options::platformName(lcPlatform)); | |
450 | break; | |
451 | #endif | |
452 | case Options::kPlatformUnknown: | |
453 | // skip if the target platform is unknown | |
454 | break; | |
455 | } | |
456 | } | |
457 | } | |
458 | else { | |
459 | switch (platform) { | |
460 | case Options::kPlatformOSX: | |
461 | case Options::kPlatformiOS: | |
462 | if ( lcPlatform == Options::kPlatformUnknown ) | |
463 | break; | |
464 | // fall through if the Platform is not Unknown | |
465 | case Options::kPlatformWatchOS: | |
466 | // WatchOS errors on cross-linking all the time. | |
467 | throwf("building for %s, but linking against dylib built for %s,", | |
468 | Options::platformName(platform), | |
469 | Options::platformName(lcPlatform)); | |
470 | break; | |
471 | #if SUPPORT_APPLE_TV | |
472 | case Options::kPlatform_tvOS: | |
473 | // tvOS is a warning temporarily. rdar://problem/21746965 | |
dd9e569f A |
474 | if ( _usingBitcode ) |
475 | throwf("building for %s, but linking against dylib built for %s,", | |
476 | Options::platformName(platform), | |
477 | Options::platformName(lcPlatform)); | |
478 | else | |
eaf282aa A |
479 | warning("URGENT: building for %s, but linking against dylib (%s) built for %s. " |
480 | "Note: This will be an error in the future.", | |
481 | Options::platformName(platform), path(), | |
482 | Options::platformName(lcPlatform)); | |
483 | break; | |
484 | #endif | |
485 | case Options::kPlatformUnknown: | |
486 | // skip if the target platform is unknown | |
487 | break; | |
488 | } | |
489 | } | |
490 | } | |
491 | } | |
a645023d A |
492 | |
493 | // figure out if we need to examine dependent dylibs | |
494 | // with compressed LINKEDIT format, MH_NO_REEXPORTED_DYLIBS can be trusted | |
495 | bool processDependentLibraries = true; | |
496 | if ( compressedLinkEdit && _noRexports && !linkingFlatNamespace) | |
497 | processDependentLibraries = false; | |
498 | ||
499 | if ( processDependentLibraries ) { | |
500 | // pass 2 builds list of all dependent libraries | |
501 | _dependentDylibs.reserve(dependentLibCount); | |
502 | cmd = cmds; | |
b1f7435d | 503 | unsigned int reExportDylibCount = 0; |
a645023d A |
504 | for (uint32_t i = 0; i < cmd_count; ++i) { |
505 | switch (cmd->cmd()) { | |
506 | case LC_LOAD_DYLIB: | |
507 | case LC_LOAD_WEAK_DYLIB: | |
508 | // with new linkedit format only care about LC_REEXPORT_DYLIB | |
509 | if ( compressedLinkEdit && !linkingFlatNamespace ) | |
510 | break; | |
511 | case LC_REEXPORT_DYLIB: | |
b1f7435d | 512 | ++reExportDylibCount; |
a645023d A |
513 | Dependent entry; |
514 | entry.path = strdup(((macho_dylib_command<P>*)cmd)->name()); | |
515 | entry.dylib = NULL; | |
516 | entry.reExport = (cmd->cmd() == LC_REEXPORT_DYLIB); | |
afe874b1 A |
517 | if ( (targetInstallPath == NULL) || (strcmp(targetInstallPath, entry.path) != 0) ) |
518 | _dependentDylibs.push_back(entry); | |
a645023d A |
519 | break; |
520 | } | |
521 | cmd = (const macho_load_command<P>*)(((char*)cmd)+cmd->cmdsize()); | |
522 | } | |
523 | // verify MH_NO_REEXPORTED_DYLIBS bit was correct | |
524 | if ( compressedLinkEdit && !linkingFlatNamespace ) { | |
eaf282aa A |
525 | if ( reExportDylibCount == 0 ) |
526 | throwf("malformed dylib has MH_NO_REEXPORTED_DYLIBS flag but no LC_REEXPORT_DYLIB load commands: %s", pth); | |
a645023d A |
527 | } |
528 | // pass 3 add re-export info | |
529 | cmd = cmds; | |
530 | for (uint32_t i = 0; i < cmd_count; ++i) { | |
531 | const char* frameworkLeafName; | |
532 | const char* dylibBaseName; | |
533 | switch (cmd->cmd()) { | |
534 | case LC_SUB_UMBRELLA: | |
535 | frameworkLeafName = ((macho_sub_umbrella_command<P>*)cmd)->sub_umbrella(); | |
536 | for (typename std::vector<Dependent>::iterator it = _dependentDylibs.begin(); it != _dependentDylibs.end(); ++it) { | |
537 | const char* dylibName = it->path; | |
538 | const char* lastSlash = strrchr(dylibName, '/'); | |
539 | if ( (lastSlash != NULL) && (strcmp(&lastSlash[1], frameworkLeafName) == 0) ) | |
540 | it->reExport = true; | |
541 | } | |
542 | break; | |
543 | case LC_SUB_LIBRARY: | |
544 | dylibBaseName = ((macho_sub_library_command<P>*)cmd)->sub_library(); | |
545 | for (typename std::vector<Dependent>::iterator it = _dependentDylibs.begin(); it != _dependentDylibs.end(); ++it) { | |
546 | const char* dylibName = it->path; | |
547 | const char* lastSlash = strrchr(dylibName, '/'); | |
548 | const char* leafStart = &lastSlash[1]; | |
549 | if ( lastSlash == NULL ) | |
550 | leafStart = dylibName; | |
551 | const char* firstDot = strchr(leafStart, '.'); | |
552 | int len = strlen(leafStart); | |
553 | if ( firstDot != NULL ) | |
554 | len = firstDot - leafStart; | |
555 | if ( strncmp(leafStart, dylibBaseName, len) == 0 ) | |
556 | it->reExport = true; | |
557 | } | |
558 | break; | |
559 | } | |
560 | cmd = (const macho_load_command<P>*)(((char*)cmd)+cmd->cmdsize()); | |
561 | } | |
562 | } | |
563 | ||
564 | // validate minimal load commands | |
565 | if ( (_dylibInstallPath == NULL) && ((header->filetype() == MH_DYLIB) || (header->filetype() == MH_DYLIB_STUB)) ) | |
566 | throwf("dylib %s missing LC_ID_DYLIB load command", pth); | |
567 | if ( dyldInfo == NULL ) { | |
568 | if ( symbolTable == NULL ) | |
569 | throw "binary missing LC_SYMTAB load command"; | |
570 | if ( dynamicInfo == NULL ) | |
571 | throw "binary missing LC_DYSYMTAB load command"; | |
572 | } | |
573 | ||
574 | // if linking flat and this is a flat dylib, create one atom that references all imported symbols | |
575 | if ( linkingFlatNamespace && linkingMainExecutable && ((header->flags() & MH_TWOLEVEL) == 0) ) { | |
576 | std::vector<const char*> importNames; | |
577 | importNames.reserve(dynamicInfo->nundefsym()); | |
578 | const macho_nlist<P>* start = &symbolTable[dynamicInfo->iundefsym()]; | |
579 | const macho_nlist<P>* end = &start[dynamicInfo->nundefsym()]; | |
580 | for (const macho_nlist<P>* sym=start; sym < end; ++sym) { | |
581 | importNames.push_back(&strings[sym->n_strx()]); | |
582 | } | |
583 | _importAtom = new ImportAtom<A>(*this, importNames); | |
584 | } | |
eaf282aa | 585 | |
a645023d A |
586 | // build hash table |
587 | if ( dyldInfo != NULL ) | |
588 | buildExportHashTableFromExportInfo(dyldInfo, fileContent); | |
589 | else | |
590 | buildExportHashTableFromSymbolTable(dynamicInfo, symbolTable, strings, fileContent); | |
591 | ||
592 | // unmap file | |
593 | munmap((caddr_t)fileContent, fileLength); | |
594 | } | |
595 | ||
eaf282aa | 596 | |
9543cb2f A |
597 | // |
598 | // Parses number of form X[.Y[.Z]] into a uint32_t where the nibbles are xxxx.yy.zz | |
599 | // | |
600 | template <typename A> | |
601 | uint32_t File<A>::parseVersionNumber32(const char* versionString) | |
602 | { | |
603 | uint32_t x = 0; | |
604 | uint32_t y = 0; | |
605 | uint32_t z = 0; | |
606 | char* end; | |
607 | x = strtoul(versionString, &end, 10); | |
608 | if ( *end == '.' ) { | |
609 | y = strtoul(&end[1], &end, 10); | |
610 | if ( *end == '.' ) { | |
611 | z = strtoul(&end[1], &end, 10); | |
612 | } | |
613 | } | |
614 | if ( (*end != '\0') || (x > 0xffff) || (y > 0xff) || (z > 0xff) ) | |
615 | throwf("malformed 32-bit x.y.z version number: %s", versionString); | |
616 | ||
617 | return (x << 16) | ( y << 8 ) | z; | |
618 | } | |
a645023d A |
619 | |
620 | template <typename A> | |
621 | void File<A>::buildExportHashTableFromSymbolTable(const macho_dysymtab_command<P>* dynamicInfo, | |
622 | const macho_nlist<P>* symbolTable, const char* strings, | |
623 | const uint8_t* fileContent) | |
624 | { | |
625 | if ( dynamicInfo->tocoff() == 0 ) { | |
626 | if ( _s_logHashtable ) fprintf(stderr, "ld: building hashtable of %u toc entries for %s\n", dynamicInfo->nextdefsym(), this->path()); | |
627 | const macho_nlist<P>* start = &symbolTable[dynamicInfo->iextdefsym()]; | |
628 | const macho_nlist<P>* end = &start[dynamicInfo->nextdefsym()]; | |
d425e388 | 629 | _atoms.reserve(dynamicInfo->nextdefsym()); // set initial bucket count |
a645023d A |
630 | for (const macho_nlist<P>* sym=start; sym < end; ++sym) { |
631 | this->addSymbol(&strings[sym->n_strx()], (sym->n_desc() & N_WEAK_DEF) != 0, false, sym->n_value()); | |
632 | } | |
633 | } | |
634 | else { | |
635 | int32_t count = dynamicInfo->ntoc(); | |
d425e388 | 636 | _atoms.reserve(count); // set initial bucket count |
a645023d A |
637 | if ( _s_logHashtable ) fprintf(stderr, "ld: building hashtable of %u entries for %s\n", count, this->path()); |
638 | const struct dylib_table_of_contents* toc = (dylib_table_of_contents*)(fileContent + dynamicInfo->tocoff()); | |
639 | for (int32_t i = 0; i < count; ++i) { | |
640 | const uint32_t index = E::get32(toc[i].symbol_index); | |
641 | const macho_nlist<P>* sym = &symbolTable[index]; | |
642 | this->addSymbol(&strings[sym->n_strx()], (sym->n_desc() & N_WEAK_DEF) != 0, false, sym->n_value()); | |
643 | } | |
644 | } | |
645 | ||
646 | // special case old libSystem | |
647 | if ( (_dylibInstallPath != NULL) && (strcmp(_dylibInstallPath, "/usr/lib/libSystem.B.dylib") == 0) ) | |
648 | addDyldFastStub(); | |
649 | } | |
650 | ||
651 | ||
652 | template <typename A> | |
653 | void File<A>::buildExportHashTableFromExportInfo(const macho_dyld_info_command<P>* dyldInfo, | |
654 | const uint8_t* fileContent) | |
655 | { | |
656 | if ( _s_logHashtable ) fprintf(stderr, "ld: building hashtable from export info in %s\n", this->path()); | |
657 | if ( dyldInfo->export_size() > 0 ) { | |
658 | const uint8_t* start = fileContent + dyldInfo->export_off(); | |
659 | const uint8_t* end = &start[dyldInfo->export_size()]; | |
660 | std::vector<mach_o::trie::Entry> list; | |
661 | parseTrie(start, end, list); | |
662 | for (std::vector<mach_o::trie::Entry>::iterator it=list.begin(); it != list.end(); ++it) | |
663 | this->addSymbol(it->name, | |
664 | it->flags & EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION, | |
665 | (it->flags & EXPORT_SYMBOL_FLAGS_KIND_MASK) == EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL, | |
666 | it->address); | |
667 | } | |
668 | } | |
669 | ||
670 | ||
671 | template <> | |
672 | void File<x86_64>::addDyldFastStub() | |
673 | { | |
674 | addSymbol("dyld_stub_binder", false, false, 0); | |
675 | } | |
676 | ||
677 | template <> | |
678 | void File<x86>::addDyldFastStub() | |
679 | { | |
680 | addSymbol("dyld_stub_binder", false, false, 0); | |
681 | } | |
682 | ||
683 | template <typename A> | |
684 | void File<A>::addDyldFastStub() | |
685 | { | |
686 | // do nothing | |
687 | } | |
688 | ||
689 | template <typename A> | |
690 | void File<A>::addSymbol(const char* name, bool weakDef, bool tlv, pint_t address) | |
691 | { | |
a645023d A |
692 | //fprintf(stderr, "addSymbol() %s\n", name); |
693 | // symbols that start with $ld$ are meta-data to the static linker | |
694 | // <rdar://problem/5182537> need way for ld and dyld to see different exported symbols in a dylib | |
695 | if ( strncmp(name, "$ld$", 4) == 0 ) { | |
696 | // $ld$ <action> $ <condition> $ <symbol-name> | |
697 | const char* symAction = &name[4]; | |
698 | const char* symCond = strchr(symAction, '$'); | |
699 | if ( symCond != NULL ) { | |
700 | char curOSVers[16]; | |
eaf282aa | 701 | sprintf(curOSVers, "$os%d.%d$", (_linkMinOSVersion >> 16), ((_linkMinOSVersion >> 8) & 0xFF)); |
a645023d A |
702 | if ( strncmp(symCond, curOSVers, strlen(curOSVers)) == 0 ) { |
703 | const char* symName = strchr(&symCond[1], '$'); | |
704 | if ( symName != NULL ) { | |
705 | ++symName; | |
706 | if ( strncmp(symAction, "hide$", 5) == 0 ) { | |
707 | if ( _s_logHashtable ) fprintf(stderr, " adding %s to ignore set for %s\n", symName, this->path()); | |
708 | _ignoreExports.insert(strdup(symName)); | |
709 | return; | |
710 | } | |
711 | else if ( strncmp(symAction, "add$", 4) == 0 ) { | |
712 | this->addSymbol(symName, weakDef, false, 0); | |
713 | return; | |
714 | } | |
ebf6f434 A |
715 | else if ( strncmp(symAction, "install_name$", 13) == 0 ) { |
716 | _dylibInstallPath = symName; | |
f80fe69f | 717 | _installPathOverride = true; |
9543cb2f A |
718 | // <rdar://problem/14448206> CoreGraphics redirects to ApplicationServices, but with wrong compat version |
719 | if ( strcmp(_dylibInstallPath, "/System/Library/Frameworks/ApplicationServices.framework/Versions/A/ApplicationServices") == 0 ) | |
720 | _dylibCompatibilityVersion = parseVersionNumber32("1.0"); | |
721 | return; | |
722 | } | |
723 | else if ( strncmp(symAction, "compatibility_version$", 22) == 0 ) { | |
724 | _dylibCompatibilityVersion = parseVersionNumber32(symName); | |
ebf6f434 A |
725 | return; |
726 | } | |
a645023d A |
727 | else { |
728 | warning("bad symbol action: %s in dylib %s", name, this->path()); | |
729 | } | |
730 | } | |
731 | } | |
732 | } | |
733 | else { | |
734 | warning("bad symbol condition: %s in dylib %s", name, this->path()); | |
735 | } | |
736 | } | |
737 | ||
738 | // add symbol as possible export if we are not supposed to ignore it | |
739 | if ( _ignoreExports.count(name) == 0 ) { | |
740 | AtomAndWeak bucket; | |
741 | bucket.atom = NULL; | |
afe874b1 | 742 | bucket.weakDef = weakDef; |
a645023d A |
743 | bucket.tlv = tlv; |
744 | bucket.address = address; | |
745 | if ( _s_logHashtable ) fprintf(stderr, " adding %s to hash table for %s\n", name, this->path()); | |
746 | _atoms[strdup(name)] = bucket; | |
747 | } | |
748 | } | |
749 | ||
750 | ||
751 | template <typename A> | |
752 | bool File<A>::forEachAtom(ld::File::AtomHandler& handler) const | |
753 | { | |
754 | handler.doFile(*this); | |
755 | // if doing flatnamespace and need all this dylib's imports resolve | |
756 | // add atom which references alls undefines in this dylib | |
757 | if ( _importAtom != NULL ) { | |
758 | handler.doAtom(*_importAtom); | |
759 | return true; | |
760 | } | |
761 | return false; | |
762 | } | |
763 | ||
eaf282aa A |
764 | |
765 | template <typename A> | |
766 | std::pair<bool, bool> File<A>::hasWeakDefinitionImpl(const char* name) const | |
767 | { | |
768 | const auto pos = _atoms.find(name); | |
769 | if ( pos != _atoms.end() ) | |
770 | return std::make_pair(true, pos->second.weakDef); | |
771 | ||
772 | // look in children that I re-export | |
773 | for (const auto &dep : _dependentDylibs) { | |
774 | if ( dep.reExport ) { | |
775 | auto ret = dep.dylib->hasWeakDefinitionImpl(name); | |
776 | if ( ret.first ) | |
777 | return ret; | |
778 | } | |
779 | } | |
780 | return std::make_pair(false, false); | |
781 | } | |
782 | ||
783 | ||
a645023d A |
784 | template <typename A> |
785 | bool File<A>::hasWeakDefinition(const char* name) const | |
786 | { | |
787 | // if supposed to ignore this export, then pretend I don't have it | |
788 | if ( _ignoreExports.count(name) != 0 ) | |
789 | return false; | |
eaf282aa A |
790 | |
791 | return hasWeakDefinitionImpl(name).second; | |
a645023d A |
792 | } |
793 | ||
afe874b1 A |
794 | |
795 | // <rdar://problem/5529626> If only weak_import symbols are used, linker should use LD_LOAD_WEAK_DYLIB | |
796 | template <typename A> | |
797 | bool File<A>::allSymbolsAreWeakImported() const | |
798 | { | |
799 | bool foundNonWeakImport = false; | |
800 | bool foundWeakImport = false; | |
801 | //fprintf(stderr, "%s:\n", this->path()); | |
802 | for (typename NameToAtomMap::const_iterator it = _atoms.begin(); it != _atoms.end(); ++it) { | |
803 | const ld::Atom* atom = it->second.atom; | |
804 | if ( atom != NULL ) { | |
805 | if ( atom->weakImported() ) | |
806 | foundWeakImport = true; | |
807 | else | |
808 | foundNonWeakImport = true; | |
809 | //fprintf(stderr, " weak_import=%d, name=%s\n", atom->weakImported(), it->first); | |
810 | } | |
811 | } | |
812 | ||
813 | // don't automatically weak link dylib with no imports | |
814 | // so at least one weak import symbol and no non-weak-imported symbols must be found | |
815 | return foundWeakImport && !foundNonWeakImport; | |
816 | } | |
817 | ||
818 | ||
a645023d | 819 | template <typename A> |
eaf282aa | 820 | bool File<A>::containsOrReExports(const char* name, bool& weakDef, bool& tlv, uint64_t& defAddress) const |
a645023d | 821 | { |
afe874b1 A |
822 | if ( _ignoreExports.count(name) != 0 ) |
823 | return false; | |
824 | ||
d425e388 | 825 | // check myself |
eaf282aa | 826 | const auto pos = _atoms.find(name); |
a645023d | 827 | if ( pos != _atoms.end() ) { |
eaf282aa A |
828 | weakDef = pos->second.weakDef; |
829 | tlv = pos->second.tlv; | |
830 | defAddress = pos->second.address; | |
a645023d A |
831 | return true; |
832 | } | |
833 | ||
834 | // check dylibs I re-export | |
eaf282aa A |
835 | for (const auto &dep : _dependentDylibs) { |
836 | if ( dep.reExport && !dep.dylib->implicitlyLinked() ) { | |
837 | if ( dep.dylib->containsOrReExports(name, weakDef, tlv, defAddress) ) | |
a645023d A |
838 | return true; |
839 | } | |
840 | } | |
841 | ||
842 | return false; | |
843 | } | |
844 | ||
845 | ||
846 | template <typename A> | |
847 | bool File<A>::justInTimeforEachAtom(const char* name, ld::File::AtomHandler& handler) const | |
848 | { | |
849 | // if supposed to ignore this export, then pretend I don't have it | |
850 | if ( _ignoreExports.count(name) != 0 ) | |
851 | return false; | |
852 | ||
853 | ||
854 | AtomAndWeak bucket; | |
eaf282aa | 855 | if ( this->containsOrReExports(name, bucket.weakDef, bucket.tlv, bucket.address) ) { |
afe874b1 | 856 | bucket.atom = new ExportAtom<A>(*this, name, bucket.weakDef, bucket.tlv, bucket.address); |
a645023d A |
857 | _atoms[name] = bucket; |
858 | _providedAtom = true; | |
859 | if ( _s_logHashtable ) fprintf(stderr, "getJustInTimeAtomsFor: %s found in %s\n", name, this->path()); | |
860 | // call handler with new export atom | |
861 | handler.doAtom(*bucket.atom); | |
862 | return true; | |
863 | } | |
864 | ||
865 | return false; | |
866 | } | |
867 | ||
868 | ||
869 | ||
870 | template <typename A> | |
871 | bool File<A>::isPublicLocation(const char* pth) | |
872 | { | |
873 | // -no_implicit_dylibs disables this optimization | |
874 | if ( ! _implicitlyLinkPublicDylibs ) | |
875 | return false; | |
876 | ||
877 | // /usr/lib is a public location | |
878 | if ( (strncmp(pth, "/usr/lib/", 9) == 0) && (strchr(&pth[9], '/') == NULL) ) | |
879 | return true; | |
880 | ||
881 | // /System/Library/Frameworks/ is a public location | |
882 | if ( strncmp(pth, "/System/Library/Frameworks/", 27) == 0 ) { | |
883 | const char* frameworkDot = strchr(&pth[27], '.'); | |
884 | // but only top level framework | |
885 | // /System/Library/Frameworks/Foo.framework/Versions/A/Foo ==> true | |
886 | // /System/Library/Frameworks/Foo.framework/Resources/libBar.dylib ==> false | |
887 | // /System/Library/Frameworks/Foo.framework/Frameworks/Bar.framework/Bar ==> false | |
888 | // /System/Library/Frameworks/Foo.framework/Frameworks/Xfoo.framework/XFoo ==> false | |
889 | if ( frameworkDot != NULL ) { | |
890 | int frameworkNameLen = frameworkDot - &pth[27]; | |
891 | if ( strncmp(&pth[strlen(pth)-frameworkNameLen-1], &pth[26], frameworkNameLen+1) == 0 ) | |
892 | return true; | |
893 | } | |
894 | } | |
895 | ||
896 | return false; | |
897 | } | |
898 | ||
899 | template <typename A> | |
900 | void File<A>::processIndirectLibraries(ld::dylib::File::DylibHandler* handler, bool addImplicitDylibs) | |
901 | { | |
9543cb2f A |
902 | // only do this once |
903 | if ( _indirectDylibsProcessed ) | |
904 | return; | |
a645023d A |
905 | const static bool log = false; |
906 | if ( log ) fprintf(stderr, "processIndirectLibraries(%s)\n", this->installPath()); | |
907 | if ( _linkingFlat ) { | |
908 | for (typename std::vector<Dependent>::iterator it = _dependentDylibs.begin(); it != _dependentDylibs.end(); it++) { | |
909 | it->dylib = (File<A>*)handler->findDylib(it->path, this->path()); | |
910 | } | |
911 | } | |
912 | else if ( _noRexports ) { | |
913 | // MH_NO_REEXPORTED_DYLIBS bit set, then nothing to do | |
914 | } | |
915 | else { | |
916 | // two-level, might have re-exports | |
917 | for (typename std::vector<Dependent>::iterator it = _dependentDylibs.begin(); it != _dependentDylibs.end(); it++) { | |
918 | if ( it->reExport ) { | |
919 | if ( log ) fprintf(stderr, "processIndirectLibraries() parent=%s, child=%s\n", this->installPath(), it->path); | |
920 | // a LC_REEXPORT_DYLIB, LC_SUB_UMBRELLA or LC_SUB_LIBRARY says we re-export this child | |
921 | it->dylib = (File<A>*)handler->findDylib(it->path, this->path()); | |
f80fe69f | 922 | if ( it->dylib->hasPublicInstallName() && !it->dylib->wrongOS() ) { |
a645023d A |
923 | // promote this child to be automatically added as a direct dependent if this already is |
924 | if ( (this->explicitlyLinked() || this->implicitlyLinked()) && (strcmp(it->path,it->dylib->installPath()) == 0) ) { | |
925 | if ( log ) fprintf(stderr, "processIndirectLibraries() implicitly linking %s\n", it->dylib->installPath()); | |
926 | it->dylib->setImplicitlyLinked(); | |
927 | } | |
928 | else if ( it->dylib->explicitlyLinked() || it->dylib->implicitlyLinked() ) { | |
929 | if ( log ) fprintf(stderr, "processIndirectLibraries() parent is not directly linked, but child is, so no need to re-export child\n"); | |
930 | } | |
931 | else { | |
932 | if ( log ) fprintf(stderr, "processIndirectLibraries() parent is not directly linked, so parent=%s will re-export child=%s\n", this->installPath(), it->path); | |
933 | } | |
934 | } | |
935 | else { | |
936 | // add all child's symbols to me | |
937 | if ( log ) fprintf(stderr, "processIndirectLibraries() child is not public, so parent=%s will re-export child=%s\n", this->installPath(), it->path); | |
938 | } | |
939 | } | |
940 | else if ( !_explictReExportFound ) { | |
941 | // see if child contains LC_SUB_FRAMEWORK with my name | |
942 | it->dylib = (File<A>*)handler->findDylib(it->path, this->path()); | |
943 | const char* parentUmbrellaName = it->dylib->parentUmbrella(); | |
944 | if ( parentUmbrellaName != NULL ) { | |
945 | const char* parentName = this->path(); | |
946 | const char* lastSlash = strrchr(parentName, '/'); | |
947 | if ( (lastSlash != NULL) && (strcmp(&lastSlash[1], parentUmbrellaName) == 0) ) { | |
948 | // add all child's symbols to me | |
949 | it->reExport = true; | |
950 | if ( log ) fprintf(stderr, "processIndirectLibraries() umbrella=%s will re-export child=%s\n", this->installPath(), it->path); | |
951 | } | |
952 | } | |
953 | } | |
954 | } | |
955 | } | |
956 | ||
957 | // check for re-export cycles | |
958 | ReExportChain chain; | |
959 | chain.prev = NULL; | |
960 | chain.file = this; | |
961 | this->assertNoReExportCycles(&chain); | |
9543cb2f A |
962 | |
963 | _indirectDylibsProcessed = true; | |
a645023d A |
964 | } |
965 | ||
966 | template <typename A> | |
eaf282aa | 967 | void File<A>::assertNoReExportCycles(ReExportChain* prev) const |
a645023d A |
968 | { |
969 | // recursively check my re-exported dylibs | |
970 | ReExportChain chain; | |
971 | chain.prev = prev; | |
972 | chain.file = this; | |
eaf282aa A |
973 | for (const auto &dep : _dependentDylibs) { |
974 | if ( dep.reExport ) { | |
975 | ld::File* child = dep.dylib; | |
a645023d | 976 | // check child is not already in chain |
eaf282aa | 977 | for (ReExportChain* p = prev; p != nullptr; p = p->prev) { |
a645023d A |
978 | if ( p->file == child ) { |
979 | throwf("cycle in dylib re-exports with %s and %s", child->path(), this->path()); | |
980 | } | |
981 | } | |
eaf282aa A |
982 | if ( dep.dylib != nullptr ) |
983 | dep.dylib->assertNoReExportCycles(&chain); | |
a645023d A |
984 | } |
985 | } | |
986 | } | |
987 | ||
988 | ||
a645023d A |
989 | template <typename A> |
990 | class Parser | |
991 | { | |
992 | public: | |
993 | typedef typename A::P P; | |
994 | ||
995 | static bool validFile(const uint8_t* fileContent, bool executableOrDyliborBundle); | |
f80fe69f | 996 | static const char* fileKind(const uint8_t* fileContent); |
a645023d A |
997 | static ld::dylib::File* parse(const uint8_t* fileContent, uint64_t fileLength, |
998 | const char* path, time_t mTime, | |
ebf6f434 A |
999 | ld::File::Ordinal ordinal, const Options& opts, bool indirectDylib) { |
1000 | return new File<A>(fileContent, fileLength, path, mTime, | |
a645023d A |
1001 | ordinal, opts.flatNamespace(), |
1002 | opts.linkingMainExecutable(), | |
1003 | opts.implicitlyLinkIndirectPublicDylibs(), | |
eaf282aa A |
1004 | opts.platform(), |
1005 | opts.minOSversion(), | |
f80fe69f | 1006 | opts.allowSimulatorToLinkWithMacOSX(), |
afe874b1 | 1007 | opts.addVersionLoadCommand(), |
eaf282aa A |
1008 | opts.targetIOSSimulator(), |
1009 | opts.logAllFiles(), | |
afe874b1 | 1010 | opts.installPath(), |
eaf282aa | 1011 | indirectDylib, |
dd9e569f A |
1012 | opts.outputKind() == Options::kPreload, |
1013 | opts.bundleBitcode()); | |
a645023d A |
1014 | } |
1015 | ||
1016 | }; | |
1017 | ||
1018 | ||
1019 | ||
a645023d A |
1020 | template <> |
1021 | bool Parser<x86>::validFile(const uint8_t* fileContent, bool executableOrDyliborBundle) | |
1022 | { | |
1023 | const macho_header<P>* header = (const macho_header<P>*)fileContent; | |
1024 | if ( header->magic() != MH_MAGIC ) | |
1025 | return false; | |
1026 | if ( header->cputype() != CPU_TYPE_I386 ) | |
1027 | return false; | |
1028 | switch ( header->filetype() ) { | |
1029 | case MH_DYLIB: | |
1030 | case MH_DYLIB_STUB: | |
1031 | return true; | |
1032 | case MH_BUNDLE: | |
1033 | if ( executableOrDyliborBundle ) | |
1034 | return true; | |
1035 | else | |
1036 | throw "can't link with bundle (MH_BUNDLE) only dylibs (MH_DYLIB)"; | |
1037 | case MH_EXECUTE: | |
1038 | if ( executableOrDyliborBundle ) | |
1039 | return true; | |
1040 | else | |
1041 | throw "can't link with a main executable"; | |
1042 | default: | |
1043 | return false; | |
1044 | } | |
1045 | } | |
1046 | ||
1047 | template <> | |
1048 | bool Parser<x86_64>::validFile(const uint8_t* fileContent, bool executableOrDyliborBundle) | |
1049 | { | |
1050 | const macho_header<P>* header = (const macho_header<P>*)fileContent; | |
1051 | if ( header->magic() != MH_MAGIC_64 ) | |
1052 | return false; | |
1053 | if ( header->cputype() != CPU_TYPE_X86_64 ) | |
1054 | return false; | |
1055 | switch ( header->filetype() ) { | |
1056 | case MH_DYLIB: | |
1057 | case MH_DYLIB_STUB: | |
1058 | return true; | |
1059 | case MH_BUNDLE: | |
1060 | if ( executableOrDyliborBundle ) | |
1061 | return true; | |
1062 | else | |
1063 | throw "can't link with bundle (MH_BUNDLE) only dylibs (MH_DYLIB)"; | |
1064 | case MH_EXECUTE: | |
1065 | if ( executableOrDyliborBundle ) | |
1066 | return true; | |
1067 | else | |
1068 | throw "can't link with a main executable"; | |
1069 | default: | |
1070 | return false; | |
1071 | } | |
1072 | } | |
1073 | ||
1074 | template <> | |
1075 | bool Parser<arm>::validFile(const uint8_t* fileContent, bool executableOrDyliborBundle) | |
1076 | { | |
1077 | const macho_header<P>* header = (const macho_header<P>*)fileContent; | |
1078 | if ( header->magic() != MH_MAGIC ) | |
1079 | return false; | |
1080 | if ( header->cputype() != CPU_TYPE_ARM ) | |
1081 | return false; | |
1082 | switch ( header->filetype() ) { | |
1083 | case MH_DYLIB: | |
1084 | case MH_DYLIB_STUB: | |
1085 | return true; | |
1086 | case MH_BUNDLE: | |
1087 | if ( executableOrDyliborBundle ) | |
1088 | return true; | |
1089 | else | |
1090 | throw "can't link with bundle (MH_BUNDLE) only dylibs (MH_DYLIB)"; | |
1091 | case MH_EXECUTE: | |
1092 | if ( executableOrDyliborBundle ) | |
1093 | return true; | |
1094 | else | |
1095 | throw "can't link with a main executable"; | |
1096 | default: | |
1097 | return false; | |
1098 | } | |
1099 | } | |
1100 | ||
1101 | ||
1102 | ||
f80fe69f A |
1103 | template <> |
1104 | bool Parser<arm64>::validFile(const uint8_t* fileContent, bool executableOrDyliborBundle) | |
1105 | { | |
1106 | const macho_header<P>* header = (const macho_header<P>*)fileContent; | |
1107 | if ( header->magic() != MH_MAGIC_64 ) | |
1108 | return false; | |
1109 | if ( header->cputype() != CPU_TYPE_ARM64 ) | |
1110 | return false; | |
1111 | switch ( header->filetype() ) { | |
1112 | case MH_DYLIB: | |
1113 | case MH_DYLIB_STUB: | |
1114 | return true; | |
1115 | case MH_BUNDLE: | |
1116 | if ( executableOrDyliborBundle ) | |
1117 | return true; | |
1118 | else | |
1119 | throw "can't link with bundle (MH_BUNDLE) only dylibs (MH_DYLIB)"; | |
1120 | case MH_EXECUTE: | |
1121 | if ( executableOrDyliborBundle ) | |
1122 | return true; | |
1123 | else | |
1124 | throw "can't link with a main executable"; | |
1125 | default: | |
1126 | return false; | |
1127 | } | |
1128 | } | |
1129 | ||
1130 | ||
1131 | bool isDylibFile(const uint8_t* fileContent, cpu_type_t* result, cpu_subtype_t* subResult) | |
1132 | { | |
1133 | if ( Parser<x86_64>::validFile(fileContent, false) ) { | |
1134 | *result = CPU_TYPE_X86_64; | |
9543cb2f A |
1135 | const macho_header<Pointer64<LittleEndian> >* header = (const macho_header<Pointer64<LittleEndian> >*)fileContent; |
1136 | *subResult = header->cpusubtype(); | |
f80fe69f A |
1137 | return true; |
1138 | } | |
1139 | if ( Parser<x86>::validFile(fileContent, false) ) { | |
1140 | *result = CPU_TYPE_I386; | |
1141 | *subResult = CPU_SUBTYPE_X86_ALL; | |
1142 | return true; | |
1143 | } | |
1144 | if ( Parser<arm>::validFile(fileContent, false) ) { | |
1145 | *result = CPU_TYPE_ARM; | |
1146 | const macho_header<Pointer32<LittleEndian> >* header = (const macho_header<Pointer32<LittleEndian> >*)fileContent; | |
1147 | *subResult = header->cpusubtype(); | |
1148 | return true; | |
1149 | } | |
1150 | if ( Parser<arm64>::validFile(fileContent, false) ) { | |
1151 | *result = CPU_TYPE_ARM64; | |
1152 | *subResult = CPU_SUBTYPE_ARM64_ALL; | |
1153 | return true; | |
1154 | } | |
f80fe69f A |
1155 | return false; |
1156 | } | |
1157 | ||
1158 | template <> | |
1159 | const char* Parser<x86>::fileKind(const uint8_t* fileContent) | |
1160 | { | |
1161 | const macho_header<P>* header = (const macho_header<P>*)fileContent; | |
1162 | if ( header->magic() != MH_MAGIC ) | |
1163 | return NULL; | |
1164 | if ( header->cputype() != CPU_TYPE_I386 ) | |
1165 | return NULL; | |
1166 | return "i386"; | |
1167 | } | |
1168 | ||
1169 | template <> | |
1170 | const char* Parser<x86_64>::fileKind(const uint8_t* fileContent) | |
1171 | { | |
1172 | const macho_header<P>* header = (const macho_header<P>*)fileContent; | |
1173 | if ( header->magic() != MH_MAGIC_64 ) | |
1174 | return NULL; | |
1175 | if ( header->cputype() != CPU_TYPE_X86_64 ) | |
1176 | return NULL; | |
1177 | return "x86_64"; | |
1178 | } | |
1179 | ||
1180 | template <> | |
1181 | const char* Parser<arm>::fileKind(const uint8_t* fileContent) | |
1182 | { | |
1183 | const macho_header<P>* header = (const macho_header<P>*)fileContent; | |
1184 | if ( header->magic() != MH_MAGIC ) | |
1185 | return NULL; | |
1186 | if ( header->cputype() != CPU_TYPE_ARM ) | |
1187 | return NULL; | |
1188 | for (const ArchInfo* t=archInfoArray; t->archName != NULL; ++t) { | |
1189 | if ( (t->cpuType == CPU_TYPE_ARM) && ((cpu_subtype_t)header->cpusubtype() == t->cpuSubType) ) { | |
1190 | return t->archName; | |
1191 | } | |
1192 | } | |
1193 | return "arm???"; | |
1194 | } | |
1195 | ||
1196 | #if SUPPORT_ARCH_arm64 | |
1197 | template <> | |
1198 | const char* Parser<arm64>::fileKind(const uint8_t* fileContent) | |
1199 | { | |
1200 | const macho_header<P>* header = (const macho_header<P>*)fileContent; | |
1201 | if ( header->magic() != MH_MAGIC_64 ) | |
1202 | return NULL; | |
1203 | if ( header->cputype() != CPU_TYPE_ARM64 ) | |
1204 | return NULL; | |
1205 | return "arm64"; | |
1206 | } | |
1207 | #endif | |
1208 | ||
1209 | // | |
1210 | // used by linker is error messages to describe mismatched files | |
1211 | // | |
1212 | const char* archName(const uint8_t* fileContent) | |
1213 | { | |
1214 | if ( Parser<x86_64>::validFile(fileContent, true) ) { | |
1215 | return Parser<x86_64>::fileKind(fileContent); | |
1216 | } | |
1217 | if ( Parser<x86>::validFile(fileContent, true) ) { | |
1218 | return Parser<x86>::fileKind(fileContent); | |
1219 | } | |
1220 | if ( Parser<arm>::validFile(fileContent, true) ) { | |
1221 | return Parser<arm>::fileKind(fileContent); | |
1222 | } | |
1223 | #if SUPPORT_ARCH_arm64 | |
1224 | if ( Parser<arm64>::validFile(fileContent, false) ) { | |
1225 | return Parser<arm64>::fileKind(fileContent); | |
1226 | } | |
1227 | #endif | |
1228 | return NULL; | |
1229 | } | |
1230 | ||
1231 | ||
a645023d A |
1232 | // |
1233 | // main function used by linker to instantiate ld::Files | |
1234 | // | |
1235 | ld::dylib::File* parse(const uint8_t* fileContent, uint64_t fileLength, | |
ebf6f434 | 1236 | const char* path, time_t modTime, const Options& opts, ld::File::Ordinal ordinal, |
afe874b1 | 1237 | bool bundleLoader, bool indirectDylib) |
a645023d A |
1238 | { |
1239 | switch ( opts.architecture() ) { | |
ebf6f434 | 1240 | #if SUPPORT_ARCH_x86_64 |
a645023d A |
1241 | case CPU_TYPE_X86_64: |
1242 | if ( Parser<x86_64>::validFile(fileContent, bundleLoader) ) | |
afe874b1 | 1243 | return Parser<x86_64>::parse(fileContent, fileLength, path, modTime, ordinal, opts, indirectDylib); |
a645023d | 1244 | break; |
ebf6f434 A |
1245 | #endif |
1246 | #if SUPPORT_ARCH_i386 | |
a645023d A |
1247 | case CPU_TYPE_I386: |
1248 | if ( Parser<x86>::validFile(fileContent, bundleLoader) ) | |
afe874b1 | 1249 | return Parser<x86>::parse(fileContent, fileLength, path, modTime, ordinal, opts, indirectDylib); |
a645023d | 1250 | break; |
ebf6f434 A |
1251 | #endif |
1252 | #if SUPPORT_ARCH_arm_any | |
a645023d A |
1253 | case CPU_TYPE_ARM: |
1254 | if ( Parser<arm>::validFile(fileContent, bundleLoader) ) | |
afe874b1 | 1255 | return Parser<arm>::parse(fileContent, fileLength, path, modTime, ordinal, opts, indirectDylib); |
a645023d | 1256 | break; |
f80fe69f A |
1257 | #endif |
1258 | #if SUPPORT_ARCH_arm64 | |
1259 | case CPU_TYPE_ARM64: | |
1260 | if ( Parser<arm64>::validFile(fileContent, bundleLoader) ) | |
1261 | return Parser<arm64>::parse(fileContent, fileLength, path, modTime, ordinal, opts, indirectDylib); | |
1262 | break; | |
ebf6f434 | 1263 | #endif |
a645023d A |
1264 | } |
1265 | return NULL; | |
1266 | } | |
1267 | ||
1268 | ||
1269 | }; // namespace dylib | |
1270 | }; // namespace mach_o | |
1271 | ||
1272 |