1/* $FreeBSD$	*/
2/*	From: NetBSD: rtld_start.S,v 1.1 1996/12/16 20:38:09 cgd Exp 	*/
3
4/*
5 * Copyright 1996 Matt Thomas <matt@3am-software.com>
6 * Copyright 2000 John D. Polstra
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in the
16 *    documentation and/or other materials provided with the distribution.
17 * 3. The name of the author may not be used to endorse or promote products
18 *    derived from this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
32#include <machine/asm.h>
33#include <sys/syscall.h>
34
35ENTRY(_rtld_start, 0)
36	alloc	r2=ar.pfs,3,0,3,0
37	;;
381:	mov	r14=ip			// calculate gp
39	addl	r3=@gprel(1b),r0
40	;;
41	sub	gp=r14,r3
42	;;
43	.section .sdata
442:	data4	@ltv(1b)		// unrelocated address of 1b
45	.align	8
46	.previous
47	add	r15=@gprel(2b),gp
48	;;
49	ld8	r15=[r15]
50	;;
51	sub	out0=r14,r15		// out0 is image base address
52	br.call.sptk.many rp=_rtld_reloc // fixup image
53
54	add	sp=-16,sp		// 16 bytes for us, 16 for _rtld
55	;;
56	mov	out0=in0
57	add	out1=16,sp		// address for exit proc
58	add	out2=24,sp		// address for obj_main
59
60	br.call.sptk.many rp=_rtld	// r8=_rtld(sp, &exit_proc, &obj_main)
61
62	add	r16=16,sp		// address for exit proc
63	;;
64	ld8	r15=[r16]		// read exit proc
65	add	sp=16,sp		// readjust stack
66	mov	b7=r8			// address of real _start
67	;;
68	alloc	r2=ar.pfs,0,0,3,0	// dump register frame
69	mov	out2=r15
70	;;
71	br.call.sptk.many rp=b7		// transfer to main program
72	br.call.sptk.many rp=exit	// die
73END(_rtld_start)
74
75/*
76 * _rtld_bind_start:	lookup a lazy binding and transfer to real target
77 *
78 * Arguments:
79 *	r1	gp value for rtld
80 *	r15	Index in plt
81 *	r16	Obj_Entry of caller
82 *	in0-in7	Arguments for target procedure
83 *	rp	Return address back to caller
84 */
85ENTRY(_rtld_bind_start, 0)
86{ .mii
87	alloc	loc0=ar.pfs,8,6,3,0	// space to save r8-r11
88	add	r17=16-8*16,sp		// leave 16 bytes for _rtld_bind
89	add	r18=32-8*16,sp
90	;;
91} { .mii
92	mov	loc2=r8			// structure return address
93	add	sp=-8*16,sp		// space to save f8-f15
94	mov	loc1=rp
95	;;
96} { .mii
97	stf.spill [r17]=f8,32		// save float arguments
98	mov	loc3=r9			// language specific
99	mov	loc4=r10		// language specific
100} { .mii
101	stf.spill [r18]=f9,32
102	mov	loc5=r11		// language specific
103	shl	out1=r15,4		// 16 * index
104	;;
105} { .mmi
106	stf.spill [r17]=f10,32
107	stf.spill [r18]=f11,32
108	mov	out0=r16		// Obj_Entry for caller
109	;;
110} { .mmi
111	stf.spill [r17]=f12,32
112	stf.spill [r18]=f13,32
113	shladd	out1=r15,3,out1		// rela offset = 24 * index
114	;;
115} { .mmb
116	stf.spill [r17]=f14,32
117	stf.spill [r18]=f15,32
118	br.call.sptk.many rp=_rtld_bind
119} { .mii
120	ld8	r14=[r8],8		// target address
121	add	r17=16,sp
122	add	r18=32,sp
123	;;
124} { .mii
125	ld8	r1=[r8]			// target gp
126	mov	ar.pfs=loc0		// clean up
127	mov	rp=loc1
128} { .mmi
129	ldf.fill f8=[r17],32		// restore float arguments
130	ldf.fill f9=[r18],32
131	mov	r8=loc2			// restore structure pointer
132	;;
133} { .mmi
134	ldf.fill f10=[r17],32
135	ldf.fill f11=[r18],32
136	mov	r9=loc3
137	;;
138} { .mmi
139	ldf.fill f12=[r17],32
140	ldf.fill f13=[r18],32
141	mov	r10=loc4
142	;;
143} { .mmi
144	ldf.fill f14=[r17],32
145	ldf.fill f15=[r18],32
146	mov	r11=loc5
147	;;
148} { .mii
149	nop.m	0
150	mov	b7=r14
151	add	sp=8*16,sp
152	;;
153} { .mib
154	alloc	r14=ar.pfs,0,0,8,0	// drop our register frame
155	nop.i	0
156	br.sptk.many b7			// jump to target
157}
158END(_rtld_bind_start)
159
160#define DT_NULL		0	/* Terminating entry. */
161#define DT_RELA		7	/* Address of ElfNN_Rela relocations. */
162#define DT_RELASZ	8	/* Total size of ElfNN_Rela relocations. */
163#define DT_RELAENT	9	/* Size of each ElfNN_Rela relocation entry. */
164
165#define R_IA_64_NONE		0	/* None */
166#define R_IA_64_DIR64LSB	0x27	/* word64 LSB	S + A */
167#define R_IA_64_REL64LSB	0x6f	/* word64 LSB	BD + A */
168
169/*
170 * _rtld_reloc:	relocate the rtld image, apart from @fptrs.
171 *
172 * Assumes that rtld was linked at zero and that we only need to
173 * handle REL64LSB and DIR64LSB relocations.
174 *
175 * Arguments:
176 *	r1	gp value for rtld
177 *	in0	rtld base address
178 */
179STATIC_ENTRY(_rtld_reloc, 1)
180	alloc	loc0=ar.pfs,1,2,0,0
181	mov	loc1=rp
182	;;
183	movl	r15=@gprel(_DYNAMIC)	// find _DYNAMIC etc.
184	;;
185	add	r15=r15,gp		// relocate _DYNAMIC etc.
186	;;
1871:	ld8	r16=[r15],8		// read r15->d_tag
188	;;
189	ld8	r17=[r15],8		// and r15->d_val
190	;;
191	cmp.eq	p6,p0=DT_NULL,r16	// done?
192(p6)	br.cond.dpnt.few 2f
193	;;
194	cmp.eq	p6,p0=DT_RELA,r16
195	;;
196(p6)	add	r18=r17,in0		// found rela section
197	;;
198	cmp.eq	p6,p0=DT_RELASZ,r16
199	;;
200(p6)	mov	r19=r17			// found rela size
201	;;
202	cmp.eq	p6,p0=DT_RELAENT,r16
203	;;
204(p6)	mov	r22=r17			// found rela entry size
205	;;
206	br.sptk.few 1b
207
2082:
209	ld8	r15=[r18],8		// read r_offset
210	;;
211	ld8	r16=[r18],8		// read r_info
212	add	r15=r15,in0		// relocate r_offset
213	;;
214	ld8	r17=[r18],8		// read r_addend
215	sub	r19=r19,r22		// update relasz
216
217	extr.u	r23=r16,0,32		// ELF64_R_TYPE(r16)
218	;;
219	cmp.eq	p6,p0=R_IA_64_NONE,r23
220(p6)	br.cond.dpnt.few 3f
221	;;
222	cmp.eq	p6,p0=R_IA_64_DIR64LSB,r23
223	;;
224(p6)	br.cond.dptk.few 4f
225	;;
226	cmp.eq	p6,p0=R_IA_64_REL64LSB,r23
227	;;
228(p6)	br.cond.dptk.few 4f
229	;;
230
2313:	cmp.ltu	p6,p0=0,r19		// more?
232(p6)	br.cond.dptk.few 2b		// loop
233
234	mov	r8=0			// success return value
235	;;
236	br.cond.sptk.few 9f		// done
237
2384:
239	ld8	r16=[r15]		// read value
240	;;
241	add	r16=r16,in0		// relocate it
242	;;
243	st8	[r15]=r16		// and store it back
244	br.cond.sptk.few 3b
245
2469:
247	mov	ar.pfs=loc0
248	mov	rp=loc1
249	;;
250	br.ret.sptk.few rp
251
252END(_rtld_reloc)
253