Initial import from FreeBSD RELENG_4:
[games.git] / libexec / rtld-elf / alpha / rtld_start.S
1 /* $FreeBSD: src/libexec/rtld-elf/alpha/rtld_start.S,v 1.3.2.2 2002/09/02 02:10:20 obrien Exp $ */
2 /*      From: NetBSD: rtld_start.S,v 1.1 1996/12/16 20:38:09 cgd Exp    */
3
4 /*
5  * Copyright 1996 Matt Thomas <matt@3am-software.com>
6  * Copyright 2000 John D. Polstra
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  * 3. The name of the author may not be used to endorse or promote products
18  *    derived from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31
32 #include <machine/asm.h>
33 #include <machine/pal.h>
34
35 .extern _GLOBAL_OFFSET_TABLE_
36 .extern _GOT_END_
37
38 LEAF(_rtld_start, 0)            /* XXX */
39         .set    noreorder
40         br      pv, $33
41 $33:    LDGP(pv)
42
43         /* save away the stack pointer */
44
45         lda     s0, 0(sp)       /* get argc from stack */
46         lda     sp, -16(sp)     /* space for arguments */
47
48         /* save ps_strings pointer */
49         mov     a3, s1
50
51         /* Step 1 -- Figure out the displacement */
52
53         br      t2, $34         /* get our PC */
54 $34:    ldiq    t3, $34         /* get where the linker thought we were */
55         subq    t2, t3, t8      /* calculate the displacement */
56
57
58         /* Step 2 -- Find bounds of global offset table */
59
60         lda     t5, _GLOBAL_OFFSET_TABLE_
61         addq    t8, t5, t9      /* add the displacement */
62         lda     t4, _GOT_END_
63         addq    t8, t4, t10     /* add the displacement */
64
65         /*
66          * Step 3 -- Every entry in the global offset table needs to
67          * modified for the displacement before any code will work.
68          */
69
70 $35:    ldq     t1, 0(t9)       /* load the value */
71         addq    t8, t1, t1      /* add the displacement */
72         stq     t1, 0(t9)       /* save the new value */
73         lda     t9, 8(t9)       /* point to next entry */
74         cmpult  t9, t10, t1     /* are we done? */
75         bne     t1, $35         /* no, do more */
76
77         /*
78          *  Ya!  Things are far enough so we can do some dynamic linking!
79          */
80
81         lda     a0, 0(s0)       /* initial sp */
82         lda     a1, -16(s0)     /* address for exit proc */
83         lda     a2, -8(s0)      /* address for obj_main */
84         CALL(_rtld)             /* v0 = _rtld(sp, &exit_proc, &obj_main); */
85
86         ldq     a1, -16(s0)     /* our atexit function */
87         ldq     a2, -8(s0)      /* obj_main entry */
88         lda     sp, 16(sp)      /* readjust our stack */
89         mov     s0, a0          /* stack pointer */
90         mov     s1, a3          /* ps_strings pointer */
91         mov     v0, pv
92         jsr     ra, (v0), 0     /* (*_start)(sp, cleanup, obj); */
93         ldgp    gp, 0(ra)
94
95         CALL(exit)
96         halt
97 END(_rtld_start)
98
99 #define RTLD_BIND_START_PROLOGUE                                        \
100         /* at_reg already used by PLT code. */                          \
101         .set    noat                                            ;       \
102                                                                         \
103         /*                                                              \
104          * Allocate stack frame and preserve all registers that the     \
105          * caller would have normally saved themselves.                 \
106          */                                                             \
107         lda     sp, -168(sp)                                    ;       \
108         stq     ra, 0(sp)                                       ;       \
109         stq     v0, 8(sp)                                       ;       \
110         stq     t0, 16(sp)                                      ;       \
111         stq     t1, 24(sp)                                      ;       \
112         stq     t2, 32(sp)                                      ;       \
113         stq     t3, 40(sp)                                      ;       \
114         stq     t4, 48(sp)                                      ;       \
115         stq     t5, 56(sp)                                      ;       \
116         stq     t6, 64(sp)                                      ;       \
117         stq     t7, 72(sp)                                      ;       \
118         stq     a0, 80(sp)                                      ;       \
119         stq     a1, 88(sp)                                      ;       \
120         stq     a2, 96(sp)                                      ;       \
121         stq     a3, 104(sp)                                     ;       \
122         stq     a4, 112(sp)                                     ;       \
123         stq     a5, 120(sp)                                     ;       \
124         stq     t8, 128(sp)                                     ;       \
125         stq     t9, 136(sp)                                     ;       \
126         stq     t10, 144(sp)                                    ;       \
127         stq     t11, 152(sp)                                    ;       \
128         stq     gp, 160(sp)                                     ;       \
129                                                                         \
130         /*                                                              \
131          * Load our global pointer.  Note, can't use pv, since it is    \
132          * already used by the PLT code.                                \
133          */                                                             \
134         br      t0, 1f                                          ;       \
135 1:      LDGP(t0)
136
137 #define RTLD_BIND_START_EPILOGUE                                        \
138         /* Move the destination address into position. */               \
139         mov     v0, pv                                          ;       \
140                                                                         \
141         /* Restore program registers. */                                \
142         ldq     ra, 0(sp)                                       ;       \
143         ldq     v0, 8(sp)                                       ;       \
144         ldq     t0, 16(sp)                                      ;       \
145         ldq     t1, 24(sp)                                      ;       \
146         ldq     t2, 32(sp)                                      ;       \
147         ldq     t3, 40(sp)                                      ;       \
148         ldq     t4, 48(sp)                                      ;       \
149         ldq     t5, 56(sp)                                      ;       \
150         ldq     t6, 64(sp)                                      ;       \
151         ldq     t7, 72(sp)                                      ;       \
152         ldq     a0, 80(sp)                                      ;       \
153         ldq     a1, 88(sp)                                      ;       \
154         ldq     a2, 96(sp)                                      ;       \
155         ldq     a3, 104(sp)                                     ;       \
156         ldq     a4, 112(sp)                                     ;       \
157         ldq     a5, 120(sp)                                     ;       \
158         ldq     t8, 128(sp)                                     ;       \
159         ldq     t9, 136(sp)                                     ;       \
160         ldq     t10, 144(sp)                                    ;       \
161         ldq     t11, 152(sp)                                    ;       \
162         ldq     gp, 160(sp)                                     ;       \
163         /* XXX LDGP? */                                                 \
164                                                                         \
165         /*                                                              \
166          * We've patched the PLT; sync the I-stream.                    \
167          */                                                             \
168         imb                                                     ;       \
169                                                                         \
170         /* Pop the stack frame and turn control to the destination. */  \
171         lda     sp, 168(sp)                                     ;       \
172         jmp     zero, (pv)
173
174
175 /*
176  * Lazy binding entry point, called via PLT.
177  */
178 NESTED_NOPROFILE(_rtld_bind_start, 0, 168, ra, 0, 0)
179
180         RTLD_BIND_START_PROLOGUE
181
182         /* Set up the arguments for _rtld_bind. */
183         subq    at_reg, pv, a1          /* calculate reloc offset */
184         ldq     a0, 8(pv)               /* object structure */
185         subq    a1, 20, a1              /* = (at - t11 - 20) / 12 * 24 */
186         addq    a1, a1, a1
187
188         CALL(_rtld_bind)
189
190         RTLD_BIND_START_EPILOGUE
191
192 END(_rtld_bind_start)
193
194 /*
195  * Lazy binding entry point, called via PLT.  This version is for the
196  * old PLT entry format.
197  */
198 NESTED_NOPROFILE(_rtld_bind_start_old, 0, 168, ra, 0, 0)
199
200         RTLD_BIND_START_PROLOGUE
201
202         /* Set up the arguments for _rtld_bind. */
203         ldq     a0, 8(pv)               /* object structure */
204         mov     at_reg, a1              /* offset of reloc entry */
205
206         CALL(_rtld_bind)
207
208         RTLD_BIND_START_EPILOGUE
209
210 END(_rtld_bind_start_old)
211
212 /*
213  * int cmp0_and_store_int(volatile int *p, int newval);
214  *
215  * If an int holds 0, store newval into it; else do nothing.  Returns
216  * the previous value.
217  */
218 LEAF(cmp0_and_store_int, 2)
219 1:      mov     a1, t0
220         ldl_l   v0, 0(a0)
221         bne     v0, 3f
222         stl_c   t0, 0(a0)
223         beq     t0, 2f
224         mb
225         RET
226 2:      br      1b
227 3:      RET
228 END(cmp0_and_store_int)
229
230 LEAF(atomic_add_int, 2)
231 0:      ldl_l   t0, 0(a0)
232         addq    t0, a1, t0
233         stl_c   t0, 0(a0)
234         beq     t0, 1f
235         mb
236         RET
237 1:      br      0b
238 END(atomic_add_int)
239  
240 /* Atomically increment an int. */
241 LEAF(atomic_incr_int, 1)
242 0:      ldl_l   t0, 0(a0)
243         addq    t0, 1, t0
244         stl_c   t0, 0(a0)
245         beq     t0, 1f
246         mb
247         RET
248 1:      br      0b
249 END(atomic_incr_int)
250
251 /* Atomically decrement an int. */
252 LEAF(atomic_decr_int, 1)
253 0:      ldl_l   t0, 0(a0)
254         subq    t0, 1, t0
255         stl_c   t0, 0(a0)
256         beq     t0, 1f
257         mb
258         RET
259 1:      br      0b
260 END(atomic_decr_int)