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#pragma ident "%Z%%M% %I% %E% SMI" 31 32#include <link.h> 33#include "machdep.h" 34#include "_audit.h" 35 36#if defined(lint) 37#include <sys/types.h> 38#include "_rtld.h" 39#else 40#include <sys/stack.h> 41#include <sys/asm_linkage.h> 42 43 .file "boot_elf.s" 44 .seg ".text" 45#endif 46 47/* 48 * We got here because the initial call to a function resolved to a procedure 49 * linkage table entry. That entry did a branch to the first PLT entry, which 50 * in turn did a call to elf_rtbndr (refer elf_plt_init()). 51 * 52 * the code sequence that got us here was: 53 * 54 * PLT entry for foo(): 55 * sethi (.-PLT0), %g1 ! not changed by rtld 56 * ba,a .PLT0 ! patched atomically 2nd 57 * nop ! patched first 58 * 59 * Therefore on entry, %i7 has the address of the call, which will be added 60 * to the offset to the plt entry in %g1 to calculate the plt entry address 61 * we must also subtract 4 because the address of PLT0 points to the 62 * save instruction before the call. 63 * 64 * the plt entry is rewritten: 65 * 66 * PLT entry for foo(): 67 * sethi (.-PLT0), %g1 68 * sethi %hi(entry_pt), %g1 69 * jmpl %g1 + %lo(entry_pt), %g0 70 */ 71 72#if defined(lint) 73 74extern unsigned long elf_bndr(Rt_map *, unsigned long, caddr_t); 75 76static void 77elf_rtbndr(Rt_map *lmp, unsigned long pltoff, caddr_t from) 78{ 79 (void) elf_bndr(lmp, pltoff, from); 80} 81 82 83#else 84 .weak _elf_rtbndr ! keep dbx happy as it likes to 85 _elf_rtbndr = elf_rtbndr ! rummage around for our symbols 86 87 .global elf_rtbndr 88 .type elf_rtbndr, #function 89 .align 4 90 91elf_rtbndr: 92 mov %i7, %o0 ! Save callers address(profiling) 93 save %sp, -SA(MINFRAME), %sp ! Make a frame 94 srl %g1, 10, %o1 ! shift offset set by sethi 95 ! %o1 has offset from jump slot 96 ! to PLT0 which will be used to 97 ! calculate plt relocation entry 98 ! by elf_bndr 99 ld [%i7 + 8], %o0 ! %o0 has ptr to lm 100 call elf_bndr ! returns function address in %o0 101 mov %i0, %o2 ! Callers address is arg 3 102 mov %o0, %g1 ! save address of routine binded 103 restore ! how many restores needed ? 2 104 jmp %g1 ! jump to it 105 restore 106 .size elf_rtbndr, . - elf_rtbndr 107 108#endif 109 110 111#if defined(lint) 112void 113iflush_range(caddr_t addr, size_t len) 114{ 115 /* LINTED */ 116 uintptr_t base; 117 118 base = (uintptr_t)addr & ~7; /* round down to 8 byte alignment */ 119 len = (len + 7) & ~7; /* round up to multiple of 8 bytes */ 120 for (len -= 8; (long)len >= 0; len -= 8) 121 /* iflush(base + len) */; 122} 123#else 124 ENTRY(iflush_range) 125 add %o1, 7, %o1 126 andn %o0, 7, %o0 127 andn %o1, 7, %o1 1281: subcc %o1, 8, %o1 129 bge,a 1b 130 iflush %o0 + %o1 131 retl 132 nop 133 SET_SIZE(iflush_range) 134#endif 135 136/* 137 * Initialize the first plt entry so that function calls go to elf_rtbndr 138 * 139 * The first plt entry (PLT0) is: 140 * 141 * save %sp, -64, %sp 142 * call elf_rtbndr 143 * nop 144 * address of lm 145 */ 146 147#if defined(lint) 148 149void 150elf_plt_init(void *plt, caddr_t lmp) 151{ 152 *((uint_t *)plt + 0) = (unsigned long) M_SAVESP64; 153 *((uint_t *)plt + 4) = M_CALL | (((unsigned long)elf_rtbndr - 154 ((unsigned long)plt)) >> 2); 155 *((uint_t *)plt + 8) = M_NOP; 156 *((uint_t *)plt + 12) = (unsigned long) lmp; 157} 158 159#else 160 .global elf_plt_init 161 .type elf_plt_init, #function 162 .align 4 163 164elf_plt_init: 165 save %sp, -SA(MINFRAME), %sp ! Make a frame 1661: 167 call 2f 168 sethi %hi((_GLOBAL_OFFSET_TABLE_ - (1b - .))), %l7 1692: 170 sethi %hi(M_SAVESP64), %o0 ! Get save instruction 171 or %o0, %lo(M_SAVESP64), %o0 172 or %l7, %lo((_GLOBAL_OFFSET_TABLE_ - (1b - .))), %l7 173 st %o0, [%i0] ! Store in plt[0] 174 iflush %i0 175 add %l7, %o7, %l7 176 ld [%l7 + elf_rtbndr], %l7 177 inc 4, %i0 ! Bump plt to point to plt[1] 178 sub %l7, %i0, %o0 ! Determine -pc so as to produce 179 ! offset from plt[1] 180 srl %o0, 2, %o0 ! Express offset as number of words 181 sethi %hi(M_CALL), %o4 ! Get sethi instruction 182 or %o4, %o0, %o4 ! Add elf_rtbndr address 183 st %o4, [%i0] ! Store instruction in plt 184 iflush %i0 185 sethi %hi(M_NOP), %o0 ! Generate nop instruction 186 st %o0, [%i0 + 4] ! Store instruction in plt[2] 187 iflush %i0 + 4 188 st %i1, [%i0 + 8] ! Store instruction in plt[3] 189 iflush %i0 + 8 190 ret 191 restore 192 .size elf_plt_init, . - elf_plt_init 193#endif 194 195#if defined(lint) 196 197ulong_t 198elf_plt_trace() 199{ 200 return (0); 201} 202#else 203 .global elf_plt_trace 204 .type elf_plt_trace, #function 205 .align 4 206 207/* 208 * The dyn_plt that called us has already created a stack-frame for 209 * us and placed the following entries in it: 210 * 211 * [%fp - 0x4] * dyndata 212 * [%fp - 0x8] * prev stack size 213 * 214 * dyndata currently contains: 215 * 216 * dyndata: 217 * 0x0 uintptr_t *reflmp 218 * 0x4 uintptr_t *deflmp 219 * 0x8 ulong_t symndx 220 * 0xc ulong_t sb_flags 221 * 0x10 Sym symdef.st_name 222 * 0x14 symdef.st_value 223 * 0x18 symdef.st_size 224 * 0x1c symdef.st_info 225 * 0x1d symdef.st_other 226 * 0x1e symdef.st_shndx 227 */ 228#define REFLMP_OFF 0x0 229#define DEFLMP_OFF 0x4 230#define SYMNDX_OFF 0x8 231#define SBFLAGS_OFF 0xc 232#define SYMDEF_OFF 0x10 233#define SYMDEF_VALUE_OFF 0x14 234 235elf_plt_trace: 2361: call 2f 237 sethi %hi(_GLOBAL_OFFSET_TABLE_+(.-1b)), %l7 2382: or %l7, %lo(_GLOBAL_OFFSET_TABLE_+(.-1b)), %l7 239 add %l7, %o7, %l7 240 241 ld [%l7+audit_flags], %l3 242 ld [%l3], %l3 ! %l3 = audit_flags 243 andcc %l3, AF_PLTENTER, %g0 244 beq .end_pltenter 245 ld [%fp + -0x4], %l1 ! l1 = * dyndata 246 ld [%l1 + SBFLAGS_OFF], %l2 ! l2 = sb_flags 247 andcc %l2, LA_SYMB_NOPLTENTER, %g0 248 beq .start_pltenter 249 ld [%l1 + SYMDEF_VALUE_OFF], %l0 ! l0 = 250 ! sym.st_value(calling address) 251 ba .end_pltenter 252 nop 253 254 /* 255 * save all registers into La_sparcv8_regs 256 */ 257.start_pltenter: 258 sub %sp, 0x20, %sp ! create space for La_sparcv8_regs 259 ! storage on the stack. 260 261 sub %fp, 0x28, %o4 262 263 st %i0, [%o4] 264 st %i1, [%o4 + 0x4] 265 st %i2, [%o4 + 0x8] 266 st %i3, [%o4 + 0xc] ! because a regwindow shift has 267 st %i4, [%o4 + 0x10] ! already occured our current %i* 268 st %i5, [%o4 + 0x14] ! register's are the equivalent of 269 st %i6, [%o4 + 0x18] ! the %o* registers that the final 270 st %i7, [%o4 + 0x1c] ! procedure shall see. 271 272 ld [%fp + -0x4], %l1 ! %l1 == * dyndata 273 ld [%l1 + REFLMP_OFF], %o0 ! %o0 = reflmp 274 ld [%l1 + DEFLMP_OFF], %o1 ! %o1 = deflmp 275 add %l1, SYMDEF_OFF, %o2 ! %o2 = symp 276 ld [%l1 + SYMNDX_OFF], %o3 ! %o3 = symndx 277 call audit_pltenter 278 add %l1, SBFLAGS_OFF, %o5 ! %o3 = * sb_flags 279 280 mov %o0, %l0 ! %l0 == calling address 281 282 add %sp, 0x20, %sp ! cleanup La_sparcv8_regs off 283 ! of the stack. 284 285.end_pltenter: 286 /* 287 * If *no* la_pltexit() routines exist we do not need to keep the 288 * stack frame before we call the actual routine. Instead we jump to 289 * it and remove our self from the stack at the same time. 290 */ 291 ld [%l7+audit_flags], %l3 292 ld [%l3], %l3 ! %l3 = audit_flags 293 andcc %l3, AF_PLTEXIT, %g0 294 beq .bypass_pltexit 295 ld [%fp + -0x4], %l1 ! %l1 = * dyndata 296 ld [%l1 + SBFLAGS_OFF], %l2 ! %l2 = sb_flags 297 andcc %l2, LA_SYMB_NOPLTEXIT, %g0 298 bne .bypass_pltexit 299 nop 300 301 ba .start_pltexit 302 nop 303.bypass_pltexit: 304 jmpl %l0, %g0 305 restore 306 307.start_pltexit: 308 /* 309 * In order to call la_pltexit() we must duplicate the 310 * arguments from the 'callers' stack on our stack frame. 311 * 312 * First we check the size of the callers stack and grow 313 * our stack to hold any of the arguments. That need 314 * duplicating (these are arguments 6->N), because the 315 * first 6 (0->5) are passed via register windows on sparc. 316 */ 317 318 /* 319 * The first calculation is to determine how large the 320 * argument passing area might be. Since there is no 321 * way to distinquish between 'argument passing' and 322 * 'local storage' from the previous stack this amount must 323 * cover both. 324 */ 325 ld [%fp + -0x8], %l1 ! %l1 = callers stack size 326 sub %l1, 0x58, %l1 ! %l1 = argument space on caller's 327 ! stack 328 /* 329 * Next we compare the prev. stack size against the audit_argcnt. 330 * We copy at most 'audit_argcnt' arguments. 331 * 332 * NOTE: on sparc we always copy at least six args since these 333 * are in reg-windows and not on the stack. 334 * 335 * NOTE: Also note that we multiply (shift really) the arg count 336 * by 4 which is the 'word size' to calculate the amount 337 * of stack space needed. 338 */ 339 ld [%l7 + audit_argcnt], %l2 340 ld [%l2], %l2 ! %l2 = audit_arg_count 341 cmp %l2, 6 342 ble .grow_stack 343 sub %l2, 6, %l2 344 sll %l2, 2, %l2 345 cmp %l1, %l2 346 ble .grow_stack 347 nop 348 mov %l2, %l1 349.grow_stack: 350 /* 351 * When duplicating the stack we skip the first '0x5c' bytes. 352 * This is the space on the stack reserved for preserving 353 * the register windows and such and do not need to be duplicated 354 * on this new stack frame. We start duplicating at the 355 * portion of the stack reserved for argument's above 6. 356 */ 357 sub %sp, %l1, %sp ! grow our stack by amount required. 358 sra %l1, 0x2, %l1 ! %l1 = %l1 / 4 (words to copy) 359 mov 0x5c, %l2 ! %l2 = index into stack & frame 360 3611: 362 cmp %l1, 0 363 ble 2f 364 nop 365 ld [%fp + %l2], %l3 ! duplicate args from previous 366 st %l3, [%sp + %l2] ! stack onto current stack 367 add %l2, 0x4, %l2 368 ba 1b 369 sub %l1, 0x1, %l1 3702: 371 mov %i0, %o0 ! copy ins to outs 372 mov %i1, %o1 373 mov %i2, %o2 374 mov %i3, %o3 375 mov %i4, %o4 376 call %l0 ! call routine 377 mov %i5, %o5 378 mov %o1, %l2 ! l2 = second 1/2 of return value 379 ! for those those 64 bit operations 380 ! link div64 - yuck... 381 382 ! %o0 = retval 383 ld [%fp + -0x4], %l1 384 ld [%l1 + REFLMP_OFF], %o1 ! %o1 = reflmp 385 ld [%l1 + DEFLMP_OFF], %o2 ! %o2 = deflmp 386 add %l1, SYMDEF_OFF, %o3 ! %o3 = symp 387 call audit_pltexit 388 ld [%l1 + SYMNDX_OFF], %o4 ! %o4 = symndx 389 390 mov %o0, %i0 ! pass on return code 391 mov %l2, %i1 392 ret 393 restore 394 .size elf_plt_trace, . - elf_plt_trace 395 396#endif 397 398/* 399 * After the first call to a plt, elf_bndr() will have determined the true 400 * address of the function being bound. The plt is now rewritten so that 401 * any subsequent calls go directly to the bound function. If the library 402 * to which the function belongs is being profiled refer to _plt_cg_write. 403 * 404 * the new plt entry is: 405 * 406 * sethi (.-PLT0), %g1 ! constant 407 * sethi %hi(function address), %g1 ! patched second 408 * jmpl %g1 + %lo(function address, %g0 ! patched first 409 */ 410 411#if defined(lint) 412 413void 414plt_full_range(uintptr_t pc, uintptr_t symval) 415{ 416 uint_t * plttab = (uint_t *)pc; 417 plttab[2] = (M_JMPL | ((unsigned long)symval & S_MASK(10))); 418 plttab[1] = (M_SETHIG1 | ((unsigned long)symval >> (32 - 22))); 419} 420 421#else 422 ENTRY(plt_full_range) 423 424 sethi %hi(M_JMPL), %o3 ! Get jmpl instruction 425 and %o1, 0x3ff, %o2 ! Lower part of function address 426 or %o3, %o2, %o3 ! is or'ed into instruction 427 st %o3, [%o0 + 8] ! Store instruction in plt[2] 428 iflush %o0 + 8 429 stbar 430 431 srl %o1, 10, %o1 ! Get high part of function address 432 sethi %hi(M_SETHIG1), %o3 ! Get sethi instruction 433 or %o3, %o1, %o3 ! Add sethi and function address 434 st %o3, [%o0 + 4] ! Store instruction in plt[1] 435 retl 436 iflush %o0 + 4 437 438 SET_SIZE(plt_full_range) 439 440#endif /* defined(lint) */ 441 442