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