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