mdreloc.c revision 1.13 1 /* $NetBSD: mdreloc.c,v 1.13 2002/09/12 20:20:59 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 void _rtld_relocate_nonplt_self(Elf_Dyn *, Elf_Addr);
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 void
20 _rtld_relocate_nonplt_self(dynp, relocbase)
21 Elf_Dyn *dynp;
22 Elf_Addr relocbase;
23 {
24 const Elf_Rel *rel = 0, *rellim;
25 Elf_Addr relsz = 0;
26 Elf_Addr *where;
27
28 for (; dynp->d_tag != DT_NULL; dynp++) {
29 switch (dynp->d_tag) {
30 case DT_REL:
31 rel = (const Elf_Rel *)(relocbase + dynp->d_un.d_ptr);
32 break;
33 case DT_RELSZ:
34 relsz = dynp->d_un.d_val;
35 break;
36 }
37 }
38 rellim = (const Elf_Rel *)((caddr_t)rel + relsz);
39 for (; rel < rellim; rel++) {
40 where = (Elf_Addr *)(relocbase + rel->r_offset);
41 *where += (Elf_Addr)relocbase;
42 }
43 }
44
45 int
46 _rtld_relocate_nonplt_objects(obj, self, dodebug)
47 const Obj_Entry *obj;
48 bool self;
49 bool dodebug;
50 {
51 const Elf_Rel *rel;
52
53 if (self)
54 return 0;
55
56 for (rel = obj->rel; rel < obj->rellim; rel++) {
57 Elf_Addr *where;
58 const Elf_Sym *def;
59 const Obj_Entry *defobj;
60 Elf_Addr tmp;
61 unsigned long symnum;
62
63 where = (Elf_Addr *)(obj->relocbase + rel->r_offset);
64 symnum = ELF_R_SYM(rel->r_info);
65
66 switch (ELF_R_TYPE(rel->r_info)) {
67 case R_TYPE(NONE):
68 break;
69
70 #if 1 /* XXX should not occur */
71 case R_TYPE(PC24): { /* word32 S - P + A */
72 Elf32_Sword addend;
73
74 /*
75 * Extract addend and sign-extend if needed.
76 */
77 addend = *where;
78 if (addend & 0x00800000)
79 addend |= 0xff000000;
80
81 def = _rtld_find_symdef(symnum, obj, &defobj, false);
82 if (def == NULL)
83 return -1;
84 tmp = (Elf_Addr)obj->relocbase + def->st_value
85 - (Elf_Addr)where + (addend << 2);
86 if ((tmp & 0xfe000000) != 0xfe000000 &&
87 (tmp & 0xfe000000) != 0) {
88 _rtld_error(
89 "%s: R_ARM_PC24 relocation @ %p to %s failed "
90 "(displacement %ld (%#lx) out of range)",
91 obj->path, where,
92 obj->strtab + obj->symtab[symnum].st_name,
93 (long) tmp, (long) tmp);
94 return -1;
95 }
96 tmp >>= 2;
97 *where = (*where & 0xff000000) | (tmp & 0x00ffffff);
98 rdbg(dodebug, ("PC24 %s in %s --> %p @ %p in %s",
99 obj->strtab + obj->symtab[symnum].st_name,
100 obj->path, (void *)*where, where, defobj->path));
101 break;
102 }
103 #endif
104
105 case R_TYPE(ABS32): /* word32 B + S + A */
106 def = _rtld_find_symdef(symnum, obj, &defobj, false);
107 if (def == NULL)
108 return -1;
109 *where += (Elf_Addr)defobj->relocbase + def->st_value;
110 rdbg(dodebug, ("ABS32 %s in %s --> %p @ %p in %s",
111 obj->strtab + obj->symtab[symnum].st_name,
112 obj->path, (void *)*where, where, defobj->path));
113 break;
114
115 case R_TYPE(GLOB_DAT): /* word32 B + S */
116 def = _rtld_find_symdef(symnum, obj, &defobj, false);
117 if (def == NULL)
118 return -1;
119 *where = (Elf_Addr)(defobj->relocbase + def->st_value);
120 rdbg(dodebug, ("GLOB_DAT %s in %s --> %p @ %p in %s",
121 obj->strtab + obj->symtab[symnum].st_name,
122 obj->path, (void *)*where, where, defobj->path));
123 break;
124
125 case R_TYPE(RELATIVE): /* word32 B + A */
126 *where += (Elf_Addr)obj->relocbase;
127 rdbg(dodebug, ("RELATIVE in %s --> %p", obj->path,
128 (void *)*where));
129 break;
130
131 case R_TYPE(COPY):
132 /*
133 * These are deferred until all other relocations have
134 * been done. All we do here is make sure that the
135 * COPY relocation is not in a shared library. They
136 * are allowed only in executable files.
137 */
138 if (obj->isdynamic) {
139 _rtld_error(
140 "%s: Unexpected R_COPY relocation in shared library",
141 obj->path);
142 return -1;
143 }
144 rdbg(dodebug, ("COPY (avoid in main)"));
145 break;
146
147 default:
148 rdbg(dodebug, ("sym = %lu, type = %lu, offset = %p, "
149 "contents = %p, symbol = %s",
150 symnum, (u_long)ELF_R_TYPE(rel->r_info),
151 (void *)rel->r_offset, (void *)*where,
152 obj->strtab + obj->symtab[symnum].st_name));
153 _rtld_error("%s: Unsupported relocation type %ld "
154 "in non-PLT relocations\n",
155 obj->path, (u_long) ELF_R_TYPE(rel->r_info));
156 return -1;
157 }
158 }
159 return 0;
160 }
161
162 int
163 _rtld_relocate_plt_lazy(obj, dodebug)
164 const Obj_Entry *obj;
165 bool dodebug;
166 {
167 const Elf_Rel *rel;
168
169 if (!obj->isdynamic)
170 return 0;
171
172 for (rel = obj->pltrel; rel < obj->pltrellim; rel++) {
173 Elf_Addr *where = (Elf_Addr *)(obj->relocbase + rel->r_offset);
174
175 assert(ELF_R_TYPE(rel->r_info) == R_TYPE(JUMP_SLOT));
176
177 /* Just relocate the GOT slots pointing into the PLT */
178 *where += (Elf_Addr)obj->relocbase;
179 rdbg(dodebug, ("fixup !main in %s --> %p", obj->path,
180 (void *)*where));
181 }
182
183 return 0;
184 }
185
186 int
187 _rtld_relocate_plt_object(obj, rela, addrp, dodebug)
188 const Obj_Entry *obj;
189 const Elf_Rela *rela;
190 caddr_t *addrp;
191 bool dodebug;
192 {
193 Elf_Addr *where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
194 Elf_Addr new_value;
195 const Elf_Sym *def;
196 const Obj_Entry *defobj;
197
198 assert(ELF_R_TYPE(rela->r_info) == R_TYPE(JUMP_SLOT));
199
200 def = _rtld_find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, true);
201 if (def == NULL)
202 return -1;
203
204 new_value = (Elf_Addr)(defobj->relocbase + def->st_value);
205 rdbg(dodebug, ("bind now/fixup in %s --> old=%p new=%p",
206 defobj->strtab + def->st_name, (void *)*where, (void *)new_value));
207 if (*where != new_value)
208 *where = new_value;
209
210 *addrp = (caddr_t)new_value;
211 return 0;
212 }
213