mdreloc.c revision 1.19 1 /* $NetBSD: mdreloc.c,v 1.19 2003/07/24 10:12:28 skrll Exp $ */
2
3 #include <sys/types.h>
4 #include <sys/stat.h>
5
6 #include "debug.h"
7 #include "rtld.h"
8
9 void _rtld_bind_start(void);
10 void _rtld_relocate_nonplt_self(Elf_Dyn *, Elf_Addr);
11 caddr_t _rtld_bind(const Obj_Entry *, Elf_Word);
12
13 void
14 _rtld_setup_pltgot(const Obj_Entry *obj)
15 {
16 obj->pltgot[1] = (Elf_Addr) obj;
17 obj->pltgot[2] = (Elf_Addr) &_rtld_bind_start;
18 }
19
20 void
21 _rtld_relocate_nonplt_self(Elf_Dyn *dynp, Elf_Addr relocbase)
22 {
23 const Elf_Rel *rel = 0, *rellim;
24 Elf_Addr relsz = 0;
25 Elf_Addr *where;
26
27 for (; dynp->d_tag != DT_NULL; dynp++) {
28 switch (dynp->d_tag) {
29 case DT_REL:
30 rel = (const Elf_Rel *)(relocbase + dynp->d_un.d_ptr);
31 break;
32 case DT_RELSZ:
33 relsz = dynp->d_un.d_val;
34 break;
35 }
36 }
37 rellim = (const Elf_Rel *)((caddr_t)rel + relsz);
38 for (; rel < rellim; rel++) {
39 where = (Elf_Addr *)(relocbase + rel->r_offset);
40 *where += (Elf_Addr)relocbase;
41 }
42 }
43
44 int
45 _rtld_relocate_nonplt_objects(const Obj_Entry *obj)
46 {
47 const Elf_Rel *rel;
48 #define COMBRELOC
49 #ifdef COMBRELOC
50 unsigned long lastsym = -1;
51 #endif
52 Elf_Addr target;
53
54 for (rel = obj->rel; rel < obj->rellim; rel++) {
55 Elf_Addr *where;
56 const Elf_Sym *def;
57 const Obj_Entry *defobj;
58 Elf_Addr tmp;
59 unsigned long symnum;
60
61 where = (Elf_Addr *)(obj->relocbase + rel->r_offset);
62 symnum = ELF_R_SYM(rel->r_info);
63
64 switch (ELF_R_TYPE(rel->r_info)) {
65 case R_TYPE(NONE):
66 break;
67
68 #if 1 /* XXX should not occur */
69 case R_TYPE(PC32):
70 #ifdef COMBRELOC
71 if (symnum != lastsym) {
72 #endif
73 def = _rtld_find_symdef(symnum, obj, &defobj,
74 false);
75 if (def == NULL)
76 return -1;
77 target = (Elf_Addr)(defobj->relocbase +
78 def->st_value);
79 #ifdef COMBRELOC
80 lastsym = symnum;
81 }
82 #endif
83
84 *where += target - (Elf_Addr)where;
85 rdbg(("PC32 %s in %s --> %p in %s",
86 obj->strtab + obj->symtab[symnum].st_name,
87 obj->path, (void *)*where, defobj->path));
88 break;
89
90 case R_TYPE(GOT32):
91 #endif
92 case R_TYPE(32):
93 case R_TYPE(GLOB_DAT):
94 #ifdef COMBRELOC
95 if (symnum != lastsym) {
96 #endif
97 def = _rtld_find_symdef(symnum, obj, &defobj,
98 false);
99 if (def == NULL)
100 return -1;
101 target = (Elf_Addr)(defobj->relocbase +
102 def->st_value);
103 #ifdef COMBRELOC
104 lastsym = symnum;
105 }
106 #endif
107
108 tmp = target + *where;
109 if (*where != tmp)
110 *where = tmp;
111 rdbg(("32/GLOB_DAT %s in %s --> %p in %s",
112 obj->strtab + obj->symtab[symnum].st_name,
113 obj->path, (void *)*where, defobj->path));
114 break;
115
116 case R_TYPE(RELATIVE):
117 *where += (Elf_Addr)obj->relocbase;
118 rdbg(("RELATIVE in %s --> %p", obj->path,
119 (void *)*where));
120 break;
121
122 case R_TYPE(COPY):
123 /*
124 * These are deferred until all other relocations have
125 * been done. All we do here is make sure that the
126 * COPY relocation is not in a shared library. They
127 * are allowed only in executable files.
128 */
129 if (obj->isdynamic) {
130 _rtld_error(
131 "%s: Unexpected R_COPY relocation in shared library",
132 obj->path);
133 return -1;
134 }
135 rdbg(("COPY (avoid in main)"));
136 break;
137
138 default:
139 rdbg(("sym = %lu, type = %lu, offset = %p, "
140 "contents = %p, symbol = %s",
141 symnum, (u_long)ELF_R_TYPE(rel->r_info),
142 (void *)rel->r_offset, (void *)*where,
143 obj->strtab + obj->symtab[symnum].st_name));
144 _rtld_error("%s: Unsupported relocation type %ld "
145 "in non-PLT relocations\n",
146 obj->path, (u_long) ELF_R_TYPE(rel->r_info));
147 return -1;
148 }
149 }
150 return 0;
151 }
152
153 int
154 _rtld_relocate_plt_lazy(const Obj_Entry *obj)
155 {
156 const Elf_Rel *rel;
157
158 if (!obj->relocbase)
159 return 0;
160
161 for (rel = obj->pltrel; rel < obj->pltrellim; rel++) {
162 Elf_Addr *where = (Elf_Addr *)(obj->relocbase + rel->r_offset);
163
164 assert(ELF_R_TYPE(rel->r_info) == R_TYPE(JMP_SLOT));
165
166 /* Just relocate the GOT slots pointing into the PLT */
167 *where += (Elf_Addr)obj->relocbase;
168 rdbg(("fixup !main in %s --> %p", obj->path, (void *)*where));
169 }
170
171 return 0;
172 }
173
174 caddr_t
175 _rtld_bind(const Obj_Entry *obj, Elf_Word reloff)
176 {
177 const Elf_Rel *rel = (const Elf_Rel *)((caddr_t)obj->pltrel + reloff);
178 Elf_Addr *where = (Elf_Addr *)(obj->relocbase + rel->r_offset);
179 Elf_Addr new_value;
180 const Elf_Sym *def;
181 const Obj_Entry *defobj;
182
183 assert(ELF_R_TYPE(rel->r_info) == R_TYPE(JMP_SLOT));
184
185 def = _rtld_find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj, true);
186 if (def == NULL)
187 _rtld_die();
188
189 new_value = (Elf_Addr)(defobj->relocbase + def->st_value);
190 rdbg(("bind now/fixup in %s --> old=%p new=%p",
191 defobj->strtab + def->st_name, (void *)*where, (void *)new_value));
192 if (*where != new_value)
193 *where = new_value;
194
195 return (caddr_t)new_value;
196 }
197
198 int
199 _rtld_relocate_plt_objects(const Obj_Entry *obj)
200 {
201 const Elf_Rel *rel;
202
203 for (rel = obj->pltrel; rel < obj->pltrellim; rel++) {
204 Elf_Addr *where = (Elf_Addr *)(obj->relocbase + rel->r_offset);
205 Elf_Addr target;
206 const Elf_Sym *def;
207 const Obj_Entry *defobj;
208
209 assert(ELF_R_TYPE(rel->r_info) == R_TYPE(JMP_SLOT));
210
211 def = _rtld_find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj,
212 true);
213 if (def == NULL)
214 return -1;
215 target = (Elf_Addr)(defobj->relocbase + def->st_value);
216 rdbg(("bind now/fixup in %s --> old=%p new=%p",
217 defobj->strtab + def->st_name, (void *)*where,
218 (void *)target));
219 if (*where != target)
220 *where = target;
221 }
222 return 0;
223 }
224