2 * Copyright (c) 2008 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
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.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
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.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
29 #include <mach-o/loader.h>
30 #include <mach-o/reloc.h>
31 #include <sys/types.h>
33 #define DEBUG_ASSERT_COMPONENT_NAME_STRING "kxld"
34 #include <AssertMacros.h>
36 #include "kxld_reloc.h"
37 #include "kxld_sect.h"
39 #include "kxld_symtab.h"
40 #include "kxld_util.h"
42 static kern_return_t
export_macho(const KXLDSect
*sect
, u_char
*buf
, u_long offset
,
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
);
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
);
53 #if KXLD_USER_OR_ILP32
54 /*******************************************************************************
55 *******************************************************************************/
57 kxld_sect_init_from_macho_32(KXLDSect
*sect
, u_char
*macho
, u_long
*sect_offset
,
58 u_int sectnum
, const KXLDRelocator
*relocator
)
60 kern_return_t rval
= KERN_FAILURE
;
61 struct section
*src
= (struct section
*) ((void *) (macho
+ *sect_offset
));
62 struct relocation_info
*relocs
= NULL
;
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
;
80 sect
->data
= macho
+ src
->offset
;
85 relocs
= (struct relocation_info
*) ((void *) (macho
+ src
->reloff
));
87 rval
= kxld_reloc_create_macho(§
->relocs
, relocator
,
89 require_noerr(rval
, finish
);
91 *sect_offset
+= sizeof(*src
);
95 if (rval
) kxld_sect_deinit(sect
);
99 #endif /* KXLD_USER_OR_ILP32 */
101 #if KXLD_USER_OR_LP64
102 /*******************************************************************************
103 *******************************************************************************/
105 kxld_sect_init_from_macho_64(KXLDSect
*sect
, u_char
*macho
, u_long
*sect_offset
,
106 u_int sectnum
, const KXLDRelocator
*relocator
)
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
;
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
;
128 sect
->data
= macho
+ src
->offset
;
133 relocs
= (struct relocation_info
*) ((void *) (macho
+ src
->reloff
));
135 rval
= kxld_reloc_create_macho(§
->relocs
, relocator
,
136 relocs
, src
->nreloc
);
137 require_noerr(rval
, finish
);
139 *sect_offset
+= sizeof(*src
);
143 if (rval
) kxld_sect_deinit(sect
);
147 #endif /* KXLD_USER_OR_LP64 */
150 /*******************************************************************************
151 * Assumes GOT is comprised of kxld_addr_t entries
152 *******************************************************************************/
154 kxld_sect_init_got(KXLDSect
*sect
, u_int ngots
)
156 kern_return_t rval
= KERN_FAILURE
;
160 strlcpy(sect
->segname
, KXLD_SEG_GOT
, sizeof(sect
->segname
));
161 strlcpy(sect
->sectname
, KXLD_SECT_GOT
, sizeof(sect
->sectname
));
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
);
173 sect
->allocated
= TRUE
;
180 #endif /* KXLD_USER_OR_GOT */
182 #if KXLD_USER_OR_COMMON
183 /*******************************************************************************
184 *******************************************************************************/
186 kxld_sect_init_zerofill(KXLDSect
*sect
, const char *segname
,
187 const char *sectname
, kxld_size_t size
, u_int align
)
193 strlcpy(sect
->segname
, segname
, sizeof(sect
->segname
));
194 strlcpy(sect
->sectname
, sectname
, sizeof(sect
->sectname
));
199 sect
->flags
= S_ZEROFILL
;
201 #endif /* KXLD_USER_OR_COMMON */
203 /*******************************************************************************
204 *******************************************************************************/
206 kxld_sect_clear(KXLDSect
*sect
)
210 if (sect
->allocated
) {
211 kxld_free(sect
->data
, (u_long
) sect
->size
);
212 sect
->allocated
= FALSE
;
215 bzero(sect
->sectname
, sizeof(sect
->sectname
));
216 bzero(sect
->segname
, sizeof(sect
->segname
));
225 kxld_array_clear(§
->relocs
);
228 /*******************************************************************************
229 *******************************************************************************/
231 kxld_sect_deinit(KXLDSect
*sect
)
235 if (streq_safe(sect
->sectname
, KXLD_SECT_GOT
, sizeof(KXLD_SECT_GOT
))) {
236 kxld_free(sect
->data
, (u_long
) sect
->size
);
239 kxld_array_deinit(§
->relocs
);
240 bzero(sect
, sizeof(*sect
));
243 /*******************************************************************************
244 *******************************************************************************/
246 kxld_sect_get_num_relocs(const KXLDSect
*sect
)
250 return sect
->relocs
.nitems
;
253 /*******************************************************************************
254 *******************************************************************************/
256 kxld_sect_get_macho_header_size(boolean_t is_32_bit
)
259 return sizeof(struct section
);
261 return sizeof(struct section_64
);
265 /*******************************************************************************
266 *******************************************************************************/
268 kxld_sect_get_macho_data_size(const KXLDSect
*sect
)
275 size
= (u_long
) sect
->size
;
282 /*******************************************************************************
283 *******************************************************************************/
285 kxld_sect_get_ngots(const KXLDSect
*sect
, const KXLDRelocator
*relocator
,
286 const KXLDSymtab
*symtab
)
288 const KXLDReloc
*reloc
= NULL
;
293 for (i
= 0; i
< sect
->relocs
.nitems
; ++i
) {
294 reloc
= kxld_array_get_item(§
->relocs
, i
);
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)
300 sym
= kxld_reloc_get_symbol(relocator
, reloc
, sect
->data
, symtab
);
301 if (!kxld_sym_is_got(sym
)) {
302 kxld_sym_set_got(sym
);
310 #endif /* KXLD_USER_OR_GOT */
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 *******************************************************************************/
319 kxld_sect_align_address(const KXLDSect
*sect
, kxld_addr_t address
)
321 return kxld_align_address(address
, sect
->align
);
324 /*******************************************************************************
325 *******************************************************************************/
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
)
331 kern_return_t rval
= KERN_FAILURE
;
335 check(header_offset
);
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.
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
);
347 *data_offset
= (u_long
) kxld_sect_align_address(sect
, *data_offset
);
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
);
354 rval
= export_macho(sect
, buf
, *data_offset
, data_size
);
355 require_noerr(rval
, finish
);
357 *data_offset
+= (u_long
) sect
->size
;
366 /*******************************************************************************
367 *******************************************************************************/
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
)
374 kern_return_t rval
= KERN_FAILURE
;
375 u_long data_offset
= (u_long
) (sect
->link_addr
- link_addr
);
379 check(header_offset
);
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
);
386 rval
= export_macho(sect
, buf
, data_offset
, data_size
);
387 require_noerr(rval
, finish
);
395 /*******************************************************************************
396 *******************************************************************************/
398 export_macho(const KXLDSect
*sect
, u_char
*buf
, u_long offset
, u_long bufsize
)
400 kern_return_t rval
= KERN_FAILURE
;
410 /* Verify that the section is properly aligned */
412 require_action(kxld_sect_align_address(sect
, offset
) == offset
, finish
,
413 rval
= KERN_FAILURE
);
415 /* Verify that we have enough space to copy */
417 require_action(sect
->size
<= bufsize
- offset
, finish
,
420 /* Copy section data */
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
:
427 case S_CSTRING_LITERALS
:
428 case S_4BYTE_LITERALS
:
429 case S_8BYTE_LITERALS
:
430 case S_LITERAL_POINTERS
:
432 case S_16BYTE_LITERALS
:
434 memcpy(buf
+ offset
, sect
->data
, (size_t)sect
->size
);
436 case S_ZEROFILL
: /* sect->data should be NULL, so we'll never get here */
437 case S_LAZY_SYMBOL_POINTERS
:
443 kxld_log(kKxldLogLinking
, kKxldLogErr
, kKxldLogMalformedMachO
444 "Invalid section type: %u.", sect
->flags
& SECTION_TYPE
);
454 #if KXLD_USER_OR_ILP32
455 /*******************************************************************************
456 *******************************************************************************/
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
)
461 kern_return_t rval
= KERN_FAILURE
;
462 struct section
*secthdr
= NULL
;
466 check(header_offset
);
468 require_action(sizeof(*secthdr
) <= header_size
- *header_offset
, finish
,
470 secthdr
= (struct section
*) ((void *) (buf
+ *header_offset
));
471 *header_offset
+= sizeof(*secthdr
);
473 /* Initalize header */
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
;
483 secthdr
->flags
= sect
->flags
;
484 secthdr
->reserved1
= sect
->reserved1
;
485 secthdr
->reserved2
= sect
->reserved2
;
492 #endif /* KXLD_USER_OR_ILP32 */
494 #if KXLD_USER_OR_LP64
495 /*******************************************************************************
496 *******************************************************************************/
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
)
501 kern_return_t rval
= KERN_FAILURE
;
502 struct section_64
*secthdr
= NULL
;
506 check(header_offset
);
508 require_action(sizeof(*secthdr
) <= header_size
- *header_offset
, finish
,
510 secthdr
= (struct section_64
*) ((void *) (buf
+ *header_offset
));
511 *header_offset
+= sizeof(*secthdr
);
513 /* Initalize header */
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
;
523 secthdr
->flags
= sect
->flags
;
524 secthdr
->reserved1
= sect
->reserved1
;
525 secthdr
->reserved2
= sect
->reserved2
;
532 #endif /* KXLD_USER_OR_LP64 */
534 #if KXLD_USER_OR_COMMON
535 /*******************************************************************************
536 *******************************************************************************/
538 kxld_sect_grow(KXLDSect
*sect
, kxld_size_t nbytes
, u_int align
)
540 kxld_size_t size
= kxld_align_address(sect
->size
, align
);
542 if (align
> sect
->align
) sect
->align
= align
;
543 sect
->size
= size
+ nbytes
;
547 #endif /* KXLD_USER_OR_COMMON */
549 /*******************************************************************************
550 *******************************************************************************/
552 kxld_sect_relocate(KXLDSect
*sect
, kxld_addr_t link_addr
)
554 sect
->link_addr
= kxld_sect_align_address(sect
,
555 sect
->link_addr
+ link_addr
);
559 /*******************************************************************************
560 *******************************************************************************/
562 kxld_sect_populate_got(KXLDSect
*sect
, KXLDSymtab
*symtab
,
563 boolean_t swap __unused
)
565 kern_return_t rval
= KERN_FAILURE
;
566 KXLDSymtabIterator iter
;
568 kxld_addr_t
*entry
= NULL
;
569 kxld_addr_t entry_addr
= 0;
573 require(streq_safe(sect
->segname
, KXLD_SEG_GOT
, sizeof(KXLD_SEG_GOT
)),
575 require(streq_safe(sect
->sectname
, KXLD_SECT_GOT
, sizeof(KXLD_SECT_GOT
)),
578 kxld_symtab_iterator_init(&iter
, symtab
, kxld_sym_is_got
, FALSE
);
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
;
587 if (swap
) *entry
= OSSwapInt64(*entry
);
591 entry_addr
+= sizeof(*entry
);
599 #endif /* KXLD_USER_OR_GOT */
601 /*******************************************************************************
602 *******************************************************************************/
604 kxld_sect_process_relocs(KXLDSect
*sect
, KXLDRelocator
*relocator
)
606 kern_return_t rval
= KERN_FAILURE
;
607 KXLDReloc
*reloc
= NULL
;
610 for (i
= 0; i
< sect
->relocs
.nitems
; ++i
) {
611 reloc
= kxld_array_get_item(§
->relocs
, i
);
612 rval
= kxld_relocator_process_sect_reloc(relocator
, reloc
, sect
);
613 require_noerr(rval
, finish
);