#include "machdep.h"
#include "_audit.h"
#if defined(lint)
#include <sys/types.h>
#include "_rtld.h"
#else
#include <sys/stack.h>
#include <sys/asm_linkage.h>
.file "boot_elf.s"
.seg ".text"
#endif
#if defined(lint)
extern unsigned long elf_bndr(Rt_map *, unsigned long, caddr_t);
void
elf_rtbndr(Rt_map *lmp, unsigned long pltoff, caddr_t from)
{
(void) elf_bndr(lmp, pltoff, from);
}
#else
.weak _elf_rtbndr ! keep dbx happy as it likes to
_elf_rtbndr = elf_rtbndr ! rummage around for our symbols
ENTRY(elf_rtbndr)
mov %i7, %o3 ! Save callers address(profiling)
save %sp, -SA(MINFRAME), %sp
mov %g4, %l5 ! Save g4 (safe across function calls)
sub %i1, 0x38, %o1 ! compute addr of .PLT0 from addr of .PLT1 jmpl
ldx [%o1 + 0x40], %o0 ! ld PLT2[X] into third arg
srl %i0, 10, %o1 ! shift offset set by sethi
call elf_bndr ! returns function address in %o0
mov %i3, %o2 ! Callers address is arg 3
mov %o0, %g1 ! save address of routine binded
mov %l5, %g4 ! restore g4
restore ! how many restores needed ? 2
jmp %g1 ! jump to it
restore
SET_SIZE(elf_rtbndr)
#endif
#if defined(lint)
void
elf_rtbndr_far(Rt_map *lmp, unsigned long pltoff, caddr_t from)
{
(void) elf_bndr(lmp, pltoff, from);
}
#else
ENTRY(elf_rtbndr_far)
mov %i7, %o3 ! Save callers address
save %sp, -SA(MINFRAME), %sp
mov %g4, %l5 ! preserve %g4
sub %i1, 0x18, %o2 ! compute address of .PLT0 from
! .PLT0 jmpl instr.
sub %i0, %o2, %o1 ! pltoff = pc - 0x10 - .PLT0
sub %o1, 0x10, %o1
ldx [%o2 + 0x40], %o0 ! ld PLT2[X] into third arg
call elf_bndr ! returns function address in %o0
mov %i3, %o2 ! Callers address is arg3
mov %o0, %g1 ! save address of routine binded
mov %l5, %g4 ! restore g4
restore ! how many restores needed ? 2
jmp %g1 ! jump to it
restore
SET_SIZE(elf_rtbndr_far)
#endif
#define M_SAVE_SP176SP 0x9de3bf50
#define M_SETHI_L0 0x21000000
#define M_SETHI_L1 0x23000000
#define M_OR_L0L0 0xa0142000
#define M_SLLX_L032L0 0xa12c3020
#define M_OR_L0L1L0 0xa0140011
#define M_JMPL_L0O1 0x93c42000
#define M_MOV_G1O0 0x90100001
#if defined(lint)
#define HH22(x) 0
#define LM22(x) 0
#define HM10(x) 0
#define LO10(x) 0
void
elf_plt_init(void *plt, caddr_t bindfunc)
{
uint_t *_plt;
_plt = (uint_t *)plt;
_plt[0] = M_SAVE_SP176SP;
_plt[1] = M_SETHI_L0 | HH22(bindfunc);
_plt[2] = M_SETHI_L1 | LM22(bindfunc);
_plt[3] = M_OR_L0L0 | HM10(bindfunc);
_plt[4] = M_SLLX_L032L0;
_plt[5] = M_OR_L0L1L0;
_plt[6] = M_JMPL_L0O1 | LO10(bindfunc);
_plt[7] = M_MOV_G1O0;
}
#else
ENTRY(elf_plt_init)
save %sp, -SA(MINFRAME), %sp ! Make a frame
sethi %hi(M_SAVE_SP176SP), %o0 ! Get save instruction
or %o0, %lo(M_SAVE_SP176SP), %o0
st %o0, [%i0] ! Store in plt[0]
sethi %hi(M_SETHI_L0), %o4 ! Get "sethi 0x0, %l0" insn
srlx %i1, 42, %o2 ! get %hh(function address)
or %o4, %o2, %o4 ! or value into instruction
st %o4, [%i0 + 0x4] ! Store instruction in plt[1]
iflush %i0 ! .. and flush
sethi %hi(M_SETHI_L1), %o4 ! Get "sethi 0x0, %l1" insn
srl %i1, 10, %o2 ! get %lm(function address)
or %o4, %o2, %o4 ! or value into instruction
st %o4, [%i0 + 0x8] ! Store instruction in plt[2]
sethi %hi(M_OR_L0L0), %o4 ! Get "or %l0, 0x0, %l0" insn
or %o4, %lo(M_OR_L0L0), %o4
srlx %i1, 32, %o2 ! get %hm(function address)
and %o2, 0x3ff, %o2 ! pick out bits 42-33
or %o4, %o2, %o4 ! or value into instruction
st %o4, [%i0 + 0xc] ! Store instruction in plt[3]
iflush %i0 + 8 ! .. and flush
sethi %hi(M_SLLX_L032L0), %o4 ! get "sllx %l0, 32, %l0" insn
or %o4, %lo(M_SLLX_L032L0), %o4
st %o4, [%i0 + 0x10] ! Store instruction in plt[4]
sethi %hi(M_OR_L0L1L0), %o4 ! get "or %l0, %l1, %l0" insn
or %o4, %lo(M_OR_L0L1L0), %o4
st %o4, [%i0 + 0x14] ! Store instruction in plt[5]
iflush %i0 + 0x10 ! .. and flush
sethi %hi(M_JMPL_L0O1), %o4 ! get "jmpl %l0 + 0, %o1" insn
or %o4, %lo(M_JMPL_L0O1), %o4
and %i1, 0x3ff, %o2 ! get %lo(function address)
or %o4, %o2, %o4 ! or value into instruction
st %o4, [%i0 + 0x18] ! Store instruction in plt[6]
sethi %hi(M_MOV_G1O0), %o4 ! get "mov %g1, %o0" insn
or %o4, %lo(M_MOV_G1O0), %o4
st %o4, [%i0 + 0x1c] ! Store instruction in plt[7]
iflush %i0 + 0x18 ! .. and flush
ret
restore
SET_SIZE(elf_plt_init)
#endif
#if defined(lint)
void
elf_plt2_init(unsigned int *plt2, Rt_map * lmp)
{
*(unsigned long *)plt2 = (unsigned long)lmp;
}
#else
ENTRY(elf_plt2_init)
stx %o1, [%o0]
retl
iflush %o0
SET_SIZE(elf_plt2_init)
#endif
#define M_JMPL_G5G0 0x81c16000
#define M_OR_G1G5G5 0x8a104005
#define M_SLLX_G132G1 0x83287020
#define M_OR_G1G1 0x82106000
#define M_SETHI_G5 0x0b000000
#define M_SETHI_G1 0x03000000
#define M_NOP 0x01000000
#define M_JMPL_G1G0 0x81c06000
#define M_SLLX_G112G1 0x8328700c
#define M_XNOR_G5G1 0x82396000
#if defined(lint)
#define MASK(m) ((1ul << (m)) - 1ul)
#define BITS(v, u, l) (((v) >> (l)) & MASK((u) - (l) + 1))
#define H44(v) BITS(v, 43, 22)
#define M44(v) BITS(v, 21, 12)
#define L44(v) BITS(v, 11, 0)
#endif
#if defined(lint)
void
plt_upper_32(uintptr_t pc, uintptr_t symval)
{
ulong_t sym = (ulong_t)symval;
ulong_t nsym = ~sym;
uint_t * plttab = (uint_t *)pc;
plttab[3] = M_JMPL_G1G0;
plttab[2] = (uint_t)(M_XNOR_G5G1 | LO10(nsym));
*(ulong_t *)pc =
((ulong_t)M_NOP << 32) | (M_SETHI_G5 | LM22(nsym));
}
#else
ENTRY(plt_upper_32)
!
! Address lies in top 32-bits of address space, so use
! compact PLT sequence
!
sethi %hi(M_JMPL_G1G0), %o3 ! Get "jmpl %g1, %g0" insn
st %o3, [%o0 + 0xc] ! store instruction in plt[3]
iflush %o0 + 0xc ! .. and flush
not %o1, %o4
sethi %hi(M_XNOR_G5G1), %o3 ! Get "xnor %g5, %g1, %g1" insn
and %o4, 0x3ff, %o2 ! pick out bits 0-9
or %o3, %o2, %o3 ! or value into instruction
st %o3, [%o0 + 0x8] ! store instruction in plt[2]
iflush %o0 + 0x8 ! .. and flush
sethi %hi(M_SETHI_G5), %o3 ! Get "sethi 0x0, %g5" insn
srl %o4, 10, %o2 ! get %lm(~function address)
or %o3, %o2, %o3 ! or value into instruction
sethi %hi(M_NOP), %o4 ! Get "nop" instruction
sllx %o4, 32, %o4 ! shift to top of instruction pair
or %o3, %o4, %o3 ! or value into instruction pair
stx %o3, [%o0] ! store instructions into plt[0] plt[1]
retl
iflush %o0 ! .. and flush
SET_SIZE(plt_upper_32)
#endif
#if defined(lint)
void
plt_upper_44(uintptr_t pc, uintptr_t symval)
{
ulong_t sym = (ulong_t)symval;
ulong_t nsym = ~sym;
uint_t * plttab = (uint_t *)pc;
plttab[4] = (uint_t)(M_JMPL_G1G0 | L44(sym));
plttab[3] = M_SLLX_G112G1;
plttab[2] = (uint_t)(M_XNOR_G5G1 | M44(nsym));
*(ulong_t *)pc = ((ulong_t)M_NOP << 32) | (M_SETHI_G5 | H44(nsym));
}
#else
ENTRY(plt_upper_44)
!
! Address lies in top 44-bits of address space, so use
! compact PLT sequence
!
setuw M_JMPL_G1G0, %o3 ! Get "jmpl %g1, %g0" insn
and %o1, 0xfff, %o2 ! lower 12 bits of function address
or %o3, %o2, %o3 ! is or'ed into instruction
st %o3, [%o0 + 0x10] ! store instruction in plt[4]
iflush %o0 + 0x10 ! .. and flush
setuw M_SLLX_G112G1, %o3 ! Get "sllx %g1, 12, %g1" insn
st %o3, [%o0 + 0xc] ! store instruction in plt[3]
not %o1, %o4
setuw M_XNOR_G5G1, %o3 ! Get "xnor %g5, 0, %g1" insn
srlx %o4, 12, %o2 ! get %m44(0 - function address)
and %o2, 0x3ff, %o2 ! pick out bits 21-12
or %o3, %o2, %o3 ! or value into instruction
st %o3, [%o0 + 8] ! store instruction in plt[2]
iflush %o0 + 8 ! .. and flush
setuw M_SETHI_G5, %o3 ! Get "sethi 0x0, %g5" insn
srlx %o4, 22, %o2 ! get %h44(0 - function address)
or %o3, %o2, %o3 ! or value into instruction
setuw M_NOP, %o4 ! Get "nop" instruction
sllx %o4, 32, %o4 ! shift to top of instruction pair
or %o3, %o4, %o3 ! or value into instruction pair
stx %o3, [%o0] ! store instructions into plt[0] plt[1]
retl
iflush %o0 ! .. and flush
SET_SIZE(plt_upper_44)
#endif
#if defined(lint)
void
plt_full_range(uintptr_t pc, uintptr_t symval)
{
uint_t * plttab = (uint_t *)pc;
plttab[6] = M_JMPL_G5G0 | LO10(symval);
plttab[5] = M_OR_G1G5G5;
plttab[4] = M_SLLX_G132G1;
plttab[3] = M_OR_G1G1 | HM10(symval);
plttab[2] = M_SETHI_G5 | LM22(symval);
*(ulong_t *)pc =
((ulong_t)M_NOP << 32) | (M_SETHI_G1 | HH22(symval));
}
#else
ENTRY(plt_full_range)
!
! Address lies anywhere in 64-bit address space, so use
! full PLT sequence
!
sethi %hi(M_JMPL_G5G0), %o3 ! Get "jmpl %g5, %g0" insn
and %o1, 0x3ff, %o2 ! lower 10 bits of function address
or %o3, %o2, %o3 ! is or'ed into instruction
st %o3, [%o0 + 0x18] ! store instruction in plt[6]
iflush %o0 + 0x18 ! .. and flush
sethi %hi(M_OR_G1G5G5), %o3 ! Get "or %g1, %g5, %g1" insn
or %o3, %lo(M_OR_G1G5G5), %o3
st %o3, [%o0 + 0x14] ! store instruction in plt[5]
sethi %hi(M_SLLX_G132G1), %o3 ! Get "sllx %g1, 32, %g1" insn
or %o3, %lo(M_SLLX_G132G1), %o3
st %o3, [%o0 + 0x10] ! store instruction in plt[4]
iflush %o0 + 0x10 ! .. and flush
sethi %hi(M_OR_G1G1), %o3 ! Get "or %g1, 0x0, %g1" insn
or %o3, %lo(M_OR_G1G1), %o3
srlx %o1, 32, %o2 ! get %hm(function address)
and %o2, 0x3ff, %o2 ! pick out bits 42-33
or %o3, %o2, %o3 ! or value into instruction
st %o3, [%o0 + 0xc] ! store instruction in plt[3]
sethi %hi(M_SETHI_G5), %o3 ! Get "sethi 0x0, %g5" insn
srl %o1, 10, %o2 ! get %lm(function address)
or %o3, %o2, %o3 ! or value into instruction
st %o3, [%o0 + 0x8] ! store instruction in plt[2]
iflush %o0 + 8 ! .. and flush
sethi %hi(M_SETHI_G1), %o3 ! Get "sethi 0x0, %g1" insn
srlx %o1, 42, %o2 ! get %hh(function address)
or %o3, %o2, %o3 ! or value into instruction
sethi %hi(M_NOP), %o4 ! Get "nop" instruction
sllx %o4, 32, %o4 ! shift to top of instruction pair
or %o3, %o4, %o3 ! or value into instruction pair
stx %o3, [%o0] ! store instructions into plt[0] plt[1]
retl
iflush %o0 ! .. and flush
SET_SIZE(plt_full_range)
#endif
#if defined(lint)
void
iflush_range(caddr_t addr, size_t len)
{
uintptr_t base;
base = (uintptr_t)addr & ~7;
len = (len + 7) & ~7;
for (len -= 8; (long)len >= 0; len -= 8)
;
}
#else
ENTRY(iflush_range)
add %o1, 7, %o1
andn %o0, 7, %o0
andn %o1, 7, %o1
1: subcc %o1, 8, %o1
bge,a,pt %xcc, 1b
iflush %o0 + %o1
retl
nop
SET_SIZE(iflush_range)
#endif
#if defined(lint)
ulong_t
elf_plt_trace()
{
return (0);
}
#else
.global elf_plt_trace
.type elf_plt_trace, #function
#define REFLMP_OFF 0x0
#define DEFLMP_OFF 0x8
#define SYMNDX_OFF 0x10
#define SBFLAGS_OFF 0x14
#define SYMDEF_OFF 0x18
#define SYMDEF_VALUE_OFF 0x20
#define LAREGSSZ 0x40
elf_plt_trace:
1: call 2f
sethi %hi(_GLOBAL_OFFSET_TABLE_ - (1b - .)), %l7
2: or %l7, %lo(_GLOBAL_OFFSET_TABLE_ - (1b - .)), %l7
add %l7, %o7, %l7
ldx [%fp + STACK_BIAS + -CLONGSIZE], %l1 ! l1 = * dyndata
lduw [%l1 + SBFLAGS_OFF], %l2 ! l2 = sb_flags
andcc %l2, LA_SYMB_NOPLTENTER, %g0
be,pt %icc, .start_pltenter
ldx [%l1 + SYMDEF_VALUE_OFF], %l0 ! l0 =
! sym.st_value(calling address)
ba,a,pt %icc, .end_pltenter
nop
.start_pltenter:
sub %sp, LAREGSSZ, %sp ! create space for La_sparcv9_regs
! storage on the stack.
add %fp, STACK_BIAS - (LAREGSSZ + (2 * CLONGSIZE)), %o4 ! addr of new space.
stx %i0, [%o4 + 0x0]
stx %i1, [%o4 + 0x8]
stx %i2, [%o4 + 0x10]
stx %i3, [%o4 + 0x18] ! because a regwindow shift has
stx %i4, [%o4 + 0x20] ! already occured our current %i*
stx %i5, [%o4 + 0x28] ! register's are the equivalent of
stx %i6, [%o4 + 0x30] ! the %o* registers that the final
stx %i7, [%o4 + 0x38] ! procedure shall see.
mov %g4, %l5 ! save g4 (safe across function calls)
ldx [%fp + STACK_BIAS + -CLONGSIZE], %l1 ! %l1 == * dyndata
ldx [%l1 + REFLMP_OFF], %o0 ! %o0 = reflmp
ldx [%l1 + DEFLMP_OFF], %o1 ! %o1 = deflmp
add %l1, SYMDEF_OFF, %o2 ! %o2 = symp
lduw [%l1 + SYMNDX_OFF], %o3 ! %o3 = symndx
call audit_pltenter
add %l1, SBFLAGS_OFF, %o5 ! %o3 = * sb_flags
mov %o0, %l0 ! %l0 == calling address
add %sp, LAREGSSZ, %sp ! cleanup La_sparcv9_regs off
! of the stack.
.end_pltenter:
ldx [%l7+audit_flags], %l3
lduw [%l3], %l3 ! %l3 = audit_flags
andcc %l3, AF_PLTEXIT, %g0 ! AF_PLTEXIT = 2
be,pt %icc, .bypass_pltexit
ldx [%fp + STACK_BIAS + -CLONGSIZE], %l1 ! %l1 = * dyndata
lduw [%l1 + SBFLAGS_OFF], %l2 ! %l2 = sb_flags
andcc %l2, LA_SYMB_NOPLTEXIT, %g0 ! LA_SYMB_NOPLTEXIT = 2
bne,a,pt %icc, .bypass_pltexit
nop
ba,a,pt %icc, .start_pltexit
nop
.bypass_pltexit:
mov %l5, %g4 ! restore g4
jmpl %l0, %g0
restore
.start_pltexit:
ldx [%fp + STACK_BIAS + -(2 * CLONGSIZE)], %l1 ! %l1 = callers
! stack size
sub %l1, MINFRAME, %l1 ! %l1 = argument space on
! caller's stack
ldx [%l7 + audit_argcnt], %l2
lduw [%l2], %l2 ! %l2 = audit_argcnt
cmp %l2, 6
ble,pn %icc, .grow_stack
sub %l2, 6, %l2
sllx %l2, CLONGSHIFT, %l2 ! arg count * 8
cmp %l1, %l2 !
ble,a,pn %icc, .grow_stack
nop
mov %l2, %l1
.grow_stack:
sub %sp, %l1, %sp ! grow our stack by amount required.
srax %l1, CLONGSHIFT, %l1 ! %l1 = %l1 / 8 (words to copy)
mov SA(MINFRAME), %l2 ! %l2 = index into stack & frame
1:
cmp %l1, 0
ble,a,pn %icc, 2f
nop
add %fp, %l2, %l4
ldx [%l4 + STACK_BIAS], %l3 ! duplicate args from previous
add %sp, %l2, %l4
stx %l3, [%l4 + STACK_BIAS] ! stack onto current stack
add %l2, CLONGSIZE, %l2
ba,pt %icc, 1b
sub %l1, 0x1, %l1
2:
mov %i0, %o0 ! copy ins to outs
mov %i1, %o1
mov %i2, %o2
mov %i3, %o3
mov %i4, %o4
mov %i5, %o5
call %l0 ! call original routine
mov %l5, %g4 ! restore g4
mov %o1, %l2 ! l2 = second 1/2 of return value
! for those those 64 bit operations
! link div64 - yuck...
! %o0 = retval
ldx [%fp + STACK_BIAS + -CLONGSIZE], %l1
ldx [%l1 + REFLMP_OFF], %o1 ! %o1 = reflmp
ldx [%l1 + DEFLMP_OFF], %o2 ! %o2 = deflmp
add %l1, SYMDEF_OFF, %o3 ! %o3 = symp
call audit_pltexit
lduw [%l1 + SYMNDX_OFF], %o4 ! %o4 = symndx
mov %o0, %i0 ! pass on return code
mov %l2, %i1
ret
restore
.size elf_plt_trace, . - elf_plt_trace
#endif