hppa_reloc.c revision 1.4 1 1.4 mycroft /* $NetBSD: hppa_reloc.c,v 1.4 2002/09/05 18:25:46 mycroft Exp $ */
2 1.1 fredette
3 1.1 fredette /*-
4 1.1 fredette * Copyright (c) 2002 The NetBSD Foundation, Inc.
5 1.1 fredette * All rights reserved.
6 1.1 fredette *
7 1.1 fredette * This code is derived from software contributed to The NetBSD Foundation
8 1.1 fredette * by Matt Fredette.
9 1.1 fredette *
10 1.1 fredette * Redistribution and use in source and binary forms, with or without
11 1.1 fredette * modification, are permitted provided that the following conditions
12 1.1 fredette * are met:
13 1.1 fredette * 1. Redistributions of source code must retain the above copyright
14 1.1 fredette * notice, this list of conditions and the following disclaimer.
15 1.1 fredette * 2. Redistributions in binary form must reproduce the above copyright
16 1.1 fredette * notice, this list of conditions and the following disclaimer in the
17 1.1 fredette * documentation and/or other materials provided with the distribution.
18 1.1 fredette * 3. All advertising materials mentioning features or use of this software
19 1.1 fredette * must display the following acknowledgement:
20 1.1 fredette * This product includes software developed by the NetBSD
21 1.1 fredette * Foundation, Inc. and its contributors.
22 1.1 fredette * 4. Neither the name of The NetBSD Foundation nor the names of its
23 1.1 fredette * contributors may be used to endorse or promote products derived
24 1.1 fredette * from this software without specific prior written permission.
25 1.1 fredette *
26 1.1 fredette * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 1.1 fredette * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 1.1 fredette * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 1.1 fredette * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 1.1 fredette * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 1.1 fredette * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 1.1 fredette * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 1.1 fredette * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 1.1 fredette * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 1.1 fredette * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 1.1 fredette * POSSIBILITY OF SUCH DAMAGE.
37 1.1 fredette */
38 1.1 fredette
39 1.1 fredette #include <stdlib.h>
40 1.1 fredette #include <sys/types.h>
41 1.1 fredette #include <sys/stat.h>
42 1.1 fredette #include <sys/queue.h>
43 1.1 fredette
44 1.1 fredette #include "rtld.h"
45 1.1 fredette #include "debug.h"
46 1.1 fredette
47 1.1 fredette #ifdef RTLD_DEBUG_HPPA
48 1.1 fredette #define hdbg(x) if (dodebug) xprintf x
49 1.1 fredette #else
50 1.1 fredette #define hdbg(x) /* nothing */
51 1.1 fredette #endif
52 1.1 fredette
53 1.1 fredette /*
54 1.1 fredette * In the runtime architecture (ABI), PLABEL function
55 1.1 fredette * pointers are distinguished from normal function
56 1.1 fredette * pointers by having the next-least-significant bit
57 1.1 fredette * set. (This bit is referred to as the L field in
58 1.1 fredette * HP documentation). The $$dyncall millicode is
59 1.1 fredette * aware of this.
60 1.1 fredette */
61 1.1 fredette #define RTLD_MAKE_PLABEL(plabel) (((Elf_Addr)(plabel)) | (1 << 1))
62 1.1 fredette #define RTLD_IS_PLABEL(addr) (((Elf_Addr)(addr)) & (1 << 1))
63 1.1 fredette #define RTLD_GET_PLABEL(addr) ((hppa_plabel *) (((Elf_Addr)addr) & ~3))
64 1.1 fredette
65 1.1 fredette /*
66 1.1 fredette * This is the PLABEL structure. The function PC and
67 1.1 fredette * shared linkage members must come first, as they are
68 1.1 fredette * the actual PLABEL.
69 1.1 fredette */
70 1.1 fredette typedef struct _hppa_plabel {
71 1.1 fredette Elf_Addr hppa_plabel_pc;
72 1.1 fredette Elf_Addr hppa_plabel_sl;
73 1.1 fredette SLIST_ENTRY(_hppa_plabel) hppa_plabel_next;
74 1.1 fredette } hppa_plabel;
75 1.1 fredette
76 1.1 fredette /*
77 1.1 fredette * For now allocated PLABEL structures are tracked on a
78 1.1 fredette * singly linked list. This maybe should be revisited.
79 1.1 fredette */
80 1.1 fredette static SLIST_HEAD(hppa_plabel_head, _hppa_plabel) hppa_plabel_list
81 1.1 fredette = SLIST_HEAD_INITIALIZER(hppa_plabel_list);
82 1.1 fredette
83 1.1 fredette /*
84 1.1 fredette * Because I'm hesitant to use NEW while relocating self,
85 1.1 fredette * this is a small pool of preallocated PLABELs.
86 1.1 fredette */
87 1.1 fredette #define HPPA_PLABEL_PRE (10)
88 1.1 fredette static hppa_plabel hppa_plabel_pre[HPPA_PLABEL_PRE];
89 1.1 fredette static int hppa_plabel_pre_next = 0;
90 1.1 fredette
91 1.1 fredette /*
92 1.1 fredette * The DT_PLTGOT _DYNAMIC entry always gives the linkage table
93 1.1 fredette * pointer for an object. This is often, but not always, the
94 1.1 fredette * same as the object's value for _GLOBAL_OFFSET_TABLE_. We
95 1.1 fredette * cache one object's GOT value, otherwise we look it up.
96 1.1 fredette * XXX it would be nice to be able to keep this in the Obj_Entry.
97 1.1 fredette */
98 1.1 fredette static const Obj_Entry *hppa_got_cache_obj = NULL;
99 1.1 fredette static Elf_Addr *hppa_got_cache_got;
100 1.1 fredette #define HPPA_OBJ_SL(obj) ((obj)->pltgot)
101 1.1 fredette #define HPPA_OBJ_GOT(obj) ((obj) == hppa_got_cache_obj ? \
102 1.1 fredette hppa_got_cache_got : \
103 1.1 fredette _rtld_fill_hppa_got_cache(obj))
104 1.1 fredette static Elf_Addr *_rtld_fill_hppa_got_cache __P((const Obj_Entry *));
105 1.1 fredette
106 1.1 fredette /*
107 1.1 fredette * This bootstraps the dynamic linker by relocating its GOT.
108 1.1 fredette * On the hppa, unlike on other architectures, static strings
109 1.1 fredette * are found through the GOT. Static strings are essential
110 1.1 fredette * for RTLD_DEBUG, and I suspect they're used early even when
111 1.1 fredette * !defined(RTLD_DEBUG), making relocating the GOT essential.
112 1.1 fredette *
113 1.1 fredette * It gets worse. Relocating the GOT doesn't mean just walking
114 1.1 fredette * it and adding the relocbase to all of the entries. You must
115 1.1 fredette * find and use the GOT relocations, since those RELA relocations
116 1.1 fredette * have the necessary addends - the GOT comes initialized as
117 1.1 fredette * zeroes.
118 1.1 fredette */
119 1.1 fredette void
120 1.1 fredette _rtld_bootstrap_hppa_got(Elf_Dyn *dynp, Elf_Addr relocbase,
121 1.1 fredette Elf_Addr got_begin, Elf_Addr got_end)
122 1.1 fredette {
123 1.1 fredette const Elf_Rela *relafirst, *rela, *relalim;
124 1.1 fredette Elf_Addr relasz = 0;
125 1.1 fredette Elf_Addr where;
126 1.1 fredette
127 1.1 fredette /*
128 1.1 fredette * Process the DYNAMIC section, looking for the non-PLT
129 1.1 fredette * relocations.
130 1.1 fredette */
131 1.1 fredette relafirst = NULL;
132 1.1 fredette for (; dynp->d_tag != DT_NULL; ++dynp) {
133 1.1 fredette switch (dynp->d_tag) {
134 1.1 fredette
135 1.1 fredette case DT_RELA:
136 1.1 fredette relafirst = (const Elf_Rela *)
137 1.1 fredette (relocbase + dynp->d_un.d_ptr);
138 1.1 fredette break;
139 1.1 fredette
140 1.1 fredette case DT_RELASZ:
141 1.1 fredette relasz = dynp->d_un.d_val;
142 1.1 fredette break;
143 1.1 fredette }
144 1.1 fredette }
145 1.1 fredette relalim = (const Elf_Rela *)((caddr_t)relafirst + relasz);
146 1.1 fredette
147 1.1 fredette /*
148 1.1 fredette * Process all relocations that look like they're in
149 1.1 fredette * the GOT.
150 1.1 fredette */
151 1.1 fredette for(rela = relafirst; rela < relalim; rela++) {
152 1.1 fredette where = (Elf_Addr)(relocbase + rela->r_offset);
153 1.1 fredette if (where >= got_begin && where < got_end)
154 1.1 fredette *((Elf_Addr *)where) = relocbase + rela->r_addend;
155 1.1 fredette }
156 1.1 fredette
157 1.1 fredette #if defined(RTLD_DEBUG_HPPA)
158 1.1 fredette for(rela = relafirst; rela < relalim; rela++) {
159 1.1 fredette where = (Elf_Addr)(relocbase + rela->r_offset);
160 1.1 fredette if (where >= got_begin && where < got_end)
161 1.1 fredette xprintf("GOT rela @%p(%p) -> %p(%p)\n",
162 1.1 fredette (void *)rela->r_offset,
163 1.1 fredette (void *)where,
164 1.1 fredette (void *)rela->r_addend,
165 1.1 fredette (void *)*((Elf_Addr *)where));
166 1.1 fredette }
167 1.1 fredette #endif /* RTLD_DEBUG_HPPA */
168 1.1 fredette }
169 1.1 fredette
170 1.1 fredette /*
171 1.1 fredette * This looks up the object's _GLOBAL_OFFSET_TABLE_
172 1.1 fredette * and caches the result.
173 1.1 fredette */
174 1.1 fredette static Elf_Addr *
175 1.1 fredette _rtld_fill_hppa_got_cache(const Obj_Entry *obj)
176 1.1 fredette {
177 1.1 fredette const char *name = "_GLOBAL_OFFSET_TABLE_";
178 1.1 fredette unsigned long hash;
179 1.1 fredette const Elf_Sym *def;
180 1.1 fredette
181 1.1 fredette hash = _rtld_elf_hash(name);
182 1.1 fredette def = _rtld_symlook_obj(name, hash, obj, true);
183 1.1 fredette assert(def != NULL);
184 1.1 fredette hppa_got_cache_obj = obj;
185 1.1 fredette return hppa_got_cache_got =
186 1.1 fredette (Elf_Addr *)(obj->relocbase + def->st_value);
187 1.1 fredette }
188 1.1 fredette
189 1.1 fredette /*
190 1.1 fredette * This allocates a PLABEL. If called with a non-NULL def, the
191 1.1 fredette * plabel is for the function associated with that definition
192 1.1 fredette * in the defining object defobj, plus the given addend. If
193 1.1 fredette * called with a NULL def, the plabel is for the function at
194 1.1 fredette * the (unrelocated) address in addend in the object defobj.
195 1.1 fredette */
196 1.1 fredette Elf_Addr
197 1.1 fredette _rtld_function_descriptor_alloc(const Obj_Entry *defobj, const Elf_Sym *def,
198 1.1 fredette Elf_Addr addend)
199 1.1 fredette {
200 1.1 fredette Elf_Addr func_pc, func_sl;
201 1.1 fredette hppa_plabel *plabel;
202 1.1 fredette
203 1.1 fredette if (def != NULL) {
204 1.1 fredette
205 1.1 fredette /*
206 1.1 fredette * We assume that symbols of type STT_NOTYPE
207 1.1 fredette * are undefined. Return NULL for these.
208 1.1 fredette */
209 1.1 fredette if (ELF_ST_TYPE(def->st_info) == STT_NOTYPE)
210 1.1 fredette return (Elf_Addr)NULL;
211 1.1 fredette
212 1.1 fredette /* Otherwise assert that this symbol must be a function. */
213 1.1 fredette assert(ELF_ST_TYPE(def->st_info) == STT_FUNC);
214 1.1 fredette
215 1.1 fredette func_pc = (Elf_Addr)(defobj->relocbase + def->st_value +
216 1.1 fredette addend);
217 1.1 fredette } else
218 1.1 fredette func_pc = (Elf_Addr)(defobj->relocbase + addend);
219 1.1 fredette
220 1.1 fredette /*
221 1.1 fredette * Search the existing PLABELs for one matching
222 1.1 fredette * this function. If there is one, return it.
223 1.1 fredette */
224 1.1 fredette func_sl = (Elf_Addr)HPPA_OBJ_SL(defobj);
225 1.1 fredette SLIST_FOREACH(plabel, &hppa_plabel_list, hppa_plabel_next)
226 1.1 fredette if (plabel->hppa_plabel_pc == func_pc &&
227 1.1 fredette plabel->hppa_plabel_sl == func_sl)
228 1.1 fredette return RTLD_MAKE_PLABEL(plabel);
229 1.1 fredette
230 1.1 fredette /*
231 1.1 fredette * XXX - this assumes that the dynamic linker doesn't
232 1.1 fredette * have more than HPPA_PLABEL_PRE PLABEL relocations.
233 1.1 fredette * Once we've used up the preallocated set, we start
234 1.1 fredette * using NEW to allocate plabels.
235 1.1 fredette */
236 1.1 fredette if (hppa_plabel_pre_next < HPPA_PLABEL_PRE)
237 1.1 fredette plabel = &hppa_plabel_pre[hppa_plabel_pre_next++];
238 1.1 fredette else {
239 1.1 fredette plabel = NEW(hppa_plabel);
240 1.1 fredette if (plabel == NULL)
241 1.1 fredette return (Elf_Addr)-1;
242 1.1 fredette }
243 1.1 fredette
244 1.1 fredette /* Fill the new entry and insert it on the list. */
245 1.1 fredette plabel->hppa_plabel_pc = func_pc;
246 1.1 fredette plabel->hppa_plabel_sl = func_sl;
247 1.1 fredette SLIST_INSERT_HEAD(&hppa_plabel_list, plabel, hppa_plabel_next);
248 1.1 fredette
249 1.1 fredette return RTLD_MAKE_PLABEL(plabel);
250 1.1 fredette }
251 1.1 fredette
252 1.1 fredette /*
253 1.1 fredette * If a pointer is a PLABEL, this unwraps it.
254 1.1 fredette */
255 1.1 fredette const void *
256 1.1 fredette _rtld_function_descriptor_function(const void *addr)
257 1.1 fredette {
258 1.1 fredette return (RTLD_IS_PLABEL(addr) ?
259 1.1 fredette (const void *) RTLD_GET_PLABEL(addr)->hppa_plabel_pc :
260 1.1 fredette addr);
261 1.1 fredette }
262 1.1 fredette
263 1.1 fredette /*
264 1.1 fredette * This handles an IPLT relocation, with or without a symbol.
265 1.1 fredette */
266 1.1 fredette int
267 1.1 fredette _rtld_relocate_plt_object(Obj_Entry *obj, const Elf_Rela *rela, caddr_t *addrp,
268 1.1 fredette bool bind_now, bool dodebug)
269 1.1 fredette {
270 1.1 fredette Elf_Addr *where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
271 1.1 fredette const Elf_Sym *def;
272 1.1 fredette const Obj_Entry *defobj;
273 1.1 fredette Elf_Addr func_pc, func_sl;
274 1.1 fredette
275 1.1 fredette assert(ELF_R_TYPE(rela->r_info) == R_TYPE(IPLT));
276 1.1 fredette
277 1.1 fredette /*
278 1.1 fredette * If this is an IPLT reloc for a static function,
279 1.1 fredette * fully resolve the PLT entry now.
280 1.1 fredette */
281 1.1 fredette if (ELF_R_SYM(rela->r_info) == 0) {
282 1.1 fredette func_pc = (Elf_Addr)(obj->relocbase + rela->r_addend);
283 1.1 fredette func_sl = (Elf_Addr)HPPA_OBJ_SL(obj);
284 1.1 fredette }
285 1.1 fredette
286 1.1 fredette /*
287 1.1 fredette * If we must bind now, fully resolve the PLT entry.
288 1.1 fredette */
289 1.1 fredette else if (bind_now) {
290 1.1 fredette
291 1.1 fredette /*
292 1.1 fredette * Look up the symbol. While we're relocating self,
293 1.1 fredette * _rtld_objlist is NULL, so just pass in self.
294 1.1 fredette */
295 1.3 junyoung def = _rtld_find_symdef(rela->r_info, obj, &defobj, false);
296 1.1 fredette if (def == NULL)
297 1.1 fredette return -1;
298 1.1 fredette func_pc = (Elf_Addr)(defobj->relocbase + def->st_value +
299 1.1 fredette rela->r_addend);
300 1.1 fredette func_sl = (Elf_Addr)HPPA_OBJ_SL(defobj);
301 1.1 fredette }
302 1.1 fredette
303 1.1 fredette /*
304 1.1 fredette * Otherwise set up for lazy binding.
305 1.1 fredette */
306 1.1 fredette else {
307 1.1 fredette
308 1.1 fredette /*
309 1.1 fredette * This function pointer points to the PLT
310 1.1 fredette * stub added by the linker, and instead of
311 1.1 fredette * a shared linkage value, we stash this
312 1.1 fredette * relocation's offset. The PLT stub has
313 1.1 fredette * already been set up to transfer to
314 1.1 fredette * _rtld_bind_start.
315 1.1 fredette */
316 1.1 fredette func_pc = ((Elf_Addr)HPPA_OBJ_GOT(obj)) - 16;
317 1.1 fredette func_sl = (Elf_Addr)((caddr_t)rela - (caddr_t)obj->pltrela);
318 1.1 fredette }
319 1.1 fredette
320 1.1 fredette /*
321 1.1 fredette * Fill this PLT entry and return.
322 1.1 fredette */
323 1.1 fredette where[0] = func_pc;
324 1.1 fredette where[1] = func_sl;
325 1.1 fredette if (addrp != NULL)
326 1.1 fredette *addrp = (caddr_t)where;
327 1.1 fredette return 0;
328 1.2 mycroft }
329 1.2 mycroft
330 1.2 mycroft /* This sets up an object's GOT. */
331 1.2 mycroft void
332 1.2 mycroft _rtld_setup_pltgot(const Obj_Entry *obj)
333 1.2 mycroft {
334 1.2 mycroft __rtld_setup_hppa_pltgot(obj, HPPA_OBJ_GOT(obj));
335 1.4 mycroft }
336 1.4 mycroft
337 1.4 mycroft int
338 1.4 mycroft _rtld_relocate_nonplt_object(obj, rela, dodebug)
339 1.4 mycroft Obj_Entry *obj;
340 1.4 mycroft const Elf_Rela *rela;
341 1.4 mycroft bool dodebug;
342 1.4 mycroft {
343 1.4 mycroft Elf_Addr *where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
344 1.4 mycroft const Elf_Sym *def;
345 1.4 mycroft const Obj_Entry *defobj;
346 1.4 mycroft Elf_Addr tmp;
347 1.4 mycroft
348 1.4 mycroft switch (ELF_R_TYPE(rela->r_info)) {
349 1.4 mycroft
350 1.4 mycroft case R_TYPE(NONE):
351 1.4 mycroft break;
352 1.4 mycroft
353 1.4 mycroft case R_TYPE(DIR32):
354 1.4 mycroft if (ELF_R_SYM(rela->r_info)) {
355 1.4 mycroft /*
356 1.4 mycroft * This is either a DIR32 against a symbol
357 1.4 mycroft * (def->st_name != 0), or against a local
358 1.4 mycroft * section (def->st_name == 0).
359 1.4 mycroft */
360 1.4 mycroft def = obj->symtab + ELF_R_SYM(rela->r_info);
361 1.4 mycroft defobj = obj;
362 1.4 mycroft if (def->st_name != 0)
363 1.4 mycroft /*
364 1.4 mycroft * While we're relocating self, _rtld_objlist
365 1.4 mycroft * is NULL, so we just pass in self.
366 1.4 mycroft */
367 1.4 mycroft def = _rtld_find_symdef(rela->r_info, obj,
368 1.4 mycroft &defobj, false);
369 1.4 mycroft if (def == NULL)
370 1.4 mycroft return -1;
371 1.4 mycroft
372 1.4 mycroft tmp = (Elf_Addr)(defobj->relocbase + def->st_value +
373 1.4 mycroft rela->r_addend);
374 1.4 mycroft
375 1.4 mycroft if (*where != tmp)
376 1.4 mycroft *where = tmp;
377 1.4 mycroft rdbg(dodebug, ("DIR32 %s in %s --> %p in %s",
378 1.4 mycroft defobj->strtab + def->st_name, obj->path,
379 1.4 mycroft (void *)*where, defobj->path));
380 1.4 mycroft } else {
381 1.4 mycroft extern Elf_Addr _GLOBAL_OFFSET_TABLE_[];
382 1.4 mycroft extern Elf_Addr _GOT_END_[];
383 1.4 mycroft
384 1.4 mycroft tmp = (Elf_Addr)(obj->relocbase + rela->r_addend);
385 1.4 mycroft
386 1.4 mycroft /* This is the ...iffy hueristic. */
387 1.4 mycroft if (!dodebug ||
388 1.4 mycroft (caddr_t)where < (caddr_t)_GLOBAL_OFFSET_TABLE_ ||
389 1.4 mycroft (caddr_t)where >= (caddr_t)_GOT_END_) {
390 1.4 mycroft if (*where != tmp)
391 1.4 mycroft *where = tmp;
392 1.4 mycroft rdbg(dodebug, ("DIR32 in %s --> %p", obj->path,
393 1.4 mycroft (void *)*where));
394 1.4 mycroft } else
395 1.4 mycroft rdbg(dodebug, ("DIR32 in %s stays at %p",
396 1.4 mycroft obj->path, (void *)*where));
397 1.4 mycroft }
398 1.4 mycroft break;
399 1.4 mycroft
400 1.4 mycroft case R_TYPE(PLABEL32):
401 1.4 mycroft if (ELF_R_SYM(rela->r_info)) {
402 1.4 mycroft /*
403 1.4 mycroft * While we're relocating self, _rtld_objlist
404 1.4 mycroft * is NULL, so we just pass in self.
405 1.4 mycroft */
406 1.4 mycroft def = _rtld_find_symdef(rela->r_info, obj, &defobj,
407 1.4 mycroft false);
408 1.4 mycroft if (def == NULL)
409 1.4 mycroft return -1;
410 1.4 mycroft
411 1.4 mycroft tmp = _rtld_function_descriptor_alloc(defobj, def,
412 1.4 mycroft rela->r_addend);
413 1.4 mycroft if (tmp == (Elf_Addr)-1)
414 1.4 mycroft return -1;
415 1.4 mycroft
416 1.4 mycroft if (*where != tmp)
417 1.4 mycroft *where = tmp;
418 1.4 mycroft rdbg(dodebug, ("PLABEL32 %s in %s --> %p in %s",
419 1.4 mycroft defobj->strtab + def->st_name, obj->path,
420 1.4 mycroft (void *)*where, defobj->path));
421 1.4 mycroft } else {
422 1.4 mycroft /*
423 1.4 mycroft * This is a PLABEL for a static function, and the
424 1.4 mycroft * dynamic linker has both allocated a PLT entry
425 1.4 mycroft * for this function and told us where it is. We
426 1.4 mycroft * can safely use the PLT entry as the PLABEL
427 1.4 mycroft * because there should be no other PLABEL reloc
428 1.4 mycroft * referencing this function. This object should
429 1.4 mycroft * also have an IPLT relocation to initialize the
430 1.4 mycroft * PLT entry.
431 1.4 mycroft *
432 1.4 mycroft * The dynamic linker should also have ensured
433 1.4 mycroft * that the addend has the next-least-significant
434 1.4 mycroft * bit set; the $$dyncall millicode uses this to
435 1.4 mycroft * distinguish a PLABEL pointer from a plain
436 1.4 mycroft * function pointer.
437 1.4 mycroft */
438 1.4 mycroft tmp = (Elf_Addr)(obj->relocbase + rela->r_addend);
439 1.4 mycroft
440 1.4 mycroft if (*where != tmp)
441 1.4 mycroft *where = tmp;
442 1.4 mycroft rdbg(dodebug, ("PLABEL32 in %s --> %p",
443 1.4 mycroft obj->path, (void *)*where));
444 1.4 mycroft }
445 1.4 mycroft break;
446 1.4 mycroft
447 1.4 mycroft case R_TYPE(COPY):
448 1.4 mycroft /*
449 1.4 mycroft * These are deferred until all other relocations have
450 1.4 mycroft * been done. All we do here is make sure that the COPY
451 1.4 mycroft * relocation is not in a shared library. They are allowed
452 1.4 mycroft * only in executable files.
453 1.4 mycroft */
454 1.4 mycroft if (!obj->mainprog) {
455 1.4 mycroft _rtld_error(
456 1.4 mycroft "%s: Unexpected R_COPY relocation in shared library",
457 1.4 mycroft obj->path);
458 1.4 mycroft return -1;
459 1.4 mycroft }
460 1.4 mycroft rdbg(dodebug, ("COPY (avoid in main)"));
461 1.4 mycroft break;
462 1.4 mycroft
463 1.4 mycroft default:
464 1.4 mycroft def = _rtld_find_symdef(rela->r_info, obj, &defobj, true);
465 1.4 mycroft rdbg(dodebug, ("sym = %lu, type = %lu, offset = %p, "
466 1.4 mycroft "addend = %p, contents = %p, symbol = %s",
467 1.4 mycroft (u_long)ELF_R_SYM(rela->r_info),
468 1.4 mycroft (u_long)ELF_R_TYPE(rela->r_info),
469 1.4 mycroft (void *)rela->r_offset, (void *)rela->r_addend,
470 1.4 mycroft (void *)*where,
471 1.4 mycroft def ? defobj->strtab + def->st_name : "??"));
472 1.4 mycroft _rtld_error("%s: Unsupported relocation type %ld "
473 1.4 mycroft "in non-PLT relocations\n",
474 1.4 mycroft obj->path, (u_long) ELF_R_TYPE(rela->r_info));
475 1.4 mycroft return -1;
476 1.4 mycroft }
477 1.4 mycroft return 0;
478 1.1 fredette }
479