xref: /onnv-gate/usr/src/cmd/sgs/rtld/i386/boot_elf.s (revision 0:68f95e015346)
1*0Sstevel@tonic-gate/*
2*0Sstevel@tonic-gate * CDDL HEADER START
3*0Sstevel@tonic-gate *
4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate * with the License.
8*0Sstevel@tonic-gate *
9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate * and limitations under the License.
13*0Sstevel@tonic-gate *
14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate *
20*0Sstevel@tonic-gate * CDDL HEADER END
21*0Sstevel@tonic-gate */
22*0Sstevel@tonic-gate/*
23*0Sstevel@tonic-gate *	Copyright (c) 1988 AT&T
24*0Sstevel@tonic-gate *	  All Rights Reserved
25*0Sstevel@tonic-gate *
26*0Sstevel@tonic-gate *
27*0Sstevel@tonic-gate *	Copyright 2000-2002 Sun Microsystems, Inc.  All rights reserved.
28*0Sstevel@tonic-gate *	Use is subject to license terms.
29*0Sstevel@tonic-gate */
30*0Sstevel@tonic-gate#pragma ident	"%Z%%M%	%I%	%E% SMI"
31*0Sstevel@tonic-gate
32*0Sstevel@tonic-gate#if	defined(lint)
33*0Sstevel@tonic-gate
34*0Sstevel@tonic-gate#include	<sys/types.h>
35*0Sstevel@tonic-gate#include	"_rtld.h"
36*0Sstevel@tonic-gate#include	"_audit.h"
37*0Sstevel@tonic-gate#include	"_elf.h"
38*0Sstevel@tonic-gate
39*0Sstevel@tonic-gate/* ARGSUSED0 */
40*0Sstevel@tonic-gateint
41*0Sstevel@tonic-gateelf_plt_trace()
42*0Sstevel@tonic-gate{
43*0Sstevel@tonic-gate	return (0);
44*0Sstevel@tonic-gate}
45*0Sstevel@tonic-gate#else
46*0Sstevel@tonic-gate
47*0Sstevel@tonic-gate#include	<link.h>
48*0Sstevel@tonic-gate#include	"_audit.h"
49*0Sstevel@tonic-gate
50*0Sstevel@tonic-gate	.file	"boot_elf.s"
51*0Sstevel@tonic-gate	.text
52*0Sstevel@tonic-gate
53*0Sstevel@tonic-gate/*
54*0Sstevel@tonic-gate * On entry the 'glue code' has already  done the following:
55*0Sstevel@tonic-gate *
56*0Sstevel@tonic-gate *	pushl	%ebp
57*0Sstevel@tonic-gate *	movl	%esp, %ebp
58*0Sstevel@tonic-gate *	pushl	dyndata_ptr
59*0Sstevel@tonic-gate *	jmp	elf_plt_trace
60*0Sstevel@tonic-gate *
61*0Sstevel@tonic-gate * so - -4(%ebp) contains the dyndata ptr
62*0Sstevel@tonic-gate *
63*0Sstevel@tonic-gate *	0x0	uintptr_t	reflmp
64*0Sstevel@tonic-gate *	0x4	uintptr_t	deflmp
65*0Sstevel@tonic-gate *	0x8	ulong_t		symndx
66*0Sstevel@tonic-gate *	0xc	ulont_t		sb_flags
67*0Sstevel@tonic-gate *	0x10	Elf32_Sym	symdef.st_name
68*0Sstevel@tonic-gate *	0x14			symdef.st_value
69*0Sstevel@tonic-gate *	0x18			symdef.st_size
70*0Sstevel@tonic-gate *	0x1c			symdef.st_info
71*0Sstevel@tonic-gate *	0x1d			symdef.st_other
72*0Sstevel@tonic-gate *	0x1e			symdef.st_shndx
73*0Sstevel@tonic-gate */
74*0Sstevel@tonic-gate#define	REFLMP_OFF		0x0
75*0Sstevel@tonic-gate#define	DEFLMP_OFF		0x4
76*0Sstevel@tonic-gate#define	SYMNDX_OFF		0x8
77*0Sstevel@tonic-gate#define	SBFLAGS_OFF		0xc
78*0Sstevel@tonic-gate#define	SYMDEF_OFF		0x10
79*0Sstevel@tonic-gate#define	SYMDEF_VALUE_OFF	0x14
80*0Sstevel@tonic-gate
81*0Sstevel@tonic-gate	.globl	elf_plt_trace
82*0Sstevel@tonic-gate	.type	elf_plt_trace,@function
83*0Sstevel@tonic-gate	.align 16
84*0Sstevel@tonic-gateelf_plt_trace:
85*0Sstevel@tonic-gate	subl	$84,%esp			/ create some local storage
86*0Sstevel@tonic-gate	pushl	%eax
87*0Sstevel@tonic-gate	pushl	%ebx
88*0Sstevel@tonic-gate	pushl	%edi
89*0Sstevel@tonic-gate	pushl	%esi
90*0Sstevel@tonic-gate	call	.L1				/ initialize %ebx to GOT
91*0Sstevel@tonic-gate.L1:
92*0Sstevel@tonic-gate	popl	%ebx
93*0Sstevel@tonic-gate	addl	$_GLOBAL_OFFSET_TABLE_+[.-.L1], %ebx
94*0Sstevel@tonic-gate	/*
95*0Sstevel@tonic-gate	 * Local stack space storage is allocated as follows:
96*0Sstevel@tonic-gate	 *
97*0Sstevel@tonic-gate	 *	-4(%ebp)	store dyndata ptr
98*0Sstevel@tonic-gate	 *	-8(%ebp)	store call destination
99*0Sstevel@tonic-gate	 *	-84(%ebp)	space for gregset
100*0Sstevel@tonic-gate	 *	-88(%ebp)	prev stack size
101*0Sstevel@tonic-gate	 *	-92(%ebp)	entering %eax
102*0Sstevel@tonic-gate	 *	-96(%ebp)	entering %ebx
103*0Sstevel@tonic-gate	 *	-100(%ebp)	entering %edi
104*0Sstevel@tonic-gate	 *	-104(%ebp)	entering %esi
105*0Sstevel@tonic-gate	 */
106*0Sstevel@tonic-gate	movl	-4(%ebp), %eax			/ %eax = dyndata
107*0Sstevel@tonic-gate	testb	$LA_SYMB_NOPLTENTER, 0xc(%eax)	/ <link.h>
108*0Sstevel@tonic-gate	je	.start_pltenter
109*0Sstevel@tonic-gate	movl	SYMDEF_VALUE_OFF(%eax), %edi
110*0Sstevel@tonic-gate	movl	%edi, -8(%ebp)			/ save destination address
111*0Sstevel@tonic-gate	jmp	.end_pltenter
112*0Sstevel@tonic-gate
113*0Sstevel@tonic-gate.start_pltenter:
114*0Sstevel@tonic-gate	/*
115*0Sstevel@tonic-gate	 * save all registers into gregset_t
116*0Sstevel@tonic-gate	 */
117*0Sstevel@tonic-gate	lea	4(%ebp), %edi
118*0Sstevel@tonic-gate	movl	%edi, -84(%ebp)		/ %esp
119*0Sstevel@tonic-gate	movl	0(%ebp), %edi
120*0Sstevel@tonic-gate	movl	%edi, -80(%ebp)		/ %ebp
121*0Sstevel@tonic-gate	/*
122*0Sstevel@tonic-gate	 * trapno, err, eip, cs, efl, uesp, ss
123*0Sstevel@tonic-gate	 */
124*0Sstevel@tonic-gate	movl	-4(%ebp), %edi
125*0Sstevel@tonic-gate	lea	SBFLAGS_OFF(%edi), %eax
126*0Sstevel@tonic-gate	pushl	%eax				/ arg5 (&sb_flags)
127*0Sstevel@tonic-gate	lea	-84(%ebp), %eax
128*0Sstevel@tonic-gate	pushl	%eax				/ arg4 (regset)
129*0Sstevel@tonic-gate	pushl	SYMNDX_OFF(%edi)		/ arg3 (symndx)
130*0Sstevel@tonic-gate	lea	SYMDEF_OFF(%edi), %eax
131*0Sstevel@tonic-gate	pushl	%eax				/ arg2 (&sym)
132*0Sstevel@tonic-gate	pushl	DEFLMP_OFF(%edi)		/ arg1 (dlmp)
133*0Sstevel@tonic-gate	pushl	REFLMP_OFF(%edi)		/ arg0 (rlmp)
134*0Sstevel@tonic-gate	call	audit_pltenter@PLT
135*0Sstevel@tonic-gate	addl	$24, %esp			/ cleanup stack
136*0Sstevel@tonic-gate	movl	%eax, -8(%ebp)			/ save calling address
137*0Sstevel@tonic-gate.end_pltenter:
138*0Sstevel@tonic-gate
139*0Sstevel@tonic-gate	/*
140*0Sstevel@tonic-gate	 * If *no* la_pltexit() routines exist
141*0Sstevel@tonic-gate	 * we do not need to keep the stack frame
142*0Sstevel@tonic-gate	 * before we call the actual routine.  Instead we
143*0Sstevel@tonic-gate	 * jump to it and remove our stack from the stack
144*0Sstevel@tonic-gate	 * at the same time.
145*0Sstevel@tonic-gate	 */
146*0Sstevel@tonic-gate	movl	audit_flags@GOT(%ebx), %eax
147*0Sstevel@tonic-gate	movl	(%eax), %eax
148*0Sstevel@tonic-gate	andl	$AF_PLTEXIT, %eax		/ value of audit.h:AF_PLTEXIT
149*0Sstevel@tonic-gate	cmpl	$0, %eax
150*0Sstevel@tonic-gate	je	.bypass_pltexit
151*0Sstevel@tonic-gate	/*
152*0Sstevel@tonic-gate	 * Has the *nopltexit* flag been set for this entry point
153*0Sstevel@tonic-gate	 */
154*0Sstevel@tonic-gate	testb	$LA_SYMB_NOPLTEXIT, 12(%edi)
155*0Sstevel@tonic-gate	je	.start_pltexit
156*0Sstevel@tonic-gate
157*0Sstevel@tonic-gate.bypass_pltexit:
158*0Sstevel@tonic-gate	/*
159*0Sstevel@tonic-gate	 * No PLTEXIT processing required.
160*0Sstevel@tonic-gate	 */
161*0Sstevel@tonic-gate	movl	0(%ebp), %eax
162*0Sstevel@tonic-gate	movl	%eax, -4(%ebp)
163*0Sstevel@tonic-gate	movl	-8(%ebp), %eax			/ eax == calling destination
164*0Sstevel@tonic-gate	movl	%eax, 0(%ebp)			/ store destination at top
165*0Sstevel@tonic-gate
166*0Sstevel@tonic-gate	popl	%esi				/
167*0Sstevel@tonic-gate	popl	%edi				/    clean up stack
168*0Sstevel@tonic-gate	popl	%ebx				/
169*0Sstevel@tonic-gate	popl	%eax				/
170*0Sstevel@tonic-gate	subl	$4, %ebp			/ adjust %ebp for 'ret'
171*0Sstevel@tonic-gate	/*
172*0Sstevel@tonic-gate	 * At this point, after a little doctoring, we should
173*0Sstevel@tonic-gate	 * have the following on the stack:
174*0Sstevel@tonic-gate	 *
175*0Sstevel@tonic-gate	 *	8(%esp):  ret addr
176*0Sstevel@tonic-gate	 *	4(%esp):  dest_addr
177*0Sstevel@tonic-gate	 *	0(%esp):  Previous %ebp
178*0Sstevel@tonic-gate	 *
179*0Sstevel@tonic-gate	 * So - we pop the previous %ebp, and then
180*0Sstevel@tonic-gate	 * ret to our final destination.
181*0Sstevel@tonic-gate	 */
182*0Sstevel@tonic-gate	movl	%ebp, %esp			/
183*0Sstevel@tonic-gate	popl	%ebp				/
184*0Sstevel@tonic-gate	ret					/ jmp to final destination
185*0Sstevel@tonic-gate						/ and clean up stack :)
186*0Sstevel@tonic-gate
187*0Sstevel@tonic-gate.start_pltexit:
188*0Sstevel@tonic-gate
189*0Sstevel@tonic-gate	/*
190*0Sstevel@tonic-gate	 * In order to call the destination procedure and then return
191*0Sstevel@tonic-gate	 * to audit_pltexit() for post analysis we must first grow
192*0Sstevel@tonic-gate	 * our stack frame and then duplicate the original callers
193*0Sstevel@tonic-gate	 * stack state.  This duplicates all of the arguements
194*0Sstevel@tonic-gate	 * that were to be passed to the destination procedure.
195*0Sstevel@tonic-gate	 */
196*0Sstevel@tonic-gate	movl	%ebp, %edi			/
197*0Sstevel@tonic-gate	addl	$8, %edi			/    %edi = src
198*0Sstevel@tonic-gate	movl	(%ebp), %edx			/
199*0Sstevel@tonic-gate	subl	%edi, %edx			/    %edx == prev frame sz
200*0Sstevel@tonic-gate	/*
201*0Sstevel@tonic-gate	 * If audit_argcnt > 0 then we limit the number of
202*0Sstevel@tonic-gate	 * arguements that will be duplicated to audit_argcnt.
203*0Sstevel@tonic-gate	 *
204*0Sstevel@tonic-gate	 * If (prev_stack_size > (audit_argcnt * 4))
205*0Sstevel@tonic-gate	 *	prev_stack_size = audit_argcnt * 4;
206*0Sstevel@tonic-gate	 */
207*0Sstevel@tonic-gate	movl	audit_argcnt@GOT(%ebx),%eax
208*0Sstevel@tonic-gate	movl	(%eax), %eax			/    %eax = audit_argcnt
209*0Sstevel@tonic-gate	cmpl	$0, %eax
210*0Sstevel@tonic-gate	jle	.grow_stack
211*0Sstevel@tonic-gate	lea	(,%eax,4), %eax			/    %eax = %eax * 4
212*0Sstevel@tonic-gate	cmpl	%eax,%edx
213*0Sstevel@tonic-gate	jle	.grow_stack
214*0Sstevel@tonic-gate	movl	%eax, %edx
215*0Sstevel@tonic-gate	/*
216*0Sstevel@tonic-gate	 * Grow the stack and duplicate the arguements of the
217*0Sstevel@tonic-gate	 * original caller.
218*0Sstevel@tonic-gate	 */
219*0Sstevel@tonic-gate.grow_stack:
220*0Sstevel@tonic-gate	subl	%edx, %esp			/    grow the stack
221*0Sstevel@tonic-gate	movl	%edx, -88(%ebp)			/    -88(%ebp) == prev frame sz
222*0Sstevel@tonic-gate	movl	%esp, %ecx			/    %ecx = dest
223*0Sstevel@tonic-gate	addl	%ecx, %edx			/    %edx == tail of dest
224*0Sstevel@tonic-gate.while_base:
225*0Sstevel@tonic-gate	cmpl	%edx, %ecx			/   while (base+size >= src++) {
226*0Sstevel@tonic-gate	jge	.end_while				/
227*0Sstevel@tonic-gate	movl	(%edi), %esi
228*0Sstevel@tonic-gate	movl	%esi,(%ecx)			/        *dest = *src
229*0Sstevel@tonic-gate	addl	$4, %edi			/	 src++
230*0Sstevel@tonic-gate	addl	$4, %ecx			/        dest++
231*0Sstevel@tonic-gate	jmp	.while_base			/    }
232*0Sstevel@tonic-gate
233*0Sstevel@tonic-gate	/*
234*0Sstevel@tonic-gate	 * The above stack is now an exact duplicate of
235*0Sstevel@tonic-gate	 * the stack of the original calling procedure.
236*0Sstevel@tonic-gate	 */
237*0Sstevel@tonic-gate.end_while:
238*0Sstevel@tonic-gate	movl	-92(%ebp), %eax			/ restore %eax
239*0Sstevel@tonic-gate	movl	-96(%ebp), %ebx			/ restore %ebx
240*0Sstevel@tonic-gate	movl	-104(%ebp), %esi		/ restore %esi
241*0Sstevel@tonic-gate
242*0Sstevel@tonic-gate	movl	-8(%ebp), %edi
243*0Sstevel@tonic-gate	call	*%edi				/ call dest_proc()
244*0Sstevel@tonic-gate
245*0Sstevel@tonic-gate	addl	-88(%ebp), %esp			/ cleanup dupped stack
246*0Sstevel@tonic-gate
247*0Sstevel@tonic-gate	movl	-4(%ebp), %edi
248*0Sstevel@tonic-gate	pushl	SYMNDX_OFF(%edi)		/ arg4 (symndx)
249*0Sstevel@tonic-gate	lea	SYMDEF_OFF(%edi), %ecx
250*0Sstevel@tonic-gate	pushl	%ecx				/ arg3 (symp)
251*0Sstevel@tonic-gate	pushl	DEFLMP_OFF(%edi)		/ arg2 (dlmp)
252*0Sstevel@tonic-gate	pushl	REFLMP_OFF(%edi)		/ arg1 (rlmp)
253*0Sstevel@tonic-gate	pushl	%eax				/ arg0 (retval)
254*0Sstevel@tonic-gate	call	audit_pltexit@PLT
255*0Sstevel@tonic-gate	addl	$20, %esp			/ cleanup stack
256*0Sstevel@tonic-gate
257*0Sstevel@tonic-gate	/*
258*0Sstevel@tonic-gate	 * Clean up after ourselves and return to the
259*0Sstevel@tonic-gate	 * original calling procedure.
260*0Sstevel@tonic-gate	 */
261*0Sstevel@tonic-gate	popl	%esi				/
262*0Sstevel@tonic-gate	popl	%edi				/ clean up stack
263*0Sstevel@tonic-gate	popl	%ebx				/
264*0Sstevel@tonic-gate	movl	%ebp, %esp			/
265*0Sstevel@tonic-gate	popl	%ebp				/
266*0Sstevel@tonic-gate	ret					/ return to caller
267*0Sstevel@tonic-gate	.size	elf_plt_trace, .-elf_plt_trace
268*0Sstevel@tonic-gate#endif
269*0Sstevel@tonic-gate
270*0Sstevel@tonic-gate/*
271*0Sstevel@tonic-gate * We got here because a call to a function resolved to a procedure
272*0Sstevel@tonic-gate * linkage table entry.  That entry did a JMPL to the first PLT entry, which
273*0Sstevel@tonic-gate * in turn did a call to elf_rtbndr.
274*0Sstevel@tonic-gate *
275*0Sstevel@tonic-gate * the code sequence that got us here was:
276*0Sstevel@tonic-gate *
277*0Sstevel@tonic-gate * PLT entry for foo:
278*0Sstevel@tonic-gate *	jmp	*name1@GOT(%ebx)
279*0Sstevel@tonic-gate *	pushl	$rel.plt.foo
280*0Sstevel@tonic-gate *	jmp	PLT0
281*0Sstevel@tonic-gate *
282*0Sstevel@tonic-gate * 1st PLT entry (PLT0):
283*0Sstevel@tonic-gate *	pushl	4(%ebx)
284*0Sstevel@tonic-gate *	jmp	*8(%ebx)
285*0Sstevel@tonic-gate *	nop; nop; nop;nop;
286*0Sstevel@tonic-gate *
287*0Sstevel@tonic-gate */
288*0Sstevel@tonic-gate#if defined(lint)
289*0Sstevel@tonic-gate
290*0Sstevel@tonic-gateextern unsigned long	elf_bndr(Rt_map *, unsigned long, caddr_t);
291*0Sstevel@tonic-gate
292*0Sstevel@tonic-gatevoid
293*0Sstevel@tonic-gateelf_rtbndr(Rt_map * lmp, unsigned long reloc, caddr_t pc)
294*0Sstevel@tonic-gate{
295*0Sstevel@tonic-gate	(void) elf_bndr(lmp, reloc, pc);
296*0Sstevel@tonic-gate}
297*0Sstevel@tonic-gate
298*0Sstevel@tonic-gate#else
299*0Sstevel@tonic-gate	.globl	elf_bndr
300*0Sstevel@tonic-gate	.globl	elf_rtbndr
301*0Sstevel@tonic-gate	.weak	_elf_rtbndr
302*0Sstevel@tonic-gate	_elf_rtbndr = elf_rtbndr	/ Make dbx happy
303*0Sstevel@tonic-gate	.type   elf_rtbndr,@function
304*0Sstevel@tonic-gate	.align	4
305*0Sstevel@tonic-gate
306*0Sstevel@tonic-gateelf_rtbndr:
307*0Sstevel@tonic-gate	pushl	%ebp
308*0Sstevel@tonic-gate	movl	%esp, %ebp
309*0Sstevel@tonic-gate	pushl	%eax
310*0Sstevel@tonic-gate	pushl	%ecx
311*0Sstevel@tonic-gate	pushl	%edx
312*0Sstevel@tonic-gate	pushl	12(%ebp)		/ push pc
313*0Sstevel@tonic-gate	pushl	8(%ebp)			/ push reloc
314*0Sstevel@tonic-gate	pushl	4(%ebp)			/ push *lmp
315*0Sstevel@tonic-gate	call	elf_bndr@PLT		/ call the C binder code
316*0Sstevel@tonic-gate	addl	$12, %esp		/ pop args
317*0Sstevel@tonic-gate	movl	%eax, 8(%ebp)		/ store final destination
318*0Sstevel@tonic-gate	popl	%edx
319*0Sstevel@tonic-gate	popl	%ecx
320*0Sstevel@tonic-gate	popl	%eax
321*0Sstevel@tonic-gate	movl	%ebp, %esp
322*0Sstevel@tonic-gate	popl	%ebp
323*0Sstevel@tonic-gate	addl	$4,%esp			/ pop args
324*0Sstevel@tonic-gate	ret				/ invoke resolved function
325*0Sstevel@tonic-gate	.size 	elf_rtbndr, .-elf_rtbndr
326*0Sstevel@tonic-gate#endif
327