]> git.saurik.com Git - apple/xnu.git/blob - libkern/kxld/kxld_sect.c
xnu-3247.1.106.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);
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 *) ((void *) (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 *) ((void *) (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 *) ((void *) (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 *) ((void *) (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 __unused)
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);
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 __unused)
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);
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 {
400 kern_return_t rval = KERN_FAILURE;
401
402 check(sect);
403 check(buf);
404
405 if (!sect->data) {
406 rval = KERN_SUCCESS;
407 goto finish;
408 }
409
410 /* Verify that the section is properly aligned */
411
412 require_action(kxld_sect_align_address(sect, offset) == offset, finish,
413 rval = KERN_FAILURE);
414
415 /* Verify that we have enough space to copy */
416
417 require_action(sect->size <= bufsize - offset, finish,
418 rval=KERN_FAILURE);
419
420 /* Copy section data */
421
422 switch (sect->flags & SECTION_TYPE) {
423 case S_NON_LAZY_SYMBOL_POINTERS:
424 case S_MOD_INIT_FUNC_POINTERS:
425 case S_MOD_TERM_FUNC_POINTERS:
426 case S_REGULAR:
427 case S_CSTRING_LITERALS:
428 case S_4BYTE_LITERALS:
429 case S_8BYTE_LITERALS:
430 case S_LITERAL_POINTERS:
431 case S_COALESCED:
432 case S_16BYTE_LITERALS:
433 case S_SYMBOL_STUBS:
434 memcpy(buf + offset, sect->data, (size_t)sect->size);
435 break;
436 case S_ZEROFILL: /* sect->data should be NULL, so we'll never get here */
437 case S_LAZY_SYMBOL_POINTERS:
438 case S_GB_ZEROFILL:
439 case S_INTERPOSING:
440 case S_DTRACE_DOF:
441 default:
442 rval = KERN_FAILURE;
443 kxld_log(kKxldLogLinking, kKxldLogErr, kKxldLogMalformedMachO
444 "Invalid section type: %u.", sect->flags & SECTION_TYPE);
445 goto finish;
446 }
447
448 rval = KERN_SUCCESS;
449
450 finish:
451 return rval;
452 }
453
454 #if KXLD_USER_OR_ILP32
455 /*******************************************************************************
456 *******************************************************************************/
457 static kern_return_t
458 sect_export_macho_header_32(const KXLDSect *sect, u_char *buf,
459 u_long *header_offset, u_long header_size, u_long data_offset)
460 {
461 kern_return_t rval = KERN_FAILURE;
462 struct section *secthdr = NULL;
463
464 check(sect);
465 check(buf);
466 check(header_offset);
467
468 require_action(sizeof(*secthdr) <= header_size - *header_offset, finish,
469 rval=KERN_FAILURE);
470 secthdr = (struct section *) ((void *) (buf + *header_offset));
471 *header_offset += sizeof(*secthdr);
472
473 /* Initalize header */
474
475 strlcpy(secthdr->sectname, sect->sectname, sizeof(secthdr->sectname));
476 strlcpy(secthdr->segname, sect->segname, sizeof(secthdr->segname));
477 secthdr->addr = (uint32_t) sect->link_addr;
478 secthdr->size = (uint32_t) sect->size;
479 secthdr->offset = (uint32_t) ((sect->data) ? data_offset : 0);
480 secthdr->align = sect->align;
481 secthdr->reloff = 0;
482 secthdr->nreloc = 0;
483 secthdr->flags = sect->flags;
484 secthdr->reserved1 = sect->reserved1;
485 secthdr->reserved2 = sect->reserved2;
486
487 rval = KERN_SUCCESS;
488
489 finish:
490 return rval;
491 }
492 #endif /* KXLD_USER_OR_ILP32 */
493
494 #if KXLD_USER_OR_LP64
495 /*******************************************************************************
496 *******************************************************************************/
497 static kern_return_t
498 sect_export_macho_header_64(const KXLDSect *sect, u_char *buf,
499 u_long *header_offset, u_long header_size, u_long data_offset)
500 {
501 kern_return_t rval = KERN_FAILURE;
502 struct section_64 *secthdr = NULL;
503
504 check(sect);
505 check(buf);
506 check(header_offset);
507
508 require_action(sizeof(*secthdr) <= header_size - *header_offset, finish,
509 rval=KERN_FAILURE);
510 secthdr = (struct section_64 *) ((void *) (buf + *header_offset));
511 *header_offset += sizeof(*secthdr);
512
513 /* Initalize header */
514
515 strlcpy(secthdr->sectname, sect->sectname, sizeof(secthdr->sectname));
516 strlcpy(secthdr->segname, sect->segname, sizeof(secthdr->segname));
517 secthdr->addr = (uint64_t) sect->link_addr;
518 secthdr->size = (uint64_t) sect->size;
519 secthdr->offset = (uint32_t) ((sect->data) ? data_offset : 0);
520 secthdr->align = sect->align;
521 secthdr->reloff = 0;
522 secthdr->nreloc = 0;
523 secthdr->flags = sect->flags;
524 secthdr->reserved1 = sect->reserved1;
525 secthdr->reserved2 = sect->reserved2;
526
527 rval = KERN_SUCCESS;
528
529 finish:
530 return rval;
531 }
532 #endif /* KXLD_USER_OR_LP64 */
533
534 #if KXLD_USER_OR_COMMON
535 /*******************************************************************************
536 *******************************************************************************/
537 kxld_size_t
538 kxld_sect_grow(KXLDSect *sect, kxld_size_t nbytes, u_int align)
539 {
540 kxld_size_t size = kxld_align_address(sect->size, align);
541
542 if (align > sect->align) sect->align = align;
543 sect->size = size + nbytes;
544
545 return size;
546 }
547 #endif /* KXLD_USER_OR_COMMON */
548
549 /*******************************************************************************
550 *******************************************************************************/
551 void
552 kxld_sect_relocate(KXLDSect *sect, kxld_addr_t link_addr)
553 {
554 sect->link_addr = kxld_sect_align_address(sect,
555 sect->link_addr + link_addr);
556 }
557
558 #if KXLD_USER_OR_GOT
559 /*******************************************************************************
560 *******************************************************************************/
561 kern_return_t
562 kxld_sect_populate_got(KXLDSect *sect, KXLDSymtab *symtab,
563 boolean_t swap __unused)
564 {
565 kern_return_t rval = KERN_FAILURE;
566 KXLDSymtabIterator iter;
567 KXLDSym *sym = NULL;
568 kxld_addr_t *entry = NULL;
569 kxld_addr_t entry_addr = 0;
570
571 check(sect);
572 check(symtab);
573 require(streq_safe(sect->segname, KXLD_SEG_GOT, sizeof(KXLD_SEG_GOT)),
574 finish);
575 require(streq_safe(sect->sectname, KXLD_SECT_GOT, sizeof(KXLD_SECT_GOT)),
576 finish);
577
578 kxld_symtab_iterator_init(&iter, symtab, kxld_sym_is_got, FALSE);
579
580 entry = (kxld_addr_t *) sect->data;
581 entry_addr = sect->link_addr;
582 while ((sym = kxld_symtab_iterator_get_next(&iter))) {
583 *entry = sym->link_addr;
584 sym->got_addr = entry_addr;
585
586 #if !KERNEL
587 if (swap) *entry = OSSwapInt64(*entry);
588 #endif /* !KERNEL */
589
590 ++entry;
591 entry_addr += sizeof(*entry);
592 }
593
594 rval = KERN_SUCCESS;
595
596 finish:
597 return rval;
598 }
599 #endif /* KXLD_USER_OR_GOT */
600
601 /*******************************************************************************
602 *******************************************************************************/
603 kern_return_t
604 kxld_sect_process_relocs(KXLDSect *sect, KXLDRelocator *relocator)
605 {
606 kern_return_t rval = KERN_FAILURE;
607 KXLDReloc *reloc = NULL;
608 u_int i = 0;
609
610 for (i = 0; i < sect->relocs.nitems; ++i) {
611 reloc = kxld_array_get_item(&sect->relocs, i);
612 rval = kxld_relocator_process_sect_reloc(relocator, reloc, sect);
613 require_noerr(rval, finish);
614 }
615
616 rval = KERN_SUCCESS;
617 finish:
618 return rval;
619 }
620