relocate.c revision 11827:d7ef53deac3f
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 2010 Sun Microsystems, Inc.  All rights reserved.
24 * Use is subject to license terms.
25 */
26
27#include	<libelf.h>
28#include	<dlfcn.h>
29#include	"machdep.h"
30#include	"reloc.h"
31#include	"msg.h"
32#include	"_librtld.h"
33#include	"alist.h"
34
35static 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 */
52int
53count_reloc(Cache *cache, Cache *_cache, Rt_map *lmp, int flags, Addr addr,
54    Xword *null, Xword *data, Xword *func, Alist *nodirect)
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, M_MACH);
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		Sresult		sr;
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		 * Initialize the symbol lookup, and symbol result, data
279		 * structures.
280		 */
281		SLOOKUP_INIT(sl, name, lmp, LIST(lmp)->lm_head, ld_entry_cnt,
282		    0, rsymndx, sym, type, LKUP_STDRELOC);
283		SRESULT_INIT(sr, name);
284
285		_bound = _weak = 0;
286		_sym = sym;
287		if (lookup_sym(&sl, &sr, &binfo, NULL)) {
288			_lmp = sr.sr_dmap;
289			sym = sr.sr_sym;
290
291			/*
292			 * Determine from the various relocation requirements
293			 * whether this binding is appropriate.  If we're called
294			 * from crle(1), RTLD_CONFSET is set, then only inspect
295			 * objects selected from the configuration file
296			 * (FL1_RT_CONFSET was set during load()).
297			 */
298			if (!(flags & RTLD_CONFSET) ||
299			    (FLAGS1(_lmp) & FL1_RT_CONFSET)) {
300				if (((flags & RTLD_REL_ALL) == RTLD_REL_ALL) ||
301				    ((flags & RTLD_REL_EXEC) &&
302				    (FLAGS(_lmp) & FLG_RT_ISMAIN)) ||
303				    ((flags & RTLD_REL_DEPENDS) &&
304				    (!(FLAGS(_lmp) & FLG_RT_ISMAIN))) ||
305				    ((flags & RTLD_REL_PRELOAD) &&
306				    (FLAGS(_lmp) & FLG_RT_PRELOAD)) ||
307				    ((flags & RTLD_REL_SELF) &&
308				    (lmp == _lmp))) {
309					Aliste	idx;
310					Word	*ndx;
311
312					_bound = 1;
313
314					/*
315					 * If this symbol is explicitly defined
316					 * as nodirect, don't allow any local
317					 * binding.
318					 */
319					for (ALIST_TRAVERSE(nodirect, idx,
320					    ndx)) {
321						if (*ndx == rsymndx) {
322							_bound = 0;
323							break;
324						}
325					}
326				}
327			}
328		} else {
329			/*
330			 * If this is a weak reference and we've been asked to
331			 * bind unresolved weak references consider ourself
332			 * bound.  This category is typically set by clre(1) for
333			 * an application cache.
334			 */
335			if ((ELF_ST_BIND(_sym->st_info) == STB_WEAK) &&
336			    (_sym->st_shndx == SHN_UNDEF) &&
337			    (flags & RTLD_REL_WEAK))
338				_bound = _weak = 1;
339		}
340
341		if (flags & RTLD_MEMORY) {
342			if (_bound) {
343				/*
344				 * We know that all data relocations will have
345				 * been performed at process startup thus clear
346				 * the relocation record so that it will not be
347				 * performed again.  However, we don't know what
348				 * function relocations have been performed
349				 * because of lazy binding - regardless, we can
350				 * leave all the function relocation records in
351				 * place, because if the function has already
352				 * been bound the record won't be referenced
353				 * anyway.  In the case of using LD_BIND_NOW,
354				 * a function may be bound twice - so what.
355				 */
356				if (type == M_R_JMP_SLOT) {
357					reloc->r_flags = FLG_R_INC;
358					(*func)++;
359				} else {
360					if (type != M_R_COPY)
361						reloc->r_flags = FLG_R_CLR;
362					(*null)++;
363				}
364			} else {
365				/*
366				 * Clear any unrequired relocation.
367				 */
368				reloc->r_flags = FLG_R_UNDO | FLG_R_INC;
369				reloc->r_value = addr;
370				if (type == M_R_JMP_SLOT)
371					(*func)++;
372				else
373					(*data)++;
374			}
375		} else {
376			if (_bound) {
377				/*
378				 * Apply the global relocation to the file
379				 * image.  Clear the relocation record so that
380				 * it will not be performed again.
381				 */
382				if (_weak) {
383					reloc->r_value = 0;
384					reloc->r_size = 0;
385				} else {
386					reloc->r_value = sym->st_value;
387					if (IS_PC_RELATIVE(type))
388						reloc->r_value -= offset;
389					if ((!(FLAGS(_lmp) & FLG_RT_FIXED)) &&
390					    (sym->st_shndx != SHN_ABS))
391						reloc->r_value += ADDR(_lmp);
392					reloc->r_size = sym->st_size;
393				}
394
395				reloc->r_flags = FLG_R_APPLY | FLG_R_CLR;
396				reloc->r_name = name;
397				if (type == M_R_JMP_SLOT)
398					(*func)++;
399				else
400					(*null)++;
401			} else {
402				/*
403				 * Do not apply any unrequired relocations.
404				 */
405				reloc->r_flags = FLG_R_INC;
406				reloc->r_value = addr;
407				if (type == M_R_JMP_SLOT)
408					(*func)++;
409				else
410					(*data)++;
411			}
412		}
413	}
414	return (0);
415}
416
417
418/*
419 * Perform any relocation updates to the new image using the information from
420 * the `Reloc' structure constructed during count_reloc().
421 */
422void
423update_reloc(Cache *ocache, Cache *icache, Cache *_icache, const char *name,
424    Rt_map *lmp, Rel **null, Rel **data, Rel **func)
425{
426	Shdr	*shdr;
427	Rel	*rel;
428	Reloc	*reloc;
429	Xword	ent, cnt, _cnt;
430	Cache	*orcache, *ircache = 0;
431	Half	ndx;
432
433	/*
434	 * Set up to read the output relocation table.
435	 */
436	shdr = _icache->c_shdr;
437	rel = (Rel *)_icache->c_data->d_buf;
438	reloc = (Reloc *)_icache->c_info;
439	ent = shdr->sh_entsize;
440	cnt = shdr->sh_size / ent;
441
442	/*
443	 * Loop through the relocation table.
444	 */
445	for (_cnt = 0; _cnt < cnt; _cnt++, reloc++,
446	    rel = (Rel *)((uintptr_t)rel + ent)) {
447		uchar_t		*iaddr, *oaddr;
448		/* LINTED */
449		uchar_t		type = (uchar_t)ELF_R_TYPE(rel->r_info, M_MACH);
450		Addr		off, bgn, end;
451
452		/*
453		 * Ignore null relocations (these may have been created from a
454		 * previous dldump() of this image).
455		 */
456		if (type == M_R_NONE) {
457			(*null)++;
458			continue;
459		}
460
461		/*
462		 * Determine the section being relocated if we haven't already
463		 * done so (we may have had to skip over some null relocation to
464		 * get to the first valid offset).  The System V ABI states that
465		 * a relocation sections sh_info field indicates the section
466		 * that must be relocated.  However, on Intel it seems that the
467		 * .rel.plt sh_info records the section index of the .plt, when
468		 * in fact it's the .got that gets relocated.  In addition we
469		 * now create combined relocation sections with -zcomreloc.  To
470		 * generically be able to cope with these anomalies, search for
471		 * the appropriate section to be relocated by comparing the
472		 * offset of the first relocation record against each sections
473		 * offset and size.
474		 */
475		/* BEGIN CSTYLED */
476#if	!defined(__lint)
477		if ((ircache == (Cache *)0) || (rel->r_offset < bgn) ||
478			(rel->r_offset > end)) {
479#else
480		/*
481		 * lint sees `bgn' and `end' as potentially referenced
482		 * before being set.
483		 */
484		if (ircache == (Cache *)0) {
485#endif
486			_icache = icache;
487			_icache++;
488
489			for (ndx = 1; _icache->c_flags != FLG_C_END; ndx++,
490			    _icache++) {
491
492				shdr = _icache->c_shdr;
493				bgn = shdr->sh_addr;
494				end = bgn + shdr->sh_size;
495
496				if ((rel->r_offset >= bgn) &&
497				    (rel->r_offset <= end))
498					break;
499			}
500			ircache = &icache[ndx];
501			orcache = &ocache[ndx];
502		}
503		/* END CSTYLED */
504
505		/*
506		 * Determine the relocation location of both the input and
507		 * output data.  Take into account that an input section may be
508		 * NOBITS (ppc .plt for example).
509		 */
510		off = rel->r_offset - ircache->c_shdr->sh_addr;
511		if (ircache->c_data->d_buf)
512			iaddr = (uchar_t *)ircache->c_data->d_buf + off;
513		else
514			iaddr = 0;
515		oaddr = (uchar_t *)orcache->c_data->d_buf + off;
516
517		/*
518		 * Apply the relocation to the new output image.  Any base
519		 * address, or symbol value, will have been saved in the reloc
520		 * structure during count_reloc().
521		 */
522		if (reloc->r_flags & FLG_R_APPLY)
523			apply_reloc(rel, reloc, name, oaddr, lmp);
524
525		/*
526		 * Undo any relocation that might already been applied to the
527		 * memory image by the runtime linker.  Using the original
528		 * file, determine the relocation offset original value and
529		 * restore the new image to that value.
530		 */
531		if ((reloc->r_flags & FLG_R_UNDO) &&
532		    (FLAGS(lmp) & FLG_RT_RELOCED))
533			undo_reloc(rel, oaddr, iaddr, reloc);
534
535		/*
536		 * If a relocation has been applied then the relocation record
537		 * should be cleared so that the relocation isn't applied again
538		 * when the new image is used.
539		 */
540		if (reloc->r_flags & FLG_R_CLR) {
541			if (type == M_R_JMP_SLOT) {
542				clear_reloc(*func);
543				*func = (Rel *)((uintptr_t)*func + ent);
544			} else {
545				clear_reloc(*null);
546				*null = (Rel *)((uintptr_t)*null + ent);
547			}
548		}
549
550		/*
551		 * If a relocation isn't applied, update the relocation record
552		 * to take into account the new address of the image.
553		 */
554		if (reloc->r_flags & FLG_R_INC) {
555			if (type == M_R_JMP_SLOT) {
556				inc_reloc(*func, rel, reloc, oaddr, iaddr);
557				*func = (Rel *)((uintptr_t)*func + ent);
558			} else {
559				inc_reloc(*data, rel, reloc, oaddr, iaddr);
560				*data = (Rel *)((uintptr_t)*data + ent);
561			}
562		}
563	}
564}
565