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