1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
|
/* $NetBSD: rtld_start.S,v 1.24 2014/08/17 16:57:37 matt Exp $ */
/*
* Copyright 1996 Matt Thomas <matt@3am-software.com>
* Portions copyright 2002, 2003 Charles M. Hannum <root@ihack.net>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <machine/asm.h>
/* R9 contains the address of PS_STRINGS and since its caller saved,
* we can just use it. R6 has a backup copy of the stack pointer which
* we can use as well.
*/
ENTRY(_rtld_start, 0)
/* Allocate space on the stack for the cleanup and obj_main
* entries that _rtld() will provide for us.
*/
clrl %fp
subl2 $8,%sp
movab _DYNAMIC,%r0
subl3 _GLOBAL_OFFSET_TABLE_,%r0,%r10
pushl %r10 /* relocbase */
pushl %r0 /* &_DYNAMIC */
calls $2,_rtld_relocate_nonplt_self
pushl %r10 /* relocbase */
pushal 4(%sp) /* sp */
calls $2,_rtld /* entry = _rtld(sp, relocbase) */
movq (%sp)+,%r7 /* grab cleanup and obj_main into %r7/%r8 */
jmp 2(%r0) /* jump to entry point + 2 */
END(_rtld_start)
/*
* Lazy binding entry point, called via PLT via JMP into pltgot[1].
* SP+4: address to relocation offset
* SP+0: obj entry points
*/
ALTENTRY(_rtld_bind_start)
pushl %r1 /* need to preserve r1 */
movq -8(%fp),%r0 /* get addresses of plt.got & reloc index */
pushl (%r1) /* push relocation offset */
pushl %r0 /* push address of obj entry */
calls $2,_rtld_bind
/*
* This code checks to see if we got called via a call{s,g} $n,*pcrel32
* This is by far the most common case (a call indirectly via the PLT).
*/
subl3 $7,16(%fp),%r1 /* return address */
bicb3 $1,(%r1),%r2 /* fetch opcode of instruction */
cmpb $0xfa,%r2 /* is it calls/callg */
jneq 20f /* no it isn't */
cmpb $0xff,2(%r1) /* and deferred 32-bit PC displacement? */
jneq 20f /* no it isn't */
/*
* This makes sure the longword with the PLT's address has been updated
* to point to the routine's address. If it hasn't, then returning
* would put us in an infinite loop. Instead we punt and fake up a
* callframe.
*/
movl 3(%r1),%r3 /* get displacement */
addl2 16(%fp),%r3 /* add ending location */
cmpl (%r3),%r0 /* does it contain the routine address? */
#ifdef DEBUG
jneq 30f /* no it doesn't, die */
#else
jneq 20f /* no it doesn't, go fake a new callframe */
#endif
11: movl %r1,16(%fp) /* backup to the calls/callg */
jbc $29,4(%fp),12f /* skip if this was a callg */
clrl (%ap) /* clear argument count */
12: movl (%sp)+,%r1 /* restore r1 */
ret /* return and redo the call */
#if 1
20:
/*
* Since the calling standard says only r6-r11 should be saved,
* that simplies things for us. That means we can use r0-r5 as
* temporaries without worrying about preserving them. This means
* can hold the current fixed callframe in r2-r5 as we build the
* callframe without having to worry about overwriting the existing
* callframe.
*/
extzv $0,$12,(%r0),%r1/* get routine's save mask */
bitw $0x3f,%r1 /* does the routine use r0-r5? */
jneq 30f /* yes, that sucks */
jbc $29,4(%fp),27f /* handle callg */
movq 4(%fp),%r2 /* fetch callframe status & saved AP */
movq 12(%fp),%r4 /* fetch callframe saved FP & PC */
insv %r1,$16,$12,%r2 /* update save mask */
movl (%sp)+,%fp /* use fp to keep saved r1 */
movl %ap,%sp /* reset stack to top of callframe */
22: pushr %r1 /* push registers */
movq %r4,-(%sp) /* push callframe saved FP & PC */
movq %r2,-(%sp) /* push callframe status & saved AP */
pushl $0 /* push condition handler */
movl %fp,%r1 /* restore r1 */
movl %sp,%fp /* sp == fp now */
#if 1
jmp 2(%r0) /* jump past entry mask */
#else
/*
* More correct but IV/DV are never set so ignore doing this for now.
*/
movpsl -(%sp) /* push PSL */
clrb (%sp) /* clear user flags */
jbc $14,(%r0),24f /* IV need to be set? */
bisb2 $0x20,(%sp) /* yes, set it. */
24: jbc $15,(%r0),25f /* DV need to be set? */
bisb2 $0x80,(%sp) /* yes, set it. */
25: pushab 2(%r0) /* push address of first instruction */
rei /* and go to it (updating PSW) */
#endif
/*
* Count how many registers are being used for callg.
*/
27: movl $0x32212110,%r3 /* bit counts */
extzv $6,$3,%r1,%r2 /* extract bits 6-8 */
ashl $2,%r2,%r2 /* shift by 2 */
extzv %r2,$4,%r3,%r4 /* extract count */
extzv $9,$3,%r1,%r2 /* extract bits 9-11 */
ashl $2,%r2,%r2 /* shift by 2 */
extzv %r2,$4,%r3,%r5 /* extract count */
movq 4(%fp),%r2 /* fetch callframe status & saved AP */
insv %r1,$16,$12,%r2 /* update save mask */
addl3 %r4,%r5,%r1 /* add counts and discard them */
movq 12(%fp),%r4 /* fetch callframe saved FP & PC */
moval 20(%fp)[%r1],%sp/* pop callframe */
extzv $16,$12,%r2,%r1 /* get save mask back */
jbr 22b /* now build the new callframe */
30:
calls $0,_C_LABEL(_rtld_die)
#else
/*
* Check to see if called via call? $n,w^off(reg)
*/
20: addl2 $2,%r1 /* 16-bit displacement */
bicb3 $1,(%r1),%r2 /* fetch opcode of instruction */
cmpb $0xfa,%r2 /* is it calls/callg */
jneq 30f /* no it isn't */
bicb3 $0x1f,2(%r1),%r3/* extract addressing mode */
cmpb $0xc0,%r3 /* 16-bit displacement? */
jeql 11b /* yes, redo the call */
halt
/*
* Check to see if called via call? $n,b^off(reg)
*/
30: incl %r1 /* 8-bit displacement */
bicb3 $1,(%r1),%r2 /* fetch opcode of instruction */
cmpb $0xfa,%r2 /* is it calls/callg */
jneq 40f /* no it isn't */
bicb3 $0x1f,2(%r1),%r3/* extract addressing mode */
cmpb $0xa0,%r3 /* 8-bit displacement? */
jeql 11b /* yes, redo the call */
halt
/*
* Check to see if called via call? $n,(reg)
*/
40: incl %r1 /* no displacement */
bicb3 $1,(%r1),%r2 /* fetch opcode of instruction */
cmpb $0xfa,%r2 /* is it calls/callg */
jeql 41f /* yes it is */
halt /* no, die die die */
41: bicb3 $0x0f,2(%r1),%r2/* extract addressing mode */
bicb3 $0xf0,2(%r1),%r3/* extract register */
extzv $0,$12,6(%fp),%r4/* extract saved mask */
cmpb $0x60,%r2 /* register deferred? */
jeql 42f /* yes, deal with it */
cmpb $0x90,%r2 /* autoincrement deferred? */
jeql 70f /* yes, deal with it */
halt /* no, die die die */
42: cmpw %r4,$0xffc /* did we save r2-r11? */
jneq 50f /* no, deal with it */
jbc %r3,%r4,43f /* is the register in the saved mask? */
/*
* We saved r2-r11, so it's easy to replace the saved register with
* the right value by indexing into saved register (offset by 8).
*/
movl %r0,(20-8)(%fp)[%r3] /* replace address in saved registers */
jbr 11b /* go back and redo call */
/*
* Must have been called via r0 or r1 which are saved locally.
* So move the routine address in the appropriate slot on the stack.
*/
43: movl %r0,(%sp)[%r3]
jbr 11b /* go back and redo call */
50: jbs %r3,%r4,60f /* is the register in the saved mask? */
jbs %r3,$0x3f,43b /* is it r0-r5? */
/*
* The register used for the call was not saved so we need to move
* the new function address into it so the re-call will use the new
* address.
*/
pushl %r0 /* save function address on the stack */
ashl %r5,$1,%r0 /* create a bitmask for the register */
popr %r0 /* pop it off the stack. */
jbr 11b /* and redo the call */
60: clrl %r2 /* starting offset into saved registers */
clrl %r5 /* start with register 0 */
61: cmpl %r2,%r3 /* is the register to save? */
jneq 62f /* no, advance to next */
movl %r0,20(%fp)[%r5]/* yes, save return address in saved reg */
jbr 11b /* and return the call */
62: jbc %r5,%r4,63f /* is this register saved? */
incl %r5 /* yes, account for it */
63: incl %r2 /* increment register number */
jbr 61b /* and loop */
70: cmpb %r3,$12
blss 71f
halt
71: cmpw %r4,$0xffc /* did we save r2-r11? */
jneq 72f /* no, deal with it */
subl2 $4,(20-8)(%fp)[%r3] /* backup incremented register */
jbr 11b /* and redo the call.
72: jbs %r3,%r4,80f
jbs %r3,%3f,74f
ashl %r5,$1,%r0 /* create a bitmask for the register */
pushr %r0 /* pop it off the stack. */
subl2 $4,(%sp) /* backup incremented register */
popr %r0 /* pop it off the stack. */
jbr 11b /* and redo the call.
73: subl2 %4,(%sp)[%r3] /* backup incremented register */
jbr 11b /* and redo the call.
80: clrl %r2 /* starting offset into saved registers */
clrl %r5 /* start with register 0 */
81: cmpl %r2,%r3 /* is the register to save? */
jneq 82f /* no, advance to next */
subl $4,20(%fp)[%r5] /* yes, backup incremented register */
jbr 11b /* and return the call */
82: jbc %r5,%r4,83f /* is this register saved? */
incl %r5 /* yes, account for it */
83: incl %r2 /* increment register number */
jbr 81b /* and loop */
#endif
END(_rtld_bind_start)
|