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