Home | History | Annotate | Line # | Download | only in alpha
      1  1.17  riastrad /*	$NetBSD: rtld_start.S,v 1.17 2025/04/18 17:56:49 riastradh Exp $	*/
      2   1.1       cgd 
      3   1.1       cgd /*
      4   1.1       cgd  * Copyright 1996 Matt Thomas <matt (at) 3am-software.com>
      5  1.15   mycroft  * Portions copyright 2002 Charles M. Hannum <root (at) ihack.net>
      6   1.1       cgd  * All rights reserved.
      7   1.1       cgd  *
      8   1.1       cgd  * Redistribution and use in source and binary forms, with or without
      9   1.1       cgd  * modification, are permitted provided that the following conditions
     10   1.1       cgd  * are met:
     11   1.1       cgd  * 1. Redistributions of source code must retain the above copyright
     12   1.1       cgd  *    notice, this list of conditions and the following disclaimer.
     13   1.1       cgd  * 2. Redistributions in binary form must reproduce the above copyright
     14   1.1       cgd  *    notice, this list of conditions and the following disclaimer in the
     15   1.1       cgd  *    documentation and/or other materials provided with the distribution.
     16   1.1       cgd  * 3. The name of the author may not be used to endorse or promote products
     17   1.1       cgd  *    derived from this software without specific prior written permission.
     18   1.1       cgd  *
     19   1.1       cgd  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     20   1.1       cgd  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     21   1.1       cgd  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     22   1.1       cgd  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     23   1.1       cgd  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     24   1.1       cgd  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     25   1.1       cgd  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     26   1.1       cgd  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     27   1.1       cgd  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     28   1.1       cgd  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     29   1.1       cgd  */
     30   1.1       cgd 
     31   1.1       cgd #include <machine/asm.h>
     32   1.1       cgd 
     33   1.2   thorpej /*
     34   1.2   thorpej  * Note: we can call ourselves LEAF even though we use callee-saved
     35   1.2   thorpej  * registers because we're the root of the call graph.
     36   1.2   thorpej  */
     37   1.2   thorpej LEAF_NOPROFILE(_rtld_start, 0)
     38   1.1       cgd 	.set	noreorder
     39   1.6   thorpej 	br	pv, 1f
     40   1.6   thorpej 1:	LDGP(pv)
     41   1.1       cgd 
     42  1.11   mycroft 	/*
     43  1.11   mycroft 	 * Relocate ourself.
     44  1.11   mycroft 	 */
     45  1.13   mycroft 	br	s2, 2f		/* get our PC */
     46  1.13   mycroft 2:	ldiq	s3, 2b		/* get where the linker thought we were */
     47   1.1       cgd 
     48  1.13   mycroft 	subq	s2, s3, a1	/* relocbase */
     49  1.11   mycroft 	lda	t5, _DYNAMIC
     50  1.13   mycroft 	addq	a1, t5, a0	/* &_DYNAMIC */
     51   1.1       cgd 
     52  1.16     enami 	/* Squirrel away ps_strings. */
     53  1.16     enami 	mov	a3, s0
     54  1.16     enami 
     55  1.11   mycroft 	bsr	ra, _rtld_relocate_nonplt_self
     56  1.11   mycroft 	LDGP(ra)
     57   1.3   thorpej 
     58   1.3   thorpej 	/*
     59   1.3   thorpej 	 * Allocate space on the stack for the cleanup and obj_main
     60   1.3   thorpej 	 * entries that _rtld() will provide for us.
     61   1.3   thorpej 	 */
     62   1.3   thorpej 	lda	sp, -16(sp)
     63   1.3   thorpej 
     64  1.13   mycroft 	subq	s2, s3, a1	/* relocbase */
     65  1.13   mycroft 	mov	sp, a0		/* sp */
     66  1.13   mycroft 	CALL(_rtld)		/* v0 = _rtld(sp, relocbase); */
     67   1.3   thorpej 
     68   1.3   thorpej 	ldq	a1, 0(sp)	/* cleanup */
     69   1.3   thorpej 	ldq	a2, 8(sp)	/* obj_main */
     70   1.3   thorpej 	lda	sp, 16(sp)	/* pop stack */
     71   1.3   thorpej 
     72   1.3   thorpej 	mov	sp, a0		/* stack pointer */
     73   1.3   thorpej 	mov	s0, a3		/* ps_strings */
     74   1.3   thorpej 
     75   1.3   thorpej 	mov	v0, pv		/* set up PV for entry point */
     76   1.1       cgd 
     77   1.2   thorpej 	jsr	ra, (v0), 0	/* (*_start)(sp, cleanup, obj, ps_strings); */
     78   1.1       cgd 	ldgp	gp, 0(ra)
     79   1.1       cgd 
     80   1.1       cgd 	CALL(exit)
     81   1.1       cgd 	halt
     82   1.1       cgd END(_rtld_start)
     83   1.1       cgd 
     84   1.7   thorpej #define	RTLD_BIND_START_PROLOGUE					\
     85   1.7   thorpej 	/* at_reg already used by PLT code. */				\
     86   1.7   thorpej 	.set	noat						;	\
     87   1.7   thorpej 									\
     88   1.7   thorpej 	/*								\
     89   1.7   thorpej 	 * Allocate stack frame and preserve all registers that the	\
     90   1.7   thorpej 	 * caller would have normally saved themselves.			\
     91   1.7   thorpej 	 */								\
     92   1.7   thorpej 	lda	sp, -168(sp)					;	\
     93   1.7   thorpej 	stq	ra, 0(sp)					;	\
     94   1.7   thorpej 	stq	v0, 8(sp)					;	\
     95  1.17  riastrad 	stq	t0, 16(sp)	/* XXX t0-t7 necessary? */	;	\
     96   1.7   thorpej 	stq	t1, 24(sp)					;	\
     97   1.7   thorpej 	stq	t2, 32(sp)					;	\
     98   1.7   thorpej 	stq	t3, 40(sp)					;	\
     99   1.7   thorpej 	stq	t4, 48(sp)					;	\
    100   1.7   thorpej 	stq	t5, 56(sp)					;	\
    101   1.7   thorpej 	stq	t6, 64(sp)					;	\
    102   1.7   thorpej 	stq	t7, 72(sp)					;	\
    103   1.7   thorpej 	stq	a0, 80(sp)					;	\
    104   1.7   thorpej 	stq	a1, 88(sp)					;	\
    105   1.7   thorpej 	stq	a2, 96(sp)					;	\
    106   1.7   thorpej 	stq	a3, 104(sp)					;	\
    107   1.7   thorpej 	stq	a4, 112(sp)					;	\
    108   1.7   thorpej 	stq	a5, 120(sp)					;	\
    109  1.17  riastrad 	stq	t8, 128(sp)	/* XXX t8-t11 necessary? */	;	\
    110   1.7   thorpej 	stq	t9, 136(sp)					;	\
    111   1.7   thorpej 	stq	t10, 144(sp)					;	\
    112   1.7   thorpej 	stq	t11, 152(sp)					;	\
    113   1.7   thorpej 	stq	gp, 160(sp)					;	\
    114   1.7   thorpej 									\
    115   1.7   thorpej 	/*								\
    116   1.7   thorpej 	 * Load our global pointer.  Note, can't use pv, since it is	\
    117   1.7   thorpej 	 * already used by the PLT code.				\
    118   1.7   thorpej 	 */								\
    119   1.7   thorpej 	br	t0, 1f						;	\
    120   1.7   thorpej 1:	LDGP(t0)
    121   1.7   thorpej 
    122  1.17  riastrad #define	RTLD_BIND_START_EPILOGUE(imb)					\
    123   1.7   thorpej 	/* Move the destination address into position. */		\
    124   1.7   thorpej 	mov	v0, pv						;	\
    125   1.7   thorpej 									\
    126   1.7   thorpej 	/* Restore program registers. */				\
    127   1.7   thorpej 	ldq	ra, 0(sp)					;	\
    128   1.7   thorpej 	ldq	v0, 8(sp)					;	\
    129   1.7   thorpej 	ldq	t0, 16(sp)					;	\
    130   1.7   thorpej 	ldq	t1, 24(sp)					;	\
    131   1.7   thorpej 	ldq	t2, 32(sp)					;	\
    132   1.7   thorpej 	ldq	t3, 40(sp)					;	\
    133   1.7   thorpej 	ldq	t4, 48(sp)					;	\
    134   1.7   thorpej 	ldq	t5, 56(sp)					;	\
    135   1.7   thorpej 	ldq	t6, 64(sp)					;	\
    136   1.7   thorpej 	ldq	t7, 72(sp)					;	\
    137   1.7   thorpej 	ldq	a0, 80(sp)					;	\
    138   1.7   thorpej 	ldq	a1, 88(sp)					;	\
    139   1.7   thorpej 	ldq	a2, 96(sp)					;	\
    140   1.7   thorpej 	ldq	a3, 104(sp)					;	\
    141   1.7   thorpej 	ldq	a4, 112(sp)					;	\
    142   1.7   thorpej 	ldq	a5, 120(sp)					;	\
    143   1.7   thorpej 	ldq	t8, 128(sp)					;	\
    144   1.7   thorpej 	ldq	t9, 136(sp)					;	\
    145   1.7   thorpej 	ldq	t10, 144(sp)					;	\
    146   1.7   thorpej 	ldq	t11, 152(sp)					;	\
    147   1.7   thorpej 	ldq	gp, 160(sp)					;	\
    148   1.7   thorpej 	/* XXX LDGP? */							\
    149   1.7   thorpej 									\
    150  1.10   thorpej 	/*								\
    151  1.10   thorpej 	 * We've patched the PLT; sync the I-stream.			\
    152  1.10   thorpej 	 */								\
    153  1.10   thorpej 	imb							;	\
    154  1.10   thorpej 									\
    155   1.7   thorpej 	/* Pop the stack frame and turn control to the destination. */	\
    156   1.7   thorpej 	lda     sp, 168(sp)					;	\
    157   1.7   thorpej 	jmp	zero, (pv)
    158   1.7   thorpej 
    159   1.2   thorpej /*
    160  1.17  riastrad  * _rtld_bind_start_secureplt(_rtld_bind_start_secureplt@pv, obj@at,
    161  1.17  riastrad  *     (sizeof(Elf_Rela)*index)@t11)
    162  1.17  riastrad  *
    163  1.17  riastrad  *	Lazy binding entry point, called via PLT with read-only
    164  1.17  riastrad  *	secureplt, when DT_ALPHA_PLTRO is set.  The PLT itself looks
    165  1.17  riastrad  *	something like this:
    166  1.17  riastrad  *
    167  1.17  riastrad  *	_PROCEDURE_LINKAGE_TABLE_:
    168  1.17  riastrad  *		subq	pv, at, t11	// t11 := pv - ent0 = 4*index
    169  1.17  riastrad  *		s4subq	t11, t11, t11	// t11 := 12*index
    170  1.17  riastrad  *		addq	t11, t11, t11	// t11 := 24*index
    171  1.17  riastrad  *					//      = sizeof(Elf_Rela)*index
    172  1.17  riastrad  *		ldah	at, ...(at)	// at  := PLTGOT
    173  1.17  riastrad  *		lda	at, ...(at)
    174  1.17  riastrad  *		ldq	pv, 0(at)	// pv  := PLTGOT[0]
    175  1.17  riastrad  *					//      = _rtld_bind_start_secureplt
    176  1.17  riastrad  *		ldq	at, 8(at)	// at  := PLTGOT[1]
    177  1.17  riastrad  *					//	= obj
    178  1.17  riastrad  *		jmp	(pv)
    179  1.17  riastrad  *	0:	br	at, _PROCEDURE_LINKAGE_TABLE_	// at := ent0
    180  1.17  riastrad  *	ent0:	br	0b		// pv - ent0 = 0 = 4*index
    181  1.17  riastrad  *	ent1:	br	0b		// pv - ent0 = 4 = 4*index
    182  1.17  riastrad  *	ent2:	br	0b		// pv - ent0 = 8 = 4*index
    183  1.17  riastrad  *	...
    184  1.17  riastrad  */
    185  1.17  riastrad NESTED_NOPROFILE(_rtld_bind_start_secureplt, 0, 168, ra, 0, 0)
    186  1.17  riastrad 
    187  1.17  riastrad 	RTLD_BIND_START_PROLOGUE
    188  1.17  riastrad 
    189  1.17  riastrad 	/* Set up the arguments for _rtld_bind. */
    190  1.17  riastrad 	mov	at_reg, a0
    191  1.17  riastrad 	mov	t11, a1
    192  1.17  riastrad 
    193  1.17  riastrad 	CALL(_rtld_bind)
    194  1.17  riastrad 
    195  1.17  riastrad 	RTLD_BIND_START_EPILOGUE(/* no text writes, so no imb */)
    196  1.17  riastrad 
    197  1.17  riastrad END(_rtld_bind_start_secureplt)
    198  1.17  riastrad 
    199  1.17  riastrad /*
    200  1.17  riastrad  * _rtld_bind_start(_rtld_bind_start@pv, &PLTGOT[2]@pv,
    201  1.17  riastrad  *     (ent0 + 4*(3*index + 1))@at)
    202  1.17  riastrad  *
    203  1.17  riastrad  *	Lazy binding entry point, called via PLT with read/write
    204  1.17  riastrad  *	non-secureplt, when DT_ALPHA_PLTRO is not set.  The PLT itself
    205  1.17  riastrad  *	looks something like this at program startup, with PLTGOT (an
    206  1.17  riastrad  *	array of 64-bit Elf_Addr) pointing at _PROCEDURE_LINKAGE_TABLE_
    207  1.17  riastrad  *	and PLTGOT[2] and PLTGOT[3] initialized by _rtld_setup_pltgot:
    208  1.17  riastrad  *
    209  1.17  riastrad  *	_PROCEDURE_LINKAGE_TABLE_:
    210  1.17  riastrad  *		br	pv, .Lref	// pv  := .Lref
    211  1.17  riastrad  *	.Lref:	ldq	pv, 12(pv)	// pv  := PLTGOT[2]
    212  1.17  riastrad  *					        = _rtld_bind_start
    213  1.17  riastrad  *		unop			// no-op for alignment
    214  1.17  riastrad  *		jmp	pv, (pv)	// pv  := &PLTGOT[2]
    215  1.17  riastrad  *		.qword	(_rtld_bind_start)	// PLTGOT[2]
    216  1.17  riastrad  *		.qword	(object pointer)	// PLTGOT[3]
    217  1.17  riastrad  *	ent0:	br	at, _PROCEDURE_LINKAGE_TABLE_
    218  1.17  riastrad  *		unop			// space for adjusted stub
    219  1.17  riastrad  *		unop			// space for adjusted stub
    220  1.17  riastrad  *	ent1:	br	at, _PROCEDURE_LINKAGE_TABLE_
    221  1.17  riastrad  *		unop
    222  1.17  riastrad  *		unop
    223  1.17  riastrad  *	ent2:	br	at, _PROCEDURE_LINKAGE_TABLE_
    224  1.17  riastrad  *		unop
    225  1.17  riastrad  *		unop
    226  1.17  riastrad  *	...
    227  1.17  riastrad  *
    228  1.17  riastrad  *	Note: Distance from &PLTGOT[2] (pv) to ent[0] + 4 (at) is 20
    229  1.17  riastrad  *	bytes, and each ent[index] + 4 (at) after that is separated by
    230  1.17  riastrad  *	3 instructions, i.e., 12 bytes.
    231   1.2   thorpej  */
    232   1.2   thorpej NESTED_NOPROFILE(_rtld_bind_start, 0, 168, ra, 0, 0)
    233   1.2   thorpej 
    234   1.7   thorpej 	RTLD_BIND_START_PROLOGUE
    235   1.2   thorpej 
    236   1.1       cgd 	/* Set up the arguments for _rtld_bind. */
    237   1.5   thorpej 	subq	at_reg, pv, a1		/* calculate offset of reloc entry */
    238   1.5   thorpej 	ldq	a0, 8(pv)		/* object structure */
    239   1.5   thorpej 	subq	a1, 20, a1		/* = (at - pv - 20) / 12 * 24 */
    240   1.5   thorpej 	addq	a1, a1, a1
    241   1.7   thorpej 
    242   1.7   thorpej 	CALL(_rtld_bind)
    243   1.7   thorpej 
    244  1.17  riastrad 	RTLD_BIND_START_EPILOGUE(imb)
    245   1.7   thorpej 
    246   1.7   thorpej END(_rtld_bind_start)
    247   1.7   thorpej 
    248   1.7   thorpej /*
    249  1.17  riastrad  * _rtld_bind_start_old(&PLTGOT[2]@pv, (sizeof(Elf_Rela)*index)@at)
    250  1.17  riastrad  *
    251  1.17  riastrad  *	Lazy binding entry point, called via PLT.  This version is for
    252  1.17  riastrad  *	the old PLT entry format, for which the PLT looks something
    253  1.17  riastrad  *	like this at program startup, with PLTGOT (an array of 64-bit
    254  1.17  riastrad  *	Elf_Addr) pointing at _PROCEDURE_LINKAGE_TABLE_, and PLTGOT[2]
    255  1.17  riastrad  *	and PLTGOT[3] initialized by _rtld_setup_pltgot:
    256  1.17  riastrad  *
    257  1.17  riastrad  *	_PROCEDURE_LINKAGE_TABLE_:
    258  1.17  riastrad  *		br	pv, 1f		// pv  := .Lref
    259  1.17  riastrad  *	.Lref:	ldq	pv, 12(pv)	// pv  := PLTGOT[2]
    260  1.17  riastrad  *					        = _rtld_bind_start
    261  1.17  riastrad  *		unop			// no-op for alignment
    262  1.17  riastrad  *		jmp	pv, (pv)	// pv  := &PLTGOT[2]
    263  1.17  riastrad  *		.qword	(_rtld_bind_start)	// PLTGOT[2]
    264  1.17  riastrad  *		.qword	(object pointer)	// PLTGOT[3]
    265  1.17  riastrad  *	ent0:	ldah	at, 0		// at  := 24*0
    266  1.17  riastrad  *		lda	at, 0(at)	//      = sizeof(Elf_Rela)*index
    267  1.17  riastrad  *		br	_PROCEDURE_LINKAGE_TABLE_
    268  1.17  riastrad  *	ent1:	ldah	at, 0		// at  := 24*1
    269  1.17  riastrad  *		lda	at, 24(at)	//      = sizeof(Elf_Rela)*index
    270  1.17  riastrad  *		br	_PROCEDURE_LINKAGE_TABLE_
    271  1.17  riastrad  *	ent3:	ldah	at, 0		// at  := 24*2
    272  1.17  riastrad  *		lda	at, 48(at)	//      = sizeof(Elf_Rela)*index
    273  1.17  riastrad  *		br	_PROCEDURE_LINKAGE_TABLE_
    274  1.17  riastrad  *	...
    275   1.7   thorpej  */
    276   1.7   thorpej NESTED_NOPROFILE(_rtld_bind_start_old, 0, 168, ra, 0, 0)
    277   1.7   thorpej 
    278   1.7   thorpej 	RTLD_BIND_START_PROLOGUE
    279   1.7   thorpej 
    280   1.7   thorpej 	/* Set up the arguments for _rtld_bind. */
    281   1.2   thorpej 	ldq	a0, 8(pv)		/* object structure */
    282   1.1       cgd 	mov	at_reg, a1		/* offset of reloc entry */
    283   1.7   thorpej 
    284   1.1       cgd 	CALL(_rtld_bind)
    285   1.1       cgd 
    286  1.17  riastrad 	RTLD_BIND_START_EPILOGUE(imb)
    287   1.1       cgd 
    288   1.7   thorpej END(_rtld_bind_start_old)
    289