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/kern/link_aout.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) 1997 Doug Rabson
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  *
   14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   24  * SUCH DAMAGE.
   25  *
   26  * $FreeBSD$
   27  */
   28 
   29 #ifndef __alpha__
   30 
   31 #define FREEBSD_AOUT    1
   32 
   33 #include <sys/param.h>
   34 #include <sys/kernel.h>
   35 #include <sys/systm.h>
   36 #include <sys/malloc.h>
   37 #include <sys/proc.h>
   38 #include <sys/namei.h>
   39 #include <sys/fcntl.h>
   40 #include <sys/vnode.h>
   41 #include <sys/linker.h>
   42 
   43 #include <vm/vm_zone.h>
   44 
   45 #ifndef __ELF__
   46 #include <vm/vm.h>
   47 #include <vm/pmap.h>
   48 #include <machine/vmparam.h>
   49 #endif
   50 
   51 #include <a.out.h>
   52 #include <link.h>
   53 
   54 static int              link_aout_load_module(const char*, linker_file_t*);
   55 
   56 static int              link_aout_load_file(const char*, linker_file_t*);
   57 
   58 static int              link_aout_lookup_symbol(linker_file_t, const char*,
   59                                                 c_linker_sym_t*);
   60 static int              link_aout_symbol_values(linker_file_t file, c_linker_sym_t sym,
   61                                                 linker_symval_t* symval);
   62 static int              link_aout_search_symbol(linker_file_t lf, caddr_t value,
   63                                                 c_linker_sym_t* sym, long* diffp);
   64 static void             link_aout_unload_file(linker_file_t);
   65 static void             link_aout_unload_module(linker_file_t);
   66 
   67 static struct linker_class_ops link_aout_class_ops = {
   68     link_aout_load_module,
   69 };
   70 
   71 static struct linker_file_ops link_aout_file_ops = {
   72     link_aout_lookup_symbol,
   73     link_aout_symbol_values,
   74     link_aout_search_symbol,
   75     link_aout_unload_file,
   76 };
   77 static struct linker_file_ops link_aout_module_ops = {
   78     link_aout_lookup_symbol,
   79     link_aout_symbol_values,
   80     link_aout_search_symbol,
   81     link_aout_unload_module,
   82 };
   83 
   84 typedef struct aout_file {
   85     char*               address;        /* Load address */
   86     struct _dynamic*    dynamic;        /* Symbol table etc. */
   87 } *aout_file_t;
   88 
   89 static int              load_dependancies(linker_file_t lf);
   90 static int              relocate_file(linker_file_t lf);
   91 
   92 /*
   93  * The kernel symbol table starts here.
   94  */
   95 extern struct _dynamic _DYNAMIC;
   96 
   97 static void
   98 link_aout_init(void* arg)
   99 {
  100 #ifndef __ELF__
  101     struct _dynamic* dp = &_DYNAMIC;
  102 #endif
  103 
  104     linker_add_class("a.out", NULL, &link_aout_class_ops);
  105 
  106 #ifndef __ELF__
  107     if (dp) {
  108         aout_file_t af;
  109 
  110         af = malloc(sizeof(struct aout_file), M_LINKER, M_NOWAIT);
  111         if (af == NULL)
  112             panic("link_aout_init: Can't create linker structures for kernel");
  113         bzero(af, sizeof(*af));
  114 
  115         af->address = 0;
  116         af->dynamic = dp;
  117         linker_kernel_file =
  118             linker_make_file(kernelname, af, &link_aout_file_ops);
  119         if (linker_kernel_file == NULL)
  120             panic("link_aout_init: Can't create linker structures for kernel");
  121         linker_kernel_file->address = (caddr_t) KERNBASE;
  122         linker_kernel_file->size = -(long)linker_kernel_file->address;
  123         linker_current_file = linker_kernel_file;
  124         linker_kernel_file->flags |= LINKER_FILE_LINKED;
  125     }
  126 #endif
  127 }
  128 
  129 SYSINIT(link_aout, SI_SUB_KLD, SI_ORDER_THIRD, link_aout_init, 0);
  130 
  131 static int
  132 link_aout_load_module(const char* filename, linker_file_t* result)
  133 {
  134     caddr_t             modptr, baseptr;
  135     char                *type;
  136     struct exec         *ehdr;
  137     aout_file_t         af;
  138     linker_file_t       lf;
  139     int                 error;
  140     
  141     /* Look to see if we have the module preloaded. */
  142     if ((modptr = preload_search_by_name(filename)) == NULL)
  143         return(link_aout_load_file(filename, result));
  144 
  145     /* It's preloaded, check we can handle it and collect information. */
  146     if (((type = (char *)preload_search_info(modptr, MODINFO_TYPE)) == NULL) ||
  147         strcmp(type, "a.out module") ||
  148         ((baseptr = preload_search_info(modptr, MODINFO_ADDR)) == NULL) ||
  149         ((ehdr = (struct exec *)preload_search_info(modptr, MODINFO_METADATA | MODINFOMD_AOUTEXEC)) == NULL))
  150         return(0);                      /* we can't handle this */
  151 
  152     /* Looks like we can handle this one */
  153     af = malloc(sizeof(struct aout_file), M_LINKER, M_WAITOK);
  154     bzero(af, sizeof(*af));
  155     af->address = baseptr;
  156 
  157     /* Assume _DYNAMIC is the first data item. */
  158     af->dynamic = (struct _dynamic*)(af->address + ehdr->a_text);
  159     if (af->dynamic->d_version != LD_VERSION_BSD) {
  160         free(af, M_LINKER);
  161         return(0);                      /* we can't handle this */
  162     }
  163     af->dynamic->d_un.d_sdt = (struct section_dispatch_table *)
  164         ((char *)af->dynamic->d_un.d_sdt + (vm_offset_t)af->address);
  165 
  166     /* Register with kld */
  167     lf = linker_make_file(filename, af, &link_aout_module_ops);
  168     if (lf == NULL) {
  169         free(af, M_LINKER);
  170         return(ENOMEM);
  171     }
  172     lf->address = af->address;
  173     lf->size = ehdr->a_text + ehdr->a_data + ehdr->a_bss;
  174 
  175     /* Try to load dependancies */
  176     if (((error = load_dependancies(lf)) != 0) ||
  177         ((error = relocate_file(lf)) != 0)) {
  178         linker_file_unload(lf);
  179         return(error);
  180     }
  181     lf->flags |= LINKER_FILE_LINKED;
  182     *result = lf;
  183     return(0);
  184 }
  185 
  186 static int
  187 link_aout_load_file(const char* filename, linker_file_t* result)
  188 {
  189     struct nameidata nd;
  190     struct proc* p = curproc;   /* XXX */
  191     int error = 0;
  192     int resid;
  193     struct exec header;
  194     aout_file_t af;
  195     linker_file_t lf;
  196     char *pathname;
  197 
  198     pathname = linker_search_path(filename);
  199     if (pathname == NULL)
  200         return ENOENT;
  201     NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, pathname, p);
  202     error = vn_open(&nd, FREAD, 0);
  203     free(pathname, M_LINKER);
  204     if (error)
  205         return error;
  206     NDFREE(&nd, NDF_ONLY_PNBUF);
  207 
  208     /*
  209      * Read the a.out header from the file.
  210      */
  211     error = vn_rdwr(UIO_READ, nd.ni_vp, (void*) &header, sizeof header, 0,
  212                     UIO_SYSSPACE, IO_NODELOCKED, p->p_ucred, &resid, p);
  213     if (error)
  214         goto out;
  215 
  216     if (N_BADMAG(header) || !(N_GETFLAG(header) & EX_DYNAMIC))
  217         goto out;
  218 
  219     /*
  220      * We have an a.out file, so make some space to read it in.
  221      */
  222     af = malloc(sizeof(struct aout_file), M_LINKER, M_WAITOK);
  223     bzero(af, sizeof(*af));
  224     af->address = malloc(header.a_text + header.a_data + header.a_bss,
  225                          M_LINKER, M_WAITOK);
  226     
  227     /*
  228      * Read the text and data sections and zero the bss.
  229      */
  230     error = vn_rdwr(UIO_READ, nd.ni_vp, (void*) af->address,
  231                     header.a_text + header.a_data, 0,
  232                     UIO_SYSSPACE, IO_NODELOCKED, p->p_ucred, &resid, p);
  233     if (error)
  234         goto out;
  235     bzero(af->address + header.a_text + header.a_data, header.a_bss);
  236 
  237     /*
  238      * Assume _DYNAMIC is the first data item.
  239      */
  240     af->dynamic = (struct _dynamic*) (af->address + header.a_text);
  241     if (af->dynamic->d_version != LD_VERSION_BSD) {
  242         free(af->address, M_LINKER);
  243         free(af, M_LINKER);
  244         goto out;
  245     }
  246     af->dynamic->d_un.d_sdt = (struct section_dispatch_table *)
  247         ((char *)af->dynamic->d_un.d_sdt + (vm_offset_t)af->address);
  248 
  249     lf = linker_make_file(filename, af, &link_aout_file_ops);
  250     if (lf == NULL) {
  251         free(af->address, M_LINKER);
  252         free(af, M_LINKER);
  253         error = ENOMEM;
  254         goto out;
  255     }
  256     lf->address = af->address;
  257     lf->size = header.a_text + header.a_data + header.a_bss;
  258 
  259     if ((error = load_dependancies(lf)) != 0
  260         || (error = relocate_file(lf)) != 0) {
  261         linker_file_unload(lf);
  262         goto out;
  263     }
  264 
  265     lf->flags |= LINKER_FILE_LINKED;
  266     *result = lf;
  267 
  268 out:
  269     VOP_UNLOCK(nd.ni_vp, 0, p);
  270     vn_close(nd.ni_vp, FREAD, p->p_ucred, p);
  271 
  272     return error;
  273 }
  274 
  275 static void
  276 link_aout_unload_file(linker_file_t file)
  277 {
  278     aout_file_t af = file->priv;
  279 
  280     if (af) {
  281         if (af->address)
  282             free(af->address, M_LINKER);
  283         free(af, M_LINKER);
  284     }
  285 }
  286 
  287 static void
  288 link_aout_unload_module(linker_file_t file)
  289 {
  290     aout_file_t af = file->priv;
  291 
  292     if (af)
  293         free(af, M_LINKER);
  294     if (file->filename)
  295         preload_delete_name(file->filename);
  296 }
  297 
  298 #define AOUT_RELOC(af, type, off) (type*) ((af)->address + (off))
  299 
  300 static int
  301 load_dependancies(linker_file_t lf)
  302 {
  303     aout_file_t af = lf->priv;
  304     linker_file_t lfdep;
  305     long off;
  306     struct sod* sodp;
  307     char* name;
  308     char* filename = 0;
  309     int error = 0;
  310 
  311     /*
  312      * All files are dependant on /kernel.
  313      */
  314     if (linker_kernel_file) {
  315         linker_kernel_file->refs++;
  316         linker_file_add_dependancy(lf, linker_kernel_file);
  317     }
  318 
  319     off = LD_NEED(af->dynamic);
  320 
  321     /*
  322      * Load the dependancies.
  323      */
  324     while (off != 0) {
  325         sodp = AOUT_RELOC(af, struct sod, off);
  326         name = AOUT_RELOC(af, char, sodp->sod_name);
  327 
  328         error = linker_load_file(name, &lfdep);
  329         if (error)
  330             goto out;
  331         error = linker_file_add_dependancy(lf, lfdep);
  332         if (error)
  333             goto out;
  334         off = sodp->sod_next;
  335     }
  336 
  337 out:
  338     if (filename)
  339         free(filename, M_TEMP);
  340     return error;
  341 }
  342 
  343 /*
  344  * XXX i386 dependant.
  345  */
  346 static long
  347 read_relocation(struct relocation_info* r, char* addr)
  348 {
  349     int length = r->r_length;
  350     if (length == 0)
  351         return *(u_char*) addr;
  352     else if (length == 1)
  353         return *(u_short*) addr;
  354     else if (length == 2)
  355         return *(u_int*) addr;
  356     else
  357         printf("link_aout: unsupported relocation size %d\n", r->r_length);
  358     return 0;
  359 }
  360 
  361 static void
  362 write_relocation(struct relocation_info* r, char* addr, long value)
  363 {
  364     int length = r->r_length;
  365     if (length == 0)
  366         *(u_char*) addr = value;
  367     else if (length == 1)
  368         *(u_short*) addr = value;
  369     else if (length == 2)
  370         *(u_int*) addr = value;
  371     else
  372         printf("link_aout: unsupported relocation size %d\n", r->r_length);
  373 }
  374 
  375 static int
  376 relocate_file(linker_file_t lf)
  377 {
  378     aout_file_t af = lf->priv;
  379     struct relocation_info* rel;
  380     struct relocation_info* erel;
  381     struct relocation_info* r;
  382     struct nzlist* symbolbase;
  383     char* stringbase;
  384     struct nzlist* np;
  385     char* sym;
  386     long relocation;
  387 
  388     rel = AOUT_RELOC(af, struct relocation_info, LD_REL(af->dynamic));
  389     erel = AOUT_RELOC(af, struct relocation_info,
  390                       LD_REL(af->dynamic) + LD_RELSZ(af->dynamic));
  391     symbolbase = AOUT_RELOC(af, struct nzlist, LD_SYMBOL(af->dynamic));
  392     stringbase = AOUT_RELOC(af, char, LD_STRINGS(af->dynamic));
  393 
  394     for (r = rel; r < erel; r++) {
  395         char* addr;
  396 
  397         if (r->r_address == 0)
  398             break;
  399 
  400         addr = AOUT_RELOC(af, char, r->r_address);
  401         if (r->r_extern) {
  402             np = &symbolbase[r->r_symbolnum];
  403             sym = &stringbase[np->nz_strx];
  404 
  405             if (sym[0] != '_') {
  406                 printf("link_aout: bad symbol name %s\n", sym);
  407                 relocation = 0;
  408             } else
  409                 relocation = (intptr_t)
  410                     linker_file_lookup_symbol(lf, sym + 1,
  411                                               np->nz_type != (N_SETV+N_EXT));
  412             if (!relocation) {
  413                 printf("link_aout: symbol %s not found\n", sym);
  414                 return ENOENT;
  415             }
  416             
  417             relocation += read_relocation(r, addr);
  418 
  419             if (r->r_jmptable) {
  420                 printf("link_aout: can't cope with jump table relocations\n");
  421                 continue;
  422             }
  423 
  424             if (r->r_pcrel)
  425                 relocation -= (intptr_t) af->address;
  426 
  427             if (r->r_copy) {
  428                 printf("link_aout: can't cope with copy relocations\n");
  429                 continue;
  430             }
  431             
  432             write_relocation(r, addr, relocation);
  433         } else {
  434             write_relocation(r, addr,
  435                              (intptr_t)(read_relocation(r, addr) + af->address));
  436         }
  437         
  438     }
  439 
  440     return 0;
  441 }
  442 
  443 static long
  444 symbol_hash_value(aout_file_t af, const char* name)
  445 {
  446     long hashval;
  447     const char* p;
  448 
  449     hashval = '_';              /* fake a starting '_' for C symbols */
  450     for (p = name; *p; p++)
  451         hashval = (hashval << 1) + *p;
  452 
  453     return (hashval & 0x7fffffff) % LD_BUCKETS(af->dynamic);
  454 }
  455 
  456 int
  457 link_aout_lookup_symbol(linker_file_t file, const char* name,
  458                         c_linker_sym_t* sym)
  459 {
  460     aout_file_t af = file->priv;
  461     long hashval;
  462     struct rrs_hash* hashbase;
  463     struct nzlist* symbolbase;
  464     char* stringbase;
  465     struct rrs_hash* hp;
  466     struct nzlist* np;
  467     char* cp;
  468 
  469     if (LD_BUCKETS(af->dynamic) == 0)
  470         return 0;
  471 
  472     hashbase = AOUT_RELOC(af, struct rrs_hash, LD_HASH(af->dynamic));
  473     symbolbase = AOUT_RELOC(af, struct nzlist, LD_SYMBOL(af->dynamic));
  474     stringbase = AOUT_RELOC(af, char, LD_STRINGS(af->dynamic));
  475 
  476 restart:
  477     hashval = symbol_hash_value(af, name);
  478     hp = &hashbase[hashval];
  479     if (hp->rh_symbolnum == -1)
  480         return ENOENT;
  481 
  482     while (hp) {
  483         np = (struct nzlist *) &symbolbase[hp->rh_symbolnum];
  484         cp = stringbase + np->nz_strx;
  485         /*
  486          * Note: we fake the leading '_' for C symbols.
  487          */
  488         if (cp[0] == '_' && !strcmp(cp + 1, name))
  489             break;
  490 
  491         if (hp->rh_next == 0)
  492             hp = NULL;
  493         else
  494             hp = &hashbase[hp->rh_next];
  495     }
  496 
  497     if (hp == NULL)
  498         /*
  499          * Not found.
  500          */
  501         return ENOENT;
  502 
  503     /*
  504      * Check for an aliased symbol, whatever that is.
  505      */
  506     if (np->nz_type == N_INDR+N_EXT) {
  507         name = stringbase + (++np)->nz_strx + 1; /* +1 for '_' */
  508         goto restart;
  509     }
  510 
  511     /*
  512      * Check this is an actual definition of the symbol.
  513      */
  514     if (np->nz_value == 0)
  515         return ENOENT;
  516 
  517     if (np->nz_type == N_UNDF+N_EXT && np->nz_value != 0) {
  518         if (np->nz_other == AUX_FUNC)
  519             /* weak function */
  520             return ENOENT;
  521     }
  522 
  523     *sym = (linker_sym_t) np;
  524 
  525     return 0;
  526 }
  527 
  528 
  529 static int
  530 link_aout_symbol_values(linker_file_t file, c_linker_sym_t sym,
  531                         linker_symval_t* symval)
  532 {
  533     aout_file_t af = file->priv;
  534     const struct nzlist* np = (const struct nzlist*) sym;
  535     char* stringbase;
  536     long numsym = LD_STABSZ(af->dynamic) / sizeof(struct nzlist);
  537     struct nzlist *symbase;
  538 
  539     /* Is it one of ours?  It could be another module... */
  540     symbase = AOUT_RELOC(af, struct nzlist, LD_SYMBOL(af->dynamic));
  541     if (np < symbase)
  542         return ENOENT;
  543     if ((np - symbase) > numsym)
  544         return ENOENT;
  545 
  546     stringbase = AOUT_RELOC(af, char, LD_STRINGS(af->dynamic));
  547 
  548     symval->name = stringbase + np->nz_strx + 1; /* +1 for '_' */
  549     if (np->nz_type == N_UNDF+N_EXT && np->nz_value != 0) {
  550         symval->value = 0;
  551         symval->size = np->nz_value;
  552     } else {
  553         symval->value = AOUT_RELOC(af, char, np->nz_value);
  554         symval->size = np->nz_size;
  555     }
  556     return 0;
  557 }
  558 
  559 static int
  560 link_aout_search_symbol(linker_file_t lf, caddr_t value,
  561                         c_linker_sym_t* sym, long* diffp)
  562 {
  563         aout_file_t af = lf->priv;
  564         u_long off = (uintptr_t) (void *) value;
  565         u_long diff = off;
  566         u_long sp_nz_value;
  567         struct nzlist* sp;
  568         struct nzlist* ep;
  569         struct nzlist* best = 0;
  570 
  571         for (sp = AOUT_RELOC(af, struct nzlist, LD_SYMBOL(af->dynamic)),
  572                  ep = (struct nzlist *) ((caddr_t) sp + LD_STABSZ(af->dynamic));
  573              sp < ep; sp++) {
  574                 if (sp->nz_name == 0)
  575                         continue;
  576                 sp_nz_value = sp->nz_value + (uintptr_t) (void *) af->address;
  577                 if (off >= sp_nz_value) {
  578                         if (off - sp_nz_value < diff) {
  579                                 diff = off - sp_nz_value;
  580                                 best = sp;
  581                                 if (diff == 0)
  582                                         break;
  583                         } else if (off - sp_nz_value == diff) {
  584                                 best = sp;
  585                         }
  586                 }
  587         }
  588         if (best == 0)
  589                 *diffp = off;
  590         else
  591                 *diffp = diff;
  592         *sym = (linker_sym_t) best;
  593 
  594         return 0;
  595 }
  596 
  597 #endif /* !__alpha__ */

Cache object: 2f6df4b74e1c831b67429fa5a0689f68


[ 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.