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

Cache object: 414f30237eed5690c844e43413d77751


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