xref: /freebsd/libexec/rtld-elf/arm/reloc.c (revision 6af83ee0d2941d18880b6aaa2b4facd1d30c6106)
1 /*	$NetBSD: mdreloc.c,v 1.23 2003/07/26 15:04:38 mrg Exp $	*/
2 
3 #include <sys/cdefs.h>
4 __FBSDID("$FreeBSD$");
5 #include <sys/param.h>
6 #include <sys/mman.h>
7 
8 #include <errno.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <unistd.h>
13 #include "debug.h"
14 #include "rtld.h"
15 
16 void
17 init_pltgot(Obj_Entry *obj)
18 {
19 	if (obj->pltgot != NULL) {
20 		obj->pltgot[1] = (Elf_Addr) obj;
21 		obj->pltgot[2] = (Elf_Addr) &_rtld_bind_start;
22 	}
23 }
24 
25 int
26 do_copy_relocations(Obj_Entry *dstobj)
27 {
28 	const Elf_Rel *rellim;
29 	const Elf_Rel *rel;
30 
31 	assert(dstobj->mainprog);	/* COPY relocations are invalid elsewhere */
32 
33    	rellim = (const Elf_Rel *) ((caddr_t) dstobj->rel + dstobj->relsize);
34 	for (rel = dstobj->rel;  rel < rellim;  rel++) {
35 		if (ELF_R_TYPE(rel->r_info) == R_ARM_COPY) {
36 	    		void *dstaddr;
37 			const Elf_Sym *dstsym;
38 			const char *name;
39 			unsigned long hash;
40 			size_t size;
41 			const void *srcaddr;
42 			const Elf_Sym *srcsym;
43 			Obj_Entry *srcobj;
44 
45 			dstaddr = (void *) (dstobj->relocbase + rel->r_offset);
46 			dstsym = dstobj->symtab + ELF_R_SYM(rel->r_info);
47 			name = dstobj->strtab + dstsym->st_name;
48 			hash = elf_hash(name);
49 			size = dstsym->st_size;
50 
51 			for (srcobj = dstobj->next;  srcobj != NULL;  srcobj = srcobj->next)
52 				if ((srcsym = symlook_obj(name, hash, srcobj, false)) != NULL)
53 					break;
54 
55 			if (srcobj == NULL) {
56 				_rtld_error("Undefined symbol \"%s\" referenced from COPY"
57 				    " relocation in %s", name, dstobj->path);
58 				return -1;
59 			}
60 
61 			srcaddr = (const void *) (srcobj->relocbase + srcsym->st_value);
62 			memcpy(dstaddr, srcaddr, size);
63 		}
64 	}
65 	return 0;
66 }
67 
68 void _rtld_bind_start(void);
69 void _rtld_relocate_nonplt_self(Elf_Dyn *, Elf_Addr);
70 
71 int open();
72 int _open();
73 void
74 _rtld_relocate_nonplt_self(Elf_Dyn *dynp, Elf_Addr relocbase)
75 {
76 	const Elf_Rel *rel = 0, *rellim;
77 	Elf_Addr relsz = 0;
78 	Elf_Addr *where;
79 	uint32_t size;
80 
81 	for (; dynp->d_tag != DT_NULL; dynp++) {
82 		switch (dynp->d_tag) {
83 		case DT_REL:
84 			rel = (const Elf_Rel *)(relocbase + dynp->d_un.d_ptr);
85 			break;
86 		case DT_RELSZ:
87 			relsz = dynp->d_un.d_val;
88 			break;
89 		}
90 	}
91 	rellim = (const Elf_Rel *)((caddr_t)rel + relsz);
92 	size = (rellim - 1)->r_offset - rel->r_offset;
93 	for (; rel < rellim; rel++) {
94 		where = (Elf_Addr *)(relocbase + rel->r_offset);
95 
96 		*where += (Elf_Addr)relocbase;
97 	}
98 }
99 /*
100  * It is possible for the compiler to emit relocations for unaligned data.
101  * We handle this situation with these inlines.
102  */
103 #define	RELOC_ALIGNED_P(x) \
104 	(((uintptr_t)(x) & (sizeof(void *) - 1)) == 0)
105 
106 static __inline Elf_Addr
107 load_ptr(void *where)
108 {
109 	Elf_Addr res;
110 
111 	memcpy(&res, where, sizeof(res));
112 
113 	return (res);
114 }
115 
116 static __inline void
117 store_ptr(void *where, Elf_Addr val)
118 {
119 
120 	memcpy(where, &val, sizeof(val));
121 }
122 
123 static int
124 reloc_nonplt_object(Obj_Entry *obj, const Elf_Rel *rel, SymCache *cache)
125 {
126 	Elf_Addr        *where;
127 	const Elf_Sym   *def;
128 	const Obj_Entry *defobj;
129 	Elf_Addr         tmp;
130 	unsigned long	 symnum;
131 
132 	where = (Elf_Addr *)(obj->relocbase + rel->r_offset);
133 	symnum = ELF_R_SYM(rel->r_info);
134 
135 	switch (ELF_R_TYPE(rel->r_info)) {
136 	case R_ARM_NONE:
137 		break;
138 
139 #if 1 /* XXX should not occur */
140 	case R_ARM_PC24: {	/* word32 S - P + A */
141 		Elf32_Sword addend;
142 
143 		/*
144 		 * Extract addend and sign-extend if needed.
145 		 */
146 		addend = *where;
147 		if (addend & 0x00800000)
148 			addend |= 0xff000000;
149 
150 		def = find_symdef(symnum, obj, &defobj, false, cache);
151 		if (def == NULL)
152 				return -1;
153 			tmp = (Elf_Addr)obj->relocbase + def->st_value
154 			    - (Elf_Addr)where + (addend << 2);
155 			if ((tmp & 0xfe000000) != 0xfe000000 &&
156 			    (tmp & 0xfe000000) != 0) {
157 				_rtld_error(
158 				"%s: R_ARM_PC24 relocation @ %p to %s failed "
159 				"(displacement %ld (%#lx) out of range)",
160 				    obj->path, where,
161 				    obj->strtab + obj->symtab[symnum].st_name,
162 				    (long) tmp, (long) tmp);
163 				return -1;
164 			}
165 			tmp >>= 2;
166 			*where = (*where & 0xff000000) | (tmp & 0x00ffffff);
167 			dbg("PC24 %s in %s --> %p @ %p in %s",
168 			    obj->strtab + obj->symtab[symnum].st_name,
169 			    obj->path, (void *)*where, where, defobj->path);
170 			break;
171 		}
172 #endif
173 
174 		case R_ARM_ABS32:	/* word32 B + S + A */
175 		case R_ARM_GLOB_DAT:	/* word32 B + S */
176 			def = find_symdef(symnum, obj, &defobj, false, cache);
177 			if (def == NULL)
178 				return -1;
179 			if (__predict_true(RELOC_ALIGNED_P(where))) {
180 				tmp =  *where + (Elf_Addr)defobj->relocbase +
181 				    def->st_value;
182 				*where = tmp;
183 			} else {
184 				tmp = load_ptr(where) +
185 				    (Elf_Addr)defobj->relocbase +
186 				    def->st_value;
187 				store_ptr(where, tmp);
188 			}
189 			dbg("ABS32/GLOB_DAT %s in %s --> %p @ %p in %s",
190 			    obj->strtab + obj->symtab[symnum].st_name,
191 			    obj->path, (void *)tmp, where, defobj->path);
192 			break;
193 
194 		case R_ARM_RELATIVE:	/* word32 B + A */
195 			if (__predict_true(RELOC_ALIGNED_P(where))) {
196 				tmp = *where + (Elf_Addr)obj->relocbase;
197 				*where = tmp;
198 			} else {
199 				tmp = load_ptr(where) +
200 				    (Elf_Addr)obj->relocbase;
201 				store_ptr(where, tmp);
202 			}
203 			dbg("RELATIVE in %s --> %p", obj->path,
204 			    (void *)tmp);
205 			break;
206 
207 		case R_ARM_COPY:
208 			/*
209 			 * These are deferred until all other relocations have
210 			 * been done.  All we do here is make sure that the
211 			 * COPY relocation is not in a shared library.  They
212 			 * are allowed only in executable files.
213 			 */
214 			if (!obj->mainprog) {
215 				_rtld_error(
216 			"%s: Unexpected R_COPY relocation in shared library",
217 				    obj->path);
218 				return -1;
219 			}
220 			dbg("COPY (avoid in main)");
221 			break;
222 
223 		default:
224 			dbg("sym = %lu, type = %lu, offset = %p, "
225 			    "contents = %p, symbol = %s",
226 			    symnum, (u_long)ELF_R_TYPE(rel->r_info),
227 			    (void *)rel->r_offset, (void *)load_ptr(where),
228 			    obj->strtab + obj->symtab[symnum].st_name);
229 			_rtld_error("%s: Unsupported relocation type %ld "
230 			    "in non-PLT relocations\n",
231 			    obj->path, (u_long) ELF_R_TYPE(rel->r_info));
232 			return -1;
233 	}
234 	return 0;
235 }
236 
237 /*
238  *  * Process non-PLT relocations
239  *   */
240 int
241 reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld)
242 {
243 	const Elf_Rel *rellim;
244 	const Elf_Rel *rel;
245 	SymCache *cache;
246 	int bytes = obj->nchains * sizeof(SymCache);
247 	int r = -1;
248 
249 	/* The relocation for the dynamic loader has already been done. */
250 	if (obj == obj_rtld)
251 		return (0);
252 	/*
253  	 * The dynamic loader may be called from a thread, we have
254 	 * limited amounts of stack available so we cannot use alloca().
255 	 */
256 	cache = mmap(NULL, bytes, PROT_READ|PROT_WRITE, MAP_ANON, -1, 0);
257 	if (cache == MAP_FAILED)
258 		cache = NULL;
259 
260 	rellim = (const Elf_Rel *)((caddr_t)obj->rel + obj->relsize);
261 	for (rel = obj->rel; rel < rellim; rel++) {
262 		if (reloc_nonplt_object(obj, rel, cache) < 0)
263 			goto done;
264 	}
265 	r = 0;
266 done:
267 	if (cache) {
268 		munmap(cache, bytes);
269 	}
270 	return (r);
271 }
272 
273 /*
274  *  * Process the PLT relocations.
275  *   */
276 int
277 reloc_plt(Obj_Entry *obj)
278 {
279 	const Elf_Rel *rellim;
280 	const Elf_Rel *rel;
281 
282 	rellim = (const Elf_Rel *)((char *)obj->pltrel +
283 	    obj->pltrelsize);
284 	for (rel = obj->pltrel;  rel < rellim;  rel++) {
285 		Elf_Addr *where;
286 
287 		assert(ELF_R_TYPE(rel->r_info) == R_ARM_JUMP_SLOT);
288 
289 		where = (Elf_Addr *)(obj->relocbase + rel->r_offset);
290 		*where += (Elf_Addr )obj->relocbase;
291 	}
292 
293 	return (0);
294 }
295 
296 /*
297  *  * LD_BIND_NOW was set - force relocation for all jump slots
298  *   */
299 int
300 reloc_jmpslots(Obj_Entry *obj)
301 {
302 	const Obj_Entry *defobj;
303 	const Elf_Rel *rellim;
304 	const Elf_Rel *rel;
305 	const Elf_Sym *def;
306 	Elf_Addr *where;
307 	Elf_Addr target;
308 
309 	rellim = (const Elf_Rel *)((char *)obj->pltrel + obj->pltrelsize);
310 	for (rel = obj->pltrel; rel < rellim; rel++) {
311 		assert(ELF_R_TYPE(rel->r_info) == R_ARM_JUMP_SLOT);
312 		where = (Elf_Addr *)(obj->relocbase + rel->r_offset);
313 		def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj,
314 		    true, NULL);
315 		if (def == NULL) {
316 			dbg("reloc_jmpslots: sym not found");
317 			return (-1);
318 		}
319 
320 		target = (Elf_Addr)(defobj->relocbase + def->st_value);
321 		reloc_jmpslot(where, target, defobj, obj,
322 		    (const Elf_Rel *) rel);
323 	}
324 
325 	obj->jmpslots_done = true;
326 
327 	return (0);
328 }
329 
330 Elf_Addr
331 reloc_jmpslot(Elf_Addr *where, Elf_Addr target, const Obj_Entry *defobj,
332     		const Obj_Entry *obj, const Elf_Rel *rel)
333 {
334 
335 	assert(ELF_R_TYPE(rel->r_info) == R_ARM_JUMP_SLOT);
336 
337 	if (*where != target)
338 		*where = target;
339 
340 	return target;
341 }
342 
343 void
344 allocate_initial_tls(Obj_Entry *objs)
345 {
346 
347 }
348 
349 void *
350 __tls_get_addr(tls_index* ti)
351 {
352 	return (NULL);
353 }
354