]> git.saurik.com Git - apple/ld64.git/blob - src/ld/passes/stubs/stub_x86_64.hpp
ld64-242.tar.gz
[apple/ld64.git] / src / ld / passes / stubs / stub_x86_64.hpp
1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
2 *
3 * Copyright (c) 2009-2012 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 // already in ld::passes::stubs namespace
27 namespace x86_64 {
28
29
30
31 class FastBindingPointerAtom : public ld::Atom {
32 public:
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); }
40
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]; }
49
50 private:
51 mutable ld::Fixup _fixup;
52
53 static ld::Section _s_section;
54 };
55
56 ld::Section FastBindingPointerAtom::_s_section("__DATA", "__nl_symbol_ptr", ld::Section::typeNonLazyPointer);
57
58
59 class ImageCachePointerAtom : public ld::Atom {
60 public:
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); }
65
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) { }
72
73 private:
74
75 static ld::Section _s_section;
76 };
77
78 ld::Section ImageCachePointerAtom::_s_section("__DATA", "__nl_symbol_ptr", ld::Section::typeNonLazyPointer);
79
80
81
82
83
84 //
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.
88 //
89 class StubHelperHelperAtom : public ld::Atom {
90 public:
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); }
98
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
105 buffer[1] = 0x8D;
106 buffer[2] = 0x1D;
107 buffer[3] = 0x00;
108 buffer[4] = 0x00;
109 buffer[5] = 0x00;
110 buffer[6] = 0x00;
111 buffer[7] = 0x41; // pushq %r11
112 buffer[8] = 0x53;
113 buffer[9] = 0xFF; // jmp *_fast_lazy_bind(%rip)
114 buffer[10] = 0x25;
115 buffer[11] = 0x00;
116 buffer[12] = 0x00;
117 buffer[13] = 0x00;
118 buffer[14] = 0x00;
119 buffer[15] = 0x90; // nop
120 }
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]; }
124
125 private:
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;
130 }
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;
135 }
136
137 mutable ld::Fixup _fixup1;
138 ld::Fixup _fixup2;
139
140 static ld::Section _s_section;
141 };
142
143 ld::Section StubHelperHelperAtom::_s_section("__TEXT", "__stub_helper", ld::Section::typeStubHelper);
144
145
146
147 class StubHelperAtom : public ld::Atom {
148 public:
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)),
154 _stubTo(stubTo),
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)) { }
158
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
165 buffer[1] = 0x00;
166 buffer[2] = 0x00;
167 buffer[3] = 0x00;
168 buffer[4] = 0x00;
169 buffer[5] = 0xE9; // jmp helperhelper
170 buffer[6] = 0x00;
171 buffer[7] = 0x00;
172 buffer[8] = 0x00;
173 buffer[9] = 0x00;
174 }
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]; }
178
179 private:
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;
184 }
185
186 const ld::Atom& _stubTo;
187 mutable ld::Fixup _fixup1;
188 ld::Fixup _fixup2;
189 ld::Fixup _fixup3;
190
191 static ld::Section _s_section;
192 };
193
194 ld::Section StubHelperAtom::_s_section("__TEXT", "__stub_helper", ld::Section::typeStubHelper);
195
196
197 class ResolverHelperAtom : public ld::Atom {
198 public:
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)),
204 _stubTo(stubTo),
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) { }
208
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
220 buffer[ 6] = 0x50;
221 buffer[ 7] = 0x41; // push %r9
222 buffer[ 8] = 0x51;
223 buffer[ 9] = 0xE8; // call foo
224 buffer[10] = 0x00;
225 buffer[11] = 0x00;
226 buffer[12] = 0x00;
227 buffer[13] = 0x00;
228 buffer[14] = 0x48; // movq %rax,foo$lazy_pointer(%rip)
229 buffer[15] = 0x89;
230 buffer[16] = 0x05;
231 buffer[17] = 0x00;
232 buffer[18] = 0x00;
233 buffer[19] = 0x00;
234 buffer[20] = 0x00;
235 buffer[21] = 0x41; // pop %r9
236 buffer[22] = 0x59;
237 buffer[23] = 0x41; // pop %r8
238 buffer[24] = 0x58;
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)
245 buffer[31] = 0x25;
246 buffer[32] = 0x00;
247 buffer[33] = 0x00;
248 buffer[34] = 0x00;
249 buffer[35] = 0x00;
250 }
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]; }
254
255 private:
256
257 const ld::Atom& _stubTo;
258 mutable ld::Fixup _fixup1;
259 ld::Fixup _fixup2;
260 ld::Fixup _fixup3;
261
262 static ld::Section _s_section;
263 };
264
265 ld::Section ResolverHelperAtom::_s_section("__TEXT", "__stub_helper", ld::Section::typeStubHelper);
266
267
268
269 class LazyPointerAtom : public ld::Atom {
270 public:
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)),
276 _stubTo(stubTo),
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);
288 }
289
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]; }
298
299 private:
300 const ld::Atom& _stubTo;
301 StubHelperAtom _helper;
302 ResolverHelperAtom _resolverHelper;
303 mutable ld::Fixup _fixup1;
304 ld::Fixup _fixup2;
305
306 static ld::Section _s_section;
307 };
308
309 ld::Section LazyPointerAtom::_s_section("__DATA", "__la_symbol_ptr", ld::Section::typeLazyPointer);
310
311
312 class StubAtom : public ld::Atom {
313 public:
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)),
319 _stubTo(stubTo),
320 _lazyPointer(pass, stubTo, stubToGlobalWeakDef, stubToResolver, weakImport),
321 _fixup(2, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressX86PCRel32, &_lazyPointer) { pass.addAtom(*this); }
322
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)
329 buffer[1] = 0x25;
330 buffer[2] = 0x00;
331 buffer[3] = 0x00;
332 buffer[4] = 0x00;
333 buffer[5] = 0x00;
334 }
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]; }
338
339 private:
340 const ld::Atom& _stubTo;
341 LazyPointerAtom _lazyPointer;
342 mutable ld::Fixup _fixup;
343
344 static ld::Section _s_section;
345 };
346
347 ld::Section StubAtom::_s_section("__TEXT", "__stubs", ld::Section::typeStub);
348
349
350
351
352 class NonLazyPointerAtom : public ld::Atom {
353 public:
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)),
358 _stubTo(stubTo),
359 _fixup1(0, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressLittleEndian64, &stubTo) {
360 pass.addAtom(*this);
361 }
362
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]; }
371
372 private:
373 const ld::Atom& _stubTo;
374 ld::Fixup _fixup1;
375
376 static ld::Section _s_section;
377 };
378
379 ld::Section NonLazyPointerAtom::_s_section("__DATA", "__got", ld::Section::typeNonLazyPointer);
380
381
382
383 class KextStubAtom : public ld::Atom {
384 public:
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)),
389 _stubTo(stubTo),
390 _nonLazyPointer(pass, stubTo),
391 _fixup(2, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressX86PCRel32, &_nonLazyPointer) { pass.addAtom(*this); }
392
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)
399 buffer[1] = 0x25;
400 buffer[2] = 0x00;
401 buffer[3] = 0x00;
402 buffer[4] = 0x00;
403 buffer[5] = 0x00;
404 }
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]; }
408
409 private:
410 const ld::Atom& _stubTo;
411 NonLazyPointerAtom _nonLazyPointer;
412 mutable ld::Fixup _fixup;
413
414 static ld::Section _s_section;
415 };
416
417 ld::Section KextStubAtom::_s_section("__TEXT", "__stubs", ld::Section::typeStub);
418
419
420 } // namespace x86_64
421