8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / cmd / sgs / rtld / sparc / boot_elf.s
blobf20470e84f7a38de395b880c72d25caf7815df40
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
23 * Copyright (c) 1988 AT&T
24 * All Rights Reserved
26 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
27 * Use is subject to license terms.
29 #pragma ident "%Z%%M% %I% %E% SMI"
31 #include <link.h>
32 #include "machdep.h"
33 #include "_audit.h"
35 #if defined(lint)
36 #include <sys/types.h>
37 #include "_rtld.h"
38 #else
39 #include <sys/stack.h>
40 #include <sys/asm_linkage.h>
42 .file "boot_elf.s"
43 .seg ".text"
44 #endif
47 * We got here because the initial call to a function resolved to a procedure
48 * linkage table entry. That entry did a branch to the first PLT entry, which
49 * in turn did a call to elf_rtbndr (refer elf_plt_init()).
51 * the code sequence that got us here was:
53 * PLT entry for foo():
54 * sethi (.-PLT0), %g1 ! not changed by rtld
55 * ba,a .PLT0 ! patched atomically 2nd
56 * nop ! patched first
58 * Therefore on entry, %i7 has the address of the call, which will be added
59 * to the offset to the plt entry in %g1 to calculate the plt entry address
60 * we must also subtract 4 because the address of PLT0 points to the
61 * save instruction before the call.
63 * the plt entry is rewritten:
65 * PLT entry for foo():
66 * sethi (.-PLT0), %g1
67 * sethi %hi(entry_pt), %g1
68 * jmpl %g1 + %lo(entry_pt), %g0
71 #if defined(lint)
73 extern unsigned long elf_bndr(Rt_map *, unsigned long, caddr_t);
75 static void
76 elf_rtbndr(Rt_map *lmp, unsigned long pltoff, caddr_t from)
78 (void) elf_bndr(lmp, pltoff, from);
82 #else
83 .weak _elf_rtbndr ! keep dbx happy as it likes to
84 _elf_rtbndr = elf_rtbndr ! rummage around for our symbols
86 .global elf_rtbndr
87 .type elf_rtbndr, #function
88 .align 4
90 elf_rtbndr:
91 mov %i7, %o0 ! Save callers address(profiling)
92 save %sp, -SA(MINFRAME), %sp ! Make a frame
93 srl %g1, 10, %o1 ! shift offset set by sethi
94 ! %o1 has offset from jump slot
95 ! to PLT0 which will be used to
96 ! calculate plt relocation entry
97 ! by elf_bndr
98 ld [%i7 + 8], %o0 ! %o0 has ptr to lm
99 call elf_bndr ! returns function address in %o0
100 mov %i0, %o2 ! Callers address is arg 3
101 mov %o0, %g1 ! save address of routine binded
102 restore ! how many restores needed ? 2
103 jmp %g1 ! jump to it
104 restore
105 .size elf_rtbndr, . - elf_rtbndr
107 #endif
110 #if defined(lint)
111 void
112 iflush_range(caddr_t addr, size_t len)
114 /* LINTED */
115 uintptr_t base;
117 base = (uintptr_t)addr & ~7; /* round down to 8 byte alignment */
118 len = (len + 7) & ~7; /* round up to multiple of 8 bytes */
119 for (len -= 8; (long)len >= 0; len -= 8)
120 /* iflush(base + len) */;
122 #else
123 ENTRY(iflush_range)
124 add %o1, 7, %o1
125 andn %o0, 7, %o0
126 andn %o1, 7, %o1
127 1: subcc %o1, 8, %o1
128 bge,a 1b
129 iflush %o0 + %o1
130 retl
132 SET_SIZE(iflush_range)
133 #endif
136 * Initialize the first plt entry so that function calls go to elf_rtbndr
138 * The first plt entry (PLT0) is:
140 * save %sp, -64, %sp
141 * call elf_rtbndr
142 * nop
143 * address of lm
146 #if defined(lint)
148 void
149 elf_plt_init(void *plt, caddr_t lmp)
151 *((uint_t *)plt + 0) = (unsigned long) M_SAVESP64;
152 *((uint_t *)plt + 4) = M_CALL | (((unsigned long)elf_rtbndr -
153 ((unsigned long)plt)) >> 2);
154 *((uint_t *)plt + 8) = M_NOP;
155 *((uint_t *)plt + 12) = (unsigned long) lmp;
158 #else
159 .global elf_plt_init
160 .type elf_plt_init, #function
161 .align 4
163 elf_plt_init:
164 save %sp, -SA(MINFRAME), %sp ! Make a frame
166 call 2f
167 sethi %hi((_GLOBAL_OFFSET_TABLE_ - (1b - .))), %l7
169 sethi %hi(M_SAVESP64), %o0 ! Get save instruction
170 or %o0, %lo(M_SAVESP64), %o0
171 or %l7, %lo((_GLOBAL_OFFSET_TABLE_ - (1b - .))), %l7
172 st %o0, [%i0] ! Store in plt[0]
173 iflush %i0
174 add %l7, %o7, %l7
175 ld [%l7 + elf_rtbndr], %l7
176 inc 4, %i0 ! Bump plt to point to plt[1]
177 sub %l7, %i0, %o0 ! Determine -pc so as to produce
178 ! offset from plt[1]
179 srl %o0, 2, %o0 ! Express offset as number of words
180 sethi %hi(M_CALL), %o4 ! Get sethi instruction
181 or %o4, %o0, %o4 ! Add elf_rtbndr address
182 st %o4, [%i0] ! Store instruction in plt
183 iflush %i0
184 sethi %hi(M_NOP), %o0 ! Generate nop instruction
185 st %o0, [%i0 + 4] ! Store instruction in plt[2]
186 iflush %i0 + 4
187 st %i1, [%i0 + 8] ! Store instruction in plt[3]
188 iflush %i0 + 8
190 restore
191 .size elf_plt_init, . - elf_plt_init
192 #endif
194 #if defined(lint)
196 ulong_t
197 elf_plt_trace()
199 return (0);
201 #else
202 .global elf_plt_trace
203 .type elf_plt_trace, #function
204 .align 4
207 * The dyn_plt that called us has already created a stack-frame for
208 * us and placed the following entries in it:
210 * [%fp - 0x4] * dyndata
211 * [%fp - 0x8] * prev stack size
213 * dyndata currently contains:
215 * dyndata:
216 * 0x0 uintptr_t *reflmp
217 * 0x4 uintptr_t *deflmp
218 * 0x8 ulong_t symndx
219 * 0xc ulong_t sb_flags
220 * 0x10 Sym symdef.st_name
221 * 0x14 symdef.st_value
222 * 0x18 symdef.st_size
223 * 0x1c symdef.st_info
224 * 0x1d symdef.st_other
225 * 0x1e symdef.st_shndx
227 #define REFLMP_OFF 0x0
228 #define DEFLMP_OFF 0x4
229 #define SYMNDX_OFF 0x8
230 #define SBFLAGS_OFF 0xc
231 #define SYMDEF_OFF 0x10
232 #define SYMDEF_VALUE_OFF 0x14
234 elf_plt_trace:
235 1: call 2f
236 sethi %hi(_GLOBAL_OFFSET_TABLE_+(.-1b)), %l7
237 2: or %l7, %lo(_GLOBAL_OFFSET_TABLE_+(.-1b)), %l7
238 add %l7, %o7, %l7
240 ld [%l7+audit_flags], %l3
241 ld [%l3], %l3 ! %l3 = audit_flags
242 andcc %l3, AF_PLTENTER, %g0
243 beq .end_pltenter
244 ld [%fp + -0x4], %l1 ! l1 = * dyndata
245 ld [%l1 + SBFLAGS_OFF], %l2 ! l2 = sb_flags
246 andcc %l2, LA_SYMB_NOPLTENTER, %g0
247 beq .start_pltenter
248 ld [%l1 + SYMDEF_VALUE_OFF], %l0 ! l0 =
249 ! sym.st_value(calling address)
250 ba .end_pltenter
254 * save all registers into La_sparcv8_regs
256 .start_pltenter:
257 sub %sp, 0x20, %sp ! create space for La_sparcv8_regs
258 ! storage on the stack.
260 sub %fp, 0x28, %o4
262 st %i0, [%o4]
263 st %i1, [%o4 + 0x4]
264 st %i2, [%o4 + 0x8]
265 st %i3, [%o4 + 0xc] ! because a regwindow shift has
266 st %i4, [%o4 + 0x10] ! already occured our current %i*
267 st %i5, [%o4 + 0x14] ! register's are the equivalent of
268 st %i6, [%o4 + 0x18] ! the %o* registers that the final
269 st %i7, [%o4 + 0x1c] ! procedure shall see.
271 ld [%fp + -0x4], %l1 ! %l1 == * dyndata
272 ld [%l1 + REFLMP_OFF], %o0 ! %o0 = reflmp
273 ld [%l1 + DEFLMP_OFF], %o1 ! %o1 = deflmp
274 add %l1, SYMDEF_OFF, %o2 ! %o2 = symp
275 ld [%l1 + SYMNDX_OFF], %o3 ! %o3 = symndx
276 call audit_pltenter
277 add %l1, SBFLAGS_OFF, %o5 ! %o3 = * sb_flags
279 mov %o0, %l0 ! %l0 == calling address
281 add %sp, 0x20, %sp ! cleanup La_sparcv8_regs off
282 ! of the stack.
284 .end_pltenter:
286 * If *no* la_pltexit() routines exist we do not need to keep the
287 * stack frame before we call the actual routine. Instead we jump to
288 * it and remove our self from the stack at the same time.
290 ld [%l7+audit_flags], %l3
291 ld [%l3], %l3 ! %l3 = audit_flags
292 andcc %l3, AF_PLTEXIT, %g0
293 beq .bypass_pltexit
294 ld [%fp + -0x4], %l1 ! %l1 = * dyndata
295 ld [%l1 + SBFLAGS_OFF], %l2 ! %l2 = sb_flags
296 andcc %l2, LA_SYMB_NOPLTEXIT, %g0
297 bne .bypass_pltexit
300 ba .start_pltexit
302 .bypass_pltexit:
303 jmpl %l0, %g0
304 restore
306 .start_pltexit:
308 * In order to call la_pltexit() we must duplicate the
309 * arguments from the 'callers' stack on our stack frame.
311 * First we check the size of the callers stack and grow
312 * our stack to hold any of the arguments. That need
313 * duplicating (these are arguments 6->N), because the
314 * first 6 (0->5) are passed via register windows on sparc.
318 * The first calculation is to determine how large the
319 * argument passing area might be. Since there is no
320 * way to distinquish between 'argument passing' and
321 * 'local storage' from the previous stack this amount must
322 * cover both.
324 ld [%fp + -0x8], %l1 ! %l1 = callers stack size
325 sub %l1, 0x58, %l1 ! %l1 = argument space on caller's
326 ! stack
328 * Next we compare the prev. stack size against the audit_argcnt.
329 * We copy at most 'audit_argcnt' arguments.
331 * NOTE: on sparc we always copy at least six args since these
332 * are in reg-windows and not on the stack.
334 * NOTE: Also note that we multiply (shift really) the arg count
335 * by 4 which is the 'word size' to calculate the amount
336 * of stack space needed.
338 ld [%l7 + audit_argcnt], %l2
339 ld [%l2], %l2 ! %l2 = audit_arg_count
340 cmp %l2, 6
341 ble .grow_stack
342 sub %l2, 6, %l2
343 sll %l2, 2, %l2
344 cmp %l1, %l2
345 ble .grow_stack
347 mov %l2, %l1
348 .grow_stack:
350 * When duplicating the stack we skip the first '0x5c' bytes.
351 * This is the space on the stack reserved for preserving
352 * the register windows and such and do not need to be duplicated
353 * on this new stack frame. We start duplicating at the
354 * portion of the stack reserved for argument's above 6.
356 sub %sp, %l1, %sp ! grow our stack by amount required.
357 sra %l1, 0x2, %l1 ! %l1 = %l1 / 4 (words to copy)
358 mov 0x5c, %l2 ! %l2 = index into stack & frame
361 cmp %l1, 0
362 ble 2f
364 ld [%fp + %l2], %l3 ! duplicate args from previous
365 st %l3, [%sp + %l2] ! stack onto current stack
366 add %l2, 0x4, %l2
367 ba 1b
368 sub %l1, 0x1, %l1
370 mov %i0, %o0 ! copy ins to outs
371 mov %i1, %o1
372 mov %i2, %o2
373 mov %i3, %o3
374 mov %i4, %o4
375 call %l0 ! call routine
376 mov %i5, %o5
377 mov %o1, %l2 ! l2 = second 1/2 of return value
378 ! for those those 64 bit operations
379 ! link div64 - yuck...
381 ! %o0 = retval
382 ld [%fp + -0x4], %l1
383 ld [%l1 + REFLMP_OFF], %o1 ! %o1 = reflmp
384 ld [%l1 + DEFLMP_OFF], %o2 ! %o2 = deflmp
385 add %l1, SYMDEF_OFF, %o3 ! %o3 = symp
386 call audit_pltexit
387 ld [%l1 + SYMNDX_OFF], %o4 ! %o4 = symndx
389 mov %o0, %i0 ! pass on return code
390 mov %l2, %i1
392 restore
393 .size elf_plt_trace, . - elf_plt_trace
395 #endif
398 * After the first call to a plt, elf_bndr() will have determined the true
399 * address of the function being bound. The plt is now rewritten so that
400 * any subsequent calls go directly to the bound function. If the library
401 * to which the function belongs is being profiled refer to _plt_cg_write.
403 * the new plt entry is:
405 * sethi (.-PLT0), %g1 ! constant
406 * sethi %hi(function address), %g1 ! patched second
407 * jmpl %g1 + %lo(function address, %g0 ! patched first
410 #if defined(lint)
412 void
413 plt_full_range(uintptr_t pc, uintptr_t symval)
415 uint_t * plttab = (uint_t *)pc;
416 plttab[2] = (M_JMPL | ((unsigned long)symval & S_MASK(10)));
417 plttab[1] = (M_SETHIG1 | ((unsigned long)symval >> (32 - 22)));
420 #else
421 ENTRY(plt_full_range)
423 sethi %hi(M_JMPL), %o3 ! Get jmpl instruction
424 and %o1, 0x3ff, %o2 ! Lower part of function address
425 or %o3, %o2, %o3 ! is or'ed into instruction
426 st %o3, [%o0 + 8] ! Store instruction in plt[2]
427 iflush %o0 + 8
428 stbar
430 srl %o1, 10, %o1 ! Get high part of function address
431 sethi %hi(M_SETHIG1), %o3 ! Get sethi instruction
432 or %o3, %o1, %o3 ! Add sethi and function address
433 st %o3, [%o0 + 4] ! Store instruction in plt[1]
434 retl
435 iflush %o0 + 4
437 SET_SIZE(plt_full_range)
439 #endif /* defined(lint) */