1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
3 * Copyright (c) 2009-2012 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
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 // already in ld::passes::stubs namespace
31 class FastBindingPointerAtom : public ld::Atom {
33 FastBindingPointerAtom(ld::passes::stubs::Pass& pass)
34 : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
35 ld::Atom::scopeLinkageUnit, ld::Atom::typeNonLazyPointer,
36 symbolTableNotIn, false, false, false, ld::Atom::Alignment(3)),
37 _fixup(0, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressLittleEndian64,
38 pass.internal()->compressedFastBinderProxy)
39 { pass.addAtom(*this); }
41 virtual const ld::File* file() const { return NULL; }
42 virtual const char* name() const { return "fast binder pointer"; }
43 virtual uint64_t size() const { return 8; }
44 virtual uint64_t objectAddress() const { return 0; }
45 virtual void copyRawContent(uint8_t buffer[]) const { }
46 virtual void setScope(Scope) { }
47 virtual ld::Fixup::iterator fixupsBegin() const { return &_fixup; }
48 virtual ld::Fixup::iterator fixupsEnd() const { return &((ld::Fixup*)&_fixup)[1]; }
51 mutable ld::Fixup _fixup;
53 static ld::Section _s_section;
56 ld::Section FastBindingPointerAtom::_s_section("__DATA", "__nl_symbol_ptr", ld::Section::typeNonLazyPointer);
59 class ImageCachePointerAtom : public ld::Atom {
61 ImageCachePointerAtom(ld::passes::stubs::Pass& pass)
62 : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
63 ld::Atom::scopeLinkageUnit, ld::Atom::typeNonLazyPointer,
64 symbolTableNotIn, false, false, false, ld::Atom::Alignment(3)) { pass.addAtom(*this); }
66 virtual const ld::File* file() const { return NULL; }
67 virtual const char* name() const { return "image cache pointer"; }
68 virtual uint64_t size() const { return 8; }
69 virtual uint64_t objectAddress() const { return 0; }
70 virtual void copyRawContent(uint8_t buffer[]) const { }
71 virtual void setScope(Scope) { }
75 static ld::Section _s_section;
78 ld::Section ImageCachePointerAtom::_s_section("__DATA", "__nl_symbol_ptr", ld::Section::typeNonLazyPointer);
85 // The stub-helper-helper is the common code factored out of each helper function.
86 // It is in the same section as the stub-helpers.
87 // Similar to the PLT0 entry in ELF.
89 class StubHelperHelperAtom : public ld::Atom {
91 StubHelperHelperAtom(ld::passes::stubs::Pass& pass)
92 : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
93 ld::Atom::scopeLinkageUnit, ld::Atom::typeStubHelper,
94 symbolTableNotIn, false, false, false, ld::Atom::Alignment(2)),
95 _fixup1(3, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressX86PCRel32, compressedImageCache(pass)),
96 _fixup2(11, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressX86PCRel32, compressedFastBinder(pass))
97 { pass.addAtom(*this); }
99 virtual ld::File* file() const { return NULL; }
100 virtual const char* name() const { return "helper helper"; }
101 virtual uint64_t size() const { return 16; }
102 virtual uint64_t objectAddress() const { return 0; }
103 virtual void copyRawContent(uint8_t buffer[]) const {
104 buffer[0] = 0x4C; // leaq dyld_mageLoaderCache(%rip),%r11
111 buffer[7] = 0x41; // pushq %r11
113 buffer[9] = 0xFF; // jmp *_fast_lazy_bind(%rip)
119 buffer[15] = 0x90; // nop
121 virtual void setScope(Scope) { }
122 virtual ld::Fixup::iterator fixupsBegin() const { return &_fixup1; }
123 virtual ld::Fixup::iterator fixupsEnd() const { return &((ld::Fixup*)&_fixup2)[1]; }
126 static ld::Atom* compressedImageCache(ld::passes::stubs::Pass& pass) {
127 if ( pass.compressedImageCache == NULL )
128 pass.compressedImageCache = new ImageCachePointerAtom(pass);
129 return pass.compressedImageCache;
131 static ld::Atom* compressedFastBinder(ld::passes::stubs::Pass& pass) {
132 if ( pass.compressedFastBinderPointer == NULL )
133 pass.compressedFastBinderPointer = new FastBindingPointerAtom(pass);
134 return pass.compressedFastBinderPointer;
137 mutable ld::Fixup _fixup1;
140 static ld::Section _s_section;
143 ld::Section StubHelperHelperAtom::_s_section("__TEXT", "__stub_helper", ld::Section::typeStubHelper);
147 class StubHelperAtom : public ld::Atom {
149 StubHelperAtom(ld::passes::stubs::Pass& pass, const ld::Atom* lazyPointer,
150 const ld::Atom& stubTo)
151 : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
152 ld::Atom::scopeLinkageUnit, ld::Atom::typeStubHelper,
153 symbolTableNotIn, false, false, false, ld::Atom::Alignment(1)),
155 _fixup1(1, ld::Fixup::k1of2, ld::Fixup::kindSetLazyOffset, lazyPointer),
156 _fixup2(1, ld::Fixup::k2of2, ld::Fixup::kindStoreLittleEndian32),
157 _fixup3(6, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressX86BranchPCRel32, helperHelper(pass)) { }
159 virtual const ld::File* file() const { return _stubTo.file(); }
160 virtual const char* name() const { return _stubTo.name(); }
161 virtual uint64_t size() const { return 10; }
162 virtual uint64_t objectAddress() const { return 0; }
163 virtual void copyRawContent(uint8_t buffer[]) const {
164 buffer[0] = 0x68; // pushq $lazy-info-offset
169 buffer[5] = 0xE9; // jmp helperhelper
175 virtual void setScope(Scope) { }
176 virtual ld::Fixup::iterator fixupsBegin() const { return &_fixup1; }
177 virtual ld::Fixup::iterator fixupsEnd() const { return &((ld::Fixup*)&_fixup3)[1]; }
180 static ld::Atom* helperHelper(ld::passes::stubs::Pass& pass) {
181 if ( pass.compressedHelperHelper == NULL )
182 pass.compressedHelperHelper = new StubHelperHelperAtom(pass);
183 return pass.compressedHelperHelper;
186 const ld::Atom& _stubTo;
187 mutable ld::Fixup _fixup1;
191 static ld::Section _s_section;
194 ld::Section StubHelperAtom::_s_section("__TEXT", "__stub_helper", ld::Section::typeStubHelper);
197 class ResolverHelperAtom : public ld::Atom {
199 ResolverHelperAtom(ld::passes::stubs::Pass& pass, const ld::Atom* lazyPointer,
200 const ld::Atom& stubTo)
201 : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
202 ld::Atom::scopeLinkageUnit, ld::Atom::typeStubHelper,
203 symbolTableNotIn, false, false, false, ld::Atom::Alignment(1)),
205 _fixup1(10, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressX86BranchPCRel32, &stubTo),
206 _fixup2(17, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressX86PCRel32, lazyPointer),
207 _fixup3(32, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressX86PCRel32, lazyPointer) { }
209 virtual const ld::File* file() const { return _stubTo.file(); }
210 virtual const char* name() const { return _stubTo.name(); }
211 virtual uint64_t size() const { return 36; }
212 virtual uint64_t objectAddress() const { return 0; }
213 virtual void copyRawContent(uint8_t buffer[]) const {
214 buffer[ 0] = 0x50; // push %rax
215 buffer[ 1] = 0x57; // push %rdi
216 buffer[ 2] = 0x56; // push %rsi
217 buffer[ 3] = 0x52; // push %rdx
218 buffer[ 4] = 0x51; // push %rcx
219 buffer[ 5] = 0x41; // push %r8
221 buffer[ 7] = 0x41; // push %r9
223 buffer[ 9] = 0xE8; // call foo
228 buffer[14] = 0x48; // movq %rax,foo$lazy_pointer(%rip)
235 buffer[21] = 0x41; // pop %r9
237 buffer[23] = 0x41; // pop %r8
239 buffer[25] = 0x59; // pop %rcx
240 buffer[26] = 0x5A; // pop %rdx
241 buffer[27] = 0x5E; // pop %rsi
242 buffer[28] = 0x5F; // pop %rdi
243 buffer[29] = 0x58; // pop %rax
244 buffer[30] = 0xFF; // jmp *foo$lazy_ptr(%rip)
251 virtual void setScope(Scope) { }
252 virtual ld::Fixup::iterator fixupsBegin() const { return &_fixup1; }
253 virtual ld::Fixup::iterator fixupsEnd() const { return &((ld::Fixup*)&_fixup3)[1]; }
257 const ld::Atom& _stubTo;
258 mutable ld::Fixup _fixup1;
262 static ld::Section _s_section;
265 ld::Section ResolverHelperAtom::_s_section("__TEXT", "__stub_helper", ld::Section::typeStubHelper);
269 class LazyPointerAtom : public ld::Atom {
271 LazyPointerAtom(ld::passes::stubs::Pass& pass, const ld::Atom& stubTo,
272 bool stubToGlobalWeakDef, bool stubToResolver, bool weakImport)
273 : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
274 ld::Atom::scopeTranslationUnit, ld::Atom::typeLazyPointer,
275 symbolTableNotIn, false, false, false, ld::Atom::Alignment(3)),
277 _helper(pass, this, stubTo),
278 _resolverHelper(pass, this, stubTo),
279 _fixup1(0, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressLittleEndian64,
280 stubToResolver ? &_resolverHelper :
281 (stubToGlobalWeakDef ? &stubTo : &_helper)),
282 _fixup2(0, ld::Fixup::k1of1, ld::Fixup::kindLazyTarget, &stubTo) {
283 _fixup2.weakImport = weakImport; pass.addAtom(*this);
284 if ( stubToResolver )
285 pass.addAtom(_resolverHelper);
286 else if ( !stubToGlobalWeakDef )
287 pass.addAtom(_helper);
290 virtual const ld::File* file() const { return _stubTo.file(); }
291 virtual const char* name() const { return _stubTo.name(); }
292 virtual uint64_t size() const { return 8; }
293 virtual uint64_t objectAddress() const { return 0; }
294 virtual void copyRawContent(uint8_t buffer[]) const { }
295 virtual void setScope(Scope) { }
296 virtual ld::Fixup::iterator fixupsBegin() const { return &_fixup1; }
297 virtual ld::Fixup::iterator fixupsEnd() const { return &((ld::Fixup*)&_fixup2)[1]; }
300 const ld::Atom& _stubTo;
301 StubHelperAtom _helper;
302 ResolverHelperAtom _resolverHelper;
303 mutable ld::Fixup _fixup1;
306 static ld::Section _s_section;
309 ld::Section LazyPointerAtom::_s_section("__DATA", "__la_symbol_ptr", ld::Section::typeLazyPointer);
312 class StubAtom : public ld::Atom {
314 StubAtom(ld::passes::stubs::Pass& pass, const ld::Atom& stubTo,
315 bool stubToGlobalWeakDef, bool stubToResolver, bool weakImport)
316 : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
317 ld::Atom::scopeLinkageUnit, ld::Atom::typeStub,
318 symbolTableNotIn, false, false, false, ld::Atom::Alignment(1)),
320 _lazyPointer(pass, stubTo, stubToGlobalWeakDef, stubToResolver, weakImport),
321 _fixup(2, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressX86PCRel32, &_lazyPointer) { pass.addAtom(*this); }
323 virtual const ld::File* file() const { return _stubTo.file(); }
324 virtual const char* name() const { return _stubTo.name(); }
325 virtual uint64_t size() const { return 6; }
326 virtual uint64_t objectAddress() const { return 0; }
327 virtual void copyRawContent(uint8_t buffer[]) const {
328 buffer[0] = 0xFF; // jmp *foo$lazy_pointer(%rip)
335 virtual void setScope(Scope) { }
336 virtual ld::Fixup::iterator fixupsBegin() const { return &_fixup; }
337 virtual ld::Fixup::iterator fixupsEnd() const { return &((ld::Fixup*)&_fixup)[1]; }
340 const ld::Atom& _stubTo;
341 LazyPointerAtom _lazyPointer;
342 mutable ld::Fixup _fixup;
344 static ld::Section _s_section;
347 ld::Section StubAtom::_s_section("__TEXT", "__stubs", ld::Section::typeStub);
352 class NonLazyPointerAtom : public ld::Atom {
354 NonLazyPointerAtom(ld::passes::stubs::Pass& pass, const ld::Atom& stubTo)
355 : ld::Atom(_s_section, ld::Atom::definitionRegular,
356 ld::Atom::combineNever, ld::Atom::scopeLinkageUnit, ld::Atom::typeNonLazyPointer,
357 symbolTableNotIn, false, false, false, ld::Atom::Alignment(3)),
359 _fixup1(0, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressLittleEndian64, &stubTo) {
363 virtual const ld::File* file() const { return _stubTo.file(); }
364 virtual const char* name() const { return _stubTo.name(); }
365 virtual uint64_t size() const { return 8; }
366 virtual uint64_t objectAddress() const { return 0; }
367 virtual void copyRawContent(uint8_t buffer[]) const { }
368 virtual void setScope(Scope) { }
369 virtual ld::Fixup::iterator fixupsBegin() const { return (ld::Fixup*)&_fixup1; }
370 virtual ld::Fixup::iterator fixupsEnd() const { return &((ld::Fixup*)&_fixup1)[1]; }
373 const ld::Atom& _stubTo;
376 static ld::Section _s_section;
379 ld::Section NonLazyPointerAtom::_s_section("__DATA", "__got", ld::Section::typeNonLazyPointer);
383 class KextStubAtom : public ld::Atom {
385 KextStubAtom(ld::passes::stubs::Pass& pass, const ld::Atom& stubTo)
386 : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
387 ld::Atom::scopeLinkageUnit, ld::Atom::typeStub,
388 symbolTableNotIn, false, false, false, ld::Atom::Alignment(1)),
390 _nonLazyPointer(pass, stubTo),
391 _fixup(2, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressX86PCRel32, &_nonLazyPointer) { pass.addAtom(*this); }
393 virtual const ld::File* file() const { return _stubTo.file(); }
394 virtual const char* name() const { return _stubTo.name(); }
395 virtual uint64_t size() const { return 6; }
396 virtual uint64_t objectAddress() const { return 0; }
397 virtual void copyRawContent(uint8_t buffer[]) const {
398 buffer[0] = 0xFF; // jmp *foo$non_lazy_pointer(%rip)
405 virtual void setScope(Scope) { }
406 virtual ld::Fixup::iterator fixupsBegin() const { return &_fixup; }
407 virtual ld::Fixup::iterator fixupsEnd() const { return &((ld::Fixup*)&_fixup)[1]; }
410 const ld::Atom& _stubTo;
411 NonLazyPointerAtom _nonLazyPointer;
412 mutable ld::Fixup _fixup;
414 static ld::Section _s_section;
417 ld::Section KextStubAtom::_s_section("__TEXT", "__stubs", ld::Section::typeStub);
420 } // namespace x86_64