]> git.saurik.com Git - apple/ld64.git/blob - src/ld/passes/stubs/stub_arm64.hpp
cb1ceb33cb51d516bcb00c218df9ef82f02e2a22
[apple/ld64.git] / src / ld / passes / stubs / stub_arm64.hpp
1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
2 *
3 * Copyright (c) 2010-2013 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 arm64 {
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", "__got", 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", "__got", 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(0, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressARM64Page21, compressedImageCache(pass)),
96 _fixup2(4, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressARM64PageOff12, compressedImageCache(pass)),
97 _fixup3(12, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressARM64Page21, compressedFastBinder(pass)),
98 _fixup4(16, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressARM64PageOff12, compressedFastBinder(pass))
99 { pass.addAtom(*this); }
100
101 virtual ld::File* file() const { return NULL; }
102 virtual const char* name() const { return "helper helper"; }
103 virtual uint64_t size() const { return 24; }
104 virtual uint64_t objectAddress() const { return 0; }
105 virtual void copyRawContent(uint8_t buffer[]) const {
106 OSWriteLittleInt32(&buffer[ 0], 0, 0x90000011); // ADRP X17, dyld_mageLoaderCache@page
107 OSWriteLittleInt32(&buffer[ 4], 0, 0x91000231); // ADD X17, X17, dyld_mageLoaderCache@pageoff
108 OSWriteLittleInt32(&buffer[ 8], 0, 0xA9BF47F0); // STP X16/X17, [SP, #-16]!
109 OSWriteLittleInt32(&buffer[12], 0, 0x90000010); // ADRP X16, _fast_lazy_bind@page
110 OSWriteLittleInt32(&buffer[16], 0, 0xF9400210); // LDR X16, [X16,_fast_lazy_bind@pageoff]
111 OSWriteLittleInt32(&buffer[20], 0, 0xD61F0200); // BR X16
112 }
113 virtual void setScope(Scope) { }
114 virtual ld::Fixup::iterator fixupsBegin() const { return &_fixup1; }
115 virtual ld::Fixup::iterator fixupsEnd() const { return &((ld::Fixup*)&_fixup4)[1]; }
116
117 private:
118 static ld::Atom* compressedImageCache(ld::passes::stubs::Pass& pass) {
119 if ( pass.compressedImageCache == NULL )
120 pass.compressedImageCache = new ImageCachePointerAtom(pass);
121 return pass.compressedImageCache;
122 }
123 static ld::Atom* compressedFastBinder(ld::passes::stubs::Pass& pass) {
124 if ( pass.compressedFastBinderPointer == NULL )
125 pass.compressedFastBinderPointer = new FastBindingPointerAtom(pass);
126 return pass.compressedFastBinderPointer;
127 }
128
129 mutable ld::Fixup _fixup1;
130 ld::Fixup _fixup2;
131 ld::Fixup _fixup3;
132 ld::Fixup _fixup4;
133
134 static ld::Section _s_section;
135 };
136
137 ld::Section StubHelperHelperAtom::_s_section("__TEXT", "__stub_helper", ld::Section::typeStubHelper);
138
139
140
141 class StubHelperAtom : public ld::Atom {
142 public:
143 StubHelperAtom(ld::passes::stubs::Pass& pass, const ld::Atom* lazyPointer,
144 const ld::Atom& stubTo)
145 : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
146 ld::Atom::scopeLinkageUnit, ld::Atom::typeStubHelper,
147 symbolTableNotIn, false, false, false, ld::Atom::Alignment(1)),
148 _stubTo(stubTo),
149 _fixup1(4, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressARM64Branch26, helperHelper(pass)),
150 _fixup2(8, ld::Fixup::k1of2, ld::Fixup::kindSetLazyOffset, lazyPointer),
151 _fixup3(8, ld::Fixup::k2of2, ld::Fixup::kindStoreLittleEndian32) { }
152
153 virtual const ld::File* file() const { return _stubTo.file(); }
154 virtual const char* name() const { return _stubTo.name(); }
155 virtual uint64_t size() const { return 12; }
156 virtual uint64_t objectAddress() const { return 0; }
157 virtual void copyRawContent(uint8_t buffer[]) const {
158 OSWriteLittleInt32(&buffer[0], 0, 0x18000050); // LDR W16, L0
159 OSWriteLittleInt32(&buffer[4], 0, 0x14000000); // B helperhelper
160 OSWriteLittleInt32(&buffer[8], 0, 0x00000000); // L0: .long 0
161 }
162 virtual void setScope(Scope) { }
163 virtual ld::Fixup::iterator fixupsBegin() const { return &_fixup1; }
164 virtual ld::Fixup::iterator fixupsEnd() const { return &((ld::Fixup*)&_fixup3)[1]; }
165
166 private:
167 static ld::Atom* helperHelper(ld::passes::stubs::Pass& pass) {
168 if ( pass.compressedHelperHelper == NULL )
169 pass.compressedHelperHelper = new StubHelperHelperAtom(pass);
170 return pass.compressedHelperHelper;
171 }
172
173 const ld::Atom& _stubTo;
174 mutable ld::Fixup _fixup1;
175 ld::Fixup _fixup2;
176 ld::Fixup _fixup3;
177
178 static ld::Section _s_section;
179 };
180
181 ld::Section StubHelperAtom::_s_section("__TEXT", "__stub_helper", ld::Section::typeStubHelper);
182
183
184 class ResolverHelperAtom : public ld::Atom {
185 public:
186 ResolverHelperAtom(ld::passes::stubs::Pass& pass, const ld::Atom* lazyPointer,
187 const ld::Atom& stubTo)
188 : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
189 ld::Atom::scopeLinkageUnit, ld::Atom::typeStubHelper,
190 symbolTableNotIn, false, false, false, ld::Atom::Alignment(1)),
191 _stubTo(stubTo),
192 _fixup1(24, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressARM64Branch26, &stubTo),
193 _fixup2(28, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressARM64Page21, lazyPointer),
194 _fixup3(32, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressARM64PageOff12, lazyPointer) { }
195
196 virtual const ld::File* file() const { return _stubTo.file(); }
197 virtual const char* name() const { return _stubTo.name(); }
198 virtual uint64_t size() const { return 68; }
199 virtual uint64_t objectAddress() const { return 0; }
200 virtual void copyRawContent(uint8_t buffer[]) const {
201 OSWriteLittleInt32(&buffer[ 0], 0, 0xa9bf7bfd); // stp fp, lr, [sp, #-16]!
202 OSWriteLittleInt32(&buffer[ 4], 0, 0x910003fd); // mov fp, sp
203 OSWriteLittleInt32(&buffer[ 8], 0, 0xa9bf03e1); // stp x1, x0, [sp, #-16]!
204 OSWriteLittleInt32(&buffer[12], 0, 0xa9bf0be3); // stp x3, x2, [sp, #-16]!
205 OSWriteLittleInt32(&buffer[16], 0, 0xa9bf13e5); // stp x5, x4, [sp, #-16]!
206 OSWriteLittleInt32(&buffer[20], 0, 0xa9bf1be7); // stp x7, x6, [sp, #-16]!
207 OSWriteLittleInt32(&buffer[24], 0, 0x94000000); // bl _foo
208 OSWriteLittleInt32(&buffer[28], 0, 0x90000010); // adrp x16, lazy_pointer@PAGE
209 OSWriteLittleInt32(&buffer[32], 0, 0x91000210); // add x16, x16, lazy_pointer@PAGEOFF
210 OSWriteLittleInt32(&buffer[36], 0, 0xf9000200); // str x0, [x16]
211 OSWriteLittleInt32(&buffer[40], 0, 0xaa0003f0); // mov x16, x0
212 OSWriteLittleInt32(&buffer[44], 0, 0xa8c11be7); // ldp x7, x6, [sp], #16
213 OSWriteLittleInt32(&buffer[48], 0, 0xa8c113e5); // ldp x5, x4, [sp], #16
214 OSWriteLittleInt32(&buffer[52], 0, 0xa8c10be3); // ldp x3, x2, [sp], #16
215 OSWriteLittleInt32(&buffer[56], 0, 0xa8c103e1); // ldp x1, x0, [sp], #16
216 OSWriteLittleInt32(&buffer[60], 0, 0xa8c17bfd); // ldp fp, lr, [sp], #16
217 OSWriteLittleInt32(&buffer[64], 0, 0xd61f0200); // br x16
218 }
219 virtual void setScope(Scope) { }
220 virtual ld::Fixup::iterator fixupsBegin() const { return &_fixup1; }
221 virtual ld::Fixup::iterator fixupsEnd() const { return &((ld::Fixup*)&_fixup3)[1]; }
222
223 private:
224
225 const ld::Atom& _stubTo;
226 mutable ld::Fixup _fixup1;
227 ld::Fixup _fixup2;
228 ld::Fixup _fixup3;
229
230 static ld::Section _s_section;
231 };
232
233 ld::Section ResolverHelperAtom::_s_section("__TEXT", "__stub_helper", ld::Section::typeStubHelper);
234
235
236
237 class LazyPointerAtom : public ld::Atom {
238 public:
239 LazyPointerAtom(ld::passes::stubs::Pass& pass, const ld::Atom& stubTo,
240 bool stubToGlobalWeakDef, bool stubToResolver, bool weakImport)
241 : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
242 ld::Atom::scopeTranslationUnit, ld::Atom::typeLazyPointer,
243 symbolTableNotIn, false, false, false, ld::Atom::Alignment(3)),
244 _stubTo(stubTo),
245 _helper(pass, this, stubTo),
246 _resolverHelper(pass, this, stubTo),
247 _fixup1(0, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressLittleEndian64,
248 stubToResolver ? &_resolverHelper :
249 (stubToGlobalWeakDef ? &stubTo : &_helper)),
250 _fixup2(0, ld::Fixup::k1of1, ld::Fixup::kindLazyTarget, &stubTo) {
251 _fixup2.weakImport = weakImport; pass.addAtom(*this);
252 if ( stubToResolver )
253 pass.addAtom(_resolverHelper);
254 else if ( !stubToGlobalWeakDef )
255 pass.addAtom(_helper);
256 }
257
258 virtual const ld::File* file() const { return _stubTo.file(); }
259 virtual const char* name() const { return _stubTo.name(); }
260 virtual uint64_t size() const { return 8; }
261 virtual uint64_t objectAddress() const { return 0; }
262 virtual void copyRawContent(uint8_t buffer[]) const { }
263 virtual void setScope(Scope) { }
264 virtual ld::Fixup::iterator fixupsBegin() const { return &_fixup1; }
265 virtual ld::Fixup::iterator fixupsEnd() const { return &((ld::Fixup*)&_fixup2)[1]; }
266
267 private:
268 const ld::Atom& _stubTo;
269 StubHelperAtom _helper;
270 ResolverHelperAtom _resolverHelper;
271 mutable ld::Fixup _fixup1;
272 ld::Fixup _fixup2;
273
274 static ld::Section _s_section;
275 };
276
277 ld::Section LazyPointerAtom::_s_section("__DATA", "__la_symbol_ptr", ld::Section::typeLazyPointer);
278
279
280 class StubAtom : public ld::Atom {
281 public:
282 StubAtom(ld::passes::stubs::Pass& pass, const ld::Atom& stubTo,
283 bool stubToGlobalWeakDef, bool stubToResolver, bool weakImport)
284 : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
285 ld::Atom::scopeLinkageUnit, ld::Atom::typeStub,
286 symbolTableNotIn, false, false, false, ld::Atom::Alignment(1)),
287 _stubTo(stubTo),
288 _lazyPointer(pass, stubTo, stubToGlobalWeakDef, stubToResolver, weakImport),
289 _fixup1(0, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressARM64Page21, &_lazyPointer),
290 _fixup2(4, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressARM64PageOff12, &_lazyPointer)
291 { pass.addAtom(*this); }
292
293 virtual const ld::File* file() const { return _stubTo.file(); }
294 virtual const char* name() const { return _stubTo.name(); }
295 virtual uint64_t size() const { return 12; }
296 virtual uint64_t objectAddress() const { return 0; }
297 virtual void copyRawContent(uint8_t buffer[]) const {
298 OSWriteLittleInt32(&buffer[0], 0, 0x90000010); // ADRP X16, lazy_pointer@page
299 OSWriteLittleInt32(&buffer[4], 0, 0xF9400210); // LDR X16, [X16, lazy_pointer@pageoff]
300 OSWriteLittleInt32(&buffer[8], 0, 0xD61F0200); // BR X16
301 }
302 virtual void setScope(Scope) { }
303 virtual ld::Fixup::iterator fixupsBegin() const { return &_fixup1; }
304 virtual ld::Fixup::iterator fixupsEnd() const { return &((ld::Fixup*)&_fixup2)[1]; }
305
306 private:
307 const ld::Atom& _stubTo;
308 LazyPointerAtom _lazyPointer;
309 mutable ld::Fixup _fixup1;
310 mutable ld::Fixup _fixup2;
311
312 static ld::Section _s_section;
313 };
314
315 ld::Section StubAtom::_s_section("__TEXT", "__stubs", ld::Section::typeStub);
316
317
318
319 class NonLazyPointerAtom : public ld::Atom {
320 public:
321 NonLazyPointerAtom(ld::passes::stubs::Pass& pass, const ld::Atom& stubTo)
322 : ld::Atom(_s_section, ld::Atom::definitionRegular,
323 ld::Atom::combineNever, ld::Atom::scopeLinkageUnit, ld::Atom::typeNonLazyPointer,
324 symbolTableNotIn, false, false, false, ld::Atom::Alignment(3)),
325 _stubTo(stubTo),
326 _fixup1(0, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressLittleEndian64, &stubTo) {
327 pass.addAtom(*this);
328 }
329
330 virtual const ld::File* file() const { return _stubTo.file(); }
331 virtual const char* name() const { return _stubTo.name(); }
332 virtual uint64_t size() const { return 8; }
333 virtual uint64_t objectAddress() const { return 0; }
334 virtual void copyRawContent(uint8_t buffer[]) const { }
335 virtual void setScope(Scope) { }
336 virtual ld::Fixup::iterator fixupsBegin() const { return (ld::Fixup*)&_fixup1; }
337 virtual ld::Fixup::iterator fixupsEnd() const { return &((ld::Fixup*)&_fixup1)[1]; }
338
339 private:
340 const ld::Atom& _stubTo;
341 ld::Fixup _fixup1;
342
343 static ld::Section _s_section;
344 };
345
346 ld::Section NonLazyPointerAtom::_s_section("__DATA", "__got", ld::Section::typeNonLazyPointer);
347
348
349 class KextStubAtom : public ld::Atom {
350 public:
351 KextStubAtom(ld::passes::stubs::Pass& pass, const ld::Atom& stubTo)
352 : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
353 ld::Atom::scopeLinkageUnit, ld::Atom::typeStub,
354 symbolTableIn, false, false, false, ld::Atom::Alignment(1)),
355 _stubTo(stubTo),
356 _nonLazyPointer(pass, stubTo),
357 _fixup1(0, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressARM64Page21, &_nonLazyPointer),
358 _fixup2(4, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressARM64PageOff12, &_nonLazyPointer) {
359 pass.addAtom(*this);
360 asprintf((char**)&_name, "%s.stub", _stubTo.name());
361 }
362
363 virtual const ld::File* file() const { return _stubTo.file(); }
364 virtual const char* name() const { return _name; }
365 virtual uint64_t size() const { return 12; }
366 virtual uint64_t objectAddress() const { return 0; }
367 virtual void copyRawContent(uint8_t buffer[]) const {
368 OSWriteLittleInt32(&buffer[0], 0, 0x90000010); // ADRP X16, non_lazy_pointer@page
369 OSWriteLittleInt32(&buffer[4], 0, 0xF9400210); // LDR X16, [X16, non_lazy_pointer@pageoff]
370 OSWriteLittleInt32(&buffer[8], 0, 0xD61F0200); // BR X16
371 }
372 virtual void setScope(Scope) { }
373 virtual ld::Fixup::iterator fixupsBegin() const { return &_fixup1; }
374 virtual ld::Fixup::iterator fixupsEnd() const { return &((ld::Fixup*)&_fixup2)[1]; }
375
376 private:
377 const ld::Atom& _stubTo;
378 const char* _name;
379 NonLazyPointerAtom _nonLazyPointer;
380 mutable ld::Fixup _fixup1;
381 mutable ld::Fixup _fixup2;
382
383 static ld::Section _s_section;
384 };
385
386 ld::Section KextStubAtom::_s_section("__TEXT", "__stubs", ld::Section::typeCode);
387
388
389 } // namespace x86_64
390