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