dynamic.c revision 2766:897bcb036a29
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 2006 Sun Microsystems, Inc.  All rights reserved.
24 * Use is subject to license terms.
25 *
26 * Update any dynamic entry offsets.  One issue with dynamic entries is that
27 * you only know whether they refer to a value or an offset if you know each
28 * type.  Thus we check for all types we know about, it a type is found that
29 * we don't know about then return and error as we have no idea what to do.
30 */
31#pragma ident	"%Z%%M%	%I%	%E% SMI"
32
33#include	<libelf.h>
34#include	<link.h>
35#include	"libld.h"
36#include	"msg.h"
37#include	"rtld.h"
38#include	"_librtld.h"
39
40int
41update_dynamic(Cache *cache, Cache *_cache, Rt_map *lmp, int flags,
42    Addr addr, Off off, const char *file, Xword null, Xword data, Xword func,
43    Xword entsize, Xword checksum)
44{
45	Dyn		*dyn = (Dyn *)_cache->c_data->d_buf, *posdyn = 0;
46	const char	*strs;
47	Cache		*__cache;
48
49	/*
50	 * If we're dealing with an object that might have bound to an external
51	 * dependency establish our string table for possible NEEDED processing.
52	 */
53	if (flags & RTLD_REL_DEPENDS) {
54		__cache = &cache[_cache->c_shdr->sh_link];
55		strs = (const char *)__cache->c_data->d_buf;
56	}
57
58	/*
59	 * Loop through the dynamic table updating all offsets.
60	 */
61	while (dyn->d_tag != DT_NULL) {
62		switch ((Xword)dyn->d_tag) {
63		case DT_NEEDED:
64			if (posdyn) {
65				Rt_map	*dlmp;
66
67				/*
68				 * Determine whether this dependency has been
69				 * loaded (this is the most generic way to check
70				 * any alias names), and if it has been bound
71				 * to, undo any lazy-loading position flag.
72				 */
73				if (dlmp = is_so_loaded(LIST(lmp),
74				    (strs + dyn->d_un.d_val), 1)) {
75					Bnd_desc **	bdpp;
76					Aliste		off;
77
78					for (ALIST_TRAVERSE(DEPENDS(lmp), off,
79					    bdpp)) {
80						if (dlmp == (*bdpp)->b_depend) {
81						    posdyn->d_un.d_val &=
82							~DF_P1_LAZYLOAD;
83						    break;
84						}
85					}
86				}
87			}
88			break;
89
90		case DT_RELAENT:
91		case DT_STRSZ:
92		case DT_SYMENT:
93		case DT_SONAME:
94		case DT_RPATH:
95		case DT_SYMBOLIC:
96		case DT_RELENT:
97		case DT_PLTREL:
98		case DT_TEXTREL:
99		case DT_VERDEFNUM:
100		case DT_VERNEEDNUM:
101		case DT_AUXILIARY:
102		case DT_USED:
103		case DT_FILTER:
104		case DT_DEPRECATED_SPARC_REGISTER:
105		case M_DT_REGISTER:
106		case DT_BIND_NOW:
107		case DT_INIT_ARRAYSZ:
108		case DT_FINI_ARRAYSZ:
109		case DT_RUNPATH:
110		case DT_FLAGS:
111		case DT_CONFIG:
112		case DT_DEPAUDIT:
113		case DT_AUDIT:
114		case DT_SUNW_SYMSZ:
115			break;
116		case DT_PLTGOT:
117		case DT_HASH:
118		case DT_STRTAB:
119		case DT_SYMTAB:
120		case DT_SUNW_SYMTAB:
121		case DT_INIT:
122		case DT_FINI:
123		case DT_VERSYM:
124		case DT_VERDEF:
125		case DT_VERNEED:
126		case DT_INIT_ARRAY:
127		case DT_FINI_ARRAY:
128			dyn->d_un.d_ptr += addr;
129			break;
130
131		/*
132		 * If the memory image is being used, this element would have
133		 * been initialized to the runtime linkers internal link-map
134		 * list.  Clear it.
135		 */
136		case DT_DEBUG:
137			dyn->d_un.d_val = 0;
138			break;
139
140		/*
141		 * The number of relocations may have been reduced if
142		 * relocations have been saved in the new image.  Thus we
143		 * compute the new relocation size and start.
144		 */
145		case DT_RELASZ:
146		case DT_RELSZ:
147			dyn->d_un.d_val = ((data + func) * entsize);
148			break;
149
150		case DT_RELA:
151		case DT_REL:
152			dyn->d_un.d_ptr = (addr + off + (null * entsize));
153			break;
154
155		/*
156		 * If relative relocations have been processed clear the count.
157		 */
158		case DT_RELACOUNT:
159		case DT_RELCOUNT:
160			if (flags & RTLD_REL_RELATIVE)
161				dyn->d_un.d_val = 0;
162			break;
163
164		case DT_PLTRELSZ:
165			dyn->d_un.d_val = (func * entsize);
166			break;
167
168		case DT_JMPREL:
169			dyn->d_un.d_ptr = (addr + off +
170				((null + data) * entsize));
171			break;
172
173		/*
174		 * Recompute the images elf checksum.
175		 */
176		case DT_CHECKSUM:
177			dyn->d_un.d_val = checksum;
178			break;
179
180		/*
181		 * If a flag entry is available, indicate if this image has
182		 * been generated via the configuration process (crle(1)).
183		 * Because we only started depositing DT_FLAGS_1 entries in all
184		 * objects starting with Solaris 8, set a feature flag if it
185		 * is present (these got added in Solaris 7).
186		 * The runtime linker may use this flag to search for a local
187		 * configuration file - this is only meaningful in executables
188		 * but the flag has value for identifying images regardless.
189		 *
190		 * If this file is acting as a filter, and dependency
191		 * relocations have been processed (a filter is thought of as a
192		 * dependency in terms of symbol binding), we may have bound to
193		 * the filtee, and hence carried out the relocation.  Indicate
194		 * that the filtee must be preloaded, as the .plt won't get
195		 * exercised to cause its normal loading.
196		 */
197		case DT_FLAGS_1:
198			if (flags & RTLD_CONFSET)
199				dyn->d_un.d_val |= DF_1_CONFALT;
200			if ((flags & RTLD_REL_DEPENDS) &&
201			    (FLAGS1(lmp)) & MSK_RT_FILTER)
202				dyn->d_un.d_val |= DF_1_LOADFLTR;
203			break;
204
205		case DT_FEATURE_1:
206			if (flags & RTLD_CONFSET)
207				dyn->d_un.d_val |= DTF_1_CONFEXP;
208			break;
209
210		/*
211		 * If a position flag is available save it for possible update
212		 * when processing the next NEEDED tag.
213		 */
214		case DT_POSFLAG_1:
215			if (flags & RTLD_REL_DEPENDS) {
216				posdyn = dyn++;
217				continue;
218			}
219			break;
220
221		/*
222		 * Collect the defaults.
223		 */
224		default:
225			/*
226			 * If d_val is used, don't touch.
227			 */
228			if ((dyn->d_tag >= DT_VALRNGLO) &&
229			    (dyn->d_tag <= DT_VALRNGHI))
230				break;
231
232			/*
233			 * If d_ptr is used, adjust.  Note, some entries that
234			 * fell into this range are offsets into the dynamic
235			 * string table.  Although these would need modifying
236			 * if the section itself were resized, there is no
237			 * resizing with dldump().  Entries that correspond to
238			 * offsets are picked off in the initial DT_ loop
239			 * above.
240			 */
241			if ((dyn->d_tag >= DT_ADDRRNGLO) &&
242			    (dyn->d_tag <= DT_ADDRRNGHI)) {
243				dyn->d_un.d_ptr += addr;
244				break;
245			}
246
247			/*
248			 * Check to see if this DT_ entry conforms
249			 * to the DT_ENCODING rules.
250			 */
251			if ((dyn->d_tag >= DT_ENCODING) &&
252			    (dyn->d_tag <= DT_HIOS)) {
253				/*
254				 * Even tag values are ADDRESS encodings
255				 */
256				if ((dyn->d_tag % 2) == 0) {
257					dyn->d_un.d_ptr += addr;
258				}
259				break;
260			}
261			eprintf(LIST(lmp), ERR_WARNING,
262			    MSG_INTL(MSG_DT_UNKNOWN), file,
263			    EC_XWORD(dyn->d_tag));
264			return (1);
265		}
266		posdyn = 0;
267		dyn++;
268	}
269	return (0);
270}
271