10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 51618Srie * Common Development and Distribution License (the "License"). 61618Srie * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 211618Srie 220Sstevel@tonic-gate /* 230Sstevel@tonic-gate * Copyright (c) 1988 AT&T 240Sstevel@tonic-gate * All Rights Reserved 250Sstevel@tonic-gate * 265892Sab196087 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 271618Srie * Use is subject to license terms. 280Sstevel@tonic-gate */ 290Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 300Sstevel@tonic-gate 310Sstevel@tonic-gate /* 320Sstevel@tonic-gate * SPARC machine dependent and ELF file class dependent functions. 330Sstevel@tonic-gate * Contains routines for performing function binding and symbol relocations. 340Sstevel@tonic-gate */ 350Sstevel@tonic-gate #include "_synonyms.h" 360Sstevel@tonic-gate 370Sstevel@tonic-gate #include <stdio.h> 380Sstevel@tonic-gate #include <sys/elf.h> 390Sstevel@tonic-gate #include <sys/elf_SPARC.h> 400Sstevel@tonic-gate #include <sys/mman.h> 410Sstevel@tonic-gate #include <dlfcn.h> 420Sstevel@tonic-gate #include <synch.h> 430Sstevel@tonic-gate #include <string.h> 441618Srie #include <debug.h> 451618Srie #include <reloc.h> 461618Srie #include <conv.h> 470Sstevel@tonic-gate #include "_rtld.h" 480Sstevel@tonic-gate #include "_audit.h" 490Sstevel@tonic-gate #include "_elf.h" 500Sstevel@tonic-gate #include "msg.h" 510Sstevel@tonic-gate 520Sstevel@tonic-gate 530Sstevel@tonic-gate extern void iflush_range(caddr_t, size_t); 540Sstevel@tonic-gate extern void plt_full_range(uintptr_t, uintptr_t); 550Sstevel@tonic-gate 560Sstevel@tonic-gate 570Sstevel@tonic-gate int 580Sstevel@tonic-gate elf_mach_flags_check(Rej_desc *rej, Ehdr *ehdr) 590Sstevel@tonic-gate { 600Sstevel@tonic-gate /* 610Sstevel@tonic-gate * Check machine type and flags. 620Sstevel@tonic-gate */ 630Sstevel@tonic-gate if (ehdr->e_machine != EM_SPARC) { 640Sstevel@tonic-gate if (ehdr->e_machine != EM_SPARC32PLUS) { 650Sstevel@tonic-gate rej->rej_type = SGS_REJ_MACH; 660Sstevel@tonic-gate rej->rej_info = (uint_t)ehdr->e_machine; 670Sstevel@tonic-gate return (0); 680Sstevel@tonic-gate } 690Sstevel@tonic-gate if ((ehdr->e_flags & EF_SPARC_32PLUS) == 0) { 700Sstevel@tonic-gate rej->rej_type = SGS_REJ_MISFLAG; 710Sstevel@tonic-gate rej->rej_info = (uint_t)ehdr->e_flags; 720Sstevel@tonic-gate return (0); 730Sstevel@tonic-gate } 740Sstevel@tonic-gate if ((ehdr->e_flags & ~at_flags) & EF_SPARC_32PLUS_MASK) { 750Sstevel@tonic-gate rej->rej_type = SGS_REJ_BADFLAG; 760Sstevel@tonic-gate rej->rej_info = (uint_t)ehdr->e_flags; 770Sstevel@tonic-gate return (0); 780Sstevel@tonic-gate } 790Sstevel@tonic-gate } else if ((ehdr->e_flags & ~EF_SPARCV9_MM) != 0) { 800Sstevel@tonic-gate rej->rej_type = SGS_REJ_BADFLAG; 810Sstevel@tonic-gate rej->rej_info = (uint_t)ehdr->e_flags; 820Sstevel@tonic-gate return (0); 830Sstevel@tonic-gate } 840Sstevel@tonic-gate return (1); 850Sstevel@tonic-gate } 860Sstevel@tonic-gate 870Sstevel@tonic-gate void 880Sstevel@tonic-gate ldso_plt_init(Rt_map * lmp) 890Sstevel@tonic-gate { 900Sstevel@tonic-gate /* 910Sstevel@tonic-gate * There is no need to analyze ld.so because we don't map in any of 920Sstevel@tonic-gate * its dependencies. However we may map these dependencies in later 930Sstevel@tonic-gate * (as if ld.so had dlopened them), so initialize the plt and the 940Sstevel@tonic-gate * permission information. 950Sstevel@tonic-gate */ 960Sstevel@tonic-gate if (PLTGOT(lmp)) 970Sstevel@tonic-gate elf_plt_init((PLTGOT(lmp)), (caddr_t)lmp); 980Sstevel@tonic-gate } 990Sstevel@tonic-gate 1000Sstevel@tonic-gate /* 1010Sstevel@tonic-gate * elf_plt_write() will test to see how far away our destination 1020Sstevel@tonic-gate * address lies. If it is close enough that a branch can 1030Sstevel@tonic-gate * be used instead of a jmpl - we will fill the plt in with 1040Sstevel@tonic-gate * single branch. The branches are much quicker then 1050Sstevel@tonic-gate * a jmpl instruction - see bug#4356879 for further 1060Sstevel@tonic-gate * details. 1070Sstevel@tonic-gate * 1080Sstevel@tonic-gate * NOTE: we pass in both a 'pltaddr' and a 'vpltaddr' since 1090Sstevel@tonic-gate * librtld/dldump update PLT's who's physical 1100Sstevel@tonic-gate * address is not the same as the 'virtual' runtime 1110Sstevel@tonic-gate * address. 1120Sstevel@tonic-gate */ 1130Sstevel@tonic-gate Pltbindtype 1140Sstevel@tonic-gate /* ARGSUSED4 */ 1150Sstevel@tonic-gate elf_plt_write(uintptr_t addr, uintptr_t vaddr, void *rptr, uintptr_t symval, 1160Sstevel@tonic-gate Xword pltndx) 1170Sstevel@tonic-gate { 1180Sstevel@tonic-gate Rela *rel = (Rela *)rptr; 1190Sstevel@tonic-gate uintptr_t vpltaddr, pltaddr; 1200Sstevel@tonic-gate long disp; 1210Sstevel@tonic-gate 1220Sstevel@tonic-gate 1230Sstevel@tonic-gate pltaddr = addr + rel->r_offset; 1240Sstevel@tonic-gate vpltaddr = vaddr + rel->r_offset; 1250Sstevel@tonic-gate disp = symval - vpltaddr - 4; 1260Sstevel@tonic-gate 1270Sstevel@tonic-gate /* 1280Sstevel@tonic-gate * Test if the destination address is close enough to use 1290Sstevel@tonic-gate * a ba,a... instruction to reach it. 1300Sstevel@tonic-gate */ 1310Sstevel@tonic-gate if (S_INRANGE(disp, 23) && !(rtld_flags & RT_FL_NOBAPLT)) { 1320Sstevel@tonic-gate uint_t *pltent, bainstr; 1330Sstevel@tonic-gate Pltbindtype rc; 1340Sstevel@tonic-gate 1350Sstevel@tonic-gate pltent = (uint_t *)pltaddr; 1360Sstevel@tonic-gate /* 1370Sstevel@tonic-gate * The 1380Sstevel@tonic-gate * 1390Sstevel@tonic-gate * ba,a,pt %icc, <dest> 1400Sstevel@tonic-gate * 1410Sstevel@tonic-gate * is the most efficient of the PLT's. If we 1420Sstevel@tonic-gate * are within +-20 bits *and* running on a 1430Sstevel@tonic-gate * v8plus architecture - use that branch. 1440Sstevel@tonic-gate */ 1450Sstevel@tonic-gate if ((at_flags & EF_SPARC_32PLUS) && 1460Sstevel@tonic-gate S_INRANGE(disp, 20)) { 1470Sstevel@tonic-gate bainstr = M_BA_A_PT; /* ba,a,pt %icc,<dest> */ 1480Sstevel@tonic-gate bainstr |= (S_MASK(19) & (disp >> 2)); 1490Sstevel@tonic-gate rc = PLT_T_21D; 1500Sstevel@tonic-gate DBG_CALL(pltcnt21d++); 1510Sstevel@tonic-gate } else { 1520Sstevel@tonic-gate /* 1530Sstevel@tonic-gate * Otherwise - we fall back to the good old 1540Sstevel@tonic-gate * 1550Sstevel@tonic-gate * ba,a <dest> 1560Sstevel@tonic-gate * 1570Sstevel@tonic-gate * Which still beats a jmpl instruction. 1580Sstevel@tonic-gate */ 1590Sstevel@tonic-gate bainstr = M_BA_A; /* ba,a <dest> */ 1600Sstevel@tonic-gate bainstr |= (S_MASK(22) & (disp >> 2)); 1610Sstevel@tonic-gate rc = PLT_T_24D; 1620Sstevel@tonic-gate DBG_CALL(pltcnt24d++); 1630Sstevel@tonic-gate } 1640Sstevel@tonic-gate 1650Sstevel@tonic-gate pltent[2] = M_NOP; /* nop instr */ 1660Sstevel@tonic-gate pltent[1] = bainstr; 1670Sstevel@tonic-gate 1680Sstevel@tonic-gate iflush_range((char *)(&pltent[1]), 4); 1690Sstevel@tonic-gate pltent[0] = M_NOP; /* nop instr */ 1700Sstevel@tonic-gate iflush_range((char *)(&pltent[0]), 4); 1710Sstevel@tonic-gate return (rc); 1720Sstevel@tonic-gate } 1730Sstevel@tonic-gate 1740Sstevel@tonic-gate /* 1750Sstevel@tonic-gate * The PLT destination is not in reach of 1760Sstevel@tonic-gate * a branch instruction - so we fall back 1770Sstevel@tonic-gate * to a 'jmpl' sequence. 1780Sstevel@tonic-gate */ 1790Sstevel@tonic-gate plt_full_range(pltaddr, symval); 1800Sstevel@tonic-gate DBG_CALL(pltcntfull++); 1810Sstevel@tonic-gate return (PLT_T_FULL); 1820Sstevel@tonic-gate } 1830Sstevel@tonic-gate 1840Sstevel@tonic-gate 1850Sstevel@tonic-gate /* 1860Sstevel@tonic-gate * Local storage space created on the stack created for this glue 1870Sstevel@tonic-gate * code includes space for: 1880Sstevel@tonic-gate * 0x4 pointer to dyn_data 1890Sstevel@tonic-gate * 0x4 size prev stack frame 1900Sstevel@tonic-gate */ 1910Sstevel@tonic-gate static const uchar_t dyn_plt_template[] = { 1920Sstevel@tonic-gate /* 0x00 */ 0x80, 0x90, 0x00, 0x1e, /* tst %fp */ 1930Sstevel@tonic-gate /* 0x04 */ 0x02, 0x80, 0x00, 0x04, /* be 0x14 */ 1940Sstevel@tonic-gate /* 0x08 */ 0x82, 0x27, 0x80, 0x0e, /* sub %sp, %fp, %g1 */ 1950Sstevel@tonic-gate /* 0x0c */ 0x10, 0x80, 0x00, 0x03, /* ba 0x20 */ 1960Sstevel@tonic-gate /* 0x10 */ 0x01, 0x00, 0x00, 0x00, /* nop */ 1970Sstevel@tonic-gate /* 0x14 */ 0x82, 0x10, 0x20, 0x60, /* mov 0x60, %g1 */ 1980Sstevel@tonic-gate /* 0x18 */ 0x9d, 0xe3, 0xbf, 0x98, /* save %sp, -0x68, %sp */ 1990Sstevel@tonic-gate /* 0x1c */ 0xc2, 0x27, 0xbf, 0xf8, /* st %g1, [%fp + -0x8] */ 2000Sstevel@tonic-gate /* 0x20 */ 0x03, 0x00, 0x00, 0x00, /* sethi %hi(val), %g1 */ 2010Sstevel@tonic-gate /* 0x24 */ 0x82, 0x10, 0x60, 0x00, /* or %g1, %lo(val), %g1 */ 2020Sstevel@tonic-gate /* 0x28 */ 0x40, 0x00, 0x00, 0x00, /* call <rel_addr> */ 2030Sstevel@tonic-gate /* 0x2c */ 0xc2, 0x27, 0xbf, 0xfc /* st %g1, [%fp + -0x4] */ 2040Sstevel@tonic-gate }; 2050Sstevel@tonic-gate 2060Sstevel@tonic-gate int dyn_plt_ent_size = sizeof (dyn_plt_template) + 2070Sstevel@tonic-gate sizeof (uintptr_t) + /* reflmp */ 2080Sstevel@tonic-gate sizeof (uintptr_t) + /* deflmp */ 2090Sstevel@tonic-gate sizeof (ulong_t) + /* symndx */ 2100Sstevel@tonic-gate sizeof (ulong_t) + /* sb_flags */ 2110Sstevel@tonic-gate sizeof (Sym); /* symdef */ 2120Sstevel@tonic-gate 2130Sstevel@tonic-gate /* 2140Sstevel@tonic-gate * the dynamic plt entry is: 2150Sstevel@tonic-gate * 2160Sstevel@tonic-gate * tst %fp 2170Sstevel@tonic-gate * be 1f 2180Sstevel@tonic-gate * nop 2190Sstevel@tonic-gate * sub %sp, %fp, %g1 2200Sstevel@tonic-gate * ba 2f 2210Sstevel@tonic-gate * nop 2220Sstevel@tonic-gate * 1: 2230Sstevel@tonic-gate * mov SA(MINFRAME), %g1 ! if %fp is null this is the 2240Sstevel@tonic-gate * ! 'minimum stack'. %fp is null 2250Sstevel@tonic-gate * ! on the initial stack frame 2260Sstevel@tonic-gate * 2: 2270Sstevel@tonic-gate * save %sp, -(SA(MINFRAME) + 2 * CLONGSIZE), %sp 2280Sstevel@tonic-gate * st %g1, [%fp + -0x8] ! store prev_stack size in [%fp - 8] 2290Sstevel@tonic-gate * sethi %hi(dyn_data), %g1 2300Sstevel@tonic-gate * or %g1, %lo(dyn_data), %g1 2310Sstevel@tonic-gate * call elf_plt_trace 2320Sstevel@tonic-gate * st %g1, [%fp + -0x4] ! store dyn_data ptr in [%fp - 4] 2330Sstevel@tonic-gate * dyn data: 2340Sstevel@tonic-gate * uintptr_t reflmp 2350Sstevel@tonic-gate * uintptr_t deflmp 2360Sstevel@tonic-gate * ulong_t symndx 2370Sstevel@tonic-gate * ulong_t sb_flags 2380Sstevel@tonic-gate * Sym symdef 2390Sstevel@tonic-gate */ 2400Sstevel@tonic-gate static caddr_t 2410Sstevel@tonic-gate elf_plt_trace_write(caddr_t addr, Rela *rptr, Rt_map *rlmp, Rt_map *dlmp, 2420Sstevel@tonic-gate Sym *sym, ulong_t symndx, ulong_t pltndx, caddr_t to, ulong_t sb_flags, 2430Sstevel@tonic-gate int *fail) 2440Sstevel@tonic-gate { 2450Sstevel@tonic-gate extern ulong_t elf_plt_trace(); 2461618Srie uintptr_t dyn_plt, *dyndata; 2470Sstevel@tonic-gate 2480Sstevel@tonic-gate /* 2490Sstevel@tonic-gate * If both pltenter & pltexit have been disabled there 2500Sstevel@tonic-gate * there is no reason to even create the glue code. 2510Sstevel@tonic-gate */ 2520Sstevel@tonic-gate if ((sb_flags & (LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT)) == 2530Sstevel@tonic-gate (LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT)) { 2540Sstevel@tonic-gate (void) elf_plt_write((uintptr_t)addr, (uintptr_t)addr, 2550Sstevel@tonic-gate rptr, (uintptr_t)to, pltndx); 2560Sstevel@tonic-gate return (to); 2570Sstevel@tonic-gate } 2580Sstevel@tonic-gate 2590Sstevel@tonic-gate /* 2600Sstevel@tonic-gate * We only need to add the glue code if there is an auditing 2610Sstevel@tonic-gate * library that is interested in this binding. 2620Sstevel@tonic-gate */ 2630Sstevel@tonic-gate dyn_plt = (uintptr_t)AUDINFO(rlmp)->ai_dynplts + 2644679Srie (pltndx * dyn_plt_ent_size); 2650Sstevel@tonic-gate 2660Sstevel@tonic-gate /* 2670Sstevel@tonic-gate * Have we initialized this dynamic plt entry yet? If we haven't do it 2680Sstevel@tonic-gate * now. Otherwise this function has been called before, but from a 2690Sstevel@tonic-gate * different plt (ie. from another shared object). In that case 2700Sstevel@tonic-gate * we just set the plt to point to the new dyn_plt. 2710Sstevel@tonic-gate */ 2720Sstevel@tonic-gate if (*(uint_t *)dyn_plt == 0) { 2731618Srie Sym *symp; 2740Sstevel@tonic-gate Xword symvalue; 2751618Srie Lm_list *lml = LIST(rlmp); 2760Sstevel@tonic-gate 2770Sstevel@tonic-gate (void) memcpy((void *)dyn_plt, dyn_plt_template, 2780Sstevel@tonic-gate sizeof (dyn_plt_template)); 2790Sstevel@tonic-gate dyndata = (uintptr_t *)(dyn_plt + sizeof (dyn_plt_template)); 2800Sstevel@tonic-gate 2810Sstevel@tonic-gate /* 2820Sstevel@tonic-gate * relocating: 2830Sstevel@tonic-gate * sethi %hi(dyndata), %g1 2840Sstevel@tonic-gate */ 2850Sstevel@tonic-gate symvalue = (Xword)dyndata; 2865189Sab196087 if (do_reloc_rtld(R_SPARC_HI22, (uchar_t *)(dyn_plt + 0x20), 2870Sstevel@tonic-gate &symvalue, MSG_ORIG(MSG_SYM_LADYNDATA), 2881618Srie MSG_ORIG(MSG_SPECFIL_DYNPLT), lml) == 0) { 2890Sstevel@tonic-gate *fail = 1; 2900Sstevel@tonic-gate return (0); 2910Sstevel@tonic-gate } 2920Sstevel@tonic-gate 2930Sstevel@tonic-gate /* 2940Sstevel@tonic-gate * relocating: 2950Sstevel@tonic-gate * or %g1, %lo(dyndata), %g1 2960Sstevel@tonic-gate */ 2970Sstevel@tonic-gate symvalue = (Xword)dyndata; 2985189Sab196087 if (do_reloc_rtld(R_SPARC_LO10, (uchar_t *)(dyn_plt + 0x24), 2990Sstevel@tonic-gate &symvalue, MSG_ORIG(MSG_SYM_LADYNDATA), 3001618Srie MSG_ORIG(MSG_SPECFIL_DYNPLT), lml) == 0) { 3010Sstevel@tonic-gate *fail = 1; 3020Sstevel@tonic-gate return (0); 3030Sstevel@tonic-gate } 3040Sstevel@tonic-gate 3050Sstevel@tonic-gate /* 3060Sstevel@tonic-gate * relocating: 3070Sstevel@tonic-gate * call elf_plt_trace 3080Sstevel@tonic-gate */ 3090Sstevel@tonic-gate symvalue = (Xword)((uintptr_t)&elf_plt_trace - 3101618Srie (dyn_plt + 0x28)); 3115189Sab196087 if (do_reloc_rtld(R_SPARC_WDISP30, (uchar_t *)(dyn_plt + 0x28), 3120Sstevel@tonic-gate &symvalue, MSG_ORIG(MSG_SYM_ELFPLTTRACE), 3131618Srie MSG_ORIG(MSG_SPECFIL_DYNPLT), lml) == 0) { 3140Sstevel@tonic-gate *fail = 1; 3150Sstevel@tonic-gate return (0); 3160Sstevel@tonic-gate } 3170Sstevel@tonic-gate 3180Sstevel@tonic-gate *dyndata++ = (uintptr_t)rlmp; 3190Sstevel@tonic-gate *dyndata++ = (uintptr_t)dlmp; 3200Sstevel@tonic-gate *(ulong_t *)dyndata++ = symndx; 3210Sstevel@tonic-gate *(ulong_t *)dyndata++ = sb_flags; 3220Sstevel@tonic-gate symp = (Sym *)dyndata; 3230Sstevel@tonic-gate *symp = *sym; 3240Sstevel@tonic-gate symp->st_name += (Word)STRTAB(dlmp); 3250Sstevel@tonic-gate symp->st_value = (Addr)to; 3260Sstevel@tonic-gate 3270Sstevel@tonic-gate iflush_range((void *)dyn_plt, sizeof (dyn_plt_template)); 3280Sstevel@tonic-gate } 3290Sstevel@tonic-gate 3300Sstevel@tonic-gate (void) elf_plt_write((uintptr_t)addr, (uintptr_t)addr, 3314679Srie rptr, (uintptr_t)dyn_plt, 0); 3320Sstevel@tonic-gate return ((caddr_t)dyn_plt); 3330Sstevel@tonic-gate } 3340Sstevel@tonic-gate 3350Sstevel@tonic-gate 3360Sstevel@tonic-gate /* 3370Sstevel@tonic-gate * Function binding routine - invoked on the first call to a function through 3380Sstevel@tonic-gate * the procedure linkage table; 3390Sstevel@tonic-gate * passes first through an assembly language interface. 3400Sstevel@tonic-gate * 3410Sstevel@tonic-gate * Takes the address of the PLT entry where the call originated, 3420Sstevel@tonic-gate * the offset into the relocation table of the associated 3430Sstevel@tonic-gate * relocation entry and the address of the link map (rt_private_map struct) 3440Sstevel@tonic-gate * for the entry. 3450Sstevel@tonic-gate * 3460Sstevel@tonic-gate * Returns the address of the function referenced after re-writing the PLT 3470Sstevel@tonic-gate * entry to invoke the function directly. 3480Sstevel@tonic-gate * 3490Sstevel@tonic-gate * On error, causes process to terminate with a signal. 3500Sstevel@tonic-gate */ 3510Sstevel@tonic-gate ulong_t 3520Sstevel@tonic-gate elf_bndr(Rt_map *lmp, ulong_t pltoff, caddr_t from) 3530Sstevel@tonic-gate { 3540Sstevel@tonic-gate Rt_map *nlmp, *llmp; 3550Sstevel@tonic-gate ulong_t addr, vaddr, reloff, symval, rsymndx; 3560Sstevel@tonic-gate char *name; 3570Sstevel@tonic-gate Rela *rptr; 3585220Srie Sym *rsym, *nsym; 3590Sstevel@tonic-gate Xword pltndx; 3600Sstevel@tonic-gate uint_t binfo, sb_flags = 0; 3610Sstevel@tonic-gate Slookup sl; 3620Sstevel@tonic-gate Pltbindtype pbtype; 3631618Srie int entry, lmflags; 3641618Srie uint_t dbg_class; 3651618Srie Lm_list *lml = LIST(lmp); 3660Sstevel@tonic-gate 3670Sstevel@tonic-gate /* 3680Sstevel@tonic-gate * For compatibility with libthread (TI_VERSION 1) we track the entry 3690Sstevel@tonic-gate * value. A zero value indicates we have recursed into ld.so.1 to 3700Sstevel@tonic-gate * further process a locking request. Under this recursion we disable 3710Sstevel@tonic-gate * tsort and cleanup activities. 3720Sstevel@tonic-gate */ 3730Sstevel@tonic-gate entry = enter(); 3740Sstevel@tonic-gate 3751618Srie if ((lmflags = lml->lm_flags) & LML_FLG_RTLDLM) { 3761618Srie dbg_class = dbg_desc->d_class; 3771618Srie dbg_desc->d_class = 0; 3780Sstevel@tonic-gate } 3790Sstevel@tonic-gate 3800Sstevel@tonic-gate /* 3810Sstevel@tonic-gate * Must calculate true plt relocation address from reloc. 3820Sstevel@tonic-gate * Take offset, subtract number of reserved PLT entries, and divide 3830Sstevel@tonic-gate * by PLT entry size, which should give the index of the plt 3840Sstevel@tonic-gate * entry (and relocation entry since they have been defined to be 3850Sstevel@tonic-gate * in the same order). Then we must multiply by the size of 3860Sstevel@tonic-gate * a relocation entry, which will give us the offset of the 3870Sstevel@tonic-gate * plt relocation entry from the start of them given by JMPREL(lm). 3880Sstevel@tonic-gate */ 3890Sstevel@tonic-gate addr = pltoff - M_PLT_RESERVSZ; 3900Sstevel@tonic-gate pltndx = addr / M_PLT_ENTSIZE; 3910Sstevel@tonic-gate 3920Sstevel@tonic-gate /* 3930Sstevel@tonic-gate * Perform some basic sanity checks. If we didn't get a load map 3940Sstevel@tonic-gate * or the plt offset is invalid then its possible someone has walked 3950Sstevel@tonic-gate * over the plt entries or jumped to plt0 out of the blue. 3960Sstevel@tonic-gate */ 3970Sstevel@tonic-gate if (!lmp || ((addr % M_PLT_ENTSIZE) != 0)) { 3984734Sab196087 Conv_inv_buf_t inv_buf; 3994734Sab196087 4001618Srie eprintf(lml, ERR_FATAL, MSG_INTL(MSG_REL_PLTREF), 4014734Sab196087 conv_reloc_SPARC_type(R_SPARC_JMP_SLOT, 0, &inv_buf), 4021618Srie EC_NATPTR(lmp), EC_XWORD(pltoff), EC_NATPTR(from)); 4031618Srie rtldexit(lml, 1); 4040Sstevel@tonic-gate } 4050Sstevel@tonic-gate reloff = pltndx * sizeof (Rela); 4060Sstevel@tonic-gate 4070Sstevel@tonic-gate /* 4080Sstevel@tonic-gate * Use relocation entry to get symbol table entry and symbol name. 4090Sstevel@tonic-gate */ 4100Sstevel@tonic-gate addr = (ulong_t)JMPREL(lmp); 4110Sstevel@tonic-gate rptr = (Rela *)(addr + reloff); 4120Sstevel@tonic-gate rsymndx = ELF_R_SYM(rptr->r_info); 4135220Srie rsym = (Sym *)((ulong_t)SYMTAB(lmp) + (rsymndx * SYMENT(lmp))); 4145220Srie name = (char *)(STRTAB(lmp) + rsym->st_name); 4150Sstevel@tonic-gate 4160Sstevel@tonic-gate /* 4170Sstevel@tonic-gate * Determine the last link-map of this list, this'll be the starting 4180Sstevel@tonic-gate * point for any tsort() processing. 4190Sstevel@tonic-gate */ 4201618Srie llmp = lml->lm_tail; 4210Sstevel@tonic-gate 4220Sstevel@tonic-gate /* 423*5950Srie * Find definition for symbol. Initialize the symbol lookup data 424*5950Srie * structure. 4250Sstevel@tonic-gate */ 426*5950Srie SLOOKUP_INIT(sl, name, lmp, lml->lm_head, ld_entry_cnt, 0, 427*5950Srie rsymndx, rsym, 0, LKUP_DEFT); 4280Sstevel@tonic-gate 4290Sstevel@tonic-gate if ((nsym = lookup_sym(&sl, &nlmp, &binfo)) == 0) { 4301618Srie eprintf(lml, ERR_FATAL, MSG_INTL(MSG_REL_NOSYM), NAME(lmp), 4310Sstevel@tonic-gate demangle(name)); 4321618Srie rtldexit(lml, 1); 4330Sstevel@tonic-gate } 4340Sstevel@tonic-gate 4350Sstevel@tonic-gate symval = nsym->st_value; 4360Sstevel@tonic-gate if (!(FLAGS(nlmp) & FLG_RT_FIXED) && 4370Sstevel@tonic-gate (nsym->st_shndx != SHN_ABS)) 4380Sstevel@tonic-gate symval += ADDR(nlmp); 4390Sstevel@tonic-gate if ((lmp != nlmp) && ((FLAGS1(nlmp) & FL1_RT_NOINIFIN) == 0)) { 4400Sstevel@tonic-gate /* 4410Sstevel@tonic-gate * Record that this new link map is now bound to the caller. 4420Sstevel@tonic-gate */ 4430Sstevel@tonic-gate if (bind_one(lmp, nlmp, BND_REFER) == 0) 4441618Srie rtldexit(lml, 1); 4450Sstevel@tonic-gate } 4460Sstevel@tonic-gate 4471618Srie if ((lml->lm_tflags | FLAGS1(lmp)) & LML_TFLG_AUD_SYMBIND) { 4480Sstevel@tonic-gate ulong_t symndx = (((uintptr_t)nsym - 4494679Srie (uintptr_t)SYMTAB(nlmp)) / SYMENT(nlmp)); 4500Sstevel@tonic-gate 4510Sstevel@tonic-gate symval = audit_symbind(lmp, nlmp, nsym, symndx, symval, 4524679Srie &sb_flags); 4530Sstevel@tonic-gate } 4540Sstevel@tonic-gate 4550Sstevel@tonic-gate if (FLAGS(lmp) & FLG_RT_FIXED) 4560Sstevel@tonic-gate vaddr = 0; 4570Sstevel@tonic-gate else 4580Sstevel@tonic-gate vaddr = ADDR(lmp); 4590Sstevel@tonic-gate 4600Sstevel@tonic-gate pbtype = PLT_T_NONE; 4610Sstevel@tonic-gate if (!(rtld_flags & RT_FL_NOBIND)) { 4621618Srie if (((lml->lm_tflags | FLAGS1(lmp)) & 4630Sstevel@tonic-gate (LML_TFLG_AUD_PLTENTER | LML_TFLG_AUD_PLTEXIT)) && 4640Sstevel@tonic-gate AUDINFO(lmp)->ai_dynplts) { 4650Sstevel@tonic-gate int fail = 0; 4660Sstevel@tonic-gate ulong_t symndx = (((uintptr_t)nsym - 4674679Srie (uintptr_t)SYMTAB(nlmp)) / SYMENT(nlmp)); 4680Sstevel@tonic-gate 4690Sstevel@tonic-gate symval = (ulong_t)elf_plt_trace_write((caddr_t)vaddr, 4700Sstevel@tonic-gate rptr, lmp, nlmp, nsym, symndx, pltndx, 4710Sstevel@tonic-gate (caddr_t)symval, sb_flags, &fail); 4720Sstevel@tonic-gate if (fail) 4731618Srie rtldexit(lml, 1); 4740Sstevel@tonic-gate } else { 4750Sstevel@tonic-gate /* 4760Sstevel@tonic-gate * Write standard PLT entry to jump directly 4770Sstevel@tonic-gate * to newly bound function. 4780Sstevel@tonic-gate */ 4790Sstevel@tonic-gate pbtype = elf_plt_write((uintptr_t)vaddr, 4804679Srie (uintptr_t)vaddr, rptr, symval, pltndx); 4810Sstevel@tonic-gate } 4820Sstevel@tonic-gate } 4830Sstevel@tonic-gate 4840Sstevel@tonic-gate /* 4850Sstevel@tonic-gate * Print binding information and rebuild PLT entry. 4860Sstevel@tonic-gate */ 4871618Srie DBG_CALL(Dbg_bind_global(lmp, (Addr)from, (Off)(from - ADDR(lmp)), 4881618Srie pltndx, pbtype, nlmp, (Addr)symval, nsym->st_value, name, binfo)); 4890Sstevel@tonic-gate 4900Sstevel@tonic-gate /* 4910Sstevel@tonic-gate * Complete any processing for newly loaded objects. Note we don't 4920Sstevel@tonic-gate * know exactly where any new objects are loaded (we know the object 4930Sstevel@tonic-gate * that supplied the symbol, but others may have been loaded lazily as 4940Sstevel@tonic-gate * we searched for the symbol), so sorting starts from the last 4950Sstevel@tonic-gate * link-map know on entry to this routine. 4960Sstevel@tonic-gate */ 4970Sstevel@tonic-gate if (entry) 4984679Srie load_completion(llmp); 4990Sstevel@tonic-gate 5000Sstevel@tonic-gate /* 5010Sstevel@tonic-gate * Some operations like dldump() or dlopen()'ing a relocatable object 5020Sstevel@tonic-gate * result in objects being loaded on rtld's link-map, make sure these 5030Sstevel@tonic-gate * objects are initialized also. 5040Sstevel@tonic-gate */ 5050Sstevel@tonic-gate if ((LIST(nlmp)->lm_flags & LML_FLG_RTLDLM) && LIST(nlmp)->lm_init) 5064679Srie load_completion(nlmp); 5070Sstevel@tonic-gate 5080Sstevel@tonic-gate /* 5090Sstevel@tonic-gate * If the object we've bound to is in the process of being initialized 5100Sstevel@tonic-gate * by another thread, determine whether we should block. 5110Sstevel@tonic-gate */ 5120Sstevel@tonic-gate is_dep_ready(nlmp, lmp, DBG_WAIT_SYMBOL); 5130Sstevel@tonic-gate 5140Sstevel@tonic-gate /* 5150Sstevel@tonic-gate * Make sure the object to which we've bound has had it's .init fired. 5160Sstevel@tonic-gate * Cleanup before return to user code. 5170Sstevel@tonic-gate */ 5180Sstevel@tonic-gate if (entry) { 5190Sstevel@tonic-gate is_dep_init(nlmp, lmp); 5201618Srie leave(lml); 5210Sstevel@tonic-gate } 5220Sstevel@tonic-gate 5230Sstevel@tonic-gate if (lmflags & LML_FLG_RTLDLM) 5241618Srie dbg_desc->d_class = dbg_class; 5250Sstevel@tonic-gate 5260Sstevel@tonic-gate return (symval); 5270Sstevel@tonic-gate } 5280Sstevel@tonic-gate 5290Sstevel@tonic-gate 5300Sstevel@tonic-gate /* 5310Sstevel@tonic-gate * Read and process the relocations for one link object, we assume all 5320Sstevel@tonic-gate * relocation sections for loadable segments are stored contiguously in 5330Sstevel@tonic-gate * the file. 5340Sstevel@tonic-gate */ 5350Sstevel@tonic-gate int 5360Sstevel@tonic-gate elf_reloc(Rt_map *lmp, uint_t plt) 5370Sstevel@tonic-gate { 5380Sstevel@tonic-gate ulong_t relbgn, relend, relsiz, basebgn, pltbgn, pltend; 5390Sstevel@tonic-gate ulong_t roffset, rsymndx, psymndx = 0, etext = ETEXT(lmp); 5400Sstevel@tonic-gate ulong_t emap, dsymndx, pltndx; 5410Sstevel@tonic-gate uchar_t rtype; 5420Sstevel@tonic-gate long reladd, value, pvalue; 5430Sstevel@tonic-gate Sym *symref, *psymref, *symdef, *psymdef; 5440Sstevel@tonic-gate char *name, *pname; 5450Sstevel@tonic-gate Rt_map *_lmp, *plmp; 5460Sstevel@tonic-gate int textrel = 0, ret = 1, noplt = 0; 5470Sstevel@tonic-gate long relacount = RELACOUNT(lmp); 5480Sstevel@tonic-gate Rela *rel; 5490Sstevel@tonic-gate Pltbindtype pbtype; 5500Sstevel@tonic-gate uint_t binfo, pbinfo; 5515892Sab196087 APlist *bound = NULL; 5520Sstevel@tonic-gate 5530Sstevel@tonic-gate /* 5540Sstevel@tonic-gate * If an object has any DT_REGISTER entries associated with 5550Sstevel@tonic-gate * it, they are processed now. 5560Sstevel@tonic-gate */ 5570Sstevel@tonic-gate if ((plt == 0) && (FLAGS(lmp) & FLG_RT_REGSYMS)) { 5580Sstevel@tonic-gate if (elf_regsyms(lmp) == 0) 5590Sstevel@tonic-gate return (0); 5600Sstevel@tonic-gate } 5610Sstevel@tonic-gate 5620Sstevel@tonic-gate /* 5630Sstevel@tonic-gate * Although only necessary for lazy binding, initialize the first 5640Sstevel@tonic-gate * procedure linkage table entry to go to elf_rtbndr(). dbx(1) seems 5650Sstevel@tonic-gate * to find this useful. 5660Sstevel@tonic-gate */ 5670Sstevel@tonic-gate if ((plt == 0) && PLTGOT(lmp)) { 5680Sstevel@tonic-gate if ((ulong_t)PLTGOT(lmp) < etext) { 5690Sstevel@tonic-gate if (elf_set_prot(lmp, PROT_WRITE) == 0) 5700Sstevel@tonic-gate return (0); 5710Sstevel@tonic-gate textrel = 1; 5720Sstevel@tonic-gate } 5730Sstevel@tonic-gate elf_plt_init(PLTGOT(lmp), (caddr_t)lmp); 5740Sstevel@tonic-gate } 5750Sstevel@tonic-gate 5760Sstevel@tonic-gate /* 5770Sstevel@tonic-gate * Initialize the plt start and end addresses. 5780Sstevel@tonic-gate */ 5790Sstevel@tonic-gate if ((pltbgn = (ulong_t)JMPREL(lmp)) != 0) 5800Sstevel@tonic-gate pltend = pltbgn + (ulong_t)(PLTRELSZ(lmp)); 5810Sstevel@tonic-gate 5820Sstevel@tonic-gate /* 5830Sstevel@tonic-gate * If we've been called upon to promote an RTLD_LAZY object to an 5840Sstevel@tonic-gate * RTLD_NOW then we're only interested in scaning the .plt table. 5850Sstevel@tonic-gate */ 5860Sstevel@tonic-gate if (plt) { 5870Sstevel@tonic-gate relbgn = pltbgn; 5880Sstevel@tonic-gate relend = pltend; 5890Sstevel@tonic-gate } else { 5900Sstevel@tonic-gate /* 5910Sstevel@tonic-gate * The relocation sections appear to the run-time linker as a 5920Sstevel@tonic-gate * single table. Determine the address of the beginning and end 5930Sstevel@tonic-gate * of this table. There are two different interpretations of 5940Sstevel@tonic-gate * the ABI at this point: 5950Sstevel@tonic-gate * 5960Sstevel@tonic-gate * o The REL table and its associated RELSZ indicate the 5970Sstevel@tonic-gate * concatenation of *all* relocation sections (this is the 5980Sstevel@tonic-gate * model our link-editor constructs). 5990Sstevel@tonic-gate * 6000Sstevel@tonic-gate * o The REL table and its associated RELSZ indicate the 6010Sstevel@tonic-gate * concatenation of all *but* the .plt relocations. These 6020Sstevel@tonic-gate * relocations are specified individually by the JMPREL and 6030Sstevel@tonic-gate * PLTRELSZ entries. 6040Sstevel@tonic-gate * 6050Sstevel@tonic-gate * Determine from our knowledege of the relocation range and 6060Sstevel@tonic-gate * .plt range, the range of the total relocation table. Note 6070Sstevel@tonic-gate * that one other ABI assumption seems to be that the .plt 6080Sstevel@tonic-gate * relocations always follow any other relocations, the 6090Sstevel@tonic-gate * following range checking drops that assumption. 6100Sstevel@tonic-gate */ 6110Sstevel@tonic-gate relbgn = (ulong_t)(REL(lmp)); 6120Sstevel@tonic-gate relend = relbgn + (ulong_t)(RELSZ(lmp)); 6130Sstevel@tonic-gate if (pltbgn) { 6140Sstevel@tonic-gate if (!relbgn || (relbgn > pltbgn)) 6150Sstevel@tonic-gate relbgn = pltbgn; 6160Sstevel@tonic-gate if (!relbgn || (relend < pltend)) 6170Sstevel@tonic-gate relend = pltend; 6180Sstevel@tonic-gate } 6190Sstevel@tonic-gate } 6200Sstevel@tonic-gate if (!relbgn || (relbgn == relend)) { 6211618Srie DBG_CALL(Dbg_reloc_run(lmp, 0, plt, DBG_REL_NONE)); 6220Sstevel@tonic-gate return (1); 6230Sstevel@tonic-gate } 6240Sstevel@tonic-gate 6250Sstevel@tonic-gate relsiz = (ulong_t)(RELENT(lmp)); 6260Sstevel@tonic-gate basebgn = ADDR(lmp); 6270Sstevel@tonic-gate emap = ADDR(lmp) + MSIZE(lmp); 6280Sstevel@tonic-gate 6291618Srie DBG_CALL(Dbg_reloc_run(lmp, M_REL_SHT_TYPE, plt, DBG_REL_START)); 6300Sstevel@tonic-gate 6310Sstevel@tonic-gate /* 6320Sstevel@tonic-gate * If we're processing in lazy mode there is no need to scan the 6330Sstevel@tonic-gate * .rela.plt table. 6340Sstevel@tonic-gate */ 6350Sstevel@tonic-gate if (pltbgn && ((MODE(lmp) & RTLD_NOW) == 0)) 6360Sstevel@tonic-gate noplt = 1; 6370Sstevel@tonic-gate 6380Sstevel@tonic-gate /* 6390Sstevel@tonic-gate * Loop through relocations. 6400Sstevel@tonic-gate */ 6410Sstevel@tonic-gate while (relbgn < relend) { 6420Sstevel@tonic-gate Addr vaddr; 6430Sstevel@tonic-gate uint_t sb_flags = 0; 6440Sstevel@tonic-gate 6450Sstevel@tonic-gate rtype = ELF_R_TYPE(((Rela *)relbgn)->r_info); 6460Sstevel@tonic-gate 6470Sstevel@tonic-gate /* 6480Sstevel@tonic-gate * If this is a RELATIVE relocation in a shared object (the 6490Sstevel@tonic-gate * common case), and if we are not debugging, then jump into a 6500Sstevel@tonic-gate * tighter relocation loop (elf_reloc_relative). Only make the 6510Sstevel@tonic-gate * jump if we've been given a hint on the number of relocations. 6520Sstevel@tonic-gate */ 6530Sstevel@tonic-gate if ((rtype == R_SPARC_RELATIVE) && 6541618Srie ((FLAGS(lmp) & FLG_RT_FIXED) == 0) && (DBG_ENABLED == 0)) { 6550Sstevel@tonic-gate /* 6560Sstevel@tonic-gate * It's possible that the relative relocation block 6570Sstevel@tonic-gate * has relocations against the text segment as well 6580Sstevel@tonic-gate * as the data segment. Since our optimized relocation 6590Sstevel@tonic-gate * engine does not check which segment the relocation 6600Sstevel@tonic-gate * is against - just mprotect it now if it's been 6610Sstevel@tonic-gate * marked as containing TEXTREL's. 6620Sstevel@tonic-gate */ 6630Sstevel@tonic-gate if ((textrel == 0) && (FLAGS1(lmp) & FL1_RT_TEXTREL)) { 6640Sstevel@tonic-gate if (elf_set_prot(lmp, PROT_WRITE) == 0) { 6650Sstevel@tonic-gate ret = 0; 6660Sstevel@tonic-gate break; 6670Sstevel@tonic-gate } 6680Sstevel@tonic-gate textrel = 1; 6690Sstevel@tonic-gate } 6700Sstevel@tonic-gate if (relacount) { 6710Sstevel@tonic-gate relbgn = elf_reloc_relacount(relbgn, relacount, 6720Sstevel@tonic-gate relsiz, basebgn); 6730Sstevel@tonic-gate relacount = 0; 6740Sstevel@tonic-gate } else { 6750Sstevel@tonic-gate relbgn = elf_reloc_relative(relbgn, relend, 6760Sstevel@tonic-gate relsiz, basebgn, etext, emap); 6770Sstevel@tonic-gate } 6780Sstevel@tonic-gate if (relbgn >= relend) 6790Sstevel@tonic-gate break; 6800Sstevel@tonic-gate rtype = ELF_R_TYPE(((Rela *)relbgn)->r_info); 6810Sstevel@tonic-gate } 6820Sstevel@tonic-gate 6830Sstevel@tonic-gate roffset = ((Rela *)relbgn)->r_offset; 6840Sstevel@tonic-gate 6850Sstevel@tonic-gate reladd = (long)(((Rela *)relbgn)->r_addend); 6860Sstevel@tonic-gate rsymndx = ELF_R_SYM(((Rela *)relbgn)->r_info); 6870Sstevel@tonic-gate 6880Sstevel@tonic-gate rel = (Rela *)relbgn; 6890Sstevel@tonic-gate relbgn += relsiz; 6900Sstevel@tonic-gate 6910Sstevel@tonic-gate /* 6920Sstevel@tonic-gate * Optimizations. 6930Sstevel@tonic-gate */ 6940Sstevel@tonic-gate if (rtype == R_SPARC_NONE) 6950Sstevel@tonic-gate continue; 6960Sstevel@tonic-gate if (noplt && ((ulong_t)rel >= pltbgn) && 6970Sstevel@tonic-gate ((ulong_t)rel < pltend)) { 6980Sstevel@tonic-gate relbgn = pltend; 6990Sstevel@tonic-gate continue; 7000Sstevel@tonic-gate } 7010Sstevel@tonic-gate 7020Sstevel@tonic-gate if (rtype != R_SPARC_REGISTER) { 7030Sstevel@tonic-gate /* 7040Sstevel@tonic-gate * If this is a shared object, add the base address 7050Sstevel@tonic-gate * to offset. 7060Sstevel@tonic-gate */ 7070Sstevel@tonic-gate if (!(FLAGS(lmp) & FLG_RT_FIXED)) 7080Sstevel@tonic-gate roffset += basebgn; 7090Sstevel@tonic-gate 7100Sstevel@tonic-gate /* 7110Sstevel@tonic-gate * If this relocation is not against part of the image 7120Sstevel@tonic-gate * mapped into memory we skip it. 7130Sstevel@tonic-gate */ 7140Sstevel@tonic-gate if ((roffset < ADDR(lmp)) || (roffset > (ADDR(lmp) + 7150Sstevel@tonic-gate MSIZE(lmp)))) { 7160Sstevel@tonic-gate elf_reloc_bad(lmp, (void *)rel, rtype, roffset, 7170Sstevel@tonic-gate rsymndx); 7180Sstevel@tonic-gate continue; 7190Sstevel@tonic-gate } 7200Sstevel@tonic-gate } 7210Sstevel@tonic-gate 7220Sstevel@tonic-gate /* 7233731Srie * If we're promoting .plts try and determine if this one has 7243731Srie * already been written. An uninitialized .plts' second 7253731Srie * instruction is a branch. Note, elf_plt_write() optimizes 7263731Srie * .plt relocations, and it's possible that a relocated entry 7273731Srie * is a branch. If this is the case, we can't tell the 7283731Srie * difference between an uninitialized .plt and a relocated, 7293731Srie * .plt that uses a branch. In this case, we'll simply redo 7303731Srie * the relocation calculation, which is a bit sad. 7310Sstevel@tonic-gate */ 7320Sstevel@tonic-gate if (plt) { 7330Sstevel@tonic-gate ulong_t *_roffset = (ulong_t *)roffset; 7340Sstevel@tonic-gate 7350Sstevel@tonic-gate _roffset++; 7360Sstevel@tonic-gate if ((*_roffset & (~(S_MASK(22)))) != M_BA_A) 7370Sstevel@tonic-gate continue; 7380Sstevel@tonic-gate } 7390Sstevel@tonic-gate 7400Sstevel@tonic-gate binfo = 0; 7410Sstevel@tonic-gate pltndx = (ulong_t)-1; 7420Sstevel@tonic-gate pbtype = PLT_T_NONE; 7430Sstevel@tonic-gate /* 7440Sstevel@tonic-gate * If a symbol index is specified then get the symbol table 7450Sstevel@tonic-gate * entry, locate the symbol definition, and determine its 7460Sstevel@tonic-gate * address. 7470Sstevel@tonic-gate */ 7480Sstevel@tonic-gate if (rsymndx) { 7490Sstevel@tonic-gate /* 7500Sstevel@tonic-gate * Get the local symbol table entry. 7510Sstevel@tonic-gate */ 7520Sstevel@tonic-gate symref = (Sym *)((ulong_t)SYMTAB(lmp) + 7530Sstevel@tonic-gate (rsymndx * SYMENT(lmp))); 7540Sstevel@tonic-gate 7550Sstevel@tonic-gate /* 7560Sstevel@tonic-gate * If this is a local symbol, just use the base address. 7570Sstevel@tonic-gate * (we should have no local relocations in the 7580Sstevel@tonic-gate * executable). 7590Sstevel@tonic-gate */ 7600Sstevel@tonic-gate if (ELF_ST_BIND(symref->st_info) == STB_LOCAL) { 7610Sstevel@tonic-gate value = basebgn; 7620Sstevel@tonic-gate name = (char *)0; 7630Sstevel@tonic-gate 7640Sstevel@tonic-gate /* 7652145Srie * Special case TLS relocations. 7660Sstevel@tonic-gate */ 7672145Srie if (rtype == R_SPARC_TLS_DTPMOD32) { 7682145Srie /* 7692145Srie * Use the TLS modid. 7702145Srie */ 7710Sstevel@tonic-gate value = TLSMODID(lmp); 7722145Srie 7732145Srie } else if (rtype == R_SPARC_TLS_TPOFF32) { 7742145Srie if ((value = elf_static_tls(lmp, symref, 7752145Srie rel, rtype, 0, roffset, 0)) == 0) { 7762145Srie ret = 0; 7772145Srie break; 7782145Srie } 7792145Srie } 7800Sstevel@tonic-gate } else { 7810Sstevel@tonic-gate /* 7820Sstevel@tonic-gate * If the symbol index is equal to the previous 7830Sstevel@tonic-gate * symbol index relocation we processed then 7840Sstevel@tonic-gate * reuse the previous values. (Note that there 7850Sstevel@tonic-gate * have been cases where a relocation exists 7860Sstevel@tonic-gate * against a copy relocation symbol, our ld(1) 7870Sstevel@tonic-gate * should optimize this away, but make sure we 7880Sstevel@tonic-gate * don't use the same symbol information should 7890Sstevel@tonic-gate * this case exist). 7900Sstevel@tonic-gate */ 7910Sstevel@tonic-gate if ((rsymndx == psymndx) && 7920Sstevel@tonic-gate (rtype != R_SPARC_COPY)) { 7930Sstevel@tonic-gate /* LINTED */ 7940Sstevel@tonic-gate if (psymdef == 0) { 7951618Srie DBG_CALL(Dbg_bind_weak(lmp, 7961618Srie (Addr)roffset, (Addr) 7970Sstevel@tonic-gate (roffset - basebgn), name)); 7980Sstevel@tonic-gate continue; 7990Sstevel@tonic-gate } 8000Sstevel@tonic-gate /* LINTED */ 8010Sstevel@tonic-gate value = pvalue; 8020Sstevel@tonic-gate /* LINTED */ 8030Sstevel@tonic-gate name = pname; 8040Sstevel@tonic-gate symdef = psymdef; 8050Sstevel@tonic-gate /* LINTED */ 8060Sstevel@tonic-gate symref = psymref; 8070Sstevel@tonic-gate /* LINTED */ 8080Sstevel@tonic-gate _lmp = plmp; 8090Sstevel@tonic-gate /* LINTED */ 8100Sstevel@tonic-gate binfo = pbinfo; 8110Sstevel@tonic-gate 8120Sstevel@tonic-gate if ((LIST(_lmp)->lm_tflags | 8130Sstevel@tonic-gate FLAGS1(_lmp)) & 8140Sstevel@tonic-gate LML_TFLG_AUD_SYMBIND) { 8150Sstevel@tonic-gate value = audit_symbind(lmp, _lmp, 8160Sstevel@tonic-gate /* LINTED */ 8170Sstevel@tonic-gate symdef, dsymndx, value, 8180Sstevel@tonic-gate &sb_flags); 8190Sstevel@tonic-gate } 8200Sstevel@tonic-gate } else { 8210Sstevel@tonic-gate Slookup sl; 8220Sstevel@tonic-gate 8230Sstevel@tonic-gate /* 8240Sstevel@tonic-gate * Lookup the symbol definition. 825*5950Srie * Initialize the symbol lookup data 826*5950Srie * structure. 8270Sstevel@tonic-gate */ 8280Sstevel@tonic-gate name = (char *)(STRTAB(lmp) + 8290Sstevel@tonic-gate symref->st_name); 8300Sstevel@tonic-gate 831*5950Srie SLOOKUP_INIT(sl, name, lmp, 0, 832*5950Srie ld_entry_cnt, 0, rsymndx, symref, 833*5950Srie rtype, LKUP_STDRELOC); 8340Sstevel@tonic-gate 8350Sstevel@tonic-gate symdef = lookup_sym(&sl, &_lmp, &binfo); 8360Sstevel@tonic-gate 8370Sstevel@tonic-gate /* 8380Sstevel@tonic-gate * If the symbol is not found and the 8390Sstevel@tonic-gate * reference was not to a weak symbol, 8400Sstevel@tonic-gate * report an error. Weak references 8410Sstevel@tonic-gate * may be unresolved. 8420Sstevel@tonic-gate */ 8434679Srie /* BEGIN CSTYLED */ 8440Sstevel@tonic-gate if (symdef == 0) { 8451618Srie Lm_list *lml = LIST(lmp); 8461618Srie 8475220Srie if (sl.sl_bind != STB_WEAK) { 8481618Srie if (lml->lm_flags & 8490Sstevel@tonic-gate LML_FLG_IGNRELERR) { 8500Sstevel@tonic-gate continue; 8511618Srie } else if (lml->lm_flags & 8520Sstevel@tonic-gate LML_FLG_TRC_WARN) { 8530Sstevel@tonic-gate (void) printf(MSG_INTL( 8540Sstevel@tonic-gate MSG_LDD_SYM_NFOUND), 8550Sstevel@tonic-gate demangle(name), 8560Sstevel@tonic-gate NAME(lmp)); 8570Sstevel@tonic-gate continue; 8580Sstevel@tonic-gate } else { 8592145Srie DBG_CALL(Dbg_reloc_in(lml, 8602145Srie ELF_DBG_RTLD, M_MACH, 8612145Srie M_REL_SHT_TYPE, rel, 8622145Srie NULL, name)); 8631618Srie eprintf(lml, ERR_FATAL, 8640Sstevel@tonic-gate MSG_INTL(MSG_REL_NOSYM), 8650Sstevel@tonic-gate NAME(lmp), 8660Sstevel@tonic-gate demangle(name)); 8670Sstevel@tonic-gate ret = 0; 8680Sstevel@tonic-gate break; 8690Sstevel@tonic-gate } 8700Sstevel@tonic-gate } else { 8710Sstevel@tonic-gate psymndx = rsymndx; 8720Sstevel@tonic-gate psymdef = 0; 8730Sstevel@tonic-gate 8741618Srie DBG_CALL(Dbg_bind_weak(lmp, 8751618Srie (Addr)roffset, (Addr) 8760Sstevel@tonic-gate (roffset - basebgn), name)); 8770Sstevel@tonic-gate continue; 8780Sstevel@tonic-gate } 8790Sstevel@tonic-gate } 8804679Srie /* END CSTYLED */ 8810Sstevel@tonic-gate 8820Sstevel@tonic-gate /* 8830Sstevel@tonic-gate * If symbol was found in an object 8840Sstevel@tonic-gate * other than the referencing object 8850Sstevel@tonic-gate * then record the binding. 8860Sstevel@tonic-gate */ 8870Sstevel@tonic-gate if ((lmp != _lmp) && ((FLAGS1(_lmp) & 8880Sstevel@tonic-gate FL1_RT_NOINIFIN) == 0)) { 8895892Sab196087 if (aplist_test(&bound, _lmp, 8900Sstevel@tonic-gate AL_CNT_RELBIND) == 0) { 8910Sstevel@tonic-gate ret = 0; 8920Sstevel@tonic-gate break; 8930Sstevel@tonic-gate } 8940Sstevel@tonic-gate } 8950Sstevel@tonic-gate 8960Sstevel@tonic-gate /* 8970Sstevel@tonic-gate * Calculate the location of definition; 8980Sstevel@tonic-gate * symbol value plus base address of 8990Sstevel@tonic-gate * containing shared object. 9000Sstevel@tonic-gate */ 9012850Srie if (IS_SIZE(rtype)) 9022850Srie value = symdef->st_size; 9032850Srie else 9042850Srie value = symdef->st_value; 9052850Srie 9060Sstevel@tonic-gate if (!(FLAGS(_lmp) & FLG_RT_FIXED) && 9072850Srie !(IS_SIZE(rtype)) && 9080Sstevel@tonic-gate (symdef->st_shndx != SHN_ABS) && 9090Sstevel@tonic-gate (ELF_ST_TYPE(symdef->st_info) != 9100Sstevel@tonic-gate STT_TLS)) 9110Sstevel@tonic-gate value += ADDR(_lmp); 9120Sstevel@tonic-gate 9130Sstevel@tonic-gate /* 9140Sstevel@tonic-gate * Retain this symbol index and the 9150Sstevel@tonic-gate * value in case it can be used for the 9160Sstevel@tonic-gate * subsequent relocations. 9170Sstevel@tonic-gate */ 9180Sstevel@tonic-gate if (rtype != R_SPARC_COPY) { 9190Sstevel@tonic-gate psymndx = rsymndx; 9200Sstevel@tonic-gate pvalue = value; 9210Sstevel@tonic-gate pname = name; 9220Sstevel@tonic-gate psymdef = symdef; 9230Sstevel@tonic-gate psymref = symref; 9240Sstevel@tonic-gate plmp = _lmp; 9250Sstevel@tonic-gate pbinfo = binfo; 9260Sstevel@tonic-gate } 9270Sstevel@tonic-gate if ((LIST(_lmp)->lm_tflags | 9280Sstevel@tonic-gate FLAGS1(_lmp)) & 9290Sstevel@tonic-gate LML_TFLG_AUD_SYMBIND) { 9300Sstevel@tonic-gate dsymndx = (((uintptr_t)symdef - 9310Sstevel@tonic-gate (uintptr_t)SYMTAB(_lmp)) / 9320Sstevel@tonic-gate SYMENT(_lmp)); 9330Sstevel@tonic-gate value = audit_symbind(lmp, _lmp, 9340Sstevel@tonic-gate symdef, dsymndx, value, 9350Sstevel@tonic-gate &sb_flags); 9360Sstevel@tonic-gate } 9370Sstevel@tonic-gate } 9380Sstevel@tonic-gate 9390Sstevel@tonic-gate /* 9400Sstevel@tonic-gate * If relocation is PC-relative, subtract 9410Sstevel@tonic-gate * offset address. 9420Sstevel@tonic-gate */ 9430Sstevel@tonic-gate if (IS_PC_RELATIVE(rtype)) 9440Sstevel@tonic-gate value -= roffset; 9450Sstevel@tonic-gate 9460Sstevel@tonic-gate /* 9472145Srie * Special case TLS relocations. 9480Sstevel@tonic-gate */ 9492145Srie if (rtype == R_SPARC_TLS_DTPMOD32) { 9502145Srie /* 9512145Srie * Relocation value is the TLS modid. 9522145Srie */ 9530Sstevel@tonic-gate value = TLSMODID(_lmp); 9542145Srie 9552145Srie } else if (rtype == R_SPARC_TLS_TPOFF32) { 9562145Srie if ((value = elf_static_tls(_lmp, 9572145Srie symdef, rel, rtype, name, roffset, 9582145Srie value)) == 0) { 9592145Srie ret = 0; 9602145Srie break; 9612145Srie } 9622145Srie } 9630Sstevel@tonic-gate } 9640Sstevel@tonic-gate } else { 9650Sstevel@tonic-gate /* 9662145Srie * Special cases. 9670Sstevel@tonic-gate */ 9682145Srie if (rtype == R_SPARC_REGISTER) { 9692145Srie /* 9702145Srie * A register symbol associated with symbol 9712145Srie * index 0 is initialized (i.e. relocated) to 9722145Srie * a constant in the r_addend field rather than 9732145Srie * to a symbol value. 9742145Srie */ 9750Sstevel@tonic-gate value = 0; 9762145Srie 9772145Srie } else if (rtype == R_SPARC_TLS_DTPMOD32) { 9782145Srie /* 9792145Srie * TLS relocation value is the TLS modid. 9802145Srie */ 9810Sstevel@tonic-gate value = TLSMODID(lmp); 9822145Srie } else 9830Sstevel@tonic-gate value = basebgn; 9840Sstevel@tonic-gate name = (char *)0; 9850Sstevel@tonic-gate } 9860Sstevel@tonic-gate 9872145Srie DBG_CALL(Dbg_reloc_in(LIST(lmp), ELF_DBG_RTLD, M_MACH, 9882145Srie M_REL_SHT_TYPE, rel, NULL, name)); 9892145Srie 9900Sstevel@tonic-gate /* 9910Sstevel@tonic-gate * If this object has relocations in the text segment, turn 9920Sstevel@tonic-gate * off the write protect. 9930Sstevel@tonic-gate */ 9940Sstevel@tonic-gate if ((rtype != R_SPARC_REGISTER) && (roffset < etext) && 9950Sstevel@tonic-gate (textrel == 0)) { 9960Sstevel@tonic-gate if (elf_set_prot(lmp, PROT_WRITE) == 0) { 9970Sstevel@tonic-gate ret = 0; 9980Sstevel@tonic-gate break; 9990Sstevel@tonic-gate } 10000Sstevel@tonic-gate textrel = 1; 10010Sstevel@tonic-gate } 10020Sstevel@tonic-gate 10030Sstevel@tonic-gate /* 10040Sstevel@tonic-gate * Call relocation routine to perform required relocation. 10050Sstevel@tonic-gate */ 10060Sstevel@tonic-gate switch (rtype) { 10070Sstevel@tonic-gate case R_SPARC_REGISTER: 10080Sstevel@tonic-gate /* 10090Sstevel@tonic-gate * The v9 ABI 4.2.4 says that system objects may, 10100Sstevel@tonic-gate * but are not required to, use register symbols 10110Sstevel@tonic-gate * to inidcate how they use global registers. Thus 10120Sstevel@tonic-gate * at least %g6, %g7 must be allowed in addition 10130Sstevel@tonic-gate * to %g2 and %g3. 10140Sstevel@tonic-gate */ 10150Sstevel@tonic-gate value += reladd; 10160Sstevel@tonic-gate if (roffset == STO_SPARC_REGISTER_G1) { 10170Sstevel@tonic-gate set_sparc_g1(value); 10180Sstevel@tonic-gate } else if (roffset == STO_SPARC_REGISTER_G2) { 10190Sstevel@tonic-gate set_sparc_g2(value); 10200Sstevel@tonic-gate } else if (roffset == STO_SPARC_REGISTER_G3) { 10210Sstevel@tonic-gate set_sparc_g3(value); 10220Sstevel@tonic-gate } else if (roffset == STO_SPARC_REGISTER_G4) { 10230Sstevel@tonic-gate set_sparc_g4(value); 10240Sstevel@tonic-gate } else if (roffset == STO_SPARC_REGISTER_G5) { 10250Sstevel@tonic-gate set_sparc_g5(value); 10260Sstevel@tonic-gate } else if (roffset == STO_SPARC_REGISTER_G6) { 10270Sstevel@tonic-gate set_sparc_g6(value); 10280Sstevel@tonic-gate } else if (roffset == STO_SPARC_REGISTER_G7) { 10290Sstevel@tonic-gate set_sparc_g7(value); 10300Sstevel@tonic-gate } else { 10311618Srie eprintf(LIST(lmp), ERR_FATAL, 10321618Srie MSG_INTL(MSG_REL_BADREG), NAME(lmp), 10331618Srie EC_ADDR(roffset)); 10340Sstevel@tonic-gate ret = 0; 10350Sstevel@tonic-gate break; 10360Sstevel@tonic-gate } 10370Sstevel@tonic-gate 10381618Srie DBG_CALL(Dbg_reloc_apply_reg(LIST(lmp), ELF_DBG_RTLD, 10391618Srie M_MACH, (Xword)roffset, (Xword)value)); 10400Sstevel@tonic-gate break; 10410Sstevel@tonic-gate case R_SPARC_COPY: 10420Sstevel@tonic-gate if (elf_copy_reloc(name, symref, lmp, (void *)roffset, 10430Sstevel@tonic-gate symdef, _lmp, (const void *)value) == 0) 10440Sstevel@tonic-gate ret = 0; 10450Sstevel@tonic-gate break; 10460Sstevel@tonic-gate case R_SPARC_JMP_SLOT: 10470Sstevel@tonic-gate pltndx = ((ulong_t)rel - 10484679Srie (uintptr_t)JMPREL(lmp)) / relsiz; 10490Sstevel@tonic-gate 10500Sstevel@tonic-gate if (FLAGS(lmp) & FLG_RT_FIXED) 10510Sstevel@tonic-gate vaddr = 0; 10520Sstevel@tonic-gate else 10530Sstevel@tonic-gate vaddr = ADDR(lmp); 10540Sstevel@tonic-gate 10550Sstevel@tonic-gate if (((LIST(lmp)->lm_tflags | FLAGS1(lmp)) & 10560Sstevel@tonic-gate (LML_TFLG_AUD_PLTENTER | LML_TFLG_AUD_PLTEXIT)) && 10570Sstevel@tonic-gate AUDINFO(lmp)->ai_dynplts) { 10580Sstevel@tonic-gate int fail = 0; 10590Sstevel@tonic-gate ulong_t symndx = (((uintptr_t)symdef - 10604679Srie (uintptr_t)SYMTAB(_lmp)) / SYMENT(_lmp)); 10610Sstevel@tonic-gate 10620Sstevel@tonic-gate (void) elf_plt_trace_write((caddr_t)vaddr, 10630Sstevel@tonic-gate (Rela *)rel, lmp, _lmp, symdef, symndx, 10640Sstevel@tonic-gate pltndx, (caddr_t)value, sb_flags, &fail); 10650Sstevel@tonic-gate if (fail) 10660Sstevel@tonic-gate ret = 0; 10670Sstevel@tonic-gate } else { 10680Sstevel@tonic-gate /* 10690Sstevel@tonic-gate * Write standard PLT entry to jump directly 10700Sstevel@tonic-gate * to newly bound function. 10710Sstevel@tonic-gate */ 10721618Srie DBG_CALL(Dbg_reloc_apply_val(LIST(lmp), 10731618Srie ELF_DBG_RTLD, (Xword)roffset, 10740Sstevel@tonic-gate (Xword)value)); 10750Sstevel@tonic-gate pbtype = elf_plt_write((uintptr_t)vaddr, 10760Sstevel@tonic-gate (uintptr_t)vaddr, (void *)rel, value, 10770Sstevel@tonic-gate pltndx); 10780Sstevel@tonic-gate } 10790Sstevel@tonic-gate break; 10800Sstevel@tonic-gate default: 10810Sstevel@tonic-gate value += reladd; 10820Sstevel@tonic-gate 10830Sstevel@tonic-gate /* 10840Sstevel@tonic-gate * Write the relocation out. If this relocation is a 10850Sstevel@tonic-gate * common basic write, skip the doreloc() engine. 10860Sstevel@tonic-gate */ 10870Sstevel@tonic-gate if ((rtype == R_SPARC_GLOB_DAT) || 10880Sstevel@tonic-gate (rtype == R_SPARC_32)) { 10890Sstevel@tonic-gate if (roffset & 0x3) { 10904734Sab196087 Conv_inv_buf_t inv_buf; 10914734Sab196087 10921618Srie eprintf(LIST(lmp), ERR_FATAL, 10930Sstevel@tonic-gate MSG_INTL(MSG_REL_NONALIGN), 10944734Sab196087 conv_reloc_SPARC_type(rtype, 10954734Sab196087 0, &inv_buf), 10960Sstevel@tonic-gate NAME(lmp), demangle(name), 10970Sstevel@tonic-gate EC_OFF(roffset)); 10980Sstevel@tonic-gate ret = 0; 10990Sstevel@tonic-gate } else 11000Sstevel@tonic-gate *(uint_t *)roffset += value; 11010Sstevel@tonic-gate } else { 11025189Sab196087 if (do_reloc_rtld(rtype, (uchar_t *)roffset, 11031618Srie (Xword *)&value, name, 11041618Srie NAME(lmp), LIST(lmp)) == 0) 11050Sstevel@tonic-gate ret = 0; 11060Sstevel@tonic-gate } 11070Sstevel@tonic-gate 11080Sstevel@tonic-gate /* 11090Sstevel@tonic-gate * The value now contains the 'bit-shifted' value that 11105189Sab196087 * was or'ed into memory (this was set by 11115189Sab196087 * do_reloc_rtld()). 11120Sstevel@tonic-gate */ 11131618Srie DBG_CALL(Dbg_reloc_apply_val(LIST(lmp), ELF_DBG_RTLD, 11141618Srie (Xword)roffset, (Xword)value)); 11150Sstevel@tonic-gate 11160Sstevel@tonic-gate /* 11170Sstevel@tonic-gate * If this relocation is against a text segment, make 11180Sstevel@tonic-gate * sure that the instruction cache is flushed. 11190Sstevel@tonic-gate */ 11200Sstevel@tonic-gate if (textrel) 11210Sstevel@tonic-gate iflush_range((caddr_t)roffset, 0x4); 11220Sstevel@tonic-gate } 11230Sstevel@tonic-gate 11240Sstevel@tonic-gate if ((ret == 0) && 11250Sstevel@tonic-gate ((LIST(lmp)->lm_flags & LML_FLG_TRC_WARN) == 0)) 11260Sstevel@tonic-gate break; 11270Sstevel@tonic-gate 11280Sstevel@tonic-gate if (binfo) { 11291618Srie DBG_CALL(Dbg_bind_global(lmp, (Addr)roffset, 11301618Srie (Off)(roffset - basebgn), pltndx, pbtype, 11311618Srie _lmp, (Addr)value, symdef->st_value, name, binfo)); 11320Sstevel@tonic-gate } 11330Sstevel@tonic-gate } 11340Sstevel@tonic-gate 11350Sstevel@tonic-gate return (relocate_finish(lmp, bound, textrel, ret)); 11360Sstevel@tonic-gate } 11370Sstevel@tonic-gate 11380Sstevel@tonic-gate /* 11390Sstevel@tonic-gate * Provide a machine specific interface to the conversion routine. By calling 11400Sstevel@tonic-gate * the machine specific version, rather than the generic version, we insure that 11410Sstevel@tonic-gate * the data tables/strings for all known machine versions aren't dragged into 11420Sstevel@tonic-gate * ld.so.1. 11430Sstevel@tonic-gate */ 11440Sstevel@tonic-gate const char * 11451618Srie _conv_reloc_type(uint_t rel) 11460Sstevel@tonic-gate { 11474734Sab196087 static Conv_inv_buf_t inv_buf; 11484734Sab196087 11494734Sab196087 return (conv_reloc_SPARC_type(rel, 0, &inv_buf)); 11500Sstevel@tonic-gate } 1151