1 /* $OpenBSD: rtld_machine.c,v 1.35 2022/01/08 06:49:42 guenther Exp $ */
2
3 /*
4 * Copyright (c) 1998-2004 Opsycon AB, Sweden.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
16 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
19 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 */
28
29 #define _DYN_LOADER
30
31 #include <sys/types.h>
32 #include <sys/exec_elf.h>
33 #include <sys/syscall.h>
34 #include <sys/unistd.h>
35
36 #include <machine/reloc.h>
37
38 #include "util.h"
39 #include "resolve.h"
40
41 int64_t pcookie __attribute__((section(".openbsd.randomdata"))) __dso_hidden;
42
43 static inline void
_dl_reloc_ent(Elf_Addr r_addr,Elf_Addr value)44 _dl_reloc_ent(Elf_Addr r_addr, Elf_Addr value)
45 {
46 if ((r_addr & 7) == 0)
47 *(u_int64_t *)r_addr += value;
48 else {
49 /*
50 * XXX Handle non aligned relocs. .eh_frame
51 * XXX in libstdc++ seems to have them...
52 */
53 u_int64_t robj;
54
55 _dl_bcopy((char *)r_addr, &robj, sizeof(robj));
56 robj += value;
57 _dl_bcopy(&robj, (char *)r_addr, sizeof(robj));
58 }
59 }
60
61 int
_dl_md_reloc(elf_object_t * object,int rel,int relsz)62 _dl_md_reloc(elf_object_t *object, int rel, int relsz)
63 {
64 int i;
65 int numrel;
66 int fails = 0;
67 Elf_Addr loff;
68 Elf_Rel *relocs;
69 const Elf_Sym *sym, *this;
70 Elf_Addr prev_value = 0;
71 const Elf_Sym *prev_sym = NULL;
72
73 loff = object->obj_base;
74 numrel = object->Dyn.info[relsz] / sizeof(Elf_Rel);
75 relocs = (Elf_Rel *)(object->Dyn.info[rel]);
76
77 if (relocs == NULL)
78 return 0;
79
80 DL_DEB(("relocating %d\n", numrel));
81 for (i = 0; i < numrel; i++, relocs++) {
82 Elf_Addr r_addr = relocs->r_offset + loff;
83 const char *symn;
84
85 if (ELF_R_SYM(relocs->r_info) == 0xffffff)
86 continue;
87
88 sym = object->dyn.symtab;
89 sym += ELF_R_SYM(relocs->r_info);
90 symn = object->dyn.strtab + sym->st_name;
91
92 this = NULL;
93 if (ELF_R_SYM(relocs->r_info)) {
94 if (sym == prev_sym)
95 this = sym; /* XXX non-NULL */
96 else if (!(ELF_ST_BIND(sym->st_info) == STB_LOCAL &&
97 ELF_ST_TYPE (sym->st_info) == STT_NOTYPE)) {
98 struct sym_res sr;
99
100 sr = _dl_find_symbol(symn,
101 SYM_SEARCH_ALL | SYM_WARNNOTFOUND | SYM_PLT,
102 sym, object);
103
104 if (sr.sym == NULL) {
105 if (ELF_ST_BIND(sym->st_info) !=
106 STB_WEAK)
107 fails++;
108 continue;
109 }
110 prev_sym = sym;
111 prev_value = sr.obj->obj_base +
112 sr.sym->st_value;
113 this = sym; /* XXX non-NULL */
114 }
115 }
116
117 switch (ELF_R_TYPE(relocs->r_info)) {
118 case R_MIPS_REL32_64:
119 if (ELF_ST_BIND(sym->st_info) == STB_LOCAL &&
120 (ELF_ST_TYPE(sym->st_info) == STT_SECTION ||
121 ELF_ST_TYPE(sym->st_info) == STT_NOTYPE) )
122 _dl_reloc_ent(r_addr, loff + sym->st_value);
123 else if (this)
124 _dl_reloc_ent(r_addr, prev_value);
125 break;
126
127 case R_MIPS_NONE:
128 break;
129
130 default:
131 _dl_die("unsupported relocation '%llu'",
132 ELF_R_TYPE(relocs->r_info));
133 }
134 }
135
136 DL_DEB(("done %d fails\n", fails));
137 return fails;
138 }
139
140 extern void _dl_bind_start(void);
141
142 /*
143 * Relocate the Global Offset Table (GOT). Currently we don't
144 * do lazy evaluation here because the GNU linker doesn't
145 * follow the ABI spec which says that if an external symbol
146 * is referenced by other relocations than CALL16 and 26 it
147 * should not be given a stub and have a zero value in the
148 * symbol table. By not doing so, we can't use pointers to
149 * external functions and use them in comparisons...
150 */
151 int
_dl_md_reloc_got(elf_object_t * object,int lazy)152 _dl_md_reloc_got(elf_object_t *object, int lazy)
153 {
154 int i, n;
155 Elf_Addr loff;
156 Elf_Addr *gotp;
157 const Elf_Sym *symp;
158 const char *strt;
159
160 if (object->status & STAT_GOT_DONE)
161 return 0;
162
163 loff = object->obj_base;
164 strt = object->dyn.strtab;
165 gotp = object->dyn.pltgot;
166 n = object->Dyn.info[DT_MIPS_LOCAL_GOTNO - DT_LOPROC + DT_NUM];
167
168 DL_DEB(("loff: 0x%lx\n", (unsigned long)loff));
169 /*
170 * Set up pointers for run time (lazy) resolving.
171 */
172 gotp[0] = (long)_dl_bind_start;
173 gotp[1] = (long)object;
174
175 /* First do all local references. */
176 for (i = 2; i < n; i++) {
177 gotp[i] += loff;
178 }
179
180 gotp += n;
181
182 symp = object->dyn.symtab;
183 symp += object->Dyn.info[DT_MIPS_GOTSYM - DT_LOPROC + DT_NUM];
184 n = object->Dyn.info[DT_MIPS_SYMTABNO - DT_LOPROC + DT_NUM] -
185 object->Dyn.info[DT_MIPS_GOTSYM - DT_LOPROC + DT_NUM];
186
187 /*
188 * Then do all global references according to the ABI.
189 * Quickstart is not yet implemented.
190 */
191 while (n--) {
192 const char *symn = strt + symp->st_name;
193 struct sym_res sr;
194
195 if (symp->st_shndx == SHN_UNDEF &&
196 ELF_ST_TYPE(symp->st_info) == STT_FUNC) {
197 if (symp->st_value == 0 || !lazy) {
198 sr = _dl_find_symbol(symn,
199 SYM_SEARCH_ALL|SYM_NOWARNNOTFOUND|SYM_PLT,
200 symp, object);
201 if (sr.sym)
202 *gotp = sr.sym->st_value +
203 sr.obj->obj_base;
204 } else
205 *gotp = symp->st_value + loff;
206 } else if (symp->st_shndx == SHN_COMMON ||
207 symp->st_shndx == SHN_UNDEF) {
208 sr = _dl_find_symbol(symn,
209 SYM_SEARCH_ALL|SYM_NOWARNNOTFOUND|SYM_PLT,
210 symp, object);
211 if (sr.sym)
212 *gotp = sr.sym->st_value + sr.obj->obj_base;
213 } else if ((ELF_ST_TYPE(symp->st_info) == STT_FUNC &&
214 symp->st_value != *gotp) ||
215 ELF_ST_VISIBILITY(symp->st_other) == STV_PROTECTED) {
216 *gotp += loff;
217 } else { /* Resolve all others immediately */
218 sr = _dl_find_symbol(symn,
219 SYM_SEARCH_ALL|SYM_NOWARNNOTFOUND|SYM_PLT,
220 symp, object);
221 if (sr.sym)
222 *gotp = sr.sym->st_value + sr.obj->obj_base;
223 else
224 *gotp = symp->st_value + loff;
225 }
226 gotp++;
227 symp++;
228 }
229 object->status |= STAT_GOT_DONE;
230
231 return 0;
232 }
233
234 Elf_Addr
_dl_bind(elf_object_t * object,int symidx)235 _dl_bind(elf_object_t *object, int symidx)
236 {
237 Elf_Addr *gotp = object->dyn.pltgot;
238 struct sym_res sr;
239 const Elf_Sym *sym;
240 const char *symn;
241 int64_t cookie = pcookie;
242 struct {
243 struct __kbind param;
244 Elf_Addr newval;
245 } buf;
246 int n;
247
248 sym = object->dyn.symtab;
249 sym += symidx;
250 symn = object->dyn.strtab + sym->st_name;
251 n = object->Dyn.info[DT_MIPS_LOCAL_GOTNO - DT_LOPROC + DT_NUM] -
252 object->Dyn.info[DT_MIPS_GOTSYM - DT_LOPROC + DT_NUM];
253
254 sr = _dl_find_symbol(symn, SYM_SEARCH_ALL|SYM_WARNNOTFOUND|SYM_PLT,
255 sym, object);
256 if (sr.sym == NULL)
257 _dl_die("lazy binding failed!");
258
259 buf.newval = sr.obj->obj_base + sr.sym->st_value;
260
261 if (__predict_false(sr.obj->traced) && _dl_trace_plt(sr.obj, symn))
262 return buf.newval;
263
264 buf.param.kb_addr = &gotp[n + symidx];
265 buf.param.kb_size = sizeof(Elf_Addr);
266
267 /* directly code the syscall, so that it's actually inline here */
268 {
269 register long syscall_num __asm("v0") = SYS_kbind;
270 register void *arg1 __asm("a0") = &buf;
271 register long arg2 __asm("a1") = sizeof(buf);
272 register long arg3 __asm("a2") = cookie;
273
274 __asm volatile("syscall" : "+r" (syscall_num)
275 : "r" (arg1), "r" (arg2), "r" (arg3)
276 : "v1", "a3", "memory");
277 }
278
279 return buf.newval;
280 }
281