]> git.saurik.com Git - apple/xnu.git/blob - libkern/kxld/kxld_sect.c
xnu-1504.7.4.tar.gz
[apple/xnu.git] / libkern / kxld / kxld_sect.c
1 /*
2 * Copyright (c) 2008 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28 #include <string.h>
29 #include <mach-o/loader.h>
30 #include <mach-o/reloc.h>
31 #include <sys/types.h>
32
33 #define DEBUG_ASSERT_COMPONENT_NAME_STRING "kxld"
34 #include <AssertMacros.h>
35
36 #include "kxld_reloc.h"
37 #include "kxld_sect.h"
38 #include "kxld_seg.h"
39 #include "kxld_symtab.h"
40 #include "kxld_util.h"
41
42 static kern_return_t export_macho(const KXLDSect *sect, u_char *buf, u_long offset,
43 u_long bufsize, boolean_t is_32_bit);
44 #if KXLD_USER_OR_ILP32
45 static kern_return_t sect_export_macho_header_32(const KXLDSect *sect, u_char *buf,
46 u_long *header_offset, u_long header_size, u_long data_offset);
47 #endif
48 #if KXLD_USER_OR_LP64
49 static kern_return_t sect_export_macho_header_64(const KXLDSect *sect, u_char *buf,
50 u_long *header_offset, u_long header_size, u_long data_offset);
51 #endif
52
53 #if KXLD_USER_OR_ILP32
54 /*******************************************************************************
55 *******************************************************************************/
56 kern_return_t
57 kxld_sect_init_from_macho_32(KXLDSect *sect, u_char *macho, u_long *sect_offset,
58 u_int sectnum, const KXLDRelocator *relocator)
59 {
60 kern_return_t rval = KERN_FAILURE;
61 struct section *src = (struct section *) (macho + *sect_offset);
62 struct relocation_info *relocs = NULL;
63
64 check(sect);
65 check(macho);
66 check(src);
67
68 strlcpy(sect->segname, src->segname, sizeof(sect->segname));
69 strlcpy(sect->sectname, src->sectname, sizeof(sect->sectname));
70 sect->base_addr = src->addr;
71 sect->link_addr = src->addr;
72 sect->size = src->size;
73 sect->sectnum = sectnum;
74 sect->flags = src->flags;
75 sect->align = src->align;
76 sect->reserved1 = src->reserved1;
77 sect->reserved2 = src->reserved2;
78
79 if (src->offset) {
80 sect->data = macho + src->offset;
81 } else {
82 sect->data = NULL;
83 }
84
85 relocs = (struct relocation_info *) (macho + src->reloff);
86
87 rval = kxld_reloc_create_macho(&sect->relocs, relocator,
88 relocs, src->nreloc);
89 require_noerr(rval, finish);
90
91 *sect_offset += sizeof(*src);
92 rval = KERN_SUCCESS;
93
94 finish:
95 if (rval) kxld_sect_deinit(sect);
96
97 return rval;
98 }
99 #endif /* KXLD_USER_OR_ILP32 */
100
101 #if KXLD_USER_OR_LP64
102 /*******************************************************************************
103 *******************************************************************************/
104 kern_return_t
105 kxld_sect_init_from_macho_64(KXLDSect *sect, u_char *macho, u_long *sect_offset,
106 u_int sectnum, const KXLDRelocator *relocator)
107 {
108 kern_return_t rval = KERN_FAILURE;
109 struct section_64 *src = (struct section_64 *) (macho + *sect_offset);
110 struct relocation_info *relocs = NULL;
111
112 check(sect);
113 check(macho);
114 check(src);
115
116 strlcpy(sect->segname, src->segname, sizeof(sect->segname));
117 strlcpy(sect->sectname, src->sectname, sizeof(sect->sectname));
118 sect->base_addr = src->addr;
119 sect->link_addr = src->addr;
120 sect->size = src->size;
121 sect->sectnum = sectnum;
122 sect->flags = src->flags;
123 sect->align = src->align;
124 sect->reserved1 = src->reserved1;
125 sect->reserved2 = src->reserved2;
126
127 if (src->offset) {
128 sect->data = macho + src->offset;
129 } else {
130 sect->data = NULL;
131 }
132
133 relocs = (struct relocation_info *) (macho + src->reloff);
134
135 rval = kxld_reloc_create_macho(&sect->relocs, relocator,
136 relocs, src->nreloc);
137 require_noerr(rval, finish);
138
139 *sect_offset += sizeof(*src);
140 rval = KERN_SUCCESS;
141
142 finish:
143 if (rval) kxld_sect_deinit(sect);
144
145 return rval;
146 }
147 #endif /* KXLD_USER_OR_LP64 */
148
149 #if KXLD_USER_OR_GOT
150 /*******************************************************************************
151 * Assumes GOT is comprised of kxld_addr_t entries
152 *******************************************************************************/
153 kern_return_t
154 kxld_sect_init_got(KXLDSect *sect, u_int ngots)
155 {
156 kern_return_t rval = KERN_FAILURE;
157
158 check(sect);
159
160 strlcpy(sect->segname, KXLD_SEG_GOT, sizeof(sect->segname));
161 strlcpy(sect->sectname, KXLD_SECT_GOT, sizeof(sect->sectname));
162 sect->base_addr = 0;
163 sect->link_addr = 0;
164 sect->flags = 0;
165 sect->align = 4;
166 sect->reserved1 = 0;
167 sect->reserved2 = 0;
168
169 sect->size = ngots * sizeof(kxld_addr_t);
170 sect->data = kxld_alloc((u_long) sect->size);
171 require_action(sect->data, finish, rval=KERN_RESOURCE_SHORTAGE);
172
173 sect->allocated = TRUE;
174
175 rval = KERN_SUCCESS;
176
177 finish:
178 return rval;
179 }
180 #endif /* KXLD_USER_OR_GOT */
181
182 #if KXLD_USER_OR_COMMON
183 /*******************************************************************************
184 *******************************************************************************/
185 void
186 kxld_sect_init_zerofill(KXLDSect *sect, const char *segname,
187 const char *sectname, kxld_size_t size, u_int align)
188 {
189 check(sect);
190 check(segname);
191 check(sectname);
192
193 strlcpy(sect->segname, segname, sizeof(sect->segname));
194 strlcpy(sect->sectname, sectname, sizeof(sect->sectname));
195 sect->size = size;
196 sect->align = align;
197 sect->base_addr = 0;
198 sect->link_addr = 0;
199 sect->flags = S_ZEROFILL;
200 }
201 #endif /* KXLD_USER_OR_COMMON */
202
203 /*******************************************************************************
204 *******************************************************************************/
205 void
206 kxld_sect_clear(KXLDSect *sect)
207 {
208 check(sect);
209
210 if (sect->allocated) {
211 kxld_free(sect->data, (u_long) sect->size);
212 sect->allocated = FALSE;
213 }
214
215 bzero(sect->sectname, sizeof(sect->sectname));
216 bzero(sect->segname, sizeof(sect->segname));
217 sect->data = NULL;
218 sect->base_addr = 0;
219 sect->link_addr = 0;
220 sect->size = 0;
221 sect->flags = 0;
222 sect->align = 0;
223 sect->reserved1 = 0;
224 sect->reserved2 = 0;
225 kxld_array_clear(&sect->relocs);
226 }
227
228 /*******************************************************************************
229 *******************************************************************************/
230 void
231 kxld_sect_deinit(KXLDSect *sect)
232 {
233 check(sect);
234
235 if (streq_safe(sect->sectname, KXLD_SECT_GOT, sizeof(KXLD_SECT_GOT))) {
236 kxld_free(sect->data, (u_long) sect->size);
237 }
238
239 kxld_array_deinit(&sect->relocs);
240 bzero(sect, sizeof(*sect));
241 }
242
243 /*******************************************************************************
244 *******************************************************************************/
245 u_int
246 kxld_sect_get_num_relocs(const KXLDSect *sect)
247 {
248 check(sect);
249
250 return sect->relocs.nitems;
251 }
252
253 /*******************************************************************************
254 *******************************************************************************/
255 u_long
256 kxld_sect_get_macho_header_size(boolean_t is_32_bit)
257 {
258 if (is_32_bit) {
259 return sizeof(struct section);
260 } else {
261 return sizeof(struct section_64);
262 }
263 }
264
265 /*******************************************************************************
266 *******************************************************************************/
267 u_long
268 kxld_sect_get_macho_data_size(const KXLDSect *sect)
269 {
270 u_long size = 0;
271
272 check(sect);
273
274 if (sect->data) {
275 size = (u_long) sect->size;
276 }
277
278 return size;
279 }
280
281 #if KXLD_USER_OR_GOT
282 /*******************************************************************************
283 *******************************************************************************/
284 u_int
285 kxld_sect_get_ngots(const KXLDSect *sect, const KXLDRelocator *relocator,
286 const KXLDSymtab *symtab)
287 {
288 const KXLDReloc *reloc = NULL;
289 KXLDSym *sym = NULL;
290 u_int ngots = 0;
291 u_int i = 0;
292
293 for (i = 0; i < sect->relocs.nitems; ++i) {
294 reloc = kxld_array_get_item(&sect->relocs, i);
295
296 if (relocator->reloc_has_got(reloc->reloc_type)) {
297 /* @TODO This assumes 64-bit symbols (which is valid at the
298 * moment since only x86_64 has a GOT)
299 */
300 sym = kxld_reloc_get_symbol(relocator, reloc, sect->data, symtab);
301 if (!kxld_sym_is_got(sym)) {
302 kxld_sym_set_got(sym);
303 ++ngots;
304 }
305 }
306 }
307
308 return ngots;
309 }
310 #endif /* KXLD_USER_OR_GOT */
311
312 /*******************************************************************************
313 * Each section must be aligned at a certain power of two. To figure out that
314 * alignment, we mask for the low bits that may need to be adjusted. If they are
315 * non zero, we then subtract them from the target alignment to find the offset,
316 * and then add that offset to the link address.
317 *******************************************************************************/
318 kxld_addr_t
319 kxld_sect_align_address(const KXLDSect *sect, kxld_addr_t address)
320 {
321 return kxld_align_address(address, sect->align);
322 }
323
324 /*******************************************************************************
325 *******************************************************************************/
326 kern_return_t
327 kxld_sect_export_macho_to_file_buffer(const KXLDSect *sect, u_char *buf,
328 u_long *header_offset, u_long header_size, u_long *data_offset,
329 u_long data_size, boolean_t is_32_bit)
330 {
331 kern_return_t rval = KERN_FAILURE;
332
333 check(sect);
334 check(buf);
335 check(header_offset);
336 check(data_offset);
337
338 /* If there is no data to export, we only need to write the header. We
339 * make it a separate call so that we don't modify data_offset.
340 */
341 if (!sect->data) {
342 KXLD_3264_FUNC(is_32_bit, rval,
343 sect_export_macho_header_32, sect_export_macho_header_64,
344 sect, buf, header_offset, header_size, /* data_offset */ 0);
345 require_noerr(rval, finish);
346 } else {
347 *data_offset = (u_long) kxld_sect_align_address(sect, *data_offset);
348
349 KXLD_3264_FUNC(is_32_bit, rval,
350 sect_export_macho_header_32, sect_export_macho_header_64,
351 sect, buf, header_offset, header_size, *data_offset);
352 require_noerr(rval, finish);
353
354 rval = export_macho(sect, buf, *data_offset, data_size, is_32_bit);
355 require_noerr(rval, finish);
356
357 *data_offset += (u_long) sect->size;
358 }
359
360 rval = KERN_SUCCESS;
361
362 finish:
363 return rval;
364 }
365
366 /*******************************************************************************
367 *******************************************************************************/
368 kern_return_t
369 kxld_sect_export_macho_to_vm(const KXLDSect *sect, u_char *buf,
370 u_long *header_offset, u_long header_size,
371 kxld_addr_t link_addr, u_long data_size,
372 boolean_t is_32_bit)
373 {
374 kern_return_t rval = KERN_FAILURE;
375 u_long data_offset = (u_long) (sect->link_addr - link_addr);
376
377 check(sect);
378 check(buf);
379 check(header_offset);
380
381 KXLD_3264_FUNC(is_32_bit, rval,
382 sect_export_macho_header_32, sect_export_macho_header_64,
383 sect, buf, header_offset, header_size, data_offset);
384 require_noerr(rval, finish);
385
386 rval = export_macho(sect, buf, data_offset, data_size, is_32_bit);
387 require_noerr(rval, finish);
388
389 rval = KERN_SUCCESS;
390
391 finish:
392 return rval;
393 }
394
395 /*******************************************************************************
396 *******************************************************************************/
397 static kern_return_t
398 export_macho(const KXLDSect *sect, u_char *buf, u_long offset, u_long bufsize,
399 boolean_t is_32_bit)
400 {
401 kern_return_t rval = KERN_FAILURE;
402
403 check(sect);
404 check(buf);
405
406 if (!sect->data) {
407 rval = KERN_SUCCESS;
408 goto finish;
409 }
410
411 /* Verify that the section is properly aligned */
412
413 require_action(kxld_sect_align_address(sect, offset) == offset, finish,
414 rval = KERN_FAILURE);
415
416 /* Verify that we have enough space to copy */
417
418 require_action(sect->size <= bufsize - offset, finish,
419 rval=KERN_FAILURE);
420
421 /* Copy section data */
422
423 switch (sect->flags & SECTION_TYPE) {
424 case S_NON_LAZY_SYMBOL_POINTERS:
425 case S_MOD_INIT_FUNC_POINTERS:
426 case S_MOD_TERM_FUNC_POINTERS:
427 require_action(!is_32_bit, finish, rval=KERN_FAILURE;
428 kxld_log(kKxldLogLinking, kKxldLogErr, kKxldLogMalformedMachO
429 "Invalid section type in 32-bit kext: %u.",
430 sect->flags & SECTION_TYPE));
431 /* Fall through */
432 case S_REGULAR:
433 case S_CSTRING_LITERALS:
434 case S_4BYTE_LITERALS:
435 case S_8BYTE_LITERALS:
436 case S_LITERAL_POINTERS:
437 case S_COALESCED:
438 case S_16BYTE_LITERALS:
439 memcpy(buf + offset, sect->data, (size_t)sect->size);
440 break;
441 case S_ZEROFILL: /* sect->data should be NULL, so we'll never get here */
442 case S_LAZY_SYMBOL_POINTERS:
443 case S_SYMBOL_STUBS:
444 case S_GB_ZEROFILL:
445 case S_INTERPOSING:
446 case S_DTRACE_DOF:
447 default:
448 rval = KERN_FAILURE;
449 kxld_log(kKxldLogLinking, kKxldLogErr, kKxldLogMalformedMachO
450 "Invalid section type: %u.", sect->flags & SECTION_TYPE);
451 goto finish;
452 }
453
454 rval = KERN_SUCCESS;
455
456 finish:
457 return rval;
458 }
459
460 #if KXLD_USER_OR_ILP32
461 /*******************************************************************************
462 *******************************************************************************/
463 static kern_return_t
464 sect_export_macho_header_32(const KXLDSect *sect, u_char *buf,
465 u_long *header_offset, u_long header_size, u_long data_offset)
466 {
467 kern_return_t rval = KERN_FAILURE;
468 struct section *secthdr = NULL;
469
470 check(sect);
471 check(buf);
472 check(header_offset);
473
474 require_action(sizeof(*secthdr) <= header_size - *header_offset, finish,
475 rval=KERN_FAILURE);
476 secthdr = (struct section *) (buf + *header_offset);
477 *header_offset += sizeof(*secthdr);
478
479 /* Initalize header */
480
481 strlcpy(secthdr->sectname, sect->sectname, sizeof(secthdr->sectname));
482 strlcpy(secthdr->segname, sect->segname, sizeof(secthdr->segname));
483 secthdr->addr = (uint32_t) sect->link_addr;
484 secthdr->size = (uint32_t) sect->size;
485 secthdr->offset = (uint32_t) ((sect->data) ? data_offset : 0);
486 secthdr->align = sect->align;
487 secthdr->reloff = 0;
488 secthdr->nreloc = 0;
489 secthdr->flags = sect->flags;
490 secthdr->reserved1 = sect->reserved1;
491 secthdr->reserved2 = sect->reserved2;
492
493 rval = KERN_SUCCESS;
494
495 finish:
496 return rval;
497 }
498 #endif /* KXLD_USER_OR_ILP32 */
499
500 #if KXLD_USER_OR_LP64
501 /*******************************************************************************
502 *******************************************************************************/
503 static kern_return_t
504 sect_export_macho_header_64(const KXLDSect *sect, u_char *buf,
505 u_long *header_offset, u_long header_size, u_long data_offset)
506 {
507 kern_return_t rval = KERN_FAILURE;
508 struct section_64 *secthdr = NULL;
509
510 check(sect);
511 check(buf);
512 check(header_offset);
513
514 require_action(sizeof(*secthdr) <= header_size - *header_offset, finish,
515 rval=KERN_FAILURE);
516 secthdr = (struct section_64 *) (buf + *header_offset);
517 *header_offset += sizeof(*secthdr);
518
519 /* Initalize header */
520
521 strlcpy(secthdr->sectname, sect->sectname, sizeof(secthdr->sectname));
522 strlcpy(secthdr->segname, sect->segname, sizeof(secthdr->segname));
523 secthdr->addr = (uint64_t) sect->link_addr;
524 secthdr->size = (uint64_t) sect->size;
525 secthdr->offset = (uint32_t) ((sect->data) ? data_offset : 0);
526 secthdr->align = sect->align;
527 secthdr->reloff = 0;
528 secthdr->nreloc = 0;
529 secthdr->flags = sect->flags;
530 secthdr->reserved1 = sect->reserved1;
531 secthdr->reserved2 = sect->reserved2;
532
533 rval = KERN_SUCCESS;
534
535 finish:
536 return rval;
537 }
538 #endif /* KXLD_USER_OR_LP64 */
539
540 #if KXLD_USER_OR_COMMON
541 /*******************************************************************************
542 *******************************************************************************/
543 kxld_size_t
544 kxld_sect_grow(KXLDSect *sect, kxld_size_t nbytes, u_int align)
545 {
546 kxld_size_t size = kxld_align_address(sect->size, align);
547
548 if (align > sect->align) sect->align = align;
549 sect->size = size + nbytes;
550
551 return size;
552 }
553 #endif /* KXLD_USER_OR_COMMON */
554
555 /*******************************************************************************
556 *******************************************************************************/
557 void
558 kxld_sect_relocate(KXLDSect *sect, kxld_addr_t link_addr)
559 {
560 sect->link_addr = kxld_sect_align_address(sect,
561 sect->link_addr + link_addr);
562 }
563
564 #if KXLD_USER_OR_GOT
565 /*******************************************************************************
566 *******************************************************************************/
567 kern_return_t
568 kxld_sect_populate_got(KXLDSect *sect, KXLDSymtab *symtab,
569 boolean_t swap __unused)
570 {
571 kern_return_t rval = KERN_FAILURE;
572 KXLDSymtabIterator iter;
573 KXLDSym *sym = NULL;
574 kxld_addr_t *entry = NULL;
575 kxld_addr_t entry_addr = 0;
576
577 check(sect);
578 check(symtab);
579 require(streq_safe(sect->segname, KXLD_SEG_GOT, sizeof(KXLD_SEG_GOT)),
580 finish);
581 require(streq_safe(sect->sectname, KXLD_SECT_GOT, sizeof(KXLD_SECT_GOT)),
582 finish);
583
584 kxld_symtab_iterator_init(&iter, symtab, kxld_sym_is_got, FALSE);
585
586 entry = (kxld_addr_t *) sect->data;
587 entry_addr = sect->link_addr;
588 while ((sym = kxld_symtab_iterator_get_next(&iter))) {
589 *entry = sym->link_addr;
590 sym->got_addr = entry_addr;
591
592 #if !KERNEL
593 if (swap) *entry = OSSwapInt64(*entry);
594 #endif /* !KERNEL */
595
596 ++entry;
597 entry_addr += sizeof(*entry);
598 }
599
600 rval = KERN_SUCCESS;
601
602 finish:
603 return rval;
604 }
605 #endif /* KXLD_USER_OR_GOT */
606
607 /*******************************************************************************
608 *******************************************************************************/
609 kern_return_t
610 kxld_sect_process_relocs(KXLDSect *sect, const KXLDRelocator *relocator,
611 const KXLDArray *sectarray, const KXLDSymtab *symtab)
612 {
613 kern_return_t rval = KERN_FAILURE;
614 KXLDReloc *reloc = NULL;
615 u_int i = 0;
616
617 for (i = 0; i < sect->relocs.nitems; ++i) {
618 reloc = kxld_array_get_item(&sect->relocs, i);
619 rval = kxld_relocator_process_sect_reloc(relocator, reloc, sect,
620 sectarray, symtab);
621 require_noerr(rval, finish);
622 }
623
624 rval = KERN_SUCCESS;
625
626 finish:
627 return rval;
628 }
629