]> git.saurik.com Git - apple/xnu.git/blame - libkern/kxld/kxld_seg.c
xnu-7195.50.7.100.1.tar.gz
[apple/xnu.git] / libkern / kxld / kxld_seg.c
CommitLineData
b0d623f7
A
1/*
2 * Copyright (c) 2008 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
0a7de745 5 *
b0d623f7
A
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.
0a7de745 14 *
b0d623f7
A
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
0a7de745 17 *
b0d623f7
A
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.
0a7de745 25 *
b0d623f7
A
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
316670eb 42#include "kxld_reloc.h"
b0d623f7
A
43#include "kxld_sect.h"
44#include "kxld_seg.h"
6d2010ae 45#include "kxld_symtab.h"
b0d623f7
A
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
39037602
A
53extern boolean_t isSplitKext;
54extern boolean_t isOldInterface;
55
b0d623f7
A
56#if KXLD_USER_OR_OBJECT
57static kern_return_t reorder_sections(KXLDSeg *seg, KXLDArray *section_order);
0a7de745 58static void reorder_section(KXLDArray *sects, u_int *sect_reorder_index,
b0d623f7
A
59 KXLDSect **reorder_buffer, u_int reorder_buffer_index);
60#endif /* KXLD_USER_OR_OBJECT */
61
62#if 0
63static KXLDSeg * get_segment_by_name(KXLDArray *segarray, const char *name);
64#endif
65
66#if KXLD_USER_OR_ILP32
67static 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
71static 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
75static KXLDSect * get_sect_by_index(const KXLDSeg *seg, u_int idx);
76
77#if KXLD_USER_OR_ILP32
78/*******************************************************************************
79*******************************************************************************/
80kern_return_t
81kxld_seg_init_from_macho_32(KXLDSeg *seg, struct segment_command *src)
82{
0a7de745
A
83 kern_return_t rval = KERN_FAILURE;
84 check(seg);
85 check(src);
b0d623f7 86
0a7de745
A
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;
b0d623f7 95
0a7de745
A
96 rval = kxld_array_init(&seg->sects, sizeof(KXLDSect *), src->nsects);
97 require_noerr(rval, finish);
b0d623f7 98
0a7de745 99 rval = KERN_SUCCESS;
b0d623f7
A
100
101finish:
0a7de745 102 return rval;
b0d623f7
A
103}
104#endif /* KXLD_USER_OR_ILP32 */
105
106#if KXLD_USER_OR_LP64
107/*******************************************************************************
108*******************************************************************************/
109kern_return_t
110kxld_seg_init_from_macho_64(KXLDSeg *seg, struct segment_command_64 *src)
111{
0a7de745
A
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;
b0d623f7
A
130
131finish:
0a7de745 132 return rval;
b0d623f7
A
133}
134#endif /* KXLD_USER_OR_LP64 */
135
136#if KXLD_USER_OR_OBJECT
137/*******************************************************************************
138*******************************************************************************/
139kern_return_t
140kxld_seg_create_seg_from_sections(KXLDArray *segarray, KXLDArray *sectarray)
141{
0a7de745
A
142 kern_return_t rval = KERN_FAILURE;
143 KXLDSeg *seg = NULL;
144 KXLDSect *sect = NULL;
145 KXLDSect **sectp = NULL;
146 u_int i = 0;
b0d623f7 147
0a7de745 148 /* Initialize the segment array to one segment */
b0d623f7 149
0a7de745
A
150 rval = kxld_array_init(segarray, sizeof(KXLDSeg), 1);
151 require_noerr(rval, finish);
b0d623f7 152
0a7de745 153 /* Initialize the segment */
b0d623f7 154
0a7de745
A
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;
b0d623f7 159
0a7de745 160 /* Add the sections to the segment */
b0d623f7 161
0a7de745
A
162 rval = kxld_array_init(&seg->sects, sizeof(KXLDSect *), sectarray->nitems);
163 require_noerr(rval, finish);
b0d623f7 164
0a7de745
A
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);
b0d623f7 168
0a7de745
A
169 *sectp = sect;
170 }
b0d623f7 171
0a7de745 172 rval = KERN_SUCCESS;
b0d623f7 173finish:
0a7de745 174 return rval;
b0d623f7
A
175}
176
177/*******************************************************************************
178*******************************************************************************/
179kern_return_t
180kxld_seg_finalize_object_segment(KXLDArray *segarray, KXLDArray *section_order,
181 u_long hdrsize)
182{
0a7de745
A
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);
b0d623f7 192
0a7de745 193 seg = kxld_array_get_item(segarray, 0);
b0d623f7 194
0a7de745 195 /* Reorder the sections */
b0d623f7 196
0a7de745
A
197 rval = reorder_sections(seg, section_order);
198 require_noerr(rval, finish);
b0d623f7 199
0a7de745 200 /* Set the initial link address at the end of the header pages */
b0d623f7 201
0a7de745 202 seg->link_addr = kxld_round_page_cross_safe(hdrsize);
b0d623f7 203
0a7de745 204 /* Fix up all of the section addresses */
b0d623f7 205
0a7de745
A
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);
b0d623f7 209
0a7de745
A
210 sect->link_addr = kxld_sect_align_address(sect, sect_offset);
211 sect_offset = (u_long) (sect->link_addr + sect->size);
212 }
b0d623f7 213
0a7de745 214 /* Finish initializing the segment */
b0d623f7 215
0a7de745
A
216 seg->vmsize = kxld_round_page_cross_safe(sect_offset) - seg->link_addr;
217
218 rval = KERN_SUCCESS;
b0d623f7 219finish:
0a7de745 220 return rval;
b0d623f7
A
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
b0d623f7
A
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*******************************************************************************/
268static kern_return_t
269reorder_sections(KXLDSeg *seg, KXLDArray *section_order)
270{
0a7de745
A
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 /* Find the next group of sections with a common segment in the
294 * section_order array.
295 */
296
297 legacy_start = legacy_index++;
298 legacy_end = legacy_index;
299
300 section_name = kxld_array_get_item(section_order, legacy_start);
301 segname = section_name->segname;
302 while (legacy_index < section_order->nitems) {
303 section_name = kxld_array_get_item(section_order, legacy_index);
304 if (!streq_safe(segname, section_name->segname,
305 sizeof(section_name->segname))) {
306 break;
307 }
308
309 ++legacy_index;
310 ++legacy_end;
311 }
312
313 /* Find a group of sections in the kext that match the current
314 * section_order segment.
315 */
316
317 sect_start = sect_index;
318 sect_end = sect_index;
319
320 while (sect_index < seg->sects.nitems) {
321 sect = *(KXLDSect **) kxld_array_get_item(&seg->sects, sect_index);
322 if (!streq_safe(segname, sect->segname, sizeof(sect->segname))) {
323 break;
324 }
325
326 ++sect_index;
327 ++sect_end;
328 }
329 nsects = sect_end - sect_start;
330
331 if (!nsects) {
332 continue;
333 }
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) {
355 continue;
356 }
357
358 if (streq_safe(section_name->sectname, sect->sectname,
359 sizeof(section_name->sectname))) {
360 break;
361 }
362
363 sect = NULL;
364 }
365
366 if (sect) {
367 (void) reorder_section(&seg->sects, &sect_reorder_index,
368 reorder_buffer, j);
369 }
370 }
371
372 /* If any sections remain in the reorder buffer, they are not specified
373 * in the section_order array, so append them to the section index in
374 * in the order they are found.
375 */
376
377 for (i = 0; i < nsects; ++i) {
378 if (!reorder_buffer[i]) {
379 continue;
380 }
381 reorder_section(&seg->sects, &sect_reorder_index, reorder_buffer, i);
382 }
383 }
384
385 rval = KERN_SUCCESS;
b0d623f7
A
386
387finish:
388
0a7de745
A
389 if (reorder_buffer) {
390 kxld_free(reorder_buffer, seg->sects.nitems * sizeof(*reorder_buffer));
391 reorder_buffer = NULL;
392 }
b0d623f7 393
0a7de745 394 return rval;
b0d623f7
A
395}
396
397/*******************************************************************************
398*******************************************************************************/
399static void
0a7de745 400reorder_section(KXLDArray *sects, u_int *sect_reorder_index,
b0d623f7
A
401 KXLDSect **reorder_buffer, u_int reorder_buffer_index)
402{
0a7de745 403 KXLDSect **tmp = NULL;
b0d623f7 404
0a7de745 405 tmp = kxld_array_get_item(sects, *sect_reorder_index);
b0d623f7 406
0a7de745
A
407 *tmp = reorder_buffer[reorder_buffer_index];
408 reorder_buffer[reorder_buffer_index]->sectnum = *sect_reorder_index;
409 reorder_buffer[reorder_buffer_index] = NULL;
b0d623f7 410
0a7de745 411 ++(*sect_reorder_index);
b0d623f7 412}
6d2010ae
A
413
414/*******************************************************************************
415*******************************************************************************/
416kern_return_t
417kxld_seg_init_linkedit(KXLDArray *segs)
418{
0a7de745
A
419 kern_return_t rval = KERN_FAILURE;
420 KXLDSeg *seg = NULL;
421 KXLDSeg *le = NULL;
422
423 rval = kxld_array_resize(segs, 2);
424 require_noerr(rval, finish);
6d2010ae 425
0a7de745
A
426 seg = kxld_array_get_item(segs, 0);
427 le = kxld_array_get_item(segs, 1);
6d2010ae 428
0a7de745
A
429 strlcpy(le->segname, SEG_LINKEDIT, sizeof(le->segname));
430 le->link_addr = kxld_round_page_cross_safe(seg->link_addr + seg->vmsize);
431 le->maxprot = VM_PROT_ALL;
432 le->initprot = VM_PROT_DEFAULT;
6d2010ae 433
0a7de745 434 rval = KERN_SUCCESS;
6d2010ae
A
435
436finish:
0a7de745 437 return rval;
6d2010ae 438}
b0d623f7
A
439#endif /* KXLD_USER_OR_OBJECT */
440
441/*******************************************************************************
442*******************************************************************************/
443void
444kxld_seg_clear(KXLDSeg *seg)
445{
0a7de745
A
446 check(seg);
447
448 bzero(seg->segname, sizeof(seg->segname));
449 seg->base_addr = 0;
450 seg->link_addr = 0;
451 seg->vmsize = 0;
452 seg->flags = 0;
453 seg->maxprot = 0;
454 seg->initprot = 0;
455
456 /* Don't clear the individual sections here because kxld_kext.c will take
457 * care of that.
458 */
459 kxld_array_clear(&seg->sects);
b0d623f7
A
460}
461
462/*******************************************************************************
463*******************************************************************************/
0a7de745 464void
b0d623f7
A
465kxld_seg_deinit(KXLDSeg *seg)
466{
0a7de745 467 check(seg);
b0d623f7 468
0a7de745
A
469 kxld_array_deinit(&seg->sects);
470 bzero(seg, sizeof(*seg));
b0d623f7
A
471}
472
473/*******************************************************************************
474*******************************************************************************/
0a7de745 475kxld_size_t
b0d623f7
A
476kxld_seg_get_vmsize(const KXLDSeg *seg)
477{
0a7de745
A
478 check(seg);
479
480 return seg->vmsize;
b0d623f7
A
481}
482
483/*******************************************************************************
484*******************************************************************************/
485u_long
486kxld_seg_get_macho_header_size(const KXLDSeg *seg, boolean_t is_32_bit)
487{
0a7de745
A
488 u_long size = 0;
489
490 check(seg);
491
492 if (is_32_bit) {
493 size += sizeof(struct segment_command);
494 } else {
495 size += sizeof(struct segment_command_64);
496 }
497 size += seg->sects.nitems * kxld_sect_get_macho_header_size(is_32_bit);
498
499 return size;
b0d623f7
A
500}
501
502/*******************************************************************************
503*******************************************************************************/
316670eb
A
504/* This is no longer used, but may be useful some day... */
505#if 0
b0d623f7
A
506u_long
507kxld_seg_get_macho_data_size(const KXLDSeg *seg)
508{
0a7de745
A
509 u_long size = 0;
510 u_int i = 0;
511 KXLDSect *sect = NULL;
b0d623f7 512
0a7de745 513 check(seg);
b0d623f7 514
0a7de745
A
515 for (i = 0; i < seg->sects.nitems; ++i) {
516 sect = get_sect_by_index(seg, i);
517 size = (u_long) kxld_sect_align_address(sect, size);
518 size += kxld_sect_get_macho_data_size(sect);
519 }
b0d623f7 520
0a7de745 521 return kxld_round_page_cross_safe(size);
b0d623f7 522}
316670eb 523#endif
b0d623f7
A
524
525/*******************************************************************************
526*******************************************************************************/
0a7de745 527static KXLDSect *
b0d623f7
A
528get_sect_by_index(const KXLDSeg *seg, u_int idx)
529{
0a7de745 530 check(seg);
b0d623f7 531
0a7de745 532 return *(KXLDSect **) kxld_array_get_item(&seg->sects, idx);
b0d623f7
A
533}
534
535/*******************************************************************************
536*******************************************************************************/
537kern_return_t
538kxld_seg_export_macho_to_file_buffer(const KXLDSeg *seg, u_char *buf,
0a7de745 539 u_long *header_offset, u_long header_size,
b0d623f7
A
540 u_long *data_offset, u_long data_size,
541 boolean_t is_32_bit)
542{
0a7de745
A
543 kern_return_t rval = KERN_FAILURE;
544 KXLDSect *sect = NULL;
545 u_long base_data_offset = *data_offset;
546 u_int i = 0;
547 struct segment_command *hdr32 =
548 (struct segment_command *) ((void *) (buf + *header_offset));
549 struct segment_command_64 *hdr64 =
550 (struct segment_command_64 *) ((void *) (buf + *header_offset));
b0d623f7 551
0a7de745
A
552 check(seg);
553 check(buf);
554 check(header_offset);
555 check(data_offset);
b0d623f7 556
0a7de745 557 /* Write out the header */
b0d623f7 558
0a7de745
A
559 KXLD_3264_FUNC(is_32_bit, rval,
560 seg_export_macho_header_32, seg_export_macho_header_64,
561 seg, buf, header_offset, header_size, *data_offset);
562 require_noerr(rval, finish);
b0d623f7 563
0a7de745 564 /* Write out each section */
b0d623f7 565
0a7de745
A
566 for (i = 0; i < seg->sects.nitems; ++i) {
567 sect = get_sect_by_index(seg, i);
b0d623f7 568
0a7de745
A
569 rval = kxld_sect_export_macho_to_file_buffer(sect, buf, header_offset,
570 header_size, data_offset, data_size, is_32_bit);
571 require_noerr(rval, finish);
572 }
b0d623f7 573
0a7de745 574 /* Update the filesize */
b0d623f7 575
0a7de745
A
576 if (is_32_bit) {
577 hdr32->filesize = (uint32_t) (*data_offset - base_data_offset);
578 } else {
579 hdr64->filesize = (uint64_t) (*data_offset - base_data_offset);
580 }
b0d623f7 581
0a7de745 582 *data_offset = (u_long)kxld_round_page_cross_safe(*data_offset);
b0d623f7 583
0a7de745 584 rval = KERN_SUCCESS;
b0d623f7
A
585
586finish:
0a7de745 587 return rval;
b0d623f7
A
588}
589
39037602 590
b0d623f7
A
591/*******************************************************************************
592*******************************************************************************/
593kern_return_t
39037602 594kxld_seg_export_macho_to_vm(const KXLDSeg *seg,
0a7de745
A
595 u_char *buf,
596 u_long *header_offset,
597 u_long header_size,
598 u_long data_size,
599 kxld_addr_t file_link_addr,
600 boolean_t is_32_bit)
b0d623f7 601{
0a7de745
A
602 kern_return_t rval = KERN_FAILURE;
603 KXLDSect * sect = NULL;
604
605 // data_offset is used to set fileoff field in segment header
606 u_long data_offset;
607 u_int i = 0;
608
609 check(seg);
610 check(buf);
611 check(header_offset);
b0d623f7 612
0a7de745 613 data_offset = (u_long) (seg->link_addr - file_link_addr);
b0d623f7 614
0a7de745 615 /* Write out the header */
b0d623f7 616
0a7de745
A
617 KXLD_3264_FUNC(is_32_bit, rval,
618 seg_export_macho_header_32, seg_export_macho_header_64,
619 seg,
620 buf,
621 header_offset, header_size, data_offset);
622 require_noerr(rval, finish);
b0d623f7 623
0a7de745 624 /* Write out each section */
b0d623f7 625
0a7de745
A
626 for (i = 0; i < seg->sects.nitems; ++i) {
627 sect = get_sect_by_index(seg, i);
b0d623f7 628
0a7de745
A
629 rval = kxld_sect_export_macho_to_vm(sect, buf, header_offset,
630 header_size, file_link_addr, data_size, is_32_bit);
631 require_noerr(rval, finish);
632 }
b0d623f7 633
0a7de745 634 rval = KERN_SUCCESS;
b0d623f7
A
635
636finish:
0a7de745 637 return rval;
b0d623f7
A
638}
639
640#if KXLD_USER_OR_ILP32
641/*******************************************************************************
642*******************************************************************************/
643static kern_return_t
644seg_export_macho_header_32(const KXLDSeg *seg, u_char *buf,
645 u_long *header_offset, u_long header_size, u_long data_offset)
646{
0a7de745
A
647 kern_return_t rval = KERN_FAILURE;
648 struct segment_command *seghdr = NULL;
649
650 check(seg);
651 check(buf);
652 check(header_offset);
653
654 require_action(sizeof(*seghdr) <= header_size - *header_offset, finish,
655 rval = KERN_FAILURE);
656 seghdr = (struct segment_command *) ((void *) (buf + *header_offset));
657 *header_offset += sizeof(*seghdr);
658
659 seghdr->cmd = LC_SEGMENT;
660 seghdr->cmdsize = (uint32_t) sizeof(*seghdr);
661 seghdr->cmdsize +=
662 (uint32_t) (seg->sects.nitems * kxld_sect_get_macho_header_size(TRUE));
663 strlcpy(seghdr->segname, seg->segname, sizeof(seghdr->segname));
664 seghdr->vmaddr = (uint32_t) seg->link_addr;
665 seghdr->vmsize = (uint32_t) seg->vmsize;
666 seghdr->fileoff = (uint32_t) data_offset;
667 seghdr->filesize = (uint32_t) seg->vmsize;
668 seghdr->maxprot = seg->maxprot;
669 seghdr->initprot = seg->initprot;
670 seghdr->nsects = seg->sects.nitems;
671 seghdr->flags = 0;
b0d623f7 672
39037602 673#if SPLIT_KEXTS_DEBUG
0a7de745
A
674 {
675 kxld_log(kKxldLogLinking, kKxldLogErr,
676 "segname %s seghdr %p vmaddr %p vmsize 0x%02X %u fileoff 0x%02X %u <%s>",
677 seg->segname[0] ? seg->segname : "none",
678 (void *) seghdr,
679 (void *) ((uint64_t)seghdr->vmaddr),
680 seghdr->vmsize,
681 seghdr->vmsize,
682 seghdr->fileoff,
683 seghdr->fileoff,
684 __func__);
685 }
39037602 686#endif
0a7de745
A
687
688 rval = KERN_SUCCESS;
b0d623f7
A
689
690finish:
0a7de745 691 return rval;
b0d623f7
A
692}
693#endif /* KXLD_USER_OR_ILP32 */
694
0a7de745 695#if KXLD_USER_OR_LP64
b0d623f7
A
696/*******************************************************************************
697*******************************************************************************/
698static kern_return_t
699seg_export_macho_header_64(const KXLDSeg *seg, u_char *buf,
700 u_long *header_offset, u_long header_size, u_long data_offset)
701{
0a7de745
A
702 kern_return_t rval = KERN_FAILURE;
703 struct segment_command_64 *seghdr = NULL;
b0d623f7 704
0a7de745
A
705 check(seg);
706 check(buf);
707 check(header_offset);
708
709 require_action(sizeof(*seghdr) <= header_size - *header_offset, finish,
710 rval = KERN_FAILURE);
b0d623f7 711
39037602 712#if SPLIT_KEXTS_DEBUG
0a7de745
A
713 {
714 struct mach_header_64 *mach;
715
716 mach = (struct mach_header_64 *) ((void *) buf);
717
718 if (mach->magic != MH_MAGIC_64) {
719 kxld_log(kKxldLogLinking, kKxldLogErr,
720 "bad macho header at %p <%s>",
721 (void *) mach, __func__);
722 goto finish;
723 }
724 }
39037602 725#endif
0a7de745
A
726
727 seghdr = (struct segment_command_64 *) ((void *) (buf + *header_offset));
728 *header_offset += sizeof(*seghdr);
729
730 seghdr->cmd = LC_SEGMENT_64;
731 seghdr->cmdsize = (uint32_t) sizeof(*seghdr);
732 seghdr->cmdsize +=
733 (uint32_t) (seg->sects.nitems * kxld_sect_get_macho_header_size(FALSE));
734 strlcpy(seghdr->segname, seg->segname, sizeof(seghdr->segname));
735 seghdr->vmaddr = (uint64_t) seg->link_addr;
736 seghdr->vmsize = (uint64_t) seg->vmsize;
737 seghdr->fileoff = (uint64_t) data_offset;
738 seghdr->filesize = (uint64_t) seg->vmsize;
739 seghdr->maxprot = seg->maxprot;
740 seghdr->initprot = seg->initprot;
741 seghdr->nsects = seg->sects.nitems;
742 seghdr->flags = 0;
b0d623f7 743
39037602 744#if SPLIT_KEXTS_DEBUG
0a7de745
A
745 {
746 kxld_log(kKxldLogLinking, kKxldLogErr,
747 "%p >>> Start of %s seghdr (size %lu) <%s>",
748 (void *) seghdr,
749 seg->segname[0] ? seg->segname : "none",
750 sizeof(*seghdr),
751 __func__);
752 kxld_log(kKxldLogLinking, kKxldLogErr,
753 "%p <<< End of %s seghdr <%s>",
754 (void *) ((u_char *)seghdr + sizeof(*seghdr)),
755 seg->segname[0] ? seg->segname : "none",
756 __func__);
757
758 kxld_log(kKxldLogLinking, kKxldLogErr,
759 "%s seghdr, cmdsize %d vmaddr %p vmsize %p %llu fileoff %p %llu <%s>",
760 seg->segname[0] ? seg->segname : "none",
761 seghdr->cmdsize,
762 (void *) seghdr->vmaddr,
763 (void *) seghdr->vmsize,
764 seghdr->vmsize,
765 (void *) seghdr->fileoff,
766 seghdr->fileoff,
767 __func__);
768 }
39037602
A
769#endif
770
0a7de745 771 rval = KERN_SUCCESS;
b0d623f7
A
772
773finish:
0a7de745 774 return rval;
b0d623f7
A
775}
776#endif /* KXLD_USER_OR_LP64 */
777
778/*******************************************************************************
779*******************************************************************************/
780kern_return_t
781kxld_seg_add_section(KXLDSeg *seg, KXLDSect *sect)
782{
0a7de745
A
783 kern_return_t rval = KERN_FAILURE;
784 KXLDSect **sectp = NULL;
785 u_int i;
786
787 check(seg);
788 check(sect);
789 require_action(streq_safe(seg->segname, sect->segname, sizeof(seg->segname)),
790 finish, rval = KERN_FAILURE);
791
792 /* Add the section into the section index */
793
794 for (i = 0; i < seg->sects.nitems; ++i) {
795 sectp = kxld_array_get_item(&seg->sects, i);
796 if (NULL == *sectp) {
797 *sectp = sect;
798 break;
799 }
800 }
801 require_action(i < seg->sects.nitems, finish, rval = KERN_FAILURE);
802
803 rval = KERN_SUCCESS;
b0d623f7
A
804
805finish:
806
0a7de745 807 return rval;
b0d623f7
A
808}
809
810/*******************************************************************************
811*******************************************************************************/
812kern_return_t
813kxld_seg_finish_init(KXLDSeg *seg)
814{
0a7de745
A
815 kern_return_t rval = KERN_FAILURE;
816 u_int i = 0;
817 KXLDSect *sect = NULL;
818 kxld_addr_t maxaddr = 0;
819 kxld_size_t maxsize = 0;
820
821 /* If we already have a size for this segment (e.g. from the mach-o load
822 * command) then don't recalculate the segment size. This is safer since
823 * when we recalculate we are making assumptions about page alignment and
824 * padding that the kext mach-o file was built with. Better to trust the
825 * macho-o info, if we have it. If we don't (i.e. vmsize == 0) then add up
826 * the section sizes and take a best guess at page padding.
827 */
828 if ((seg->vmsize == 0) && (seg->sects.nitems)) {
829 for (i = 0; i < seg->sects.nitems; ++i) {
830 sect = get_sect_by_index(seg, i);
831 require_action(sect, finish, rval = KERN_FAILURE);
832 if (sect->base_addr > maxaddr) {
833 maxaddr = sect->base_addr;
834 maxsize = sect->size;
835 }
836 }
837 seg->vmsize = kxld_round_page_cross_safe(maxaddr +
838 maxsize - seg->base_addr);
839 }
840
841 rval = KERN_SUCCESS;
842
b0d623f7 843finish:
0a7de745 844 return rval;
b0d623f7
A
845}
846
847/*******************************************************************************
848*******************************************************************************/
849void
850kxld_seg_set_vm_protections(KXLDSeg *seg, boolean_t strict_protections)
851{
0a7de745
A
852 if (strict_protections) {
853 if (!strncmp(seg->segname, SEG_TEXT, sizeof(seg->segname))) {
854 seg->initprot = TEXT_SEG_PROT;
855 seg->maxprot = TEXT_SEG_PROT;
856 } else {
857 seg->initprot = DATA_SEG_PROT;
858 seg->maxprot = DATA_SEG_PROT;
859 }
860 } else {
861 seg->initprot = VM_PROT_ALL;
862 seg->maxprot = VM_PROT_ALL;
863 }
b0d623f7
A
864}
865
866/*******************************************************************************
867*******************************************************************************/
868void
869kxld_seg_relocate(KXLDSeg *seg, kxld_addr_t link_addr)
870{
0a7de745
A
871 KXLDSect *sect = NULL;
872 u_int i = 0;
873 splitKextLinkInfo * link_info = (splitKextLinkInfo *) link_addr;
874 kxld_addr_t my_link_addr;
875
876 if (isOldInterface) {
877 seg->link_addr += link_addr;
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 } else if (kxld_seg_is_text_exec_seg(seg)) {
886 my_link_addr = link_info->vmaddr_TEXT_EXEC;
887 seg->link_addr = my_link_addr;
888 // vmaddr_TEXT_EXEC is the actual vmaddr for this segment so we need
889 // to adjust for kxld_sect_relocate assuming the link addr is
890 // the address of the kext (macho header in __TEXT)
891 my_link_addr -= seg->base_addr;
892 } else if (kxld_seg_is_data_seg(seg)) {
893 my_link_addr = link_info->vmaddr_DATA;
894 seg->link_addr = my_link_addr;
895 // vmaddr_DATA is the actual vmaddr for this segment so we need
896 // to adjust for kxld_sect_relocate assuming the link addr is
897 // the address of the kext (macho header in __TEXT)
898 my_link_addr -= seg->base_addr;
899 } else if (kxld_seg_is_data_const_seg(seg)) {
900 my_link_addr = link_info->vmaddr_DATA_CONST;
901 seg->link_addr = my_link_addr;
902 // vmaddr_DATA_CONST is the actual vmaddr for this segment so we need
903 // to adjust for kxld_sect_relocate assuming the link addr is
904 // the address of the kext (macho header in __TEXT)
905 my_link_addr -= seg->base_addr;
906 } else if (kxld_seg_is_llvm_cov_seg(seg)) {
907 my_link_addr = link_info->vmaddr_LLVM_COV;
908 seg->link_addr = my_link_addr;
909 // vmaddr_LLVM_COV is the actual vmaddr for this segment so we need
910 // to adjust for kxld_sect_relocate assuming the link addr is
911 // the address of the kext (macho header in __TEXT)
912 my_link_addr -= seg->base_addr;
913 } else if (kxld_seg_is_linkedit_seg(seg)) {
914 my_link_addr = link_info->vmaddr_LINKEDIT;
915 seg->link_addr = my_link_addr;
916 // vmaddr_DATA is the actual vmaddr for this segment so we need
917 // to adjust for kxld_sect_relocate assuming the link addr is
918 // the address of the kext (macho header in __TEXT)
919 my_link_addr -= seg->base_addr;
920 } else {
921 kxld_log(kKxldLogLinking, kKxldLogErr,
922 " not expecting this segment %s!!! <%s>",
923 seg->segname[0] ? seg->segname : "none",
924 __func__);
925 my_link_addr = link_info->vmaddr_TEXT;
926 seg->link_addr += my_link_addr;
927 }
928 } else {
929 my_link_addr = link_info->vmaddr_TEXT;
930 seg->link_addr += my_link_addr;
931 }
932 }
933
39037602 934#if SPLIT_KEXTS_DEBUG
0a7de745
A
935 {
936 kxld_log(kKxldLogLinking, kKxldLogErr,
937 "%p >>> Start of %s segment (vmsize %llu) <%s>)",
938 (void *) seg->link_addr,
939 seg->segname[0] ? seg->segname : "none",
940 seg->vmsize,
941 __func__);
942 kxld_log(kKxldLogLinking, kKxldLogErr,
943 "%p <<< End of %s segment <%s>",
944 (void *) (seg->link_addr + seg->vmsize),
945 seg->segname[0] ? seg->segname : "none",
946 __func__);
947 }
39037602 948#endif
0a7de745
A
949
950 for (i = 0; i < seg->sects.nitems; ++i) {
951 sect = get_sect_by_index(seg, i);
952 if (isOldInterface) {
953 kxld_sect_relocate(sect, link_addr);
954 } else {
955 kxld_sect_relocate(sect, my_link_addr);
956 }
957 }
b0d623f7
A
958}
959
6d2010ae
A
960/*******************************************************************************
961*******************************************************************************/
0a7de745
A
962void
963kxld_seg_populate_linkedit(KXLDSeg *seg, const KXLDSymtab *symtab, boolean_t is_32_bit
316670eb
A
964#if KXLD_PIC_KEXTS
965 , const KXLDArray *locrelocs
966 , const KXLDArray *extrelocs
967 , boolean_t target_supports_slideable_kexts
968#endif /* KXLD_PIC_KEXTS */
39037602 969 , uint32_t splitinfolc_size
0a7de745 970 )
6d2010ae 971{
0a7de745 972 u_long size = 0;
316670eb 973
0a7de745 974 size += kxld_symtab_get_macho_data_size(symtab, is_32_bit);
316670eb
A
975
976#if KXLD_PIC_KEXTS
0a7de745
A
977 if (target_supports_slideable_kexts) {
978 size += kxld_reloc_get_macho_data_size(locrelocs, extrelocs);
979 }
980#endif /* KXLD_PIC_KEXTS */
316670eb 981
0a7de745
A
982 // 0 unless this is a split kext
983 size += splitinfolc_size;
39037602 984
0a7de745 985 seg->vmsize = kxld_round_page_cross_safe(size);
6d2010ae
A
986}
987
39037602 988/*******************************************************************************
0a7de745 989*******************************************************************************/
39037602
A
990boolean_t
991kxld_seg_is_split_seg(const KXLDSeg *seg)
992{
0a7de745
A
993 boolean_t result = FALSE;
994
995 check(seg);
996 if (isSplitKext) {
997 if (kxld_seg_is_data_seg(seg) || kxld_seg_is_linkedit_seg(seg) ||
998 kxld_seg_is_text_exec_seg(seg) || kxld_seg_is_data_const_seg(seg) ||
999 kxld_seg_is_llvm_cov_seg(seg)) {
1000 result = TRUE;
1001 }
1002 }
1003
1004 return result;
39037602
A
1005}
1006
1007boolean_t
1008kxld_seg_is_text_seg(const KXLDSeg *seg)
1009{
0a7de745
A
1010 boolean_t result = FALSE;
1011
1012 check(seg);
1013 result = !strncmp(seg->segname, SEG_TEXT, sizeof(seg->segname));
1014
1015 return result;
39037602
A
1016}
1017
1018boolean_t
1019kxld_seg_is_text_exec_seg(const KXLDSeg *seg)
1020{
0a7de745
A
1021 boolean_t result = FALSE;
1022
1023 check(seg);
1024 result = !strncmp(seg->segname, "__TEXT_EXEC", sizeof(seg->segname));
1025
1026 return result;
39037602
A
1027}
1028
1029boolean_t
1030kxld_seg_is_data_seg(const KXLDSeg *seg)
1031{
0a7de745
A
1032 boolean_t result = FALSE;
1033
1034 check(seg);
1035 result = !strncmp(seg->segname, SEG_DATA, sizeof(seg->segname));
1036
1037 return result;
39037602
A
1038}
1039
1040boolean_t
1041kxld_seg_is_data_const_seg(const KXLDSeg *seg)
1042{
0a7de745
A
1043 boolean_t result = FALSE;
1044
1045 check(seg);
1046 result = !strncmp(seg->segname, "__DATA_CONST", sizeof(seg->segname));
1047
1048 return result;
39037602
A
1049}
1050
1051boolean_t
1052kxld_seg_is_linkedit_seg(const KXLDSeg *seg)
1053{
0a7de745
A
1054 boolean_t result = FALSE;
1055
1056 check(seg);
1057 result = !strncmp(seg->segname, SEG_LINKEDIT, sizeof(seg->segname));
1058
1059 return result;
39037602
A
1060}
1061
813fb2f6
A
1062boolean_t
1063kxld_seg_is_llvm_cov_seg(const KXLDSeg *seg)
1064{
0a7de745 1065 boolean_t result = FALSE;
813fb2f6 1066
0a7de745
A
1067 check(seg);
1068 result = !strncmp(seg->segname, "__LLVM_COV", sizeof(seg->segname));
813fb2f6 1069
0a7de745 1070 return result;
813fb2f6 1071}