1/*	$NetBSD: rtld_start.S,v 1.11 2011/09/30 03:05:43 mrg Exp $	*/
2
3/*-
4 * Copyright (c) 2002 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Matt Fredette.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32#include <machine/asm.h>
33#include <machine/frame.h>
34
35	.import _GLOBAL_OFFSET_TABLE_
36
37ENTRY($rtld_start,HPPA_FRAME_SIZE)
38
39	/* Start stack calling convention. */
40	copy	%r3, %r1
41	copy	%sp, %r3
42	stw,ma	%r1, HPPA_FRAME_SIZE(%sp)
43
44	/*
45	 * Save our single argument, the ps_strings pointer. We'll need this
46	 * twice later: once to call _rtld, and again to transfer to the
47	 * program's entry point.
48	 */
49	stw     %arg0, HPPA_FRAME_ARG(0)(%r3)
50
51	/*
52	 * We can't move to C until we relocate at least the
53	 * Global Offset Table.  Even finding the GOT is tricky
54	 * without inadvertently causing the linker to make
55	 * relocations for this part of the text segment.
56	 */
57
58	bl	L$lpc1, %r19
59	depi	0, 31, 2, %r19
60L$lpc1:	addil	L'_DYNAMIC - ($PIC_pcrel$0 - 8), %r19
61	ldo	R'_DYNAMIC - ($PIC_pcrel$0 - 12)(%r1),%arg0
62
63	/*
64	 * Load the absolute address of the beginning of the GOT into %r19, the
65	 * shared library linkage table register, leaving it ready-to-use by
66	 * the dynamic linker C code.
67	 */
68	addil	L'_GLOBAL_OFFSET_TABLE_ - ($PIC_pcrel$0 - 16), %r19
69	ldo	R'_GLOBAL_OFFSET_TABLE_ - ($PIC_pcrel$0 - 20)(%r1),%r19
70
71	/*
72	 * The linker sets the first entry in the GOT to the unrelocated
73	 *  address of _DYNAMIC.  Subtract this from the absolute address of
74	 * _DYNAMIC to get our relocbase.
75	 */
76	ldw	0(%r19), %arg1
77	sub	%arg0, %arg1, %arg1	; %arg1 = relocbase
78	bl	_rtld_relocate_nonplt_self, %rp
79	copy	%arg1, %r4		; save for later
80
81	/*
82	 * Recover the ps_strings pointer, and take out the
83	 * ps_argvstr member.
84	 */
85	ldw	HPPA_FRAME_ARG(0)(%r3), %arg0	; ps_strings
86	ldw	0(%arg0), %arg0		; ps_argvstr member first in struct
87
88	/*
89	 * ps_argvstr - 4 would get us a pointer to argc, comparable to the
90	 * initial stack pointer on architectures where the stack grows down.
91	 * Subtracting an additional eight creates the storage for obj and
92	 * cleanup that _rtld needs.
93	 */
94	ldo	-12(%arg0), %arg0
95	stw	%arg0, HPPA_FRAME_ARG(1)(%r3)
96
97	/* Call _rtld, copying relocbase into arg1. */
98	bl	_rtld, %rp
99	copy	%r4, %arg1		; %arg1 = relocbase
100
101	/* Prepare the arguments for the entry point. */
102	ldw	HPPA_FRAME_ARG(1)(%r3), %r1
103	ldw	HPPA_FRAME_ARG(0)(%r3), %arg0	; ps_strings
104	ldw	0(%r1), %arg1			; cleanup
105	ldw	4(%r1), %arg2			; obj
106
107	/* End stack calling convention. */
108	ldo	HPPA_FRAME_SIZE(%r3), %sp
109	ldw,mb	-HPPA_FRAME_SIZE(%sp), %r3
110
111	/* Go for it. */
112	bv	%r0(%ret0)
113	copy	%r0, %rp
114EXIT($rtld_start)
115
116/*
117 * This does our setup for an object's GOT.  %arg0 is the Obj_Entry * for the
118 * object, and %arg1 is its GOT pointer.
119 */
120LEAF_ENTRY(__rtld_setup_hppa_pltgot)
121
122	/*
123	 * The second entry of the GOT is reserved for the dynamic linker.  We
124	 * put the Obj_Entry * for the object in there.
125	 */
126	stw	%arg0, 4(%arg1)
127
128	/*
129	 * Fill the fixup_func and fixup_ltp members of the PLT stub.  This
130	 * stub is inserted by the linker immediately before the GOT.  We use
131	 * this stub to enter our binder.
132	 */
133
134	bl	L$lpc2, %arg0
135	depi	0, 31, 2, %arg0
136L$lpc2:	addil	L'_rtld_bind_start - ($PIC_pcrel$0 - 8), %arg0
137	ldo	R'_rtld_bind_start - ($PIC_pcrel$0 - 12)(%r1),%arg0
138
139	stw	%arg0, -8(%arg1)
140	bv	%r0(%rp)
141	stw	%r19, -4(%arg1)
142EXIT(__rtld_setup_hppa_pltgot)
143
144/*
145 * In order to support lazy binding, this implementation of _rtld_bind_start is
146 * very closely tied to the shared-library call stub and the PLT stub, both
147 * inserted by the linker.
148 */
149
150/*
151 * This is a magic branch instruction that is used by GCC's
152 * __canonicalize_funcptr_for_compare() function to fixup relocations
153 * in order to do function pointer comparisons.
154 */
155
156	bl	_rtld_bind, %rp
157
158ENTRY(_rtld_bind_start,HPPA_FRAME_SIZE)
159
160	/* Start stack calling convention.  */
161	copy	%r3, %r1
162	copy	%sp, %r3
163
164	stw,ma	%r1, HPPA_FRAME_SIZE(%sp)
165
166	/*
167	 * We have to save all calling convention registers that are set by the
168	 * caller, because we have to restore them before transferring to the
169	 * bound function.  Note that this includes %ret0, %ret1, and %t1.
170	 *
171	 * %ret0 and %ret1 because they can have meaning on entry to a
172	 * function.
173	 *
174	 * %t1 because it's used by libc to pass on errno values to cerror.
175	 */
176	stw	%rp, HPPA_FRAME_CRP(%r3)
177	stw	%arg0, HPPA_FRAME_ARG(0)(%r3)
178	stw	%arg1, HPPA_FRAME_ARG(1)(%r3)
179	stw	%arg2, HPPA_FRAME_ARG(2)(%r3)
180	stw	%arg3, HPPA_FRAME_ARG(3)(%r3)
181	/* 0(%r3) is filled with the saved %r3 above */
182	stw	%ret0, 4(%r3)
183	stw	%ret1, 8(%r3)
184	stw	%t1, 12(%r3)		/* %r22 */
185
186	/*
187	 * The linker PLT stub loads %r20 with (GOT - 8) for the object that
188	 * needs binding done.  The second entry of the GOT is reserved for the
189	 * dynamic linker's use, and we previously stashed the object's
190	 * Obj_Entry * there.
191	 */
192	ldw	12(%r20), %arg0
193
194	/*
195	 * The linker shared-library call stub loads %r19 from the shared
196	 * linkage member of the PLT entry.  We previously stashed the reloff
197	 * of the relocation there.
198	 */
199	copy	%r19, %arg1
200
201	/*
202	 * The linker PLT stub loads %r21 with the fixup_ltp word in itself.
203	 * We previously stashed our %r19 value there.
204	 */
205	bl	_rtld_bind, %rp
206	copy	%r21, %r19
207
208	/*
209	 * Our hppa version of _rtld_bind returns to us the address of the PLT
210	 * entry that it fixed up.  Load the function address and shared
211	 * linkage for the newly bound function.
212	 */
213	ldw	0(%ret0), %r21
214	ldw	4(%ret0), %r19
215
216	/* Restore registers saved above. */
217	ldw	HPPA_FRAME_CRP(%r3), %rp
218	ldw	HPPA_FRAME_ARG(0)(%r3), %arg0
219	ldw	HPPA_FRAME_ARG(1)(%r3), %arg1
220	ldw	HPPA_FRAME_ARG(2)(%r3), %arg2
221	ldw	HPPA_FRAME_ARG(3)(%r3), %arg3
222	ldw	4(%r3), %ret0
223	ldw	8(%r3), %ret1
224	ldw	12(%r3), %t1		/* %r22 */
225
226	/* End stack calling convention. */
227	ldo	HPPA_FRAME_SIZE(%r3), %sp
228	ldw,mb	-HPPA_FRAME_SIZE(%sp), %r3
229
230	/* Transfer to the function. */
231	bv	%r0(%r21)
232	nop
233EXIT(_rtld_bind_start)
234