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 * 264679Srie * Copyright 2007 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 * x86 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_386.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 elf_rtbndr(Rt_map *, ulong_t, caddr_t); 540Sstevel@tonic-gate 550Sstevel@tonic-gate int 560Sstevel@tonic-gate elf_mach_flags_check(Rej_desc *rej, Ehdr *ehdr) 570Sstevel@tonic-gate { 580Sstevel@tonic-gate /* 590Sstevel@tonic-gate * Check machine type and flags. 600Sstevel@tonic-gate */ 610Sstevel@tonic-gate if (ehdr->e_flags != 0) { 620Sstevel@tonic-gate rej->rej_type = SGS_REJ_BADFLAG; 630Sstevel@tonic-gate rej->rej_info = (uint_t)ehdr->e_flags; 640Sstevel@tonic-gate return (0); 650Sstevel@tonic-gate } 660Sstevel@tonic-gate return (1); 670Sstevel@tonic-gate } 680Sstevel@tonic-gate 690Sstevel@tonic-gate void 700Sstevel@tonic-gate ldso_plt_init(Rt_map * lmp) 710Sstevel@tonic-gate { 720Sstevel@tonic-gate /* 730Sstevel@tonic-gate * There is no need to analyze ld.so because we don't map in any of 740Sstevel@tonic-gate * its dependencies. However we may map these dependencies in later 750Sstevel@tonic-gate * (as if ld.so had dlopened them), so initialize the plt and the 760Sstevel@tonic-gate * permission information. 770Sstevel@tonic-gate */ 780Sstevel@tonic-gate if (PLTGOT(lmp)) 790Sstevel@tonic-gate elf_plt_init((PLTGOT(lmp)), (caddr_t)lmp); 800Sstevel@tonic-gate } 810Sstevel@tonic-gate 820Sstevel@tonic-gate static const uchar_t dyn_plt_template[] = { 830Sstevel@tonic-gate /* 0x00 */ 0x55, /* pushl %ebp */ 840Sstevel@tonic-gate /* 0x01 */ 0x8b, 0xec, /* movl %esp, %ebp */ 850Sstevel@tonic-gate /* 0x03 */ 0x68, 0x00, 0x00, 0x00, 0x00, /* pushl trace_fields */ 860Sstevel@tonic-gate /* 0x08 */ 0xe9, 0xfc, 0xff, 0xff, 0xff, 0xff /* jmp elf_plt_trace */ 870Sstevel@tonic-gate }; 880Sstevel@tonic-gate int dyn_plt_ent_size = sizeof (dyn_plt_template); 890Sstevel@tonic-gate 900Sstevel@tonic-gate /* 910Sstevel@tonic-gate * the dynamic plt entry is: 920Sstevel@tonic-gate * 930Sstevel@tonic-gate * pushl %ebp 940Sstevel@tonic-gate * movl %esp, %ebp 950Sstevel@tonic-gate * pushl tfp 960Sstevel@tonic-gate * jmp elf_plt_trace 970Sstevel@tonic-gate * dyn_data: 980Sstevel@tonic-gate * .align 4 990Sstevel@tonic-gate * uintptr_t reflmp 1000Sstevel@tonic-gate * uintptr_t deflmp 1010Sstevel@tonic-gate * uint_t symndx 1020Sstevel@tonic-gate * uint_t sb_flags 1030Sstevel@tonic-gate * Sym symdef 1040Sstevel@tonic-gate */ 1050Sstevel@tonic-gate static caddr_t 1060Sstevel@tonic-gate elf_plt_trace_write(uint_t roffset, Rt_map *rlmp, Rt_map *dlmp, Sym *sym, 1070Sstevel@tonic-gate uint_t symndx, uint_t pltndx, caddr_t to, uint_t sb_flags, int *fail) 1080Sstevel@tonic-gate { 1090Sstevel@tonic-gate extern int elf_plt_trace(); 1100Sstevel@tonic-gate ulong_t got_entry; 1110Sstevel@tonic-gate uchar_t *dyn_plt; 1120Sstevel@tonic-gate uintptr_t *dyndata; 1130Sstevel@tonic-gate 1140Sstevel@tonic-gate /* 1150Sstevel@tonic-gate * We only need to add the glue code if there is an auditing 1160Sstevel@tonic-gate * library that is interested in this binding. 1170Sstevel@tonic-gate */ 1180Sstevel@tonic-gate dyn_plt = (uchar_t *)((uintptr_t)AUDINFO(rlmp)->ai_dynplts + 1191618Srie (pltndx * dyn_plt_ent_size)); 1200Sstevel@tonic-gate 1210Sstevel@tonic-gate /* 1220Sstevel@tonic-gate * Have we initialized this dynamic plt entry yet? If we haven't do it 1230Sstevel@tonic-gate * now. Otherwise this function has been called before, but from a 1240Sstevel@tonic-gate * different plt (ie. from another shared object). In that case 1250Sstevel@tonic-gate * we just set the plt to point to the new dyn_plt. 1260Sstevel@tonic-gate */ 1270Sstevel@tonic-gate if (*dyn_plt == 0) { 1281618Srie Sym *symp; 1290Sstevel@tonic-gate Word symvalue; 1301618Srie Lm_list *lml = LIST(rlmp); 1310Sstevel@tonic-gate 1320Sstevel@tonic-gate (void) memcpy((void *)dyn_plt, dyn_plt_template, 1330Sstevel@tonic-gate sizeof (dyn_plt_template)); 1340Sstevel@tonic-gate dyndata = (uintptr_t *)((uintptr_t)dyn_plt + 1350Sstevel@tonic-gate ROUND(sizeof (dyn_plt_template), M_WORD_ALIGN)); 1360Sstevel@tonic-gate 1370Sstevel@tonic-gate /* 1380Sstevel@tonic-gate * relocate: 1390Sstevel@tonic-gate * pushl dyn_data 1400Sstevel@tonic-gate */ 1410Sstevel@tonic-gate symvalue = (Word)dyndata; 142*5189Sab196087 if (do_reloc_rtld(R_386_32, &dyn_plt[4], &symvalue, 1430Sstevel@tonic-gate MSG_ORIG(MSG_SYM_LADYNDATA), 1441618Srie MSG_ORIG(MSG_SPECFIL_DYNPLT), lml) == 0) { 1450Sstevel@tonic-gate *fail = 1; 1460Sstevel@tonic-gate return (0); 1470Sstevel@tonic-gate } 1480Sstevel@tonic-gate 1490Sstevel@tonic-gate /* 1500Sstevel@tonic-gate * jmps are relative, so I need to figure out the relative 1510Sstevel@tonic-gate * address to elf_plt_trace. 1520Sstevel@tonic-gate * 1530Sstevel@tonic-gate * relocating: 1540Sstevel@tonic-gate * jmp elf_plt_trace 1550Sstevel@tonic-gate */ 1560Sstevel@tonic-gate symvalue = (ulong_t)(elf_plt_trace) - (ulong_t)(dyn_plt + 9); 157*5189Sab196087 if (do_reloc_rtld(R_386_PC32, &dyn_plt[9], &symvalue, 1580Sstevel@tonic-gate MSG_ORIG(MSG_SYM_ELFPLTTRACE), 1591618Srie MSG_ORIG(MSG_SPECFIL_DYNPLT), lml) == 0) { 1600Sstevel@tonic-gate *fail = 1; 1610Sstevel@tonic-gate return (0); 1620Sstevel@tonic-gate } 1630Sstevel@tonic-gate 1640Sstevel@tonic-gate *dyndata++ = (uintptr_t)rlmp; 1650Sstevel@tonic-gate *dyndata++ = (uintptr_t)dlmp; 1660Sstevel@tonic-gate *dyndata++ = (uint_t)symndx; 1670Sstevel@tonic-gate *dyndata++ = (uint_t)sb_flags; 1680Sstevel@tonic-gate symp = (Sym *)dyndata; 1690Sstevel@tonic-gate *symp = *sym; 1700Sstevel@tonic-gate symp->st_name += (Word)STRTAB(dlmp); 1710Sstevel@tonic-gate symp->st_value = (Addr)to; 1720Sstevel@tonic-gate } 1730Sstevel@tonic-gate 1740Sstevel@tonic-gate got_entry = (ulong_t)roffset; 1750Sstevel@tonic-gate *(ulong_t *)got_entry = (ulong_t)dyn_plt; 1760Sstevel@tonic-gate return ((caddr_t)dyn_plt); 1770Sstevel@tonic-gate } 1780Sstevel@tonic-gate 1790Sstevel@tonic-gate 1800Sstevel@tonic-gate /* 1810Sstevel@tonic-gate * Function binding routine - invoked on the first call to a function through 1820Sstevel@tonic-gate * the procedure linkage table; 1830Sstevel@tonic-gate * passes first through an assembly language interface. 1840Sstevel@tonic-gate * 1850Sstevel@tonic-gate * Takes the offset into the relocation table of the associated 1860Sstevel@tonic-gate * relocation entry and the address of the link map (rt_private_map struct) 1870Sstevel@tonic-gate * for the entry. 1880Sstevel@tonic-gate * 1890Sstevel@tonic-gate * Returns the address of the function referenced after re-writing the PLT 1900Sstevel@tonic-gate * entry to invoke the function directly. 1910Sstevel@tonic-gate * 1920Sstevel@tonic-gate * On error, causes process to terminate with a signal. 1930Sstevel@tonic-gate */ 1940Sstevel@tonic-gate ulong_t 1950Sstevel@tonic-gate elf_bndr(Rt_map *lmp, ulong_t reloff, caddr_t from) 1960Sstevel@tonic-gate { 1971618Srie Rt_map *nlmp, *llmp; 1980Sstevel@tonic-gate ulong_t addr, symval, rsymndx; 1990Sstevel@tonic-gate char *name; 2000Sstevel@tonic-gate Rel *rptr; 2010Sstevel@tonic-gate Sym *sym, *nsym; 2021618Srie uint_t binfo, sb_flags = 0, dbg_class; 2030Sstevel@tonic-gate Slookup sl; 2041618Srie int entry, lmflags; 2051618Srie Lm_list *lml; 2060Sstevel@tonic-gate 2070Sstevel@tonic-gate /* 2080Sstevel@tonic-gate * For compatibility with libthread (TI_VERSION 1) we track the entry 2090Sstevel@tonic-gate * value. A zero value indicates we have recursed into ld.so.1 to 2100Sstevel@tonic-gate * further process a locking request. Under this recursion we disable 2110Sstevel@tonic-gate * tsort and cleanup activities. 2120Sstevel@tonic-gate */ 2130Sstevel@tonic-gate entry = enter(); 2140Sstevel@tonic-gate 2151618Srie lml = LIST(lmp); 2161618Srie if ((lmflags = lml->lm_flags) & LML_FLG_RTLDLM) { 2171618Srie dbg_class = dbg_desc->d_class; 2181618Srie dbg_desc->d_class = 0; 2190Sstevel@tonic-gate } 2200Sstevel@tonic-gate 2210Sstevel@tonic-gate /* 2220Sstevel@tonic-gate * Perform some basic sanity checks. If we didn't get a load map or 2230Sstevel@tonic-gate * the relocation offset is invalid then its possible someone has walked 2240Sstevel@tonic-gate * over the .got entries or jumped to plt0 out of the blue. 2250Sstevel@tonic-gate */ 2260Sstevel@tonic-gate if (!lmp || ((reloff % sizeof (Rel)) != 0)) { 2274734Sab196087 Conv_inv_buf_t inv_buf; 2284734Sab196087 2291618Srie eprintf(lml, ERR_FATAL, MSG_INTL(MSG_REL_PLTREF), 2304734Sab196087 conv_reloc_386_type(R_386_JMP_SLOT, 0, &inv_buf), 2311618Srie EC_NATPTR(lmp), EC_XWORD(reloff), EC_NATPTR(from)); 2321618Srie rtldexit(lml, 1); 2330Sstevel@tonic-gate } 2340Sstevel@tonic-gate 2350Sstevel@tonic-gate /* 2360Sstevel@tonic-gate * Use relocation entry to get symbol table entry and symbol name. 2370Sstevel@tonic-gate */ 2380Sstevel@tonic-gate addr = (ulong_t)JMPREL(lmp); 2390Sstevel@tonic-gate rptr = (Rel *)(addr + reloff); 2400Sstevel@tonic-gate rsymndx = ELF_R_SYM(rptr->r_info); 2410Sstevel@tonic-gate sym = (Sym *)((ulong_t)SYMTAB(lmp) + (rsymndx * SYMENT(lmp))); 2420Sstevel@tonic-gate name = (char *)(STRTAB(lmp) + sym->st_name); 2430Sstevel@tonic-gate 2440Sstevel@tonic-gate /* 2450Sstevel@tonic-gate * Determine the last link-map of this list, this'll be the starting 2460Sstevel@tonic-gate * point for any tsort() processing. 2470Sstevel@tonic-gate */ 2481618Srie llmp = lml->lm_tail; 2490Sstevel@tonic-gate 2500Sstevel@tonic-gate /* 2510Sstevel@tonic-gate * Find definition for symbol. 2520Sstevel@tonic-gate */ 2530Sstevel@tonic-gate sl.sl_name = name; 2540Sstevel@tonic-gate sl.sl_cmap = lmp; 2551618Srie sl.sl_imap = lml->lm_head; 2560Sstevel@tonic-gate sl.sl_hash = 0; 2570Sstevel@tonic-gate sl.sl_rsymndx = rsymndx; 2580Sstevel@tonic-gate sl.sl_flags = LKUP_DEFT; 2590Sstevel@tonic-gate 2600Sstevel@tonic-gate if ((nsym = lookup_sym(&sl, &nlmp, &binfo)) == 0) { 2611618Srie eprintf(lml, ERR_FATAL, MSG_INTL(MSG_REL_NOSYM), NAME(lmp), 2620Sstevel@tonic-gate demangle(name)); 2631618Srie rtldexit(lml, 1); 2640Sstevel@tonic-gate } 2650Sstevel@tonic-gate 2660Sstevel@tonic-gate symval = nsym->st_value; 2670Sstevel@tonic-gate if (!(FLAGS(nlmp) & FLG_RT_FIXED) && 2680Sstevel@tonic-gate (nsym->st_shndx != SHN_ABS)) 2690Sstevel@tonic-gate symval += ADDR(nlmp); 2700Sstevel@tonic-gate if ((lmp != nlmp) && ((FLAGS1(nlmp) & FL1_RT_NOINIFIN) == 0)) { 2710Sstevel@tonic-gate /* 2720Sstevel@tonic-gate * Record that this new link map is now bound to the caller. 2730Sstevel@tonic-gate */ 2740Sstevel@tonic-gate if (bind_one(lmp, nlmp, BND_REFER) == 0) 2751618Srie rtldexit(lml, 1); 2760Sstevel@tonic-gate } 2770Sstevel@tonic-gate 2781618Srie if ((lml->lm_tflags | FLAGS1(lmp)) & LML_TFLG_AUD_SYMBIND) { 2790Sstevel@tonic-gate uint_t symndx = (((uintptr_t)nsym - 2804679Srie (uintptr_t)SYMTAB(nlmp)) / SYMENT(nlmp)); 2810Sstevel@tonic-gate symval = audit_symbind(lmp, nlmp, nsym, symndx, symval, 2824679Srie &sb_flags); 2830Sstevel@tonic-gate } 2840Sstevel@tonic-gate 2850Sstevel@tonic-gate if (!(rtld_flags & RT_FL_NOBIND)) { 2860Sstevel@tonic-gate addr = rptr->r_offset; 2870Sstevel@tonic-gate if (!(FLAGS(lmp) & FLG_RT_FIXED)) 2880Sstevel@tonic-gate addr += ADDR(lmp); 2891618Srie if (((lml->lm_tflags | FLAGS1(lmp)) & 2900Sstevel@tonic-gate (LML_TFLG_AUD_PLTENTER | LML_TFLG_AUD_PLTEXIT)) && 2910Sstevel@tonic-gate AUDINFO(lmp)->ai_dynplts) { 2920Sstevel@tonic-gate int fail = 0; 2930Sstevel@tonic-gate uint_t pltndx = reloff / sizeof (Rel); 2940Sstevel@tonic-gate uint_t symndx = (((uintptr_t)nsym - 2954679Srie (uintptr_t)SYMTAB(nlmp)) / SYMENT(nlmp)); 2960Sstevel@tonic-gate 2970Sstevel@tonic-gate symval = (ulong_t)elf_plt_trace_write(addr, lmp, nlmp, 2980Sstevel@tonic-gate nsym, symndx, pltndx, (caddr_t)symval, sb_flags, 2990Sstevel@tonic-gate &fail); 3000Sstevel@tonic-gate if (fail) 3011618Srie rtldexit(lml, 1); 3020Sstevel@tonic-gate } else { 3030Sstevel@tonic-gate /* 3040Sstevel@tonic-gate * Write standard PLT entry to jump directly 3050Sstevel@tonic-gate * to newly bound function. 3060Sstevel@tonic-gate */ 3070Sstevel@tonic-gate *(ulong_t *)addr = symval; 3080Sstevel@tonic-gate } 3090Sstevel@tonic-gate } 3100Sstevel@tonic-gate 3110Sstevel@tonic-gate /* 3120Sstevel@tonic-gate * Print binding information and rebuild PLT entry. 3130Sstevel@tonic-gate */ 3141618Srie DBG_CALL(Dbg_bind_global(lmp, (Addr)from, (Off)(from - ADDR(lmp)), 3151618Srie (Xword)(reloff / sizeof (Rel)), PLT_T_FULL, nlmp, (Addr)symval, 3161618Srie nsym->st_value, name, binfo)); 3170Sstevel@tonic-gate 3180Sstevel@tonic-gate /* 3190Sstevel@tonic-gate * Complete any processing for newly loaded objects. Note we don't 3200Sstevel@tonic-gate * know exactly where any new objects are loaded (we know the object 3210Sstevel@tonic-gate * that supplied the symbol, but others may have been loaded lazily as 3220Sstevel@tonic-gate * we searched for the symbol), so sorting starts from the last 3230Sstevel@tonic-gate * link-map know on entry to this routine. 3240Sstevel@tonic-gate */ 3250Sstevel@tonic-gate if (entry) 3264679Srie load_completion(llmp); 3270Sstevel@tonic-gate 3280Sstevel@tonic-gate /* 3290Sstevel@tonic-gate * Some operations like dldump() or dlopen()'ing a relocatable object 3300Sstevel@tonic-gate * result in objects being loaded on rtld's link-map, make sure these 3310Sstevel@tonic-gate * objects are initialized also. 3320Sstevel@tonic-gate */ 3330Sstevel@tonic-gate if ((LIST(nlmp)->lm_flags & LML_FLG_RTLDLM) && LIST(nlmp)->lm_init) 3344679Srie load_completion(nlmp); 3350Sstevel@tonic-gate 3360Sstevel@tonic-gate /* 3370Sstevel@tonic-gate * If the object we've bound to is in the process of being initialized 3380Sstevel@tonic-gate * by another thread, determine whether we should block. 3390Sstevel@tonic-gate */ 3400Sstevel@tonic-gate is_dep_ready(nlmp, lmp, DBG_WAIT_SYMBOL); 3410Sstevel@tonic-gate 3420Sstevel@tonic-gate /* 3430Sstevel@tonic-gate * Make sure the object to which we've bound has had it's .init fired. 3440Sstevel@tonic-gate * Cleanup before return to user code. 3450Sstevel@tonic-gate */ 3460Sstevel@tonic-gate if (entry) { 3470Sstevel@tonic-gate is_dep_init(nlmp, lmp); 3481618Srie leave(lml); 3490Sstevel@tonic-gate } 3500Sstevel@tonic-gate 3510Sstevel@tonic-gate if (lmflags & LML_FLG_RTLDLM) 3521618Srie dbg_desc->d_class = dbg_class; 3530Sstevel@tonic-gate 3540Sstevel@tonic-gate return (symval); 3550Sstevel@tonic-gate } 3560Sstevel@tonic-gate 3570Sstevel@tonic-gate 3580Sstevel@tonic-gate /* 3590Sstevel@tonic-gate * When the relocation loop realizes that it's dealing with relative 3600Sstevel@tonic-gate * relocations in a shared object, it breaks into this tighter loop 3610Sstevel@tonic-gate * as an optimization. 3620Sstevel@tonic-gate */ 3630Sstevel@tonic-gate ulong_t 3640Sstevel@tonic-gate elf_reloc_relative(ulong_t relbgn, ulong_t relend, ulong_t relsiz, 3650Sstevel@tonic-gate ulong_t basebgn, ulong_t etext, ulong_t emap) 3660Sstevel@tonic-gate { 3670Sstevel@tonic-gate ulong_t roffset = ((Rel *)relbgn)->r_offset; 3680Sstevel@tonic-gate char rtype; 3690Sstevel@tonic-gate 3700Sstevel@tonic-gate do { 3710Sstevel@tonic-gate roffset += basebgn; 3720Sstevel@tonic-gate 3730Sstevel@tonic-gate /* 3740Sstevel@tonic-gate * If this relocation is against an address not mapped in, 3750Sstevel@tonic-gate * then break out of the relative relocation loop, falling 3760Sstevel@tonic-gate * back on the main relocation loop. 3770Sstevel@tonic-gate */ 3780Sstevel@tonic-gate if (roffset < etext || roffset > emap) 3790Sstevel@tonic-gate break; 3800Sstevel@tonic-gate 3810Sstevel@tonic-gate /* 3820Sstevel@tonic-gate * Perform the actual relocation. 3830Sstevel@tonic-gate */ 3840Sstevel@tonic-gate *((ulong_t *)roffset) += basebgn; 3850Sstevel@tonic-gate 3860Sstevel@tonic-gate relbgn += relsiz; 3870Sstevel@tonic-gate 3880Sstevel@tonic-gate if (relbgn >= relend) 3890Sstevel@tonic-gate break; 3900Sstevel@tonic-gate 3910Sstevel@tonic-gate rtype = ELF_R_TYPE(((Rel *)relbgn)->r_info); 3920Sstevel@tonic-gate roffset = ((Rel *)relbgn)->r_offset; 3930Sstevel@tonic-gate 3940Sstevel@tonic-gate } while (rtype == R_386_RELATIVE); 3950Sstevel@tonic-gate 3960Sstevel@tonic-gate return (relbgn); 3970Sstevel@tonic-gate } 3980Sstevel@tonic-gate 3990Sstevel@tonic-gate /* 4000Sstevel@tonic-gate * This is the tightest loop for RELATIVE relocations for those 4010Sstevel@tonic-gate * objects built with the DT_RELACOUNT .dynamic entry. 4020Sstevel@tonic-gate */ 4030Sstevel@tonic-gate ulong_t 4040Sstevel@tonic-gate elf_reloc_relacount(ulong_t relbgn, ulong_t relacount, ulong_t relsiz, 4050Sstevel@tonic-gate ulong_t basebgn) 4060Sstevel@tonic-gate { 4070Sstevel@tonic-gate ulong_t roffset = ((Rel *) relbgn)->r_offset; 4080Sstevel@tonic-gate 4090Sstevel@tonic-gate for (; relacount; relacount--) { 4100Sstevel@tonic-gate roffset += basebgn; 4110Sstevel@tonic-gate 4120Sstevel@tonic-gate /* 4130Sstevel@tonic-gate * Perform the actual relocation. 4140Sstevel@tonic-gate */ 4150Sstevel@tonic-gate *((ulong_t *)roffset) += basebgn; 4160Sstevel@tonic-gate 4170Sstevel@tonic-gate relbgn += relsiz; 4180Sstevel@tonic-gate 4190Sstevel@tonic-gate roffset = ((Rel *)relbgn)->r_offset; 4200Sstevel@tonic-gate 4210Sstevel@tonic-gate } 4220Sstevel@tonic-gate 4230Sstevel@tonic-gate return (relbgn); 4240Sstevel@tonic-gate } 4250Sstevel@tonic-gate 4260Sstevel@tonic-gate /* 4270Sstevel@tonic-gate * Read and process the relocations for one link object, we assume all 4280Sstevel@tonic-gate * relocation sections for loadable segments are stored contiguously in 4290Sstevel@tonic-gate * the file. 4300Sstevel@tonic-gate */ 4310Sstevel@tonic-gate int 4320Sstevel@tonic-gate elf_reloc(Rt_map *lmp, uint_t plt) 4330Sstevel@tonic-gate { 4340Sstevel@tonic-gate ulong_t relbgn, relend, relsiz, basebgn; 4350Sstevel@tonic-gate ulong_t pltbgn, pltend, _pltbgn, _pltend; 4360Sstevel@tonic-gate ulong_t roffset, rsymndx, psymndx = 0, etext = ETEXT(lmp); 4370Sstevel@tonic-gate ulong_t emap, dsymndx; 4380Sstevel@tonic-gate uchar_t rtype; 4390Sstevel@tonic-gate long value, pvalue; 4400Sstevel@tonic-gate Sym *symref, *psymref, *symdef, *psymdef; 4410Sstevel@tonic-gate char *name, *pname; 4420Sstevel@tonic-gate Rt_map *_lmp, *plmp; 4430Sstevel@tonic-gate int textrel = 0, ret = 1, noplt = 0; 4440Sstevel@tonic-gate int relacount = RELACOUNT(lmp), plthint = 0; 4450Sstevel@tonic-gate Rel *rel; 4460Sstevel@tonic-gate uint_t binfo, pbinfo; 4470Sstevel@tonic-gate Alist *bound = 0; 4480Sstevel@tonic-gate 4490Sstevel@tonic-gate /* 4500Sstevel@tonic-gate * Although only necessary for lazy binding, initialize the first 4510Sstevel@tonic-gate * global offset entry to go to elf_rtbndr(). dbx(1) seems 4520Sstevel@tonic-gate * to find this useful. 4530Sstevel@tonic-gate */ 4540Sstevel@tonic-gate if ((plt == 0) && PLTGOT(lmp)) { 4550Sstevel@tonic-gate if ((ulong_t)PLTGOT(lmp) < etext) { 4560Sstevel@tonic-gate if (elf_set_prot(lmp, PROT_WRITE) == 0) 4570Sstevel@tonic-gate return (0); 4580Sstevel@tonic-gate textrel = 1; 4590Sstevel@tonic-gate } 4600Sstevel@tonic-gate elf_plt_init(PLTGOT(lmp), (caddr_t)lmp); 4610Sstevel@tonic-gate } 4620Sstevel@tonic-gate 4630Sstevel@tonic-gate /* 4640Sstevel@tonic-gate * Initialize the plt start and end addresses. 4650Sstevel@tonic-gate */ 4660Sstevel@tonic-gate if ((pltbgn = (ulong_t)JMPREL(lmp)) != 0) 4670Sstevel@tonic-gate pltend = pltbgn + (ulong_t)(PLTRELSZ(lmp)); 4680Sstevel@tonic-gate 4690Sstevel@tonic-gate 4700Sstevel@tonic-gate relsiz = (ulong_t)(RELENT(lmp)); 4710Sstevel@tonic-gate basebgn = ADDR(lmp); 4720Sstevel@tonic-gate emap = ADDR(lmp) + MSIZE(lmp); 4730Sstevel@tonic-gate 4740Sstevel@tonic-gate if (PLTRELSZ(lmp)) 4750Sstevel@tonic-gate plthint = PLTRELSZ(lmp) / relsiz; 4760Sstevel@tonic-gate 4770Sstevel@tonic-gate /* 4780Sstevel@tonic-gate * If we've been called upon to promote an RTLD_LAZY object to an 4790Sstevel@tonic-gate * RTLD_NOW then we're only interested in scaning the .plt table. 4800Sstevel@tonic-gate * An uninitialized .plt is the case where the associated got entry 4810Sstevel@tonic-gate * points back to the plt itself. Determine the range of the real .plt 4820Sstevel@tonic-gate * entries using the _PROCEDURE_LINKAGE_TABLE_ symbol. 4830Sstevel@tonic-gate */ 4840Sstevel@tonic-gate if (plt) { 4850Sstevel@tonic-gate Slookup sl; 4860Sstevel@tonic-gate 4870Sstevel@tonic-gate relbgn = pltbgn; 4880Sstevel@tonic-gate relend = pltend; 4890Sstevel@tonic-gate if (!relbgn || (relbgn == relend)) 4900Sstevel@tonic-gate return (1); 4910Sstevel@tonic-gate 4920Sstevel@tonic-gate sl.sl_name = MSG_ORIG(MSG_SYM_PLT); 4930Sstevel@tonic-gate sl.sl_cmap = lmp; 4940Sstevel@tonic-gate sl.sl_imap = lmp; 495546Srie sl.sl_hash = elf_hash(MSG_ORIG(MSG_SYM_PLT)); 4960Sstevel@tonic-gate sl.sl_rsymndx = 0; 4970Sstevel@tonic-gate sl.sl_flags = LKUP_DEFT; 4980Sstevel@tonic-gate 4990Sstevel@tonic-gate if ((symdef = elf_find_sym(&sl, &_lmp, &binfo)) == 0) 5000Sstevel@tonic-gate return (1); 5010Sstevel@tonic-gate 5020Sstevel@tonic-gate _pltbgn = symdef->st_value; 5030Sstevel@tonic-gate if (!(FLAGS(lmp) & FLG_RT_FIXED) && 5040Sstevel@tonic-gate (symdef->st_shndx != SHN_ABS)) 5050Sstevel@tonic-gate _pltbgn += basebgn; 5060Sstevel@tonic-gate _pltend = _pltbgn + (((PLTRELSZ(lmp) / relsiz)) * 5074679Srie M_PLT_ENTSIZE) + M_PLT_RESERVSZ; 5080Sstevel@tonic-gate 5090Sstevel@tonic-gate } else { 5100Sstevel@tonic-gate /* 5110Sstevel@tonic-gate * The relocation sections appear to the run-time linker as a 5120Sstevel@tonic-gate * single table. Determine the address of the beginning and end 5130Sstevel@tonic-gate * of this table. There are two different interpretations of 5140Sstevel@tonic-gate * the ABI at this point: 5150Sstevel@tonic-gate * 5160Sstevel@tonic-gate * o The REL table and its associated RELSZ indicate the 5170Sstevel@tonic-gate * concatenation of *all* relocation sections (this is the 5180Sstevel@tonic-gate * model our link-editor constructs). 5190Sstevel@tonic-gate * 5200Sstevel@tonic-gate * o The REL table and its associated RELSZ indicate the 5210Sstevel@tonic-gate * concatenation of all *but* the .plt relocations. These 5220Sstevel@tonic-gate * relocations are specified individually by the JMPREL and 5230Sstevel@tonic-gate * PLTRELSZ entries. 5240Sstevel@tonic-gate * 5250Sstevel@tonic-gate * Determine from our knowledege of the relocation range and 5260Sstevel@tonic-gate * .plt range, the range of the total relocation table. Note 5270Sstevel@tonic-gate * that one other ABI assumption seems to be that the .plt 5280Sstevel@tonic-gate * relocations always follow any other relocations, the 5290Sstevel@tonic-gate * following range checking drops that assumption. 5300Sstevel@tonic-gate */ 5310Sstevel@tonic-gate relbgn = (ulong_t)(REL(lmp)); 5320Sstevel@tonic-gate relend = relbgn + (ulong_t)(RELSZ(lmp)); 5330Sstevel@tonic-gate if (pltbgn) { 5340Sstevel@tonic-gate if (!relbgn || (relbgn > pltbgn)) 5350Sstevel@tonic-gate relbgn = pltbgn; 5360Sstevel@tonic-gate if (!relbgn || (relend < pltend)) 5370Sstevel@tonic-gate relend = pltend; 5380Sstevel@tonic-gate } 5390Sstevel@tonic-gate } 5400Sstevel@tonic-gate if (!relbgn || (relbgn == relend)) { 5411618Srie DBG_CALL(Dbg_reloc_run(lmp, 0, plt, DBG_REL_NONE)); 5420Sstevel@tonic-gate return (1); 5430Sstevel@tonic-gate } 5441618Srie DBG_CALL(Dbg_reloc_run(lmp, M_REL_SHT_TYPE, plt, DBG_REL_START)); 5450Sstevel@tonic-gate 5460Sstevel@tonic-gate /* 5470Sstevel@tonic-gate * If we're processing a dynamic executable in lazy mode there is no 5480Sstevel@tonic-gate * need to scan the .rel.plt table, however if we're processing a shared 5490Sstevel@tonic-gate * object in lazy mode the .got addresses associated to each .plt must 5500Sstevel@tonic-gate * be relocated to reflect the location of the shared object. 5510Sstevel@tonic-gate */ 5520Sstevel@tonic-gate if (pltbgn && ((MODE(lmp) & RTLD_NOW) == 0) && 5530Sstevel@tonic-gate (FLAGS(lmp) & FLG_RT_FIXED)) 5540Sstevel@tonic-gate noplt = 1; 5550Sstevel@tonic-gate 5560Sstevel@tonic-gate /* 5570Sstevel@tonic-gate * Loop through relocations. 5580Sstevel@tonic-gate */ 5590Sstevel@tonic-gate while (relbgn < relend) { 5600Sstevel@tonic-gate uint_t sb_flags = 0; 5610Sstevel@tonic-gate 5620Sstevel@tonic-gate rtype = ELF_R_TYPE(((Rel *)relbgn)->r_info); 5630Sstevel@tonic-gate 5640Sstevel@tonic-gate /* 5650Sstevel@tonic-gate * If this is a RELATIVE relocation in a shared object (the 5660Sstevel@tonic-gate * common case), and if we are not debugging, then jump into a 5670Sstevel@tonic-gate * tighter relocation loop (elf_reloc_relative). Only make the 5680Sstevel@tonic-gate * jump if we've been given a hint on the number of relocations. 5690Sstevel@tonic-gate */ 5700Sstevel@tonic-gate if ((rtype == R_386_RELATIVE) && 5711618Srie ((FLAGS(lmp) & FLG_RT_FIXED) == 0) && (DBG_ENABLED == 0)) { 5720Sstevel@tonic-gate /* 5730Sstevel@tonic-gate * It's possible that the relative relocation block 5740Sstevel@tonic-gate * has relocations against the text segment as well 5750Sstevel@tonic-gate * as the data segment. Since our optimized relocation 5760Sstevel@tonic-gate * engine does not check which segment the relocation 5770Sstevel@tonic-gate * is against - just mprotect it now if it's been 5780Sstevel@tonic-gate * marked as containing TEXTREL's. 5790Sstevel@tonic-gate */ 5800Sstevel@tonic-gate if ((textrel == 0) && (FLAGS1(lmp) & FL1_RT_TEXTREL)) { 5810Sstevel@tonic-gate if (elf_set_prot(lmp, PROT_WRITE) == 0) { 5820Sstevel@tonic-gate ret = 0; 5830Sstevel@tonic-gate break; 5840Sstevel@tonic-gate } 5850Sstevel@tonic-gate textrel = 1; 5860Sstevel@tonic-gate } 5872145Srie 5880Sstevel@tonic-gate if (relacount) { 5890Sstevel@tonic-gate relbgn = elf_reloc_relacount(relbgn, relacount, 5900Sstevel@tonic-gate relsiz, basebgn); 5910Sstevel@tonic-gate relacount = 0; 5920Sstevel@tonic-gate } else { 5930Sstevel@tonic-gate relbgn = elf_reloc_relative(relbgn, relend, 5940Sstevel@tonic-gate relsiz, basebgn, etext, emap); 5950Sstevel@tonic-gate } 5960Sstevel@tonic-gate if (relbgn >= relend) 5970Sstevel@tonic-gate break; 5980Sstevel@tonic-gate rtype = ELF_R_TYPE(((Rel *)relbgn)->r_info); 5990Sstevel@tonic-gate } 6000Sstevel@tonic-gate 6010Sstevel@tonic-gate roffset = ((Rel *)relbgn)->r_offset; 6020Sstevel@tonic-gate 6030Sstevel@tonic-gate /* 6040Sstevel@tonic-gate * If this is a shared object, add the base address to offset. 6050Sstevel@tonic-gate */ 6060Sstevel@tonic-gate if (!(FLAGS(lmp) & FLG_RT_FIXED)) { 6070Sstevel@tonic-gate 6080Sstevel@tonic-gate /* 6090Sstevel@tonic-gate * If we're processing lazy bindings, we have to step 6100Sstevel@tonic-gate * through the plt entries and add the base address 6110Sstevel@tonic-gate * to the corresponding got entry. 6120Sstevel@tonic-gate */ 6130Sstevel@tonic-gate if (plthint && (plt == 0) && 6140Sstevel@tonic-gate (rtype == R_386_JMP_SLOT) && 6150Sstevel@tonic-gate ((MODE(lmp) & RTLD_NOW) == 0)) { 6160Sstevel@tonic-gate relbgn = elf_reloc_relacount(relbgn, 6170Sstevel@tonic-gate plthint, relsiz, basebgn); 6180Sstevel@tonic-gate plthint = 0; 6190Sstevel@tonic-gate continue; 6200Sstevel@tonic-gate } 6210Sstevel@tonic-gate roffset += basebgn; 6220Sstevel@tonic-gate } 6230Sstevel@tonic-gate 6240Sstevel@tonic-gate rsymndx = ELF_R_SYM(((Rel *)relbgn)->r_info); 6250Sstevel@tonic-gate rel = (Rel *)relbgn; 6260Sstevel@tonic-gate relbgn += relsiz; 6270Sstevel@tonic-gate 6280Sstevel@tonic-gate /* 6290Sstevel@tonic-gate * Optimizations. 6300Sstevel@tonic-gate */ 6310Sstevel@tonic-gate if (rtype == R_386_NONE) 6320Sstevel@tonic-gate continue; 6330Sstevel@tonic-gate if (noplt && ((ulong_t)rel >= pltbgn) && 6340Sstevel@tonic-gate ((ulong_t)rel < pltend)) { 6350Sstevel@tonic-gate relbgn = pltend; 6360Sstevel@tonic-gate continue; 6370Sstevel@tonic-gate } 6380Sstevel@tonic-gate 6390Sstevel@tonic-gate /* 6400Sstevel@tonic-gate * If we're promoting plts determine if this one has already 6410Sstevel@tonic-gate * been written. 6420Sstevel@tonic-gate */ 6430Sstevel@tonic-gate if (plt) { 6440Sstevel@tonic-gate if ((*(ulong_t *)roffset < _pltbgn) || 6450Sstevel@tonic-gate (*(ulong_t *)roffset > _pltend)) 6460Sstevel@tonic-gate continue; 6470Sstevel@tonic-gate } 6480Sstevel@tonic-gate 6490Sstevel@tonic-gate /* 6500Sstevel@tonic-gate * If this relocation is not against part of the image 6510Sstevel@tonic-gate * mapped into memory we skip it. 6520Sstevel@tonic-gate */ 6530Sstevel@tonic-gate if ((roffset < ADDR(lmp)) || (roffset > (ADDR(lmp) + 6540Sstevel@tonic-gate MSIZE(lmp)))) { 6554679Srie elf_reloc_bad(lmp, (void *)rel, rtype, roffset, 6564679Srie rsymndx); 6570Sstevel@tonic-gate continue; 6580Sstevel@tonic-gate } 6590Sstevel@tonic-gate 6600Sstevel@tonic-gate binfo = 0; 6610Sstevel@tonic-gate /* 6620Sstevel@tonic-gate * If a symbol index is specified then get the symbol table 6630Sstevel@tonic-gate * entry, locate the symbol definition, and determine its 6640Sstevel@tonic-gate * address. 6650Sstevel@tonic-gate */ 6660Sstevel@tonic-gate if (rsymndx) { 6670Sstevel@tonic-gate /* 6680Sstevel@tonic-gate * Get the local symbol table entry. 6690Sstevel@tonic-gate */ 6700Sstevel@tonic-gate symref = (Sym *)((ulong_t)SYMTAB(lmp) + 6710Sstevel@tonic-gate (rsymndx * SYMENT(lmp))); 6720Sstevel@tonic-gate 6730Sstevel@tonic-gate /* 6740Sstevel@tonic-gate * If this is a local symbol, just use the base address. 6750Sstevel@tonic-gate * (we should have no local relocations in the 6760Sstevel@tonic-gate * executable). 6770Sstevel@tonic-gate */ 6780Sstevel@tonic-gate if (ELF_ST_BIND(symref->st_info) == STB_LOCAL) { 6790Sstevel@tonic-gate value = basebgn; 6800Sstevel@tonic-gate name = (char *)0; 6810Sstevel@tonic-gate 6820Sstevel@tonic-gate /* 6832145Srie * Special case TLS relocations. 6840Sstevel@tonic-gate */ 6852145Srie if (rtype == R_386_TLS_DTPMOD32) { 6862145Srie /* 6872145Srie * Use the TLS modid. 6882145Srie */ 6890Sstevel@tonic-gate value = TLSMODID(lmp); 6902145Srie 6912145Srie } else if (rtype == R_386_TLS_TPOFF) { 6922145Srie if ((value = elf_static_tls(lmp, symref, 6932145Srie rel, rtype, 0, roffset, 0)) == 0) { 6942145Srie ret = 0; 6952145Srie break; 6962145Srie } 6972145Srie } 6980Sstevel@tonic-gate } else { 6990Sstevel@tonic-gate /* 7000Sstevel@tonic-gate * If the symbol index is equal to the previous 7010Sstevel@tonic-gate * symbol index relocation we processed then 7020Sstevel@tonic-gate * reuse the previous values. (Note that there 7030Sstevel@tonic-gate * have been cases where a relocation exists 7040Sstevel@tonic-gate * against a copy relocation symbol, our ld(1) 7050Sstevel@tonic-gate * should optimize this away, but make sure we 7060Sstevel@tonic-gate * don't use the same symbol information should 7070Sstevel@tonic-gate * this case exist). 7080Sstevel@tonic-gate */ 7090Sstevel@tonic-gate if ((rsymndx == psymndx) && 7100Sstevel@tonic-gate (rtype != R_386_COPY)) { 7110Sstevel@tonic-gate /* LINTED */ 7120Sstevel@tonic-gate if (psymdef == 0) { 7131618Srie DBG_CALL(Dbg_bind_weak(lmp, 7141618Srie (Addr)roffset, (Addr) 7150Sstevel@tonic-gate (roffset - basebgn), name)); 7160Sstevel@tonic-gate continue; 7170Sstevel@tonic-gate } 7180Sstevel@tonic-gate /* LINTED */ 7190Sstevel@tonic-gate value = pvalue; 7200Sstevel@tonic-gate /* LINTED */ 7210Sstevel@tonic-gate name = pname; 7220Sstevel@tonic-gate /* LINTED */ 7230Sstevel@tonic-gate symdef = psymdef; 7240Sstevel@tonic-gate /* LINTED */ 7250Sstevel@tonic-gate symref = psymref; 7260Sstevel@tonic-gate /* LINTED */ 7270Sstevel@tonic-gate _lmp = plmp; 7280Sstevel@tonic-gate /* LINTED */ 7290Sstevel@tonic-gate binfo = pbinfo; 7300Sstevel@tonic-gate 7310Sstevel@tonic-gate if ((LIST(_lmp)->lm_tflags | 7320Sstevel@tonic-gate FLAGS1(_lmp)) & 7330Sstevel@tonic-gate LML_TFLG_AUD_SYMBIND) { 7340Sstevel@tonic-gate value = audit_symbind(lmp, _lmp, 7350Sstevel@tonic-gate /* LINTED */ 7360Sstevel@tonic-gate symdef, dsymndx, value, 7370Sstevel@tonic-gate &sb_flags); 7380Sstevel@tonic-gate } 7390Sstevel@tonic-gate } else { 7400Sstevel@tonic-gate Slookup sl; 7410Sstevel@tonic-gate uchar_t bind; 7420Sstevel@tonic-gate 7430Sstevel@tonic-gate /* 7440Sstevel@tonic-gate * Lookup the symbol definition. 7450Sstevel@tonic-gate */ 7460Sstevel@tonic-gate name = (char *)(STRTAB(lmp) + 7470Sstevel@tonic-gate symref->st_name); 7480Sstevel@tonic-gate 7490Sstevel@tonic-gate sl.sl_name = name; 7500Sstevel@tonic-gate sl.sl_cmap = lmp; 7510Sstevel@tonic-gate sl.sl_imap = 0; 7520Sstevel@tonic-gate sl.sl_hash = 0; 7530Sstevel@tonic-gate sl.sl_rsymndx = rsymndx; 7540Sstevel@tonic-gate 7550Sstevel@tonic-gate if (rtype == R_386_COPY) 7560Sstevel@tonic-gate sl.sl_flags = LKUP_COPY; 7570Sstevel@tonic-gate else 7580Sstevel@tonic-gate sl.sl_flags = LKUP_DEFT; 7590Sstevel@tonic-gate 7600Sstevel@tonic-gate sl.sl_flags |= LKUP_ALLCNTLIST; 7610Sstevel@tonic-gate 7620Sstevel@tonic-gate if (rtype != R_386_JMP_SLOT) 7630Sstevel@tonic-gate sl.sl_flags |= LKUP_SPEC; 7640Sstevel@tonic-gate 7654947Srie /* 7664947Srie * Under ldd -w, any unresolved weak 7674947Srie * references are diagnosed. Set the 7684947Srie * symbol binding as global to trigger 7694947Srie * a relocation error if the symbol can 7704947Srie * not be found. 7714947Srie */ 7724947Srie if (LIST(lmp)->lm_flags & 7734947Srie LML_FLG_TRC_NOUNRESWEAK) { 7744947Srie bind = STB_GLOBAL; 7754947Srie } else if ((bind = 7764947Srie ELF_ST_BIND(symref->st_info)) == 7774947Srie STB_WEAK) { 7780Sstevel@tonic-gate sl.sl_flags |= LKUP_WEAK; 7794947Srie } 7800Sstevel@tonic-gate 7810Sstevel@tonic-gate symdef = lookup_sym(&sl, &_lmp, &binfo); 7820Sstevel@tonic-gate 7830Sstevel@tonic-gate /* 7840Sstevel@tonic-gate * If the symbol is not found and the 7850Sstevel@tonic-gate * reference was not to a weak symbol, 7860Sstevel@tonic-gate * report an error. Weak references 7870Sstevel@tonic-gate * may be unresolved. 7880Sstevel@tonic-gate * chkmsg: MSG_INTL(MSG_LDD_SYM_NFOUND) 7890Sstevel@tonic-gate */ 7904679Srie /* BEGIN CSTYLED */ 7910Sstevel@tonic-gate if (symdef == 0) { 7921618Srie Lm_list *lml = LIST(lmp); 7931618Srie 7940Sstevel@tonic-gate if (bind != STB_WEAK) { 7951618Srie if (lml->lm_flags & 7960Sstevel@tonic-gate LML_FLG_IGNRELERR) { 7970Sstevel@tonic-gate continue; 7981618Srie } else if (lml->lm_flags & 7990Sstevel@tonic-gate LML_FLG_TRC_WARN) { 8000Sstevel@tonic-gate (void) printf(MSG_INTL( 8010Sstevel@tonic-gate MSG_LDD_SYM_NFOUND), 8020Sstevel@tonic-gate demangle(name), 8030Sstevel@tonic-gate NAME(lmp)); 8040Sstevel@tonic-gate continue; 8050Sstevel@tonic-gate } else { 8062145Srie DBG_CALL(Dbg_reloc_in(lml, 8072145Srie ELF_DBG_RTLD, M_MACH, 8082145Srie M_REL_SHT_TYPE, rel, 8092145Srie NULL, name)); 8101618Srie eprintf(lml, ERR_FATAL, 8110Sstevel@tonic-gate MSG_INTL(MSG_REL_NOSYM), 8120Sstevel@tonic-gate NAME(lmp), 8130Sstevel@tonic-gate demangle(name)); 8140Sstevel@tonic-gate ret = 0; 8150Sstevel@tonic-gate break; 8160Sstevel@tonic-gate } 8170Sstevel@tonic-gate } else { 8180Sstevel@tonic-gate psymndx = rsymndx; 8190Sstevel@tonic-gate psymdef = 0; 8200Sstevel@tonic-gate 8211618Srie DBG_CALL(Dbg_bind_weak(lmp, 8221618Srie (Addr)roffset, (Addr) 8230Sstevel@tonic-gate (roffset - basebgn), name)); 8240Sstevel@tonic-gate continue; 8250Sstevel@tonic-gate } 8260Sstevel@tonic-gate } 8274679Srie /* END CSTYLED */ 8280Sstevel@tonic-gate 8290Sstevel@tonic-gate /* 8300Sstevel@tonic-gate * If symbol was found in an object 8310Sstevel@tonic-gate * other than the referencing object 8320Sstevel@tonic-gate * then record the binding. 8330Sstevel@tonic-gate */ 8340Sstevel@tonic-gate if ((lmp != _lmp) && ((FLAGS1(_lmp) & 8350Sstevel@tonic-gate FL1_RT_NOINIFIN) == 0)) { 8360Sstevel@tonic-gate if (alist_test(&bound, _lmp, 8370Sstevel@tonic-gate sizeof (Rt_map *), 8380Sstevel@tonic-gate AL_CNT_RELBIND) == 0) { 8390Sstevel@tonic-gate ret = 0; 8400Sstevel@tonic-gate break; 8410Sstevel@tonic-gate } 8420Sstevel@tonic-gate } 8430Sstevel@tonic-gate 8440Sstevel@tonic-gate /* 8450Sstevel@tonic-gate * Calculate the location of definition; 8460Sstevel@tonic-gate * symbol value plus base address of 8470Sstevel@tonic-gate * containing shared object. 8480Sstevel@tonic-gate */ 8492850Srie if (IS_SIZE(rtype)) 8502850Srie value = symdef->st_size; 8512850Srie else 8522850Srie value = symdef->st_value; 8532850Srie 8540Sstevel@tonic-gate if (!(FLAGS(_lmp) & FLG_RT_FIXED) && 8552850Srie !(IS_SIZE(rtype)) && 8560Sstevel@tonic-gate (symdef->st_shndx != SHN_ABS) && 8570Sstevel@tonic-gate (ELF_ST_TYPE(symdef->st_info) != 8580Sstevel@tonic-gate STT_TLS)) 8590Sstevel@tonic-gate value += ADDR(_lmp); 8600Sstevel@tonic-gate 8610Sstevel@tonic-gate /* 8620Sstevel@tonic-gate * Retain this symbol index and the 8630Sstevel@tonic-gate * value in case it can be used for the 8640Sstevel@tonic-gate * subsequent relocations. 8650Sstevel@tonic-gate */ 8660Sstevel@tonic-gate if (rtype != R_386_COPY) { 8670Sstevel@tonic-gate psymndx = rsymndx; 8680Sstevel@tonic-gate pvalue = value; 8690Sstevel@tonic-gate pname = name; 8700Sstevel@tonic-gate psymdef = symdef; 8710Sstevel@tonic-gate psymref = symref; 8720Sstevel@tonic-gate plmp = _lmp; 8730Sstevel@tonic-gate pbinfo = binfo; 8740Sstevel@tonic-gate } 8750Sstevel@tonic-gate if ((LIST(_lmp)->lm_tflags | 8760Sstevel@tonic-gate FLAGS1(_lmp)) & 8770Sstevel@tonic-gate LML_TFLG_AUD_SYMBIND) { 8780Sstevel@tonic-gate dsymndx = (((uintptr_t)symdef - 8790Sstevel@tonic-gate (uintptr_t)SYMTAB(_lmp)) / 8800Sstevel@tonic-gate SYMENT(_lmp)); 8810Sstevel@tonic-gate value = audit_symbind(lmp, _lmp, 8820Sstevel@tonic-gate symdef, dsymndx, value, 8830Sstevel@tonic-gate &sb_flags); 8840Sstevel@tonic-gate } 8850Sstevel@tonic-gate } 8860Sstevel@tonic-gate 8870Sstevel@tonic-gate /* 8880Sstevel@tonic-gate * If relocation is PC-relative, subtract 8890Sstevel@tonic-gate * offset address. 8900Sstevel@tonic-gate */ 8910Sstevel@tonic-gate if (IS_PC_RELATIVE(rtype)) 8920Sstevel@tonic-gate value -= roffset; 8930Sstevel@tonic-gate 8940Sstevel@tonic-gate /* 8952145Srie * Special case TLS relocations. 8960Sstevel@tonic-gate */ 8972145Srie if (rtype == R_386_TLS_DTPMOD32) { 8982145Srie /* 8992145Srie * Relocation value is the TLS modid. 9002145Srie */ 9010Sstevel@tonic-gate value = TLSMODID(_lmp); 9022145Srie 9032145Srie } else if (rtype == R_386_TLS_TPOFF) { 9042145Srie if ((value = elf_static_tls(_lmp, 9052145Srie symdef, rel, rtype, name, roffset, 9062145Srie value)) == 0) { 9072145Srie ret = 0; 9082145Srie break; 9092145Srie } 9102145Srie } 9110Sstevel@tonic-gate } 9120Sstevel@tonic-gate } else { 9130Sstevel@tonic-gate /* 9142145Srie * Special cases. 9150Sstevel@tonic-gate */ 9162145Srie if (rtype == R_386_TLS_DTPMOD32) { 9172145Srie /* 9182145Srie * TLS relocation value is the TLS modid. 9192145Srie */ 9200Sstevel@tonic-gate value = TLSMODID(lmp); 9212145Srie } else 9220Sstevel@tonic-gate value = basebgn; 9230Sstevel@tonic-gate name = (char *)0; 9240Sstevel@tonic-gate } 9250Sstevel@tonic-gate 9262145Srie DBG_CALL(Dbg_reloc_in(LIST(lmp), ELF_DBG_RTLD, M_MACH, 9272145Srie M_REL_SHT_TYPE, rel, NULL, name)); 9282145Srie 9290Sstevel@tonic-gate /* 9300Sstevel@tonic-gate * If this object has relocations in the text segment, turn 9310Sstevel@tonic-gate * off the write protect. 9320Sstevel@tonic-gate */ 9330Sstevel@tonic-gate if ((roffset < etext) && (textrel == 0)) { 9340Sstevel@tonic-gate if (elf_set_prot(lmp, PROT_WRITE) == 0) { 9350Sstevel@tonic-gate ret = 0; 9360Sstevel@tonic-gate break; 9370Sstevel@tonic-gate } 9380Sstevel@tonic-gate textrel = 1; 9390Sstevel@tonic-gate } 9400Sstevel@tonic-gate 9410Sstevel@tonic-gate /* 9420Sstevel@tonic-gate * Call relocation routine to perform required relocation. 9430Sstevel@tonic-gate */ 9440Sstevel@tonic-gate switch (rtype) { 9450Sstevel@tonic-gate case R_386_COPY: 9460Sstevel@tonic-gate if (elf_copy_reloc(name, symref, lmp, (void *)roffset, 9470Sstevel@tonic-gate symdef, _lmp, (const void *)value) == 0) 9480Sstevel@tonic-gate ret = 0; 9490Sstevel@tonic-gate break; 9500Sstevel@tonic-gate case R_386_JMP_SLOT: 9510Sstevel@tonic-gate if (((LIST(lmp)->lm_tflags | FLAGS1(lmp)) & 9520Sstevel@tonic-gate (LML_TFLG_AUD_PLTENTER | LML_TFLG_AUD_PLTEXIT)) && 9530Sstevel@tonic-gate AUDINFO(lmp)->ai_dynplts) { 9540Sstevel@tonic-gate int fail = 0; 9550Sstevel@tonic-gate int pltndx = (((ulong_t)rel - 9564679Srie (uintptr_t)JMPREL(lmp)) / relsiz); 9570Sstevel@tonic-gate int symndx = (((uintptr_t)symdef - 9584679Srie (uintptr_t)SYMTAB(_lmp)) / SYMENT(_lmp)); 9590Sstevel@tonic-gate 9600Sstevel@tonic-gate (void) elf_plt_trace_write(roffset, lmp, _lmp, 9610Sstevel@tonic-gate symdef, symndx, pltndx, (caddr_t)value, 9620Sstevel@tonic-gate sb_flags, &fail); 9630Sstevel@tonic-gate if (fail) 9640Sstevel@tonic-gate ret = 0; 9650Sstevel@tonic-gate } else { 9660Sstevel@tonic-gate /* 9670Sstevel@tonic-gate * Write standard PLT entry to jump directly 9680Sstevel@tonic-gate * to newly bound function. 9690Sstevel@tonic-gate */ 9701618Srie DBG_CALL(Dbg_reloc_apply_val(LIST(lmp), 9711618Srie ELF_DBG_RTLD, (Xword)roffset, 9720Sstevel@tonic-gate (Xword)value)); 9730Sstevel@tonic-gate *(ulong_t *)roffset = value; 9740Sstevel@tonic-gate } 9750Sstevel@tonic-gate break; 9760Sstevel@tonic-gate default: 9770Sstevel@tonic-gate /* 9780Sstevel@tonic-gate * Write the relocation out. 9790Sstevel@tonic-gate */ 980*5189Sab196087 if (do_reloc_rtld(rtype, (uchar_t *)roffset, 981*5189Sab196087 (Word *)&value, name, NAME(lmp), LIST(lmp)) == 0) 9820Sstevel@tonic-gate ret = 0; 9830Sstevel@tonic-gate 9841618Srie DBG_CALL(Dbg_reloc_apply_val(LIST(lmp), ELF_DBG_RTLD, 9851618Srie (Xword)roffset, (Xword)value)); 9860Sstevel@tonic-gate } 9870Sstevel@tonic-gate 9880Sstevel@tonic-gate if ((ret == 0) && 9890Sstevel@tonic-gate ((LIST(lmp)->lm_flags & LML_FLG_TRC_WARN) == 0)) 9900Sstevel@tonic-gate break; 9910Sstevel@tonic-gate 9920Sstevel@tonic-gate if (binfo) { 9931618Srie DBG_CALL(Dbg_bind_global(lmp, (Addr)roffset, 9941618Srie (Off)(roffset - basebgn), (Xword)(-1), PLT_T_FULL, 9951618Srie _lmp, (Addr)value, symdef->st_value, name, binfo)); 9960Sstevel@tonic-gate } 9970Sstevel@tonic-gate } 9980Sstevel@tonic-gate 9990Sstevel@tonic-gate return (relocate_finish(lmp, bound, textrel, ret)); 10000Sstevel@tonic-gate } 10010Sstevel@tonic-gate 10020Sstevel@tonic-gate /* 10030Sstevel@tonic-gate * Initialize the first few got entries so that function calls go to 10040Sstevel@tonic-gate * elf_rtbndr: 10050Sstevel@tonic-gate * 10060Sstevel@tonic-gate * GOT[GOT_XLINKMAP] = the address of the link map 10070Sstevel@tonic-gate * GOT[GOT_XRTLD] = the address of rtbinder 10080Sstevel@tonic-gate */ 10090Sstevel@tonic-gate void 10100Sstevel@tonic-gate elf_plt_init(void *got, caddr_t l) 10110Sstevel@tonic-gate { 10120Sstevel@tonic-gate uint_t *_got; 10130Sstevel@tonic-gate /* LINTED */ 10140Sstevel@tonic-gate Rt_map *lmp = (Rt_map *)l; 10150Sstevel@tonic-gate 10160Sstevel@tonic-gate _got = (uint_t *)got + M_GOT_XLINKMAP; 10170Sstevel@tonic-gate *_got = (uint_t)lmp; 10180Sstevel@tonic-gate _got = (uint_t *)got + M_GOT_XRTLD; 10190Sstevel@tonic-gate *_got = (uint_t)elf_rtbndr; 10200Sstevel@tonic-gate } 10210Sstevel@tonic-gate 10220Sstevel@tonic-gate /* 10230Sstevel@tonic-gate * For SVR4 Intel compatability. USL uses /usr/lib/libc.so.1 as the run-time 10240Sstevel@tonic-gate * linker, so the interpreter's address will differ from /usr/lib/ld.so.1. 10250Sstevel@tonic-gate * Further, USL has special _iob[] and _ctype[] processing that makes up for the 10260Sstevel@tonic-gate * fact that these arrays do not have associated copy relocations. So we try 10270Sstevel@tonic-gate * and make up for that here. Any relocations found will be added to the global 10280Sstevel@tonic-gate * copy relocation list and will be processed in setup(). 10290Sstevel@tonic-gate */ 10300Sstevel@tonic-gate static int 10310Sstevel@tonic-gate _elf_copy_reloc(const char *name, Rt_map *rlmp, Rt_map *dlmp) 10320Sstevel@tonic-gate { 10330Sstevel@tonic-gate Sym *symref, *symdef; 10340Sstevel@tonic-gate caddr_t ref, def; 10350Sstevel@tonic-gate Rt_map *_lmp; 10360Sstevel@tonic-gate Rel rel; 10370Sstevel@tonic-gate Slookup sl; 10380Sstevel@tonic-gate uint_t binfo; 10390Sstevel@tonic-gate 10400Sstevel@tonic-gate /* 10410Sstevel@tonic-gate * Determine if the special symbol exists as a reference in the dynamic 10420Sstevel@tonic-gate * executable, and that an associated definition exists in libc.so.1. 10430Sstevel@tonic-gate */ 10440Sstevel@tonic-gate sl.sl_name = name; 10450Sstevel@tonic-gate sl.sl_cmap = rlmp; 10460Sstevel@tonic-gate sl.sl_imap = rlmp; 10470Sstevel@tonic-gate sl.sl_hash = 0; 10480Sstevel@tonic-gate sl.sl_rsymndx = 0; 10490Sstevel@tonic-gate sl.sl_flags = LKUP_FIRST; 10500Sstevel@tonic-gate 10510Sstevel@tonic-gate if ((symref = lookup_sym(&sl, &_lmp, &binfo)) == 0) 10520Sstevel@tonic-gate return (1); 10530Sstevel@tonic-gate 10540Sstevel@tonic-gate sl.sl_imap = dlmp; 10550Sstevel@tonic-gate sl.sl_flags = LKUP_DEFT; 10560Sstevel@tonic-gate 10570Sstevel@tonic-gate if ((symdef = lookup_sym(&sl, &_lmp, &binfo)) == 0) 10580Sstevel@tonic-gate return (1); 10590Sstevel@tonic-gate if (strcmp(NAME(_lmp), MSG_ORIG(MSG_PTH_LIBC))) 10600Sstevel@tonic-gate return (1); 10610Sstevel@tonic-gate 10620Sstevel@tonic-gate /* 10630Sstevel@tonic-gate * Determine the reference and definition addresses. 10640Sstevel@tonic-gate */ 10650Sstevel@tonic-gate ref = (void *)(symref->st_value); 10660Sstevel@tonic-gate if (!(FLAGS(rlmp) & FLG_RT_FIXED)) 10670Sstevel@tonic-gate ref += ADDR(rlmp); 10680Sstevel@tonic-gate def = (void *)(symdef->st_value); 10690Sstevel@tonic-gate if (!(FLAGS(_lmp) & FLG_RT_FIXED)) 10700Sstevel@tonic-gate def += ADDR(_lmp); 10710Sstevel@tonic-gate 10720Sstevel@tonic-gate /* 10730Sstevel@tonic-gate * Set up a relocation entry for debugging and call the generic copy 10740Sstevel@tonic-gate * relocation function to provide symbol size error checking and to 10750Sstevel@tonic-gate * record the copy relocation that must be performed. 10760Sstevel@tonic-gate */ 10770Sstevel@tonic-gate rel.r_offset = (Addr)ref; 10780Sstevel@tonic-gate rel.r_info = (Word)R_386_COPY; 10791618Srie DBG_CALL(Dbg_reloc_in(LIST(rlmp), ELF_DBG_RTLD, M_MACH, M_REL_SHT_TYPE, 10801618Srie &rel, NULL, name)); 10810Sstevel@tonic-gate 10820Sstevel@tonic-gate return (elf_copy_reloc((char *)name, symref, rlmp, (void *)ref, symdef, 10830Sstevel@tonic-gate _lmp, (void *)def)); 10840Sstevel@tonic-gate } 10850Sstevel@tonic-gate 10860Sstevel@tonic-gate int 10870Sstevel@tonic-gate elf_copy_gen(Rt_map *lmp) 10880Sstevel@tonic-gate { 10890Sstevel@tonic-gate if (interp && ((ulong_t)interp->i_faddr != 10900Sstevel@tonic-gate r_debug.rtd_rdebug.r_ldbase) && 10910Sstevel@tonic-gate !(strcmp(interp->i_name, MSG_ORIG(MSG_PTH_LIBC)))) { 10920Sstevel@tonic-gate 10931618Srie DBG_CALL(Dbg_reloc_run(lmp, M_REL_SHT_TYPE, 0, 10940Sstevel@tonic-gate DBG_REL_START)); 10950Sstevel@tonic-gate 10960Sstevel@tonic-gate if (_elf_copy_reloc(MSG_ORIG(MSG_SYM_CTYPE), lmp, 10970Sstevel@tonic-gate (Rt_map *)NEXT(lmp)) == 0) 10980Sstevel@tonic-gate return (0); 10990Sstevel@tonic-gate if (_elf_copy_reloc(MSG_ORIG(MSG_SYM_IOB), lmp, 11000Sstevel@tonic-gate (Rt_map *)NEXT(lmp)) == 0) 11010Sstevel@tonic-gate return (0); 11020Sstevel@tonic-gate } 11030Sstevel@tonic-gate return (1); 11040Sstevel@tonic-gate } 11050Sstevel@tonic-gate 11060Sstevel@tonic-gate /* 11070Sstevel@tonic-gate * Plt writing interface to allow debugging initialization to be generic. 11080Sstevel@tonic-gate */ 11090Sstevel@tonic-gate Pltbindtype 11100Sstevel@tonic-gate /* ARGSUSED1 */ 11110Sstevel@tonic-gate elf_plt_write(uintptr_t addr, uintptr_t vaddr, void *rptr, uintptr_t symval, 11120Sstevel@tonic-gate Xword pltndx) 11130Sstevel@tonic-gate { 11140Sstevel@tonic-gate Rel *rel = (Rel*)rptr; 11150Sstevel@tonic-gate uintptr_t pltaddr; 11160Sstevel@tonic-gate 11170Sstevel@tonic-gate pltaddr = addr + rel->r_offset; 11180Sstevel@tonic-gate *(ulong_t *)pltaddr = (ulong_t)symval; 11190Sstevel@tonic-gate DBG_CALL(pltcntfull++); 11200Sstevel@tonic-gate return (PLT_T_FULL); 11210Sstevel@tonic-gate } 11220Sstevel@tonic-gate 11230Sstevel@tonic-gate /* 11240Sstevel@tonic-gate * Provide a machine specific interface to the conversion routine. By calling 11250Sstevel@tonic-gate * the machine specific version, rather than the generic version, we insure that 11260Sstevel@tonic-gate * the data tables/strings for all known machine versions aren't dragged into 11270Sstevel@tonic-gate * ld.so.1. 11280Sstevel@tonic-gate */ 11290Sstevel@tonic-gate const char * 11301618Srie _conv_reloc_type(uint_t rel) 11310Sstevel@tonic-gate { 11324734Sab196087 static Conv_inv_buf_t inv_buf; 11334734Sab196087 11344734Sab196087 return (conv_reloc_386_type(rel, 0, &inv_buf)); 11350Sstevel@tonic-gate } 1136