Home | History | Annotate | Download | only in sparc
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 
     22 /*
     23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     24  * Use is subject to license terms.
     25  */
     26 
     27 #include	<stdio.h>
     28 #include	<strings.h>
     29 #include	<sys/elf.h>
     30 #include	<sys/elf_SPARC.h>
     31 #include	<alloca.h>
     32 #include	"_rtld.h"
     33 #include	"_elf.h"
     34 #include	"msg.h"
     35 #include	"conv.h"
     36 
     37 /*
     38  *
     39  *  Matrix of legal combinations of usage of a given register:
     40  *
     41  *	Obj1\Obj2       Scratch Named
     42  *	Scratch          OK      NO
     43  *	Named            NO      *
     44  *
     45  *  * OK if the symbols are identical, NO if they are not.  Two symbols
     46  *  are identical if and only if one of the following is true:
     47  *        A. They are both global and have the same name.
     48  *        B. They are both local, have the same name, and are defined in
     49  *        the same object.  (Note that a local symbol in one object is
     50  *        never identical to a local symbol in another object, even if the
     51  *        name is the same.)
     52  *
     53  *  Matrix of legal combinations of st_shndx for the same register symbol:
     54  *
     55  *	Obj1\Obj2       UNDEF   ABS
     56  *	UNDEF            OK      OK
     57  *	ABS              OK      NO
     58  */
     59 
     60 /*
     61  * Test the compatiblity of two register symbols, 0 pass, >0 fail
     62  */
     63 static uintptr_t
     64 check_regsyms(Sym *sym1, const char *name1, Sym *sym2, const char *name2)
     65 {
     66 	if ((sym1->st_name == 0) && (sym2->st_name == 0))
     67 		return (0);	/* scratches are always compatible */
     68 
     69 	if ((ELF_ST_BIND(sym1->st_info) == STB_LOCAL) ||
     70 	    (ELF_ST_BIND(sym2->st_info) == STB_LOCAL)) {
     71 		if (sym1->st_value == sym2->st_value)
     72 			return (1);	/* local symbol incompat */
     73 		return (0);		/* no other prob from locals */
     74 	}
     75 
     76 	if (sym1->st_value == sym2->st_value) {
     77 		/* NOTE this just avoids strcmp */
     78 		if ((sym1->st_name == 0) || (sym2->st_name == 0))
     79 			return (2);	/* can't match scratch to named */
     80 
     81 		if (strcmp(name1, name2) != 0)
     82 			return (4);	/* diff name, same register value */
     83 
     84 		if ((sym1->st_shndx == SHN_ABS) && (sym2->st_shndx == SHN_ABS))
     85 			return (3);	/* multiply defined */
     86 	} else if (strcmp(name1, name2) == 0)
     87 		return (5);	/* same name, diff register value */
     88 
     89 	return (0);
     90 }
     91 
     92 int
     93 elf_regsyms(Rt_map *lmp)
     94 {
     95 	Dyn	*dyn;
     96 	Sym	*symdef;
     97 	ulong_t	rsymndx;
     98 
     99 	/*
    100 	 * Scan through the .dynamic section of this object looking for all
    101 	 * DT_REGISTER entries.  For each DT_REGISTER entry found identify the
    102 	 * register symbol it identifies and confirm that it doesn't conflict
    103 	 * with any other register symbols.
    104 	 */
    105 	for (dyn = DYN(lmp); dyn->d_tag != DT_NULL; dyn++) {
    106 		Reglist	*rp;
    107 
    108 		if ((dyn->d_tag != DT_SPARC_REGISTER) &&
    109 		    (dyn->d_tag != DT_DEPRECATED_SPARC_REGISTER))
    110 			continue;
    111 
    112 		/*
    113 		 * Get the local symbol table entry.
    114 		 */
    115 		rsymndx = dyn->d_un.d_val;
    116 		symdef = (Sym *)((unsigned long)SYMTAB(lmp) +
    117 		    (rsymndx * SYMENT(lmp)));
    118 
    119 		for (rp = reglist; rp; rp = rp->rl_next) {
    120 			Conv_inv_buf_t	inv_buf;
    121 			const char	*str, *sym1, *sym2;
    122 
    123 			if (rp->rl_sym == symdef) {
    124 				/*
    125 				 * Same symbol definition - everything is a-ok.
    126 				 */
    127 				return (1);
    128 			}
    129 
    130 			sym1 = (STRTAB(rp->rl_lmp) + rp->rl_sym->st_name);
    131 			sym2 = (STRTAB(lmp) + symdef->st_name);
    132 
    133 			if (check_regsyms(rp->rl_sym, sym1, symdef, sym2) == 0)
    134 				continue;
    135 
    136 			if ((str = demangle(sym1)) != sym1) {
    137 				char	*_str = alloca(strlen(str) + 1);
    138 				(void) strcpy(_str, str);
    139 				sym1 = (const char *)_str;
    140 			}
    141 			sym2 = demangle(sym2);
    142 
    143 			if (LIST(lmp)->lm_flags & LML_FLG_TRC_WARN) {
    144 				(void) printf(MSG_INTL(MSG_LDD_REG_SYMCONF),
    145 				    conv_sym_SPARC_value(symdef->st_value,
    146 				    0, &inv_buf), NAME(rp->rl_lmp),
    147 				    sym1, NAME(lmp), sym2);
    148 			} else {
    149 				eprintf(LIST(lmp), ERR_FATAL,
    150 				    MSG_INTL(MSG_REG_SYMCONF),
    151 				    conv_sym_SPARC_value(symdef->st_value,
    152 				    0, &inv_buf), NAME(rp->rl_lmp),
    153 				    sym1, NAME(lmp), sym2);
    154 				return (0);
    155 			}
    156 		}
    157 		if ((rp = calloc(sizeof (Reglist), 1)) == NULL)
    158 			return (0);
    159 		rp->rl_lmp = lmp;
    160 		rp->rl_sym = symdef;
    161 		rp->rl_next = reglist;
    162 		reglist = rp;
    163 	}
    164 	return (1);
    165 }
    166