rtld_machine.c revision 1.46
1/*	$OpenBSD: rtld_machine.c,v 1.46 2019/11/26 23:38:52 guenther Exp $ */
2
3/*
4 * Copyright (c) 2002 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 * Copyright (c) 2000 Eduardo Horvath.
31 * Copyright (c) 1999 The NetBSD Foundation, Inc.
32 * All rights reserved.
33 *
34 * This code is derived from software contributed to The NetBSD Foundation
35 * by Paul Kranenburg.
36 *
37 * Redistribution and use in source and binary forms, with or without
38 * modification, are permitted provided that the following conditions
39 * are met:
40 * 1. Redistributions of source code must retain the above copyright
41 *    notice, this list of conditions and the following disclaimer.
42 * 2. Redistributions in binary form must reproduce the above copyright
43 *    notice, this list of conditions and the following disclaimer in the
44 *    documentation and/or other materials provided with the distribution.
45 * 3. All advertising materials mentioning features or use of this software
46 *    must display the following acknowledgement:
47 *	This product includes software developed by the NetBSD
48 *	Foundation, Inc. and its contributors.
49 * 4. Neither the name of The NetBSD Foundation nor the names of its
50 *    contributors may be used to endorse or promote products derived
51 *    from this software without specific prior written permission.
52 *
53 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
54 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
55 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
56 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
57 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
58 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
59 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
60 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
61 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
62 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
63 * POSSIBILITY OF SUCH DAMAGE.
64 */
65
66#define _DYN_LOADER
67
68#include <sys/types.h>
69#include <sys/mman.h>
70#include <sys/syscall.h>
71#include <sys/unistd.h>
72
73#include <nlist.h>
74#include <link.h>
75
76#include "syscall.h"
77#include "archdep.h"
78#include "resolve.h"
79
80int64_t pcookie __attribute__((section(".openbsd.randomdata"))) __dso_hidden;
81
82int
83_dl_md_reloc(elf_object_t *object, int rel, int relsz)
84{
85	long	i;
86	long	numrel;
87	long	relrel;
88	Elf_Addr loff;
89	Elf_Addr prev_value = 0;
90	const Elf_Sym *prev_sym = NULL;
91	Elf_Rel *rels;
92
93	loff = object->obj_base;
94	numrel = object->Dyn.info[relsz] / sizeof(Elf_Rel);
95	relrel = object->relcount;
96	rels = (Elf_Rel *)(object->Dyn.info[rel]);
97
98	if (rels == NULL)
99		return 0;
100
101	if (relrel > numrel)
102		_dl_die("relcount > numrel: %ld > %ld", relrel, numrel);
103
104	/* tight loop for leading RELATIVE relocs */
105	for (i = 0; i < relrel; i++, rels++) {
106		Elf_Addr *where;
107
108		where = (Elf_Addr *)(rels->r_offset + loff);
109		*where += loff;
110	}
111	for (; i < numrel; i++, rels++) {
112		Elf_Addr *where, value;
113		Elf_Word type;
114		const Elf_Sym *sym;
115		const char *symn;
116
117		where = (Elf_Addr *)(rels->r_offset + loff);
118
119		sym = object->dyn.symtab;
120		sym += ELF_R_SYM(rels->r_info);
121		symn = object->dyn.strtab + sym->st_name;
122
123		type = ELF_R_TYPE(rels->r_info);
124		switch (type) {
125		case R_TYPE(NONE):
126		case R_TYPE(JUMP_SLOT):		/* shouldn't happen */
127			continue;
128
129		case R_TYPE(RELATIVE):
130			*where += loff;
131			continue;
132
133		case R_TYPE(32):
134			value = *where;
135			break;
136
137		case R_TYPE(GLOB_DAT):
138			value = 0;
139			break;
140
141		case R_TYPE(COPY):
142		{
143			struct sym_res sr;
144
145			sr = _dl_find_symbol(symn,
146			    SYM_SEARCH_OTHER|SYM_WARNNOTFOUND|SYM_NOTPLT,
147			    sym, object);
148			if (sr.sym == NULL)
149				return 1;
150
151			value = sr.obj->obj_base + sr.sym->st_value;
152			_dl_bcopy((void *)value, where, sym->st_size);
153			continue;
154		}
155
156		default:
157			_dl_die("unknown relocation %d", type);
158		}
159
160		if (sym->st_shndx != SHN_UNDEF &&
161		    ELF_ST_BIND(sym->st_info) == STB_LOCAL) {
162			value += loff;
163		} else if (sym == prev_sym) {
164			value += prev_value;
165		} else {
166			struct sym_res sr;
167
168			sr = _dl_find_symbol(symn,
169			    SYM_SEARCH_ALL|SYM_WARNNOTFOUND|SYM_NOTPLT,
170			    sym, object);
171			if (sr.sym == NULL) {
172				if (ELF_ST_BIND(sym->st_info) != STB_WEAK)
173					return 1;
174				continue;
175			}
176			prev_sym = sym;
177			prev_value = sr.obj->obj_base + sr.sym->st_value;
178			value += prev_value;
179		}
180
181		*where = value;
182	}
183
184	return 0;
185}
186
187#if 0
188struct jmpslot {
189	u_short opcode;
190	u_short addr[2];
191	u_short reloc_index;
192#define JMPSLOT_RELOC_MASK	0xffff
193};
194#define JUMP			0xe990	/* NOP + JMP opcode */
195#endif
196
197/*
198 * Resolve a symbol at run-time.
199 */
200Elf_Addr
201_dl_bind(elf_object_t *object, int index)
202{
203	Elf_Rel *rel;
204	const Elf_Sym *sym;
205	const char *symn;
206	struct sym_res sr;
207	uint64_t cookie = pcookie;
208	struct {
209		struct __kbind param;
210		Elf_Addr newval;
211	} buf;
212
213	rel = (Elf_Rel *)(object->Dyn.info[DT_JMPREL]);
214
215	rel += index/sizeof(Elf_Rel);
216
217	sym = object->dyn.symtab;
218	sym += ELF_R_SYM(rel->r_info);
219	symn = object->dyn.strtab + sym->st_name;
220
221	sr = _dl_find_symbol(symn, SYM_SEARCH_ALL|SYM_WARNNOTFOUND|SYM_PLT,
222	    sym, object);
223	if (sr.sym == NULL)
224		_dl_die("lazy binding failed!");
225
226	buf.newval = sr.obj->obj_base + sr.sym->st_value;
227
228	if (__predict_false(sr.obj->traced) && _dl_trace_plt(sr.obj, symn))
229		return buf.newval;
230
231	buf.param.kb_addr = (Elf_Word *)(object->obj_base + rel->r_offset);
232	buf.param.kb_size = sizeof(Elf_Addr);
233
234	/* directly code the syscall, so that it's actually inline here */
235	{
236		register long syscall_num __asm("eax") = SYS_kbind;
237
238		__asm volatile("lea %3, %%edx; pushl 4(%%edx);"
239		    " pushl (%%edx); pushl %2; pushl %1;"
240		    " push %%eax; int $0x80; addl $20, %%esp" :
241		    "+a" (syscall_num) : "r" (&buf), "i" (sizeof(buf)),
242		    "m" (cookie) : "edx", "cc", "memory");
243	}
244
245	return buf.newval;
246}
247
248static int
249_dl_md_reloc_all_plt(elf_object_t *object, const Elf_Rel *reloc,
250    const Elf_Rel *rend)
251{
252	for (; reloc < rend; reloc++) {
253		const Elf_Sym *sym;
254		const char *symn;
255		Elf_Addr *where;
256		struct sym_res sr;
257
258		sym = object->dyn.symtab;
259		sym += ELF_R_SYM(reloc->r_info);
260		symn = object->dyn.strtab + sym->st_name;
261
262		sr = _dl_find_symbol(symn,
263		    SYM_SEARCH_ALL|SYM_WARNNOTFOUND|SYM_PLT, sym, object);
264		if (sr.sym == NULL) {
265			if (ELF_ST_BIND(sym->st_info) != STB_WEAK)
266				return 1;
267			continue;
268		}
269
270		where = (Elf_Addr *)(reloc->r_offset + object->obj_base);
271		*where = sr.obj->obj_base + sr.sym->st_value;
272	}
273
274	return 0;
275}
276
277int
278_dl_md_reloc_got(elf_object_t *object, int lazy)
279{
280	extern void _dl_bind_start(void);	/* XXX */
281	Elf_Addr	*pltgot = (Elf_Addr *)object->Dyn.info[DT_PLTGOT];
282	const Elf_Rel	*reloc, *rend;
283
284	if (pltgot == NULL)
285		return 0; /* it is possible to have no PLT/GOT relocations */
286
287	if (object->Dyn.info[DT_PLTREL] != DT_REL)
288		return 0;
289
290	if (object->traced)
291		lazy = 1;
292
293	reloc = (const Elf_Rel *)(object->Dyn.info[DT_JMPREL]);
294	rend = (const Elf_Rel *)((char *)reloc + object->Dyn.info[DT_PLTRELSZ]);
295
296	if (!lazy)
297		return _dl_md_reloc_all_plt(object, reloc, rend);
298
299	/* Lazy */
300	pltgot[1] = (Elf_Addr)object;
301	pltgot[2] = (Elf_Addr)&_dl_bind_start;
302
303	for (; reloc < rend; reloc++) {
304		Elf_Addr *where;
305		where = (Elf_Addr *)(reloc->r_offset + object->obj_base);
306		*where += object->obj_base;
307	}
308
309	return 0;
310}
311