17c478bd9Sstevel@tonic-gate/* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*b02637afSrie * Common Development and Distribution License (the "License"). 6*b02637afSrie * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 21*b02637afSrie 227c478bd9Sstevel@tonic-gate/* 237c478bd9Sstevel@tonic-gate * Copyright (c) 1988 AT&T 247c478bd9Sstevel@tonic-gate * All Rights Reserved 257c478bd9Sstevel@tonic-gate * 26*b02637afSrie * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 277c478bd9Sstevel@tonic-gate * Use is subject to license terms. 287c478bd9Sstevel@tonic-gate */ 297c478bd9Sstevel@tonic-gate#pragma ident "%Z%%M% %I% %E% SMI" 307c478bd9Sstevel@tonic-gate 317c478bd9Sstevel@tonic-gate#include <link.h> 327c478bd9Sstevel@tonic-gate#include "machdep.h" 337c478bd9Sstevel@tonic-gate#include "_audit.h" 347c478bd9Sstevel@tonic-gate 357c478bd9Sstevel@tonic-gate#if defined(lint) 367c478bd9Sstevel@tonic-gate#include <sys/types.h> 377c478bd9Sstevel@tonic-gate#include "_rtld.h" 387c478bd9Sstevel@tonic-gate#else 397c478bd9Sstevel@tonic-gate#include <sys/stack.h> 407c478bd9Sstevel@tonic-gate#include <sys/asm_linkage.h> 417c478bd9Sstevel@tonic-gate 427c478bd9Sstevel@tonic-gate .file "boot_elf.s" 437c478bd9Sstevel@tonic-gate .seg ".text" 447c478bd9Sstevel@tonic-gate#endif 457c478bd9Sstevel@tonic-gate 467c478bd9Sstevel@tonic-gate/* 477c478bd9Sstevel@tonic-gate * We got here because the initial call to a function resolved to a procedure 487c478bd9Sstevel@tonic-gate * linkage table entry. That entry did a branch to the first PLT entry, which 497c478bd9Sstevel@tonic-gate * in turn did a call to elf_rtbndr (refer elf_plt_init()). 507c478bd9Sstevel@tonic-gate * 517c478bd9Sstevel@tonic-gate * the code sequence that got us here was: 527c478bd9Sstevel@tonic-gate * 537c478bd9Sstevel@tonic-gate * PLT entry for foo(): 547c478bd9Sstevel@tonic-gate * sethi (.-PLT0), %g1 ! not changed by rtld 557c478bd9Sstevel@tonic-gate * ba,a .PLT0 ! patched atomically 2nd 567c478bd9Sstevel@tonic-gate * nop ! patched first 577c478bd9Sstevel@tonic-gate * 587c478bd9Sstevel@tonic-gate * Therefore on entry, %i7 has the address of the call, which will be added 597c478bd9Sstevel@tonic-gate * to the offset to the plt entry in %g1 to calculate the plt entry address 607c478bd9Sstevel@tonic-gate * we must also subtract 4 because the address of PLT0 points to the 617c478bd9Sstevel@tonic-gate * save instruction before the call. 627c478bd9Sstevel@tonic-gate * 637c478bd9Sstevel@tonic-gate * the plt entry is rewritten: 647c478bd9Sstevel@tonic-gate * 657c478bd9Sstevel@tonic-gate * PLT entry for foo(): 667c478bd9Sstevel@tonic-gate * sethi (.-PLT0), %g1 677c478bd9Sstevel@tonic-gate * sethi %hi(entry_pt), %g1 687c478bd9Sstevel@tonic-gate * jmpl %g1 + %lo(entry_pt), %g0 697c478bd9Sstevel@tonic-gate */ 707c478bd9Sstevel@tonic-gate 717c478bd9Sstevel@tonic-gate#if defined(lint) 727c478bd9Sstevel@tonic-gate 737c478bd9Sstevel@tonic-gateextern unsigned long elf_bndr(Rt_map *, unsigned long, caddr_t); 747c478bd9Sstevel@tonic-gate 757c478bd9Sstevel@tonic-gatestatic void 767c478bd9Sstevel@tonic-gateelf_rtbndr(Rt_map *lmp, unsigned long pltoff, caddr_t from) 777c478bd9Sstevel@tonic-gate{ 787c478bd9Sstevel@tonic-gate (void) elf_bndr(lmp, pltoff, from); 797c478bd9Sstevel@tonic-gate} 807c478bd9Sstevel@tonic-gate 817c478bd9Sstevel@tonic-gate 827c478bd9Sstevel@tonic-gate#else 837c478bd9Sstevel@tonic-gate .weak _elf_rtbndr ! keep dbx happy as it likes to 847c478bd9Sstevel@tonic-gate _elf_rtbndr = elf_rtbndr ! rummage around for our symbols 857c478bd9Sstevel@tonic-gate 867c478bd9Sstevel@tonic-gate .global elf_rtbndr 877c478bd9Sstevel@tonic-gate .type elf_rtbndr, #function 887c478bd9Sstevel@tonic-gate .align 4 897c478bd9Sstevel@tonic-gate 907c478bd9Sstevel@tonic-gateelf_rtbndr: 917c478bd9Sstevel@tonic-gate mov %i7, %o0 ! Save callers address(profiling) 927c478bd9Sstevel@tonic-gate save %sp, -SA(MINFRAME), %sp ! Make a frame 937c478bd9Sstevel@tonic-gate srl %g1, 10, %o1 ! shift offset set by sethi 947c478bd9Sstevel@tonic-gate ! %o1 has offset from jump slot 957c478bd9Sstevel@tonic-gate ! to PLT0 which will be used to 967c478bd9Sstevel@tonic-gate ! calculate plt relocation entry 977c478bd9Sstevel@tonic-gate ! by elf_bndr 987c478bd9Sstevel@tonic-gate ld [%i7 + 8], %o0 ! %o0 has ptr to lm 997c478bd9Sstevel@tonic-gate call elf_bndr ! returns function address in %o0 1007c478bd9Sstevel@tonic-gate mov %i0, %o2 ! Callers address is arg 3 1017c478bd9Sstevel@tonic-gate mov %o0, %g1 ! save address of routine binded 1027c478bd9Sstevel@tonic-gate restore ! how many restores needed ? 2 1037c478bd9Sstevel@tonic-gate jmp %g1 ! jump to it 1047c478bd9Sstevel@tonic-gate restore 1057c478bd9Sstevel@tonic-gate .size elf_rtbndr, . - elf_rtbndr 1067c478bd9Sstevel@tonic-gate 1077c478bd9Sstevel@tonic-gate#endif 1087c478bd9Sstevel@tonic-gate 1097c478bd9Sstevel@tonic-gate 1107c478bd9Sstevel@tonic-gate#if defined(lint) 1117c478bd9Sstevel@tonic-gatevoid 1127c478bd9Sstevel@tonic-gateiflush_range(caddr_t addr, size_t len) 1137c478bd9Sstevel@tonic-gate{ 1147c478bd9Sstevel@tonic-gate /* LINTED */ 1157c478bd9Sstevel@tonic-gate uintptr_t base; 1167c478bd9Sstevel@tonic-gate 1177c478bd9Sstevel@tonic-gate base = (uintptr_t)addr & ~7; /* round down to 8 byte alignment */ 1187c478bd9Sstevel@tonic-gate len = (len + 7) & ~7; /* round up to multiple of 8 bytes */ 1197c478bd9Sstevel@tonic-gate for (len -= 8; (long)len >= 0; len -= 8) 1207c478bd9Sstevel@tonic-gate /* iflush(base + len) */; 1217c478bd9Sstevel@tonic-gate} 1227c478bd9Sstevel@tonic-gate#else 1237c478bd9Sstevel@tonic-gate ENTRY(iflush_range) 1247c478bd9Sstevel@tonic-gate add %o1, 7, %o1 1257c478bd9Sstevel@tonic-gate andn %o0, 7, %o0 1267c478bd9Sstevel@tonic-gate andn %o1, 7, %o1 1277c478bd9Sstevel@tonic-gate1: subcc %o1, 8, %o1 1287c478bd9Sstevel@tonic-gate bge,a 1b 1297c478bd9Sstevel@tonic-gate iflush %o0 + %o1 1307c478bd9Sstevel@tonic-gate retl 1317c478bd9Sstevel@tonic-gate nop 1327c478bd9Sstevel@tonic-gate SET_SIZE(iflush_range) 1337c478bd9Sstevel@tonic-gate#endif 1347c478bd9Sstevel@tonic-gate 1357c478bd9Sstevel@tonic-gate/* 1367c478bd9Sstevel@tonic-gate * Initialize the first plt entry so that function calls go to elf_rtbndr 1377c478bd9Sstevel@tonic-gate * 1387c478bd9Sstevel@tonic-gate * The first plt entry (PLT0) is: 1397c478bd9Sstevel@tonic-gate * 1407c478bd9Sstevel@tonic-gate * save %sp, -64, %sp 1417c478bd9Sstevel@tonic-gate * call elf_rtbndr 1427c478bd9Sstevel@tonic-gate * nop 1437c478bd9Sstevel@tonic-gate * address of lm 1447c478bd9Sstevel@tonic-gate */ 1457c478bd9Sstevel@tonic-gate 1467c478bd9Sstevel@tonic-gate#if defined(lint) 1477c478bd9Sstevel@tonic-gate 1487c478bd9Sstevel@tonic-gatevoid 1497c478bd9Sstevel@tonic-gateelf_plt_init(void *plt, caddr_t lmp) 1507c478bd9Sstevel@tonic-gate{ 1517c478bd9Sstevel@tonic-gate *((uint_t *)plt + 0) = (unsigned long) M_SAVESP64; 1527c478bd9Sstevel@tonic-gate *((uint_t *)plt + 4) = M_CALL | (((unsigned long)elf_rtbndr - 1537c478bd9Sstevel@tonic-gate ((unsigned long)plt)) >> 2); 1547c478bd9Sstevel@tonic-gate *((uint_t *)plt + 8) = M_NOP; 1557c478bd9Sstevel@tonic-gate *((uint_t *)plt + 12) = (unsigned long) lmp; 1567c478bd9Sstevel@tonic-gate} 1577c478bd9Sstevel@tonic-gate 1587c478bd9Sstevel@tonic-gate#else 1597c478bd9Sstevel@tonic-gate .global elf_plt_init 1607c478bd9Sstevel@tonic-gate .type elf_plt_init, #function 1617c478bd9Sstevel@tonic-gate .align 4 1627c478bd9Sstevel@tonic-gate 1637c478bd9Sstevel@tonic-gateelf_plt_init: 1647c478bd9Sstevel@tonic-gate save %sp, -SA(MINFRAME), %sp ! Make a frame 1657c478bd9Sstevel@tonic-gate1: 1667c478bd9Sstevel@tonic-gate call 2f 1677c478bd9Sstevel@tonic-gate sethi %hi((_GLOBAL_OFFSET_TABLE_ - (1b - .))), %l7 1687c478bd9Sstevel@tonic-gate2: 1697c478bd9Sstevel@tonic-gate sethi %hi(M_SAVESP64), %o0 ! Get save instruction 1707c478bd9Sstevel@tonic-gate or %o0, %lo(M_SAVESP64), %o0 1717c478bd9Sstevel@tonic-gate or %l7, %lo((_GLOBAL_OFFSET_TABLE_ - (1b - .))), %l7 1727c478bd9Sstevel@tonic-gate st %o0, [%i0] ! Store in plt[0] 1737c478bd9Sstevel@tonic-gate iflush %i0 1747c478bd9Sstevel@tonic-gate add %l7, %o7, %l7 1757c478bd9Sstevel@tonic-gate ld [%l7 + elf_rtbndr], %l7 1767c478bd9Sstevel@tonic-gate inc 4, %i0 ! Bump plt to point to plt[1] 1777c478bd9Sstevel@tonic-gate sub %l7, %i0, %o0 ! Determine -pc so as to produce 1787c478bd9Sstevel@tonic-gate ! offset from plt[1] 1797c478bd9Sstevel@tonic-gate srl %o0, 2, %o0 ! Express offset as number of words 1807c478bd9Sstevel@tonic-gate sethi %hi(M_CALL), %o4 ! Get sethi instruction 1817c478bd9Sstevel@tonic-gate or %o4, %o0, %o4 ! Add elf_rtbndr address 1827c478bd9Sstevel@tonic-gate st %o4, [%i0] ! Store instruction in plt 1837c478bd9Sstevel@tonic-gate iflush %i0 1847c478bd9Sstevel@tonic-gate sethi %hi(M_NOP), %o0 ! Generate nop instruction 1857c478bd9Sstevel@tonic-gate st %o0, [%i0 + 4] ! Store instruction in plt[2] 1867c478bd9Sstevel@tonic-gate iflush %i0 + 4 1877c478bd9Sstevel@tonic-gate st %i1, [%i0 + 8] ! Store instruction in plt[3] 1887c478bd9Sstevel@tonic-gate iflush %i0 + 8 1897c478bd9Sstevel@tonic-gate ret 1907c478bd9Sstevel@tonic-gate restore 1917c478bd9Sstevel@tonic-gate .size elf_plt_init, . - elf_plt_init 1927c478bd9Sstevel@tonic-gate#endif 1937c478bd9Sstevel@tonic-gate 1947c478bd9Sstevel@tonic-gate#if defined(lint) 1957c478bd9Sstevel@tonic-gate 1967c478bd9Sstevel@tonic-gateulong_t 1977c478bd9Sstevel@tonic-gateelf_plt_trace() 1987c478bd9Sstevel@tonic-gate{ 1997c478bd9Sstevel@tonic-gate return (0); 2007c478bd9Sstevel@tonic-gate} 2017c478bd9Sstevel@tonic-gate#else 2027c478bd9Sstevel@tonic-gate .global elf_plt_trace 2037c478bd9Sstevel@tonic-gate .type elf_plt_trace, #function 2047c478bd9Sstevel@tonic-gate .align 4 2057c478bd9Sstevel@tonic-gate 2067c478bd9Sstevel@tonic-gate/* 2077c478bd9Sstevel@tonic-gate * The dyn_plt that called us has already created a stack-frame for 2087c478bd9Sstevel@tonic-gate * us and placed the following entries in it: 2097c478bd9Sstevel@tonic-gate * 2107c478bd9Sstevel@tonic-gate * [%fp - 0x4] * dyndata 2117c478bd9Sstevel@tonic-gate * [%fp - 0x8] * prev stack size 2127c478bd9Sstevel@tonic-gate * 2137c478bd9Sstevel@tonic-gate * dyndata currently contains: 2147c478bd9Sstevel@tonic-gate * 2157c478bd9Sstevel@tonic-gate * dyndata: 2167c478bd9Sstevel@tonic-gate * 0x0 uintptr_t *reflmp 2177c478bd9Sstevel@tonic-gate * 0x4 uintptr_t *deflmp 2187c478bd9Sstevel@tonic-gate * 0x8 ulong_t symndx 2197c478bd9Sstevel@tonic-gate * 0xc ulong_t sb_flags 2207c478bd9Sstevel@tonic-gate * 0x10 Sym symdef.st_name 2217c478bd9Sstevel@tonic-gate * 0x14 symdef.st_value 2227c478bd9Sstevel@tonic-gate * 0x18 symdef.st_size 2237c478bd9Sstevel@tonic-gate * 0x1c symdef.st_info 2247c478bd9Sstevel@tonic-gate * 0x1d symdef.st_other 2257c478bd9Sstevel@tonic-gate * 0x1e symdef.st_shndx 2267c478bd9Sstevel@tonic-gate */ 2277c478bd9Sstevel@tonic-gate#define REFLMP_OFF 0x0 2287c478bd9Sstevel@tonic-gate#define DEFLMP_OFF 0x4 2297c478bd9Sstevel@tonic-gate#define SYMNDX_OFF 0x8 2307c478bd9Sstevel@tonic-gate#define SBFLAGS_OFF 0xc 2317c478bd9Sstevel@tonic-gate#define SYMDEF_OFF 0x10 2327c478bd9Sstevel@tonic-gate#define SYMDEF_VALUE_OFF 0x14 2337c478bd9Sstevel@tonic-gate 2347c478bd9Sstevel@tonic-gateelf_plt_trace: 2357c478bd9Sstevel@tonic-gate1: call 2f 2367c478bd9Sstevel@tonic-gate sethi %hi(_GLOBAL_OFFSET_TABLE_+(.-1b)), %l7 2377c478bd9Sstevel@tonic-gate2: or %l7, %lo(_GLOBAL_OFFSET_TABLE_+(.-1b)), %l7 2387c478bd9Sstevel@tonic-gate add %l7, %o7, %l7 2397c478bd9Sstevel@tonic-gate 2407c478bd9Sstevel@tonic-gate ld [%l7+audit_flags], %l3 2417c478bd9Sstevel@tonic-gate ld [%l3], %l3 ! %l3 = audit_flags 2427c478bd9Sstevel@tonic-gate andcc %l3, AF_PLTENTER, %g0 2437c478bd9Sstevel@tonic-gate beq .end_pltenter 2447c478bd9Sstevel@tonic-gate ld [%fp + -0x4], %l1 ! l1 = * dyndata 2457c478bd9Sstevel@tonic-gate ld [%l1 + SBFLAGS_OFF], %l2 ! l2 = sb_flags 2467c478bd9Sstevel@tonic-gate andcc %l2, LA_SYMB_NOPLTENTER, %g0 2477c478bd9Sstevel@tonic-gate beq .start_pltenter 2487c478bd9Sstevel@tonic-gate ld [%l1 + SYMDEF_VALUE_OFF], %l0 ! l0 = 2497c478bd9Sstevel@tonic-gate ! sym.st_value(calling address) 2507c478bd9Sstevel@tonic-gate ba .end_pltenter 2517c478bd9Sstevel@tonic-gate nop 2527c478bd9Sstevel@tonic-gate 2537c478bd9Sstevel@tonic-gate /* 2547c478bd9Sstevel@tonic-gate * save all registers into La_sparcv8_regs 2557c478bd9Sstevel@tonic-gate */ 2567c478bd9Sstevel@tonic-gate.start_pltenter: 2577c478bd9Sstevel@tonic-gate sub %sp, 0x20, %sp ! create space for La_sparcv8_regs 2587c478bd9Sstevel@tonic-gate ! storage on the stack. 2597c478bd9Sstevel@tonic-gate 2607c478bd9Sstevel@tonic-gate sub %fp, 0x28, %o4 2617c478bd9Sstevel@tonic-gate 2627c478bd9Sstevel@tonic-gate st %i0, [%o4] 2637c478bd9Sstevel@tonic-gate st %i1, [%o4 + 0x4] 2647c478bd9Sstevel@tonic-gate st %i2, [%o4 + 0x8] 2657c478bd9Sstevel@tonic-gate st %i3, [%o4 + 0xc] ! because a regwindow shift has 2667c478bd9Sstevel@tonic-gate st %i4, [%o4 + 0x10] ! already occured our current %i* 2677c478bd9Sstevel@tonic-gate st %i5, [%o4 + 0x14] ! register's are the equivalent of 2687c478bd9Sstevel@tonic-gate st %i6, [%o4 + 0x18] ! the %o* registers that the final 2697c478bd9Sstevel@tonic-gate st %i7, [%o4 + 0x1c] ! procedure shall see. 2707c478bd9Sstevel@tonic-gate 2717c478bd9Sstevel@tonic-gate ld [%fp + -0x4], %l1 ! %l1 == * dyndata 2727c478bd9Sstevel@tonic-gate ld [%l1 + REFLMP_OFF], %o0 ! %o0 = reflmp 2737c478bd9Sstevel@tonic-gate ld [%l1 + DEFLMP_OFF], %o1 ! %o1 = deflmp 2747c478bd9Sstevel@tonic-gate add %l1, SYMDEF_OFF, %o2 ! %o2 = symp 2757c478bd9Sstevel@tonic-gate ld [%l1 + SYMNDX_OFF], %o3 ! %o3 = symndx 2767c478bd9Sstevel@tonic-gate call audit_pltenter 2777c478bd9Sstevel@tonic-gate add %l1, SBFLAGS_OFF, %o5 ! %o3 = * sb_flags 2787c478bd9Sstevel@tonic-gate 2797c478bd9Sstevel@tonic-gate mov %o0, %l0 ! %l0 == calling address 2807c478bd9Sstevel@tonic-gate 2817c478bd9Sstevel@tonic-gate add %sp, 0x20, %sp ! cleanup La_sparcv8_regs off 2827c478bd9Sstevel@tonic-gate ! of the stack. 2837c478bd9Sstevel@tonic-gate 2847c478bd9Sstevel@tonic-gate.end_pltenter: 2857c478bd9Sstevel@tonic-gate /* 2867c478bd9Sstevel@tonic-gate * If *no* la_pltexit() routines exist we do not need to keep the 2877c478bd9Sstevel@tonic-gate * stack frame before we call the actual routine. Instead we jump to 2887c478bd9Sstevel@tonic-gate * it and remove our self from the stack at the same time. 2897c478bd9Sstevel@tonic-gate */ 2907c478bd9Sstevel@tonic-gate ld [%l7+audit_flags], %l3 2917c478bd9Sstevel@tonic-gate ld [%l3], %l3 ! %l3 = audit_flags 2927c478bd9Sstevel@tonic-gate andcc %l3, AF_PLTEXIT, %g0 2937c478bd9Sstevel@tonic-gate beq .bypass_pltexit 2947c478bd9Sstevel@tonic-gate ld [%fp + -0x4], %l1 ! %l1 = * dyndata 2957c478bd9Sstevel@tonic-gate ld [%l1 + SBFLAGS_OFF], %l2 ! %l2 = sb_flags 2967c478bd9Sstevel@tonic-gate andcc %l2, LA_SYMB_NOPLTEXIT, %g0 2977c478bd9Sstevel@tonic-gate bne .bypass_pltexit 2987c478bd9Sstevel@tonic-gate nop 2997c478bd9Sstevel@tonic-gate 3007c478bd9Sstevel@tonic-gate ba .start_pltexit 3017c478bd9Sstevel@tonic-gate nop 3027c478bd9Sstevel@tonic-gate.bypass_pltexit: 3037c478bd9Sstevel@tonic-gate jmpl %l0, %g0 3047c478bd9Sstevel@tonic-gate restore 3057c478bd9Sstevel@tonic-gate 3067c478bd9Sstevel@tonic-gate.start_pltexit: 3077c478bd9Sstevel@tonic-gate /* 3087c478bd9Sstevel@tonic-gate * In order to call la_pltexit() we must duplicate the 3097c478bd9Sstevel@tonic-gate * arguments from the 'callers' stack on our stack frame. 3107c478bd9Sstevel@tonic-gate * 3117c478bd9Sstevel@tonic-gate * First we check the size of the callers stack and grow 3127c478bd9Sstevel@tonic-gate * our stack to hold any of the arguments. That need 3137c478bd9Sstevel@tonic-gate * duplicating (these are arguments 6->N), because the 3147c478bd9Sstevel@tonic-gate * first 6 (0->5) are passed via register windows on sparc. 3157c478bd9Sstevel@tonic-gate */ 3167c478bd9Sstevel@tonic-gate 3177c478bd9Sstevel@tonic-gate /* 3187c478bd9Sstevel@tonic-gate * The first calculation is to determine how large the 3197c478bd9Sstevel@tonic-gate * argument passing area might be. Since there is no 3207c478bd9Sstevel@tonic-gate * way to distinquish between 'argument passing' and 3217c478bd9Sstevel@tonic-gate * 'local storage' from the previous stack this amount must 3227c478bd9Sstevel@tonic-gate * cover both. 3237c478bd9Sstevel@tonic-gate */ 3247c478bd9Sstevel@tonic-gate ld [%fp + -0x8], %l1 ! %l1 = callers stack size 3257c478bd9Sstevel@tonic-gate sub %l1, 0x58, %l1 ! %l1 = argument space on caller's 3267c478bd9Sstevel@tonic-gate ! stack 3277c478bd9Sstevel@tonic-gate /* 3287c478bd9Sstevel@tonic-gate * Next we compare the prev. stack size against the audit_argcnt. 3297c478bd9Sstevel@tonic-gate * We copy at most 'audit_argcnt' arguments. 3307c478bd9Sstevel@tonic-gate * 3317c478bd9Sstevel@tonic-gate * NOTE: on sparc we always copy at least six args since these 3327c478bd9Sstevel@tonic-gate * are in reg-windows and not on the stack. 3337c478bd9Sstevel@tonic-gate * 3347c478bd9Sstevel@tonic-gate * NOTE: Also note that we multiply (shift really) the arg count 3357c478bd9Sstevel@tonic-gate * by 4 which is the 'word size' to calculate the amount 3367c478bd9Sstevel@tonic-gate * of stack space needed. 3377c478bd9Sstevel@tonic-gate */ 3387c478bd9Sstevel@tonic-gate ld [%l7 + audit_argcnt], %l2 3397c478bd9Sstevel@tonic-gate ld [%l2], %l2 ! %l2 = audit_arg_count 3407c478bd9Sstevel@tonic-gate cmp %l2, 6 3417c478bd9Sstevel@tonic-gate ble .grow_stack 3427c478bd9Sstevel@tonic-gate sub %l2, 6, %l2 3437c478bd9Sstevel@tonic-gate sll %l2, 2, %l2 3447c478bd9Sstevel@tonic-gate cmp %l1, %l2 3457c478bd9Sstevel@tonic-gate ble .grow_stack 3467c478bd9Sstevel@tonic-gate nop 3477c478bd9Sstevel@tonic-gate mov %l2, %l1 3487c478bd9Sstevel@tonic-gate.grow_stack: 3497c478bd9Sstevel@tonic-gate /* 3507c478bd9Sstevel@tonic-gate * When duplicating the stack we skip the first '0x5c' bytes. 3517c478bd9Sstevel@tonic-gate * This is the space on the stack reserved for preserving 3527c478bd9Sstevel@tonic-gate * the register windows and such and do not need to be duplicated 3537c478bd9Sstevel@tonic-gate * on this new stack frame. We start duplicating at the 3547c478bd9Sstevel@tonic-gate * portion of the stack reserved for argument's above 6. 3557c478bd9Sstevel@tonic-gate */ 3567c478bd9Sstevel@tonic-gate sub %sp, %l1, %sp ! grow our stack by amount required. 3577c478bd9Sstevel@tonic-gate sra %l1, 0x2, %l1 ! %l1 = %l1 / 4 (words to copy) 3587c478bd9Sstevel@tonic-gate mov 0x5c, %l2 ! %l2 = index into stack & frame 3597c478bd9Sstevel@tonic-gate 3607c478bd9Sstevel@tonic-gate1: 3617c478bd9Sstevel@tonic-gate cmp %l1, 0 3627c478bd9Sstevel@tonic-gate ble 2f 3637c478bd9Sstevel@tonic-gate nop 3647c478bd9Sstevel@tonic-gate ld [%fp + %l2], %l3 ! duplicate args from previous 3657c478bd9Sstevel@tonic-gate st %l3, [%sp + %l2] ! stack onto current stack 3667c478bd9Sstevel@tonic-gate add %l2, 0x4, %l2 3677c478bd9Sstevel@tonic-gate ba 1b 3687c478bd9Sstevel@tonic-gate sub %l1, 0x1, %l1 3697c478bd9Sstevel@tonic-gate2: 3707c478bd9Sstevel@tonic-gate mov %i0, %o0 ! copy ins to outs 3717c478bd9Sstevel@tonic-gate mov %i1, %o1 3727c478bd9Sstevel@tonic-gate mov %i2, %o2 3737c478bd9Sstevel@tonic-gate mov %i3, %o3 3747c478bd9Sstevel@tonic-gate mov %i4, %o4 3757c478bd9Sstevel@tonic-gate call %l0 ! call routine 3767c478bd9Sstevel@tonic-gate mov %i5, %o5 3777c478bd9Sstevel@tonic-gate mov %o1, %l2 ! l2 = second 1/2 of return value 3787c478bd9Sstevel@tonic-gate ! for those those 64 bit operations 3797c478bd9Sstevel@tonic-gate ! link div64 - yuck... 3807c478bd9Sstevel@tonic-gate 3817c478bd9Sstevel@tonic-gate ! %o0 = retval 3827c478bd9Sstevel@tonic-gate ld [%fp + -0x4], %l1 3837c478bd9Sstevel@tonic-gate ld [%l1 + REFLMP_OFF], %o1 ! %o1 = reflmp 3847c478bd9Sstevel@tonic-gate ld [%l1 + DEFLMP_OFF], %o2 ! %o2 = deflmp 3857c478bd9Sstevel@tonic-gate add %l1, SYMDEF_OFF, %o3 ! %o3 = symp 3867c478bd9Sstevel@tonic-gate call audit_pltexit 3877c478bd9Sstevel@tonic-gate ld [%l1 + SYMNDX_OFF], %o4 ! %o4 = symndx 3887c478bd9Sstevel@tonic-gate 3897c478bd9Sstevel@tonic-gate mov %o0, %i0 ! pass on return code 3907c478bd9Sstevel@tonic-gate mov %l2, %i1 3917c478bd9Sstevel@tonic-gate ret 3927c478bd9Sstevel@tonic-gate restore 3937c478bd9Sstevel@tonic-gate .size elf_plt_trace, . - elf_plt_trace 3947c478bd9Sstevel@tonic-gate 3957c478bd9Sstevel@tonic-gate#endif 3967c478bd9Sstevel@tonic-gate 3977c478bd9Sstevel@tonic-gate/* 3987c478bd9Sstevel@tonic-gate * After the first call to a plt, elf_bndr() will have determined the true 3997c478bd9Sstevel@tonic-gate * address of the function being bound. The plt is now rewritten so that 4007c478bd9Sstevel@tonic-gate * any subsequent calls go directly to the bound function. If the library 4017c478bd9Sstevel@tonic-gate * to which the function belongs is being profiled refer to _plt_cg_write. 4027c478bd9Sstevel@tonic-gate * 4037c478bd9Sstevel@tonic-gate * the new plt entry is: 4047c478bd9Sstevel@tonic-gate * 4057c478bd9Sstevel@tonic-gate * sethi (.-PLT0), %g1 ! constant 4067c478bd9Sstevel@tonic-gate * sethi %hi(function address), %g1 ! patched second 4077c478bd9Sstevel@tonic-gate * jmpl %g1 + %lo(function address, %g0 ! patched first 4087c478bd9Sstevel@tonic-gate */ 4097c478bd9Sstevel@tonic-gate 4107c478bd9Sstevel@tonic-gate#if defined(lint) 4117c478bd9Sstevel@tonic-gate 4127c478bd9Sstevel@tonic-gatevoid 4137c478bd9Sstevel@tonic-gateplt_full_range(uintptr_t pc, uintptr_t symval) 4147c478bd9Sstevel@tonic-gate{ 4157c478bd9Sstevel@tonic-gate uint_t * plttab = (uint_t *)pc; 4167c478bd9Sstevel@tonic-gate plttab[2] = (M_JMPL | ((unsigned long)symval & S_MASK(10))); 4177c478bd9Sstevel@tonic-gate plttab[1] = (M_SETHIG1 | ((unsigned long)symval >> (32 - 22))); 4187c478bd9Sstevel@tonic-gate} 4197c478bd9Sstevel@tonic-gate 4207c478bd9Sstevel@tonic-gate#else 4217c478bd9Sstevel@tonic-gate ENTRY(plt_full_range) 4227c478bd9Sstevel@tonic-gate 4237c478bd9Sstevel@tonic-gate sethi %hi(M_JMPL), %o3 ! Get jmpl instruction 4247c478bd9Sstevel@tonic-gate and %o1, 0x3ff, %o2 ! Lower part of function address 4257c478bd9Sstevel@tonic-gate or %o3, %o2, %o3 ! is or'ed into instruction 4267c478bd9Sstevel@tonic-gate st %o3, [%o0 + 8] ! Store instruction in plt[2] 4277c478bd9Sstevel@tonic-gate iflush %o0 + 8 4287c478bd9Sstevel@tonic-gate stbar 4297c478bd9Sstevel@tonic-gate 4307c478bd9Sstevel@tonic-gate srl %o1, 10, %o1 ! Get high part of function address 4317c478bd9Sstevel@tonic-gate sethi %hi(M_SETHIG1), %o3 ! Get sethi instruction 4327c478bd9Sstevel@tonic-gate or %o3, %o1, %o3 ! Add sethi and function address 4337c478bd9Sstevel@tonic-gate st %o3, [%o0 + 4] ! Store instruction in plt[1] 4347c478bd9Sstevel@tonic-gate retl 4357c478bd9Sstevel@tonic-gate iflush %o0 + 4 4367c478bd9Sstevel@tonic-gate 4377c478bd9Sstevel@tonic-gate SET_SIZE(plt_full_range) 4387c478bd9Sstevel@tonic-gate 4397c478bd9Sstevel@tonic-gate#endif /* defined(lint) */ 4407c478bd9Sstevel@tonic-gate 441