xref: /titanic_51/usr/src/cmd/sgs/rtld/sparc/boot_elf.s (revision b02637af6dc592eb1f43cb4c74f06268648dbd2d)
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
5*b02637afSrie * Common Development and Distribution License (the "License").
6*b02637afSrie * 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 */
21*b02637afSrie
227c478bd9Sstevel@tonic-gate/*
237c478bd9Sstevel@tonic-gate *	Copyright (c) 1988 AT&T
247c478bd9Sstevel@tonic-gate *	  All Rights Reserved
257c478bd9Sstevel@tonic-gate *
26*b02637afSrie * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
277c478bd9Sstevel@tonic-gate * Use is subject to license terms.
287c478bd9Sstevel@tonic-gate */
297c478bd9Sstevel@tonic-gate#pragma ident	"%Z%%M%	%I%	%E% SMI"
307c478bd9Sstevel@tonic-gate
317c478bd9Sstevel@tonic-gate#include	<link.h>
327c478bd9Sstevel@tonic-gate#include	"machdep.h"
337c478bd9Sstevel@tonic-gate#include	"_audit.h"
347c478bd9Sstevel@tonic-gate
357c478bd9Sstevel@tonic-gate#if	defined(lint)
367c478bd9Sstevel@tonic-gate#include	<sys/types.h>
377c478bd9Sstevel@tonic-gate#include	"_rtld.h"
387c478bd9Sstevel@tonic-gate#else
397c478bd9Sstevel@tonic-gate#include	<sys/stack.h>
407c478bd9Sstevel@tonic-gate#include	<sys/asm_linkage.h>
417c478bd9Sstevel@tonic-gate
427c478bd9Sstevel@tonic-gate	.file	"boot_elf.s"
437c478bd9Sstevel@tonic-gate	.seg	".text"
447c478bd9Sstevel@tonic-gate#endif
457c478bd9Sstevel@tonic-gate
467c478bd9Sstevel@tonic-gate/*
477c478bd9Sstevel@tonic-gate * We got here because the initial call to a function resolved to a procedure
487c478bd9Sstevel@tonic-gate * linkage table entry.  That entry did a branch to the first PLT entry, which
497c478bd9Sstevel@tonic-gate * in turn did a call to elf_rtbndr (refer elf_plt_init()).
507c478bd9Sstevel@tonic-gate *
517c478bd9Sstevel@tonic-gate * the code sequence that got us here was:
527c478bd9Sstevel@tonic-gate *
537c478bd9Sstevel@tonic-gate * PLT entry for foo():
547c478bd9Sstevel@tonic-gate *	sethi	(.-PLT0), %g1			! not changed by rtld
557c478bd9Sstevel@tonic-gate *	ba,a	.PLT0				! patched atomically 2nd
567c478bd9Sstevel@tonic-gate *	nop					! patched first
577c478bd9Sstevel@tonic-gate *
587c478bd9Sstevel@tonic-gate * Therefore on entry, %i7 has the address of the call, which will be added
597c478bd9Sstevel@tonic-gate * to the offset to the plt entry in %g1 to calculate the plt entry address
607c478bd9Sstevel@tonic-gate * we must also subtract 4 because the address of PLT0 points to the
617c478bd9Sstevel@tonic-gate * save instruction before the call.
627c478bd9Sstevel@tonic-gate *
637c478bd9Sstevel@tonic-gate * the plt entry is rewritten:
647c478bd9Sstevel@tonic-gate *
657c478bd9Sstevel@tonic-gate * PLT entry for foo():
667c478bd9Sstevel@tonic-gate *	sethi	(.-PLT0), %g1
677c478bd9Sstevel@tonic-gate *	sethi	%hi(entry_pt), %g1
687c478bd9Sstevel@tonic-gate *	jmpl	%g1 + %lo(entry_pt), %g0
697c478bd9Sstevel@tonic-gate */
707c478bd9Sstevel@tonic-gate
717c478bd9Sstevel@tonic-gate#if	defined(lint)
727c478bd9Sstevel@tonic-gate
737c478bd9Sstevel@tonic-gateextern unsigned long	elf_bndr(Rt_map *, unsigned long, caddr_t);
747c478bd9Sstevel@tonic-gate
757c478bd9Sstevel@tonic-gatestatic void
767c478bd9Sstevel@tonic-gateelf_rtbndr(Rt_map *lmp, unsigned long pltoff, caddr_t from)
777c478bd9Sstevel@tonic-gate{
787c478bd9Sstevel@tonic-gate	(void) elf_bndr(lmp, pltoff, from);
797c478bd9Sstevel@tonic-gate}
807c478bd9Sstevel@tonic-gate
817c478bd9Sstevel@tonic-gate
827c478bd9Sstevel@tonic-gate#else
837c478bd9Sstevel@tonic-gate	.weak	_elf_rtbndr		! keep dbx happy as it likes to
847c478bd9Sstevel@tonic-gate	_elf_rtbndr = elf_rtbndr	! rummage around for our symbols
857c478bd9Sstevel@tonic-gate
867c478bd9Sstevel@tonic-gate	.global	elf_rtbndr
877c478bd9Sstevel@tonic-gate	.type   elf_rtbndr, #function
887c478bd9Sstevel@tonic-gate	.align	4
897c478bd9Sstevel@tonic-gate
907c478bd9Sstevel@tonic-gateelf_rtbndr:
917c478bd9Sstevel@tonic-gate	mov	%i7, %o0		! Save callers address(profiling)
927c478bd9Sstevel@tonic-gate	save	%sp, -SA(MINFRAME), %sp	! Make a frame
937c478bd9Sstevel@tonic-gate	srl	%g1, 10, %o1		! shift offset set by sethi
947c478bd9Sstevel@tonic-gate					! %o1 has offset from jump slot
957c478bd9Sstevel@tonic-gate					! to PLT0 which will be used to
967c478bd9Sstevel@tonic-gate					! calculate plt relocation entry
977c478bd9Sstevel@tonic-gate					! by elf_bndr
987c478bd9Sstevel@tonic-gate	ld	[%i7 + 8], %o0		! %o0 has ptr to lm
997c478bd9Sstevel@tonic-gate	call	elf_bndr		! returns function address in %o0
1007c478bd9Sstevel@tonic-gate	mov	%i0, %o2		! Callers address is arg 3
1017c478bd9Sstevel@tonic-gate	mov	%o0, %g1		! save address of routine binded
1027c478bd9Sstevel@tonic-gate	restore				! how many restores needed ? 2
1037c478bd9Sstevel@tonic-gate	jmp	%g1			! jump to it
1047c478bd9Sstevel@tonic-gate	restore
1057c478bd9Sstevel@tonic-gate	.size 	elf_rtbndr, . - elf_rtbndr
1067c478bd9Sstevel@tonic-gate
1077c478bd9Sstevel@tonic-gate#endif
1087c478bd9Sstevel@tonic-gate
1097c478bd9Sstevel@tonic-gate
1107c478bd9Sstevel@tonic-gate#if defined(lint)
1117c478bd9Sstevel@tonic-gatevoid
1127c478bd9Sstevel@tonic-gateiflush_range(caddr_t addr, size_t len)
1137c478bd9Sstevel@tonic-gate{
1147c478bd9Sstevel@tonic-gate	/* LINTED */
1157c478bd9Sstevel@tonic-gate	uintptr_t base;
1167c478bd9Sstevel@tonic-gate
1177c478bd9Sstevel@tonic-gate	base = (uintptr_t)addr & ~7;	/* round down to 8 byte alignment */
1187c478bd9Sstevel@tonic-gate	len = (len + 7) & ~7;		/* round up to multiple of 8 bytes */
1197c478bd9Sstevel@tonic-gate	for (len -= 8; (long)len >= 0; len -= 8)
1207c478bd9Sstevel@tonic-gate		/* iflush(base + len) */;
1217c478bd9Sstevel@tonic-gate}
1227c478bd9Sstevel@tonic-gate#else
1237c478bd9Sstevel@tonic-gate	ENTRY(iflush_range)
1247c478bd9Sstevel@tonic-gate	add	%o1, 7, %o1
1257c478bd9Sstevel@tonic-gate	andn	%o0, 7, %o0
1267c478bd9Sstevel@tonic-gate	andn	%o1, 7, %o1
1277c478bd9Sstevel@tonic-gate1:	subcc	%o1, 8, %o1
1287c478bd9Sstevel@tonic-gate	bge,a	1b
1297c478bd9Sstevel@tonic-gate	iflush	%o0 + %o1
1307c478bd9Sstevel@tonic-gate	retl
1317c478bd9Sstevel@tonic-gate	nop
1327c478bd9Sstevel@tonic-gate	SET_SIZE(iflush_range)
1337c478bd9Sstevel@tonic-gate#endif
1347c478bd9Sstevel@tonic-gate
1357c478bd9Sstevel@tonic-gate/*
1367c478bd9Sstevel@tonic-gate * Initialize the first plt entry so that function calls go to elf_rtbndr
1377c478bd9Sstevel@tonic-gate *
1387c478bd9Sstevel@tonic-gate * The first plt entry (PLT0) is:
1397c478bd9Sstevel@tonic-gate *
1407c478bd9Sstevel@tonic-gate *	save	%sp, -64, %sp
1417c478bd9Sstevel@tonic-gate *	call	elf_rtbndr
1427c478bd9Sstevel@tonic-gate *	nop
1437c478bd9Sstevel@tonic-gate *	address of lm
1447c478bd9Sstevel@tonic-gate */
1457c478bd9Sstevel@tonic-gate
1467c478bd9Sstevel@tonic-gate#if	defined(lint)
1477c478bd9Sstevel@tonic-gate
1487c478bd9Sstevel@tonic-gatevoid
1497c478bd9Sstevel@tonic-gateelf_plt_init(void *plt, caddr_t lmp)
1507c478bd9Sstevel@tonic-gate{
1517c478bd9Sstevel@tonic-gate	*((uint_t *)plt + 0) = (unsigned long) M_SAVESP64;
1527c478bd9Sstevel@tonic-gate	*((uint_t *)plt + 4) = M_CALL | (((unsigned long)elf_rtbndr -
1537c478bd9Sstevel@tonic-gate			((unsigned long)plt)) >> 2);
1547c478bd9Sstevel@tonic-gate	*((uint_t *)plt + 8) = M_NOP;
1557c478bd9Sstevel@tonic-gate	*((uint_t *)plt + 12) = (unsigned long) lmp;
1567c478bd9Sstevel@tonic-gate}
1577c478bd9Sstevel@tonic-gate
1587c478bd9Sstevel@tonic-gate#else
1597c478bd9Sstevel@tonic-gate	.global	elf_plt_init
1607c478bd9Sstevel@tonic-gate	.type	elf_plt_init, #function
1617c478bd9Sstevel@tonic-gate	.align	4
1627c478bd9Sstevel@tonic-gate
1637c478bd9Sstevel@tonic-gateelf_plt_init:
1647c478bd9Sstevel@tonic-gate	save	%sp, -SA(MINFRAME), %sp	! Make a frame
1657c478bd9Sstevel@tonic-gate1:
1667c478bd9Sstevel@tonic-gate	call	2f
1677c478bd9Sstevel@tonic-gate	sethi	%hi((_GLOBAL_OFFSET_TABLE_ - (1b - .))), %l7
1687c478bd9Sstevel@tonic-gate2:
1697c478bd9Sstevel@tonic-gate	sethi	%hi(M_SAVESP64), %o0	! Get save instruction
1707c478bd9Sstevel@tonic-gate	or	%o0, %lo(M_SAVESP64), %o0
1717c478bd9Sstevel@tonic-gate	or	%l7, %lo((_GLOBAL_OFFSET_TABLE_ - (1b - .))), %l7
1727c478bd9Sstevel@tonic-gate	st	%o0, [%i0]		! Store in plt[0]
1737c478bd9Sstevel@tonic-gate	iflush	%i0
1747c478bd9Sstevel@tonic-gate	add	%l7, %o7, %l7
1757c478bd9Sstevel@tonic-gate	ld	[%l7 + elf_rtbndr], %l7
1767c478bd9Sstevel@tonic-gate	inc	4, %i0			! Bump plt to point to plt[1]
1777c478bd9Sstevel@tonic-gate	sub	%l7, %i0, %o0		! Determine -pc so as to produce
1787c478bd9Sstevel@tonic-gate					! offset from plt[1]
1797c478bd9Sstevel@tonic-gate	srl	%o0, 2, %o0		! Express offset as number of words
1807c478bd9Sstevel@tonic-gate	sethi	%hi(M_CALL), %o4	! Get sethi instruction
1817c478bd9Sstevel@tonic-gate	or	%o4, %o0, %o4		! Add elf_rtbndr address
1827c478bd9Sstevel@tonic-gate	st	%o4, [%i0]		! Store instruction in plt
1837c478bd9Sstevel@tonic-gate	iflush	%i0
1847c478bd9Sstevel@tonic-gate	sethi	%hi(M_NOP), %o0		! Generate nop instruction
1857c478bd9Sstevel@tonic-gate	st	%o0, [%i0 + 4]		! Store instruction in plt[2]
1867c478bd9Sstevel@tonic-gate	iflush	%i0 + 4
1877c478bd9Sstevel@tonic-gate	st	%i1, [%i0 + 8]		! Store instruction in plt[3]
1887c478bd9Sstevel@tonic-gate	iflush	%i0 + 8
1897c478bd9Sstevel@tonic-gate	ret
1907c478bd9Sstevel@tonic-gate	restore
1917c478bd9Sstevel@tonic-gate	.size	elf_plt_init, . - elf_plt_init
1927c478bd9Sstevel@tonic-gate#endif
1937c478bd9Sstevel@tonic-gate
1947c478bd9Sstevel@tonic-gate#if	defined(lint)
1957c478bd9Sstevel@tonic-gate
1967c478bd9Sstevel@tonic-gateulong_t
1977c478bd9Sstevel@tonic-gateelf_plt_trace()
1987c478bd9Sstevel@tonic-gate{
1997c478bd9Sstevel@tonic-gate	return (0);
2007c478bd9Sstevel@tonic-gate}
2017c478bd9Sstevel@tonic-gate#else
2027c478bd9Sstevel@tonic-gate	.global	elf_plt_trace
2037c478bd9Sstevel@tonic-gate	.type   elf_plt_trace, #function
2047c478bd9Sstevel@tonic-gate	.align	4
2057c478bd9Sstevel@tonic-gate
2067c478bd9Sstevel@tonic-gate/*
2077c478bd9Sstevel@tonic-gate * The dyn_plt that called us has already created a stack-frame for
2087c478bd9Sstevel@tonic-gate * us and placed the following entries in it:
2097c478bd9Sstevel@tonic-gate *
2107c478bd9Sstevel@tonic-gate *	[%fp - 0x4]	* dyndata
2117c478bd9Sstevel@tonic-gate *	[%fp - 0x8]	* prev stack size
2127c478bd9Sstevel@tonic-gate *
2137c478bd9Sstevel@tonic-gate * dyndata currently contains:
2147c478bd9Sstevel@tonic-gate *
2157c478bd9Sstevel@tonic-gate *	dyndata:
2167c478bd9Sstevel@tonic-gate *	0x0	uintptr_t	*reflmp
2177c478bd9Sstevel@tonic-gate *	0x4	uintptr_t	*deflmp
2187c478bd9Sstevel@tonic-gate *	0x8	ulong_t		symndx
2197c478bd9Sstevel@tonic-gate *	0xc	ulong_t		sb_flags
2207c478bd9Sstevel@tonic-gate *	0x10	Sym		symdef.st_name
2217c478bd9Sstevel@tonic-gate *	0x14			symdef.st_value
2227c478bd9Sstevel@tonic-gate *	0x18			symdef.st_size
2237c478bd9Sstevel@tonic-gate *	0x1c			symdef.st_info
2247c478bd9Sstevel@tonic-gate *	0x1d			symdef.st_other
2257c478bd9Sstevel@tonic-gate *	0x1e			symdef.st_shndx
2267c478bd9Sstevel@tonic-gate */
2277c478bd9Sstevel@tonic-gate#define	REFLMP_OFF		0x0
2287c478bd9Sstevel@tonic-gate#define	DEFLMP_OFF		0x4
2297c478bd9Sstevel@tonic-gate#define	SYMNDX_OFF		0x8
2307c478bd9Sstevel@tonic-gate#define	SBFLAGS_OFF		0xc
2317c478bd9Sstevel@tonic-gate#define	SYMDEF_OFF		0x10
2327c478bd9Sstevel@tonic-gate#define	SYMDEF_VALUE_OFF	0x14
2337c478bd9Sstevel@tonic-gate
2347c478bd9Sstevel@tonic-gateelf_plt_trace:
2357c478bd9Sstevel@tonic-gate1:	call	2f
2367c478bd9Sstevel@tonic-gate	sethi	%hi(_GLOBAL_OFFSET_TABLE_+(.-1b)), %l7
2377c478bd9Sstevel@tonic-gate2:	or	%l7, %lo(_GLOBAL_OFFSET_TABLE_+(.-1b)), %l7
2387c478bd9Sstevel@tonic-gate	add	%l7, %o7, %l7
2397c478bd9Sstevel@tonic-gate
2407c478bd9Sstevel@tonic-gate	ld	[%l7+audit_flags], %l3
2417c478bd9Sstevel@tonic-gate	ld	[%l3], %l3		! %l3 = audit_flags
2427c478bd9Sstevel@tonic-gate	andcc	%l3, AF_PLTENTER, %g0
2437c478bd9Sstevel@tonic-gate	beq	.end_pltenter
2447c478bd9Sstevel@tonic-gate	ld	[%fp + -0x4], %l1	! l1 = * dyndata
2457c478bd9Sstevel@tonic-gate	ld	[%l1 + SBFLAGS_OFF], %l2 ! l2 = sb_flags
2467c478bd9Sstevel@tonic-gate	andcc	%l2, LA_SYMB_NOPLTENTER, %g0
2477c478bd9Sstevel@tonic-gate	beq	.start_pltenter
2487c478bd9Sstevel@tonic-gate	ld	[%l1 + SYMDEF_VALUE_OFF], %l0	! l0 =
2497c478bd9Sstevel@tonic-gate						!  sym.st_value(calling address)
2507c478bd9Sstevel@tonic-gate	ba	.end_pltenter
2517c478bd9Sstevel@tonic-gate	nop
2527c478bd9Sstevel@tonic-gate
2537c478bd9Sstevel@tonic-gate	/*
2547c478bd9Sstevel@tonic-gate	 * save all registers into La_sparcv8_regs
2557c478bd9Sstevel@tonic-gate	 */
2567c478bd9Sstevel@tonic-gate.start_pltenter:
2577c478bd9Sstevel@tonic-gate	sub	%sp, 0x20, %sp		! create space for La_sparcv8_regs
2587c478bd9Sstevel@tonic-gate					! storage on the stack.
2597c478bd9Sstevel@tonic-gate
2607c478bd9Sstevel@tonic-gate	sub	%fp, 0x28, %o4
2617c478bd9Sstevel@tonic-gate
2627c478bd9Sstevel@tonic-gate	st	%i0, [%o4]
2637c478bd9Sstevel@tonic-gate	st	%i1, [%o4 + 0x4]
2647c478bd9Sstevel@tonic-gate	st	%i2, [%o4 + 0x8]
2657c478bd9Sstevel@tonic-gate	st	%i3, [%o4 + 0xc]	! because a regwindow shift has
2667c478bd9Sstevel@tonic-gate	st	%i4, [%o4 + 0x10]	! already occured our current %i*
2677c478bd9Sstevel@tonic-gate	st	%i5, [%o4 + 0x14]	! register's are the equivalent of
2687c478bd9Sstevel@tonic-gate	st	%i6, [%o4 + 0x18]	! the %o* registers that the final
2697c478bd9Sstevel@tonic-gate	st	%i7, [%o4 + 0x1c]	! procedure shall see.
2707c478bd9Sstevel@tonic-gate
2717c478bd9Sstevel@tonic-gate	ld	[%fp + -0x4], %l1	! %l1 == * dyndata
2727c478bd9Sstevel@tonic-gate	ld	[%l1 + REFLMP_OFF], %o0	! %o0 = reflmp
2737c478bd9Sstevel@tonic-gate	ld	[%l1 + DEFLMP_OFF], %o1	! %o1 = deflmp
2747c478bd9Sstevel@tonic-gate	add	%l1, SYMDEF_OFF, %o2	! %o2 = symp
2757c478bd9Sstevel@tonic-gate	ld	[%l1 + SYMNDX_OFF], %o3	! %o3 = symndx
2767c478bd9Sstevel@tonic-gate	call	audit_pltenter
2777c478bd9Sstevel@tonic-gate	add	%l1, SBFLAGS_OFF, %o5	! %o3 = * sb_flags
2787c478bd9Sstevel@tonic-gate
2797c478bd9Sstevel@tonic-gate	mov	%o0, %l0		! %l0 == calling address
2807c478bd9Sstevel@tonic-gate
2817c478bd9Sstevel@tonic-gate	add	%sp, 0x20, %sp		! cleanup La_sparcv8_regs off
2827c478bd9Sstevel@tonic-gate					! of the stack.
2837c478bd9Sstevel@tonic-gate
2847c478bd9Sstevel@tonic-gate.end_pltenter:
2857c478bd9Sstevel@tonic-gate	/*
2867c478bd9Sstevel@tonic-gate	 * If *no* la_pltexit() routines exist we do not need to keep the
2877c478bd9Sstevel@tonic-gate	 * stack frame before we call the actual routine.  Instead we jump to
2887c478bd9Sstevel@tonic-gate	 * it and remove our self from the stack at the same time.
2897c478bd9Sstevel@tonic-gate	 */
2907c478bd9Sstevel@tonic-gate	ld	[%l7+audit_flags], %l3
2917c478bd9Sstevel@tonic-gate	ld	[%l3], %l3		! %l3 = audit_flags
2927c478bd9Sstevel@tonic-gate	andcc	%l3, AF_PLTEXIT, %g0
2937c478bd9Sstevel@tonic-gate	beq	.bypass_pltexit
2947c478bd9Sstevel@tonic-gate	ld	[%fp + -0x4], %l1	! %l1 = * dyndata
2957c478bd9Sstevel@tonic-gate	ld	[%l1 + SBFLAGS_OFF], %l2 ! %l2 = sb_flags
2967c478bd9Sstevel@tonic-gate	andcc	%l2, LA_SYMB_NOPLTEXIT, %g0
2977c478bd9Sstevel@tonic-gate	bne	.bypass_pltexit
2987c478bd9Sstevel@tonic-gate	nop
2997c478bd9Sstevel@tonic-gate
3007c478bd9Sstevel@tonic-gate	ba	.start_pltexit
3017c478bd9Sstevel@tonic-gate	nop
3027c478bd9Sstevel@tonic-gate.bypass_pltexit:
3037c478bd9Sstevel@tonic-gate	jmpl	%l0, %g0
3047c478bd9Sstevel@tonic-gate	restore
3057c478bd9Sstevel@tonic-gate
3067c478bd9Sstevel@tonic-gate.start_pltexit:
3077c478bd9Sstevel@tonic-gate	/*
3087c478bd9Sstevel@tonic-gate	 * In order to call la_pltexit() we must duplicate the
3097c478bd9Sstevel@tonic-gate	 * arguments from the 'callers' stack on our stack frame.
3107c478bd9Sstevel@tonic-gate	 *
3117c478bd9Sstevel@tonic-gate	 * First we check the size of the callers stack and grow
3127c478bd9Sstevel@tonic-gate	 * our stack to hold any of the arguments.  That need
3137c478bd9Sstevel@tonic-gate	 * duplicating (these are arguments 6->N), because the
3147c478bd9Sstevel@tonic-gate	 * first 6 (0->5) are passed via register windows on sparc.
3157c478bd9Sstevel@tonic-gate	 */
3167c478bd9Sstevel@tonic-gate
3177c478bd9Sstevel@tonic-gate	/*
3187c478bd9Sstevel@tonic-gate	 * The first calculation is to determine how large the
3197c478bd9Sstevel@tonic-gate	 * argument passing area might be.  Since there is no
3207c478bd9Sstevel@tonic-gate	 * way to distinquish between 'argument passing' and
3217c478bd9Sstevel@tonic-gate	 * 'local storage' from the previous stack this amount must
3227c478bd9Sstevel@tonic-gate	 * cover both.
3237c478bd9Sstevel@tonic-gate	 */
3247c478bd9Sstevel@tonic-gate	ld	[%fp + -0x8], %l1	! %l1 = callers stack size
3257c478bd9Sstevel@tonic-gate	sub	%l1, 0x58, %l1		! %l1 = argument space on caller's
3267c478bd9Sstevel@tonic-gate					!	stack
3277c478bd9Sstevel@tonic-gate	/*
3287c478bd9Sstevel@tonic-gate	 * Next we compare the prev. stack size against the audit_argcnt.
3297c478bd9Sstevel@tonic-gate	 * We copy at most 'audit_argcnt' arguments.
3307c478bd9Sstevel@tonic-gate	 *
3317c478bd9Sstevel@tonic-gate	 * NOTE: on sparc we always copy at least six args since these
3327c478bd9Sstevel@tonic-gate	 *	 are in reg-windows and not on the stack.
3337c478bd9Sstevel@tonic-gate	 *
3347c478bd9Sstevel@tonic-gate	 * NOTE: Also note that we multiply (shift really) the arg count
3357c478bd9Sstevel@tonic-gate	 *	 by 4 which is the 'word size' to calculate the amount
3367c478bd9Sstevel@tonic-gate	 *	 of stack space needed.
3377c478bd9Sstevel@tonic-gate	 */
3387c478bd9Sstevel@tonic-gate	ld	[%l7 + audit_argcnt], %l2
3397c478bd9Sstevel@tonic-gate	ld	[%l2], %l2		! %l2 = audit_arg_count
3407c478bd9Sstevel@tonic-gate	cmp	%l2, 6
3417c478bd9Sstevel@tonic-gate	ble	.grow_stack
3427c478bd9Sstevel@tonic-gate	sub	%l2, 6, %l2
3437c478bd9Sstevel@tonic-gate	sll	%l2, 2, %l2
3447c478bd9Sstevel@tonic-gate	cmp	%l1, %l2
3457c478bd9Sstevel@tonic-gate	ble	.grow_stack
3467c478bd9Sstevel@tonic-gate	nop
3477c478bd9Sstevel@tonic-gate	mov	%l2, %l1
3487c478bd9Sstevel@tonic-gate.grow_stack:
3497c478bd9Sstevel@tonic-gate	/*
3507c478bd9Sstevel@tonic-gate	 * When duplicating the stack we skip the first '0x5c' bytes.
3517c478bd9Sstevel@tonic-gate	 * This is the space on the stack reserved for preserving
3527c478bd9Sstevel@tonic-gate	 * the register windows and such and do not need to be duplicated
3537c478bd9Sstevel@tonic-gate	 * on this new stack frame.  We start duplicating at the
3547c478bd9Sstevel@tonic-gate	 * portion of the stack reserved for argument's above 6.
3557c478bd9Sstevel@tonic-gate	 */
3567c478bd9Sstevel@tonic-gate	sub	%sp, %l1, %sp		! grow our stack by amount required.
3577c478bd9Sstevel@tonic-gate	sra	%l1, 0x2, %l1		! %l1 = %l1 / 4 (words to copy)
3587c478bd9Sstevel@tonic-gate	mov	0x5c, %l2		! %l2 = index into stack & frame
3597c478bd9Sstevel@tonic-gate
3607c478bd9Sstevel@tonic-gate1:
3617c478bd9Sstevel@tonic-gate	cmp	%l1, 0
3627c478bd9Sstevel@tonic-gate	ble	2f
3637c478bd9Sstevel@tonic-gate	nop
3647c478bd9Sstevel@tonic-gate	ld	[%fp + %l2], %l3	! duplicate args from previous
3657c478bd9Sstevel@tonic-gate	st	%l3, [%sp + %l2]	! stack onto current stack
3667c478bd9Sstevel@tonic-gate	add	%l2, 0x4, %l2
3677c478bd9Sstevel@tonic-gate	ba	1b
3687c478bd9Sstevel@tonic-gate	sub	%l1, 0x1, %l1
3697c478bd9Sstevel@tonic-gate2:
3707c478bd9Sstevel@tonic-gate	mov	%i0, %o0		! copy ins to outs
3717c478bd9Sstevel@tonic-gate	mov	%i1, %o1
3727c478bd9Sstevel@tonic-gate	mov	%i2, %o2
3737c478bd9Sstevel@tonic-gate	mov	%i3, %o3
3747c478bd9Sstevel@tonic-gate	mov	%i4, %o4
3757c478bd9Sstevel@tonic-gate	call	%l0			! call routine
3767c478bd9Sstevel@tonic-gate	mov	%i5, %o5
3777c478bd9Sstevel@tonic-gate	mov	%o1, %l2		! l2 = second 1/2 of return value
3787c478bd9Sstevel@tonic-gate					! for those those 64 bit operations
3797c478bd9Sstevel@tonic-gate					! link div64 - yuck...
3807c478bd9Sstevel@tonic-gate
3817c478bd9Sstevel@tonic-gate					! %o0 = retval
3827c478bd9Sstevel@tonic-gate	ld	[%fp + -0x4], %l1
3837c478bd9Sstevel@tonic-gate	ld	[%l1 + REFLMP_OFF], %o1	! %o1 = reflmp
3847c478bd9Sstevel@tonic-gate	ld	[%l1 + DEFLMP_OFF], %o2	! %o2 = deflmp
3857c478bd9Sstevel@tonic-gate	add	%l1, SYMDEF_OFF, %o3	! %o3 = symp
3867c478bd9Sstevel@tonic-gate	call	audit_pltexit
3877c478bd9Sstevel@tonic-gate	ld	[%l1 + SYMNDX_OFF], %o4	! %o4 = symndx
3887c478bd9Sstevel@tonic-gate
3897c478bd9Sstevel@tonic-gate	mov	%o0, %i0		! pass on return code
3907c478bd9Sstevel@tonic-gate	mov	%l2, %i1
3917c478bd9Sstevel@tonic-gate	ret
3927c478bd9Sstevel@tonic-gate	restore
3937c478bd9Sstevel@tonic-gate	.size	elf_plt_trace, . - elf_plt_trace
3947c478bd9Sstevel@tonic-gate
3957c478bd9Sstevel@tonic-gate#endif
3967c478bd9Sstevel@tonic-gate
3977c478bd9Sstevel@tonic-gate/*
3987c478bd9Sstevel@tonic-gate * After the first call to a plt, elf_bndr() will have determined the true
3997c478bd9Sstevel@tonic-gate * address of the function being bound.  The plt is now rewritten so that
4007c478bd9Sstevel@tonic-gate * any subsequent calls go directly to the bound function.  If the library
4017c478bd9Sstevel@tonic-gate * to which the function belongs is being profiled refer to _plt_cg_write.
4027c478bd9Sstevel@tonic-gate *
4037c478bd9Sstevel@tonic-gate * the new plt entry is:
4047c478bd9Sstevel@tonic-gate *
4057c478bd9Sstevel@tonic-gate *	sethi	(.-PLT0), %g1			! constant
4067c478bd9Sstevel@tonic-gate *	sethi	%hi(function address), %g1	! patched second
4077c478bd9Sstevel@tonic-gate *	jmpl	%g1 + %lo(function address, %g0	! patched first
4087c478bd9Sstevel@tonic-gate */
4097c478bd9Sstevel@tonic-gate
4107c478bd9Sstevel@tonic-gate#if	defined(lint)
4117c478bd9Sstevel@tonic-gate
4127c478bd9Sstevel@tonic-gatevoid
4137c478bd9Sstevel@tonic-gateplt_full_range(uintptr_t pc, uintptr_t symval)
4147c478bd9Sstevel@tonic-gate{
4157c478bd9Sstevel@tonic-gate	uint_t *	plttab = (uint_t *)pc;
4167c478bd9Sstevel@tonic-gate	plttab[2] = (M_JMPL | ((unsigned long)symval & S_MASK(10)));
4177c478bd9Sstevel@tonic-gate	plttab[1] = (M_SETHIG1 | ((unsigned long)symval >> (32 - 22)));
4187c478bd9Sstevel@tonic-gate}
4197c478bd9Sstevel@tonic-gate
4207c478bd9Sstevel@tonic-gate#else
4217c478bd9Sstevel@tonic-gate	ENTRY(plt_full_range)
4227c478bd9Sstevel@tonic-gate
4237c478bd9Sstevel@tonic-gate	sethi	%hi(M_JMPL), %o3	! Get jmpl instruction
4247c478bd9Sstevel@tonic-gate	and	%o1, 0x3ff, %o2		! Lower part of function address
4257c478bd9Sstevel@tonic-gate	or	%o3, %o2, %o3		!	is or'ed into instruction
4267c478bd9Sstevel@tonic-gate	st	%o3, [%o0 + 8]		! Store instruction in plt[2]
4277c478bd9Sstevel@tonic-gate	iflush	%o0 + 8
4287c478bd9Sstevel@tonic-gate	stbar
4297c478bd9Sstevel@tonic-gate
4307c478bd9Sstevel@tonic-gate	srl	%o1, 10, %o1		! Get high part of function address
4317c478bd9Sstevel@tonic-gate	sethi	%hi(M_SETHIG1), %o3	! Get sethi instruction
4327c478bd9Sstevel@tonic-gate	or	%o3, %o1, %o3		! Add sethi and function address
4337c478bd9Sstevel@tonic-gate	st	%o3, [%o0 + 4]		! Store instruction in plt[1]
4347c478bd9Sstevel@tonic-gate	retl
4357c478bd9Sstevel@tonic-gate	iflush	%o0 + 4
4367c478bd9Sstevel@tonic-gate
4377c478bd9Sstevel@tonic-gate	SET_SIZE(plt_full_range)
4387c478bd9Sstevel@tonic-gate
4397c478bd9Sstevel@tonic-gate#endif	/* defined(lint) */
4407c478bd9Sstevel@tonic-gate
441