1/* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22/* 23 * Copyright (c) 1988 AT&T 24 * All Rights Reserved 25 * 26 * 27 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 28 * Use is subject to license terms. 29 */ 30 31#pragma ident "%Z%%M% %I% %E% SMI" 32 33#include "machdep.h" 34#include "_audit.h" 35#if defined(lint) 36#include <sys/types.h> 37#include "_rtld.h" 38#else 39#include <sys/stack.h> 40#include <sys/asm_linkage.h> 41 42 .file "%M%" 43 .seg ".text" 44#endif 45 46 47 48/* 49 * We got here because the initial call to a function resolved to a procedure 50 * linkage table entry. That entry did a branch to the first PLT entry, which 51 * in turn did a call to elf_rtbndr (refer elf_plt_init()). 52 * 53 * the code sequence that got us here was: 54 * 55 * PLT entry for foo(): 56 * sethi (.-PLT0), %g1 57 * ba,a .PLT0 ! patched atomically 2nd 58 * nop ! patched 1st 59 * nop 60 * nop 61 * nop 62 * nop 63 * nop 64 * 65 * Therefore on entry, %i7 has the address of the call, which will be added 66 * to the offset to the plt entry in %g1 to calculate the plt entry address 67 * we must also subtract 4 because the address of PLT0 points to the 68 * save instruction before the call. 69 * 70 * The PLT entry is rewritten in one of several ways. For the full 64-bit 71 * span, the following sequence is generated: 72 * 73 * nop 74 * sethi %hh(entry_pt), %g1 75 * sethi %lm(entry_pt), %g5 76 * or %g1, %hm(entry_pt), %g1 77 * sllx %g1, 32, %g1 78 * or %g1, %g5, %g5 79 * jmpl %g5 + %lo(entry_pt), %g0 80 * nop 81 * 82 * Shorter code sequences are possible, depending on reachability 83 * constraints. Note that 'call' is not as useful as it might seem in 84 * this context, because it is only capable of plus or minus 2Gbyte 85 * PC-relative jumps, and the rdpc instruction is very slow. 86 * 87 * At the time of writing, the present and future SPARC CPUs that will use 88 * this code are only capable of addressing the bottom 43-bits and top 43-bits 89 * of the address space. And since shared libraries are placed at the top 90 * of the address space, the "top 44-bits" sequence will effectively always be 91 * used. See elf_plt_write() below. The "top 32-bits" are used when they 92 * can reach. 93 */ 94 95#if defined(lint) 96 97extern unsigned long elf_bndr(Rt_map *, unsigned long, caddr_t); 98 99/* 100 * We're called here from .PLTn in a new frame, with %o0 containing 101 * the result of a sethi (. - .PLT0), and %o1 containing the pc of 102 * the jmpl instruction we're got here with inside .PLT1 103 */ 104void 105elf_rtbndr(Rt_map *lmp, unsigned long pltoff, caddr_t from) 106{ 107 (void) elf_bndr(lmp, pltoff, from); 108} 109 110#else 111 .weak _elf_rtbndr ! keep dbx happy as it likes to 112 _elf_rtbndr = elf_rtbndr ! rummage around for our symbols 113 114 ENTRY(elf_rtbndr) 115 mov %i7, %o3 ! Save callers address(profiling) 116 save %sp, -SA(MINFRAME), %sp 117 mov %g4, %l5 ! Save g4 (safe across function calls) 118 sub %i1, 0x38, %o1 ! compute addr of .PLT0 from addr of .PLT1 jmpl 119 ldx [%o1 + 0x40], %o0 ! ld PLT2[X] into third arg 120 srl %i0, 10, %o1 ! shift offset set by sethi 121 call elf_bndr ! returns function address in %o0 122 mov %i3, %o2 ! Callers address is arg 3 123 mov %o0, %g1 ! save address of routine binded 124 mov %l5, %g4 ! restore g4 125 restore ! how many restores needed ? 2 126 jmp %g1 ! jump to it 127 restore 128 SET_SIZE(elf_rtbndr) 129 130#endif 131 132 133#if defined(lint) 134void 135elf_rtbndr_far(Rt_map *lmp, unsigned long pltoff, caddr_t from) 136{ 137 (void) elf_bndr(lmp, pltoff, from); 138} 139#else 140ENTRY(elf_rtbndr_far) 141 mov %i7, %o3 ! Save callers address 142 save %sp, -SA(MINFRAME), %sp 143 mov %g4, %l5 ! preserve %g4 144 sub %i1, 0x18, %o2 ! compute address of .PLT0 from 145 ! .PLT0 jmpl instr. 146 sub %i0, %o2, %o1 ! pltoff = pc - 0x10 - .PLT0 147 sub %o1, 0x10, %o1 148 ldx [%o2 + 0x40], %o0 ! ld PLT2[X] into third arg 149 call elf_bndr ! returns function address in %o0 150 mov %i3, %o2 ! Callers address is arg3 151 mov %o0, %g1 ! save address of routine binded 152 mov %l5, %g4 ! restore g4 153 restore ! how many restores needed ? 2 154 jmp %g1 ! jump to it 155 restore 156SET_SIZE(elf_rtbndr_far) 157#endif 158 159 160/* 161 * Initialize a plt entry so that function calls go to 'bindfunc' 162 * (We parameterize the binding function here because we call this 163 * routine twice - once for PLT0 and once for PLT1 with different 164 * binding functions.) 165 * 166 * The plt entries (PLT0 and PLT1) look like: 167 * 168 * save %sp, -176, %sp 169 * sethi %hh(bindfunc), %l0 170 * sethi %lm(bindfunc), %l1 171 * or %l0, %hm(bindfunc), %l0 172 * sllx %l0, 32, %l0 173 * or %l0, %l1, %l0 174 * jmpl %l0 + %lo(bindfunc), %o1 175 * mov %g1, %o0 176 */ 177 178#define M_SAVE_SP176SP 0x9de3bf50 /* save %sp, -176, %sp */ 179#define M_SETHI_L0 0x21000000 /* sethi 0x0, %l0 */ 180#define M_SETHI_L1 0x23000000 /* sethi 0x0, %l1 */ 181#define M_OR_L0L0 0xa0142000 /* or %l0, 0x0, %l0 */ 182#define M_SLLX_L032L0 0xa12c3020 /* sllx %l0, 32, %l0 */ 183#define M_OR_L0L1L0 0xa0140011 /* or %l0, %l1, %l0 */ 184#define M_JMPL_L0O1 0x93c42000 /* jmpl %l0 + 0, %o1 */ 185#define M_MOV_G1O0 0x90100001 /* or %g0, %g1, %o0 */ 186 187#if defined(lint) 188 189#define HH22(x) 0 /* for lint's benefit */ 190#define LM22(x) 0 191#define HM10(x) 0 192#define LO10(x) 0 193 194/* ARGSUSED */ 195void 196elf_plt_init(void *plt, caddr_t bindfunc) 197{ 198 uint_t *_plt; 199 200 _plt = (uint_t *)plt; 201 _plt[0] = M_SAVE_SP176SP; 202 _plt[1] = M_SETHI_L0 | HH22(bindfunc); 203 _plt[2] = M_SETHI_L1 | LM22(bindfunc); 204 _plt[3] = M_OR_L0L0 | HM10(bindfunc); 205 _plt[4] = M_SLLX_L032L0; 206 _plt[5] = M_OR_L0L1L0; 207 _plt[6] = M_JMPL_L0O1 | LO10(bindfunc); 208 _plt[7] = M_MOV_G1O0; 209} 210 211#else 212 ENTRY(elf_plt_init) 213 save %sp, -SA(MINFRAME), %sp ! Make a frame 214 215 sethi %hi(M_SAVE_SP176SP), %o0 ! Get save instruction 216 or %o0, %lo(M_SAVE_SP176SP), %o0 217 st %o0, [%i0] ! Store in plt[0] 218 219 sethi %hi(M_SETHI_L0), %o4 ! Get "sethi 0x0, %l0" insn 220 srlx %i1, 42, %o2 ! get %hh(function address) 221 or %o4, %o2, %o4 ! or value into instruction 222 st %o4, [%i0 + 0x4] ! Store instruction in plt[1] 223 iflush %i0 ! .. and flush 224 225 sethi %hi(M_SETHI_L1), %o4 ! Get "sethi 0x0, %l1" insn 226 srl %i1, 10, %o2 ! get %lm(function address) 227 or %o4, %o2, %o4 ! or value into instruction 228 st %o4, [%i0 + 0x8] ! Store instruction in plt[2] 229 230 sethi %hi(M_OR_L0L0), %o4 ! Get "or %l0, 0x0, %l0" insn 231 or %o4, %lo(M_OR_L0L0), %o4 232 srlx %i1, 32, %o2 ! get %hm(function address) 233 and %o2, 0x3ff, %o2 ! pick out bits 42-33 234 or %o4, %o2, %o4 ! or value into instruction 235 st %o4, [%i0 + 0xc] ! Store instruction in plt[3] 236 iflush %i0 + 8 ! .. and flush 237 238 sethi %hi(M_SLLX_L032L0), %o4 ! get "sllx %l0, 32, %l0" insn 239 or %o4, %lo(M_SLLX_L032L0), %o4 240 st %o4, [%i0 + 0x10] ! Store instruction in plt[4] 241 242 sethi %hi(M_OR_L0L1L0), %o4 ! get "or %l0, %l1, %l0" insn 243 or %o4, %lo(M_OR_L0L1L0), %o4 244 st %o4, [%i0 + 0x14] ! Store instruction in plt[5] 245 iflush %i0 + 0x10 ! .. and flush 246 247 sethi %hi(M_JMPL_L0O1), %o4 ! get "jmpl %l0 + 0, %o1" insn 248 or %o4, %lo(M_JMPL_L0O1), %o4 249 and %i1, 0x3ff, %o2 ! get %lo(function address) 250 or %o4, %o2, %o4 ! or value into instruction 251 st %o4, [%i0 + 0x18] ! Store instruction in plt[6] 252 253 sethi %hi(M_MOV_G1O0), %o4 ! get "mov %g1, %o0" insn 254 or %o4, %lo(M_MOV_G1O0), %o4 255 st %o4, [%i0 + 0x1c] ! Store instruction in plt[7] 256 iflush %i0 + 0x18 ! .. and flush 257 258 ret 259 restore 260 SET_SIZE(elf_plt_init) 261#endif 262 263 264 265 266#if defined(lint) 267/* 268 * The V9 ABI assigns the link map identifier, the 269 * Rt_map pointer, to the start of .PLT2. 270 */ 271void 272elf_plt2_init(unsigned int *plt2, Rt_map * lmp) 273{ 274 /* LINTED */ 275 *(unsigned long *)plt2 = (unsigned long)lmp; 276} 277#else 278 ENTRY(elf_plt2_init) 279 stx %o1, [%o0] 280 retl 281 iflush %o0 282 SET_SIZE(elf_plt2_init) 283#endif 284 285 286 287/* 288 * After the first call to a plt, elf_bndr() will have determined the true 289 * address of the function being bound. The plt is now rewritten so that 290 * any subsequent calls go directly to the bound function. If the library 291 * to which the function belongs is being profiled refer to _plt_cg_write. 292 * 293 * For complete 64-bit spanning, the new plt entry is: 294 * 295 * nop 296 * sethi %hh(function address), %g1 297 * sethi %lm(function address), %g5 298 * or %g1, %hm(function address), %g1 299 * sllx %g1, 32, %g1 300 * or %g1, %g5, %g5 301 * jmpl %g5, %lo(function address), %g0 302 * nop 303 * 304 * However, shorter instruction sequences are possible and useful. 305 * This version gets us anywhere in the top 44 bits of the 306 * address space - since this is where shared objects live most 307 * of the time, this case is worth optimizing. 308 * 309 * nop 310 * sethi %h44(~function_address), %g5 311 * xnor %g5, %m44(~function address), %g1 312 * sllx %g1, 12, %g1 313 * jmpl %g1 + %l44(function address), %g0 314 * nop 315 * nop 316 * nop 317 * 318 * This version gets anywhere in the top 32 bits: 319 * 320 * nop 321 * sethi %hi(~function_address), %g5 322 * xnor %g5, %lo(~function_address), %g1 323 * jmpl %g1, %g0 324 * nop 325 * nop 326 * nop 327 * nop 328 * 329 * This version get's us to a destination within 330 * +- 8megs of the PLT's address: 331 * 332 * nop 333 * ba,a <dest> 334 * nop 335 * nop 336 * nop 337 * nop 338 * nop 339 * nop 340 * 341 * This version get's us to a destination within 342 * +- 2megs of the PLT's address: 343 * 344 * nop 345 * ba,a,pt %icc, <dest> 346 * nop 347 * nop 348 * nop 349 * nop 350 * nop 351 * nop 352 * 353 * 354 * The PLT is written in reverse order to ensure re-entrant behaviour. 355 * Note that the first two instructions must be overwritten with a 356 * single stx. 357 * 358 * Note that even in the 44-bit case, we deliberately use both %g5 and 359 * %g1 to prevent anyone accidentally relying on either of them being 360 * non-volatile across a function call. 361 */ 362 363#define M_JMPL_G5G0 0x81c16000 /* jmpl %g5 + 0, %g0 */ 364#define M_OR_G1G5G5 0x8a104005 /* or %g1, %g5, %g5 */ 365#define M_SLLX_G132G1 0x83287020 /* sllx %g1, 32, %g1 */ 366#define M_OR_G1G1 0x82106000 /* or %g1, 0x0, %g1 */ 367#define M_SETHI_G5 0x0b000000 /* sethi 0x0, %g5 */ 368#define M_SETHI_G1 0x03000000 /* sethi 0x0, %g1 */ 369#define M_NOP 0x01000000 /* sethi 0x0, %g0 */ 370 371#define M_JMPL_G1G0 0x81c06000 /* jmpl %g1 + 0, %g0 */ 372#define M_SLLX_G112G1 0x8328700c /* sllx %g1, 12, %g1 */ 373#define M_XNOR_G5G1 0x82396000 /* xnor %g5, 0, %g1 */ 374 375#if defined(lint) 376 377/* ARGSUSED */ 378#define MASK(m) ((1ul << (m)) - 1ul) 379#define BITS(v, u, l) (((v) >> (l)) & MASK((u) - (l) + 1)) 380#define H44(v) BITS(v, 43, 22) 381#define M44(v) BITS(v, 21, 12) 382#define L44(v) BITS(v, 11, 0) 383 384#endif 385 386#if defined(lint) 387 388void 389/* ARGSUSED1 */ 390plt_upper_32(uintptr_t pc, uintptr_t symval) 391{ 392 ulong_t sym = (ulong_t)symval; 393 /* LINTED */ 394 ulong_t nsym = ~sym; 395 uint_t * plttab = (uint_t *)pc; 396 397 plttab[3] = M_JMPL_G1G0; 398 plttab[2] = (uint_t)(M_XNOR_G5G1 | LO10(nsym)); 399 *(ulong_t *)pc = 400 ((ulong_t)M_NOP << 32) | (M_SETHI_G5 | LM22(nsym)); 401} 402 403#else 404 405 406 ENTRY(plt_upper_32) 407 ! 408 ! Address lies in top 32-bits of address space, so use 409 ! compact PLT sequence 410 ! 411 sethi %hi(M_JMPL_G1G0), %o3 ! Get "jmpl %g1, %g0" insn 412 st %o3, [%o0 + 0xc] ! store instruction in plt[3] 413 iflush %o0 + 0xc ! .. and flush 414 415 not %o1, %o4 416 sethi %hi(M_XNOR_G5G1), %o3 ! Get "xnor %g5, %g1, %g1" insn 417 and %o4, 0x3ff, %o2 ! pick out bits 0-9 418 or %o3, %o2, %o3 ! or value into instruction 419 st %o3, [%o0 + 0x8] ! store instruction in plt[2] 420 iflush %o0 + 0x8 ! .. and flush 421 422 sethi %hi(M_SETHI_G5), %o3 ! Get "sethi 0x0, %g5" insn 423 srl %o4, 10, %o2 ! get %lm(~function address) 424 or %o3, %o2, %o3 ! or value into instruction 425 426 sethi %hi(M_NOP), %o4 ! Get "nop" instruction 427 sllx %o4, 32, %o4 ! shift to top of instruction pair 428 or %o3, %o4, %o3 ! or value into instruction pair 429 stx %o3, [%o0] ! store instructions into plt[0] plt[1] 430 retl 431 iflush %o0 ! .. and flush 432 SET_SIZE(plt_upper_32) 433#endif /* defined lint */ 434 435 436#if defined(lint) 437 438void 439/* ARGSUSED1 */ 440plt_upper_44(uintptr_t pc, uintptr_t symval) 441{ 442 ulong_t sym = (ulong_t)symval; 443 ulong_t nsym = ~sym; 444 uint_t * plttab = (uint_t *)pc; 445 446 /* LINTED */ 447 plttab[4] = (uint_t)(M_JMPL_G1G0 | L44(sym)); 448 plttab[3] = M_SLLX_G112G1; 449 /* LINTED */ 450 plttab[2] = (uint_t)(M_XNOR_G5G1 | M44(nsym)); 451 *(ulong_t *)pc = ((ulong_t)M_NOP << 32) | (M_SETHI_G5 | H44(nsym)); 452} 453 454#else 455 456 457 ENTRY(plt_upper_44) 458 ! 459 ! Address lies in top 44-bits of address space, so use 460 ! compact PLT sequence 461 ! 462 setuw M_JMPL_G1G0, %o3 ! Get "jmpl %g1, %g0" insn 463 and %o1, 0xfff, %o2 ! lower 12 bits of function address 464 or %o3, %o2, %o3 ! is or'ed into instruction 465 st %o3, [%o0 + 0x10] ! store instruction in plt[4] 466 iflush %o0 + 0x10 ! .. and flush 467 468 setuw M_SLLX_G112G1, %o3 ! Get "sllx %g1, 12, %g1" insn 469 st %o3, [%o0 + 0xc] ! store instruction in plt[3] 470 471 not %o1, %o4 472 setuw M_XNOR_G5G1, %o3 ! Get "xnor %g5, 0, %g1" insn 473 srlx %o4, 12, %o2 ! get %m44(0 - function address) 474 and %o2, 0x3ff, %o2 ! pick out bits 21-12 475 or %o3, %o2, %o3 ! or value into instruction 476 st %o3, [%o0 + 8] ! store instruction in plt[2] 477 iflush %o0 + 8 ! .. and flush 478 479 setuw M_SETHI_G5, %o3 ! Get "sethi 0x0, %g5" insn 480 srlx %o4, 22, %o2 ! get %h44(0 - function address) 481 or %o3, %o2, %o3 ! or value into instruction 482 483 setuw M_NOP, %o4 ! Get "nop" instruction 484 sllx %o4, 32, %o4 ! shift to top of instruction pair 485 or %o3, %o4, %o3 ! or value into instruction pair 486 stx %o3, [%o0] ! store instructions into plt[0] plt[1] 487 retl 488 iflush %o0 ! .. and flush 489 SET_SIZE(plt_upper_44) 490 491#endif /* defined(lint) */ 492 493 494#if defined(lint) 495 496void 497/* ARGSUSED1 */ 498plt_full_range(uintptr_t pc, uintptr_t symval) 499{ 500 uint_t * plttab = (uint_t *)pc; 501 502 plttab[6] = M_JMPL_G5G0 | LO10(symval); 503 plttab[5] = M_OR_G1G5G5; 504 plttab[4] = M_SLLX_G132G1; 505 plttab[3] = M_OR_G1G1 | HM10(symval); 506 plttab[2] = M_SETHI_G5 | LM22(symval); 507 *(ulong_t *)pc = 508 ((ulong_t)M_NOP << 32) | (M_SETHI_G1 | HH22(symval)); 509} 510 511#else 512 ENTRY(plt_full_range) 513 ! 514 ! Address lies anywhere in 64-bit address space, so use 515 ! full PLT sequence 516 ! 517 sethi %hi(M_JMPL_G5G0), %o3 ! Get "jmpl %g5, %g0" insn 518 and %o1, 0x3ff, %o2 ! lower 10 bits of function address 519 or %o3, %o2, %o3 ! is or'ed into instruction 520 st %o3, [%o0 + 0x18] ! store instruction in plt[6] 521 iflush %o0 + 0x18 ! .. and flush 522 523 sethi %hi(M_OR_G1G5G5), %o3 ! Get "or %g1, %g5, %g1" insn 524 or %o3, %lo(M_OR_G1G5G5), %o3 525 st %o3, [%o0 + 0x14] ! store instruction in plt[5] 526 527 sethi %hi(M_SLLX_G132G1), %o3 ! Get "sllx %g1, 32, %g1" insn 528 or %o3, %lo(M_SLLX_G132G1), %o3 529 st %o3, [%o0 + 0x10] ! store instruction in plt[4] 530 iflush %o0 + 0x10 ! .. and flush 531 532 sethi %hi(M_OR_G1G1), %o3 ! Get "or %g1, 0x0, %g1" insn 533 or %o3, %lo(M_OR_G1G1), %o3 534 srlx %o1, 32, %o2 ! get %hm(function address) 535 and %o2, 0x3ff, %o2 ! pick out bits 42-33 536 or %o3, %o2, %o3 ! or value into instruction 537 st %o3, [%o0 + 0xc] ! store instruction in plt[3] 538 539 sethi %hi(M_SETHI_G5), %o3 ! Get "sethi 0x0, %g5" insn 540 srl %o1, 10, %o2 ! get %lm(function address) 541 or %o3, %o2, %o3 ! or value into instruction 542 st %o3, [%o0 + 0x8] ! store instruction in plt[2] 543 iflush %o0 + 8 ! .. and flush 544 545 sethi %hi(M_SETHI_G1), %o3 ! Get "sethi 0x0, %g1" insn 546 srlx %o1, 42, %o2 ! get %hh(function address) 547 or %o3, %o2, %o3 ! or value into instruction 548 549 sethi %hi(M_NOP), %o4 ! Get "nop" instruction 550 sllx %o4, 32, %o4 ! shift to top of instruction pair 551 or %o3, %o4, %o3 ! or value into instruction pair 552 stx %o3, [%o0] ! store instructions into plt[0] plt[1] 553 retl 554 iflush %o0 ! .. and flush 555 556 SET_SIZE(plt_full_range) 557 558#endif /* defined(lint) */ 559 560/* 561 * performs the 'iflush' instruction on a range of memory. 562 */ 563#if defined(lint) 564void 565iflush_range(caddr_t addr, size_t len) 566{ 567 /* LINTED */ 568 uintptr_t base; 569 570 base = (uintptr_t)addr & ~7; /* round down to 8 byte alignment */ 571 len = (len + 7) & ~7; /* round up to multiple of 8 bytes */ 572 for (len -= 8; (long)len >= 0; len -= 8) 573 /* iflush(base + len) */; 574} 575#else 576 ENTRY(iflush_range) 577 add %o1, 7, %o1 578 andn %o0, 7, %o0 579 andn %o1, 7, %o1 5801: subcc %o1, 8, %o1 581 bge,a,pt %xcc, 1b 582 iflush %o0 + %o1 583 retl 584 nop 585 SET_SIZE(iflush_range) 586#endif 587 588 589#if defined(lint) 590 591ulong_t 592elf_plt_trace() 593{ 594 return (0); 595} 596#else 597 .global elf_plt_trace 598 .type elf_plt_trace, #function 599 600/* 601 * The dyn_plt that called us has already created a stack-frame for 602 * us and placed the following entries in it: 603 * 604 * [%fp + STACK_BIAS + -0x8] * dyndata 605 * [%fp + STACK_BIAS + -0x10] * prev stack size 606 * 607 * dyndata currently contains: 608 * 609 * dyndata: 610 * 0x0 Addr *reflmp 611 * 0x8 Addr *deflmp 612 * 0x10 Word symndx 613 * 0x14 Word sb_flags 614 * 0x18 Sym symdef.st_name 615 * 0x1c symdef.st_info 616 * 0x1d symdef.st_other 617 * 0x1e symdef.st_shndx 618 * 0x20 symdef.st_value 619 * 0x28 symdef.st_size 620 */ 621#define REFLMP_OFF 0x0 622#define DEFLMP_OFF 0x8 623#define SYMNDX_OFF 0x10 624#define SBFLAGS_OFF 0x14 625#define SYMDEF_OFF 0x18 626#define SYMDEF_VALUE_OFF 0x20 627 628#define LAREGSSZ 0x40 /* sizeof (La_sparcv9_regs) */ 629 630 631elf_plt_trace: 6321: call 2f 633 sethi %hi(_GLOBAL_OFFSET_TABLE_ - (1b - .)), %l7 6342: or %l7, %lo(_GLOBAL_OFFSET_TABLE_ - (1b - .)), %l7 635 add %l7, %o7, %l7 636 637 ldx [%fp + STACK_BIAS + -CLONGSIZE], %l1 ! l1 = * dyndata 638 lduw [%l1 + SBFLAGS_OFF], %l2 ! l2 = sb_flags 639 andcc %l2, LA_SYMB_NOPLTENTER, %g0 640 be,pt %icc, .start_pltenter 641 ldx [%l1 + SYMDEF_VALUE_OFF], %l0 ! l0 = 642 ! sym.st_value(calling address) 643 ba,a,pt %icc, .end_pltenter 644 nop 645 646 /* 647 * save all registers into La_sparcv9_regs 648 */ 649.start_pltenter: 650 sub %sp, LAREGSSZ, %sp ! create space for La_sparcv9_regs 651 ! storage on the stack. 652 653 add %fp, STACK_BIAS - (LAREGSSZ + (2 * CLONGSIZE)), %o4 ! addr of new space. 654 655 stx %i0, [%o4 + 0x0] 656 stx %i1, [%o4 + 0x8] 657 stx %i2, [%o4 + 0x10] 658 stx %i3, [%o4 + 0x18] ! because a regwindow shift has 659 stx %i4, [%o4 + 0x20] ! already occured our current %i* 660 stx %i5, [%o4 + 0x28] ! register's are the equivalent of 661 stx %i6, [%o4 + 0x30] ! the %o* registers that the final 662 stx %i7, [%o4 + 0x38] ! procedure shall see. 663 mov %g4, %l5 ! save g4 (safe across function calls) 664 665 666 ldx [%fp + STACK_BIAS + -CLONGSIZE], %l1 ! %l1 == * dyndata 667 ldx [%l1 + REFLMP_OFF], %o0 ! %o0 = reflmp 668 ldx [%l1 + DEFLMP_OFF], %o1 ! %o1 = deflmp 669 add %l1, SYMDEF_OFF, %o2 ! %o2 = symp 670 lduw [%l1 + SYMNDX_OFF], %o3 ! %o3 = symndx 671 call audit_pltenter 672 add %l1, SBFLAGS_OFF, %o5 ! %o3 = * sb_flags 673 674 mov %o0, %l0 ! %l0 == calling address 675 add %sp, LAREGSSZ, %sp ! cleanup La_sparcv9_regs off 676 ! of the stack. 677 678.end_pltenter: 679 /* 680 * If *no* la_pltexit() routines exist we do not need 681 * to keep the stack frame before we call the actual 682 * routine. Instead we jump to it and remove ourself 683 * from the stack at the same time. 684 */ 685 ldx [%l7+audit_flags], %l3 686 lduw [%l3], %l3 ! %l3 = audit_flags 687 andcc %l3, AF_PLTEXIT, %g0 ! AF_PLTEXIT = 2 688 be,pt %icc, .bypass_pltexit 689 ldx [%fp + STACK_BIAS + -CLONGSIZE], %l1 ! %l1 = * dyndata 690 lduw [%l1 + SBFLAGS_OFF], %l2 ! %l2 = sb_flags 691 andcc %l2, LA_SYMB_NOPLTEXIT, %g0 ! LA_SYMB_NOPLTEXIT = 2 692 bne,a,pt %icc, .bypass_pltexit 693 nop 694 695 ba,a,pt %icc, .start_pltexit 696 nop 697.bypass_pltexit: 698 mov %l5, %g4 ! restore g4 699 jmpl %l0, %g0 700 restore 701 702.start_pltexit: 703 /* 704 * In order to call la_pltexit() we must duplicate the 705 * arguments from the 'callers' stack on our stack frame. 706 * 707 * First we check the size of the callers stack and grow 708 * our stack to hold any of the arguments that need 709 * duplicating (these are arguments 6->N), because the 710 * first 6 (0->5) are passed via register windows on sparc. 711 */ 712 713 /* 714 * The first calculation is to determine how large the 715 * argument passing area might be. Since there is no 716 * way to distinquish between 'argument passing' and 717 * 'local storage' from the previous stack this amount must 718 * cover both. 719 */ 720 ldx [%fp + STACK_BIAS + -(2 * CLONGSIZE)], %l1 ! %l1 = callers 721 ! stack size 722 sub %l1, MINFRAME, %l1 ! %l1 = argument space on 723 ! caller's stack 724 /* 725 * Next we compare the prev. stack size against the audit_argcnt. We 726 * copy at most 'audit_argcnt' arguments. The default arg count is 64. 727 * 728 * NOTE: on sparc we always copy at least six args since these 729 * are in reg-windows and not on the stack. 730 * 731 * NOTE: Also note that we multiply (shift really) the arg count 732 * by 8 which is the 'word size' to calculate the amount 733 * of stack space needed. 734 */ 735 ldx [%l7 + audit_argcnt], %l2 736 lduw [%l2], %l2 ! %l2 = audit_argcnt 737 cmp %l2, 6 738 ble,pn %icc, .grow_stack 739 sub %l2, 6, %l2 740 sllx %l2, CLONGSHIFT, %l2 ! arg count * 8 741 cmp %l1, %l2 ! 742 ble,a,pn %icc, .grow_stack 743 nop 744 mov %l2, %l1 745.grow_stack: 746 /* 747 * When duplicating the stack we skip the first SA(MINFRAME) 748 * bytes. This is the space on the stack reserved for preserving 749 * the register windows and such and do not need to be duplicated 750 * on this new stack frame. We start duplicating at the portion 751 * of the stack reserved for argument's above 6. 752 */ 753 sub %sp, %l1, %sp ! grow our stack by amount required. 754 srax %l1, CLONGSHIFT, %l1 ! %l1 = %l1 / 8 (words to copy) 755 mov SA(MINFRAME), %l2 ! %l2 = index into stack & frame 756 7571: 758 cmp %l1, 0 759 ble,a,pn %icc, 2f 760 nop 761 762 add %fp, %l2, %l4 763 ldx [%l4 + STACK_BIAS], %l3 ! duplicate args from previous 764 add %sp, %l2, %l4 765 stx %l3, [%l4 + STACK_BIAS] ! stack onto current stack 766 767 add %l2, CLONGSIZE, %l2 768 ba,pt %icc, 1b 769 sub %l1, 0x1, %l1 7702: 771 mov %i0, %o0 ! copy ins to outs 772 mov %i1, %o1 773 mov %i2, %o2 774 mov %i3, %o3 775 mov %i4, %o4 776 mov %i5, %o5 777 call %l0 ! call original routine 778 mov %l5, %g4 ! restore g4 779 mov %o1, %l2 ! l2 = second 1/2 of return value 780 ! for those those 64 bit operations 781 ! link div64 - yuck... 782 783 ! %o0 = retval 784 ldx [%fp + STACK_BIAS + -CLONGSIZE], %l1 785 ldx [%l1 + REFLMP_OFF], %o1 ! %o1 = reflmp 786 ldx [%l1 + DEFLMP_OFF], %o2 ! %o2 = deflmp 787 add %l1, SYMDEF_OFF, %o3 ! %o3 = symp 788 call audit_pltexit 789 lduw [%l1 + SYMNDX_OFF], %o4 ! %o4 = symndx 790 791 mov %o0, %i0 ! pass on return code 792 mov %l2, %i1 793 ret 794 restore 795 .size elf_plt_trace, . - elf_plt_trace 796 797#endif 798 799