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