xref: /netbsd-src/sys/arch/acorn32/stand/lib/rmreloc.c (revision 53524e44efd7c7176da8dc8190a698b2fe184db1)
1 /* $NetBSD: rmreloc.c,v 1.3 2007/03/04 05:59:07 christos Exp $ */
2 
3 /*
4  * Copyright 1996 John D. Polstra.
5  * Copyright 1996 Matt Thomas <matt@3am-software.com>
6  * Copyright 2002 Charles M. Hannum <root@ihack.net>
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  * 3. All advertising materials mentioning features or use of this software
18  *    must display the following acknowledgement:
19  *      This product includes software developed by John Polstra.
20  * 4. The name of the author may not be used to endorse or promote products
21  *    derived from this software without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
24  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
27  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
28  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
32  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33  */
34 /*
35  * rmreloc.c - relocate an ELFish RISC OS relocatable module.
36  */
37 /*
38  * This code is a heavily hacked version of parts of:
39  * lib/libexec/ld.elf_so/headers.c
40  * lib/libexec/ld.elf_so/arch/arm/mdreloc.c
41  *
42  * At present it only deals with DT_REL tables containing R_ARM_NONE
43  * and R_ARM_RELATIVE relocations, because those are all that my
44  * linker emits.  More can be added as needed.  Note that this has to
45  * handle relocating already-relocated code, e.g. after *RMTidy, so
46  * most relocations have to reference oldbase, which ld.elf_so just
47  * assumes is zero.  There may be a cleverer way to do this.
48  */
49 
50 #include <sys/types.h>
51 #include <sys/stdint.h>
52 #include <lib/libsa/stand.h>
53 #define ELFSIZE 32
54 #include <sys/exec_elf.h>
55 
56 #include <riscoscalls.h>
57 
58 os_error *relocate_self(Elf_Dyn *, void *, void *);
59 
60 #define assert(x) /* nothing */
61 
62 /*
63  * While relocating ourselves, we must not refer to any global variables.
64  * This includes _DYNAMIC -- the startup code finds it for us and passes
65  * it to us along with the base address of the module.
66  */
67 
68 typedef struct {
69 	void *        relocbase;	/* Reloc const = mapbase - *vaddrbase */
70 	Elf_Dyn        *dynamic;	/* Dynamic section */
71 	const Elf_Rel  *rel;		/* Relocation entries */
72 	const Elf_Rel  *rellim;		/* Limit of Relocation entries */
73 } Obj_Entry;
74 
75 #define rdbg(x) /* nothing */
76 
77 /*
78  * It is possible for the compiler to emit relocations for unaligned data.
79  * We handle this situation with these inlines.
80  */
81 #define	RELOC_ALIGNED_P(x) \
82 	(((uintptr_t)(x) & (sizeof(void *) - 1)) == 0)
83 
84 static inline Elf_Addr
load_ptr(void * where)85 load_ptr(void *where)
86 {
87 	Elf_Addr res;
88 
89 	memcpy(&res, where, sizeof(res));
90 
91 	return (res);
92 }
93 
94 static inline void
store_ptr(void * where,Elf_Addr val)95 store_ptr(void *where, Elf_Addr val)
96 {
97 
98 	memcpy(where, &val, sizeof(val));
99 }
100 
101 static struct os_error bad_reloc = {
102 	0, "Unhandled ELF redirection"
103 };
104 
105 os_error *
relocate_self(Elf_Dyn * dynamic,void * oldbase,void * newbase)106 relocate_self(Elf_Dyn *dynamic, void *oldbase, void *newbase)
107 {
108 	Elf_Dyn *dynp;
109 	Obj_Entry o = { 0 };
110 	Obj_Entry *obj;
111 	const Elf_Rel *rel;
112 	Elf_Addr        relsz = 0;
113 
114 	obj = &o; obj->dynamic = dynamic; obj->relocbase = newbase;
115 
116 	for (dynp = obj->dynamic; dynp->d_tag != DT_NULL; ++dynp) {
117 		switch (dynp->d_tag) {
118 		case DT_REL:
119 			obj->rel = (const Elf_Rel *)
120 			    (obj->relocbase + dynp->d_un.d_ptr);
121 			break;
122 		case DT_RELSZ:
123 			relsz = dynp->d_un.d_val;
124 			break;
125 		case DT_RELENT:
126 			assert(dynp->d_un.d_val == sizeof(Elf_Rel));
127 			break;
128 		}
129 	}
130 
131 	obj->rellim = (const Elf_Rel *)((void *)obj->rel + relsz);
132 
133 	for (rel = obj->rel; rel < obj->rellim; rel++) {
134 		Elf_Addr        *where;
135 		Elf_Addr         tmp;
136 
137 		where = (Elf_Addr *)(obj->relocbase + rel->r_offset);
138 
139 		switch (ELF_R_TYPE(rel->r_info)) {
140 		case R_TYPE(NONE):
141 			break;
142 
143 		case R_TYPE(RELATIVE):	/* word32 B + A */
144 			if (__predict_true(RELOC_ALIGNED_P(where))) {
145 				tmp = *where + (Elf_Addr)obj->relocbase -
146 				    (Elf_Addr)oldbase;
147 				*where = tmp;
148 			} else {
149 				tmp = load_ptr(where) +
150 				    (Elf_Addr)obj->relocbase -
151 				    (Elf_Addr)oldbase;
152 				store_ptr(where, tmp);
153 			}
154 			rdbg(("RELATIVE in %s --> %p", obj->path,
155 			    (void *)tmp));
156 			break;
157 
158 		default:
159 			return &bad_reloc;
160 		}
161 	}
162 	return NULL;
163 }
164