xref: /openbsd-src/libexec/ld.so/alpha/rtld_machine.c (revision b722ba42570161220f25c5d789b5bec8a0166743)
1*b722ba42Sguenther /*	$OpenBSD: rtld_machine.c,v 1.71 2022/01/08 06:49:41 guenther Exp $ */
255ed5643Sniklas 
355ed5643Sniklas /*
455ed5643Sniklas  * Copyright (c) 1999 Dale Rahn
555ed5643Sniklas  * Copyright (c) 2001 Niklas Hallqvist
60e2cad47Sart  * Copyright (c) 2001 Artur Grabowski
755ed5643Sniklas  *
855ed5643Sniklas  * Redistribution and use in source and binary forms, with or without
955ed5643Sniklas  * modification, are permitted provided that the following conditions
1055ed5643Sniklas  * are met:
1155ed5643Sniklas  * 1. Redistributions of source code must retain the above copyright
1255ed5643Sniklas  *    notice, this list of conditions and the following disclaimer.
1355ed5643Sniklas  * 2. Redistributions in binary form must reproduce the above copyright
1455ed5643Sniklas  *    notice, this list of conditions and the following disclaimer in the
1555ed5643Sniklas  *    documentation and/or other materials provided with the distribution.
1655ed5643Sniklas  *
1755ed5643Sniklas  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
1855ed5643Sniklas  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
1955ed5643Sniklas  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2055ed5643Sniklas  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
2155ed5643Sniklas  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2255ed5643Sniklas  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2355ed5643Sniklas  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2455ed5643Sniklas  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2555ed5643Sniklas  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2655ed5643Sniklas  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2755ed5643Sniklas  * SUCH DAMAGE.
2855ed5643Sniklas  *
2955ed5643Sniklas  */
3055ed5643Sniklas 
3155ed5643Sniklas #define _DYN_LOADER
3255ed5643Sniklas 
3355ed5643Sniklas #include <sys/types.h>
34*b722ba42Sguenther #include <sys/exec_elf.h>
357ad95679Sguenther #include <sys/syscall.h>
367ad95679Sguenther #include <sys/unistd.h>
37*b722ba42Sguenther 
387ad95679Sguenther #include <machine/pal.h>
39*b722ba42Sguenther #include <machine/reloc.h>
4055ed5643Sniklas 
41*b722ba42Sguenther #include "util.h"
4255ed5643Sniklas #include "resolve.h"
4355ed5643Sniklas 
444131953dSmiod #define	DT_PROC(n)	((n) - DT_LOPROC + DT_NUM)
454131953dSmiod 
467ad95679Sguenther int64_t pcookie __attribute__((section(".openbsd.randomdata"))) __dso_hidden;
477ad95679Sguenther 
4855ed5643Sniklas int
_dl_md_reloc(elf_object_t * object,int rel,int relasz)4955ed5643Sniklas _dl_md_reloc(elf_object_t *object, int rel, int relasz)
5055ed5643Sniklas {
51dca21f58Sart 	long	i;
52dca21f58Sart 	long	numrela;
5388098a4dSguenther 	long	relrel;
54e9cfe40cSmiod 	int	fails = 0;
55e3b0f1d9Sguenther 	Elf_Addr loff;
56e3b0f1d9Sguenther 	Elf_Addr prev_value = 0;
5788098a4dSguenther 	const Elf_Sym *prev_sym = NULL;
58e3b0f1d9Sguenther 	Elf_RelA  *relas;
5955ed5643Sniklas 
60ce11e090Skurt 	loff = object->obj_base;
61e3b0f1d9Sguenther 	numrela = object->Dyn.info[relasz] / sizeof(Elf_RelA);
6288098a4dSguenther 	relrel = rel == DT_RELA ? object->relacount : 0;
63e3b0f1d9Sguenther 	relas = (Elf_RelA *)(object->Dyn.info[rel]);
6455ed5643Sniklas 
65bb87ac8eSart 	if (relas == NULL)
66e3b0f1d9Sguenther 		return 0;
6755ed5643Sniklas 
683b50b772Sguenther 	if (relrel > numrela)
693b50b772Sguenther 		_dl_die("relacount > numrel: %ld > %ld", relrel, numrela);
7088098a4dSguenther 
719e9d93fdSguenther 	if (! object->Dyn.info[DT_PROC(DT_ALPHA_PLTRO)])
729e9d93fdSguenther 		_dl_die("unsupported insecure PLT object");
739e9d93fdSguenther 
7488098a4dSguenther 	/* tight loop for leading RELATIVE relocs */
7588098a4dSguenther 	for (i = 0; i < relrel; i++, relas++) {
7688098a4dSguenther 		Elf_Addr *r_addr;
7788098a4dSguenther 
78e3b0f1d9Sguenther 		r_addr = (Elf_Addr *)(relas->r_offset + loff);
7988098a4dSguenther 
8088098a4dSguenther 		/* Handle unaligned RELATIVE relocs */
8188098a4dSguenther 		if ((((Elf_Addr)r_addr) & 0x7) != 0) {
8288098a4dSguenther 			Elf_Addr tmp;
8388098a4dSguenther 			_dl_bcopy(r_addr, &tmp, sizeof(Elf_Addr));
8488098a4dSguenther 			tmp += loff;
8588098a4dSguenther 			_dl_bcopy(&tmp, r_addr, sizeof(Elf_Addr));
8688098a4dSguenther 		} else
8788098a4dSguenther 			*r_addr += loff;
8888098a4dSguenther 	}
8988098a4dSguenther 	for (; i < numrela; i++, relas++) {
90e3b0f1d9Sguenther 		Elf_Addr *r_addr;
91143e5accSguenther 		struct sym_res sr;
92e3b0f1d9Sguenther 		const Elf_Sym *sym;
9355ed5643Sniklas 		const char *symn;
9455ed5643Sniklas 
95e3b0f1d9Sguenther 		r_addr = (Elf_Addr *)(relas->r_offset + loff);
9655ed5643Sniklas 
97e3b0f1d9Sguenther 		if (ELF_R_SYM(relas->r_info) == 0xffffffff)
9855ed5643Sniklas 			continue;
9939b7d201Sderaadt 
10055ed5643Sniklas 
10155ed5643Sniklas 		sym = object->dyn.symtab;
102e3b0f1d9Sguenther 		sym += ELF_R_SYM(relas->r_info);
10355ed5643Sniklas 		symn = object->dyn.strtab + sym->st_name;
10455ed5643Sniklas 
105e3b0f1d9Sguenther 		switch (ELF_R_TYPE(relas->r_info)) {
10655ed5643Sniklas 		case R_TYPE(REFQUAD):
107143e5accSguenther 			sr = _dl_find_symbol(symn,
1080acae5e5Sdrahn 			    SYM_SEARCH_ALL|SYM_WARNNOTFOUND|SYM_NOTPLT,
109143e5accSguenther 			    sym, object);
110143e5accSguenther 			if (sr.sym == NULL)
111dca21f58Sart 				goto resolve_failed;
112143e5accSguenther 			*r_addr += sr.obj->obj_base + sr.sym->st_value +
113143e5accSguenther 			    relas->r_addend;
11455ed5643Sniklas 			break;
11555ed5643Sniklas 		case R_TYPE(RELATIVE):
11657b5f4bcSart 			/*
11757b5f4bcSart 			 * There is a lot of unaligned RELATIVE
11857b5f4bcSart 			 * relocs generated by gcc in the exception handlers.
11957b5f4bcSart 			 */
12057b5f4bcSart 			if ((((Elf_Addr) r_addr) & 0x7) != 0) {
12157b5f4bcSart 				Elf_Addr tmp;
12257b5f4bcSart #if 0
1232c65dbe9Sart _dl_printf("unaligned RELATIVE: %p type: %d %s 0x%lx -> 0x%lx\n", r_addr,
1242c65dbe9Sart     ELF_R_TYPE(relas->r_info), object->load_name, *r_addr, *r_addr+loff);
12557b5f4bcSart #endif
12657b5f4bcSart 				_dl_bcopy(r_addr, &tmp, sizeof(Elf_Addr));
12757b5f4bcSart 				tmp += loff;
12857b5f4bcSart 				_dl_bcopy(&tmp, r_addr, sizeof(Elf_Addr));
12939b7d201Sderaadt 			} else
130dca21f58Sart 				*r_addr += loff;
13155ed5643Sniklas 			break;
13255ed5643Sniklas 		case R_TYPE(JMP_SLOT):
133143e5accSguenther 			sr = _dl_find_symbol(symn,
1340acae5e5Sdrahn 			    SYM_SEARCH_ALL|SYM_WARNNOTFOUND|SYM_PLT,
135143e5accSguenther 			    sym, object);
136143e5accSguenther 			if (sr.sym == NULL)
137dca21f58Sart 				goto resolve_failed;
138143e5accSguenther 			*r_addr = sr.obj->obj_base + sr.sym->st_value +
139143e5accSguenther 			    relas->r_addend;
14055ed5643Sniklas 			break;
14155ed5643Sniklas 		case R_TYPE(GLOB_DAT):
14288098a4dSguenther 			if (sym == prev_sym) {
14388098a4dSguenther 				*r_addr = prev_value + relas->r_addend;
14488098a4dSguenther 				break;
14588098a4dSguenther 			}
146143e5accSguenther 			sr = _dl_find_symbol(symn,
1470acae5e5Sdrahn 			    SYM_SEARCH_ALL|SYM_WARNNOTFOUND|SYM_NOTPLT,
148143e5accSguenther 			    sym, object);
149143e5accSguenther 			if (sr.sym == NULL)
150dca21f58Sart 				goto resolve_failed;
15188098a4dSguenther 			prev_sym = sym;
152143e5accSguenther 			prev_value = sr.obj->obj_base + sr.sym->st_value;
15388098a4dSguenther 			*r_addr = prev_value + relas->r_addend;
15455ed5643Sniklas 			break;
15555ed5643Sniklas 		case R_TYPE(NONE):
15655ed5643Sniklas 			break;
15755ed5643Sniklas 		default:
158d9d17dbfSderaadt 			_dl_die("%s: unsupported relocation '%s' %lld at %p",
1593b50b772Sguenther 			    object->load_name, symn,
160e3b0f1d9Sguenther 			    ELF_R_TYPE(relas->r_info), (void *)r_addr);
16155ed5643Sniklas 		}
162dca21f58Sart 		continue;
163dca21f58Sart resolve_failed:
16406462af4Sdrahn 		if (ELF_ST_BIND(sym->st_info) != STB_WEAK)
165dca21f58Sart 			fails++;
16655ed5643Sniklas 	}
167f6193deeSguenther 	__asm volatile("imb" : : : "memory");
168f7991f91Sart 
169e3b0f1d9Sguenther 	return fails;
17055ed5643Sniklas }
17155ed5643Sniklas 
17255ed5643Sniklas /*
1732c65dbe9Sart  * Resolve a symbol at run-time.
1742c65dbe9Sart  */
1755b36bcefSderaadt Elf_Addr
_dl_bind(elf_object_t * object,int reloff)1765b36bcefSderaadt _dl_bind(elf_object_t *object, int reloff)
1772c65dbe9Sart {
1782c65dbe9Sart 	Elf_RelA *rela;
179143e5accSguenther 	struct sym_res sr;
180143e5accSguenther 	const Elf_Sym *sym;
1812c65dbe9Sart 	const char *symn;
1827ad95679Sguenther 	uint64_t cookie = pcookie;
1837ad95679Sguenther 	struct {
1847ad95679Sguenther 		struct __kbind param;
1857ad95679Sguenther 		Elf_Addr newval;
1867ad95679Sguenther 	} buf;
1872c65dbe9Sart 
1882c65dbe9Sart 	rela = (Elf_RelA *)(object->Dyn.info[DT_JMPREL] + reloff);
189b42aa5e0Sdrahn 
1902c65dbe9Sart 	sym = object->dyn.symtab;
191e3b0f1d9Sguenther 	sym += ELF_R_SYM(rela->r_info);
1922c65dbe9Sart 	symn = object->dyn.strtab + sym->st_name;
1932c65dbe9Sart 
194143e5accSguenther 	sr = _dl_find_symbol(symn, SYM_SEARCH_ALL|SYM_WARNNOTFOUND|SYM_PLT,
195143e5accSguenther 	    sym, object);
196143e5accSguenther 	if (sr.sym == NULL)
1973b50b772Sguenther 		_dl_die("lazy binding failed!");
198b42aa5e0Sdrahn 
199143e5accSguenther 	buf.newval = sr.obj->obj_base + sr.sym->st_value + rela->r_addend;
200ae398163Smiod 
201143e5accSguenther 	if (__predict_false(sr.obj->traced) && _dl_trace_plt(sr.obj, symn))
202e3b0f1d9Sguenther 		return buf.newval;
2037ad95679Sguenther 
2047ad95679Sguenther 	buf.param.kb_addr = (Elf_Addr *)(object->obj_base + rela->r_offset);
2057ad95679Sguenther 	buf.param.kb_size = sizeof(Elf_Addr);
2067ad95679Sguenther 
2077ad95679Sguenther 	/* directly code the syscall, so that it's actually inline here */
2087ad95679Sguenther 	{
2097ad95679Sguenther 		register long syscall_num __asm("$0") /* v0 */ = SYS_kbind;
2107ad95679Sguenther 		register void *arg1 __asm("$16") /* a0 */ = &buf;
2117ad95679Sguenther 		register long  arg2 __asm("$17") /* a1 */ = sizeof(buf);
2127ad95679Sguenther 		register long  arg3 __asm("$18") /* a2 */ = cookie;
2137ad95679Sguenther 
2147ad95679Sguenther 		__asm volatile( "call_pal %1" : "+r" (syscall_num)
2157ad95679Sguenther 		    : "i" (PAL_OSF1_callsys), "r" (arg1), "r" (arg2),
2167ad95679Sguenther 		    "r" (arg3) : "$19", "$20", "memory");
21791d8decdSdrahn 	}
21891d8decdSdrahn 
219e3b0f1d9Sguenther 	return buf.newval;
2202c65dbe9Sart }
2212c65dbe9Sart 
222c9db2c6cSguenther void _dl_bind_start(void) __dso_hidden;	/* XXX */
2239e9d93fdSguenther 
2242c65dbe9Sart /*
2250e2cad47Sart  *	Relocate the Global Offset Table (GOT).
22655ed5643Sniklas  */
227e9cfe40cSmiod int
_dl_md_reloc_got(elf_object_t * object,int lazy)22855ed5643Sniklas _dl_md_reloc_got(elf_object_t *object, int lazy)
22955ed5643Sniklas {
230e9cfe40cSmiod 	int	fails = 0;
2312c65dbe9Sart 	Elf_Addr *pltgot;
23291d8decdSdrahn 
233e23a26ffSguenther 	if (object->Dyn.info[DT_PLTREL] != DT_RELA)
234e3b0f1d9Sguenther 		return 0;
235e23a26ffSguenther 
2362c65dbe9Sart 	pltgot = (Elf_Addr *)object->Dyn.info[DT_PLTGOT];
2372c65dbe9Sart 
2389e9d93fdSguenther 	if (!lazy || pltgot == NULL) {
239e9cfe40cSmiod 		fails = _dl_md_reloc(object, DT_JMPREL, DT_PLTRELSZ);
240ab7fd747Sdrahn 	} else {
2418e012c2aSkurt 		if (object->obj_base != 0) {
24286c5e2bdSart 			int i, size;
24386c5e2bdSart 			Elf_Addr *addr;
24486c5e2bdSart 			Elf_RelA *rela;
24586c5e2bdSart 
246ab7fd747Sdrahn 			size = object->Dyn.info[DT_PLTRELSZ] /
247ab7fd747Sdrahn 			    sizeof(Elf_RelA);
24886c5e2bdSart 			rela = (Elf_RelA *)(object->Dyn.info[DT_JMPREL]);
24986c5e2bdSart 
25086c5e2bdSart 			for (i = 0; i < size; i++) {
251ce11e090Skurt 				addr = (Elf_Addr *)(object->obj_base +
252ab7fd747Sdrahn 				    rela[i].r_offset);
253ce11e090Skurt 				*addr += object->obj_base;
25486c5e2bdSart 			}
25586c5e2bdSart 		}
256c9db2c6cSguenther 		pltgot[0] = (Elf_Addr)_dl_bind_start;
2574131953dSmiod 		pltgot[1] = (Elf_Addr)object;
2584131953dSmiod 	}
259e23a26ffSguenther 
260e3b0f1d9Sguenther 	return fails;
26155ed5643Sniklas }
262