1 /* $OpenBSD: rtld_machine.c,v 1.71 2022/01/08 06:49:41 guenther Exp $ */
2
3 /*
4 * Copyright (c) 1999 Dale Rahn
5 * Copyright (c) 2001 Niklas Hallqvist
6 * Copyright (c) 2001 Artur Grabowski
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
18 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 */
30
31 #define _DYN_LOADER
32
33 #include <sys/types.h>
34 #include <sys/exec_elf.h>
35 #include <sys/syscall.h>
36 #include <sys/unistd.h>
37
38 #include <machine/pal.h>
39 #include <machine/reloc.h>
40
41 #include "util.h"
42 #include "resolve.h"
43
44 #define DT_PROC(n) ((n) - DT_LOPROC + DT_NUM)
45
46 int64_t pcookie __attribute__((section(".openbsd.randomdata"))) __dso_hidden;
47
48 int
_dl_md_reloc(elf_object_t * object,int rel,int relasz)49 _dl_md_reloc(elf_object_t *object, int rel, int relasz)
50 {
51 long i;
52 long numrela;
53 long relrel;
54 int fails = 0;
55 Elf_Addr loff;
56 Elf_Addr prev_value = 0;
57 const Elf_Sym *prev_sym = NULL;
58 Elf_RelA *relas;
59
60 loff = object->obj_base;
61 numrela = object->Dyn.info[relasz] / sizeof(Elf_RelA);
62 relrel = rel == DT_RELA ? object->relacount : 0;
63 relas = (Elf_RelA *)(object->Dyn.info[rel]);
64
65 if (relas == NULL)
66 return 0;
67
68 if (relrel > numrela)
69 _dl_die("relacount > numrel: %ld > %ld", relrel, numrela);
70
71 if (! object->Dyn.info[DT_PROC(DT_ALPHA_PLTRO)])
72 _dl_die("unsupported insecure PLT object");
73
74 /* tight loop for leading RELATIVE relocs */
75 for (i = 0; i < relrel; i++, relas++) {
76 Elf_Addr *r_addr;
77
78 r_addr = (Elf_Addr *)(relas->r_offset + loff);
79
80 /* Handle unaligned RELATIVE relocs */
81 if ((((Elf_Addr)r_addr) & 0x7) != 0) {
82 Elf_Addr tmp;
83 _dl_bcopy(r_addr, &tmp, sizeof(Elf_Addr));
84 tmp += loff;
85 _dl_bcopy(&tmp, r_addr, sizeof(Elf_Addr));
86 } else
87 *r_addr += loff;
88 }
89 for (; i < numrela; i++, relas++) {
90 Elf_Addr *r_addr;
91 struct sym_res sr;
92 const Elf_Sym *sym;
93 const char *symn;
94
95 r_addr = (Elf_Addr *)(relas->r_offset + loff);
96
97 if (ELF_R_SYM(relas->r_info) == 0xffffffff)
98 continue;
99
100
101 sym = object->dyn.symtab;
102 sym += ELF_R_SYM(relas->r_info);
103 symn = object->dyn.strtab + sym->st_name;
104
105 switch (ELF_R_TYPE(relas->r_info)) {
106 case R_TYPE(REFQUAD):
107 sr = _dl_find_symbol(symn,
108 SYM_SEARCH_ALL|SYM_WARNNOTFOUND|SYM_NOTPLT,
109 sym, object);
110 if (sr.sym == NULL)
111 goto resolve_failed;
112 *r_addr += sr.obj->obj_base + sr.sym->st_value +
113 relas->r_addend;
114 break;
115 case R_TYPE(RELATIVE):
116 /*
117 * There is a lot of unaligned RELATIVE
118 * relocs generated by gcc in the exception handlers.
119 */
120 if ((((Elf_Addr) r_addr) & 0x7) != 0) {
121 Elf_Addr tmp;
122 #if 0
123 _dl_printf("unaligned RELATIVE: %p type: %d %s 0x%lx -> 0x%lx\n", r_addr,
124 ELF_R_TYPE(relas->r_info), object->load_name, *r_addr, *r_addr+loff);
125 #endif
126 _dl_bcopy(r_addr, &tmp, sizeof(Elf_Addr));
127 tmp += loff;
128 _dl_bcopy(&tmp, r_addr, sizeof(Elf_Addr));
129 } else
130 *r_addr += loff;
131 break;
132 case R_TYPE(JMP_SLOT):
133 sr = _dl_find_symbol(symn,
134 SYM_SEARCH_ALL|SYM_WARNNOTFOUND|SYM_PLT,
135 sym, object);
136 if (sr.sym == NULL)
137 goto resolve_failed;
138 *r_addr = sr.obj->obj_base + sr.sym->st_value +
139 relas->r_addend;
140 break;
141 case R_TYPE(GLOB_DAT):
142 if (sym == prev_sym) {
143 *r_addr = prev_value + relas->r_addend;
144 break;
145 }
146 sr = _dl_find_symbol(symn,
147 SYM_SEARCH_ALL|SYM_WARNNOTFOUND|SYM_NOTPLT,
148 sym, object);
149 if (sr.sym == NULL)
150 goto resolve_failed;
151 prev_sym = sym;
152 prev_value = sr.obj->obj_base + sr.sym->st_value;
153 *r_addr = prev_value + relas->r_addend;
154 break;
155 case R_TYPE(NONE):
156 break;
157 default:
158 _dl_die("%s: unsupported relocation '%s' %lld at %p",
159 object->load_name, symn,
160 ELF_R_TYPE(relas->r_info), (void *)r_addr);
161 }
162 continue;
163 resolve_failed:
164 if (ELF_ST_BIND(sym->st_info) != STB_WEAK)
165 fails++;
166 }
167 __asm volatile("imb" : : : "memory");
168
169 return fails;
170 }
171
172 /*
173 * Resolve a symbol at run-time.
174 */
175 Elf_Addr
_dl_bind(elf_object_t * object,int reloff)176 _dl_bind(elf_object_t *object, int reloff)
177 {
178 Elf_RelA *rela;
179 struct sym_res sr;
180 const Elf_Sym *sym;
181 const char *symn;
182 uint64_t cookie = pcookie;
183 struct {
184 struct __kbind param;
185 Elf_Addr newval;
186 } buf;
187
188 rela = (Elf_RelA *)(object->Dyn.info[DT_JMPREL] + reloff);
189
190 sym = object->dyn.symtab;
191 sym += ELF_R_SYM(rela->r_info);
192 symn = object->dyn.strtab + sym->st_name;
193
194 sr = _dl_find_symbol(symn, SYM_SEARCH_ALL|SYM_WARNNOTFOUND|SYM_PLT,
195 sym, object);
196 if (sr.sym == NULL)
197 _dl_die("lazy binding failed!");
198
199 buf.newval = sr.obj->obj_base + sr.sym->st_value + rela->r_addend;
200
201 if (__predict_false(sr.obj->traced) && _dl_trace_plt(sr.obj, symn))
202 return buf.newval;
203
204 buf.param.kb_addr = (Elf_Addr *)(object->obj_base + rela->r_offset);
205 buf.param.kb_size = sizeof(Elf_Addr);
206
207 /* directly code the syscall, so that it's actually inline here */
208 {
209 register long syscall_num __asm("$0") /* v0 */ = SYS_kbind;
210 register void *arg1 __asm("$16") /* a0 */ = &buf;
211 register long arg2 __asm("$17") /* a1 */ = sizeof(buf);
212 register long arg3 __asm("$18") /* a2 */ = cookie;
213
214 __asm volatile( "call_pal %1" : "+r" (syscall_num)
215 : "i" (PAL_OSF1_callsys), "r" (arg1), "r" (arg2),
216 "r" (arg3) : "$19", "$20", "memory");
217 }
218
219 return buf.newval;
220 }
221
222 void _dl_bind_start(void) __dso_hidden; /* XXX */
223
224 /*
225 * Relocate the Global Offset Table (GOT).
226 */
227 int
_dl_md_reloc_got(elf_object_t * object,int lazy)228 _dl_md_reloc_got(elf_object_t *object, int lazy)
229 {
230 int fails = 0;
231 Elf_Addr *pltgot;
232
233 if (object->Dyn.info[DT_PLTREL] != DT_RELA)
234 return 0;
235
236 pltgot = (Elf_Addr *)object->Dyn.info[DT_PLTGOT];
237
238 if (!lazy || pltgot == NULL) {
239 fails = _dl_md_reloc(object, DT_JMPREL, DT_PLTRELSZ);
240 } else {
241 if (object->obj_base != 0) {
242 int i, size;
243 Elf_Addr *addr;
244 Elf_RelA *rela;
245
246 size = object->Dyn.info[DT_PLTRELSZ] /
247 sizeof(Elf_RelA);
248 rela = (Elf_RelA *)(object->Dyn.info[DT_JMPREL]);
249
250 for (i = 0; i < size; i++) {
251 addr = (Elf_Addr *)(object->obj_base +
252 rela[i].r_offset);
253 *addr += object->obj_base;
254 }
255 }
256 pltgot[0] = (Elf_Addr)_dl_bind_start;
257 pltgot[1] = (Elf_Addr)object;
258 }
259
260 return fails;
261 }
262