xref: /netbsd-src/libexec/ld.elf_so/arch/vax/rtld_start.S (revision ce716eeb9a02c7ecc82ab81d906a970d97432925)
1*ce716eebSriastradh/*	$NetBSD: rtld_start.S,v 1.25 2024/08/03 21:59:59 riastradh Exp $	*/
2741f18b6Smatt
3741f18b6Smatt/*
4741f18b6Smatt * Copyright 1996 Matt Thomas <matt@3am-software.com>
5d2fd5f83Smycroft * Portions copyright 2002, 2003 Charles M. Hannum <root@ihack.net>
6741f18b6Smatt * All rights reserved.
7741f18b6Smatt *
8741f18b6Smatt * Redistribution and use in source and binary forms, with or without
9741f18b6Smatt * modification, are permitted provided that the following conditions
10741f18b6Smatt * are met:
11741f18b6Smatt * 1. Redistributions of source code must retain the above copyright
12741f18b6Smatt *    notice, this list of conditions and the following disclaimer.
13741f18b6Smatt * 2. Redistributions in binary form must reproduce the above copyright
14741f18b6Smatt *    notice, this list of conditions and the following disclaimer in the
15741f18b6Smatt *    documentation and/or other materials provided with the distribution.
16741f18b6Smatt * 3. The name of the author may not be used to endorse or promote products
17741f18b6Smatt *    derived from this software without specific prior written permission.
18741f18b6Smatt *
19741f18b6Smatt * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20741f18b6Smatt * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21741f18b6Smatt * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22741f18b6Smatt * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23741f18b6Smatt * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24741f18b6Smatt * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25741f18b6Smatt * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26741f18b6Smatt * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27741f18b6Smatt * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28741f18b6Smatt * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29741f18b6Smatt */
30741f18b6Smatt
31741f18b6Smatt#include <machine/asm.h>
32741f18b6Smatt
33741f18b6Smatt/* R9 contains the address of PS_STRINGS and since its caller saved,
34741f18b6Smatt * we can just use it.  R6 has a backup copy of the stack pointer which
35d2fd5f83Smycroft * we can use as well.
36741f18b6Smatt */
3786d15d82SmattENTRY(_rtld_start, 0)
38741f18b6Smatt	/* Allocate space on the stack for the cleanup and obj_main
39741f18b6Smatt	 * entries that _rtld() will provide for us.
40741f18b6Smatt	 */
410ce5ca14Smatt	clrl	%fp
420ce5ca14Smatt	subl2	$8,%sp
4363465d31Smatt
44d437f652Smycroft	movab	_DYNAMIC,%r0
45d2fd5f83Smycroft	subl3	_GLOBAL_OFFSET_TABLE_,%r0,%r10
4606f9fa98Smycroft	pushl	%r10		/* relocbase */
47d437f652Smycroft	pushl	%r0		/* &_DYNAMIC */
48d437f652Smycroft	calls	$2,_rtld_relocate_nonplt_self
49d437f652Smycroft
5006f9fa98Smycroft	pushl	%r10		/* relocbase */
5142fb5b53Smycroft	pushal	4(%sp)		/* sp */
52d04429c6Smycroft	calls	$2,_rtld	/* entry = _rtld(sp, relocbase) */
53741f18b6Smatt
540ce5ca14Smatt	movq	(%sp)+,%r7	/* grab cleanup and obj_main into %r7/%r8 */
550ce5ca14Smatt	jmp	2(%r0)		/* jump to entry point + 2 */
56bf06b103SmattEND(_rtld_start)
57741f18b6Smatt
58741f18b6Smatt/*
59bf06b103Smatt * Lazy binding entry point, called via PLT via JMP into pltgot[1].
60e26b436cSmatt * SP+4: address to relocation offset
61bf06b103Smatt * SP+0: obj entry points
62741f18b6Smatt */
6386d15d82SmattALTENTRY(_rtld_bind_start)
64a1f21652Smatt	pushl	%r1		/* need to preserve r1 */
65db747c73Smatt	movq	-8(%fp),%r0	/* get addresses of plt.got & reloc index */
66e26b436cSmatt	pushl	(%r1)		/* push relocation offset */
670ce5ca14Smatt	pushl	%r0		/* push address of obj entry */
68741f18b6Smatt	calls	$2,_rtld_bind
69db747c73Smatt
70e26b436cSmatt	/*
71e26b436cSmatt	 * This code checks to see if we got called via a call{s,g} $n,*pcrel32
72e26b436cSmatt	 * This is by far the most common case (a call indirectly via the PLT).
73e26b436cSmatt	 */
74e26b436cSmatt	subl3	$7,16(%fp),%r1	/* return address */
75e26b436cSmatt	bicb3	$1,(%r1),%r2	/* fetch opcode of instruction */
76e26b436cSmatt	cmpb	$0xfa,%r2	/* is it calls/callg */
77e26b436cSmatt	jneq	20f		/*   no it isn't */
78e26b436cSmatt	cmpb	$0xff,2(%r1)	/* and deferred 32-bit PC displacement? */
79e26b436cSmatt	jneq	20f		/*   no it isn't */
80db747c73Smatt
81db747c73Smatt	/*
82e26b436cSmatt	 * This makes sure the longword with the PLT's address has been updated
83e26b436cSmatt	 * to point to the routine's address.  If it hasn't, then returning
84e26b436cSmatt	 * would put us in an infinite loop.  Instead we punt and fake up a
85e26b436cSmatt	 * callframe.
86db747c73Smatt	 */
87e26b436cSmatt	movl	3(%r1),%r3	/* get displacement */
88e26b436cSmatt	addl2	16(%fp),%r3	/* add ending location */
89e26b436cSmatt	cmpl	(%r3),%r0	/* does it contain the routine address? */
90e26b436cSmatt#ifdef DEBUG
91e26b436cSmatt	jneq	30f		/*   no it doesn't, die */
92e26b436cSmatt#else
93e26b436cSmatt	jneq	20f		/*   no it doesn't, go fake a new callframe */
94e26b436cSmatt#endif
95db747c73Smatt
96e26b436cSmatt11:	movl	%r1,16(%fp)	/* backup to the calls/callg */
97e26b436cSmatt	jbc	$29,4(%fp),12f	/* skip if this was a callg */
98e26b436cSmatt	clrl	(%ap)		/* clear argument count */
99a1f21652Smatt12:	movl	(%sp)+,%r1	/* restore r1 */
100a1f21652Smatt	ret			/* return and redo the call */
101e26b436cSmatt
102e26b436cSmatt#if 1
103e26b436cSmatt20:
104db747c73Smatt	/*
105e26b436cSmatt	 * Since the calling standard says only r6-r11 should be saved,
106e26b436cSmatt	 * that simplies things for us.  That means we can use r0-r5 as
107e26b436cSmatt	 * temporaries without worrying about preserving them.  This means
108e26b436cSmatt	 * can hold the current fixed callframe in r2-r5 as we build the
109e26b436cSmatt	 * callframe without having to worry about overwriting the existing
110e26b436cSmatt	 * callframe.
111db747c73Smatt	 */
112e26b436cSmatt	extzv	$0,$12,(%r0),%r1/* get routine's save mask */
113e26b436cSmatt	bitw	$0x3f,%r1	/* does the routine use r0-r5? */
114e26b436cSmatt	jneq	30f		/*   yes, that sucks */
115e26b436cSmatt	jbc	$29,4(%fp),27f	/* handle callg */
116e26b436cSmatt	movq	4(%fp),%r2	/* fetch callframe status & saved AP */
117e26b436cSmatt	movq	12(%fp),%r4	/* fetch callframe saved FP & PC */
118e26b436cSmatt	insv	%r1,$16,$12,%r2	/* update save mask */
119a1f21652Smatt	movl	(%sp)+,%fp	/* use fp to keep saved r1 */
120e26b436cSmatt	movl	%ap,%sp		/* reset stack to top of callframe */
121e26b436cSmatt22:	pushr	%r1		/* push registers */
122e26b436cSmatt	movq	%r4,-(%sp)	/* push callframe saved FP & PC */
123e26b436cSmatt	movq	%r2,-(%sp)	/* push callframe status & saved AP */
124e26b436cSmatt	pushl	$0		/* push condition handler */
125a1f21652Smatt	movl	%fp,%r1		/* restore r1 */
126e26b436cSmatt	movl	%sp,%fp		/* sp == fp now */
127e26b436cSmatt#if 1
128e26b436cSmatt	jmp	2(%r0)		/* jump past entry mask */
129e26b436cSmatt#else
130db747c73Smatt	/*
131e26b436cSmatt	 * More correct but IV/DV are never set so ignore doing this for now.
132db747c73Smatt	 */
133e26b436cSmatt	movpsl	-(%sp)		/* push PSL */
134e26b436cSmatt	clrb	(%sp)		/* clear user flags */
135e26b436cSmatt	jbc	$14,(%r0),24f	/* IV need to be set? */
136e26b436cSmatt	bisb2	$0x20,(%sp)	/*   yes, set it. */
137e26b436cSmatt24:	jbc	$15,(%r0),25f	/* DV need to be set? */
138e26b436cSmatt	bisb2	$0x80,(%sp)	/*   yes, set it. */
139e26b436cSmatt25:	pushab	2(%r0)		/* push address of first instruction */
140e26b436cSmatt	rei			/* and go to it (updating PSW) */
141e26b436cSmatt#endif
142db747c73Smatt
143db747c73Smatt	/*
144e26b436cSmatt	 * Count how many registers are being used for callg.
145db747c73Smatt	 */
146e26b436cSmatt27:	movl	$0x32212110,%r3	/* bit counts */
147e26b436cSmatt	extzv	$6,$3,%r1,%r2	/* extract bits 6-8 */
148e26b436cSmatt	ashl	$2,%r2,%r2	/* shift by 2 */
149e26b436cSmatt	extzv	%r2,$4,%r3,%r4	/* extract count */
150e26b436cSmatt	extzv	$9,$3,%r1,%r2	/* extract bits 9-11 */
151e26b436cSmatt	ashl	$2,%r2,%r2	/* shift by 2 */
152e26b436cSmatt	extzv	%r2,$4,%r3,%r5	/* extract count */
153e26b436cSmatt	movq	4(%fp),%r2	/* fetch callframe status & saved AP */
154e26b436cSmatt	insv	%r1,$16,$12,%r2	/* update save mask */
1555b335481Smatt	addl3	%r4,%r5,%r1	/* add counts and discard them */
156e26b436cSmatt	movq	12(%fp),%r4	/* fetch callframe saved FP & PC */
157e26b436cSmatt	moval	20(%fp)[%r1],%sp/* pop callframe */
158e26b436cSmatt	extzv	$16,$12,%r2,%r1	/* get save mask back */
159e26b436cSmatt	jbr	22b		/* now build the new callframe */
160e26b436cSmatt
161e26b436cSmatt30:
162e26b436cSmatt	calls	$0,_C_LABEL(_rtld_die)
163e26b436cSmatt#else
164e26b436cSmatt	/*
165e26b436cSmatt	 * Check to see if called via call? $n,w^off(reg)
166e26b436cSmatt	 */
167e26b436cSmatt20:	addl2	$2,%r1		/* 16-bit displacement */
168e26b436cSmatt	bicb3	$1,(%r1),%r2	/* fetch opcode of instruction */
169e26b436cSmatt	cmpb	$0xfa,%r2	/* is it calls/callg */
170e26b436cSmatt	jneq	30f		/*   no it isn't */
171e26b436cSmatt	bicb3	$0x1f,2(%r1),%r3/* extract addressing mode */
172e26b436cSmatt	cmpb	$0xc0,%r3	/* 16-bit displacement? */
173e26b436cSmatt	jeql	11b		/*   yes, redo the call */
174e26b436cSmatt	halt
175e26b436cSmatt
176e26b436cSmatt	/*
177e26b436cSmatt	 * Check to see if called via call? $n,b^off(reg)
178e26b436cSmatt	 */
179e26b436cSmatt30:	incl	%r1		/* 8-bit displacement */
180e26b436cSmatt	bicb3	$1,(%r1),%r2	/* fetch opcode of instruction */
181e26b436cSmatt	cmpb	$0xfa,%r2	/* is it calls/callg */
182e26b436cSmatt	jneq	40f		/*   no it isn't */
183e26b436cSmatt	bicb3	$0x1f,2(%r1),%r3/* extract addressing mode */
184e26b436cSmatt	cmpb	$0xa0,%r3	/* 8-bit displacement? */
185e26b436cSmatt	jeql	11b		/*   yes, redo the call */
186e26b436cSmatt	halt
187e26b436cSmatt
188e26b436cSmatt	/*
189e26b436cSmatt	 * Check to see if called via call? $n,(reg)
190e26b436cSmatt	 */
191e26b436cSmatt40:	incl	%r1		/* no displacement */
192e26b436cSmatt	bicb3	$1,(%r1),%r2	/* fetch opcode of instruction */
193e26b436cSmatt	cmpb	$0xfa,%r2	/* is it calls/callg */
194e26b436cSmatt	jeql	41f		/*   yes it is */
195e26b436cSmatt	halt			/*   no, die die die */
196e26b436cSmatt41:	bicb3	$0x0f,2(%r1),%r2/* extract addressing mode */
197e26b436cSmatt	bicb3	$0xf0,2(%r1),%r3/* extract register */
198e26b436cSmatt	extzv	$0,$12,6(%fp),%r4/* extract saved mask */
199e26b436cSmatt	cmpb	$0x60,%r2	/* register deferred? */
200e26b436cSmatt	jeql	42f		/*   yes, deal with it */
201e26b436cSmatt	cmpb	$0x90,%r2	/* autoincrement deferred? */
202e26b436cSmatt	jeql	70f		/*   yes, deal with it */
203e26b436cSmatt	halt			/*   no, die die die */
204e26b436cSmatt
205e26b436cSmatt42:	cmpw	%r4,$0xffc	/* did we save r2-r11? */
206e26b436cSmatt	jneq	50f		/*   no, deal with it */
207e26b436cSmatt	jbc	%r3,%r4,43f	/* is the register in the saved mask? */
208e26b436cSmatt
209e26b436cSmatt	/*
210e26b436cSmatt	 * We saved r2-r11, so it's easy to replace the saved register with
211e26b436cSmatt	 * the right value by indexing into saved register (offset by 8).
212e26b436cSmatt	 */
213e26b436cSmatt	movl	%r0,(20-8)(%fp)[%r3] /* replace address in saved registers */
214e26b436cSmatt	jbr	11b		/* go back and redo call */
215e26b436cSmatt	/*
216e26b436cSmatt	 * Must have been called via r0 or r1 which are saved locally.
217e26b436cSmatt	 * So move the routine address in the appropriate slot on the stack.
218e26b436cSmatt	 */
219e26b436cSmatt43:	movl	%r0,(%sp)[%r3]
220e26b436cSmatt	jbr	11b		/* go back and redo call */
221e26b436cSmatt
222e26b436cSmatt50:	jbs	%r3,%r4,60f	/* is the register in the saved mask? */
223e26b436cSmatt	jbs	%r3,$0x3f,43b	/* is it r0-r5? */
224e26b436cSmatt	/*
225e26b436cSmatt	 * The register used for the call was not saved so we need to move
226e26b436cSmatt	 * the new function address into it so the re-call will use the new
227e26b436cSmatt	 * address.
228e26b436cSmatt	 */
229e26b436cSmatt	pushl	%r0		/* save function address on the stack */
230e26b436cSmatt	ashl	%r5,$1,%r0	/* create a bitmask for the register */
231e26b436cSmatt	popr	%r0		/* pop it off the stack. */
232e26b436cSmatt	jbr	11b		/* and redo the call */
233e26b436cSmatt
234e26b436cSmatt60:	clrl	%r2		/* starting offset into saved registers */
235e26b436cSmatt	clrl	%r5		/* start with register 0 */
236e26b436cSmatt
237e26b436cSmatt61:	cmpl	%r2,%r3		/* is the register to save? */
238e26b436cSmatt	jneq	62f		/*   no, advance to next */
239e26b436cSmatt	movl	%r0,20(%fp)[%r5]/*   yes, save return address in saved reg */
240e26b436cSmatt	jbr	11b		/*        and return the call */
241e26b436cSmatt62:	jbc	%r5,%r4,63f	/* is this register saved? */
242e26b436cSmatt	incl	%r5		/*   yes, account for it */
243e26b436cSmatt63:	incl	%r2		/* increment register number */
244e26b436cSmatt	jbr	61b		/* and loop */
245e26b436cSmatt
246e26b436cSmatt70:	cmpb	%r3,$12
247e26b436cSmatt	blss	71f
248e26b436cSmatt	halt
249e26b436cSmatt
250e26b436cSmatt71:	cmpw	%r4,$0xffc	/* did we save r2-r11? */
251e26b436cSmatt	jneq	72f		/*   no, deal with it */
252e26b436cSmatt	subl2	$4,(20-8)(%fp)[%r3] /* backup incremented register */
253e26b436cSmatt	jbr	11b		/* and redo the call.
254e26b436cSmatt
255e26b436cSmatt72:	jbs	%r3,%r4,80f
256e26b436cSmatt	jbs	%r3,%3f,74f
257e26b436cSmatt	ashl	%r5,$1,%r0	/* create a bitmask for the register */
258e26b436cSmatt	pushr	%r0		/* pop it off the stack. */
259e26b436cSmatt	subl2	$4,(%sp)	/* backup incremented register */
260e26b436cSmatt	popr	%r0		/* pop it off the stack. */
261e26b436cSmatt	jbr	11b		/* and redo the call.
262e26b436cSmatt
263e26b436cSmatt73:	subl2	%4,(%sp)[%r3]	/* backup incremented register */
264e26b436cSmatt	jbr	11b		/* and redo the call.
265e26b436cSmatt
266e26b436cSmatt80:	clrl	%r2		/* starting offset into saved registers */
267e26b436cSmatt	clrl	%r5		/* start with register 0 */
268e26b436cSmatt
269e26b436cSmatt81:	cmpl	%r2,%r3		/* is the register to save? */
270e26b436cSmatt	jneq	82f		/*   no, advance to next */
271e26b436cSmatt	subl	$4,20(%fp)[%r5]	/*   yes, backup incremented register */
272e26b436cSmatt	jbr	11b		/*        and return the call */
273e26b436cSmatt82:	jbc	%r5,%r4,83f	/* is this register saved? */
274e26b436cSmatt	incl	%r5		/*   yes, account for it */
275e26b436cSmatt83:	incl	%r2		/* increment register number */
276e26b436cSmatt	jbr	81b		/* and loop */
277e26b436cSmatt#endif
278bf06b103SmattEND(_rtld_bind_start)
279