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 /*
     28  *	Copyright (c) 1988 AT&T
     29  *	All Rights Reserved
     30  */
     31 
     32 /*
     33  * SPARC machine dependent and a.out format file class dependent functions.
     34  * Contains routines for performing function binding and symbol relocations.
     35  */
     36 
     37 #include	<stdio.h>
     38 #include	<sys/types.h>
     39 #include	<sys/mman.h>
     40 #include	<synch.h>
     41 #include	<dlfcn.h>
     42 #include	<debug.h>
     43 #include	"_a.out.h"
     44 #include	"_rtld.h"
     45 #include	"_audit.h"
     46 #include	"_inline.h"
     47 #include	"msg.h"
     48 
     49 extern void	iflush_range(caddr_t, size_t);
     50 
     51 /*
     52  * Function binding routine - invoked on the first call to a function through
     53  * the procedure linkage table;
     54  * passes first through an assembly language interface.
     55  *
     56  * Takes the address of the PLT entry where the call originated,
     57  * the offset into the relocation table of the associated
     58  * relocation entry and the address of the link map (rt_private_map struct)
     59  * for the entry.
     60  *
     61  * Returns the address of the function referenced after re-writing the PLT
     62  * entry to invoke the function directly.
     63  *
     64  * On error, causes process to terminate with a signal.
     65  */
     66 ulong_t
     67 aout_bndr(caddr_t pc)
     68 {
     69 	Rt_map		*lmp, *nlmp, *llmp;
     70 	struct relocation_info *rp;
     71 	struct nlist	*sp;
     72 	Sym		*sym;
     73 	char		*name;
     74 	int 		rndx, entry;
     75 	ulong_t		symval;
     76 	Slookup		sl;
     77 	uint_t		binfo;
     78 	Lm_list		*lml;
     79 
     80 	/*
     81 	 * For compatibility with libthread (TI_VERSION 1) we track the entry
     82 	 * value.  A zero value indicates we have recursed into ld.so.1 to
     83 	 * further process a locking request (see comments in completion()).
     84 	 * Under this recursion we disable tsort and cleanup activities.
     85 	 */
     86 	entry = enter(0);
     87 
     88 	for (lmp = lml_main.lm_head; lmp; lmp = NEXT_RT_MAP(lmp)) {
     89 		if (THIS_IS_AOUT(lmp)) {
     90 			if (pc > (caddr_t)(LM2LP(lmp)->lp_plt) &&
     91 			    pc < (caddr_t)((int)LM2LP(lmp)->lp_plt +
     92 			    AOUTDYN(lmp)->v2->ld_plt_sz))  {
     93 				break;
     94 			}
     95 		}
     96 	}
     97 
     98 #define	LAST22BITS	0x3fffff
     99 
    100 	/* LINTED */
    101 	rndx = *(int *)(pc + (sizeof (ulong_t *) * 2)) & LAST22BITS;
    102 	rp = &LM2LP(lmp)->lp_rp[rndx];
    103 	sp = &LM2LP(lmp)->lp_symtab[rp->r_symbolnum];
    104 	name = &LM2LP(lmp)->lp_symstr[sp->n_un.n_strx];
    105 
    106 	/*
    107 	 * Determine the last link-map of this list, this'll be the starting
    108 	 * point for any tsort() processing.
    109 	 */
    110 	lml = LIST(lmp);
    111 	llmp = lml->lm_tail;
    112 
    113 	/*
    114 	 * Find definition for symbol.  Initialize the symbol lookup data
    115 	 * structure.
    116 	 */
    117 	SLOOKUP_INIT(sl, name, lmp, lml->lm_head, ld_entry_cnt, 0, 0, 0, 0,
    118 	    LKUP_DEFT);
    119 
    120 	if ((sym = aout_lookup_sym(&sl, &nlmp, &binfo, NULL)) == 0) {
    121 		eprintf(lml, ERR_FATAL, MSG_INTL(MSG_REL_NOSYM), NAME(lmp),
    122 		    demangle(name));
    123 		rtldexit(lml, 1);
    124 	}
    125 
    126 	symval = sym->st_value;
    127 	if (!(FLAGS(nlmp) & FLG_RT_FIXED) &&
    128 	    (sym->st_shndx != SHN_ABS))
    129 		symval += (int)(ADDR(nlmp));
    130 	if ((lmp != nlmp) && ((FLAGS1(nlmp) & FL1_RT_NOINIFIN) == 0)) {
    131 		/*
    132 		 * Record that this new link map is now bound to the caller.
    133 		 */
    134 		if (bind_one(lmp, nlmp, BND_REFER) == 0)
    135 			rtldexit(lml, 1);
    136 	}
    137 
    138 	/*
    139 	 * Print binding information and rebuild PLT entry.
    140 	 */
    141 	DBG_CALL(Dbg_bind_global(lmp, (Addr)(ADDR(lmp) + rp->r_address),
    142 	    (Off)rp->r_address, (Xword)(-1), PLT_T_NONE, nlmp,
    143 	    (Addr)symval, sym->st_value, name, binfo));
    144 
    145 	if (!(rtld_flags & RT_FL_NOBIND))
    146 		aout_plt_write((caddr_t)(ADDR(lmp) + rp->r_address), symval);
    147 
    148 	/*
    149 	 * Complete any processing for newly loaded objects.  Note we don't
    150 	 * know exactly where any new objects are loaded (we know the object
    151 	 * that supplied the symbol, but others may have been loaded lazily as
    152 	 * we searched for the symbol), so sorting starts from the last
    153 	 * link-map know on entry to this routine.
    154 	 */
    155 	if (entry)
    156 		load_completion(llmp);
    157 
    158 	/*
    159 	 * Make sure the object to which we've bound has had it's .init fired.
    160 	 * Cleanup before return to user code.
    161 	 */
    162 	if (entry) {
    163 		is_dep_init(nlmp, lmp);
    164 		leave(lml, 0);
    165 	}
    166 
    167 	return (symval);
    168 }
    169 
    170 
    171 #define	IS_PC_RELATIVE(X) (pc_rel_type[(X)] == 1)
    172 
    173 static const uchar_t pc_rel_type[] = {
    174 	0,				/* RELOC_8 */
    175 	0,				/* RELOC_16 */
    176 	0,				/* RELOC_32 */
    177 	1,				/* RELOC_DISP8 */
    178 	1,				/* RELOC_DISP16 */
    179 	1,				/* RELOC_DISP32 */
    180 	1,				/* RELOC_WDISP30 */
    181 	1,				/* RELOC_WDISP22 */
    182 	0,				/* RELOC_HI22 */
    183 	0,				/* RELOC_22 */
    184 	0,				/* RELOC_13 */
    185 	0,				/* RELOC_LO10 */
    186 	0,				/* RELOC_SFA_BASE */
    187 	0,				/* RELOC_SFA_OFF13 */
    188 	0,				/* RELOC_BASE10 */
    189 	0,				/* RELOC_BASE13 */
    190 	0,				/* RELOC_BASE22 */
    191 	0,				/* RELOC_PC10 */
    192 	0,				/* RELOC_PC22 */
    193 	0,				/* RELOC_JMP_TBL */
    194 	0,				/* RELOC_SEGOFF16 */
    195 	0,				/* RELOC_GLOB_DAT */
    196 	0,				/* RELOC_JMP_SLOT */
    197 	0				/* RELOC_RELATIVE */
    198 };
    199 
    200 int
    201 aout_reloc(Rt_map *lmp, uint_t plt, int *in_nfavl, APlist **textrel)
    202 {
    203 	int		k;		/* loop temporary */
    204 	int		nr;		/* number of relocations */
    205 	char		*name;		/* symbol being searched for */
    206 	long		value;		/* relocation temporary */
    207 	long		*ra;		/* cached relocation address */
    208 	struct relocation_info *rp;	/* current relocation */
    209 	struct nlist	*sp;		/* symbol table of "symbol" */
    210 	Rt_map *	_lmp;		/* lm which holds symbol definition */
    211 	Sym *		sym;		/* symbol definition */
    212 	int		ret = 1;
    213 	APlist		*bound = NULL;
    214 	Lm_list		*lml = LIST(lmp);
    215 
    216 	DBG_CALL(Dbg_reloc_run(lmp, SHT_RELA, plt, DBG_REL_START));
    217 
    218 	/*
    219 	 * If we've been called upon to promote an RTLD_LAZY object to an
    220 	 * RTLD_NOW don't bother to do anything - a.out's are bound as if
    221 	 * RTLD_NOW regardless.
    222 	 */
    223 	if (plt)
    224 		return (1);
    225 
    226 	rp = LM2LP(lmp)->lp_rp;
    227 	nr = GETRELSZ(AOUTDYN(lmp)) / sizeof (struct relocation_info);
    228 
    229 	/*
    230 	 * Initialize _PLT_, if any.
    231 	 */
    232 	if (AOUTDYN(lmp)->v2->ld_plt_sz)
    233 		aout_plt_write((caddr_t)LM2LP(lmp)->lp_plt->jb_inst,
    234 		    (ulong_t)aout_rtbndr);
    235 
    236 	/*
    237 	 * Loop through relocations.
    238 	 */
    239 	for (k = 0; k < nr; k++, rp++) {
    240 		mmapobj_result_t	*mpp;
    241 
    242 		/* LINTED */
    243 		ra = (long *)&((char *)ADDR(lmp))[rp->r_address];
    244 
    245 		/*
    246 		 * Make sure the segment is writable.
    247 		 */
    248 		if (((mpp = find_segment((caddr_t)ra, lmp)) != NULL) &&
    249 		    ((mpp->mr_prot & PROT_WRITE) == 0)) {
    250 			if ((set_prot(lmp, mpp, 1) == 0) ||
    251 			    (aplist_append(textrel, mpp,
    252 			    AL_CNT_TEXTREL) == NULL)) {
    253 				ret = 0;
    254 				break;
    255 			}
    256 		}
    257 
    258 		/*
    259 		 * Perform the relocation.
    260 		 */
    261 		if (rp->r_extern == 0) {
    262 			name = (char *)0;
    263 			value = ADDR(lmp);
    264 		} else {
    265 			Slookup		sl;
    266 			uint_t		binfo;
    267 
    268 			if (rp->r_type == RELOC_JMP_SLOT)
    269 				continue;
    270 			sp = &LM2LP(lmp)->lp_symtab[rp->r_symbolnum];
    271 			name = &LM2LP(lmp)->lp_symstr[sp->n_un.n_strx];
    272 
    273 			/*
    274 			 * Locate symbol.  Initialize the symbol lookup data
    275 			 * structure.
    276 			 */
    277 			SLOOKUP_INIT(sl, name, lmp, 0, ld_entry_cnt,
    278 			    0, 0, 0, 0, LKUP_STDRELOC);
    279 
    280 			if ((sym = aout_lookup_sym(&sl, &_lmp,
    281 			    &binfo, in_nfavl)) == 0) {
    282 				if (lml->lm_flags & LML_FLG_TRC_WARN) {
    283 					(void)
    284 					    printf(MSG_INTL(MSG_LDD_SYM_NFOUND),
    285 					    demangle(name), NAME(lmp));
    286 					continue;
    287 				} else {
    288 					eprintf(lml, ERR_FATAL,
    289 					    MSG_INTL(MSG_REL_NOSYM), NAME(lmp),
    290 					    demangle(name));
    291 					ret = 0;
    292 					break;
    293 				}
    294 			}
    295 
    296 			/*
    297 			 * If symbol was found in an object other than the
    298 			 * referencing object then record the binding.
    299 			 */
    300 			if ((lmp != _lmp) &&
    301 			    ((FLAGS1(_lmp) & FL1_RT_NOINIFIN) == 0)) {
    302 				if (aplist_test(&bound, _lmp,
    303 				    AL_CNT_RELBIND) == 0) {
    304 					ret = 0;
    305 					break;
    306 				}
    307 			}
    308 
    309 			value = sym->st_value + rp->r_addend;
    310 			if (!(FLAGS(_lmp) & FLG_RT_FIXED) &&
    311 			    (sym->st_shndx != SHN_COMMON) &&
    312 			    (sym->st_shndx != SHN_ABS))
    313 				value += ADDR(_lmp);
    314 
    315 			if (IS_PC_RELATIVE(rp->r_type))
    316 				value -= (long)ADDR(lmp);
    317 
    318 			DBG_CALL(Dbg_bind_global(lmp, (Addr)ra,
    319 			    (Off)(ra - ADDR(lmp)), (Xword)(-1), PLT_T_NONE,
    320 			    _lmp, (Addr)value, sym->st_value, name, binfo));
    321 		}
    322 
    323 		/*
    324 		 * Perform a specific relocation operation.
    325 		 */
    326 		switch (rp->r_type) {
    327 		case RELOC_RELATIVE:
    328 			value += *ra << (32-22);
    329 			*(long *)ra = (*(long *)ra & ~S_MASK(22)) |
    330 			    ((value >> (32 - 22)) & S_MASK(22));
    331 			ra++;
    332 			value += (*ra & S_MASK(10));
    333 			*(long *)ra = (*(long *)ra & ~S_MASK(10)) |
    334 			    (value & S_MASK(10));
    335 			break;
    336 		case RELOC_8:
    337 		case RELOC_DISP8:
    338 			value += *ra & S_MASK(8);
    339 			if (!S_INRANGE(value, 8)) {
    340 				eprintf(lml, ERR_FATAL,
    341 				    MSG_INTL(MSG_REL_OVERFLOW), NAME(lmp),
    342 				    (name ? demangle(name) :
    343 				    MSG_INTL(MSG_STR_UNKNOWN)), (int)value, 8,
    344 				    (uint_t)ra);
    345 			}
    346 			*ra = value;
    347 			break;
    348 		case RELOC_LO10:
    349 		case RELOC_BASE10:
    350 			value += *ra & S_MASK(10);
    351 			*(long *)ra = (*(long *)ra & ~S_MASK(10)) |
    352 			    (value & S_MASK(10));
    353 			break;
    354 		case RELOC_BASE13:
    355 		case RELOC_13:
    356 			value += *ra & S_MASK(13);
    357 			*(long *)ra = (*(long *)ra & ~S_MASK(13)) |
    358 			    (value & S_MASK(13));
    359 			break;
    360 		case RELOC_16:
    361 		case RELOC_DISP16:
    362 			value += *ra & S_MASK(16);
    363 			if (!S_INRANGE(value, 16)) {
    364 				eprintf(lml, ERR_FATAL,
    365 				    MSG_INTL(MSG_REL_OVERFLOW), NAME(lmp),
    366 				    (name ? demangle(name) :
    367 				    MSG_INTL(MSG_STR_UNKNOWN)), (int)value, 16,
    368 				    (uint_t)ra);
    369 			}
    370 			*(short *)ra = value;
    371 			break;
    372 		case RELOC_22:
    373 		case RELOC_BASE22:
    374 			value += *ra & S_MASK(22);
    375 			if (!S_INRANGE(value, 22)) {
    376 				eprintf(lml, ERR_FATAL,
    377 				    MSG_INTL(MSG_REL_OVERFLOW), NAME(lmp),
    378 				    (name ? demangle(name) :
    379 				    MSG_INTL(MSG_STR_UNKNOWN)), (int)value, 22,
    380 				    (uint_t)ra);
    381 			}
    382 			*(long *)ra = (*(long *)ra & ~S_MASK(22)) |
    383 			    (value & S_MASK(22));
    384 			break;
    385 		case RELOC_HI22:
    386 			value += (*ra & S_MASK(22)) << (32 - 22);
    387 			*(long *)ra = (*(long *)ra & ~S_MASK(22)) |
    388 			    ((value >> (32 - 22)) & S_MASK(22));
    389 			break;
    390 		case RELOC_WDISP22:
    391 			value += *ra & S_MASK(22);
    392 			value >>= 2;
    393 			if (!S_INRANGE(value, 22)) {
    394 				eprintf(lml, ERR_FATAL,
    395 				    MSG_INTL(MSG_REL_OVERFLOW), NAME(lmp),
    396 				    (name ? demangle(name) :
    397 				    MSG_INTL(MSG_STR_UNKNOWN)), (int)value, 22,
    398 				    (uint_t)ra);
    399 			}
    400 			*(long *)ra = (*(long *)ra & ~S_MASK(22)) |
    401 			    (value & S_MASK(22));
    402 			break;
    403 		case RELOC_WDISP30:
    404 			value += *ra & S_MASK(30);
    405 			value >>= 2;
    406 			*(long *)ra = (*(long *)ra & ~S_MASK(30)) |
    407 			    (value & S_MASK(30));
    408 			break;
    409 		case RELOC_32:
    410 		case RELOC_GLOB_DAT:
    411 		case RELOC_DISP32:
    412 			value += *ra;
    413 			*(long *)ra = value;
    414 			break;
    415 		default:
    416 			eprintf(lml, ERR_FATAL, MSG_INTL(MSG_REL_UNIMPL),
    417 			    NAME(lmp), (name ? demangle(name) :
    418 			    MSG_INTL(MSG_STR_UNKNOWN)), rp->r_type);
    419 			ret = 0;
    420 			break;
    421 		}
    422 
    423 		/*
    424 		 * If this relocation is against a text segment we must make
    425 		 * sure that the instruction cache is flushed.
    426 		 */
    427 		if (textrel) {
    428 			if (rp->r_type == RELOC_RELATIVE)
    429 				iflush_range((caddr_t)(ra - 1), 0x8);
    430 			else
    431 				iflush_range((caddr_t)ra, 0x4);
    432 		}
    433 	}
    434 
    435 	return (relocate_finish(lmp, bound, ret));
    436 }
    437