]> git.saurik.com Git - apple/xnu.git/blame - libkern/kxld/kxld_sect.c
xnu-2782.40.9.tar.gz
[apple/xnu.git] / libkern / kxld / kxld_sect.c
CommitLineData
b0d623f7
A
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
42static kern_return_t export_macho(const KXLDSect *sect, u_char *buf, u_long offset,
6d2010ae 43 u_long bufsize);
b0d623f7
A
44#if KXLD_USER_OR_ILP32
45static 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
49static 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*******************************************************************************/
56kern_return_t
57kxld_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;
316670eb 61 struct section *src = (struct section *) ((void *) (macho + *sect_offset));
b0d623f7
A
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
316670eb 85 relocs = (struct relocation_info *) ((void *) (macho + src->reloff));
b0d623f7
A
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
94finish:
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*******************************************************************************/
104kern_return_t
105kxld_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;
316670eb 109 struct section_64 *src = (struct section_64 *) ((void *) (macho + *sect_offset));
b0d623f7
A
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
316670eb 133 relocs = (struct relocation_info *) ((void *) (macho + src->reloff));
b0d623f7
A
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
142finish:
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*******************************************************************************/
153kern_return_t
154kxld_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
177finish:
178 return rval;
179}
180#endif /* KXLD_USER_OR_GOT */
181
182#if KXLD_USER_OR_COMMON
183/*******************************************************************************
184*******************************************************************************/
185void
186kxld_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*******************************************************************************/
205void
206kxld_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*******************************************************************************/
230void
231kxld_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*******************************************************************************/
245u_int
246kxld_sect_get_num_relocs(const KXLDSect *sect)
247{
248 check(sect);
249
250 return sect->relocs.nitems;
251}
252
253/*******************************************************************************
254*******************************************************************************/
255u_long
256kxld_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*******************************************************************************/
267u_long
268kxld_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*******************************************************************************/
284u_int
285kxld_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*******************************************************************************/
318kxld_addr_t
319kxld_sect_align_address(const KXLDSect *sect, kxld_addr_t address)
320{
321 return kxld_align_address(address, sect->align);
322}
323
324/*******************************************************************************
325*******************************************************************************/
326kern_return_t
327kxld_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,
6d2010ae 329 u_long data_size, boolean_t is_32_bit __unused)
b0d623f7
A
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
6d2010ae 354 rval = export_macho(sect, buf, *data_offset, data_size);
b0d623f7
A
355 require_noerr(rval, finish);
356
357 *data_offset += (u_long) sect->size;
358 }
359
360 rval = KERN_SUCCESS;
361
362finish:
363 return rval;
364}
365
366/*******************************************************************************
367*******************************************************************************/
368kern_return_t
369kxld_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,
6d2010ae 372 boolean_t is_32_bit __unused)
b0d623f7
A
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
6d2010ae 386 rval = export_macho(sect, buf, data_offset, data_size);
b0d623f7
A
387 require_noerr(rval, finish);
388
389 rval = KERN_SUCCESS;
390
391finish:
392 return rval;
393}
394
395/*******************************************************************************
396*******************************************************************************/
397static kern_return_t
6d2010ae 398export_macho(const KXLDSect *sect, u_char *buf, u_long offset, u_long bufsize)
b0d623f7
A
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:
b0d623f7
A
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:
316670eb 433 case S_SYMBOL_STUBS:
b0d623f7
A
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:
b0d623f7
A
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
450finish:
451 return rval;
452}
453
454#if KXLD_USER_OR_ILP32
455/*******************************************************************************
456*******************************************************************************/
457static kern_return_t
458sect_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);
316670eb 470 secthdr = (struct section *) ((void *) (buf + *header_offset));
b0d623f7
A
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
489finish:
490 return rval;
491}
492#endif /* KXLD_USER_OR_ILP32 */
493
494#if KXLD_USER_OR_LP64
495/*******************************************************************************
496*******************************************************************************/
497static kern_return_t
498sect_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);
316670eb 510 secthdr = (struct section_64 *) ((void *) (buf + *header_offset));
b0d623f7
A
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
529finish:
530 return rval;
531}
532#endif /* KXLD_USER_OR_LP64 */
533
534#if KXLD_USER_OR_COMMON
535/*******************************************************************************
536*******************************************************************************/
537kxld_size_t
538kxld_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*******************************************************************************/
551void
552kxld_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*******************************************************************************/
561kern_return_t
562kxld_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
596finish:
597 return rval;
598}
599#endif /* KXLD_USER_OR_GOT */
600
601/*******************************************************************************
602*******************************************************************************/
603kern_return_t
6d2010ae 604kxld_sect_process_relocs(KXLDSect *sect, KXLDRelocator *relocator)
b0d623f7
A
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);
6d2010ae 612 rval = kxld_relocator_process_sect_reloc(relocator, reloc, sect);
b0d623f7
A
613 require_noerr(rval, finish);
614 }
615
616 rval = KERN_SUCCESS;
b0d623f7
A
617finish:
618 return rval;
619}
620