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