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