]> git.saurik.com Git - apple/ld64.git/blame - src/ld/parsers/textstub_dylib_file.cpp
ld64-305.tar.gz
[apple/ld64.git] / src / ld / parsers / textstub_dylib_file.cpp
CommitLineData
eaf282aa
A
1/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
2 *
3 * Copyright (c) 2015 Apple Inc. All rights reserved.
4 *
5 * @APPLE_LICENSE_HEADER_START@
6 *
7 * This file contains Original Code and/or Modifications of Original Code
8 * as defined in and that are subject to the Apple Public Source License
9 * Version 2.0 (the 'License'). You may not use this file except in
10 * compliance with the License. Please obtain a copy of the License at
11 * http://www.opensource.apple.com/apsl/ and read it before using this
12 * file.
13 *
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
19 * Please see the License for the specific language governing rights and
20 * limitations under the License.
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24
25
26#include <sys/param.h>
27#include <sys/mman.h>
0a8dc3df 28#include <tapi/tapi.h>
eaf282aa
A
29#include <vector>
30
31#include "Architectures.hpp"
32#include "bitcode.hpp"
33#include "MachOFileAbstraction.hpp"
34#include "MachOTrie.hpp"
ec29ba20 35#include "generic_dylib_file.hpp"
eaf282aa
A
36#include "textstub_dylib_file.hpp"
37
eaf282aa
A
38
39namespace textstub {
40namespace dylib {
41
eaf282aa
A
42//
43// The reader for a dylib extracts all exported symbols names from the memory-mapped
44// dylib, builds a hash table, then unmaps the file. This is an important memory
45// savings for large dylibs.
46//
47template <typename A>
ec29ba20 48class File final : public generic::dylib::File<A>
eaf282aa 49{
ec29ba20
A
50 using Base = generic::dylib::File<A>;
51
eaf282aa 52public:
0a8dc3df 53 File(const char* path, const uint8_t* fileContent, uint64_t fileLength,
eaf282aa 54 time_t mTime, ld::File::Ordinal ordinal, bool linkingFlatNamespace,
0a8dc3df
A
55 bool linkingMainExecutable, bool hoistImplicitPublicDylibs,
56 Options::Platform platform, uint32_t linkMinOSVersion, bool allowWeakImports,
57 cpu_type_t cpuType, cpu_subtype_t cpuSubType, bool enforceDylibSubtypesMatch,
eaf282aa
A
58 bool allowSimToMacOSX, bool addVers, bool buildingForSimulator,
59 bool logAllFiles, const char* installPath, bool indirectDylib);
ec29ba20 60 virtual ~File() noexcept {}
eaf282aa
A
61
62private:
0a8dc3df 63 void buildExportHashTable(const tapi::LinkerInterfaceFile* file);
ec29ba20 64};
eaf282aa 65
0a8dc3df
A
66static ld::File::ObjcConstraint mapObjCConstraint(tapi::ObjCConstraint constraint) {
67 switch (constraint) {
68 case tapi::ObjCConstraint::None:
69 return ld::File::objcConstraintNone;
70 case tapi::ObjCConstraint::Retain_Release:
71 return ld::File::objcConstraintRetainRelease;
72 case tapi::ObjCConstraint::Retain_Release_For_Simulator:
73 return ld::File::objcConstraintRetainReleaseForSimulator;
74 case tapi::ObjCConstraint::Retain_Release_Or_GC:
75 return ld::File::objcConstraintRetainReleaseOrGC;
76 case tapi::ObjCConstraint::GC:
77 return ld::File::objcConstraintGC;
78 }
79
80 return ld::File::objcConstraintNone;
81}
82
83static Options::Platform mapPlatform(tapi::Platform platform) {
84 switch (platform) {
85 case tapi::Platform::Unknown:
86 return Options::kPlatformUnknown;
87 case tapi::Platform::OSX:
88 return Options::kPlatformOSX;
89 case tapi::Platform::iOS:
90 return Options::kPlatformiOS;
91 case tapi::Platform::watchOS:
92 return Options::kPlatformWatchOS;
93 case tapi::Platform::tvOS:
94 return Options::kPlatform_tvOS;
bee7e226
A
95 #if ((TAPI_API_VERSION_MAJOR == 1 && TAPI_API_VERSION_MINOR >= 2) || (TAPI_API_VERSION_MAJOR > 1))
96 case tapi::Platform::bridgeOS:
97 return Options::kPlatform_bridgeOS;
98 #endif
0a8dc3df
A
99 }
100
101 return Options::kPlatformUnknown;
102}
103
eaf282aa 104template <typename A>
0a8dc3df
A
105 File<A>::File(const char* path, const uint8_t* fileContent, uint64_t fileLength,
106 time_t mTime, ld::File::Ordinal ord, bool linkingFlatNamespace,
107 bool linkingMainExecutable, bool hoistImplicitPublicDylibs, Options::Platform platform,
108 uint32_t linkMinOSVersion, bool allowWeakImports, cpu_type_t cpuType, cpu_subtype_t cpuSubType,
109 bool enforceDylibSubtypesMatch, bool allowSimToMacOSX, bool addVers,
eaf282aa
A
110 bool buildingForSimulator, bool logAllFiles, const char* targetInstallPath,
111 bool indirectDylib)
0a8dc3df
A
112 : Base(strdup(path), mTime, ord, platform, linkMinOSVersion, allowWeakImports, linkingFlatNamespace,
113 hoistImplicitPublicDylibs, allowSimToMacOSX, addVers)
eaf282aa 114{
82b4b32b
A
115 std::unique_ptr<tapi::LinkerInterfaceFile> file;
116 std::string errorMessage;
117
118// <rdar://problem/29038544> Support $ld$weak symbols in .tbd files
119#if ((TAPI_API_VERSION_MAJOR == 1 && TAPI_API_VERSION_MINOR >= 1) || (TAPI_API_VERSION_MAJOR > 1))
120 // Check if the library supports the new create API.
121 if (tapi::APIVersion::isAtLeast(1, 1)) {
122 tapi::ParsingFlags flags = tapi::ParsingFlags::None;
123 if (enforceDylibSubtypesMatch)
124 flags |= tapi::ParsingFlags::ExactCpuSubType;
125
126 if (!allowWeakImports)
127 flags |= tapi::ParsingFlags::DisallowWeakImports;
128
129 file.reset(tapi::LinkerInterfaceFile::create(
130 path, fileContent, fileLength, cpuType, cpuSubType, flags,
131 tapi::PackedVersion32(linkMinOSVersion), errorMessage));
132 } else {
133 auto matchingType = enforceDylibSubtypesMatch ?
134 tapi::CpuSubTypeMatching::Exact : tapi::CpuSubTypeMatching::ABI_Compatible;
135
136 file.reset(tapi::LinkerInterfaceFile::create(
137 path, fileContent, fileLength, cpuType, cpuSubType, matchingType,
138 tapi::PackedVersion32(linkMinOSVersion), errorMessage));
139 }
140#else
0a8dc3df 141 auto matchingType = enforceDylibSubtypesMatch ?
82b4b32b 142 tapi::CpuSubTypeMatching::Exact : tapi::CpuSubTypeMatching::ABI_Compatible;
0a8dc3df 143
82b4b32b
A
144 file.reset(tapi::LinkerInterfaceFile::create(
145 path, fileContent, fileLength, cpuType, cpuSubType, matchingType,
146 tapi::PackedVersion32(linkMinOSVersion), errorMessage));
147#endif
0a8dc3df
A
148
149 if (file == nullptr)
150 throw strdup(errorMessage.c_str());
151
152 // unmap file - it is no longer needed.
153 munmap((caddr_t)fileContent, fileLength);
ec29ba20 154
eaf282aa
A
155 // write out path for -t option
156 if ( logAllFiles )
157 printf("%s\n", path);
158
0a8dc3df
A
159 this->_bitcode = std::unique_ptr<ld::Bitcode>(new ld::Bitcode(nullptr, 0));
160 this->_noRexports = !file->hasReexportedLibraries();
161 this->_hasWeakExports = file->hasWeakDefinedExports();
162 this->_dylibInstallPath = strdup(file->getInstallName().c_str());
163 this->_installPathOverride = file->isInstallNameVersionSpecific();
164 this->_dylibCurrentVersion = file->getCurrentVersion();
165 this->_dylibCompatibilityVersion = file->getCompatibilityVersion();
166 this->_swiftVersion = file->getSwiftVersion();
167 this->_objcConstraint = mapObjCConstraint(file->getObjCConstraint());
168 this->_parentUmbrella = file->getParentFrameworkName().empty() ? nullptr : strdup(file->getParentFrameworkName().c_str());
169 this->_appExtensionSafe = file->isApplicationExtensionSafe();
ec29ba20
A
170
171 // if framework, capture framework name
172 const char* lastSlash = strrchr(this->_dylibInstallPath, '/');
173 if ( lastSlash != NULL ) {
174 const char* leafName = lastSlash+1;
175 char frname[strlen(leafName)+32];
176 strcpy(frname, leafName);
177 strcat(frname, ".framework/");
178
179 if ( strstr(this->_dylibInstallPath, frname) != NULL )
180 this->_frameworkName = leafName;
181 }
182
0a8dc3df
A
183 for (auto &client : file->allowableClients())
184 this->_allowableClients.push_back(strdup(client.c_str()));
eaf282aa
A
185
186 // <rdar://problem/20659505> [TAPI] Don't hoist "public" (in /usr/lib/) dylibs that should not be directly linked
0a8dc3df
A
187 this->_hasPublicInstallName = file->hasAllowableClients() ? false : this->isPublicLocation(file->getInstallName().c_str());
188
189 for (const auto &client : file->allowableClients())
190 this->_allowableClients.emplace_back(strdup(client.c_str()));
eaf282aa 191
0a8dc3df
A
192 auto dylibPlatform = mapPlatform(file->getPlatform());
193 if ( (dylibPlatform != platform) && (platform != Options::kPlatformUnknown) ) {
ec29ba20
A
194 this->_wrongOS = true;
195 if ( this->_addVersionLoadCommand && !indirectDylib ) {
eaf282aa 196 if ( buildingForSimulator ) {
ec29ba20 197 if ( !this->_allowSimToMacOSXLinking )
eaf282aa 198 throwf("building for %s simulator, but linking against dylib built for %s (%s).",
0a8dc3df 199 Options::platformName(platform), Options::platformName(dylibPlatform), path);
eaf282aa
A
200 } else {
201 throwf("building for %s, but linking against dylib built for %s (%s).",
0a8dc3df 202 Options::platformName(platform), Options::platformName(dylibPlatform), path);
eaf282aa
A
203 }
204 }
205 }
206
0a8dc3df
A
207 for (const auto& reexport : file->reexportedLibraries()) {
208 const char *path = strdup(reexport.c_str());
ec29ba20
A
209 if ( (targetInstallPath == nullptr) || (strcmp(targetInstallPath, path) != 0) )
210 this->_dependentDylibs.emplace_back(path, true);
eaf282aa
A
211 }
212
0a8dc3df
A
213 for (const auto& symbol : file->ignoreExports())
214 this->_ignoreExports.insert(strdup(symbol.c_str()));
eaf282aa 215
0a8dc3df
A
216 // if linking flat and this is a flat dylib, create one atom that references all imported symbols.
217 if ( linkingFlatNamespace && linkingMainExecutable && (file->hasTwoLevelNamespace() == false) ) {
218 std::vector<const char*> importNames;
219 importNames.reserve(file->undefineds().size());
220 // We do not need to strdup the name, because that will be done by the
221 // ImportAtom constructor.
222 for (const auto &sym : file->undefineds())
223 importNames.emplace_back(sym.getName().c_str());
224 this->_importAtom = new generic::dylib::ImportAtom<A>(*this, importNames);
225 }
226
227 // build hash table
228 buildExportHashTable(file.get());
eaf282aa
A
229}
230
231template <typename A>
0a8dc3df 232void File<A>::buildExportHashTable(const tapi::LinkerInterfaceFile* file) {
ec29ba20 233 if (this->_s_logHashtable )
eaf282aa
A
234 fprintf(stderr, "ld: building hashtable from text-stub info in %s\n", this->path());
235
0a8dc3df
A
236 for (const auto &sym : file->exports()) {
237 const char* name = sym.getName().c_str();
238 bool weakDef = sym.isWeakDefined();
239 bool tlv = sym.isThreadLocalValue();
eaf282aa 240
0a8dc3df
A
241 typename Base::AtomAndWeak bucket = { nullptr, weakDef, tlv, 0 };
242 if ( this->_s_logHashtable )
243 fprintf(stderr, " adding %s to hash table for %s\n", name, this->path());
244 this->_atoms[strdup(name)] = bucket;
eaf282aa 245 }
eaf282aa
A
246}
247
eaf282aa
A
248template <typename A>
249class Parser
250{
251public:
ec29ba20 252 using P = typename A::P;
eaf282aa 253
0a8dc3df
A
254 static ld::dylib::File* parse(const char* path, const uint8_t* fileContent,
255 uint64_t fileLength, time_t mTime,
256 ld::File::Ordinal ordinal, const Options& opts,
ec29ba20
A
257 bool indirectDylib)
258 {
0a8dc3df 259 return new File<A>(path, fileContent, fileLength,mTime, ordinal,
eaf282aa 260 opts.flatNamespace(),
0a8dc3df 261 opts.linkingMainExecutable(),
eaf282aa
A
262 opts.implicitlyLinkIndirectPublicDylibs(),
263 opts.platform(),
eaf282aa 264 opts.minOSversion(),
0a8dc3df
A
265 opts.allowWeakImports(),
266 opts.architecture(),
267 opts.subArchitecture(),
268 opts.enforceDylibSubtypesMatch(),
eaf282aa
A
269 opts.allowSimulatorToLinkWithMacOSX(),
270 opts.addVersionLoadCommand(),
271 opts.targetIOSSimulator(),
272 opts.logAllFiles(),
273 opts.installPath(),
274 indirectDylib);
275 }
276};
277
eaf282aa
A
278//
279// main function used by linker to instantiate ld::Files
280//
281ld::dylib::File* parse(const uint8_t* fileContent, uint64_t fileLength, const char* path,
282 time_t modTime, const Options& opts, ld::File::Ordinal ordinal,
283 bool bundleLoader, bool indirectDylib)
284{
0a8dc3df 285
eaf282aa
A
286 switch ( opts.architecture() ) {
287#if SUPPORT_ARCH_x86_64
288 case CPU_TYPE_X86_64:
0a8dc3df
A
289 if (tapi::LinkerInterfaceFile::isSupported(path, fileContent, fileLength))
290 return Parser<x86_64>::parse(path, fileContent, fileLength, modTime, ordinal, opts, indirectDylib);
eaf282aa
A
291#endif
292#if SUPPORT_ARCH_i386
293 case CPU_TYPE_I386:
0a8dc3df
A
294 if (tapi::LinkerInterfaceFile::isSupported(path, fileContent, fileLength))
295 return Parser<x86>::parse(path, fileContent, fileLength, modTime, ordinal, opts, indirectDylib);
eaf282aa
A
296#endif
297#if SUPPORT_ARCH_arm_any
298 case CPU_TYPE_ARM:
0a8dc3df
A
299 if (tapi::LinkerInterfaceFile::isSupported(path, fileContent, fileLength))
300 return Parser<arm>::parse(path, fileContent, fileLength, modTime, ordinal, opts, indirectDylib);
eaf282aa
A
301#endif
302#if SUPPORT_ARCH_arm64
303 case CPU_TYPE_ARM64:
0a8dc3df
A
304 if (tapi::LinkerInterfaceFile::isSupported(path, fileContent, fileLength))
305 return Parser<arm64>::parse(path, fileContent, fileLength, modTime, ordinal, opts, indirectDylib);
eaf282aa
A
306#endif
307 }
308 return nullptr;
309}
310
311
312} // namespace dylib
313} // namespace textstub