xref: /netbsd/libexec/ld.elf_so/arch/sh3/mdreloc.c (revision c4a72b64)
1 /*	$NetBSD: mdreloc.c,v 1.14 2002/10/03 20:39:23 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 
11 void
12 _rtld_setup_pltgot(const Obj_Entry *obj)
13 {
14 	obj->pltgot[1] = (Elf_Addr) obj;
15 	obj->pltgot[2] = (Elf_Addr) &_rtld_bind_start;
16 }
17 
18 int
19 _rtld_relocate_nonplt_objects(obj)
20 	const Obj_Entry *obj;
21 {
22 	const Elf_Rela *rela;
23 
24 	for (rela = obj->rela; rela < obj->relalim; rela++) {
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 + rela->r_offset);
32 		symnum = ELF_R_SYM(rela->r_info);
33 
34 		switch (ELF_R_TYPE(rela->r_info)) {
35 		case R_TYPE(NONE):
36 			break;
37 
38 #if 1 /* XXX should not occur */
39 		case R_TYPE(GOT32):
40 			def = _rtld_find_symdef(symnum, obj, &defobj, false);
41 			if (def == NULL)
42 				return -1;
43 
44 			tmp = (Elf_Addr)(defobj->relocbase + def->st_value +
45 			    rela->r_addend);
46 			if (*where != tmp)
47 				*where = tmp;
48 			rdbg(("GOT32 %s in %s --> %p in %s",
49 			    obj->strtab + obj->symtab[symnum].st_name,
50 			    obj->path, (void *)*where, defobj->path));
51 			break;
52 
53 		case R_TYPE(REL32):
54 			def = _rtld_find_symdef(symnum, obj, &defobj, false);
55 			if (def == NULL)
56 				return -1;
57 
58 			*where += (Elf_Addr)(defobj->relocbase + def->st_value +
59 			    rela->r_addend) - (Elf_Addr)where;
60 			rdbg(("PC32 %s in %s --> %p in %s",
61 			    obj->strtab + obj->symtab[symnum].st_name,
62 			    obj->path, (void *)*where, defobj->path));
63 			break;
64 #endif
65 
66 		case R_TYPE(DIR32):
67 			def = _rtld_find_symdef(symnum, obj, &defobj, false);
68 			if (def == NULL)
69 				return -1;
70 
71 			*where += (Elf_Addr)(defobj->relocbase + def->st_value +
72 			    rela->r_addend);
73 			rdbg(("32 %s in %s --> %p in %s",
74 			    obj->strtab + obj->symtab[symnum].st_name,
75 			    obj->path, (void *)*where, defobj->path));
76 			break;
77 
78 		case R_TYPE(GLOB_DAT):
79 			def = _rtld_find_symdef(symnum, obj, &defobj, false);
80 			if (def == NULL)
81 				return -1;
82 
83 			tmp = (Elf_Addr)(defobj->relocbase + def->st_value) +
84 			    rela->r_addend;
85 			if (*where != tmp)
86 				*where = tmp;
87 			rdbg(("GLOB_DAT %s in %s --> %p in %s",
88 			    obj->strtab + obj->symtab[symnum].st_name,
89 			    obj->path, (void *)*where, defobj->path));
90 			break;
91 
92 		case R_TYPE(RELATIVE):
93 			if (rela->r_addend)
94 				*where = (Elf_Addr)obj->relocbase + rela->r_addend;
95 			else
96 				*where += (Elf_Addr)obj->relocbase;
97 			rdbg(("RELATIVE in %s --> %p", obj->path,
98 			    (void *)*where));
99 			break;
100 
101 		case R_TYPE(COPY):
102 			/*
103 			 * These are deferred until all other relocations have
104 			 * been done.  All we do here is make sure that the
105 			 * COPY relocation is not in a shared library.  They
106 			 * are allowed only in executable files.
107 			 */
108 			if (obj->isdynamic) {
109 				_rtld_error(
110 			"%s: Unexpected R_COPY relocation in shared library",
111 				    obj->path);
112 				return -1;
113 			}
114 			rdbg(("COPY (avoid in main)"));
115 			break;
116 
117 		default:
118 			rdbg(("sym = %lu, type = %lu, offset = %p, "
119 			    "addend = %p, contents = %p, symbol = %s",
120 			    symnum, (u_long)ELF_R_TYPE(rela->r_info),
121 			    (void *)rela->r_offset, (void *)rela->r_addend,
122 			    (void *)*where,
123 			    obj->strtab + obj->symtab[symnum].st_name));
124 			_rtld_error("%s: Unsupported relocation type %ld "
125 			    "in non-PLT relocations\n",
126 			    obj->path, (u_long) ELF_R_TYPE(rela->r_info));
127 			return -1;
128 		}
129 	}
130 	return 0;
131 }
132 
133 int
134 _rtld_relocate_plt_lazy(obj)
135 	const Obj_Entry *obj;
136 {
137 	const Elf_Rela *rela;
138 
139 	if (!obj->relocbase)
140 		return 0;
141 
142 	for (rela = obj->pltrela; rela < obj->pltrelalim; rela++) {
143 		Elf_Addr *where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
144 
145 		assert(ELF_R_TYPE(rela->r_info) == R_TYPE(JMP_SLOT));
146 
147 		/* Just relocate the GOT slots pointing into the PLT */
148 		*where += (Elf_Addr)obj->relocbase;
149 		rdbg(("fixup !main in %s --> %p", obj->path, (void *)*where));
150 	}
151 
152 	return 0;
153 }
154 
155 int
156 _rtld_relocate_plt_object(obj, rela, addrp)
157 	const Obj_Entry *obj;
158 	const Elf_Rela *rela;
159 	caddr_t *addrp;
160 {
161 	Elf_Addr *where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
162 	Elf_Addr new_value;
163 	const Elf_Sym  *def;
164 	const Obj_Entry *defobj;
165 
166 	assert(ELF_R_TYPE(rela->r_info) == R_TYPE(JMP_SLOT));
167 
168 	def = _rtld_find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, true);
169 	if (def == NULL)
170 		return -1;
171 
172 	new_value = (Elf_Addr)(defobj->relocbase + def->st_value +
173 	    rela->r_addend);
174 	rdbg(("bind now/fixup in %s --> old=%p new=%p",
175 	    defobj->strtab + def->st_name, (void *)*where, (void *)new_value));
176 	if (*where != new_value)
177 		*where = new_value;
178 
179 	*addrp = (caddr_t)new_value;
180 	return 0;
181 }
182