mdreloc.c revision 1.1 1 /* $NetBSD: mdreloc.c,v 1.1 2014/09/19 17:36:25 matt Exp $ */
2
3 /*-
4 * Copyright (c) 2014 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Matt Thomas of 3am Software Foundry.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #include <sys/cdefs.h>
33 #ifndef lint
34 __RCSID("$NetBSD: mdreloc.c,v 1.1 2014/09/19 17:36:25 matt Exp $");
35 #endif /* not lint */
36
37 #include <sys/types.h>
38 #include <sys/endian.h>
39 #include <sys/tls.h>
40
41 #include <stdlib.h>
42 #include <string.h>
43
44 #include "debug.h"
45 #include "rtld.h"
46
47 void _rtld_bind_start(void);
48 void _rtld_relocate_nonplt_self(Elf_Dyn *, Elf_Addr);
49 void *_rtld_bind(const Obj_Entry *, Elf_Word);
50
51 #if ELFSIZE == 64
52 #define Elf_Sxword Elf64_Sxword
53 #else
54 #define Elf_Sxword Elf32_Sword
55 #endif
56
57 void
58 _rtld_setup_pltgot(const Obj_Entry *obj)
59 {
60 obj->pltgot[0] = (Elf_Addr) &_rtld_bind_start;
61 obj->pltgot[1] = (Elf_Addr) obj;
62 }
63
64 void
65 _rtld_relocate_nonplt_self(Elf_Dyn *dynp, Elf_Addr relocbase)
66 {
67 const Elf_Rel *rel = 0, *rellim;
68 Elf_Addr relsz = 0;
69 Elf_Sxword *where;
70 const Elf_Sym *symtab = NULL, *sym;
71 Elf_Addr *got = NULL;
72 Elf_Word local_gotno = 0, symtabno = 0, gotsym = 0;
73 size_t i;
74
75 for (; dynp->d_tag != DT_NULL; dynp++) {
76 switch (dynp->d_tag) {
77 case DT_REL:
78 rel = (const Elf_Rel *)(relocbase + dynp->d_un.d_ptr);
79 break;
80 case DT_RELSZ:
81 relsz = dynp->d_un.d_val;
82 break;
83 case DT_SYMTAB:
84 symtab = (const Elf_Sym *)(relocbase + dynp->d_un.d_ptr);
85 break;
86 case DT_PLTGOT:
87 got = (Elf_Addr *)(relocbase + dynp->d_un.d_ptr);
88 break;
89 case DT_RISCV_LOCAL_GOTNO:
90 local_gotno = dynp->d_un.d_val;
91 break;
92 case DT_RISCV_SYMTABNO:
93 symtabno = dynp->d_un.d_val;
94 break;
95 case DT_RISCV_GOTSYM:
96 gotsym = dynp->d_un.d_val;
97 break;
98 }
99 }
100
101 i = (got[1] & 0x80000000) ? 2 : 1;
102 /* Relocate the local GOT entries */
103 got += i;
104 for (; i < local_gotno; i++)
105 *got++ += relocbase;
106 sym = symtab + gotsym;
107 /* Now do the global GOT entries */
108 for (i = gotsym; i < symtabno; i++) {
109 *got = sym->st_value + relocbase;
110 ++sym;
111 ++got;
112 }
113
114 rellim = (const Elf_Rel *)((uintptr_t)rel + relsz);
115 for (; rel < rellim; rel++) {
116 Elf_Word r_symndx, r_type;
117
118 where = (Elf_Sxword *)(relocbase + rel->r_offset);
119
120 r_symndx = ELF_R_SYM(rel->r_info);
121 r_type = ELF_R_TYPE(rel->r_info);
122
123 switch (r_type & 0xff) {
124 case R_TYPE(REL32): {
125 Elf_Sxword old = *where;
126 Elf_Sxword val = old;
127 #if ELFSIZE == 64
128 assert(r_type == R_TYPE(REL32)
129 || r_type == (R_TYPE(REL32)|(R_TYPE(64) << 8)));
130 #endif
131 assert(r_symndx < gotsym);
132 sym = symtab + r_symndx;
133 assert(ELF_ST_BIND(sym->st_info) == STB_LOCAL);
134 val += relocbase;
135 *(Elf_Sword *)where = val;
136 rdbg(("REL32/L(%p) %p -> %p in <self>",
137 where, (void *)old, (void *)val));
138 break;
139 }
140
141 case R_TYPE(NONE):
142 break;
143
144 default:
145 abort();
146 }
147 }
148 }
149
150 int
151 _rtld_relocate_nonplt_objects(Obj_Entry *obj)
152 {
153 const Elf_Rel *rel;
154 Elf_Addr *got = obj->pltgot;
155 const Elf_Sym *sym, *def;
156 const Obj_Entry *defobj;
157 Elf_Word i;
158
159 i = 2;
160 /* Relocate the local GOT entries */
161 got += i;
162 for (; i < obj->local_gotno; i++)
163 *got++ += (Elf_Addr)obj->relocbase;
164
165 sym = obj->symtab + obj->gotsym;
166 /* Now do the global GOT entries */
167 for (i = obj->gotsym; i < obj->symtabno; i++) {
168 rdbg((" doing got %d sym %p (%s, %lx)", i - obj->gotsym, sym,
169 sym->st_name + obj->strtab, (u_long) *got));
170
171 if (ELF_ST_TYPE(sym->st_info) == STT_FUNC &&
172 sym->st_value != 0 && sym->st_shndx == SHN_UNDEF) {
173 /*
174 * If there are non-PLT references to the function,
175 * st_value should be 0, forcing us to resolve the
176 * address immediately.
177 *
178 * XXX DANGER WILL ROBINSON!
179 * The linker is not outputting PLT slots for calls to
180 * functions that are defined in the same shared
181 * library. This is a bug, because it can screw up
182 * link ordering rules if the symbol is defined in
183 * more than one module. For now, if there is a
184 * definition, we fail the test above and force a full
185 * symbol lookup. This means that all intra-module
186 * calls are bound immediately. - mycroft, 2003/09/24
187 */
188 *got = sym->st_value + (Elf_Addr)obj->relocbase;
189 } else if (sym->st_info == ELF_ST_INFO(STB_GLOBAL, STT_SECTION)) {
190 /* Symbols with index SHN_ABS are not relocated. */
191 if (sym->st_shndx != SHN_ABS)
192 *got = sym->st_value +
193 (Elf_Addr)obj->relocbase;
194 } else {
195 def = _rtld_find_symdef(i, obj, &defobj, false);
196 if (def == NULL)
197 return -1;
198 *got = def->st_value + (Elf_Addr)defobj->relocbase;
199 }
200
201 rdbg((" --> now %lx", (u_long) *got));
202 ++sym;
203 ++got;
204 }
205
206 got = obj->pltgot;
207 for (rel = obj->rel; rel < obj->rellim; rel++) {
208 Elf_Addr * const where =
209 (Elf_Addr *)(obj->relocbase + rel->r_offset);
210 const Elf_Word r_symndx = ELF_R_SYM(rel->r_info);
211 const Elf_Word r_type = ELF_R_TYPE(rel->r_info);
212
213 switch (r_type) {
214 case R_TYPE(NONE):
215 break;
216
217 case R_TYPE(REL32): {
218 /* 32-bit PC-relative reference */
219 Elf_Sxword old = *where;
220 Elf_Sxword val = old;
221
222 def = obj->symtab + r_symndx;
223
224 if (r_symndx < obj->gotsym) {
225 val += (Elf_Addr)obj->relocbase;
226
227 rdbg(("REL32/L(%p) %p -> %p (%s) in %s",
228 where, (void *)old, (void *)val,
229 obj->strtab + def->st_name, obj->path));
230 } else {
231 val += got[obj->local_gotno + r_symndx - obj->gotsym];
232 rdbg(("REL32/G(%p) %p --> %p (%s) in %s",
233 where, (void *)old, (void *)val,
234 obj->strtab + def->st_name,
235 obj->path));
236 }
237 *where = val;
238 break;
239 }
240
241 #if ELFSIZE == 64
242 case R_TYPE(TLS_DTPMOD64):
243 #else
244 case R_TYPE(TLS_DTPMOD32):
245 #endif
246 {
247 Elf_Addr old = *where;
248 Elf_Addr val = old;
249
250 def = _rtld_find_symdef(r_symndx, obj, &defobj, false);
251 if (def == NULL)
252 return -1;
253
254 val += (Elf_Addr)defobj->tlsindex;
255
256 *where = val;
257 rdbg(("DTPMOD %s in %s --> %p in %s",
258 obj->strtab + obj->symtab[r_symndx].st_name,
259 obj->path, (void *)old, defobj->path));
260 break;
261 }
262
263 #if ELFSIZE == 64
264 case R_TYPE(TLS_DTPREL64):
265 #else
266 case R_TYPE(TLS_DTPREL32):
267 #endif
268 {
269 Elf_Addr old = *where;
270 Elf_Addr val = old;
271
272 def = _rtld_find_symdef(r_symndx, obj, &defobj, false);
273 if (def == NULL)
274 return -1;
275
276 if (!defobj->tls_done && _rtld_tls_offset_allocate(obj))
277 return -1;
278
279 val += (Elf_Addr)def->st_value - TLS_DTV_OFFSET;
280 *(Elf_Word *) where = val;
281
282 rdbg(("DTPREL %s in %s --> %p in %s",
283 obj->strtab + obj->symtab[r_symndx].st_name,
284 obj->path, (void *)old, defobj->path));
285 break;
286 }
287
288 default:
289 rdbg(("sym = %lu, type = %lu, offset = %p, "
290 "contents = %p, symbol = %s",
291 (u_long)r_symndx, (u_long)ELF_R_TYPE(rel->r_info),
292 (void *)rel->r_offset,
293 (void *)load_ptr(where, sizeof(Elf_Sword)),
294 obj->strtab + obj->symtab[r_symndx].st_name));
295 _rtld_error("%s: Unsupported relocation type %ld "
296 "in non-PLT relocations",
297 obj->path, (u_long) ELF_R_TYPE(rel->r_info));
298 return -1;
299 }
300 }
301
302 return 0;
303 }
304
305 int
306 _rtld_relocate_plt_lazy(const Obj_Entry *obj)
307 {
308 /* PLT fixups were done above in the GOT relocation. */
309 return 0;
310 }
311
312 static int
313 _rtld_relocate_plt_object(const Obj_Entry *obj, const Elf_Rel *rel,
314 Elf_Addr *tp)
315 {
316 const Obj_Entry *defobj;
317 Elf_Addr new_value;
318
319 assert(ELF_R_TYPE(rel->r_info) == R_TYPE(JMP_SLOT));
320
321 const Elf_Sym *def = _rtld_find_plt_symdef(ELF_R_SYM(rel->r_info),
322 obj, &defobj, tp != NULL);
323 if (__predict_false(def == NULL))
324 return -1;
325 if (__predict_false(def == &_rtld_sym_zero))
326 return -1;
327
328 if (ELF_ST_TYPE(def->st_info) == STT_GNU_IFUNC) {
329 if (tp == NULL)
330 return 0;
331 new_value = _rtld_resolve_ifunc(defobj, def);
332 } else {
333 new_value = (Elf_Addr)(defobj->relocbase + def->st_value);
334 }
335 rdbg(("bind now/fixup in %s --> new=%p",
336 defobj->strtab + def->st_name, (void *)new_value));
337 *(Elf_Addr *)(obj->relocbase + rel->r_offset) = new_value;
338
339 if (tp)
340 *tp = new_value;
341 return 0;
342 }
343
344 void *
345 _rtld_bind(const Obj_Entry *obj, Elf_Word reloff)
346 {
347 const Elf_Rel *pltrel = (const Elf_Rel *)(obj->pltrel + reloff);
348 Elf_Addr new_value;
349 int err;
350
351 _rtld_shared_enter();
352 err = _rtld_relocate_plt_object(obj, pltrel, &new_value);
353 if (err)
354 _rtld_die();
355 _rtld_shared_exit();
356
357 return (caddr_t)new_value;
358 }
359
360 int
361 _rtld_relocate_plt_objects(const Obj_Entry *obj)
362 {
363
364 for (const Elf_Rel *rel = obj->pltrel; rel < obj->pltrellim; rel++) {
365 if (_rtld_relocate_plt_object(obj, rel, NULL) < 0)
366 return -1;
367 }
368
369 return 0;
370 }
371