[BACK]Return to symbol.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / libexec / ld.elf_so

Annotation of src/libexec/ld.elf_so/symbol.c, Revision 1.39

1.39    ! chs         1: /*     $NetBSD: symbol.c,v 1.38 2005/01/11 21:58:27 martin Exp $        */
1.1       cgd         2:
                      3: /*
                      4:  * Copyright 1996 John D. Polstra.
                      5:  * Copyright 1996 Matt Thomas <matt@3am-software.com>
1.25      mycroft     6:  * Copyright 2002 Charles M. Hannum <root@ihack.net>
1.1       cgd         7:  * All rights reserved.
                      8:  *
                      9:  * Redistribution and use in source and binary forms, with or without
                     10:  * modification, are permitted provided that the following conditions
                     11:  * are met:
                     12:  * 1. Redistributions of source code must retain the above copyright
                     13:  *    notice, this list of conditions and the following disclaimer.
                     14:  * 2. Redistributions in binary form must reproduce the above copyright
                     15:  *    notice, this list of conditions and the following disclaimer in the
                     16:  *    documentation and/or other materials provided with the distribution.
                     17:  * 3. All advertising materials mentioning features or use of this software
                     18:  *    must display the following acknowledgement:
                     19:  *      This product includes software developed by John Polstra.
                     20:  * 4. The name of the author may not be used to endorse or promote products
                     21:  *    derived from this software without specific prior written permission.
                     22:  *
                     23:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
                     24:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
                     25:  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
                     26:  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
                     27:  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
                     28:  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
                     29:  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
                     30:  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
                     31:  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
                     32:  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
                     33:  */
                     34:
                     35: /*
                     36:  * Dynamic linker for ELF.
                     37:  *
                     38:  * John Polstra <jdp@polstra.com>.
                     39:  */
                     40:
1.37      skrll      41: #include <sys/cdefs.h>
                     42: #ifndef lint
1.39    ! chs        43: __RCSID("$NetBSD: symbol.c,v 1.38 2005/01/11 21:58:27 martin Exp $");
1.37      skrll      44: #endif /* not lint */
                     45:
1.1       cgd        46: #include <err.h>
                     47: #include <errno.h>
                     48: #include <fcntl.h>
                     49: #include <stdarg.h>
                     50: #include <stdio.h>
                     51: #include <stdlib.h>
                     52: #include <string.h>
                     53: #include <unistd.h>
                     54: #include <sys/types.h>
                     55: #include <sys/mman.h>
                     56: #include <dirent.h>
                     57:
                     58: #include "debug.h"
                     59: #include "rtld.h"
                     60:
1.39    ! chs        61: typedef void (*fptr_t)(void);
        !            62:
1.33      skrll      63: static bool
                     64: _rtld_is_exported(const Elf_Sym *def)
                     65: {
1.39    ! chs        66:        static fptr_t _rtld_exports[] = {
        !            67:                (fptr_t)dlopen,
        !            68:                (fptr_t)dlclose,
        !            69:                (fptr_t)dlsym,
        !            70:                (fptr_t)dlerror,
        !            71:                (fptr_t)dladdr,
        !            72:                NULL
1.33      skrll      73:        };
                     74:        int i;
1.39    ! chs        75:        fptr_t value;
1.33      skrll      76:
1.39    ! chs        77:        value = (fptr_t)(_rtld_objself.relocbase + def->st_value);
        !            78:        for (i = 0; _rtld_exports[i] != NULL; i++) {
1.33      skrll      79:                if (value == _rtld_exports[i])
                     80:                        return true;
                     81:        }
                     82:        return false;
                     83: }
                     84:
1.1       cgd        85: /*
                     86:  * Hash function for symbol table lookup.  Don't even think about changing
                     87:  * this.  It is specified by the System V ABI.
                     88:  */
                     89: unsigned long
1.31      skrll      90: _rtld_elf_hash(const char *name)
1.1       cgd        91: {
1.3       christos   92:        const unsigned char *p = (const unsigned char *) name;
                     93:        unsigned long   h = 0;
                     94:        unsigned long   g;
1.24      mycroft    95:        unsigned long   c;
1.3       christos   96:
1.24      mycroft    97:        for (; __predict_true((c = *p) != '\0'); p++) {
                     98:                h <<= 4;
                     99:                h += c;
                    100:                if ((g = h & 0xf0000000) != 0) {
                    101:                        h ^= g;
1.3       christos  102:                        h ^= g >> 24;
1.24      mycroft   103:                }
1.3       christos  104:        }
1.24      mycroft   105:        return (h);
1.1       cgd       106: }
                    107:
1.5       mycroft   108: const Elf_Sym *
1.23      mycroft   109: _rtld_symlook_list(const char *name, unsigned long hash, const Objlist *objlist,
1.31      skrll     110:     const Obj_Entry **defobj_out, bool in_plt)
1.5       mycroft   111: {
                    112:        const Elf_Sym *symp;
                    113:        const Elf_Sym *def;
1.27      mycroft   114:        const Obj_Entry *defobj;
1.5       mycroft   115:        const Objlist_Entry *elm;
                    116:
                    117:        def = NULL;
1.27      mycroft   118:        defobj = NULL;
1.12      lukem     119:        SIMPLEQ_FOREACH(elm, objlist, link) {
1.23      mycroft   120:                rdbg(("search object %p (%s)", elm->obj, elm->obj->path));
1.21      mycroft   121:                if ((symp = _rtld_symlook_obj(name, hash, elm->obj, in_plt))
1.5       mycroft   122:                    != NULL) {
                    123:                        if ((def == NULL) ||
1.6       thorpej   124:                            (ELF_ST_BIND(symp->st_info) != STB_WEAK)) {
1.5       mycroft   125:                                def = symp;
1.27      mycroft   126:                                defobj = elm->obj;
1.6       thorpej   127:                                if (ELF_ST_BIND(def->st_info) != STB_WEAK)
1.5       mycroft   128:                                        break;
                    129:                        }
                    130:                }
                    131:        }
1.27      mycroft   132:        if (def != NULL)
                    133:                *defobj_out = defobj;
1.5       mycroft   134:        return def;
                    135: }
                    136:
1.1       cgd       137: /*
                    138:  * Search the symbol table of a single shared object for a symbol of
                    139:  * the given name.  Returns a pointer to the symbol, or NULL if no
                    140:  * definition was found.
                    141:  *
                    142:  * The symbol's hash value is passed in for efficiency reasons; that
                    143:  * eliminates many recomputations of the hash value.
                    144:  */
                    145: const Elf_Sym *
1.31      skrll     146: _rtld_symlook_obj(const char *name, unsigned long hash,
                    147:     const Obj_Entry *obj, bool in_plt)
1.1       cgd       148: {
1.20      mycroft   149:        unsigned long symnum;
1.1       cgd       150:
1.20      mycroft   151:        for (symnum = obj->buckets[hash % obj->nbuckets];
                    152:             symnum != ELF_SYM_UNDEFINED;
                    153:             symnum = obj->chains[symnum]) {
1.3       christos  154:                const Elf_Sym  *symp;
                    155:                const char     *strp;
                    156:
                    157:                assert(symnum < obj->nchains);
                    158:                symp = obj->symtab + symnum;
                    159:                strp = obj->strtab + symp->st_name;
1.38      martin    160:                rdbg(("check \"%s\" vs \"%s\" in %p", name, strp, obj));
1.20      mycroft   161:                if (name[1] == strp[1] && !strcmp(name, strp)) {
                    162:                        if (symp->st_shndx != SHN_UNDEF)
1.3       christos  163:                                return symp;
1.21      mycroft   164: #ifndef __mips__
1.22      mycroft   165:                        /*
                    166:                         * XXX DANGER WILL ROBINSON!
                    167:                         * If we have a function pointer in the executable's
                    168:                         * data section, it points to the executable's PLT
                    169:                         * slot, and there is NO relocation emitted.  To make
                    170:                         * the function pointer comparable to function pointers
                    171:                         * in shared libraries, we must resolve data references
                    172:                         * in the libraries to point to PLT slots in the
                    173:                         * executable, if they exist.
                    174:                         */
1.21      mycroft   175:                        else if (!in_plt && symp->st_value != 0 &&
                    176:                             ELF_ST_TYPE(symp->st_info) == STT_FUNC)
                    177:                                return symp;
                    178: #endif
1.19      mycroft   179:                        else
                    180:                                return NULL;
1.3       christos  181:                }
1.1       cgd       182:        }
                    183:
1.3       christos  184:        return NULL;
1.1       cgd       185: }
                    186:
                    187: /*
                    188:  * Given a symbol number in a referencing object, find the corresponding
                    189:  * definition of the symbol.  Returns a pointer to the symbol, or NULL if
                    190:  * no definition was found.  Returns a pointer to the Obj_Entry of the
                    191:  * defining object via the reference parameter DEFOBJ_OUT.
                    192:  */
                    193: const Elf_Sym *
1.31      skrll     194: _rtld_find_symdef(unsigned long symnum, const Obj_Entry *refobj,
                    195:     const Obj_Entry **defobj_out, bool in_plt)
1.1       cgd       196: {
1.27      mycroft   197:        const Elf_Sym  *ref;
1.5       mycroft   198:        const Elf_Sym  *def;
                    199:        const Elf_Sym  *symp;
1.3       christos  200:        const Obj_Entry *obj;
1.27      mycroft   201:        const Obj_Entry *defobj;
1.5       mycroft   202:        const Objlist_Entry *elm;
1.27      mycroft   203:        const char     *name;
1.3       christos  204:        unsigned long   hash;
                    205:
1.27      mycroft   206:        ref = refobj->symtab + symnum;
                    207:        name = refobj->strtab + ref->st_name;
                    208:
1.3       christos  209:        hash = _rtld_elf_hash(name);
1.5       mycroft   210:        def = NULL;
1.27      mycroft   211:        defobj = NULL;
1.5       mycroft   212:
1.32      skrll     213:        /* Look first in the referencing object if linked symbolically */
                    214:        if (refobj->symbolic) {
1.21      mycroft   215:                symp = _rtld_symlook_obj(name, hash, refobj, in_plt);
1.5       mycroft   216:                if (symp != NULL) {
                    217:                        def = symp;
1.27      mycroft   218:                        defobj = refobj;
1.5       mycroft   219:                }
                    220:        }
                    221:
                    222:        /* Search all objects loaded at program start up. */
1.6       thorpej   223:        if (def == NULL || ELF_ST_BIND(def->st_info) == STB_WEAK) {
1.23      mycroft   224:                rdbg(("search _rtld_list_main"));
1.21      mycroft   225:                symp = _rtld_symlook_list(name, hash, &_rtld_list_main, &obj, in_plt);
1.5       mycroft   226:                if (symp != NULL &&
1.6       thorpej   227:                    (def == NULL || ELF_ST_BIND(symp->st_info) != STB_WEAK)) {
1.5       mycroft   228:                        def = symp;
1.27      mycroft   229:                        defobj = obj;
1.5       mycroft   230:                }
                    231:        }
                    232:
1.35      mrauch    233:        /* Search all RTLD_GLOBAL objects. */
                    234:        if (def == NULL || ELF_ST_BIND(def->st_info) == STB_WEAK) {
                    235:                rdbg(("search _rtld_list_global"));
                    236:                symp = _rtld_symlook_list(name, hash, &_rtld_list_global, &obj, in_plt);
1.5       mycroft   237:                if (symp != NULL &&
1.6       thorpej   238:                    (def == NULL || ELF_ST_BIND(symp->st_info) != STB_WEAK)) {
1.5       mycroft   239:                        def = symp;
1.27      mycroft   240:                        defobj = obj;
1.3       christos  241:                }
                    242:        }
1.5       mycroft   243:
1.35      mrauch    244:        /* Search all dlopened DAGs containing the referencing object. */
                    245:        SIMPLEQ_FOREACH(elm, &refobj->dldags, link) {
                    246:                if (def != NULL && ELF_ST_BIND(def->st_info) != STB_WEAK)
                    247:                        break;
                    248:                rdbg(("search DAG with root %p (%s)", elm->obj, elm->obj->path));
                    249:                symp = _rtld_symlook_list(name, hash, &elm->obj->dagmembers, &obj, in_plt);
1.5       mycroft   250:                if (symp != NULL &&
1.6       thorpej   251:                    (def == NULL || ELF_ST_BIND(symp->st_info) != STB_WEAK)) {
1.5       mycroft   252:                        def = symp;
1.27      mycroft   253:                        defobj = obj;
1.3       christos  254:                }
                    255:        }
1.5       mycroft   256:
1.27      mycroft   257:        /*
1.33      skrll     258:         * Search the dynamic linker itself, and possibly resolve the
                    259:         * symbol from there.  This is how the application links to
                    260:         * dynamic linker services such as dlopen.  Only the values listed
                    261:         * in the "_rtld_exports" array can be resolved from the dynamic linker.
                    262:         */
                    263:        if (def == NULL || ELF_ST_BIND(def->st_info) == STB_WEAK) {
1.39    ! chs       264:                rdbg(("search rtld itself"));
1.33      skrll     265:                symp = _rtld_symlook_obj(name, hash, &_rtld_objself, in_plt);
                    266:                if (symp != NULL && _rtld_is_exported(symp)) {
                    267:                        def = symp;
                    268:                        defobj = &_rtld_objself;
                    269:                }
                    270:        }
                    271:
                    272:        /*
1.27      mycroft   273:         * If we found no definition and the reference is weak, treat the
                    274:         * symbol as having the value zero.
                    275:         */
                    276:        if (def == NULL && ELF_ST_BIND(ref->st_info) == STB_WEAK) {
                    277:                rdbg(("  returning _rtld_sym_zero@_rtld_objmain"));
                    278:                def = &_rtld_sym_zero;
                    279:                defobj = _rtld_objmain;
                    280:        }
1.33      skrll     281:
1.27      mycroft   282:        if (def != NULL)
                    283:                *defobj_out = defobj;
                    284:        else {
                    285:                rdbg(("lookup failed"));
                    286:                _rtld_error("%s: Undefined %ssymbol \"%s\" (symnum = %ld)",
                    287:                    refobj->path, in_plt ? "PLT " : "", name, symnum);
                    288:        }
1.26      mycroft   289:        return def;
1.28      christos  290: }
                    291:
                    292: /*
                    293:  * Given a symbol name in a referencing object, find the corresponding
                    294:  * definition of the symbol.  Returns a pointer to the symbol, or NULL if
                    295:  * no definition was found.  Returns a pointer to the Obj_Entry of the
                    296:  * defining object via the reference parameter DEFOBJ_OUT.
                    297:  */
                    298: const Elf_Sym *
                    299: _rtld_symlook_default(const char *name, unsigned long hash,
                    300:     const Obj_Entry *refobj, const Obj_Entry **defobj_out, bool in_plt)
                    301: {
1.29      skrll     302:        const Elf_Sym *def;
                    303:        const Elf_Sym *symp;
                    304:        const Obj_Entry *obj;
                    305:        const Obj_Entry *defobj;
                    306:        const Objlist_Entry *elm;
                    307:        def = NULL;
                    308:        defobj = NULL;
                    309:
                    310:        /* Look first in the referencing object if linked symbolically. */
                    311:        if (refobj->symbolic) {
                    312:                symp = _rtld_symlook_obj(name, hash, refobj, in_plt);
                    313:                if (symp != NULL) {
                    314:                        def = symp;
                    315:                        defobj = refobj;
                    316:                }
                    317:        }
                    318:
                    319:        /* Search all objects loaded at program start up. */
                    320:        if (def == NULL || ELF_ST_BIND(def->st_info) == STB_WEAK) {
                    321:                symp = _rtld_symlook_list(name, hash, &_rtld_list_main, &obj, in_plt);
                    322:                if (symp != NULL &&
                    323:                  (def == NULL || ELF_ST_BIND(symp->st_info) != STB_WEAK)) {
                    324:                        def = symp;
                    325:                        defobj = obj;
                    326:                }
                    327:        }
                    328:
                    329:        /* Search all dlopened DAGs containing the referencing object. */
                    330:        SIMPLEQ_FOREACH(elm, &refobj->dldags, link) {
                    331:                if (def != NULL && ELF_ST_BIND(def->st_info) != STB_WEAK)
                    332:                        break;
                    333:                symp = _rtld_symlook_list(name, hash, &elm->obj->dagmembers, &obj,
                    334:                    in_plt);
                    335:                if (symp != NULL &&
                    336:                    (def == NULL || ELF_ST_BIND(symp->st_info) != STB_WEAK)) {
                    337:                        def = symp;
                    338:                        defobj = obj;
                    339:                }
                    340:        }
                    341:
                    342:        /* Search all DAGs whose roots are RTLD_GLOBAL objects. */
                    343:        SIMPLEQ_FOREACH(elm, &_rtld_list_global, link) {
                    344:                if (def != NULL && ELF_ST_BIND(def->st_info) != STB_WEAK)
                    345:                        break;
                    346:                symp = _rtld_symlook_list(name, hash, &elm->obj->dagmembers, &obj,
                    347:                    in_plt);
                    348:                if (symp != NULL &&
                    349:                    (def == NULL || ELF_ST_BIND(symp->st_info) != STB_WEAK)) {
                    350:                        def = symp;
                    351:                        defobj = obj;
                    352:                }
1.28      christos  353:        }
                    354:
                    355: #ifdef notyet
1.29      skrll     356:        /*
                    357:         * Search the dynamic linker itself, and possibly resolve the
                    358:         * symbol from there.  This is how the application links to
                    359:         * dynamic linker services such as dlopen.  Only the values listed
                    360:         * in the "exports" array can be resolved from the dynamic linker.
                    361:         */
                    362:        if (def == NULL || ELF_ST_BIND(def->st_info) == STB_WEAK) {
1.30      skrll     363:                symp = _rtld_symlook_obj(name, hash, &_rtld_objself, in_plt);
1.29      skrll     364:                if (symp != NULL && is_exported(symp)) {
                    365:                        def = symp;
1.30      skrll     366:                        defobj = &_rtld_objself;
1.29      skrll     367:                }
1.28      christos  368:        }
                    369: #endif
                    370:
1.29      skrll     371:        if (def != NULL)
                    372:                *defobj_out = defobj;
                    373:        return def;
1.1       cgd       374: }

CVSweb <webmaster@jp.NetBSD.org>