1/*	$NetBSD: rtld_start.S,v 1.15 2002/10/05 11:59:05 mycroft Exp $	*/
2
3/*
4 * Copyright 1996 Matt Thomas <matt@3am-software.com>
5 * Portions copyright 2002 Charles M. Hannum <root@ihack.net>
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 * 3. The name of the author may not be used to endorse or promote products
17 *    derived from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31#include <machine/asm.h>
32
33/*
34 * Note: we can call ourselves LEAF even though we use callee-saved
35 * registers because we're the root of the call graph.
36 */
37LEAF_NOPROFILE(_rtld_start, 0)
38	.set	noreorder
39	br	pv, 1f
401:	LDGP(pv)
41
42	/*
43	 * Relocate ourself.
44	 */
45	br	s2, 2f		/* get our PC */
462:	ldiq	s3, 2b		/* get where the linker thought we were */
47
48	subq	s2, s3, a1	/* relocbase */
49	lda	t5, _DYNAMIC
50	addq	a1, t5, a0	/* &_DYNAMIC */
51
52	/* Squirrel away ps_strings. */
53	mov	a3, s0
54
55	bsr	ra, _rtld_relocate_nonplt_self
56	LDGP(ra)
57
58	/*
59	 * Allocate space on the stack for the cleanup and obj_main
60	 * entries that _rtld() will provide for us.
61	 */
62	lda	sp, -16(sp)
63
64	subq	s2, s3, a1	/* relocbase */
65	mov	sp, a0		/* sp */
66	CALL(_rtld)		/* v0 = _rtld(sp, relocbase); */
67
68	ldq	a1, 0(sp)	/* cleanup */
69	ldq	a2, 8(sp)	/* obj_main */
70	lda	sp, 16(sp)	/* pop stack */
71
72	mov	sp, a0		/* stack pointer */
73	mov	s0, a3		/* ps_strings */
74
75	mov	v0, pv		/* set up PV for entry point */
76
77	jsr	ra, (v0), 0	/* (*_start)(sp, cleanup, obj, ps_strings); */
78	ldgp	gp, 0(ra)
79
80	CALL(exit)
81	halt
82END(_rtld_start)
83
84#define	RTLD_BIND_START_PROLOGUE					\
85	/* at_reg already used by PLT code. */				\
86	.set	noat						;	\
87									\
88	/*								\
89	 * Allocate stack frame and preserve all registers that the	\
90	 * caller would have normally saved themselves.			\
91	 */								\
92	lda	sp, -168(sp)					;	\
93	stq	ra, 0(sp)					;	\
94	stq	v0, 8(sp)					;	\
95	stq	t0, 16(sp)					;	\
96	stq	t1, 24(sp)					;	\
97	stq	t2, 32(sp)					;	\
98	stq	t3, 40(sp)					;	\
99	stq	t4, 48(sp)					;	\
100	stq	t5, 56(sp)					;	\
101	stq	t6, 64(sp)					;	\
102	stq	t7, 72(sp)					;	\
103	stq	a0, 80(sp)					;	\
104	stq	a1, 88(sp)					;	\
105	stq	a2, 96(sp)					;	\
106	stq	a3, 104(sp)					;	\
107	stq	a4, 112(sp)					;	\
108	stq	a5, 120(sp)					;	\
109	stq	t8, 128(sp)					;	\
110	stq	t9, 136(sp)					;	\
111	stq	t10, 144(sp)					;	\
112	stq	t11, 152(sp)					;	\
113	stq	gp, 160(sp)					;	\
114									\
115	/*								\
116	 * Load our global pointer.  Note, can't use pv, since it is	\
117	 * already used by the PLT code.				\
118	 */								\
119	br	t0, 1f						;	\
1201:	LDGP(t0)
121
122#define	RTLD_BIND_START_EPILOGUE					\
123	/* Move the destination address into position. */		\
124	mov	v0, pv						;	\
125									\
126	/* Restore program registers. */				\
127	ldq	ra, 0(sp)					;	\
128	ldq	v0, 8(sp)					;	\
129	ldq	t0, 16(sp)					;	\
130	ldq	t1, 24(sp)					;	\
131	ldq	t2, 32(sp)					;	\
132	ldq	t3, 40(sp)					;	\
133	ldq	t4, 48(sp)					;	\
134	ldq	t5, 56(sp)					;	\
135	ldq	t6, 64(sp)					;	\
136	ldq	t7, 72(sp)					;	\
137	ldq	a0, 80(sp)					;	\
138	ldq	a1, 88(sp)					;	\
139	ldq	a2, 96(sp)					;	\
140	ldq	a3, 104(sp)					;	\
141	ldq	a4, 112(sp)					;	\
142	ldq	a5, 120(sp)					;	\
143	ldq	t8, 128(sp)					;	\
144	ldq	t9, 136(sp)					;	\
145	ldq	t10, 144(sp)					;	\
146	ldq	t11, 152(sp)					;	\
147	ldq	gp, 160(sp)					;	\
148	/* XXX LDGP? */							\
149									\
150	/*								\
151	 * We've patched the PLT; sync the I-stream.			\
152	 */								\
153	imb							;	\
154									\
155	/* Pop the stack frame and turn control to the destination. */	\
156	lda     sp, 168(sp)					;	\
157	jmp	zero, (pv)
158
159/*
160 * Lazy binding entry point, called via PLT.
161 */
162NESTED_NOPROFILE(_rtld_bind_start, 0, 168, ra, 0, 0)
163
164	RTLD_BIND_START_PROLOGUE
165
166	/* Set up the arguments for _rtld_bind. */
167	subq	at_reg, pv, a1		/* calculate offset of reloc entry */
168	ldq	a0, 8(pv)		/* object structure */
169	subq	a1, 20, a1		/* = (at - pv - 20) / 12 * 24 */
170	addq	a1, a1, a1
171
172	CALL(_rtld_bind)
173
174	RTLD_BIND_START_EPILOGUE
175
176END(_rtld_bind_start)
177
178/*
179 * Lazy binding entry point, called via PLT.  This version is for the
180 * old PLT entry format.
181 */
182NESTED_NOPROFILE(_rtld_bind_start_old, 0, 168, ra, 0, 0)
183
184	RTLD_BIND_START_PROLOGUE
185
186	/* Set up the arguments for _rtld_bind. */
187	ldq	a0, 8(pv)		/* object structure */
188	mov	at_reg, a1		/* offset of reloc entry */
189
190	CALL(_rtld_bind)
191
192	RTLD_BIND_START_EPILOGUE
193
194END(_rtld_bind_start_old)
195