The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/libkern/kxld/kxld.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  * Copyright (c) 2007-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 <sys/types.h>
   30 #include <mach/vm_param.h>  /* For PAGE_SIZE */
   31 
   32 #define DEBUG_ASSERT_COMPONENT_NAME_STRING "kxld"
   33 #include <AssertMacros.h>
   34 
   35 #if !KERNEL
   36     #include "kxld.h"
   37     #include "kxld_types.h"
   38 #else 
   39     #include <libkern/kxld.h>
   40     #include <libkern/kxld_types.h>
   41 #endif /* KERNEL */
   42 
   43 #include "kxld_array.h"
   44 #include "kxld_dict.h"
   45 #include "kxld_kext.h"
   46 #include "kxld_state.h"
   47 #include "kxld_sym.h"
   48 #include "kxld_symtab.h"
   49 #include "kxld_util.h"
   50 #include "kxld_vtable.h"
   51 
   52 struct kxld_vtable;
   53 
   54 struct kxld_context {
   55     KXLDKext *kext;
   56     KXLDArray *section_order;
   57     KXLDArray deps;
   58     KXLDArray tmps;
   59     KXLDDict defined_symbols;
   60     KXLDDict obsolete_symbols;
   61     KXLDDict vtables;
   62     KXLDFlags flags;
   63     KXLDAllocateCallback allocate_callback;
   64     cpu_type_t cputype;
   65     cpu_subtype_t cpusubtype;
   66 };
   67 
   68 /*******************************************************************************
   69 * Globals
   70 *******************************************************************************/
   71 
   72 /* Certain architectures alter the order of a kext's sections from its input
   73  * binary, so we track that order in a dictionary of arrays, with one array for
   74  * each architecture.  Since the kernel only has one architecture, we can
   75  * eliminate the dictionary and use a simple array.  
   76  * XXX: If we ever use the linker in a multithreaded environment, we will need 
   77  * locks around these global structures.
   78  */
   79 #if KXLD_USER_OR_OBJECT
   80 #if KERNEL
   81 static KXLDArray *s_section_order;
   82 #else
   83 static KXLDDict *s_order_dict;
   84 #endif
   85 #endif
   86 
   87 /*******************************************************************************
   88 * Prototypes
   89 *******************************************************************************/
   90 
   91 static void clear_context(KXLDContext *context);
   92 
   93 /*******************************************************************************
   94 *******************************************************************************/
   95 kern_return_t
   96 kxld_create_context(KXLDContext **_context, 
   97     KXLDAllocateCallback allocate_callback, KXLDLoggingCallback logging_callback,
   98     KXLDFlags flags, cpu_type_t cputype, cpu_subtype_t cpusubtype)
   99 {
  100     kern_return_t rval = KERN_FAILURE;
  101     KXLDContext *context = NULL;
  102     KXLDArray *section_order = NULL;
  103 #if !KERNEL
  104     cpu_type_t *cputype_p = NULL;
  105 #endif
  106 
  107     check(_context);
  108     check(allocate_callback);
  109     check(logging_callback);
  110     *_context = NULL;
  111 
  112     context = kxld_alloc(sizeof(*context));
  113     require_action(context, finish, rval=KERN_RESOURCE_SHORTAGE);
  114     bzero(context, sizeof(*context));
  115 
  116     context->flags = flags;
  117     context->allocate_callback = allocate_callback;
  118     context->cputype = cputype;
  119     context->cpusubtype = cpusubtype;
  120 
  121     kxld_set_logging_callback(logging_callback);
  122 
  123     context->kext = kxld_alloc(kxld_kext_sizeof());
  124     require_action(context->kext, finish, rval=KERN_RESOURCE_SHORTAGE);
  125     bzero(context->kext, kxld_kext_sizeof());
  126 
  127     /* Check if we already have an order array for this arch */
  128 
  129 #if KXLD_USER_OR_OBJECT
  130 #if KERNEL   
  131     context->section_order = s_section_order;
  132 #else
  133     /* In userspace, create the dictionary if it doesn't already exist */
  134     if (!s_order_dict) {
  135         s_order_dict = kxld_alloc(sizeof(*s_order_dict));
  136         require_action(s_order_dict, finish, rval=KERN_RESOURCE_SHORTAGE);
  137         bzero(s_order_dict, sizeof(*s_order_dict));
  138 
  139         rval = kxld_dict_init(s_order_dict, kxld_dict_uint32_hash,
  140             kxld_dict_uint32_cmp, 0);
  141         require_noerr(rval, finish);
  142     }
  143 
  144     context->section_order = kxld_dict_find(s_order_dict, &cputype);
  145 #endif /* KERNEL */
  146 
  147     /* Create an order array for this arch if needed */
  148     
  149     if (!context->section_order) {
  150 
  151         section_order = kxld_alloc(sizeof(*section_order));
  152         require_action(section_order, finish, rval=KERN_RESOURCE_SHORTAGE);
  153         bzero(section_order, sizeof(*section_order));
  154 
  155 #if KERNEL
  156         s_section_order = section_order;
  157 #else
  158         /* In userspace, add the new array to the order dictionary */
  159         cputype_p = kxld_alloc(sizeof(*cputype_p));
  160         require_action(cputype_p, finish, rval=KERN_RESOURCE_SHORTAGE);
  161         *cputype_p = cputype;
  162 
  163         rval = kxld_dict_insert(s_order_dict, cputype_p, section_order);
  164         require_noerr(rval, finish);
  165 
  166         cputype_p = NULL;
  167 #endif /* KERNEL */
  168 
  169         context->section_order = section_order;
  170 
  171         section_order = NULL;
  172     }
  173 #endif /* KXLD_USER_OR_OBJECT */
  174 
  175     rval = KERN_SUCCESS;
  176     *_context = context;
  177     context = NULL;
  178 
  179 finish:
  180     if (context) kxld_free(context, sizeof(*context));
  181     if (section_order) kxld_free(section_order, sizeof(*section_order));
  182 #if !KERNEL
  183     if (cputype_p) kxld_free(cputype_p, sizeof(*cputype_p));
  184 #endif
  185 
  186     return rval;
  187 }
  188 
  189 /*******************************************************************************
  190 *******************************************************************************/
  191 void
  192 kxld_destroy_context(KXLDContext *context)
  193 {
  194     KXLDState *dep = NULL;
  195     u_int i = 0;
  196 
  197     check(context);
  198 
  199     kxld_kext_deinit(context->kext);
  200 
  201     for (i = 0; i < context->deps.maxitems; ++i) {
  202         dep = kxld_array_get_slot(&context->deps, i);
  203         kxld_state_deinit(dep);
  204     }
  205 
  206     kxld_array_deinit(&context->deps);
  207     kxld_array_deinit(&context->tmps);
  208 
  209     kxld_dict_deinit(&context->defined_symbols);
  210     kxld_dict_deinit(&context->obsolete_symbols);
  211     kxld_dict_deinit(&context->vtables);
  212 
  213     kxld_free(context->kext, kxld_kext_sizeof());
  214     kxld_free(context, sizeof(*context));
  215 
  216     kxld_print_memory_report();
  217 }
  218 
  219 /*******************************************************************************
  220 *******************************************************************************/
  221 kern_return_t
  222 kxld_link_file(
  223     KXLDContext *context,
  224     u_char *file,
  225     u_long size,
  226     const char *name,
  227     void *callback_data,
  228     u_char **deps,
  229     u_int ndeps,
  230     u_char **_linked_object,
  231     kxld_addr_t *kmod_info_kern,
  232     u_char **_link_state,
  233     u_long *_link_state_size,
  234     u_char **_symbol_file __unused,
  235     u_long *_symbol_file_size __unused)
  236 {
  237     kern_return_t rval = KERN_FAILURE;
  238     KXLDState *state = NULL;
  239     KXLDAllocateFlags flags = 0;
  240     kxld_addr_t vmaddr = 0;
  241     u_long header_size = 0;
  242     u_long vmsize = 0;
  243     u_int nsyms = 0;
  244     u_int nvtables = 0;
  245     u_int i = 0;
  246     u_char *linked_object = NULL;
  247     u_char *linked_object_alloc = NULL;
  248     u_char *link_state = NULL;
  249     u_char *symbol_file = NULL;
  250     u_long link_state_size = 0;
  251     u_long symbol_file_size = 0;
  252 
  253     kxld_set_logging_callback_data(name, callback_data);
  254 
  255     require_action(context, finish, rval=KERN_INVALID_ARGUMENT);
  256     require_action(file, finish, rval=KERN_INVALID_ARGUMENT);
  257     require_action(size, finish, rval=KERN_INVALID_ARGUMENT);
  258 
  259     rval = kxld_array_init(&context->deps, sizeof(struct kxld_state), ndeps);
  260     require_noerr(rval, finish);
  261 
  262     if (deps) {
  263         /* Initialize the dependencies */
  264         for (i = 0; i < ndeps; ++i) {
  265             state = kxld_array_get_item(&context->deps, i);
  266 
  267             rval = kxld_state_init_from_file(state, deps[i], 
  268                 context->section_order);
  269             require_noerr(rval, finish);
  270         }
  271     }
  272 
  273     rval = kxld_kext_init(context->kext, file, size, name, 
  274         context->flags, (deps == 0) /* is_kernel */, context->section_order, 
  275         context->cputype, context->cpusubtype);
  276     require_noerr(rval, finish);
  277 
  278     if (deps) {
  279 
  280         /* Calculate the base number of symbols and vtables in the kext */
  281 
  282         nsyms += kxld_kext_get_num_symbols(context->kext);
  283         nvtables += kxld_kext_get_num_vtables(context->kext);
  284 
  285         /* Extract the symbol and vtable counts from the dependencies.
  286          */
  287 
  288         for (i = 0; i < ndeps; ++i) {
  289             cpu_type_t cputype; 
  290             cpu_subtype_t cpusubtype; 
  291 
  292             state = kxld_array_get_item(&context->deps, i);
  293 
  294             kxld_state_get_cputype(state, &cputype, &cpusubtype);
  295 
  296             rval = kxld_kext_validate_cputype(context->kext, 
  297                 cputype, cpusubtype);
  298             require_noerr(rval, finish);
  299 
  300             nsyms += kxld_state_get_num_symbols(state);
  301             nvtables += kxld_state_get_num_vtables(state);
  302         }
  303 
  304         /* Create the global symbol and vtable tables */
  305 
  306         rval = kxld_dict_init(&context->defined_symbols, kxld_dict_string_hash,
  307             kxld_dict_string_cmp, nsyms);
  308         require_noerr(rval, finish);
  309 
  310         rval = kxld_dict_init(&context->obsolete_symbols, kxld_dict_string_hash,
  311             kxld_dict_string_cmp, 0);
  312         require_noerr(rval, finish);
  313 
  314         rval = kxld_dict_init(&context->vtables, kxld_dict_string_hash,
  315             kxld_dict_string_cmp, nvtables);
  316         require_noerr(rval, finish);
  317 
  318         /* Populate the global tables */
  319 
  320         for (i = 0; i < ndeps; ++i) {
  321             state = kxld_array_get_item(&context->deps, i);
  322 
  323             rval = kxld_state_get_symbols(state, &context->defined_symbols,
  324                 &context->obsolete_symbols);
  325             require_noerr(rval, finish);
  326 
  327             rval = kxld_state_get_vtables(state, &context->vtables);
  328             require_noerr(rval, finish);
  329         }
  330 
  331         if (kxld_kext_is_true_kext(context->kext)) {
  332 
  333             /* Allocate the kext object */
  334 
  335             kxld_kext_get_vmsize(context->kext, &header_size, &vmsize);
  336             vmaddr = context->allocate_callback(vmsize, &flags, callback_data);
  337             require_action(!(vmaddr & (PAGE_SIZE-1)), finish, rval=KERN_FAILURE;
  338                 kxld_log(kKxldLogLinking, kKxldLogErr,
  339                     "Load address %p is not page-aligned.",
  340                     (void *) (uintptr_t) vmaddr));
  341 
  342             if (flags & kKxldAllocateWritable) {
  343                 linked_object = (u_char *) (u_long) vmaddr;
  344             } else {
  345                 linked_object_alloc = kxld_page_alloc_untracked(vmsize);
  346                 require_action(linked_object_alloc, finish, rval=KERN_RESOURCE_SHORTAGE);
  347                 linked_object = linked_object_alloc;
  348             }
  349 
  350             /* Zero out the memory before we fill it.  We fill this buffer in a
  351              * sparse fashion, and it's simpler to clear it now rather than
  352              * track and zero any pieces we didn't touch after we've written
  353              * all of the sections to memory.
  354              */
  355             bzero(linked_object, vmsize);
  356 
  357             /* Relocate to the new link address */
  358 
  359             rval = kxld_kext_relocate(context->kext, vmaddr, &context->vtables, 
  360                 &context->defined_symbols, &context->obsolete_symbols);
  361             require_noerr(rval, finish);
  362 
  363             /* Generate linked object if requested */
  364 
  365             if (_linked_object) {
  366                 check(kmod_info_kern);
  367                 *_linked_object = NULL;
  368                 *kmod_info_kern = 0;
  369 
  370                 rval = kxld_kext_export_linked_object(context->kext, linked_object, 
  371                     kmod_info_kern);
  372                 require_noerr(rval, finish);
  373             }
  374 
  375         } else  {
  376             /* Resolve the pseudokext's symbols */
  377 
  378             rval = kxld_kext_resolve(context->kext, &context->vtables, 
  379                 &context->defined_symbols);
  380             require_noerr(rval, finish);
  381         }
  382     }
  383 
  384     /* Generate link state if requested */
  385 
  386     if (_link_state) {
  387         check(_link_state_size);
  388         *_link_state = NULL;
  389         *_link_state_size = 0;
  390 
  391         kxld_dict_clear(&context->defined_symbols);
  392         rval = kxld_state_export_kext_to_file(context->kext, &link_state,
  393             &link_state_size, &context->defined_symbols, &context->tmps);
  394         require_noerr(rval, finish);
  395     }
  396 
  397 #if !KERNEL
  398     /* Generate symbol file if requested */
  399 
  400     if (_symbol_file) {
  401         check(_symbol_file_size);
  402         *_symbol_file = NULL;
  403         *_symbol_file_size = 0;
  404 
  405         rval = kxld_kext_export_symbol_file(context->kext, &symbol_file,
  406             &symbol_file_size);
  407         require_noerr(rval, finish);
  408     }
  409 #endif /* !KERNEL */
  410 
  411     /* Commit output to return variables */
  412 
  413     if (_linked_object) {
  414         *_linked_object = linked_object;
  415         linked_object = NULL;
  416         linked_object_alloc = NULL;
  417     }
  418 
  419     if (_link_state) {
  420         *_link_state = link_state;
  421         *_link_state_size = link_state_size;
  422         link_state = NULL;
  423     }
  424 
  425 #if !KERNEL
  426     if (_symbol_file) {
  427         *_symbol_file = symbol_file;
  428         *_symbol_file_size = symbol_file_size;
  429         symbol_file = NULL;
  430     }
  431 #endif
  432 
  433     rval = KERN_SUCCESS;
  434 
  435 finish:
  436 
  437     if (linked_object_alloc) kxld_page_free_untracked(linked_object_alloc, vmsize);
  438     if (link_state) kxld_page_free_untracked(link_state, link_state_size);
  439     if (symbol_file) kxld_page_free_untracked(symbol_file, symbol_file_size);
  440 
  441     clear_context(context);
  442 
  443     kxld_set_logging_callback_data(NULL, NULL);
  444 
  445     return rval;
  446 }
  447 
  448 /*******************************************************************************
  449 *******************************************************************************/
  450 static void
  451 clear_context(KXLDContext *context)
  452 {
  453     KXLDState *state = NULL;
  454     u_int i = 0;
  455 
  456     check(context);
  457 
  458     kxld_kext_clear(context->kext);
  459     for (i = 0; i < context->deps.nitems; ++i) {
  460         state = kxld_array_get_item(&context->deps, i);
  461         kxld_state_clear(state);
  462     }
  463     kxld_array_reset(&context->deps);
  464 
  465     kxld_array_clear(&context->tmps);
  466     kxld_dict_clear(&context->defined_symbols);
  467     kxld_dict_clear(&context->obsolete_symbols);
  468     kxld_dict_clear(&context->vtables);
  469 }
  470 

Cache object: ae27ab32a1b07f5fbea309c125e2c0eb


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.