xref: /onnv-gate/usr/src/cmd/sgs/librtld/common/relocate.c (revision 11827:d7ef53deac3f)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
52850Srie  * Common Development and Distribution License (the "License").
62850Srie  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
212850Srie 
220Sstevel@tonic-gate /*
23*11827SRod.Evans@Sun.COM  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate #include	<libelf.h>
280Sstevel@tonic-gate #include	<dlfcn.h>
290Sstevel@tonic-gate #include	"machdep.h"
300Sstevel@tonic-gate #include	"reloc.h"
310Sstevel@tonic-gate #include	"msg.h"
320Sstevel@tonic-gate #include	"_librtld.h"
332850Srie #include	"alist.h"
340Sstevel@tonic-gate 
350Sstevel@tonic-gate static const char	*unknown = 0;	/* Stash MSG_INTL(MSG_STR_UNKNOWN) */
360Sstevel@tonic-gate 
370Sstevel@tonic-gate /*
380Sstevel@tonic-gate  * Process all relocation records.  A new `Reloc' structure is allocated to
390Sstevel@tonic-gate  * cache the processing decisions deduced, and these will be applied during
400Sstevel@tonic-gate  * update_reloc().
410Sstevel@tonic-gate  * A count of the number of null relocations (i.e., relocations that will be
420Sstevel@tonic-gate  * fixed and whoes records will be nulled out), data and function relocations
430Sstevel@tonic-gate  * is maintained.  This allows the relocation records themselves to be
440Sstevel@tonic-gate  * rearranged (localized) later if necessary.  Note that the number of function
450Sstevel@tonic-gate  * relocations, although coounted, shouldn't differ from the original file,
460Sstevel@tonic-gate  * the index of a .plt must be maintained to the index of its relocation record
470Sstevel@tonic-gate  * within the associated relocation section.
480Sstevel@tonic-gate  *
490Sstevel@tonic-gate  * The intention behind this file is to maintain as much relocation logic as
500Sstevel@tonic-gate  * possible in a generic form.
510Sstevel@tonic-gate  */
520Sstevel@tonic-gate int
count_reloc(Cache * cache,Cache * _cache,Rt_map * lmp,int flags,Addr addr,Xword * null,Xword * data,Xword * func,Alist * nodirect)530Sstevel@tonic-gate count_reloc(Cache *cache, Cache *_cache, Rt_map *lmp, int flags, Addr addr,
542850Srie     Xword *null, Xword *data, Xword *func, Alist *nodirect)
550Sstevel@tonic-gate {
560Sstevel@tonic-gate 	Rel		*rel;
570Sstevel@tonic-gate 	Reloc		*reloc;
580Sstevel@tonic-gate 	Shdr		*shdr;
590Sstevel@tonic-gate 	Xword		ent, cnt, _cnt;
600Sstevel@tonic-gate 	Sym		*syms;
610Sstevel@tonic-gate 	const char	*strs;
620Sstevel@tonic-gate 	Cache		*__cache;
630Sstevel@tonic-gate 	Xword		pltndx = 0;
640Sstevel@tonic-gate 
650Sstevel@tonic-gate 	/*
660Sstevel@tonic-gate 	 * Determine the number of relocation entries we'll be dealing with.
670Sstevel@tonic-gate 	 */
680Sstevel@tonic-gate 	shdr = _cache->c_shdr;
690Sstevel@tonic-gate 	rel = (Rel *)_cache->c_data->d_buf;
700Sstevel@tonic-gate 	ent = shdr->sh_entsize;
710Sstevel@tonic-gate 	cnt = shdr->sh_size / ent;
720Sstevel@tonic-gate 
730Sstevel@tonic-gate 	/*
740Sstevel@tonic-gate 	 * Allocate a relocation structure for this relocation section.
750Sstevel@tonic-gate 	 */
760Sstevel@tonic-gate 	if ((reloc = calloc(cnt, sizeof (Reloc))) == 0)
770Sstevel@tonic-gate 		return (1);
780Sstevel@tonic-gate 	_cache->c_info = (void *)reloc;
790Sstevel@tonic-gate 
800Sstevel@tonic-gate 	/*
810Sstevel@tonic-gate 	 * Determine the relocations associated symbol and string table.
820Sstevel@tonic-gate 	 */
830Sstevel@tonic-gate 	__cache = &cache[shdr->sh_link];
840Sstevel@tonic-gate 	syms = (Sym *)__cache->c_data->d_buf;
850Sstevel@tonic-gate 	shdr = __cache->c_shdr;
860Sstevel@tonic-gate 	__cache = &cache[shdr->sh_link];
870Sstevel@tonic-gate 	strs = (const char *)__cache->c_data->d_buf;
880Sstevel@tonic-gate 
890Sstevel@tonic-gate 	/*
900Sstevel@tonic-gate 	 * Loop through the relocation table.
910Sstevel@tonic-gate 	 */
920Sstevel@tonic-gate 	for (_cnt = 0; _cnt < cnt; _cnt++, reloc++,
930Sstevel@tonic-gate 	    rel = (Rel *)((uintptr_t)rel + ent)) {
940Sstevel@tonic-gate 		const char	*name;
950Sstevel@tonic-gate 		/* LINTED */
966206Sab196087 		uchar_t		type = (uchar_t)ELF_R_TYPE(rel->r_info, M_MACH);
970Sstevel@tonic-gate 		uchar_t		bind;
980Sstevel@tonic-gate 		ulong_t		offset = rel->r_offset + addr;
990Sstevel@tonic-gate 		Rt_map		*_lmp;
1000Sstevel@tonic-gate 		int		_bound, _weak;
1010Sstevel@tonic-gate 		ulong_t		rsymndx = ELF_R_SYM(rel->r_info);
1020Sstevel@tonic-gate 		Slookup		sl;
103*11827SRod.Evans@Sun.COM 		Sresult		sr;
1040Sstevel@tonic-gate 		uint_t		binfo;
1050Sstevel@tonic-gate 		Sym		*_sym, *sym = (syms + rsymndx);
1060Sstevel@tonic-gate 
1070Sstevel@tonic-gate 		if (type == M_R_JMP_SLOT)
1080Sstevel@tonic-gate 			reloc->r_pltndx = ++pltndx;
1090Sstevel@tonic-gate 
1100Sstevel@tonic-gate 		/*
1110Sstevel@tonic-gate 		 * Analyze the case where no relocations are to be applied.
1120Sstevel@tonic-gate 		 */
1130Sstevel@tonic-gate 		if ((flags & RTLD_REL_ALL) == 0) {
1140Sstevel@tonic-gate 			/*
1150Sstevel@tonic-gate 			 * Don't apply any relocations to the new image but
1160Sstevel@tonic-gate 			 * insure their offsets are incremented to reflect any
1170Sstevel@tonic-gate 			 * new fixed address.
1180Sstevel@tonic-gate 			 */
1190Sstevel@tonic-gate 			reloc->r_flags = FLG_R_INC;
1200Sstevel@tonic-gate 
1210Sstevel@tonic-gate 			/*
1220Sstevel@tonic-gate 			 * Undo any relocations that might have already been
1230Sstevel@tonic-gate 			 * applied to the memory image.
1240Sstevel@tonic-gate 			 */
1250Sstevel@tonic-gate 			if (flags & RTLD_MEMORY) {
1260Sstevel@tonic-gate 				reloc->r_flags |= FLG_R_UNDO;
1270Sstevel@tonic-gate 
1280Sstevel@tonic-gate 				/*
1290Sstevel@tonic-gate 				 * If a copy relocation is involved we'll need
1300Sstevel@tonic-gate 				 * to know the size of the copy.
1310Sstevel@tonic-gate 				 */
1320Sstevel@tonic-gate 				if (type == M_R_COPY)
1330Sstevel@tonic-gate 					reloc->r_size = sym->st_size;
1340Sstevel@tonic-gate 				else
1350Sstevel@tonic-gate 					reloc->r_size = 0;
1360Sstevel@tonic-gate 			}
1370Sstevel@tonic-gate 
1380Sstevel@tonic-gate 			/*
1390Sstevel@tonic-gate 			 * Save the objects new address.
1400Sstevel@tonic-gate 			 */
1410Sstevel@tonic-gate 			reloc->r_value = addr;
1420Sstevel@tonic-gate 
1430Sstevel@tonic-gate 			if (type == M_R_JMP_SLOT)
1440Sstevel@tonic-gate 				(*func)++;
1450Sstevel@tonic-gate 			else
1460Sstevel@tonic-gate 				(*data)++;
1470Sstevel@tonic-gate 			continue;
1480Sstevel@tonic-gate 		}
1490Sstevel@tonic-gate 
1500Sstevel@tonic-gate 		/*
1510Sstevel@tonic-gate 		 * Determine the symbol binding of the relocation. Don't assume
1520Sstevel@tonic-gate 		 * that relative relocations are simply M_R_RELATIVE.  Although
1530Sstevel@tonic-gate 		 * a pic generated shared object can normally be viewed as
1540Sstevel@tonic-gate 		 * having relative and non-relative relocations, a non-pic
1550Sstevel@tonic-gate 		 * shared object will contain a number of relocations against
1560Sstevel@tonic-gate 		 * local symbols (normally sections).  If a relocation is
1570Sstevel@tonic-gate 		 * against a local symbol it qualifies as a relative relocation.
1580Sstevel@tonic-gate 		 */
1590Sstevel@tonic-gate 		if ((type == M_R_RELATIVE) || (type == M_R_NONE) ||
1600Sstevel@tonic-gate 		    (ELF_ST_BIND(sym->st_info) == STB_LOCAL))
1610Sstevel@tonic-gate 			bind = STB_LOCAL;
1620Sstevel@tonic-gate 		else
1630Sstevel@tonic-gate 			bind = STB_GLOBAL;
1640Sstevel@tonic-gate 
1650Sstevel@tonic-gate 		/*
1660Sstevel@tonic-gate 		 * Analyze the case where only relative relocations are to be
1670Sstevel@tonic-gate 		 * applied.
1680Sstevel@tonic-gate 		 */
1690Sstevel@tonic-gate 		if ((flags & RTLD_REL_ALL) == RTLD_REL_RELATIVE) {
1700Sstevel@tonic-gate 			if (flags & RTLD_MEMORY) {
1710Sstevel@tonic-gate 				if (bind == STB_LOCAL) {
1720Sstevel@tonic-gate 					/*
1730Sstevel@tonic-gate 					 * Save the relative relocations from
1740Sstevel@tonic-gate 					 * the memory image.  The data itself
1750Sstevel@tonic-gate 					 * might already have been relocated,
1760Sstevel@tonic-gate 					 * thus clear the relocation record so
1770Sstevel@tonic-gate 					 * that it will not be performed again.
1780Sstevel@tonic-gate 					 */
1790Sstevel@tonic-gate 					reloc->r_flags = FLG_R_CLR;
1800Sstevel@tonic-gate 					(*null)++;
1810Sstevel@tonic-gate 				} else {
1820Sstevel@tonic-gate 					/*
1830Sstevel@tonic-gate 					 * Any non-relative relocation must be
1840Sstevel@tonic-gate 					 * undone, and the relocation records
1850Sstevel@tonic-gate 					 * offset updated to any new fixed
1860Sstevel@tonic-gate 					 * address.
1870Sstevel@tonic-gate 					 */
1880Sstevel@tonic-gate 					reloc->r_flags =
1890Sstevel@tonic-gate 					    (FLG_R_UNDO | FLG_R_INC);
1900Sstevel@tonic-gate 					reloc->r_value = addr;
1910Sstevel@tonic-gate 					if (type == M_R_JMP_SLOT)
1920Sstevel@tonic-gate 						(*func)++;
1930Sstevel@tonic-gate 					else
1940Sstevel@tonic-gate 						(*data)++;
1950Sstevel@tonic-gate 				}
1960Sstevel@tonic-gate 			} else {
1970Sstevel@tonic-gate 				if (bind == STB_LOCAL) {
1980Sstevel@tonic-gate 					/*
1990Sstevel@tonic-gate 					 * Apply relative relocation to the
2000Sstevel@tonic-gate 					 * file image.  Clear the relocation
2010Sstevel@tonic-gate 					 * record so that it will not be
2020Sstevel@tonic-gate 					 * performed again.
2030Sstevel@tonic-gate 					 */
2040Sstevel@tonic-gate 					reloc->r_flags =
2050Sstevel@tonic-gate 					    (FLG_R_APPLY | FLG_R_CLR);
2060Sstevel@tonic-gate 					reloc->r_value = addr;
2070Sstevel@tonic-gate 					if (IS_PC_RELATIVE(type))
2080Sstevel@tonic-gate 						reloc->r_value -= offset;
2090Sstevel@tonic-gate 
2100Sstevel@tonic-gate 					if (unknown == 0)
2115220Srie 						unknown =
2125220Srie 						    MSG_INTL(MSG_STR_UNKNOWN);
2130Sstevel@tonic-gate 					reloc->r_name = unknown;
2140Sstevel@tonic-gate 					(*null)++;
2150Sstevel@tonic-gate 				} else {
2160Sstevel@tonic-gate 					/*
2170Sstevel@tonic-gate 					 * Any non-relative relocation should be
2180Sstevel@tonic-gate 					 * left alone, but its offset should be
2190Sstevel@tonic-gate 					 * updated to any new fixed address.
2200Sstevel@tonic-gate 					 */
2210Sstevel@tonic-gate 					reloc->r_flags = FLG_R_INC;
2220Sstevel@tonic-gate 					reloc->r_value = addr;
2230Sstevel@tonic-gate 					if (type == M_R_JMP_SLOT)
2240Sstevel@tonic-gate 						(*func)++;
2250Sstevel@tonic-gate 					else
2260Sstevel@tonic-gate 						(*data)++;
2270Sstevel@tonic-gate 				}
2280Sstevel@tonic-gate 			}
2290Sstevel@tonic-gate 			continue;
2300Sstevel@tonic-gate 		}
2310Sstevel@tonic-gate 
2320Sstevel@tonic-gate 		/*
2330Sstevel@tonic-gate 		 * Analyze the case where more than just relative relocations
2340Sstevel@tonic-gate 		 * are to be applied.
2350Sstevel@tonic-gate 		 */
2360Sstevel@tonic-gate 		if (bind == STB_LOCAL) {
2370Sstevel@tonic-gate 			if (flags & RTLD_MEMORY) {
2380Sstevel@tonic-gate 				/*
2390Sstevel@tonic-gate 				 * Save the relative relocations from the memory
2400Sstevel@tonic-gate 				 * image.  The data itself has already been
2410Sstevel@tonic-gate 				 * relocated, thus clear the relocation record
2420Sstevel@tonic-gate 				 * so that it will not be performed again.
2430Sstevel@tonic-gate 				 */
2440Sstevel@tonic-gate 				reloc->r_flags = FLG_R_CLR;
2450Sstevel@tonic-gate 			} else {
2460Sstevel@tonic-gate 				/*
2470Sstevel@tonic-gate 				 * Apply relative relocation to the file image.
2480Sstevel@tonic-gate 				 * Clear the relocation record so that it will
2490Sstevel@tonic-gate 				 * not be performed again.
2500Sstevel@tonic-gate 				 */
2510Sstevel@tonic-gate 				reloc->r_flags = (FLG_R_APPLY | FLG_R_CLR);
2520Sstevel@tonic-gate 				reloc->r_value = addr;
2530Sstevel@tonic-gate 				if (IS_PC_RELATIVE(type))
2540Sstevel@tonic-gate 					reloc->r_value -= offset;
2550Sstevel@tonic-gate 
2560Sstevel@tonic-gate 				if (unknown == 0)
2570Sstevel@tonic-gate 					unknown = MSG_INTL(MSG_STR_UNKNOWN);
2580Sstevel@tonic-gate 				reloc->r_name = unknown;
2590Sstevel@tonic-gate 			}
2600Sstevel@tonic-gate 			(*null)++;
2610Sstevel@tonic-gate 			continue;
2620Sstevel@tonic-gate 		}
2630Sstevel@tonic-gate 
2640Sstevel@tonic-gate 		/*
2650Sstevel@tonic-gate 		 * At this point we're dealing with a non-relative relocation
2660Sstevel@tonic-gate 		 * that requires the symbol definition.
2670Sstevel@tonic-gate 		 */
2680Sstevel@tonic-gate 		name = strs + sym->st_name;
2690Sstevel@tonic-gate 
2700Sstevel@tonic-gate 		/*
2710Sstevel@tonic-gate 		 * Find the symbol.  As the object being investigated is already
2720Sstevel@tonic-gate 		 * a part of this process, the symbol lookup will likely
2730Sstevel@tonic-gate 		 * succeed.  However, because of lazy binding, there is still
2740Sstevel@tonic-gate 		 * the possibility of a dangling .plt relocation.  dldump()
2750Sstevel@tonic-gate 		 * users might be encouraged to set LD_FLAGS=loadavail (crle(1)
2760Sstevel@tonic-gate 		 * does this for them).
2775950Srie 		 *
278*11827SRod.Evans@Sun.COM 		 * Initialize the symbol lookup, and symbol result, data
279*11827SRod.Evans@Sun.COM 		 * structures.
2800Sstevel@tonic-gate 		 */
2815950Srie 		SLOOKUP_INIT(sl, name, lmp, LIST(lmp)->lm_head, ld_entry_cnt,
2825950Srie 		    0, rsymndx, sym, type, LKUP_STDRELOC);
283*11827SRod.Evans@Sun.COM 		SRESULT_INIT(sr, name);
2840Sstevel@tonic-gate 
2850Sstevel@tonic-gate 		_bound = _weak = 0;
2860Sstevel@tonic-gate 		_sym = sym;
287*11827SRod.Evans@Sun.COM 		if (lookup_sym(&sl, &sr, &binfo, NULL)) {
288*11827SRod.Evans@Sun.COM 			_lmp = sr.sr_dmap;
289*11827SRod.Evans@Sun.COM 			sym = sr.sr_sym;
290*11827SRod.Evans@Sun.COM 
2910Sstevel@tonic-gate 			/*
2920Sstevel@tonic-gate 			 * Determine from the various relocation requirements
2930Sstevel@tonic-gate 			 * whether this binding is appropriate.  If we're called
2940Sstevel@tonic-gate 			 * from crle(1), RTLD_CONFSET is set, then only inspect
2950Sstevel@tonic-gate 			 * objects selected from the configuration file
2960Sstevel@tonic-gate 			 * (FL1_RT_CONFSET was set during load()).
2970Sstevel@tonic-gate 			 */
2980Sstevel@tonic-gate 			if (!(flags & RTLD_CONFSET) ||
2990Sstevel@tonic-gate 			    (FLAGS1(_lmp) & FL1_RT_CONFSET)) {
3000Sstevel@tonic-gate 				if (((flags & RTLD_REL_ALL) == RTLD_REL_ALL) ||
3010Sstevel@tonic-gate 				    ((flags & RTLD_REL_EXEC) &&
3020Sstevel@tonic-gate 				    (FLAGS(_lmp) & FLG_RT_ISMAIN)) ||
3030Sstevel@tonic-gate 				    ((flags & RTLD_REL_DEPENDS) &&
3040Sstevel@tonic-gate 				    (!(FLAGS(_lmp) & FLG_RT_ISMAIN))) ||
3050Sstevel@tonic-gate 				    ((flags & RTLD_REL_PRELOAD) &&
3060Sstevel@tonic-gate 				    (FLAGS(_lmp) & FLG_RT_PRELOAD)) ||
3072850Srie 				    ((flags & RTLD_REL_SELF) &&
3082850Srie 				    (lmp == _lmp))) {
3095892Sab196087 					Aliste	idx;
3102850Srie 					Word	*ndx;
3112850Srie 
3120Sstevel@tonic-gate 					_bound = 1;
3132850Srie 
3142850Srie 					/*
3152850Srie 					 * If this symbol is explicitly defined
3162850Srie 					 * as nodirect, don't allow any local
3172850Srie 					 * binding.
3182850Srie 					 */
3195892Sab196087 					for (ALIST_TRAVERSE(nodirect, idx,
3202850Srie 					    ndx)) {
3212850Srie 						if (*ndx == rsymndx) {
3222850Srie 							_bound = 0;
3232850Srie 							break;
3242850Srie 						}
3252850Srie 					}
3262850Srie 				}
3270Sstevel@tonic-gate 			}
3280Sstevel@tonic-gate 		} else {
3290Sstevel@tonic-gate 			/*
3300Sstevel@tonic-gate 			 * If this is a weak reference and we've been asked to
3310Sstevel@tonic-gate 			 * bind unresolved weak references consider ourself
3320Sstevel@tonic-gate 			 * bound.  This category is typically set by clre(1) for
3330Sstevel@tonic-gate 			 * an application cache.
3340Sstevel@tonic-gate 			 */
3350Sstevel@tonic-gate 			if ((ELF_ST_BIND(_sym->st_info) == STB_WEAK) &&
3360Sstevel@tonic-gate 			    (_sym->st_shndx == SHN_UNDEF) &&
3370Sstevel@tonic-gate 			    (flags & RTLD_REL_WEAK))
3380Sstevel@tonic-gate 				_bound = _weak = 1;
3390Sstevel@tonic-gate 		}
3400Sstevel@tonic-gate 
3410Sstevel@tonic-gate 		if (flags & RTLD_MEMORY) {
3420Sstevel@tonic-gate 			if (_bound) {
3430Sstevel@tonic-gate 				/*
3440Sstevel@tonic-gate 				 * We know that all data relocations will have
3450Sstevel@tonic-gate 				 * been performed at process startup thus clear
3460Sstevel@tonic-gate 				 * the relocation record so that it will not be
3470Sstevel@tonic-gate 				 * performed again.  However, we don't know what
3480Sstevel@tonic-gate 				 * function relocations have been performed
3490Sstevel@tonic-gate 				 * because of lazy binding - regardless, we can
3500Sstevel@tonic-gate 				 * leave all the function relocation records in
3510Sstevel@tonic-gate 				 * place, because if the function has already
3520Sstevel@tonic-gate 				 * been bound the record won't be referenced
3530Sstevel@tonic-gate 				 * anyway.  In the case of using LD_BIND_NOW,
3540Sstevel@tonic-gate 				 * a function may be bound twice - so what.
3550Sstevel@tonic-gate 				 */
3560Sstevel@tonic-gate 				if (type == M_R_JMP_SLOT) {
3570Sstevel@tonic-gate 					reloc->r_flags = FLG_R_INC;
3580Sstevel@tonic-gate 					(*func)++;
3590Sstevel@tonic-gate 				} else {
3600Sstevel@tonic-gate 					if (type != M_R_COPY)
3610Sstevel@tonic-gate 						reloc->r_flags = FLG_R_CLR;
3620Sstevel@tonic-gate 					(*null)++;
3630Sstevel@tonic-gate 				}
3640Sstevel@tonic-gate 			} else {
3650Sstevel@tonic-gate 				/*
3660Sstevel@tonic-gate 				 * Clear any unrequired relocation.
3670Sstevel@tonic-gate 				 */
3680Sstevel@tonic-gate 				reloc->r_flags = FLG_R_UNDO | FLG_R_INC;
3690Sstevel@tonic-gate 				reloc->r_value = addr;
3700Sstevel@tonic-gate 				if (type == M_R_JMP_SLOT)
3710Sstevel@tonic-gate 					(*func)++;
3720Sstevel@tonic-gate 				else
3730Sstevel@tonic-gate 					(*data)++;
3740Sstevel@tonic-gate 			}
3750Sstevel@tonic-gate 		} else {
3760Sstevel@tonic-gate 			if (_bound) {
3770Sstevel@tonic-gate 				/*
3780Sstevel@tonic-gate 				 * Apply the global relocation to the file
3790Sstevel@tonic-gate 				 * image.  Clear the relocation record so that
3800Sstevel@tonic-gate 				 * it will not be performed again.
3810Sstevel@tonic-gate 				 */
3820Sstevel@tonic-gate 				if (_weak) {
3830Sstevel@tonic-gate 					reloc->r_value = 0;
3840Sstevel@tonic-gate 					reloc->r_size = 0;
3850Sstevel@tonic-gate 				} else {
3860Sstevel@tonic-gate 					reloc->r_value = sym->st_value;
3870Sstevel@tonic-gate 					if (IS_PC_RELATIVE(type))
3880Sstevel@tonic-gate 						reloc->r_value -= offset;
3890Sstevel@tonic-gate 					if ((!(FLAGS(_lmp) & FLG_RT_FIXED)) &&
3900Sstevel@tonic-gate 					    (sym->st_shndx != SHN_ABS))
3910Sstevel@tonic-gate 						reloc->r_value += ADDR(_lmp);
3920Sstevel@tonic-gate 					reloc->r_size = sym->st_size;
3930Sstevel@tonic-gate 				}
3940Sstevel@tonic-gate 
3950Sstevel@tonic-gate 				reloc->r_flags = FLG_R_APPLY | FLG_R_CLR;
3960Sstevel@tonic-gate 				reloc->r_name = name;
3970Sstevel@tonic-gate 				if (type == M_R_JMP_SLOT)
3980Sstevel@tonic-gate 					(*func)++;
3990Sstevel@tonic-gate 				else
4000Sstevel@tonic-gate 					(*null)++;
4010Sstevel@tonic-gate 			} else {
4020Sstevel@tonic-gate 				/*
4030Sstevel@tonic-gate 				 * Do not apply any unrequired relocations.
4040Sstevel@tonic-gate 				 */
4050Sstevel@tonic-gate 				reloc->r_flags = FLG_R_INC;
4060Sstevel@tonic-gate 				reloc->r_value = addr;
4070Sstevel@tonic-gate 				if (type == M_R_JMP_SLOT)
4080Sstevel@tonic-gate 					(*func)++;
4090Sstevel@tonic-gate 				else
4100Sstevel@tonic-gate 					(*data)++;
4110Sstevel@tonic-gate 			}
4120Sstevel@tonic-gate 		}
4130Sstevel@tonic-gate 	}
4140Sstevel@tonic-gate 	return (0);
4150Sstevel@tonic-gate }
4160Sstevel@tonic-gate 
4170Sstevel@tonic-gate 
4180Sstevel@tonic-gate /*
4190Sstevel@tonic-gate  * Perform any relocation updates to the new image using the information from
4200Sstevel@tonic-gate  * the `Reloc' structure constructed during count_reloc().
4210Sstevel@tonic-gate  */
4220Sstevel@tonic-gate void
update_reloc(Cache * ocache,Cache * icache,Cache * _icache,const char * name,Rt_map * lmp,Rel ** null,Rel ** data,Rel ** func)4230Sstevel@tonic-gate update_reloc(Cache *ocache, Cache *icache, Cache *_icache, const char *name,
4240Sstevel@tonic-gate     Rt_map *lmp, Rel **null, Rel **data, Rel **func)
4250Sstevel@tonic-gate {
4260Sstevel@tonic-gate 	Shdr	*shdr;
4270Sstevel@tonic-gate 	Rel	*rel;
4280Sstevel@tonic-gate 	Reloc	*reloc;
4290Sstevel@tonic-gate 	Xword	ent, cnt, _cnt;
4300Sstevel@tonic-gate 	Cache	*orcache, *ircache = 0;
4310Sstevel@tonic-gate 	Half	ndx;
4320Sstevel@tonic-gate 
4330Sstevel@tonic-gate 	/*
4340Sstevel@tonic-gate 	 * Set up to read the output relocation table.
4350Sstevel@tonic-gate 	 */
4360Sstevel@tonic-gate 	shdr = _icache->c_shdr;
4370Sstevel@tonic-gate 	rel = (Rel *)_icache->c_data->d_buf;
4380Sstevel@tonic-gate 	reloc = (Reloc *)_icache->c_info;
4390Sstevel@tonic-gate 	ent = shdr->sh_entsize;
4400Sstevel@tonic-gate 	cnt = shdr->sh_size / ent;
4410Sstevel@tonic-gate 
4420Sstevel@tonic-gate 	/*
4430Sstevel@tonic-gate 	 * Loop through the relocation table.
4440Sstevel@tonic-gate 	 */
4450Sstevel@tonic-gate 	for (_cnt = 0; _cnt < cnt; _cnt++, reloc++,
4460Sstevel@tonic-gate 	    rel = (Rel *)((uintptr_t)rel + ent)) {
4470Sstevel@tonic-gate 		uchar_t		*iaddr, *oaddr;
4480Sstevel@tonic-gate 		/* LINTED */
4496206Sab196087 		uchar_t		type = (uchar_t)ELF_R_TYPE(rel->r_info, M_MACH);
4500Sstevel@tonic-gate 		Addr		off, bgn, end;
4510Sstevel@tonic-gate 
4520Sstevel@tonic-gate 		/*
4530Sstevel@tonic-gate 		 * Ignore null relocations (these may have been created from a
4540Sstevel@tonic-gate 		 * previous dldump() of this image).
4550Sstevel@tonic-gate 		 */
4560Sstevel@tonic-gate 		if (type == M_R_NONE) {
4570Sstevel@tonic-gate 			(*null)++;
4580Sstevel@tonic-gate 			continue;
4590Sstevel@tonic-gate 		}
4600Sstevel@tonic-gate 
4610Sstevel@tonic-gate 		/*
4620Sstevel@tonic-gate 		 * Determine the section being relocated if we haven't already
4630Sstevel@tonic-gate 		 * done so (we may have had to skip over some null relocation to
4640Sstevel@tonic-gate 		 * get to the first valid offset).  The System V ABI states that
4650Sstevel@tonic-gate 		 * a relocation sections sh_info field indicates the section
4660Sstevel@tonic-gate 		 * that must be relocated.  However, on Intel it seems that the
4670Sstevel@tonic-gate 		 * .rel.plt sh_info records the section index of the .plt, when
4680Sstevel@tonic-gate 		 * in fact it's the .got that gets relocated.  In addition we
4690Sstevel@tonic-gate 		 * now create combined relocation sections with -zcomreloc.  To
4700Sstevel@tonic-gate 		 * generically be able to cope with these anomalies, search for
4710Sstevel@tonic-gate 		 * the appropriate section to be relocated by comparing the
4720Sstevel@tonic-gate 		 * offset of the first relocation record against each sections
4730Sstevel@tonic-gate 		 * offset and size.
4740Sstevel@tonic-gate 		 */
4755220Srie 		/* BEGIN CSTYLED */
4760Sstevel@tonic-gate #if	!defined(__lint)
4770Sstevel@tonic-gate 		if ((ircache == (Cache *)0) || (rel->r_offset < bgn) ||
4780Sstevel@tonic-gate 			(rel->r_offset > end)) {
4790Sstevel@tonic-gate #else
4800Sstevel@tonic-gate 		/*
4810Sstevel@tonic-gate 		 * lint sees `bgn' and `end' as potentially referenced
4820Sstevel@tonic-gate 		 * before being set.
4830Sstevel@tonic-gate 		 */
4840Sstevel@tonic-gate 		if (ircache == (Cache *)0) {
4850Sstevel@tonic-gate #endif
4860Sstevel@tonic-gate 			_icache = icache;
4870Sstevel@tonic-gate 			_icache++;
4880Sstevel@tonic-gate 
4890Sstevel@tonic-gate 			for (ndx = 1; _icache->c_flags != FLG_C_END; ndx++,
4900Sstevel@tonic-gate 			    _icache++) {
4910Sstevel@tonic-gate 
4920Sstevel@tonic-gate 				shdr = _icache->c_shdr;
4930Sstevel@tonic-gate 				bgn = shdr->sh_addr;
4940Sstevel@tonic-gate 				end = bgn + shdr->sh_size;
4950Sstevel@tonic-gate 
4960Sstevel@tonic-gate 				if ((rel->r_offset >= bgn) &&
4970Sstevel@tonic-gate 				    (rel->r_offset <= end))
4980Sstevel@tonic-gate 					break;
4990Sstevel@tonic-gate 			}
5000Sstevel@tonic-gate 			ircache = &icache[ndx];
5010Sstevel@tonic-gate 			orcache = &ocache[ndx];
5020Sstevel@tonic-gate 		}
5035220Srie 		/* END CSTYLED */
5040Sstevel@tonic-gate 
5050Sstevel@tonic-gate 		/*
5060Sstevel@tonic-gate 		 * Determine the relocation location of both the input and
5070Sstevel@tonic-gate 		 * output data.  Take into account that an input section may be
5080Sstevel@tonic-gate 		 * NOBITS (ppc .plt for example).
5090Sstevel@tonic-gate 		 */
5100Sstevel@tonic-gate 		off = rel->r_offset - ircache->c_shdr->sh_addr;
5110Sstevel@tonic-gate 		if (ircache->c_data->d_buf)
5120Sstevel@tonic-gate 			iaddr = (uchar_t *)ircache->c_data->d_buf + off;
5130Sstevel@tonic-gate 		else
5140Sstevel@tonic-gate 			iaddr = 0;
5150Sstevel@tonic-gate 		oaddr = (uchar_t *)orcache->c_data->d_buf + off;
5160Sstevel@tonic-gate 
5170Sstevel@tonic-gate 		/*
5180Sstevel@tonic-gate 		 * Apply the relocation to the new output image.  Any base
5190Sstevel@tonic-gate 		 * address, or symbol value, will have been saved in the reloc
5200Sstevel@tonic-gate 		 * structure during count_reloc().
5210Sstevel@tonic-gate 		 */
5220Sstevel@tonic-gate 		if (reloc->r_flags & FLG_R_APPLY)
5230Sstevel@tonic-gate 			apply_reloc(rel, reloc, name, oaddr, lmp);
5240Sstevel@tonic-gate 
5250Sstevel@tonic-gate 		/*
5260Sstevel@tonic-gate 		 * Undo any relocation that might already been applied to the
5270Sstevel@tonic-gate 		 * memory image by the runtime linker.  Using the original
5280Sstevel@tonic-gate 		 * file, determine the relocation offset original value and
5290Sstevel@tonic-gate 		 * restore the new image to that value.
5300Sstevel@tonic-gate 		 */
5310Sstevel@tonic-gate 		if ((reloc->r_flags & FLG_R_UNDO) &&
5320Sstevel@tonic-gate 		    (FLAGS(lmp) & FLG_RT_RELOCED))
5330Sstevel@tonic-gate 			undo_reloc(rel, oaddr, iaddr, reloc);
5340Sstevel@tonic-gate 
5350Sstevel@tonic-gate 		/*
5360Sstevel@tonic-gate 		 * If a relocation has been applied then the relocation record
5370Sstevel@tonic-gate 		 * should be cleared so that the relocation isn't applied again
5380Sstevel@tonic-gate 		 * when the new image is used.
5390Sstevel@tonic-gate 		 */
5400Sstevel@tonic-gate 		if (reloc->r_flags & FLG_R_CLR) {
5410Sstevel@tonic-gate 			if (type == M_R_JMP_SLOT) {
5420Sstevel@tonic-gate 				clear_reloc(*func);
5430Sstevel@tonic-gate 				*func = (Rel *)((uintptr_t)*func + ent);
5440Sstevel@tonic-gate 			} else {
5450Sstevel@tonic-gate 				clear_reloc(*null);
5460Sstevel@tonic-gate 				*null = (Rel *)((uintptr_t)*null + ent);
5470Sstevel@tonic-gate 			}
5480Sstevel@tonic-gate 		}
5490Sstevel@tonic-gate 
5500Sstevel@tonic-gate 		/*
5510Sstevel@tonic-gate 		 * If a relocation isn't applied, update the relocation record
5520Sstevel@tonic-gate 		 * to take into account the new address of the image.
5530Sstevel@tonic-gate 		 */
5540Sstevel@tonic-gate 		if (reloc->r_flags & FLG_R_INC) {
5550Sstevel@tonic-gate 			if (type == M_R_JMP_SLOT) {
5560Sstevel@tonic-gate 				inc_reloc(*func, rel, reloc, oaddr, iaddr);
5570Sstevel@tonic-gate 				*func = (Rel *)((uintptr_t)*func + ent);
5580Sstevel@tonic-gate 			} else {
5590Sstevel@tonic-gate 				inc_reloc(*data, rel, reloc, oaddr, iaddr);
5600Sstevel@tonic-gate 				*data = (Rel *)((uintptr_t)*data + ent);
5610Sstevel@tonic-gate 			}
5620Sstevel@tonic-gate 		}
5630Sstevel@tonic-gate 	}
5640Sstevel@tonic-gate }
565