]> git.saurik.com Git - apple/ld64.git/blob - src/ld/passes/stubs/stub_arm64.hpp
ld64-242.tar.gz
[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 _fixup5(ld::Fixup::kindLinkerOptimizationHint, LOH_ARM64_ADRP_ADD, 0, 4),
100 _fixup6(ld::Fixup::kindLinkerOptimizationHint, LOH_ARM64_ADRP_LDR, 12, 16)
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; }
117 virtual ld::Fixup::iterator fixupsEnd() const { return &((ld::Fixup*)&_fixup6)[1]; }
118
119 private:
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;
135 ld::Fixup _fixup5;
136 ld::Fixup _fixup6;
137
138 static ld::Section _s_section;
139 };
140
141 ld::Section StubHelperHelperAtom::_s_section("__TEXT", "__stub_helper", ld::Section::typeStubHelper);
142
143
144
145 class StubHelperAtom : public ld::Atom {
146 public:
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,
151 symbolTableNotIn, false, false, false, ld::Atom::Alignment(1)),
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
170 private:
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
185 ld::Section StubHelperAtom::_s_section("__TEXT", "__stub_helper", ld::Section::typeStubHelper);
186
187
188 class ResolverHelperAtom : public ld::Atom {
189 public:
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,
194 symbolTableNotIn, false, false, false, ld::Atom::Alignment(1)),
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
227 private:
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
237 ld::Section ResolverHelperAtom::_s_section("__TEXT", "__stub_helper", ld::Section::typeStubHelper);
238
239
240
241 class LazyPointerAtom : public ld::Atom {
242 public:
243 LazyPointerAtom(ld::passes::stubs::Pass& pass, const ld::Atom& stubTo,
244 bool stubToGlobalWeakDef, bool stubToResolver, bool weakImport)
245 : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
246 ld::Atom::scopeTranslationUnit, ld::Atom::typeLazyPointer,
247 symbolTableNotIn, false, false, false, ld::Atom::Alignment(3)),
248 _stubTo(stubTo),
249 _helper(pass, this, stubTo),
250 _resolverHelper(pass, this, stubTo),
251 _fixup1(0, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressLittleEndian64,
252 stubToResolver ? &_resolverHelper :
253 (stubToGlobalWeakDef ? &stubTo : &_helper)),
254 _fixup2(0, ld::Fixup::k1of1, ld::Fixup::kindLazyTarget, &stubTo) {
255 _fixup2.weakImport = weakImport; pass.addAtom(*this);
256 if ( stubToResolver )
257 pass.addAtom(_resolverHelper);
258 else if ( !stubToGlobalWeakDef )
259 pass.addAtom(_helper);
260 }
261
262 virtual const ld::File* file() const { return _stubTo.file(); }
263 virtual const char* name() const { return _stubTo.name(); }
264 virtual uint64_t size() const { return 8; }
265 virtual uint64_t objectAddress() const { return 0; }
266 virtual void copyRawContent(uint8_t buffer[]) const { }
267 virtual void setScope(Scope) { }
268 virtual ld::Fixup::iterator fixupsBegin() const { return &_fixup1; }
269 virtual ld::Fixup::iterator fixupsEnd() const { return &((ld::Fixup*)&_fixup2)[1]; }
270
271 private:
272 const ld::Atom& _stubTo;
273 StubHelperAtom _helper;
274 ResolverHelperAtom _resolverHelper;
275 mutable ld::Fixup _fixup1;
276 ld::Fixup _fixup2;
277
278 static ld::Section _s_section;
279 };
280
281 ld::Section LazyPointerAtom::_s_section("__DATA", "__la_symbol_ptr", ld::Section::typeLazyPointer);
282
283
284 class StubAtom : public ld::Atom {
285 public:
286 StubAtom(ld::passes::stubs::Pass& pass, const ld::Atom& stubTo,
287 bool stubToGlobalWeakDef, bool stubToResolver, bool weakImport)
288 : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
289 ld::Atom::scopeLinkageUnit, ld::Atom::typeStub,
290 symbolTableNotIn, false, false, false, ld::Atom::Alignment(1)),
291 _stubTo(stubTo),
292 _lazyPointer(pass, stubTo, stubToGlobalWeakDef, stubToResolver, weakImport),
293 _fixup1(0, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressARM64Page21, &_lazyPointer),
294 _fixup2(4, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressARM64PageOff12, &_lazyPointer),
295 _fixup3(ld::Fixup::kindLinkerOptimizationHint, LOH_ARM64_ADRP_LDR, 0, 4)
296 { pass.addAtom(*this); }
297
298 virtual const ld::File* file() const { return _stubTo.file(); }
299 virtual const char* name() const { return _stubTo.name(); }
300 virtual uint64_t size() const { return 12; }
301 virtual uint64_t objectAddress() const { return 0; }
302 virtual void copyRawContent(uint8_t buffer[]) const {
303 OSWriteLittleInt32(&buffer[0], 0, 0x90000010); // ADRP X16, lazy_pointer@page
304 OSWriteLittleInt32(&buffer[4], 0, 0xF9400210); // LDR X16, [X16, lazy_pointer@pageoff]
305 OSWriteLittleInt32(&buffer[8], 0, 0xD61F0200); // BR X16
306 }
307 virtual void setScope(Scope) { }
308 virtual ld::Fixup::iterator fixupsBegin() const { return &_fixup1; }
309 virtual ld::Fixup::iterator fixupsEnd() const { return &((ld::Fixup*)&_fixup3)[1]; }
310
311 private:
312 const ld::Atom& _stubTo;
313 LazyPointerAtom _lazyPointer;
314 mutable ld::Fixup _fixup1;
315 mutable ld::Fixup _fixup2;
316 mutable ld::Fixup _fixup3;
317
318 static ld::Section _s_section;
319 };
320
321 ld::Section StubAtom::_s_section("__TEXT", "__stubs", ld::Section::typeStub);
322
323
324
325 class NonLazyPointerAtom : public ld::Atom {
326 public:
327 NonLazyPointerAtom(ld::passes::stubs::Pass& pass, const ld::Atom& stubTo)
328 : ld::Atom(_s_section, ld::Atom::definitionRegular,
329 ld::Atom::combineNever, ld::Atom::scopeLinkageUnit, ld::Atom::typeNonLazyPointer,
330 symbolTableNotIn, false, false, false, ld::Atom::Alignment(3)),
331 _stubTo(stubTo),
332 _fixup1(0, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressLittleEndian64, &stubTo) {
333 pass.addAtom(*this);
334 }
335
336 virtual const ld::File* file() const { return _stubTo.file(); }
337 virtual const char* name() const { return _stubTo.name(); }
338 virtual uint64_t size() const { return 8; }
339 virtual uint64_t objectAddress() const { return 0; }
340 virtual void copyRawContent(uint8_t buffer[]) const { }
341 virtual void setScope(Scope) { }
342 virtual ld::Fixup::iterator fixupsBegin() const { return (ld::Fixup*)&_fixup1; }
343 virtual ld::Fixup::iterator fixupsEnd() const { return &((ld::Fixup*)&_fixup1)[1]; }
344
345 private:
346 const ld::Atom& _stubTo;
347 ld::Fixup _fixup1;
348
349 static ld::Section _s_section;
350 };
351
352 ld::Section NonLazyPointerAtom::_s_section("__DATA", "__got", ld::Section::typeNonLazyPointer);
353
354
355 class KextStubAtom : public ld::Atom {
356 public:
357 KextStubAtom(ld::passes::stubs::Pass& pass, const ld::Atom& stubTo)
358 : ld::Atom(_s_section, ld::Atom::definitionRegular, ld::Atom::combineNever,
359 ld::Atom::scopeLinkageUnit, ld::Atom::typeStub,
360 symbolTableIn, false, false, false, ld::Atom::Alignment(1)),
361 _stubTo(stubTo),
362 _nonLazyPointer(pass, stubTo),
363 _fixup1(0, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressARM64Page21, &_nonLazyPointer),
364 _fixup2(4, ld::Fixup::k1of1, ld::Fixup::kindStoreTargetAddressARM64PageOff12, &_nonLazyPointer) {
365 pass.addAtom(*this);
366 asprintf((char**)&_name, "%s.stub", _stubTo.name());
367 }
368
369 virtual const ld::File* file() const { return _stubTo.file(); }
370 virtual const char* name() const { return _name; }
371 virtual uint64_t size() const { return 12; }
372 virtual uint64_t objectAddress() const { return 0; }
373 virtual void copyRawContent(uint8_t buffer[]) const {
374 OSWriteLittleInt32(&buffer[0], 0, 0x90000010); // ADRP X16, non_lazy_pointer@page
375 OSWriteLittleInt32(&buffer[4], 0, 0xF9400210); // LDR X16, [X16, non_lazy_pointer@pageoff]
376 OSWriteLittleInt32(&buffer[8], 0, 0xD61F0200); // BR X16
377 }
378 virtual void setScope(Scope) { }
379 virtual ld::Fixup::iterator fixupsBegin() const { return &_fixup1; }
380 virtual ld::Fixup::iterator fixupsEnd() const { return &((ld::Fixup*)&_fixup2)[1]; }
381
382 private:
383 const ld::Atom& _stubTo;
384 const char* _name;
385 NonLazyPointerAtom _nonLazyPointer;
386 mutable ld::Fixup _fixup1;
387 mutable ld::Fixup _fixup2;
388
389 static ld::Section _s_section;
390 };
391
392 ld::Section KextStubAtom::_s_section("__TEXT", "__stubs", ld::Section::typeCode);
393
394
395 } // namespace x86_64
396