1 | /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- |
2 | * |
3 | * Copyright (c) 2018 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 | #ifndef __MACH_O_FIXUP_CHAINS__ |
26 | #define __MACH_O_FIXUP_CHAINS__ 6 |
27 | |
28 | |
29 | #include <stdint.h> |
30 | |
31 | |
32 | //#define LC_DYLD_EXPORTS_TRIE 0x80000033 // used with linkedit_data_command |
33 | //#define LC_DYLD_CHAINED_FIXUPS 0x80000034 // used with linkedit_data_command, payload is dyld_chained_fixups_header |
34 | |
35 | |
36 | // header of the LC_DYLD_CHAINED_FIXUPS payload |
37 | struct |
38 | { |
39 | uint32_t ; // 0 |
40 | uint32_t ; // offset of dyld_chained_starts_in_image in chain_data |
41 | uint32_t ; // offset of imports table in chain_data |
42 | uint32_t ; // offset of symbol strings in chain_data |
43 | uint32_t ; // number of imported symbol names |
44 | uint32_t ; // DYLD_CHAINED_IMPORT* |
45 | uint32_t ; // 0 => uncompressed, 1 => zlib compressed |
46 | }; |
47 | |
48 | // This struct is embedded in LC_DYLD_CHAINED_FIXUPS payload |
49 | struct dyld_chained_starts_in_image |
50 | { |
51 | uint32_t seg_count; |
52 | uint32_t seg_info_offset[1]; // each entry is offset into this struct for that segment |
53 | // followed by pool of dyld_chain_starts_in_segment data |
54 | }; |
55 | |
56 | // This struct is embedded in dyld_chain_starts_in_image |
57 | // and passed down to the kernel for page-in linking |
58 | struct dyld_chained_starts_in_segment |
59 | { |
60 | uint32_t size; // size of this (amount kernel needs to copy) |
61 | uint16_t page_size; // 0x1000 or 0x4000 |
62 | uint16_t pointer_format; // DYLD_CHAINED_PTR_* |
63 | uint64_t segment_offset; // offset in memory to start of segment |
64 | uint32_t max_valid_pointer; // for 32-bit OS, any value beyond this is not a pointer |
65 | uint16_t page_count; // how many pages are in array |
66 | uint16_t page_start[1]; // each entry is offset in each page of first element in chain |
67 | // or DYLD_CHAINED_PTR_START_NONE if no fixups on page |
68 | // uint16_t chain_starts[1]; // some 32-bit formats may require multiple starts per page. |
69 | // for those, if high bit is set in page_starts[], then it |
70 | // is index into chain_starts[] which is a list of starts |
71 | // the last of which has the high bit set |
72 | }; |
73 | |
74 | enum { |
75 | DYLD_CHAINED_PTR_START_NONE = 0xFFFF, // used in page_start[] to denote a page with no fixups |
76 | DYLD_CHAINED_PTR_START_MULTI = 0x8000, // used in page_start[] to denote a page which has multiple starts |
77 | DYLD_CHAINED_PTR_START_LAST = 0x8000, // used in chain_starts[] to denote last start in list for page |
78 | }; |
79 | |
80 | // This struct is embedded in __TEXT,__chain_starts section in firmware |
81 | struct dyld_chained_starts_offsets |
82 | { |
83 | uint32_t pointer_format; // DYLD_CHAINED_PTR_32_FIRMWARE |
84 | uint32_t starts_count; // number of starts in array |
85 | uint32_t chain_starts[1]; // array chain start offsets |
86 | }; |
87 | |
88 | |
89 | // values for dyld_chained_starts_in_segment.pointer_format |
90 | enum { |
91 | DYLD_CHAINED_PTR_ARM64E = 1, // stride 8, unauth target is vmaddr |
92 | DYLD_CHAINED_PTR_64 = 2, // target is vmaddr |
93 | DYLD_CHAINED_PTR_32 = 3, |
94 | DYLD_CHAINED_PTR_32_CACHE = 4, |
95 | DYLD_CHAINED_PTR_32_FIRMWARE = 5, |
96 | DYLD_CHAINED_PTR_64_OFFSET = 6, // target is vm offset |
97 | DYLD_CHAINED_PTR_ARM64E_OFFSET = 7, // old name |
98 | DYLD_CHAINED_PTR_ARM64E_KERNEL = 7, // stride 4, unauth target is vm offset |
99 | DYLD_CHAINED_PTR_64_KERNEL_CACHE = 8, |
100 | DYLD_CHAINED_PTR_ARM64E_USERLAND = 9, // stride 8, unauth target is vm offset |
101 | DYLD_CHAINED_PTR_ARM64E_FIRMWARE = 10, // stride 4, unauth target is vmaddr |
102 | DYLD_CHAINED_PTR_X86_64_KERNEL_CACHE = 11, // stride 1, x86_64 kernel caches |
103 | DYLD_CHAINED_PTR_ARM64E_USERLAND24 = 12, // stride 8, unauth target is vm offset, 24-bit bind |
104 | DYLD_CHAINED_PTR_ARM64E_SHARED_CACHE = 13, // stride 8, regular/auth targets both vm offsets. Only A keys supported |
105 | }; |
106 | |
107 | |
108 | // DYLD_CHAINED_PTR_ARM64E |
109 | struct dyld_chained_ptr_arm64e_rebase |
110 | { |
111 | uint64_t target : 43, |
112 | high8 : 8, |
113 | next : 11, // 4 or 8-byte stide |
114 | bind : 1, // == 0 |
115 | auth : 1; // == 0 |
116 | }; |
117 | |
118 | // DYLD_CHAINED_PTR_ARM64E |
119 | struct dyld_chained_ptr_arm64e_bind |
120 | { |
121 | uint64_t ordinal : 16, |
122 | zero : 16, |
123 | addend : 19, // +/-256K |
124 | next : 11, // 4 or 8-byte stide |
125 | bind : 1, // == 1 |
126 | auth : 1; // == 0 |
127 | }; |
128 | |
129 | // DYLD_CHAINED_PTR_ARM64E |
130 | struct dyld_chained_ptr_arm64e_auth_rebase |
131 | { |
132 | uint64_t target : 32, // runtimeOffset |
133 | diversity : 16, |
134 | addrDiv : 1, |
135 | key : 2, |
136 | next : 11, // 4 or 8-byte stide |
137 | bind : 1, // == 0 |
138 | auth : 1; // == 1 |
139 | }; |
140 | |
141 | // DYLD_CHAINED_PTR_ARM64E |
142 | struct dyld_chained_ptr_arm64e_auth_bind |
143 | { |
144 | uint64_t ordinal : 16, |
145 | zero : 16, |
146 | diversity : 16, |
147 | addrDiv : 1, |
148 | key : 2, |
149 | next : 11, // 4 or 8-byte stide |
150 | bind : 1, // == 1 |
151 | auth : 1; // == 1 |
152 | }; |
153 | |
154 | // DYLD_CHAINED_PTR_64/DYLD_CHAINED_PTR_64_OFFSET |
155 | struct dyld_chained_ptr_64_rebase |
156 | { |
157 | uint64_t target : 36, // 64GB max image size (DYLD_CHAINED_PTR_64 => vmAddr, DYLD_CHAINED_PTR_64_OFFSET => runtimeOffset) |
158 | high8 : 8, // top 8 bits set to this (DYLD_CHAINED_PTR_64 => after slide added, DYLD_CHAINED_PTR_64_OFFSET => before slide added) |
159 | reserved : 7, // all zeros |
160 | next : 12, // 4-byte stride |
161 | bind : 1; // == 0 |
162 | }; |
163 | |
164 | |
165 | // DYLD_CHAINED_PTR_ARM64E_USERLAND24 |
166 | struct dyld_chained_ptr_arm64e_bind24 |
167 | { |
168 | uint64_t ordinal : 24, |
169 | zero : 8, |
170 | addend : 19, // +/-256K |
171 | next : 11, // 8-byte stide |
172 | bind : 1, // == 1 |
173 | auth : 1; // == 0 |
174 | }; |
175 | |
176 | // DYLD_CHAINED_PTR_ARM64E_USERLAND24 |
177 | struct dyld_chained_ptr_arm64e_auth_bind24 |
178 | { |
179 | uint64_t ordinal : 24, |
180 | zero : 8, |
181 | diversity : 16, |
182 | addrDiv : 1, |
183 | key : 2, |
184 | next : 11, // 8-byte stide |
185 | bind : 1, // == 1 |
186 | auth : 1; // == 1 |
187 | }; |
188 | |
189 | |
190 | // DYLD_CHAINED_PTR_64 |
191 | struct dyld_chained_ptr_64_bind |
192 | { |
193 | uint64_t ordinal : 24, |
194 | addend : 8, // 0 thru 255 |
195 | reserved : 19, // all zeros |
196 | next : 12, // 4-byte stride |
197 | bind : 1; // == 1 |
198 | }; |
199 | |
200 | // DYLD_CHAINED_PTR_64_KERNEL_CACHE, DYLD_CHAINED_PTR_X86_64_KERNEL_CACHE |
201 | struct dyld_chained_ptr_64_kernel_cache_rebase |
202 | { |
203 | uint64_t target : 30, // basePointers[cacheLevel] + target |
204 | cacheLevel : 2, // what level of cache to bind to (indexes a mach_header array) |
205 | diversity : 16, |
206 | addrDiv : 1, |
207 | key : 2, |
208 | next : 12, // 1 or 4-byte stide |
209 | isAuth : 1; // 0 -> not authenticated. 1 -> authenticated |
210 | }; |
211 | |
212 | // DYLD_CHAINED_PTR_32 |
213 | // Note: for DYLD_CHAINED_PTR_32 some non-pointer values are co-opted into the chain |
214 | // as out of range rebases. If an entry in the chain is > max_valid_pointer, then it |
215 | // is not a pointer. To restore the value, subtract off the bias, which is |
216 | // (64MB+max_valid_pointer)/2. |
217 | struct dyld_chained_ptr_32_rebase |
218 | { |
219 | uint32_t target : 26, // vmaddr, 64MB max image size |
220 | next : 5, // 4-byte stride |
221 | bind : 1; // == 0 |
222 | }; |
223 | |
224 | // DYLD_CHAINED_PTR_32 |
225 | struct dyld_chained_ptr_32_bind |
226 | { |
227 | uint32_t ordinal : 20, |
228 | addend : 6, // 0 thru 63 |
229 | next : 5, // 4-byte stride |
230 | bind : 1; // == 1 |
231 | }; |
232 | |
233 | // DYLD_CHAINED_PTR_32_CACHE |
234 | struct dyld_chained_ptr_32_cache_rebase |
235 | { |
236 | uint32_t target : 30, // 1GB max dyld cache TEXT and DATA |
237 | next : 2; // 4-byte stride |
238 | }; |
239 | |
240 | |
241 | // DYLD_CHAINED_PTR_32_FIRMWARE |
242 | struct dyld_chained_ptr_32_firmware_rebase |
243 | { |
244 | uint32_t target : 26, // 64MB max firmware TEXT and DATA |
245 | next : 6; // 4-byte stride |
246 | }; |
247 | |
248 | // DYLD_CHAINED_PTR_ARM64E_SHARED_CACHE |
249 | struct dyld_chained_ptr_arm64e_shared_cache_rebase |
250 | { |
251 | uint64_t runtimeOffset : 34, // offset from the start of the shared cache |
252 | high8 : 8, |
253 | unused : 10, |
254 | next : 11, // 8-byte stide |
255 | auth : 1; // == 0 |
256 | }; |
257 | |
258 | // DYLD_CHAINED_PTR_ARM64E_SHARED_CACHE |
259 | struct dyld_chained_ptr_arm64e_shared_cache_auth_rebase |
260 | { |
261 | uint64_t runtimeOffset : 34, // offset from the start of the shared cache |
262 | diversity : 16, |
263 | addrDiv : 1, |
264 | keyIsData : 1, // implicitly always the 'A' key. 0 -> IA. 1 -> DA |
265 | next : 11, // 8-byte stide |
266 | auth : 1; // == 1 |
267 | }; |
268 | |
269 | |
270 | |
271 | // values for dyld_chained_fixups_header.imports_format |
272 | enum { |
273 | DYLD_CHAINED_IMPORT = 1, |
274 | DYLD_CHAINED_IMPORT_ADDEND = 2, |
275 | DYLD_CHAINED_IMPORT_ADDEND64 = 3, |
276 | }; |
277 | |
278 | // DYLD_CHAINED_IMPORT |
279 | struct dyld_chained_import |
280 | { |
281 | uint32_t lib_ordinal : 8, // -15 .. 240 (0xF1 .. 0xF0) |
282 | weak_import : 1, |
283 | name_offset : 23; |
284 | }; |
285 | |
286 | // DYLD_CHAINED_IMPORT_ADDEND |
287 | struct dyld_chained_import_addend |
288 | { |
289 | uint32_t lib_ordinal : 8, // -15 .. 240 (0xF1 .. 0xF0) |
290 | weak_import : 1, |
291 | name_offset : 23; |
292 | int32_t addend; |
293 | }; |
294 | |
295 | // DYLD_CHAINED_IMPORT_ADDEND64 |
296 | struct dyld_chained_import_addend64 |
297 | { |
298 | uint64_t lib_ordinal : 16, // -15 .. 65520 (0xFFF1 .. 0xFFF0) |
299 | weak_import : 1, |
300 | reserved : 15, |
301 | name_offset : 32; |
302 | uint64_t addend; |
303 | }; |
304 | |
305 | #endif // __MACH_O_FIXUP_CHAINS__ |
306 | |
307 | |