]> git.saurik.com Git - apple/ld64.git/blob - src/ld/passes/stubs/stubs.cpp
ld64-133.3.tar.gz
[apple/ld64.git] / src / ld / passes / stubs / stubs.cpp
1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
2 *
3 * Copyright (c) 2009-2010 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
27 #include <stdint.h>
28 #include <math.h>
29 #include <unistd.h>
30 #include <assert.h>
31 #include <libkern/OSByteOrder.h>
32
33 #include <vector>
34 #include <set>
35 #include <map>
36
37 #include "Options.h"
38 #include "ld.hpp"
39 #include "MachOFileAbstraction.hpp"
40
41 #include "make_stubs.h"
42
43
44 namespace ld {
45 namespace passes {
46 namespace stubs {
47
48 class Pass {
49 public:
50 Pass(const Options& opts);
51 void process(ld::Internal& internal);
52 void addAtom(const ld::Atom& atom) { _internal->addAtom(atom); }
53 bool usingCompressedLINKEDIT() const { return _compressedLINKEDIT; }
54 ld::Internal* internal() { return _internal; }
55
56 Atom* compressedHelperHelper;
57 Atom* compressedImageCache;
58 Atom* compressedFastBinderPointer;
59
60 private:
61
62 struct AtomByNameSorter
63 {
64 bool operator()(const ld::Atom* left, const ld::Atom* right)
65 {
66 return (strcmp(left->name(), right->name()) < 0);
67 }
68 };
69
70 const ld::Atom* stubableFixup(const ld::Fixup* fixup, ld::Internal&);
71 ld::Atom* makeStub(const ld::Atom& target, bool weakImport);
72 void verifyNoResolverFunctions(ld::Internal& state);
73
74 const Options& _options;
75 const cpu_type_t _architecture;
76 const bool _lazyDylibsInUuse;
77 const bool _compressedLINKEDIT;
78 const bool _prebind;
79 const bool _mightBeInSharedRegion;
80 const bool _pic;
81 const bool _flatNamespace;
82 ld::Internal* _internal;
83 uint32_t _stubCount;
84 bool _largeText;
85 };
86
87 #include "stub_x86_64.hpp"
88 #include "stub_x86_64_classic.hpp"
89 #include "stub_x86.hpp"
90 #include "stub_x86_classic.hpp"
91 #include "stub_arm.hpp"
92 #include "stub_arm_classic.hpp"
93
94
95
96 Pass::Pass(const Options& opts)
97 : compressedHelperHelper(NULL),
98 compressedImageCache(NULL),
99 compressedFastBinderPointer(NULL),
100 _options(opts),
101 _architecture(opts.architecture()),
102 _lazyDylibsInUuse(opts.usingLazyDylibLinking()),
103 _compressedLINKEDIT(opts.makeCompressedDyldInfo()),
104 _prebind(opts.prebind()),
105 _mightBeInSharedRegion(opts.sharedRegionEligible()),
106 _pic(opts.outputSlidable()),
107 _flatNamespace(opts.nameSpace() != Options::kTwoLevelNameSpace),
108 _internal(NULL), _stubCount(0), _largeText(false)
109 {
110
111 }
112
113
114 const ld::Atom* Pass::stubableFixup(const ld::Fixup* fixup, ld::Internal& state)
115 {
116 if ( fixup->binding == ld::Fixup::bindingsIndirectlyBound ) {
117 const ld::Atom* target = state.indirectBindingTable[fixup->u.bindingIndex];
118 switch ( fixup->kind ) {
119 case ld::Fixup::kindStoreTargetAddressX86BranchPCRel32:
120 case ld::Fixup::kindStoreTargetAddressARMBranch24:
121 case ld::Fixup::kindStoreTargetAddressThumbBranch22:
122 assert(target != NULL);
123 // create stub if target is in a dylib
124 if ( target->definition() == ld::Atom::definitionProxy )
125 return target;
126 // use stub if target is a resolver function in same linkage unit
127 if ( target->contentType() == ld::Atom::typeResolver )
128 return target;
129 if ( target->scope() == ld::Atom::scopeGlobal ) {
130 // create stub if target is global weak definition in symbol table
131 if ( (target->definition() == ld::Atom::definitionRegular)
132 && (target->combine() == ld::Atom::combineByName)
133 && ((target->symbolTableInclusion() == ld::Atom::symbolTableIn)
134 || (target->symbolTableInclusion() == ld::Atom::symbolTableInAndNeverStrip)) )
135 return target;
136 // create stub if target is interposable
137 if ( _options.interposable(target->name()) )
138 return target;
139 if ( _flatNamespace ) {
140 // flat namespace does not indirect calls within main exectuables
141 if ( _options.outputKind() == Options::kDynamicExecutable )
142 return NULL;
143 // create stub if target is global and building -flat dylib or bundle
144 return target;
145 }
146 }
147 break;
148 default:
149 if ( target->contentType() == ld::Atom::typeResolver ) {
150 // any pointer to a resolver needs to change to pointer to stub
151 return target;
152 }
153 break;
154 }
155 }
156 return NULL;
157 }
158
159
160
161 ld::Atom* Pass::makeStub(const ld::Atom& target, bool weakImport)
162 {
163 //fprintf(stderr, "makeStub(target=%p %s in sect %s)\n", &target, target.name(), target.section().sectionName());
164 bool stubToGlobalWeakDef = ( (target.scope() == ld::Atom::scopeGlobal)
165 && (target.definition() == ld::Atom::definitionRegular)
166 && (target.combine() == ld::Atom::combineByName) );
167
168 bool forLazyDylib = false;
169 const ld::dylib::File* dylib = dynamic_cast<const ld::dylib::File*>(target.file());
170 if ( (dylib != NULL) && dylib->willBeLazyLoadedDylib() )
171 forLazyDylib = true;
172 bool stubToResolver = (target.contentType() == ld::Atom::typeResolver);
173
174 if ( usingCompressedLINKEDIT() && !forLazyDylib ) {
175 if ( _internal->compressedFastBinderProxy == NULL )
176 throwf("symbol dyld_stub_binder not found (normally in libSystem.dylib). Needed to perform lazy binding to function %s", target.name());
177 }
178
179 switch ( _architecture ) {
180 #if SUPPORT_ARCH_i386
181 case CPU_TYPE_I386:
182 if ( usingCompressedLINKEDIT() && !forLazyDylib )
183 return new ld::passes::stubs::x86::StubAtom(*this, target, stubToGlobalWeakDef, stubToResolver, weakImport);
184 else
185 return new ld::passes::stubs::x86::classic::StubAtom(*this, target, forLazyDylib, weakImport);
186 break;
187 #endif
188 #if SUPPORT_ARCH_x86_64
189 case CPU_TYPE_X86_64:
190 if ( (_options.outputKind() == Options::kKextBundle) && _options.kextsUseStubs() )
191 return new ld::passes::stubs::x86_64::KextStubAtom(*this, target);
192 else if ( usingCompressedLINKEDIT() && !forLazyDylib )
193 return new ld::passes::stubs::x86_64::StubAtom(*this, target, stubToGlobalWeakDef, stubToResolver, weakImport);
194 else
195 return new ld::passes::stubs::x86_64::classic::StubAtom(*this, target, forLazyDylib, weakImport);
196 break;
197 #endif
198 #if SUPPORT_ARCH_arm_any
199 case CPU_TYPE_ARM:
200 if ( (_options.outputKind() == Options::kKextBundle) && _options.kextsUseStubs() ) {
201 // if text relocs are not allows in kext bundles, then linker must create a stub
202 return new ld::passes::stubs::arm::StubPICKextAtom(*this, target);
203 }
204 else if ( usingCompressedLINKEDIT() && !forLazyDylib ) {
205 if ( (_stubCount < 900) && !_mightBeInSharedRegion && !_largeText )
206 return new ld::passes::stubs::arm::StubCloseAtom(*this, target, stubToGlobalWeakDef, stubToResolver, weakImport);
207 else if ( _pic )
208 return new ld::passes::stubs::arm::StubPICAtom(*this, target, stubToGlobalWeakDef, stubToResolver, weakImport);
209 else
210 return new ld::passes::stubs::arm::StubNoPICAtom(*this, target, stubToGlobalWeakDef, stubToResolver, weakImport);
211 }
212 else {
213 if ( _pic )
214 return new ld::passes::stubs::arm::classic::StubPICAtom(*this, target, forLazyDylib, weakImport);
215 else
216 return new ld::passes::stubs::arm::classic::StubNoPICAtom(*this, target, forLazyDylib, weakImport);
217 }
218 break;
219 #endif
220 }
221 throw "unsupported arch for stub";
222 }
223
224
225 void Pass::verifyNoResolverFunctions(ld::Internal& state)
226 {
227 for (std::vector<ld::Internal::FinalSection*>::iterator sit=state.sections.begin(); sit != state.sections.end(); ++sit) {
228 ld::Internal::FinalSection* sect = *sit;
229 for (std::vector<const ld::Atom*>::iterator ait=sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
230 const ld::Atom* atom = *ait;
231 if ( atom->contentType() == ld::Atom::typeResolver )
232 throwf("resolver function '%s' not supported in type of output", atom->name());
233 }
234 }
235 }
236
237 void Pass::process(ld::Internal& state)
238 {
239 switch ( _options.outputKind() ) {
240 case Options::kObjectFile:
241 // these kinds don't use stubs and can have resolver functions
242 return;
243 case Options::kStaticExecutable:
244 case Options::kPreload:
245 case Options::kDyld:
246 // these kinds don't use stubs and cannot have resolver functions
247 verifyNoResolverFunctions(state);
248 return;
249 case Options::kDynamicLibrary:
250 // uses stubs and can have resolver functions
251 break;
252 case Options::kKextBundle:
253 verifyNoResolverFunctions(state);
254 // if kext don't use stubs, don't do this pass
255 if ( !_options.kextsUseStubs() )
256 return;
257 break;
258 case Options::kDynamicExecutable:
259 case Options::kDynamicBundle:
260 // these kinds do use stubs and cannot have resolver functions
261 verifyNoResolverFunctions(state);
262 break;
263 }
264
265 // walk all atoms and fixups looking for stubable references
266 // don't create stubs inline because that could invalidate the sections iterator
267 std::vector<const ld::Atom*> atomsCallingStubs;
268 std::map<const ld::Atom*,ld::Atom*> stubFor;
269 std::map<const ld::Atom*,bool> weakImportMap;
270 atomsCallingStubs.reserve(128);
271 uint64_t codeSize = 0;
272 for (std::vector<ld::Internal::FinalSection*>::iterator sit=state.sections.begin(); sit != state.sections.end(); ++sit) {
273 ld::Internal::FinalSection* sect = *sit;
274 for (std::vector<const ld::Atom*>::iterator ait=sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
275 const ld::Atom* atom = *ait;
276 codeSize += atom->size();
277 bool atomNeedsStub = false;
278 for (ld::Fixup::iterator fit = atom->fixupsBegin(), end=atom->fixupsEnd(); fit != end; ++fit) {
279 const ld::Atom* stubableTargetOfFixup = stubableFixup(fit, state);
280 if ( stubableTargetOfFixup != NULL ) {
281 if ( !atomNeedsStub ) {
282 atomsCallingStubs.push_back(atom);
283 atomNeedsStub = true;
284 }
285 stubFor[stubableTargetOfFixup] = NULL;
286 // record weak_import attribute
287 std::map<const ld::Atom*,bool>::iterator pos = weakImportMap.find(stubableTargetOfFixup);
288 if ( pos == weakImportMap.end() ) {
289 // target not in weakImportMap, so add
290 weakImportMap[stubableTargetOfFixup] = fit->weakImport;
291 }
292 else {
293 // target in weakImportMap, check for weakness mismatch
294 if ( pos->second != fit->weakImport ) {
295 // found mismatch
296 switch ( _options.weakReferenceMismatchTreatment() ) {
297 case Options::kWeakReferenceMismatchError:
298 throwf("mismatching weak references for symbol: %s", stubableTargetOfFixup->name());
299 case Options::kWeakReferenceMismatchWeak:
300 pos->second = true;
301 break;
302 case Options::kWeakReferenceMismatchNonWeak:
303 pos->second = false;
304 break;
305 }
306 }
307 }
308 }
309 }
310 // all resolver functions must have a corresponding stub
311 if ( atom->contentType() == ld::Atom::typeResolver ) {
312 if ( _options.outputKind() != Options::kDynamicLibrary )
313 throwf("resolver functions (%s) can only be used in dylibs", atom->name());
314 if ( !_options.makeCompressedDyldInfo() ) {
315 if ( _options.architecture() == CPU_TYPE_ARM )
316 throwf("resolver functions (%s) can only be used when targeting iOS 4.2 or later", atom->name());
317 else
318 throwf("resolver functions (%s) can only be used when targeting Mac OS X 10.6 or later", atom->name());
319 }
320 stubFor[atom] = NULL;
321 }
322 }
323 }
324
325 const bool needStubForMain = _options.needsEntryPointLoadCommand()
326 && (state.entryPoint != NULL)
327 && (state.entryPoint->definition() == ld::Atom::definitionProxy);
328 if ( needStubForMain ) {
329 // _main not found in any .o files. Currently have proxy to dylib
330 // Add to map, so that a stub will be made
331 stubFor[state.entryPoint] = NULL;
332 }
333
334 // short circuit if no stubs needed
335 _internal = &state;
336 _stubCount = stubFor.size();
337 if ( _stubCount == 0 )
338 return;
339
340 // <rdar://problem/8553283> lazily check for helper
341 if ( !_options.makeCompressedDyldInfo() && (state.classicBindingHelper == NULL) && (_options.outputKind() != Options::kKextBundle) )
342 throw "symbol dyld_stub_binding_helper not found, normally in crt1.o/dylib1.o/bundle1.o";
343
344 // disable arm close stubs in some cases
345 if ( _architecture == CPU_TYPE_ARM ) {
346 if ( codeSize > 4*1024*1024 )
347 _largeText = true;
348 else {
349 for (std::vector<ld::Internal::FinalSection*>::iterator sit=state.sections.begin(); sit != state.sections.end(); ++sit) {
350 ld::Internal::FinalSection* sect = *sit;
351 if ( sect->type() == ld::Section::typeMachHeader )
352 continue;
353 if ( strcmp(sect->segmentName(), "__TEXT") == 0) {
354 for (std::vector<const ld::Atom*>::iterator ait=sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
355 const ld::Atom* atom = *ait;
356 if ( atom->alignment().powerOf2 > 10 ) {
357 // overaligned section means might not be able to keep closestubs sect pushed to end of __TEXT
358 //warning("alignment 1<<%d in atom %s in section %s disables close stubs optimization",
359 // atom->alignment().powerOf2, atom->name(), sect->segmentName());
360 _largeText = true;
361 break;
362 }
363 }
364 }
365 }
366 }
367 }
368
369 // make stub atoms
370 for (std::map<const ld::Atom*,ld::Atom*>::iterator it = stubFor.begin(); it != stubFor.end(); ++it) {
371 it->second = makeStub(*it->first, weakImportMap[it->first]);
372 }
373
374 // updated atoms to use stubs
375 for (std::vector<const ld::Atom*>::iterator it=atomsCallingStubs.begin(); it != atomsCallingStubs.end(); ++it) {
376 const ld::Atom* atom = *it;
377 for (ld::Fixup::iterator fit = atom->fixupsBegin(), end=atom->fixupsEnd(); fit != end; ++fit) {
378 const ld::Atom* stubableTargetOfFixup = stubableFixup(fit, state);
379 if ( stubableTargetOfFixup != NULL ) {
380 ld::Atom* stub = stubFor[stubableTargetOfFixup];
381 assert(stub != NULL && "stub not created");
382 fit->binding = ld::Fixup::bindingDirectlyBound;
383 fit->u.target = stub;
384 }
385 }
386 }
387
388 // switch entry point from proxy to stub
389 if ( needStubForMain ) {
390 const ld::Atom* mainStub = stubFor[state.entryPoint];
391 assert(mainStub != NULL);
392 state.entryPoint = mainStub;
393 }
394
395 // sort new atoms so links are consistent
396 for (std::vector<ld::Internal::FinalSection*>::iterator sit=state.sections.begin(); sit != state.sections.end(); ++sit) {
397 ld::Internal::FinalSection* sect = *sit;
398 switch ( sect->type() ) {
399 case ld::Section::typeStubHelper:
400 case ld::Section::typeStub:
401 case ld::Section::typeStubClose:
402 case ld::Section::typeLazyPointer:
403 case ld::Section::typeLazyPointerClose:
404 std::sort(sect->atoms.begin(), sect->atoms.end(), AtomByNameSorter());
405 break;
406 default:
407 break;
408 }
409 }
410
411 }
412
413
414 void doPass(const Options& opts, ld::Internal& internal)
415 {
416 Pass pass(opts);
417 pass.process(internal);
418 }
419
420
421
422 } // namespace stubs
423 } // namespace passes
424 } // namespace ld
425