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 <link.h> 320Sstevel@tonic-gate#include "machdep.h" 330Sstevel@tonic-gate#include "_audit.h" 340Sstevel@tonic-gate 350Sstevel@tonic-gate#if defined(lint) 360Sstevel@tonic-gate#include <sys/types.h> 370Sstevel@tonic-gate#include "_rtld.h" 380Sstevel@tonic-gate#else 390Sstevel@tonic-gate#include <sys/stack.h> 400Sstevel@tonic-gate#include <sys/asm_linkage.h> 410Sstevel@tonic-gate 420Sstevel@tonic-gate .file "boot_elf.s" 430Sstevel@tonic-gate .seg ".text" 440Sstevel@tonic-gate#endif 450Sstevel@tonic-gate 460Sstevel@tonic-gate/* 470Sstevel@tonic-gate * We got here because the initial call to a function resolved to a procedure 480Sstevel@tonic-gate * linkage table entry. That entry did a branch to the first PLT entry, which 490Sstevel@tonic-gate * in turn did a call to elf_rtbndr (refer elf_plt_init()). 500Sstevel@tonic-gate * 510Sstevel@tonic-gate * the code sequence that got us here was: 520Sstevel@tonic-gate * 530Sstevel@tonic-gate * PLT entry for foo(): 540Sstevel@tonic-gate * sethi (.-PLT0), %g1 ! not changed by rtld 550Sstevel@tonic-gate * ba,a .PLT0 ! patched atomically 2nd 560Sstevel@tonic-gate * nop ! patched first 570Sstevel@tonic-gate * 580Sstevel@tonic-gate * Therefore on entry, %i7 has the address of the call, which will be added 590Sstevel@tonic-gate * to the offset to the plt entry in %g1 to calculate the plt entry address 600Sstevel@tonic-gate * we must also subtract 4 because the address of PLT0 points to the 610Sstevel@tonic-gate * save instruction before the call. 620Sstevel@tonic-gate * 630Sstevel@tonic-gate * the plt entry is rewritten: 640Sstevel@tonic-gate * 650Sstevel@tonic-gate * PLT entry for foo(): 660Sstevel@tonic-gate * sethi (.-PLT0), %g1 670Sstevel@tonic-gate * sethi %hi(entry_pt), %g1 680Sstevel@tonic-gate * jmpl %g1 + %lo(entry_pt), %g0 690Sstevel@tonic-gate */ 700Sstevel@tonic-gate 710Sstevel@tonic-gate#if defined(lint) 720Sstevel@tonic-gate 730Sstevel@tonic-gateextern unsigned long elf_bndr(Rt_map *, unsigned long, caddr_t); 740Sstevel@tonic-gate 750Sstevel@tonic-gatestatic void 760Sstevel@tonic-gateelf_rtbndr(Rt_map *lmp, unsigned long pltoff, caddr_t from) 770Sstevel@tonic-gate{ 780Sstevel@tonic-gate (void) elf_bndr(lmp, pltoff, from); 790Sstevel@tonic-gate} 800Sstevel@tonic-gate 810Sstevel@tonic-gate 820Sstevel@tonic-gate#else 830Sstevel@tonic-gate .weak _elf_rtbndr ! keep dbx happy as it likes to 840Sstevel@tonic-gate _elf_rtbndr = elf_rtbndr ! rummage around for our symbols 850Sstevel@tonic-gate 860Sstevel@tonic-gate .global elf_rtbndr 870Sstevel@tonic-gate .type elf_rtbndr, #function 880Sstevel@tonic-gate .align 4 890Sstevel@tonic-gate 900Sstevel@tonic-gateelf_rtbndr: 910Sstevel@tonic-gate mov %i7, %o0 ! Save callers address(profiling) 920Sstevel@tonic-gate save %sp, -SA(MINFRAME), %sp ! Make a frame 930Sstevel@tonic-gate srl %g1, 10, %o1 ! shift offset set by sethi 940Sstevel@tonic-gate ! %o1 has offset from jump slot 950Sstevel@tonic-gate ! to PLT0 which will be used to 960Sstevel@tonic-gate ! calculate plt relocation entry 970Sstevel@tonic-gate ! by elf_bndr 980Sstevel@tonic-gate ld [%i7 + 8], %o0 ! %o0 has ptr to lm 990Sstevel@tonic-gate call elf_bndr ! returns function address in %o0 1000Sstevel@tonic-gate mov %i0, %o2 ! Callers address is arg 3 1010Sstevel@tonic-gate mov %o0, %g1 ! save address of routine binded 1020Sstevel@tonic-gate restore ! how many restores needed ? 2 1030Sstevel@tonic-gate jmp %g1 ! jump to it 1040Sstevel@tonic-gate restore 1050Sstevel@tonic-gate .size elf_rtbndr, . - elf_rtbndr 1060Sstevel@tonic-gate 1070Sstevel@tonic-gate#endif 1080Sstevel@tonic-gate 1090Sstevel@tonic-gate 1100Sstevel@tonic-gate#if defined(lint) 1110Sstevel@tonic-gatevoid 1120Sstevel@tonic-gateiflush_range(caddr_t addr, size_t len) 1130Sstevel@tonic-gate{ 1140Sstevel@tonic-gate /* LINTED */ 1150Sstevel@tonic-gate uintptr_t base; 1160Sstevel@tonic-gate 1170Sstevel@tonic-gate base = (uintptr_t)addr & ~7; /* round down to 8 byte alignment */ 1180Sstevel@tonic-gate len = (len + 7) & ~7; /* round up to multiple of 8 bytes */ 1190Sstevel@tonic-gate for (len -= 8; (long)len >= 0; len -= 8) 1200Sstevel@tonic-gate /* iflush(base + len) */; 1210Sstevel@tonic-gate} 1220Sstevel@tonic-gate#else 1230Sstevel@tonic-gate ENTRY(iflush_range) 1240Sstevel@tonic-gate add %o1, 7, %o1 1250Sstevel@tonic-gate andn %o0, 7, %o0 1260Sstevel@tonic-gate andn %o1, 7, %o1 1270Sstevel@tonic-gate1: subcc %o1, 8, %o1 1280Sstevel@tonic-gate bge,a 1b 1290Sstevel@tonic-gate iflush %o0 + %o1 1300Sstevel@tonic-gate retl 1310Sstevel@tonic-gate nop 1320Sstevel@tonic-gate SET_SIZE(iflush_range) 1330Sstevel@tonic-gate#endif 1340Sstevel@tonic-gate 1350Sstevel@tonic-gate/* 1360Sstevel@tonic-gate * Initialize the first plt entry so that function calls go to elf_rtbndr 1370Sstevel@tonic-gate * 1380Sstevel@tonic-gate * The first plt entry (PLT0) is: 1390Sstevel@tonic-gate * 1400Sstevel@tonic-gate * save %sp, -64, %sp 1410Sstevel@tonic-gate * call elf_rtbndr 1420Sstevel@tonic-gate * nop 1430Sstevel@tonic-gate * address of lm 1440Sstevel@tonic-gate */ 1450Sstevel@tonic-gate 1460Sstevel@tonic-gate#if defined(lint) 1470Sstevel@tonic-gate 1480Sstevel@tonic-gatevoid 1490Sstevel@tonic-gateelf_plt_init(void *plt, caddr_t lmp) 1500Sstevel@tonic-gate{ 1510Sstevel@tonic-gate *((uint_t *)plt + 0) = (unsigned long) M_SAVESP64; 1520Sstevel@tonic-gate *((uint_t *)plt + 4) = M_CALL | (((unsigned long)elf_rtbndr - 1530Sstevel@tonic-gate ((unsigned long)plt)) >> 2); 1540Sstevel@tonic-gate *((uint_t *)plt + 8) = M_NOP; 1550Sstevel@tonic-gate *((uint_t *)plt + 12) = (unsigned long) lmp; 1560Sstevel@tonic-gate} 1570Sstevel@tonic-gate 1580Sstevel@tonic-gate#else 1590Sstevel@tonic-gate .global elf_plt_init 1600Sstevel@tonic-gate .type elf_plt_init, #function 1610Sstevel@tonic-gate .align 4 1620Sstevel@tonic-gate 1630Sstevel@tonic-gateelf_plt_init: 1640Sstevel@tonic-gate save %sp, -SA(MINFRAME), %sp ! Make a frame 1650Sstevel@tonic-gate1: 1660Sstevel@tonic-gate call 2f 1670Sstevel@tonic-gate sethi %hi((_GLOBAL_OFFSET_TABLE_ - (1b - .))), %l7 1680Sstevel@tonic-gate2: 1690Sstevel@tonic-gate sethi %hi(M_SAVESP64), %o0 ! Get save instruction 1700Sstevel@tonic-gate or %o0, %lo(M_SAVESP64), %o0 1710Sstevel@tonic-gate or %l7, %lo((_GLOBAL_OFFSET_TABLE_ - (1b - .))), %l7 1720Sstevel@tonic-gate st %o0, [%i0] ! Store in plt[0] 1730Sstevel@tonic-gate iflush %i0 1740Sstevel@tonic-gate add %l7, %o7, %l7 1750Sstevel@tonic-gate ld [%l7 + elf_rtbndr], %l7 1760Sstevel@tonic-gate inc 4, %i0 ! Bump plt to point to plt[1] 1770Sstevel@tonic-gate sub %l7, %i0, %o0 ! Determine -pc so as to produce 1780Sstevel@tonic-gate ! offset from plt[1] 1790Sstevel@tonic-gate srl %o0, 2, %o0 ! Express offset as number of words 1800Sstevel@tonic-gate sethi %hi(M_CALL), %o4 ! Get sethi instruction 1810Sstevel@tonic-gate or %o4, %o0, %o4 ! Add elf_rtbndr address 1820Sstevel@tonic-gate st %o4, [%i0] ! Store instruction in plt 1830Sstevel@tonic-gate iflush %i0 1840Sstevel@tonic-gate sethi %hi(M_NOP), %o0 ! Generate nop instruction 1850Sstevel@tonic-gate st %o0, [%i0 + 4] ! Store instruction in plt[2] 1860Sstevel@tonic-gate iflush %i0 + 4 1870Sstevel@tonic-gate st %i1, [%i0 + 8] ! Store instruction in plt[3] 1880Sstevel@tonic-gate iflush %i0 + 8 1890Sstevel@tonic-gate ret 1900Sstevel@tonic-gate restore 1910Sstevel@tonic-gate .size elf_plt_init, . - elf_plt_init 1920Sstevel@tonic-gate#endif 1930Sstevel@tonic-gate 1940Sstevel@tonic-gate#if defined(lint) 1950Sstevel@tonic-gate 1960Sstevel@tonic-gateulong_t 1970Sstevel@tonic-gateelf_plt_trace() 1980Sstevel@tonic-gate{ 1990Sstevel@tonic-gate return (0); 2000Sstevel@tonic-gate} 2010Sstevel@tonic-gate#else 2020Sstevel@tonic-gate .global elf_plt_trace 2030Sstevel@tonic-gate .type elf_plt_trace, #function 2040Sstevel@tonic-gate .align 4 2050Sstevel@tonic-gate 2060Sstevel@tonic-gate/* 2070Sstevel@tonic-gate * The dyn_plt that called us has already created a stack-frame for 2080Sstevel@tonic-gate * us and placed the following entries in it: 2090Sstevel@tonic-gate * 2100Sstevel@tonic-gate * [%fp - 0x4] * dyndata 2110Sstevel@tonic-gate * [%fp - 0x8] * prev stack size 2120Sstevel@tonic-gate * 2130Sstevel@tonic-gate * dyndata currently contains: 2140Sstevel@tonic-gate * 2150Sstevel@tonic-gate * dyndata: 2160Sstevel@tonic-gate * 0x0 uintptr_t *reflmp 2170Sstevel@tonic-gate * 0x4 uintptr_t *deflmp 2180Sstevel@tonic-gate * 0x8 ulong_t symndx 2190Sstevel@tonic-gate * 0xc ulong_t sb_flags 2200Sstevel@tonic-gate * 0x10 Sym symdef.st_name 2210Sstevel@tonic-gate * 0x14 symdef.st_value 2220Sstevel@tonic-gate * 0x18 symdef.st_size 2230Sstevel@tonic-gate * 0x1c symdef.st_info 2240Sstevel@tonic-gate * 0x1d symdef.st_other 2250Sstevel@tonic-gate * 0x1e symdef.st_shndx 2260Sstevel@tonic-gate */ 2270Sstevel@tonic-gate#define REFLMP_OFF 0x0 2280Sstevel@tonic-gate#define DEFLMP_OFF 0x4 2290Sstevel@tonic-gate#define SYMNDX_OFF 0x8 2300Sstevel@tonic-gate#define SBFLAGS_OFF 0xc 2310Sstevel@tonic-gate#define SYMDEF_OFF 0x10 2320Sstevel@tonic-gate#define SYMDEF_VALUE_OFF 0x14 2330Sstevel@tonic-gate 2340Sstevel@tonic-gateelf_plt_trace: 2350Sstevel@tonic-gate1: call 2f 2360Sstevel@tonic-gate sethi %hi(_GLOBAL_OFFSET_TABLE_+(.-1b)), %l7 2370Sstevel@tonic-gate2: or %l7, %lo(_GLOBAL_OFFSET_TABLE_+(.-1b)), %l7 2380Sstevel@tonic-gate add %l7, %o7, %l7 2390Sstevel@tonic-gate 2400Sstevel@tonic-gate ld [%l7+audit_flags], %l3 2410Sstevel@tonic-gate ld [%l3], %l3 ! %l3 = audit_flags 2420Sstevel@tonic-gate andcc %l3, AF_PLTENTER, %g0 2430Sstevel@tonic-gate beq .end_pltenter 2440Sstevel@tonic-gate ld [%fp + -0x4], %l1 ! l1 = * dyndata 2450Sstevel@tonic-gate ld [%l1 + SBFLAGS_OFF], %l2 ! l2 = sb_flags 2460Sstevel@tonic-gate andcc %l2, LA_SYMB_NOPLTENTER, %g0 2470Sstevel@tonic-gate beq .start_pltenter 2480Sstevel@tonic-gate ld [%l1 + SYMDEF_VALUE_OFF], %l0 ! l0 = 2490Sstevel@tonic-gate ! sym.st_value(calling address) 2500Sstevel@tonic-gate ba .end_pltenter 2510Sstevel@tonic-gate nop 2520Sstevel@tonic-gate 2530Sstevel@tonic-gate /* 2540Sstevel@tonic-gate * save all registers into La_sparcv8_regs 2550Sstevel@tonic-gate */ 2560Sstevel@tonic-gate.start_pltenter: 2570Sstevel@tonic-gate sub %sp, 0x20, %sp ! create space for La_sparcv8_regs 2580Sstevel@tonic-gate ! storage on the stack. 2590Sstevel@tonic-gate 2600Sstevel@tonic-gate sub %fp, 0x28, %o4 2610Sstevel@tonic-gate 2620Sstevel@tonic-gate st %i0, [%o4] 2630Sstevel@tonic-gate st %i1, [%o4 + 0x4] 2640Sstevel@tonic-gate st %i2, [%o4 + 0x8] 2650Sstevel@tonic-gate st %i3, [%o4 + 0xc] ! because a regwindow shift has 2660Sstevel@tonic-gate st %i4, [%o4 + 0x10] ! already occured our current %i* 2670Sstevel@tonic-gate st %i5, [%o4 + 0x14] ! register's are the equivalent of 2680Sstevel@tonic-gate st %i6, [%o4 + 0x18] ! the %o* registers that the final 2690Sstevel@tonic-gate st %i7, [%o4 + 0x1c] ! procedure shall see. 2700Sstevel@tonic-gate 2710Sstevel@tonic-gate ld [%fp + -0x4], %l1 ! %l1 == * dyndata 2720Sstevel@tonic-gate ld [%l1 + REFLMP_OFF], %o0 ! %o0 = reflmp 2730Sstevel@tonic-gate ld [%l1 + DEFLMP_OFF], %o1 ! %o1 = deflmp 2740Sstevel@tonic-gate add %l1, SYMDEF_OFF, %o2 ! %o2 = symp 2750Sstevel@tonic-gate ld [%l1 + SYMNDX_OFF], %o3 ! %o3 = symndx 2760Sstevel@tonic-gate call audit_pltenter 2770Sstevel@tonic-gate add %l1, SBFLAGS_OFF, %o5 ! %o3 = * sb_flags 2780Sstevel@tonic-gate 2790Sstevel@tonic-gate mov %o0, %l0 ! %l0 == calling address 2800Sstevel@tonic-gate 2810Sstevel@tonic-gate add %sp, 0x20, %sp ! cleanup La_sparcv8_regs off 2820Sstevel@tonic-gate ! of the stack. 2830Sstevel@tonic-gate 2840Sstevel@tonic-gate.end_pltenter: 2850Sstevel@tonic-gate /* 2860Sstevel@tonic-gate * If *no* la_pltexit() routines exist we do not need to keep the 2870Sstevel@tonic-gate * stack frame before we call the actual routine. Instead we jump to 2880Sstevel@tonic-gate * it and remove our self from the stack at the same time. 2890Sstevel@tonic-gate */ 2900Sstevel@tonic-gate ld [%l7+audit_flags], %l3 2910Sstevel@tonic-gate ld [%l3], %l3 ! %l3 = audit_flags 2920Sstevel@tonic-gate andcc %l3, AF_PLTEXIT, %g0 2930Sstevel@tonic-gate beq .bypass_pltexit 2940Sstevel@tonic-gate ld [%fp + -0x4], %l1 ! %l1 = * dyndata 2950Sstevel@tonic-gate ld [%l1 + SBFLAGS_OFF], %l2 ! %l2 = sb_flags 2960Sstevel@tonic-gate andcc %l2, LA_SYMB_NOPLTEXIT, %g0 2970Sstevel@tonic-gate bne .bypass_pltexit 2980Sstevel@tonic-gate nop 2990Sstevel@tonic-gate 3000Sstevel@tonic-gate ba .start_pltexit 3010Sstevel@tonic-gate nop 3020Sstevel@tonic-gate.bypass_pltexit: 3030Sstevel@tonic-gate jmpl %l0, %g0 3040Sstevel@tonic-gate restore 3050Sstevel@tonic-gate 3060Sstevel@tonic-gate.start_pltexit: 3070Sstevel@tonic-gate /* 3080Sstevel@tonic-gate * In order to call la_pltexit() we must duplicate the 3090Sstevel@tonic-gate * arguments from the 'callers' stack on our stack frame. 3100Sstevel@tonic-gate * 3110Sstevel@tonic-gate * First we check the size of the callers stack and grow 3120Sstevel@tonic-gate * our stack to hold any of the arguments. That need 3130Sstevel@tonic-gate * duplicating (these are arguments 6->N), because the 3140Sstevel@tonic-gate * first 6 (0->5) are passed via register windows on sparc. 3150Sstevel@tonic-gate */ 3160Sstevel@tonic-gate 3170Sstevel@tonic-gate /* 3180Sstevel@tonic-gate * The first calculation is to determine how large the 3190Sstevel@tonic-gate * argument passing area might be. Since there is no 3200Sstevel@tonic-gate * way to distinquish between 'argument passing' and 3210Sstevel@tonic-gate * 'local storage' from the previous stack this amount must 3220Sstevel@tonic-gate * cover both. 3230Sstevel@tonic-gate */ 3240Sstevel@tonic-gate ld [%fp + -0x8], %l1 ! %l1 = callers stack size 3250Sstevel@tonic-gate sub %l1, 0x58, %l1 ! %l1 = argument space on caller's 3260Sstevel@tonic-gate ! stack 3270Sstevel@tonic-gate /* 3280Sstevel@tonic-gate * Next we compare the prev. stack size against the audit_argcnt. 3290Sstevel@tonic-gate * We copy at most 'audit_argcnt' arguments. 3300Sstevel@tonic-gate * 3310Sstevel@tonic-gate * NOTE: on sparc we always copy at least six args since these 3320Sstevel@tonic-gate * are in reg-windows and not on the stack. 3330Sstevel@tonic-gate * 3340Sstevel@tonic-gate * NOTE: Also note that we multiply (shift really) the arg count 3350Sstevel@tonic-gate * by 4 which is the 'word size' to calculate the amount 3360Sstevel@tonic-gate * of stack space needed. 3370Sstevel@tonic-gate */ 3380Sstevel@tonic-gate ld [%l7 + audit_argcnt], %l2 3390Sstevel@tonic-gate ld [%l2], %l2 ! %l2 = audit_arg_count 3400Sstevel@tonic-gate cmp %l2, 6 3410Sstevel@tonic-gate ble .grow_stack 3420Sstevel@tonic-gate sub %l2, 6, %l2 3430Sstevel@tonic-gate sll %l2, 2, %l2 3440Sstevel@tonic-gate cmp %l1, %l2 3450Sstevel@tonic-gate ble .grow_stack 3460Sstevel@tonic-gate nop 3470Sstevel@tonic-gate mov %l2, %l1 3480Sstevel@tonic-gate.grow_stack: 3490Sstevel@tonic-gate /* 3500Sstevel@tonic-gate * When duplicating the stack we skip the first '0x5c' bytes. 3510Sstevel@tonic-gate * This is the space on the stack reserved for preserving 3520Sstevel@tonic-gate * the register windows and such and do not need to be duplicated 3530Sstevel@tonic-gate * on this new stack frame. We start duplicating at the 3540Sstevel@tonic-gate * portion of the stack reserved for argument's above 6. 3550Sstevel@tonic-gate */ 3560Sstevel@tonic-gate sub %sp, %l1, %sp ! grow our stack by amount required. 3570Sstevel@tonic-gate sra %l1, 0x2, %l1 ! %l1 = %l1 / 4 (words to copy) 3580Sstevel@tonic-gate mov 0x5c, %l2 ! %l2 = index into stack & frame 3590Sstevel@tonic-gate 3600Sstevel@tonic-gate1: 3610Sstevel@tonic-gate cmp %l1, 0 3620Sstevel@tonic-gate ble 2f 3630Sstevel@tonic-gate nop 3640Sstevel@tonic-gate ld [%fp + %l2], %l3 ! duplicate args from previous 3650Sstevel@tonic-gate st %l3, [%sp + %l2] ! stack onto current stack 3660Sstevel@tonic-gate add %l2, 0x4, %l2 3670Sstevel@tonic-gate ba 1b 3680Sstevel@tonic-gate sub %l1, 0x1, %l1 3690Sstevel@tonic-gate2: 3700Sstevel@tonic-gate mov %i0, %o0 ! copy ins to outs 3710Sstevel@tonic-gate mov %i1, %o1 3720Sstevel@tonic-gate mov %i2, %o2 3730Sstevel@tonic-gate mov %i3, %o3 3740Sstevel@tonic-gate mov %i4, %o4 3750Sstevel@tonic-gate call %l0 ! call routine 3760Sstevel@tonic-gate mov %i5, %o5 3770Sstevel@tonic-gate mov %o1, %l2 ! l2 = second 1/2 of return value 3780Sstevel@tonic-gate ! for those those 64 bit operations 3790Sstevel@tonic-gate ! link div64 - yuck... 3800Sstevel@tonic-gate 3810Sstevel@tonic-gate ! %o0 = retval 3820Sstevel@tonic-gate ld [%fp + -0x4], %l1 3830Sstevel@tonic-gate ld [%l1 + REFLMP_OFF], %o1 ! %o1 = reflmp 3840Sstevel@tonic-gate ld [%l1 + DEFLMP_OFF], %o2 ! %o2 = deflmp 3850Sstevel@tonic-gate add %l1, SYMDEF_OFF, %o3 ! %o3 = symp 3860Sstevel@tonic-gate call audit_pltexit 3870Sstevel@tonic-gate ld [%l1 + SYMNDX_OFF], %o4 ! %o4 = symndx 3880Sstevel@tonic-gate 3890Sstevel@tonic-gate mov %o0, %i0 ! pass on return code 3900Sstevel@tonic-gate mov %l2, %i1 3910Sstevel@tonic-gate ret 3920Sstevel@tonic-gate restore 3930Sstevel@tonic-gate .size elf_plt_trace, . - elf_plt_trace 3940Sstevel@tonic-gate 3950Sstevel@tonic-gate#endif 3960Sstevel@tonic-gate 3970Sstevel@tonic-gate/* 3980Sstevel@tonic-gate * After the first call to a plt, elf_bndr() will have determined the true 3990Sstevel@tonic-gate * address of the function being bound. The plt is now rewritten so that 4000Sstevel@tonic-gate * any subsequent calls go directly to the bound function. If the library 4010Sstevel@tonic-gate * to which the function belongs is being profiled refer to _plt_cg_write. 4020Sstevel@tonic-gate * 4030Sstevel@tonic-gate * the new plt entry is: 4040Sstevel@tonic-gate * 4050Sstevel@tonic-gate * sethi (.-PLT0), %g1 ! constant 4060Sstevel@tonic-gate * sethi %hi(function address), %g1 ! patched second 4070Sstevel@tonic-gate * jmpl %g1 + %lo(function address, %g0 ! patched first 4080Sstevel@tonic-gate */ 4090Sstevel@tonic-gate 4100Sstevel@tonic-gate#if defined(lint) 4110Sstevel@tonic-gate 4120Sstevel@tonic-gatevoid 4130Sstevel@tonic-gateplt_full_range(uintptr_t pc, uintptr_t symval) 4140Sstevel@tonic-gate{ 4150Sstevel@tonic-gate uint_t * plttab = (uint_t *)pc; 4160Sstevel@tonic-gate plttab[2] = (M_JMPL | ((unsigned long)symval & S_MASK(10))); 4170Sstevel@tonic-gate plttab[1] = (M_SETHIG1 | ((unsigned long)symval >> (32 - 22))); 4180Sstevel@tonic-gate} 4190Sstevel@tonic-gate 4200Sstevel@tonic-gate#else 4210Sstevel@tonic-gate ENTRY(plt_full_range) 4220Sstevel@tonic-gate 4230Sstevel@tonic-gate sethi %hi(M_JMPL), %o3 ! Get jmpl instruction 4240Sstevel@tonic-gate and %o1, 0x3ff, %o2 ! Lower part of function address 4250Sstevel@tonic-gate or %o3, %o2, %o3 ! is or'ed into instruction 4260Sstevel@tonic-gate st %o3, [%o0 + 8] ! Store instruction in plt[2] 4270Sstevel@tonic-gate iflush %o0 + 8 4280Sstevel@tonic-gate stbar 4290Sstevel@tonic-gate 4300Sstevel@tonic-gate srl %o1, 10, %o1 ! Get high part of function address 4310Sstevel@tonic-gate sethi %hi(M_SETHIG1), %o3 ! Get sethi instruction 4320Sstevel@tonic-gate or %o3, %o1, %o3 ! Add sethi and function address 4330Sstevel@tonic-gate st %o3, [%o0 + 4] ! Store instruction in plt[1] 4340Sstevel@tonic-gate retl 4350Sstevel@tonic-gate iflush %o0 + 4 4360Sstevel@tonic-gate 4370Sstevel@tonic-gate SET_SIZE(plt_full_range) 4380Sstevel@tonic-gate 4390Sstevel@tonic-gate#endif /* defined(lint) */ 4400Sstevel@tonic-gate 441