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	bsr	ra, _rtld_relocate_nonplt_self
53	LDGP(ra)
54
55	/*
56	 * Allocate space on the stack for the cleanup and obj_main
57	 * entries that _rtld() will provide for us.
58	 */
59	lda	sp, -16(sp)
60
61	subq	s2, s3, a1	/* relocbase */
62	mov	sp, a0		/* sp */
63	CALL(_rtld)		/* v0 = _rtld(sp, relocbase); */
64
65	ldq	a1, 0(sp)	/* cleanup */
66	ldq	a2, 8(sp)	/* obj_main */
67	lda	sp, 16(sp)	/* pop stack */
68
69	mov	sp, a0		/* stack pointer */
70	mov	s0, a3		/* ps_strings */
71
72	mov	v0, pv		/* set up PV for entry point */
73
74	jsr	ra, (v0), 0	/* (*_start)(sp, cleanup, obj, ps_strings); */
75	ldgp	gp, 0(ra)
76
77	CALL(exit)
78	halt
79END(_rtld_start)
80
81#define	RTLD_BIND_START_PROLOGUE					\
82	/* at_reg already used by PLT code. */				\
83	.set	noat						;	\
84									\
85	/*								\
86	 * Allocate stack frame and preserve all registers that the	\
87	 * caller would have normally saved themselves.			\
88	 */								\
89	lda	sp, -168(sp)					;	\
90	stq	ra, 0(sp)					;	\
91	stq	v0, 8(sp)					;	\
92	stq	t0, 16(sp)					;	\
93	stq	t1, 24(sp)					;	\
94	stq	t2, 32(sp)					;	\
95	stq	t3, 40(sp)					;	\
96	stq	t4, 48(sp)					;	\
97	stq	t5, 56(sp)					;	\
98	stq	t6, 64(sp)					;	\
99	stq	t7, 72(sp)					;	\
100	stq	a0, 80(sp)					;	\
101	stq	a1, 88(sp)					;	\
102	stq	a2, 96(sp)					;	\
103	stq	a3, 104(sp)					;	\
104	stq	a4, 112(sp)					;	\
105	stq	a5, 120(sp)					;	\
106	stq	t8, 128(sp)					;	\
107	stq	t9, 136(sp)					;	\
108	stq	t10, 144(sp)					;	\
109	stq	t11, 152(sp)					;	\
110	stq	gp, 160(sp)					;	\
111									\
112	/*								\
113	 * Load our global pointer.  Note, can't use pv, since it is	\
114	 * already used by the PLT code.				\
115	 */								\
116	br	t0, 1f						;	\
1171:	LDGP(t0)
118
119#define	RTLD_BIND_START_EPILOGUE					\
120	/* Move the destination address into position. */		\
121	mov	v0, pv						;	\
122									\
123	/* Restore program registers. */				\
124	ldq	ra, 0(sp)					;	\
125	ldq	v0, 8(sp)					;	\
126	ldq	t0, 16(sp)					;	\
127	ldq	t1, 24(sp)					;	\
128	ldq	t2, 32(sp)					;	\
129	ldq	t3, 40(sp)					;	\
130	ldq	t4, 48(sp)					;	\
131	ldq	t5, 56(sp)					;	\
132	ldq	t6, 64(sp)					;	\
133	ldq	t7, 72(sp)					;	\
134	ldq	a0, 80(sp)					;	\
135	ldq	a1, 88(sp)					;	\
136	ldq	a2, 96(sp)					;	\
137	ldq	a3, 104(sp)					;	\
138	ldq	a4, 112(sp)					;	\
139	ldq	a5, 120(sp)					;	\
140	ldq	t8, 128(sp)					;	\
141	ldq	t9, 136(sp)					;	\
142	ldq	t10, 144(sp)					;	\
143	ldq	t11, 152(sp)					;	\
144	ldq	gp, 160(sp)					;	\
145	/* XXX LDGP? */							\
146									\
147	/*								\
148	 * We've patched the PLT; sync the I-stream.			\
149	 */								\
150	imb							;	\
151									\
152	/* Pop the stack frame and turn control to the destination. */	\
153	lda     sp, 168(sp)					;	\
154	jmp	zero, (pv)
155
156/*
157 * Lazy binding entry point, called via PLT.
158 */
159NESTED_NOPROFILE(_rtld_bind_start, 0, 168, ra, 0, 0)
160
161	RTLD_BIND_START_PROLOGUE
162
163	/* Set up the arguments for _rtld_bind. */
164	subq	at_reg, pv, a1		/* calculate offset of reloc entry */
165	ldq	a0, 8(pv)		/* object structure */
166	subq	a1, 20, a1		/* = (at - pv - 20) / 12 * 24 */
167	addq	a1, a1, a1
168
169	CALL(_rtld_bind)
170
171	RTLD_BIND_START_EPILOGUE
172
173END(_rtld_bind_start)
174
175/*
176 * Lazy binding entry point, called via PLT.  This version is for the
177 * old PLT entry format.
178 */
179NESTED_NOPROFILE(_rtld_bind_start_old, 0, 168, ra, 0, 0)
180
181	RTLD_BIND_START_PROLOGUE
182
183	/* Set up the arguments for _rtld_bind. */
184	ldq	a0, 8(pv)		/* object structure */
185	mov	at_reg, a1		/* offset of reloc entry */
186
187	CALL(_rtld_bind)
188
189	RTLD_BIND_START_EPILOGUE
190
191END(_rtld_bind_start_old)
192