10Sstevel@tonic-gate/* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*4832Srie * Common Development and Distribution License (the "License"). 6*4832Srie * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 21*4832Srie 220Sstevel@tonic-gate/* 230Sstevel@tonic-gate * Copyright (c) 1988 AT&T 240Sstevel@tonic-gate * All Rights Reserved 250Sstevel@tonic-gate * 26*4832Srie * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 27*4832Srie * Use is subject to license terms. 280Sstevel@tonic-gate */ 290Sstevel@tonic-gate#pragma ident "%Z%%M% %I% %E% SMI" 300Sstevel@tonic-gate 310Sstevel@tonic-gate#include "machdep.h" 320Sstevel@tonic-gate#include "_audit.h" 330Sstevel@tonic-gate#if defined(lint) 340Sstevel@tonic-gate#include <sys/types.h> 350Sstevel@tonic-gate#include "_rtld.h" 360Sstevel@tonic-gate#else 370Sstevel@tonic-gate#include <sys/stack.h> 380Sstevel@tonic-gate#include <sys/asm_linkage.h> 390Sstevel@tonic-gate 40*4832Srie .file "boot_elf.s" 410Sstevel@tonic-gate .seg ".text" 420Sstevel@tonic-gate#endif 430Sstevel@tonic-gate 440Sstevel@tonic-gate/* 450Sstevel@tonic-gate * We got here because the initial call to a function resolved to a procedure 460Sstevel@tonic-gate * linkage table entry. That entry did a branch to the first PLT entry, which 470Sstevel@tonic-gate * in turn did a call to elf_rtbndr (refer elf_plt_init()). 480Sstevel@tonic-gate * 490Sstevel@tonic-gate * the code sequence that got us here was: 500Sstevel@tonic-gate * 510Sstevel@tonic-gate * PLT entry for foo(): 520Sstevel@tonic-gate * sethi (.-PLT0), %g1 530Sstevel@tonic-gate * ba,a .PLT0 ! patched atomically 2nd 540Sstevel@tonic-gate * nop ! patched 1st 550Sstevel@tonic-gate * nop 560Sstevel@tonic-gate * nop 570Sstevel@tonic-gate * nop 580Sstevel@tonic-gate * nop 590Sstevel@tonic-gate * nop 600Sstevel@tonic-gate * 610Sstevel@tonic-gate * Therefore on entry, %i7 has the address of the call, which will be added 620Sstevel@tonic-gate * to the offset to the plt entry in %g1 to calculate the plt entry address 630Sstevel@tonic-gate * we must also subtract 4 because the address of PLT0 points to the 640Sstevel@tonic-gate * save instruction before the call. 650Sstevel@tonic-gate * 660Sstevel@tonic-gate * The PLT entry is rewritten in one of several ways. For the full 64-bit 670Sstevel@tonic-gate * span, the following sequence is generated: 680Sstevel@tonic-gate * 690Sstevel@tonic-gate * nop 700Sstevel@tonic-gate * sethi %hh(entry_pt), %g1 710Sstevel@tonic-gate * sethi %lm(entry_pt), %g5 720Sstevel@tonic-gate * or %g1, %hm(entry_pt), %g1 730Sstevel@tonic-gate * sllx %g1, 32, %g1 740Sstevel@tonic-gate * or %g1, %g5, %g5 750Sstevel@tonic-gate * jmpl %g5 + %lo(entry_pt), %g0 760Sstevel@tonic-gate * nop 770Sstevel@tonic-gate * 780Sstevel@tonic-gate * Shorter code sequences are possible, depending on reachability 790Sstevel@tonic-gate * constraints. Note that 'call' is not as useful as it might seem in 800Sstevel@tonic-gate * this context, because it is only capable of plus or minus 2Gbyte 810Sstevel@tonic-gate * PC-relative jumps, and the rdpc instruction is very slow. 820Sstevel@tonic-gate * 830Sstevel@tonic-gate * At the time of writing, the present and future SPARC CPUs that will use 840Sstevel@tonic-gate * this code are only capable of addressing the bottom 43-bits and top 43-bits 850Sstevel@tonic-gate * of the address space. And since shared libraries are placed at the top 860Sstevel@tonic-gate * of the address space, the "top 44-bits" sequence will effectively always be 870Sstevel@tonic-gate * used. See elf_plt_write() below. The "top 32-bits" are used when they 880Sstevel@tonic-gate * can reach. 890Sstevel@tonic-gate */ 900Sstevel@tonic-gate 910Sstevel@tonic-gate#if defined(lint) 920Sstevel@tonic-gate 930Sstevel@tonic-gateextern unsigned long elf_bndr(Rt_map *, unsigned long, caddr_t); 940Sstevel@tonic-gate 950Sstevel@tonic-gate/* 960Sstevel@tonic-gate * We're called here from .PLTn in a new frame, with %o0 containing 970Sstevel@tonic-gate * the result of a sethi (. - .PLT0), and %o1 containing the pc of 980Sstevel@tonic-gate * the jmpl instruction we're got here with inside .PLT1 990Sstevel@tonic-gate */ 1000Sstevel@tonic-gatevoid 1010Sstevel@tonic-gateelf_rtbndr(Rt_map *lmp, unsigned long pltoff, caddr_t from) 1020Sstevel@tonic-gate{ 1030Sstevel@tonic-gate (void) elf_bndr(lmp, pltoff, from); 1040Sstevel@tonic-gate} 1050Sstevel@tonic-gate 1060Sstevel@tonic-gate#else 1070Sstevel@tonic-gate .weak _elf_rtbndr ! keep dbx happy as it likes to 1080Sstevel@tonic-gate _elf_rtbndr = elf_rtbndr ! rummage around for our symbols 1090Sstevel@tonic-gate 1100Sstevel@tonic-gate ENTRY(elf_rtbndr) 1110Sstevel@tonic-gate mov %i7, %o3 ! Save callers address(profiling) 1120Sstevel@tonic-gate save %sp, -SA(MINFRAME), %sp 1130Sstevel@tonic-gate mov %g4, %l5 ! Save g4 (safe across function calls) 1140Sstevel@tonic-gate sub %i1, 0x38, %o1 ! compute addr of .PLT0 from addr of .PLT1 jmpl 1150Sstevel@tonic-gate ldx [%o1 + 0x40], %o0 ! ld PLT2[X] into third arg 1160Sstevel@tonic-gate srl %i0, 10, %o1 ! shift offset set by sethi 1170Sstevel@tonic-gate call elf_bndr ! returns function address in %o0 1180Sstevel@tonic-gate mov %i3, %o2 ! Callers address is arg 3 1190Sstevel@tonic-gate mov %o0, %g1 ! save address of routine binded 1200Sstevel@tonic-gate mov %l5, %g4 ! restore g4 1210Sstevel@tonic-gate restore ! how many restores needed ? 2 1220Sstevel@tonic-gate jmp %g1 ! jump to it 1230Sstevel@tonic-gate restore 1240Sstevel@tonic-gate SET_SIZE(elf_rtbndr) 1250Sstevel@tonic-gate 1260Sstevel@tonic-gate#endif 1270Sstevel@tonic-gate 1280Sstevel@tonic-gate 1290Sstevel@tonic-gate#if defined(lint) 1300Sstevel@tonic-gatevoid 1310Sstevel@tonic-gateelf_rtbndr_far(Rt_map *lmp, unsigned long pltoff, caddr_t from) 1320Sstevel@tonic-gate{ 1330Sstevel@tonic-gate (void) elf_bndr(lmp, pltoff, from); 1340Sstevel@tonic-gate} 1350Sstevel@tonic-gate#else 1360Sstevel@tonic-gateENTRY(elf_rtbndr_far) 1370Sstevel@tonic-gate mov %i7, %o3 ! Save callers address 1380Sstevel@tonic-gate save %sp, -SA(MINFRAME), %sp 1390Sstevel@tonic-gate mov %g4, %l5 ! preserve %g4 1400Sstevel@tonic-gate sub %i1, 0x18, %o2 ! compute address of .PLT0 from 1410Sstevel@tonic-gate ! .PLT0 jmpl instr. 1420Sstevel@tonic-gate sub %i0, %o2, %o1 ! pltoff = pc - 0x10 - .PLT0 1430Sstevel@tonic-gate sub %o1, 0x10, %o1 1440Sstevel@tonic-gate ldx [%o2 + 0x40], %o0 ! ld PLT2[X] into third arg 1450Sstevel@tonic-gate call elf_bndr ! returns function address in %o0 1460Sstevel@tonic-gate mov %i3, %o2 ! Callers address is arg3 1470Sstevel@tonic-gate mov %o0, %g1 ! save address of routine binded 1480Sstevel@tonic-gate mov %l5, %g4 ! restore g4 1490Sstevel@tonic-gate restore ! how many restores needed ? 2 1500Sstevel@tonic-gate jmp %g1 ! jump to it 1510Sstevel@tonic-gate restore 1520Sstevel@tonic-gateSET_SIZE(elf_rtbndr_far) 1530Sstevel@tonic-gate#endif 1540Sstevel@tonic-gate 1550Sstevel@tonic-gate 1560Sstevel@tonic-gate/* 1570Sstevel@tonic-gate * Initialize a plt entry so that function calls go to 'bindfunc' 1580Sstevel@tonic-gate * (We parameterize the binding function here because we call this 1590Sstevel@tonic-gate * routine twice - once for PLT0 and once for PLT1 with different 1600Sstevel@tonic-gate * binding functions.) 1610Sstevel@tonic-gate * 1620Sstevel@tonic-gate * The plt entries (PLT0 and PLT1) look like: 1630Sstevel@tonic-gate * 1640Sstevel@tonic-gate * save %sp, -176, %sp 1650Sstevel@tonic-gate * sethi %hh(bindfunc), %l0 1660Sstevel@tonic-gate * sethi %lm(bindfunc), %l1 1670Sstevel@tonic-gate * or %l0, %hm(bindfunc), %l0 1680Sstevel@tonic-gate * sllx %l0, 32, %l0 1690Sstevel@tonic-gate * or %l0, %l1, %l0 1700Sstevel@tonic-gate * jmpl %l0 + %lo(bindfunc), %o1 1710Sstevel@tonic-gate * mov %g1, %o0 1720Sstevel@tonic-gate */ 1730Sstevel@tonic-gate 1740Sstevel@tonic-gate#define M_SAVE_SP176SP 0x9de3bf50 /* save %sp, -176, %sp */ 1750Sstevel@tonic-gate#define M_SETHI_L0 0x21000000 /* sethi 0x0, %l0 */ 1760Sstevel@tonic-gate#define M_SETHI_L1 0x23000000 /* sethi 0x0, %l1 */ 1770Sstevel@tonic-gate#define M_OR_L0L0 0xa0142000 /* or %l0, 0x0, %l0 */ 1780Sstevel@tonic-gate#define M_SLLX_L032L0 0xa12c3020 /* sllx %l0, 32, %l0 */ 1790Sstevel@tonic-gate#define M_OR_L0L1L0 0xa0140011 /* or %l0, %l1, %l0 */ 1800Sstevel@tonic-gate#define M_JMPL_L0O1 0x93c42000 /* jmpl %l0 + 0, %o1 */ 1810Sstevel@tonic-gate#define M_MOV_G1O0 0x90100001 /* or %g0, %g1, %o0 */ 1820Sstevel@tonic-gate 1830Sstevel@tonic-gate#if defined(lint) 1840Sstevel@tonic-gate 1850Sstevel@tonic-gate#define HH22(x) 0 /* for lint's benefit */ 1860Sstevel@tonic-gate#define LM22(x) 0 1870Sstevel@tonic-gate#define HM10(x) 0 1880Sstevel@tonic-gate#define LO10(x) 0 1890Sstevel@tonic-gate 1900Sstevel@tonic-gate/* ARGSUSED */ 1910Sstevel@tonic-gatevoid 1920Sstevel@tonic-gateelf_plt_init(void *plt, caddr_t bindfunc) 1930Sstevel@tonic-gate{ 1940Sstevel@tonic-gate uint_t *_plt; 1950Sstevel@tonic-gate 1960Sstevel@tonic-gate _plt = (uint_t *)plt; 1970Sstevel@tonic-gate _plt[0] = M_SAVE_SP176SP; 1980Sstevel@tonic-gate _plt[1] = M_SETHI_L0 | HH22(bindfunc); 1990Sstevel@tonic-gate _plt[2] = M_SETHI_L1 | LM22(bindfunc); 2000Sstevel@tonic-gate _plt[3] = M_OR_L0L0 | HM10(bindfunc); 2010Sstevel@tonic-gate _plt[4] = M_SLLX_L032L0; 2020Sstevel@tonic-gate _plt[5] = M_OR_L0L1L0; 2030Sstevel@tonic-gate _plt[6] = M_JMPL_L0O1 | LO10(bindfunc); 2040Sstevel@tonic-gate _plt[7] = M_MOV_G1O0; 2050Sstevel@tonic-gate} 2060Sstevel@tonic-gate 2070Sstevel@tonic-gate#else 2080Sstevel@tonic-gate ENTRY(elf_plt_init) 2090Sstevel@tonic-gate save %sp, -SA(MINFRAME), %sp ! Make a frame 2100Sstevel@tonic-gate 2110Sstevel@tonic-gate sethi %hi(M_SAVE_SP176SP), %o0 ! Get save instruction 2120Sstevel@tonic-gate or %o0, %lo(M_SAVE_SP176SP), %o0 2130Sstevel@tonic-gate st %o0, [%i0] ! Store in plt[0] 2140Sstevel@tonic-gate 2150Sstevel@tonic-gate sethi %hi(M_SETHI_L0), %o4 ! Get "sethi 0x0, %l0" insn 2160Sstevel@tonic-gate srlx %i1, 42, %o2 ! get %hh(function address) 2170Sstevel@tonic-gate or %o4, %o2, %o4 ! or value into instruction 2180Sstevel@tonic-gate st %o4, [%i0 + 0x4] ! Store instruction in plt[1] 2190Sstevel@tonic-gate iflush %i0 ! .. and flush 2200Sstevel@tonic-gate 2210Sstevel@tonic-gate sethi %hi(M_SETHI_L1), %o4 ! Get "sethi 0x0, %l1" insn 2220Sstevel@tonic-gate srl %i1, 10, %o2 ! get %lm(function address) 2230Sstevel@tonic-gate or %o4, %o2, %o4 ! or value into instruction 2240Sstevel@tonic-gate st %o4, [%i0 + 0x8] ! Store instruction in plt[2] 2250Sstevel@tonic-gate 2260Sstevel@tonic-gate sethi %hi(M_OR_L0L0), %o4 ! Get "or %l0, 0x0, %l0" insn 2270Sstevel@tonic-gate or %o4, %lo(M_OR_L0L0), %o4 2280Sstevel@tonic-gate srlx %i1, 32, %o2 ! get %hm(function address) 2290Sstevel@tonic-gate and %o2, 0x3ff, %o2 ! pick out bits 42-33 2300Sstevel@tonic-gate or %o4, %o2, %o4 ! or value into instruction 2310Sstevel@tonic-gate st %o4, [%i0 + 0xc] ! Store instruction in plt[3] 2320Sstevel@tonic-gate iflush %i0 + 8 ! .. and flush 2330Sstevel@tonic-gate 2340Sstevel@tonic-gate sethi %hi(M_SLLX_L032L0), %o4 ! get "sllx %l0, 32, %l0" insn 2350Sstevel@tonic-gate or %o4, %lo(M_SLLX_L032L0), %o4 2360Sstevel@tonic-gate st %o4, [%i0 + 0x10] ! Store instruction in plt[4] 2370Sstevel@tonic-gate 2380Sstevel@tonic-gate sethi %hi(M_OR_L0L1L0), %o4 ! get "or %l0, %l1, %l0" insn 2390Sstevel@tonic-gate or %o4, %lo(M_OR_L0L1L0), %o4 2400Sstevel@tonic-gate st %o4, [%i0 + 0x14] ! Store instruction in plt[5] 2410Sstevel@tonic-gate iflush %i0 + 0x10 ! .. and flush 2420Sstevel@tonic-gate 2430Sstevel@tonic-gate sethi %hi(M_JMPL_L0O1), %o4 ! get "jmpl %l0 + 0, %o1" insn 2440Sstevel@tonic-gate or %o4, %lo(M_JMPL_L0O1), %o4 2450Sstevel@tonic-gate and %i1, 0x3ff, %o2 ! get %lo(function address) 2460Sstevel@tonic-gate or %o4, %o2, %o4 ! or value into instruction 2470Sstevel@tonic-gate st %o4, [%i0 + 0x18] ! Store instruction in plt[6] 2480Sstevel@tonic-gate 2490Sstevel@tonic-gate sethi %hi(M_MOV_G1O0), %o4 ! get "mov %g1, %o0" insn 2500Sstevel@tonic-gate or %o4, %lo(M_MOV_G1O0), %o4 2510Sstevel@tonic-gate st %o4, [%i0 + 0x1c] ! Store instruction in plt[7] 2520Sstevel@tonic-gate iflush %i0 + 0x18 ! .. and flush 2530Sstevel@tonic-gate 2540Sstevel@tonic-gate ret 2550Sstevel@tonic-gate restore 2560Sstevel@tonic-gate SET_SIZE(elf_plt_init) 2570Sstevel@tonic-gate#endif 2580Sstevel@tonic-gate 2590Sstevel@tonic-gate 2600Sstevel@tonic-gate 2610Sstevel@tonic-gate 2620Sstevel@tonic-gate#if defined(lint) 2630Sstevel@tonic-gate/* 2640Sstevel@tonic-gate * The V9 ABI assigns the link map identifier, the 2650Sstevel@tonic-gate * Rt_map pointer, to the start of .PLT2. 2660Sstevel@tonic-gate */ 2670Sstevel@tonic-gatevoid 2680Sstevel@tonic-gateelf_plt2_init(unsigned int *plt2, Rt_map * lmp) 2690Sstevel@tonic-gate{ 2700Sstevel@tonic-gate /* LINTED */ 2710Sstevel@tonic-gate *(unsigned long *)plt2 = (unsigned long)lmp; 2720Sstevel@tonic-gate} 2730Sstevel@tonic-gate#else 2740Sstevel@tonic-gate ENTRY(elf_plt2_init) 2750Sstevel@tonic-gate stx %o1, [%o0] 2760Sstevel@tonic-gate retl 2770Sstevel@tonic-gate iflush %o0 2780Sstevel@tonic-gate SET_SIZE(elf_plt2_init) 2790Sstevel@tonic-gate#endif 2800Sstevel@tonic-gate 2810Sstevel@tonic-gate 2820Sstevel@tonic-gate 2830Sstevel@tonic-gate/* 2840Sstevel@tonic-gate * After the first call to a plt, elf_bndr() will have determined the true 2850Sstevel@tonic-gate * address of the function being bound. The plt is now rewritten so that 2860Sstevel@tonic-gate * any subsequent calls go directly to the bound function. If the library 2870Sstevel@tonic-gate * to which the function belongs is being profiled refer to _plt_cg_write. 2880Sstevel@tonic-gate * 2890Sstevel@tonic-gate * For complete 64-bit spanning, the new plt entry is: 2900Sstevel@tonic-gate * 2910Sstevel@tonic-gate * nop 2920Sstevel@tonic-gate * sethi %hh(function address), %g1 2930Sstevel@tonic-gate * sethi %lm(function address), %g5 2940Sstevel@tonic-gate * or %g1, %hm(function address), %g1 2950Sstevel@tonic-gate * sllx %g1, 32, %g1 2960Sstevel@tonic-gate * or %g1, %g5, %g5 2970Sstevel@tonic-gate * jmpl %g5, %lo(function address), %g0 2980Sstevel@tonic-gate * nop 2990Sstevel@tonic-gate * 3000Sstevel@tonic-gate * However, shorter instruction sequences are possible and useful. 3010Sstevel@tonic-gate * This version gets us anywhere in the top 44 bits of the 3020Sstevel@tonic-gate * address space - since this is where shared objects live most 3030Sstevel@tonic-gate * of the time, this case is worth optimizing. 3040Sstevel@tonic-gate * 3050Sstevel@tonic-gate * nop 3060Sstevel@tonic-gate * sethi %h44(~function_address), %g5 3070Sstevel@tonic-gate * xnor %g5, %m44(~function address), %g1 3080Sstevel@tonic-gate * sllx %g1, 12, %g1 3090Sstevel@tonic-gate * jmpl %g1 + %l44(function address), %g0 3100Sstevel@tonic-gate * nop 3110Sstevel@tonic-gate * nop 3120Sstevel@tonic-gate * nop 3130Sstevel@tonic-gate * 3140Sstevel@tonic-gate * This version gets anywhere in the top 32 bits: 3150Sstevel@tonic-gate * 3160Sstevel@tonic-gate * nop 3170Sstevel@tonic-gate * sethi %hi(~function_address), %g5 3180Sstevel@tonic-gate * xnor %g5, %lo(~function_address), %g1 3190Sstevel@tonic-gate * jmpl %g1, %g0 3200Sstevel@tonic-gate * nop 3210Sstevel@tonic-gate * nop 3220Sstevel@tonic-gate * nop 3230Sstevel@tonic-gate * nop 3240Sstevel@tonic-gate * 3250Sstevel@tonic-gate * This version get's us to a destination within 3260Sstevel@tonic-gate * +- 8megs of the PLT's address: 3270Sstevel@tonic-gate * 3280Sstevel@tonic-gate * nop 3290Sstevel@tonic-gate * ba,a <dest> 3300Sstevel@tonic-gate * nop 3310Sstevel@tonic-gate * nop 3320Sstevel@tonic-gate * nop 3330Sstevel@tonic-gate * nop 3340Sstevel@tonic-gate * nop 3350Sstevel@tonic-gate * nop 3360Sstevel@tonic-gate * 3370Sstevel@tonic-gate * This version get's us to a destination within 3380Sstevel@tonic-gate * +- 2megs of the PLT's address: 3390Sstevel@tonic-gate * 3400Sstevel@tonic-gate * nop 3410Sstevel@tonic-gate * ba,a,pt %icc, <dest> 3420Sstevel@tonic-gate * nop 3430Sstevel@tonic-gate * nop 3440Sstevel@tonic-gate * nop 3450Sstevel@tonic-gate * nop 3460Sstevel@tonic-gate * nop 3470Sstevel@tonic-gate * nop 3480Sstevel@tonic-gate * 3490Sstevel@tonic-gate * 3500Sstevel@tonic-gate * The PLT is written in reverse order to ensure re-entrant behaviour. 3510Sstevel@tonic-gate * Note that the first two instructions must be overwritten with a 3520Sstevel@tonic-gate * single stx. 3530Sstevel@tonic-gate * 3540Sstevel@tonic-gate * Note that even in the 44-bit case, we deliberately use both %g5 and 3550Sstevel@tonic-gate * %g1 to prevent anyone accidentally relying on either of them being 3560Sstevel@tonic-gate * non-volatile across a function call. 3570Sstevel@tonic-gate */ 3580Sstevel@tonic-gate 3590Sstevel@tonic-gate#define M_JMPL_G5G0 0x81c16000 /* jmpl %g5 + 0, %g0 */ 3600Sstevel@tonic-gate#define M_OR_G1G5G5 0x8a104005 /* or %g1, %g5, %g5 */ 3610Sstevel@tonic-gate#define M_SLLX_G132G1 0x83287020 /* sllx %g1, 32, %g1 */ 3620Sstevel@tonic-gate#define M_OR_G1G1 0x82106000 /* or %g1, 0x0, %g1 */ 3630Sstevel@tonic-gate#define M_SETHI_G5 0x0b000000 /* sethi 0x0, %g5 */ 3640Sstevel@tonic-gate#define M_SETHI_G1 0x03000000 /* sethi 0x0, %g1 */ 3650Sstevel@tonic-gate#define M_NOP 0x01000000 /* sethi 0x0, %g0 */ 3660Sstevel@tonic-gate 3670Sstevel@tonic-gate#define M_JMPL_G1G0 0x81c06000 /* jmpl %g1 + 0, %g0 */ 3680Sstevel@tonic-gate#define M_SLLX_G112G1 0x8328700c /* sllx %g1, 12, %g1 */ 3690Sstevel@tonic-gate#define M_XNOR_G5G1 0x82396000 /* xnor %g5, 0, %g1 */ 3700Sstevel@tonic-gate 3710Sstevel@tonic-gate#if defined(lint) 3720Sstevel@tonic-gate 3730Sstevel@tonic-gate/* ARGSUSED */ 3740Sstevel@tonic-gate#define MASK(m) ((1ul << (m)) - 1ul) 3750Sstevel@tonic-gate#define BITS(v, u, l) (((v) >> (l)) & MASK((u) - (l) + 1)) 3760Sstevel@tonic-gate#define H44(v) BITS(v, 43, 22) 3770Sstevel@tonic-gate#define M44(v) BITS(v, 21, 12) 3780Sstevel@tonic-gate#define L44(v) BITS(v, 11, 0) 3790Sstevel@tonic-gate 3800Sstevel@tonic-gate#endif 3810Sstevel@tonic-gate 3820Sstevel@tonic-gate#if defined(lint) 3830Sstevel@tonic-gate 3840Sstevel@tonic-gatevoid 3850Sstevel@tonic-gate/* ARGSUSED1 */ 3860Sstevel@tonic-gateplt_upper_32(uintptr_t pc, uintptr_t symval) 3870Sstevel@tonic-gate{ 3880Sstevel@tonic-gate ulong_t sym = (ulong_t)symval; 3890Sstevel@tonic-gate /* LINTED */ 3900Sstevel@tonic-gate ulong_t nsym = ~sym; 3910Sstevel@tonic-gate uint_t * plttab = (uint_t *)pc; 3920Sstevel@tonic-gate 3930Sstevel@tonic-gate plttab[3] = M_JMPL_G1G0; 3940Sstevel@tonic-gate plttab[2] = (uint_t)(M_XNOR_G5G1 | LO10(nsym)); 3950Sstevel@tonic-gate *(ulong_t *)pc = 3960Sstevel@tonic-gate ((ulong_t)M_NOP << 32) | (M_SETHI_G5 | LM22(nsym)); 3970Sstevel@tonic-gate} 3980Sstevel@tonic-gate 3990Sstevel@tonic-gate#else 4000Sstevel@tonic-gate 4010Sstevel@tonic-gate 4020Sstevel@tonic-gate ENTRY(plt_upper_32) 4030Sstevel@tonic-gate ! 4040Sstevel@tonic-gate ! Address lies in top 32-bits of address space, so use 4050Sstevel@tonic-gate ! compact PLT sequence 4060Sstevel@tonic-gate ! 4070Sstevel@tonic-gate sethi %hi(M_JMPL_G1G0), %o3 ! Get "jmpl %g1, %g0" insn 4080Sstevel@tonic-gate st %o3, [%o0 + 0xc] ! store instruction in plt[3] 4090Sstevel@tonic-gate iflush %o0 + 0xc ! .. and flush 4100Sstevel@tonic-gate 4110Sstevel@tonic-gate not %o1, %o4 4120Sstevel@tonic-gate sethi %hi(M_XNOR_G5G1), %o3 ! Get "xnor %g5, %g1, %g1" insn 4130Sstevel@tonic-gate and %o4, 0x3ff, %o2 ! pick out bits 0-9 4140Sstevel@tonic-gate or %o3, %o2, %o3 ! or value into instruction 4150Sstevel@tonic-gate st %o3, [%o0 + 0x8] ! store instruction in plt[2] 4160Sstevel@tonic-gate iflush %o0 + 0x8 ! .. and flush 4170Sstevel@tonic-gate 4180Sstevel@tonic-gate sethi %hi(M_SETHI_G5), %o3 ! Get "sethi 0x0, %g5" insn 4190Sstevel@tonic-gate srl %o4, 10, %o2 ! get %lm(~function address) 4200Sstevel@tonic-gate or %o3, %o2, %o3 ! or value into instruction 4210Sstevel@tonic-gate 4220Sstevel@tonic-gate sethi %hi(M_NOP), %o4 ! Get "nop" instruction 4230Sstevel@tonic-gate sllx %o4, 32, %o4 ! shift to top of instruction pair 4240Sstevel@tonic-gate or %o3, %o4, %o3 ! or value into instruction pair 4250Sstevel@tonic-gate stx %o3, [%o0] ! store instructions into plt[0] plt[1] 4260Sstevel@tonic-gate retl 4270Sstevel@tonic-gate iflush %o0 ! .. and flush 4280Sstevel@tonic-gate SET_SIZE(plt_upper_32) 4290Sstevel@tonic-gate#endif /* defined lint */ 4300Sstevel@tonic-gate 4310Sstevel@tonic-gate 4320Sstevel@tonic-gate#if defined(lint) 4330Sstevel@tonic-gate 4340Sstevel@tonic-gatevoid 4350Sstevel@tonic-gate/* ARGSUSED1 */ 4360Sstevel@tonic-gateplt_upper_44(uintptr_t pc, uintptr_t symval) 4370Sstevel@tonic-gate{ 4380Sstevel@tonic-gate ulong_t sym = (ulong_t)symval; 4390Sstevel@tonic-gate ulong_t nsym = ~sym; 4400Sstevel@tonic-gate uint_t * plttab = (uint_t *)pc; 4410Sstevel@tonic-gate 4420Sstevel@tonic-gate /* LINTED */ 4430Sstevel@tonic-gate plttab[4] = (uint_t)(M_JMPL_G1G0 | L44(sym)); 4440Sstevel@tonic-gate plttab[3] = M_SLLX_G112G1; 4450Sstevel@tonic-gate /* LINTED */ 4460Sstevel@tonic-gate plttab[2] = (uint_t)(M_XNOR_G5G1 | M44(nsym)); 4470Sstevel@tonic-gate *(ulong_t *)pc = ((ulong_t)M_NOP << 32) | (M_SETHI_G5 | H44(nsym)); 4480Sstevel@tonic-gate} 4490Sstevel@tonic-gate 4500Sstevel@tonic-gate#else 4510Sstevel@tonic-gate 4520Sstevel@tonic-gate 4530Sstevel@tonic-gate ENTRY(plt_upper_44) 4540Sstevel@tonic-gate ! 4550Sstevel@tonic-gate ! Address lies in top 44-bits of address space, so use 4560Sstevel@tonic-gate ! compact PLT sequence 4570Sstevel@tonic-gate ! 4580Sstevel@tonic-gate setuw M_JMPL_G1G0, %o3 ! Get "jmpl %g1, %g0" insn 4590Sstevel@tonic-gate and %o1, 0xfff, %o2 ! lower 12 bits of function address 4600Sstevel@tonic-gate or %o3, %o2, %o3 ! is or'ed into instruction 4610Sstevel@tonic-gate st %o3, [%o0 + 0x10] ! store instruction in plt[4] 4620Sstevel@tonic-gate iflush %o0 + 0x10 ! .. and flush 4630Sstevel@tonic-gate 4640Sstevel@tonic-gate setuw M_SLLX_G112G1, %o3 ! Get "sllx %g1, 12, %g1" insn 4650Sstevel@tonic-gate st %o3, [%o0 + 0xc] ! store instruction in plt[3] 4660Sstevel@tonic-gate 4670Sstevel@tonic-gate not %o1, %o4 4680Sstevel@tonic-gate setuw M_XNOR_G5G1, %o3 ! Get "xnor %g5, 0, %g1" insn 4690Sstevel@tonic-gate srlx %o4, 12, %o2 ! get %m44(0 - function address) 4700Sstevel@tonic-gate and %o2, 0x3ff, %o2 ! pick out bits 21-12 4710Sstevel@tonic-gate or %o3, %o2, %o3 ! or value into instruction 4720Sstevel@tonic-gate st %o3, [%o0 + 8] ! store instruction in plt[2] 4730Sstevel@tonic-gate iflush %o0 + 8 ! .. and flush 4740Sstevel@tonic-gate 4750Sstevel@tonic-gate setuw M_SETHI_G5, %o3 ! Get "sethi 0x0, %g5" insn 4760Sstevel@tonic-gate srlx %o4, 22, %o2 ! get %h44(0 - function address) 4770Sstevel@tonic-gate or %o3, %o2, %o3 ! or value into instruction 4780Sstevel@tonic-gate 4790Sstevel@tonic-gate setuw M_NOP, %o4 ! Get "nop" instruction 4800Sstevel@tonic-gate sllx %o4, 32, %o4 ! shift to top of instruction pair 4810Sstevel@tonic-gate or %o3, %o4, %o3 ! or value into instruction pair 4820Sstevel@tonic-gate stx %o3, [%o0] ! store instructions into plt[0] plt[1] 4830Sstevel@tonic-gate retl 4840Sstevel@tonic-gate iflush %o0 ! .. and flush 4850Sstevel@tonic-gate SET_SIZE(plt_upper_44) 4860Sstevel@tonic-gate 4870Sstevel@tonic-gate#endif /* defined(lint) */ 4880Sstevel@tonic-gate 4890Sstevel@tonic-gate 4900Sstevel@tonic-gate#if defined(lint) 4910Sstevel@tonic-gate 4920Sstevel@tonic-gatevoid 4930Sstevel@tonic-gate/* ARGSUSED1 */ 4940Sstevel@tonic-gateplt_full_range(uintptr_t pc, uintptr_t symval) 4950Sstevel@tonic-gate{ 4960Sstevel@tonic-gate uint_t * plttab = (uint_t *)pc; 4970Sstevel@tonic-gate 4980Sstevel@tonic-gate plttab[6] = M_JMPL_G5G0 | LO10(symval); 4990Sstevel@tonic-gate plttab[5] = M_OR_G1G5G5; 5000Sstevel@tonic-gate plttab[4] = M_SLLX_G132G1; 5010Sstevel@tonic-gate plttab[3] = M_OR_G1G1 | HM10(symval); 5020Sstevel@tonic-gate plttab[2] = M_SETHI_G5 | LM22(symval); 5030Sstevel@tonic-gate *(ulong_t *)pc = 5040Sstevel@tonic-gate ((ulong_t)M_NOP << 32) | (M_SETHI_G1 | HH22(symval)); 5050Sstevel@tonic-gate} 5060Sstevel@tonic-gate 5070Sstevel@tonic-gate#else 5080Sstevel@tonic-gate ENTRY(plt_full_range) 5090Sstevel@tonic-gate ! 5100Sstevel@tonic-gate ! Address lies anywhere in 64-bit address space, so use 5110Sstevel@tonic-gate ! full PLT sequence 5120Sstevel@tonic-gate ! 5130Sstevel@tonic-gate sethi %hi(M_JMPL_G5G0), %o3 ! Get "jmpl %g5, %g0" insn 5140Sstevel@tonic-gate and %o1, 0x3ff, %o2 ! lower 10 bits of function address 5150Sstevel@tonic-gate or %o3, %o2, %o3 ! is or'ed into instruction 5160Sstevel@tonic-gate st %o3, [%o0 + 0x18] ! store instruction in plt[6] 5170Sstevel@tonic-gate iflush %o0 + 0x18 ! .. and flush 5180Sstevel@tonic-gate 5190Sstevel@tonic-gate sethi %hi(M_OR_G1G5G5), %o3 ! Get "or %g1, %g5, %g1" insn 5200Sstevel@tonic-gate or %o3, %lo(M_OR_G1G5G5), %o3 5210Sstevel@tonic-gate st %o3, [%o0 + 0x14] ! store instruction in plt[5] 5220Sstevel@tonic-gate 5230Sstevel@tonic-gate sethi %hi(M_SLLX_G132G1), %o3 ! Get "sllx %g1, 32, %g1" insn 5240Sstevel@tonic-gate or %o3, %lo(M_SLLX_G132G1), %o3 5250Sstevel@tonic-gate st %o3, [%o0 + 0x10] ! store instruction in plt[4] 5260Sstevel@tonic-gate iflush %o0 + 0x10 ! .. and flush 5270Sstevel@tonic-gate 5280Sstevel@tonic-gate sethi %hi(M_OR_G1G1), %o3 ! Get "or %g1, 0x0, %g1" insn 5290Sstevel@tonic-gate or %o3, %lo(M_OR_G1G1), %o3 5300Sstevel@tonic-gate srlx %o1, 32, %o2 ! get %hm(function address) 5310Sstevel@tonic-gate and %o2, 0x3ff, %o2 ! pick out bits 42-33 5320Sstevel@tonic-gate or %o3, %o2, %o3 ! or value into instruction 5330Sstevel@tonic-gate st %o3, [%o0 + 0xc] ! store instruction in plt[3] 5340Sstevel@tonic-gate 5350Sstevel@tonic-gate sethi %hi(M_SETHI_G5), %o3 ! Get "sethi 0x0, %g5" insn 5360Sstevel@tonic-gate srl %o1, 10, %o2 ! get %lm(function address) 5370Sstevel@tonic-gate or %o3, %o2, %o3 ! or value into instruction 5380Sstevel@tonic-gate st %o3, [%o0 + 0x8] ! store instruction in plt[2] 5390Sstevel@tonic-gate iflush %o0 + 8 ! .. and flush 5400Sstevel@tonic-gate 5410Sstevel@tonic-gate sethi %hi(M_SETHI_G1), %o3 ! Get "sethi 0x0, %g1" insn 5420Sstevel@tonic-gate srlx %o1, 42, %o2 ! get %hh(function address) 5430Sstevel@tonic-gate or %o3, %o2, %o3 ! or value into instruction 5440Sstevel@tonic-gate 5450Sstevel@tonic-gate sethi %hi(M_NOP), %o4 ! Get "nop" instruction 5460Sstevel@tonic-gate sllx %o4, 32, %o4 ! shift to top of instruction pair 5470Sstevel@tonic-gate or %o3, %o4, %o3 ! or value into instruction pair 5480Sstevel@tonic-gate stx %o3, [%o0] ! store instructions into plt[0] plt[1] 5490Sstevel@tonic-gate retl 5500Sstevel@tonic-gate iflush %o0 ! .. and flush 5510Sstevel@tonic-gate 5520Sstevel@tonic-gate SET_SIZE(plt_full_range) 5530Sstevel@tonic-gate 5540Sstevel@tonic-gate#endif /* defined(lint) */ 5550Sstevel@tonic-gate 5560Sstevel@tonic-gate/* 5570Sstevel@tonic-gate * performs the 'iflush' instruction on a range of memory. 5580Sstevel@tonic-gate */ 5590Sstevel@tonic-gate#if defined(lint) 5600Sstevel@tonic-gatevoid 5610Sstevel@tonic-gateiflush_range(caddr_t addr, size_t len) 5620Sstevel@tonic-gate{ 5630Sstevel@tonic-gate /* LINTED */ 5640Sstevel@tonic-gate uintptr_t base; 5650Sstevel@tonic-gate 5660Sstevel@tonic-gate base = (uintptr_t)addr & ~7; /* round down to 8 byte alignment */ 5670Sstevel@tonic-gate len = (len + 7) & ~7; /* round up to multiple of 8 bytes */ 5680Sstevel@tonic-gate for (len -= 8; (long)len >= 0; len -= 8) 5690Sstevel@tonic-gate /* iflush(base + len) */; 5700Sstevel@tonic-gate} 5710Sstevel@tonic-gate#else 5720Sstevel@tonic-gate ENTRY(iflush_range) 5730Sstevel@tonic-gate add %o1, 7, %o1 5740Sstevel@tonic-gate andn %o0, 7, %o0 5750Sstevel@tonic-gate andn %o1, 7, %o1 5760Sstevel@tonic-gate1: subcc %o1, 8, %o1 5770Sstevel@tonic-gate bge,a,pt %xcc, 1b 5780Sstevel@tonic-gate iflush %o0 + %o1 5790Sstevel@tonic-gate retl 5800Sstevel@tonic-gate nop 5810Sstevel@tonic-gate SET_SIZE(iflush_range) 5820Sstevel@tonic-gate#endif 5830Sstevel@tonic-gate 5840Sstevel@tonic-gate 5850Sstevel@tonic-gate#if defined(lint) 5860Sstevel@tonic-gate 5870Sstevel@tonic-gateulong_t 5880Sstevel@tonic-gateelf_plt_trace() 5890Sstevel@tonic-gate{ 5900Sstevel@tonic-gate return (0); 5910Sstevel@tonic-gate} 5920Sstevel@tonic-gate#else 5930Sstevel@tonic-gate .global elf_plt_trace 5940Sstevel@tonic-gate .type elf_plt_trace, #function 5950Sstevel@tonic-gate 5960Sstevel@tonic-gate/* 5970Sstevel@tonic-gate * The dyn_plt that called us has already created a stack-frame for 5980Sstevel@tonic-gate * us and placed the following entries in it: 5990Sstevel@tonic-gate * 6000Sstevel@tonic-gate * [%fp + STACK_BIAS + -0x8] * dyndata 6010Sstevel@tonic-gate * [%fp + STACK_BIAS + -0x10] * prev stack size 6020Sstevel@tonic-gate * 6030Sstevel@tonic-gate * dyndata currently contains: 6040Sstevel@tonic-gate * 6050Sstevel@tonic-gate * dyndata: 6060Sstevel@tonic-gate * 0x0 Addr *reflmp 6070Sstevel@tonic-gate * 0x8 Addr *deflmp 6080Sstevel@tonic-gate * 0x10 Word symndx 6090Sstevel@tonic-gate * 0x14 Word sb_flags 6100Sstevel@tonic-gate * 0x18 Sym symdef.st_name 6110Sstevel@tonic-gate * 0x1c symdef.st_info 6120Sstevel@tonic-gate * 0x1d symdef.st_other 6130Sstevel@tonic-gate * 0x1e symdef.st_shndx 6140Sstevel@tonic-gate * 0x20 symdef.st_value 6150Sstevel@tonic-gate * 0x28 symdef.st_size 6160Sstevel@tonic-gate */ 6170Sstevel@tonic-gate#define REFLMP_OFF 0x0 6180Sstevel@tonic-gate#define DEFLMP_OFF 0x8 6190Sstevel@tonic-gate#define SYMNDX_OFF 0x10 6200Sstevel@tonic-gate#define SBFLAGS_OFF 0x14 6210Sstevel@tonic-gate#define SYMDEF_OFF 0x18 6220Sstevel@tonic-gate#define SYMDEF_VALUE_OFF 0x20 6230Sstevel@tonic-gate 6240Sstevel@tonic-gate#define LAREGSSZ 0x40 /* sizeof (La_sparcv9_regs) */ 6250Sstevel@tonic-gate 6260Sstevel@tonic-gate 6270Sstevel@tonic-gateelf_plt_trace: 6280Sstevel@tonic-gate1: call 2f 6290Sstevel@tonic-gate sethi %hi(_GLOBAL_OFFSET_TABLE_ - (1b - .)), %l7 6300Sstevel@tonic-gate2: or %l7, %lo(_GLOBAL_OFFSET_TABLE_ - (1b - .)), %l7 6310Sstevel@tonic-gate add %l7, %o7, %l7 6320Sstevel@tonic-gate 6330Sstevel@tonic-gate ldx [%fp + STACK_BIAS + -CLONGSIZE], %l1 ! l1 = * dyndata 6340Sstevel@tonic-gate lduw [%l1 + SBFLAGS_OFF], %l2 ! l2 = sb_flags 6350Sstevel@tonic-gate andcc %l2, LA_SYMB_NOPLTENTER, %g0 6360Sstevel@tonic-gate be,pt %icc, .start_pltenter 6370Sstevel@tonic-gate ldx [%l1 + SYMDEF_VALUE_OFF], %l0 ! l0 = 6380Sstevel@tonic-gate ! sym.st_value(calling address) 6390Sstevel@tonic-gate ba,a,pt %icc, .end_pltenter 6400Sstevel@tonic-gate nop 6410Sstevel@tonic-gate 6420Sstevel@tonic-gate /* 6430Sstevel@tonic-gate * save all registers into La_sparcv9_regs 6440Sstevel@tonic-gate */ 6450Sstevel@tonic-gate.start_pltenter: 6460Sstevel@tonic-gate sub %sp, LAREGSSZ, %sp ! create space for La_sparcv9_regs 6470Sstevel@tonic-gate ! storage on the stack. 6480Sstevel@tonic-gate 6490Sstevel@tonic-gate add %fp, STACK_BIAS - (LAREGSSZ + (2 * CLONGSIZE)), %o4 ! addr of new space. 6500Sstevel@tonic-gate 6510Sstevel@tonic-gate stx %i0, [%o4 + 0x0] 6520Sstevel@tonic-gate stx %i1, [%o4 + 0x8] 6530Sstevel@tonic-gate stx %i2, [%o4 + 0x10] 6540Sstevel@tonic-gate stx %i3, [%o4 + 0x18] ! because a regwindow shift has 6550Sstevel@tonic-gate stx %i4, [%o4 + 0x20] ! already occured our current %i* 6560Sstevel@tonic-gate stx %i5, [%o4 + 0x28] ! register's are the equivalent of 6570Sstevel@tonic-gate stx %i6, [%o4 + 0x30] ! the %o* registers that the final 6580Sstevel@tonic-gate stx %i7, [%o4 + 0x38] ! procedure shall see. 6590Sstevel@tonic-gate mov %g4, %l5 ! save g4 (safe across function calls) 6600Sstevel@tonic-gate 6610Sstevel@tonic-gate 6620Sstevel@tonic-gate ldx [%fp + STACK_BIAS + -CLONGSIZE], %l1 ! %l1 == * dyndata 6630Sstevel@tonic-gate ldx [%l1 + REFLMP_OFF], %o0 ! %o0 = reflmp 6640Sstevel@tonic-gate ldx [%l1 + DEFLMP_OFF], %o1 ! %o1 = deflmp 6650Sstevel@tonic-gate add %l1, SYMDEF_OFF, %o2 ! %o2 = symp 6660Sstevel@tonic-gate lduw [%l1 + SYMNDX_OFF], %o3 ! %o3 = symndx 6670Sstevel@tonic-gate call audit_pltenter 6680Sstevel@tonic-gate add %l1, SBFLAGS_OFF, %o5 ! %o3 = * sb_flags 6690Sstevel@tonic-gate 6700Sstevel@tonic-gate mov %o0, %l0 ! %l0 == calling address 6710Sstevel@tonic-gate add %sp, LAREGSSZ, %sp ! cleanup La_sparcv9_regs off 6720Sstevel@tonic-gate ! of the stack. 6730Sstevel@tonic-gate 6740Sstevel@tonic-gate.end_pltenter: 6750Sstevel@tonic-gate /* 6760Sstevel@tonic-gate * If *no* la_pltexit() routines exist we do not need 6770Sstevel@tonic-gate * to keep the stack frame before we call the actual 6780Sstevel@tonic-gate * routine. Instead we jump to it and remove ourself 6790Sstevel@tonic-gate * from the stack at the same time. 6800Sstevel@tonic-gate */ 6810Sstevel@tonic-gate ldx [%l7+audit_flags], %l3 6820Sstevel@tonic-gate lduw [%l3], %l3 ! %l3 = audit_flags 6830Sstevel@tonic-gate andcc %l3, AF_PLTEXIT, %g0 ! AF_PLTEXIT = 2 6840Sstevel@tonic-gate be,pt %icc, .bypass_pltexit 6850Sstevel@tonic-gate ldx [%fp + STACK_BIAS + -CLONGSIZE], %l1 ! %l1 = * dyndata 6860Sstevel@tonic-gate lduw [%l1 + SBFLAGS_OFF], %l2 ! %l2 = sb_flags 6870Sstevel@tonic-gate andcc %l2, LA_SYMB_NOPLTEXIT, %g0 ! LA_SYMB_NOPLTEXIT = 2 6880Sstevel@tonic-gate bne,a,pt %icc, .bypass_pltexit 6890Sstevel@tonic-gate nop 6900Sstevel@tonic-gate 6910Sstevel@tonic-gate ba,a,pt %icc, .start_pltexit 6920Sstevel@tonic-gate nop 6930Sstevel@tonic-gate.bypass_pltexit: 6940Sstevel@tonic-gate mov %l5, %g4 ! restore g4 6950Sstevel@tonic-gate jmpl %l0, %g0 6960Sstevel@tonic-gate restore 6970Sstevel@tonic-gate 6980Sstevel@tonic-gate.start_pltexit: 6990Sstevel@tonic-gate /* 7000Sstevel@tonic-gate * In order to call la_pltexit() we must duplicate the 7010Sstevel@tonic-gate * arguments from the 'callers' stack on our stack frame. 7020Sstevel@tonic-gate * 7030Sstevel@tonic-gate * First we check the size of the callers stack and grow 7040Sstevel@tonic-gate * our stack to hold any of the arguments that need 7050Sstevel@tonic-gate * duplicating (these are arguments 6->N), because the 7060Sstevel@tonic-gate * first 6 (0->5) are passed via register windows on sparc. 7070Sstevel@tonic-gate */ 7080Sstevel@tonic-gate 7090Sstevel@tonic-gate /* 7100Sstevel@tonic-gate * The first calculation is to determine how large the 7110Sstevel@tonic-gate * argument passing area might be. Since there is no 7120Sstevel@tonic-gate * way to distinquish between 'argument passing' and 7130Sstevel@tonic-gate * 'local storage' from the previous stack this amount must 7140Sstevel@tonic-gate * cover both. 7150Sstevel@tonic-gate */ 7160Sstevel@tonic-gate ldx [%fp + STACK_BIAS + -(2 * CLONGSIZE)], %l1 ! %l1 = callers 7170Sstevel@tonic-gate ! stack size 7180Sstevel@tonic-gate sub %l1, MINFRAME, %l1 ! %l1 = argument space on 7190Sstevel@tonic-gate ! caller's stack 7200Sstevel@tonic-gate /* 7210Sstevel@tonic-gate * Next we compare the prev. stack size against the audit_argcnt. We 7220Sstevel@tonic-gate * copy at most 'audit_argcnt' arguments. The default arg count is 64. 7230Sstevel@tonic-gate * 7240Sstevel@tonic-gate * NOTE: on sparc we always copy at least six args since these 7250Sstevel@tonic-gate * are in reg-windows and not on the stack. 7260Sstevel@tonic-gate * 7270Sstevel@tonic-gate * NOTE: Also note that we multiply (shift really) the arg count 7280Sstevel@tonic-gate * by 8 which is the 'word size' to calculate the amount 7290Sstevel@tonic-gate * of stack space needed. 7300Sstevel@tonic-gate */ 7310Sstevel@tonic-gate ldx [%l7 + audit_argcnt], %l2 7320Sstevel@tonic-gate lduw [%l2], %l2 ! %l2 = audit_argcnt 7330Sstevel@tonic-gate cmp %l2, 6 7340Sstevel@tonic-gate ble,pn %icc, .grow_stack 7350Sstevel@tonic-gate sub %l2, 6, %l2 7360Sstevel@tonic-gate sllx %l2, CLONGSHIFT, %l2 ! arg count * 8 7370Sstevel@tonic-gate cmp %l1, %l2 ! 7380Sstevel@tonic-gate ble,a,pn %icc, .grow_stack 7390Sstevel@tonic-gate nop 7400Sstevel@tonic-gate mov %l2, %l1 7410Sstevel@tonic-gate.grow_stack: 7420Sstevel@tonic-gate /* 7430Sstevel@tonic-gate * When duplicating the stack we skip the first SA(MINFRAME) 7440Sstevel@tonic-gate * bytes. This is the space on the stack reserved for preserving 7450Sstevel@tonic-gate * the register windows and such and do not need to be duplicated 7460Sstevel@tonic-gate * on this new stack frame. We start duplicating at the portion 7470Sstevel@tonic-gate * of the stack reserved for argument's above 6. 7480Sstevel@tonic-gate */ 7490Sstevel@tonic-gate sub %sp, %l1, %sp ! grow our stack by amount required. 7500Sstevel@tonic-gate srax %l1, CLONGSHIFT, %l1 ! %l1 = %l1 / 8 (words to copy) 7510Sstevel@tonic-gate mov SA(MINFRAME), %l2 ! %l2 = index into stack & frame 7520Sstevel@tonic-gate 7530Sstevel@tonic-gate1: 7540Sstevel@tonic-gate cmp %l1, 0 7550Sstevel@tonic-gate ble,a,pn %icc, 2f 7560Sstevel@tonic-gate nop 7570Sstevel@tonic-gate 7580Sstevel@tonic-gate add %fp, %l2, %l4 7590Sstevel@tonic-gate ldx [%l4 + STACK_BIAS], %l3 ! duplicate args from previous 7600Sstevel@tonic-gate add %sp, %l2, %l4 7610Sstevel@tonic-gate stx %l3, [%l4 + STACK_BIAS] ! stack onto current stack 7620Sstevel@tonic-gate 7630Sstevel@tonic-gate add %l2, CLONGSIZE, %l2 7640Sstevel@tonic-gate ba,pt %icc, 1b 7650Sstevel@tonic-gate sub %l1, 0x1, %l1 7660Sstevel@tonic-gate2: 7670Sstevel@tonic-gate mov %i0, %o0 ! copy ins to outs 7680Sstevel@tonic-gate mov %i1, %o1 7690Sstevel@tonic-gate mov %i2, %o2 7700Sstevel@tonic-gate mov %i3, %o3 7710Sstevel@tonic-gate mov %i4, %o4 7720Sstevel@tonic-gate mov %i5, %o5 7730Sstevel@tonic-gate call %l0 ! call original routine 7740Sstevel@tonic-gate mov %l5, %g4 ! restore g4 7750Sstevel@tonic-gate mov %o1, %l2 ! l2 = second 1/2 of return value 7760Sstevel@tonic-gate ! for those those 64 bit operations 7770Sstevel@tonic-gate ! link div64 - yuck... 7780Sstevel@tonic-gate 7790Sstevel@tonic-gate ! %o0 = retval 7800Sstevel@tonic-gate ldx [%fp + STACK_BIAS + -CLONGSIZE], %l1 7810Sstevel@tonic-gate ldx [%l1 + REFLMP_OFF], %o1 ! %o1 = reflmp 7820Sstevel@tonic-gate ldx [%l1 + DEFLMP_OFF], %o2 ! %o2 = deflmp 7830Sstevel@tonic-gate add %l1, SYMDEF_OFF, %o3 ! %o3 = symp 7840Sstevel@tonic-gate call audit_pltexit 7850Sstevel@tonic-gate lduw [%l1 + SYMNDX_OFF], %o4 ! %o4 = symndx 7860Sstevel@tonic-gate 7870Sstevel@tonic-gate mov %o0, %i0 ! pass on return code 7880Sstevel@tonic-gate mov %l2, %i1 7890Sstevel@tonic-gate ret 7900Sstevel@tonic-gate restore 7910Sstevel@tonic-gate .size elf_plt_trace, . - elf_plt_trace 7920Sstevel@tonic-gate 7930Sstevel@tonic-gate#endif 7940Sstevel@tonic-gate 795