]> git.saurik.com Git - apple/ld64.git/blame - src/ld/passes/stubs/stubs.cpp
ld64-128.2.tar.gz
[apple/ld64.git] / src / ld / passes / stubs / stubs.cpp
CommitLineData
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
43namespace ld {
44namespace passes {
45namespace stubs {
46
47class Pass {
48public:
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
59private:
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
95Pass::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
113const 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
159ld::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
211void 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
223void 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
379void 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