17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
52926dd2eSrie  * Common Development and Distribution License (the "License").
62926dd2eSrie  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
212926dd2eSrie 
227c478bd9Sstevel@tonic-gate /*
23*08278a5eSRod Evans  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate #include	<libelf.h>
287c478bd9Sstevel@tonic-gate #include	<dlfcn.h>
297c478bd9Sstevel@tonic-gate #include	"machdep.h"
307c478bd9Sstevel@tonic-gate #include	"reloc.h"
317c478bd9Sstevel@tonic-gate #include	"msg.h"
327c478bd9Sstevel@tonic-gate #include	"_librtld.h"
332926dd2eSrie #include	"alist.h"
347c478bd9Sstevel@tonic-gate 
357c478bd9Sstevel@tonic-gate static const char	*unknown = 0;	/* Stash MSG_INTL(MSG_STR_UNKNOWN) */
367c478bd9Sstevel@tonic-gate 
377c478bd9Sstevel@tonic-gate /*
387c478bd9Sstevel@tonic-gate  * Process all relocation records.  A new `Reloc' structure is allocated to
397c478bd9Sstevel@tonic-gate  * cache the processing decisions deduced, and these will be applied during
407c478bd9Sstevel@tonic-gate  * update_reloc().
417c478bd9Sstevel@tonic-gate  * A count of the number of null relocations (i.e., relocations that will be
427c478bd9Sstevel@tonic-gate  * fixed and whoes records will be nulled out), data and function relocations
437c478bd9Sstevel@tonic-gate  * is maintained.  This allows the relocation records themselves to be
447c478bd9Sstevel@tonic-gate  * rearranged (localized) later if necessary.  Note that the number of function
457c478bd9Sstevel@tonic-gate  * relocations, although coounted, shouldn't differ from the original file,
467c478bd9Sstevel@tonic-gate  * the index of a .plt must be maintained to the index of its relocation record
477c478bd9Sstevel@tonic-gate  * within the associated relocation section.
487c478bd9Sstevel@tonic-gate  *
497c478bd9Sstevel@tonic-gate  * The intention behind this file is to maintain as much relocation logic as
507c478bd9Sstevel@tonic-gate  * possible in a generic form.
517c478bd9Sstevel@tonic-gate  */
527c478bd9Sstevel@tonic-gate int
count_reloc(Cache * cache,Cache * _cache,Rt_map * lmp,int flags,Addr addr,Xword * null,Xword * data,Xword * func,Alist * nodirect)537c478bd9Sstevel@tonic-gate count_reloc(Cache *cache, Cache *_cache, Rt_map *lmp, int flags, Addr addr,
542926dd2eSrie     Xword *null, Xword *data, Xword *func, Alist *nodirect)
557c478bd9Sstevel@tonic-gate {
567c478bd9Sstevel@tonic-gate 	Rel		*rel;
577c478bd9Sstevel@tonic-gate 	Reloc		*reloc;
587c478bd9Sstevel@tonic-gate 	Shdr		*shdr;
597c478bd9Sstevel@tonic-gate 	Xword		ent, cnt, _cnt;
607c478bd9Sstevel@tonic-gate 	Sym		*syms;
617c478bd9Sstevel@tonic-gate 	const char	*strs;
627c478bd9Sstevel@tonic-gate 	Cache		*__cache;
637c478bd9Sstevel@tonic-gate 	Xword		pltndx = 0;
647c478bd9Sstevel@tonic-gate 
657c478bd9Sstevel@tonic-gate 	/*
667c478bd9Sstevel@tonic-gate 	 * Determine the number of relocation entries we'll be dealing with.
677c478bd9Sstevel@tonic-gate 	 */
687c478bd9Sstevel@tonic-gate 	shdr = _cache->c_shdr;
697c478bd9Sstevel@tonic-gate 	rel = (Rel *)_cache->c_data->d_buf;
707c478bd9Sstevel@tonic-gate 	ent = shdr->sh_entsize;
717c478bd9Sstevel@tonic-gate 	cnt = shdr->sh_size / ent;
727c478bd9Sstevel@tonic-gate 
737c478bd9Sstevel@tonic-gate 	/*
747c478bd9Sstevel@tonic-gate 	 * Allocate a relocation structure for this relocation section.
757c478bd9Sstevel@tonic-gate 	 */
767c478bd9Sstevel@tonic-gate 	if ((reloc = calloc(cnt, sizeof (Reloc))) == 0)
777c478bd9Sstevel@tonic-gate 		return (1);
787c478bd9Sstevel@tonic-gate 	_cache->c_info = (void *)reloc;
797c478bd9Sstevel@tonic-gate 
807c478bd9Sstevel@tonic-gate 	/*
817c478bd9Sstevel@tonic-gate 	 * Determine the relocations associated symbol and string table.
827c478bd9Sstevel@tonic-gate 	 */
837c478bd9Sstevel@tonic-gate 	__cache = &cache[shdr->sh_link];
847c478bd9Sstevel@tonic-gate 	syms = (Sym *)__cache->c_data->d_buf;
857c478bd9Sstevel@tonic-gate 	shdr = __cache->c_shdr;
867c478bd9Sstevel@tonic-gate 	__cache = &cache[shdr->sh_link];
877c478bd9Sstevel@tonic-gate 	strs = (const char *)__cache->c_data->d_buf;
887c478bd9Sstevel@tonic-gate 
897c478bd9Sstevel@tonic-gate 	/*
907c478bd9Sstevel@tonic-gate 	 * Loop through the relocation table.
917c478bd9Sstevel@tonic-gate 	 */
927c478bd9Sstevel@tonic-gate 	for (_cnt = 0; _cnt < cnt; _cnt++, reloc++,
937c478bd9Sstevel@tonic-gate 	    rel = (Rel *)((uintptr_t)rel + ent)) {
947c478bd9Sstevel@tonic-gate 		const char	*name;
957c478bd9Sstevel@tonic-gate 		/* LINTED */
96ba2be530Sab 		uchar_t		type = (uchar_t)ELF_R_TYPE(rel->r_info, M_MACH);
977c478bd9Sstevel@tonic-gate 		uchar_t		bind;
987c478bd9Sstevel@tonic-gate 		ulong_t		offset = rel->r_offset + addr;
997c478bd9Sstevel@tonic-gate 		Rt_map		*_lmp;
1007c478bd9Sstevel@tonic-gate 		int		_bound, _weak;
1017c478bd9Sstevel@tonic-gate 		ulong_t		rsymndx = ELF_R_SYM(rel->r_info);
1027c478bd9Sstevel@tonic-gate 		Slookup		sl;
103*08278a5eSRod Evans 		Sresult		sr;
1047c478bd9Sstevel@tonic-gate 		uint_t		binfo;
1057c478bd9Sstevel@tonic-gate 		Sym		*_sym, *sym = (syms + rsymndx);
1067c478bd9Sstevel@tonic-gate 
1077c478bd9Sstevel@tonic-gate 		if (type == M_R_JMP_SLOT)
1087c478bd9Sstevel@tonic-gate 			reloc->r_pltndx = ++pltndx;
1097c478bd9Sstevel@tonic-gate 
1107c478bd9Sstevel@tonic-gate 		/*
1117c478bd9Sstevel@tonic-gate 		 * Analyze the case where no relocations are to be applied.
1127c478bd9Sstevel@tonic-gate 		 */
1137c478bd9Sstevel@tonic-gate 		if ((flags & RTLD_REL_ALL) == 0) {
1147c478bd9Sstevel@tonic-gate 			/*
1157c478bd9Sstevel@tonic-gate 			 * Don't apply any relocations to the new image but
1167c478bd9Sstevel@tonic-gate 			 * insure their offsets are incremented to reflect any
1177c478bd9Sstevel@tonic-gate 			 * new fixed address.
1187c478bd9Sstevel@tonic-gate 			 */
1197c478bd9Sstevel@tonic-gate 			reloc->r_flags = FLG_R_INC;
1207c478bd9Sstevel@tonic-gate 
1217c478bd9Sstevel@tonic-gate 			/*
1227c478bd9Sstevel@tonic-gate 			 * Undo any relocations that might have already been
1237c478bd9Sstevel@tonic-gate 			 * applied to the memory image.
1247c478bd9Sstevel@tonic-gate 			 */
1257c478bd9Sstevel@tonic-gate 			if (flags & RTLD_MEMORY) {
1267c478bd9Sstevel@tonic-gate 				reloc->r_flags |= FLG_R_UNDO;
1277c478bd9Sstevel@tonic-gate 
1287c478bd9Sstevel@tonic-gate 				/*
1297c478bd9Sstevel@tonic-gate 				 * If a copy relocation is involved we'll need
1307c478bd9Sstevel@tonic-gate 				 * to know the size of the copy.
1317c478bd9Sstevel@tonic-gate 				 */
1327c478bd9Sstevel@tonic-gate 				if (type == M_R_COPY)
1337c478bd9Sstevel@tonic-gate 					reloc->r_size = sym->st_size;
1347c478bd9Sstevel@tonic-gate 				else
1357c478bd9Sstevel@tonic-gate 					reloc->r_size = 0;
1367c478bd9Sstevel@tonic-gate 			}
1377c478bd9Sstevel@tonic-gate 
1387c478bd9Sstevel@tonic-gate 			/*
1397c478bd9Sstevel@tonic-gate 			 * Save the objects new address.
1407c478bd9Sstevel@tonic-gate 			 */
1417c478bd9Sstevel@tonic-gate 			reloc->r_value = addr;
1427c478bd9Sstevel@tonic-gate 
1437c478bd9Sstevel@tonic-gate 			if (type == M_R_JMP_SLOT)
1447c478bd9Sstevel@tonic-gate 				(*func)++;
1457c478bd9Sstevel@tonic-gate 			else
1467c478bd9Sstevel@tonic-gate 				(*data)++;
1477c478bd9Sstevel@tonic-gate 			continue;
1487c478bd9Sstevel@tonic-gate 		}
1497c478bd9Sstevel@tonic-gate 
1507c478bd9Sstevel@tonic-gate 		/*
1517c478bd9Sstevel@tonic-gate 		 * Determine the symbol binding of the relocation. Don't assume
1527c478bd9Sstevel@tonic-gate 		 * that relative relocations are simply M_R_RELATIVE.  Although
1537c478bd9Sstevel@tonic-gate 		 * a pic generated shared object can normally be viewed as
1547c478bd9Sstevel@tonic-gate 		 * having relative and non-relative relocations, a non-pic
1557c478bd9Sstevel@tonic-gate 		 * shared object will contain a number of relocations against
1567c478bd9Sstevel@tonic-gate 		 * local symbols (normally sections).  If a relocation is
1577c478bd9Sstevel@tonic-gate 		 * against a local symbol it qualifies as a relative relocation.
1587c478bd9Sstevel@tonic-gate 		 */
1597c478bd9Sstevel@tonic-gate 		if ((type == M_R_RELATIVE) || (type == M_R_NONE) ||
1607c478bd9Sstevel@tonic-gate 		    (ELF_ST_BIND(sym->st_info) == STB_LOCAL))
1617c478bd9Sstevel@tonic-gate 			bind = STB_LOCAL;
1627c478bd9Sstevel@tonic-gate 		else
1637c478bd9Sstevel@tonic-gate 			bind = STB_GLOBAL;
1647c478bd9Sstevel@tonic-gate 
1657c478bd9Sstevel@tonic-gate 		/*
1667c478bd9Sstevel@tonic-gate 		 * Analyze the case where only relative relocations are to be
1677c478bd9Sstevel@tonic-gate 		 * applied.
1687c478bd9Sstevel@tonic-gate 		 */
1697c478bd9Sstevel@tonic-gate 		if ((flags & RTLD_REL_ALL) == RTLD_REL_RELATIVE) {
1707c478bd9Sstevel@tonic-gate 			if (flags & RTLD_MEMORY) {
1717c478bd9Sstevel@tonic-gate 				if (bind == STB_LOCAL) {
1727c478bd9Sstevel@tonic-gate 					/*
1737c478bd9Sstevel@tonic-gate 					 * Save the relative relocations from
1747c478bd9Sstevel@tonic-gate 					 * the memory image.  The data itself
1757c478bd9Sstevel@tonic-gate 					 * might already have been relocated,
1767c478bd9Sstevel@tonic-gate 					 * thus clear the relocation record so
1777c478bd9Sstevel@tonic-gate 					 * that it will not be performed again.
1787c478bd9Sstevel@tonic-gate 					 */
1797c478bd9Sstevel@tonic-gate 					reloc->r_flags = FLG_R_CLR;
1807c478bd9Sstevel@tonic-gate 					(*null)++;
1817c478bd9Sstevel@tonic-gate 				} else {
1827c478bd9Sstevel@tonic-gate 					/*
1837c478bd9Sstevel@tonic-gate 					 * Any non-relative relocation must be
1847c478bd9Sstevel@tonic-gate 					 * undone, and the relocation records
1857c478bd9Sstevel@tonic-gate 					 * offset updated to any new fixed
1867c478bd9Sstevel@tonic-gate 					 * address.
1877c478bd9Sstevel@tonic-gate 					 */
1887c478bd9Sstevel@tonic-gate 					reloc->r_flags =
1897c478bd9Sstevel@tonic-gate 					    (FLG_R_UNDO | FLG_R_INC);
1907c478bd9Sstevel@tonic-gate 					reloc->r_value = addr;
1917c478bd9Sstevel@tonic-gate 					if (type == M_R_JMP_SLOT)
1927c478bd9Sstevel@tonic-gate 						(*func)++;
1937c478bd9Sstevel@tonic-gate 					else
1947c478bd9Sstevel@tonic-gate 						(*data)++;
1957c478bd9Sstevel@tonic-gate 				}
1967c478bd9Sstevel@tonic-gate 			} else {
1977c478bd9Sstevel@tonic-gate 				if (bind == STB_LOCAL) {
1987c478bd9Sstevel@tonic-gate 					/*
1997c478bd9Sstevel@tonic-gate 					 * Apply relative relocation to the
2007c478bd9Sstevel@tonic-gate 					 * file image.  Clear the relocation
2017c478bd9Sstevel@tonic-gate 					 * record so that it will not be
2027c478bd9Sstevel@tonic-gate 					 * performed again.
2037c478bd9Sstevel@tonic-gate 					 */
2047c478bd9Sstevel@tonic-gate 					reloc->r_flags =
2057c478bd9Sstevel@tonic-gate 					    (FLG_R_APPLY | FLG_R_CLR);
2067c478bd9Sstevel@tonic-gate 					reloc->r_value = addr;
2077c478bd9Sstevel@tonic-gate 					if (IS_PC_RELATIVE(type))
2087c478bd9Sstevel@tonic-gate 						reloc->r_value -= offset;
2097c478bd9Sstevel@tonic-gate 
2107c478bd9Sstevel@tonic-gate 					if (unknown == 0)
21160758829Srie 						unknown =
21260758829Srie 						    MSG_INTL(MSG_STR_UNKNOWN);
2137c478bd9Sstevel@tonic-gate 					reloc->r_name = unknown;
2147c478bd9Sstevel@tonic-gate 					(*null)++;
2157c478bd9Sstevel@tonic-gate 				} else {
2167c478bd9Sstevel@tonic-gate 					/*
2177c478bd9Sstevel@tonic-gate 					 * Any non-relative relocation should be
2187c478bd9Sstevel@tonic-gate 					 * left alone, but its offset should be
2197c478bd9Sstevel@tonic-gate 					 * updated to any new fixed address.
2207c478bd9Sstevel@tonic-gate 					 */
2217c478bd9Sstevel@tonic-gate 					reloc->r_flags = FLG_R_INC;
2227c478bd9Sstevel@tonic-gate 					reloc->r_value = addr;
2237c478bd9Sstevel@tonic-gate 					if (type == M_R_JMP_SLOT)
2247c478bd9Sstevel@tonic-gate 						(*func)++;
2257c478bd9Sstevel@tonic-gate 					else
2267c478bd9Sstevel@tonic-gate 						(*data)++;
2277c478bd9Sstevel@tonic-gate 				}
2287c478bd9Sstevel@tonic-gate 			}
2297c478bd9Sstevel@tonic-gate 			continue;
2307c478bd9Sstevel@tonic-gate 		}
2317c478bd9Sstevel@tonic-gate 
2327c478bd9Sstevel@tonic-gate 		/*
2337c478bd9Sstevel@tonic-gate 		 * Analyze the case where more than just relative relocations
2347c478bd9Sstevel@tonic-gate 		 * are to be applied.
2357c478bd9Sstevel@tonic-gate 		 */
2367c478bd9Sstevel@tonic-gate 		if (bind == STB_LOCAL) {
2377c478bd9Sstevel@tonic-gate 			if (flags & RTLD_MEMORY) {
2387c478bd9Sstevel@tonic-gate 				/*
2397c478bd9Sstevel@tonic-gate 				 * Save the relative relocations from the memory
2407c478bd9Sstevel@tonic-gate 				 * image.  The data itself has already been
2417c478bd9Sstevel@tonic-gate 				 * relocated, thus clear the relocation record
2427c478bd9Sstevel@tonic-gate 				 * so that it will not be performed again.
2437c478bd9Sstevel@tonic-gate 				 */
2447c478bd9Sstevel@tonic-gate 				reloc->r_flags = FLG_R_CLR;
2457c478bd9Sstevel@tonic-gate 			} else {
2467c478bd9Sstevel@tonic-gate 				/*
2477c478bd9Sstevel@tonic-gate 				 * Apply relative relocation to the file image.
2487c478bd9Sstevel@tonic-gate 				 * Clear the relocation record so that it will
2497c478bd9Sstevel@tonic-gate 				 * not be performed again.
2507c478bd9Sstevel@tonic-gate 				 */
2517c478bd9Sstevel@tonic-gate 				reloc->r_flags = (FLG_R_APPLY | FLG_R_CLR);
2527c478bd9Sstevel@tonic-gate 				reloc->r_value = addr;
2537c478bd9Sstevel@tonic-gate 				if (IS_PC_RELATIVE(type))
2547c478bd9Sstevel@tonic-gate 					reloc->r_value -= offset;
2557c478bd9Sstevel@tonic-gate 
2567c478bd9Sstevel@tonic-gate 				if (unknown == 0)
2577c478bd9Sstevel@tonic-gate 					unknown = MSG_INTL(MSG_STR_UNKNOWN);
2587c478bd9Sstevel@tonic-gate 				reloc->r_name = unknown;
2597c478bd9Sstevel@tonic-gate 			}
2607c478bd9Sstevel@tonic-gate 			(*null)++;
2617c478bd9Sstevel@tonic-gate 			continue;
2627c478bd9Sstevel@tonic-gate 		}
2637c478bd9Sstevel@tonic-gate 
2647c478bd9Sstevel@tonic-gate 		/*
2657c478bd9Sstevel@tonic-gate 		 * At this point we're dealing with a non-relative relocation
2667c478bd9Sstevel@tonic-gate 		 * that requires the symbol definition.
2677c478bd9Sstevel@tonic-gate 		 */
2687c478bd9Sstevel@tonic-gate 		name = strs + sym->st_name;
2697c478bd9Sstevel@tonic-gate 
2707c478bd9Sstevel@tonic-gate 		/*
2717c478bd9Sstevel@tonic-gate 		 * Find the symbol.  As the object being investigated is already
2727c478bd9Sstevel@tonic-gate 		 * a part of this process, the symbol lookup will likely
2737c478bd9Sstevel@tonic-gate 		 * succeed.  However, because of lazy binding, there is still
2747c478bd9Sstevel@tonic-gate 		 * the possibility of a dangling .plt relocation.  dldump()
2757c478bd9Sstevel@tonic-gate 		 * users might be encouraged to set LD_FLAGS=loadavail (crle(1)
2767c478bd9Sstevel@tonic-gate 		 * does this for them).
27775e7992aSrie 		 *
278*08278a5eSRod Evans 		 * Initialize the symbol lookup, and symbol result, data
279*08278a5eSRod Evans 		 * structures.
2807c478bd9Sstevel@tonic-gate 		 */
28175e7992aSrie 		SLOOKUP_INIT(sl, name, lmp, LIST(lmp)->lm_head, ld_entry_cnt,
28275e7992aSrie 		    0, rsymndx, sym, type, LKUP_STDRELOC);
283*08278a5eSRod Evans 		SRESULT_INIT(sr, name);
2847c478bd9Sstevel@tonic-gate 
2857c478bd9Sstevel@tonic-gate 		_bound = _weak = 0;
2867c478bd9Sstevel@tonic-gate 		_sym = sym;
287*08278a5eSRod Evans 		if (lookup_sym(&sl, &sr, &binfo, NULL)) {
288*08278a5eSRod Evans 			_lmp = sr.sr_dmap;
289*08278a5eSRod Evans 			sym = sr.sr_sym;
290*08278a5eSRod Evans 
2917c478bd9Sstevel@tonic-gate 			/*
2927c478bd9Sstevel@tonic-gate 			 * Determine from the various relocation requirements
2937c478bd9Sstevel@tonic-gate 			 * whether this binding is appropriate.  If we're called
2947c478bd9Sstevel@tonic-gate 			 * from crle(1), RTLD_CONFSET is set, then only inspect
2957c478bd9Sstevel@tonic-gate 			 * objects selected from the configuration file
2967c478bd9Sstevel@tonic-gate 			 * (FL1_RT_CONFSET was set during load()).
2977c478bd9Sstevel@tonic-gate 			 */
2987c478bd9Sstevel@tonic-gate 			if (!(flags & RTLD_CONFSET) ||
2997c478bd9Sstevel@tonic-gate 			    (FLAGS1(_lmp) & FL1_RT_CONFSET)) {
3007c478bd9Sstevel@tonic-gate 				if (((flags & RTLD_REL_ALL) == RTLD_REL_ALL) ||
3017c478bd9Sstevel@tonic-gate 				    ((flags & RTLD_REL_EXEC) &&
3027c478bd9Sstevel@tonic-gate 				    (FLAGS(_lmp) & FLG_RT_ISMAIN)) ||
3037c478bd9Sstevel@tonic-gate 				    ((flags & RTLD_REL_DEPENDS) &&
3047c478bd9Sstevel@tonic-gate 				    (!(FLAGS(_lmp) & FLG_RT_ISMAIN))) ||
3057c478bd9Sstevel@tonic-gate 				    ((flags & RTLD_REL_PRELOAD) &&
3067c478bd9Sstevel@tonic-gate 				    (FLAGS(_lmp) & FLG_RT_PRELOAD)) ||
3072926dd2eSrie 				    ((flags & RTLD_REL_SELF) &&
3082926dd2eSrie 				    (lmp == _lmp))) {
309cce0e03bSab 					Aliste	idx;
3102926dd2eSrie 					Word	*ndx;
3112926dd2eSrie 
3127c478bd9Sstevel@tonic-gate 					_bound = 1;
3132926dd2eSrie 
3142926dd2eSrie 					/*
3152926dd2eSrie 					 * If this symbol is explicitly defined
3162926dd2eSrie 					 * as nodirect, don't allow any local
3172926dd2eSrie 					 * binding.
3182926dd2eSrie 					 */
319cce0e03bSab 					for (ALIST_TRAVERSE(nodirect, idx,
3202926dd2eSrie 					    ndx)) {
3212926dd2eSrie 						if (*ndx == rsymndx) {
3222926dd2eSrie 							_bound = 0;
3232926dd2eSrie 							break;
3242926dd2eSrie 						}
3252926dd2eSrie 					}
3262926dd2eSrie 				}
3277c478bd9Sstevel@tonic-gate 			}
3287c478bd9Sstevel@tonic-gate 		} else {
3297c478bd9Sstevel@tonic-gate 			/*
3307c478bd9Sstevel@tonic-gate 			 * If this is a weak reference and we've been asked to
3317c478bd9Sstevel@tonic-gate 			 * bind unresolved weak references consider ourself
3327c478bd9Sstevel@tonic-gate 			 * bound.  This category is typically set by clre(1) for
3337c478bd9Sstevel@tonic-gate 			 * an application cache.
3347c478bd9Sstevel@tonic-gate 			 */
3357c478bd9Sstevel@tonic-gate 			if ((ELF_ST_BIND(_sym->st_info) == STB_WEAK) &&
3367c478bd9Sstevel@tonic-gate 			    (_sym->st_shndx == SHN_UNDEF) &&
3377c478bd9Sstevel@tonic-gate 			    (flags & RTLD_REL_WEAK))
3387c478bd9Sstevel@tonic-gate 				_bound = _weak = 1;
3397c478bd9Sstevel@tonic-gate 		}
3407c478bd9Sstevel@tonic-gate 
3417c478bd9Sstevel@tonic-gate 		if (flags & RTLD_MEMORY) {
3427c478bd9Sstevel@tonic-gate 			if (_bound) {
3437c478bd9Sstevel@tonic-gate 				/*
3447c478bd9Sstevel@tonic-gate 				 * We know that all data relocations will have
3457c478bd9Sstevel@tonic-gate 				 * been performed at process startup thus clear
3467c478bd9Sstevel@tonic-gate 				 * the relocation record so that it will not be
3477c478bd9Sstevel@tonic-gate 				 * performed again.  However, we don't know what
3487c478bd9Sstevel@tonic-gate 				 * function relocations have been performed
3497c478bd9Sstevel@tonic-gate 				 * because of lazy binding - regardless, we can
3507c478bd9Sstevel@tonic-gate 				 * leave all the function relocation records in
3517c478bd9Sstevel@tonic-gate 				 * place, because if the function has already
3527c478bd9Sstevel@tonic-gate 				 * been bound the record won't be referenced
3537c478bd9Sstevel@tonic-gate 				 * anyway.  In the case of using LD_BIND_NOW,
3547c478bd9Sstevel@tonic-gate 				 * a function may be bound twice - so what.
3557c478bd9Sstevel@tonic-gate 				 */
3567c478bd9Sstevel@tonic-gate 				if (type == M_R_JMP_SLOT) {
3577c478bd9Sstevel@tonic-gate 					reloc->r_flags = FLG_R_INC;
3587c478bd9Sstevel@tonic-gate 					(*func)++;
3597c478bd9Sstevel@tonic-gate 				} else {
3607c478bd9Sstevel@tonic-gate 					if (type != M_R_COPY)
3617c478bd9Sstevel@tonic-gate 						reloc->r_flags = FLG_R_CLR;
3627c478bd9Sstevel@tonic-gate 					(*null)++;
3637c478bd9Sstevel@tonic-gate 				}
3647c478bd9Sstevel@tonic-gate 			} else {
3657c478bd9Sstevel@tonic-gate 				/*
3667c478bd9Sstevel@tonic-gate 				 * Clear any unrequired relocation.
3677c478bd9Sstevel@tonic-gate 				 */
3687c478bd9Sstevel@tonic-gate 				reloc->r_flags = FLG_R_UNDO | FLG_R_INC;
3697c478bd9Sstevel@tonic-gate 				reloc->r_value = addr;
3707c478bd9Sstevel@tonic-gate 				if (type == M_R_JMP_SLOT)
3717c478bd9Sstevel@tonic-gate 					(*func)++;
3727c478bd9Sstevel@tonic-gate 				else
3737c478bd9Sstevel@tonic-gate 					(*data)++;
3747c478bd9Sstevel@tonic-gate 			}
3757c478bd9Sstevel@tonic-gate 		} else {
3767c478bd9Sstevel@tonic-gate 			if (_bound) {
3777c478bd9Sstevel@tonic-gate 				/*
3787c478bd9Sstevel@tonic-gate 				 * Apply the global relocation to the file
3797c478bd9Sstevel@tonic-gate 				 * image.  Clear the relocation record so that
3807c478bd9Sstevel@tonic-gate 				 * it will not be performed again.
3817c478bd9Sstevel@tonic-gate 				 */
3827c478bd9Sstevel@tonic-gate 				if (_weak) {
3837c478bd9Sstevel@tonic-gate 					reloc->r_value = 0;
3847c478bd9Sstevel@tonic-gate 					reloc->r_size = 0;
3857c478bd9Sstevel@tonic-gate 				} else {
3867c478bd9Sstevel@tonic-gate 					reloc->r_value = sym->st_value;
3877c478bd9Sstevel@tonic-gate 					if (IS_PC_RELATIVE(type))
3887c478bd9Sstevel@tonic-gate 						reloc->r_value -= offset;
3897c478bd9Sstevel@tonic-gate 					if ((!(FLAGS(_lmp) & FLG_RT_FIXED)) &&
3907c478bd9Sstevel@tonic-gate 					    (sym->st_shndx != SHN_ABS))
3917c478bd9Sstevel@tonic-gate 						reloc->r_value += ADDR(_lmp);
3927c478bd9Sstevel@tonic-gate 					reloc->r_size = sym->st_size;
3937c478bd9Sstevel@tonic-gate 				}
3947c478bd9Sstevel@tonic-gate 
3957c478bd9Sstevel@tonic-gate 				reloc->r_flags = FLG_R_APPLY | FLG_R_CLR;
3967c478bd9Sstevel@tonic-gate 				reloc->r_name = name;
3977c478bd9Sstevel@tonic-gate 				if (type == M_R_JMP_SLOT)
3987c478bd9Sstevel@tonic-gate 					(*func)++;
3997c478bd9Sstevel@tonic-gate 				else
4007c478bd9Sstevel@tonic-gate 					(*null)++;
4017c478bd9Sstevel@tonic-gate 			} else {
4027c478bd9Sstevel@tonic-gate 				/*
4037c478bd9Sstevel@tonic-gate 				 * Do not apply any unrequired relocations.
4047c478bd9Sstevel@tonic-gate 				 */
4057c478bd9Sstevel@tonic-gate 				reloc->r_flags = FLG_R_INC;
4067c478bd9Sstevel@tonic-gate 				reloc->r_value = addr;
4077c478bd9Sstevel@tonic-gate 				if (type == M_R_JMP_SLOT)
4087c478bd9Sstevel@tonic-gate 					(*func)++;
4097c478bd9Sstevel@tonic-gate 				else
4107c478bd9Sstevel@tonic-gate 					(*data)++;
4117c478bd9Sstevel@tonic-gate 			}
4127c478bd9Sstevel@tonic-gate 		}
4137c478bd9Sstevel@tonic-gate 	}
4147c478bd9Sstevel@tonic-gate 	return (0);
4157c478bd9Sstevel@tonic-gate }
4167c478bd9Sstevel@tonic-gate 
4177c478bd9Sstevel@tonic-gate 
4187c478bd9Sstevel@tonic-gate /*
4197c478bd9Sstevel@tonic-gate  * Perform any relocation updates to the new image using the information from
4207c478bd9Sstevel@tonic-gate  * the `Reloc' structure constructed during count_reloc().
4217c478bd9Sstevel@tonic-gate  */
4227c478bd9Sstevel@tonic-gate void
update_reloc(Cache * ocache,Cache * icache,Cache * _icache,const char * name,Rt_map * lmp,Rel ** null,Rel ** data,Rel ** func)4237c478bd9Sstevel@tonic-gate update_reloc(Cache *ocache, Cache *icache, Cache *_icache, const char *name,
4247c478bd9Sstevel@tonic-gate     Rt_map *lmp, Rel **null, Rel **data, Rel **func)
4257c478bd9Sstevel@tonic-gate {
4267c478bd9Sstevel@tonic-gate 	Shdr	*shdr;
4277c478bd9Sstevel@tonic-gate 	Rel	*rel;
4287c478bd9Sstevel@tonic-gate 	Reloc	*reloc;
4297c478bd9Sstevel@tonic-gate 	Xword	ent, cnt, _cnt;
4307c478bd9Sstevel@tonic-gate 	Cache	*orcache, *ircache = 0;
4317c478bd9Sstevel@tonic-gate 	Half	ndx;
4327c478bd9Sstevel@tonic-gate 
4337c478bd9Sstevel@tonic-gate 	/*
4347c478bd9Sstevel@tonic-gate 	 * Set up to read the output relocation table.
4357c478bd9Sstevel@tonic-gate 	 */
4367c478bd9Sstevel@tonic-gate 	shdr = _icache->c_shdr;
4377c478bd9Sstevel@tonic-gate 	rel = (Rel *)_icache->c_data->d_buf;
4387c478bd9Sstevel@tonic-gate 	reloc = (Reloc *)_icache->c_info;
4397c478bd9Sstevel@tonic-gate 	ent = shdr->sh_entsize;
4407c478bd9Sstevel@tonic-gate 	cnt = shdr->sh_size / ent;
4417c478bd9Sstevel@tonic-gate 
4427c478bd9Sstevel@tonic-gate 	/*
4437c478bd9Sstevel@tonic-gate 	 * Loop through the relocation table.
4447c478bd9Sstevel@tonic-gate 	 */
4457c478bd9Sstevel@tonic-gate 	for (_cnt = 0; _cnt < cnt; _cnt++, reloc++,
4467c478bd9Sstevel@tonic-gate 	    rel = (Rel *)((uintptr_t)rel + ent)) {
4477c478bd9Sstevel@tonic-gate 		uchar_t		*iaddr, *oaddr;
4487c478bd9Sstevel@tonic-gate 		/* LINTED */
449ba2be530Sab 		uchar_t		type = (uchar_t)ELF_R_TYPE(rel->r_info, M_MACH);
4507c478bd9Sstevel@tonic-gate 		Addr		off, bgn, end;
4517c478bd9Sstevel@tonic-gate 
4527c478bd9Sstevel@tonic-gate 		/*
4537c478bd9Sstevel@tonic-gate 		 * Ignore null relocations (these may have been created from a
4547c478bd9Sstevel@tonic-gate 		 * previous dldump() of this image).
4557c478bd9Sstevel@tonic-gate 		 */
4567c478bd9Sstevel@tonic-gate 		if (type == M_R_NONE) {
4577c478bd9Sstevel@tonic-gate 			(*null)++;
4587c478bd9Sstevel@tonic-gate 			continue;
4597c478bd9Sstevel@tonic-gate 		}
4607c478bd9Sstevel@tonic-gate 
4617c478bd9Sstevel@tonic-gate 		/*
4627c478bd9Sstevel@tonic-gate 		 * Determine the section being relocated if we haven't already
4637c478bd9Sstevel@tonic-gate 		 * done so (we may have had to skip over some null relocation to
4647c478bd9Sstevel@tonic-gate 		 * get to the first valid offset).  The System V ABI states that
4657c478bd9Sstevel@tonic-gate 		 * a relocation sections sh_info field indicates the section
4667c478bd9Sstevel@tonic-gate 		 * that must be relocated.  However, on Intel it seems that the
4677c478bd9Sstevel@tonic-gate 		 * .rel.plt sh_info records the section index of the .plt, when
4687c478bd9Sstevel@tonic-gate 		 * in fact it's the .got that gets relocated.  In addition we
4697c478bd9Sstevel@tonic-gate 		 * now create combined relocation sections with -zcomreloc.  To
4707c478bd9Sstevel@tonic-gate 		 * generically be able to cope with these anomalies, search for
4717c478bd9Sstevel@tonic-gate 		 * the appropriate section to be relocated by comparing the
4727c478bd9Sstevel@tonic-gate 		 * offset of the first relocation record against each sections
4737c478bd9Sstevel@tonic-gate 		 * offset and size.
4747c478bd9Sstevel@tonic-gate 		 */
47560758829Srie 		/* BEGIN CSTYLED */
4767c478bd9Sstevel@tonic-gate #if	!defined(__lint)
4777c478bd9Sstevel@tonic-gate 		if ((ircache == (Cache *)0) || (rel->r_offset < bgn) ||
4787c478bd9Sstevel@tonic-gate 			(rel->r_offset > end)) {
4797c478bd9Sstevel@tonic-gate #else
4807c478bd9Sstevel@tonic-gate 		/*
4817c478bd9Sstevel@tonic-gate 		 * lint sees `bgn' and `end' as potentially referenced
4827c478bd9Sstevel@tonic-gate 		 * before being set.
4837c478bd9Sstevel@tonic-gate 		 */
4847c478bd9Sstevel@tonic-gate 		if (ircache == (Cache *)0) {
4857c478bd9Sstevel@tonic-gate #endif
4867c478bd9Sstevel@tonic-gate 			_icache = icache;
4877c478bd9Sstevel@tonic-gate 			_icache++;
4887c478bd9Sstevel@tonic-gate 
4897c478bd9Sstevel@tonic-gate 			for (ndx = 1; _icache->c_flags != FLG_C_END; ndx++,
4907c478bd9Sstevel@tonic-gate 			    _icache++) {
4917c478bd9Sstevel@tonic-gate 
4927c478bd9Sstevel@tonic-gate 				shdr = _icache->c_shdr;
4937c478bd9Sstevel@tonic-gate 				bgn = shdr->sh_addr;
4947c478bd9Sstevel@tonic-gate 				end = bgn + shdr->sh_size;
4957c478bd9Sstevel@tonic-gate 
4967c478bd9Sstevel@tonic-gate 				if ((rel->r_offset >= bgn) &&
4977c478bd9Sstevel@tonic-gate 				    (rel->r_offset <= end))
4987c478bd9Sstevel@tonic-gate 					break;
4997c478bd9Sstevel@tonic-gate 			}
5007c478bd9Sstevel@tonic-gate 			ircache = &icache[ndx];
5017c478bd9Sstevel@tonic-gate 			orcache = &ocache[ndx];
5027c478bd9Sstevel@tonic-gate 		}
50360758829Srie 		/* END CSTYLED */
5047c478bd9Sstevel@tonic-gate 
5057c478bd9Sstevel@tonic-gate 		/*
5067c478bd9Sstevel@tonic-gate 		 * Determine the relocation location of both the input and
5077c478bd9Sstevel@tonic-gate 		 * output data.  Take into account that an input section may be
5087c478bd9Sstevel@tonic-gate 		 * NOBITS (ppc .plt for example).
5097c478bd9Sstevel@tonic-gate 		 */
5107c478bd9Sstevel@tonic-gate 		off = rel->r_offset - ircache->c_shdr->sh_addr;
5117c478bd9Sstevel@tonic-gate 		if (ircache->c_data->d_buf)
5127c478bd9Sstevel@tonic-gate 			iaddr = (uchar_t *)ircache->c_data->d_buf + off;
5137c478bd9Sstevel@tonic-gate 		else
5147c478bd9Sstevel@tonic-gate 			iaddr = 0;
5157c478bd9Sstevel@tonic-gate 		oaddr = (uchar_t *)orcache->c_data->d_buf + off;
5167c478bd9Sstevel@tonic-gate 
5177c478bd9Sstevel@tonic-gate 		/*
5187c478bd9Sstevel@tonic-gate 		 * Apply the relocation to the new output image.  Any base
5197c478bd9Sstevel@tonic-gate 		 * address, or symbol value, will have been saved in the reloc
5207c478bd9Sstevel@tonic-gate 		 * structure during count_reloc().
5217c478bd9Sstevel@tonic-gate 		 */
5227c478bd9Sstevel@tonic-gate 		if (reloc->r_flags & FLG_R_APPLY)
5237c478bd9Sstevel@tonic-gate 			apply_reloc(rel, reloc, name, oaddr, lmp);
5247c478bd9Sstevel@tonic-gate 
5257c478bd9Sstevel@tonic-gate 		/*
5267c478bd9Sstevel@tonic-gate 		 * Undo any relocation that might already been applied to the
5277c478bd9Sstevel@tonic-gate 		 * memory image by the runtime linker.  Using the original
5287c478bd9Sstevel@tonic-gate 		 * file, determine the relocation offset original value and
5297c478bd9Sstevel@tonic-gate 		 * restore the new image to that value.
5307c478bd9Sstevel@tonic-gate 		 */
5317c478bd9Sstevel@tonic-gate 		if ((reloc->r_flags & FLG_R_UNDO) &&
5327c478bd9Sstevel@tonic-gate 		    (FLAGS(lmp) & FLG_RT_RELOCED))
5337c478bd9Sstevel@tonic-gate 			undo_reloc(rel, oaddr, iaddr, reloc);
5347c478bd9Sstevel@tonic-gate 
5357c478bd9Sstevel@tonic-gate 		/*
5367c478bd9Sstevel@tonic-gate 		 * If a relocation has been applied then the relocation record
5377c478bd9Sstevel@tonic-gate 		 * should be cleared so that the relocation isn't applied again
5387c478bd9Sstevel@tonic-gate 		 * when the new image is used.
5397c478bd9Sstevel@tonic-gate 		 */
5407c478bd9Sstevel@tonic-gate 		if (reloc->r_flags & FLG_R_CLR) {
5417c478bd9Sstevel@tonic-gate 			if (type == M_R_JMP_SLOT) {
5427c478bd9Sstevel@tonic-gate 				clear_reloc(*func);
5437c478bd9Sstevel@tonic-gate 				*func = (Rel *)((uintptr_t)*func + ent);
5447c478bd9Sstevel@tonic-gate 			} else {
5457c478bd9Sstevel@tonic-gate 				clear_reloc(*null);
5467c478bd9Sstevel@tonic-gate 				*null = (Rel *)((uintptr_t)*null + ent);
5477c478bd9Sstevel@tonic-gate 			}
5487c478bd9Sstevel@tonic-gate 		}
5497c478bd9Sstevel@tonic-gate 
5507c478bd9Sstevel@tonic-gate 		/*
5517c478bd9Sstevel@tonic-gate 		 * If a relocation isn't applied, update the relocation record
5527c478bd9Sstevel@tonic-gate 		 * to take into account the new address of the image.
5537c478bd9Sstevel@tonic-gate 		 */
5547c478bd9Sstevel@tonic-gate 		if (reloc->r_flags & FLG_R_INC) {
5557c478bd9Sstevel@tonic-gate 			if (type == M_R_JMP_SLOT) {
5567c478bd9Sstevel@tonic-gate 				inc_reloc(*func, rel, reloc, oaddr, iaddr);
5577c478bd9Sstevel@tonic-gate 				*func = (Rel *)((uintptr_t)*func + ent);
5587c478bd9Sstevel@tonic-gate 			} else {
5597c478bd9Sstevel@tonic-gate 				inc_reloc(*data, rel, reloc, oaddr, iaddr);
5607c478bd9Sstevel@tonic-gate 				*data = (Rel *)((uintptr_t)*data + ent);
5617c478bd9Sstevel@tonic-gate 			}
5627c478bd9Sstevel@tonic-gate 		}
5637c478bd9Sstevel@tonic-gate 	}
5647c478bd9Sstevel@tonic-gate }
565