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 "machdep.h" 327c478bd9Sstevel@tonic-gate#include "_audit.h" 337c478bd9Sstevel@tonic-gate#if defined(lint) 347c478bd9Sstevel@tonic-gate#include <sys/types.h> 357c478bd9Sstevel@tonic-gate#include "_rtld.h" 367c478bd9Sstevel@tonic-gate#else 377c478bd9Sstevel@tonic-gate#include <sys/stack.h> 387c478bd9Sstevel@tonic-gate#include <sys/asm_linkage.h> 397c478bd9Sstevel@tonic-gate 40*b02637afSrie .file "boot_elf.s" 417c478bd9Sstevel@tonic-gate .seg ".text" 427c478bd9Sstevel@tonic-gate#endif 437c478bd9Sstevel@tonic-gate 447c478bd9Sstevel@tonic-gate/* 457c478bd9Sstevel@tonic-gate * We got here because the initial call to a function resolved to a procedure 467c478bd9Sstevel@tonic-gate * linkage table entry. That entry did a branch to the first PLT entry, which 477c478bd9Sstevel@tonic-gate * in turn did a call to elf_rtbndr (refer elf_plt_init()). 487c478bd9Sstevel@tonic-gate * 497c478bd9Sstevel@tonic-gate * the code sequence that got us here was: 507c478bd9Sstevel@tonic-gate * 517c478bd9Sstevel@tonic-gate * PLT entry for foo(): 527c478bd9Sstevel@tonic-gate * sethi (.-PLT0), %g1 537c478bd9Sstevel@tonic-gate * ba,a .PLT0 ! patched atomically 2nd 547c478bd9Sstevel@tonic-gate * nop ! patched 1st 557c478bd9Sstevel@tonic-gate * nop 567c478bd9Sstevel@tonic-gate * nop 577c478bd9Sstevel@tonic-gate * nop 587c478bd9Sstevel@tonic-gate * nop 597c478bd9Sstevel@tonic-gate * nop 607c478bd9Sstevel@tonic-gate * 617c478bd9Sstevel@tonic-gate * Therefore on entry, %i7 has the address of the call, which will be added 627c478bd9Sstevel@tonic-gate * to the offset to the plt entry in %g1 to calculate the plt entry address 637c478bd9Sstevel@tonic-gate * we must also subtract 4 because the address of PLT0 points to the 647c478bd9Sstevel@tonic-gate * save instruction before the call. 657c478bd9Sstevel@tonic-gate * 667c478bd9Sstevel@tonic-gate * The PLT entry is rewritten in one of several ways. For the full 64-bit 677c478bd9Sstevel@tonic-gate * span, the following sequence is generated: 687c478bd9Sstevel@tonic-gate * 697c478bd9Sstevel@tonic-gate * nop 707c478bd9Sstevel@tonic-gate * sethi %hh(entry_pt), %g1 717c478bd9Sstevel@tonic-gate * sethi %lm(entry_pt), %g5 727c478bd9Sstevel@tonic-gate * or %g1, %hm(entry_pt), %g1 737c478bd9Sstevel@tonic-gate * sllx %g1, 32, %g1 747c478bd9Sstevel@tonic-gate * or %g1, %g5, %g5 757c478bd9Sstevel@tonic-gate * jmpl %g5 + %lo(entry_pt), %g0 767c478bd9Sstevel@tonic-gate * nop 777c478bd9Sstevel@tonic-gate * 787c478bd9Sstevel@tonic-gate * Shorter code sequences are possible, depending on reachability 797c478bd9Sstevel@tonic-gate * constraints. Note that 'call' is not as useful as it might seem in 807c478bd9Sstevel@tonic-gate * this context, because it is only capable of plus or minus 2Gbyte 817c478bd9Sstevel@tonic-gate * PC-relative jumps, and the rdpc instruction is very slow. 827c478bd9Sstevel@tonic-gate * 837c478bd9Sstevel@tonic-gate * At the time of writing, the present and future SPARC CPUs that will use 847c478bd9Sstevel@tonic-gate * this code are only capable of addressing the bottom 43-bits and top 43-bits 857c478bd9Sstevel@tonic-gate * of the address space. And since shared libraries are placed at the top 867c478bd9Sstevel@tonic-gate * of the address space, the "top 44-bits" sequence will effectively always be 877c478bd9Sstevel@tonic-gate * used. See elf_plt_write() below. The "top 32-bits" are used when they 887c478bd9Sstevel@tonic-gate * can reach. 897c478bd9Sstevel@tonic-gate */ 907c478bd9Sstevel@tonic-gate 917c478bd9Sstevel@tonic-gate#if defined(lint) 927c478bd9Sstevel@tonic-gate 937c478bd9Sstevel@tonic-gateextern unsigned long elf_bndr(Rt_map *, unsigned long, caddr_t); 947c478bd9Sstevel@tonic-gate 957c478bd9Sstevel@tonic-gate/* 967c478bd9Sstevel@tonic-gate * We're called here from .PLTn in a new frame, with %o0 containing 977c478bd9Sstevel@tonic-gate * the result of a sethi (. - .PLT0), and %o1 containing the pc of 987c478bd9Sstevel@tonic-gate * the jmpl instruction we're got here with inside .PLT1 997c478bd9Sstevel@tonic-gate */ 1007c478bd9Sstevel@tonic-gatevoid 1017c478bd9Sstevel@tonic-gateelf_rtbndr(Rt_map *lmp, unsigned long pltoff, caddr_t from) 1027c478bd9Sstevel@tonic-gate{ 1037c478bd9Sstevel@tonic-gate (void) elf_bndr(lmp, pltoff, from); 1047c478bd9Sstevel@tonic-gate} 1057c478bd9Sstevel@tonic-gate 1067c478bd9Sstevel@tonic-gate#else 1077c478bd9Sstevel@tonic-gate .weak _elf_rtbndr ! keep dbx happy as it likes to 1087c478bd9Sstevel@tonic-gate _elf_rtbndr = elf_rtbndr ! rummage around for our symbols 1097c478bd9Sstevel@tonic-gate 1107c478bd9Sstevel@tonic-gate ENTRY(elf_rtbndr) 1117c478bd9Sstevel@tonic-gate mov %i7, %o3 ! Save callers address(profiling) 1127c478bd9Sstevel@tonic-gate save %sp, -SA(MINFRAME), %sp 1137c478bd9Sstevel@tonic-gate mov %g4, %l5 ! Save g4 (safe across function calls) 1147c478bd9Sstevel@tonic-gate sub %i1, 0x38, %o1 ! compute addr of .PLT0 from addr of .PLT1 jmpl 1157c478bd9Sstevel@tonic-gate ldx [%o1 + 0x40], %o0 ! ld PLT2[X] into third arg 1167c478bd9Sstevel@tonic-gate srl %i0, 10, %o1 ! shift offset set by sethi 1177c478bd9Sstevel@tonic-gate call elf_bndr ! returns function address in %o0 1187c478bd9Sstevel@tonic-gate mov %i3, %o2 ! Callers address is arg 3 1197c478bd9Sstevel@tonic-gate mov %o0, %g1 ! save address of routine binded 1207c478bd9Sstevel@tonic-gate mov %l5, %g4 ! restore g4 1217c478bd9Sstevel@tonic-gate restore ! how many restores needed ? 2 1227c478bd9Sstevel@tonic-gate jmp %g1 ! jump to it 1237c478bd9Sstevel@tonic-gate restore 1247c478bd9Sstevel@tonic-gate SET_SIZE(elf_rtbndr) 1257c478bd9Sstevel@tonic-gate 1267c478bd9Sstevel@tonic-gate#endif 1277c478bd9Sstevel@tonic-gate 1287c478bd9Sstevel@tonic-gate 1297c478bd9Sstevel@tonic-gate#if defined(lint) 1307c478bd9Sstevel@tonic-gatevoid 1317c478bd9Sstevel@tonic-gateelf_rtbndr_far(Rt_map *lmp, unsigned long pltoff, caddr_t from) 1327c478bd9Sstevel@tonic-gate{ 1337c478bd9Sstevel@tonic-gate (void) elf_bndr(lmp, pltoff, from); 1347c478bd9Sstevel@tonic-gate} 1357c478bd9Sstevel@tonic-gate#else 1367c478bd9Sstevel@tonic-gateENTRY(elf_rtbndr_far) 1377c478bd9Sstevel@tonic-gate mov %i7, %o3 ! Save callers address 1387c478bd9Sstevel@tonic-gate save %sp, -SA(MINFRAME), %sp 1397c478bd9Sstevel@tonic-gate mov %g4, %l5 ! preserve %g4 1407c478bd9Sstevel@tonic-gate sub %i1, 0x18, %o2 ! compute address of .PLT0 from 1417c478bd9Sstevel@tonic-gate ! .PLT0 jmpl instr. 1427c478bd9Sstevel@tonic-gate sub %i0, %o2, %o1 ! pltoff = pc - 0x10 - .PLT0 1437c478bd9Sstevel@tonic-gate sub %o1, 0x10, %o1 1447c478bd9Sstevel@tonic-gate ldx [%o2 + 0x40], %o0 ! ld PLT2[X] into third arg 1457c478bd9Sstevel@tonic-gate call elf_bndr ! returns function address in %o0 1467c478bd9Sstevel@tonic-gate mov %i3, %o2 ! Callers address is arg3 1477c478bd9Sstevel@tonic-gate mov %o0, %g1 ! save address of routine binded 1487c478bd9Sstevel@tonic-gate mov %l5, %g4 ! restore g4 1497c478bd9Sstevel@tonic-gate restore ! how many restores needed ? 2 1507c478bd9Sstevel@tonic-gate jmp %g1 ! jump to it 1517c478bd9Sstevel@tonic-gate restore 1527c478bd9Sstevel@tonic-gateSET_SIZE(elf_rtbndr_far) 1537c478bd9Sstevel@tonic-gate#endif 1547c478bd9Sstevel@tonic-gate 1557c478bd9Sstevel@tonic-gate 1567c478bd9Sstevel@tonic-gate/* 1577c478bd9Sstevel@tonic-gate * Initialize a plt entry so that function calls go to 'bindfunc' 1587c478bd9Sstevel@tonic-gate * (We parameterize the binding function here because we call this 1597c478bd9Sstevel@tonic-gate * routine twice - once for PLT0 and once for PLT1 with different 1607c478bd9Sstevel@tonic-gate * binding functions.) 1617c478bd9Sstevel@tonic-gate * 1627c478bd9Sstevel@tonic-gate * The plt entries (PLT0 and PLT1) look like: 1637c478bd9Sstevel@tonic-gate * 1647c478bd9Sstevel@tonic-gate * save %sp, -176, %sp 1657c478bd9Sstevel@tonic-gate * sethi %hh(bindfunc), %l0 1667c478bd9Sstevel@tonic-gate * sethi %lm(bindfunc), %l1 1677c478bd9Sstevel@tonic-gate * or %l0, %hm(bindfunc), %l0 1687c478bd9Sstevel@tonic-gate * sllx %l0, 32, %l0 1697c478bd9Sstevel@tonic-gate * or %l0, %l1, %l0 1707c478bd9Sstevel@tonic-gate * jmpl %l0 + %lo(bindfunc), %o1 1717c478bd9Sstevel@tonic-gate * mov %g1, %o0 1727c478bd9Sstevel@tonic-gate */ 1737c478bd9Sstevel@tonic-gate 1747c478bd9Sstevel@tonic-gate#define M_SAVE_SP176SP 0x9de3bf50 /* save %sp, -176, %sp */ 1757c478bd9Sstevel@tonic-gate#define M_SETHI_L0 0x21000000 /* sethi 0x0, %l0 */ 1767c478bd9Sstevel@tonic-gate#define M_SETHI_L1 0x23000000 /* sethi 0x0, %l1 */ 1777c478bd9Sstevel@tonic-gate#define M_OR_L0L0 0xa0142000 /* or %l0, 0x0, %l0 */ 1787c478bd9Sstevel@tonic-gate#define M_SLLX_L032L0 0xa12c3020 /* sllx %l0, 32, %l0 */ 1797c478bd9Sstevel@tonic-gate#define M_OR_L0L1L0 0xa0140011 /* or %l0, %l1, %l0 */ 1807c478bd9Sstevel@tonic-gate#define M_JMPL_L0O1 0x93c42000 /* jmpl %l0 + 0, %o1 */ 1817c478bd9Sstevel@tonic-gate#define M_MOV_G1O0 0x90100001 /* or %g0, %g1, %o0 */ 1827c478bd9Sstevel@tonic-gate 1837c478bd9Sstevel@tonic-gate#if defined(lint) 1847c478bd9Sstevel@tonic-gate 1857c478bd9Sstevel@tonic-gate#define HH22(x) 0 /* for lint's benefit */ 1867c478bd9Sstevel@tonic-gate#define LM22(x) 0 1877c478bd9Sstevel@tonic-gate#define HM10(x) 0 1887c478bd9Sstevel@tonic-gate#define LO10(x) 0 1897c478bd9Sstevel@tonic-gate 1907c478bd9Sstevel@tonic-gate/* ARGSUSED */ 1917c478bd9Sstevel@tonic-gatevoid 1927c478bd9Sstevel@tonic-gateelf_plt_init(void *plt, caddr_t bindfunc) 1937c478bd9Sstevel@tonic-gate{ 1947c478bd9Sstevel@tonic-gate uint_t *_plt; 1957c478bd9Sstevel@tonic-gate 1967c478bd9Sstevel@tonic-gate _plt = (uint_t *)plt; 1977c478bd9Sstevel@tonic-gate _plt[0] = M_SAVE_SP176SP; 1987c478bd9Sstevel@tonic-gate _plt[1] = M_SETHI_L0 | HH22(bindfunc); 1997c478bd9Sstevel@tonic-gate _plt[2] = M_SETHI_L1 | LM22(bindfunc); 2007c478bd9Sstevel@tonic-gate _plt[3] = M_OR_L0L0 | HM10(bindfunc); 2017c478bd9Sstevel@tonic-gate _plt[4] = M_SLLX_L032L0; 2027c478bd9Sstevel@tonic-gate _plt[5] = M_OR_L0L1L0; 2037c478bd9Sstevel@tonic-gate _plt[6] = M_JMPL_L0O1 | LO10(bindfunc); 2047c478bd9Sstevel@tonic-gate _plt[7] = M_MOV_G1O0; 2057c478bd9Sstevel@tonic-gate} 2067c478bd9Sstevel@tonic-gate 2077c478bd9Sstevel@tonic-gate#else 2087c478bd9Sstevel@tonic-gate ENTRY(elf_plt_init) 2097c478bd9Sstevel@tonic-gate save %sp, -SA(MINFRAME), %sp ! Make a frame 2107c478bd9Sstevel@tonic-gate 2117c478bd9Sstevel@tonic-gate sethi %hi(M_SAVE_SP176SP), %o0 ! Get save instruction 2127c478bd9Sstevel@tonic-gate or %o0, %lo(M_SAVE_SP176SP), %o0 2137c478bd9Sstevel@tonic-gate st %o0, [%i0] ! Store in plt[0] 2147c478bd9Sstevel@tonic-gate 2157c478bd9Sstevel@tonic-gate sethi %hi(M_SETHI_L0), %o4 ! Get "sethi 0x0, %l0" insn 2167c478bd9Sstevel@tonic-gate srlx %i1, 42, %o2 ! get %hh(function address) 2177c478bd9Sstevel@tonic-gate or %o4, %o2, %o4 ! or value into instruction 2187c478bd9Sstevel@tonic-gate st %o4, [%i0 + 0x4] ! Store instruction in plt[1] 2197c478bd9Sstevel@tonic-gate iflush %i0 ! .. and flush 2207c478bd9Sstevel@tonic-gate 2217c478bd9Sstevel@tonic-gate sethi %hi(M_SETHI_L1), %o4 ! Get "sethi 0x0, %l1" insn 2227c478bd9Sstevel@tonic-gate srl %i1, 10, %o2 ! get %lm(function address) 2237c478bd9Sstevel@tonic-gate or %o4, %o2, %o4 ! or value into instruction 2247c478bd9Sstevel@tonic-gate st %o4, [%i0 + 0x8] ! Store instruction in plt[2] 2257c478bd9Sstevel@tonic-gate 2267c478bd9Sstevel@tonic-gate sethi %hi(M_OR_L0L0), %o4 ! Get "or %l0, 0x0, %l0" insn 2277c478bd9Sstevel@tonic-gate or %o4, %lo(M_OR_L0L0), %o4 2287c478bd9Sstevel@tonic-gate srlx %i1, 32, %o2 ! get %hm(function address) 2297c478bd9Sstevel@tonic-gate and %o2, 0x3ff, %o2 ! pick out bits 42-33 2307c478bd9Sstevel@tonic-gate or %o4, %o2, %o4 ! or value into instruction 2317c478bd9Sstevel@tonic-gate st %o4, [%i0 + 0xc] ! Store instruction in plt[3] 2327c478bd9Sstevel@tonic-gate iflush %i0 + 8 ! .. and flush 2337c478bd9Sstevel@tonic-gate 2347c478bd9Sstevel@tonic-gate sethi %hi(M_SLLX_L032L0), %o4 ! get "sllx %l0, 32, %l0" insn 2357c478bd9Sstevel@tonic-gate or %o4, %lo(M_SLLX_L032L0), %o4 2367c478bd9Sstevel@tonic-gate st %o4, [%i0 + 0x10] ! Store instruction in plt[4] 2377c478bd9Sstevel@tonic-gate 2387c478bd9Sstevel@tonic-gate sethi %hi(M_OR_L0L1L0), %o4 ! get "or %l0, %l1, %l0" insn 2397c478bd9Sstevel@tonic-gate or %o4, %lo(M_OR_L0L1L0), %o4 2407c478bd9Sstevel@tonic-gate st %o4, [%i0 + 0x14] ! Store instruction in plt[5] 2417c478bd9Sstevel@tonic-gate iflush %i0 + 0x10 ! .. and flush 2427c478bd9Sstevel@tonic-gate 2437c478bd9Sstevel@tonic-gate sethi %hi(M_JMPL_L0O1), %o4 ! get "jmpl %l0 + 0, %o1" insn 2447c478bd9Sstevel@tonic-gate or %o4, %lo(M_JMPL_L0O1), %o4 2457c478bd9Sstevel@tonic-gate and %i1, 0x3ff, %o2 ! get %lo(function address) 2467c478bd9Sstevel@tonic-gate or %o4, %o2, %o4 ! or value into instruction 2477c478bd9Sstevel@tonic-gate st %o4, [%i0 + 0x18] ! Store instruction in plt[6] 2487c478bd9Sstevel@tonic-gate 2497c478bd9Sstevel@tonic-gate sethi %hi(M_MOV_G1O0), %o4 ! get "mov %g1, %o0" insn 2507c478bd9Sstevel@tonic-gate or %o4, %lo(M_MOV_G1O0), %o4 2517c478bd9Sstevel@tonic-gate st %o4, [%i0 + 0x1c] ! Store instruction in plt[7] 2527c478bd9Sstevel@tonic-gate iflush %i0 + 0x18 ! .. and flush 2537c478bd9Sstevel@tonic-gate 2547c478bd9Sstevel@tonic-gate ret 2557c478bd9Sstevel@tonic-gate restore 2567c478bd9Sstevel@tonic-gate SET_SIZE(elf_plt_init) 2577c478bd9Sstevel@tonic-gate#endif 2587c478bd9Sstevel@tonic-gate 2597c478bd9Sstevel@tonic-gate 2607c478bd9Sstevel@tonic-gate 2617c478bd9Sstevel@tonic-gate 2627c478bd9Sstevel@tonic-gate#if defined(lint) 2637c478bd9Sstevel@tonic-gate/* 2647c478bd9Sstevel@tonic-gate * The V9 ABI assigns the link map identifier, the 2657c478bd9Sstevel@tonic-gate * Rt_map pointer, to the start of .PLT2. 2667c478bd9Sstevel@tonic-gate */ 2677c478bd9Sstevel@tonic-gatevoid 2687c478bd9Sstevel@tonic-gateelf_plt2_init(unsigned int *plt2, Rt_map * lmp) 2697c478bd9Sstevel@tonic-gate{ 2707c478bd9Sstevel@tonic-gate /* LINTED */ 2717c478bd9Sstevel@tonic-gate *(unsigned long *)plt2 = (unsigned long)lmp; 2727c478bd9Sstevel@tonic-gate} 2737c478bd9Sstevel@tonic-gate#else 2747c478bd9Sstevel@tonic-gate ENTRY(elf_plt2_init) 2757c478bd9Sstevel@tonic-gate stx %o1, [%o0] 2767c478bd9Sstevel@tonic-gate retl 2777c478bd9Sstevel@tonic-gate iflush %o0 2787c478bd9Sstevel@tonic-gate SET_SIZE(elf_plt2_init) 2797c478bd9Sstevel@tonic-gate#endif 2807c478bd9Sstevel@tonic-gate 2817c478bd9Sstevel@tonic-gate 2827c478bd9Sstevel@tonic-gate 2837c478bd9Sstevel@tonic-gate/* 2847c478bd9Sstevel@tonic-gate * After the first call to a plt, elf_bndr() will have determined the true 2857c478bd9Sstevel@tonic-gate * address of the function being bound. The plt is now rewritten so that 2867c478bd9Sstevel@tonic-gate * any subsequent calls go directly to the bound function. If the library 2877c478bd9Sstevel@tonic-gate * to which the function belongs is being profiled refer to _plt_cg_write. 2887c478bd9Sstevel@tonic-gate * 2897c478bd9Sstevel@tonic-gate * For complete 64-bit spanning, the new plt entry is: 2907c478bd9Sstevel@tonic-gate * 2917c478bd9Sstevel@tonic-gate * nop 2927c478bd9Sstevel@tonic-gate * sethi %hh(function address), %g1 2937c478bd9Sstevel@tonic-gate * sethi %lm(function address), %g5 2947c478bd9Sstevel@tonic-gate * or %g1, %hm(function address), %g1 2957c478bd9Sstevel@tonic-gate * sllx %g1, 32, %g1 2967c478bd9Sstevel@tonic-gate * or %g1, %g5, %g5 2977c478bd9Sstevel@tonic-gate * jmpl %g5, %lo(function address), %g0 2987c478bd9Sstevel@tonic-gate * nop 2997c478bd9Sstevel@tonic-gate * 3007c478bd9Sstevel@tonic-gate * However, shorter instruction sequences are possible and useful. 3017c478bd9Sstevel@tonic-gate * This version gets us anywhere in the top 44 bits of the 3027c478bd9Sstevel@tonic-gate * address space - since this is where shared objects live most 3037c478bd9Sstevel@tonic-gate * of the time, this case is worth optimizing. 3047c478bd9Sstevel@tonic-gate * 3057c478bd9Sstevel@tonic-gate * nop 3067c478bd9Sstevel@tonic-gate * sethi %h44(~function_address), %g5 3077c478bd9Sstevel@tonic-gate * xnor %g5, %m44(~function address), %g1 3087c478bd9Sstevel@tonic-gate * sllx %g1, 12, %g1 3097c478bd9Sstevel@tonic-gate * jmpl %g1 + %l44(function address), %g0 3107c478bd9Sstevel@tonic-gate * nop 3117c478bd9Sstevel@tonic-gate * nop 3127c478bd9Sstevel@tonic-gate * nop 3137c478bd9Sstevel@tonic-gate * 3147c478bd9Sstevel@tonic-gate * This version gets anywhere in the top 32 bits: 3157c478bd9Sstevel@tonic-gate * 3167c478bd9Sstevel@tonic-gate * nop 3177c478bd9Sstevel@tonic-gate * sethi %hi(~function_address), %g5 3187c478bd9Sstevel@tonic-gate * xnor %g5, %lo(~function_address), %g1 3197c478bd9Sstevel@tonic-gate * jmpl %g1, %g0 3207c478bd9Sstevel@tonic-gate * nop 3217c478bd9Sstevel@tonic-gate * nop 3227c478bd9Sstevel@tonic-gate * nop 3237c478bd9Sstevel@tonic-gate * nop 3247c478bd9Sstevel@tonic-gate * 3257c478bd9Sstevel@tonic-gate * This version get's us to a destination within 3267c478bd9Sstevel@tonic-gate * +- 8megs of the PLT's address: 3277c478bd9Sstevel@tonic-gate * 3287c478bd9Sstevel@tonic-gate * nop 3297c478bd9Sstevel@tonic-gate * ba,a <dest> 3307c478bd9Sstevel@tonic-gate * nop 3317c478bd9Sstevel@tonic-gate * nop 3327c478bd9Sstevel@tonic-gate * nop 3337c478bd9Sstevel@tonic-gate * nop 3347c478bd9Sstevel@tonic-gate * nop 3357c478bd9Sstevel@tonic-gate * nop 3367c478bd9Sstevel@tonic-gate * 3377c478bd9Sstevel@tonic-gate * This version get's us to a destination within 3387c478bd9Sstevel@tonic-gate * +- 2megs of the PLT's address: 3397c478bd9Sstevel@tonic-gate * 3407c478bd9Sstevel@tonic-gate * nop 3417c478bd9Sstevel@tonic-gate * ba,a,pt %icc, <dest> 3427c478bd9Sstevel@tonic-gate * nop 3437c478bd9Sstevel@tonic-gate * nop 3447c478bd9Sstevel@tonic-gate * nop 3457c478bd9Sstevel@tonic-gate * nop 3467c478bd9Sstevel@tonic-gate * nop 3477c478bd9Sstevel@tonic-gate * nop 3487c478bd9Sstevel@tonic-gate * 3497c478bd9Sstevel@tonic-gate * 3507c478bd9Sstevel@tonic-gate * The PLT is written in reverse order to ensure re-entrant behaviour. 3517c478bd9Sstevel@tonic-gate * Note that the first two instructions must be overwritten with a 3527c478bd9Sstevel@tonic-gate * single stx. 3537c478bd9Sstevel@tonic-gate * 3547c478bd9Sstevel@tonic-gate * Note that even in the 44-bit case, we deliberately use both %g5 and 3557c478bd9Sstevel@tonic-gate * %g1 to prevent anyone accidentally relying on either of them being 3567c478bd9Sstevel@tonic-gate * non-volatile across a function call. 3577c478bd9Sstevel@tonic-gate */ 3587c478bd9Sstevel@tonic-gate 3597c478bd9Sstevel@tonic-gate#define M_JMPL_G5G0 0x81c16000 /* jmpl %g5 + 0, %g0 */ 3607c478bd9Sstevel@tonic-gate#define M_OR_G1G5G5 0x8a104005 /* or %g1, %g5, %g5 */ 3617c478bd9Sstevel@tonic-gate#define M_SLLX_G132G1 0x83287020 /* sllx %g1, 32, %g1 */ 3627c478bd9Sstevel@tonic-gate#define M_OR_G1G1 0x82106000 /* or %g1, 0x0, %g1 */ 3637c478bd9Sstevel@tonic-gate#define M_SETHI_G5 0x0b000000 /* sethi 0x0, %g5 */ 3647c478bd9Sstevel@tonic-gate#define M_SETHI_G1 0x03000000 /* sethi 0x0, %g1 */ 3657c478bd9Sstevel@tonic-gate#define M_NOP 0x01000000 /* sethi 0x0, %g0 */ 3667c478bd9Sstevel@tonic-gate 3677c478bd9Sstevel@tonic-gate#define M_JMPL_G1G0 0x81c06000 /* jmpl %g1 + 0, %g0 */ 3687c478bd9Sstevel@tonic-gate#define M_SLLX_G112G1 0x8328700c /* sllx %g1, 12, %g1 */ 3697c478bd9Sstevel@tonic-gate#define M_XNOR_G5G1 0x82396000 /* xnor %g5, 0, %g1 */ 3707c478bd9Sstevel@tonic-gate 3717c478bd9Sstevel@tonic-gate#if defined(lint) 3727c478bd9Sstevel@tonic-gate 3737c478bd9Sstevel@tonic-gate/* ARGSUSED */ 3747c478bd9Sstevel@tonic-gate#define MASK(m) ((1ul << (m)) - 1ul) 3757c478bd9Sstevel@tonic-gate#define BITS(v, u, l) (((v) >> (l)) & MASK((u) - (l) + 1)) 3767c478bd9Sstevel@tonic-gate#define H44(v) BITS(v, 43, 22) 3777c478bd9Sstevel@tonic-gate#define M44(v) BITS(v, 21, 12) 3787c478bd9Sstevel@tonic-gate#define L44(v) BITS(v, 11, 0) 3797c478bd9Sstevel@tonic-gate 3807c478bd9Sstevel@tonic-gate#endif 3817c478bd9Sstevel@tonic-gate 3827c478bd9Sstevel@tonic-gate#if defined(lint) 3837c478bd9Sstevel@tonic-gate 3847c478bd9Sstevel@tonic-gatevoid 3857c478bd9Sstevel@tonic-gate/* ARGSUSED1 */ 3867c478bd9Sstevel@tonic-gateplt_upper_32(uintptr_t pc, uintptr_t symval) 3877c478bd9Sstevel@tonic-gate{ 3887c478bd9Sstevel@tonic-gate ulong_t sym = (ulong_t)symval; 3897c478bd9Sstevel@tonic-gate /* LINTED */ 3907c478bd9Sstevel@tonic-gate ulong_t nsym = ~sym; 3917c478bd9Sstevel@tonic-gate uint_t * plttab = (uint_t *)pc; 3927c478bd9Sstevel@tonic-gate 3937c478bd9Sstevel@tonic-gate plttab[3] = M_JMPL_G1G0; 3947c478bd9Sstevel@tonic-gate plttab[2] = (uint_t)(M_XNOR_G5G1 | LO10(nsym)); 3957c478bd9Sstevel@tonic-gate *(ulong_t *)pc = 3967c478bd9Sstevel@tonic-gate ((ulong_t)M_NOP << 32) | (M_SETHI_G5 | LM22(nsym)); 3977c478bd9Sstevel@tonic-gate} 3987c478bd9Sstevel@tonic-gate 3997c478bd9Sstevel@tonic-gate#else 4007c478bd9Sstevel@tonic-gate 4017c478bd9Sstevel@tonic-gate 4027c478bd9Sstevel@tonic-gate ENTRY(plt_upper_32) 4037c478bd9Sstevel@tonic-gate ! 4047c478bd9Sstevel@tonic-gate ! Address lies in top 32-bits of address space, so use 4057c478bd9Sstevel@tonic-gate ! compact PLT sequence 4067c478bd9Sstevel@tonic-gate ! 4077c478bd9Sstevel@tonic-gate sethi %hi(M_JMPL_G1G0), %o3 ! Get "jmpl %g1, %g0" insn 4087c478bd9Sstevel@tonic-gate st %o3, [%o0 + 0xc] ! store instruction in plt[3] 4097c478bd9Sstevel@tonic-gate iflush %o0 + 0xc ! .. and flush 4107c478bd9Sstevel@tonic-gate 4117c478bd9Sstevel@tonic-gate not %o1, %o4 4127c478bd9Sstevel@tonic-gate sethi %hi(M_XNOR_G5G1), %o3 ! Get "xnor %g5, %g1, %g1" insn 4137c478bd9Sstevel@tonic-gate and %o4, 0x3ff, %o2 ! pick out bits 0-9 4147c478bd9Sstevel@tonic-gate or %o3, %o2, %o3 ! or value into instruction 4157c478bd9Sstevel@tonic-gate st %o3, [%o0 + 0x8] ! store instruction in plt[2] 4167c478bd9Sstevel@tonic-gate iflush %o0 + 0x8 ! .. and flush 4177c478bd9Sstevel@tonic-gate 4187c478bd9Sstevel@tonic-gate sethi %hi(M_SETHI_G5), %o3 ! Get "sethi 0x0, %g5" insn 4197c478bd9Sstevel@tonic-gate srl %o4, 10, %o2 ! get %lm(~function address) 4207c478bd9Sstevel@tonic-gate or %o3, %o2, %o3 ! or value into instruction 4217c478bd9Sstevel@tonic-gate 4227c478bd9Sstevel@tonic-gate sethi %hi(M_NOP), %o4 ! Get "nop" instruction 4237c478bd9Sstevel@tonic-gate sllx %o4, 32, %o4 ! shift to top of instruction pair 4247c478bd9Sstevel@tonic-gate or %o3, %o4, %o3 ! or value into instruction pair 4257c478bd9Sstevel@tonic-gate stx %o3, [%o0] ! store instructions into plt[0] plt[1] 4267c478bd9Sstevel@tonic-gate retl 4277c478bd9Sstevel@tonic-gate iflush %o0 ! .. and flush 4287c478bd9Sstevel@tonic-gate SET_SIZE(plt_upper_32) 4297c478bd9Sstevel@tonic-gate#endif /* defined lint */ 4307c478bd9Sstevel@tonic-gate 4317c478bd9Sstevel@tonic-gate 4327c478bd9Sstevel@tonic-gate#if defined(lint) 4337c478bd9Sstevel@tonic-gate 4347c478bd9Sstevel@tonic-gatevoid 4357c478bd9Sstevel@tonic-gate/* ARGSUSED1 */ 4367c478bd9Sstevel@tonic-gateplt_upper_44(uintptr_t pc, uintptr_t symval) 4377c478bd9Sstevel@tonic-gate{ 4387c478bd9Sstevel@tonic-gate ulong_t sym = (ulong_t)symval; 4397c478bd9Sstevel@tonic-gate ulong_t nsym = ~sym; 4407c478bd9Sstevel@tonic-gate uint_t * plttab = (uint_t *)pc; 4417c478bd9Sstevel@tonic-gate 4427c478bd9Sstevel@tonic-gate /* LINTED */ 4437c478bd9Sstevel@tonic-gate plttab[4] = (uint_t)(M_JMPL_G1G0 | L44(sym)); 4447c478bd9Sstevel@tonic-gate plttab[3] = M_SLLX_G112G1; 4457c478bd9Sstevel@tonic-gate /* LINTED */ 4467c478bd9Sstevel@tonic-gate plttab[2] = (uint_t)(M_XNOR_G5G1 | M44(nsym)); 4477c478bd9Sstevel@tonic-gate *(ulong_t *)pc = ((ulong_t)M_NOP << 32) | (M_SETHI_G5 | H44(nsym)); 4487c478bd9Sstevel@tonic-gate} 4497c478bd9Sstevel@tonic-gate 4507c478bd9Sstevel@tonic-gate#else 4517c478bd9Sstevel@tonic-gate 4527c478bd9Sstevel@tonic-gate 4537c478bd9Sstevel@tonic-gate ENTRY(plt_upper_44) 4547c478bd9Sstevel@tonic-gate ! 4557c478bd9Sstevel@tonic-gate ! Address lies in top 44-bits of address space, so use 4567c478bd9Sstevel@tonic-gate ! compact PLT sequence 4577c478bd9Sstevel@tonic-gate ! 4587c478bd9Sstevel@tonic-gate setuw M_JMPL_G1G0, %o3 ! Get "jmpl %g1, %g0" insn 4597c478bd9Sstevel@tonic-gate and %o1, 0xfff, %o2 ! lower 12 bits of function address 4607c478bd9Sstevel@tonic-gate or %o3, %o2, %o3 ! is or'ed into instruction 4617c478bd9Sstevel@tonic-gate st %o3, [%o0 + 0x10] ! store instruction in plt[4] 4627c478bd9Sstevel@tonic-gate iflush %o0 + 0x10 ! .. and flush 4637c478bd9Sstevel@tonic-gate 4647c478bd9Sstevel@tonic-gate setuw M_SLLX_G112G1, %o3 ! Get "sllx %g1, 12, %g1" insn 4657c478bd9Sstevel@tonic-gate st %o3, [%o0 + 0xc] ! store instruction in plt[3] 4667c478bd9Sstevel@tonic-gate 4677c478bd9Sstevel@tonic-gate not %o1, %o4 4687c478bd9Sstevel@tonic-gate setuw M_XNOR_G5G1, %o3 ! Get "xnor %g5, 0, %g1" insn 4697c478bd9Sstevel@tonic-gate srlx %o4, 12, %o2 ! get %m44(0 - function address) 4707c478bd9Sstevel@tonic-gate and %o2, 0x3ff, %o2 ! pick out bits 21-12 4717c478bd9Sstevel@tonic-gate or %o3, %o2, %o3 ! or value into instruction 4727c478bd9Sstevel@tonic-gate st %o3, [%o0 + 8] ! store instruction in plt[2] 4737c478bd9Sstevel@tonic-gate iflush %o0 + 8 ! .. and flush 4747c478bd9Sstevel@tonic-gate 4757c478bd9Sstevel@tonic-gate setuw M_SETHI_G5, %o3 ! Get "sethi 0x0, %g5" insn 4767c478bd9Sstevel@tonic-gate srlx %o4, 22, %o2 ! get %h44(0 - function address) 4777c478bd9Sstevel@tonic-gate or %o3, %o2, %o3 ! or value into instruction 4787c478bd9Sstevel@tonic-gate 4797c478bd9Sstevel@tonic-gate setuw M_NOP, %o4 ! Get "nop" instruction 4807c478bd9Sstevel@tonic-gate sllx %o4, 32, %o4 ! shift to top of instruction pair 4817c478bd9Sstevel@tonic-gate or %o3, %o4, %o3 ! or value into instruction pair 4827c478bd9Sstevel@tonic-gate stx %o3, [%o0] ! store instructions into plt[0] plt[1] 4837c478bd9Sstevel@tonic-gate retl 4847c478bd9Sstevel@tonic-gate iflush %o0 ! .. and flush 4857c478bd9Sstevel@tonic-gate SET_SIZE(plt_upper_44) 4867c478bd9Sstevel@tonic-gate 4877c478bd9Sstevel@tonic-gate#endif /* defined(lint) */ 4887c478bd9Sstevel@tonic-gate 4897c478bd9Sstevel@tonic-gate 4907c478bd9Sstevel@tonic-gate#if defined(lint) 4917c478bd9Sstevel@tonic-gate 4927c478bd9Sstevel@tonic-gatevoid 4937c478bd9Sstevel@tonic-gate/* ARGSUSED1 */ 4947c478bd9Sstevel@tonic-gateplt_full_range(uintptr_t pc, uintptr_t symval) 4957c478bd9Sstevel@tonic-gate{ 4967c478bd9Sstevel@tonic-gate uint_t * plttab = (uint_t *)pc; 4977c478bd9Sstevel@tonic-gate 4987c478bd9Sstevel@tonic-gate plttab[6] = M_JMPL_G5G0 | LO10(symval); 4997c478bd9Sstevel@tonic-gate plttab[5] = M_OR_G1G5G5; 5007c478bd9Sstevel@tonic-gate plttab[4] = M_SLLX_G132G1; 5017c478bd9Sstevel@tonic-gate plttab[3] = M_OR_G1G1 | HM10(symval); 5027c478bd9Sstevel@tonic-gate plttab[2] = M_SETHI_G5 | LM22(symval); 5037c478bd9Sstevel@tonic-gate *(ulong_t *)pc = 5047c478bd9Sstevel@tonic-gate ((ulong_t)M_NOP << 32) | (M_SETHI_G1 | HH22(symval)); 5057c478bd9Sstevel@tonic-gate} 5067c478bd9Sstevel@tonic-gate 5077c478bd9Sstevel@tonic-gate#else 5087c478bd9Sstevel@tonic-gate ENTRY(plt_full_range) 5097c478bd9Sstevel@tonic-gate ! 5107c478bd9Sstevel@tonic-gate ! Address lies anywhere in 64-bit address space, so use 5117c478bd9Sstevel@tonic-gate ! full PLT sequence 5127c478bd9Sstevel@tonic-gate ! 5137c478bd9Sstevel@tonic-gate sethi %hi(M_JMPL_G5G0), %o3 ! Get "jmpl %g5, %g0" insn 5147c478bd9Sstevel@tonic-gate and %o1, 0x3ff, %o2 ! lower 10 bits of function address 5157c478bd9Sstevel@tonic-gate or %o3, %o2, %o3 ! is or'ed into instruction 5167c478bd9Sstevel@tonic-gate st %o3, [%o0 + 0x18] ! store instruction in plt[6] 5177c478bd9Sstevel@tonic-gate iflush %o0 + 0x18 ! .. and flush 5187c478bd9Sstevel@tonic-gate 5197c478bd9Sstevel@tonic-gate sethi %hi(M_OR_G1G5G5), %o3 ! Get "or %g1, %g5, %g1" insn 5207c478bd9Sstevel@tonic-gate or %o3, %lo(M_OR_G1G5G5), %o3 5217c478bd9Sstevel@tonic-gate st %o3, [%o0 + 0x14] ! store instruction in plt[5] 5227c478bd9Sstevel@tonic-gate 5237c478bd9Sstevel@tonic-gate sethi %hi(M_SLLX_G132G1), %o3 ! Get "sllx %g1, 32, %g1" insn 5247c478bd9Sstevel@tonic-gate or %o3, %lo(M_SLLX_G132G1), %o3 5257c478bd9Sstevel@tonic-gate st %o3, [%o0 + 0x10] ! store instruction in plt[4] 5267c478bd9Sstevel@tonic-gate iflush %o0 + 0x10 ! .. and flush 5277c478bd9Sstevel@tonic-gate 5287c478bd9Sstevel@tonic-gate sethi %hi(M_OR_G1G1), %o3 ! Get "or %g1, 0x0, %g1" insn 5297c478bd9Sstevel@tonic-gate or %o3, %lo(M_OR_G1G1), %o3 5307c478bd9Sstevel@tonic-gate srlx %o1, 32, %o2 ! get %hm(function address) 5317c478bd9Sstevel@tonic-gate and %o2, 0x3ff, %o2 ! pick out bits 42-33 5327c478bd9Sstevel@tonic-gate or %o3, %o2, %o3 ! or value into instruction 5337c478bd9Sstevel@tonic-gate st %o3, [%o0 + 0xc] ! store instruction in plt[3] 5347c478bd9Sstevel@tonic-gate 5357c478bd9Sstevel@tonic-gate sethi %hi(M_SETHI_G5), %o3 ! Get "sethi 0x0, %g5" insn 5367c478bd9Sstevel@tonic-gate srl %o1, 10, %o2 ! get %lm(function address) 5377c478bd9Sstevel@tonic-gate or %o3, %o2, %o3 ! or value into instruction 5387c478bd9Sstevel@tonic-gate st %o3, [%o0 + 0x8] ! store instruction in plt[2] 5397c478bd9Sstevel@tonic-gate iflush %o0 + 8 ! .. and flush 5407c478bd9Sstevel@tonic-gate 5417c478bd9Sstevel@tonic-gate sethi %hi(M_SETHI_G1), %o3 ! Get "sethi 0x0, %g1" insn 5427c478bd9Sstevel@tonic-gate srlx %o1, 42, %o2 ! get %hh(function address) 5437c478bd9Sstevel@tonic-gate or %o3, %o2, %o3 ! or value into instruction 5447c478bd9Sstevel@tonic-gate 5457c478bd9Sstevel@tonic-gate sethi %hi(M_NOP), %o4 ! Get "nop" instruction 5467c478bd9Sstevel@tonic-gate sllx %o4, 32, %o4 ! shift to top of instruction pair 5477c478bd9Sstevel@tonic-gate or %o3, %o4, %o3 ! or value into instruction pair 5487c478bd9Sstevel@tonic-gate stx %o3, [%o0] ! store instructions into plt[0] plt[1] 5497c478bd9Sstevel@tonic-gate retl 5507c478bd9Sstevel@tonic-gate iflush %o0 ! .. and flush 5517c478bd9Sstevel@tonic-gate 5527c478bd9Sstevel@tonic-gate SET_SIZE(plt_full_range) 5537c478bd9Sstevel@tonic-gate 5547c478bd9Sstevel@tonic-gate#endif /* defined(lint) */ 5557c478bd9Sstevel@tonic-gate 5567c478bd9Sstevel@tonic-gate/* 5577c478bd9Sstevel@tonic-gate * performs the 'iflush' instruction on a range of memory. 5587c478bd9Sstevel@tonic-gate */ 5597c478bd9Sstevel@tonic-gate#if defined(lint) 5607c478bd9Sstevel@tonic-gatevoid 5617c478bd9Sstevel@tonic-gateiflush_range(caddr_t addr, size_t len) 5627c478bd9Sstevel@tonic-gate{ 5637c478bd9Sstevel@tonic-gate /* LINTED */ 5647c478bd9Sstevel@tonic-gate uintptr_t base; 5657c478bd9Sstevel@tonic-gate 5667c478bd9Sstevel@tonic-gate base = (uintptr_t)addr & ~7; /* round down to 8 byte alignment */ 5677c478bd9Sstevel@tonic-gate len = (len + 7) & ~7; /* round up to multiple of 8 bytes */ 5687c478bd9Sstevel@tonic-gate for (len -= 8; (long)len >= 0; len -= 8) 5697c478bd9Sstevel@tonic-gate /* iflush(base + len) */; 5707c478bd9Sstevel@tonic-gate} 5717c478bd9Sstevel@tonic-gate#else 5727c478bd9Sstevel@tonic-gate ENTRY(iflush_range) 5737c478bd9Sstevel@tonic-gate add %o1, 7, %o1 5747c478bd9Sstevel@tonic-gate andn %o0, 7, %o0 5757c478bd9Sstevel@tonic-gate andn %o1, 7, %o1 5767c478bd9Sstevel@tonic-gate1: subcc %o1, 8, %o1 5777c478bd9Sstevel@tonic-gate bge,a,pt %xcc, 1b 5787c478bd9Sstevel@tonic-gate iflush %o0 + %o1 5797c478bd9Sstevel@tonic-gate retl 5807c478bd9Sstevel@tonic-gate nop 5817c478bd9Sstevel@tonic-gate SET_SIZE(iflush_range) 5827c478bd9Sstevel@tonic-gate#endif 5837c478bd9Sstevel@tonic-gate 5847c478bd9Sstevel@tonic-gate 5857c478bd9Sstevel@tonic-gate#if defined(lint) 5867c478bd9Sstevel@tonic-gate 5877c478bd9Sstevel@tonic-gateulong_t 5887c478bd9Sstevel@tonic-gateelf_plt_trace() 5897c478bd9Sstevel@tonic-gate{ 5907c478bd9Sstevel@tonic-gate return (0); 5917c478bd9Sstevel@tonic-gate} 5927c478bd9Sstevel@tonic-gate#else 5937c478bd9Sstevel@tonic-gate .global elf_plt_trace 5947c478bd9Sstevel@tonic-gate .type elf_plt_trace, #function 5957c478bd9Sstevel@tonic-gate 5967c478bd9Sstevel@tonic-gate/* 5977c478bd9Sstevel@tonic-gate * The dyn_plt that called us has already created a stack-frame for 5987c478bd9Sstevel@tonic-gate * us and placed the following entries in it: 5997c478bd9Sstevel@tonic-gate * 6007c478bd9Sstevel@tonic-gate * [%fp + STACK_BIAS + -0x8] * dyndata 6017c478bd9Sstevel@tonic-gate * [%fp + STACK_BIAS + -0x10] * prev stack size 6027c478bd9Sstevel@tonic-gate * 6037c478bd9Sstevel@tonic-gate * dyndata currently contains: 6047c478bd9Sstevel@tonic-gate * 6057c478bd9Sstevel@tonic-gate * dyndata: 6067c478bd9Sstevel@tonic-gate * 0x0 Addr *reflmp 6077c478bd9Sstevel@tonic-gate * 0x8 Addr *deflmp 6087c478bd9Sstevel@tonic-gate * 0x10 Word symndx 6097c478bd9Sstevel@tonic-gate * 0x14 Word sb_flags 6107c478bd9Sstevel@tonic-gate * 0x18 Sym symdef.st_name 6117c478bd9Sstevel@tonic-gate * 0x1c symdef.st_info 6127c478bd9Sstevel@tonic-gate * 0x1d symdef.st_other 6137c478bd9Sstevel@tonic-gate * 0x1e symdef.st_shndx 6147c478bd9Sstevel@tonic-gate * 0x20 symdef.st_value 6157c478bd9Sstevel@tonic-gate * 0x28 symdef.st_size 6167c478bd9Sstevel@tonic-gate */ 6177c478bd9Sstevel@tonic-gate#define REFLMP_OFF 0x0 6187c478bd9Sstevel@tonic-gate#define DEFLMP_OFF 0x8 6197c478bd9Sstevel@tonic-gate#define SYMNDX_OFF 0x10 6207c478bd9Sstevel@tonic-gate#define SBFLAGS_OFF 0x14 6217c478bd9Sstevel@tonic-gate#define SYMDEF_OFF 0x18 6227c478bd9Sstevel@tonic-gate#define SYMDEF_VALUE_OFF 0x20 6237c478bd9Sstevel@tonic-gate 6247c478bd9Sstevel@tonic-gate#define LAREGSSZ 0x40 /* sizeof (La_sparcv9_regs) */ 6257c478bd9Sstevel@tonic-gate 6267c478bd9Sstevel@tonic-gate 6277c478bd9Sstevel@tonic-gateelf_plt_trace: 6287c478bd9Sstevel@tonic-gate1: call 2f 6297c478bd9Sstevel@tonic-gate sethi %hi(_GLOBAL_OFFSET_TABLE_ - (1b - .)), %l7 6307c478bd9Sstevel@tonic-gate2: or %l7, %lo(_GLOBAL_OFFSET_TABLE_ - (1b - .)), %l7 6317c478bd9Sstevel@tonic-gate add %l7, %o7, %l7 6327c478bd9Sstevel@tonic-gate 6337c478bd9Sstevel@tonic-gate ldx [%fp + STACK_BIAS + -CLONGSIZE], %l1 ! l1 = * dyndata 6347c478bd9Sstevel@tonic-gate lduw [%l1 + SBFLAGS_OFF], %l2 ! l2 = sb_flags 6357c478bd9Sstevel@tonic-gate andcc %l2, LA_SYMB_NOPLTENTER, %g0 6367c478bd9Sstevel@tonic-gate be,pt %icc, .start_pltenter 6377c478bd9Sstevel@tonic-gate ldx [%l1 + SYMDEF_VALUE_OFF], %l0 ! l0 = 6387c478bd9Sstevel@tonic-gate ! sym.st_value(calling address) 6397c478bd9Sstevel@tonic-gate ba,a,pt %icc, .end_pltenter 6407c478bd9Sstevel@tonic-gate nop 6417c478bd9Sstevel@tonic-gate 6427c478bd9Sstevel@tonic-gate /* 6437c478bd9Sstevel@tonic-gate * save all registers into La_sparcv9_regs 6447c478bd9Sstevel@tonic-gate */ 6457c478bd9Sstevel@tonic-gate.start_pltenter: 6467c478bd9Sstevel@tonic-gate sub %sp, LAREGSSZ, %sp ! create space for La_sparcv9_regs 6477c478bd9Sstevel@tonic-gate ! storage on the stack. 6487c478bd9Sstevel@tonic-gate 6497c478bd9Sstevel@tonic-gate add %fp, STACK_BIAS - (LAREGSSZ + (2 * CLONGSIZE)), %o4 ! addr of new space. 6507c478bd9Sstevel@tonic-gate 6517c478bd9Sstevel@tonic-gate stx %i0, [%o4 + 0x0] 6527c478bd9Sstevel@tonic-gate stx %i1, [%o4 + 0x8] 6537c478bd9Sstevel@tonic-gate stx %i2, [%o4 + 0x10] 6547c478bd9Sstevel@tonic-gate stx %i3, [%o4 + 0x18] ! because a regwindow shift has 6557c478bd9Sstevel@tonic-gate stx %i4, [%o4 + 0x20] ! already occured our current %i* 6567c478bd9Sstevel@tonic-gate stx %i5, [%o4 + 0x28] ! register's are the equivalent of 6577c478bd9Sstevel@tonic-gate stx %i6, [%o4 + 0x30] ! the %o* registers that the final 6587c478bd9Sstevel@tonic-gate stx %i7, [%o4 + 0x38] ! procedure shall see. 6597c478bd9Sstevel@tonic-gate mov %g4, %l5 ! save g4 (safe across function calls) 6607c478bd9Sstevel@tonic-gate 6617c478bd9Sstevel@tonic-gate 6627c478bd9Sstevel@tonic-gate ldx [%fp + STACK_BIAS + -CLONGSIZE], %l1 ! %l1 == * dyndata 6637c478bd9Sstevel@tonic-gate ldx [%l1 + REFLMP_OFF], %o0 ! %o0 = reflmp 6647c478bd9Sstevel@tonic-gate ldx [%l1 + DEFLMP_OFF], %o1 ! %o1 = deflmp 6657c478bd9Sstevel@tonic-gate add %l1, SYMDEF_OFF, %o2 ! %o2 = symp 6667c478bd9Sstevel@tonic-gate lduw [%l1 + SYMNDX_OFF], %o3 ! %o3 = symndx 6677c478bd9Sstevel@tonic-gate call audit_pltenter 6687c478bd9Sstevel@tonic-gate add %l1, SBFLAGS_OFF, %o5 ! %o3 = * sb_flags 6697c478bd9Sstevel@tonic-gate 6707c478bd9Sstevel@tonic-gate mov %o0, %l0 ! %l0 == calling address 6717c478bd9Sstevel@tonic-gate add %sp, LAREGSSZ, %sp ! cleanup La_sparcv9_regs off 6727c478bd9Sstevel@tonic-gate ! of the stack. 6737c478bd9Sstevel@tonic-gate 6747c478bd9Sstevel@tonic-gate.end_pltenter: 6757c478bd9Sstevel@tonic-gate /* 6767c478bd9Sstevel@tonic-gate * If *no* la_pltexit() routines exist we do not need 6777c478bd9Sstevel@tonic-gate * to keep the stack frame before we call the actual 6787c478bd9Sstevel@tonic-gate * routine. Instead we jump to it and remove ourself 6797c478bd9Sstevel@tonic-gate * from the stack at the same time. 6807c478bd9Sstevel@tonic-gate */ 6817c478bd9Sstevel@tonic-gate ldx [%l7+audit_flags], %l3 6827c478bd9Sstevel@tonic-gate lduw [%l3], %l3 ! %l3 = audit_flags 6837c478bd9Sstevel@tonic-gate andcc %l3, AF_PLTEXIT, %g0 ! AF_PLTEXIT = 2 6847c478bd9Sstevel@tonic-gate be,pt %icc, .bypass_pltexit 6857c478bd9Sstevel@tonic-gate ldx [%fp + STACK_BIAS + -CLONGSIZE], %l1 ! %l1 = * dyndata 6867c478bd9Sstevel@tonic-gate lduw [%l1 + SBFLAGS_OFF], %l2 ! %l2 = sb_flags 6877c478bd9Sstevel@tonic-gate andcc %l2, LA_SYMB_NOPLTEXIT, %g0 ! LA_SYMB_NOPLTEXIT = 2 6887c478bd9Sstevel@tonic-gate bne,a,pt %icc, .bypass_pltexit 6897c478bd9Sstevel@tonic-gate nop 6907c478bd9Sstevel@tonic-gate 6917c478bd9Sstevel@tonic-gate ba,a,pt %icc, .start_pltexit 6927c478bd9Sstevel@tonic-gate nop 6937c478bd9Sstevel@tonic-gate.bypass_pltexit: 6947c478bd9Sstevel@tonic-gate mov %l5, %g4 ! restore g4 6957c478bd9Sstevel@tonic-gate jmpl %l0, %g0 6967c478bd9Sstevel@tonic-gate restore 6977c478bd9Sstevel@tonic-gate 6987c478bd9Sstevel@tonic-gate.start_pltexit: 6997c478bd9Sstevel@tonic-gate /* 7007c478bd9Sstevel@tonic-gate * In order to call la_pltexit() we must duplicate the 7017c478bd9Sstevel@tonic-gate * arguments from the 'callers' stack on our stack frame. 7027c478bd9Sstevel@tonic-gate * 7037c478bd9Sstevel@tonic-gate * First we check the size of the callers stack and grow 7047c478bd9Sstevel@tonic-gate * our stack to hold any of the arguments that need 7057c478bd9Sstevel@tonic-gate * duplicating (these are arguments 6->N), because the 7067c478bd9Sstevel@tonic-gate * first 6 (0->5) are passed via register windows on sparc. 7077c478bd9Sstevel@tonic-gate */ 7087c478bd9Sstevel@tonic-gate 7097c478bd9Sstevel@tonic-gate /* 7107c478bd9Sstevel@tonic-gate * The first calculation is to determine how large the 7117c478bd9Sstevel@tonic-gate * argument passing area might be. Since there is no 7127c478bd9Sstevel@tonic-gate * way to distinquish between 'argument passing' and 7137c478bd9Sstevel@tonic-gate * 'local storage' from the previous stack this amount must 7147c478bd9Sstevel@tonic-gate * cover both. 7157c478bd9Sstevel@tonic-gate */ 7167c478bd9Sstevel@tonic-gate ldx [%fp + STACK_BIAS + -(2 * CLONGSIZE)], %l1 ! %l1 = callers 7177c478bd9Sstevel@tonic-gate ! stack size 7187c478bd9Sstevel@tonic-gate sub %l1, MINFRAME, %l1 ! %l1 = argument space on 7197c478bd9Sstevel@tonic-gate ! caller's stack 7207c478bd9Sstevel@tonic-gate /* 7217c478bd9Sstevel@tonic-gate * Next we compare the prev. stack size against the audit_argcnt. We 7227c478bd9Sstevel@tonic-gate * copy at most 'audit_argcnt' arguments. The default arg count is 64. 7237c478bd9Sstevel@tonic-gate * 7247c478bd9Sstevel@tonic-gate * NOTE: on sparc we always copy at least six args since these 7257c478bd9Sstevel@tonic-gate * are in reg-windows and not on the stack. 7267c478bd9Sstevel@tonic-gate * 7277c478bd9Sstevel@tonic-gate * NOTE: Also note that we multiply (shift really) the arg count 7287c478bd9Sstevel@tonic-gate * by 8 which is the 'word size' to calculate the amount 7297c478bd9Sstevel@tonic-gate * of stack space needed. 7307c478bd9Sstevel@tonic-gate */ 7317c478bd9Sstevel@tonic-gate ldx [%l7 + audit_argcnt], %l2 7327c478bd9Sstevel@tonic-gate lduw [%l2], %l2 ! %l2 = audit_argcnt 7337c478bd9Sstevel@tonic-gate cmp %l2, 6 7347c478bd9Sstevel@tonic-gate ble,pn %icc, .grow_stack 7357c478bd9Sstevel@tonic-gate sub %l2, 6, %l2 7367c478bd9Sstevel@tonic-gate sllx %l2, CLONGSHIFT, %l2 ! arg count * 8 7377c478bd9Sstevel@tonic-gate cmp %l1, %l2 ! 7387c478bd9Sstevel@tonic-gate ble,a,pn %icc, .grow_stack 7397c478bd9Sstevel@tonic-gate nop 7407c478bd9Sstevel@tonic-gate mov %l2, %l1 7417c478bd9Sstevel@tonic-gate.grow_stack: 7427c478bd9Sstevel@tonic-gate /* 7437c478bd9Sstevel@tonic-gate * When duplicating the stack we skip the first SA(MINFRAME) 7447c478bd9Sstevel@tonic-gate * bytes. This is the space on the stack reserved for preserving 7457c478bd9Sstevel@tonic-gate * the register windows and such and do not need to be duplicated 7467c478bd9Sstevel@tonic-gate * on this new stack frame. We start duplicating at the portion 7477c478bd9Sstevel@tonic-gate * of the stack reserved for argument's above 6. 7487c478bd9Sstevel@tonic-gate */ 7497c478bd9Sstevel@tonic-gate sub %sp, %l1, %sp ! grow our stack by amount required. 7507c478bd9Sstevel@tonic-gate srax %l1, CLONGSHIFT, %l1 ! %l1 = %l1 / 8 (words to copy) 7517c478bd9Sstevel@tonic-gate mov SA(MINFRAME), %l2 ! %l2 = index into stack & frame 7527c478bd9Sstevel@tonic-gate 7537c478bd9Sstevel@tonic-gate1: 7547c478bd9Sstevel@tonic-gate cmp %l1, 0 7557c478bd9Sstevel@tonic-gate ble,a,pn %icc, 2f 7567c478bd9Sstevel@tonic-gate nop 7577c478bd9Sstevel@tonic-gate 7587c478bd9Sstevel@tonic-gate add %fp, %l2, %l4 7597c478bd9Sstevel@tonic-gate ldx [%l4 + STACK_BIAS], %l3 ! duplicate args from previous 7607c478bd9Sstevel@tonic-gate add %sp, %l2, %l4 7617c478bd9Sstevel@tonic-gate stx %l3, [%l4 + STACK_BIAS] ! stack onto current stack 7627c478bd9Sstevel@tonic-gate 7637c478bd9Sstevel@tonic-gate add %l2, CLONGSIZE, %l2 7647c478bd9Sstevel@tonic-gate ba,pt %icc, 1b 7657c478bd9Sstevel@tonic-gate sub %l1, 0x1, %l1 7667c478bd9Sstevel@tonic-gate2: 7677c478bd9Sstevel@tonic-gate mov %i0, %o0 ! copy ins to outs 7687c478bd9Sstevel@tonic-gate mov %i1, %o1 7697c478bd9Sstevel@tonic-gate mov %i2, %o2 7707c478bd9Sstevel@tonic-gate mov %i3, %o3 7717c478bd9Sstevel@tonic-gate mov %i4, %o4 7727c478bd9Sstevel@tonic-gate mov %i5, %o5 7737c478bd9Sstevel@tonic-gate call %l0 ! call original routine 7747c478bd9Sstevel@tonic-gate mov %l5, %g4 ! restore g4 7757c478bd9Sstevel@tonic-gate mov %o1, %l2 ! l2 = second 1/2 of return value 7767c478bd9Sstevel@tonic-gate ! for those those 64 bit operations 7777c478bd9Sstevel@tonic-gate ! link div64 - yuck... 7787c478bd9Sstevel@tonic-gate 7797c478bd9Sstevel@tonic-gate ! %o0 = retval 7807c478bd9Sstevel@tonic-gate ldx [%fp + STACK_BIAS + -CLONGSIZE], %l1 7817c478bd9Sstevel@tonic-gate ldx [%l1 + REFLMP_OFF], %o1 ! %o1 = reflmp 7827c478bd9Sstevel@tonic-gate ldx [%l1 + DEFLMP_OFF], %o2 ! %o2 = deflmp 7837c478bd9Sstevel@tonic-gate add %l1, SYMDEF_OFF, %o3 ! %o3 = symp 7847c478bd9Sstevel@tonic-gate call audit_pltexit 7857c478bd9Sstevel@tonic-gate lduw [%l1 + SYMNDX_OFF], %o4 ! %o4 = symndx 7867c478bd9Sstevel@tonic-gate 7877c478bd9Sstevel@tonic-gate mov %o0, %i0 ! pass on return code 7887c478bd9Sstevel@tonic-gate mov %l2, %i1 7897c478bd9Sstevel@tonic-gate ret 7907c478bd9Sstevel@tonic-gate restore 7917c478bd9Sstevel@tonic-gate .size elf_plt_trace, . - elf_plt_trace 7927c478bd9Sstevel@tonic-gate 7937c478bd9Sstevel@tonic-gate#endif 7947c478bd9Sstevel@tonic-gate 795