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