xref: /openbsd-src/libexec/ld.so/hppa/rtld_machine.c (revision 07c7d596a12cd69c29a54967c1ad35cdd24dbd4f)
1*07c7d596Sjsg /*	$OpenBSD: rtld_machine.c,v 1.44 2022/08/29 02:08:13 jsg Exp $	*/
216117f8fSmickey 
316117f8fSmickey /*
416117f8fSmickey  * Copyright (c) 2004 Michael Shalayeff
516117f8fSmickey  * Copyright (c) 2001 Niklas Hallqvist
616117f8fSmickey  * Copyright (c) 2001 Artur Grabowski
716117f8fSmickey  * Copyright (c) 1999 Dale Rahn
816117f8fSmickey  * All rights reserved.
916117f8fSmickey  *
1016117f8fSmickey  * Redistribution and use in source and binary forms, with or without
1116117f8fSmickey  * modification, are permitted provided that the following conditions
1216117f8fSmickey  * are met:
1316117f8fSmickey  * 1. Redistributions of source code must retain the above copyright
1416117f8fSmickey  *    notice, this list of conditions and the following disclaimer.
1516117f8fSmickey  * 2. Redistributions in binary form must reproduce the above copyright
1616117f8fSmickey  *    notice, this list of conditions and the following disclaimer in the
1716117f8fSmickey  *    documentation and/or other materials provided with the distribution.
1816117f8fSmickey  *
1916117f8fSmickey  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
2016117f8fSmickey  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2116117f8fSmickey  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2216117f8fSmickey  * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT,
2316117f8fSmickey  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
2416117f8fSmickey  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
2516117f8fSmickey  * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2616117f8fSmickey  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
2716117f8fSmickey  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
2816117f8fSmickey  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
2916117f8fSmickey  * THE POSSIBILITY OF SUCH DAMAGE.
3016117f8fSmickey  */
3116117f8fSmickey 
3216117f8fSmickey #define _DYN_LOADER
3316117f8fSmickey 
3416117f8fSmickey #include <sys/types.h>
35b722ba42Sguenther #include <sys/exec_elf.h>
36672c18a0Sguenther #include <sys/syscall.h>
37b722ba42Sguenther #include <sys/tree.h>
38672c18a0Sguenther #include <sys/unistd.h>
39672c18a0Sguenther 
40b722ba42Sguenther #include <machine/reloc.h>
41672c18a0Sguenther #include <machine/vmparam.h>	/* SYSCALLGATE */
4216117f8fSmickey 
43b722ba42Sguenther #include "util.h"
44ae398163Smiod #define	_dl_bind XXX_dl_bind
4516117f8fSmickey #include "resolve.h"
46ae398163Smiod #undef	_dl_bind
47ae398163Smiod uint64_t _dl_bind(elf_object_t *object, int reloff);
4816117f8fSmickey 
4916117f8fSmickey typedef
5016117f8fSmickey struct hppa_plabel {
5116117f8fSmickey 	Elf_Addr	pc;
5244f1effdSmickey 	Elf_Addr	*sl;
5316117f8fSmickey 	SPLAY_ENTRY(hppa_plabel) node;
5416117f8fSmickey } hppa_plabel_t;
5516117f8fSmickey SPLAY_HEAD(_dl_md_plabels, hppa_plabel) _dl_md_plabel_root;
5616117f8fSmickey 
57b79fcc9bSmickey void	_hppa_dl_set_dp(Elf_Addr *dp);	/* from ldasm.S */
58b79fcc9bSmickey 
59672c18a0Sguenther int64_t pcookie __attribute__((section(".openbsd.randomdata"))) __dso_hidden;
60672c18a0Sguenther 
6116117f8fSmickey static __inline int
_dl_md_plcmp(hppa_plabel_t * a,hppa_plabel_t * b)6216117f8fSmickey _dl_md_plcmp(hppa_plabel_t *a, hppa_plabel_t *b)
6316117f8fSmickey {
6416117f8fSmickey 	if (a->sl < b->sl)
65e3b0f1d9Sguenther 		return -1;
6616117f8fSmickey 	else if (a->sl > b->sl)
67e3b0f1d9Sguenther 		return 1;
6816117f8fSmickey 	else if (a->pc < b->pc)
69e3b0f1d9Sguenther 		return -1;
7016117f8fSmickey 	else if (a->pc > b->pc)
71e3b0f1d9Sguenther 		return 1;
7216117f8fSmickey 	else
73e3b0f1d9Sguenther 		return 0;
7416117f8fSmickey }
7516117f8fSmickey 
7616117f8fSmickey SPLAY_PROTOTYPE(_dl_md_plabels, hppa_plabel, node, _dl_md_plcmp);
7716117f8fSmickey SPLAY_GENERATE(_dl_md_plabels, hppa_plabel, node, _dl_md_plcmp);
7816117f8fSmickey 
7916117f8fSmickey Elf_Addr
_dl_md_plabel(Elf_Addr pc,Elf_Addr * sl)8044f1effdSmickey _dl_md_plabel(Elf_Addr pc, Elf_Addr *sl)
8116117f8fSmickey {
8216117f8fSmickey 	hppa_plabel_t key, *p;
8316117f8fSmickey 
8444f1effdSmickey 	key.pc = pc;
8544f1effdSmickey 	key.sl = sl;
8616117f8fSmickey 	p = SPLAY_FIND(_dl_md_plabels, &_dl_md_plabel_root, &key);
8716117f8fSmickey 	if (p == NULL) {
8816117f8fSmickey 		p = _dl_malloc(sizeof(*p));
8916117f8fSmickey 		if (p == NULL)
903b50b772Sguenther 			_dl_oom();
919dbe46faSmickey 		p->pc = pc;
929dbe46faSmickey 		p->sl = sl;
9316117f8fSmickey 		SPLAY_INSERT(_dl_md_plabels, &_dl_md_plabel_root, p);
9416117f8fSmickey 	}
9516117f8fSmickey 
9616117f8fSmickey 	return (Elf_Addr)p | 2;
9716117f8fSmickey }
9816117f8fSmickey 
9916117f8fSmickey int
_dl_md_reloc(elf_object_t * object,int rel,int relasz)10016117f8fSmickey _dl_md_reloc(elf_object_t *object, int rel, int relasz)
10116117f8fSmickey {
10216117f8fSmickey 	Elf_RelA	*rela;
10316117f8fSmickey 	Elf_Addr	loff;
104d4afc0cdSguenther 	int	num_relative;
10516117f8fSmickey 	int	i, numrela, fails = 0;
10616117f8fSmickey 
107ce11e090Skurt 	loff = object->obj_base;
10816117f8fSmickey 	numrela = object->Dyn.info[relasz] / sizeof(Elf_RelA);
109d4afc0cdSguenther 	num_relative = rel == DT_RELA ? object->relacount : 0;
11016117f8fSmickey 	rela = (Elf_RelA *)(object->Dyn.info[rel]);
11116117f8fSmickey 
1126a54f14dSdrahn #ifdef DEBUG
11316117f8fSmickey 	DL_DEB(("object %s relasz %x, numrela %x loff %x\n",
11416117f8fSmickey 	    object->load_name, object->Dyn.info[relasz], numrela, loff));
1156a54f14dSdrahn #endif
11616117f8fSmickey 
11716117f8fSmickey 	if (rela == NULL)
118e3b0f1d9Sguenther 		return 0;
11916117f8fSmickey 
12084374377Smickey 	/* either it's an ld bug or a wacky hpux abi */
12184374377Smickey 	if (!object->dyn.pltgot)
12284374377Smickey 		object->Dyn.info[DT_PLTGOT] += loff;
12384374377Smickey 
12444f1effdSmickey 	if (object->dyn.init && !((Elf_Addr)object->dyn.init & 2)) {
12544f1effdSmickey 		Elf_Addr addr = _dl_md_plabel((Elf_Addr)object->dyn.init,
12644f1effdSmickey 		    object->dyn.pltgot);
1276a54f14dSdrahn #ifdef DEBUG
128d1ba08ccSmickey 		DL_DEB(("PLABEL32: %p:%p(_init) -> 0x%x in %s\n",
129d1ba08ccSmickey 		    object->dyn.init, object->dyn.pltgot,
130d1ba08ccSmickey 		    addr, object->load_name));
1316a54f14dSdrahn #endif
13244f1effdSmickey 		object->dyn.init = (void *)addr;
13344f1effdSmickey 	}
13444f1effdSmickey 
13544f1effdSmickey 	if (object->dyn.fini && !((Elf_Addr)object->dyn.fini & 2)) {
13644f1effdSmickey 		Elf_Addr addr = _dl_md_plabel((Elf_Addr)object->dyn.fini,
13744f1effdSmickey 		    object->dyn.pltgot);
1386a54f14dSdrahn #ifdef DEBUG
139d1ba08ccSmickey 		DL_DEB(("PLABEL32: %p:%p(_fini) -> 0x%x in %s\n",
140d1ba08ccSmickey 		    object->dyn.fini, object->dyn.pltgot,
141d1ba08ccSmickey 		    addr, object->load_name));
1426a54f14dSdrahn #endif
14344f1effdSmickey 		object->dyn.fini = (void *)addr;
14444f1effdSmickey 	}
14544f1effdSmickey 
146b79fcc9bSmickey 	/*
147b79fcc9bSmickey 	 * this is normally done by the crt0 code but we have to make
148b79fcc9bSmickey 	 * sure it's set here to allow constructors to call functions
1497c635cc4Stobias 	 * that are overridden in the user binary (that are un-pic)
150b79fcc9bSmickey 	 */
151b79fcc9bSmickey 	if (object->obj_type == OBJTYPE_EXE)
152b79fcc9bSmickey 		_hppa_dl_set_dp(object->dyn.pltgot);
153b79fcc9bSmickey 
154d4afc0cdSguenther 	/* tight loop for leading relative relocs */
155d4afc0cdSguenther 	for (i = 0; i < num_relative; i++, rela++) {
156d4afc0cdSguenther 		Elf_Addr *where = (Elf_Addr *)(rela->r_offset + loff);
157d4afc0cdSguenther 		*where = rela->r_addend + loff;
158d4afc0cdSguenther 	}
159d4afc0cdSguenther 	for (; i < numrela; i++, rela++) {
160143e5accSguenther 		struct sym_res sr;
161143e5accSguenther 		const Elf_Sym *sym;
162143e5accSguenther 		Elf_Addr *pt;
16316117f8fSmickey 		const char *symn;
16416117f8fSmickey 		int type;
16516117f8fSmickey 
16616117f8fSmickey 		type = ELF_R_TYPE(rela->r_info);
16716117f8fSmickey 		if (type == RELOC_NONE)
16816117f8fSmickey 			continue;
16916117f8fSmickey 
1706718d15cSdrahn 		sym = object->dyn.symtab + ELF_R_SYM(rela->r_info);
17116117f8fSmickey 		symn = object->dyn.strtab + sym->st_name;
17216117f8fSmickey 		pt = (Elf_Addr *)(rela->r_offset + loff);
17316117f8fSmickey 
17416117f8fSmickey 		if (ELF_R_SYM(rela->r_info) && sym->st_name) {
175143e5accSguenther 			sr = _dl_find_symbol(symn,
176143e5accSguenther 			    SYM_SEARCH_ALL|SYM_WARNNOTFOUND|SYM_NOTPLT,
177143e5accSguenther 			    sym, object);
178143e5accSguenther 			if (sr.sym == NULL) {
17906462af4Sdrahn 				if (ELF_ST_BIND(sym->st_info) != STB_WEAK)
18016117f8fSmickey 					fails++;
18116117f8fSmickey 				continue;
18216117f8fSmickey 			}
183143e5accSguenther 		} else {
184143e5accSguenther 			sr.sym = NULL;
185143e5accSguenther 			sr.obj = object;
18616117f8fSmickey 		}
18716117f8fSmickey 
1886a54f14dSdrahn #ifdef DEBUG
18916117f8fSmickey 		DL_DEB(("*pt=%x r_addend=%x r_sym=%x\n",
19016117f8fSmickey 		    *pt, rela->r_addend, ELF_R_SYM(rela->r_info)));
1916a54f14dSdrahn #endif
19216117f8fSmickey 
19316117f8fSmickey 		switch (type) {
19416117f8fSmickey 		case RELOC_DIR32:
19516117f8fSmickey 			if (ELF_R_SYM(rela->r_info) && sym->st_name) {
196143e5accSguenther 				*pt = sr.obj->obj_base + sr.sym->st_value +
197143e5accSguenther 				    rela->r_addend;
1986a54f14dSdrahn #ifdef DEBUG
19916117f8fSmickey 				DL_DEB(("[%x]DIR32: %s:%s -> 0x%x in %s\n",
20016117f8fSmickey 				    i, symn, object->load_name,
201143e5accSguenther 				    *pt, sr.obj->load_name));
2026a54f14dSdrahn #endif
20316117f8fSmickey 			} else {
20416117f8fSmickey 				/*
205d4afc0cdSguenther 				 * Either a relative relocation (symbol 0)
206d4afc0cdSguenther 				 * or a relocation against a local section
20716117f8fSmickey 				 */
208d4afc0cdSguenther 				*pt = loff + sym->st_value + rela->r_addend;
2096a54f14dSdrahn #ifdef DEBUG
21016117f8fSmickey 				DL_DEB(("[%x]DIR32: %s @ 0x%x\n", i,
21116117f8fSmickey 				    object->load_name, *pt));
2126a54f14dSdrahn #endif
21316117f8fSmickey 			}
21416117f8fSmickey 			break;
21516117f8fSmickey 
21616117f8fSmickey 		case RELOC_PLABEL32:
21716117f8fSmickey 			if (ELF_R_SYM(rela->r_info)) {
218143e5accSguenther 				if (ELF_ST_TYPE(sr.sym->st_info) != STT_FUNC) {
21944f1effdSmickey 					DL_DEB(("[%x]PLABEL32: bad\n", i));
22044f1effdSmickey 					break;
22144f1effdSmickey 				}
222143e5accSguenther 				*pt = _dl_md_plabel(sr.obj->obj_base +
223143e5accSguenther 				    sr.sym->st_value + rela->r_addend,
224143e5accSguenther 				    sr.obj->dyn.pltgot);
2256a54f14dSdrahn #ifdef DEBUG
22616117f8fSmickey 				DL_DEB(("[%x]PLABEL32: %s:%s -> 0x%x in %s\n",
22716117f8fSmickey 				    i, symn, object->load_name,
228143e5accSguenther 				    *pt, sr.obj->load_name));
2296a54f14dSdrahn #endif
23016117f8fSmickey 			} else {
23116117f8fSmickey 				*pt = loff + rela->r_addend;
2326a54f14dSdrahn #ifdef DEBUG
23316117f8fSmickey 				DL_DEB(("[%x]PLABEL32: %s @ 0x%x\n", i,
23416117f8fSmickey 				    object->load_name, *pt));
2356a54f14dSdrahn #endif
23616117f8fSmickey 			}
23716117f8fSmickey 			break;
23816117f8fSmickey 
23916117f8fSmickey 		case RELOC_IPLT:
24016117f8fSmickey 			if (ELF_R_SYM(rela->r_info)) {
241143e5accSguenther 				pt[0] = sr.obj->obj_base + sr.sym->st_value +
242143e5accSguenther 				    rela->r_addend;
243143e5accSguenther 				pt[1] = (Elf_Addr)sr.obj->dyn.pltgot;
2446a54f14dSdrahn #ifdef DEBUG
24516117f8fSmickey 				DL_DEB(("[%x]IPLT: %s:%s -> 0x%x:0x%x in %s\n",
24616117f8fSmickey 				    i, symn, object->load_name,
247143e5accSguenther 				    pt[0], pt[1], sr.obj->load_name));
2486a54f14dSdrahn #endif
24916117f8fSmickey 			} else {
25016117f8fSmickey 				pt[0] = loff + rela->r_addend;
25116117f8fSmickey 				pt[1] = (Elf_Addr)object->dyn.pltgot;
2526a54f14dSdrahn #ifdef DEBUG
25316117f8fSmickey 				DL_DEB(("[%x]IPLT: %s @ 0x%x:0x%x\n", i,
25416117f8fSmickey 				    object->load_name, pt[0], pt[1]));
2556a54f14dSdrahn #endif
25616117f8fSmickey 			}
25716117f8fSmickey 			break;
25816117f8fSmickey 
25916117f8fSmickey 		case RELOC_COPY:
2606718d15cSdrahn 		{
261143e5accSguenther 			sr = _dl_find_symbol(symn,
2620acae5e5Sdrahn 			    SYM_SEARCH_OTHER|SYM_WARNNOTFOUND|SYM_NOTPLT,
263143e5accSguenther 			    sym, object);
264143e5accSguenther 			if (sr.sym) {
265143e5accSguenther 				_dl_bcopy((void *)(sr.obj->obj_base +
266143e5accSguenther 				    sr.sym->st_value), pt, sym->st_size);
2676a54f14dSdrahn #ifdef DEBUG
26816117f8fSmickey 				DL_DEB(("[%x]COPY: %s[%x]:%s -> %p[%x] in %s\n",
269143e5accSguenther 				    i, symn, sr.obj->obj_base +
270143e5accSguenther 				    sr.sym->st_value, object->load_name,
271143e5accSguenther 				    pt, sym->st_size, sr.obj->load_name));
2726a54f14dSdrahn #endif
27316117f8fSmickey 			} else
27416117f8fSmickey 				DL_DEB(("[%x]COPY: no sym\n", i));
27516117f8fSmickey 			break;
2766718d15cSdrahn 		}
27716117f8fSmickey 		default:
27816117f8fSmickey 			DL_DEB(("[%x]UNKNOWN(%d): type=%d off=0x%lx "
27916117f8fSmickey 			    "addend=0x%lx rel=0x%x\n", i, type,
28016117f8fSmickey 			    ELF_R_TYPE(rela->r_info), rela->r_offset,
28116117f8fSmickey 			    rela->r_addend, *pt));
28216117f8fSmickey 			break;
28316117f8fSmickey 		}
28416117f8fSmickey 	}
28516117f8fSmickey 
286e3b0f1d9Sguenther 	return fails;
28716117f8fSmickey }
28816117f8fSmickey 
2898cd9acbbSkettenis extern void _dl_bind_start(void);
2908cd9acbbSkettenis 
2918cd9acbbSkettenis #define PLT_STUB_SIZE	(7 * 4)
2928cd9acbbSkettenis #define PLT_ENTRY_SIZE	(2 * 4)
2938cd9acbbSkettenis #define PLT_STUB_GOTOFF	(4 * 4)
2948cd9acbbSkettenis 
2958cd9acbbSkettenis #define PLT_STUB_MAGIC1	0x00c0ffee
2968cd9acbbSkettenis #define PLT_STUB_MAGIC2	0xdeadbeef
2978cd9acbbSkettenis 
2988cd9acbbSkettenis #define PLT_STUB_INSN1	0x0e801081	/* ldw	0(%r20), %r1 */
2998cd9acbbSkettenis #define PLT_STUB_INSN2	0xe820c000	/* bv	%r0(%r1) */
3008cd9acbbSkettenis 
301e9cfe40cSmiod int
_dl_md_reloc_got(elf_object_t * object,int lazy)30216117f8fSmickey _dl_md_reloc_got(elf_object_t *object, int lazy)
30316117f8fSmickey {
30416117f8fSmickey 	Elf_RelA *rela;
30516117f8fSmickey 	Elf_Addr  ooff;
306e9cfe40cSmiod 	int	i, numrela, fails = 0;
30716117f8fSmickey 
30816117f8fSmickey 	if (object->dyn.pltrel != DT_RELA)
309e3b0f1d9Sguenther 		return 0;
31016117f8fSmickey 
31116117f8fSmickey 	if (!lazy) {
312e9cfe40cSmiod 		fails = _dl_md_reloc(object, DT_JMPREL, DT_PLTRELSZ);
31316117f8fSmickey 	} else {
3148cd9acbbSkettenis 		register Elf_Addr ltp __asm ("%r19");
3158cd9acbbSkettenis 		Elf_Addr *got = NULL;
3168cd9acbbSkettenis 
31716117f8fSmickey 		rela = (Elf_RelA *)(object->dyn.jmprel);
31816117f8fSmickey 		numrela = object->dyn.pltrelsz / sizeof(Elf_RelA);
319ce11e090Skurt 		ooff = object->obj_base;
32016117f8fSmickey 
3218cd9acbbSkettenis 		/*
3228cd9acbbSkettenis 		 * Find the PLT stub by looking at all the
3238cd9acbbSkettenis 		 * relocations.  The PLT stub should be at the end of
3248cd9acbbSkettenis 		 * the .plt section so we start with the last
3258cd9acbbSkettenis 		 * relocation, since the linker should have emitted
3268cd9acbbSkettenis 		 * them in order.
3278cd9acbbSkettenis 		 */
3288cd9acbbSkettenis 		for (i = numrela - 1; i >= 0; i--) {
3298cd9acbbSkettenis 			got = (Elf_Addr *)(ooff + rela[i].r_offset +
3308cd9acbbSkettenis 			    PLT_ENTRY_SIZE + PLT_STUB_SIZE);
3318cd9acbbSkettenis 			if (got[-2] == PLT_STUB_MAGIC1 ||
3328cd9acbbSkettenis 			    got[-1] == PLT_STUB_MAGIC2)
3338cd9acbbSkettenis 				break;
3348cd9acbbSkettenis 			got = NULL;
3358cd9acbbSkettenis 		}
3368cd9acbbSkettenis 		if (got == NULL)
337e3b0f1d9Sguenther 			return 1;
3388cd9acbbSkettenis 
3398cd9acbbSkettenis 		/*
3408cd9acbbSkettenis 		 * Patch up the PLT stub such that it doesn't clobber
3418cd9acbbSkettenis 		 * %r22, which is used to pass on the errno values
3428cd9acbbSkettenis 		 * from failed system calls to __cerrno() in libc.
3438cd9acbbSkettenis 		 */
3448cd9acbbSkettenis 		got[-7] = PLT_STUB_INSN1;
3458cd9acbbSkettenis 		got[-6] = PLT_STUB_INSN2;
346f6193deeSguenther 		__asm volatile("fdc 0(%0)" :: "r" (&got[-7]));
347f6193deeSguenther 		__asm volatile("fdc 0(%0)" :: "r" (&got[-6]));
348f6193deeSguenther 		__asm volatile("sync");
349f6193deeSguenther 		__asm volatile("fic 0(%%sr0,%0)" :: "r" (&got[-7]));
350f6193deeSguenther 		__asm volatile("fic 0(%%sr0,%0)" :: "r" (&got[-6]));
351f6193deeSguenther 		__asm volatile("sync");
3528cd9acbbSkettenis 
3538cd9acbbSkettenis 		/*
3548cd9acbbSkettenis 		 * Fill in the PLT stub such that it invokes the
3558cd9acbbSkettenis 		 * _dl_bind_start() trampoline to fix up the
3568cd9acbbSkettenis 		 * relocation.
3578cd9acbbSkettenis 		 */
3588cd9acbbSkettenis 		got[1] = (Elf_Addr)object;
3598cd9acbbSkettenis 		got[-2] = (Elf_Addr)&_dl_bind_start;
3608cd9acbbSkettenis 		got[-1] = ltp;
361cfa9f13aSkettenis 		/*
3629e4a9586Skettenis 		 * We need the real address of the trampoline.  Get it
3639e4a9586Skettenis 		 * from the function descriptor if that's what we got.
3649e4a9586Skettenis 		 */
3659e4a9586Skettenis 		if (got[-2] & 2) {
3669e4a9586Skettenis 			hppa_plabel_t *p = (hppa_plabel_t *)(got[-2] & ~2);
3679e4a9586Skettenis 			got[-2] = p->pc;
3689e4a9586Skettenis 		}
3699e4a9586Skettenis 		/*
370cfa9f13aSkettenis 		 * Even though we didn't modify any instructions it
3719e4a9586Skettenis 		 * seems we still need to synchronize the caches.
372cfa9f13aSkettenis 		 * There may be instructions in the same cache line
373cfa9f13aSkettenis 		 * and they end up being corrupted otherwise.
374cfa9f13aSkettenis 		 */
375f6193deeSguenther 		__asm volatile("fdc 0(%0)" :: "r" (&got[-2]));
376f6193deeSguenther 		__asm volatile("fdc 0(%0)" :: "r" (&got[-1]));
377f6193deeSguenther 		__asm volatile("sync");
378f6193deeSguenther 		__asm volatile("fic 0(%%sr0,%0)" :: "r" (&got[-2]));
379f6193deeSguenther 		__asm volatile("fic 0(%%sr0,%0)" :: "r" (&got[-1]));
380f6193deeSguenther 		__asm volatile("sync");
38116117f8fSmickey 		for (i = 0; i < numrela; i++, rela++) {
38216117f8fSmickey 			Elf_Addr *r_addr = (Elf_Addr *)(ooff + rela->r_offset);
38316117f8fSmickey 
3848cd9acbbSkettenis 			if (ELF_R_TYPE(rela->r_info) != RELOC_IPLT) {
3858cd9acbbSkettenis 				_dl_printf("unexpected reloc 0x%x\n",
3868cd9acbbSkettenis 				    ELF_R_TYPE(rela->r_info));
387e3b0f1d9Sguenther 				return 1;
3888cd9acbbSkettenis 			}
3898cd9acbbSkettenis 
39016117f8fSmickey 			if (ELF_R_SYM(rela->r_info)) {
3918cd9acbbSkettenis 				r_addr[0] = (Elf_Addr)got - PLT_STUB_GOTOFF;
3928cd9acbbSkettenis 				r_addr[1] = (Elf_Addr) (rela -
3938cd9acbbSkettenis 				    (Elf_RelA *)object->dyn.jmprel);
39416117f8fSmickey 			} else {
39516117f8fSmickey 				r_addr[0] = ooff + rela->r_addend;
39616117f8fSmickey 				r_addr[1] = (Elf_Addr)object->dyn.pltgot;
39716117f8fSmickey 			}
39816117f8fSmickey 		}
39916117f8fSmickey 	}
400e23a26ffSguenther 
401e3b0f1d9Sguenther 	return fails;
40216117f8fSmickey }
40316117f8fSmickey 
40416117f8fSmickey /*
40516117f8fSmickey  * Resolve a symbol at run-time.
40616117f8fSmickey  */
407ae398163Smiod uint64_t
_dl_bind(elf_object_t * object,int reloff)40816117f8fSmickey _dl_bind(elf_object_t *object, int reloff)
40916117f8fSmickey {
410143e5accSguenther 	struct sym_res sr;
411143e5accSguenther 	const Elf_Sym *sym;
41216117f8fSmickey 	const char *symn;
41316117f8fSmickey 	Elf_Addr value;
41416117f8fSmickey 	Elf_RelA *rela;
415672c18a0Sguenther 	uint64_t cookie = pcookie;
416672c18a0Sguenther 	struct {
417672c18a0Sguenther 		struct __kbind param;
418672c18a0Sguenther 		uint64_t newval;
419672c18a0Sguenther 	} buf;
42016117f8fSmickey 
4218cd9acbbSkettenis 	rela = (Elf_RelA *)object->dyn.jmprel + reloff;
42216117f8fSmickey 
42316117f8fSmickey 	sym = object->dyn.symtab;
42416117f8fSmickey 	sym += ELF_R_SYM(rela->r_info);
42516117f8fSmickey 	symn = object->dyn.strtab + sym->st_name;
42616117f8fSmickey 
427143e5accSguenther 	sr = _dl_find_symbol(symn, SYM_SEARCH_ALL|SYM_WARNNOTFOUND|SYM_PLT,
428143e5accSguenther 	    sym, object);
429143e5accSguenther 	if (sr.sym == NULL)
4303b50b772Sguenther 		_dl_die("lazy binding failed!");
43116117f8fSmickey 
432143e5accSguenther 	value = sr.obj->obj_base + sr.sym->st_value + rela->r_addend;
43316117f8fSmickey 
434143e5accSguenther 	buf.newval = ((uint64_t)value << 32) | (Elf_Addr)sr.obj->dyn.pltgot;
435ae398163Smiod 
436143e5accSguenther 	if (__predict_false(sr.obj->traced) && _dl_trace_plt(sr.obj, symn))
437e3b0f1d9Sguenther 		return buf.newval;
438672c18a0Sguenther 
439672c18a0Sguenther 	buf.param.kb_addr = (Elf_Addr *)(object->obj_base + rela->r_offset);
440672c18a0Sguenther 	buf.param.kb_size = sizeof(uint64_t);
441672c18a0Sguenther 
442672c18a0Sguenther 	/* directly code the syscall, so that it's actually inline here */
443672c18a0Sguenther 	{
444672c18a0Sguenther 		register long r1 __asm__("r1") = SYSCALLGATE;
445672c18a0Sguenther 		register void *arg0 __asm__("r26") = &buf;
446672c18a0Sguenther 		register long arg1 __asm__("r25") = sizeof(buf);
447672c18a0Sguenther 		register long arg2 __asm__("r24") = 0xffffffff & (cookie >> 32);
448672c18a0Sguenther 		register long arg3 __asm__("r23") = 0xffffffff & cookie;
449*07c7d596Sjsg 		__asm__ volatile ("ble 4(%%sr7, %%r1) ! ldi %0, %%r22"
450672c18a0Sguenther 		    :
451672c18a0Sguenther 		    : "i" (SYS_kbind), "r" (r1), "r"(arg0), "r"(arg1),
452672c18a0Sguenther 		      "r"(arg2), "r"(arg3)
453672c18a0Sguenther 		    : "r22", "r28", "r29", "cc", "memory");
45416117f8fSmickey 	}
45516117f8fSmickey 
456e3b0f1d9Sguenther 	return buf.newval;
45716117f8fSmickey }
458