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