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,
43    u_long bufsize);
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;
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
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;
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
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,
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
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,
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
391finish:
392    return rval;
393}
394
395/*******************************************************************************
396*******************************************************************************/
397static kern_return_t
398export_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
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);
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
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);
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
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
604kxld_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;
617finish:
618    return rval;
619}
620
621