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