]> git.saurik.com Git - apple/xnu.git/blob - libkern/kxld/kxld_seg.c
xnu-3789.70.16.tar.gz
[apple/xnu.git] / libkern / kxld / kxld_seg.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/vm_prot.h>
30 #include <mach-o/loader.h>
31 #include <sys/types.h>
32
33 #if KERNEL
34 #include <mach/vm_param.h>
35 #else
36 #include <mach/mach_init.h>
37 #endif /* KERNEL */
38
39 #define DEBUG_ASSERT_COMPONENT_NAME_STRING "kxld"
40 #include <AssertMacros.h>
41
42 #include "kxld_reloc.h"
43 #include "kxld_sect.h"
44 #include "kxld_seg.h"
45 #include "kxld_symtab.h"
46 #include "kxld_util.h"
47
48 #define MAX_SEGS 20
49
50 #define TEXT_SEG_PROT (VM_PROT_READ | VM_PROT_EXECUTE)
51 #define DATA_SEG_PROT (VM_PROT_READ | VM_PROT_WRITE)
52
53 extern boolean_t isSplitKext;
54 extern boolean_t isOldInterface;
55
56 #if KXLD_USER_OR_OBJECT
57 static kern_return_t reorder_sections(KXLDSeg *seg, KXLDArray *section_order);
58 static void reorder_section(KXLDArray *sects, u_int *sect_reorder_index,
59 KXLDSect **reorder_buffer, u_int reorder_buffer_index);
60 #endif /* KXLD_USER_OR_OBJECT */
61
62 #if 0
63 static KXLDSeg * get_segment_by_name(KXLDArray *segarray, const char *name);
64 #endif
65
66 #if KXLD_USER_OR_ILP32
67 static kern_return_t seg_export_macho_header_32(const KXLDSeg *seg, u_char *buf,
68 u_long *header_offset, u_long header_size, u_long data_offset);
69 #endif
70 #if KXLD_USER_OR_LP64
71 static kern_return_t seg_export_macho_header_64(const KXLDSeg *seg, u_char *buf,
72 u_long *header_offset, u_long header_size, u_long data_offset);
73 #endif
74
75 static KXLDSect * get_sect_by_index(const KXLDSeg *seg, u_int idx);
76
77 #if KXLD_USER_OR_ILP32
78 /*******************************************************************************
79 *******************************************************************************/
80 kern_return_t
81 kxld_seg_init_from_macho_32(KXLDSeg *seg, struct segment_command *src)
82 {
83 kern_return_t rval = KERN_FAILURE;
84 check(seg);
85 check(src);
86
87 strlcpy(seg->segname, src->segname, sizeof(seg->segname));
88 seg->base_addr = src->vmaddr;
89 seg->link_addr = src->vmaddr;
90 seg->vmsize = src->vmsize;
91 seg->fileoff = src->fileoff;
92 seg->maxprot = src->maxprot;
93 seg->initprot = src->initprot;
94 seg->flags = src->flags;
95
96 rval = kxld_array_init(&seg->sects, sizeof(KXLDSect *), src->nsects);
97 require_noerr(rval, finish);
98
99 rval = KERN_SUCCESS;
100
101 finish:
102 return rval;
103 }
104 #endif /* KXLD_USER_OR_ILP32 */
105
106 #if KXLD_USER_OR_LP64
107 /*******************************************************************************
108 *******************************************************************************/
109 kern_return_t
110 kxld_seg_init_from_macho_64(KXLDSeg *seg, struct segment_command_64 *src)
111 {
112 kern_return_t rval = KERN_FAILURE;
113 check(seg);
114 check(src);
115
116 strlcpy(seg->segname, src->segname, sizeof(seg->segname));
117 seg->base_addr = src->vmaddr;
118 seg->link_addr = src->vmaddr;
119 seg->vmsize = src->vmsize;
120
121 seg->fileoff = src->fileoff;
122 seg->maxprot = src->maxprot;
123 seg->initprot = src->initprot;
124 seg->flags = src->flags;
125
126 rval = kxld_array_init(&seg->sects, sizeof(KXLDSect *), src->nsects);
127 require_noerr(rval, finish);
128
129 rval = KERN_SUCCESS;
130
131 finish:
132 return rval;
133 }
134 #endif /* KXLD_USER_OR_LP64 */
135
136 #if KXLD_USER_OR_OBJECT
137 /*******************************************************************************
138 *******************************************************************************/
139 kern_return_t
140 kxld_seg_create_seg_from_sections(KXLDArray *segarray, KXLDArray *sectarray)
141 {
142 kern_return_t rval = KERN_FAILURE;
143 KXLDSeg *seg = NULL;
144 KXLDSect *sect = NULL;
145 KXLDSect **sectp = NULL;
146 u_int i = 0;
147
148 /* Initialize the segment array to one segment */
149
150 rval = kxld_array_init(segarray, sizeof(KXLDSeg), 1);
151 require_noerr(rval, finish);
152
153 /* Initialize the segment */
154
155 seg = kxld_array_get_item(segarray, 0);
156 seg->initprot = VM_PROT_ALL;
157 seg->maxprot = VM_PROT_ALL;
158 seg->link_addr = 0;
159
160 /* Add the sections to the segment */
161
162 rval = kxld_array_init(&seg->sects, sizeof(KXLDSect *), sectarray->nitems);
163 require_noerr(rval, finish);
164
165 for (i = 0; i < sectarray->nitems; ++i) {
166 sect = kxld_array_get_item(sectarray, i);
167 sectp = kxld_array_get_item(&seg->sects, i);
168
169 *sectp = sect;
170 }
171
172 rval = KERN_SUCCESS;
173 finish:
174 return rval;
175 }
176
177 /*******************************************************************************
178 *******************************************************************************/
179 kern_return_t
180 kxld_seg_finalize_object_segment(KXLDArray *segarray, KXLDArray *section_order,
181 u_long hdrsize)
182 {
183 kern_return_t rval = KERN_FAILURE;
184 KXLDSeg *seg = NULL;
185 KXLDSect *sect = NULL;
186 u_long sect_offset = 0;
187 u_int i = 0;
188
189 check(segarray);
190 check(section_order);
191 require_action(segarray->nitems == 1, finish, rval=KERN_FAILURE);
192
193 seg = kxld_array_get_item(segarray, 0);
194
195 /* Reorder the sections */
196
197 rval = reorder_sections(seg, section_order);
198 require_noerr(rval, finish);
199
200 /* Set the initial link address at the end of the header pages */
201
202 seg->link_addr = kxld_round_page_cross_safe(hdrsize);
203
204 /* Fix up all of the section addresses */
205
206 sect_offset = (u_long) seg->link_addr;
207 for (i = 0; i < seg->sects.nitems; ++i) {
208 sect = *(KXLDSect **)kxld_array_get_item(&seg->sects, i);
209
210 sect->link_addr = kxld_sect_align_address(sect, sect_offset);
211 sect_offset = (u_long) (sect->link_addr + sect->size);
212 }
213
214 /* Finish initializing the segment */
215
216 seg->vmsize = kxld_round_page_cross_safe(sect_offset) - seg->link_addr;
217
218 rval = KERN_SUCCESS;
219 finish:
220 return rval;
221 }
222
223 /*******************************************************************************
224 * The legacy section ordering used by kld was based of the order of sections
225 * in the kernel file. To achieve the same layout, we save the kernel's
226 * section ordering as an array of section names when the kernel file itself
227 * is linked. Then, when kexts are linked with the KXLD_LEGACY_LAYOUT flag,
228 * we refer to the kernel's section layout to order the kext's sections.
229 *
230 * The algorithm below is as follows. We iterate through all of the kernel's
231 * sections grouped by segment name, so that we are processing all of the __TEXT
232 * sections, then all of the __DATA sections, etc. We then iterate through the
233 * kext's sections with a similar grouping, looking for sections that match
234 * the current kernel's section. In this way, we order all of the matching
235 * kext sections in the order in which they appear in the kernel, and then place
236 * all remaining kext sections at the end of the current segment grouping in
237 * the order in which they originally appeared. Sections that only appear in
238 * the kernel are not created. segments that only appear in the kext are
239 * left in their original ordering.
240 *
241 * An example:
242 *
243 * Kernel sections:
244 * __TEXT,__text
245 * __TEXT,__const
246 * __DATA,__data
247 *
248 * Kext sections:
249 * __TEXT,__const
250 * __TEXT,__literal4
251 * __TEXT,__text
252 * __DATA,__const
253 * __DATA,__data
254 *
255 * Reordered kext sections:
256 * __TEXT,__text
257 * __TEXT,__const
258 * __TEXT,__literal4
259 * __DATA,__data
260 * __DATA,__const
261 *
262 * In the implementation below, we use a reorder buffer to hold pointers to the
263 * sections of the current working segment. We scan this buffer looking for
264 * matching sections, placing them in the segment's section index as we find them.
265 * If this function must exit early, the segment's section index is left in an
266 * unusable state.
267 *******************************************************************************/
268 static kern_return_t
269 reorder_sections(KXLDSeg *seg, KXLDArray *section_order)
270 {
271 kern_return_t rval = KERN_FAILURE;
272 KXLDSect *sect = NULL;
273 KXLDSect **reorder_buffer = NULL;
274 KXLDSectionName *section_name = NULL;
275 const char *segname = NULL;
276 u_int sect_index = 0, legacy_index = 0, sect_reorder_index = 0;
277 u_int i = 0, j = 0;
278 u_int sect_start = 0, sect_end = 0, legacy_start = 0, legacy_end = 0;
279 u_int nsects = 0;
280
281 check(seg);
282 check(section_order);
283
284 /* Allocate the reorder buffer with enough space to hold all of the
285 * sections.
286 */
287
288 reorder_buffer = kxld_alloc(
289 seg->sects.nitems * sizeof(*reorder_buffer));
290 require_action(reorder_buffer, finish, rval=KERN_RESOURCE_SHORTAGE);
291
292 while (legacy_index < section_order->nitems) {
293
294 /* Find the next group of sections with a common segment in the
295 * section_order array.
296 */
297
298 legacy_start = legacy_index++;
299 legacy_end = legacy_index;
300
301 section_name = kxld_array_get_item(section_order, legacy_start);
302 segname = section_name->segname;
303 while (legacy_index < section_order->nitems) {
304 section_name = kxld_array_get_item(section_order, legacy_index);
305 if (!streq_safe(segname, section_name->segname,
306 sizeof(section_name->segname)))
307 {
308 break;
309 }
310
311 ++legacy_index;
312 ++legacy_end;
313 }
314
315 /* Find a group of sections in the kext that match the current
316 * section_order segment.
317 */
318
319 sect_start = sect_index;
320 sect_end = sect_index;
321
322 while (sect_index < seg->sects.nitems) {
323 sect = *(KXLDSect **) kxld_array_get_item(&seg->sects, sect_index);
324 if (!streq_safe(segname, sect->segname, sizeof(sect->segname))) {
325 break;
326 }
327
328 ++sect_index;
329 ++sect_end;
330 }
331 nsects = sect_end - sect_start;
332
333 if (!nsects) continue;
334
335 /* Populate the reorder buffer with the current group of kext sections */
336
337 for (i = sect_start; i < sect_end; ++i) {
338 reorder_buffer[i - sect_start] =
339 *(KXLDSect **) kxld_array_get_item(&seg->sects, i);
340 }
341
342 /* For each section_order section, scan the reorder buffer for a matching
343 * kext section. If one is found, copy it into the next slot in the
344 * segment's section index.
345 */
346
347 sect_reorder_index = sect_start;
348 for (i = legacy_start; i < legacy_end; ++i) {
349 section_name = kxld_array_get_item(section_order, i);
350 sect = NULL;
351
352 for (j = 0; j < nsects; ++j) {
353 sect = reorder_buffer[j];
354 if (!sect) continue;
355
356 if (streq_safe(section_name->sectname, sect->sectname,
357 sizeof(section_name->sectname)))
358 {
359 break;
360 }
361
362 sect = NULL;
363 }
364
365 if (sect) {
366 (void) reorder_section(&seg->sects, &sect_reorder_index,
367 reorder_buffer, j);
368 }
369 }
370
371 /* If any sections remain in the reorder buffer, they are not specified
372 * in the section_order array, so append them to the section index in
373 * in the order they are found.
374 */
375
376 for (i = 0; i < nsects; ++i) {
377 if (!reorder_buffer[i]) continue;
378 reorder_section(&seg->sects, &sect_reorder_index, reorder_buffer, i);
379 }
380 }
381
382 rval = KERN_SUCCESS;
383
384 finish:
385
386 if (reorder_buffer) {
387 kxld_free(reorder_buffer, seg->sects.nitems * sizeof(*reorder_buffer));
388 reorder_buffer = NULL;
389 }
390
391 return rval;
392 }
393
394 /*******************************************************************************
395 *******************************************************************************/
396 static void
397 reorder_section(KXLDArray *sects, u_int *sect_reorder_index,
398 KXLDSect **reorder_buffer, u_int reorder_buffer_index)
399 {
400 KXLDSect **tmp = NULL;
401
402 tmp = kxld_array_get_item(sects, *sect_reorder_index);
403
404 *tmp = reorder_buffer[reorder_buffer_index];
405 reorder_buffer[reorder_buffer_index]->sectnum = *sect_reorder_index;
406 reorder_buffer[reorder_buffer_index] = NULL;
407
408 ++(*sect_reorder_index);
409 }
410
411 /*******************************************************************************
412 *******************************************************************************/
413 kern_return_t
414 kxld_seg_init_linkedit(KXLDArray *segs)
415 {
416 kern_return_t rval = KERN_FAILURE;
417 KXLDSeg *seg = NULL;
418 KXLDSeg *le = NULL;
419
420 rval = kxld_array_resize(segs, 2);
421 require_noerr(rval, finish);
422
423 seg = kxld_array_get_item(segs, 0);
424 le = kxld_array_get_item(segs, 1);
425
426 strlcpy(le->segname, SEG_LINKEDIT, sizeof(le->segname));
427 le->link_addr = kxld_round_page_cross_safe(seg->link_addr + seg->vmsize);
428 le->maxprot = VM_PROT_ALL;
429 le->initprot = VM_PROT_DEFAULT;
430
431 rval = KERN_SUCCESS;
432
433 finish:
434 return rval;
435 }
436 #endif /* KXLD_USER_OR_OBJECT */
437
438 /*******************************************************************************
439 *******************************************************************************/
440 void
441 kxld_seg_clear(KXLDSeg *seg)
442 {
443 check(seg);
444
445 bzero(seg->segname, sizeof(seg->segname));
446 seg->base_addr = 0;
447 seg->link_addr = 0;
448 seg->vmsize = 0;
449 seg->flags = 0;
450 seg->maxprot = 0;
451 seg->initprot = 0;
452
453 /* Don't clear the individual sections here because kxld_kext.c will take
454 * care of that.
455 */
456 kxld_array_clear(&seg->sects);
457 }
458
459 /*******************************************************************************
460 *******************************************************************************/
461 void
462 kxld_seg_deinit(KXLDSeg *seg)
463 {
464 check(seg);
465
466 kxld_array_deinit(&seg->sects);
467 bzero(seg, sizeof(*seg));
468 }
469
470 /*******************************************************************************
471 *******************************************************************************/
472 kxld_size_t
473 kxld_seg_get_vmsize(const KXLDSeg *seg)
474 {
475 check(seg);
476
477 return seg->vmsize;
478 }
479
480 /*******************************************************************************
481 *******************************************************************************/
482 u_long
483 kxld_seg_get_macho_header_size(const KXLDSeg *seg, boolean_t is_32_bit)
484 {
485 u_long size = 0;
486
487 check(seg);
488
489 if (is_32_bit) {
490 size += sizeof(struct segment_command);
491 } else {
492 size += sizeof(struct segment_command_64);
493 }
494 size += seg->sects.nitems * kxld_sect_get_macho_header_size(is_32_bit);
495
496 return size;
497 }
498
499 /*******************************************************************************
500 *******************************************************************************/
501 /* This is no longer used, but may be useful some day... */
502 #if 0
503 u_long
504 kxld_seg_get_macho_data_size(const KXLDSeg *seg)
505 {
506 u_long size = 0;
507 u_int i = 0;
508 KXLDSect *sect = NULL;
509
510 check(seg);
511
512 for (i = 0; i < seg->sects.nitems; ++i) {
513 sect = get_sect_by_index(seg, i);
514 size = (u_long) kxld_sect_align_address(sect, size);
515 size += kxld_sect_get_macho_data_size(sect);
516 }
517
518 return kxld_round_page_cross_safe(size);
519 }
520 #endif
521
522 /*******************************************************************************
523 *******************************************************************************/
524 static KXLDSect *
525 get_sect_by_index(const KXLDSeg *seg, u_int idx)
526 {
527 check(seg);
528
529 return *(KXLDSect **) kxld_array_get_item(&seg->sects, idx);
530 }
531
532 /*******************************************************************************
533 *******************************************************************************/
534 kern_return_t
535 kxld_seg_export_macho_to_file_buffer(const KXLDSeg *seg, u_char *buf,
536 u_long *header_offset, u_long header_size,
537 u_long *data_offset, u_long data_size,
538 boolean_t is_32_bit)
539 {
540 kern_return_t rval = KERN_FAILURE;
541 KXLDSect *sect = NULL;
542 u_long base_data_offset = *data_offset;
543 u_int i = 0;
544 struct segment_command *hdr32 =
545 (struct segment_command *) ((void *) (buf + *header_offset));
546 struct segment_command_64 *hdr64 =
547 (struct segment_command_64 *) ((void *) (buf + *header_offset));
548
549 check(seg);
550 check(buf);
551 check(header_offset);
552 check(data_offset);
553
554 /* Write out the header */
555
556 KXLD_3264_FUNC(is_32_bit, rval,
557 seg_export_macho_header_32, seg_export_macho_header_64,
558 seg, buf, header_offset, header_size, *data_offset);
559 require_noerr(rval, finish);
560
561 /* Write out each section */
562
563 for (i = 0; i < seg->sects.nitems; ++i) {
564 sect = get_sect_by_index(seg, i);
565
566 rval = kxld_sect_export_macho_to_file_buffer(sect, buf, header_offset,
567 header_size, data_offset, data_size, is_32_bit);
568 require_noerr(rval, finish);
569 }
570
571 /* Update the filesize */
572
573 if (is_32_bit) {
574 hdr32->filesize = (uint32_t) (*data_offset - base_data_offset);
575 } else {
576 hdr64->filesize = (uint64_t) (*data_offset - base_data_offset);
577 }
578
579 *data_offset = (u_long)kxld_round_page_cross_safe(*data_offset);
580
581 rval = KERN_SUCCESS;
582
583 finish:
584 return rval;
585
586 }
587
588
589 /*******************************************************************************
590 *******************************************************************************/
591 kern_return_t
592 kxld_seg_export_macho_to_vm(const KXLDSeg *seg,
593 u_char *buf,
594 u_long *header_offset,
595 u_long header_size,
596 u_long data_size,
597 kxld_addr_t file_link_addr,
598 boolean_t is_32_bit)
599 {
600 kern_return_t rval = KERN_FAILURE;
601 KXLDSect * sect = NULL;
602
603 // data_offset is used to set fileoff field in segment header
604 u_long data_offset;
605 u_int i = 0;
606
607 check(seg);
608 check(buf);
609 check(header_offset);
610
611 data_offset = (u_long) (seg->link_addr - file_link_addr);
612
613 /* Write out the header */
614
615 KXLD_3264_FUNC(is_32_bit, rval,
616 seg_export_macho_header_32, seg_export_macho_header_64,
617 seg,
618 buf,
619 header_offset, header_size, data_offset);
620 require_noerr(rval, finish);
621
622 /* Write out each section */
623
624 for (i = 0; i < seg->sects.nitems; ++i) {
625 sect = get_sect_by_index(seg, i);
626
627 rval = kxld_sect_export_macho_to_vm(sect, buf, header_offset,
628 header_size, file_link_addr, data_size, is_32_bit);
629 require_noerr(rval, finish);
630 }
631
632 rval = KERN_SUCCESS;
633
634 finish:
635 return rval;
636 }
637
638 #if KXLD_USER_OR_ILP32
639 /*******************************************************************************
640 *******************************************************************************/
641 static kern_return_t
642 seg_export_macho_header_32(const KXLDSeg *seg, u_char *buf,
643 u_long *header_offset, u_long header_size, u_long data_offset)
644 {
645 kern_return_t rval = KERN_FAILURE;
646 struct segment_command *seghdr = NULL;
647
648 check(seg);
649 check(buf);
650 check(header_offset);
651
652 require_action(sizeof(*seghdr) <= header_size - *header_offset, finish,
653 rval=KERN_FAILURE);
654 seghdr = (struct segment_command *) ((void *) (buf + *header_offset));
655 *header_offset += sizeof(*seghdr);
656
657 seghdr->cmd = LC_SEGMENT;
658 seghdr->cmdsize = (uint32_t) sizeof(*seghdr);
659 seghdr->cmdsize +=
660 (uint32_t) (seg->sects.nitems * kxld_sect_get_macho_header_size(TRUE));
661 strlcpy(seghdr->segname, seg->segname, sizeof(seghdr->segname));
662 seghdr->vmaddr = (uint32_t) seg->link_addr;
663 seghdr->vmsize = (uint32_t) seg->vmsize;
664 seghdr->fileoff = (uint32_t) data_offset;
665 seghdr->filesize = (uint32_t) seg->vmsize;
666 seghdr->maxprot = seg->maxprot;
667 seghdr->initprot = seg->initprot;
668 seghdr->nsects = seg->sects.nitems;
669 seghdr->flags = 0;
670
671 #if SPLIT_KEXTS_DEBUG
672 {
673 kxld_log(kKxldLogLinking, kKxldLogErr,
674 "segname %s seghdr %p vmaddr %p vmsize 0x%02X %u fileoff 0x%02X %u <%s>",
675 seg->segname[0] ? seg->segname : "none",
676 (void *) seghdr,
677 (void *) ((uint64_t)seghdr->vmaddr),
678 seghdr->vmsize,
679 seghdr->vmsize,
680 seghdr->fileoff,
681 seghdr->fileoff,
682 __func__);
683 }
684 #endif
685
686 rval = KERN_SUCCESS;
687
688 finish:
689 return rval;
690 }
691 #endif /* KXLD_USER_OR_ILP32 */
692
693 #if KXLD_USER_OR_LP64
694 /*******************************************************************************
695 *******************************************************************************/
696 static kern_return_t
697 seg_export_macho_header_64(const KXLDSeg *seg, u_char *buf,
698 u_long *header_offset, u_long header_size, u_long data_offset)
699 {
700 kern_return_t rval = KERN_FAILURE;
701 struct segment_command_64 *seghdr = NULL;
702
703 check(seg);
704 check(buf);
705 check(header_offset);
706
707 require_action(sizeof(*seghdr) <= header_size - *header_offset, finish,
708 rval=KERN_FAILURE);
709
710 #if SPLIT_KEXTS_DEBUG
711 {
712 struct mach_header_64 *mach;
713
714 mach = (struct mach_header_64 *) ((void *) buf);
715
716 if (mach->magic != MH_MAGIC_64) {
717 kxld_log(kKxldLogLinking, kKxldLogErr,
718 "bad macho header at %p <%s>",
719 (void *) mach, __func__);
720 goto finish;
721 }
722 }
723 #endif
724
725 seghdr = (struct segment_command_64 *) ((void *) (buf + *header_offset));
726 *header_offset += sizeof(*seghdr);
727
728 seghdr->cmd = LC_SEGMENT_64;
729 seghdr->cmdsize = (uint32_t) sizeof(*seghdr);
730 seghdr->cmdsize +=
731 (uint32_t) (seg->sects.nitems * kxld_sect_get_macho_header_size(FALSE));
732 strlcpy(seghdr->segname, seg->segname, sizeof(seghdr->segname));
733 seghdr->vmaddr = (uint64_t) seg->link_addr;
734 seghdr->vmsize = (uint64_t) seg->vmsize;
735 seghdr->fileoff = (uint64_t) data_offset;
736 seghdr->filesize = (uint64_t) seg->vmsize;
737 seghdr->maxprot = seg->maxprot;
738 seghdr->initprot = seg->initprot;
739 seghdr->nsects = seg->sects.nitems;
740 seghdr->flags = 0;
741
742 #if SPLIT_KEXTS_DEBUG
743 {
744 kxld_log(kKxldLogLinking, kKxldLogErr,
745 "%p >>> Start of %s seghdr (size %lu) <%s>",
746 (void *) seghdr,
747 seg->segname[0] ? seg->segname : "none",
748 sizeof(*seghdr),
749 __func__);
750 kxld_log(kKxldLogLinking, kKxldLogErr,
751 "%p <<< End of %s seghdr <%s>",
752 (void *) ((u_char *)seghdr + sizeof(*seghdr)),
753 seg->segname[0] ? seg->segname : "none",
754 __func__);
755
756 kxld_log(kKxldLogLinking, kKxldLogErr,
757 "%s seghdr, cmdsize %d vmaddr %p vmsize %p %llu fileoff %p %llu <%s>",
758 seg->segname[0] ? seg->segname : "none",
759 seghdr->cmdsize,
760 (void *) seghdr->vmaddr,
761 (void *) seghdr->vmsize,
762 seghdr->vmsize,
763 (void *) seghdr->fileoff,
764 seghdr->fileoff,
765 __func__);
766 }
767 #endif
768
769 rval = KERN_SUCCESS;
770
771 finish:
772 return rval;
773 }
774 #endif /* KXLD_USER_OR_LP64 */
775
776 /*******************************************************************************
777 *******************************************************************************/
778 kern_return_t
779 kxld_seg_add_section(KXLDSeg *seg, KXLDSect *sect)
780 {
781 kern_return_t rval = KERN_FAILURE;
782 KXLDSect **sectp = NULL;
783 u_int i;
784
785 check(seg);
786 check(sect);
787 require_action(streq_safe(seg->segname, sect->segname, sizeof(seg->segname)),
788 finish, rval=KERN_FAILURE);
789
790 /* Add the section into the section index */
791
792 for (i = 0; i < seg->sects.nitems; ++i) {
793 sectp = kxld_array_get_item(&seg->sects, i);
794 if (NULL == *sectp) {
795 *sectp = sect;
796 break;
797 }
798 }
799 require_action(i < seg->sects.nitems, finish, rval=KERN_FAILURE);
800
801 rval = KERN_SUCCESS;
802
803 finish:
804
805 return rval;
806 }
807
808 /*******************************************************************************
809 *******************************************************************************/
810 kern_return_t
811 kxld_seg_finish_init(KXLDSeg *seg)
812 {
813 kern_return_t rval = KERN_FAILURE;
814 u_int i = 0;
815 KXLDSect *sect = NULL;
816 kxld_addr_t maxaddr = 0;
817 kxld_size_t maxsize = 0;
818
819 /* If we already have a size for this segment (e.g. from the mach-o load
820 * command) then don't recalculate the segment size. This is safer since
821 * when we recalculate we are making assumptions about page alignment and
822 * padding that the kext mach-o file was built with. Better to trust the
823 * macho-o info, if we have it. If we don't (i.e. vmsize == 0) then add up
824 * the section sizes and take a best guess at page padding.
825 */
826 if ((seg->vmsize == 0) && (seg->sects.nitems)) {
827 for (i = 0; i < seg->sects.nitems; ++i) {
828 sect = get_sect_by_index(seg, i);
829 require_action(sect, finish, rval=KERN_FAILURE);
830 if (sect->base_addr > maxaddr) {
831 maxaddr = sect->base_addr;
832 maxsize = sect->size;
833 }
834 }
835 seg->vmsize = kxld_round_page_cross_safe(maxaddr +
836 maxsize - seg->base_addr);
837
838 }
839
840 rval = KERN_SUCCESS;
841
842 finish:
843 return rval;
844 }
845
846 /*******************************************************************************
847 *******************************************************************************/
848 void
849 kxld_seg_set_vm_protections(KXLDSeg *seg, boolean_t strict_protections)
850 {
851 if (strict_protections) {
852 if (!strncmp(seg->segname, SEG_TEXT, sizeof(seg->segname))) {
853 seg->initprot = TEXT_SEG_PROT;
854 seg->maxprot = TEXT_SEG_PROT;
855 } else {
856 seg->initprot = DATA_SEG_PROT;
857 seg->maxprot = DATA_SEG_PROT;
858 }
859 } else {
860 seg->initprot = VM_PROT_ALL;
861 seg->maxprot = VM_PROT_ALL;
862 }
863 }
864
865 /*******************************************************************************
866 *******************************************************************************/
867 void
868 kxld_seg_relocate(KXLDSeg *seg, kxld_addr_t link_addr)
869 {
870 KXLDSect *sect = NULL;
871 u_int i = 0;
872 splitKextLinkInfo * link_info = (splitKextLinkInfo *) link_addr;
873 kxld_addr_t my_link_addr;
874
875 if (isOldInterface) {
876 seg->link_addr += link_addr;
877 }
878 else {
879 if (isSplitKext) {
880 // we have a split kext
881 if (kxld_seg_is_text_seg(seg)) {
882 // assumes this is the beginning of the kext
883 my_link_addr = link_info->vmaddr_TEXT;
884 seg->link_addr = my_link_addr;
885 }
886 else if (kxld_seg_is_text_exec_seg(seg)) {
887 my_link_addr = link_info->vmaddr_TEXT_EXEC;
888 seg->link_addr = my_link_addr;
889 // vmaddr_TEXT_EXEC is the actual vmaddr for this segment so we need
890 // to adjust for kxld_sect_relocate assuming the link addr is
891 // the address of the kext (macho header in __TEXT)
892 my_link_addr -= seg->base_addr;
893 }
894 else if (kxld_seg_is_data_seg(seg)) {
895 my_link_addr = link_info->vmaddr_DATA;
896 seg->link_addr = my_link_addr;
897 // vmaddr_DATA is the actual vmaddr for this segment so we need
898 // to adjust for kxld_sect_relocate assuming the link addr is
899 // the address of the kext (macho header in __TEXT)
900 my_link_addr -= seg->base_addr;
901 }
902 else if (kxld_seg_is_data_const_seg(seg)) {
903 my_link_addr = link_info->vmaddr_DATA_CONST;
904 seg->link_addr = my_link_addr;
905 // vmaddr_DATA_CONST is the actual vmaddr for this segment so we need
906 // to adjust for kxld_sect_relocate assuming the link addr is
907 // the address of the kext (macho header in __TEXT)
908 my_link_addr -= seg->base_addr;
909 }
910 else if (kxld_seg_is_llvm_cov_seg(seg)) {
911 my_link_addr = link_info->vmaddr_LLVM_COV;
912 seg->link_addr = my_link_addr;
913 // vmaddr_LLVM_COV is the actual vmaddr for this segment so we need
914 // to adjust for kxld_sect_relocate assuming the link addr is
915 // the address of the kext (macho header in __TEXT)
916 my_link_addr -= seg->base_addr;
917 }
918 else if (kxld_seg_is_linkedit_seg(seg)) {
919 my_link_addr = link_info->vmaddr_LINKEDIT;
920 seg->link_addr = my_link_addr;
921 // vmaddr_DATA is the actual vmaddr for this segment so we need
922 // to adjust for kxld_sect_relocate assuming the link addr is
923 // the address of the kext (macho header in __TEXT)
924 my_link_addr -= seg->base_addr;
925 }
926 else {
927 kxld_log(kKxldLogLinking, kKxldLogErr,
928 " not expecting this segment %s!!! <%s>",
929 seg->segname[0] ? seg->segname : "none",
930 __func__);
931 my_link_addr = link_info->vmaddr_TEXT;
932 seg->link_addr += my_link_addr;
933 }
934 }
935 else {
936 my_link_addr = link_info->vmaddr_TEXT;
937 seg->link_addr += my_link_addr;
938 }
939 }
940
941 #if SPLIT_KEXTS_DEBUG
942 {
943 kxld_log(kKxldLogLinking, kKxldLogErr,
944 "%p >>> Start of %s segment (vmsize %llu) <%s>)",
945 (void *) seg->link_addr,
946 seg->segname[0] ? seg->segname : "none",
947 seg->vmsize,
948 __func__);
949 kxld_log(kKxldLogLinking, kKxldLogErr,
950 "%p <<< End of %s segment <%s>",
951 (void *) (seg->link_addr + seg->vmsize),
952 seg->segname[0] ? seg->segname : "none",
953 __func__);
954 }
955 #endif
956
957 for (i = 0; i < seg->sects.nitems; ++i) {
958 sect = get_sect_by_index(seg, i);
959 if (isOldInterface) {
960 kxld_sect_relocate(sect, link_addr);
961 }
962 else {
963 kxld_sect_relocate(sect, my_link_addr);
964 }
965 }
966 }
967
968 /*******************************************************************************
969 *******************************************************************************/
970 void
971 kxld_seg_populate_linkedit(KXLDSeg *seg, const KXLDSymtab *symtab, boolean_t is_32_bit
972 #if KXLD_PIC_KEXTS
973 , const KXLDArray *locrelocs
974 , const KXLDArray *extrelocs
975 , boolean_t target_supports_slideable_kexts
976 #endif /* KXLD_PIC_KEXTS */
977 , uint32_t splitinfolc_size
978 )
979 {
980 u_long size = 0;
981
982 size += kxld_symtab_get_macho_data_size(symtab, is_32_bit);
983
984 #if KXLD_PIC_KEXTS
985 if (target_supports_slideable_kexts) {
986 size += kxld_reloc_get_macho_data_size(locrelocs, extrelocs);
987 }
988 #endif /* KXLD_PIC_KEXTS */
989
990 // 0 unless this is a split kext
991 size += splitinfolc_size;
992
993 seg->vmsize = kxld_round_page_cross_safe(size);
994 }
995
996 /*******************************************************************************
997 *******************************************************************************/
998 boolean_t
999 kxld_seg_is_split_seg(const KXLDSeg *seg)
1000 {
1001 boolean_t result = FALSE;
1002
1003 check(seg);
1004 if (isSplitKext) {
1005 if (kxld_seg_is_data_seg(seg) || kxld_seg_is_linkedit_seg(seg) ||
1006 kxld_seg_is_text_exec_seg(seg) || kxld_seg_is_data_const_seg(seg) ||
1007 kxld_seg_is_llvm_cov_seg(seg)) {
1008 result = TRUE;
1009 }
1010 }
1011
1012 return result;
1013 }
1014
1015 boolean_t
1016 kxld_seg_is_text_seg(const KXLDSeg *seg)
1017 {
1018 boolean_t result = FALSE;
1019
1020 check(seg);
1021 result = !strncmp(seg->segname, SEG_TEXT, sizeof(seg->segname));
1022
1023 return result;
1024 }
1025
1026 boolean_t
1027 kxld_seg_is_text_exec_seg(const KXLDSeg *seg)
1028 {
1029 boolean_t result = FALSE;
1030
1031 check(seg);
1032 result = !strncmp(seg->segname, "__TEXT_EXEC", sizeof(seg->segname));
1033
1034 return result;
1035 }
1036
1037 boolean_t
1038 kxld_seg_is_data_seg(const KXLDSeg *seg)
1039 {
1040 boolean_t result = FALSE;
1041
1042 check(seg);
1043 result = !strncmp(seg->segname, SEG_DATA, sizeof(seg->segname));
1044
1045 return result;
1046 }
1047
1048 boolean_t
1049 kxld_seg_is_data_const_seg(const KXLDSeg *seg)
1050 {
1051 boolean_t result = FALSE;
1052
1053 check(seg);
1054 result = !strncmp(seg->segname, "__DATA_CONST", sizeof(seg->segname));
1055
1056 return result;
1057 }
1058
1059 boolean_t
1060 kxld_seg_is_linkedit_seg(const KXLDSeg *seg)
1061 {
1062 boolean_t result = FALSE;
1063
1064 check(seg);
1065 result = !strncmp(seg->segname, SEG_LINKEDIT, sizeof(seg->segname));
1066
1067 return result;
1068 }
1069
1070 boolean_t
1071 kxld_seg_is_llvm_cov_seg(const KXLDSeg *seg)
1072 {
1073 boolean_t result = FALSE;
1074
1075 check(seg);
1076 result = !strncmp(seg->segname, "__LLVM_COV", sizeof(seg->segname));
1077
1078 return result;
1079 }