xref: /illumos-gate/usr/src/cmd/sgs/librtld/common/dynamic.c (revision 2e0fe3efe5f9d579d4e44b3532d8e342c68b40ca)
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 
38 int
39 update_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