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