rtld_start.S revision 1.16.54.1 1 1.16.54.1 yamt /* $NetBSD: rtld_start.S,v 1.16.54.1 2014/05/22 11:37:14 yamt 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.54.1 yamt END(_rtld_start)
57 1.1 matt
58 1.1 matt /*
59 1.16.54.1 yamt * Lazy binding entry point, called via PLT via JMP into pltgot[1].
60 1.16.54.1 yamt * SP+4: address to relocation offset
61 1.16.54.1 yamt * SP+0: obj entry points
62 1.1 matt */
63 1.3 matt ALTENTRY(_rtld_bind_start)
64 1.16.54.1 yamt pushl %r1 /* need to preserve r1 */
65 1.16.54.1 yamt movq -8(%fp),%r0 /* get addresses of plt.got & reloc index */
66 1.16.54.1 yamt 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.54.1 yamt
70 1.16.54.1 yamt /*
71 1.16.54.1 yamt * This code checks to see if we got called via a call{s,g} $n,*pcrel32
72 1.16.54.1 yamt * This is by far the most common case (a call indirectly via the PLT).
73 1.16.54.1 yamt */
74 1.16.54.1 yamt subl3 $7,16(%fp),%r1 /* return address */
75 1.16.54.1 yamt bicb3 $1,(%r1),%r2 /* fetch opcode of instruction */
76 1.16.54.1 yamt cmpb $0xfa,%r2 /* is it calls/callg */
77 1.16.54.1 yamt jneq 20f /* no it isn't */
78 1.16.54.1 yamt cmpb $0xff,2(%r1) /* and deferred 32-bit PC displacement? */
79 1.16.54.1 yamt jneq 20f /* no it isn't */
80 1.16.54.1 yamt
81 1.16.54.1 yamt /*
82 1.16.54.1 yamt * This makes sure the longword with the PLT's address has been updated
83 1.16.54.1 yamt * to point to the routine's address. If it hasn't, then returning
84 1.16.54.1 yamt * would put us in an infinite loop. Instead we punt and fake up a
85 1.16.54.1 yamt * callframe.
86 1.16.54.1 yamt */
87 1.16.54.1 yamt movl 3(%r1),%r3 /* get displacement */
88 1.16.54.1 yamt addl2 16(%fp),%r3 /* add ending location */
89 1.16.54.1 yamt cmpl (%r3),%r0 /* does it contain the routine address? */
90 1.16.54.1 yamt #ifdef DEBUG
91 1.16.54.1 yamt jneq 30f /* no it doesn't, die */
92 1.16.54.1 yamt #else
93 1.16.54.1 yamt jneq 20f /* no it doesn't, go fake a new callframe */
94 1.16.54.1 yamt #endif
95 1.16.54.1 yamt
96 1.16.54.1 yamt 11: movl %r1,16(%fp) /* backup to the calls/callg */
97 1.16.54.1 yamt jbc $29,4(%fp),12f /* skip if this was a callg */
98 1.16.54.1 yamt clrl (%ap) /* clear argument count */
99 1.16.54.1 yamt 12: movl (%sp)+,%r1 /* restore r1 */
100 1.16.54.1 yamt ret /* return and redo the call */
101 1.16.54.1 yamt
102 1.16.54.1 yamt #if 1
103 1.16.54.1 yamt 20:
104 1.16.54.1 yamt /*
105 1.16.54.1 yamt * Since the calling standard says only r6-r11 should be saved,
106 1.16.54.1 yamt * that simplies things for us. That means we can use r0-r5 as
107 1.16.54.1 yamt * temporaries without worrying about preserving them. This means
108 1.16.54.1 yamt * can hold the current fixed callframe in r2-r5 as we build the
109 1.16.54.1 yamt * callframe without having to worry about overwriting the existing
110 1.16.54.1 yamt * callframe.
111 1.16.54.1 yamt */
112 1.16.54.1 yamt extzv $0,$12,(%r0),%r1/* get routine's save mask */
113 1.16.54.1 yamt bitw $0x3f,%r1 /* does the routine use r0-r5? */
114 1.16.54.1 yamt jneq 30f /* yes, that sucks */
115 1.16.54.1 yamt jbc $29,4(%fp),27f /* handle callg */
116 1.16.54.1 yamt movq 4(%fp),%r2 /* fetch callframe status & saved AP */
117 1.16.54.1 yamt movq 12(%fp),%r4 /* fetch callframe saved FP & PC */
118 1.16.54.1 yamt insv %r1,$16,$12,%r2 /* update save mask */
119 1.16.54.1 yamt movl (%sp)+,%fp /* use fp to keep saved r1 */
120 1.16.54.1 yamt movl %ap,%sp /* reset stack to top of callframe */
121 1.16.54.1 yamt 22: pushr %r1 /* push registers */
122 1.16.54.1 yamt movq %r4,-(%sp) /* push callframe saved FP & PC */
123 1.16.54.1 yamt movq %r2,-(%sp) /* push callframe status & saved AP */
124 1.16.54.1 yamt pushl $0 /* push condition handler */
125 1.16.54.1 yamt movl %fp,%r1 /* restore r1 */
126 1.16.54.1 yamt movl %sp,%fp /* sp == fp now */
127 1.16.54.1 yamt #if 1
128 1.16.54.1 yamt jmp 2(%r0) /* jump past entry mask */
129 1.16.54.1 yamt #else
130 1.16.54.1 yamt /*
131 1.16.54.1 yamt * More correct but IV/DV are never set so ignore doing this for now.
132 1.16.54.1 yamt */
133 1.16.54.1 yamt movpsl -(%sp) /* push PSL */
134 1.16.54.1 yamt clrb (%sp) /* clear user flags */
135 1.16.54.1 yamt jbc $14,(%r0),24f /* IV need to be set? */
136 1.16.54.1 yamt bisb2 $0x20,(%sp) /* yes, set it. */
137 1.16.54.1 yamt 24: jbc $15,(%r0),25f /* DV need to be set? */
138 1.16.54.1 yamt bisb2 $0x80,(%sp) /* yes, set it. */
139 1.16.54.1 yamt 25: pushab 2(%r0) /* push address of first instruction */
140 1.16.54.1 yamt rei /* and go to it (updating PSW) */
141 1.16.54.1 yamt #endif
142 1.16.54.1 yamt
143 1.16.54.1 yamt /*
144 1.16.54.1 yamt * Count how many registers are being used for callg.
145 1.16.54.1 yamt */
146 1.16.54.1 yamt 27: movl $0x32212110,%r3 /* bit counts */
147 1.16.54.1 yamt extzv $6,$3,%r1,%r2 /* extract bits 6-8 */
148 1.16.54.1 yamt ashl $2,%r2,%r2 /* shift by 2 */
149 1.16.54.1 yamt extzv %r2,$4,%r3,%r4 /* extract count */
150 1.16.54.1 yamt extzv $9,$3,%r1,%r2 /* extract bits 9-11 */
151 1.16.54.1 yamt ashl $2,%r2,%r2 /* shift by 2 */
152 1.16.54.1 yamt extzv %r2,$4,%r3,%r5 /* extract count */
153 1.16.54.1 yamt movq 4(%fp),%r2 /* fetch callframe status & saved AP */
154 1.16.54.1 yamt insv %r1,$16,$12,%r2 /* update save mask */
155 1.16.54.1 yamt addl3 %r3,r4,%r1 /* add counts and discard them */
156 1.16.54.1 yamt movq 12(%fp),%r4 /* fetch callframe saved FP & PC */
157 1.16.54.1 yamt moval 20(%fp)[%r1],%sp/* pop callframe */
158 1.16.54.1 yamt extzv $16,$12,%r2,%r1 /* get save mask back */
159 1.16.54.1 yamt jbr 22b /* now build the new callframe */
160 1.16.54.1 yamt
161 1.16.54.1 yamt 30:
162 1.16.54.1 yamt calls $0,_C_LABEL(_rtld_die)
163 1.16.54.1 yamt #else
164 1.16.54.1 yamt /*
165 1.16.54.1 yamt * Check to see if called via call? $n,w^off(reg)
166 1.16.54.1 yamt */
167 1.16.54.1 yamt 20: addl2 $2,%r1 /* 16-bit displacement */
168 1.16.54.1 yamt bicb3 $1,(%r1),%r2 /* fetch opcode of instruction */
169 1.16.54.1 yamt cmpb $0xfa,%r2 /* is it calls/callg */
170 1.16.54.1 yamt jneq 30f /* no it isn't */
171 1.16.54.1 yamt bicb3 $0x1f,2(%r1),%r3/* extract addressing mode */
172 1.16.54.1 yamt cmpb $0xc0,%r3 /* 16-bit displacement? */
173 1.16.54.1 yamt jeql 11b /* yes, redo the call */
174 1.16.54.1 yamt halt
175 1.16.54.1 yamt
176 1.16.54.1 yamt /*
177 1.16.54.1 yamt * Check to see if called via call? $n,b^off(reg)
178 1.16.54.1 yamt */
179 1.16.54.1 yamt 30: incl %r1 /* 8-bit displacement */
180 1.16.54.1 yamt bicb3 $1,(%r1),%r2 /* fetch opcode of instruction */
181 1.16.54.1 yamt cmpb $0xfa,%r2 /* is it calls/callg */
182 1.16.54.1 yamt jneq 40f /* no it isn't */
183 1.16.54.1 yamt bicb3 $0x1f,2(%r1),%r3/* extract addressing mode */
184 1.16.54.1 yamt cmpb $0xa0,%r3 /* 8-bit displacement? */
185 1.16.54.1 yamt jeql 11b /* yes, redo the call */
186 1.16.54.1 yamt halt
187 1.16.54.1 yamt
188 1.16.54.1 yamt /*
189 1.16.54.1 yamt * Check to see if called via call? $n,(reg)
190 1.16.54.1 yamt */
191 1.16.54.1 yamt 40: incl %r1 /* no displacement */
192 1.16.54.1 yamt bicb3 $1,(%r1),%r2 /* fetch opcode of instruction */
193 1.16.54.1 yamt cmpb $0xfa,%r2 /* is it calls/callg */
194 1.16.54.1 yamt jeql 41f /* yes it is */
195 1.16.54.1 yamt halt /* no, die die die */
196 1.16.54.1 yamt 41: bicb3 $0x0f,2(%r1),%r2/* extract addressing mode */
197 1.16.54.1 yamt bicb3 $0xf0,2(%r1),%r3/* extract register */
198 1.16.54.1 yamt extzv $0,$12,6(%fp),%r4/* extract saved mask */
199 1.16.54.1 yamt cmpb $0x60,%r2 /* register deferred? */
200 1.16.54.1 yamt jeql 42f /* yes, deal with it */
201 1.16.54.1 yamt cmpb $0x90,%r2 /* autoincrement deferred? */
202 1.16.54.1 yamt jeql 70f /* yes, deal with it */
203 1.16.54.1 yamt halt /* no, die die die */
204 1.16.54.1 yamt
205 1.16.54.1 yamt 42: cmpw %r4,$0xffc /* did we save r2-r11? */
206 1.16.54.1 yamt jneq 50f /* no, deal with it */
207 1.16.54.1 yamt jbc %r3,%r4,43f /* is the register in the saved mask? */
208 1.16.54.1 yamt
209 1.16.54.1 yamt /*
210 1.16.54.1 yamt * We saved r2-r11, so it's easy to replace the saved register with
211 1.16.54.1 yamt * the right value by indexing into saved register (offset by 8).
212 1.16.54.1 yamt */
213 1.16.54.1 yamt movl %r0,(20-8)(%fp)[%r3] /* replace address in saved registers */
214 1.16.54.1 yamt jbr 11b /* go back and redo call */
215 1.16.54.1 yamt /*
216 1.16.54.1 yamt * Must have been called via r0 or r1 which are saved locally.
217 1.16.54.1 yamt * So move the routine address in the appropriate slot on the stack.
218 1.16.54.1 yamt */
219 1.16.54.1 yamt 43: movl %r0,(%sp)[%r3]
220 1.16.54.1 yamt jbr 11b /* go back and redo call */
221 1.16.54.1 yamt
222 1.16.54.1 yamt 50: jbs %r3,%r4,60f /* is the register in the saved mask? */
223 1.16.54.1 yamt jbs %r3,$0x3f,43b /* is it r0-r5? */
224 1.16.54.1 yamt /*
225 1.16.54.1 yamt * The register used for the call was not saved so we need to move
226 1.16.54.1 yamt * the new function address into it so the re-call will use the new
227 1.16.54.1 yamt * address.
228 1.16.54.1 yamt */
229 1.16.54.1 yamt pushl %r0 /* save function address on the stack */
230 1.16.54.1 yamt ashl %r5,$1,%r0 /* create a bitmask for the register */
231 1.16.54.1 yamt popr %r0 /* pop it off the stack. */
232 1.16.54.1 yamt jbr 11b /* and redo the call */
233 1.16.54.1 yamt
234 1.16.54.1 yamt 60: clrl %r2 /* starting offset into saved registers */
235 1.16.54.1 yamt clrl %r5 /* start with register 0 */
236 1.16.54.1 yamt
237 1.16.54.1 yamt 61: cmpl %r2,%r3 /* is the register to save? */
238 1.16.54.1 yamt jneq 62f /* no, advance to next */
239 1.16.54.1 yamt movl %r0,20(%fp)[%r5]/* yes, save return address in saved reg */
240 1.16.54.1 yamt jbr 11b /* and return the call */
241 1.16.54.1 yamt 62: jbc %r5,%r4,63f /* is this register saved? */
242 1.16.54.1 yamt incl %r5 /* yes, account for it */
243 1.16.54.1 yamt 63: incl %r2 /* increment register number */
244 1.16.54.1 yamt jbr 61b /* and loop */
245 1.16.54.1 yamt
246 1.16.54.1 yamt 70: cmpb %r3,$12
247 1.16.54.1 yamt blss 71f
248 1.16.54.1 yamt halt
249 1.16.54.1 yamt
250 1.16.54.1 yamt 71: cmpw %r4,$0xffc /* did we save r2-r11? */
251 1.16.54.1 yamt jneq 72f /* no, deal with it */
252 1.16.54.1 yamt subl2 $4,(20-8)(%fp)[%r3] /* backup incremented register */
253 1.16.54.1 yamt jbr 11b /* and redo the call.
254 1.16.54.1 yamt
255 1.16.54.1 yamt 72: jbs %r3,%r4,80f
256 1.16.54.1 yamt jbs %r3,%3f,74f
257 1.16.54.1 yamt ashl %r5,$1,%r0 /* create a bitmask for the register */
258 1.16.54.1 yamt pushr %r0 /* pop it off the stack. */
259 1.16.54.1 yamt subl2 $4,(%sp) /* backup incremented register */
260 1.16.54.1 yamt popr %r0 /* pop it off the stack. */
261 1.16.54.1 yamt jbr 11b /* and redo the call.
262 1.16.54.1 yamt
263 1.16.54.1 yamt 73: subl2 %4,(%sp)[%r3] /* backup incremented register */
264 1.16.54.1 yamt jbr 11b /* and redo the call.
265 1.16.54.1 yamt
266 1.16.54.1 yamt 80: clrl %r2 /* starting offset into saved registers */
267 1.16.54.1 yamt clrl %r5 /* start with register 0 */
268 1.16.54.1 yamt
269 1.16.54.1 yamt 81: cmpl %r2,%r3 /* is the register to save? */
270 1.16.54.1 yamt jneq 82f /* no, advance to next */
271 1.16.54.1 yamt subl $4,20(%fp)[%r5] /* yes, backup incremented register */
272 1.16.54.1 yamt jbr 11b /* and return the call */
273 1.16.54.1 yamt 82: jbc %r5,%r4,83f /* is this register saved? */
274 1.16.54.1 yamt incl %r5 /* yes, account for it */
275 1.16.54.1 yamt 83: incl %r2 /* increment register number */
276 1.16.54.1 yamt jbr 81b /* and loop */
277 1.16.54.1 yamt #endif
278 1.16.54.1 yamt END(_rtld_bind_start)
279