Some header changes to fix the build with other compilers.
[darwin-xtools.git] / ld64 / src / ld / parsers / textstub_dylib_file.cpp
blob75cb228bd10b7a29a489d7e1e75f388ca7cf914d
1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
3 * Copyright (c) 2015 Apple Inc. All rights reserved.
5 * @APPLE_LICENSE_HEADER_START@
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.
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.
22 * @APPLE_LICENSE_HEADER_END@
26 #include <sys/param.h>
27 #include <sys/mman.h>
28 #include <tapi/tapi.h>
29 #include <vector>
30 #include <algorithm>
31 #include <memory>
33 #include "Architectures.hpp"
34 #include "Bitcode.hpp"
35 #include "MachOFileAbstraction.hpp"
36 #include "MachOTrie.hpp"
37 #include "generic_dylib_file.hpp"
38 #include "textstub_dylib_file.hpp"
41 namespace textstub {
42 namespace dylib {
45 // The reader for a dylib extracts all exported symbols names from the memory-mapped
46 // dylib, builds a hash table, then unmaps the file. This is an important memory
47 // savings for large dylibs.
49 template <typename A>
50 class File final : public generic::dylib::File<A>
52 using Base = generic::dylib::File<A>;
54 public:
55 File(const char* path, const uint8_t* fileContent, uint64_t fileLength,
56 time_t mTime, ld::File::Ordinal ordinal, bool linkingFlatNamespace,
57 bool linkingMainExecutable, bool hoistImplicitPublicDylibs,
58 Options::Platform platform, uint32_t linkMinOSVersion, bool allowWeakImports,
59 cpu_type_t cpuType, cpu_subtype_t cpuSubType, bool enforceDylibSubtypesMatch,
60 bool allowSimToMacOSX, bool addVers, bool buildingForSimulator,
61 bool logAllFiles, const char* installPath, bool indirectDylib);
62 virtual ~File() noexcept {}
64 private:
65 void buildExportHashTable(const tapi::LinkerInterfaceFile* file);
68 static ld::File::ObjcConstraint mapObjCConstraint(tapi::ObjCConstraint constraint) {
69 switch (constraint) {
70 case tapi::ObjCConstraint::None:
71 return ld::File::objcConstraintNone;
72 case tapi::ObjCConstraint::Retain_Release:
73 return ld::File::objcConstraintRetainRelease;
74 case tapi::ObjCConstraint::Retain_Release_For_Simulator:
75 return ld::File::objcConstraintRetainReleaseForSimulator;
76 case tapi::ObjCConstraint::Retain_Release_Or_GC:
77 return ld::File::objcConstraintRetainReleaseOrGC;
78 case tapi::ObjCConstraint::GC:
79 return ld::File::objcConstraintGC;
82 return ld::File::objcConstraintNone;
85 static Options::Platform mapPlatform(tapi::Platform platform) {
86 switch (platform) {
87 case tapi::Platform::Unknown:
88 return Options::kPlatformUnknown;
89 case tapi::Platform::OSX:
90 return Options::kPlatformOSX;
91 case tapi::Platform::iOS:
92 return Options::kPlatformiOS;
93 case tapi::Platform::watchOS:
94 return Options::kPlatformWatchOS;
95 case tapi::Platform::tvOS:
96 return Options::kPlatform_tvOS;
99 return Options::kPlatformUnknown;
102 template <typename A>
103 File<A>::File(const char* path, const uint8_t* fileContent, uint64_t fileLength,
104 time_t mTime, ld::File::Ordinal ord, bool linkingFlatNamespace,
105 bool linkingMainExecutable, bool hoistImplicitPublicDylibs, Options::Platform platform,
106 uint32_t linkMinOSVersion, bool allowWeakImports, cpu_type_t cpuType, cpu_subtype_t cpuSubType,
107 bool enforceDylibSubtypesMatch, bool allowSimToMacOSX, bool addVers,
108 bool buildingForSimulator, bool logAllFiles, const char* targetInstallPath,
109 bool indirectDylib)
110 : Base(strdup(path), mTime, ord, platform, linkMinOSVersion, allowWeakImports, linkingFlatNamespace,
111 hoistImplicitPublicDylibs, allowSimToMacOSX, addVers)
113 auto matchingType = enforceDylibSubtypesMatch ?
114 tapi::CpuSubTypeMatching::Exact : tapi::CpuSubTypeMatching::ABI_Compatible;
116 std::string errorMessage;
117 auto file = std::unique_ptr<tapi::LinkerInterfaceFile>(
118 tapi::LinkerInterfaceFile::create(path, fileContent, fileLength, cpuType,
119 cpuSubType, matchingType,
120 tapi::PackedVersion32(linkMinOSVersion), errorMessage));
122 if (file == nullptr)
123 throw strdup(errorMessage.c_str());
125 // unmap file - it is no longer needed.
126 munmap((caddr_t)fileContent, fileLength);
128 // write out path for -t option
129 if ( logAllFiles )
130 printf("%s\n", path);
132 this->_bitcode = std::unique_ptr<ld::Bitcode>(new ld::Bitcode(nullptr, 0));
133 this->_noRexports = !file->hasReexportedLibraries();
134 this->_hasWeakExports = file->hasWeakDefinedExports();
135 this->_dylibInstallPath = strdup(file->getInstallName().c_str());
136 this->_installPathOverride = file->isInstallNameVersionSpecific();
137 this->_dylibCurrentVersion = file->getCurrentVersion();
138 this->_dylibCompatibilityVersion = file->getCompatibilityVersion();
139 this->_swiftVersion = file->getSwiftVersion();
140 this->_objcConstraint = mapObjCConstraint(file->getObjCConstraint());
141 this->_parentUmbrella = file->getParentFrameworkName().empty() ? nullptr : strdup(file->getParentFrameworkName().c_str());
142 this->_appExtensionSafe = file->isApplicationExtensionSafe();
144 // if framework, capture framework name
145 const char* lastSlash = strrchr(this->_dylibInstallPath, '/');
146 if ( lastSlash != NULL ) {
147 const char* leafName = lastSlash+1;
148 char frname[strlen(leafName)+32];
149 strcpy(frname, leafName);
150 strcat(frname, ".framework/");
152 if ( strstr(this->_dylibInstallPath, frname) != NULL )
153 this->_frameworkName = leafName;
156 for (auto &client : file->allowableClients())
157 this->_allowableClients.push_back(strdup(client.c_str()));
159 // <rdar://problem/20659505> [TAPI] Don't hoist "public" (in /usr/lib/) dylibs that should not be directly linked
160 this->_hasPublicInstallName = file->hasAllowableClients() ? false : this->isPublicLocation(file->getInstallName().c_str());
162 for (const auto &client : file->allowableClients())
163 this->_allowableClients.emplace_back(strdup(client.c_str()));
165 auto dylibPlatform = mapPlatform(file->getPlatform());
166 if ( (dylibPlatform != platform) && (platform != Options::kPlatformUnknown) ) {
167 this->_wrongOS = true;
168 if ( this->_addVersionLoadCommand && !indirectDylib ) {
169 if ( buildingForSimulator ) {
170 if ( !this->_allowSimToMacOSXLinking )
171 throwf("building for %s simulator, but linking against dylib built for %s (%s).",
172 Options::platformName(platform), Options::platformName(dylibPlatform), path);
173 } else {
174 throwf("building for %s, but linking against dylib built for %s (%s).",
175 Options::platformName(platform), Options::platformName(dylibPlatform), path);
180 for (const auto& reexport : file->reexportedLibraries()) {
181 const char *path = strdup(reexport.c_str());
182 if ( (targetInstallPath == nullptr) || (strcmp(targetInstallPath, path) != 0) )
183 this->_dependentDylibs.emplace_back(path, true);
186 for (const auto& symbol : file->ignoreExports())
187 this->_ignoreExports.insert(strdup(symbol.c_str()));
189 // if linking flat and this is a flat dylib, create one atom that references all imported symbols.
190 if ( linkingFlatNamespace && linkingMainExecutable && (file->hasTwoLevelNamespace() == false) ) {
191 std::vector<const char*> importNames;
192 importNames.reserve(file->undefineds().size());
193 // We do not need to strdup the name, because that will be done by the
194 // ImportAtom constructor.
195 for (const auto &sym : file->undefineds())
196 importNames.emplace_back(sym.getName().c_str());
197 this->_importAtom = new generic::dylib::ImportAtom<A>(*this, importNames);
200 // build hash table
201 buildExportHashTable(file.get());
204 template <typename A>
205 void File<A>::buildExportHashTable(const tapi::LinkerInterfaceFile* file) {
206 if (this->_s_logHashtable )
207 fprintf(stderr, "ld: building hashtable from text-stub info in %s\n", this->path());
209 for (const auto &sym : file->exports()) {
210 const char* name = sym.getName().c_str();
211 bool weakDef = sym.isWeakDefined();
212 bool tlv = sym.isThreadLocalValue();
214 typename Base::AtomAndWeak bucket = { nullptr, weakDef, tlv, 0 };
215 if ( this->_s_logHashtable )
216 fprintf(stderr, " adding %s to hash table for %s\n", name, this->path());
217 this->_atoms[strdup(name)] = bucket;
221 template <typename A>
222 class Parser
224 public:
225 using P = typename A::P;
227 static ld::dylib::File* parse(const char* path, const uint8_t* fileContent,
228 uint64_t fileLength, time_t mTime,
229 ld::File::Ordinal ordinal, const Options& opts,
230 bool indirectDylib)
232 return new File<A>(path, fileContent, fileLength,mTime, ordinal,
233 opts.flatNamespace(),
234 opts.linkingMainExecutable(),
235 opts.implicitlyLinkIndirectPublicDylibs(),
236 opts.platform(),
237 opts.minOSversion(),
238 opts.allowWeakImports(),
239 opts.architecture(),
240 opts.subArchitecture(),
241 opts.enforceDylibSubtypesMatch(),
242 opts.allowSimulatorToLinkWithMacOSX(),
243 opts.addVersionLoadCommand(),
244 opts.targetIOSSimulator(),
245 opts.logAllFiles(),
246 opts.installPath(),
247 indirectDylib);
252 // main function used by linker to instantiate ld::Files
254 ld::dylib::File* parse(const uint8_t* fileContent, uint64_t fileLength, const char* path,
255 time_t modTime, const Options& opts, ld::File::Ordinal ordinal,
256 bool bundleLoader, bool indirectDylib)
259 switch ( opts.architecture() ) {
260 #if SUPPORT_ARCH_x86_64
261 case CPU_TYPE_X86_64:
262 if (tapi::LinkerInterfaceFile::isSupported(path, fileContent, fileLength))
263 return Parser<x86_64>::parse(path, fileContent, fileLength, modTime, ordinal, opts, indirectDylib);
264 #endif
265 #if SUPPORT_ARCH_i386
266 case CPU_TYPE_I386:
267 if (tapi::LinkerInterfaceFile::isSupported(path, fileContent, fileLength))
268 return Parser<x86>::parse(path, fileContent, fileLength, modTime, ordinal, opts, indirectDylib);
269 #endif
270 #if SUPPORT_ARCH_arm_any
271 case CPU_TYPE_ARM:
272 if (tapi::LinkerInterfaceFile::isSupported(path, fileContent, fileLength))
273 return Parser<arm>::parse(path, fileContent, fileLength, modTime, ordinal, opts, indirectDylib);
274 #endif
275 #if SUPPORT_ARCH_arm64
276 case CPU_TYPE_ARM64:
277 if (tapi::LinkerInterfaceFile::isSupported(path, fileContent, fileLength))
278 return Parser<arm64>::parse(path, fileContent, fileLength, modTime, ordinal, opts, indirectDylib);
279 #endif
281 return nullptr;
285 } // namespace dylib
286 } // namespace textstub