xref: /openbsd/libexec/ld.so/alpha/rtld_machine.c (revision d6b8755e)
1 /*	$OpenBSD: rtld_machine.c,v 1.68 2019/10/05 00:08:50 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/mman.h>
35 #include <sys/exec.h>
36 #include <sys/syscall.h>
37 #include <sys/unistd.h>
38 #include <machine/pal.h>
39 
40 #include <nlist.h>
41 #include <link.h>
42 
43 #include "syscall.h"
44 #include "archdep.h"
45 #include "resolve.h"
46 
47 #define	DT_PROC(n)	((n) - DT_LOPROC + DT_NUM)
48 
49 int64_t pcookie __attribute__((section(".openbsd.randomdata"))) __dso_hidden;
50 
51 int
52 _dl_md_reloc(elf_object_t *object, int rel, int relasz)
53 {
54 	long	i;
55 	long	numrela;
56 	long	relrel;
57 	int	fails = 0;
58 	Elf64_Addr loff;
59 	Elf64_Addr prev_value = 0;
60 	const Elf_Sym *prev_sym = NULL;
61 	Elf64_Rela  *relas;
62 
63 	loff = object->obj_base;
64 	numrela = object->Dyn.info[relasz] / sizeof(Elf64_Rela);
65 	relrel = rel == DT_RELA ? object->relacount : 0;
66 	relas = (Elf64_Rela *)(object->Dyn.info[rel]);
67 
68 	if (relas == NULL)
69 		return(0);
70 
71 	if (relrel > numrela)
72 		_dl_die("relacount > numrel: %ld > %ld", relrel, numrela);
73 
74 	if (! object->Dyn.info[DT_PROC(DT_ALPHA_PLTRO)])
75 		_dl_die("unsupported insecure PLT object");
76 
77 	/* tight loop for leading RELATIVE relocs */
78 	for (i = 0; i < relrel; i++, relas++) {
79 		Elf_Addr *r_addr;
80 
81 		r_addr = (Elf64_Addr *)(relas->r_offset + loff);
82 
83 		/* Handle unaligned RELATIVE relocs */
84 		if ((((Elf_Addr)r_addr) & 0x7) != 0) {
85 			Elf_Addr tmp;
86 			_dl_bcopy(r_addr, &tmp, sizeof(Elf_Addr));
87 			tmp += loff;
88 			_dl_bcopy(&tmp, r_addr, sizeof(Elf_Addr));
89 		} else
90 			*r_addr += loff;
91 	}
92 	for (; i < numrela; i++, relas++) {
93 		Elf64_Addr *r_addr;
94 		struct sym_res sr;
95 		const Elf64_Sym *sym;
96 		const char *symn;
97 
98 		r_addr = (Elf64_Addr *)(relas->r_offset + loff);
99 
100 		if (ELF64_R_SYM(relas->r_info) == 0xffffffff)
101 			continue;
102 
103 
104 		sym = object->dyn.symtab;
105 		sym += ELF64_R_SYM(relas->r_info);
106 		symn = object->dyn.strtab + sym->st_name;
107 
108 		switch (ELF64_R_TYPE(relas->r_info)) {
109 		case R_TYPE(REFQUAD):
110 			sr = _dl_find_symbol(symn,
111 			    SYM_SEARCH_ALL|SYM_WARNNOTFOUND|SYM_NOTPLT,
112 			    sym, object);
113 			if (sr.sym == NULL)
114 				goto resolve_failed;
115 			*r_addr += sr.obj->obj_base + sr.sym->st_value +
116 			    relas->r_addend;
117 			break;
118 		case R_TYPE(RELATIVE):
119 			/*
120 			 * There is a lot of unaligned RELATIVE
121 			 * relocs generated by gcc in the exception handlers.
122 			 */
123 			if ((((Elf_Addr) r_addr) & 0x7) != 0) {
124 				Elf_Addr tmp;
125 #if 0
126 _dl_printf("unaligned RELATIVE: %p type: %d %s 0x%lx -> 0x%lx\n", r_addr,
127     ELF_R_TYPE(relas->r_info), object->load_name, *r_addr, *r_addr+loff);
128 #endif
129 				_dl_bcopy(r_addr, &tmp, sizeof(Elf_Addr));
130 				tmp += loff;
131 				_dl_bcopy(&tmp, r_addr, sizeof(Elf_Addr));
132 			} else
133 				*r_addr += loff;
134 			break;
135 		case R_TYPE(JMP_SLOT):
136 			sr = _dl_find_symbol(symn,
137 			    SYM_SEARCH_ALL|SYM_WARNNOTFOUND|SYM_PLT,
138 			    sym, object);
139 			if (sr.sym == NULL)
140 				goto resolve_failed;
141 			*r_addr = sr.obj->obj_base + sr.sym->st_value +
142 			    relas->r_addend;
143 			break;
144 		case R_TYPE(GLOB_DAT):
145 			if (sym == prev_sym) {
146 				*r_addr = prev_value + relas->r_addend;
147 				break;
148 			}
149 			sr = _dl_find_symbol(symn,
150 			    SYM_SEARCH_ALL|SYM_WARNNOTFOUND|SYM_NOTPLT,
151 			    sym, object);
152 			if (sr.sym == NULL)
153 				goto resolve_failed;
154 			prev_sym = sym;
155 			prev_value = sr.obj->obj_base + sr.sym->st_value;
156 			*r_addr = prev_value + relas->r_addend;
157 			break;
158 		case R_TYPE(NONE):
159 			break;
160 		default:
161 			_dl_die("%s: unsupported relocation '%s' %lld at %p",
162 			    object->load_name, symn,
163 			    ELF64_R_TYPE(relas->r_info), (void *)r_addr);
164 		}
165 		continue;
166 resolve_failed:
167 		if (ELF_ST_BIND(sym->st_info) != STB_WEAK)
168 			fails++;
169 	}
170 	__asm volatile("imb" : : : "memory");
171 
172 	return (fails);
173 }
174 
175 /*
176  * Resolve a symbol at run-time.
177  */
178 Elf_Addr
179 _dl_bind(elf_object_t *object, int reloff)
180 {
181 	Elf_RelA *rela;
182 	struct sym_res sr;
183 	const Elf_Sym *sym;
184 	const char *symn;
185 	uint64_t cookie = pcookie;
186 	struct {
187 		struct __kbind param;
188 		Elf_Addr newval;
189 	} buf;
190 
191 	rela = (Elf_RelA *)(object->Dyn.info[DT_JMPREL] + reloff);
192 
193 	sym = object->dyn.symtab;
194 	sym += ELF64_R_SYM(rela->r_info);
195 	symn = object->dyn.strtab + sym->st_name;
196 
197 	sr = _dl_find_symbol(symn, SYM_SEARCH_ALL|SYM_WARNNOTFOUND|SYM_PLT,
198 	    sym, object);
199 	if (sr.sym == NULL)
200 		_dl_die("lazy binding failed!");
201 
202 	buf.newval = sr.obj->obj_base + sr.sym->st_value + rela->r_addend;
203 
204 	if (__predict_false(sr.obj->traced) && _dl_trace_plt(sr.obj, symn))
205 		return (buf.newval);
206 
207 	buf.param.kb_addr = (Elf_Addr *)(object->obj_base + rela->r_offset);
208 	buf.param.kb_size = sizeof(Elf_Addr);
209 
210 	/* directly code the syscall, so that it's actually inline here */
211 	{
212 		register long syscall_num __asm("$0") /* v0 */ = SYS_kbind;
213 		register void *arg1 __asm("$16") /* a0 */ = &buf;
214 		register long  arg2 __asm("$17") /* a1 */ = sizeof(buf);
215 		register long  arg3 __asm("$18") /* a2 */ = cookie;
216 
217 		__asm volatile( "call_pal %1" : "+r" (syscall_num)
218 		    : "i" (PAL_OSF1_callsys), "r" (arg1), "r" (arg2),
219 		    "r" (arg3) : "$19", "$20", "memory");
220 	}
221 
222 	return (buf.newval);
223 }
224 
225 void _dl_bind_start(void) __dso_hidden;	/* XXX */
226 
227 /*
228  *	Relocate the Global Offset Table (GOT).
229  */
230 int
231 _dl_md_reloc_got(elf_object_t *object, int lazy)
232 {
233 	int	fails = 0;
234 	Elf_Addr *pltgot;
235 
236 	if (object->Dyn.info[DT_PLTREL] != DT_RELA)
237 		return (0);
238 
239 	pltgot = (Elf_Addr *)object->Dyn.info[DT_PLTGOT];
240 
241 	if (object->traced)
242 		lazy = 1;
243 
244 	if (!lazy || pltgot == NULL) {
245 		fails = _dl_md_reloc(object, DT_JMPREL, DT_PLTRELSZ);
246 	} else {
247 		if (object->obj_base != 0) {
248 			int i, size;
249 			Elf_Addr *addr;
250 			Elf_RelA *rela;
251 
252 			size = object->Dyn.info[DT_PLTRELSZ] /
253 			    sizeof(Elf_RelA);
254 			rela = (Elf_RelA *)(object->Dyn.info[DT_JMPREL]);
255 
256 			for (i = 0; i < size; i++) {
257 				addr = (Elf_Addr *)(object->obj_base +
258 				    rela[i].r_offset);
259 				*addr += object->obj_base;
260 			}
261 		}
262 		pltgot[0] = (Elf_Addr)_dl_bind_start;
263 		pltgot[1] = (Elf_Addr)object;
264 	}
265 
266 	return (fails);
267 }
268