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