rtld_start.S revision 1.20 1 /* $NetBSD: rtld_start.S,v 1.20 2014/03/19 21:52:00 joerg Exp $ */
2
3 /*
4 * Copyright 1996 Matt Thomas <matt (at) 3am-software.com>
5 * Portions copyright 2002, 2003 Charles M. Hannum <root (at) ihack.net>
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. The name of the author may not be used to endorse or promote products
17 * derived from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 #include <machine/asm.h>
32
33 /* R9 contains the address of PS_STRINGS and since its caller saved,
34 * we can just use it. R6 has a backup copy of the stack pointer which
35 * we can use as well.
36 */
37 ENTRY(_rtld_start, 0)
38 /* Allocate space on the stack for the cleanup and obj_main
39 * entries that _rtld() will provide for us.
40 */
41 clrl %fp
42 subl2 $8,%sp
43
44 movab _DYNAMIC,%r0
45 subl3 _GLOBAL_OFFSET_TABLE_,%r0,%r10
46 pushl %r10 /* relocbase */
47 pushl %r0 /* &_DYNAMIC */
48 calls $2,_rtld_relocate_nonplt_self
49
50 pushl %r10 /* relocbase */
51 pushal 4(%sp) /* sp */
52 calls $2,_rtld /* entry = _rtld(sp, relocbase) */
53
54 movq (%sp)+,%r7 /* grab cleanup and obj_main into %r7/%r8 */
55 jmp 2(%r0) /* jump to entry point + 2 */
56 END(_rtld_start)
57
58 /*
59 * Lazy binding entry point, called via PLT via JMP into pltgot[1].
60 * SP+0: obj entry points
61 * SP+4: address to relocation index
62 *
63 * Note: Some functions rely on there not being an additional call frame;
64 * hence the `optimization' to avoid the callg opportunistically.
65 */
66 ALTENTRY(_rtld_bind_start)
67 movab -64(%sp),%sp /* reserve some space */
68 pushr $0x3f /* save R0-R5 */
69 movq -8(%fp),%r0 /* get addresses of plt.got & reloc index */
70 pushl (%r1) /* push relocation index */
71 pushl %r0 /* push address of obj entry */
72 calls $2,_rtld_bind
73
74 addl3 $2,%r0,%r3 /* save routine address */
75 extzv $0,$12,(%r0),%r1 /* get entry mask */
76 extzv $0,$12,6(%fp),%r2 /* get saved mask */
77 cmpw %r1,%r2 /* compare them */
78 bneq 12f /* if they are different, rebuild */
79 movl %r3,-4(%fp) /* save routine address */
80 popr $0x3f /* pop registers */
81 movab 68(%sp),%sp /* restore sp */
82 rsb /* and jump to it */
83
84 /*
85 * We need to rebuild the callframe. Save the current one in case
86 * we might overwrite it.
87 */
88 12: movq 4(%fp),-(%sp) /* save PSW and AP */
89 movq 12(%fp),-(%sp) /* save FP and return address */
90 /*
91 * Find out where this this call frame ends.
92 */
93 movl %ap,%r0 /* get past callframe and registers */
94 bbs $29,4(%fp),22f /* calls is easy, it's where AP is */
95 /*
96 * Callg not so much
97 */
98 movab 20(%fp),%r0 /* past fixed callframe */
99 tstw %r2 /* no saved registers? */
100 beql 22f /* none, so we are done. */
101 movl $11,%r4 /* start with register 11 */
102 20: bbc %r4,%r2,21f /* save this register? */
103 addl2 $4,%r0 /* yes, adjust for saved register */
104 21: sobgeq %r4,20b /* try next register */
105
106 22:
107 /*
108 * First "push" the caller saved registers (if there any that
109 * need to saved.)
110 */
111 tstw %r1 /* if there are no registers to save */
112 beql 1f /* just push the callframe */
113 cmpw %r1,$63 /* if there are no caller-saved registers */
114 blequ 5f /* skip them */
115 bbc $11,%r1,10f /* does it need to be saved? */
116 movl %r11,-(%r0)
117 10: bbc $10,%r1,9f /* does it need to be saved? */
118 movl %r10,-(%r0)
119 9: bbc $9,%r1,8f /* does it need to be saved? */
120 movl %r9,-(%r0)
121 8: bbc $8,%r1,7f /* does it need to be saved? */
122 movl %r8,-(%r0)
123 7: bbc $7,%r1,6f /* does it need to be saved? */
124 movl %r7,-(%r0)
125 6: bbc $6,%r1,5f /* does it need to be saved? */
126 movl %r6,-(%r0)
127 5:
128 /*
129 * r0-r5 are not normally preserved so we should be done.
130 */
131 cmpw %r1,$63
132 bgtru 1f
133 /*
134 * For some reason, we have to preserve these.
135 */
136 movab 16(%sp),%r2
137 bbc $5,%r1,4f /* does it need to be saved? */
138 movl 20(%r2),-(%r0)
139 4: bbc $4,%r1,3f /* does it need to be saved? */
140 movl 16(%r2),-(%r0)
141 3: bbc $3,%r1,2f /* does it need to be saved? */
142 movl 12(%r2),-(%r0)
143 2: bbc $2,%r1,1f /* does it need to be saved? */
144 movl 8(%r2),-(%r0)
145
146 /*
147 * Now we save the fixed part of the callframe.
148 */
149 1: clrl %r4 /* clear condition handler slot */
150 movq (%sp)+,-(%r0) /* move FP and PC into place */
151 movq (%sp)+,-(%r0) /* move PSW/save-mask/etc + AP into place */
152 movq %r3,-(%r0) /* move routine address + cond handle slot */
153 addl3 $4,%r0,%fp /* get start of new callframe */
154 insv %r1,$0,$12,6(%fp) /* insert new saved mask */
155 popr $0x3f /* restore R0-R5 (cond flags not modified) */
156 subl3 $4,%fp,%sp /* sp needs to be equal to fp */
157 rsb /* and jmp to the routine */
158 END(_rtld_bind_start)
159