]> git.saurik.com Git - apple/ld64.git/blame - src/ld/passes/stubs/stub_arm64.hpp
ld64-409.12.tar.gz
[apple/ld64.git] / src / ld / passes / stubs / stub_arm64.hpp
CommitLineData
f80fe69f
A
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
27namespace arm64 {
28
29
30
31class FastBindingPointerAtom : public ld::Atom {
32public:
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
50private:
51 mutable ld::Fixup _fixup;
52
53 static ld::Section _s_section;
54};
55
56ld::Section FastBindingPointerAtom::_s_section("__DATA", "__got", ld::Section::typeNonLazyPointer);
57
58
59class ImageCachePointerAtom : public ld::Atom {
60public:
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
73private:
74
75 static ld::Section _s_section;
76};
77
78ld::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//
89class StubHelperHelperAtom : public ld::Atom {
90public:
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)),
9543cb2f
A
98 _fixup4(16, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressARM64PageOff12, compressedFastBinder(pass)),
99 _fixup5(ld::Fixup::kindLinkerOptimizationHint, LOH_ARM64_ADRP_ADD, 0, 4),
100 _fixup6(ld::Fixup::kindLinkerOptimizationHint, LOH_ARM64_ADRP_LDR, 12, 16)
f80fe69f
A
101 { pass.addAtom(*this); }
102
103 virtual ld::File* file() const { return NULL; }
104 virtual const char* name() const { return "helper helper"; }
105 virtual uint64_t size() const { return 24; }
106 virtual uint64_t objectAddress() const { return 0; }
107 virtual void copyRawContent(uint8_t buffer[]) const {
108 OSWriteLittleInt32(&buffer[ 0], 0, 0x90000011); // ADRP X17, dyld_mageLoaderCache@page
109 OSWriteLittleInt32(&buffer[ 4], 0, 0x91000231); // ADD X17, X17, dyld_mageLoaderCache@pageoff
110 OSWriteLittleInt32(&buffer[ 8], 0, 0xA9BF47F0); // STP X16/X17, [SP, #-16]!
111 OSWriteLittleInt32(&buffer[12], 0, 0x90000010); // ADRP X16, _fast_lazy_bind@page
112 OSWriteLittleInt32(&buffer[16], 0, 0xF9400210); // LDR X16, [X16,_fast_lazy_bind@pageoff]
113 OSWriteLittleInt32(&buffer[20], 0, 0xD61F0200); // BR X16
114 }
115 virtual void setScope(Scope) { }
116 virtual ld::Fixup::iterator fixupsBegin() const { return &_fixup1; }
9543cb2f 117 virtual ld::Fixup::iterator fixupsEnd() const { return &((ld::Fixup*)&_fixup6)[1]; }
f80fe69f
A
118
119private:
120 static ld::Atom* compressedImageCache(ld::passes::stubs::Pass& pass) {
121 if ( pass.compressedImageCache == NULL )
122 pass.compressedImageCache = new ImageCachePointerAtom(pass);
123 return pass.compressedImageCache;
124 }
125 static ld::Atom* compressedFastBinder(ld::passes::stubs::Pass& pass) {
126 if ( pass.compressedFastBinderPointer == NULL )
127 pass.compressedFastBinderPointer = new FastBindingPointerAtom(pass);
128 return pass.compressedFastBinderPointer;
129 }
130
131 mutable ld::Fixup _fixup1;
132 ld::Fixup _fixup2;
133 ld::Fixup _fixup3;
134 ld::Fixup _fixup4;
9543cb2f
A
135 ld::Fixup _fixup5;
136 ld::Fixup _fixup6;
f80fe69f
A
137
138 static ld::Section _s_section;
139};
140
141ld::Section StubHelperHelperAtom::_s_section("__TEXT", "__stub_helper", ld::Section::typeStubHelper);
142
143
144
145class StubHelperAtom : public ld::Atom {
146public:
147 StubHelperAtom(ld::passes::stubs::Pass& pass, const ld::Atom* lazyPointer,
148 const ld::Atom& stubTo)
149 : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
150 ld::Atom::scopeLinkageUnit, ld::Atom::typeStubHelper,
e456bf10 151 symbolTableNotIn, false, false, false, ld::Atom::Alignment(2)),
f80fe69f
A
152 _stubTo(stubTo),
153 _fixup1(4, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressARM64Branch26, helperHelper(pass)),
154 _fixup2(8, ld::Fixup::k1of2, ld::Fixup::kindSetLazyOffset, lazyPointer),
155 _fixup3(8, ld::Fixup::k2of2, ld::Fixup::kindStoreLittleEndian32) { }
156
157 virtual const ld::File* file() const { return _stubTo.file(); }
158 virtual const char* name() const { return _stubTo.name(); }
159 virtual uint64_t size() const { return 12; }
160 virtual uint64_t objectAddress() const { return 0; }
161 virtual void copyRawContent(uint8_t buffer[]) const {
162 OSWriteLittleInt32(&buffer[0], 0, 0x18000050); // LDR W16, L0
163 OSWriteLittleInt32(&buffer[4], 0, 0x14000000); // B helperhelper
164 OSWriteLittleInt32(&buffer[8], 0, 0x00000000); // L0: .long 0
165 }
166 virtual void setScope(Scope) { }
167 virtual ld::Fixup::iterator fixupsBegin() const { return &_fixup1; }
168 virtual ld::Fixup::iterator fixupsEnd() const { return &((ld::Fixup*)&_fixup3)[1]; }
169
170private:
171 static ld::Atom* helperHelper(ld::passes::stubs::Pass& pass) {
172 if ( pass.compressedHelperHelper == NULL )
173 pass.compressedHelperHelper = new StubHelperHelperAtom(pass);
174 return pass.compressedHelperHelper;
175 }
176
177 const ld::Atom& _stubTo;
178 mutable ld::Fixup _fixup1;
179 ld::Fixup _fixup2;
180 ld::Fixup _fixup3;
181
182 static ld::Section _s_section;
183};
184
185ld::Section StubHelperAtom::_s_section("__TEXT", "__stub_helper", ld::Section::typeStubHelper);
186
187
188class ResolverHelperAtom : public ld::Atom {
189public:
190 ResolverHelperAtom(ld::passes::stubs::Pass& pass, const ld::Atom* lazyPointer,
191 const ld::Atom& stubTo)
192 : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
193 ld::Atom::scopeLinkageUnit, ld::Atom::typeStubHelper,
e456bf10 194 symbolTableNotIn, false, false, false, ld::Atom::Alignment(2)),
f80fe69f
A
195 _stubTo(stubTo),
196 _fixup1(24, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressARM64Branch26, &stubTo),
197 _fixup2(28, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressARM64Page21, lazyPointer),
198 _fixup3(32, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressARM64PageOff12, lazyPointer) { }
199
200 virtual const ld::File* file() const { return _stubTo.file(); }
201 virtual const char* name() const { return _stubTo.name(); }
202 virtual uint64_t size() const { return 68; }
203 virtual uint64_t objectAddress() const { return 0; }
204 virtual void copyRawContent(uint8_t buffer[]) const {
205 OSWriteLittleInt32(&buffer[ 0], 0, 0xa9bf7bfd); // stp fp, lr, [sp, #-16]!
206 OSWriteLittleInt32(&buffer[ 4], 0, 0x910003fd); // mov fp, sp
207 OSWriteLittleInt32(&buffer[ 8], 0, 0xa9bf03e1); // stp x1, x0, [sp, #-16]!
208 OSWriteLittleInt32(&buffer[12], 0, 0xa9bf0be3); // stp x3, x2, [sp, #-16]!
209 OSWriteLittleInt32(&buffer[16], 0, 0xa9bf13e5); // stp x5, x4, [sp, #-16]!
210 OSWriteLittleInt32(&buffer[20], 0, 0xa9bf1be7); // stp x7, x6, [sp, #-16]!
211 OSWriteLittleInt32(&buffer[24], 0, 0x94000000); // bl _foo
212 OSWriteLittleInt32(&buffer[28], 0, 0x90000010); // adrp x16, lazy_pointer@PAGE
213 OSWriteLittleInt32(&buffer[32], 0, 0x91000210); // add x16, x16, lazy_pointer@PAGEOFF
214 OSWriteLittleInt32(&buffer[36], 0, 0xf9000200); // str x0, [x16]
215 OSWriteLittleInt32(&buffer[40], 0, 0xaa0003f0); // mov x16, x0
216 OSWriteLittleInt32(&buffer[44], 0, 0xa8c11be7); // ldp x7, x6, [sp], #16
217 OSWriteLittleInt32(&buffer[48], 0, 0xa8c113e5); // ldp x5, x4, [sp], #16
218 OSWriteLittleInt32(&buffer[52], 0, 0xa8c10be3); // ldp x3, x2, [sp], #16
219 OSWriteLittleInt32(&buffer[56], 0, 0xa8c103e1); // ldp x1, x0, [sp], #16
220 OSWriteLittleInt32(&buffer[60], 0, 0xa8c17bfd); // ldp fp, lr, [sp], #16
221 OSWriteLittleInt32(&buffer[64], 0, 0xd61f0200); // br x16
222 }
223 virtual void setScope(Scope) { }
224 virtual ld::Fixup::iterator fixupsBegin() const { return &_fixup1; }
225 virtual ld::Fixup::iterator fixupsEnd() const { return &((ld::Fixup*)&_fixup3)[1]; }
226
227private:
228
229 const ld::Atom& _stubTo;
230 mutable ld::Fixup _fixup1;
231 ld::Fixup _fixup2;
232 ld::Fixup _fixup3;
233
234 static ld::Section _s_section;
235};
236
237ld::Section ResolverHelperAtom::_s_section("__TEXT", "__stub_helper", ld::Section::typeStubHelper);
238
239
240
241class LazyPointerAtom : public ld::Atom {
242public:
243 LazyPointerAtom(ld::passes::stubs::Pass& pass, const ld::Atom& stubTo,
eaf282aa
A
244 bool stubToGlobalWeakDef, bool stubToResolver, bool weakImport, bool dataConstUsed)
245 : ld::Atom(selectSection(stubToGlobalWeakDef, stubToResolver, dataConstUsed),
246 ld::Atom::definitionRegular, ld::Atom::combineNever,
f80fe69f
A
247 ld::Atom::scopeTranslationUnit, ld::Atom::typeLazyPointer,
248 symbolTableNotIn, false, false, false, ld::Atom::Alignment(3)),
249 _stubTo(stubTo),
250 _helper(pass, this, stubTo),
251 _resolverHelper(pass, this, stubTo),
252 _fixup1(0, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressLittleEndian64,
253 stubToResolver ? &_resolverHelper :
254 (stubToGlobalWeakDef ? &stubTo : &_helper)),
255 _fixup2(0, ld::Fixup::k1of1, ld::Fixup::kindLazyTarget, &stubTo) {
256 _fixup2.weakImport = weakImport; pass.addAtom(*this);
257 if ( stubToResolver )
258 pass.addAtom(_resolverHelper);
259 else if ( !stubToGlobalWeakDef )
260 pass.addAtom(_helper);
261 }
262
263 virtual const ld::File* file() const { return _stubTo.file(); }
264 virtual const char* name() const { return _stubTo.name(); }
265 virtual uint64_t size() const { return 8; }
266 virtual uint64_t objectAddress() const { return 0; }
267 virtual void copyRawContent(uint8_t buffer[]) const { }
268 virtual void setScope(Scope) { }
269 virtual ld::Fixup::iterator fixupsBegin() const { return &_fixup1; }
270 virtual ld::Fixup::iterator fixupsEnd() const { return &((ld::Fixup*)&_fixup2)[1]; }
271
272private:
eaf282aa
A
273 static ld::Section& selectSection(bool stubToGlobalWeakDef, bool stubToResolver, bool dataConstUsed) {
274 if ( stubToGlobalWeakDef && dataConstUsed )
275 return _s_sectionWeak;
276 else if ( stubToResolver && dataConstUsed )
277 return _s_sectionResolver;
278 else
279 return _s_section;
280 }
281
f80fe69f
A
282 const ld::Atom& _stubTo;
283 StubHelperAtom _helper;
284 ResolverHelperAtom _resolverHelper;
285 mutable ld::Fixup _fixup1;
286 ld::Fixup _fixup2;
287
288 static ld::Section _s_section;
eaf282aa
A
289 static ld::Section _s_sectionResolver;
290 static ld::Section _s_sectionWeak;
f80fe69f
A
291};
292
293ld::Section LazyPointerAtom::_s_section("__DATA", "__la_symbol_ptr", ld::Section::typeLazyPointer);
eaf282aa
A
294ld::Section LazyPointerAtom::_s_sectionResolver("__DATA_DIRTY", "__la_resolver", ld::Section::typeLazyPointer);
295ld::Section LazyPointerAtom::_s_sectionWeak("__DATA", "__la_weak_ptr", ld::Section::typeLazyPointer);
f80fe69f
A
296
297
298class StubAtom : public ld::Atom {
299public:
300 StubAtom(ld::passes::stubs::Pass& pass, const ld::Atom& stubTo,
eaf282aa 301 bool stubToGlobalWeakDef, bool stubToResolver, bool weakImport, bool dataConstUsed)
f80fe69f
A
302 : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
303 ld::Atom::scopeLinkageUnit, ld::Atom::typeStub,
e456bf10 304 symbolTableNotIn, false, false, false, ld::Atom::Alignment(2)),
f80fe69f 305 _stubTo(stubTo),
eaf282aa 306 _lazyPointer(pass, stubTo, stubToGlobalWeakDef, stubToResolver, weakImport, dataConstUsed),
f80fe69f 307 _fixup1(0, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressARM64Page21, &_lazyPointer),
9543cb2f
A
308 _fixup2(4, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressARM64PageOff12, &_lazyPointer),
309 _fixup3(ld::Fixup::kindLinkerOptimizationHint, LOH_ARM64_ADRP_LDR, 0, 4)
310 { pass.addAtom(*this); }
f80fe69f
A
311
312 virtual const ld::File* file() const { return _stubTo.file(); }
313 virtual const char* name() const { return _stubTo.name(); }
314 virtual uint64_t size() const { return 12; }
315 virtual uint64_t objectAddress() const { return 0; }
316 virtual void copyRawContent(uint8_t buffer[]) const {
317 OSWriteLittleInt32(&buffer[0], 0, 0x90000010); // ADRP X16, lazy_pointer@page
318 OSWriteLittleInt32(&buffer[4], 0, 0xF9400210); // LDR X16, [X16, lazy_pointer@pageoff]
319 OSWriteLittleInt32(&buffer[8], 0, 0xD61F0200); // BR X16
320 }
321 virtual void setScope(Scope) { }
322 virtual ld::Fixup::iterator fixupsBegin() const { return &_fixup1; }
9543cb2f 323 virtual ld::Fixup::iterator fixupsEnd() const { return &((ld::Fixup*)&_fixup3)[1]; }
f80fe69f
A
324
325private:
326 const ld::Atom& _stubTo;
327 LazyPointerAtom _lazyPointer;
328 mutable ld::Fixup _fixup1;
329 mutable ld::Fixup _fixup2;
9543cb2f 330 mutable ld::Fixup _fixup3;
f80fe69f
A
331
332 static ld::Section _s_section;
333};
334
335ld::Section StubAtom::_s_section("__TEXT", "__stubs", ld::Section::typeStub);
336
337
338
339class NonLazyPointerAtom : public ld::Atom {
340public:
e456bf10
A
341 NonLazyPointerAtom(ld::passes::stubs::Pass& pass, const ld::Atom& stubTo,
342 bool weakImport)
f80fe69f
A
343 : ld::Atom(_s_section, ld::Atom::definitionRegular,
344 ld::Atom::combineNever, ld::Atom::scopeLinkageUnit, ld::Atom::typeNonLazyPointer,
345 symbolTableNotIn, false, false, false, ld::Atom::Alignment(3)),
346 _stubTo(stubTo),
347 _fixup1(0, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressLittleEndian64, &stubTo) {
e456bf10 348 _fixup1.weakImport = weakImport;
f80fe69f
A
349 pass.addAtom(*this);
350 }
351
352 virtual const ld::File* file() const { return _stubTo.file(); }
353 virtual const char* name() const { return _stubTo.name(); }
354 virtual uint64_t size() const { return 8; }
355 virtual uint64_t objectAddress() const { return 0; }
356 virtual void copyRawContent(uint8_t buffer[]) const { }
357 virtual void setScope(Scope) { }
358 virtual ld::Fixup::iterator fixupsBegin() const { return (ld::Fixup*)&_fixup1; }
359 virtual ld::Fixup::iterator fixupsEnd() const { return &((ld::Fixup*)&_fixup1)[1]; }
360
361private:
362 const ld::Atom& _stubTo;
363 ld::Fixup _fixup1;
364
365 static ld::Section _s_section;
366};
367
368ld::Section NonLazyPointerAtom::_s_section("__DATA", "__got", ld::Section::typeNonLazyPointer);
369
370
e456bf10 371class NonLazyStubAtom : public ld::Atom {
f80fe69f 372public:
e456bf10
A
373 NonLazyStubAtom(ld::passes::stubs::Pass& pass, const ld::Atom& stubTo,
374 bool weakImport)
f80fe69f
A
375 : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
376 ld::Atom::scopeLinkageUnit, ld::Atom::typeStub,
e456bf10 377 symbolTableNotIn, false, false, false, ld::Atom::Alignment(2)),
f80fe69f 378 _stubTo(stubTo),
e456bf10 379 _nonLazyPointer(pass, stubTo, weakImport),
f80fe69f 380 _fixup1(0, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressARM64Page21, &_nonLazyPointer),
e456bf10 381 _fixup2(4, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressARM64PageOff12, &_nonLazyPointer) {
f80fe69f 382 asprintf((char**)&_name, "%s.stub", _stubTo.name());
e456bf10 383 pass.addAtom(*this);
f80fe69f
A
384 }
385
386 virtual const ld::File* file() const { return _stubTo.file(); }
387 virtual const char* name() const { return _name; }
388 virtual uint64_t size() const { return 12; }
389 virtual uint64_t objectAddress() const { return 0; }
390 virtual void copyRawContent(uint8_t buffer[]) const {
391 OSWriteLittleInt32(&buffer[0], 0, 0x90000010); // ADRP X16, non_lazy_pointer@page
392 OSWriteLittleInt32(&buffer[4], 0, 0xF9400210); // LDR X16, [X16, non_lazy_pointer@pageoff]
393 OSWriteLittleInt32(&buffer[8], 0, 0xD61F0200); // BR X16
394 }
395 virtual void setScope(Scope) { }
396 virtual ld::Fixup::iterator fixupsBegin() const { return &_fixup1; }
397 virtual ld::Fixup::iterator fixupsEnd() const { return &((ld::Fixup*)&_fixup2)[1]; }
398
399private:
400 const ld::Atom& _stubTo;
401 const char* _name;
402 NonLazyPointerAtom _nonLazyPointer;
403 mutable ld::Fixup _fixup1;
404 mutable ld::Fixup _fixup2;
405
406 static ld::Section _s_section;
407};
408
e456bf10 409ld::Section NonLazyStubAtom::_s_section("__TEXT", "__stubs", ld::Section::typeStub);
f80fe69f
A
410
411
0a8dc3df 412} // namespace arm64
f80fe69f 413
e456bf10
A
414#if SUPPORT_ARCH_arm64e
415
416// already in ld::passes::stubs namespace
417namespace arm64e {
418
419
420
421class FastBindingPointerAtom : public ld::Atom {
422public:
423 FastBindingPointerAtom(ld::passes::stubs::Pass& pass)
424 : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
425 ld::Atom::scopeLinkageUnit, ld::Atom::typeNonLazyPointer,
426 symbolTableNotIn, false, false, false, ld::Atom::Alignment(3)),
427 _fixup(0, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressLittleEndian64,
428 pass.internal()->compressedFastBinderProxy)
429 { pass.addAtom(*this); }
430
431 virtual const ld::File* file() const { return NULL; }
432 virtual const char* name() const { return "fast binder pointer"; }
433 virtual uint64_t size() const { return 8; }
434 virtual uint64_t objectAddress() const { return 0; }
435 virtual void copyRawContent(uint8_t buffer[]) const { }
436 virtual void setScope(Scope) { }
437 virtual ld::Fixup::iterator fixupsBegin() const { return &_fixup; }
438 virtual ld::Fixup::iterator fixupsEnd() const { return &((ld::Fixup*)&_fixup)[1]; }
439
440private:
441 mutable ld::Fixup _fixup;
442
443 static ld::Section _s_section;
444};
445
446ld::Section FastBindingPointerAtom::_s_section("__DATA", "__got", ld::Section::typeNonLazyPointer);
447
448
449class ImageCachePointerAtom : public ld::Atom {
450public:
451 ImageCachePointerAtom(ld::passes::stubs::Pass& pass)
452 : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
453 ld::Atom::scopeLinkageUnit, ld::Atom::typeNonLazyPointer,
454 symbolTableNotIn, false, false, false, ld::Atom::Alignment(3)) { pass.addAtom(*this); }
455
456 virtual const ld::File* file() const { return NULL; }
457 virtual const char* name() const { return "image cache pointer"; }
458 virtual uint64_t size() const { return 8; }
459 virtual uint64_t objectAddress() const { return 0; }
460 virtual void copyRawContent(uint8_t buffer[]) const { }
461 virtual void setScope(Scope) { }
462
463private:
464
465 static ld::Section _s_section;
466};
467
468ld::Section ImageCachePointerAtom::_s_section("__DATA", "__got", ld::Section::typeNonLazyPointer);
469
470
471
472
473
474//
475// The stub-helper-helper is the common code factored out of each helper function.
476// It is in the same section as the stub-helpers.
477// Similar to the PLT0 entry in ELF.
478//
479class StubHelperHelperAtom : public ld::Atom {
480public:
481 StubHelperHelperAtom(ld::passes::stubs::Pass& pass)
482 : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
483 ld::Atom::scopeLinkageUnit, ld::Atom::typeStubHelper,
484 symbolTableNotIn, false, false, false, ld::Atom::Alignment(2)),
485 _fixup1(0, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressARM64Page21, compressedImageCache(pass)),
486 _fixup2(4, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressARM64PageOff12, compressedImageCache(pass)),
487 _fixup3(12, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressARM64Page21, compressedFastBinder(pass)),
488 _fixup4(16, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressARM64PageOff12, compressedFastBinder(pass)),
489 _fixup5(ld::Fixup::kindLinkerOptimizationHint, LOH_ARM64_ADRP_ADD, 0, 4),
490 _fixup6(ld::Fixup::kindLinkerOptimizationHint, LOH_ARM64_ADRP_LDR, 12, 16)
491 { pass.addAtom(*this); }
492
493 virtual ld::File* file() const { return NULL; }
494 virtual const char* name() const { return "helper helper"; }
495 virtual uint64_t size() const { return 24; }
496 virtual uint64_t objectAddress() const { return 0; }
497 virtual void copyRawContent(uint8_t buffer[]) const {
498 OSWriteLittleInt32(&buffer[ 0], 0, 0x90000011); // ADRP X17, dyld_mageLoaderCache@page
499 OSWriteLittleInt32(&buffer[ 4], 0, 0x91000231); // ADD X17, X17, dyld_mageLoaderCache@pageoff
500 OSWriteLittleInt32(&buffer[ 8], 0, 0xA9BF47F0); // STP X16/X17, [SP, #-16]!
501 OSWriteLittleInt32(&buffer[12], 0, 0x90000010); // ADRP X16, _fast_lazy_bind@page
502 OSWriteLittleInt32(&buffer[16], 0, 0xF9400210); // LDR X16, [X16,_fast_lazy_bind@pageoff]
503 OSWriteLittleInt32(&buffer[20], 0, 0xD61F0200); // BR X16
504 }
505 virtual void setScope(Scope) { }
506 virtual ld::Fixup::iterator fixupsBegin() const { return &_fixup1; }
507 virtual ld::Fixup::iterator fixupsEnd() const { return &((ld::Fixup*)&_fixup6)[1]; }
508
509private:
510 static ld::Atom* compressedImageCache(ld::passes::stubs::Pass& pass) {
511 if ( pass.compressedImageCache == NULL )
512 pass.compressedImageCache = new ImageCachePointerAtom(pass);
513 return pass.compressedImageCache;
514 }
515 static ld::Atom* compressedFastBinder(ld::passes::stubs::Pass& pass) {
516 if ( pass.compressedFastBinderPointer == NULL )
517 pass.compressedFastBinderPointer = new FastBindingPointerAtom(pass);
518 return pass.compressedFastBinderPointer;
519 }
520
521 mutable ld::Fixup _fixup1;
522 ld::Fixup _fixup2;
523 ld::Fixup _fixup3;
524 ld::Fixup _fixup4;
525 ld::Fixup _fixup5;
526 ld::Fixup _fixup6;
527
528 static ld::Section _s_section;
529};
530
531ld::Section StubHelperHelperAtom::_s_section("__TEXT", "__stub_helper", ld::Section::typeStubHelper);
532
533
534
535class StubHelperAtom : public ld::Atom {
536public:
537 StubHelperAtom(ld::passes::stubs::Pass& pass, const ld::Atom* lazyPointer,
538 const ld::Atom& stubTo)
539 : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
540 ld::Atom::scopeLinkageUnit, ld::Atom::typeStubHelper,
541 symbolTableNotIn, false, false, false, ld::Atom::Alignment(2)),
542 _stubTo(stubTo),
543 _fixup1(4, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressARM64Branch26, helperHelper(pass)),
544 _fixup2(8, ld::Fixup::k1of2, ld::Fixup::kindSetLazyOffset, lazyPointer),
545 _fixup3(8, ld::Fixup::k2of2, ld::Fixup::kindStoreLittleEndian32) { }
546
547 virtual const ld::File* file() const { return _stubTo.file(); }
548 virtual const char* name() const { return _stubTo.name(); }
549 virtual uint64_t size() const { return 12; }
550 virtual uint64_t objectAddress() const { return 0; }
551 virtual void copyRawContent(uint8_t buffer[]) const {
552 OSWriteLittleInt32(&buffer[0], 0, 0x18000050); // LDR W16, L0
553 OSWriteLittleInt32(&buffer[4], 0, 0x14000000); // B helperhelper
554 OSWriteLittleInt32(&buffer[8], 0, 0x00000000); // L0: .long 0
555 }
556 virtual void setScope(Scope) { }
557 virtual ld::Fixup::iterator fixupsBegin() const { return &_fixup1; }
558 virtual ld::Fixup::iterator fixupsEnd() const { return &((ld::Fixup*)&_fixup3)[1]; }
559
560private:
561 static ld::Atom* helperHelper(ld::passes::stubs::Pass& pass) {
562 if ( pass.compressedHelperHelper == NULL )
563 pass.compressedHelperHelper = new StubHelperHelperAtom(pass);
564 return pass.compressedHelperHelper;
565 }
566
567 const ld::Atom& _stubTo;
568 mutable ld::Fixup _fixup1;
569 ld::Fixup _fixup2;
570 ld::Fixup _fixup3;
571
572 static ld::Section _s_section;
573};
574
575ld::Section StubHelperAtom::_s_section("__TEXT", "__stub_helper", ld::Section::typeStubHelper);
576
577
578class ResolverHelperAtom : public ld::Atom {
579public:
580 ResolverHelperAtom(ld::passes::stubs::Pass& pass, const ld::Atom* lazyPointer,
581 const ld::Atom& stubTo)
582 : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
583 ld::Atom::scopeLinkageUnit, ld::Atom::typeStubHelper,
584 symbolTableNotIn, false, false, false, ld::Atom::Alignment(2)),
585 _stubTo(stubTo),
586 _fixup1(24, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressARM64Branch26, &stubTo),
587 _fixup2(28, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressARM64Page21, lazyPointer),
588 _fixup3(32, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressARM64PageOff12, lazyPointer) { }
589
590 virtual const ld::File* file() const { return _stubTo.file(); }
591 virtual const char* name() const { return _stubTo.name(); }
592 virtual uint64_t size() const { return 68; }
593 virtual uint64_t objectAddress() const { return 0; }
594 virtual void copyRawContent(uint8_t buffer[]) const {
595 OSWriteLittleInt32(&buffer[ 0], 0, 0xa9bf7bfd); // stp fp, lr, [sp, #-16]!
596 OSWriteLittleInt32(&buffer[ 4], 0, 0x910003fd); // mov fp, sp
597 OSWriteLittleInt32(&buffer[ 8], 0, 0xa9bf03e1); // stp x1, x0, [sp, #-16]!
598 OSWriteLittleInt32(&buffer[12], 0, 0xa9bf0be3); // stp x3, x2, [sp, #-16]!
599 OSWriteLittleInt32(&buffer[16], 0, 0xa9bf13e5); // stp x5, x4, [sp, #-16]!
600 OSWriteLittleInt32(&buffer[20], 0, 0xa9bf1be7); // stp x7, x6, [sp, #-16]!
601 OSWriteLittleInt32(&buffer[24], 0, 0x94000000); // bl _foo
602 OSWriteLittleInt32(&buffer[28], 0, 0x90000010); // adrp x16, lazy_pointer@PAGE
603 OSWriteLittleInt32(&buffer[32], 0, 0x91000210); // add x16, x16, lazy_pointer@PAGEOFF
604 OSWriteLittleInt32(&buffer[36], 0, 0xf9000200); // str x0, [x16]
605 OSWriteLittleInt32(&buffer[40], 0, 0xaa0003f0); // mov x16, x0
606 OSWriteLittleInt32(&buffer[44], 0, 0xa8c11be7); // ldp x7, x6, [sp], #16
607 OSWriteLittleInt32(&buffer[48], 0, 0xa8c113e5); // ldp x5, x4, [sp], #16
608 OSWriteLittleInt32(&buffer[52], 0, 0xa8c10be3); // ldp x3, x2, [sp], #16
609 OSWriteLittleInt32(&buffer[56], 0, 0xa8c103e1); // ldp x1, x0, [sp], #16
610 OSWriteLittleInt32(&buffer[60], 0, 0xa8c17bfd); // ldp fp, lr, [sp], #16
611 OSWriteLittleInt32(&buffer[64], 0, 0xD61F0A1F); // braaz x16
612 }
613
614 virtual void setScope(Scope) { }
615 virtual ld::Fixup::iterator fixupsBegin() const { return &_fixup1; }
616 virtual ld::Fixup::iterator fixupsEnd() const { return &((ld::Fixup*)&_fixup3)[1]; }
617
618private:
619
620 const ld::Atom& _stubTo;
621 mutable ld::Fixup _fixup1;
622 ld::Fixup _fixup2;
623 ld::Fixup _fixup3;
624
625 static ld::Section _s_section;
626};
627
628ld::Section ResolverHelperAtom::_s_section("__TEXT", "__stub_helper", ld::Section::typeStubHelper);
629
630
631
632class LazyPointerAtom : public ld::Atom {
633public:
634 LazyPointerAtom(ld::passes::stubs::Pass& pass, const ld::Atom& stubTo,
635 bool stubToGlobalWeakDef, bool stubToResolver, bool weakImport, bool dataConstUsed)
636 : ld::Atom(selectSection(stubToGlobalWeakDef, stubToResolver, dataConstUsed),
637 ld::Atom::definitionRegular, ld::Atom::combineNever,
638 ld::Atom::scopeTranslationUnit, ld::Atom::typeLazyPointer,
639 symbolTableNotIn, false, false, false, ld::Atom::Alignment(3)),
640 _stubTo(stubTo),
641 _helper(pass, this, stubTo),
642 _resolverHelper(pass, this, stubTo),
643 _fixup1(0, ld::Fixup::k1of2, ld::Fixup::kindSetAuthData, (ld::Fixup::AuthData){ 0, false, ld::Fixup::AuthData::ptrauth_key_asia }),
644 _fixup2(0, ld::Fixup::k2of2, ld::Fixup::kindStoreTargetAddressLittleEndianAuth64,
645 stubToResolver ? &_resolverHelper : (stubToGlobalWeakDef ? &stubTo : &_helper)),
646 _fixup3(0, ld::Fixup::k1of1, ld::Fixup::kindLazyTarget, &stubTo) {
647 _fixup2.weakImport = weakImport; pass.addAtom(*this);
648 if ( stubToResolver )
649 pass.addAtom(_resolverHelper);
650 else if ( !stubToGlobalWeakDef )
651 pass.addAtom(_helper);
652 }
653
654 virtual const ld::File* file() const { return _stubTo.file(); }
655 virtual const char* name() const { return _stubTo.name(); }
656 virtual uint64_t size() const { return 8; }
657 virtual uint64_t objectAddress() const { return 0; }
658 virtual void copyRawContent(uint8_t buffer[]) const { }
659 virtual void setScope(Scope) { }
660 virtual ld::Fixup::iterator fixupsBegin() const { return &_fixup1; }
661 virtual ld::Fixup::iterator fixupsEnd() const { return &((ld::Fixup*)&_fixup3)[1]; }
662
663private:
664 static ld::Section& selectSection(bool stubToGlobalWeakDef, bool stubToResolver, bool dataConstUsed) {
665 if ( stubToGlobalWeakDef && dataConstUsed )
666 return _s_sectionWeak;
667 else if ( stubToResolver && dataConstUsed )
668 return _s_sectionResolver;
669 else
670 return _s_section;
671 }
672
673 const ld::Atom& _stubTo;
674 StubHelperAtom _helper;
675 ResolverHelperAtom _resolverHelper;
676 mutable ld::Fixup _fixup1;
677 ld::Fixup _fixup2;
678 ld::Fixup _fixup3;
679
680 static ld::Section _s_section;
681 static ld::Section _s_sectionResolver;
682 static ld::Section _s_sectionWeak;
683};
684
685ld::Section LazyPointerAtom::_s_section("__DATA", "__la_symbol_ptr", ld::Section::typeLazyPointer);
686ld::Section LazyPointerAtom::_s_sectionResolver("__DATA_DIRTY", "__la_resolver", ld::Section::typeLazyPointer);
687ld::Section LazyPointerAtom::_s_sectionWeak("__DATA", "__la_weak_ptr", ld::Section::typeLazyPointer);
688
689
690class StubAtom : public ld::Atom {
691public:
692 StubAtom(ld::passes::stubs::Pass& pass, const ld::Atom& stubTo,
693 bool stubToGlobalWeakDef, bool stubToResolver, bool weakImport, bool dataConstUsed)
694 : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
695 ld::Atom::scopeLinkageUnit, ld::Atom::typeStub,
696 symbolTableNotIn, false, false, false, ld::Atom::Alignment(2)),
697 _stubTo(stubTo),
698 _lazyPointer(pass, stubTo, stubToGlobalWeakDef, stubToResolver, weakImport, dataConstUsed),
699 _fixup1(0, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressARM64Page21, &_lazyPointer),
700 _fixup2(4, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressARM64PageOff12, &_lazyPointer),
701 _fixup3(ld::Fixup::kindLinkerOptimizationHint, LOH_ARM64_ADRP_LDR, 0, 4)
702 { pass.addAtom(*this); }
703
704 virtual const ld::File* file() const { return _stubTo.file(); }
705 virtual const char* name() const { return _stubTo.name(); }
706 virtual uint64_t size() const { return 12; }
707 virtual uint64_t objectAddress() const { return 0; }
708 virtual void copyRawContent(uint8_t buffer[]) const {
709 OSWriteLittleInt32(&buffer[0], 0, 0x90000010); // ADRP X16, lazy_pointer@page
710 OSWriteLittleInt32(&buffer[4], 0, 0xF9400210); // LDR X16, [X16, lazy_pointer@pageoff]
711 OSWriteLittleInt32(&buffer[8], 0, 0xD61F0A1F); // BRAAZ X16
712 }
713 virtual void setScope(Scope) { }
714 virtual ld::Fixup::iterator fixupsBegin() const { return &_fixup1; }
715 virtual ld::Fixup::iterator fixupsEnd() const { return &((ld::Fixup*)&_fixup3)[1]; }
716
717private:
718 const ld::Atom& _stubTo;
719 LazyPointerAtom _lazyPointer;
720 mutable ld::Fixup _fixup1;
721 mutable ld::Fixup _fixup2;
722 mutable ld::Fixup _fixup3;
723
724 static ld::Section _s_section;
725};
726
727ld::Section StubAtom::_s_section("__TEXT", "__stubs", ld::Section::typeStub);
728
729
730
731class NonLazyPointerAtom : public ld::Atom {
732public:
733 NonLazyPointerAtom(ld::passes::stubs::Pass& pass, const ld::Atom& stubTo,
734 bool weakImport)
735 : ld::Atom(_s_section, ld::Atom::definitionRegular,
736 ld::Atom::combineNever, ld::Atom::scopeLinkageUnit, ld::Atom::typeNonLazyPointer,
737 symbolTableNotIn, false, false, false, ld::Atom::Alignment(3)),
738 _stubTo(stubTo),
739 _fixup1(0, ld::Fixup::k1of2, ld::Fixup::kindSetAuthData, (ld::Fixup::AuthData){ 0, true, ld::Fixup::AuthData::ptrauth_key_asia }),
740 _fixup2(0, ld::Fixup::k2of2, ld::Fixup::kindStoreTargetAddressLittleEndianAuth64, &stubTo) {
741 _fixup2.weakImport = weakImport;
742 pass.addAtom(*this);
743 }
744
745 virtual const ld::File* file() const { return _stubTo.file(); }
746 virtual const char* name() const { return _stubTo.name(); }
747 virtual uint64_t size() const { return 8; }
748 virtual uint64_t objectAddress() const { return 0; }
749 virtual void copyRawContent(uint8_t buffer[]) const { }
750 virtual void setScope(Scope) { }
751 virtual ld::Fixup::iterator fixupsBegin() const { return (ld::Fixup*)&_fixup1; }
752 virtual ld::Fixup::iterator fixupsEnd() const { return &((ld::Fixup*)&_fixup2)[1]; }
753
754private:
755 const ld::Atom& _stubTo;
756 ld::Fixup _fixup1;
757 ld::Fixup _fixup2;
758
759 static ld::Section _s_section;
760};
761
762ld::Section NonLazyPointerAtom::_s_section("__DATA", "__auth_got", ld::Section::typeNonLazyPointer);
763
764
765class NonLazyStubAtom : public ld::Atom {
766public:
767 NonLazyStubAtom(ld::passes::stubs::Pass& pass, const ld::Atom& stubTo,
768 bool weakImport)
769 : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
770 ld::Atom::scopeLinkageUnit, ld::Atom::typeStub,
771 symbolTableNotIn, false, false, false, ld::Atom::Alignment(2)),
772 _stubTo(stubTo),
773 _nonLazyPointer(pass, stubTo, weakImport),
774 _fixup1(0, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressARM64Page21, &_nonLazyPointer),
775 _fixup2(4, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressARM64PageOff12, &_nonLazyPointer) {
776 asprintf((char**)&_name, "%s.stub", _stubTo.name());
777 pass.addAtom(*this);
778 }
779
780 virtual const ld::File* file() const { return _stubTo.file(); }
781 virtual const char* name() const { return _name; }
782 virtual uint64_t size() const { return 16; }
783 virtual uint64_t objectAddress() const { return 0; }
784 virtual void copyRawContent(uint8_t buffer[]) const {
785 OSWriteLittleInt32(&buffer[ 0], 0, 0x90000011); // ADRP X17, dyld_mageLoaderCache@page
786 OSWriteLittleInt32(&buffer[ 4], 0, 0x91000231); // ADD X17, X17, dyld_mageLoaderCache@pageoff
787 OSWriteLittleInt32(&buffer[ 8], 0, 0xF9400230); // LDR X16, [X17]
788 OSWriteLittleInt32(&buffer[12], 0, 0xD71F0A11); // BRAA X16, X17
789 }
790 virtual void setScope(Scope) { }
791 virtual ld::Fixup::iterator fixupsBegin() const { return &_fixup1; }
792 virtual ld::Fixup::iterator fixupsEnd() const { return &((ld::Fixup*)&_fixup2)[1]; }
793
794private:
795 const ld::Atom& _stubTo;
796 const char* _name;
797 NonLazyPointerAtom _nonLazyPointer;
798 mutable ld::Fixup _fixup1;
799 mutable ld::Fixup _fixup2;
800
801 static ld::Section _s_section;
802};
803
804ld::Section NonLazyStubAtom::_s_section("__TEXT", "__auth_stubs", ld::Section::typeStub);
805
806
807} // namespace arm64e
808#endif
809