Home | History | Annotate | Download | only in common
      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 2008 Sun Microsystems, Inc.  All rights reserved.
     24  * Use is subject to license terms.
     25  */
     26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
     27 
     28 #include	<libelf.h>
     29 #include	<dlfcn.h>
     30 #include	"machdep.h"
     31 #include	"reloc.h"
     32 #include	"msg.h"
     33 #include	"_librtld.h"
     34 #include	"alist.h"
     35 
     36 static const char	*unknown = 0;	/* Stash MSG_INTL(MSG_STR_UNKNOWN) */
     37 
     38 /*
     39  * Process all relocation records.  A new `Reloc' structure is allocated to
     40  * cache the processing decisions deduced, and these will be applied during
     41  * update_reloc().
     42  * A count of the number of null relocations (i.e., relocations that will be
     43  * fixed and whoes records will be nulled out), data and function relocations
     44  * is maintained.  This allows the relocation records themselves to be
     45  * rearranged (localized) later if necessary.  Note that the number of function
     46  * relocations, although coounted, shouldn't differ from the original file,
     47  * the index of a .plt must be maintained to the index of its relocation record
     48  * within the associated relocation section.
     49  *
     50  * The intention behind this file is to maintain as much relocation logic as
     51  * possible in a generic form.
     52  */
     53 int
     54 count_reloc(Cache *cache, Cache *_cache, Rt_map *lmp, int flags, Addr addr,
     55     Xword *null, Xword *data, Xword *func, Alist *nodirect)
     56 {
     57 	Rel		*rel;
     58 	Reloc		*reloc;
     59 	Shdr		*shdr;
     60 	Xword		ent, cnt, _cnt;
     61 	Sym		*syms;
     62 	const char	*strs;
     63 	Cache		*__cache;
     64 	Xword		pltndx = 0;
     65 
     66 	/*
     67 	 * Determine the number of relocation entries we'll be dealing with.
     68 	 */
     69 	shdr = _cache->c_shdr;
     70 	rel = (Rel *)_cache->c_data->d_buf;
     71 	ent = shdr->sh_entsize;
     72 	cnt = shdr->sh_size / ent;
     73 
     74 	/*
     75 	 * Allocate a relocation structure for this relocation section.
     76 	 */
     77 	if ((reloc = calloc(cnt, sizeof (Reloc))) == 0)
     78 		return (1);
     79 	_cache->c_info = (void *)reloc;
     80 
     81 	/*
     82 	 * Determine the relocations associated symbol and string table.
     83 	 */
     84 	__cache = &cache[shdr->sh_link];
     85 	syms = (Sym *)__cache->c_data->d_buf;
     86 	shdr = __cache->c_shdr;
     87 	__cache = &cache[shdr->sh_link];
     88 	strs = (const char *)__cache->c_data->d_buf;
     89 
     90 	/*
     91 	 * Loop through the relocation table.
     92 	 */
     93 	for (_cnt = 0; _cnt < cnt; _cnt++, reloc++,
     94 	    rel = (Rel *)((uintptr_t)rel + ent)) {
     95 		const char	*name;
     96 		/* LINTED */
     97 		uchar_t		type = (uchar_t)ELF_R_TYPE(rel->r_info, M_MACH);
     98 		uchar_t		bind;
     99 		ulong_t		offset = rel->r_offset + addr;
    100 		Rt_map		*_lmp;
    101 		int		_bound, _weak;
    102 		ulong_t		rsymndx = ELF_R_SYM(rel->r_info);
    103 		Slookup		sl;
    104 		uint_t		binfo;
    105 		Sym		*_sym, *sym = (syms + rsymndx);
    106 
    107 		if (type == M_R_JMP_SLOT)
    108 			reloc->r_pltndx = ++pltndx;
    109 
    110 		/*
    111 		 * Analyze the case where no relocations are to be applied.
    112 		 */
    113 		if ((flags & RTLD_REL_ALL) == 0) {
    114 			/*
    115 			 * Don't apply any relocations to the new image but
    116 			 * insure their offsets are incremented to reflect any
    117 			 * new fixed address.
    118 			 */
    119 			reloc->r_flags = FLG_R_INC;
    120 
    121 			/*
    122 			 * Undo any relocations that might have already been
    123 			 * applied to the memory image.
    124 			 */
    125 			if (flags & RTLD_MEMORY) {
    126 				reloc->r_flags |= FLG_R_UNDO;
    127 
    128 				/*
    129 				 * If a copy relocation is involved we'll need
    130 				 * to know the size of the copy.
    131 				 */
    132 				if (type == M_R_COPY)
    133 					reloc->r_size = sym->st_size;
    134 				else
    135 					reloc->r_size = 0;
    136 			}
    137 
    138 			/*
    139 			 * Save the objects new address.
    140 			 */
    141 			reloc->r_value = addr;
    142 
    143 			if (type == M_R_JMP_SLOT)
    144 				(*func)++;
    145 			else
    146 				(*data)++;
    147 			continue;
    148 		}
    149 
    150 		/*
    151 		 * Determine the symbol binding of the relocation. Don't assume
    152 		 * that relative relocations are simply M_R_RELATIVE.  Although
    153 		 * a pic generated shared object can normally be viewed as
    154 		 * having relative and non-relative relocations, a non-pic
    155 		 * shared object will contain a number of relocations against
    156 		 * local symbols (normally sections).  If a relocation is
    157 		 * against a local symbol it qualifies as a relative relocation.
    158 		 */
    159 		if ((type == M_R_RELATIVE) || (type == M_R_NONE) ||
    160 		    (ELF_ST_BIND(sym->st_info) == STB_LOCAL))
    161 			bind = STB_LOCAL;
    162 		else
    163 			bind = STB_GLOBAL;
    164 
    165 		/*
    166 		 * Analyze the case where only relative relocations are to be
    167 		 * applied.
    168 		 */
    169 		if ((flags & RTLD_REL_ALL) == RTLD_REL_RELATIVE) {
    170 			if (flags & RTLD_MEMORY) {
    171 				if (bind == STB_LOCAL) {
    172 					/*
    173 					 * Save the relative relocations from
    174 					 * the memory image.  The data itself
    175 					 * might already have been relocated,
    176 					 * thus clear the relocation record so
    177 					 * that it will not be performed again.
    178 					 */
    179 					reloc->r_flags = FLG_R_CLR;
    180 					(*null)++;
    181 				} else {
    182 					/*
    183 					 * Any non-relative relocation must be
    184 					 * undone, and the relocation records
    185 					 * offset updated to any new fixed
    186 					 * address.
    187 					 */
    188 					reloc->r_flags =
    189 					    (FLG_R_UNDO | FLG_R_INC);
    190 					reloc->r_value = addr;
    191 					if (type == M_R_JMP_SLOT)
    192 						(*func)++;
    193 					else
    194 						(*data)++;
    195 				}
    196 			} else {
    197 				if (bind == STB_LOCAL) {
    198 					/*
    199 					 * Apply relative relocation to the
    200 					 * file image.  Clear the relocation
    201 					 * record so that it will not be
    202 					 * performed again.
    203 					 */
    204 					reloc->r_flags =
    205 					    (FLG_R_APPLY | FLG_R_CLR);
    206 					reloc->r_value = addr;
    207 					if (IS_PC_RELATIVE(type))
    208 						reloc->r_value -= offset;
    209 
    210 					if (unknown == 0)
    211 						unknown =
    212 						    MSG_INTL(MSG_STR_UNKNOWN);
    213 					reloc->r_name = unknown;
    214 					(*null)++;
    215 				} else {
    216 					/*
    217 					 * Any non-relative relocation should be
    218 					 * left alone, but its offset should be
    219 					 * updated to any new fixed address.
    220 					 */
    221 					reloc->r_flags = FLG_R_INC;
    222 					reloc->r_value = addr;
    223 					if (type == M_R_JMP_SLOT)
    224 						(*func)++;
    225 					else
    226 						(*data)++;
    227 				}
    228 			}
    229 			continue;
    230 		}
    231 
    232 		/*
    233 		 * Analyze the case where more than just relative relocations
    234 		 * are to be applied.
    235 		 */
    236 		if (bind == STB_LOCAL) {
    237 			if (flags & RTLD_MEMORY) {
    238 				/*
    239 				 * Save the relative relocations from the memory
    240 				 * image.  The data itself has already been
    241 				 * relocated, thus clear the relocation record
    242 				 * so that it will not be performed again.
    243 				 */
    244 				reloc->r_flags = FLG_R_CLR;
    245 			} else {
    246 				/*
    247 				 * Apply relative relocation to the file image.
    248 				 * Clear the relocation record so that it will
    249 				 * not be performed again.
    250 				 */
    251 				reloc->r_flags = (FLG_R_APPLY | FLG_R_CLR);
    252 				reloc->r_value = addr;
    253 				if (IS_PC_RELATIVE(type))
    254 					reloc->r_value -= offset;
    255 
    256 				if (unknown == 0)
    257 					unknown = MSG_INTL(MSG_STR_UNKNOWN);
    258 				reloc->r_name = unknown;
    259 			}
    260 			(*null)++;
    261 			continue;
    262 		}
    263 
    264 		/*
    265 		 * At this point we're dealing with a non-relative relocation
    266 		 * that requires the symbol definition.
    267 		 */
    268 		name = strs + sym->st_name;
    269 
    270 		/*
    271 		 * Find the symbol.  As the object being investigated is already
    272 		 * a part of this process, the symbol lookup will likely
    273 		 * succeed.  However, because of lazy binding, there is still
    274 		 * the possibility of a dangling .plt relocation.  dldump()
    275 		 * users might be encouraged to set LD_FLAGS=loadavail (crle(1)
    276 		 * does this for them).
    277 		 *
    278 		 * Initialize the symbol lookup data structure.
    279 		 */
    280 		SLOOKUP_INIT(sl, name, lmp, LIST(lmp)->lm_head, ld_entry_cnt,
    281 		    0, rsymndx, sym, type, LKUP_STDRELOC);
    282 
    283 		_bound = _weak = 0;
    284 		_sym = sym;
    285 		if ((sym = lookup_sym(&sl, &_lmp, &binfo, NULL)) != 0) {
    286 			/*
    287 			 * Determine from the various relocation requirements
    288 			 * whether this binding is appropriate.  If we're called
    289 			 * from crle(1), RTLD_CONFSET is set, then only inspect
    290 			 * objects selected from the configuration file
    291 			 * (FL1_RT_CONFSET was set during load()).
    292 			 */
    293 			if (!(flags & RTLD_CONFSET) ||
    294 			    (FLAGS1(_lmp) & FL1_RT_CONFSET)) {
    295 				if (((flags & RTLD_REL_ALL) == RTLD_REL_ALL) ||
    296 				    ((flags & RTLD_REL_EXEC) &&
    297 				    (FLAGS(_lmp) & FLG_RT_ISMAIN)) ||
    298 				    ((flags & RTLD_REL_DEPENDS) &&
    299 				    (!(FLAGS(_lmp) & FLG_RT_ISMAIN))) ||
    300 				    ((flags & RTLD_REL_PRELOAD) &&
    301 				    (FLAGS(_lmp) & FLG_RT_PRELOAD)) ||
    302 				    ((flags & RTLD_REL_SELF) &&
    303 				    (lmp == _lmp))) {
    304 					Aliste	idx;
    305 					Word	*ndx;
    306 
    307 					_bound = 1;
    308 
    309 					/*
    310 					 * If this symbol is explicitly defined
    311 					 * as nodirect, don't allow any local
    312 					 * binding.
    313 					 */
    314 					for (ALIST_TRAVERSE(nodirect, idx,
    315 					    ndx)) {
    316 						if (*ndx == rsymndx) {
    317 							_bound = 0;
    318 							break;
    319 						}
    320 					}
    321 				}
    322 			}
    323 		} else {
    324 			/*
    325 			 * If this is a weak reference and we've been asked to
    326 			 * bind unresolved weak references consider ourself
    327 			 * bound.  This category is typically set by clre(1) for
    328 			 * an application cache.
    329 			 */
    330 			if ((ELF_ST_BIND(_sym->st_info) == STB_WEAK) &&
    331 			    (_sym->st_shndx == SHN_UNDEF) &&
    332 			    (flags & RTLD_REL_WEAK))
    333 				_bound = _weak = 1;
    334 		}
    335 
    336 		if (flags & RTLD_MEMORY) {
    337 			if (_bound) {
    338 				/*
    339 				 * We know that all data relocations will have
    340 				 * been performed at process startup thus clear
    341 				 * the relocation record so that it will not be
    342 				 * performed again.  However, we don't know what
    343 				 * function relocations have been performed
    344 				 * because of lazy binding - regardless, we can
    345 				 * leave all the function relocation records in
    346 				 * place, because if the function has already
    347 				 * been bound the record won't be referenced
    348 				 * anyway.  In the case of using LD_BIND_NOW,
    349 				 * a function may be bound twice - so what.
    350 				 */
    351 				if (type == M_R_JMP_SLOT) {
    352 					reloc->r_flags = FLG_R_INC;
    353 					(*func)++;
    354 				} else {
    355 					if (type != M_R_COPY)
    356 						reloc->r_flags = FLG_R_CLR;
    357 					(*null)++;
    358 				}
    359 			} else {
    360 				/*
    361 				 * Clear any unrequired relocation.
    362 				 */
    363 				reloc->r_flags = FLG_R_UNDO | FLG_R_INC;
    364 				reloc->r_value = addr;
    365 				if (type == M_R_JMP_SLOT)
    366 					(*func)++;
    367 				else
    368 					(*data)++;
    369 			}
    370 		} else {
    371 			if (_bound) {
    372 				/*
    373 				 * Apply the global relocation to the file
    374 				 * image.  Clear the relocation record so that
    375 				 * it will not be performed again.
    376 				 */
    377 				if (_weak) {
    378 					reloc->r_value = 0;
    379 					reloc->r_size = 0;
    380 				} else {
    381 					reloc->r_value = sym->st_value;
    382 					if (IS_PC_RELATIVE(type))
    383 						reloc->r_value -= offset;
    384 					if ((!(FLAGS(_lmp) & FLG_RT_FIXED)) &&
    385 					    (sym->st_shndx != SHN_ABS))
    386 						reloc->r_value += ADDR(_lmp);
    387 					reloc->r_size = sym->st_size;
    388 				}
    389 
    390 				reloc->r_flags = FLG_R_APPLY | FLG_R_CLR;
    391 				reloc->r_name = name;
    392 				if (type == M_R_JMP_SLOT)
    393 					(*func)++;
    394 				else
    395 					(*null)++;
    396 			} else {
    397 				/*
    398 				 * Do not apply any unrequired relocations.
    399 				 */
    400 				reloc->r_flags = FLG_R_INC;
    401 				reloc->r_value = addr;
    402 				if (type == M_R_JMP_SLOT)
    403 					(*func)++;
    404 				else
    405 					(*data)++;
    406 			}
    407 		}
    408 	}
    409 	return (0);
    410 }
    411 
    412 
    413 /*
    414  * Perform any relocation updates to the new image using the information from
    415  * the `Reloc' structure constructed during count_reloc().
    416  */
    417 void
    418 update_reloc(Cache *ocache, Cache *icache, Cache *_icache, const char *name,
    419     Rt_map *lmp, Rel **null, Rel **data, Rel **func)
    420 {
    421 	Shdr	*shdr;
    422 	Rel	*rel;
    423 	Reloc	*reloc;
    424 	Xword	ent, cnt, _cnt;
    425 	Cache	*orcache, *ircache = 0;
    426 	Half	ndx;
    427 
    428 	/*
    429 	 * Set up to read the output relocation table.
    430 	 */
    431 	shdr = _icache->c_shdr;
    432 	rel = (Rel *)_icache->c_data->d_buf;
    433 	reloc = (Reloc *)_icache->c_info;
    434 	ent = shdr->sh_entsize;
    435 	cnt = shdr->sh_size / ent;
    436 
    437 	/*
    438 	 * Loop through the relocation table.
    439 	 */
    440 	for (_cnt = 0; _cnt < cnt; _cnt++, reloc++,
    441 	    rel = (Rel *)((uintptr_t)rel + ent)) {
    442 		uchar_t		*iaddr, *oaddr;
    443 		/* LINTED */
    444 		uchar_t		type = (uchar_t)ELF_R_TYPE(rel->r_info, M_MACH);
    445 		Addr		off, bgn, end;
    446 
    447 		/*
    448 		 * Ignore null relocations (these may have been created from a
    449 		 * previous dldump() of this image).
    450 		 */
    451 		if (type == M_R_NONE) {
    452 			(*null)++;
    453 			continue;
    454 		}
    455 
    456 		/*
    457 		 * Determine the section being relocated if we haven't already
    458 		 * done so (we may have had to skip over some null relocation to
    459 		 * get to the first valid offset).  The System V ABI states that
    460 		 * a relocation sections sh_info field indicates the section
    461 		 * that must be relocated.  However, on Intel it seems that the
    462 		 * .rel.plt sh_info records the section index of the .plt, when
    463 		 * in fact it's the .got that gets relocated.  In addition we
    464 		 * now create combined relocation sections with -zcomreloc.  To
    465 		 * generically be able to cope with these anomalies, search for
    466 		 * the appropriate section to be relocated by comparing the
    467 		 * offset of the first relocation record against each sections
    468 		 * offset and size.
    469 		 */
    470 		/* BEGIN CSTYLED */
    471 #if	!defined(__lint)
    472 		if ((ircache == (Cache *)0) || (rel->r_offset < bgn) ||
    473 			(rel->r_offset > end)) {
    474 #else
    475 		/*
    476 		 * lint sees `bgn' and `end' as potentially referenced
    477 		 * before being set.
    478 		 */
    479 		if (ircache == (Cache *)0) {
    480 #endif
    481 			_icache = icache;
    482 			_icache++;
    483 
    484 			for (ndx = 1; _icache->c_flags != FLG_C_END; ndx++,
    485 			    _icache++) {
    486 
    487 				shdr = _icache->c_shdr;
    488 				bgn = shdr->sh_addr;
    489 				end = bgn + shdr->sh_size;
    490 
    491 				if ((rel->r_offset >= bgn) &&
    492 				    (rel->r_offset <= end))
    493 					break;
    494 			}
    495 			ircache = &icache[ndx];
    496 			orcache = &ocache[ndx];
    497 		}
    498 		/* END CSTYLED */
    499 
    500 		/*
    501 		 * Determine the relocation location of both the input and
    502 		 * output data.  Take into account that an input section may be
    503 		 * NOBITS (ppc .plt for example).
    504 		 */
    505 		off = rel->r_offset - ircache->c_shdr->sh_addr;
    506 		if (ircache->c_data->d_buf)
    507 			iaddr = (uchar_t *)ircache->c_data->d_buf + off;
    508 		else
    509 			iaddr = 0;
    510 		oaddr = (uchar_t *)orcache->c_data->d_buf + off;
    511 
    512 		/*
    513 		 * Apply the relocation to the new output image.  Any base
    514 		 * address, or symbol value, will have been saved in the reloc
    515 		 * structure during count_reloc().
    516 		 */
    517 		if (reloc->r_flags & FLG_R_APPLY)
    518 			apply_reloc(rel, reloc, name, oaddr, lmp);
    519 
    520 		/*
    521 		 * Undo any relocation that might already been applied to the
    522 		 * memory image by the runtime linker.  Using the original
    523 		 * file, determine the relocation offset original value and
    524 		 * restore the new image to that value.
    525 		 */
    526 		if ((reloc->r_flags & FLG_R_UNDO) &&
    527 		    (FLAGS(lmp) & FLG_RT_RELOCED))
    528 			undo_reloc(rel, oaddr, iaddr, reloc);
    529 
    530 		/*
    531 		 * If a relocation has been applied then the relocation record
    532 		 * should be cleared so that the relocation isn't applied again
    533 		 * when the new image is used.
    534 		 */
    535 		if (reloc->r_flags & FLG_R_CLR) {
    536 			if (type == M_R_JMP_SLOT) {
    537 				clear_reloc(*func);
    538 				*func = (Rel *)((uintptr_t)*func + ent);
    539 			} else {
    540 				clear_reloc(*null);
    541 				*null = (Rel *)((uintptr_t)*null + ent);
    542 			}
    543 		}
    544 
    545 		/*
    546 		 * If a relocation isn't applied, update the relocation record
    547 		 * to take into account the new address of the image.
    548 		 */
    549 		if (reloc->r_flags & FLG_R_INC) {
    550 			if (type == M_R_JMP_SLOT) {
    551 				inc_reloc(*func, rel, reloc, oaddr, iaddr);
    552 				*func = (Rel *)((uintptr_t)*func + ent);
    553 			} else {
    554 				inc_reloc(*data, rel, reloc, oaddr, iaddr);
    555 				*data = (Rel *)((uintptr_t)*data + ent);
    556 			}
    557 		}
    558 	}
    559 }
    560