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
update_dynamic(Cache * cache,Cache * _cache,Rt_map * lmp,int flags,Addr addr,Off off,const char * file,Xword null,Xword data,Xword func,Xword entsize,Xword checksum)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