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