mdreloc.c revision 1.7
1#include <sys/types.h>
2#include <sys/stat.h>
3
4#include "debug.h"
5#include "rtld.h"
6
7void
8_rtld_setup_pltgot(const Obj_Entry *obj)
9{
10	obj->pltgot[1] = (Elf_Addr) obj;
11	obj->pltgot[2] = (Elf_Addr) &_rtld_bind_start;
12}
13
14int
15_rtld_relocate_nonplt_objects(obj, dodebug)
16	const Obj_Entry *obj;
17	bool dodebug;
18{
19	const Elf_Rela *rela;
20
21	for (rela = obj->rela; rela < obj->relalim; rela++) {
22		Elf_Addr        *where;
23		const Elf_Sym   *def;
24		const Obj_Entry *defobj;
25		Elf_Addr         tmp;
26		unsigned long	 symnum;
27
28		where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
29		symnum = ELF_R_SYM(rela->r_info);
30
31		switch (ELF_R_TYPE(rela->r_info)) {
32		case R_TYPE(NONE):
33			break;
34
35#if 1 /* XXX should not occur */
36		case R_TYPE(PC32):
37			def = _rtld_find_symdef(symnum, obj, &defobj, false);
38			if (def == NULL)
39				return -1;
40
41			tmp = (Elf_Addr)(defobj->relocbase + def->st_value +
42			    rela->r_addend) - (Elf_Addr)where;
43			if (*where != tmp)
44				*where = tmp;
45			rdbg(dodebug, ("PC32 %s in %s --> %p in %s",
46			    obj->strtab + obj->symtab[symnum].st_name,
47			    obj->path, (void *)*where, defobj->path));
48			break;
49
50		case R_TYPE(GOT32):
51#endif
52		case R_TYPE(32):
53		case R_TYPE(GLOB_DAT):
54			def = _rtld_find_symdef(symnum, obj, &defobj, false);
55			if (def == NULL)
56				return -1;
57
58			tmp = (Elf_Addr)(defobj->relocbase + def->st_value +
59			    rela->r_addend);
60			if (*where != tmp)
61				*where = tmp;
62			rdbg(dodebug, ("32/GLOB_DAT %s in %s --> %p in %s",
63			    obj->strtab + obj->symtab[symnum].st_name,
64			    obj->path, (void *)*where, defobj->path));
65			break;
66
67		case R_TYPE(RELATIVE):
68			*where += (Elf_Addr)obj->relocbase;
69			rdbg(dodebug, ("RELATIVE in %s --> %p", obj->path,
70			    (void *)*where));
71			break;
72
73		case R_TYPE(COPY):
74			/*
75			 * These are deferred until all other relocations have
76			 * been done.  All we do here is make sure that the
77			 * COPY relocation is not in a shared library.  They
78			 * are allowed only in executable files.
79			 */
80			if (!obj->mainprog) {
81				_rtld_error(
82			"%s: Unexpected R_COPY relocation in shared library",
83				    obj->path);
84				return -1;
85			}
86			rdbg(dodebug, ("COPY (avoid in main)"));
87			break;
88
89		default:
90			rdbg(dodebug, ("sym = %lu, type = %lu, offset = %p, "
91			    "addend = %p, contents = %p, symbol = %s",
92			    symnum, (u_long)ELF_R_TYPE(rela->r_info),
93			    (void *)rela->r_offset, (void *)rela->r_addend,
94			    (void *)*where,
95			    obj->strtab + obj->symtab[symnum].st_name));
96			_rtld_error("%s: Unsupported relocation type %ld "
97			    "in non-PLT relocations\n",
98			    obj->path, (u_long) ELF_R_TYPE(rela->r_info));
99			return -1;
100		}
101	}
102	return 0;
103}
104
105int
106_rtld_relocate_plt_lazy(obj, dodebug)
107	const Obj_Entry *obj;
108	bool dodebug;
109{
110	const Elf_Rela *rela;
111
112	if (obj->mainprog)
113		return 0;
114
115	for (rela = obj->pltrela; rela < obj->pltrelalim; rela++) {
116		Elf_Addr *where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
117
118		assert(ELF_R_TYPE(rela->r_info) == R_TYPE(JMP_SLOT));
119
120		/* Just relocate the GOT slots pointing into the PLT */
121		*where += (Elf_Addr)obj->relocbase;
122		rdbg(dodebug, ("fixup !main in %s --> %p", obj->path,
123		    (void *)*where));
124	}
125
126	return 0;
127}
128
129int
130_rtld_relocate_plt_object(obj, rela, addrp, dodebug)
131	const Obj_Entry *obj;
132	const Elf_Rela *rela;
133	caddr_t *addrp;
134	bool dodebug;
135{
136	Elf_Addr *where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
137	Elf_Addr new_value;
138	const Elf_Sym  *def;
139	const Obj_Entry *defobj;
140
141	assert(ELF_R_TYPE(rela->r_info) == R_TYPE(JMP_SLOT));
142
143	def = _rtld_find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, true);
144	if (def == NULL)
145		return -1;
146
147	new_value = (Elf_Addr)(defobj->relocbase + def->st_value);
148	rdbg(dodebug, ("bind now/fixup in %s --> old=%p new=%p",
149	    defobj->strtab + def->st_name, (void *)*where, (void *)new_value));
150	if (*where != new_value)
151		*where = new_value;
152
153	*addrp = (caddr_t)new_value;
154	return 0;
155}
156