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 55aefb655Srie * Common Development and Distribution License (the "License"). 65aefb655Srie * 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 */ 215aefb655Srie 227c478bd9Sstevel@tonic-gate /* 237257d1b4Sraf * Copyright (c) 1988 AT&T 247257d1b4Sraf * All Rights Reserved 25f441771bSRod Evans * 26f441771bSRod Evans * Copyright (c) 1990, 2010, Oracle and/or its affiliates. All rights reserved. 27*38f4bdddSBryan Cantrill * Copyright (c) 2012, Joyent, Inc. All rights reserved. 287257d1b4Sraf */ 297257d1b4Sraf 307c478bd9Sstevel@tonic-gate /* 317c478bd9Sstevel@tonic-gate * SPARC machine dependent and ELF file class dependent functions. 327c478bd9Sstevel@tonic-gate * Contains routines for performing function binding and symbol relocations. 337c478bd9Sstevel@tonic-gate */ 347c478bd9Sstevel@tonic-gate 357c478bd9Sstevel@tonic-gate #include <stdio.h> 367c478bd9Sstevel@tonic-gate #include <sys/elf.h> 377c478bd9Sstevel@tonic-gate #include <sys/elf_SPARC.h> 387c478bd9Sstevel@tonic-gate #include <sys/mman.h> 397c478bd9Sstevel@tonic-gate #include <dlfcn.h> 407c478bd9Sstevel@tonic-gate #include <synch.h> 417c478bd9Sstevel@tonic-gate #include <string.h> 425aefb655Srie #include <debug.h> 435aefb655Srie #include <reloc.h> 445aefb655Srie #include <conv.h> 457c478bd9Sstevel@tonic-gate #include "_rtld.h" 467c478bd9Sstevel@tonic-gate #include "_audit.h" 477c478bd9Sstevel@tonic-gate #include "_elf.h" 48f441771bSRod Evans #include "_inline_gen.h" 49f441771bSRod Evans #include "_inline_reloc.h" 507c478bd9Sstevel@tonic-gate #include "msg.h" 517c478bd9Sstevel@tonic-gate 527c478bd9Sstevel@tonic-gate extern void iflush_range(caddr_t, size_t); 537c478bd9Sstevel@tonic-gate extern void plt_full_range(uintptr_t, uintptr_t); 547c478bd9Sstevel@tonic-gate 557c478bd9Sstevel@tonic-gate int 567c478bd9Sstevel@tonic-gate elf_mach_flags_check(Rej_desc *rej, Ehdr *ehdr) 577c478bd9Sstevel@tonic-gate { 587c478bd9Sstevel@tonic-gate /* 597c478bd9Sstevel@tonic-gate * Check machine type and flags. 607c478bd9Sstevel@tonic-gate */ 617c478bd9Sstevel@tonic-gate if (ehdr->e_machine != EM_SPARC) { 627c478bd9Sstevel@tonic-gate if (ehdr->e_machine != EM_SPARC32PLUS) { 637c478bd9Sstevel@tonic-gate rej->rej_type = SGS_REJ_MACH; 647c478bd9Sstevel@tonic-gate rej->rej_info = (uint_t)ehdr->e_machine; 657c478bd9Sstevel@tonic-gate return (0); 667c478bd9Sstevel@tonic-gate } 677c478bd9Sstevel@tonic-gate if ((ehdr->e_flags & EF_SPARC_32PLUS) == 0) { 687c478bd9Sstevel@tonic-gate rej->rej_type = SGS_REJ_MISFLAG; 697c478bd9Sstevel@tonic-gate rej->rej_info = (uint_t)ehdr->e_flags; 707c478bd9Sstevel@tonic-gate return (0); 717c478bd9Sstevel@tonic-gate } 727c478bd9Sstevel@tonic-gate if ((ehdr->e_flags & ~at_flags) & EF_SPARC_32PLUS_MASK) { 737c478bd9Sstevel@tonic-gate rej->rej_type = SGS_REJ_BADFLAG; 747c478bd9Sstevel@tonic-gate rej->rej_info = (uint_t)ehdr->e_flags; 757c478bd9Sstevel@tonic-gate return (0); 767c478bd9Sstevel@tonic-gate } 777c478bd9Sstevel@tonic-gate } else if ((ehdr->e_flags & ~EF_SPARCV9_MM) != 0) { 787c478bd9Sstevel@tonic-gate rej->rej_type = SGS_REJ_BADFLAG; 797c478bd9Sstevel@tonic-gate rej->rej_info = (uint_t)ehdr->e_flags; 807c478bd9Sstevel@tonic-gate return (0); 817c478bd9Sstevel@tonic-gate } 827c478bd9Sstevel@tonic-gate return (1); 837c478bd9Sstevel@tonic-gate } 847c478bd9Sstevel@tonic-gate 857c478bd9Sstevel@tonic-gate void 867c478bd9Sstevel@tonic-gate ldso_plt_init(Rt_map *lmp) 877c478bd9Sstevel@tonic-gate { 887c478bd9Sstevel@tonic-gate /* 897c478bd9Sstevel@tonic-gate * There is no need to analyze ld.so because we don't map in any of 907c478bd9Sstevel@tonic-gate * its dependencies. However we may map these dependencies in later 917c478bd9Sstevel@tonic-gate * (as if ld.so had dlopened them), so initialize the plt and the 927c478bd9Sstevel@tonic-gate * permission information. 937c478bd9Sstevel@tonic-gate */ 947c478bd9Sstevel@tonic-gate if (PLTGOT(lmp)) 957c478bd9Sstevel@tonic-gate elf_plt_init((PLTGOT(lmp)), (caddr_t)lmp); 967c478bd9Sstevel@tonic-gate } 977c478bd9Sstevel@tonic-gate 987c478bd9Sstevel@tonic-gate /* 997c478bd9Sstevel@tonic-gate * elf_plt_write() will test to see how far away our destination 1007c478bd9Sstevel@tonic-gate * address lies. If it is close enough that a branch can 1017c478bd9Sstevel@tonic-gate * be used instead of a jmpl - we will fill the plt in with 1027c478bd9Sstevel@tonic-gate * single branch. The branches are much quicker then 1037c478bd9Sstevel@tonic-gate * a jmpl instruction - see bug#4356879 for further 1047c478bd9Sstevel@tonic-gate * details. 1057c478bd9Sstevel@tonic-gate * 1067c478bd9Sstevel@tonic-gate * NOTE: we pass in both a 'pltaddr' and a 'vpltaddr' since 1077c478bd9Sstevel@tonic-gate * librtld/dldump update PLT's who's physical 1087c478bd9Sstevel@tonic-gate * address is not the same as the 'virtual' runtime 1097c478bd9Sstevel@tonic-gate * address. 1107c478bd9Sstevel@tonic-gate */ 1117c478bd9Sstevel@tonic-gate Pltbindtype 1127c478bd9Sstevel@tonic-gate /* ARGSUSED4 */ 1137c478bd9Sstevel@tonic-gate elf_plt_write(uintptr_t addr, uintptr_t vaddr, void *rptr, uintptr_t symval, 1147c478bd9Sstevel@tonic-gate Xword pltndx) 1157c478bd9Sstevel@tonic-gate { 1167c478bd9Sstevel@tonic-gate Rela *rel = (Rela *)rptr; 1177c478bd9Sstevel@tonic-gate uintptr_t vpltaddr, pltaddr; 1187c478bd9Sstevel@tonic-gate long disp; 1197c478bd9Sstevel@tonic-gate 1207c478bd9Sstevel@tonic-gate pltaddr = addr + rel->r_offset; 1217c478bd9Sstevel@tonic-gate vpltaddr = vaddr + rel->r_offset; 1227c478bd9Sstevel@tonic-gate disp = symval - vpltaddr - 4; 1237c478bd9Sstevel@tonic-gate 1247c478bd9Sstevel@tonic-gate /* 1257c478bd9Sstevel@tonic-gate * Test if the destination address is close enough to use 1267c478bd9Sstevel@tonic-gate * a ba,a... instruction to reach it. 1277c478bd9Sstevel@tonic-gate */ 1287c478bd9Sstevel@tonic-gate if (S_INRANGE(disp, 23) && !(rtld_flags & RT_FL_NOBAPLT)) { 1297c478bd9Sstevel@tonic-gate uint_t *pltent, bainstr; 1307c478bd9Sstevel@tonic-gate Pltbindtype rc; 1317c478bd9Sstevel@tonic-gate 1327c478bd9Sstevel@tonic-gate pltent = (uint_t *)pltaddr; 13356deab07SRod Evans 1347c478bd9Sstevel@tonic-gate /* 1357c478bd9Sstevel@tonic-gate * The 1367c478bd9Sstevel@tonic-gate * 1377c478bd9Sstevel@tonic-gate * ba,a,pt %icc, <dest> 1387c478bd9Sstevel@tonic-gate * 1397c478bd9Sstevel@tonic-gate * is the most efficient of the PLT's. If we 1407c478bd9Sstevel@tonic-gate * are within +-20 bits *and* running on a 1417c478bd9Sstevel@tonic-gate * v8plus architecture - use that branch. 1427c478bd9Sstevel@tonic-gate */ 1437c478bd9Sstevel@tonic-gate if ((at_flags & EF_SPARC_32PLUS) && 1447c478bd9Sstevel@tonic-gate S_INRANGE(disp, 20)) { 1457c478bd9Sstevel@tonic-gate bainstr = M_BA_A_PT; /* ba,a,pt %icc,<dest> */ 1467c478bd9Sstevel@tonic-gate bainstr |= (S_MASK(19) & (disp >> 2)); 1477c478bd9Sstevel@tonic-gate rc = PLT_T_21D; 1487c478bd9Sstevel@tonic-gate DBG_CALL(pltcnt21d++); 1497c478bd9Sstevel@tonic-gate } else { 1507c478bd9Sstevel@tonic-gate /* 1517c478bd9Sstevel@tonic-gate * Otherwise - we fall back to the good old 1527c478bd9Sstevel@tonic-gate * 1537c478bd9Sstevel@tonic-gate * ba,a <dest> 1547c478bd9Sstevel@tonic-gate * 1557c478bd9Sstevel@tonic-gate * Which still beats a jmpl instruction. 1567c478bd9Sstevel@tonic-gate */ 1577c478bd9Sstevel@tonic-gate bainstr = M_BA_A; /* ba,a <dest> */ 1587c478bd9Sstevel@tonic-gate bainstr |= (S_MASK(22) & (disp >> 2)); 1597c478bd9Sstevel@tonic-gate rc = PLT_T_24D; 1607c478bd9Sstevel@tonic-gate DBG_CALL(pltcnt24d++); 1617c478bd9Sstevel@tonic-gate } 1627c478bd9Sstevel@tonic-gate 1637c478bd9Sstevel@tonic-gate pltent[2] = M_NOP; /* nop instr */ 1647c478bd9Sstevel@tonic-gate pltent[1] = bainstr; 1657c478bd9Sstevel@tonic-gate 1667c478bd9Sstevel@tonic-gate iflush_range((char *)(&pltent[1]), 4); 1677c478bd9Sstevel@tonic-gate pltent[0] = M_NOP; /* nop instr */ 1687c478bd9Sstevel@tonic-gate iflush_range((char *)(&pltent[0]), 4); 1697c478bd9Sstevel@tonic-gate return (rc); 1707c478bd9Sstevel@tonic-gate } 1717c478bd9Sstevel@tonic-gate 1727c478bd9Sstevel@tonic-gate /* 1737c478bd9Sstevel@tonic-gate * The PLT destination is not in reach of 1747c478bd9Sstevel@tonic-gate * a branch instruction - so we fall back 1757c478bd9Sstevel@tonic-gate * to a 'jmpl' sequence. 1767c478bd9Sstevel@tonic-gate */ 1777c478bd9Sstevel@tonic-gate plt_full_range(pltaddr, symval); 1787c478bd9Sstevel@tonic-gate DBG_CALL(pltcntfull++); 1797c478bd9Sstevel@tonic-gate return (PLT_T_FULL); 1807c478bd9Sstevel@tonic-gate } 1817c478bd9Sstevel@tonic-gate 1827c478bd9Sstevel@tonic-gate /* 1837c478bd9Sstevel@tonic-gate * Local storage space created on the stack created for this glue 1847c478bd9Sstevel@tonic-gate * code includes space for: 1857c478bd9Sstevel@tonic-gate * 0x4 pointer to dyn_data 1867c478bd9Sstevel@tonic-gate * 0x4 size prev stack frame 1877c478bd9Sstevel@tonic-gate */ 1887c478bd9Sstevel@tonic-gate static const uchar_t dyn_plt_template[] = { 1897c478bd9Sstevel@tonic-gate /* 0x00 */ 0x80, 0x90, 0x00, 0x1e, /* tst %fp */ 1907c478bd9Sstevel@tonic-gate /* 0x04 */ 0x02, 0x80, 0x00, 0x04, /* be 0x14 */ 1917c478bd9Sstevel@tonic-gate /* 0x08 */ 0x82, 0x27, 0x80, 0x0e, /* sub %sp, %fp, %g1 */ 1927c478bd9Sstevel@tonic-gate /* 0x0c */ 0x10, 0x80, 0x00, 0x03, /* ba 0x20 */ 1937c478bd9Sstevel@tonic-gate /* 0x10 */ 0x01, 0x00, 0x00, 0x00, /* nop */ 1947c478bd9Sstevel@tonic-gate /* 0x14 */ 0x82, 0x10, 0x20, 0x60, /* mov 0x60, %g1 */ 1957c478bd9Sstevel@tonic-gate /* 0x18 */ 0x9d, 0xe3, 0xbf, 0x98, /* save %sp, -0x68, %sp */ 1967c478bd9Sstevel@tonic-gate /* 0x1c */ 0xc2, 0x27, 0xbf, 0xf8, /* st %g1, [%fp + -0x8] */ 1977c478bd9Sstevel@tonic-gate /* 0x20 */ 0x03, 0x00, 0x00, 0x00, /* sethi %hi(val), %g1 */ 1987c478bd9Sstevel@tonic-gate /* 0x24 */ 0x82, 0x10, 0x60, 0x00, /* or %g1, %lo(val), %g1 */ 1997c478bd9Sstevel@tonic-gate /* 0x28 */ 0x40, 0x00, 0x00, 0x00, /* call <rel_addr> */ 2007c478bd9Sstevel@tonic-gate /* 0x2c */ 0xc2, 0x27, 0xbf, 0xfc /* st %g1, [%fp + -0x4] */ 2017c478bd9Sstevel@tonic-gate }; 2027c478bd9Sstevel@tonic-gate 2037c478bd9Sstevel@tonic-gate int dyn_plt_ent_size = sizeof (dyn_plt_template) + 2047c478bd9Sstevel@tonic-gate sizeof (uintptr_t) + /* reflmp */ 2057c478bd9Sstevel@tonic-gate sizeof (uintptr_t) + /* deflmp */ 2067c478bd9Sstevel@tonic-gate sizeof (ulong_t) + /* symndx */ 2077c478bd9Sstevel@tonic-gate sizeof (ulong_t) + /* sb_flags */ 2087c478bd9Sstevel@tonic-gate sizeof (Sym); /* symdef */ 2097c478bd9Sstevel@tonic-gate 2107c478bd9Sstevel@tonic-gate /* 2117c478bd9Sstevel@tonic-gate * the dynamic plt entry is: 2127c478bd9Sstevel@tonic-gate * 2137c478bd9Sstevel@tonic-gate * tst %fp 2147c478bd9Sstevel@tonic-gate * be 1f 2157c478bd9Sstevel@tonic-gate * nop 2167c478bd9Sstevel@tonic-gate * sub %sp, %fp, %g1 2177c478bd9Sstevel@tonic-gate * ba 2f 2187c478bd9Sstevel@tonic-gate * nop 2197c478bd9Sstevel@tonic-gate * 1: 2207c478bd9Sstevel@tonic-gate * mov SA(MINFRAME), %g1 ! if %fp is null this is the 2217c478bd9Sstevel@tonic-gate * ! 'minimum stack'. %fp is null 2227c478bd9Sstevel@tonic-gate * ! on the initial stack frame 2237c478bd9Sstevel@tonic-gate * 2: 2247c478bd9Sstevel@tonic-gate * save %sp, -(SA(MINFRAME) + 2 * CLONGSIZE), %sp 2257c478bd9Sstevel@tonic-gate * st %g1, [%fp + -0x8] ! store prev_stack size in [%fp - 8] 2267c478bd9Sstevel@tonic-gate * sethi %hi(dyn_data), %g1 2277c478bd9Sstevel@tonic-gate * or %g1, %lo(dyn_data), %g1 2287c478bd9Sstevel@tonic-gate * call elf_plt_trace 2297c478bd9Sstevel@tonic-gate * st %g1, [%fp + -0x4] ! store dyn_data ptr in [%fp - 4] 2307c478bd9Sstevel@tonic-gate * dyn data: 2317c478bd9Sstevel@tonic-gate * uintptr_t reflmp 2327c478bd9Sstevel@tonic-gate * uintptr_t deflmp 2337c478bd9Sstevel@tonic-gate * ulong_t symndx 2347c478bd9Sstevel@tonic-gate * ulong_t sb_flags 2357c478bd9Sstevel@tonic-gate * Sym symdef 2367c478bd9Sstevel@tonic-gate */ 2377c478bd9Sstevel@tonic-gate static caddr_t 2387c478bd9Sstevel@tonic-gate elf_plt_trace_write(caddr_t addr, Rela *rptr, Rt_map *rlmp, Rt_map *dlmp, 2397c478bd9Sstevel@tonic-gate Sym *sym, ulong_t symndx, ulong_t pltndx, caddr_t to, ulong_t sb_flags, 2407c478bd9Sstevel@tonic-gate int *fail) 2417c478bd9Sstevel@tonic-gate { 2427c478bd9Sstevel@tonic-gate extern ulong_t elf_plt_trace(); 24356deab07SRod Evans uchar_t *dyn_plt; 24456deab07SRod Evans uintptr_t *dyndata; 2457c478bd9Sstevel@tonic-gate 2467c478bd9Sstevel@tonic-gate /* 2477c478bd9Sstevel@tonic-gate * If both pltenter & pltexit have been disabled there 2487c478bd9Sstevel@tonic-gate * there is no reason to even create the glue code. 2497c478bd9Sstevel@tonic-gate */ 2507c478bd9Sstevel@tonic-gate if ((sb_flags & (LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT)) == 2517c478bd9Sstevel@tonic-gate (LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT)) { 2527c478bd9Sstevel@tonic-gate (void) elf_plt_write((uintptr_t)addr, (uintptr_t)addr, 2537c478bd9Sstevel@tonic-gate rptr, (uintptr_t)to, pltndx); 2547c478bd9Sstevel@tonic-gate return (to); 2557c478bd9Sstevel@tonic-gate } 2567c478bd9Sstevel@tonic-gate 2577c478bd9Sstevel@tonic-gate /* 2587c478bd9Sstevel@tonic-gate * We only need to add the glue code if there is an auditing 2597c478bd9Sstevel@tonic-gate * library that is interested in this binding. 2607c478bd9Sstevel@tonic-gate */ 26156deab07SRod Evans dyn_plt = (uchar_t *)((uintptr_t)AUDINFO(rlmp)->ai_dynplts + 26256deab07SRod Evans (pltndx * dyn_plt_ent_size)); 2637c478bd9Sstevel@tonic-gate 2647c478bd9Sstevel@tonic-gate /* 2657c478bd9Sstevel@tonic-gate * Have we initialized this dynamic plt entry yet? If we haven't do it 2667c478bd9Sstevel@tonic-gate * now. Otherwise this function has been called before, but from a 2677c478bd9Sstevel@tonic-gate * different plt (ie. from another shared object). In that case 2687c478bd9Sstevel@tonic-gate * we just set the plt to point to the new dyn_plt. 2697c478bd9Sstevel@tonic-gate */ 27056deab07SRod Evans if (*dyn_plt == 0) { 2717c478bd9Sstevel@tonic-gate Sym *symp; 2727c478bd9Sstevel@tonic-gate Xword symvalue; 2735aefb655Srie Lm_list *lml = LIST(rlmp); 2747c478bd9Sstevel@tonic-gate 2757c478bd9Sstevel@tonic-gate (void) memcpy((void *)dyn_plt, dyn_plt_template, 2767c478bd9Sstevel@tonic-gate sizeof (dyn_plt_template)); 27756deab07SRod Evans dyndata = (uintptr_t *)((uintptr_t)dyn_plt + 27856deab07SRod Evans sizeof (dyn_plt_template)); 2797c478bd9Sstevel@tonic-gate 2807c478bd9Sstevel@tonic-gate /* 2817c478bd9Sstevel@tonic-gate * relocating: 2827c478bd9Sstevel@tonic-gate * sethi %hi(dyndata), %g1 2837c478bd9Sstevel@tonic-gate */ 2847c478bd9Sstevel@tonic-gate symvalue = (Xword)dyndata; 28556deab07SRod Evans if (do_reloc_rtld(R_SPARC_HI22, (dyn_plt + 0x20), 2867c478bd9Sstevel@tonic-gate &symvalue, MSG_ORIG(MSG_SYM_LADYNDATA), 2875aefb655Srie MSG_ORIG(MSG_SPECFIL_DYNPLT), lml) == 0) { 2887c478bd9Sstevel@tonic-gate *fail = 1; 2897c478bd9Sstevel@tonic-gate return (0); 2907c478bd9Sstevel@tonic-gate } 2917c478bd9Sstevel@tonic-gate 2927c478bd9Sstevel@tonic-gate /* 2937c478bd9Sstevel@tonic-gate * relocating: 2947c478bd9Sstevel@tonic-gate * or %g1, %lo(dyndata), %g1 2957c478bd9Sstevel@tonic-gate */ 2967c478bd9Sstevel@tonic-gate symvalue = (Xword)dyndata; 29756deab07SRod Evans if (do_reloc_rtld(R_SPARC_LO10, (dyn_plt + 0x24), 2987c478bd9Sstevel@tonic-gate &symvalue, MSG_ORIG(MSG_SYM_LADYNDATA), 2995aefb655Srie MSG_ORIG(MSG_SPECFIL_DYNPLT), lml) == 0) { 3007c478bd9Sstevel@tonic-gate *fail = 1; 3017c478bd9Sstevel@tonic-gate return (0); 3027c478bd9Sstevel@tonic-gate } 3037c478bd9Sstevel@tonic-gate 3047c478bd9Sstevel@tonic-gate /* 3057c478bd9Sstevel@tonic-gate * relocating: 3067c478bd9Sstevel@tonic-gate * call elf_plt_trace 3077c478bd9Sstevel@tonic-gate */ 3087c478bd9Sstevel@tonic-gate symvalue = (Xword)((uintptr_t)&elf_plt_trace - 30956deab07SRod Evans (uintptr_t)(dyn_plt + 0x28)); 31056deab07SRod Evans if (do_reloc_rtld(R_SPARC_WDISP30, (dyn_plt + 0x28), 3117c478bd9Sstevel@tonic-gate &symvalue, MSG_ORIG(MSG_SYM_ELFPLTTRACE), 3125aefb655Srie MSG_ORIG(MSG_SPECFIL_DYNPLT), lml) == 0) { 3137c478bd9Sstevel@tonic-gate *fail = 1; 3147c478bd9Sstevel@tonic-gate return (0); 3157c478bd9Sstevel@tonic-gate } 3167c478bd9Sstevel@tonic-gate 3177c478bd9Sstevel@tonic-gate *dyndata++ = (uintptr_t)rlmp; 3187c478bd9Sstevel@tonic-gate *dyndata++ = (uintptr_t)dlmp; 3197c478bd9Sstevel@tonic-gate *(ulong_t *)dyndata++ = symndx; 3207c478bd9Sstevel@tonic-gate *(ulong_t *)dyndata++ = sb_flags; 3217c478bd9Sstevel@tonic-gate symp = (Sym *)dyndata; 3227c478bd9Sstevel@tonic-gate *symp = *sym; 3237c478bd9Sstevel@tonic-gate symp->st_name += (Word)STRTAB(dlmp); 3247c478bd9Sstevel@tonic-gate symp->st_value = (Addr)to; 3257c478bd9Sstevel@tonic-gate 3267c478bd9Sstevel@tonic-gate iflush_range((void *)dyn_plt, sizeof (dyn_plt_template)); 3277c478bd9Sstevel@tonic-gate } 3287c478bd9Sstevel@tonic-gate 32956deab07SRod Evans (void) elf_plt_write((uintptr_t)addr, (uintptr_t)addr, rptr, 33056deab07SRod Evans (uintptr_t)dyn_plt, 0); 3317c478bd9Sstevel@tonic-gate return ((caddr_t)dyn_plt); 3327c478bd9Sstevel@tonic-gate } 3337c478bd9Sstevel@tonic-gate 3347c478bd9Sstevel@tonic-gate /* 3357c478bd9Sstevel@tonic-gate * Function binding routine - invoked on the first call to a function through 3367c478bd9Sstevel@tonic-gate * the procedure linkage table; 3377c478bd9Sstevel@tonic-gate * passes first through an assembly language interface. 3387c478bd9Sstevel@tonic-gate * 3397c478bd9Sstevel@tonic-gate * Takes the address of the PLT entry where the call originated, 3407c478bd9Sstevel@tonic-gate * the offset into the relocation table of the associated 3417c478bd9Sstevel@tonic-gate * relocation entry and the address of the link map (rt_private_map struct) 3427c478bd9Sstevel@tonic-gate * for the entry. 3437c478bd9Sstevel@tonic-gate * 3447c478bd9Sstevel@tonic-gate * Returns the address of the function referenced after re-writing the PLT 3457c478bd9Sstevel@tonic-gate * entry to invoke the function directly. 3467c478bd9Sstevel@tonic-gate * 3477c478bd9Sstevel@tonic-gate * On error, causes process to terminate with a signal. 3487c478bd9Sstevel@tonic-gate */ 3497c478bd9Sstevel@tonic-gate ulong_t 3507c478bd9Sstevel@tonic-gate elf_bndr(Rt_map *lmp, ulong_t pltoff, caddr_t from) 3517c478bd9Sstevel@tonic-gate { 3527c478bd9Sstevel@tonic-gate Rt_map *nlmp, *llmp; 3537c478bd9Sstevel@tonic-gate ulong_t addr, vaddr, reloff, symval, rsymndx; 3547c478bd9Sstevel@tonic-gate char *name; 3557c478bd9Sstevel@tonic-gate Rela *rptr; 35660758829Srie Sym *rsym, *nsym; 3577c478bd9Sstevel@tonic-gate Xword pltndx; 35856deab07SRod Evans uint_t binfo, sb_flags = 0, dbg_class; 3597c478bd9Sstevel@tonic-gate Slookup sl; 36008278a5eSRod Evans Sresult sr; 3617c478bd9Sstevel@tonic-gate Pltbindtype pbtype; 3625aefb655Srie int entry, lmflags; 36356deab07SRod Evans Lm_list *lml; 3647c478bd9Sstevel@tonic-gate 3657c478bd9Sstevel@tonic-gate /* 3667c478bd9Sstevel@tonic-gate * For compatibility with libthread (TI_VERSION 1) we track the entry 3677c478bd9Sstevel@tonic-gate * value. A zero value indicates we have recursed into ld.so.1 to 3687c478bd9Sstevel@tonic-gate * further process a locking request. Under this recursion we disable 3697c478bd9Sstevel@tonic-gate * tsort and cleanup activities. 3707c478bd9Sstevel@tonic-gate */ 3718cd45542Sraf entry = enter(0); 3727c478bd9Sstevel@tonic-gate 37356deab07SRod Evans lml = LIST(lmp); 3745aefb655Srie if ((lmflags = lml->lm_flags) & LML_FLG_RTLDLM) { 3755aefb655Srie dbg_class = dbg_desc->d_class; 3765aefb655Srie dbg_desc->d_class = 0; 3777c478bd9Sstevel@tonic-gate } 3787c478bd9Sstevel@tonic-gate 3797c478bd9Sstevel@tonic-gate /* 3807c478bd9Sstevel@tonic-gate * Must calculate true plt relocation address from reloc. 3817c478bd9Sstevel@tonic-gate * Take offset, subtract number of reserved PLT entries, and divide 3827c478bd9Sstevel@tonic-gate * by PLT entry size, which should give the index of the plt 3837c478bd9Sstevel@tonic-gate * entry (and relocation entry since they have been defined to be 3847c478bd9Sstevel@tonic-gate * in the same order). Then we must multiply by the size of 3857c478bd9Sstevel@tonic-gate * a relocation entry, which will give us the offset of the 3867c478bd9Sstevel@tonic-gate * plt relocation entry from the start of them given by JMPREL(lm). 3877c478bd9Sstevel@tonic-gate */ 3887c478bd9Sstevel@tonic-gate addr = pltoff - M_PLT_RESERVSZ; 3897c478bd9Sstevel@tonic-gate pltndx = addr / M_PLT_ENTSIZE; 3907c478bd9Sstevel@tonic-gate 3917c478bd9Sstevel@tonic-gate /* 3927c478bd9Sstevel@tonic-gate * Perform some basic sanity checks. If we didn't get a load map 3937c478bd9Sstevel@tonic-gate * or the plt offset is invalid then its possible someone has walked 39456deab07SRod Evans * over the plt entries or jumped to plt[0] out of the blue. 3957c478bd9Sstevel@tonic-gate */ 3967c478bd9Sstevel@tonic-gate if (!lmp || ((addr % M_PLT_ENTSIZE) != 0)) { 397de777a60Sab196087 Conv_inv_buf_t inv_buf; 398de777a60Sab196087 3995aefb655Srie eprintf(lml, ERR_FATAL, MSG_INTL(MSG_REL_PLTREF), 400de777a60Sab196087 conv_reloc_SPARC_type(R_SPARC_JMP_SLOT, 0, &inv_buf), 4015aefb655Srie EC_NATPTR(lmp), EC_XWORD(pltoff), EC_NATPTR(from)); 4025aefb655Srie rtldexit(lml, 1); 4037c478bd9Sstevel@tonic-gate } 4047c478bd9Sstevel@tonic-gate reloff = pltndx * sizeof (Rela); 4057c478bd9Sstevel@tonic-gate 4067c478bd9Sstevel@tonic-gate /* 4077c478bd9Sstevel@tonic-gate * Use relocation entry to get symbol table entry and symbol name. 4087c478bd9Sstevel@tonic-gate */ 4097c478bd9Sstevel@tonic-gate addr = (ulong_t)JMPREL(lmp); 4107c478bd9Sstevel@tonic-gate rptr = (Rela *)(addr + reloff); 4117c478bd9Sstevel@tonic-gate rsymndx = ELF_R_SYM(rptr->r_info); 41260758829Srie rsym = (Sym *)((ulong_t)SYMTAB(lmp) + (rsymndx * SYMENT(lmp))); 41360758829Srie name = (char *)(STRTAB(lmp) + rsym->st_name); 4147c478bd9Sstevel@tonic-gate 4157c478bd9Sstevel@tonic-gate /* 4167c478bd9Sstevel@tonic-gate * Determine the last link-map of this list, this'll be the starting 4177c478bd9Sstevel@tonic-gate * point for any tsort() processing. 4187c478bd9Sstevel@tonic-gate */ 4195aefb655Srie llmp = lml->lm_tail; 4207c478bd9Sstevel@tonic-gate 4217c478bd9Sstevel@tonic-gate /* 42208278a5eSRod Evans * Find definition for symbol. Initialize the symbol lookup, and 42308278a5eSRod Evans * symbol result, data structures. 4247c478bd9Sstevel@tonic-gate */ 42575e7992aSrie SLOOKUP_INIT(sl, name, lmp, lml->lm_head, ld_entry_cnt, 0, 42675e7992aSrie rsymndx, rsym, 0, LKUP_DEFT); 42708278a5eSRod Evans SRESULT_INIT(sr, name); 4287c478bd9Sstevel@tonic-gate 42908278a5eSRod Evans if (lookup_sym(&sl, &sr, &binfo, NULL) == 0) { 4305aefb655Srie eprintf(lml, ERR_FATAL, MSG_INTL(MSG_REL_NOSYM), NAME(lmp), 4317c478bd9Sstevel@tonic-gate demangle(name)); 4325aefb655Srie rtldexit(lml, 1); 4337c478bd9Sstevel@tonic-gate } 4347c478bd9Sstevel@tonic-gate 43508278a5eSRod Evans name = (char *)sr.sr_name; 43608278a5eSRod Evans nlmp = sr.sr_dmap; 43708278a5eSRod Evans nsym = sr.sr_sym; 43808278a5eSRod Evans 4397c478bd9Sstevel@tonic-gate symval = nsym->st_value; 44008278a5eSRod Evans 4417c478bd9Sstevel@tonic-gate if (!(FLAGS(nlmp) & FLG_RT_FIXED) && 4427c478bd9Sstevel@tonic-gate (nsym->st_shndx != SHN_ABS)) 4437c478bd9Sstevel@tonic-gate symval += ADDR(nlmp); 4447c478bd9Sstevel@tonic-gate if ((lmp != nlmp) && ((FLAGS1(nlmp) & FL1_RT_NOINIFIN) == 0)) { 4457c478bd9Sstevel@tonic-gate /* 4467c478bd9Sstevel@tonic-gate * Record that this new link map is now bound to the caller. 4477c478bd9Sstevel@tonic-gate */ 4487c478bd9Sstevel@tonic-gate if (bind_one(lmp, nlmp, BND_REFER) == 0) 4495aefb655Srie rtldexit(lml, 1); 4507c478bd9Sstevel@tonic-gate } 4517c478bd9Sstevel@tonic-gate 452*38f4bdddSBryan Cantrill if ((lml->lm_tflags | AFLAGS(lmp) | AFLAGS(nlmp)) & 453*38f4bdddSBryan Cantrill LML_TFLG_AUD_SYMBIND) { 4547c478bd9Sstevel@tonic-gate ulong_t symndx = (((uintptr_t)nsym - 4557c478bd9Sstevel@tonic-gate (uintptr_t)SYMTAB(nlmp)) / SYMENT(nlmp)); 4567c478bd9Sstevel@tonic-gate 4577c478bd9Sstevel@tonic-gate symval = audit_symbind(lmp, nlmp, nsym, symndx, symval, 4587c478bd9Sstevel@tonic-gate &sb_flags); 4597c478bd9Sstevel@tonic-gate } 4607c478bd9Sstevel@tonic-gate 4617c478bd9Sstevel@tonic-gate if (FLAGS(lmp) & FLG_RT_FIXED) 4627c478bd9Sstevel@tonic-gate vaddr = 0; 4637c478bd9Sstevel@tonic-gate else 4647c478bd9Sstevel@tonic-gate vaddr = ADDR(lmp); 4657c478bd9Sstevel@tonic-gate 4667c478bd9Sstevel@tonic-gate pbtype = PLT_T_NONE; 4677c478bd9Sstevel@tonic-gate if (!(rtld_flags & RT_FL_NOBIND)) { 46856deab07SRod Evans if (((lml->lm_tflags | AFLAGS(lmp)) & 4697c478bd9Sstevel@tonic-gate (LML_TFLG_AUD_PLTENTER | LML_TFLG_AUD_PLTEXIT)) && 4707c478bd9Sstevel@tonic-gate AUDINFO(lmp)->ai_dynplts) { 4717c478bd9Sstevel@tonic-gate int fail = 0; 4727c478bd9Sstevel@tonic-gate ulong_t symndx = (((uintptr_t)nsym - 4737c478bd9Sstevel@tonic-gate (uintptr_t)SYMTAB(nlmp)) / SYMENT(nlmp)); 4747c478bd9Sstevel@tonic-gate 4757c478bd9Sstevel@tonic-gate symval = (ulong_t)elf_plt_trace_write((caddr_t)vaddr, 4767c478bd9Sstevel@tonic-gate rptr, lmp, nlmp, nsym, symndx, pltndx, 4777c478bd9Sstevel@tonic-gate (caddr_t)symval, sb_flags, &fail); 4787c478bd9Sstevel@tonic-gate if (fail) 4795aefb655Srie rtldexit(lml, 1); 4807c478bd9Sstevel@tonic-gate } else { 4817c478bd9Sstevel@tonic-gate /* 4827c478bd9Sstevel@tonic-gate * Write standard PLT entry to jump directly 4837c478bd9Sstevel@tonic-gate * to newly bound function. 4847c478bd9Sstevel@tonic-gate */ 4857c478bd9Sstevel@tonic-gate pbtype = elf_plt_write((uintptr_t)vaddr, 4867c478bd9Sstevel@tonic-gate (uintptr_t)vaddr, rptr, symval, pltndx); 4877c478bd9Sstevel@tonic-gate } 4887c478bd9Sstevel@tonic-gate } 4897c478bd9Sstevel@tonic-gate 4907c478bd9Sstevel@tonic-gate /* 4917c478bd9Sstevel@tonic-gate * Print binding information and rebuild PLT entry. 4927c478bd9Sstevel@tonic-gate */ 4935aefb655Srie DBG_CALL(Dbg_bind_global(lmp, (Addr)from, (Off)(from - ADDR(lmp)), 4945aefb655Srie pltndx, pbtype, nlmp, (Addr)symval, nsym->st_value, name, binfo)); 4957c478bd9Sstevel@tonic-gate 4967c478bd9Sstevel@tonic-gate /* 4977c478bd9Sstevel@tonic-gate * Complete any processing for newly loaded objects. Note we don't 4987c478bd9Sstevel@tonic-gate * know exactly where any new objects are loaded (we know the object 4997c478bd9Sstevel@tonic-gate * that supplied the symbol, but others may have been loaded lazily as 5007c478bd9Sstevel@tonic-gate * we searched for the symbol), so sorting starts from the last 5017c478bd9Sstevel@tonic-gate * link-map know on entry to this routine. 5027c478bd9Sstevel@tonic-gate */ 5037c478bd9Sstevel@tonic-gate if (entry) 5047247f888Srie load_completion(llmp); 5057c478bd9Sstevel@tonic-gate 5067c478bd9Sstevel@tonic-gate /* 5077c478bd9Sstevel@tonic-gate * Some operations like dldump() or dlopen()'ing a relocatable object 5087c478bd9Sstevel@tonic-gate * result in objects being loaded on rtld's link-map, make sure these 5097c478bd9Sstevel@tonic-gate * objects are initialized also. 5107c478bd9Sstevel@tonic-gate */ 5117c478bd9Sstevel@tonic-gate if ((LIST(nlmp)->lm_flags & LML_FLG_RTLDLM) && LIST(nlmp)->lm_init) 5127247f888Srie load_completion(nlmp); 5137c478bd9Sstevel@tonic-gate 5147c478bd9Sstevel@tonic-gate /* 5157c478bd9Sstevel@tonic-gate * Make sure the object to which we've bound has had it's .init fired. 5167c478bd9Sstevel@tonic-gate * Cleanup before return to user code. 5177c478bd9Sstevel@tonic-gate */ 5187c478bd9Sstevel@tonic-gate if (entry) { 5197c478bd9Sstevel@tonic-gate is_dep_init(nlmp, lmp); 5208cd45542Sraf leave(lml, 0); 5217c478bd9Sstevel@tonic-gate } 5227c478bd9Sstevel@tonic-gate 5237c478bd9Sstevel@tonic-gate if (lmflags & LML_FLG_RTLDLM) 5245aefb655Srie dbg_desc->d_class = dbg_class; 5257c478bd9Sstevel@tonic-gate 5267c478bd9Sstevel@tonic-gate return (symval); 5277c478bd9Sstevel@tonic-gate } 5287c478bd9Sstevel@tonic-gate 5297c478bd9Sstevel@tonic-gate /* 5307c478bd9Sstevel@tonic-gate * Read and process the relocations for one link object, we assume all 5317c478bd9Sstevel@tonic-gate * relocation sections for loadable segments are stored contiguously in 5327c478bd9Sstevel@tonic-gate * the file. 5337c478bd9Sstevel@tonic-gate */ 5347c478bd9Sstevel@tonic-gate int 53556deab07SRod Evans elf_reloc(Rt_map *lmp, uint_t plt, int *in_nfavl, APlist **textrel) 5367c478bd9Sstevel@tonic-gate { 5377c478bd9Sstevel@tonic-gate ulong_t relbgn, relend, relsiz, basebgn, pltbgn, pltend; 53856deab07SRod Evans ulong_t dsymndx, pltndx, roffset, rsymndx, psymndx = 0; 5397c478bd9Sstevel@tonic-gate uchar_t rtype; 54056deab07SRod Evans long reladd, value, pvalue, relacount = RELACOUNT(lmp); 5417c478bd9Sstevel@tonic-gate Sym *symref, *psymref, *symdef, *psymdef; 542f441771bSRod Evans Syminfo *sip; 5437c478bd9Sstevel@tonic-gate char *name, *pname; 5447c478bd9Sstevel@tonic-gate Rt_map *_lmp, *plmp; 54556deab07SRod Evans int ret = 1, noplt = 0; 5467c478bd9Sstevel@tonic-gate Rela *rel; 5477c478bd9Sstevel@tonic-gate Pltbindtype pbtype; 5487c478bd9Sstevel@tonic-gate uint_t binfo, pbinfo; 549cce0e03bSab196087 APlist *bound = NULL; 5507c478bd9Sstevel@tonic-gate 5517c478bd9Sstevel@tonic-gate /* 5527c478bd9Sstevel@tonic-gate * If an object has any DT_REGISTER entries associated with 5537c478bd9Sstevel@tonic-gate * it, they are processed now. 5547c478bd9Sstevel@tonic-gate */ 5557c478bd9Sstevel@tonic-gate if ((plt == 0) && (FLAGS(lmp) & FLG_RT_REGSYMS)) { 5567c478bd9Sstevel@tonic-gate if (elf_regsyms(lmp) == 0) 5577c478bd9Sstevel@tonic-gate return (0); 5587c478bd9Sstevel@tonic-gate } 5597c478bd9Sstevel@tonic-gate 5607c478bd9Sstevel@tonic-gate /* 5617c478bd9Sstevel@tonic-gate * Although only necessary for lazy binding, initialize the first 5627c478bd9Sstevel@tonic-gate * procedure linkage table entry to go to elf_rtbndr(). dbx(1) seems 5637c478bd9Sstevel@tonic-gate * to find this useful. 5647c478bd9Sstevel@tonic-gate */ 5657c478bd9Sstevel@tonic-gate if ((plt == 0) && PLTGOT(lmp)) { 56656deab07SRod Evans mmapobj_result_t *mpp; 56756deab07SRod Evans 56856deab07SRod Evans /* 56956deab07SRod Evans * Make sure the segment is writable. 57056deab07SRod Evans */ 57156deab07SRod Evans if ((((mpp = 57256deab07SRod Evans find_segment((caddr_t)PLTGOT(lmp), lmp)) != NULL) && 57356deab07SRod Evans ((mpp->mr_prot & PROT_WRITE) == 0)) && 57456deab07SRod Evans ((set_prot(lmp, mpp, 1) == 0) || 57556deab07SRod Evans (aplist_append(textrel, mpp, AL_CNT_TEXTREL) == NULL))) 5767c478bd9Sstevel@tonic-gate return (0); 57756deab07SRod Evans 5787c478bd9Sstevel@tonic-gate elf_plt_init(PLTGOT(lmp), (caddr_t)lmp); 5797c478bd9Sstevel@tonic-gate } 5807c478bd9Sstevel@tonic-gate 5817c478bd9Sstevel@tonic-gate /* 5827c478bd9Sstevel@tonic-gate * Initialize the plt start and end addresses. 5837c478bd9Sstevel@tonic-gate */ 5847c478bd9Sstevel@tonic-gate if ((pltbgn = (ulong_t)JMPREL(lmp)) != 0) 5857c478bd9Sstevel@tonic-gate pltend = pltbgn + (ulong_t)(PLTRELSZ(lmp)); 5867c478bd9Sstevel@tonic-gate 5877c478bd9Sstevel@tonic-gate /* 5887c478bd9Sstevel@tonic-gate * If we've been called upon to promote an RTLD_LAZY object to an 5897c478bd9Sstevel@tonic-gate * RTLD_NOW then we're only interested in scaning the .plt table. 5907c478bd9Sstevel@tonic-gate */ 5917c478bd9Sstevel@tonic-gate if (plt) { 5927c478bd9Sstevel@tonic-gate relbgn = pltbgn; 5937c478bd9Sstevel@tonic-gate relend = pltend; 5947c478bd9Sstevel@tonic-gate } else { 5957c478bd9Sstevel@tonic-gate /* 5967c478bd9Sstevel@tonic-gate * The relocation sections appear to the run-time linker as a 5977c478bd9Sstevel@tonic-gate * single table. Determine the address of the beginning and end 5987c478bd9Sstevel@tonic-gate * of this table. There are two different interpretations of 5997c478bd9Sstevel@tonic-gate * the ABI at this point: 6007c478bd9Sstevel@tonic-gate * 60108278a5eSRod Evans * - The REL table and its associated RELSZ indicate the 6027c478bd9Sstevel@tonic-gate * concatenation of *all* relocation sections (this is the 6037c478bd9Sstevel@tonic-gate * model our link-editor constructs). 6047c478bd9Sstevel@tonic-gate * 60508278a5eSRod Evans * - The REL table and its associated RELSZ indicate the 6067c478bd9Sstevel@tonic-gate * concatenation of all *but* the .plt relocations. These 6077c478bd9Sstevel@tonic-gate * relocations are specified individually by the JMPREL and 6087c478bd9Sstevel@tonic-gate * PLTRELSZ entries. 6097c478bd9Sstevel@tonic-gate * 6107c478bd9Sstevel@tonic-gate * Determine from our knowledege of the relocation range and 6117c478bd9Sstevel@tonic-gate * .plt range, the range of the total relocation table. Note 6127c478bd9Sstevel@tonic-gate * that one other ABI assumption seems to be that the .plt 6137c478bd9Sstevel@tonic-gate * relocations always follow any other relocations, the 6147c478bd9Sstevel@tonic-gate * following range checking drops that assumption. 6157c478bd9Sstevel@tonic-gate */ 6167c478bd9Sstevel@tonic-gate relbgn = (ulong_t)(REL(lmp)); 6177c478bd9Sstevel@tonic-gate relend = relbgn + (ulong_t)(RELSZ(lmp)); 6187c478bd9Sstevel@tonic-gate if (pltbgn) { 6197c478bd9Sstevel@tonic-gate if (!relbgn || (relbgn > pltbgn)) 6207c478bd9Sstevel@tonic-gate relbgn = pltbgn; 6217c478bd9Sstevel@tonic-gate if (!relbgn || (relend < pltend)) 6227c478bd9Sstevel@tonic-gate relend = pltend; 6237c478bd9Sstevel@tonic-gate } 6247c478bd9Sstevel@tonic-gate } 6257c478bd9Sstevel@tonic-gate if (!relbgn || (relbgn == relend)) { 6265aefb655Srie DBG_CALL(Dbg_reloc_run(lmp, 0, plt, DBG_REL_NONE)); 6277c478bd9Sstevel@tonic-gate return (1); 6287c478bd9Sstevel@tonic-gate } 6297c478bd9Sstevel@tonic-gate 6307c478bd9Sstevel@tonic-gate relsiz = (ulong_t)(RELENT(lmp)); 6317c478bd9Sstevel@tonic-gate basebgn = ADDR(lmp); 6327c478bd9Sstevel@tonic-gate 6335aefb655Srie DBG_CALL(Dbg_reloc_run(lmp, M_REL_SHT_TYPE, plt, DBG_REL_START)); 6347c478bd9Sstevel@tonic-gate 6357c478bd9Sstevel@tonic-gate /* 6367c478bd9Sstevel@tonic-gate * If we're processing in lazy mode there is no need to scan the 6377c478bd9Sstevel@tonic-gate * .rela.plt table. 6387c478bd9Sstevel@tonic-gate */ 6397c478bd9Sstevel@tonic-gate if (pltbgn && ((MODE(lmp) & RTLD_NOW) == 0)) 6407c478bd9Sstevel@tonic-gate noplt = 1; 6417c478bd9Sstevel@tonic-gate 642f441771bSRod Evans sip = SYMINFO(lmp); 6437c478bd9Sstevel@tonic-gate /* 6447c478bd9Sstevel@tonic-gate * Loop through relocations. 6457c478bd9Sstevel@tonic-gate */ 6467c478bd9Sstevel@tonic-gate while (relbgn < relend) { 64756deab07SRod Evans mmapobj_result_t *mpp; 6487c478bd9Sstevel@tonic-gate uint_t sb_flags = 0; 64956deab07SRod Evans Addr vaddr; 6507c478bd9Sstevel@tonic-gate 651ba2be530Sab196087 rtype = ELF_R_TYPE(((Rela *)relbgn)->r_info, M_MACH); 6527c478bd9Sstevel@tonic-gate 6537c478bd9Sstevel@tonic-gate /* 6547c478bd9Sstevel@tonic-gate * If this is a RELATIVE relocation in a shared object (the 65556deab07SRod Evans * common case), and if we are not debugging, then jump into one 65656deab07SRod Evans * of the tighter relocation loops. 6577c478bd9Sstevel@tonic-gate */ 6587c478bd9Sstevel@tonic-gate if ((rtype == R_SPARC_RELATIVE) && 6595aefb655Srie ((FLAGS(lmp) & FLG_RT_FIXED) == 0) && (DBG_ENABLED == 0)) { 6607c478bd9Sstevel@tonic-gate if (relacount) { 66156deab07SRod Evans relbgn = elf_reloc_relative_count(relbgn, 662f441771bSRod Evans relacount, relsiz, basebgn, lmp, 663f441771bSRod Evans textrel, 0); 6647c478bd9Sstevel@tonic-gate relacount = 0; 6657c478bd9Sstevel@tonic-gate } else { 6667c478bd9Sstevel@tonic-gate relbgn = elf_reloc_relative(relbgn, relend, 667f441771bSRod Evans relsiz, basebgn, lmp, textrel, 0); 6687c478bd9Sstevel@tonic-gate } 6697c478bd9Sstevel@tonic-gate if (relbgn >= relend) 6707c478bd9Sstevel@tonic-gate break; 671ba2be530Sab196087 rtype = ELF_R_TYPE(((Rela *)relbgn)->r_info, M_MACH); 6727c478bd9Sstevel@tonic-gate } 6737c478bd9Sstevel@tonic-gate 6747c478bd9Sstevel@tonic-gate roffset = ((Rela *)relbgn)->r_offset; 6757c478bd9Sstevel@tonic-gate 6767c478bd9Sstevel@tonic-gate reladd = (long)(((Rela *)relbgn)->r_addend); 6777c478bd9Sstevel@tonic-gate rsymndx = ELF_R_SYM(((Rela *)relbgn)->r_info); 6787c478bd9Sstevel@tonic-gate rel = (Rela *)relbgn; 6797c478bd9Sstevel@tonic-gate relbgn += relsiz; 6807c478bd9Sstevel@tonic-gate 6817c478bd9Sstevel@tonic-gate /* 6827c478bd9Sstevel@tonic-gate * Optimizations. 6837c478bd9Sstevel@tonic-gate */ 6847c478bd9Sstevel@tonic-gate if (rtype == R_SPARC_NONE) 6857c478bd9Sstevel@tonic-gate continue; 6867c478bd9Sstevel@tonic-gate if (noplt && ((ulong_t)rel >= pltbgn) && 6877c478bd9Sstevel@tonic-gate ((ulong_t)rel < pltend)) { 6887c478bd9Sstevel@tonic-gate relbgn = pltend; 6897c478bd9Sstevel@tonic-gate continue; 6907c478bd9Sstevel@tonic-gate } 6917c478bd9Sstevel@tonic-gate 6927c478bd9Sstevel@tonic-gate if (rtype != R_SPARC_REGISTER) { 6937c478bd9Sstevel@tonic-gate /* 6947c478bd9Sstevel@tonic-gate * If this is a shared object, add the base address 6957c478bd9Sstevel@tonic-gate * to offset. 6967c478bd9Sstevel@tonic-gate */ 6977c478bd9Sstevel@tonic-gate if (!(FLAGS(lmp) & FLG_RT_FIXED)) 6987c478bd9Sstevel@tonic-gate roffset += basebgn; 6997c478bd9Sstevel@tonic-gate 7007c478bd9Sstevel@tonic-gate /* 7017c478bd9Sstevel@tonic-gate * If this relocation is not against part of the image 7027c478bd9Sstevel@tonic-gate * mapped into memory we skip it. 7037c478bd9Sstevel@tonic-gate */ 70456deab07SRod Evans if ((mpp = find_segment((caddr_t)roffset, 70556deab07SRod Evans lmp)) == NULL) { 7067c478bd9Sstevel@tonic-gate elf_reloc_bad(lmp, (void *)rel, rtype, roffset, 7077c478bd9Sstevel@tonic-gate rsymndx); 7087c478bd9Sstevel@tonic-gate continue; 7097c478bd9Sstevel@tonic-gate } 7107c478bd9Sstevel@tonic-gate } 7117c478bd9Sstevel@tonic-gate 7127c478bd9Sstevel@tonic-gate /* 71356deab07SRod Evans * If we're promoting .plts, try and determine if this one has 71402ca3e02Srie * already been written. An uninitialized .plts' second 71502ca3e02Srie * instruction is a branch. Note, elf_plt_write() optimizes 71602ca3e02Srie * .plt relocations, and it's possible that a relocated entry 71702ca3e02Srie * is a branch. If this is the case, we can't tell the 71802ca3e02Srie * difference between an uninitialized .plt and a relocated, 71902ca3e02Srie * .plt that uses a branch. In this case, we'll simply redo 72002ca3e02Srie * the relocation calculation, which is a bit sad. 7217c478bd9Sstevel@tonic-gate */ 7227c478bd9Sstevel@tonic-gate if (plt) { 7237c478bd9Sstevel@tonic-gate ulong_t *_roffset = (ulong_t *)roffset; 7247c478bd9Sstevel@tonic-gate 7257c478bd9Sstevel@tonic-gate _roffset++; 7267c478bd9Sstevel@tonic-gate if ((*_roffset & (~(S_MASK(22)))) != M_BA_A) 7277c478bd9Sstevel@tonic-gate continue; 7287c478bd9Sstevel@tonic-gate } 7297c478bd9Sstevel@tonic-gate 7307c478bd9Sstevel@tonic-gate binfo = 0; 7317c478bd9Sstevel@tonic-gate pltndx = (ulong_t)-1; 7327c478bd9Sstevel@tonic-gate pbtype = PLT_T_NONE; 73356deab07SRod Evans 7347c478bd9Sstevel@tonic-gate /* 7357c478bd9Sstevel@tonic-gate * If a symbol index is specified then get the symbol table 7367c478bd9Sstevel@tonic-gate * entry, locate the symbol definition, and determine its 7377c478bd9Sstevel@tonic-gate * address. 7387c478bd9Sstevel@tonic-gate */ 7397c478bd9Sstevel@tonic-gate if (rsymndx) { 7407c478bd9Sstevel@tonic-gate /* 741f441771bSRod Evans * If a Syminfo section is provided, determine if this 742f441771bSRod Evans * symbol is deferred, and if so, skip this relocation. 743f441771bSRod Evans */ 744f441771bSRod Evans if (sip && is_sym_deferred((ulong_t)rel, basebgn, lmp, 745f441771bSRod Evans textrel, sip, rsymndx)) 746f441771bSRod Evans continue; 747f441771bSRod Evans 748f441771bSRod Evans /* 7497c478bd9Sstevel@tonic-gate * Get the local symbol table entry. 7507c478bd9Sstevel@tonic-gate */ 7517c478bd9Sstevel@tonic-gate symref = (Sym *)((ulong_t)SYMTAB(lmp) + 7527c478bd9Sstevel@tonic-gate (rsymndx * SYMENT(lmp))); 7537c478bd9Sstevel@tonic-gate 7547c478bd9Sstevel@tonic-gate /* 7557c478bd9Sstevel@tonic-gate * If this is a local symbol, just use the base address. 7567c478bd9Sstevel@tonic-gate * (we should have no local relocations in the 7577c478bd9Sstevel@tonic-gate * executable). 7587c478bd9Sstevel@tonic-gate */ 7597c478bd9Sstevel@tonic-gate if (ELF_ST_BIND(symref->st_info) == STB_LOCAL) { 7607c478bd9Sstevel@tonic-gate value = basebgn; 76108278a5eSRod Evans name = NULL; 7627c478bd9Sstevel@tonic-gate 7637c478bd9Sstevel@tonic-gate /* 764d326b23bSrie * Special case TLS relocations. 7657c478bd9Sstevel@tonic-gate */ 766d326b23bSrie if (rtype == R_SPARC_TLS_DTPMOD32) { 767d326b23bSrie /* 768d326b23bSrie * Use the TLS modid. 769d326b23bSrie */ 7707c478bd9Sstevel@tonic-gate value = TLSMODID(lmp); 771d326b23bSrie 772d326b23bSrie } else if (rtype == R_SPARC_TLS_TPOFF32) { 773d326b23bSrie if ((value = elf_static_tls(lmp, symref, 774d326b23bSrie rel, rtype, 0, roffset, 0)) == 0) { 775d326b23bSrie ret = 0; 776d326b23bSrie break; 777d326b23bSrie } 778d326b23bSrie } 7797c478bd9Sstevel@tonic-gate } else { 7807c478bd9Sstevel@tonic-gate /* 7817c478bd9Sstevel@tonic-gate * If the symbol index is equal to the previous 7827c478bd9Sstevel@tonic-gate * symbol index relocation we processed then 7837c478bd9Sstevel@tonic-gate * reuse the previous values. (Note that there 7847c478bd9Sstevel@tonic-gate * have been cases where a relocation exists 7857c478bd9Sstevel@tonic-gate * against a copy relocation symbol, our ld(1) 7867c478bd9Sstevel@tonic-gate * should optimize this away, but make sure we 7877c478bd9Sstevel@tonic-gate * don't use the same symbol information should 7887c478bd9Sstevel@tonic-gate * this case exist). 7897c478bd9Sstevel@tonic-gate */ 7907c478bd9Sstevel@tonic-gate if ((rsymndx == psymndx) && 7917c478bd9Sstevel@tonic-gate (rtype != R_SPARC_COPY)) { 7927c478bd9Sstevel@tonic-gate /* LINTED */ 7937c478bd9Sstevel@tonic-gate if (psymdef == 0) { 7945aefb655Srie DBG_CALL(Dbg_bind_weak(lmp, 7955aefb655Srie (Addr)roffset, (Addr) 7967c478bd9Sstevel@tonic-gate (roffset - basebgn), name)); 7977c478bd9Sstevel@tonic-gate continue; 7987c478bd9Sstevel@tonic-gate } 7997c478bd9Sstevel@tonic-gate /* LINTED */ 8007c478bd9Sstevel@tonic-gate value = pvalue; 8017c478bd9Sstevel@tonic-gate /* LINTED */ 8027c478bd9Sstevel@tonic-gate name = pname; 8037c478bd9Sstevel@tonic-gate symdef = psymdef; 8047c478bd9Sstevel@tonic-gate /* LINTED */ 8057c478bd9Sstevel@tonic-gate symref = psymref; 8067c478bd9Sstevel@tonic-gate /* LINTED */ 8077c478bd9Sstevel@tonic-gate _lmp = plmp; 8087c478bd9Sstevel@tonic-gate /* LINTED */ 8097c478bd9Sstevel@tonic-gate binfo = pbinfo; 8107c478bd9Sstevel@tonic-gate 8117c478bd9Sstevel@tonic-gate if ((LIST(_lmp)->lm_tflags | 81256deab07SRod Evans AFLAGS(_lmp)) & 8137c478bd9Sstevel@tonic-gate LML_TFLG_AUD_SYMBIND) { 8147c478bd9Sstevel@tonic-gate value = audit_symbind(lmp, _lmp, 8157c478bd9Sstevel@tonic-gate /* LINTED */ 8167c478bd9Sstevel@tonic-gate symdef, dsymndx, value, 8177c478bd9Sstevel@tonic-gate &sb_flags); 8187c478bd9Sstevel@tonic-gate } 8197c478bd9Sstevel@tonic-gate } else { 8207c478bd9Sstevel@tonic-gate Slookup sl; 82108278a5eSRod Evans Sresult sr; 8227c478bd9Sstevel@tonic-gate 8237c478bd9Sstevel@tonic-gate /* 8247c478bd9Sstevel@tonic-gate * Lookup the symbol definition. 82508278a5eSRod Evans * Initialize the symbol lookup, and 82608278a5eSRod Evans * symbol result, data structures. 8277c478bd9Sstevel@tonic-gate */ 8287c478bd9Sstevel@tonic-gate name = (char *)(STRTAB(lmp) + 8297c478bd9Sstevel@tonic-gate symref->st_name); 8307c478bd9Sstevel@tonic-gate 83175e7992aSrie SLOOKUP_INIT(sl, name, lmp, 0, 83275e7992aSrie ld_entry_cnt, 0, rsymndx, symref, 83375e7992aSrie rtype, LKUP_STDRELOC); 83408278a5eSRod Evans SRESULT_INIT(sr, name); 83508278a5eSRod Evans symdef = NULL; 8367c478bd9Sstevel@tonic-gate 83708278a5eSRod Evans if (lookup_sym(&sl, &sr, &binfo, 83808278a5eSRod Evans in_nfavl)) { 83908278a5eSRod Evans name = (char *)sr.sr_name; 84008278a5eSRod Evans _lmp = sr.sr_dmap; 84108278a5eSRod Evans symdef = sr.sr_sym; 84208278a5eSRod Evans } 8437c478bd9Sstevel@tonic-gate 8447c478bd9Sstevel@tonic-gate /* 8457c478bd9Sstevel@tonic-gate * If the symbol is not found and the 8467c478bd9Sstevel@tonic-gate * reference was not to a weak symbol, 8477c478bd9Sstevel@tonic-gate * report an error. Weak references 8487c478bd9Sstevel@tonic-gate * may be unresolved. 8497c478bd9Sstevel@tonic-gate */ 8507247f888Srie /* BEGIN CSTYLED */ 8517c478bd9Sstevel@tonic-gate if (symdef == 0) { 85260758829Srie if (sl.sl_bind != STB_WEAK) { 853dae2dfb7Srie if (elf_reloc_error(lmp, name, 854dae2dfb7Srie rel, binfo)) 8557c478bd9Sstevel@tonic-gate continue; 856dae2dfb7Srie 8577c478bd9Sstevel@tonic-gate ret = 0; 8587c478bd9Sstevel@tonic-gate break; 859dae2dfb7Srie 8607c478bd9Sstevel@tonic-gate } else { 8617c478bd9Sstevel@tonic-gate psymndx = rsymndx; 8627c478bd9Sstevel@tonic-gate psymdef = 0; 8637c478bd9Sstevel@tonic-gate 8645aefb655Srie DBG_CALL(Dbg_bind_weak(lmp, 8655aefb655Srie (Addr)roffset, (Addr) 8667c478bd9Sstevel@tonic-gate (roffset - basebgn), name)); 8677c478bd9Sstevel@tonic-gate continue; 8687c478bd9Sstevel@tonic-gate } 8697c478bd9Sstevel@tonic-gate } 8707247f888Srie /* END CSTYLED */ 8717c478bd9Sstevel@tonic-gate 8727c478bd9Sstevel@tonic-gate /* 8737c478bd9Sstevel@tonic-gate * If symbol was found in an object 8747c478bd9Sstevel@tonic-gate * other than the referencing object 8757c478bd9Sstevel@tonic-gate * then record the binding. 8767c478bd9Sstevel@tonic-gate */ 8777c478bd9Sstevel@tonic-gate if ((lmp != _lmp) && ((FLAGS1(_lmp) & 8787c478bd9Sstevel@tonic-gate FL1_RT_NOINIFIN) == 0)) { 879cce0e03bSab196087 if (aplist_test(&bound, _lmp, 8807c478bd9Sstevel@tonic-gate AL_CNT_RELBIND) == 0) { 8817c478bd9Sstevel@tonic-gate ret = 0; 8827c478bd9Sstevel@tonic-gate break; 8837c478bd9Sstevel@tonic-gate } 8847c478bd9Sstevel@tonic-gate } 8857c478bd9Sstevel@tonic-gate 8867c478bd9Sstevel@tonic-gate /* 8877c478bd9Sstevel@tonic-gate * Calculate the location of definition; 8887c478bd9Sstevel@tonic-gate * symbol value plus base address of 8897c478bd9Sstevel@tonic-gate * containing shared object. 8907c478bd9Sstevel@tonic-gate */ 8912926dd2eSrie if (IS_SIZE(rtype)) 8922926dd2eSrie value = symdef->st_size; 8932926dd2eSrie else 8947c478bd9Sstevel@tonic-gate value = symdef->st_value; 8952926dd2eSrie 8967c478bd9Sstevel@tonic-gate if (!(FLAGS(_lmp) & FLG_RT_FIXED) && 8972926dd2eSrie !(IS_SIZE(rtype)) && 8987c478bd9Sstevel@tonic-gate (symdef->st_shndx != SHN_ABS) && 8997c478bd9Sstevel@tonic-gate (ELF_ST_TYPE(symdef->st_info) != 9007c478bd9Sstevel@tonic-gate STT_TLS)) 9017c478bd9Sstevel@tonic-gate value += ADDR(_lmp); 9027c478bd9Sstevel@tonic-gate 9037c478bd9Sstevel@tonic-gate /* 9047c478bd9Sstevel@tonic-gate * Retain this symbol index and the 9057c478bd9Sstevel@tonic-gate * value in case it can be used for the 9067c478bd9Sstevel@tonic-gate * subsequent relocations. 9077c478bd9Sstevel@tonic-gate */ 9087c478bd9Sstevel@tonic-gate if (rtype != R_SPARC_COPY) { 9097c478bd9Sstevel@tonic-gate psymndx = rsymndx; 9107c478bd9Sstevel@tonic-gate pvalue = value; 9117c478bd9Sstevel@tonic-gate pname = name; 9127c478bd9Sstevel@tonic-gate psymdef = symdef; 9137c478bd9Sstevel@tonic-gate psymref = symref; 9147c478bd9Sstevel@tonic-gate plmp = _lmp; 9157c478bd9Sstevel@tonic-gate pbinfo = binfo; 9167c478bd9Sstevel@tonic-gate } 9177c478bd9Sstevel@tonic-gate if ((LIST(_lmp)->lm_tflags | 91856deab07SRod Evans AFLAGS(_lmp)) & 9197c478bd9Sstevel@tonic-gate LML_TFLG_AUD_SYMBIND) { 9207c478bd9Sstevel@tonic-gate dsymndx = (((uintptr_t)symdef - 9217c478bd9Sstevel@tonic-gate (uintptr_t)SYMTAB(_lmp)) / 9227c478bd9Sstevel@tonic-gate SYMENT(_lmp)); 9237c478bd9Sstevel@tonic-gate value = audit_symbind(lmp, _lmp, 9247c478bd9Sstevel@tonic-gate symdef, dsymndx, value, 9257c478bd9Sstevel@tonic-gate &sb_flags); 9267c478bd9Sstevel@tonic-gate } 9277c478bd9Sstevel@tonic-gate } 9287c478bd9Sstevel@tonic-gate 9297c478bd9Sstevel@tonic-gate /* 9307c478bd9Sstevel@tonic-gate * If relocation is PC-relative, subtract 9317c478bd9Sstevel@tonic-gate * offset address. 9327c478bd9Sstevel@tonic-gate */ 9337c478bd9Sstevel@tonic-gate if (IS_PC_RELATIVE(rtype)) 9347c478bd9Sstevel@tonic-gate value -= roffset; 9357c478bd9Sstevel@tonic-gate 9367c478bd9Sstevel@tonic-gate /* 937d326b23bSrie * Special case TLS relocations. 9387c478bd9Sstevel@tonic-gate */ 939d326b23bSrie if (rtype == R_SPARC_TLS_DTPMOD32) { 940d326b23bSrie /* 941d326b23bSrie * Relocation value is the TLS modid. 942d326b23bSrie */ 9437c478bd9Sstevel@tonic-gate value = TLSMODID(_lmp); 944d326b23bSrie 945d326b23bSrie } else if (rtype == R_SPARC_TLS_TPOFF32) { 946d326b23bSrie if ((value = elf_static_tls(_lmp, 947d326b23bSrie symdef, rel, rtype, name, roffset, 948d326b23bSrie value)) == 0) { 949d326b23bSrie ret = 0; 950d326b23bSrie break; 951d326b23bSrie } 952d326b23bSrie } 9537c478bd9Sstevel@tonic-gate } 9547c478bd9Sstevel@tonic-gate } else { 9557c478bd9Sstevel@tonic-gate /* 956d326b23bSrie * Special cases. 9577c478bd9Sstevel@tonic-gate */ 958d326b23bSrie if (rtype == R_SPARC_REGISTER) { 959d326b23bSrie /* 960d326b23bSrie * A register symbol associated with symbol 961d326b23bSrie * index 0 is initialized (i.e. relocated) to 962d326b23bSrie * a constant in the r_addend field rather than 963d326b23bSrie * to a symbol value. 964d326b23bSrie */ 9657c478bd9Sstevel@tonic-gate value = 0; 966d326b23bSrie 967d326b23bSrie } else if (rtype == R_SPARC_TLS_DTPMOD32) { 968d326b23bSrie /* 969d326b23bSrie * TLS relocation value is the TLS modid. 970d326b23bSrie */ 9717c478bd9Sstevel@tonic-gate value = TLSMODID(lmp); 972d326b23bSrie } else 9737c478bd9Sstevel@tonic-gate value = basebgn; 97408278a5eSRod Evans 97508278a5eSRod Evans name = NULL; 9767c478bd9Sstevel@tonic-gate } 9777c478bd9Sstevel@tonic-gate 978d326b23bSrie DBG_CALL(Dbg_reloc_in(LIST(lmp), ELF_DBG_RTLD, M_MACH, 979e23c41c9SAli Bahrami M_REL_SHT_TYPE, rel, NULL, 0, name)); 980d326b23bSrie 9817c478bd9Sstevel@tonic-gate /* 98256deab07SRod Evans * Make sure the segment is writable. 9837c478bd9Sstevel@tonic-gate */ 98456deab07SRod Evans if ((rtype != R_SPARC_REGISTER) && 98556deab07SRod Evans ((mpp->mr_prot & PROT_WRITE) == 0) && 98656deab07SRod Evans ((set_prot(lmp, mpp, 1) == 0) || 98756deab07SRod Evans (aplist_append(textrel, mpp, AL_CNT_TEXTREL) == NULL))) { 9887c478bd9Sstevel@tonic-gate ret = 0; 9897c478bd9Sstevel@tonic-gate break; 9907c478bd9Sstevel@tonic-gate } 9917c478bd9Sstevel@tonic-gate 9927c478bd9Sstevel@tonic-gate /* 9937c478bd9Sstevel@tonic-gate * Call relocation routine to perform required relocation. 9947c478bd9Sstevel@tonic-gate */ 9957c478bd9Sstevel@tonic-gate switch (rtype) { 9967c478bd9Sstevel@tonic-gate case R_SPARC_REGISTER: 9977c478bd9Sstevel@tonic-gate /* 9987c478bd9Sstevel@tonic-gate * The v9 ABI 4.2.4 says that system objects may, 9997c478bd9Sstevel@tonic-gate * but are not required to, use register symbols 10007c478bd9Sstevel@tonic-gate * to inidcate how they use global registers. Thus 10017c478bd9Sstevel@tonic-gate * at least %g6, %g7 must be allowed in addition 10027c478bd9Sstevel@tonic-gate * to %g2 and %g3. 10037c478bd9Sstevel@tonic-gate */ 10047c478bd9Sstevel@tonic-gate value += reladd; 10057c478bd9Sstevel@tonic-gate if (roffset == STO_SPARC_REGISTER_G1) { 10067c478bd9Sstevel@tonic-gate set_sparc_g1(value); 10077c478bd9Sstevel@tonic-gate } else if (roffset == STO_SPARC_REGISTER_G2) { 10087c478bd9Sstevel@tonic-gate set_sparc_g2(value); 10097c478bd9Sstevel@tonic-gate } else if (roffset == STO_SPARC_REGISTER_G3) { 10107c478bd9Sstevel@tonic-gate set_sparc_g3(value); 10117c478bd9Sstevel@tonic-gate } else if (roffset == STO_SPARC_REGISTER_G4) { 10127c478bd9Sstevel@tonic-gate set_sparc_g4(value); 10137c478bd9Sstevel@tonic-gate } else if (roffset == STO_SPARC_REGISTER_G5) { 10147c478bd9Sstevel@tonic-gate set_sparc_g5(value); 10157c478bd9Sstevel@tonic-gate } else if (roffset == STO_SPARC_REGISTER_G6) { 10167c478bd9Sstevel@tonic-gate set_sparc_g6(value); 10177c478bd9Sstevel@tonic-gate } else if (roffset == STO_SPARC_REGISTER_G7) { 10187c478bd9Sstevel@tonic-gate set_sparc_g7(value); 10197c478bd9Sstevel@tonic-gate } else { 10205aefb655Srie eprintf(LIST(lmp), ERR_FATAL, 10215aefb655Srie MSG_INTL(MSG_REL_BADREG), NAME(lmp), 10225aefb655Srie EC_ADDR(roffset)); 10237c478bd9Sstevel@tonic-gate ret = 0; 10247c478bd9Sstevel@tonic-gate break; 10257c478bd9Sstevel@tonic-gate } 10267c478bd9Sstevel@tonic-gate 10275aefb655Srie DBG_CALL(Dbg_reloc_apply_reg(LIST(lmp), ELF_DBG_RTLD, 10285aefb655Srie M_MACH, (Xword)roffset, (Xword)value)); 10297c478bd9Sstevel@tonic-gate break; 10307c478bd9Sstevel@tonic-gate case R_SPARC_COPY: 10317c478bd9Sstevel@tonic-gate if (elf_copy_reloc(name, symref, lmp, (void *)roffset, 10327c478bd9Sstevel@tonic-gate symdef, _lmp, (const void *)value) == 0) 10337c478bd9Sstevel@tonic-gate ret = 0; 10347c478bd9Sstevel@tonic-gate break; 10357c478bd9Sstevel@tonic-gate case R_SPARC_JMP_SLOT: 10367c478bd9Sstevel@tonic-gate pltndx = ((ulong_t)rel - 10377c478bd9Sstevel@tonic-gate (uintptr_t)JMPREL(lmp)) / relsiz; 10387c478bd9Sstevel@tonic-gate 10397c478bd9Sstevel@tonic-gate if (FLAGS(lmp) & FLG_RT_FIXED) 10407c478bd9Sstevel@tonic-gate vaddr = 0; 10417c478bd9Sstevel@tonic-gate else 10427c478bd9Sstevel@tonic-gate vaddr = ADDR(lmp); 10437c478bd9Sstevel@tonic-gate 104456deab07SRod Evans if (((LIST(lmp)->lm_tflags | AFLAGS(lmp)) & 10457c478bd9Sstevel@tonic-gate (LML_TFLG_AUD_PLTENTER | LML_TFLG_AUD_PLTEXIT)) && 10467c478bd9Sstevel@tonic-gate AUDINFO(lmp)->ai_dynplts) { 10477c478bd9Sstevel@tonic-gate int fail = 0; 10487c478bd9Sstevel@tonic-gate ulong_t symndx = (((uintptr_t)symdef - 10497247f888Srie (uintptr_t)SYMTAB(_lmp)) / SYMENT(_lmp)); 10507c478bd9Sstevel@tonic-gate 10517c478bd9Sstevel@tonic-gate (void) elf_plt_trace_write((caddr_t)vaddr, 10527c478bd9Sstevel@tonic-gate (Rela *)rel, lmp, _lmp, symdef, symndx, 10537c478bd9Sstevel@tonic-gate pltndx, (caddr_t)value, sb_flags, &fail); 10547c478bd9Sstevel@tonic-gate if (fail) 10557c478bd9Sstevel@tonic-gate ret = 0; 10567c478bd9Sstevel@tonic-gate } else { 10577c478bd9Sstevel@tonic-gate /* 10587c478bd9Sstevel@tonic-gate * Write standard PLT entry to jump directly 10597c478bd9Sstevel@tonic-gate * to newly bound function. 10607c478bd9Sstevel@tonic-gate */ 10615aefb655Srie DBG_CALL(Dbg_reloc_apply_val(LIST(lmp), 10625aefb655Srie ELF_DBG_RTLD, (Xword)roffset, 10637c478bd9Sstevel@tonic-gate (Xword)value)); 10647c478bd9Sstevel@tonic-gate pbtype = elf_plt_write((uintptr_t)vaddr, 10657c478bd9Sstevel@tonic-gate (uintptr_t)vaddr, (void *)rel, value, 10667c478bd9Sstevel@tonic-gate pltndx); 10677c478bd9Sstevel@tonic-gate } 10687c478bd9Sstevel@tonic-gate break; 10697c478bd9Sstevel@tonic-gate default: 10707c478bd9Sstevel@tonic-gate value += reladd; 10717c478bd9Sstevel@tonic-gate 10727c478bd9Sstevel@tonic-gate /* 10737c478bd9Sstevel@tonic-gate * Write the relocation out. If this relocation is a 10747c478bd9Sstevel@tonic-gate * common basic write, skip the doreloc() engine. 10757c478bd9Sstevel@tonic-gate */ 10767c478bd9Sstevel@tonic-gate if ((rtype == R_SPARC_GLOB_DAT) || 10777c478bd9Sstevel@tonic-gate (rtype == R_SPARC_32)) { 10787c478bd9Sstevel@tonic-gate if (roffset & 0x3) { 1079de777a60Sab196087 Conv_inv_buf_t inv_buf; 1080de777a60Sab196087 10815aefb655Srie eprintf(LIST(lmp), ERR_FATAL, 10827c478bd9Sstevel@tonic-gate MSG_INTL(MSG_REL_NONALIGN), 1083de777a60Sab196087 conv_reloc_SPARC_type(rtype, 1084de777a60Sab196087 0, &inv_buf), 10857c478bd9Sstevel@tonic-gate NAME(lmp), demangle(name), 10867c478bd9Sstevel@tonic-gate EC_OFF(roffset)); 10877c478bd9Sstevel@tonic-gate ret = 0; 10887c478bd9Sstevel@tonic-gate } else 10897c478bd9Sstevel@tonic-gate *(uint_t *)roffset += value; 10907c478bd9Sstevel@tonic-gate } else { 1091f3324781Sab196087 if (do_reloc_rtld(rtype, (uchar_t *)roffset, 10925aefb655Srie (Xword *)&value, name, 10935aefb655Srie NAME(lmp), LIST(lmp)) == 0) 10947c478bd9Sstevel@tonic-gate ret = 0; 10957c478bd9Sstevel@tonic-gate } 10967c478bd9Sstevel@tonic-gate 10977c478bd9Sstevel@tonic-gate /* 10987c478bd9Sstevel@tonic-gate * The value now contains the 'bit-shifted' value that 1099f3324781Sab196087 * was or'ed into memory (this was set by 1100f3324781Sab196087 * do_reloc_rtld()). 11017c478bd9Sstevel@tonic-gate */ 11025aefb655Srie DBG_CALL(Dbg_reloc_apply_val(LIST(lmp), ELF_DBG_RTLD, 11035aefb655Srie (Xword)roffset, (Xword)value)); 11047c478bd9Sstevel@tonic-gate 11057c478bd9Sstevel@tonic-gate /* 11067c478bd9Sstevel@tonic-gate * If this relocation is against a text segment, make 11077c478bd9Sstevel@tonic-gate * sure that the instruction cache is flushed. 11087c478bd9Sstevel@tonic-gate */ 11097c478bd9Sstevel@tonic-gate if (textrel) 11107c478bd9Sstevel@tonic-gate iflush_range((caddr_t)roffset, 0x4); 11117c478bd9Sstevel@tonic-gate } 11127c478bd9Sstevel@tonic-gate 11137c478bd9Sstevel@tonic-gate if ((ret == 0) && 11147c478bd9Sstevel@tonic-gate ((LIST(lmp)->lm_flags & LML_FLG_TRC_WARN) == 0)) 11157c478bd9Sstevel@tonic-gate break; 11167c478bd9Sstevel@tonic-gate 11177c478bd9Sstevel@tonic-gate if (binfo) { 11185aefb655Srie DBG_CALL(Dbg_bind_global(lmp, (Addr)roffset, 11195aefb655Srie (Off)(roffset - basebgn), pltndx, pbtype, 11205aefb655Srie _lmp, (Addr)value, symdef->st_value, name, binfo)); 11217c478bd9Sstevel@tonic-gate } 11227c478bd9Sstevel@tonic-gate } 11237c478bd9Sstevel@tonic-gate 112456deab07SRod Evans return (relocate_finish(lmp, bound, ret)); 11257c478bd9Sstevel@tonic-gate } 11267c478bd9Sstevel@tonic-gate 11277c478bd9Sstevel@tonic-gate /* 11287c478bd9Sstevel@tonic-gate * Provide a machine specific interface to the conversion routine. By calling 11297c478bd9Sstevel@tonic-gate * the machine specific version, rather than the generic version, we insure that 11307c478bd9Sstevel@tonic-gate * the data tables/strings for all known machine versions aren't dragged into 11317c478bd9Sstevel@tonic-gate * ld.so.1. 11327c478bd9Sstevel@tonic-gate */ 11337c478bd9Sstevel@tonic-gate const char * 11345aefb655Srie _conv_reloc_type(uint_t rel) 11357c478bd9Sstevel@tonic-gate { 1136de777a60Sab196087 static Conv_inv_buf_t inv_buf; 1137de777a60Sab196087 1138de777a60Sab196087 return (conv_reloc_SPARC_type(rel, 0, &inv_buf)); 11397c478bd9Sstevel@tonic-gate } 1140