17c478bd9Sstevel@tonic-gate/*
27c478bd9Sstevel@tonic-gate * CDDL HEADER START
37c478bd9Sstevel@tonic-gate *
47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the
5b02637afSrie * Common Development and Distribution License (the "License").
6b02637afSrie * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate *
87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate * and limitations under the License.
127c478bd9Sstevel@tonic-gate *
137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate *
197c478bd9Sstevel@tonic-gate * CDDL HEADER END
207c478bd9Sstevel@tonic-gate */
21b02637afSrie
227c478bd9Sstevel@tonic-gate/*
237c478bd9Sstevel@tonic-gate *	Copyright (c) 1988 AT&T
247c478bd9Sstevel@tonic-gate *	  All Rights Reserved
257c478bd9Sstevel@tonic-gate *
26b02637afSrie * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
27b02637afSrie * Use is subject to license terms.
287c478bd9Sstevel@tonic-gate */
297c478bd9Sstevel@tonic-gate
307c478bd9Sstevel@tonic-gate#include	"machdep.h"
317c478bd9Sstevel@tonic-gate#include	"_audit.h"
327c478bd9Sstevel@tonic-gate#if	defined(lint)
337c478bd9Sstevel@tonic-gate#include	<sys/types.h>
347c478bd9Sstevel@tonic-gate#include	"_rtld.h"
357c478bd9Sstevel@tonic-gate#else
367c478bd9Sstevel@tonic-gate#include	<sys/stack.h>
377c478bd9Sstevel@tonic-gate#include	<sys/asm_linkage.h>
387c478bd9Sstevel@tonic-gate
39b02637afSrie	.file	"boot_elf.s"
407c478bd9Sstevel@tonic-gate	.seg	".text"
417c478bd9Sstevel@tonic-gate#endif
427c478bd9Sstevel@tonic-gate
437c478bd9Sstevel@tonic-gate/*
447c478bd9Sstevel@tonic-gate * We got here because the initial call to a function resolved to a procedure
457c478bd9Sstevel@tonic-gate * linkage table entry.  That entry did a branch to the first PLT entry, which
467c478bd9Sstevel@tonic-gate * in turn did a call to elf_rtbndr (refer elf_plt_init()).
477c478bd9Sstevel@tonic-gate *
487c478bd9Sstevel@tonic-gate * the code sequence that got us here was:
497c478bd9Sstevel@tonic-gate *
507c478bd9Sstevel@tonic-gate * PLT entry for foo():
517c478bd9Sstevel@tonic-gate *	sethi	(.-PLT0), %g1
527c478bd9Sstevel@tonic-gate *	ba,a	.PLT0				! patched atomically 2nd
537c478bd9Sstevel@tonic-gate *	nop					! patched 1st
547c478bd9Sstevel@tonic-gate *	nop
557c478bd9Sstevel@tonic-gate *	nop
567c478bd9Sstevel@tonic-gate *	nop
577c478bd9Sstevel@tonic-gate *	nop
587c478bd9Sstevel@tonic-gate *	nop
597c478bd9Sstevel@tonic-gate *
607c478bd9Sstevel@tonic-gate * Therefore on entry, %i7 has the address of the call, which will be added
617c478bd9Sstevel@tonic-gate * to the offset to the plt entry in %g1 to calculate the plt entry address
627c478bd9Sstevel@tonic-gate * we must also subtract 4 because the address of PLT0 points to the
637c478bd9Sstevel@tonic-gate * save instruction before the call.
647c478bd9Sstevel@tonic-gate *
657c478bd9Sstevel@tonic-gate * The PLT entry is rewritten in one of several ways.  For the full 64-bit
667c478bd9Sstevel@tonic-gate * span, the following sequence is generated:
677c478bd9Sstevel@tonic-gate *
687c478bd9Sstevel@tonic-gate *	nop
697c478bd9Sstevel@tonic-gate *	sethi	%hh(entry_pt), %g1
707c478bd9Sstevel@tonic-gate *	sethi	%lm(entry_pt), %g5
717c478bd9Sstevel@tonic-gate *	or	%g1, %hm(entry_pt), %g1
727c478bd9Sstevel@tonic-gate *	sllx	%g1, 32, %g1
737c478bd9Sstevel@tonic-gate *	or	%g1, %g5, %g5
747c478bd9Sstevel@tonic-gate *	jmpl	%g5 + %lo(entry_pt), %g0
757c478bd9Sstevel@tonic-gate *	nop
767c478bd9Sstevel@tonic-gate *
777c478bd9Sstevel@tonic-gate * Shorter code sequences are possible, depending on reachability
787c478bd9Sstevel@tonic-gate * constraints.  Note that 'call' is not as useful as it might seem in
797c478bd9Sstevel@tonic-gate * this context, because it is only capable of plus or minus 2Gbyte
807c478bd9Sstevel@tonic-gate * PC-relative jumps, and the rdpc instruction is very slow.
817c478bd9Sstevel@tonic-gate *
827c478bd9Sstevel@tonic-gate * At the time of writing, the present and future SPARC CPUs that will use
837c478bd9Sstevel@tonic-gate * this code are only capable of addressing the bottom 43-bits and top 43-bits
847c478bd9Sstevel@tonic-gate * of the address space.  And since shared libraries are placed at the top
857c478bd9Sstevel@tonic-gate * of the address space, the "top 44-bits" sequence will effectively always be
867c478bd9Sstevel@tonic-gate * used.  See elf_plt_write() below.  The "top 32-bits" are used when they
877c478bd9Sstevel@tonic-gate * can reach.
887c478bd9Sstevel@tonic-gate */
897c478bd9Sstevel@tonic-gate
907c478bd9Sstevel@tonic-gate#if	defined(lint)
917c478bd9Sstevel@tonic-gate
927c478bd9Sstevel@tonic-gateextern unsigned long	elf_bndr(Rt_map *, unsigned long, caddr_t);
937c478bd9Sstevel@tonic-gate
947c478bd9Sstevel@tonic-gate/*
957c478bd9Sstevel@tonic-gate * We're called here from .PLTn in a new frame, with %o0 containing
967c478bd9Sstevel@tonic-gate * the result of a sethi (. - .PLT0), and %o1 containing the pc of
977c478bd9Sstevel@tonic-gate * the jmpl instruction we're got here with inside .PLT1
987c478bd9Sstevel@tonic-gate */
997c478bd9Sstevel@tonic-gatevoid
1007c478bd9Sstevel@tonic-gateelf_rtbndr(Rt_map *lmp, unsigned long pltoff, caddr_t from)
1017c478bd9Sstevel@tonic-gate{
1027c478bd9Sstevel@tonic-gate	(void) elf_bndr(lmp, pltoff, from);
1037c478bd9Sstevel@tonic-gate}
1047c478bd9Sstevel@tonic-gate
1057c478bd9Sstevel@tonic-gate#else
1067c478bd9Sstevel@tonic-gate	.weak	_elf_rtbndr		! keep dbx happy as it likes to
1077c478bd9Sstevel@tonic-gate	_elf_rtbndr = elf_rtbndr	! rummage around for our symbols
1087c478bd9Sstevel@tonic-gate
1097c478bd9Sstevel@tonic-gate	ENTRY(elf_rtbndr)
1107c478bd9Sstevel@tonic-gate	mov	%i7, %o3		! Save callers address(profiling)
1117c478bd9Sstevel@tonic-gate	save	%sp, -SA(MINFRAME), %sp
1127c478bd9Sstevel@tonic-gate	mov	%g4, %l5		! Save g4 (safe across function calls)
1137c478bd9Sstevel@tonic-gate	sub	%i1, 0x38, %o1		! compute addr of .PLT0 from addr of .PLT1 jmpl
1147c478bd9Sstevel@tonic-gate	ldx	[%o1 + 0x40], %o0	! ld PLT2[X] into third arg
1157c478bd9Sstevel@tonic-gate	srl	%i0, 10, %o1		! shift offset set by sethi
1167c478bd9Sstevel@tonic-gate	call	elf_bndr		! returns function address in %o0
1172a8bcb4eSToomas Soome	mov	%i3, %o2		! Callers address is arg 3
1187c478bd9Sstevel@tonic-gate	mov	%o0, %g1		! save address of routine binded
1197c478bd9Sstevel@tonic-gate	mov	%l5, %g4		! restore g4
1207c478bd9Sstevel@tonic-gate	restore				! how many restores needed ? 2
1217c478bd9Sstevel@tonic-gate	jmp	%g1			! jump to it
1227c478bd9Sstevel@tonic-gate	restore
1237c478bd9Sstevel@tonic-gate	SET_SIZE(elf_rtbndr)
1247c478bd9Sstevel@tonic-gate
1257c478bd9Sstevel@tonic-gate#endif
1267c478bd9Sstevel@tonic-gate
1277c478bd9Sstevel@tonic-gate
1287c478bd9Sstevel@tonic-gate#if	defined(lint)
1297c478bd9Sstevel@tonic-gatevoid
1307c478bd9Sstevel@tonic-gateelf_rtbndr_far(Rt_map *lmp, unsigned long pltoff, caddr_t from)
1317c478bd9Sstevel@tonic-gate{
1327c478bd9Sstevel@tonic-gate	(void) elf_bndr(lmp, pltoff, from);
1337c478bd9Sstevel@tonic-gate}
1347c478bd9Sstevel@tonic-gate#else
1357c478bd9Sstevel@tonic-gateENTRY(elf_rtbndr_far)
1367c478bd9Sstevel@tonic-gate	mov	%i7, %o3		! Save callers address
1377c478bd9Sstevel@tonic-gate	save	%sp, -SA(MINFRAME), %sp
1387c478bd9Sstevel@tonic-gate	mov	%g4, %l5		! preserve %g4
1397c478bd9Sstevel@tonic-gate	sub	%i1, 0x18, %o2		! compute address of .PLT0 from
1407c478bd9Sstevel@tonic-gate					!   .PLT0 jmpl instr.
1417c478bd9Sstevel@tonic-gate	sub	%i0, %o2, %o1		! pltoff = pc - 0x10 - .PLT0
1427c478bd9Sstevel@tonic-gate	sub	%o1, 0x10, %o1
1437c478bd9Sstevel@tonic-gate	ldx	[%o2 + 0x40], %o0	! ld PLT2[X] into third arg
1447c478bd9Sstevel@tonic-gate	call	elf_bndr		! returns function address in %o0
1457c478bd9Sstevel@tonic-gate	mov	%i3, %o2		! Callers address is arg3
1467c478bd9Sstevel@tonic-gate	mov	%o0, %g1		! save address of routine binded
1477c478bd9Sstevel@tonic-gate	mov	%l5, %g4		! restore g4
1487c478bd9Sstevel@tonic-gate	restore				! how many restores needed ? 2
1497c478bd9Sstevel@tonic-gate	jmp	%g1			! jump to it
1507c478bd9Sstevel@tonic-gate	restore
1517c478bd9Sstevel@tonic-gateSET_SIZE(elf_rtbndr_far)
1527c478bd9Sstevel@tonic-gate#endif
1537c478bd9Sstevel@tonic-gate
1547c478bd9Sstevel@tonic-gate
1557c478bd9Sstevel@tonic-gate/*
1567c478bd9Sstevel@tonic-gate * Initialize a plt entry so that function calls go to 'bindfunc'
1577c478bd9Sstevel@tonic-gate * (We parameterize the binding function here because we call this
1587c478bd9Sstevel@tonic-gate * routine twice - once for PLT0 and once for PLT1 with different
1597c478bd9Sstevel@tonic-gate * binding functions.)
1607c478bd9Sstevel@tonic-gate *
1617c478bd9Sstevel@tonic-gate * The plt entries (PLT0 and PLT1) look like:
1627c478bd9Sstevel@tonic-gate *
1637c478bd9Sstevel@tonic-gate *	save	%sp, -176, %sp
1647c478bd9Sstevel@tonic-gate *	sethi	%hh(bindfunc), %l0
1657c478bd9Sstevel@tonic-gate *	sethi	%lm(bindfunc), %l1
1667c478bd9Sstevel@tonic-gate *	or	%l0, %hm(bindfunc), %l0
1677c478bd9Sstevel@tonic-gate *	sllx	%l0, 32, %l0
1687c478bd9Sstevel@tonic-gate *	or	%l0, %l1, %l0
1697c478bd9Sstevel@tonic-gate *	jmpl	%l0 + %lo(bindfunc), %o1
1707c478bd9Sstevel@tonic-gate *	mov	%g1, %o0
1717c478bd9Sstevel@tonic-gate */
1727c478bd9Sstevel@tonic-gate
1737c478bd9Sstevel@tonic-gate#define	M_SAVE_SP176SP	0x9de3bf50	/*	save	%sp, -176, %sp */
1747c478bd9Sstevel@tonic-gate#define	M_SETHI_L0	0x21000000	/*	sethi	0x0, %l0 */
1757c478bd9Sstevel@tonic-gate#define	M_SETHI_L1	0x23000000	/*	sethi	0x0, %l1 */
1767c478bd9Sstevel@tonic-gate#define	M_OR_L0L0	0xa0142000	/*	or	%l0, 0x0, %l0 */
1777c478bd9Sstevel@tonic-gate#define	M_SLLX_L032L0	0xa12c3020	/*	sllx	%l0, 32, %l0 */
1787c478bd9Sstevel@tonic-gate#define	M_OR_L0L1L0	0xa0140011	/*	or	%l0, %l1, %l0 */
1797c478bd9Sstevel@tonic-gate#define	M_JMPL_L0O1	0x93c42000	/*	jmpl	%l0 + 0, %o1 */
1807c478bd9Sstevel@tonic-gate#define	M_MOV_G1O0	0x90100001	/*	or	%g0, %g1, %o0 */
1817c478bd9Sstevel@tonic-gate
1827c478bd9Sstevel@tonic-gate#if	defined(lint)
1837c478bd9Sstevel@tonic-gate
1847c478bd9Sstevel@tonic-gate#define	HH22(x)	0		/* for lint's benefit */
1857c478bd9Sstevel@tonic-gate#define	LM22(x)	0
1867c478bd9Sstevel@tonic-gate#define	HM10(x)	0
1877c478bd9Sstevel@tonic-gate#define	LO10(x)	0
1887c478bd9Sstevel@tonic-gate
1897c478bd9Sstevel@tonic-gate/* ARGSUSED */
1907c478bd9Sstevel@tonic-gatevoid
1917c478bd9Sstevel@tonic-gateelf_plt_init(void *plt, caddr_t bindfunc)
1927c478bd9Sstevel@tonic-gate{
1937c478bd9Sstevel@tonic-gate	uint_t	*_plt;
1947c478bd9Sstevel@tonic-gate
1957c478bd9Sstevel@tonic-gate	_plt = (uint_t *)plt;
1967c478bd9Sstevel@tonic-gate	_plt[0] = M_SAVE_SP176SP;
1977c478bd9Sstevel@tonic-gate	_plt[1] = M_SETHI_L0 | HH22(bindfunc);
1987c478bd9Sstevel@tonic-gate	_plt[2] = M_SETHI_L1 | LM22(bindfunc);
1997c478bd9Sstevel@tonic-gate	_plt[3] = M_OR_L0L0 | HM10(bindfunc);
2007c478bd9Sstevel@tonic-gate	_plt[4] = M_SLLX_L032L0;
2017c478bd9Sstevel@tonic-gate	_plt[5] = M_OR_L0L1L0;
2027c478bd9Sstevel@tonic-gate	_plt[6] = M_JMPL_L0O1 | LO10(bindfunc);
2037c478bd9Sstevel@tonic-gate	_plt[7] = M_MOV_G1O0;
2047c478bd9Sstevel@tonic-gate}
2057c478bd9Sstevel@tonic-gate
2067c478bd9Sstevel@tonic-gate#else
2077c478bd9Sstevel@tonic-gate	ENTRY(elf_plt_init)
2087c478bd9Sstevel@tonic-gate	save	%sp, -SA(MINFRAME), %sp	! Make a frame
2097c478bd9Sstevel@tonic-gate
2107c478bd9Sstevel@tonic-gate	sethi	%hi(M_SAVE_SP176SP), %o0	! Get save instruction
2117c478bd9Sstevel@tonic-gate	or	%o0, %lo(M_SAVE_SP176SP), %o0
2127c478bd9Sstevel@tonic-gate	st	%o0, [%i0]		! Store in plt[0]
2137c478bd9Sstevel@tonic-gate
2147c478bd9Sstevel@tonic-gate	sethi	%hi(M_SETHI_L0), %o4	! Get "sethi 0x0, %l0" insn
2157c478bd9Sstevel@tonic-gate	srlx	%i1, 42, %o2		! get %hh(function address)
2167c478bd9Sstevel@tonic-gate	or	%o4, %o2, %o4		!	or value into instruction
2177c478bd9Sstevel@tonic-gate	st	%o4, [%i0 + 0x4]	! Store instruction in plt[1]
2187c478bd9Sstevel@tonic-gate	iflush	%i0			! .. and flush
2197c478bd9Sstevel@tonic-gate
2207c478bd9Sstevel@tonic-gate	sethi	%hi(M_SETHI_L1), %o4	! Get "sethi 0x0, %l1" insn
2217c478bd9Sstevel@tonic-gate	srl	%i1, 10, %o2		! get %lm(function address)
2227c478bd9Sstevel@tonic-gate	or	%o4, %o2, %o4		!	or value into instruction
2237c478bd9Sstevel@tonic-gate	st	%o4, [%i0 + 0x8]	! Store instruction in plt[2]
2247c478bd9Sstevel@tonic-gate
2257c478bd9Sstevel@tonic-gate	sethi	%hi(M_OR_L0L0), %o4	! Get "or %l0, 0x0, %l0" insn
2267c478bd9Sstevel@tonic-gate	or	%o4, %lo(M_OR_L0L0), %o4
2277c478bd9Sstevel@tonic-gate	srlx	%i1, 32, %o2		! get %hm(function address)
2287c478bd9Sstevel@tonic-gate	and	%o2, 0x3ff, %o2		! pick out bits 42-33
2297c478bd9Sstevel@tonic-gate	or	%o4, %o2, %o4		!	or value into instruction
2307c478bd9Sstevel@tonic-gate	st	%o4, [%i0 + 0xc]	! Store instruction in plt[3]
2317c478bd9Sstevel@tonic-gate	iflush	%i0 + 8			! .. and flush
2327c478bd9Sstevel@tonic-gate
2337c478bd9Sstevel@tonic-gate	sethi	%hi(M_SLLX_L032L0), %o4	! get "sllx %l0, 32, %l0" insn
2347c478bd9Sstevel@tonic-gate	or	%o4, %lo(M_SLLX_L032L0), %o4
2357c478bd9Sstevel@tonic-gate	st	%o4, [%i0 + 0x10]	! Store instruction in plt[4]
2367c478bd9Sstevel@tonic-gate
2377c478bd9Sstevel@tonic-gate	sethi	%hi(M_OR_L0L1L0), %o4	! get "or %l0, %l1, %l0" insn
2387c478bd9Sstevel@tonic-gate	or	%o4, %lo(M_OR_L0L1L0), %o4
2397c478bd9Sstevel@tonic-gate	st	%o4, [%i0 + 0x14]	! Store instruction in plt[5]
2407c478bd9Sstevel@tonic-gate	iflush	%i0 + 0x10		! .. and flush
2417c478bd9Sstevel@tonic-gate
2427c478bd9Sstevel@tonic-gate	sethi	%hi(M_JMPL_L0O1), %o4	! get "jmpl %l0 + 0, %o1" insn
2437c478bd9Sstevel@tonic-gate	or	%o4, %lo(M_JMPL_L0O1), %o4
2447c478bd9Sstevel@tonic-gate	and	%i1, 0x3ff, %o2		! get %lo(function address)
2457c478bd9Sstevel@tonic-gate	or	%o4, %o2, %o4		!	or value into instruction
2467c478bd9Sstevel@tonic-gate	st	%o4, [%i0 + 0x18]	! Store instruction in plt[6]
2477c478bd9Sstevel@tonic-gate
2487c478bd9Sstevel@tonic-gate	sethi	%hi(M_MOV_G1O0), %o4	! get "mov %g1, %o0" insn
2497c478bd9Sstevel@tonic-gate	or	%o4, %lo(M_MOV_G1O0), %o4
2507c478bd9Sstevel@tonic-gate	st	%o4, [%i0 + 0x1c]	! Store instruction in plt[7]
2517c478bd9Sstevel@tonic-gate	iflush	%i0 + 0x18		! .. and flush
2522a8bcb4eSToomas Soome
2537c478bd9Sstevel@tonic-gate	ret
2547c478bd9Sstevel@tonic-gate	restore
2557c478bd9Sstevel@tonic-gate	SET_SIZE(elf_plt_init)
2567c478bd9Sstevel@tonic-gate#endif
2577c478bd9Sstevel@tonic-gate
2587c478bd9Sstevel@tonic-gate
2592a8bcb4eSToomas Soome
2607c478bd9Sstevel@tonic-gate
2617c478bd9Sstevel@tonic-gate#if	defined(lint)
2627c478bd9Sstevel@tonic-gate/*
2637c478bd9Sstevel@tonic-gate *  The V9 ABI assigns the link map identifier, the
2647c478bd9Sstevel@tonic-gate *  Rt_map pointer, to the start of .PLT2.
2657c478bd9Sstevel@tonic-gate */
2667c478bd9Sstevel@tonic-gatevoid
2677c478bd9Sstevel@tonic-gateelf_plt2_init(unsigned int *plt2, Rt_map * lmp)
2687c478bd9Sstevel@tonic-gate{
2697c478bd9Sstevel@tonic-gate	/* LINTED */
2707c478bd9Sstevel@tonic-gate	*(unsigned long *)plt2 = (unsigned long)lmp;
2717c478bd9Sstevel@tonic-gate}
2727c478bd9Sstevel@tonic-gate#else
2737c478bd9Sstevel@tonic-gate	ENTRY(elf_plt2_init)
2747c478bd9Sstevel@tonic-gate	stx	%o1, [%o0]
2757c478bd9Sstevel@tonic-gate	retl
2767c478bd9Sstevel@tonic-gate	iflush	%o0
2777c478bd9Sstevel@tonic-gate	SET_SIZE(elf_plt2_init)
2787c478bd9Sstevel@tonic-gate#endif
2797c478bd9Sstevel@tonic-gate
2802a8bcb4eSToomas Soome
2817c478bd9Sstevel@tonic-gate
2827c478bd9Sstevel@tonic-gate/*
2837c478bd9Sstevel@tonic-gate * After the first call to a plt, elf_bndr() will have determined the true
2847c478bd9Sstevel@tonic-gate * address of the function being bound.  The plt is now rewritten so that
2857c478bd9Sstevel@tonic-gate * any subsequent calls go directly to the bound function.  If the library
2867c478bd9Sstevel@tonic-gate * to which the function belongs is being profiled refer to _plt_cg_write.
2877c478bd9Sstevel@tonic-gate *
2887c478bd9Sstevel@tonic-gate * For complete 64-bit spanning, the new plt entry is:
2897c478bd9Sstevel@tonic-gate *
2907c478bd9Sstevel@tonic-gate *	nop
2917c478bd9Sstevel@tonic-gate *	sethi	%hh(function address), %g1
2927c478bd9Sstevel@tonic-gate *	sethi	%lm(function address), %g5
2937c478bd9Sstevel@tonic-gate *	or	%g1, %hm(function address), %g1
2947c478bd9Sstevel@tonic-gate *	sllx	%g1, 32, %g1
2957c478bd9Sstevel@tonic-gate *	or	%g1, %g5, %g5
2967c478bd9Sstevel@tonic-gate *	jmpl	%g5, %lo(function address), %g0
2977c478bd9Sstevel@tonic-gate *	nop
2987c478bd9Sstevel@tonic-gate *
2997c478bd9Sstevel@tonic-gate * However, shorter instruction sequences are possible and useful.
3007c478bd9Sstevel@tonic-gate * This version gets us anywhere in the top 44 bits of the
3017c478bd9Sstevel@tonic-gate * address space - since this is where shared objects live most
3027c478bd9Sstevel@tonic-gate * of the time, this case is worth optimizing.
3037c478bd9Sstevel@tonic-gate *
3047c478bd9Sstevel@tonic-gate *	nop
3057c478bd9Sstevel@tonic-gate *	sethi	%h44(~function_address), %g5
3067c478bd9Sstevel@tonic-gate *	xnor	%g5, %m44(~function address), %g1
3077c478bd9Sstevel@tonic-gate *	sllx	%g1, 12, %g1
3087c478bd9Sstevel@tonic-gate *	jmpl	%g1 + %l44(function address), %g0
3097c478bd9Sstevel@tonic-gate *	nop
3107c478bd9Sstevel@tonic-gate *	nop
3117c478bd9Sstevel@tonic-gate *	nop
3127c478bd9Sstevel@tonic-gate *
3137c478bd9Sstevel@tonic-gate * This version gets anywhere in the top 32 bits:
3147c478bd9Sstevel@tonic-gate *
3157c478bd9Sstevel@tonic-gate *	nop
3167c478bd9Sstevel@tonic-gate *	sethi	%hi(~function_address), %g5
3177c478bd9Sstevel@tonic-gate *	xnor	%g5, %lo(~function_address), %g1
3187c478bd9Sstevel@tonic-gate *	jmpl	%g1, %g0
3197c478bd9Sstevel@tonic-gate *	nop
3207c478bd9Sstevel@tonic-gate *	nop
3217c478bd9Sstevel@tonic-gate *	nop
3227c478bd9Sstevel@tonic-gate *	nop
3237c478bd9Sstevel@tonic-gate *
3247c478bd9Sstevel@tonic-gate * This version get's us to a destination within
3257c478bd9Sstevel@tonic-gate * +- 8megs of the PLT's address:
3267c478bd9Sstevel@tonic-gate *
3277c478bd9Sstevel@tonic-gate *	nop
3287c478bd9Sstevel@tonic-gate *	ba,a	<dest>
3297c478bd9Sstevel@tonic-gate *	nop
3307c478bd9Sstevel@tonic-gate *	nop
3317c478bd9Sstevel@tonic-gate *	nop
3327c478bd9Sstevel@tonic-gate *	nop
3337c478bd9Sstevel@tonic-gate *	nop
3347c478bd9Sstevel@tonic-gate *	nop
3357c478bd9Sstevel@tonic-gate *
3367c478bd9Sstevel@tonic-gate * This version get's us to a destination within
3377c478bd9Sstevel@tonic-gate * +- 2megs of the PLT's address:
3387c478bd9Sstevel@tonic-gate *
3397c478bd9Sstevel@tonic-gate *	nop
3407c478bd9Sstevel@tonic-gate *	ba,a,pt	%icc, <dest>
3417c478bd9Sstevel@tonic-gate *	nop
3427c478bd9Sstevel@tonic-gate *	nop
3437c478bd9Sstevel@tonic-gate *	nop
3447c478bd9Sstevel@tonic-gate *	nop
3457c478bd9Sstevel@tonic-gate *	nop
3467c478bd9Sstevel@tonic-gate *	nop
3477c478bd9Sstevel@tonic-gate *
3487c478bd9Sstevel@tonic-gate *
3497c478bd9Sstevel@tonic-gate * The PLT is written in reverse order to ensure re-entrant behaviour.
3507c478bd9Sstevel@tonic-gate * Note that the first two instructions must be overwritten with a
3517c478bd9Sstevel@tonic-gate * single stx.
3527c478bd9Sstevel@tonic-gate *
3537c478bd9Sstevel@tonic-gate * Note that even in the 44-bit case, we deliberately use both %g5 and
3547c478bd9Sstevel@tonic-gate * %g1 to prevent anyone accidentally relying on either of them being
3557c478bd9Sstevel@tonic-gate * non-volatile across a function call.
3567c478bd9Sstevel@tonic-gate */
3577c478bd9Sstevel@tonic-gate
3587c478bd9Sstevel@tonic-gate#define	M_JMPL_G5G0	0x81c16000	/* jmpl %g5 + 0, %g0 */
3597c478bd9Sstevel@tonic-gate#define	M_OR_G1G5G5	0x8a104005	/* or %g1, %g5, %g5 */
3607c478bd9Sstevel@tonic-gate#define	M_SLLX_G132G1	0x83287020	/* sllx %g1, 32, %g1 */
3617c478bd9Sstevel@tonic-gate#define	M_OR_G1G1	0x82106000	/* or %g1, 0x0, %g1 */
3627c478bd9Sstevel@tonic-gate#define	M_SETHI_G5	0x0b000000	/* sethi 0x0, %g5 */
3637c478bd9Sstevel@tonic-gate#define	M_SETHI_G1	0x03000000	/* sethi 0x0, %g1 */
3647c478bd9Sstevel@tonic-gate#define	M_NOP		0x01000000	/* sethi 0x0, %g0 */
3657c478bd9Sstevel@tonic-gate
3667c478bd9Sstevel@tonic-gate#define	M_JMPL_G1G0	0x81c06000	/* jmpl %g1 + 0, %g0 */
3677c478bd9Sstevel@tonic-gate#define	M_SLLX_G112G1	0x8328700c	/* sllx %g1, 12, %g1 */
3687c478bd9Sstevel@tonic-gate#define	M_XNOR_G5G1	0x82396000	/* xnor	%g5, 0, %g1 */
3697c478bd9Sstevel@tonic-gate
3707c478bd9Sstevel@tonic-gate#if	defined(lint)
3717c478bd9Sstevel@tonic-gate
3727c478bd9Sstevel@tonic-gate/* ARGSUSED */
3737c478bd9Sstevel@tonic-gate#define	MASK(m)		((1ul << (m)) - 1ul)
3747c478bd9Sstevel@tonic-gate#define	BITS(v, u, l)	(((v) >> (l)) & MASK((u) - (l) + 1))
3757c478bd9Sstevel@tonic-gate#define	H44(v)		BITS(v, 43, 22)
3767c478bd9Sstevel@tonic-gate#define	M44(v)		BITS(v, 21, 12)
3777c478bd9Sstevel@tonic-gate#define	L44(v)		BITS(v, 11, 0)
3787c478bd9Sstevel@tonic-gate
3797c478bd9Sstevel@tonic-gate#endif
3807c478bd9Sstevel@tonic-gate
3817c478bd9Sstevel@tonic-gate#if	defined(lint)
3827c478bd9Sstevel@tonic-gate
3837c478bd9Sstevel@tonic-gatevoid
3847c478bd9Sstevel@tonic-gate/* ARGSUSED1 */
3857c478bd9Sstevel@tonic-gateplt_upper_32(uintptr_t pc, uintptr_t symval)
3867c478bd9Sstevel@tonic-gate{
3877c478bd9Sstevel@tonic-gate	ulong_t		sym = (ulong_t)symval;
3887c478bd9Sstevel@tonic-gate	/* LINTED */
3897c478bd9Sstevel@tonic-gate	ulong_t		nsym = ~sym;
3907c478bd9Sstevel@tonic-gate	uint_t *	plttab = (uint_t *)pc;
3917c478bd9Sstevel@tonic-gate
3927c478bd9Sstevel@tonic-gate	plttab[3] = M_JMPL_G1G0;
3937c478bd9Sstevel@tonic-gate	plttab[2] = (uint_t)(M_XNOR_G5G1 | LO10(nsym));
3947c478bd9Sstevel@tonic-gate	*(ulong_t *)pc =
3957c478bd9Sstevel@tonic-gate	    ((ulong_t)M_NOP << 32) | (M_SETHI_G5 | LM22(nsym));
3967c478bd9Sstevel@tonic-gate}
3977c478bd9Sstevel@tonic-gate
3987c478bd9Sstevel@tonic-gate#else
3997c478bd9Sstevel@tonic-gate
4007c478bd9Sstevel@tonic-gate
4017c478bd9Sstevel@tonic-gate	ENTRY(plt_upper_32)
4027c478bd9Sstevel@tonic-gate	!
4037c478bd9Sstevel@tonic-gate	! Address lies in top 32-bits of address space, so use
4047c478bd9Sstevel@tonic-gate	! compact PLT sequence
4057c478bd9Sstevel@tonic-gate	!
4067c478bd9Sstevel@tonic-gate	sethi	%hi(M_JMPL_G1G0), %o3	! Get "jmpl %g1, %g0" insn
4077c478bd9Sstevel@tonic-gate	st	%o3, [%o0 + 0xc]	! store instruction in plt[3]
4087c478bd9Sstevel@tonic-gate	iflush	%o0 + 0xc		! .. and flush
4097c478bd9Sstevel@tonic-gate
4107c478bd9Sstevel@tonic-gate	not	%o1, %o4
4117c478bd9Sstevel@tonic-gate	sethi	%hi(M_XNOR_G5G1), %o3	! Get "xnor %g5, %g1, %g1" insn
4127c478bd9Sstevel@tonic-gate	and	%o4, 0x3ff, %o2		! pick out bits 0-9
4137c478bd9Sstevel@tonic-gate	or	%o3, %o2, %o3		!	or value into instruction
4147c478bd9Sstevel@tonic-gate	st	%o3, [%o0 + 0x8]	! store instruction in plt[2]
4157c478bd9Sstevel@tonic-gate	iflush	%o0 + 0x8		! .. and flush
4167c478bd9Sstevel@tonic-gate
4177c478bd9Sstevel@tonic-gate	sethi	%hi(M_SETHI_G5), %o3	! Get "sethi 0x0, %g5" insn
4187c478bd9Sstevel@tonic-gate	srl	%o4, 10, %o2		! get %lm(~function address)
4197c478bd9Sstevel@tonic-gate	or	%o3, %o2, %o3		!	or value into instruction
4207c478bd9Sstevel@tonic-gate
4217c478bd9Sstevel@tonic-gate	sethi	%hi(M_NOP), %o4		! Get "nop" instruction
4227c478bd9Sstevel@tonic-gate	sllx	%o4, 32, %o4		! shift to top of instruction pair
4237c478bd9Sstevel@tonic-gate	or	%o3, %o4, %o3		!	or value into instruction pair
4247c478bd9Sstevel@tonic-gate	stx	%o3, [%o0]		! store instructions into plt[0] plt[1]
4257c478bd9Sstevel@tonic-gate	retl
4267c478bd9Sstevel@tonic-gate	iflush	%o0			! .. and flush
4277c478bd9Sstevel@tonic-gate	SET_SIZE(plt_upper_32)
4287c478bd9Sstevel@tonic-gate#endif	/* defined lint */
4292a8bcb4eSToomas Soome
4307c478bd9Sstevel@tonic-gate
4317c478bd9Sstevel@tonic-gate#if	defined(lint)
4327c478bd9Sstevel@tonic-gate
4337c478bd9Sstevel@tonic-gatevoid
4347c478bd9Sstevel@tonic-gate/* ARGSUSED1 */
4357c478bd9Sstevel@tonic-gateplt_upper_44(uintptr_t pc, uintptr_t symval)
4367c478bd9Sstevel@tonic-gate{
4377c478bd9Sstevel@tonic-gate	ulong_t		sym = (ulong_t)symval;
4387c478bd9Sstevel@tonic-gate	ulong_t		nsym = ~sym;
4397c478bd9Sstevel@tonic-gate	uint_t *	plttab = (uint_t *)pc;
4407c478bd9Sstevel@tonic-gate
4417c478bd9Sstevel@tonic-gate	/* LINTED */
4427c478bd9Sstevel@tonic-gate	plttab[4] = (uint_t)(M_JMPL_G1G0 | L44(sym));
4437c478bd9Sstevel@tonic-gate	plttab[3] = M_SLLX_G112G1;
4447c478bd9Sstevel@tonic-gate	/* LINTED */
4457c478bd9Sstevel@tonic-gate	plttab[2] = (uint_t)(M_XNOR_G5G1 | M44(nsym));
4467c478bd9Sstevel@tonic-gate	*(ulong_t *)pc = ((ulong_t)M_NOP << 32) | (M_SETHI_G5 | H44(nsym));
4477c478bd9Sstevel@tonic-gate}
4487c478bd9Sstevel@tonic-gate
4497c478bd9Sstevel@tonic-gate#else
4507c478bd9Sstevel@tonic-gate
4517c478bd9Sstevel@tonic-gate
4527c478bd9Sstevel@tonic-gate	ENTRY(plt_upper_44)
4537c478bd9Sstevel@tonic-gate	!
4547c478bd9Sstevel@tonic-gate	! Address lies in top 44-bits of address space, so use
4557c478bd9Sstevel@tonic-gate	! compact PLT sequence
4567c478bd9Sstevel@tonic-gate	!
4577c478bd9Sstevel@tonic-gate	setuw	M_JMPL_G1G0, %o3	! Get "jmpl %g1, %g0" insn
4587c478bd9Sstevel@tonic-gate	and	%o1, 0xfff, %o2		! lower 12 bits of function address
4597c478bd9Sstevel@tonic-gate	or	%o3, %o2, %o3		!	is or'ed into instruction
4607c478bd9Sstevel@tonic-gate	st	%o3, [%o0 + 0x10]	! store instruction in plt[4]
4617c478bd9Sstevel@tonic-gate	iflush	%o0 + 0x10		! .. and flush
4627c478bd9Sstevel@tonic-gate
4637c478bd9Sstevel@tonic-gate	setuw	M_SLLX_G112G1, %o3	! Get "sllx %g1, 12, %g1" insn
4647c478bd9Sstevel@tonic-gate	st	%o3, [%o0 + 0xc]	! store instruction in plt[3]
4657c478bd9Sstevel@tonic-gate
4667c478bd9Sstevel@tonic-gate	not	%o1, %o4
4677c478bd9Sstevel@tonic-gate	setuw	M_XNOR_G5G1, %o3	! Get "xnor %g5, 0, %g1" insn
4687c478bd9Sstevel@tonic-gate	srlx	%o4, 12, %o2		! get %m44(0 - function address)
4697c478bd9Sstevel@tonic-gate	and	%o2, 0x3ff, %o2		! pick out bits 21-12
4707c478bd9Sstevel@tonic-gate	or	%o3, %o2, %o3		!	or value into instruction
4717c478bd9Sstevel@tonic-gate	st	%o3, [%o0 + 8]		! store instruction in plt[2]
4727c478bd9Sstevel@tonic-gate	iflush	%o0 + 8			! .. and flush
4737c478bd9Sstevel@tonic-gate
4747c478bd9Sstevel@tonic-gate	setuw	M_SETHI_G5, %o3		! Get "sethi 0x0, %g5" insn
4757c478bd9Sstevel@tonic-gate	srlx	%o4, 22, %o2		! get %h44(0 - function address)
4767c478bd9Sstevel@tonic-gate	or	%o3, %o2, %o3		!	or value into instruction
4777c478bd9Sstevel@tonic-gate
4787c478bd9Sstevel@tonic-gate	setuw	M_NOP, %o4		! Get "nop" instruction
4797c478bd9Sstevel@tonic-gate	sllx	%o4, 32, %o4		! shift to top of instruction pair
4807c478bd9Sstevel@tonic-gate	or	%o3, %o4, %o3		!	or value into instruction pair
4817c478bd9Sstevel@tonic-gate	stx	%o3, [%o0]		! store instructions into plt[0] plt[1]
4827c478bd9Sstevel@tonic-gate	retl
4837c478bd9Sstevel@tonic-gate	iflush	%o0			! .. and flush
4847c478bd9Sstevel@tonic-gate	SET_SIZE(plt_upper_44)
4857c478bd9Sstevel@tonic-gate
4867c478bd9Sstevel@tonic-gate#endif	/* defined(lint) */
4877c478bd9Sstevel@tonic-gate
4887c478bd9Sstevel@tonic-gate
4897c478bd9Sstevel@tonic-gate#if	defined(lint)
4907c478bd9Sstevel@tonic-gate
4917c478bd9Sstevel@tonic-gatevoid
4927c478bd9Sstevel@tonic-gate/* ARGSUSED1 */
4937c478bd9Sstevel@tonic-gateplt_full_range(uintptr_t pc, uintptr_t symval)
4947c478bd9Sstevel@tonic-gate{
4957c478bd9Sstevel@tonic-gate	uint_t *	plttab = (uint_t *)pc;
4967c478bd9Sstevel@tonic-gate
4977c478bd9Sstevel@tonic-gate	plttab[6] = M_JMPL_G5G0 | LO10(symval);
4987c478bd9Sstevel@tonic-gate	plttab[5] = M_OR_G1G5G5;
4997c478bd9Sstevel@tonic-gate	plttab[4] = M_SLLX_G132G1;
5007c478bd9Sstevel@tonic-gate	plttab[3] = M_OR_G1G1 | HM10(symval);
5017c478bd9Sstevel@tonic-gate	plttab[2] = M_SETHI_G5 | LM22(symval);
5027c478bd9Sstevel@tonic-gate	*(ulong_t *)pc =
5037c478bd9Sstevel@tonic-gate		((ulong_t)M_NOP << 32) | (M_SETHI_G1 | HH22(symval));
5047c478bd9Sstevel@tonic-gate}
5057c478bd9Sstevel@tonic-gate
5067c478bd9Sstevel@tonic-gate#else
5077c478bd9Sstevel@tonic-gate	ENTRY(plt_full_range)
5087c478bd9Sstevel@tonic-gate	!
5097c478bd9Sstevel@tonic-gate	! Address lies anywhere in 64-bit address space, so use
5107c478bd9Sstevel@tonic-gate	! full PLT sequence
5117c478bd9Sstevel@tonic-gate	!
5127c478bd9Sstevel@tonic-gate	sethi	%hi(M_JMPL_G5G0), %o3	! Get "jmpl %g5, %g0" insn
5137c478bd9Sstevel@tonic-gate	and	%o1, 0x3ff, %o2		! lower 10 bits of function address
5147c478bd9Sstevel@tonic-gate	or	%o3, %o2, %o3		!	is or'ed into instruction
5157c478bd9Sstevel@tonic-gate	st	%o3, [%o0 + 0x18]	! store instruction in plt[6]
5167c478bd9Sstevel@tonic-gate	iflush	%o0 + 0x18		! .. and flush
5177c478bd9Sstevel@tonic-gate
5187c478bd9Sstevel@tonic-gate	sethi	%hi(M_OR_G1G5G5), %o3	! Get "or %g1, %g5, %g1" insn
5197c478bd9Sstevel@tonic-gate	or	%o3, %lo(M_OR_G1G5G5), %o3
5207c478bd9Sstevel@tonic-gate	st	%o3, [%o0 + 0x14]	! store instruction in plt[5]
5217c478bd9Sstevel@tonic-gate
5227c478bd9Sstevel@tonic-gate	sethi	%hi(M_SLLX_G132G1), %o3	!  Get "sllx %g1, 32, %g1" insn
5237c478bd9Sstevel@tonic-gate	or	%o3, %lo(M_SLLX_G132G1), %o3
5247c478bd9Sstevel@tonic-gate	st	%o3, [%o0 + 0x10]	! store instruction in plt[4]
5257c478bd9Sstevel@tonic-gate	iflush	%o0 + 0x10		! .. and flush
5267c478bd9Sstevel@tonic-gate
5277c478bd9Sstevel@tonic-gate	sethi	%hi(M_OR_G1G1), %o3	! Get "or %g1, 0x0, %g1" insn
5287c478bd9Sstevel@tonic-gate	or	%o3, %lo(M_OR_G1G1), %o3
5297c478bd9Sstevel@tonic-gate	srlx	%o1, 32, %o2		! get %hm(function address)
5307c478bd9Sstevel@tonic-gate	and	%o2, 0x3ff, %o2		! pick out bits 42-33
5317c478bd9Sstevel@tonic-gate	or	%o3, %o2, %o3		!	or value into instruction
5327c478bd9Sstevel@tonic-gate	st	%o3, [%o0 + 0xc]	! store instruction in plt[3]
5337c478bd9Sstevel@tonic-gate
5347c478bd9Sstevel@tonic-gate	sethi	%hi(M_SETHI_G5), %o3	! Get "sethi 0x0, %g5" insn
5357c478bd9Sstevel@tonic-gate	srl	%o1, 10, %o2		! get %lm(function address)
5367c478bd9Sstevel@tonic-gate	or	%o3, %o2, %o3		!	or value into instruction
5377c478bd9Sstevel@tonic-gate	st	%o3, [%o0 + 0x8]	! store instruction in plt[2]
5387c478bd9Sstevel@tonic-gate	iflush	%o0 + 8			! .. and flush
5397c478bd9Sstevel@tonic-gate
5407c478bd9Sstevel@tonic-gate	sethi	%hi(M_SETHI_G1), %o3	! Get "sethi 0x0, %g1" insn
5417c478bd9Sstevel@tonic-gate	srlx	%o1, 42, %o2		! get %hh(function address)
5427c478bd9Sstevel@tonic-gate	or	%o3, %o2, %o3		!	or value into instruction
5437c478bd9Sstevel@tonic-gate
5447c478bd9Sstevel@tonic-gate	sethi	%hi(M_NOP), %o4		! Get "nop" instruction
5457c478bd9Sstevel@tonic-gate	sllx	%o4, 32, %o4		! shift to top of instruction pair
5467c478bd9Sstevel@tonic-gate	or	%o3, %o4, %o3		!	or value into instruction pair
5477c478bd9Sstevel@tonic-gate	stx	%o3, [%o0]		! store instructions into plt[0] plt[1]
5487c478bd9Sstevel@tonic-gate	retl
5497c478bd9Sstevel@tonic-gate	iflush	%o0			! .. and flush
5507c478bd9Sstevel@tonic-gate
5517c478bd9Sstevel@tonic-gate	SET_SIZE(plt_full_range)
5527c478bd9Sstevel@tonic-gate
5537c478bd9Sstevel@tonic-gate#endif	/* defined(lint) */
5547c478bd9Sstevel@tonic-gate
5557c478bd9Sstevel@tonic-gate/*
5567c478bd9Sstevel@tonic-gate * performs the 'iflush' instruction on a range of memory.
5577c478bd9Sstevel@tonic-gate */
5587c478bd9Sstevel@tonic-gate#if	defined(lint)
5597c478bd9Sstevel@tonic-gatevoid
5607c478bd9Sstevel@tonic-gateiflush_range(caddr_t addr, size_t len)
5617c478bd9Sstevel@tonic-gate{
5627c478bd9Sstevel@tonic-gate	/* LINTED */
5637c478bd9Sstevel@tonic-gate	uintptr_t base;
5647c478bd9Sstevel@tonic-gate
5657c478bd9Sstevel@tonic-gate	base = (uintptr_t)addr & ~7;	/* round down to 8 byte alignment */
5667c478bd9Sstevel@tonic-gate	len = (len + 7) & ~7;		/* round up to multiple of 8 bytes */
5677c478bd9Sstevel@tonic-gate	for (len -= 8; (long)len >= 0; len -= 8)
5687c478bd9Sstevel@tonic-gate		/* iflush(base + len) */;
5697c478bd9Sstevel@tonic-gate}
5707c478bd9Sstevel@tonic-gate#else
5717c478bd9Sstevel@tonic-gate	ENTRY(iflush_range)
5727c478bd9Sstevel@tonic-gate	add	%o1, 7, %o1
5737c478bd9Sstevel@tonic-gate	andn	%o0, 7, %o0
5747c478bd9Sstevel@tonic-gate	andn	%o1, 7, %o1
5757c478bd9Sstevel@tonic-gate1:	subcc	%o1, 8, %o1
5767c478bd9Sstevel@tonic-gate	bge,a,pt %xcc, 1b
5777c478bd9Sstevel@tonic-gate	iflush	%o0 + %o1
5787c478bd9Sstevel@tonic-gate	retl
5797c478bd9Sstevel@tonic-gate	nop
5807c478bd9Sstevel@tonic-gate	SET_SIZE(iflush_range)
5817c478bd9Sstevel@tonic-gate#endif
5827c478bd9Sstevel@tonic-gate
5837c478bd9Sstevel@tonic-gate
5847c478bd9Sstevel@tonic-gate#if	defined(lint)
5857c478bd9Sstevel@tonic-gate
5867c478bd9Sstevel@tonic-gateulong_t
5877c478bd9Sstevel@tonic-gateelf_plt_trace()
5887c478bd9Sstevel@tonic-gate{
5897c478bd9Sstevel@tonic-gate	return (0);
5907c478bd9Sstevel@tonic-gate}
5917c478bd9Sstevel@tonic-gate#else
5927c478bd9Sstevel@tonic-gate	.global	elf_plt_trace
5937c478bd9Sstevel@tonic-gate	.type   elf_plt_trace, #function
5947c478bd9Sstevel@tonic-gate
5957c478bd9Sstevel@tonic-gate/*
5967c478bd9Sstevel@tonic-gate * The dyn_plt that called us has already created a stack-frame for
5977c478bd9Sstevel@tonic-gate * us and placed the following entries in it:
5987c478bd9Sstevel@tonic-gate *
5997c478bd9Sstevel@tonic-gate *	[%fp + STACK_BIAS + -0x8]	* dyndata
6007c478bd9Sstevel@tonic-gate *	[%fp + STACK_BIAS + -0x10]	* prev stack size
6017c478bd9Sstevel@tonic-gate *
6027c478bd9Sstevel@tonic-gate * dyndata currently contains:
6037c478bd9Sstevel@tonic-gate *
6047c478bd9Sstevel@tonic-gate *	dyndata:
6057c478bd9Sstevel@tonic-gate *	0x0	Addr		*reflmp
6067c478bd9Sstevel@tonic-gate *	0x8	Addr		*deflmp
6077c478bd9Sstevel@tonic-gate *	0x10	Word		symndx
6087c478bd9Sstevel@tonic-gate *	0x14	Word		sb_flags
6097c478bd9Sstevel@tonic-gate *	0x18	Sym		symdef.st_name
6107c478bd9Sstevel@tonic-gate *	0x1c			symdef.st_info
6117c478bd9Sstevel@tonic-gate *	0x1d			symdef.st_other
6127c478bd9Sstevel@tonic-gate *	0x1e			symdef.st_shndx
6137c478bd9Sstevel@tonic-gate *	0x20			symdef.st_value
6147c478bd9Sstevel@tonic-gate *	0x28			symdef.st_size
6157c478bd9Sstevel@tonic-gate */
6162a8bcb4eSToomas Soome#define	REFLMP_OFF		0x0
6172a8bcb4eSToomas Soome#define	DEFLMP_OFF		0x8
6187c478bd9Sstevel@tonic-gate#define	SYMNDX_OFF		0x10
6197c478bd9Sstevel@tonic-gate#define	SBFLAGS_OFF		0x14
6207c478bd9Sstevel@tonic-gate#define	SYMDEF_OFF		0x18
6217c478bd9Sstevel@tonic-gate#define	SYMDEF_VALUE_OFF	0x20
6227c478bd9Sstevel@tonic-gate
6237c478bd9Sstevel@tonic-gate#define	LAREGSSZ	0x40	/* sizeof (La_sparcv9_regs) */
6247c478bd9Sstevel@tonic-gate
6252a8bcb4eSToomas Soome
6267c478bd9Sstevel@tonic-gateelf_plt_trace:
6277c478bd9Sstevel@tonic-gate1:	call	2f
6287c478bd9Sstevel@tonic-gate	sethi	%hi(_GLOBAL_OFFSET_TABLE_ - (1b - .)), %l7
6297c478bd9Sstevel@tonic-gate2:	or	%l7, %lo(_GLOBAL_OFFSET_TABLE_ - (1b - .)), %l7
6307c478bd9Sstevel@tonic-gate	add	%l7, %o7, %l7
6317c478bd9Sstevel@tonic-gate
6327c478bd9Sstevel@tonic-gate	ldx	[%fp + STACK_BIAS + -CLONGSIZE], %l1	! l1 = * dyndata
6337c478bd9Sstevel@tonic-gate	lduw	[%l1 + SBFLAGS_OFF], %l2		! l2 = sb_flags
6347c478bd9Sstevel@tonic-gate	andcc	%l2, LA_SYMB_NOPLTENTER, %g0
6357c478bd9Sstevel@tonic-gate	be,pt	%icc, .start_pltenter
6362a8bcb4eSToomas Soome	ldx	[%l1 + SYMDEF_VALUE_OFF], %l0	! l0 =
6377c478bd9Sstevel@tonic-gate						!  sym.st_value(calling address)
6387c478bd9Sstevel@tonic-gate	ba,a,pt	%icc, .end_pltenter
6397c478bd9Sstevel@tonic-gate	nop
6407c478bd9Sstevel@tonic-gate
6417c478bd9Sstevel@tonic-gate	/*
6427c478bd9Sstevel@tonic-gate	 * save all registers into La_sparcv9_regs
6437c478bd9Sstevel@tonic-gate	 */
6447c478bd9Sstevel@tonic-gate.start_pltenter:
6457c478bd9Sstevel@tonic-gate	sub	%sp, LAREGSSZ, %sp	! create space for La_sparcv9_regs
6467c478bd9Sstevel@tonic-gate					! storage on the stack.
6477c478bd9Sstevel@tonic-gate
6487c478bd9Sstevel@tonic-gate	add	%fp, STACK_BIAS - (LAREGSSZ + (2 * CLONGSIZE)), %o4	! addr of new space.
6497c478bd9Sstevel@tonic-gate
6507c478bd9Sstevel@tonic-gate	stx	%i0, [%o4 + 0x0]
6517c478bd9Sstevel@tonic-gate	stx	%i1, [%o4 + 0x8]
6527c478bd9Sstevel@tonic-gate	stx	%i2, [%o4 + 0x10]
6537c478bd9Sstevel@tonic-gate	stx	%i3, [%o4 + 0x18]	! because a regwindow shift has
6547c478bd9Sstevel@tonic-gate	stx	%i4, [%o4 + 0x20]	! already occured our current %i*
6557c478bd9Sstevel@tonic-gate	stx	%i5, [%o4 + 0x28]	! register's are the equivalent of
6567c478bd9Sstevel@tonic-gate	stx	%i6, [%o4 + 0x30]	! the %o* registers that the final
6577c478bd9Sstevel@tonic-gate	stx	%i7, [%o4 + 0x38]	! procedure shall see.
6587c478bd9Sstevel@tonic-gate	mov	%g4, %l5		! save g4 (safe across function calls)
6597c478bd9Sstevel@tonic-gate
6607c478bd9Sstevel@tonic-gate
6617c478bd9Sstevel@tonic-gate	ldx	[%fp + STACK_BIAS + -CLONGSIZE], %l1	! %l1 == * dyndata
6627c478bd9Sstevel@tonic-gate	ldx	[%l1 + REFLMP_OFF], %o0		! %o0 = reflmp
6637c478bd9Sstevel@tonic-gate	ldx	[%l1 + DEFLMP_OFF], %o1		! %o1 = deflmp
6647c478bd9Sstevel@tonic-gate	add	%l1, SYMDEF_OFF, %o2		! %o2 = symp
6657c478bd9Sstevel@tonic-gate	lduw	[%l1 + SYMNDX_OFF], %o3		! %o3 = symndx
6667c478bd9Sstevel@tonic-gate	call	audit_pltenter
6677c478bd9Sstevel@tonic-gate	add	%l1, SBFLAGS_OFF, %o5		! %o3 = * sb_flags
6687c478bd9Sstevel@tonic-gate
6697c478bd9Sstevel@tonic-gate	mov	%o0, %l0		! %l0 == calling address
6707c478bd9Sstevel@tonic-gate	add	%sp, LAREGSSZ, %sp	! cleanup La_sparcv9_regs off
6717c478bd9Sstevel@tonic-gate					! of the stack.
6727c478bd9Sstevel@tonic-gate
6737c478bd9Sstevel@tonic-gate.end_pltenter:
6747c478bd9Sstevel@tonic-gate	/*
6757c478bd9Sstevel@tonic-gate	 * If *no* la_pltexit() routines exist we do not need
6767c478bd9Sstevel@tonic-gate	 * to keep the stack frame before we call the actual
6777c478bd9Sstevel@tonic-gate	 * routine.  Instead we jump to it and remove ourself
6787c478bd9Sstevel@tonic-gate	 * from the stack at the same time.
6797c478bd9Sstevel@tonic-gate	 */
6807c478bd9Sstevel@tonic-gate	ldx	[%l7+audit_flags], %l3
6817c478bd9Sstevel@tonic-gate	lduw	[%l3], %l3				! %l3 = audit_flags
6827c478bd9Sstevel@tonic-gate	andcc	%l3, AF_PLTEXIT, %g0			! AF_PLTEXIT = 2
6837c478bd9Sstevel@tonic-gate	be,pt	%icc, .bypass_pltexit
6847c478bd9Sstevel@tonic-gate	ldx	[%fp + STACK_BIAS + -CLONGSIZE], %l1	! %l1 = * dyndata
6857c478bd9Sstevel@tonic-gate	lduw	[%l1 + SBFLAGS_OFF], %l2		! %l2 = sb_flags
6867c478bd9Sstevel@tonic-gate	andcc	%l2, LA_SYMB_NOPLTEXIT, %g0		! LA_SYMB_NOPLTEXIT = 2
6877c478bd9Sstevel@tonic-gate	bne,a,pt	%icc, .bypass_pltexit
6887c478bd9Sstevel@tonic-gate	nop
6897c478bd9Sstevel@tonic-gate
6907c478bd9Sstevel@tonic-gate	ba,a,pt	%icc, .start_pltexit
6917c478bd9Sstevel@tonic-gate	nop
6927c478bd9Sstevel@tonic-gate.bypass_pltexit:
6937c478bd9Sstevel@tonic-gate	mov	%l5, %g4		! restore g4
6947c478bd9Sstevel@tonic-gate	jmpl	%l0, %g0
6957c478bd9Sstevel@tonic-gate	restore
6967c478bd9Sstevel@tonic-gate
6977c478bd9Sstevel@tonic-gate.start_pltexit:
6987c478bd9Sstevel@tonic-gate	/*
6997c478bd9Sstevel@tonic-gate	 * In order to call la_pltexit() we must duplicate the
7007c478bd9Sstevel@tonic-gate	 * arguments from the 'callers' stack on our stack frame.
7017c478bd9Sstevel@tonic-gate	 *
7027c478bd9Sstevel@tonic-gate	 * First we check the size of the callers stack and grow
7037c478bd9Sstevel@tonic-gate	 * our stack to hold any of the arguments that need
7047c478bd9Sstevel@tonic-gate	 * duplicating (these are arguments 6->N), because the
7057c478bd9Sstevel@tonic-gate	 * first 6 (0->5) are passed via register windows on sparc.
7067c478bd9Sstevel@tonic-gate	 */
7077c478bd9Sstevel@tonic-gate
7087c478bd9Sstevel@tonic-gate	/*
7097c478bd9Sstevel@tonic-gate	 * The first calculation is to determine how large the
7107c478bd9Sstevel@tonic-gate	 * argument passing area might be.  Since there is no
7117c478bd9Sstevel@tonic-gate	 * way to distinquish between 'argument passing' and
7127c478bd9Sstevel@tonic-gate	 * 'local storage' from the previous stack this amount must
7137c478bd9Sstevel@tonic-gate	 * cover both.
7147c478bd9Sstevel@tonic-gate	 */
7157c478bd9Sstevel@tonic-gate	ldx	[%fp + STACK_BIAS + -(2 * CLONGSIZE)], %l1	! %l1 = callers
7167c478bd9Sstevel@tonic-gate						!	stack size
7177c478bd9Sstevel@tonic-gate	sub	%l1, MINFRAME, %l1		! %l1 = argument space on
7187c478bd9Sstevel@tonic-gate						!	caller's stack
7197c478bd9Sstevel@tonic-gate	/*
7207c478bd9Sstevel@tonic-gate	 * Next we compare the prev. stack size against the audit_argcnt.  We
7217c478bd9Sstevel@tonic-gate	 * copy at most 'audit_argcnt' arguments.  The default arg count is 64.
7227c478bd9Sstevel@tonic-gate	 *
7237c478bd9Sstevel@tonic-gate	 * NOTE: on sparc we always copy at least six args since these
7247c478bd9Sstevel@tonic-gate	 *	 are in reg-windows and not on the stack.
7257c478bd9Sstevel@tonic-gate	 *
7267c478bd9Sstevel@tonic-gate	 * NOTE: Also note that we multiply (shift really) the arg count
7277c478bd9Sstevel@tonic-gate	 *	 by 8 which is the 'word size' to calculate the amount
7287c478bd9Sstevel@tonic-gate	 *	 of stack space needed.
7297c478bd9Sstevel@tonic-gate	 */
7307c478bd9Sstevel@tonic-gate	ldx	[%l7 + audit_argcnt], %l2
7317c478bd9Sstevel@tonic-gate	lduw	[%l2], %l2			! %l2 = audit_argcnt
7327c478bd9Sstevel@tonic-gate	cmp	%l2, 6
7337c478bd9Sstevel@tonic-gate	ble,pn	%icc, .grow_stack
7347c478bd9Sstevel@tonic-gate	sub	%l2, 6, %l2
7357c478bd9Sstevel@tonic-gate	sllx	%l2, CLONGSHIFT, %l2		! arg count * 8
7362a8bcb4eSToomas Soome	cmp	%l1, %l2			!
7377c478bd9Sstevel@tonic-gate	ble,a,pn	%icc, .grow_stack
7387c478bd9Sstevel@tonic-gate	nop
7397c478bd9Sstevel@tonic-gate	mov	%l2, %l1
7407c478bd9Sstevel@tonic-gate.grow_stack:
7417c478bd9Sstevel@tonic-gate	/*
7427c478bd9Sstevel@tonic-gate	 * When duplicating the stack we skip the first SA(MINFRAME)
7437c478bd9Sstevel@tonic-gate	 * bytes. This is the space on the stack reserved for preserving
7447c478bd9Sstevel@tonic-gate	 * the register windows and such and do not need to be duplicated
7457c478bd9Sstevel@tonic-gate	 * on this new stack frame.  We start duplicating at the portion
7467c478bd9Sstevel@tonic-gate	 * of the stack reserved for argument's above 6.
7477c478bd9Sstevel@tonic-gate	 */
7487c478bd9Sstevel@tonic-gate	sub	%sp, %l1, %sp		! grow our stack by amount required.
7497c478bd9Sstevel@tonic-gate	srax	%l1, CLONGSHIFT, %l1	! %l1 = %l1 / 8 (words to copy)
7507c478bd9Sstevel@tonic-gate	mov	SA(MINFRAME), %l2	! %l2 = index into stack & frame
7517c478bd9Sstevel@tonic-gate
7527c478bd9Sstevel@tonic-gate1:
7537c478bd9Sstevel@tonic-gate	cmp	%l1, 0
7547c478bd9Sstevel@tonic-gate	ble,a,pn	%icc, 2f
7557c478bd9Sstevel@tonic-gate	nop
7567c478bd9Sstevel@tonic-gate
7577c478bd9Sstevel@tonic-gate	add	%fp, %l2, %l4
7587c478bd9Sstevel@tonic-gate	ldx	[%l4 + STACK_BIAS], %l3		! duplicate args from previous
7597c478bd9Sstevel@tonic-gate	add	%sp, %l2, %l4
7607c478bd9Sstevel@tonic-gate	stx	%l3, [%l4 + STACK_BIAS]		! stack onto current stack
7617c478bd9Sstevel@tonic-gate
7627c478bd9Sstevel@tonic-gate	add	%l2, CLONGSIZE, %l2
7637c478bd9Sstevel@tonic-gate	ba,pt	%icc, 1b
7647c478bd9Sstevel@tonic-gate	sub	%l1, 0x1, %l1
7657c478bd9Sstevel@tonic-gate2:
7667c478bd9Sstevel@tonic-gate	mov	%i0, %o0		! copy ins to outs
7677c478bd9Sstevel@tonic-gate	mov	%i1, %o1
7687c478bd9Sstevel@tonic-gate	mov	%i2, %o2
7697c478bd9Sstevel@tonic-gate	mov	%i3, %o3
7707c478bd9Sstevel@tonic-gate	mov	%i4, %o4
7717c478bd9Sstevel@tonic-gate	mov	%i5, %o5
7727c478bd9Sstevel@tonic-gate	call	%l0			! call original routine
7737c478bd9Sstevel@tonic-gate	mov	%l5, %g4		! restore g4
7747c478bd9Sstevel@tonic-gate	mov	%o1, %l2		! l2 = second 1/2 of return value
7757c478bd9Sstevel@tonic-gate					! for those those 64 bit operations
7767c478bd9Sstevel@tonic-gate					! link div64 - yuck...
7777c478bd9Sstevel@tonic-gate
7787c478bd9Sstevel@tonic-gate					! %o0 = retval
7797c478bd9Sstevel@tonic-gate	ldx	[%fp + STACK_BIAS + -CLONGSIZE], %l1
7807c478bd9Sstevel@tonic-gate	ldx	[%l1 + REFLMP_OFF], %o1		! %o1 = reflmp
7817c478bd9Sstevel@tonic-gate	ldx	[%l1 + DEFLMP_OFF], %o2		! %o2 = deflmp
7827c478bd9Sstevel@tonic-gate	add	%l1, SYMDEF_OFF, %o3		! %o3 = symp
7837c478bd9Sstevel@tonic-gate	call	audit_pltexit
7847c478bd9Sstevel@tonic-gate	lduw	[%l1 + SYMNDX_OFF], %o4		! %o4 = symndx
7857c478bd9Sstevel@tonic-gate
7867c478bd9Sstevel@tonic-gate	mov	%o0, %i0			! pass on return code
7877c478bd9Sstevel@tonic-gate	mov	%l2, %i1
7887c478bd9Sstevel@tonic-gate	ret
7897c478bd9Sstevel@tonic-gate	restore
7907c478bd9Sstevel@tonic-gate	.size	elf_plt_trace, . - elf_plt_trace
7917c478bd9Sstevel@tonic-gate
7927c478bd9Sstevel@tonic-gate#endif
7937c478bd9Sstevel@tonic-gate
794