xref: /titanic_44/usr/src/cmd/sgs/librtld/common/relocate.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 #include	<libelf.h>
29 #include	<dlfcn.h>
30 #include	"machdep.h"
31 #include	"reloc.h"
32 #include	"msg.h"
33 #include	"_librtld.h"
34 
35 static const char	*unknown = 0;	/* Stash MSG_INTL(MSG_STR_UNKNOWN) */
36 
37 /*
38  * Process all relocation records.  A new `Reloc' structure is allocated to
39  * cache the processing decisions deduced, and these will be applied during
40  * update_reloc().
41  * A count of the number of null relocations (i.e., relocations that will be
42  * fixed and whoes records will be nulled out), data and function relocations
43  * is maintained.  This allows the relocation records themselves to be
44  * rearranged (localized) later if necessary.  Note that the number of function
45  * relocations, although coounted, shouldn't differ from the original file,
46  * the index of a .plt must be maintained to the index of its relocation record
47  * within the associated relocation section.
48  *
49  * The intention behind this file is to maintain as much relocation logic as
50  * possible in a generic form.
51  */
52 int
53 count_reloc(Cache *cache, Cache *_cache, Rt_map *lmp, int flags, Addr addr,
54     Xword *null, Xword *data, Xword *func)
55 {
56 	Rel		*rel;
57 	Reloc		*reloc;
58 	Shdr		*shdr;
59 	Xword		ent, cnt, _cnt;
60 	Sym		*syms;
61 	const char	*strs;
62 	Cache		*__cache;
63 	Xword		pltndx = 0;
64 
65 	/*
66 	 * Determine the number of relocation entries we'll be dealing with.
67 	 */
68 	shdr = _cache->c_shdr;
69 	rel = (Rel *)_cache->c_data->d_buf;
70 	ent = shdr->sh_entsize;
71 	cnt = shdr->sh_size / ent;
72 
73 	/*
74 	 * Allocate a relocation structure for this relocation section.
75 	 */
76 	if ((reloc = calloc(cnt, sizeof (Reloc))) == 0)
77 		return (1);
78 	_cache->c_info = (void *)reloc;
79 
80 	/*
81 	 * Determine the relocations associated symbol and string table.
82 	 */
83 	__cache = &cache[shdr->sh_link];
84 	syms = (Sym *)__cache->c_data->d_buf;
85 	shdr = __cache->c_shdr;
86 	__cache = &cache[shdr->sh_link];
87 	strs = (const char *)__cache->c_data->d_buf;
88 
89 	/*
90 	 * Loop through the relocation table.
91 	 */
92 	for (_cnt = 0; _cnt < cnt; _cnt++, reloc++,
93 	    rel = (Rel *)((uintptr_t)rel + ent)) {
94 		const char	*name;
95 		/* LINTED */
96 		uchar_t		type = (uchar_t)ELF_R_TYPE(rel->r_info);
97 		uchar_t		bind;
98 		ulong_t		offset = rel->r_offset + addr;
99 		Rt_map		*_lmp;
100 		int		_bound, _weak;
101 		ulong_t		rsymndx = ELF_R_SYM(rel->r_info);
102 		Slookup		sl;
103 		uint_t		binfo;
104 		Sym		*_sym, *sym = (syms + rsymndx);
105 
106 		if (type == M_R_JMP_SLOT)
107 			reloc->r_pltndx = ++pltndx;
108 
109 		/*
110 		 * Analyze the case where no relocations are to be applied.
111 		 */
112 		if ((flags & RTLD_REL_ALL) == 0) {
113 			/*
114 			 * Don't apply any relocations to the new image but
115 			 * insure their offsets are incremented to reflect any
116 			 * new fixed address.
117 			 */
118 			reloc->r_flags = FLG_R_INC;
119 
120 			/*
121 			 * Undo any relocations that might have already been
122 			 * applied to the memory image.
123 			 */
124 			if (flags & RTLD_MEMORY) {
125 				reloc->r_flags |= FLG_R_UNDO;
126 
127 				/*
128 				 * If a copy relocation is involved we'll need
129 				 * to know the size of the copy.
130 				 */
131 				if (type == M_R_COPY)
132 					reloc->r_size = sym->st_size;
133 				else
134 					reloc->r_size = 0;
135 			}
136 
137 			/*
138 			 * Save the objects new address.
139 			 */
140 			reloc->r_value = addr;
141 
142 			if (type == M_R_JMP_SLOT)
143 				(*func)++;
144 			else
145 				(*data)++;
146 			continue;
147 		}
148 
149 		/*
150 		 * Determine the symbol binding of the relocation. Don't assume
151 		 * that relative relocations are simply M_R_RELATIVE.  Although
152 		 * a pic generated shared object can normally be viewed as
153 		 * having relative and non-relative relocations, a non-pic
154 		 * shared object will contain a number of relocations against
155 		 * local symbols (normally sections).  If a relocation is
156 		 * against a local symbol it qualifies as a relative relocation.
157 		 */
158 		if ((type == M_R_RELATIVE) || (type == M_R_NONE) ||
159 		    (ELF_ST_BIND(sym->st_info) == STB_LOCAL))
160 			bind = STB_LOCAL;
161 		else
162 			bind = STB_GLOBAL;
163 
164 		/*
165 		 * Analyze the case where only relative relocations are to be
166 		 * applied.
167 		 */
168 		if ((flags & RTLD_REL_ALL) == RTLD_REL_RELATIVE) {
169 			if (flags & RTLD_MEMORY) {
170 				if (bind == STB_LOCAL) {
171 					/*
172 					 * Save the relative relocations from
173 					 * the memory image.  The data itself
174 					 * might already have been relocated,
175 					 * thus clear the relocation record so
176 					 * that it will not be performed again.
177 					 */
178 					reloc->r_flags = FLG_R_CLR;
179 					(*null)++;
180 				} else {
181 					/*
182 					 * Any non-relative relocation must be
183 					 * undone, and the relocation records
184 					 * offset updated to any new fixed
185 					 * address.
186 					 */
187 					reloc->r_flags =
188 					    (FLG_R_UNDO | FLG_R_INC);
189 					reloc->r_value = addr;
190 					if (type == M_R_JMP_SLOT)
191 						(*func)++;
192 					else
193 						(*data)++;
194 				}
195 			} else {
196 				if (bind == STB_LOCAL) {
197 					/*
198 					 * Apply relative relocation to the
199 					 * file image.  Clear the relocation
200 					 * record so that it will not be
201 					 * performed again.
202 					 */
203 					reloc->r_flags =
204 					    (FLG_R_APPLY | FLG_R_CLR);
205 					reloc->r_value = addr;
206 					if (IS_PC_RELATIVE(type))
207 						reloc->r_value -= offset;
208 
209 					if (unknown == 0)
210 					    unknown = MSG_INTL(MSG_STR_UNKNOWN);
211 					reloc->r_name = unknown;
212 					(*null)++;
213 				} else {
214 					/*
215 					 * Any non-relative relocation should be
216 					 * left alone, but its offset should be
217 					 * updated to any new fixed address.
218 					 */
219 					reloc->r_flags = FLG_R_INC;
220 					reloc->r_value = addr;
221 					if (type == M_R_JMP_SLOT)
222 						(*func)++;
223 					else
224 						(*data)++;
225 				}
226 			}
227 			continue;
228 		}
229 
230 		/*
231 		 * Analyze the case where more than just relative relocations
232 		 * are to be applied.
233 		 */
234 		if (bind == STB_LOCAL) {
235 			if (flags & RTLD_MEMORY) {
236 				/*
237 				 * Save the relative relocations from the memory
238 				 * image.  The data itself has already been
239 				 * relocated, thus clear the relocation record
240 				 * so that it will not be performed again.
241 				 */
242 				reloc->r_flags = FLG_R_CLR;
243 			} else {
244 				/*
245 				 * Apply relative relocation to the file image.
246 				 * Clear the relocation record so that it will
247 				 * not be performed again.
248 				 */
249 				reloc->r_flags = (FLG_R_APPLY | FLG_R_CLR);
250 				reloc->r_value = addr;
251 				if (IS_PC_RELATIVE(type))
252 					reloc->r_value -= offset;
253 
254 				if (unknown == 0)
255 					unknown = MSG_INTL(MSG_STR_UNKNOWN);
256 				reloc->r_name = unknown;
257 			}
258 			(*null)++;
259 			continue;
260 		}
261 
262 		/*
263 		 * At this point we're dealing with a non-relative relocation
264 		 * that requires the symbol definition.
265 		 */
266 		name = strs + sym->st_name;
267 
268 		/*
269 		 * Find the symbol.  As the object being investigated is already
270 		 * a part of this process, the symbol lookup will likely
271 		 * succeed.  However, because of lazy binding, there is still
272 		 * the possibility of a dangling .plt relocation.  dldump()
273 		 * users might be encouraged to set LD_FLAGS=loadavail (crle(1)
274 		 * does this for them).
275 		 */
276 		sl.sl_name = name;
277 		sl.sl_cmap = lmp;
278 		sl.sl_imap = LIST(lmp)->lm_head;
279 		sl.sl_hash = 0;
280 		sl.sl_rsymndx = rsymndx;
281 
282 		if (type == M_R_COPY)
283 			sl.sl_flags = LKUP_COPY;
284 		else
285 			sl.sl_flags = LKUP_DEFT;
286 
287 		_bound = _weak = 0;
288 		_sym = sym;
289 		if ((sym = lookup_sym(&sl, &_lmp, &binfo)) != 0) {
290 			/*
291 			 * Determine from the various relocation requirements
292 			 * whether this binding is appropriate.  If we're called
293 			 * from crle(1), RTLD_CONFSET is set, then only inspect
294 			 * objects selected from the configuration file
295 			 * (FL1_RT_CONFSET was set during load()).
296 			 */
297 			if (!(flags & RTLD_CONFSET) ||
298 			    (FLAGS1(_lmp) & FL1_RT_CONFSET)) {
299 				if (((flags & RTLD_REL_ALL) == RTLD_REL_ALL) ||
300 				    ((flags & RTLD_REL_EXEC) &&
301 				    (FLAGS(_lmp) & FLG_RT_ISMAIN)) ||
302 				    ((flags & RTLD_REL_DEPENDS) &&
303 				    (!(FLAGS(_lmp) & FLG_RT_ISMAIN))) ||
304 				    ((flags & RTLD_REL_PRELOAD) &&
305 				    (FLAGS(_lmp) & FLG_RT_PRELOAD)) ||
306 				    ((flags & RTLD_REL_SELF) && (lmp == _lmp)))
307 					_bound = 1;
308 			}
309 		} else {
310 			/*
311 			 * If this is a weak reference and we've been asked to
312 			 * bind unresolved weak references consider ourself
313 			 * bound.  This category is typically set by clre(1) for
314 			 * an application cache.
315 			 */
316 			if ((ELF_ST_BIND(_sym->st_info) == STB_WEAK) &&
317 			    (_sym->st_shndx == SHN_UNDEF) &&
318 			    (flags & RTLD_REL_WEAK))
319 				_bound = _weak = 1;
320 		}
321 
322 		if (flags & RTLD_MEMORY) {
323 			if (_bound) {
324 				/*
325 				 * We know that all data relocations will have
326 				 * been performed at process startup thus clear
327 				 * the relocation record so that it will not be
328 				 * performed again.  However, we don't know what
329 				 * function relocations have been performed
330 				 * because of lazy binding - regardless, we can
331 				 * leave all the function relocation records in
332 				 * place, because if the function has already
333 				 * been bound the record won't be referenced
334 				 * anyway.  In the case of using LD_BIND_NOW,
335 				 * a function may be bound twice - so what.
336 				 */
337 				if (type == M_R_JMP_SLOT) {
338 					reloc->r_flags = FLG_R_INC;
339 					(*func)++;
340 				} else {
341 					if (type != M_R_COPY)
342 						reloc->r_flags = FLG_R_CLR;
343 					(*null)++;
344 				}
345 			} else {
346 				/*
347 				 * Clear any unrequired relocation.
348 				 */
349 				reloc->r_flags = FLG_R_UNDO | FLG_R_INC;
350 				reloc->r_value = addr;
351 				if (type == M_R_JMP_SLOT)
352 					(*func)++;
353 				else
354 					(*data)++;
355 			}
356 		} else {
357 			if (_bound) {
358 				/*
359 				 * Apply the global relocation to the file
360 				 * image.  Clear the relocation record so that
361 				 * it will not be performed again.
362 				 */
363 				if (_weak) {
364 					reloc->r_value = 0;
365 					reloc->r_size = 0;
366 				} else {
367 					reloc->r_value = sym->st_value;
368 					if (IS_PC_RELATIVE(type))
369 						reloc->r_value -= offset;
370 					if ((!(FLAGS(_lmp) & FLG_RT_FIXED)) &&
371 					    (sym->st_shndx != SHN_ABS))
372 						reloc->r_value += ADDR(_lmp);
373 					reloc->r_size = sym->st_size;
374 				}
375 
376 				reloc->r_flags = FLG_R_APPLY | FLG_R_CLR;
377 				reloc->r_name = name;
378 				if (type == M_R_JMP_SLOT)
379 					(*func)++;
380 				else
381 					(*null)++;
382 			} else {
383 				/*
384 				 * Do not apply any unrequired relocations.
385 				 */
386 				reloc->r_flags = FLG_R_INC;
387 				reloc->r_value = addr;
388 				if (type == M_R_JMP_SLOT)
389 					(*func)++;
390 				else
391 					(*data)++;
392 			}
393 		}
394 	}
395 	return (0);
396 }
397 
398 
399 /*
400  * Perform any relocation updates to the new image using the information from
401  * the `Reloc' structure constructed during count_reloc().
402  */
403 void
404 update_reloc(Cache *ocache, Cache *icache, Cache *_icache, const char *name,
405     Rt_map *lmp, Rel **null, Rel **data, Rel **func)
406 {
407 	Shdr	*shdr;
408 	Rel	*rel;
409 	Reloc	*reloc;
410 	Xword	ent, cnt, _cnt;
411 	Cache	*orcache, *ircache = 0;
412 	Half	ndx;
413 
414 	/*
415 	 * Set up to read the output relocation table.
416 	 */
417 	shdr = _icache->c_shdr;
418 	rel = (Rel *)_icache->c_data->d_buf;
419 	reloc = (Reloc *)_icache->c_info;
420 	ent = shdr->sh_entsize;
421 	cnt = shdr->sh_size / ent;
422 
423 	/*
424 	 * Loop through the relocation table.
425 	 */
426 	for (_cnt = 0; _cnt < cnt; _cnt++, reloc++,
427 	    rel = (Rel *)((uintptr_t)rel + ent)) {
428 		uchar_t		*iaddr, *oaddr;
429 		/* LINTED */
430 		uchar_t		type = (uchar_t)ELF_R_TYPE(rel->r_info);
431 		Addr		off, bgn, end;
432 
433 		/*
434 		 * Ignore null relocations (these may have been created from a
435 		 * previous dldump() of this image).
436 		 */
437 		if (type == M_R_NONE) {
438 			(*null)++;
439 			continue;
440 		}
441 
442 		/*
443 		 * Determine the section being relocated if we haven't already
444 		 * done so (we may have had to skip over some null relocation to
445 		 * get to the first valid offset).  The System V ABI states that
446 		 * a relocation sections sh_info field indicates the section
447 		 * that must be relocated.  However, on Intel it seems that the
448 		 * .rel.plt sh_info records the section index of the .plt, when
449 		 * in fact it's the .got that gets relocated.  In addition we
450 		 * now create combined relocation sections with -zcomreloc.  To
451 		 * generically be able to cope with these anomalies, search for
452 		 * the appropriate section to be relocated by comparing the
453 		 * offset of the first relocation record against each sections
454 		 * offset and size.
455 		 */
456 #if	!defined(__lint)
457 		if ((ircache == (Cache *)0) || (rel->r_offset < bgn) ||
458 			(rel->r_offset > end)) {
459 #else
460 		/*
461 		 * lint sees `bgn' and `end' as potentially referenced
462 		 * before being set.
463 		 */
464 		if (ircache == (Cache *)0) {
465 #endif
466 			_icache = icache;
467 			_icache++;
468 
469 			for (ndx = 1; _icache->c_flags != FLG_C_END; ndx++,
470 			    _icache++) {
471 
472 				shdr = _icache->c_shdr;
473 				bgn = shdr->sh_addr;
474 				end = bgn + shdr->sh_size;
475 
476 				if ((rel->r_offset >= bgn) &&
477 				    (rel->r_offset <= end))
478 					break;
479 			}
480 			ircache = &icache[ndx];
481 			orcache = &ocache[ndx];
482 		}
483 
484 		/*
485 		 * Determine the relocation location of both the input and
486 		 * output data.  Take into account that an input section may be
487 		 * NOBITS (ppc .plt for example).
488 		 */
489 		off = rel->r_offset - ircache->c_shdr->sh_addr;
490 		if (ircache->c_data->d_buf)
491 			iaddr = (uchar_t *)ircache->c_data->d_buf + off;
492 		else
493 			iaddr = 0;
494 		oaddr = (uchar_t *)orcache->c_data->d_buf + off;
495 
496 		/*
497 		 * Apply the relocation to the new output image.  Any base
498 		 * address, or symbol value, will have been saved in the reloc
499 		 * structure during count_reloc().
500 		 */
501 		if (reloc->r_flags & FLG_R_APPLY)
502 			apply_reloc(rel, reloc, name, oaddr, lmp);
503 
504 		/*
505 		 * Undo any relocation that might already been applied to the
506 		 * memory image by the runtime linker.  Using the original
507 		 * file, determine the relocation offset original value and
508 		 * restore the new image to that value.
509 		 */
510 		if ((reloc->r_flags & FLG_R_UNDO) &&
511 		    (FLAGS(lmp) & FLG_RT_RELOCED))
512 			undo_reloc(rel, oaddr, iaddr, reloc);
513 
514 		/*
515 		 * If a relocation has been applied then the relocation record
516 		 * should be cleared so that the relocation isn't applied again
517 		 * when the new image is used.
518 		 */
519 		if (reloc->r_flags & FLG_R_CLR) {
520 			if (type == M_R_JMP_SLOT) {
521 				clear_reloc(*func);
522 				*func = (Rel *)((uintptr_t)*func + ent);
523 			} else {
524 				clear_reloc(*null);
525 				*null = (Rel *)((uintptr_t)*null + ent);
526 			}
527 		}
528 
529 		/*
530 		 * If a relocation isn't applied, update the relocation record
531 		 * to take into account the new address of the image.
532 		 */
533 		if (reloc->r_flags & FLG_R_INC) {
534 			if (type == M_R_JMP_SLOT) {
535 				inc_reloc(*func, rel, reloc, oaddr, iaddr);
536 				*func = (Rel *)((uintptr_t)*func + ent);
537 			} else {
538 				inc_reloc(*data, rel, reloc, oaddr, iaddr);
539 				*data = (Rel *)((uintptr_t)*data + ent);
540 			}
541 		}
542 	}
543 }
544