boot_elf.s revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright (c) 1988 AT&T
* All Rights Reserved
*
*
* Copyright 2000-2002 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#if defined(lint)
#include <sys/types.h>
#include "_rtld.h"
#include "_audit.h"
#include "_elf.h"
/* ARGSUSED0 */
int
elf_plt_trace()
{
return (0);
}
#else
#include <link.h>
#include "_audit.h"
.file "boot_elf.s"
.text
/*
* On entry the 'glue code' has already done the following:
*
* pushl %ebp
* movl %esp, %ebp
* pushl dyndata_ptr
* jmp elf_plt_trace
*
* so - -4(%ebp) contains the dyndata ptr
*
* 0x0 uintptr_t reflmp
* 0x4 uintptr_t deflmp
* 0x8 ulong_t symndx
* 0xc ulont_t sb_flags
* 0x10 Elf32_Sym symdef.st_name
* 0x14 symdef.st_value
* 0x18 symdef.st_size
* 0x1c symdef.st_info
* 0x1d symdef.st_other
* 0x1e symdef.st_shndx
*/
#define REFLMP_OFF 0x0
#define DEFLMP_OFF 0x4
#define SYMNDX_OFF 0x8
#define SBFLAGS_OFF 0xc
#define SYMDEF_OFF 0x10
#define SYMDEF_VALUE_OFF 0x14
.globl elf_plt_trace
.type elf_plt_trace,@function
.align 16
elf_plt_trace:
subl $84,%esp / create some local storage
pushl %eax
pushl %ebx
pushl %edi
pushl %esi
call .L1 / initialize %ebx to GOT
.L1:
popl %ebx
addl $_GLOBAL_OFFSET_TABLE_+[.-.L1], %ebx
/*
* Local stack space storage is allocated as follows:
*
* -4(%ebp) store dyndata ptr
* -8(%ebp) store call destination
* -84(%ebp) space for gregset
* -88(%ebp) prev stack size
* -92(%ebp) entering %eax
* -96(%ebp) entering %ebx
* -100(%ebp) entering %edi
* -104(%ebp) entering %esi
*/
movl -4(%ebp), %eax / %eax = dyndata
testb $LA_SYMB_NOPLTENTER, 0xc(%eax) / <link.h>
je .start_pltenter
movl SYMDEF_VALUE_OFF(%eax), %edi
movl %edi, -8(%ebp) / save destination address
jmp .end_pltenter
.start_pltenter:
/*
* save all registers into gregset_t
*/
lea 4(%ebp), %edi
movl %edi, -84(%ebp) / %esp
movl 0(%ebp), %edi
movl %edi, -80(%ebp) / %ebp
/*
* trapno, err, eip, cs, efl, uesp, ss
*/
movl -4(%ebp), %edi
lea SBFLAGS_OFF(%edi), %eax
pushl %eax / arg5 (&sb_flags)
lea -84(%ebp), %eax
pushl %eax / arg4 (regset)
pushl SYMNDX_OFF(%edi) / arg3 (symndx)
lea SYMDEF_OFF(%edi), %eax
pushl %eax / arg2 (&sym)
pushl DEFLMP_OFF(%edi) / arg1 (dlmp)
pushl REFLMP_OFF(%edi) / arg0 (rlmp)
call audit_pltenter@PLT
addl $24, %esp / cleanup stack
movl %eax, -8(%ebp) / save calling address
.end_pltenter:
/*
* If *no* la_pltexit() routines exist
* we do not need to keep the stack frame
* before we call the actual routine. Instead we
* jump to it and remove our stack from the stack
* at the same time.
*/
movl audit_flags@GOT(%ebx), %eax
movl (%eax), %eax
andl $AF_PLTEXIT, %eax / value of audit.h:AF_PLTEXIT
cmpl $0, %eax
je .bypass_pltexit
/*
* Has the *nopltexit* flag been set for this entry point
*/
testb $LA_SYMB_NOPLTEXIT, 12(%edi)
je .start_pltexit
.bypass_pltexit:
/*
* No PLTEXIT processing required.
*/
movl 0(%ebp), %eax
movl %eax, -4(%ebp)
movl -8(%ebp), %eax / eax == calling destination
movl %eax, 0(%ebp) / store destination at top
popl %esi /
popl %edi / clean up stack
popl %ebx /
popl %eax /
subl $4, %ebp / adjust %ebp for 'ret'
/*
* At this point, after a little doctoring, we should
* have the following on the stack:
*
* 8(%esp): ret addr
* 4(%esp): dest_addr
* 0(%esp): Previous %ebp
*
* So - we pop the previous %ebp, and then
* ret to our final destination.
*/
movl %ebp, %esp /
popl %ebp /
ret / jmp to final destination
/ and clean up stack :)
.start_pltexit:
/*
* In order to call the destination procedure and then return
* to audit_pltexit() for post analysis we must first grow
* our stack frame and then duplicate the original callers
* stack state. This duplicates all of the arguements
* that were to be passed to the destination procedure.
*/
movl %ebp, %edi /
addl $8, %edi / %edi = src
movl (%ebp), %edx /
subl %edi, %edx / %edx == prev frame sz
/*
* If audit_argcnt > 0 then we limit the number of
* arguements that will be duplicated to audit_argcnt.
*
* If (prev_stack_size > (audit_argcnt * 4))
* prev_stack_size = audit_argcnt * 4;
*/
movl audit_argcnt@GOT(%ebx),%eax
movl (%eax), %eax / %eax = audit_argcnt
cmpl $0, %eax
jle .grow_stack
lea (,%eax,4), %eax / %eax = %eax * 4
cmpl %eax,%edx
jle .grow_stack
movl %eax, %edx
/*
* Grow the stack and duplicate the arguements of the
* original caller.
*/
.grow_stack:
subl %edx, %esp / grow the stack
movl %edx, -88(%ebp) / -88(%ebp) == prev frame sz
movl %esp, %ecx / %ecx = dest
addl %ecx, %edx / %edx == tail of dest
.while_base:
cmpl %edx, %ecx / while (base+size >= src++) {
jge .end_while /
movl (%edi), %esi
movl %esi,(%ecx) / *dest = *src
addl $4, %edi / src++
addl $4, %ecx / dest++
jmp .while_base / }
/*
* The above stack is now an exact duplicate of
* the stack of the original calling procedure.
*/
.end_while:
movl -92(%ebp), %eax / restore %eax
movl -96(%ebp), %ebx / restore %ebx
movl -104(%ebp), %esi / restore %esi
movl -8(%ebp), %edi
call *%edi / call dest_proc()
addl -88(%ebp), %esp / cleanup dupped stack
movl -4(%ebp), %edi
pushl SYMNDX_OFF(%edi) / arg4 (symndx)
lea SYMDEF_OFF(%edi), %ecx
pushl %ecx / arg3 (symp)
pushl DEFLMP_OFF(%edi) / arg2 (dlmp)
pushl REFLMP_OFF(%edi) / arg1 (rlmp)
pushl %eax / arg0 (retval)
call audit_pltexit@PLT
addl $20, %esp / cleanup stack
/*
* Clean up after ourselves and return to the
* original calling procedure.
*/
popl %esi /
popl %edi / clean up stack
popl %ebx /
movl %ebp, %esp /
popl %ebp /
ret / return to caller
.size elf_plt_trace, .-elf_plt_trace
#endif
/*
* We got here because a call to a function resolved to a procedure
* linkage table entry. That entry did a JMPL to the first PLT entry, which
* in turn did a call to elf_rtbndr.
*
* the code sequence that got us here was:
*
* PLT entry for foo:
* jmp *name1@GOT(%ebx)
* pushl $rel.plt.foo
* jmp PLT0
*
* 1st PLT entry (PLT0):
* pushl 4(%ebx)
* jmp *8(%ebx)
* nop; nop; nop;nop;
*
*/
#if defined(lint)
extern unsigned long elf_bndr(Rt_map *, unsigned long, caddr_t);
void
elf_rtbndr(Rt_map * lmp, unsigned long reloc, caddr_t pc)
{
(void) elf_bndr(lmp, reloc, pc);
}
#else
.globl elf_bndr
.globl elf_rtbndr
.weak _elf_rtbndr
_elf_rtbndr = elf_rtbndr / Make dbx happy
.type elf_rtbndr,@function
.align 4
elf_rtbndr:
pushl %ebp
movl %esp, %ebp
pushl %eax
pushl %ecx
pushl %edx
pushl 12(%ebp) / push pc
pushl 8(%ebp) / push reloc
pushl 4(%ebp) / push *lmp
call elf_bndr@PLT / call the C binder code
addl $12, %esp / pop args
movl %eax, 8(%ebp) / store final destination
popl %edx
popl %ecx
popl %eax
movl %ebp, %esp
popl %ebp
addl $4,%esp / pop args
ret / invoke resolved function
.size elf_rtbndr, .-elf_rtbndr
#endif