17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 55aefb655Srie * Common Development and Distribution License (the "License"). 65aefb655Srie * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 2111a2bb38Srie 227c478bd9Sstevel@tonic-gate /* 23*20272c2eSAli Bahrami * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 247c478bd9Sstevel@tonic-gate * Use is subject to license terms. 257c478bd9Sstevel@tonic-gate */ 267257d1b4Sraf 277257d1b4Sraf /* 287257d1b4Sraf * Copyright (c) 1988 AT&T 297257d1b4Sraf * All Rights Reserved 307257d1b4Sraf */ 317257d1b4Sraf 327c478bd9Sstevel@tonic-gate /* 337c478bd9Sstevel@tonic-gate * Object file dependent support for ELF objects. 347c478bd9Sstevel@tonic-gate */ 357c478bd9Sstevel@tonic-gate 367c478bd9Sstevel@tonic-gate #include <stdio.h> 377c478bd9Sstevel@tonic-gate #include <sys/procfs.h> 387c478bd9Sstevel@tonic-gate #include <sys/mman.h> 397c478bd9Sstevel@tonic-gate #include <sys/debug.h> 407c478bd9Sstevel@tonic-gate #include <string.h> 417c478bd9Sstevel@tonic-gate #include <limits.h> 427c478bd9Sstevel@tonic-gate #include <dlfcn.h> 435aefb655Srie #include <debug.h> 445aefb655Srie #include <conv.h> 457c478bd9Sstevel@tonic-gate #include "_rtld.h" 467c478bd9Sstevel@tonic-gate #include "_audit.h" 477c478bd9Sstevel@tonic-gate #include "_elf.h" 4856deab07SRod Evans #include "_inline.h" 497c478bd9Sstevel@tonic-gate #include "msg.h" 507c478bd9Sstevel@tonic-gate 517c478bd9Sstevel@tonic-gate /* 527c478bd9Sstevel@tonic-gate * Default and secure dependency search paths. 537c478bd9Sstevel@tonic-gate */ 5456deab07SRod Evans static Spath_defn _elf_def_dirs[] = { 557c478bd9Sstevel@tonic-gate #if defined(_ELF64) 5656deab07SRod Evans { MSG_ORIG(MSG_PTH_LIB_64), MSG_PTH_LIB_64_SIZE }, 5756deab07SRod Evans { MSG_ORIG(MSG_PTH_USRLIB_64), MSG_PTH_USRLIB_64_SIZE }, 587c478bd9Sstevel@tonic-gate #else 5956deab07SRod Evans { MSG_ORIG(MSG_PTH_LIB), MSG_PTH_LIB_SIZE }, 6056deab07SRod Evans { MSG_ORIG(MSG_PTH_USRLIB), MSG_PTH_USRLIB_SIZE }, 617c478bd9Sstevel@tonic-gate #endif 6256deab07SRod Evans { 0, 0 } 637c478bd9Sstevel@tonic-gate }; 647c478bd9Sstevel@tonic-gate 6556deab07SRod Evans static Spath_defn _elf_sec_dirs[] = { 667c478bd9Sstevel@tonic-gate #if defined(_ELF64) 6756deab07SRod Evans { MSG_ORIG(MSG_PTH_LIBSE_64), MSG_PTH_LIBSE_64_SIZE }, 6856deab07SRod Evans { MSG_ORIG(MSG_PTH_USRLIBSE_64), MSG_PTH_USRLIBSE_64_SIZE }, 697c478bd9Sstevel@tonic-gate #else 7056deab07SRod Evans { MSG_ORIG(MSG_PTH_LIBSE), MSG_PTH_LIBSE_SIZE }, 7156deab07SRod Evans { MSG_ORIG(MSG_PTH_USRLIBSE), MSG_PTH_USRLIBSE_SIZE }, 727c478bd9Sstevel@tonic-gate #endif 7356deab07SRod Evans { 0, 0 } 747c478bd9Sstevel@tonic-gate }; 757c478bd9Sstevel@tonic-gate 7656deab07SRod Evans Alist *elf_def_dirs = NULL; 7756deab07SRod Evans Alist *elf_sec_dirs = NULL; 7856deab07SRod Evans 797c478bd9Sstevel@tonic-gate /* 807c478bd9Sstevel@tonic-gate * Defines for local functions. 817c478bd9Sstevel@tonic-gate */ 827c478bd9Sstevel@tonic-gate static void elf_dladdr(ulong_t, Rt_map *, Dl_info *, void **, int); 8356deab07SRod Evans static Addr elf_entry_point(void); 8456deab07SRod Evans static int elf_fix_name(const char *, Rt_map *, Alist **, Aliste, uint_t); 8556deab07SRod Evans static Alist **elf_get_def_dirs(void); 8656deab07SRod Evans static Alist **elf_get_sec_dirs(void); 8756deab07SRod Evans static char *elf_get_so(const char *, const char *, size_t, size_t); 889aa23310Srie static int elf_needed(Lm_list *, Aliste, Rt_map *, int *); 897c478bd9Sstevel@tonic-gate 907c478bd9Sstevel@tonic-gate /* 917c478bd9Sstevel@tonic-gate * Functions and data accessed through indirect pointers. 927c478bd9Sstevel@tonic-gate */ 937c478bd9Sstevel@tonic-gate Fct elf_fct = { 9456deab07SRod Evans elf_verify, 9556deab07SRod Evans elf_new_lmp, 9656deab07SRod Evans elf_entry_point, 977c478bd9Sstevel@tonic-gate elf_needed, 987c478bd9Sstevel@tonic-gate lookup_sym, 997c478bd9Sstevel@tonic-gate elf_reloc, 10056deab07SRod Evans elf_get_def_dirs, 10156deab07SRod Evans elf_get_sec_dirs, 1027c478bd9Sstevel@tonic-gate elf_fix_name, 1037c478bd9Sstevel@tonic-gate elf_get_so, 1047c478bd9Sstevel@tonic-gate elf_dladdr, 10556deab07SRod Evans dlsym_handle 1067c478bd9Sstevel@tonic-gate }; 1077c478bd9Sstevel@tonic-gate 10856deab07SRod Evans /* 10956deab07SRod Evans * Default and secure dependency search paths. 11056deab07SRod Evans */ 11156deab07SRod Evans static Alist ** 11256deab07SRod Evans elf_get_def_dirs() 11356deab07SRod Evans { 11456deab07SRod Evans if (elf_def_dirs == NULL) 11556deab07SRod Evans set_dirs(&elf_def_dirs, _elf_def_dirs, LA_SER_DEFAULT); 11656deab07SRod Evans return (&elf_def_dirs); 11756deab07SRod Evans } 11856deab07SRod Evans 11956deab07SRod Evans static Alist ** 12056deab07SRod Evans elf_get_sec_dirs() 12156deab07SRod Evans { 12256deab07SRod Evans if (elf_sec_dirs == NULL) 12356deab07SRod Evans set_dirs(&elf_sec_dirs, _elf_sec_dirs, LA_SER_SECURE); 12456deab07SRod Evans return (&elf_sec_dirs); 12556deab07SRod Evans } 1267c478bd9Sstevel@tonic-gate 1277c478bd9Sstevel@tonic-gate /* 1287c478bd9Sstevel@tonic-gate * Redefine NEEDED name if necessary. 1297c478bd9Sstevel@tonic-gate */ 13056deab07SRod Evans static int 13156deab07SRod Evans elf_fix_name(const char *name, Rt_map *clmp, Alist **alpp, Aliste alni, 13256deab07SRod Evans uint_t orig) 1337c478bd9Sstevel@tonic-gate { 1347c478bd9Sstevel@tonic-gate /* 1357c478bd9Sstevel@tonic-gate * For ABI compliance, if we are asked for ld.so.1, then really give 1367c478bd9Sstevel@tonic-gate * them libsys.so.1 (the SONAME of libsys.so.1 is ld.so.1). 1377c478bd9Sstevel@tonic-gate */ 1387c478bd9Sstevel@tonic-gate if (((*name == '/') && 139a953e2b1Srie /* BEGIN CSTYLED */ 1407c478bd9Sstevel@tonic-gate #if defined(_ELF64) 1417c478bd9Sstevel@tonic-gate (strcmp(name, MSG_ORIG(MSG_PTH_RTLD_64)) == 0)) || 1427c478bd9Sstevel@tonic-gate #else 1437c478bd9Sstevel@tonic-gate (strcmp(name, MSG_ORIG(MSG_PTH_RTLD)) == 0)) || 1447c478bd9Sstevel@tonic-gate #endif 1457c478bd9Sstevel@tonic-gate (strcmp(name, MSG_ORIG(MSG_FIL_RTLD)) == 0)) { 146a953e2b1Srie /* END CSTYLED */ 14756deab07SRod Evans Pdesc *pdp; 1487c478bd9Sstevel@tonic-gate 1495aefb655Srie DBG_CALL(Dbg_file_fixname(LIST(clmp), name, 1505aefb655Srie MSG_ORIG(MSG_PTH_LIBSYS))); 151dde769a2SRod Evans if ((pdp = alist_append(alpp, NULL, sizeof (Pdesc), 152dde769a2SRod Evans alni)) == NULL) 1537c478bd9Sstevel@tonic-gate return (0); 15456deab07SRod Evans 15556deab07SRod Evans pdp->pd_pname = (char *)MSG_ORIG(MSG_PTH_LIBSYS); 15656deab07SRod Evans pdp->pd_plen = MSG_PTH_LIBSYS_SIZE; 15756deab07SRod Evans pdp->pd_flags = PD_FLG_PNSLASH; 15856deab07SRod Evans 15956deab07SRod Evans return (1); 1607c478bd9Sstevel@tonic-gate } 1617c478bd9Sstevel@tonic-gate 16256deab07SRod Evans return (expand_paths(clmp, name, alpp, alni, orig, 0)); 16356deab07SRod Evans } 16456deab07SRod Evans 16556deab07SRod Evans /* 16656deab07SRod Evans * Determine whether this object requires any hardware or software capabilities. 16756deab07SRod Evans */ 16856deab07SRod Evans static int 16956deab07SRod Evans elf_cap_check(Fdesc *fdp, Ehdr *ehdr, Rej_desc *rej) 17056deab07SRod Evans { 17156deab07SRod Evans Phdr *phdr; 17256deab07SRod Evans int cnt; 17356deab07SRod Evans 17456deab07SRod Evans /* LINTED */ 17556deab07SRod Evans phdr = (Phdr *)((char *)ehdr + ehdr->e_phoff); 17656deab07SRod Evans for (cnt = 0; cnt < ehdr->e_phnum; cnt++, phdr++) { 17756deab07SRod Evans Cap *cptr; 17856deab07SRod Evans 17956deab07SRod Evans if (phdr->p_type != PT_SUNWCAP) 18056deab07SRod Evans continue; 18156deab07SRod Evans 18256deab07SRod Evans /* LINTED */ 18356deab07SRod Evans cptr = (Cap *)((char *)ehdr + phdr->p_offset); 18456deab07SRod Evans while (cptr->c_tag != CA_SUNW_NULL) { 18556deab07SRod Evans if (cptr->c_tag == CA_SUNW_HW_1) { 18656deab07SRod Evans /* 18756deab07SRod Evans * Verify the hardware capabilities. 18856deab07SRod Evans */ 18956deab07SRod Evans if (hwcap_check(cptr->c_un.c_val, rej) == 0) 19056deab07SRod Evans return (0); 19156deab07SRod Evans 19256deab07SRod Evans /* 19356deab07SRod Evans * Retain this hardware capabilities value for 19456deab07SRod Evans * possible later inspection should this object 19556deab07SRod Evans * be processed as a filtee. 19656deab07SRod Evans */ 19756deab07SRod Evans fdp->fd_hwcap = cptr->c_un.c_val; 19856deab07SRod Evans } 19956deab07SRod Evans if (cptr->c_tag == CA_SUNW_SF_1) { 20056deab07SRod Evans /* 20156deab07SRod Evans * Verify the software capabilities. 20256deab07SRod Evans */ 20356deab07SRod Evans if (sfcap_check(cptr->c_un.c_val, rej) == 0) 20456deab07SRod Evans return (0); 20556deab07SRod Evans } 20656deab07SRod Evans cptr++; 20756deab07SRod Evans } 20856deab07SRod Evans } 20956deab07SRod Evans return (1); 2107c478bd9Sstevel@tonic-gate } 2117c478bd9Sstevel@tonic-gate 2127c478bd9Sstevel@tonic-gate /* 2137c478bd9Sstevel@tonic-gate * Determine if we have been given an ELF file and if so determine if the file 2147c478bd9Sstevel@tonic-gate * is compatible. Returns 1 if true, else 0 and sets the reject descriptor 2157c478bd9Sstevel@tonic-gate * with associated error information. 2167c478bd9Sstevel@tonic-gate */ 21756deab07SRod Evans Fct * 21856deab07SRod Evans elf_verify(caddr_t addr, size_t size, Fdesc *fdp, const char *name, 21956deab07SRod Evans Rej_desc *rej) 2207c478bd9Sstevel@tonic-gate { 2217c478bd9Sstevel@tonic-gate Ehdr *ehdr; 22256deab07SRod Evans char *caddr = (char *)addr; 2237c478bd9Sstevel@tonic-gate 2247c478bd9Sstevel@tonic-gate /* 2257c478bd9Sstevel@tonic-gate * Determine if we're an elf file. If not simply return, we don't set 2267c478bd9Sstevel@tonic-gate * any rejection information as this test allows use to scroll through 2277c478bd9Sstevel@tonic-gate * the objects we support (ELF, AOUT). 2287c478bd9Sstevel@tonic-gate */ 22956deab07SRod Evans if (size < sizeof (Ehdr) || 23056deab07SRod Evans caddr[EI_MAG0] != ELFMAG0 || 23156deab07SRod Evans caddr[EI_MAG1] != ELFMAG1 || 23256deab07SRod Evans caddr[EI_MAG2] != ELFMAG2 || 23356deab07SRod Evans caddr[EI_MAG3] != ELFMAG3) { 23456deab07SRod Evans return (NULL); 2357c478bd9Sstevel@tonic-gate } 2367c478bd9Sstevel@tonic-gate 2377c478bd9Sstevel@tonic-gate /* 2387c478bd9Sstevel@tonic-gate * Check class and encoding. 2397c478bd9Sstevel@tonic-gate */ 2407c478bd9Sstevel@tonic-gate /* LINTED */ 24156deab07SRod Evans ehdr = (Ehdr *)addr; 2427c478bd9Sstevel@tonic-gate if (ehdr->e_ident[EI_CLASS] != M_CLASS) { 2437c478bd9Sstevel@tonic-gate rej->rej_type = SGS_REJ_CLASS; 2447c478bd9Sstevel@tonic-gate rej->rej_info = (uint_t)ehdr->e_ident[EI_CLASS]; 24556deab07SRod Evans return (NULL); 2467c478bd9Sstevel@tonic-gate } 2477c478bd9Sstevel@tonic-gate if (ehdr->e_ident[EI_DATA] != M_DATA) { 2487c478bd9Sstevel@tonic-gate rej->rej_type = SGS_REJ_DATA; 2497c478bd9Sstevel@tonic-gate rej->rej_info = (uint_t)ehdr->e_ident[EI_DATA]; 25056deab07SRod Evans return (NULL); 2517c478bd9Sstevel@tonic-gate } 2527c478bd9Sstevel@tonic-gate if ((ehdr->e_type != ET_REL) && (ehdr->e_type != ET_EXEC) && 2537c478bd9Sstevel@tonic-gate (ehdr->e_type != ET_DYN)) { 2547c478bd9Sstevel@tonic-gate rej->rej_type = SGS_REJ_TYPE; 2557c478bd9Sstevel@tonic-gate rej->rej_info = (uint_t)ehdr->e_type; 25656deab07SRod Evans return (NULL); 2577c478bd9Sstevel@tonic-gate } 2587c478bd9Sstevel@tonic-gate 2597c478bd9Sstevel@tonic-gate /* 26056deab07SRod Evans * Verify ELF version. 2617c478bd9Sstevel@tonic-gate */ 2627c478bd9Sstevel@tonic-gate if (ehdr->e_version > EV_CURRENT) { 2637c478bd9Sstevel@tonic-gate rej->rej_type = SGS_REJ_VERSION; 2647c478bd9Sstevel@tonic-gate rej->rej_info = (uint_t)ehdr->e_version; 26556deab07SRod Evans return (NULL); 2667c478bd9Sstevel@tonic-gate } 26756deab07SRod Evans 26856deab07SRod Evans /* 26956deab07SRod Evans * Verify machine specific flags. 27056deab07SRod Evans */ 27156deab07SRod Evans if (elf_mach_flags_check(rej, ehdr) == 0) 27256deab07SRod Evans return (NULL); 27356deab07SRod Evans 27456deab07SRod Evans /* 27556deab07SRod Evans * Verify any hardware/software capability requirements. Note, if this 27656deab07SRod Evans * object is an explicitly defined shared object under inspection by 27756deab07SRod Evans * ldd(1), and contains an incompatible hardware capabilities 27856deab07SRod Evans * requirement, then inform the user, but continue processing. 27956deab07SRod Evans */ 28056deab07SRod Evans if (elf_cap_check(fdp, ehdr, rej) == 0) { 28156deab07SRod Evans Rt_map *lmp = lml_main.lm_head; 28256deab07SRod Evans 283dde769a2SRod Evans if ((lml_main.lm_flags & LML_FLG_TRC_LDDSTUB) && lmp && 284dde769a2SRod Evans (FLAGS1(lmp) & FL1_RT_LDDSTUB) && (NEXT(lmp) == NULL)) { 28556deab07SRod Evans const char *fmt; 28656deab07SRod Evans 28756deab07SRod Evans if (rej->rej_type == SGS_REJ_HWCAP_1) 28856deab07SRod Evans fmt = MSG_INTL(MSG_LDD_GEN_HWCAP_1); 28956deab07SRod Evans else 29056deab07SRod Evans fmt = MSG_INTL(MSG_LDD_GEN_SFCAP_1); 29156deab07SRod Evans (void) printf(fmt, name, rej->rej_str); 29256deab07SRod Evans return (&elf_fct); 29356deab07SRod Evans } 29456deab07SRod Evans return (NULL); 29556deab07SRod Evans } 29656deab07SRod Evans return (&elf_fct); 2977c478bd9Sstevel@tonic-gate } 2987c478bd9Sstevel@tonic-gate 2997c478bd9Sstevel@tonic-gate /* 3007c478bd9Sstevel@tonic-gate * The runtime linker employs lazy loading to provide the libraries needed for 3017c478bd9Sstevel@tonic-gate * debugging, preloading .o's and dldump(). As these are seldom used, the 3027c478bd9Sstevel@tonic-gate * standard startup of ld.so.1 doesn't initialize all the information necessary 3037c478bd9Sstevel@tonic-gate * to perform plt relocation on ld.so.1's link-map. The first time lazy loading 3047c478bd9Sstevel@tonic-gate * is called we get here to perform these initializations: 3057c478bd9Sstevel@tonic-gate * 3062017c965SRod Evans * - elf_needed() is called to set up the DYNINFO() indexes for each lazy 3077c478bd9Sstevel@tonic-gate * dependency. Typically, for all other objects, this is called during 3087c478bd9Sstevel@tonic-gate * analyze_so(), but as ld.so.1 is set-contained we skip this processing. 3097c478bd9Sstevel@tonic-gate * 3102017c965SRod Evans * - For intel, ld.so.1's JMPSLOT relocations need relative updates. These 3117c478bd9Sstevel@tonic-gate * are by default skipped thus delaying all relative relocation processing 3127c478bd9Sstevel@tonic-gate * on every invocation of ld.so.1. 3137c478bd9Sstevel@tonic-gate */ 3147c478bd9Sstevel@tonic-gate int 3157c478bd9Sstevel@tonic-gate elf_rtld_load() 3167c478bd9Sstevel@tonic-gate { 3177c478bd9Sstevel@tonic-gate Lm_list *lml = &lml_rtld; 3187c478bd9Sstevel@tonic-gate Rt_map *lmp = lml->lm_head; 3197c478bd9Sstevel@tonic-gate 3207c478bd9Sstevel@tonic-gate if (lml->lm_flags & LML_FLG_PLTREL) 3217c478bd9Sstevel@tonic-gate return (1); 3227c478bd9Sstevel@tonic-gate 3237c478bd9Sstevel@tonic-gate /* 3247c478bd9Sstevel@tonic-gate * As we need to refer to the DYNINFO() information, insure that it has 3257c478bd9Sstevel@tonic-gate * been initialized. 3267c478bd9Sstevel@tonic-gate */ 3279aa23310Srie if (elf_needed(lml, ALIST_OFF_DATA, lmp, NULL) == 0) 3287c478bd9Sstevel@tonic-gate return (0); 3297c478bd9Sstevel@tonic-gate 33002ca3e02Srie #if defined(__i386) 3317c478bd9Sstevel@tonic-gate /* 3327c478bd9Sstevel@tonic-gate * This is a kludge to give ld.so.1 a performance benefit on i386. 3337c478bd9Sstevel@tonic-gate * It's based around two factors. 3347c478bd9Sstevel@tonic-gate * 3352017c965SRod Evans * - JMPSLOT relocations (PLT's) actually need a relative relocation 3367c478bd9Sstevel@tonic-gate * applied to the GOT entry so that they can find PLT0. 3377c478bd9Sstevel@tonic-gate * 3382017c965SRod Evans * - ld.so.1 does not exercise *any* PLT's before it has made a call 3397c478bd9Sstevel@tonic-gate * to elf_lazy_load(). This is because all dynamic dependencies 3407c478bd9Sstevel@tonic-gate * are recorded as lazy dependencies. 3417c478bd9Sstevel@tonic-gate */ 34256deab07SRod Evans (void) elf_reloc_relative_count((ulong_t)JMPREL(lmp), 3437c478bd9Sstevel@tonic-gate (ulong_t)(PLTRELSZ(lmp) / RELENT(lmp)), (ulong_t)RELENT(lmp), 34456deab07SRod Evans (ulong_t)ADDR(lmp), lmp, NULL); 3457c478bd9Sstevel@tonic-gate #endif 3467c478bd9Sstevel@tonic-gate 3477c478bd9Sstevel@tonic-gate lml->lm_flags |= LML_FLG_PLTREL; 3487c478bd9Sstevel@tonic-gate return (1); 3497c478bd9Sstevel@tonic-gate } 3507c478bd9Sstevel@tonic-gate 3517c478bd9Sstevel@tonic-gate /* 3527c478bd9Sstevel@tonic-gate * Lazy load an object. 3537c478bd9Sstevel@tonic-gate */ 3547c478bd9Sstevel@tonic-gate Rt_map * 3559aa23310Srie elf_lazy_load(Rt_map *clmp, Slookup *slp, uint_t ndx, const char *sym, 3562017c965SRod Evans uint_t flags, Grp_hdl **hdl, int *in_nfavl) 3577c478bd9Sstevel@tonic-gate { 35856deab07SRod Evans Alist *palp = NULL; 359dde769a2SRod Evans Rt_map *nlmp; 36075e7992aSrie Dyninfo *dip = &DYNINFO(clmp)[ndx], *pdip; 3617c478bd9Sstevel@tonic-gate const char *name; 3627c478bd9Sstevel@tonic-gate Lm_list *lml = LIST(clmp); 3637c478bd9Sstevel@tonic-gate Aliste lmco; 3647c478bd9Sstevel@tonic-gate 3657c478bd9Sstevel@tonic-gate /* 3667c478bd9Sstevel@tonic-gate * If this dependency has already been processed, we're done. 3677c478bd9Sstevel@tonic-gate */ 36856deab07SRod Evans if (((nlmp = (Rt_map *)dip->di_info) != NULL) || 36975e7992aSrie (dip->di_flags & FLG_DI_LDD_DONE)) 3707c478bd9Sstevel@tonic-gate return (nlmp); 3717c478bd9Sstevel@tonic-gate 3727c478bd9Sstevel@tonic-gate /* 37375e7992aSrie * If we're running under ldd(1), indicate that this dependency has been 37475e7992aSrie * processed (see test above). It doesn't matter whether the object is 37575e7992aSrie * successfully loaded or not, this flag simply ensures that we don't 37675e7992aSrie * repeatedly attempt to load an object that has already failed to load. 37775e7992aSrie * To do so would create multiple failure diagnostics for the same 37875e7992aSrie * object under ldd(1). 37975e7992aSrie */ 38075e7992aSrie if (lml->lm_flags & LML_FLG_TRC_ENABLE) 38175e7992aSrie dip->di_flags |= FLG_DI_LDD_DONE; 38275e7992aSrie 38375e7992aSrie /* 38475e7992aSrie * Determine the initial dependency name. 3857c478bd9Sstevel@tonic-gate */ 3867c478bd9Sstevel@tonic-gate name = STRTAB(clmp) + DYN(clmp)[ndx].d_un.d_val; 3875aefb655Srie DBG_CALL(Dbg_file_lazyload(clmp, name, sym)); 3887c478bd9Sstevel@tonic-gate 38975e7992aSrie /* 39075e7992aSrie * If this object needs to establish its own group, make sure a handle 39175e7992aSrie * is created. 39275e7992aSrie */ 3937c478bd9Sstevel@tonic-gate if (dip->di_flags & FLG_DI_GROUP) 3942017c965SRod Evans flags |= (FLG_RT_SETGROUP | FLG_RT_PUBHDL); 3957c478bd9Sstevel@tonic-gate 39675e7992aSrie /* 39775e7992aSrie * Lazy dependencies are identified as DT_NEEDED entries with a 39875e7992aSrie * DF_P1_LAZYLOAD flag in the previous DT_POSFLAG_1 element. The 39975e7992aSrie * dynamic information element that corresponds to the DT_POSFLAG_1 40075e7992aSrie * entry is free, and thus used to store the present entrance 40175e7992aSrie * identifier. This identifier is used to prevent multiple attempts to 40275e7992aSrie * load a failed lazy loadable dependency within the same runtime linker 40375e7992aSrie * operation. However, future attempts to reload this dependency are 40475e7992aSrie * still possible. 40575e7992aSrie */ 40675e7992aSrie if (ndx && (pdip = dip - 1) && (pdip->di_flags & FLG_DI_POSFLAG1)) 40775e7992aSrie pdip->di_info = (void *)slp->sl_id; 40875e7992aSrie 4097c478bd9Sstevel@tonic-gate /* 4107c478bd9Sstevel@tonic-gate * Expand the requested name if necessary. 4117c478bd9Sstevel@tonic-gate */ 41256deab07SRod Evans if (elf_fix_name(name, clmp, &palp, AL_CNT_NEEDED, 0) == 0) 41356deab07SRod Evans return (NULL); 4147c478bd9Sstevel@tonic-gate 4157c478bd9Sstevel@tonic-gate /* 416dde769a2SRod Evans * Establish a link-map control list for this request. 4177c478bd9Sstevel@tonic-gate */ 418dde769a2SRod Evans if ((lmco = create_cntl(lml, 0)) == NULL) { 419dde769a2SRod Evans remove_plist(&palp, 1); 420dde769a2SRod Evans return (NULL); 421dde769a2SRod Evans } 4227c478bd9Sstevel@tonic-gate 4237c478bd9Sstevel@tonic-gate /* 4247c478bd9Sstevel@tonic-gate * Load the associated object. 4257c478bd9Sstevel@tonic-gate */ 4267c478bd9Sstevel@tonic-gate dip->di_info = nlmp = 4272017c965SRod Evans load_one(lml, lmco, palp, clmp, MODE(clmp), flags, hdl, in_nfavl); 4287c478bd9Sstevel@tonic-gate 4297c478bd9Sstevel@tonic-gate /* 4307c478bd9Sstevel@tonic-gate * Remove any expanded pathname infrastructure. Reduce the pending lazy 4317c478bd9Sstevel@tonic-gate * dependency count of the caller, together with the link-map lists 4327c478bd9Sstevel@tonic-gate * count of objects that still have lazy dependencies pending. 4337c478bd9Sstevel@tonic-gate */ 43456deab07SRod Evans remove_plist(&palp, 1); 4357c478bd9Sstevel@tonic-gate if (--LAZY(clmp) == 0) 4367c478bd9Sstevel@tonic-gate LIST(clmp)->lm_lazy--; 4377c478bd9Sstevel@tonic-gate 4387c478bd9Sstevel@tonic-gate /* 43902ca3e02Srie * Finish processing the objects associated with this request, and 44002ca3e02Srie * create an association between the caller and this dependency. 4417c478bd9Sstevel@tonic-gate */ 44275e7992aSrie if (nlmp && ((bind_one(clmp, nlmp, BND_NEEDED) == 0) || 44356deab07SRod Evans ((nlmp = analyze_lmc(lml, lmco, nlmp, in_nfavl)) == NULL) || 4449aa23310Srie (relocate_lmc(lml, lmco, clmp, nlmp, in_nfavl) == 0))) 44556deab07SRod Evans dip->di_info = nlmp = NULL; 4467c478bd9Sstevel@tonic-gate 4477c478bd9Sstevel@tonic-gate /* 44802ca3e02Srie * If this lazyload has failed, and we've created a new link-map 44902ca3e02Srie * control list to which this request has added objects, then remove 45002ca3e02Srie * all the objects that have been associated to this request. 4517c478bd9Sstevel@tonic-gate */ 452481bba9eSRod Evans if ((nlmp == NULL) && (lmco != ALIST_OFF_DATA)) 453481bba9eSRod Evans remove_lmc(lml, clmp, lmco, name); 4547c478bd9Sstevel@tonic-gate 4557c478bd9Sstevel@tonic-gate /* 456dde769a2SRod Evans * Remove any temporary link-map control list. 4577c478bd9Sstevel@tonic-gate */ 458481bba9eSRod Evans if (lmco != ALIST_OFF_DATA) 4597c478bd9Sstevel@tonic-gate remove_cntl(lml, lmco); 4607c478bd9Sstevel@tonic-gate 46175e7992aSrie /* 46275e7992aSrie * If this lazy loading failed, record the fact, and bump the lazy 46375e7992aSrie * counts. 46475e7992aSrie */ 46556deab07SRod Evans if (nlmp == NULL) { 46675e7992aSrie dip->di_flags |= FLG_DI_LAZYFAIL; 46775e7992aSrie if (LAZY(clmp)++ == 0) 46875e7992aSrie LIST(clmp)->lm_lazy++; 46975e7992aSrie } 47075e7992aSrie 4717c478bd9Sstevel@tonic-gate return (nlmp); 4727c478bd9Sstevel@tonic-gate } 4737c478bd9Sstevel@tonic-gate 4747c478bd9Sstevel@tonic-gate /* 4757c478bd9Sstevel@tonic-gate * Return the entry point of the ELF executable. 4767c478bd9Sstevel@tonic-gate */ 47756deab07SRod Evans static Addr 47856deab07SRod Evans elf_entry_point(void) 4797c478bd9Sstevel@tonic-gate { 48056deab07SRod Evans Rt_map *lmp = lml_main.lm_head; 48156deab07SRod Evans Ehdr *ehdr = (Ehdr *)ADDR(lmp); 48256deab07SRod Evans Addr addr = (Addr)(ehdr->e_entry); 4837c478bd9Sstevel@tonic-gate 48456deab07SRod Evans if ((FLAGS(lmp) & FLG_RT_FIXED) == 0) 48556deab07SRod Evans addr += ADDR(lmp); 4867c478bd9Sstevel@tonic-gate 48756deab07SRod Evans return (addr); 4887c478bd9Sstevel@tonic-gate } 4897c478bd9Sstevel@tonic-gate 4907c478bd9Sstevel@tonic-gate /* 4917c478bd9Sstevel@tonic-gate * Determine if a dependency requires a particular version and if so verify 4927c478bd9Sstevel@tonic-gate * that the version exists in the dependency. 4937c478bd9Sstevel@tonic-gate */ 49456deab07SRod Evans int 4957c478bd9Sstevel@tonic-gate elf_verify_vers(const char *name, Rt_map *clmp, Rt_map *nlmp) 4967c478bd9Sstevel@tonic-gate { 4977c478bd9Sstevel@tonic-gate Verneed *vnd = VERNEED(clmp); 4987c478bd9Sstevel@tonic-gate int _num, num = VERNEEDNUM(clmp); 4997c478bd9Sstevel@tonic-gate char *cstrs = (char *)STRTAB(clmp); 5007c478bd9Sstevel@tonic-gate Lm_list *lml = LIST(clmp); 5017c478bd9Sstevel@tonic-gate 5027c478bd9Sstevel@tonic-gate /* 5037c478bd9Sstevel@tonic-gate * Traverse the callers version needed information and determine if any 5047c478bd9Sstevel@tonic-gate * specific versions are required from the dependency. 5057c478bd9Sstevel@tonic-gate */ 5065aefb655Srie DBG_CALL(Dbg_ver_need_title(LIST(clmp), NAME(clmp))); 5077c478bd9Sstevel@tonic-gate for (_num = 1; _num <= num; _num++, 5087c478bd9Sstevel@tonic-gate vnd = (Verneed *)((Xword)vnd + vnd->vn_next)) { 5097c478bd9Sstevel@tonic-gate Half cnt = vnd->vn_cnt; 5107c478bd9Sstevel@tonic-gate Vernaux *vnap; 5117c478bd9Sstevel@tonic-gate char *nstrs, *need; 5127c478bd9Sstevel@tonic-gate 5137c478bd9Sstevel@tonic-gate /* 5147c478bd9Sstevel@tonic-gate * Determine if a needed entry matches this dependency. 5157c478bd9Sstevel@tonic-gate */ 5167c478bd9Sstevel@tonic-gate need = (char *)(cstrs + vnd->vn_file); 5177c478bd9Sstevel@tonic-gate if (strcmp(name, need) != 0) 5187c478bd9Sstevel@tonic-gate continue; 5197c478bd9Sstevel@tonic-gate 5207c478bd9Sstevel@tonic-gate if ((lml->lm_flags & LML_FLG_TRC_VERBOSE) && 5217c478bd9Sstevel@tonic-gate ((FLAGS1(clmp) & FL1_RT_LDDSTUB) == 0)) 5227c478bd9Sstevel@tonic-gate (void) printf(MSG_INTL(MSG_LDD_VER_FIND), name); 5237c478bd9Sstevel@tonic-gate 5247c478bd9Sstevel@tonic-gate /* 5257c478bd9Sstevel@tonic-gate * Validate that each version required actually exists in the 5267c478bd9Sstevel@tonic-gate * dependency. 5277c478bd9Sstevel@tonic-gate */ 5287c478bd9Sstevel@tonic-gate nstrs = (char *)STRTAB(nlmp); 5297c478bd9Sstevel@tonic-gate 5307c478bd9Sstevel@tonic-gate for (vnap = (Vernaux *)((Xword)vnd + vnd->vn_aux); cnt; 5317c478bd9Sstevel@tonic-gate cnt--, vnap = (Vernaux *)((Xword)vnap + vnap->vna_next)) { 5327c478bd9Sstevel@tonic-gate char *version, *define; 5337c478bd9Sstevel@tonic-gate Verdef *vdf = VERDEF(nlmp); 5347c478bd9Sstevel@tonic-gate ulong_t _num, num = VERDEFNUM(nlmp); 5357c478bd9Sstevel@tonic-gate int found = 0; 5367c478bd9Sstevel@tonic-gate 537090a8d9eSAli Bahrami /* 538090a8d9eSAli Bahrami * Skip validation of versions that are marked 539090a8d9eSAli Bahrami * INFO. This optimization is used for versions 540090a8d9eSAli Bahrami * that are inherited by another version. Verification 541090a8d9eSAli Bahrami * of the inheriting version is sufficient. 542090a8d9eSAli Bahrami * 543090a8d9eSAli Bahrami * Such versions are recorded in the object for the 544090a8d9eSAli Bahrami * benefit of VERSYM entries that refer to them. This 545090a8d9eSAli Bahrami * provides a purely diagnositic benefit. 546090a8d9eSAli Bahrami */ 547090a8d9eSAli Bahrami if (vnap->vna_flags & VER_FLG_INFO) 548090a8d9eSAli Bahrami continue; 549090a8d9eSAli Bahrami 5507c478bd9Sstevel@tonic-gate version = (char *)(cstrs + vnap->vna_name); 5515aefb655Srie DBG_CALL(Dbg_ver_need_entry(lml, 0, need, version)); 5527c478bd9Sstevel@tonic-gate 5537c478bd9Sstevel@tonic-gate for (_num = 1; _num <= num; _num++, 5547c478bd9Sstevel@tonic-gate vdf = (Verdef *)((Xword)vdf + vdf->vd_next)) { 5557c478bd9Sstevel@tonic-gate Verdaux *vdap; 5567c478bd9Sstevel@tonic-gate 5577c478bd9Sstevel@tonic-gate if (vnap->vna_hash != vdf->vd_hash) 5587c478bd9Sstevel@tonic-gate continue; 5597c478bd9Sstevel@tonic-gate 5607c478bd9Sstevel@tonic-gate vdap = (Verdaux *)((Xword)vdf + vdf->vd_aux); 5617c478bd9Sstevel@tonic-gate define = (char *)(nstrs + vdap->vda_name); 5627c478bd9Sstevel@tonic-gate if (strcmp(version, define) != 0) 5637c478bd9Sstevel@tonic-gate continue; 5647c478bd9Sstevel@tonic-gate 5657c478bd9Sstevel@tonic-gate found++; 5667c478bd9Sstevel@tonic-gate break; 5677c478bd9Sstevel@tonic-gate } 5687c478bd9Sstevel@tonic-gate 5697c478bd9Sstevel@tonic-gate /* 5707c478bd9Sstevel@tonic-gate * If we're being traced print out any matched version 5717c478bd9Sstevel@tonic-gate * when the verbose (-v) option is in effect. Always 5727c478bd9Sstevel@tonic-gate * print any unmatched versions. 5737c478bd9Sstevel@tonic-gate */ 5747c478bd9Sstevel@tonic-gate if (lml->lm_flags & LML_FLG_TRC_ENABLE) { 575a953e2b1Srie /* BEGIN CSTYLED */ 5767c478bd9Sstevel@tonic-gate if (found) { 5777c478bd9Sstevel@tonic-gate if (!(lml->lm_flags & LML_FLG_TRC_VERBOSE)) 5787c478bd9Sstevel@tonic-gate continue; 5797c478bd9Sstevel@tonic-gate 5807c478bd9Sstevel@tonic-gate (void) printf(MSG_ORIG(MSG_LDD_VER_FOUND), 5817c478bd9Sstevel@tonic-gate need, version, NAME(nlmp)); 5827c478bd9Sstevel@tonic-gate } else { 5837c478bd9Sstevel@tonic-gate if (rtld_flags & RT_FL_SILENCERR) 5847c478bd9Sstevel@tonic-gate continue; 5857c478bd9Sstevel@tonic-gate 5867c478bd9Sstevel@tonic-gate (void) printf(MSG_INTL(MSG_LDD_VER_NFOUND), 5877c478bd9Sstevel@tonic-gate need, version); 5887c478bd9Sstevel@tonic-gate } 589a953e2b1Srie /* END CSTYLED */ 5907c478bd9Sstevel@tonic-gate continue; 5917c478bd9Sstevel@tonic-gate } 5927c478bd9Sstevel@tonic-gate 5937c478bd9Sstevel@tonic-gate /* 5947c478bd9Sstevel@tonic-gate * If the version hasn't been found then this is a 5957c478bd9Sstevel@tonic-gate * candidate for a fatal error condition. Weak 5967c478bd9Sstevel@tonic-gate * version definition requirements are silently 5977c478bd9Sstevel@tonic-gate * ignored. Also, if the image inspected for a version 5987c478bd9Sstevel@tonic-gate * definition has no versioning recorded at all then 5997c478bd9Sstevel@tonic-gate * silently ignore this (this provides better backward 6007c478bd9Sstevel@tonic-gate * compatibility to old images created prior to 6017c478bd9Sstevel@tonic-gate * versioning being available). Both of these skipped 6027c478bd9Sstevel@tonic-gate * diagnostics are available under tracing (see above). 6037c478bd9Sstevel@tonic-gate */ 6047c478bd9Sstevel@tonic-gate if ((found == 0) && (num != 0) && 6057c478bd9Sstevel@tonic-gate (!(vnap->vna_flags & VER_FLG_WEAK))) { 6065aefb655Srie eprintf(lml, ERR_FATAL, 6075aefb655Srie MSG_INTL(MSG_VER_NFOUND), need, version, 6085aefb655Srie NAME(clmp)); 6097c478bd9Sstevel@tonic-gate return (0); 6107c478bd9Sstevel@tonic-gate } 6117c478bd9Sstevel@tonic-gate } 6127c478bd9Sstevel@tonic-gate } 613*20272c2eSAli Bahrami DBG_CALL(Dbg_ver_need_done(lml)); 6147c478bd9Sstevel@tonic-gate return (1); 6157c478bd9Sstevel@tonic-gate } 6167c478bd9Sstevel@tonic-gate 6177c478bd9Sstevel@tonic-gate /* 6187c478bd9Sstevel@tonic-gate * Search through the dynamic section for DT_NEEDED entries and perform one 6197c478bd9Sstevel@tonic-gate * of two functions. If only the first argument is specified then load the 6207c478bd9Sstevel@tonic-gate * defined shared object, otherwise add the link map representing the defined 6217c478bd9Sstevel@tonic-gate * link map the the dlopen list. 6227c478bd9Sstevel@tonic-gate */ 6237c478bd9Sstevel@tonic-gate static int 6249aa23310Srie elf_needed(Lm_list *lml, Aliste lmco, Rt_map *clmp, int *in_nfavl) 6257c478bd9Sstevel@tonic-gate { 62656deab07SRod Evans Alist *palp = NULL; 62775e7992aSrie Dyn *dyn, *pdyn; 6287c478bd9Sstevel@tonic-gate ulong_t ndx = 0; 62975e7992aSrie uint_t lazy, flags; 6307c478bd9Sstevel@tonic-gate Word lmflags = lml->lm_flags; 6317c478bd9Sstevel@tonic-gate Word lmtflags = lml->lm_tflags; 6327c478bd9Sstevel@tonic-gate 6337c478bd9Sstevel@tonic-gate /* 6347c478bd9Sstevel@tonic-gate * Process each shared object on needed list. 6357c478bd9Sstevel@tonic-gate */ 636481bba9eSRod Evans if (DYN(clmp) == NULL) 6377c478bd9Sstevel@tonic-gate return (1); 6387c478bd9Sstevel@tonic-gate 63975e7992aSrie for (dyn = (Dyn *)DYN(clmp), pdyn = NULL; dyn->d_tag != DT_NULL; 64075e7992aSrie pdyn = dyn++, ndx++) { 6417c478bd9Sstevel@tonic-gate Dyninfo *dip = &DYNINFO(clmp)[ndx]; 642481bba9eSRod Evans Rt_map *nlmp = NULL; 6437c478bd9Sstevel@tonic-gate char *name; 6447c478bd9Sstevel@tonic-gate int silent = 0; 6457c478bd9Sstevel@tonic-gate 6467c478bd9Sstevel@tonic-gate switch (dyn->d_tag) { 6477c478bd9Sstevel@tonic-gate case DT_POSFLAG_1: 64875e7992aSrie dip->di_flags |= FLG_DI_POSFLAG1; 6497c478bd9Sstevel@tonic-gate continue; 6507c478bd9Sstevel@tonic-gate case DT_NEEDED: 6517c478bd9Sstevel@tonic-gate case DT_USED: 65275e7992aSrie lazy = flags = 0; 6537c478bd9Sstevel@tonic-gate dip->di_flags |= FLG_DI_NEEDED; 65475e7992aSrie 65575e7992aSrie if (pdyn && (pdyn->d_tag == DT_POSFLAG_1)) { 65675e7992aSrie if ((pdyn->d_un.d_val & DF_P1_LAZYLOAD) && 65775e7992aSrie ((lmtflags & LML_TFLG_NOLAZYLD) == 0)) { 65875e7992aSrie dip->di_flags |= FLG_DI_LAZY; 65975e7992aSrie lazy = 1; 66075e7992aSrie } 66175e7992aSrie if (pdyn->d_un.d_val & DF_P1_GROUPPERM) { 66275e7992aSrie dip->di_flags |= FLG_DI_GROUP; 66375e7992aSrie flags = 6642017c965SRod Evans (FLG_RT_SETGROUP | FLG_RT_PUBHDL); 66575e7992aSrie } 66675e7992aSrie } 6677c478bd9Sstevel@tonic-gate 6687c478bd9Sstevel@tonic-gate name = (char *)STRTAB(clmp) + dyn->d_un.d_val; 6697c478bd9Sstevel@tonic-gate 6707c478bd9Sstevel@tonic-gate /* 6717c478bd9Sstevel@tonic-gate * NOTE, libc.so.1 can't be lazy loaded. Although a 6727c478bd9Sstevel@tonic-gate * lazy position flag won't be produced when a RTLDINFO 6737c478bd9Sstevel@tonic-gate * .dynamic entry is found (introduced with the UPM in 6747c478bd9Sstevel@tonic-gate * Solaris 10), it was possible to mark libc for lazy 6757c478bd9Sstevel@tonic-gate * loading on previous releases. To reduce the overhead 6767c478bd9Sstevel@tonic-gate * of testing for this occurrence, only carry out this 6777c478bd9Sstevel@tonic-gate * check for the first object on the link-map list 6787c478bd9Sstevel@tonic-gate * (there aren't many applications built without libc). 6797c478bd9Sstevel@tonic-gate */ 6807c478bd9Sstevel@tonic-gate if (lazy && (lml->lm_head == clmp) && 6817c478bd9Sstevel@tonic-gate (strcmp(name, MSG_ORIG(MSG_FIL_LIBC)) == 0)) 6827c478bd9Sstevel@tonic-gate lazy = 0; 6837c478bd9Sstevel@tonic-gate 6847c478bd9Sstevel@tonic-gate /* 6857c478bd9Sstevel@tonic-gate * Don't bring in lazy loaded objects yet unless we've 6867c478bd9Sstevel@tonic-gate * been asked to attempt to load all available objects 6877c478bd9Sstevel@tonic-gate * (crle(1) sets LD_FLAGS=loadavail). Even under 6887c478bd9Sstevel@tonic-gate * RTLD_NOW we don't process this - RTLD_NOW will cause 6897c478bd9Sstevel@tonic-gate * relocation processing which in turn might trigger 6907c478bd9Sstevel@tonic-gate * lazy loading, but its possible that the object has a 6917c478bd9Sstevel@tonic-gate * lazy loaded file with no bindings (i.e., it should 6927c478bd9Sstevel@tonic-gate * never have been a dependency in the first place). 6937c478bd9Sstevel@tonic-gate */ 6947c478bd9Sstevel@tonic-gate if (lazy) { 6957c478bd9Sstevel@tonic-gate if ((lmflags & LML_FLG_LOADAVAIL) == 0) { 6967c478bd9Sstevel@tonic-gate LAZY(clmp)++; 6977c478bd9Sstevel@tonic-gate lazy = flags = 0; 6987c478bd9Sstevel@tonic-gate continue; 6997c478bd9Sstevel@tonic-gate } 7007c478bd9Sstevel@tonic-gate 7017c478bd9Sstevel@tonic-gate /* 7027c478bd9Sstevel@tonic-gate * Silence any error messages - see description 7037c478bd9Sstevel@tonic-gate * under elf_lookup_filtee(). 7047c478bd9Sstevel@tonic-gate */ 7057c478bd9Sstevel@tonic-gate if ((rtld_flags & RT_FL_SILENCERR) == 0) { 7067c478bd9Sstevel@tonic-gate rtld_flags |= RT_FL_SILENCERR; 7077c478bd9Sstevel@tonic-gate silent = 1; 7087c478bd9Sstevel@tonic-gate } 7097c478bd9Sstevel@tonic-gate } 7107c478bd9Sstevel@tonic-gate break; 7117c478bd9Sstevel@tonic-gate case DT_AUXILIARY: 7127c478bd9Sstevel@tonic-gate dip->di_flags |= FLG_DI_AUXFLTR; 7137c478bd9Sstevel@tonic-gate continue; 7147c478bd9Sstevel@tonic-gate case DT_SUNW_AUXILIARY: 7157c478bd9Sstevel@tonic-gate dip->di_flags |= (FLG_DI_AUXFLTR | FLG_DI_SYMFLTR); 7167c478bd9Sstevel@tonic-gate continue; 7177c478bd9Sstevel@tonic-gate case DT_FILTER: 7187c478bd9Sstevel@tonic-gate dip->di_flags |= FLG_DI_STDFLTR; 7197c478bd9Sstevel@tonic-gate continue; 7207c478bd9Sstevel@tonic-gate case DT_SUNW_FILTER: 7217c478bd9Sstevel@tonic-gate dip->di_flags |= (FLG_DI_STDFLTR | FLG_DI_SYMFLTR); 7227c478bd9Sstevel@tonic-gate continue; 7237c478bd9Sstevel@tonic-gate default: 7247c478bd9Sstevel@tonic-gate continue; 7257c478bd9Sstevel@tonic-gate } 7267c478bd9Sstevel@tonic-gate 7275aefb655Srie DBG_CALL(Dbg_file_needed(clmp, name)); 72875e7992aSrie 72975e7992aSrie /* 73075e7992aSrie * If we're running under ldd(1), indicate that this dependency 73175e7992aSrie * has been processed. It doesn't matter whether the object is 73275e7992aSrie * successfully loaded or not, this flag simply ensures that we 73375e7992aSrie * don't repeatedly attempt to load an object that has already 73475e7992aSrie * failed to load. To do so would create multiple failure 73575e7992aSrie * diagnostics for the same object under ldd(1). 73675e7992aSrie */ 7377c478bd9Sstevel@tonic-gate if (lml->lm_flags & LML_FLG_TRC_ENABLE) 73875e7992aSrie dip->di_flags |= FLG_DI_LDD_DONE; 7397c478bd9Sstevel@tonic-gate 7407c478bd9Sstevel@tonic-gate /* 7417c478bd9Sstevel@tonic-gate * Establish the objects name, load it and establish a binding 7427c478bd9Sstevel@tonic-gate * with the caller. 7437c478bd9Sstevel@tonic-gate */ 74456deab07SRod Evans if ((elf_fix_name(name, clmp, &palp, AL_CNT_NEEDED, 0) == 0) || 74556deab07SRod Evans ((nlmp = load_one(lml, lmco, palp, clmp, MODE(clmp), 74656deab07SRod Evans flags, 0, in_nfavl)) == NULL) || 74756deab07SRod Evans (bind_one(clmp, nlmp, BND_NEEDED) == 0)) 748481bba9eSRod Evans nlmp = NULL; 7497c478bd9Sstevel@tonic-gate 7507c478bd9Sstevel@tonic-gate /* 7517c478bd9Sstevel@tonic-gate * Clean up any infrastructure, including the removal of the 7527c478bd9Sstevel@tonic-gate * error suppression state, if it had been previously set in 7537c478bd9Sstevel@tonic-gate * this routine. 7547c478bd9Sstevel@tonic-gate */ 75556deab07SRod Evans remove_plist(&palp, 0); 75656deab07SRod Evans 7577c478bd9Sstevel@tonic-gate if (silent) 7587c478bd9Sstevel@tonic-gate rtld_flags &= ~RT_FL_SILENCERR; 75975e7992aSrie 760481bba9eSRod Evans if ((dip->di_info = (void *)nlmp) == NULL) { 7617c478bd9Sstevel@tonic-gate /* 7627c478bd9Sstevel@tonic-gate * If the object could not be mapped, continue if error 7637c478bd9Sstevel@tonic-gate * suppression is established or we're here with ldd(1). 7647c478bd9Sstevel@tonic-gate */ 7657c478bd9Sstevel@tonic-gate if ((MODE(clmp) & RTLD_CONFGEN) || (lmflags & 7667c478bd9Sstevel@tonic-gate (LML_FLG_LOADAVAIL | LML_FLG_TRC_ENABLE))) 7677c478bd9Sstevel@tonic-gate continue; 76856deab07SRod Evans else { 76956deab07SRod Evans remove_plist(&palp, 1); 7707c478bd9Sstevel@tonic-gate return (0); 77156deab07SRod Evans } 7727c478bd9Sstevel@tonic-gate } 7737c478bd9Sstevel@tonic-gate } 7747c478bd9Sstevel@tonic-gate 7757c478bd9Sstevel@tonic-gate if (LAZY(clmp)) 7767c478bd9Sstevel@tonic-gate lml->lm_lazy++; 7777c478bd9Sstevel@tonic-gate 77856deab07SRod Evans remove_plist(&palp, 1); 7797c478bd9Sstevel@tonic-gate return (1); 7807c478bd9Sstevel@tonic-gate } 7817c478bd9Sstevel@tonic-gate 7827c478bd9Sstevel@tonic-gate /* 7837c478bd9Sstevel@tonic-gate * A null symbol interpretor. Used if a filter has no associated filtees. 7847c478bd9Sstevel@tonic-gate */ 7857c478bd9Sstevel@tonic-gate /* ARGSUSED0 */ 7867c478bd9Sstevel@tonic-gate static Sym * 7879aa23310Srie elf_null_find_sym(Slookup *slp, Rt_map **dlmp, uint_t *binfo, int *in_nfavl) 7887c478bd9Sstevel@tonic-gate { 78937ffaf83SRod Evans return (NULL); 7907c478bd9Sstevel@tonic-gate } 7917c478bd9Sstevel@tonic-gate 7927c478bd9Sstevel@tonic-gate /* 7937c478bd9Sstevel@tonic-gate * Disable filtee use. 7947c478bd9Sstevel@tonic-gate */ 7957c478bd9Sstevel@tonic-gate static void 7969a411307Srie elf_disable_filtee(Rt_map *lmp, Dyninfo *dip) 7977c478bd9Sstevel@tonic-gate { 7987c478bd9Sstevel@tonic-gate if ((dip->di_flags & FLG_DI_SYMFLTR) == 0) { 7997c478bd9Sstevel@tonic-gate /* 80056deab07SRod Evans * If this is an object filter, null out the reference name. 8017c478bd9Sstevel@tonic-gate */ 8027c478bd9Sstevel@tonic-gate if (OBJFLTRNDX(lmp) != FLTR_DISABLED) { 80337ffaf83SRod Evans REFNAME(lmp) = NULL; 8047c478bd9Sstevel@tonic-gate OBJFLTRNDX(lmp) = FLTR_DISABLED; 8057c478bd9Sstevel@tonic-gate 8067c478bd9Sstevel@tonic-gate /* 8077c478bd9Sstevel@tonic-gate * Indicate that this filtee is no longer available. 8087c478bd9Sstevel@tonic-gate */ 8097c478bd9Sstevel@tonic-gate if (dip->di_flags & FLG_DI_STDFLTR) 8107c478bd9Sstevel@tonic-gate SYMINTP(lmp) = elf_null_find_sym; 8117c478bd9Sstevel@tonic-gate 8127c478bd9Sstevel@tonic-gate } 8137c478bd9Sstevel@tonic-gate } else if (dip->di_flags & FLG_DI_STDFLTR) { 8147c478bd9Sstevel@tonic-gate /* 8157c478bd9Sstevel@tonic-gate * Indicate that this standard filtee is no longer available. 8167c478bd9Sstevel@tonic-gate */ 8177c478bd9Sstevel@tonic-gate if (SYMSFLTRCNT(lmp)) 8187c478bd9Sstevel@tonic-gate SYMSFLTRCNT(lmp)--; 8197c478bd9Sstevel@tonic-gate } else { 8207c478bd9Sstevel@tonic-gate /* 8217c478bd9Sstevel@tonic-gate * Indicate that this auxiliary filtee is no longer available. 8227c478bd9Sstevel@tonic-gate */ 8237c478bd9Sstevel@tonic-gate if (SYMAFLTRCNT(lmp)) 8247c478bd9Sstevel@tonic-gate SYMAFLTRCNT(lmp)--; 8257c478bd9Sstevel@tonic-gate } 8267c478bd9Sstevel@tonic-gate dip->di_flags &= ~MSK_DI_FILTER; 8277c478bd9Sstevel@tonic-gate } 8287c478bd9Sstevel@tonic-gate 8297c478bd9Sstevel@tonic-gate /* 8307c478bd9Sstevel@tonic-gate * Find symbol interpreter - filters. 8317c478bd9Sstevel@tonic-gate * This function is called when the symbols from a shared object should 8327c478bd9Sstevel@tonic-gate * be resolved from the shared objects filtees instead of from within itself. 8337c478bd9Sstevel@tonic-gate * 8347c478bd9Sstevel@tonic-gate * A symbol name of 0 is used to trigger filtee loading. 8357c478bd9Sstevel@tonic-gate */ 8367c478bd9Sstevel@tonic-gate static Sym * 8379aa23310Srie _elf_lookup_filtee(Slookup *slp, Rt_map **dlmp, uint_t *binfo, uint_t ndx, 8389aa23310Srie int *in_nfavl) 8397c478bd9Sstevel@tonic-gate { 8407c478bd9Sstevel@tonic-gate const char *name = slp->sl_name, *filtees; 8417c478bd9Sstevel@tonic-gate Rt_map *clmp = slp->sl_cmap; 8427c478bd9Sstevel@tonic-gate Rt_map *ilmp = slp->sl_imap; 84356deab07SRod Evans Pdesc *pdp; 8447c478bd9Sstevel@tonic-gate int any; 8457c478bd9Sstevel@tonic-gate Dyninfo *dip = &DYNINFO(ilmp)[ndx]; 8467c478bd9Sstevel@tonic-gate Lm_list *lml = LIST(ilmp); 84756deab07SRod Evans Aliste idx; 8487c478bd9Sstevel@tonic-gate 8497c478bd9Sstevel@tonic-gate /* 8507c478bd9Sstevel@tonic-gate * Indicate that the filter has been used. If a binding already exists 8517c478bd9Sstevel@tonic-gate * to the caller, indicate that this object is referenced. This insures 8527c478bd9Sstevel@tonic-gate * we don't generate false unreferenced diagnostics from ldd -u/U or 8537c478bd9Sstevel@tonic-gate * debugging. Don't create a binding regardless, as this filter may 8547c478bd9Sstevel@tonic-gate * have been dlopen()'ed. 8557c478bd9Sstevel@tonic-gate */ 8567c478bd9Sstevel@tonic-gate if (name && (ilmp != clmp)) { 8577c478bd9Sstevel@tonic-gate Word tracing = (LIST(clmp)->lm_flags & 8587c478bd9Sstevel@tonic-gate (LML_FLG_TRC_UNREF | LML_FLG_TRC_UNUSED)); 8597c478bd9Sstevel@tonic-gate 8605aefb655Srie if (tracing || DBG_ENABLED) { 861cce0e03bSab Bnd_desc *bdp; 862cce0e03bSab Aliste idx; 8637c478bd9Sstevel@tonic-gate 8647c478bd9Sstevel@tonic-gate FLAGS1(ilmp) |= FL1_RT_USED; 8657c478bd9Sstevel@tonic-gate 8665aefb655Srie if ((tracing & LML_FLG_TRC_UNREF) || DBG_ENABLED) { 867cce0e03bSab for (APLIST_TRAVERSE(CALLERS(ilmp), idx, bdp)) { 8687c478bd9Sstevel@tonic-gate if (bdp->b_caller == clmp) { 8697c478bd9Sstevel@tonic-gate bdp->b_flags |= BND_REFER; 8707c478bd9Sstevel@tonic-gate break; 8717c478bd9Sstevel@tonic-gate } 8727c478bd9Sstevel@tonic-gate } 8737c478bd9Sstevel@tonic-gate } 8747c478bd9Sstevel@tonic-gate } 8757c478bd9Sstevel@tonic-gate } 8767c478bd9Sstevel@tonic-gate 8777c478bd9Sstevel@tonic-gate /* 8787c478bd9Sstevel@tonic-gate * If this is the first call to process this filter, establish the 8797c478bd9Sstevel@tonic-gate * filtee list. If a configuration file exists, determine if any 8807c478bd9Sstevel@tonic-gate * filtee associations for this filter, and its filtee reference, are 8817c478bd9Sstevel@tonic-gate * defined. Otherwise, process the filtee reference. Any token 8827c478bd9Sstevel@tonic-gate * expansion is also completed at this point (i.e., $PLATFORM). 8837c478bd9Sstevel@tonic-gate */ 8847c478bd9Sstevel@tonic-gate filtees = (char *)STRTAB(ilmp) + DYN(ilmp)[ndx].d_un.d_val; 885481bba9eSRod Evans if (dip->di_info == NULL) { 8867c478bd9Sstevel@tonic-gate if (rtld_flags2 & RT_FL2_FLTCFG) 88756deab07SRod Evans elf_config_flt(lml, PATHNAME(ilmp), filtees, 88856deab07SRod Evans (Alist **)&dip->di_info, AL_CNT_FILTEES); 8897c478bd9Sstevel@tonic-gate 890481bba9eSRod Evans if (dip->di_info == NULL) { 8915aefb655Srie DBG_CALL(Dbg_file_filter(lml, NAME(ilmp), filtees, 0)); 8927c478bd9Sstevel@tonic-gate if ((lml->lm_flags & 8937c478bd9Sstevel@tonic-gate (LML_FLG_TRC_VERBOSE | LML_FLG_TRC_SEARCH)) && 8947c478bd9Sstevel@tonic-gate ((FLAGS1(ilmp) & FL1_RT_LDDSTUB) == 0)) 8957c478bd9Sstevel@tonic-gate (void) printf(MSG_INTL(MSG_LDD_FIL_FILTER), 8967c478bd9Sstevel@tonic-gate NAME(ilmp), filtees); 8977c478bd9Sstevel@tonic-gate 89856deab07SRod Evans if (expand_paths(ilmp, filtees, (Alist **)&dip->di_info, 89956deab07SRod Evans AL_CNT_FILTEES, 0, 0) == 0) { 9007c478bd9Sstevel@tonic-gate elf_disable_filtee(ilmp, dip); 90137ffaf83SRod Evans return (NULL); 9027c478bd9Sstevel@tonic-gate } 9037c478bd9Sstevel@tonic-gate } 9047c478bd9Sstevel@tonic-gate } 9057c478bd9Sstevel@tonic-gate 9067c478bd9Sstevel@tonic-gate /* 9077c478bd9Sstevel@tonic-gate * Traverse the filtee list, dlopen()'ing any objects specified and 9087c478bd9Sstevel@tonic-gate * using their group handle to lookup the symbol. 9097c478bd9Sstevel@tonic-gate */ 91056deab07SRod Evans any = 0; 91156deab07SRod Evans for (ALIST_TRAVERSE((Alist *)dip->di_info, idx, pdp)) { 9127c478bd9Sstevel@tonic-gate int mode; 9137c478bd9Sstevel@tonic-gate Grp_hdl *ghp; 914481bba9eSRod Evans Rt_map *nlmp = NULL; 9157c478bd9Sstevel@tonic-gate 91656deab07SRod Evans if (pdp->pd_plen == 0) 9177c478bd9Sstevel@tonic-gate continue; 9187c478bd9Sstevel@tonic-gate 9197c478bd9Sstevel@tonic-gate /* 9207c478bd9Sstevel@tonic-gate * Establish the mode of the filtee from the filter. As filtees 9217c478bd9Sstevel@tonic-gate * are loaded via a dlopen(), make sure that RTLD_GROUP is set 9227c478bd9Sstevel@tonic-gate * and the filtees aren't global. It would be nice to have 9237c478bd9Sstevel@tonic-gate * RTLD_FIRST used here also, but as filters got out long before 9247c478bd9Sstevel@tonic-gate * RTLD_FIRST was introduced it's a little too late now. 9257c478bd9Sstevel@tonic-gate */ 9267c478bd9Sstevel@tonic-gate mode = MODE(ilmp) | RTLD_GROUP; 9277c478bd9Sstevel@tonic-gate mode &= ~RTLD_GLOBAL; 9287c478bd9Sstevel@tonic-gate 9297c478bd9Sstevel@tonic-gate /* 9307c478bd9Sstevel@tonic-gate * Insure that any auxiliary filter can locate symbols from its 9317c478bd9Sstevel@tonic-gate * caller. 9327c478bd9Sstevel@tonic-gate */ 9337c478bd9Sstevel@tonic-gate if (dip->di_flags & FLG_DI_AUXFLTR) 9347c478bd9Sstevel@tonic-gate mode |= RTLD_PARENT; 9357c478bd9Sstevel@tonic-gate 9367c478bd9Sstevel@tonic-gate /* 9377c478bd9Sstevel@tonic-gate * Process any hardware capability directory. Establish a new 9387c478bd9Sstevel@tonic-gate * link-map control list from which to analyze any newly added 93924a6229eSrie * objects. 9407c478bd9Sstevel@tonic-gate */ 941481bba9eSRod Evans if ((pdp->pd_info == NULL) && (pdp->pd_flags & PD_TKN_HWCAP)) { 94256deab07SRod Evans const char *dir = pdp->pd_pname; 94356deab07SRod Evans Aliste lmco; 94411a2bb38Srie 945dde769a2SRod Evans /* 946dde769a2SRod Evans * Establish a link-map control list for this request. 947dde769a2SRod Evans */ 948dde769a2SRod Evans if ((lmco = create_cntl(lml, 0)) == NULL) 949dde769a2SRod Evans return (NULL); 9507c478bd9Sstevel@tonic-gate 95156deab07SRod Evans /* 95256deab07SRod Evans * Determine the hardware capability filtees. If none 95356deab07SRod Evans * can be found, provide suitable diagnostics. 95456deab07SRod Evans */ 95556deab07SRod Evans DBG_CALL(Dbg_cap_hw_filter(lml, dir, ilmp)); 95656deab07SRod Evans if (hwcap_filtees((Alist **)&dip->di_info, idx, dir, 957481bba9eSRod Evans lmco, ilmp, filtees, mode, 9582017c965SRod Evans (FLG_RT_PUBHDL | FLG_RT_HWCAP), in_nfavl) == 0) { 95956deab07SRod Evans if ((lml->lm_flags & LML_FLG_TRC_ENABLE) && 96056deab07SRod Evans (dip->di_flags & FLG_DI_AUXFLTR) && 96156deab07SRod Evans (rtld_flags & RT_FL_WARNFLTR)) { 96256deab07SRod Evans (void) printf( 96356deab07SRod Evans MSG_INTL(MSG_LDD_HWCAP_NFOUND), 96456deab07SRod Evans dir); 96556deab07SRod Evans } 96656deab07SRod Evans DBG_CALL(Dbg_cap_hw_filter(lml, dir, 0)); 96756deab07SRod Evans } 96856deab07SRod Evans 96956deab07SRod Evans /* 97056deab07SRod Evans * Re-establish the originating path name descriptor, as 97156deab07SRod Evans * the expansion of hardware capabilities filtees may 97256deab07SRod Evans * have re-allocated the controlling Alist. Mark this 97356deab07SRod Evans * original pathname descriptor as unused so that the 97456deab07SRod Evans * descriptor isn't revisited for processing. Any real 97556deab07SRod Evans * hardware capabilities filtees have been added as new 97656deab07SRod Evans * pathname descriptors following this descriptor. 97756deab07SRod Evans */ 97856deab07SRod Evans pdp = alist_item((Alist *)dip->di_info, idx); 97956deab07SRod Evans pdp->pd_flags &= ~PD_TKN_HWCAP; 98056deab07SRod Evans pdp->pd_plen = 0; 98111a2bb38Srie 98211a2bb38Srie /* 98311a2bb38Srie * Now that any hardware capability objects have been 984dde769a2SRod Evans * processed, remove any temporary link-map control 985dde769a2SRod Evans * list. 98611a2bb38Srie */ 987481bba9eSRod Evans if (lmco != ALIST_OFF_DATA) 98811a2bb38Srie remove_cntl(lml, lmco); 9897c478bd9Sstevel@tonic-gate } 9907c478bd9Sstevel@tonic-gate 99156deab07SRod Evans if (pdp->pd_plen == 0) 9927c478bd9Sstevel@tonic-gate continue; 9937c478bd9Sstevel@tonic-gate 9947c478bd9Sstevel@tonic-gate /* 9957c478bd9Sstevel@tonic-gate * Process an individual filtee. 9967c478bd9Sstevel@tonic-gate */ 997481bba9eSRod Evans if (pdp->pd_info == NULL) { 99856deab07SRod Evans const char *filtee = pdp->pd_pname; 9997c478bd9Sstevel@tonic-gate int audit = 0; 10007c478bd9Sstevel@tonic-gate 10015aefb655Srie DBG_CALL(Dbg_file_filtee(lml, NAME(ilmp), filtee, 0)); 10027c478bd9Sstevel@tonic-gate 1003481bba9eSRod Evans ghp = NULL; 10047c478bd9Sstevel@tonic-gate 10057c478bd9Sstevel@tonic-gate /* 10067c478bd9Sstevel@tonic-gate * Determine if the reference link map is already 10077c478bd9Sstevel@tonic-gate * loaded. As an optimization compare the filtee with 10087c478bd9Sstevel@tonic-gate * our interpretor. The most common filter is 10097c478bd9Sstevel@tonic-gate * libdl.so.1, which is a filter on ld.so.1. 10107c478bd9Sstevel@tonic-gate */ 10117c478bd9Sstevel@tonic-gate #if defined(_ELF64) 10127c478bd9Sstevel@tonic-gate if (strcmp(filtee, MSG_ORIG(MSG_PTH_RTLD_64)) == 0) { 10137c478bd9Sstevel@tonic-gate #else 10147c478bd9Sstevel@tonic-gate if (strcmp(filtee, MSG_ORIG(MSG_PTH_RTLD)) == 0) { 10157c478bd9Sstevel@tonic-gate #endif 10162017c965SRod Evans uint_t hflags, rdflags, cdflags; 10172017c965SRod Evans 10182017c965SRod Evans /* 10192017c965SRod Evans * Establish any flags for the handle (Grp_hdl). 10202017c965SRod Evans * 10212017c965SRod Evans * - This is a special, public, ld.so.1 10222017c965SRod Evans * handle. 10232017c965SRod Evans * - Only the first object on this handle 10242017c965SRod Evans * can supply symbols. 10252017c965SRod Evans * - This handle provides a filtee. 10262017c965SRod Evans * 10272017c965SRod Evans * Essentially, this handle allows a caller to 10282017c965SRod Evans * reference the dl*() family of interfaces from 10292017c965SRod Evans * ld.so.1. 10302017c965SRod Evans */ 10312017c965SRod Evans hflags = (GPH_PUBLIC | GPH_LDSO | 10322017c965SRod Evans GPH_FIRST | GPH_FILTEE); 10332017c965SRod Evans 10342017c965SRod Evans /* 10352017c965SRod Evans * Establish the flags for the referenced 10362017c965SRod Evans * dependency descriptor (Grp_desc). 10372017c965SRod Evans * 10382017c965SRod Evans * - ld.so.1 is available for dlsym(). 10392017c965SRod Evans * - ld.so.1 is available to relocate 10402017c965SRod Evans * against. 10412017c965SRod Evans * - There's no need to add an dependencies 10422017c965SRod Evans * to this handle. 10432017c965SRod Evans */ 10442017c965SRod Evans rdflags = (GPD_DLSYM | GPD_RELOC); 10452017c965SRod Evans 10467c478bd9Sstevel@tonic-gate /* 10472017c965SRod Evans * Establish the flags for this callers 10482017c965SRod Evans * dependency descriptor (Grp_desc). 10492017c965SRod Evans * 10502017c965SRod Evans * - The explicit creation of a handle 10512017c965SRod Evans * creates a descriptor for the referenced 10522017c965SRod Evans * object and the parent (caller). 10537c478bd9Sstevel@tonic-gate */ 10542017c965SRod Evans cdflags = GPD_PARENT; 10552017c965SRod Evans 10567c478bd9Sstevel@tonic-gate nlmp = lml_rtld.lm_head; 10577c478bd9Sstevel@tonic-gate if ((ghp = hdl_create(&lml_rtld, nlmp, ilmp, 10582017c965SRod Evans hflags, rdflags, cdflags)) == NULL) 1059481bba9eSRod Evans nlmp = NULL; 10607c478bd9Sstevel@tonic-gate 10617c478bd9Sstevel@tonic-gate /* 10627c478bd9Sstevel@tonic-gate * Establish the filter handle to prevent any 10637c478bd9Sstevel@tonic-gate * recursion. 10647c478bd9Sstevel@tonic-gate */ 10657c478bd9Sstevel@tonic-gate if (nlmp && ghp) 106656deab07SRod Evans pdp->pd_info = (void *)ghp; 10677c478bd9Sstevel@tonic-gate 10687c478bd9Sstevel@tonic-gate /* 10697c478bd9Sstevel@tonic-gate * Audit the filter/filtee established. Ignore 10707c478bd9Sstevel@tonic-gate * any return from the auditor, as we can't 10717c478bd9Sstevel@tonic-gate * allow ignore filtering to ld.so.1, otherwise 10727c478bd9Sstevel@tonic-gate * nothing is going to work. 10737c478bd9Sstevel@tonic-gate */ 107456deab07SRod Evans if (nlmp && ((lml->lm_tflags | AFLAGS(ilmp)) & 107502ca3e02Srie LML_TFLG_AUD_OBJFILTER)) 10767c478bd9Sstevel@tonic-gate (void) audit_objfilter(ilmp, filtees, 10777c478bd9Sstevel@tonic-gate nlmp, 0); 10787c478bd9Sstevel@tonic-gate 10797c478bd9Sstevel@tonic-gate } else { 10807c478bd9Sstevel@tonic-gate Rej_desc rej = { 0 }; 108156deab07SRod Evans Fdesc fd = { 0 }; 108211a2bb38Srie Aliste lmco; 10837c478bd9Sstevel@tonic-gate 108456deab07SRod Evans /* 108556deab07SRod Evans * Trace the inspection of this file, determine 108656deab07SRod Evans * any auditor substitution, and seed the file 108756deab07SRod Evans * descriptor with the originating name. 108856deab07SRod Evans */ 108956deab07SRod Evans if (load_trace(lml, pdp, clmp, &fd) == NULL) 109056deab07SRod Evans continue; 109156deab07SRod Evans 10927c478bd9Sstevel@tonic-gate /* 1093dde769a2SRod Evans * Establish a link-map control list for this 1094dde769a2SRod Evans * request. 10957c478bd9Sstevel@tonic-gate */ 1096dde769a2SRod Evans if ((lmco = create_cntl(lml, 0)) == NULL) 1097dde769a2SRod Evans return (NULL); 10987c478bd9Sstevel@tonic-gate 10997c478bd9Sstevel@tonic-gate /* 110056deab07SRod Evans * Locate and load the filtee. 11017c478bd9Sstevel@tonic-gate */ 110256deab07SRod Evans if ((nlmp = load_path(lml, lmco, ilmp, mode, 11032017c965SRod Evans FLG_RT_PUBHDL, &ghp, &fd, &rej, 110456deab07SRod Evans in_nfavl)) == NULL) 11057c478bd9Sstevel@tonic-gate file_notfound(LIST(ilmp), filtee, ilmp, 11062017c965SRod Evans FLG_RT_PUBHDL, &rej); 110756deab07SRod Evans 110856deab07SRod Evans filtee = pdp->pd_pname; 11097c478bd9Sstevel@tonic-gate 11107c478bd9Sstevel@tonic-gate /* 11117c478bd9Sstevel@tonic-gate * Establish the filter handle to prevent any 11127c478bd9Sstevel@tonic-gate * recursion. 11137c478bd9Sstevel@tonic-gate */ 11147c478bd9Sstevel@tonic-gate if (nlmp && ghp) { 11157c478bd9Sstevel@tonic-gate ghp->gh_flags |= GPH_FILTEE; 111656deab07SRod Evans pdp->pd_info = (void *)ghp; 11179aa23310Srie 11189aa23310Srie FLAGS1(nlmp) |= FL1_RT_USED; 11197c478bd9Sstevel@tonic-gate } 11207c478bd9Sstevel@tonic-gate 11217c478bd9Sstevel@tonic-gate /* 11227c478bd9Sstevel@tonic-gate * Audit the filter/filtee established. A 11237c478bd9Sstevel@tonic-gate * return of 0 indicates the auditor wishes to 11247c478bd9Sstevel@tonic-gate * ignore this filtee. 11257c478bd9Sstevel@tonic-gate */ 11267c478bd9Sstevel@tonic-gate if (nlmp && ((lml->lm_tflags | FLAGS1(ilmp)) & 11277c478bd9Sstevel@tonic-gate LML_TFLG_AUD_OBJFILTER)) { 11287c478bd9Sstevel@tonic-gate if (audit_objfilter(ilmp, filtees, 11297c478bd9Sstevel@tonic-gate nlmp, 0) == 0) { 11307c478bd9Sstevel@tonic-gate audit = 1; 1131481bba9eSRod Evans nlmp = NULL; 11327c478bd9Sstevel@tonic-gate } 11337c478bd9Sstevel@tonic-gate } 11347c478bd9Sstevel@tonic-gate 11357c478bd9Sstevel@tonic-gate /* 11367c478bd9Sstevel@tonic-gate * Finish processing the objects associated with 11377c478bd9Sstevel@tonic-gate * this request. Create an association between 11387c478bd9Sstevel@tonic-gate * this object and the originating filter to 11397c478bd9Sstevel@tonic-gate * provide sufficient information to tear down 11407c478bd9Sstevel@tonic-gate * this filtee if necessary. 11417c478bd9Sstevel@tonic-gate */ 114256deab07SRod Evans if (nlmp && ghp && (((nlmp = analyze_lmc(lml, 114356deab07SRod Evans lmco, nlmp, in_nfavl)) == NULL) || 114456deab07SRod Evans (relocate_lmc(lml, lmco, ilmp, nlmp, 114556deab07SRod Evans in_nfavl) == 0))) 1146481bba9eSRod Evans nlmp = NULL; 11477c478bd9Sstevel@tonic-gate 11487c478bd9Sstevel@tonic-gate /* 11497c478bd9Sstevel@tonic-gate * If the filtee has been successfully 115002ca3e02Srie * processed, then create an association 115102ca3e02Srie * between the filter and filtee. This 115202ca3e02Srie * association provides sufficient information 115302ca3e02Srie * to tear down the filter and filtee if 115402ca3e02Srie * necessary. 11557c478bd9Sstevel@tonic-gate */ 11568af2c5b9Srie DBG_CALL(Dbg_file_hdl_title(DBG_HDL_ADD)); 11572017c965SRod Evans if (nlmp && ghp && (hdl_add(ghp, ilmp, 11582017c965SRod Evans GPD_FILTER, NULL) == NULL)) 1159481bba9eSRod Evans nlmp = NULL; 116011a2bb38Srie 116156deab07SRod Evans /* 116256deab07SRod Evans * Generate a diagnostic if the filtee couldn't 116356deab07SRod Evans * be loaded. 116456deab07SRod Evans */ 1165481bba9eSRod Evans if (nlmp == NULL) 116656deab07SRod Evans DBG_CALL(Dbg_file_filtee(lml, 0, filtee, 116756deab07SRod Evans audit)); 116856deab07SRod Evans 116911a2bb38Srie /* 117002ca3e02Srie * If this filtee loading has failed, and we've 117102ca3e02Srie * created a new link-map control list to which 117202ca3e02Srie * this request has added objects, then remove 117302ca3e02Srie * all the objects that have been associated to 117402ca3e02Srie * this request. 117511a2bb38Srie */ 1176481bba9eSRod Evans if ((nlmp == NULL) && (lmco != ALIST_OFF_DATA)) 1177481bba9eSRod Evans remove_lmc(lml, clmp, lmco, name); 117802ca3e02Srie 117902ca3e02Srie /* 1180dde769a2SRod Evans * Remove any temporary link-map control list. 118102ca3e02Srie */ 1182481bba9eSRod Evans if (lmco != ALIST_OFF_DATA) 118311a2bb38Srie remove_cntl(lml, lmco); 11847c478bd9Sstevel@tonic-gate } 11857c478bd9Sstevel@tonic-gate 11867c478bd9Sstevel@tonic-gate /* 118756deab07SRod Evans * If the filtee couldn't be loaded, null out the 118856deab07SRod Evans * path name descriptor entry, and continue the search. 118956deab07SRod Evans * Otherwise, the group handle is retained for future 119056deab07SRod Evans * symbol searches. 11917c478bd9Sstevel@tonic-gate */ 1192481bba9eSRod Evans if (nlmp == NULL) { 119356deab07SRod Evans pdp->pd_info = NULL; 119456deab07SRod Evans pdp->pd_plen = 0; 11957c478bd9Sstevel@tonic-gate continue; 11967c478bd9Sstevel@tonic-gate } 11977c478bd9Sstevel@tonic-gate } 11987c478bd9Sstevel@tonic-gate 119956deab07SRod Evans ghp = (Grp_hdl *)pdp->pd_info; 12007c478bd9Sstevel@tonic-gate 12017c478bd9Sstevel@tonic-gate /* 12027c478bd9Sstevel@tonic-gate * If we're just here to trigger filtee loading skip the symbol 12037c478bd9Sstevel@tonic-gate * lookup so we'll continue looking for additional filtees. 12047c478bd9Sstevel@tonic-gate */ 12057c478bd9Sstevel@tonic-gate if (name) { 12067c478bd9Sstevel@tonic-gate Grp_desc *gdp; 120737ffaf83SRod Evans Sym *sym = NULL; 1208cce0e03bSab Aliste idx; 12097c478bd9Sstevel@tonic-gate Slookup sl = *slp; 12107c478bd9Sstevel@tonic-gate 12117c478bd9Sstevel@tonic-gate sl.sl_flags |= LKUP_FIRST; 12127c478bd9Sstevel@tonic-gate any++; 12137c478bd9Sstevel@tonic-gate 12147c478bd9Sstevel@tonic-gate /* 12157c478bd9Sstevel@tonic-gate * Look for the symbol in the handles dependencies. 12167c478bd9Sstevel@tonic-gate */ 1217cce0e03bSab for (ALIST_TRAVERSE(ghp->gh_depends, idx, gdp)) { 1218efb9e8b8Srie if ((gdp->gd_flags & GPD_DLSYM) == 0) 12197c478bd9Sstevel@tonic-gate continue; 12207c478bd9Sstevel@tonic-gate 12217c478bd9Sstevel@tonic-gate /* 12227c478bd9Sstevel@tonic-gate * If our parent is a dependency don't look at 12237c478bd9Sstevel@tonic-gate * it (otherwise we are in a recursive loop). 12247c478bd9Sstevel@tonic-gate * This situation can occur with auxiliary 12257c478bd9Sstevel@tonic-gate * filters if the filtee has a dependency on the 12267c478bd9Sstevel@tonic-gate * filter. This dependency isn't necessary as 12277c478bd9Sstevel@tonic-gate * auxiliary filters are opened RTLD_PARENT, but 12287c478bd9Sstevel@tonic-gate * users may still unknowingly add an explicit 12297c478bd9Sstevel@tonic-gate * dependency to the parent. 12307c478bd9Sstevel@tonic-gate */ 12317c478bd9Sstevel@tonic-gate if ((sl.sl_imap = gdp->gd_depend) == ilmp) 12327c478bd9Sstevel@tonic-gate continue; 12337c478bd9Sstevel@tonic-gate 12347c478bd9Sstevel@tonic-gate if (((sym = SYMINTP(sl.sl_imap)(&sl, dlmp, 1235481bba9eSRod Evans binfo, in_nfavl)) != NULL) || 12367c478bd9Sstevel@tonic-gate (ghp->gh_flags & GPH_FIRST)) 12377c478bd9Sstevel@tonic-gate break; 12387c478bd9Sstevel@tonic-gate } 12397c478bd9Sstevel@tonic-gate 12407c478bd9Sstevel@tonic-gate /* 124102ca3e02Srie * If a symbol has been found, indicate the binding 124202ca3e02Srie * and return the symbol. 12437c478bd9Sstevel@tonic-gate */ 12447c478bd9Sstevel@tonic-gate if (sym) { 12457c478bd9Sstevel@tonic-gate *binfo |= DBG_BINFO_FILTEE; 12467c478bd9Sstevel@tonic-gate return (sym); 12477c478bd9Sstevel@tonic-gate } 12487c478bd9Sstevel@tonic-gate } 12497c478bd9Sstevel@tonic-gate 12507c478bd9Sstevel@tonic-gate /* 12517c478bd9Sstevel@tonic-gate * If this object is tagged to terminate filtee processing we're 12527c478bd9Sstevel@tonic-gate * done. 12537c478bd9Sstevel@tonic-gate */ 12545aefb655Srie if (FLAGS1(ghp->gh_ownlmp) & FL1_RT_ENDFILTE) 12557c478bd9Sstevel@tonic-gate break; 12567c478bd9Sstevel@tonic-gate } 12577c478bd9Sstevel@tonic-gate 12587c478bd9Sstevel@tonic-gate /* 12597c478bd9Sstevel@tonic-gate * If we're just here to trigger filtee loading then we're done. 12607c478bd9Sstevel@tonic-gate */ 1261481bba9eSRod Evans if (name == NULL) 126237ffaf83SRod Evans return (NULL); 12637c478bd9Sstevel@tonic-gate 12647c478bd9Sstevel@tonic-gate /* 126556deab07SRod Evans * If no filtees have been found for a filter, clean up any path name 126656deab07SRod Evans * descriptors and disable their search completely. For auxiliary 12677c478bd9Sstevel@tonic-gate * filters we can reselect the symbol search function so that we never 12687c478bd9Sstevel@tonic-gate * enter this routine again for this object. For standard filters we 12697c478bd9Sstevel@tonic-gate * use the null symbol routine. 12707c478bd9Sstevel@tonic-gate */ 12717c478bd9Sstevel@tonic-gate if (any == 0) { 127256deab07SRod Evans remove_plist((Alist **)&(dip->di_info), 1); 12737c478bd9Sstevel@tonic-gate elf_disable_filtee(ilmp, dip); 127437ffaf83SRod Evans return (NULL); 12757c478bd9Sstevel@tonic-gate } 12767c478bd9Sstevel@tonic-gate 127737ffaf83SRod Evans return (NULL); 12787c478bd9Sstevel@tonic-gate } 12797c478bd9Sstevel@tonic-gate 12807c478bd9Sstevel@tonic-gate /* 12817c478bd9Sstevel@tonic-gate * Focal point for disabling error messages for auxiliary filters. As an 12827c478bd9Sstevel@tonic-gate * auxiliary filter allows for filtee use, but provides a fallback should a 12837c478bd9Sstevel@tonic-gate * filtee not exist (or fail to load), any errors generated as a consequence of 12847c478bd9Sstevel@tonic-gate * trying to load the filtees are typically suppressed. Setting RT_FL_SILENCERR 12857c478bd9Sstevel@tonic-gate * suppresses errors generated by eprint(), but insures a debug diagnostic is 12867c478bd9Sstevel@tonic-gate * produced. ldd(1) employs printf(), and here, the selection of whether to 12877c478bd9Sstevel@tonic-gate * print a diagnostic in regards to auxiliary filters is a little more complex. 12887c478bd9Sstevel@tonic-gate * 12892017c965SRod Evans * - The determination of whether to produce an ldd message, or a fatal 12907c478bd9Sstevel@tonic-gate * error message is driven by LML_FLG_TRC_ENABLE. 12912017c965SRod Evans * - More detailed ldd messages may also be driven off of LML_FLG_TRC_WARN, 12927c478bd9Sstevel@tonic-gate * (ldd -d/-r), LML_FLG_TRC_VERBOSE (ldd -v), LML_FLG_TRC_SEARCH (ldd -s), 12937c478bd9Sstevel@tonic-gate * and LML_FLG_TRC_UNREF/LML_FLG_TRC_UNUSED (ldd -U/-u). 12947c478bd9Sstevel@tonic-gate * 12952017c965SRod Evans * - If the calling object is lddstub, then several classes of message are 12967c478bd9Sstevel@tonic-gate * suppressed. The user isn't trying to diagnose lddstub, this is simply 12977c478bd9Sstevel@tonic-gate * a stub executable employed to preload a user specified library against. 12987c478bd9Sstevel@tonic-gate * 12992017c965SRod Evans * - If RT_FL_SILENCERR is in effect then any generic ldd() messages should 13007c478bd9Sstevel@tonic-gate * be suppressed. All detailed ldd messages should still be produced. 13017c478bd9Sstevel@tonic-gate */ 13027c478bd9Sstevel@tonic-gate Sym * 13039aa23310Srie elf_lookup_filtee(Slookup *slp, Rt_map **dlmp, uint_t *binfo, uint_t ndx, 13049aa23310Srie int *in_nfavl) 13057c478bd9Sstevel@tonic-gate { 13067c478bd9Sstevel@tonic-gate Sym *sym; 13077c478bd9Sstevel@tonic-gate Dyninfo *dip = &DYNINFO(slp->sl_imap)[ndx]; 13087c478bd9Sstevel@tonic-gate int silent = 0; 13097c478bd9Sstevel@tonic-gate 13107c478bd9Sstevel@tonic-gate /* 13117c478bd9Sstevel@tonic-gate * Make sure this entry is still acting as a filter. We may have tried 13127c478bd9Sstevel@tonic-gate * to process this previously, and disabled it if the filtee couldn't 13137c478bd9Sstevel@tonic-gate * be processed. However, other entries may provide different filtees 13147c478bd9Sstevel@tonic-gate * that are yet to be completed. 13157c478bd9Sstevel@tonic-gate */ 13167c478bd9Sstevel@tonic-gate if (dip->di_flags == 0) 131737ffaf83SRod Evans return (NULL); 13187c478bd9Sstevel@tonic-gate 13197c478bd9Sstevel@tonic-gate /* 13207c478bd9Sstevel@tonic-gate * Indicate whether an error message is required should this filtee not 13217c478bd9Sstevel@tonic-gate * be found, based on the type of filter. 13227c478bd9Sstevel@tonic-gate */ 13237c478bd9Sstevel@tonic-gate if ((dip->di_flags & FLG_DI_AUXFLTR) && 13247c478bd9Sstevel@tonic-gate ((rtld_flags & (RT_FL_WARNFLTR | RT_FL_SILENCERR)) == 0)) { 13257c478bd9Sstevel@tonic-gate rtld_flags |= RT_FL_SILENCERR; 13267c478bd9Sstevel@tonic-gate silent = 1; 13277c478bd9Sstevel@tonic-gate } 13287c478bd9Sstevel@tonic-gate 13299aa23310Srie sym = _elf_lookup_filtee(slp, dlmp, binfo, ndx, in_nfavl); 13307c478bd9Sstevel@tonic-gate 13317c478bd9Sstevel@tonic-gate if (silent) 13327c478bd9Sstevel@tonic-gate rtld_flags &= ~RT_FL_SILENCERR; 13337c478bd9Sstevel@tonic-gate 13347c478bd9Sstevel@tonic-gate return (sym); 13357c478bd9Sstevel@tonic-gate } 13367c478bd9Sstevel@tonic-gate 13377c478bd9Sstevel@tonic-gate /* 13387c478bd9Sstevel@tonic-gate * Compute the elf hash value (as defined in the ELF access library). 13397c478bd9Sstevel@tonic-gate * The form of the hash table is: 13407c478bd9Sstevel@tonic-gate * 13417c478bd9Sstevel@tonic-gate * |--------------| 13427c478bd9Sstevel@tonic-gate * | # of buckets | 13437c478bd9Sstevel@tonic-gate * |--------------| 13447c478bd9Sstevel@tonic-gate * | # of chains | 13457c478bd9Sstevel@tonic-gate * |--------------| 13467c478bd9Sstevel@tonic-gate * | bucket[] | 13477c478bd9Sstevel@tonic-gate * |--------------| 13487c478bd9Sstevel@tonic-gate * | chain[] | 13497c478bd9Sstevel@tonic-gate * |--------------| 13507c478bd9Sstevel@tonic-gate */ 13517c478bd9Sstevel@tonic-gate ulong_t 13527c478bd9Sstevel@tonic-gate elf_hash(const char *name) 13537c478bd9Sstevel@tonic-gate { 13547c478bd9Sstevel@tonic-gate uint_t hval = 0; 13557c478bd9Sstevel@tonic-gate 13567c478bd9Sstevel@tonic-gate while (*name) { 13577c478bd9Sstevel@tonic-gate uint_t g; 13587c478bd9Sstevel@tonic-gate hval = (hval << 4) + *name++; 13597c478bd9Sstevel@tonic-gate if ((g = (hval & 0xf0000000)) != 0) 13607c478bd9Sstevel@tonic-gate hval ^= g >> 24; 13617c478bd9Sstevel@tonic-gate hval &= ~g; 13627c478bd9Sstevel@tonic-gate } 13637c478bd9Sstevel@tonic-gate return ((ulong_t)hval); 13647c478bd9Sstevel@tonic-gate } 13657c478bd9Sstevel@tonic-gate 13667c478bd9Sstevel@tonic-gate /* 13677c478bd9Sstevel@tonic-gate * If flag argument has LKUP_SPEC set, we treat undefined symbols of type 13687c478bd9Sstevel@tonic-gate * function specially in the executable - if they have a value, even though 13697c478bd9Sstevel@tonic-gate * undefined, we use that value. This allows us to associate all references 13707c478bd9Sstevel@tonic-gate * to a function's address to a single place in the process: the plt entry 13717c478bd9Sstevel@tonic-gate * for that function in the executable. Calls to lookup from plt binding 13727c478bd9Sstevel@tonic-gate * routines do NOT set LKUP_SPEC in the flag. 13737c478bd9Sstevel@tonic-gate */ 13747c478bd9Sstevel@tonic-gate Sym * 13759aa23310Srie elf_find_sym(Slookup *slp, Rt_map **dlmp, uint_t *binfo, int *in_nfavl) 13767c478bd9Sstevel@tonic-gate { 13777c478bd9Sstevel@tonic-gate const char *name = slp->sl_name; 13787c478bd9Sstevel@tonic-gate Rt_map *ilmp = slp->sl_imap; 13797c478bd9Sstevel@tonic-gate ulong_t hash = slp->sl_hash; 13807c478bd9Sstevel@tonic-gate uint_t ndx, htmp, buckets, *chainptr; 13817c478bd9Sstevel@tonic-gate Sym *sym, *symtabptr; 13827c478bd9Sstevel@tonic-gate char *strtabptr, *strtabname; 13837c478bd9Sstevel@tonic-gate uint_t flags1; 13847c478bd9Sstevel@tonic-gate Syminfo *sip; 13857c478bd9Sstevel@tonic-gate 1386660acd81Srie /* 1387660acd81Srie * If we're only here to establish a symbols index, skip the diagnostic 1388660acd81Srie * used to trace a symbol search. 1389660acd81Srie */ 13905aefb655Srie if ((slp->sl_flags & LKUP_SYMNDX) == 0) 13915aefb655Srie DBG_CALL(Dbg_syms_lookup(ilmp, name, MSG_ORIG(MSG_STR_ELF))); 13927c478bd9Sstevel@tonic-gate 1393481bba9eSRod Evans if (HASH(ilmp) == NULL) 139437ffaf83SRod Evans return (NULL); 13957c478bd9Sstevel@tonic-gate 13967c478bd9Sstevel@tonic-gate buckets = HASH(ilmp)[0]; 13977c478bd9Sstevel@tonic-gate /* LINTED */ 13987c478bd9Sstevel@tonic-gate htmp = (uint_t)hash % buckets; 13997c478bd9Sstevel@tonic-gate 14007c478bd9Sstevel@tonic-gate /* 14017c478bd9Sstevel@tonic-gate * Get the first symbol on hash chain and initialize the string 14027c478bd9Sstevel@tonic-gate * and symbol table pointers. 14037c478bd9Sstevel@tonic-gate */ 14047c478bd9Sstevel@tonic-gate if ((ndx = HASH(ilmp)[htmp + 2]) == 0) 140537ffaf83SRod Evans return (NULL); 14067c478bd9Sstevel@tonic-gate 14077c478bd9Sstevel@tonic-gate chainptr = HASH(ilmp) + 2 + buckets; 14087c478bd9Sstevel@tonic-gate strtabptr = STRTAB(ilmp); 14097c478bd9Sstevel@tonic-gate symtabptr = SYMTAB(ilmp); 14107c478bd9Sstevel@tonic-gate 14117c478bd9Sstevel@tonic-gate while (ndx) { 14127c478bd9Sstevel@tonic-gate sym = symtabptr + ndx; 14137c478bd9Sstevel@tonic-gate strtabname = strtabptr + sym->st_name; 14147c478bd9Sstevel@tonic-gate 14157c478bd9Sstevel@tonic-gate /* 14167c478bd9Sstevel@tonic-gate * Compare the symbol found with the name required. If the 14177c478bd9Sstevel@tonic-gate * names don't match continue with the next hash entry. 14187c478bd9Sstevel@tonic-gate */ 14197c478bd9Sstevel@tonic-gate if ((*strtabname++ != *name) || strcmp(strtabname, &name[1])) { 14207c478bd9Sstevel@tonic-gate if ((ndx = chainptr[ndx]) != 0) 14217c478bd9Sstevel@tonic-gate continue; 142237ffaf83SRod Evans return (NULL); 14237c478bd9Sstevel@tonic-gate } 14247c478bd9Sstevel@tonic-gate 14253b41b08bSab /* 1426d840867fSab * The Solaris ld does not put DT_VERSYM in the dynamic 1427d840867fSab * section, but the GNU ld does. The GNU runtime linker 1428d840867fSab * interprets the top bit of the 16-bit Versym value 1429d840867fSab * (0x8000) as the "hidden" bit. If this bit is set, 1430d840867fSab * the linker is supposed to act as if that symbol does 1431d840867fSab * not exist. The hidden bit supports their versioning 1432d840867fSab * scheme, which allows multiple incompatible functions 1433d840867fSab * with the same name to exist at different versions 1434d840867fSab * within an object. The Solaris linker does not support this 1435d840867fSab * mechanism, or the model of interface evolution that 1436d840867fSab * it allows, but we honor the hidden bit in GNU ld 1437d840867fSab * produced objects in order to interoperate with them. 14383b41b08bSab */ 1439d840867fSab if ((VERSYM(ilmp) != NULL) && 1440d840867fSab ((VERSYM(ilmp)[ndx] & 0x8000) != 0)) { 1441d840867fSab DBG_CALL(Dbg_syms_ignore_gnuver(ilmp, name, 14423b41b08bSab ndx, VERSYM(ilmp)[ndx])); 14433b41b08bSab if ((ndx = chainptr[ndx]) != 0) 14443b41b08bSab continue; 144537ffaf83SRod Evans return (NULL); 14463b41b08bSab } 14473b41b08bSab 1448660acd81Srie /* 1449660acd81Srie * If we're only here to establish a symbols index, we're done. 1450660acd81Srie */ 1451660acd81Srie if (slp->sl_flags & LKUP_SYMNDX) 1452660acd81Srie return (sym); 1453660acd81Srie 14547c478bd9Sstevel@tonic-gate /* 14557c478bd9Sstevel@tonic-gate * If we find a match and the symbol is defined, return the 14567c478bd9Sstevel@tonic-gate * symbol pointer and the link map in which it was found. 14577c478bd9Sstevel@tonic-gate */ 14587c478bd9Sstevel@tonic-gate if (sym->st_shndx != SHN_UNDEF) { 14597c478bd9Sstevel@tonic-gate *dlmp = ilmp; 14607c478bd9Sstevel@tonic-gate *binfo |= DBG_BINFO_FOUND; 14619a411307Srie if ((FLAGS(ilmp) & FLG_RT_OBJINTPO) || 14629a411307Srie ((FLAGS(ilmp) & FLG_RT_SYMINTPO) && 14639a411307Srie is_sym_interposer(ilmp, sym))) 14647c478bd9Sstevel@tonic-gate *binfo |= DBG_BINFO_INTERPOSE; 14657c478bd9Sstevel@tonic-gate break; 14667c478bd9Sstevel@tonic-gate 14677c478bd9Sstevel@tonic-gate /* 14687c478bd9Sstevel@tonic-gate * If we find a match and the symbol is undefined, the 14697c478bd9Sstevel@tonic-gate * symbol type is a function, and the value of the symbol 14707c478bd9Sstevel@tonic-gate * is non zero, then this is a special case. This allows 14717c478bd9Sstevel@tonic-gate * the resolution of a function address to the plt[] entry. 14727c478bd9Sstevel@tonic-gate * See SPARC ABI, Dynamic Linking, Function Addresses for 14737c478bd9Sstevel@tonic-gate * more details. 14747c478bd9Sstevel@tonic-gate */ 1475660acd81Srie } else if ((slp->sl_flags & LKUP_SPEC) && 14767c478bd9Sstevel@tonic-gate (FLAGS(ilmp) & FLG_RT_ISMAIN) && (sym->st_value != 0) && 14777c478bd9Sstevel@tonic-gate (ELF_ST_TYPE(sym->st_info) == STT_FUNC)) { 14787c478bd9Sstevel@tonic-gate *dlmp = ilmp; 14797c478bd9Sstevel@tonic-gate *binfo |= (DBG_BINFO_FOUND | DBG_BINFO_PLTADDR); 14809a411307Srie if ((FLAGS(ilmp) & FLG_RT_OBJINTPO) || 14819a411307Srie ((FLAGS(ilmp) & FLG_RT_SYMINTPO) && 14829a411307Srie is_sym_interposer(ilmp, sym))) 14837c478bd9Sstevel@tonic-gate *binfo |= DBG_BINFO_INTERPOSE; 14847c478bd9Sstevel@tonic-gate return (sym); 14857c478bd9Sstevel@tonic-gate } 14867c478bd9Sstevel@tonic-gate 14877c478bd9Sstevel@tonic-gate /* 14887c478bd9Sstevel@tonic-gate * Undefined symbol. 14897c478bd9Sstevel@tonic-gate */ 149037ffaf83SRod Evans return (NULL); 14917c478bd9Sstevel@tonic-gate } 14927c478bd9Sstevel@tonic-gate 14937c478bd9Sstevel@tonic-gate /* 14947c478bd9Sstevel@tonic-gate * We've found a match. Determine if the defining object contains 14957c478bd9Sstevel@tonic-gate * symbol binding information. 14967c478bd9Sstevel@tonic-gate */ 1497481bba9eSRod Evans if ((sip = SYMINFO(ilmp)) != NULL) 14989039eeafSab sip += ndx; 14997c478bd9Sstevel@tonic-gate 150060758829Srie /* 150160758829Srie * If this definition is a singleton, and we haven't followed a default 150260758829Srie * symbol search knowing that we're looking for a singleton (presumably 150360758829Srie * because the symbol definition has been changed since the referring 150460758829Srie * object was built), then reject this binding so that the caller can 150560758829Srie * fall back to a standard symbol search. 150660758829Srie */ 150760758829Srie if ((ELF_ST_VISIBILITY(sym->st_other) == STV_SINGLETON) && 150860758829Srie (((slp->sl_flags & LKUP_STANDARD) == 0) || 150960758829Srie (((slp->sl_flags & LKUP_SINGLETON) == 0) && 151060758829Srie (LIST(ilmp)->lm_flags & LML_FLG_GROUPSEXIST)))) { 151160758829Srie DBG_CALL(Dbg_bind_reject(slp->sl_cmap, ilmp, name, 151260758829Srie DBG_BNDREJ_SINGLE)); 151360758829Srie *binfo |= BINFO_REJSINGLE; 151460758829Srie *binfo &= ~DBG_BINFO_MSK; 151537ffaf83SRod Evans return (NULL); 151660758829Srie } 151760758829Srie 15187c478bd9Sstevel@tonic-gate /* 15197c478bd9Sstevel@tonic-gate * If this is a direct binding request, but the symbol definition has 15207c478bd9Sstevel@tonic-gate * disabled directly binding to it (presumably because the symbol 15217c478bd9Sstevel@tonic-gate * definition has been changed since the referring object was built), 152237ffaf83SRod Evans * reject this binding so that the caller can fall back to a standard 152360758829Srie * symbol search. 15247c478bd9Sstevel@tonic-gate */ 15257c478bd9Sstevel@tonic-gate if (sip && (slp->sl_flags & LKUP_DIRECT) && 15267c478bd9Sstevel@tonic-gate (sip->si_flags & SYMINFO_FLG_NOEXTDIRECT)) { 152760758829Srie DBG_CALL(Dbg_bind_reject(slp->sl_cmap, ilmp, name, 152837ffaf83SRod Evans DBG_BNDREJ_DIRECT)); 152960758829Srie *binfo |= BINFO_REJDIRECT; 15307c478bd9Sstevel@tonic-gate *binfo &= ~DBG_BINFO_MSK; 153137ffaf83SRod Evans return (NULL); 153237ffaf83SRod Evans } 153337ffaf83SRod Evans 153437ffaf83SRod Evans /* 153537ffaf83SRod Evans * If this is a binding request within an RTLD_GROUP family, and the 153637ffaf83SRod Evans * symbol has disabled directly binding to it, reject this binding so 153737ffaf83SRod Evans * that the caller can fall back to a standard symbol search. 153837ffaf83SRod Evans * 153937ffaf83SRod Evans * Effectively, an RTLD_GROUP family achieves what can now be 154037ffaf83SRod Evans * established with direct bindings. However, various symbols have 154137ffaf83SRod Evans * been tagged as inappropriate for direct binding to (ie. libc:malloc). 154237ffaf83SRod Evans * 154337ffaf83SRod Evans * A symbol marked as no-direct cannot be used within a group without 154437ffaf83SRod Evans * first ensuring that the symbol has not been interposed upon outside 154537ffaf83SRod Evans * of the group. A common example occurs when users implement their own 154637ffaf83SRod Evans * version of malloc() in the executable. Such a malloc() interposes on 154737ffaf83SRod Evans * the libc:malloc, and this interposition must be honored within the 154837ffaf83SRod Evans * group as well. 154937ffaf83SRod Evans * 155037ffaf83SRod Evans * Following any rejection, LKUP_WORLD is established as a means of 155137ffaf83SRod Evans * overriding this test as we return to a standard search. 155237ffaf83SRod Evans */ 155337ffaf83SRod Evans if (sip && (sip->si_flags & SYMINFO_FLG_NOEXTDIRECT) && 155437ffaf83SRod Evans ((MODE(slp->sl_cmap) & (RTLD_GROUP | RTLD_WORLD)) == RTLD_GROUP) && 155537ffaf83SRod Evans ((slp->sl_flags & LKUP_WORLD) == 0)) { 155637ffaf83SRod Evans DBG_CALL(Dbg_bind_reject(slp->sl_cmap, ilmp, name, 155737ffaf83SRod Evans DBG_BNDREJ_GROUP)); 155837ffaf83SRod Evans *binfo |= BINFO_REJGROUP; 155937ffaf83SRod Evans *binfo &= ~DBG_BINFO_MSK; 156037ffaf83SRod Evans return (NULL); 15617c478bd9Sstevel@tonic-gate } 15627c478bd9Sstevel@tonic-gate 15637c478bd9Sstevel@tonic-gate /* 15647c478bd9Sstevel@tonic-gate * Determine whether this object is acting as a filter. 15657c478bd9Sstevel@tonic-gate */ 15667c478bd9Sstevel@tonic-gate if (((flags1 = FLAGS1(ilmp)) & MSK_RT_FILTER) == 0) 15677c478bd9Sstevel@tonic-gate return (sym); 15687c478bd9Sstevel@tonic-gate 15697c478bd9Sstevel@tonic-gate /* 15707c478bd9Sstevel@tonic-gate * Determine if this object offers per-symbol filtering, and if so, 15717c478bd9Sstevel@tonic-gate * whether this symbol references a filtee. 15727c478bd9Sstevel@tonic-gate */ 15737c478bd9Sstevel@tonic-gate if (sip && (flags1 & (FL1_RT_SYMSFLTR | FL1_RT_SYMAFLTR))) { 15747c478bd9Sstevel@tonic-gate /* 15757c478bd9Sstevel@tonic-gate * If this is a standard filter reference, and no standard 15767c478bd9Sstevel@tonic-gate * filtees remain to be inspected, we're done. If this is an 15777c478bd9Sstevel@tonic-gate * auxiliary filter reference, and no auxiliary filtees remain, 15787c478bd9Sstevel@tonic-gate * we'll fall through in case any object filtering is available. 15797c478bd9Sstevel@tonic-gate */ 15807c478bd9Sstevel@tonic-gate if ((sip->si_flags & SYMINFO_FLG_FILTER) && 15817c478bd9Sstevel@tonic-gate (SYMSFLTRCNT(ilmp) == 0)) 158237ffaf83SRod Evans return (NULL); 15837c478bd9Sstevel@tonic-gate 15847c478bd9Sstevel@tonic-gate if ((sip->si_flags & SYMINFO_FLG_FILTER) || 15857c478bd9Sstevel@tonic-gate ((sip->si_flags & SYMINFO_FLG_AUXILIARY) && 15867c478bd9Sstevel@tonic-gate SYMAFLTRCNT(ilmp))) { 158775e7992aSrie Sym *fsym; 15887c478bd9Sstevel@tonic-gate 15897c478bd9Sstevel@tonic-gate /* 15907c478bd9Sstevel@tonic-gate * This symbol has an associated filtee. Lookup the 15917c478bd9Sstevel@tonic-gate * symbol in the filtee, and if it is found return it. 15927c478bd9Sstevel@tonic-gate * If the symbol doesn't exist, and this is a standard 15937c478bd9Sstevel@tonic-gate * filter, return an error, otherwise fall through to 15947c478bd9Sstevel@tonic-gate * catch any object filtering that may be available. 15957c478bd9Sstevel@tonic-gate */ 15967c478bd9Sstevel@tonic-gate if ((fsym = elf_lookup_filtee(slp, dlmp, binfo, 1597481bba9eSRod Evans sip->si_boundto, in_nfavl)) != NULL) 15987c478bd9Sstevel@tonic-gate return (fsym); 15997c478bd9Sstevel@tonic-gate if (sip->si_flags & SYMINFO_FLG_FILTER) 160037ffaf83SRod Evans return (NULL); 16017c478bd9Sstevel@tonic-gate } 16027c478bd9Sstevel@tonic-gate } 16037c478bd9Sstevel@tonic-gate 16047c478bd9Sstevel@tonic-gate /* 16057c478bd9Sstevel@tonic-gate * Determine if this object provides global filtering. 16067c478bd9Sstevel@tonic-gate */ 16077c478bd9Sstevel@tonic-gate if (flags1 & (FL1_RT_OBJSFLTR | FL1_RT_OBJAFLTR)) { 160875e7992aSrie Sym *fsym; 16097c478bd9Sstevel@tonic-gate 16107c478bd9Sstevel@tonic-gate if (OBJFLTRNDX(ilmp) != FLTR_DISABLED) { 16117c478bd9Sstevel@tonic-gate /* 16127c478bd9Sstevel@tonic-gate * This object has an associated filtee. Lookup the 16137c478bd9Sstevel@tonic-gate * symbol in the filtee, and if it is found return it. 16147c478bd9Sstevel@tonic-gate * If the symbol doesn't exist, and this is a standard 16157c478bd9Sstevel@tonic-gate * filter, return and error, otherwise return the symbol 16167c478bd9Sstevel@tonic-gate * within the filter itself. 16177c478bd9Sstevel@tonic-gate */ 16187c478bd9Sstevel@tonic-gate if ((fsym = elf_lookup_filtee(slp, dlmp, binfo, 1619481bba9eSRod Evans OBJFLTRNDX(ilmp), in_nfavl)) != NULL) 16207c478bd9Sstevel@tonic-gate return (fsym); 16217c478bd9Sstevel@tonic-gate } 16227c478bd9Sstevel@tonic-gate 16237c478bd9Sstevel@tonic-gate if (flags1 & FL1_RT_OBJSFLTR) 162437ffaf83SRod Evans return (NULL); 16257c478bd9Sstevel@tonic-gate } 16267c478bd9Sstevel@tonic-gate return (sym); 16277c478bd9Sstevel@tonic-gate } 16287c478bd9Sstevel@tonic-gate 16297c478bd9Sstevel@tonic-gate /* 16307c478bd9Sstevel@tonic-gate * Create a new Rt_map structure for an ELF object and initialize 16317c478bd9Sstevel@tonic-gate * all values. 16327c478bd9Sstevel@tonic-gate */ 16337c478bd9Sstevel@tonic-gate Rt_map * 163456deab07SRod Evans elf_new_lmp(Lm_list *lml, Aliste lmco, Fdesc *fdp, Addr addr, size_t msize, 163556deab07SRod Evans void *odyn, int *in_nfavl) 16367c478bd9Sstevel@tonic-gate { 163756deab07SRod Evans const char *name = fdp->fd_nname; 16387c478bd9Sstevel@tonic-gate Rt_map *lmp; 16397c478bd9Sstevel@tonic-gate Ehdr *ehdr = (Ehdr *)addr; 164056deab07SRod Evans Phdr *phdr, *tphdr = NULL, *dphdr = NULL, *uphdr = NULL; 164156deab07SRod Evans Dyn *dyn = (Dyn *)odyn; 164256deab07SRod Evans Cap *cap = NULL; 164356deab07SRod Evans int ndx; 164456deab07SRod Evans Addr base, fltr = 0, audit = 0, cfile = 0, crle = 0; 164556deab07SRod Evans Xword rpath = 0; 164656deab07SRod Evans size_t lmsz, rtsz, epsz, dynsz = 0; 164756deab07SRod Evans uint_t dyncnt = 0; 16487c478bd9Sstevel@tonic-gate 164956deab07SRod Evans DBG_CALL(Dbg_file_elf(lml, name, addr, msize, lml->lm_lmidstr, lmco)); 16507c478bd9Sstevel@tonic-gate 16517c478bd9Sstevel@tonic-gate /* 165256deab07SRod Evans * If this is a shared object, the base address of the shared object is 165356deab07SRod Evans * added to all address values defined within the object. Otherwise, if 165456deab07SRod Evans * this is an executable, all object addresses are used as is. 16557c478bd9Sstevel@tonic-gate */ 165656deab07SRod Evans if (ehdr->e_type == ET_EXEC) 165756deab07SRod Evans base = 0; 165856deab07SRod Evans else 165956deab07SRod Evans base = addr; 166056deab07SRod Evans 166156deab07SRod Evans /* 166256deab07SRod Evans * Traverse the program header table, picking off required items. This 166356deab07SRod Evans * traversal also provides for the sizing of the PT_DYNAMIC section. 166456deab07SRod Evans */ 166556deab07SRod Evans phdr = (Phdr *)((uintptr_t)ehdr + ehdr->e_phoff); 166656deab07SRod Evans for (ndx = 0; ndx < (int)ehdr->e_phnum; ndx++, 166756deab07SRod Evans phdr = (Phdr *)((uintptr_t)phdr + ehdr->e_phentsize)) { 166856deab07SRod Evans switch (phdr->p_type) { 166956deab07SRod Evans case PT_DYNAMIC: 167056deab07SRod Evans dphdr = phdr; 167156deab07SRod Evans dyn = (Dyn *)((uintptr_t)phdr->p_vaddr + base); 167256deab07SRod Evans break; 167356deab07SRod Evans case PT_TLS: 167456deab07SRod Evans tphdr = phdr; 167556deab07SRod Evans break; 167656deab07SRod Evans case PT_SUNWCAP: 167756deab07SRod Evans cap = (Cap *)((uintptr_t)phdr->p_vaddr + base); 167856deab07SRod Evans break; 167956deab07SRod Evans case PT_SUNW_UNWIND: 16807e16fca0SAli Bahrami case PT_SUNW_EH_FRAME: 168156deab07SRod Evans uphdr = phdr; 168256deab07SRod Evans break; 168356deab07SRod Evans default: 168456deab07SRod Evans break; 168556deab07SRod Evans } 16867c478bd9Sstevel@tonic-gate } 16877c478bd9Sstevel@tonic-gate 168856deab07SRod Evans /* 168956deab07SRod Evans * Determine the number of PT_DYNAMIC entries for the DYNINFO() 169056deab07SRod Evans * allocation. Sadly, this is a little larger than we really need, 169156deab07SRod Evans * as there are typically padding DT_NULL entries. However, adding 169256deab07SRod Evans * this data to the initial link-map allocation is a win. 169356deab07SRod Evans */ 169456deab07SRod Evans if (dyn) { 169556deab07SRod Evans dyncnt = dphdr->p_filesz / sizeof (Dyn); 169656deab07SRod Evans dynsz = dyncnt * sizeof (Dyninfo); 169756deab07SRod Evans } 169856deab07SRod Evans 169956deab07SRod Evans /* 170056deab07SRod Evans * Allocate space for the link-map, private elf information, and 170156deab07SRod Evans * DYNINFO() data. Once these are allocated and initialized, 170256deab07SRod Evans * remove_so(0, lmp) can be used to tear down the link-map allocation 170356deab07SRod Evans * should any failures occur. 170456deab07SRod Evans */ 170556deab07SRod Evans rtsz = S_DROUND(sizeof (Rt_map)); 170656deab07SRod Evans epsz = S_DROUND(sizeof (Rt_elfp)); 170756deab07SRod Evans lmsz = rtsz + epsz + dynsz; 170856deab07SRod Evans if ((lmp = calloc(lmsz, 1)) == NULL) 170956deab07SRod Evans return (NULL); 171056deab07SRod Evans ELFPRV(lmp) = (void *)((uintptr_t)lmp + rtsz); 171156deab07SRod Evans DYNINFO(lmp) = (Dyninfo *)((uintptr_t)lmp + rtsz + epsz); 171256deab07SRod Evans LMSIZE(lmp) = lmsz; 171356deab07SRod Evans 17147c478bd9Sstevel@tonic-gate /* 17157c478bd9Sstevel@tonic-gate * All fields not filled in were set to 0 by calloc. 17167c478bd9Sstevel@tonic-gate */ 171756deab07SRod Evans NAME(lmp) = (char *)name; 17187c478bd9Sstevel@tonic-gate ADDR(lmp) = addr; 17197c478bd9Sstevel@tonic-gate MSIZE(lmp) = msize; 17207c478bd9Sstevel@tonic-gate SYMINTP(lmp) = elf_find_sym; 17217c478bd9Sstevel@tonic-gate FCT(lmp) = &elf_fct; 17227c478bd9Sstevel@tonic-gate LIST(lmp) = lml; 17237c478bd9Sstevel@tonic-gate OBJFLTRNDX(lmp) = FLTR_DISABLED; 1724dffec89cSrie SORTVAL(lmp) = -1; 172556deab07SRod Evans DYN(lmp) = dyn; 172656deab07SRod Evans DYNINFOCNT(lmp) = dyncnt; 172756deab07SRod Evans PTUNWIND(lmp) = uphdr; 17287c478bd9Sstevel@tonic-gate 172956deab07SRod Evans if (ehdr->e_type == ET_EXEC) 17307c478bd9Sstevel@tonic-gate FLAGS(lmp) |= FLG_RT_FIXED; 17317c478bd9Sstevel@tonic-gate 17327c478bd9Sstevel@tonic-gate /* 17337c478bd9Sstevel@tonic-gate * Fill in rest of the link map entries with information from the file's 17347c478bd9Sstevel@tonic-gate * dynamic structure. 17357c478bd9Sstevel@tonic-gate */ 173656deab07SRod Evans if (dyn) { 173775e7992aSrie uint_t dynndx = 0; 173810a4fa49Srie Xword pltpadsz = 0; 173910a4fa49Srie Rti_desc *rti; 17407c478bd9Sstevel@tonic-gate 17417c478bd9Sstevel@tonic-gate /* CSTYLED */ 174256deab07SRod Evans for ( ; dyn->d_tag != DT_NULL; ++dyn, dynndx++) { 174356deab07SRod Evans switch ((Xword)dyn->d_tag) { 17447c478bd9Sstevel@tonic-gate case DT_SYMTAB: 174556deab07SRod Evans SYMTAB(lmp) = (void *)(dyn->d_un.d_ptr + base); 17467c478bd9Sstevel@tonic-gate break; 17479039eeafSab case DT_SUNW_SYMTAB: 17489039eeafSab SUNWSYMTAB(lmp) = 174956deab07SRod Evans (void *)(dyn->d_un.d_ptr + base); 17509039eeafSab break; 17519039eeafSab case DT_SUNW_SYMSZ: 175256deab07SRod Evans SUNWSYMSZ(lmp) = dyn->d_un.d_val; 17539039eeafSab break; 17547c478bd9Sstevel@tonic-gate case DT_STRTAB: 175556deab07SRod Evans STRTAB(lmp) = (void *)(dyn->d_un.d_ptr + base); 17567c478bd9Sstevel@tonic-gate break; 17577c478bd9Sstevel@tonic-gate case DT_SYMENT: 175856deab07SRod Evans SYMENT(lmp) = dyn->d_un.d_val; 17597c478bd9Sstevel@tonic-gate break; 17607c478bd9Sstevel@tonic-gate case DT_FEATURE_1: 176156deab07SRod Evans dyn->d_un.d_val |= DTF_1_PARINIT; 176256deab07SRod Evans if (dyn->d_un.d_val & DTF_1_CONFEXP) 17637c478bd9Sstevel@tonic-gate crle = 1; 17647c478bd9Sstevel@tonic-gate break; 17657c478bd9Sstevel@tonic-gate case DT_MOVESZ: 176656deab07SRod Evans MOVESZ(lmp) = dyn->d_un.d_val; 17677c478bd9Sstevel@tonic-gate FLAGS(lmp) |= FLG_RT_MOVE; 17687c478bd9Sstevel@tonic-gate break; 17697c478bd9Sstevel@tonic-gate case DT_MOVEENT: 177056deab07SRod Evans MOVEENT(lmp) = dyn->d_un.d_val; 17717c478bd9Sstevel@tonic-gate break; 17727c478bd9Sstevel@tonic-gate case DT_MOVETAB: 177356deab07SRod Evans MOVETAB(lmp) = (void *)(dyn->d_un.d_ptr + base); 17747c478bd9Sstevel@tonic-gate break; 17757c478bd9Sstevel@tonic-gate case DT_REL: 17767c478bd9Sstevel@tonic-gate case DT_RELA: 17777c478bd9Sstevel@tonic-gate /* 177875e7992aSrie * At this time, ld.so. can only handle one 177975e7992aSrie * type of relocation per object. 17807c478bd9Sstevel@tonic-gate */ 178156deab07SRod Evans REL(lmp) = (void *)(dyn->d_un.d_ptr + base); 17827c478bd9Sstevel@tonic-gate break; 17837c478bd9Sstevel@tonic-gate case DT_RELSZ: 17847c478bd9Sstevel@tonic-gate case DT_RELASZ: 178556deab07SRod Evans RELSZ(lmp) = dyn->d_un.d_val; 17867c478bd9Sstevel@tonic-gate break; 17877c478bd9Sstevel@tonic-gate case DT_RELENT: 17887c478bd9Sstevel@tonic-gate case DT_RELAENT: 178956deab07SRod Evans RELENT(lmp) = dyn->d_un.d_val; 17907c478bd9Sstevel@tonic-gate break; 17917c478bd9Sstevel@tonic-gate case DT_RELCOUNT: 17927c478bd9Sstevel@tonic-gate case DT_RELACOUNT: 179356deab07SRod Evans RELACOUNT(lmp) = (uint_t)dyn->d_un.d_val; 17947c478bd9Sstevel@tonic-gate break; 17957c478bd9Sstevel@tonic-gate case DT_HASH: 179656deab07SRod Evans HASH(lmp) = (uint_t *)(dyn->d_un.d_ptr + base); 17977c478bd9Sstevel@tonic-gate break; 17987c478bd9Sstevel@tonic-gate case DT_PLTGOT: 179956deab07SRod Evans PLTGOT(lmp) = 180056deab07SRod Evans (uint_t *)(dyn->d_un.d_ptr + base); 18017c478bd9Sstevel@tonic-gate break; 18027c478bd9Sstevel@tonic-gate case DT_PLTRELSZ: 180356deab07SRod Evans PLTRELSZ(lmp) = dyn->d_un.d_val; 18047c478bd9Sstevel@tonic-gate break; 18057c478bd9Sstevel@tonic-gate case DT_JMPREL: 180656deab07SRod Evans JMPREL(lmp) = (void *)(dyn->d_un.d_ptr + base); 18077c478bd9Sstevel@tonic-gate break; 18087c478bd9Sstevel@tonic-gate case DT_INIT: 180956deab07SRod Evans if (dyn->d_un.d_ptr != NULL) 18105b59e4caSab INIT(lmp) = 181156deab07SRod Evans (void (*)())(dyn->d_un.d_ptr + 181256deab07SRod Evans base); 18137c478bd9Sstevel@tonic-gate break; 18147c478bd9Sstevel@tonic-gate case DT_FINI: 181556deab07SRod Evans if (dyn->d_un.d_ptr != NULL) 18165b59e4caSab FINI(lmp) = 181756deab07SRod Evans (void (*)())(dyn->d_un.d_ptr + 181856deab07SRod Evans base); 18197c478bd9Sstevel@tonic-gate break; 18207c478bd9Sstevel@tonic-gate case DT_INIT_ARRAY: 182156deab07SRod Evans INITARRAY(lmp) = (Addr *)(dyn->d_un.d_ptr + 18227c478bd9Sstevel@tonic-gate base); 18237c478bd9Sstevel@tonic-gate break; 18247c478bd9Sstevel@tonic-gate case DT_INIT_ARRAYSZ: 182556deab07SRod Evans INITARRAYSZ(lmp) = (uint_t)dyn->d_un.d_val; 18267c478bd9Sstevel@tonic-gate break; 18277c478bd9Sstevel@tonic-gate case DT_FINI_ARRAY: 182856deab07SRod Evans FINIARRAY(lmp) = (Addr *)(dyn->d_un.d_ptr + 18297c478bd9Sstevel@tonic-gate base); 18307c478bd9Sstevel@tonic-gate break; 18317c478bd9Sstevel@tonic-gate case DT_FINI_ARRAYSZ: 183256deab07SRod Evans FINIARRAYSZ(lmp) = (uint_t)dyn->d_un.d_val; 18337c478bd9Sstevel@tonic-gate break; 18347c478bd9Sstevel@tonic-gate case DT_PREINIT_ARRAY: 183556deab07SRod Evans PREINITARRAY(lmp) = (Addr *)(dyn->d_un.d_ptr + 18367c478bd9Sstevel@tonic-gate base); 18377c478bd9Sstevel@tonic-gate break; 18387c478bd9Sstevel@tonic-gate case DT_PREINIT_ARRAYSZ: 183956deab07SRod Evans PREINITARRAYSZ(lmp) = (uint_t)dyn->d_un.d_val; 18407c478bd9Sstevel@tonic-gate break; 18417c478bd9Sstevel@tonic-gate case DT_RPATH: 18427c478bd9Sstevel@tonic-gate case DT_RUNPATH: 184356deab07SRod Evans rpath = dyn->d_un.d_val; 18447c478bd9Sstevel@tonic-gate break; 18457c478bd9Sstevel@tonic-gate case DT_FILTER: 184656deab07SRod Evans fltr = dyn->d_un.d_val; 184775e7992aSrie OBJFLTRNDX(lmp) = dynndx; 18487c478bd9Sstevel@tonic-gate FLAGS1(lmp) |= FL1_RT_OBJSFLTR; 18497c478bd9Sstevel@tonic-gate break; 18507c478bd9Sstevel@tonic-gate case DT_AUXILIARY: 18517c478bd9Sstevel@tonic-gate if (!(rtld_flags & RT_FL_NOAUXFLTR)) { 185256deab07SRod Evans fltr = dyn->d_un.d_val; 185375e7992aSrie OBJFLTRNDX(lmp) = dynndx; 18547c478bd9Sstevel@tonic-gate } 18557c478bd9Sstevel@tonic-gate FLAGS1(lmp) |= FL1_RT_OBJAFLTR; 18567c478bd9Sstevel@tonic-gate break; 18577c478bd9Sstevel@tonic-gate case DT_SUNW_FILTER: 18587c478bd9Sstevel@tonic-gate SYMSFLTRCNT(lmp)++; 18597c478bd9Sstevel@tonic-gate FLAGS1(lmp) |= FL1_RT_SYMSFLTR; 18607c478bd9Sstevel@tonic-gate break; 18617c478bd9Sstevel@tonic-gate case DT_SUNW_AUXILIARY: 18627c478bd9Sstevel@tonic-gate if (!(rtld_flags & RT_FL_NOAUXFLTR)) { 18637c478bd9Sstevel@tonic-gate SYMAFLTRCNT(lmp)++; 18647c478bd9Sstevel@tonic-gate } 18657c478bd9Sstevel@tonic-gate FLAGS1(lmp) |= FL1_RT_SYMAFLTR; 18667c478bd9Sstevel@tonic-gate break; 18677c478bd9Sstevel@tonic-gate case DT_DEPAUDIT: 18687c478bd9Sstevel@tonic-gate if (!(rtld_flags & RT_FL_NOAUDIT)) 186956deab07SRod Evans audit = dyn->d_un.d_val; 18707c478bd9Sstevel@tonic-gate break; 18717c478bd9Sstevel@tonic-gate case DT_CONFIG: 187256deab07SRod Evans cfile = dyn->d_un.d_val; 18737c478bd9Sstevel@tonic-gate break; 18747c478bd9Sstevel@tonic-gate case DT_DEBUG: 18757c478bd9Sstevel@tonic-gate /* 18767c478bd9Sstevel@tonic-gate * DT_DEBUG entries are only created in 18777c478bd9Sstevel@tonic-gate * dynamic objects that require an interpretor 18787c478bd9Sstevel@tonic-gate * (ie. all dynamic executables and some shared 18797c478bd9Sstevel@tonic-gate * objects), and provide for a hand-shake with 1880dde769a2SRod Evans * old debuggers. This entry is initialized to 1881dde769a2SRod Evans * zero by the link-editor. If a debugger is 1882dde769a2SRod Evans * monitoring us, and has updated this entry, 1883dde769a2SRod Evans * set the debugger monitor flag, and finish 1884dde769a2SRod Evans * initializing the debugging structure. See 1885dde769a2SRod Evans * setup(). Also, switch off any configuration 1886dde769a2SRod Evans * object use as most debuggers can't handle 1887dde769a2SRod Evans * fixed dynamic executables as dependencies. 18887c478bd9Sstevel@tonic-gate */ 188956deab07SRod Evans if (dyn->d_un.d_ptr) 18907c478bd9Sstevel@tonic-gate rtld_flags |= 18917c478bd9Sstevel@tonic-gate (RT_FL_DEBUGGER | RT_FL_NOOBJALT); 189256deab07SRod Evans dyn->d_un.d_ptr = (Addr)&r_debug; 18937c478bd9Sstevel@tonic-gate break; 18947c478bd9Sstevel@tonic-gate case DT_VERNEED: 189556deab07SRod Evans VERNEED(lmp) = (Verneed *)(dyn->d_un.d_ptr + 18967c478bd9Sstevel@tonic-gate base); 18977c478bd9Sstevel@tonic-gate break; 18987c478bd9Sstevel@tonic-gate case DT_VERNEEDNUM: 18997c478bd9Sstevel@tonic-gate /* LINTED */ 190056deab07SRod Evans VERNEEDNUM(lmp) = (int)dyn->d_un.d_val; 19017c478bd9Sstevel@tonic-gate break; 19027c478bd9Sstevel@tonic-gate case DT_VERDEF: 190356deab07SRod Evans VERDEF(lmp) = (Verdef *)(dyn->d_un.d_ptr + 190456deab07SRod Evans base); 19057c478bd9Sstevel@tonic-gate break; 19067c478bd9Sstevel@tonic-gate case DT_VERDEFNUM: 19077c478bd9Sstevel@tonic-gate /* LINTED */ 190856deab07SRod Evans VERDEFNUM(lmp) = (int)dyn->d_un.d_val; 19097c478bd9Sstevel@tonic-gate break; 19103b41b08bSab case DT_VERSYM: 1911d840867fSab /* 1912d840867fSab * The Solaris ld does not produce DT_VERSYM, 1913d840867fSab * but the GNU ld does, in order to support 1914d840867fSab * their style of versioning, which differs 1915d840867fSab * from ours in some ways, while using the 1916d840867fSab * same data structures. The presence of 1917d840867fSab * DT_VERSYM therefore means that GNU 1918d840867fSab * versioning rules apply to the given file. 1919d840867fSab * If DT_VERSYM is not present, then Solaris 1920d840867fSab * versioning rules apply. 1921d840867fSab */ 192256deab07SRod Evans VERSYM(lmp) = (Versym *)(dyn->d_un.d_ptr + 192356deab07SRod Evans base); 19243b41b08bSab break; 19257c478bd9Sstevel@tonic-gate case DT_BIND_NOW: 192656deab07SRod Evans if ((dyn->d_un.d_val & DF_BIND_NOW) && 192756deab07SRod Evans ((rtld_flags2 & RT_FL2_BINDLAZY) == 0)) { 19287c478bd9Sstevel@tonic-gate MODE(lmp) |= RTLD_NOW; 19297c478bd9Sstevel@tonic-gate MODE(lmp) &= ~RTLD_LAZY; 19307c478bd9Sstevel@tonic-gate } 19317c478bd9Sstevel@tonic-gate break; 19327c478bd9Sstevel@tonic-gate case DT_FLAGS: 193356deab07SRod Evans FLAGS1(lmp) |= FL1_RT_DTFLAGS; 193456deab07SRod Evans if (dyn->d_un.d_val & DF_SYMBOLIC) 19357c478bd9Sstevel@tonic-gate FLAGS1(lmp) |= FL1_RT_SYMBOLIC; 193656deab07SRod Evans if ((dyn->d_un.d_val & DF_BIND_NOW) && 1937dffec89cSrie ((rtld_flags2 & RT_FL2_BINDLAZY) == 0)) { 19387c478bd9Sstevel@tonic-gate MODE(lmp) |= RTLD_NOW; 19397c478bd9Sstevel@tonic-gate MODE(lmp) &= ~RTLD_LAZY; 19407c478bd9Sstevel@tonic-gate } 1941d326b23bSrie /* 1942d326b23bSrie * Capture any static TLS use, and enforce that 1943d326b23bSrie * this object be non-deletable. 1944d326b23bSrie */ 194556deab07SRod Evans if (dyn->d_un.d_val & DF_STATIC_TLS) { 1946d326b23bSrie FLAGS1(lmp) |= FL1_RT_TLSSTAT; 1947d326b23bSrie MODE(lmp) |= RTLD_NODELETE; 1948d326b23bSrie } 19497c478bd9Sstevel@tonic-gate break; 19507c478bd9Sstevel@tonic-gate case DT_FLAGS_1: 195156deab07SRod Evans if (dyn->d_un.d_val & DF_1_DISPRELPND) 19527c478bd9Sstevel@tonic-gate FLAGS1(lmp) |= FL1_RT_DISPREL; 195356deab07SRod Evans if (dyn->d_un.d_val & DF_1_GROUP) 19547c478bd9Sstevel@tonic-gate FLAGS(lmp) |= 19552017c965SRod Evans (FLG_RT_SETGROUP | FLG_RT_PUBHDL); 195656deab07SRod Evans if ((dyn->d_un.d_val & DF_1_NOW) && 1957dffec89cSrie ((rtld_flags2 & RT_FL2_BINDLAZY) == 0)) { 19587c478bd9Sstevel@tonic-gate MODE(lmp) |= RTLD_NOW; 19597c478bd9Sstevel@tonic-gate MODE(lmp) &= ~RTLD_LAZY; 19607c478bd9Sstevel@tonic-gate } 196156deab07SRod Evans if (dyn->d_un.d_val & DF_1_NODELETE) 19627c478bd9Sstevel@tonic-gate MODE(lmp) |= RTLD_NODELETE; 196356deab07SRod Evans if (dyn->d_un.d_val & DF_1_INITFIRST) 19647c478bd9Sstevel@tonic-gate FLAGS(lmp) |= FLG_RT_INITFRST; 196556deab07SRod Evans if (dyn->d_un.d_val & DF_1_NOOPEN) 19667c478bd9Sstevel@tonic-gate FLAGS(lmp) |= FLG_RT_NOOPEN; 196756deab07SRod Evans if (dyn->d_un.d_val & DF_1_LOADFLTR) 19687c478bd9Sstevel@tonic-gate FLAGS(lmp) |= FLG_RT_LOADFLTR; 196956deab07SRod Evans if (dyn->d_un.d_val & DF_1_NODUMP) 19707c478bd9Sstevel@tonic-gate FLAGS(lmp) |= FLG_RT_NODUMP; 197156deab07SRod Evans if (dyn->d_un.d_val & DF_1_CONFALT) 19727c478bd9Sstevel@tonic-gate crle = 1; 197356deab07SRod Evans if (dyn->d_un.d_val & DF_1_DIRECT) 19749a411307Srie FLAGS1(lmp) |= FL1_RT_DIRECT; 197556deab07SRod Evans if (dyn->d_un.d_val & DF_1_NODEFLIB) 19767c478bd9Sstevel@tonic-gate FLAGS1(lmp) |= FL1_RT_NODEFLIB; 197756deab07SRod Evans if (dyn->d_un.d_val & DF_1_ENDFILTEE) 19787c478bd9Sstevel@tonic-gate FLAGS1(lmp) |= FL1_RT_ENDFILTE; 197956deab07SRod Evans if (dyn->d_un.d_val & DF_1_TRANS) 19807c478bd9Sstevel@tonic-gate FLAGS(lmp) |= FLG_RT_TRANS; 198156deab07SRod Evans 19827247f888Srie /* 19837247f888Srie * Global auditing is only meaningful when 19847247f888Srie * specified by the initiating object of the 19857247f888Srie * process - typically the dynamic executable. 19867247f888Srie * If this is the initiaiting object, its link- 19877247f888Srie * map will not yet have been added to the 19887247f888Srie * link-map list, and consequently the link-map 19897247f888Srie * list is empty. (see setup()). 19907247f888Srie */ 199156deab07SRod Evans if (dyn->d_un.d_val & DF_1_GLOBAUDIT) { 1992481bba9eSRod Evans if (lml_main.lm_head == NULL) 19937247f888Srie FLAGS1(lmp) |= FL1_RT_GLOBAUD; 19947247f888Srie else 19957247f888Srie DBG_CALL(Dbg_audit_ignore(lmp)); 19967247f888Srie } 19977247f888Srie 19987c478bd9Sstevel@tonic-gate /* 19997c478bd9Sstevel@tonic-gate * If this object identifies itself as an 20007c478bd9Sstevel@tonic-gate * interposer, but relocation processing has 20017c478bd9Sstevel@tonic-gate * already started, then demote it. It's too 20027c478bd9Sstevel@tonic-gate * late to guarantee complete interposition. 20037c478bd9Sstevel@tonic-gate */ 2004a953e2b1Srie /* BEGIN CSTYLED */ 200556deab07SRod Evans if (dyn->d_un.d_val & 20069a411307Srie (DF_1_INTERPOSE | DF_1_SYMINTPOSE)) { 20079a411307Srie if (lml->lm_flags & LML_FLG_STARTREL) { 20085aefb655Srie DBG_CALL(Dbg_util_intoolate(lmp)); 20097c478bd9Sstevel@tonic-gate if (lml->lm_flags & LML_FLG_TRC_ENABLE) 20107c478bd9Sstevel@tonic-gate (void) printf( 20117c478bd9Sstevel@tonic-gate MSG_INTL(MSG_LDD_REL_ERR2), 20127c478bd9Sstevel@tonic-gate NAME(lmp)); 201356deab07SRod Evans } else if (dyn->d_un.d_val & DF_1_INTERPOSE) 20149a411307Srie FLAGS(lmp) |= FLG_RT_OBJINTPO; 20159a411307Srie else 20169a411307Srie FLAGS(lmp) |= FLG_RT_SYMINTPO; 20177c478bd9Sstevel@tonic-gate } 2018a953e2b1Srie /* END CSTYLED */ 20197c478bd9Sstevel@tonic-gate break; 20207c478bd9Sstevel@tonic-gate case DT_SYMINFO: 202156deab07SRod Evans SYMINFO(lmp) = (Syminfo *)(dyn->d_un.d_ptr + 20227c478bd9Sstevel@tonic-gate base); 20237c478bd9Sstevel@tonic-gate break; 20247c478bd9Sstevel@tonic-gate case DT_SYMINENT: 202556deab07SRod Evans SYMINENT(lmp) = dyn->d_un.d_val; 20267c478bd9Sstevel@tonic-gate break; 20277c478bd9Sstevel@tonic-gate case DT_PLTPAD: 202856deab07SRod Evans PLTPAD(lmp) = (void *)(dyn->d_un.d_ptr + base); 20297c478bd9Sstevel@tonic-gate break; 20307c478bd9Sstevel@tonic-gate case DT_PLTPADSZ: 203156deab07SRod Evans pltpadsz = dyn->d_un.d_val; 20327c478bd9Sstevel@tonic-gate break; 20337c478bd9Sstevel@tonic-gate case DT_SUNW_RTLDINF: 20347c478bd9Sstevel@tonic-gate /* 203510a4fa49Srie * Maintain a list of RTLDINFO structures. 203610a4fa49Srie * Typically, libc is the only supplier, and 203710a4fa49Srie * only one structure is provided. However, 203810a4fa49Srie * multiple suppliers and multiple structures 203910a4fa49Srie * are supported. For example, one structure 204010a4fa49Srie * may provide thread_init, and another 204110a4fa49Srie * structure may provide atexit reservations. 20427c478bd9Sstevel@tonic-gate */ 2043dde769a2SRod Evans if ((rti = alist_append(&lml->lm_rti, NULL, 204456deab07SRod Evans sizeof (Rti_desc), 204556deab07SRod Evans AL_CNT_RTLDINFO)) == NULL) { 20467c478bd9Sstevel@tonic-gate remove_so(0, lmp); 204756deab07SRod Evans return (NULL); 20487c478bd9Sstevel@tonic-gate } 204910a4fa49Srie rti->rti_lmp = lmp; 205056deab07SRod Evans rti->rti_info = (void *)(dyn->d_un.d_ptr + 205156deab07SRod Evans base); 20527c478bd9Sstevel@tonic-gate break; 2053d579eb63Sab case DT_SUNW_SORTENT: 205456deab07SRod Evans SUNWSORTENT(lmp) = dyn->d_un.d_val; 2055d579eb63Sab break; 2056d579eb63Sab case DT_SUNW_SYMSORT: 2057d579eb63Sab SUNWSYMSORT(lmp) = 205856deab07SRod Evans (void *)(dyn->d_un.d_ptr + base); 2059d579eb63Sab break; 2060d579eb63Sab case DT_SUNW_SYMSORTSZ: 206156deab07SRod Evans SUNWSYMSORTSZ(lmp) = dyn->d_un.d_val; 2062d579eb63Sab break; 20637c478bd9Sstevel@tonic-gate case DT_DEPRECATED_SPARC_REGISTER: 20647c478bd9Sstevel@tonic-gate case M_DT_REGISTER: 20657c478bd9Sstevel@tonic-gate FLAGS(lmp) |= FLG_RT_REGSYMS; 20667c478bd9Sstevel@tonic-gate break; 20677c478bd9Sstevel@tonic-gate } 20687c478bd9Sstevel@tonic-gate } 20697c478bd9Sstevel@tonic-gate 20707c478bd9Sstevel@tonic-gate if (PLTPAD(lmp)) { 20717c478bd9Sstevel@tonic-gate if (pltpadsz == (Xword)0) 2072481bba9eSRod Evans PLTPAD(lmp) = NULL; 20737c478bd9Sstevel@tonic-gate else 20747c478bd9Sstevel@tonic-gate PLTPADEND(lmp) = (void *)((Addr)PLTPAD(lmp) + 20757c478bd9Sstevel@tonic-gate pltpadsz); 20767c478bd9Sstevel@tonic-gate } 20777c478bd9Sstevel@tonic-gate } 20787c478bd9Sstevel@tonic-gate 20799039eeafSab /* 20809039eeafSab * A dynsym contains only global functions. We want to have 20819039eeafSab * a version of it that also includes local functions, so that 20829039eeafSab * dladdr() will be able to report names for local functions 20839039eeafSab * when used to generate a stack trace for a stripped file. 20849039eeafSab * This version of the dynsym is provided via DT_SUNW_SYMTAB. 20859039eeafSab * 20869039eeafSab * In producing DT_SUNW_SYMTAB, ld uses a non-obvious trick 20879039eeafSab * in order to avoid having to have two copies of the global 20889039eeafSab * symbols held in DT_SYMTAB: The local symbols are placed in 20899039eeafSab * a separate section than the globals in the dynsym, but the 20909039eeafSab * linker conspires to put the data for these two sections adjacent 20919039eeafSab * to each other. DT_SUNW_SYMTAB points at the top of the local 20929039eeafSab * symbols, and DT_SUNW_SYMSZ is the combined length of both tables. 20939039eeafSab * 20949039eeafSab * If the two sections are not adjacent, then something went wrong 20959039eeafSab * at link time. We use ASSERT to kill the process if this is 20969039eeafSab * a debug build. In a production build, we will silently ignore 20979039eeafSab * the presence of the .ldynsym and proceed. We can detect this 20989039eeafSab * situation by checking to see that DT_SYMTAB lies in 20999039eeafSab * the range given by DT_SUNW_SYMTAB/DT_SUNW_SYMSZ. 21009039eeafSab */ 21019039eeafSab if ((SUNWSYMTAB(lmp) != NULL) && 21029039eeafSab (((char *)SYMTAB(lmp) <= (char *)SUNWSYMTAB(lmp)) || 21039039eeafSab (((char *)SYMTAB(lmp) >= 21049039eeafSab (SUNWSYMSZ(lmp) + (char *)SUNWSYMTAB(lmp)))))) { 21059039eeafSab ASSERT(0); 21069039eeafSab SUNWSYMTAB(lmp) = NULL; 21079039eeafSab SUNWSYMSZ(lmp) = 0; 21089039eeafSab } 21099039eeafSab 21107c478bd9Sstevel@tonic-gate /* 21117c478bd9Sstevel@tonic-gate * If configuration file use hasn't been disabled, and a configuration 21127c478bd9Sstevel@tonic-gate * file hasn't already been set via an environment variable, see if any 21137c478bd9Sstevel@tonic-gate * application specific configuration file is specified. An LD_CONFIG 21147c478bd9Sstevel@tonic-gate * setting is used first, but if this image was generated via crle(1) 21157c478bd9Sstevel@tonic-gate * then a default configuration file is a fall-back. 21167c478bd9Sstevel@tonic-gate */ 2117481bba9eSRod Evans if ((!(rtld_flags & RT_FL_NOCFG)) && (config->c_name == NULL)) { 21187c478bd9Sstevel@tonic-gate if (cfile) 21197c478bd9Sstevel@tonic-gate config->c_name = (const char *)(cfile + 21207c478bd9Sstevel@tonic-gate (char *)STRTAB(lmp)); 212156deab07SRod Evans else if (crle) 21227c478bd9Sstevel@tonic-gate rtld_flags |= RT_FL_CONFAPP; 21237c478bd9Sstevel@tonic-gate } 21247c478bd9Sstevel@tonic-gate 21257c478bd9Sstevel@tonic-gate if (rpath) 21267c478bd9Sstevel@tonic-gate RPATH(lmp) = (char *)(rpath + (char *)STRTAB(lmp)); 212756deab07SRod Evans if (fltr) 212856deab07SRod Evans REFNAME(lmp) = (char *)(fltr + (char *)STRTAB(lmp)); 21297c478bd9Sstevel@tonic-gate 21307c478bd9Sstevel@tonic-gate /* 21317c478bd9Sstevel@tonic-gate * For Intel ABI compatibility. It's possible that a JMPREL can be 21327c478bd9Sstevel@tonic-gate * specified without any other relocations (e.g. a dynamic executable 21337c478bd9Sstevel@tonic-gate * normally only contains .plt relocations). If this is the case then 21347c478bd9Sstevel@tonic-gate * no REL, RELSZ or RELENT will have been created. For us to be able 21357c478bd9Sstevel@tonic-gate * to traverse the .plt relocations under LD_BIND_NOW we need to know 21367c478bd9Sstevel@tonic-gate * the RELENT for these relocations. Refer to elf_reloc() for more 21377c478bd9Sstevel@tonic-gate * details. 21387c478bd9Sstevel@tonic-gate */ 21397c478bd9Sstevel@tonic-gate if (!RELENT(lmp) && JMPREL(lmp)) 214056deab07SRod Evans RELENT(lmp) = sizeof (M_RELOC); 21417c478bd9Sstevel@tonic-gate 21427c478bd9Sstevel@tonic-gate /* 21437c478bd9Sstevel@tonic-gate * Establish any per-object auditing. If we're establishing `main's 21447c478bd9Sstevel@tonic-gate * link-map its too early to go searching for audit objects so just 21457c478bd9Sstevel@tonic-gate * hold the object name for later (see setup()). 21467c478bd9Sstevel@tonic-gate */ 21477c478bd9Sstevel@tonic-gate if (audit) { 21487c478bd9Sstevel@tonic-gate char *cp = audit + (char *)STRTAB(lmp); 21497c478bd9Sstevel@tonic-gate 21507c478bd9Sstevel@tonic-gate if (*cp) { 21517c478bd9Sstevel@tonic-gate if (((AUDITORS(lmp) = 215256deab07SRod Evans calloc(1, sizeof (Audit_desc))) == NULL) || 215356deab07SRod Evans ((AUDITORS(lmp)->ad_name = strdup(cp)) == NULL)) { 21547c478bd9Sstevel@tonic-gate remove_so(0, lmp); 215556deab07SRod Evans return (NULL); 21567c478bd9Sstevel@tonic-gate } 215741072f3cSrie if (lml_main.lm_head) { 21589aa23310Srie if (audit_setup(lmp, AUDITORS(lmp), 0, 21599aa23310Srie in_nfavl) == 0) { 21607c478bd9Sstevel@tonic-gate remove_so(0, lmp); 216156deab07SRod Evans return (NULL); 21627c478bd9Sstevel@tonic-gate } 216356deab07SRod Evans AFLAGS(lmp) |= AUDITORS(lmp)->ad_flags; 21647c478bd9Sstevel@tonic-gate lml->lm_flags |= LML_FLG_LOCAUDIT; 21657c478bd9Sstevel@tonic-gate } 21667c478bd9Sstevel@tonic-gate } 21677c478bd9Sstevel@tonic-gate } 21687c478bd9Sstevel@tonic-gate 216956deab07SRod Evans if (tphdr && (tls_assign(lml, lmp, tphdr) == 0)) { 21707c478bd9Sstevel@tonic-gate remove_so(0, lmp); 217156deab07SRod Evans return (NULL); 21727c478bd9Sstevel@tonic-gate } 21737c478bd9Sstevel@tonic-gate 217456deab07SRod Evans if (cap) 217556deab07SRod Evans cap_assign(cap, lmp); 217656deab07SRod Evans 21777c478bd9Sstevel@tonic-gate /* 21787c478bd9Sstevel@tonic-gate * Add the mapped object to the end of the link map list. 21797c478bd9Sstevel@tonic-gate */ 21807c478bd9Sstevel@tonic-gate lm_append(lml, lmco, lmp); 218156deab07SRod Evans 218256deab07SRod Evans /* 218356deab07SRod Evans * Start the system loading in the ELF information we'll be processing. 218456deab07SRod Evans */ 218556deab07SRod Evans if (REL(lmp)) { 218656deab07SRod Evans (void) madvise((void *)ADDR(lmp), (uintptr_t)REL(lmp) + 218756deab07SRod Evans (uintptr_t)RELSZ(lmp) - (uintptr_t)ADDR(lmp), 218856deab07SRod Evans MADV_WILLNEED); 218956deab07SRod Evans } 21907c478bd9Sstevel@tonic-gate return (lmp); 21917c478bd9Sstevel@tonic-gate } 21927c478bd9Sstevel@tonic-gate 21937c478bd9Sstevel@tonic-gate /* 21947c478bd9Sstevel@tonic-gate * Assign hardware/software capabilities. 21957c478bd9Sstevel@tonic-gate */ 21967c478bd9Sstevel@tonic-gate void 21977c478bd9Sstevel@tonic-gate cap_assign(Cap *cap, Rt_map *lmp) 21987c478bd9Sstevel@tonic-gate { 21997c478bd9Sstevel@tonic-gate while (cap->c_tag != CA_SUNW_NULL) { 22007c478bd9Sstevel@tonic-gate switch (cap->c_tag) { 22017c478bd9Sstevel@tonic-gate case CA_SUNW_HW_1: 22027c478bd9Sstevel@tonic-gate HWCAP(lmp) = cap->c_un.c_val; 22037c478bd9Sstevel@tonic-gate break; 22047c478bd9Sstevel@tonic-gate case CA_SUNW_SF_1: 22057c478bd9Sstevel@tonic-gate SFCAP(lmp) = cap->c_un.c_val; 22067c478bd9Sstevel@tonic-gate } 22077c478bd9Sstevel@tonic-gate cap++; 22087c478bd9Sstevel@tonic-gate } 22097c478bd9Sstevel@tonic-gate } 22107c478bd9Sstevel@tonic-gate 22117c478bd9Sstevel@tonic-gate /* 22127c478bd9Sstevel@tonic-gate * Build full pathname of shared object from given directory name and filename. 22137c478bd9Sstevel@tonic-gate */ 22147c478bd9Sstevel@tonic-gate static char * 221556deab07SRod Evans elf_get_so(const char *dir, const char *file, size_t dlen, size_t flen) 22167c478bd9Sstevel@tonic-gate { 22177c478bd9Sstevel@tonic-gate static char pname[PATH_MAX]; 22187c478bd9Sstevel@tonic-gate 221956deab07SRod Evans (void) strncpy(pname, dir, dlen); 222056deab07SRod Evans pname[dlen++] = '/'; 222156deab07SRod Evans (void) strncpy(&pname[dlen], file, flen + 1); 22227c478bd9Sstevel@tonic-gate return (pname); 22237c478bd9Sstevel@tonic-gate } 22247c478bd9Sstevel@tonic-gate 22257c478bd9Sstevel@tonic-gate /* 22267c478bd9Sstevel@tonic-gate * The copy relocation is recorded in a copy structure which will be applied 22277c478bd9Sstevel@tonic-gate * after all other relocations are carried out. This provides for copying data 22287c478bd9Sstevel@tonic-gate * that must be relocated itself (ie. pointers in shared objects). This 22297c478bd9Sstevel@tonic-gate * structure also provides a means of binding RTLD_GROUP dependencies to any 22307c478bd9Sstevel@tonic-gate * copy relocations that have been taken from any group members. 22317c478bd9Sstevel@tonic-gate * 22327c478bd9Sstevel@tonic-gate * If the size of the .bss area available for the copy information is not the 22337c478bd9Sstevel@tonic-gate * same as the source of the data inform the user if we're under ldd(1) control 22347c478bd9Sstevel@tonic-gate * (this checking was only established in 5.3, so by only issuing an error via 22357c478bd9Sstevel@tonic-gate * ldd(1) we maintain the standard set by previous releases). 22367c478bd9Sstevel@tonic-gate */ 22377c478bd9Sstevel@tonic-gate int 22387c478bd9Sstevel@tonic-gate elf_copy_reloc(char *name, Sym *rsym, Rt_map *rlmp, void *radd, Sym *dsym, 22397c478bd9Sstevel@tonic-gate Rt_map *dlmp, const void *dadd) 22407c478bd9Sstevel@tonic-gate { 22417c478bd9Sstevel@tonic-gate Rel_copy rc; 22427c478bd9Sstevel@tonic-gate Lm_list *lml = LIST(rlmp); 22437c478bd9Sstevel@tonic-gate 22447c478bd9Sstevel@tonic-gate rc.r_name = name; 22457c478bd9Sstevel@tonic-gate rc.r_rsym = rsym; /* the new reference symbol and its */ 22467c478bd9Sstevel@tonic-gate rc.r_rlmp = rlmp; /* associated link-map */ 22477c478bd9Sstevel@tonic-gate rc.r_dlmp = dlmp; /* the defining link-map */ 22487c478bd9Sstevel@tonic-gate rc.r_dsym = dsym; /* the original definition */ 22497c478bd9Sstevel@tonic-gate rc.r_radd = radd; 22507c478bd9Sstevel@tonic-gate rc.r_dadd = dadd; 22517c478bd9Sstevel@tonic-gate 22527c478bd9Sstevel@tonic-gate if (rsym->st_size > dsym->st_size) 22537c478bd9Sstevel@tonic-gate rc.r_size = (size_t)dsym->st_size; 22547c478bd9Sstevel@tonic-gate else 22557c478bd9Sstevel@tonic-gate rc.r_size = (size_t)rsym->st_size; 22567c478bd9Sstevel@tonic-gate 2257cce0e03bSab if (alist_append(©_R(dlmp), &rc, sizeof (Rel_copy), 225856deab07SRod Evans AL_CNT_COPYREL) == NULL) { 22597c478bd9Sstevel@tonic-gate if (!(lml->lm_flags & LML_FLG_TRC_WARN)) 22607c478bd9Sstevel@tonic-gate return (0); 22617c478bd9Sstevel@tonic-gate else 22627c478bd9Sstevel@tonic-gate return (1); 22637c478bd9Sstevel@tonic-gate } 22647c478bd9Sstevel@tonic-gate if (!(FLAGS1(dlmp) & FL1_RT_COPYTOOK)) { 2265cce0e03bSab if (aplist_append(©_S(rlmp), dlmp, 2266cce0e03bSab AL_CNT_COPYREL) == NULL) { 22677c478bd9Sstevel@tonic-gate if (!(lml->lm_flags & LML_FLG_TRC_WARN)) 22687c478bd9Sstevel@tonic-gate return (0); 22697c478bd9Sstevel@tonic-gate else 22707c478bd9Sstevel@tonic-gate return (1); 22717c478bd9Sstevel@tonic-gate } 22727c478bd9Sstevel@tonic-gate FLAGS1(dlmp) |= FL1_RT_COPYTOOK; 22737c478bd9Sstevel@tonic-gate } 22747c478bd9Sstevel@tonic-gate 22757c478bd9Sstevel@tonic-gate /* 22767c478bd9Sstevel@tonic-gate * If we are tracing (ldd), warn the user if 22777c478bd9Sstevel@tonic-gate * 1) the size from the reference symbol differs from the 22787c478bd9Sstevel@tonic-gate * copy definition. We can only copy as much data as the 22797c478bd9Sstevel@tonic-gate * reference (dynamic executables) entry allows. 22807c478bd9Sstevel@tonic-gate * 2) the copy definition has STV_PROTECTED visibility. 22817c478bd9Sstevel@tonic-gate */ 22827c478bd9Sstevel@tonic-gate if (lml->lm_flags & LML_FLG_TRC_WARN) { 22837c478bd9Sstevel@tonic-gate if (rsym->st_size != dsym->st_size) { 22847c478bd9Sstevel@tonic-gate (void) printf(MSG_INTL(MSG_LDD_CPY_SIZDIF), 22855aefb655Srie _conv_reloc_type(M_R_COPY), demangle(name), 22867c478bd9Sstevel@tonic-gate NAME(rlmp), EC_XWORD(rsym->st_size), 22877c478bd9Sstevel@tonic-gate NAME(dlmp), EC_XWORD(dsym->st_size)); 22887c478bd9Sstevel@tonic-gate if (rsym->st_size > dsym->st_size) 22897c478bd9Sstevel@tonic-gate (void) printf(MSG_INTL(MSG_LDD_CPY_INSDATA), 22907c478bd9Sstevel@tonic-gate NAME(dlmp)); 22917c478bd9Sstevel@tonic-gate else 22927c478bd9Sstevel@tonic-gate (void) printf(MSG_INTL(MSG_LDD_CPY_DATRUNC), 22937c478bd9Sstevel@tonic-gate NAME(rlmp)); 22947c478bd9Sstevel@tonic-gate } 22957c478bd9Sstevel@tonic-gate 22967c478bd9Sstevel@tonic-gate if (ELF_ST_VISIBILITY(dsym->st_other) == STV_PROTECTED) { 22977c478bd9Sstevel@tonic-gate (void) printf(MSG_INTL(MSG_LDD_CPY_PROT), 22985aefb655Srie _conv_reloc_type(M_R_COPY), demangle(name), 2299a953e2b1Srie NAME(dlmp)); 23007c478bd9Sstevel@tonic-gate } 23017c478bd9Sstevel@tonic-gate } 23027c478bd9Sstevel@tonic-gate 23035aefb655Srie DBG_CALL(Dbg_reloc_apply_val(lml, ELF_DBG_RTLD, (Xword)radd, 23045aefb655Srie (Xword)rc.r_size)); 23057c478bd9Sstevel@tonic-gate return (1); 23067c478bd9Sstevel@tonic-gate } 23077c478bd9Sstevel@tonic-gate 23087c478bd9Sstevel@tonic-gate /* 23097c478bd9Sstevel@tonic-gate * Determine the symbol location of an address within a link-map. Look for 23107c478bd9Sstevel@tonic-gate * the nearest symbol (whose value is less than or equal to the required 23117c478bd9Sstevel@tonic-gate * address). This is the object specific part of dladdr(). 23127c478bd9Sstevel@tonic-gate */ 23137c478bd9Sstevel@tonic-gate static void 23147c478bd9Sstevel@tonic-gate elf_dladdr(ulong_t addr, Rt_map *lmp, Dl_info *dlip, void **info, int flags) 23157c478bd9Sstevel@tonic-gate { 23167c478bd9Sstevel@tonic-gate ulong_t ndx, cnt, base, _value; 23176221fe92Sab Sym *sym, *_sym = NULL; 23187c478bd9Sstevel@tonic-gate const char *str; 23195343e1b3Sab int _flags; 2320d579eb63Sab uint_t *dynaddr_ndx; 2321d579eb63Sab uint_t dynaddr_n = 0; 2322d579eb63Sab ulong_t value; 23237c478bd9Sstevel@tonic-gate 23247c478bd9Sstevel@tonic-gate /* 23259039eeafSab * If SUNWSYMTAB() is non-NULL, then it sees a special version of 23269039eeafSab * the dynsym that starts with any local function symbols that exist in 23279039eeafSab * the library and then moves to the data held in SYMTAB(). In this 23289039eeafSab * case, SUNWSYMSZ tells us how long the symbol table is. The 23299039eeafSab * availability of local function symbols will enhance the results 23309039eeafSab * we can provide. 23319039eeafSab * 2332d579eb63Sab * If SUNWSYMTAB() is non-NULL, then there might also be a 2333d579eb63Sab * SUNWSYMSORT() vector associated with it. SUNWSYMSORT() contains 2334d579eb63Sab * an array of indices into SUNWSYMTAB, sorted by increasing 2335d579eb63Sab * address. We can use this to do an O(log N) search instead of a 2336d579eb63Sab * brute force search. 2337d579eb63Sab * 23389039eeafSab * If SUNWSYMTAB() is NULL, then SYMTAB() references a dynsym that 23399039eeafSab * contains only global symbols. In that case, the length of 23409039eeafSab * the symbol table comes from the nchain field of the related 23419039eeafSab * symbol lookup hash table. 23427c478bd9Sstevel@tonic-gate */ 23437c478bd9Sstevel@tonic-gate str = STRTAB(lmp); 23449039eeafSab if (SUNWSYMSZ(lmp) == NULL) { 23459039eeafSab sym = SYMTAB(lmp); 23469039eeafSab /* 23479039eeafSab * If we don't have a .hash table there are no symbols 23489039eeafSab * to look at. 23499039eeafSab */ 2350481bba9eSRod Evans if (HASH(lmp) == NULL) 23519039eeafSab return; 23529039eeafSab cnt = HASH(lmp)[1]; 23539039eeafSab } else { 23549039eeafSab sym = SUNWSYMTAB(lmp); 23559039eeafSab cnt = SUNWSYMSZ(lmp) / SYMENT(lmp); 2356d579eb63Sab dynaddr_ndx = SUNWSYMSORT(lmp); 2357d579eb63Sab if (dynaddr_ndx != NULL) 2358d579eb63Sab dynaddr_n = SUNWSYMSORTSZ(lmp) / SUNWSORTENT(lmp); 23599039eeafSab } 23607c478bd9Sstevel@tonic-gate 23617c478bd9Sstevel@tonic-gate if (FLAGS(lmp) & FLG_RT_FIXED) 23627c478bd9Sstevel@tonic-gate base = 0; 23637c478bd9Sstevel@tonic-gate else 23647c478bd9Sstevel@tonic-gate base = ADDR(lmp); 23657c478bd9Sstevel@tonic-gate 2366d579eb63Sab if (dynaddr_n > 0) { /* Binary search */ 2367d579eb63Sab long low = 0, low_bnd; 2368d579eb63Sab long high = dynaddr_n - 1, high_bnd; 2369d579eb63Sab long mid; 2370d579eb63Sab Sym *mid_sym; 23717c478bd9Sstevel@tonic-gate 23729039eeafSab /* 2373d579eb63Sab * Note that SUNWSYMSORT only contains symbols types that 2374d579eb63Sab * supply memory addresses, so there's no need to check and 2375d579eb63Sab * filter out any other types. 23769039eeafSab */ 2377d579eb63Sab low_bnd = low; 2378d579eb63Sab high_bnd = high; 2379d579eb63Sab while (low <= high) { 2380d579eb63Sab mid = (low + high) / 2; 2381d579eb63Sab mid_sym = &sym[dynaddr_ndx[mid]]; 2382d579eb63Sab value = mid_sym->st_value + base; 2383d579eb63Sab if (addr < value) { 2384d579eb63Sab if ((sym[dynaddr_ndx[high]].st_value + base) >= 2385d579eb63Sab addr) 2386d579eb63Sab high_bnd = high; 2387d579eb63Sab high = mid - 1; 2388d579eb63Sab } else if (addr > value) { 2389d579eb63Sab if ((sym[dynaddr_ndx[low]].st_value + base) <= 2390d579eb63Sab addr) 2391d579eb63Sab low_bnd = low; 2392d579eb63Sab low = mid + 1; 2393d579eb63Sab } else { 2394d579eb63Sab _sym = mid_sym; 2395d579eb63Sab _value = value; 2396d579eb63Sab break; 2397d579eb63Sab } 2398d579eb63Sab } 2399d579eb63Sab /* 2400d579eb63Sab * If the above didn't find it exactly, then we must 2401d579eb63Sab * return the closest symbol with a value that doesn't 2402d579eb63Sab * exceed the one we are looking for. If that symbol exists, 2403d579eb63Sab * it will lie in the range bounded by low_bnd and 2404d579eb63Sab * high_bnd. This is a linear search, but a short one. 2405d579eb63Sab */ 2406d579eb63Sab if (_sym == NULL) { 2407d579eb63Sab for (mid = low_bnd; mid <= high_bnd; mid++) { 2408d579eb63Sab mid_sym = &sym[dynaddr_ndx[mid]]; 2409d579eb63Sab value = mid_sym->st_value + base; 2410d579eb63Sab if (addr >= value) { 2411d579eb63Sab _sym = mid_sym; 2412d579eb63Sab _value = value; 2413d579eb63Sab } else { 2414d579eb63Sab break; 2415d579eb63Sab } 2416d579eb63Sab } 2417d579eb63Sab } 2418d579eb63Sab } else { /* Linear search */ 2419d579eb63Sab for (_value = 0, sym++, ndx = 1; ndx < cnt; ndx++, sym++) { 2420d579eb63Sab /* 2421d579eb63Sab * Skip expected symbol types that are not functions 2422d579eb63Sab * or data: 2423d579eb63Sab * - A symbol table starts with an undefined symbol 2424d579eb63Sab * in slot 0. If we are using SUNWSYMTAB(), 2425d579eb63Sab * there will be a second undefined symbol 2426d579eb63Sab * right before the globals. 2427d579eb63Sab * - The local part of SUNWSYMTAB() contains a 2428d579eb63Sab * series of function symbols. Each section 2429d579eb63Sab * starts with an initial STT_FILE symbol. 2430d579eb63Sab */ 2431d579eb63Sab if ((sym->st_shndx == SHN_UNDEF) || 2432d579eb63Sab (ELF_ST_TYPE(sym->st_info) == STT_FILE)) 2433d579eb63Sab continue; 24347c478bd9Sstevel@tonic-gate 2435d579eb63Sab value = sym->st_value + base; 2436d579eb63Sab if (value > addr) 2437d579eb63Sab continue; 2438d579eb63Sab if (value < _value) 2439d579eb63Sab continue; 24407c478bd9Sstevel@tonic-gate 2441d579eb63Sab _sym = sym; 2442d579eb63Sab _value = value; 24437c478bd9Sstevel@tonic-gate 2444d579eb63Sab /* 2445d579eb63Sab * Note, because we accept local and global symbols 2446d579eb63Sab * we could find a section symbol that matches the 2447d579eb63Sab * associated address, which means that the symbol 2448d579eb63Sab * name will be null. In this case continue the 2449d579eb63Sab * search in case we can find a global symbol of 2450d579eb63Sab * the same value. 2451d579eb63Sab */ 2452d579eb63Sab if ((value == addr) && 2453d579eb63Sab (ELF_ST_TYPE(sym->st_info) != STT_SECTION)) 2454d579eb63Sab break; 2455d579eb63Sab } 24567c478bd9Sstevel@tonic-gate } 24577c478bd9Sstevel@tonic-gate 24585343e1b3Sab _flags = flags & RTLD_DL_MASK; 24597c478bd9Sstevel@tonic-gate if (_sym) { 24607c478bd9Sstevel@tonic-gate if (_flags == RTLD_DL_SYMENT) 24617c478bd9Sstevel@tonic-gate *info = (void *)_sym; 24627c478bd9Sstevel@tonic-gate else if (_flags == RTLD_DL_LINKMAP) 24637c478bd9Sstevel@tonic-gate *info = (void *)lmp; 24647c478bd9Sstevel@tonic-gate 24657c478bd9Sstevel@tonic-gate dlip->dli_sname = str + _sym->st_name; 24667c478bd9Sstevel@tonic-gate dlip->dli_saddr = (void *)_value; 24675343e1b3Sab } else { 24685343e1b3Sab /* 24695343e1b3Sab * addr lies between the beginning of the mapped segment and 24705343e1b3Sab * the first global symbol. We have no symbol to return 24715343e1b3Sab * and the caller requires one. We use _START_, the base 24725343e1b3Sab * address of the mapping. 24735343e1b3Sab */ 24745343e1b3Sab 24755343e1b3Sab if (_flags == RTLD_DL_SYMENT) { 24765343e1b3Sab /* 24775343e1b3Sab * An actual symbol struct is needed, so we 24785343e1b3Sab * construct one for _START_. To do this in a 24795343e1b3Sab * fully accurate way requires a different symbol 24805343e1b3Sab * for each mapped segment. This requires the 24815343e1b3Sab * use of dynamic memory and a mutex. That's too much 24825343e1b3Sab * plumbing for a fringe case of limited importance. 24835343e1b3Sab * 24845343e1b3Sab * Fortunately, we can simplify: 24855343e1b3Sab * - Only the st_size and st_info fields are useful 24865343e1b3Sab * outside of the linker internals. The others 24875343e1b3Sab * reference things that outside code cannot see, 24885343e1b3Sab * and can be set to 0. 24895343e1b3Sab * - It's just a label and there is no size 24905343e1b3Sab * to report. So, the size should be 0. 24915343e1b3Sab * This means that only st_info needs a non-zero 24925343e1b3Sab * (constant) value. A static struct will suffice. 24935343e1b3Sab * It must be const (readonly) so the caller can't 24945343e1b3Sab * change its meaning for subsequent callers. 24955343e1b3Sab */ 24965343e1b3Sab static const Sym fsym = { 0, 0, 0, 249737ffaf83SRod Evans ELF_ST_INFO(STB_LOCAL, STT_OBJECT) }; 24985343e1b3Sab *info = (void *) &fsym; 24995343e1b3Sab } 25005343e1b3Sab 25015343e1b3Sab dlip->dli_sname = MSG_ORIG(MSG_SYM_START); 25025343e1b3Sab dlip->dli_saddr = (void *) ADDR(lmp); 25037c478bd9Sstevel@tonic-gate } 25047c478bd9Sstevel@tonic-gate } 25057c478bd9Sstevel@tonic-gate 25067c478bd9Sstevel@tonic-gate /* 250775e7992aSrie * This routine is called as a last fall-back to search for a symbol from a 25082017c965SRod Evans * standard relocation or dlsym(). To maintain lazy loadings goal of reducing 25092017c965SRod Evans * the number of objects mapped, any symbol search is first carried out using 25102017c965SRod Evans * the objects that already exist in the process (either on a link-map list or 25112017c965SRod Evans * handle). If a symbol can't be found, and lazy dependencies are still 25122017c965SRod Evans * pending, this routine loads the dependencies in an attempt to locate the 25132017c965SRod Evans * symbol. 25147c478bd9Sstevel@tonic-gate */ 25157c478bd9Sstevel@tonic-gate Sym * 25169aa23310Srie elf_lazy_find_sym(Slookup *slp, Rt_map **_lmp, uint_t *binfo, int *in_nfavl) 25177c478bd9Sstevel@tonic-gate { 251837ffaf83SRod Evans Sym *sym = NULL; 25192017c965SRod Evans static APlist *alist = NULL; 25202017c965SRod Evans Aliste idx1; 25212017c965SRod Evans Rt_map *lmp1, *lmp = slp->sl_imap, *clmp = slp->sl_cmap; 25227c478bd9Sstevel@tonic-gate const char *name = slp->sl_name; 25232017c965SRod Evans Slookup sl1 = *slp; 25242017c965SRod Evans Lm_list *lml; 25252017c965SRod Evans Lm_cntl *lmc; 25262017c965SRod Evans 25272017c965SRod Evans /* 25282017c965SRod Evans * It's quite possible we've been here before to process objects, 25292017c965SRod Evans * therefore reinitialize our dynamic list. 25302017c965SRod Evans */ 25312017c965SRod Evans if (alist) 25322017c965SRod Evans aplist_reset(alist); 25332017c965SRod Evans 25342017c965SRod Evans /* 25352017c965SRod Evans * Discard any relocation index from further symbol searches. This 25362017c965SRod Evans * index has already been used to trigger any necessary lazy-loads, 25372017c965SRod Evans * and it might be because one of these lazy loads has failed that 25382017c965SRod Evans * we're performing this fallback. By removing the relocation index 25392017c965SRod Evans * we don't try and perform the same failed lazy loading activity again. 25402017c965SRod Evans */ 25412017c965SRod Evans sl1.sl_rsymndx = 0; 25422017c965SRod Evans 25432017c965SRod Evans /* 25442017c965SRod Evans * Determine the callers link-map list so that we can monitor whether 25452017c965SRod Evans * new objects have been added. 25462017c965SRod Evans */ 25472017c965SRod Evans lml = LIST(clmp); 25482017c965SRod Evans lmc = (Lm_cntl *)alist_item_by_offset(lml->lm_lists, CNTL(clmp)); 25497c478bd9Sstevel@tonic-gate 255075e7992aSrie /* 255175e7992aSrie * Generate a local list of new objects to process. This list can grow 255275e7992aSrie * as each object supplies its own lazy dependencies. 255375e7992aSrie */ 2554cce0e03bSab if (aplist_append(&alist, lmp, AL_CNT_LAZYFIND) == NULL) 2555cce0e03bSab return (NULL); 25567c478bd9Sstevel@tonic-gate 25572017c965SRod Evans for (APLIST_TRAVERSE(alist, idx1, lmp1)) { 25587c478bd9Sstevel@tonic-gate uint_t cnt = 0; 255975e7992aSrie Dyninfo *dip, *pdip; 25607c478bd9Sstevel@tonic-gate 256175e7992aSrie /* 256275e7992aSrie * Loop through the lazy DT_NEEDED entries examining each object 256375e7992aSrie * for the required symbol. If the symbol is not found, the 256475e7992aSrie * object is in turn added to the local alist, so that the 256575e7992aSrie * objects lazy DT_NEEDED entries can be examined. 25667c478bd9Sstevel@tonic-gate */ 2567cce0e03bSab lmp = lmp1; 256875e7992aSrie for (dip = DYNINFO(lmp), pdip = NULL; cnt < DYNINFOCNT(lmp); 256975e7992aSrie cnt++, pdip = dip++) { 25702017c965SRod Evans Grp_hdl *ghp; 25712017c965SRod Evans Grp_desc *gdp; 25722017c965SRod Evans Rt_map *nlmp, *llmp; 25732017c965SRod Evans Slookup sl2; 25742017c965SRod Evans Aliste idx2; 25757c478bd9Sstevel@tonic-gate 257675e7992aSrie if (((dip->di_flags & FLG_DI_LAZY) == 0) || 25777c478bd9Sstevel@tonic-gate dip->di_info) 25787c478bd9Sstevel@tonic-gate continue; 25797c478bd9Sstevel@tonic-gate 25807c478bd9Sstevel@tonic-gate /* 258175e7992aSrie * If this object has already failed to lazy load, and 258275e7992aSrie * we're still processing the same runtime linker 258375e7992aSrie * operation that produced the failure, don't bother 258475e7992aSrie * to try and load the object again. 258575e7992aSrie */ 258675e7992aSrie if ((dip->di_flags & FLG_DI_LAZYFAIL) && pdip && 258775e7992aSrie (pdip->di_flags & FLG_DI_POSFLAG1)) { 258875e7992aSrie if (pdip->di_info == (void *)ld_entry_cnt) 258975e7992aSrie continue; 259075e7992aSrie 259175e7992aSrie dip->di_flags &= ~FLG_DI_LAZYFAIL; 259275e7992aSrie pdip->di_info = NULL; 259375e7992aSrie } 259475e7992aSrie 25952017c965SRod Evans /* 25962017c965SRod Evans * Determine the last link-map presently on the callers 25972017c965SRod Evans * link-map control list. 25982017c965SRod Evans */ 25992017c965SRod Evans llmp = lmc->lc_tail; 26002017c965SRod Evans 260175e7992aSrie /* 260275e7992aSrie * Try loading this lazy dependency. If the object 260375e7992aSrie * can't be loaded, consider this non-fatal and continue 260475e7992aSrie * the search. Lazy loaded dependencies need not exist 260575e7992aSrie * and their loading should only turn out to be fatal 260675e7992aSrie * if they are required to satisfy a relocation. 26077c478bd9Sstevel@tonic-gate * 26082017c965SRod Evans * A successful lazy load can mean one of two things: 26092017c965SRod Evans * 26102017c965SRod Evans * - new objects have been loaded, in which case the 26112017c965SRod Evans * objects will have been analyzed, relocated, and 26122017c965SRod Evans * finally moved to the callers control list. 26132017c965SRod Evans * - the objects are already loaded, and this lazy 26142017c965SRod Evans * load has simply associated the referenced object 26152017c965SRod Evans * with it's lazy dependencies. 26162017c965SRod Evans * 26172017c965SRod Evans * If new objects are loaded, look in these objects 26182017c965SRod Evans * first. Note, a new object can be the object being 26192017c965SRod Evans * referenced by this lazy load, however we can also 26202017c965SRod Evans * descend into multiple lazy loads as we relocate this 26212017c965SRod Evans * reference. 26222017c965SRod Evans * 26232017c965SRod Evans * If the symbol hasn't been found, use the referenced 26242017c965SRod Evans * objects handle, as it might have dependencies on 2625e0e63816SRod Evans * objects that are already loaded. Note that existing 2626e0e63816SRod Evans * objects might have already been searched and skipped 2627e0e63816SRod Evans * as non-available to this caller. However, a lazy 2628e0e63816SRod Evans * load might have caused the promotion of modes, or 2629e0e63816SRod Evans * added this object to the family of the caller. In 2630e0e63816SRod Evans * either case, the handle associated with the object 2631e0e63816SRod Evans * is then used to carry out the symbol search. 26327c478bd9Sstevel@tonic-gate */ 26332017c965SRod Evans if ((nlmp = elf_lazy_load(lmp, &sl1, cnt, name, 26342017c965SRod Evans FLG_RT_PRIHDL, &ghp, in_nfavl)) == NULL) 26357c478bd9Sstevel@tonic-gate continue; 26367c478bd9Sstevel@tonic-gate 26372017c965SRod Evans if (NEXT_RT_MAP(llmp)) { 26382017c965SRod Evans /* 26392017c965SRod Evans * Look in any new objects. 26402017c965SRod Evans */ 26412017c965SRod Evans sl1.sl_imap = NEXT_RT_MAP(llmp); 26422017c965SRod Evans sl1.sl_flags &= ~LKUP_STDRELOC; 26432017c965SRod Evans 2644e0e63816SRod Evans if ((sym = lookup_sym(&sl1, _lmp, binfo, 2645e0e63816SRod Evans in_nfavl)) != NULL) 2646e0e63816SRod Evans return (sym); 26472017c965SRod Evans } 26482017c965SRod Evans 26497c478bd9Sstevel@tonic-gate /* 2650e0e63816SRod Evans * Use the objects handle to inspect the family of 2651e0e63816SRod Evans * objects associated with the handle. Note, there's 26522017c965SRod Evans * a possibility of overlap with the above search, 26532017c965SRod Evans * should a lazy load bring in new objects and 26542017c965SRod Evans * reference existing objects. 26557c478bd9Sstevel@tonic-gate */ 26562017c965SRod Evans sl2 = sl1; 26572017c965SRod Evans for (ALIST_TRAVERSE(ghp->gh_depends, idx2, gdp)) { 2658e0e63816SRod Evans if ((gdp->gd_depend != NEXT_RT_MAP(llmp)) && 26592017c965SRod Evans (gdp->gd_flags & GPD_DLSYM)) { 26602017c965SRod Evans 26612017c965SRod Evans sl2.sl_imap = gdp->gd_depend; 26622017c965SRod Evans sl2.sl_flags |= LKUP_FIRST; 26632017c965SRod Evans 2664e0e63816SRod Evans if ((sym = lookup_sym(&sl2, _lmp, binfo, 2665e0e63816SRod Evans in_nfavl)) != NULL) 2666e0e63816SRod Evans return (sym); 26672017c965SRod Evans } 26682017c965SRod Evans } 26692017c965SRod Evans 26707c478bd9Sstevel@tonic-gate /* 26717c478bd9Sstevel@tonic-gate * Some dlsym() operations are already traversing a 26727c478bd9Sstevel@tonic-gate * link-map (dlopen(0)), and thus there's no need to 26732017c965SRod Evans * save them on the dynamic dependency list. 26747c478bd9Sstevel@tonic-gate */ 26752017c965SRod Evans if (slp->sl_flags & LKUP_NODESCENT) 26762017c965SRod Evans continue; 26772017c965SRod Evans 26782017c965SRod Evans if (aplist_test(&alist, nlmp, AL_CNT_LAZYFIND) == NULL) 26792017c965SRod Evans return (NULL); 26807c478bd9Sstevel@tonic-gate } 26817c478bd9Sstevel@tonic-gate } 26827c478bd9Sstevel@tonic-gate 26832017c965SRod Evans return (NULL); 26847c478bd9Sstevel@tonic-gate } 26857c478bd9Sstevel@tonic-gate 26867c478bd9Sstevel@tonic-gate /* 26877c478bd9Sstevel@tonic-gate * Warning message for bad r_offset. 26887c478bd9Sstevel@tonic-gate */ 26897c478bd9Sstevel@tonic-gate void 26907c478bd9Sstevel@tonic-gate elf_reloc_bad(Rt_map *lmp, void *rel, uchar_t rtype, ulong_t roffset, 26917c478bd9Sstevel@tonic-gate ulong_t rsymndx) 26927c478bd9Sstevel@tonic-gate { 269337ffaf83SRod Evans const char *name = NULL; 26945aefb655Srie Lm_list *lml = LIST(lmp); 26957c478bd9Sstevel@tonic-gate int trace; 26967c478bd9Sstevel@tonic-gate 26975aefb655Srie if ((lml->lm_flags & LML_FLG_TRC_ENABLE) && 26987c478bd9Sstevel@tonic-gate (((rtld_flags & RT_FL_SILENCERR) == 0) || 26995aefb655Srie (lml->lm_flags & LML_FLG_TRC_VERBOSE))) 27007c478bd9Sstevel@tonic-gate trace = 1; 27017c478bd9Sstevel@tonic-gate else 27027c478bd9Sstevel@tonic-gate trace = 0; 27037c478bd9Sstevel@tonic-gate 27045aefb655Srie if ((trace == 0) && (DBG_ENABLED == 0)) 27057c478bd9Sstevel@tonic-gate return; 27067c478bd9Sstevel@tonic-gate 27077c478bd9Sstevel@tonic-gate if (rsymndx) { 27087c478bd9Sstevel@tonic-gate Sym *symref = (Sym *)((ulong_t)SYMTAB(lmp) + 2709a953e2b1Srie (rsymndx * SYMENT(lmp))); 27107c478bd9Sstevel@tonic-gate 27117c478bd9Sstevel@tonic-gate if (ELF_ST_BIND(symref->st_info) != STB_LOCAL) 27127c478bd9Sstevel@tonic-gate name = (char *)(STRTAB(lmp) + symref->st_name); 27137c478bd9Sstevel@tonic-gate } 27147c478bd9Sstevel@tonic-gate 2715481bba9eSRod Evans if (name == NULL) 271656deab07SRod Evans name = MSG_INTL(MSG_STR_UNKNOWN); 27177c478bd9Sstevel@tonic-gate 27187c478bd9Sstevel@tonic-gate if (trace) { 27197c478bd9Sstevel@tonic-gate const char *rstr; 27207c478bd9Sstevel@tonic-gate 27215aefb655Srie rstr = _conv_reloc_type((uint_t)rtype); 27227c478bd9Sstevel@tonic-gate (void) printf(MSG_INTL(MSG_LDD_REL_ERR1), rstr, name, 27237c478bd9Sstevel@tonic-gate EC_ADDR(roffset)); 27247c478bd9Sstevel@tonic-gate return; 27257c478bd9Sstevel@tonic-gate } 27267c478bd9Sstevel@tonic-gate 27275aefb655Srie Dbg_reloc_error(lml, ELF_DBG_RTLD, M_MACH, M_REL_SHT_TYPE, rel, name); 27287c478bd9Sstevel@tonic-gate } 2729d326b23bSrie 2730d326b23bSrie /* 2731d326b23bSrie * Resolve a static TLS relocation. 2732d326b23bSrie */ 2733d326b23bSrie long 2734d326b23bSrie elf_static_tls(Rt_map *lmp, Sym *sym, void *rel, uchar_t rtype, char *name, 2735d326b23bSrie ulong_t roffset, long value) 2736d326b23bSrie { 2737d326b23bSrie Lm_list *lml = LIST(lmp); 2738d326b23bSrie 2739d326b23bSrie /* 2740d326b23bSrie * Relocations against a static TLS block have limited support once 2741d326b23bSrie * process initialization has completed. Any error condition should be 2742d326b23bSrie * discovered by testing for DF_STATIC_TLS as part of loading an object, 2743d326b23bSrie * however individual relocations are tested in case the dynamic flag 2744d326b23bSrie * had not been set when this object was built. 2745d326b23bSrie */ 2746481bba9eSRod Evans if (PTTLS(lmp) == NULL) { 2747d326b23bSrie DBG_CALL(Dbg_reloc_in(lml, ELF_DBG_RTLD, M_MACH, 2748e23c41c9SAli Bahrami M_REL_SHT_TYPE, rel, NULL, 0, name)); 2749d326b23bSrie eprintf(lml, ERR_FATAL, MSG_INTL(MSG_REL_BADTLS), 2750d326b23bSrie _conv_reloc_type((uint_t)rtype), NAME(lmp), 2751d326b23bSrie name ? demangle(name) : MSG_INTL(MSG_STR_UNKNOWN)); 2752d326b23bSrie return (0); 2753d326b23bSrie } 2754d326b23bSrie 2755d326b23bSrie /* 2756d326b23bSrie * If no static TLS has been set aside for this object, determine if 2757d326b23bSrie * any can be obtained. Enforce that any object using static TLS is 2758d326b23bSrie * non-deletable. 2759d326b23bSrie */ 2760d326b23bSrie if (TLSSTATOFF(lmp) == 0) { 2761d326b23bSrie FLAGS1(lmp) |= FL1_RT_TLSSTAT; 2762d326b23bSrie MODE(lmp) |= RTLD_NODELETE; 2763d326b23bSrie 2764d326b23bSrie if (tls_assign(lml, lmp, PTTLS(lmp)) == 0) { 2765d326b23bSrie DBG_CALL(Dbg_reloc_in(lml, ELF_DBG_RTLD, M_MACH, 2766e23c41c9SAli Bahrami M_REL_SHT_TYPE, rel, NULL, 0, name)); 2767d326b23bSrie eprintf(lml, ERR_FATAL, MSG_INTL(MSG_REL_BADTLS), 2768d326b23bSrie _conv_reloc_type((uint_t)rtype), NAME(lmp), 2769d326b23bSrie name ? demangle(name) : MSG_INTL(MSG_STR_UNKNOWN)); 2770d326b23bSrie return (0); 2771d326b23bSrie } 2772d326b23bSrie } 2773d326b23bSrie 2774d326b23bSrie /* 2775d326b23bSrie * Typically, a static TLS offset is maintained as a symbols value. 2776d326b23bSrie * For local symbols that are not apart of the dynamic symbol table, 2777d326b23bSrie * the TLS relocation points to a section symbol, and the static TLS 2778d326b23bSrie * offset was deposited in the associated GOT table. Make sure the GOT 2779d326b23bSrie * is cleared, so that the value isn't reused in do_reloc(). 2780d326b23bSrie */ 2781d326b23bSrie if (ELF_ST_BIND(sym->st_info) == STB_LOCAL) { 2782d326b23bSrie if ((ELF_ST_TYPE(sym->st_info) == STT_SECTION)) { 2783d326b23bSrie value = *(long *)roffset; 2784d326b23bSrie *(long *)roffset = 0; 2785d326b23bSrie } else { 2786d326b23bSrie value = sym->st_value; 2787d326b23bSrie } 2788d326b23bSrie } 2789d326b23bSrie return (-(TLSSTATOFF(lmp) - value)); 2790d326b23bSrie } 2791dae2dfb7Srie 2792dae2dfb7Srie /* 2793dae2dfb7Srie * If the symbol is not found and the reference was not to a weak symbol, report 2794dae2dfb7Srie * an error. Weak references may be unresolved. 2795dae2dfb7Srie */ 2796dae2dfb7Srie int 2797dae2dfb7Srie elf_reloc_error(Rt_map *lmp, const char *name, void *rel, uint_t binfo) 2798dae2dfb7Srie { 2799dae2dfb7Srie Lm_list *lml = LIST(lmp); 2800dae2dfb7Srie 2801dae2dfb7Srie /* 2802dae2dfb7Srie * Under crle(1), relocation failures are ignored. 2803dae2dfb7Srie */ 2804dae2dfb7Srie if (lml->lm_flags & LML_FLG_IGNRELERR) 2805dae2dfb7Srie return (1); 2806dae2dfb7Srie 2807dae2dfb7Srie /* 2808dae2dfb7Srie * Under ldd(1), unresolved references are reported. However, if the 2809dae2dfb7Srie * original reference is EXTERN or PARENT these references are ignored 2810dae2dfb7Srie * unless ldd's -p option is in effect. 2811dae2dfb7Srie */ 2812dae2dfb7Srie if (lml->lm_flags & LML_FLG_TRC_WARN) { 2813dae2dfb7Srie if (((binfo & DBG_BINFO_REF_MSK) == 0) || 2814dae2dfb7Srie ((lml->lm_flags & LML_FLG_TRC_NOPAREXT) != 0)) { 2815dae2dfb7Srie (void) printf(MSG_INTL(MSG_LDD_SYM_NFOUND), 2816dae2dfb7Srie demangle(name), NAME(lmp)); 2817dae2dfb7Srie } 2818dae2dfb7Srie return (1); 2819dae2dfb7Srie } 2820dae2dfb7Srie 2821dae2dfb7Srie /* 2822dae2dfb7Srie * Otherwise, the unresolved references is fatal. 2823dae2dfb7Srie */ 2824dae2dfb7Srie DBG_CALL(Dbg_reloc_in(lml, ELF_DBG_RTLD, M_MACH, M_REL_SHT_TYPE, rel, 2825e23c41c9SAli Bahrami NULL, 0, name)); 2826dae2dfb7Srie eprintf(lml, ERR_FATAL, MSG_INTL(MSG_REL_NOSYM), NAME(lmp), 2827dae2dfb7Srie demangle(name)); 2828dae2dfb7Srie 2829dae2dfb7Srie return (0); 2830dae2dfb7Srie } 283156deab07SRod Evans 283256deab07SRod Evans /* 283356deab07SRod Evans * Generic relative relocation function. 283456deab07SRod Evans */ 283556deab07SRod Evans inline static ulong_t 283656deab07SRod Evans _elf_reloc_relative(ulong_t rbgn, ulong_t base, Rt_map *lmp, APlist **textrel) 283756deab07SRod Evans { 283856deab07SRod Evans mmapobj_result_t *mpp; 283956deab07SRod Evans ulong_t roffset; 284056deab07SRod Evans 284156deab07SRod Evans roffset = ((M_RELOC *)rbgn)->r_offset; 284256deab07SRod Evans roffset += base; 284356deab07SRod Evans 284456deab07SRod Evans /* 284556deab07SRod Evans * If this relocation is against an address that is not associated with 284656deab07SRod Evans * a mapped segment, fall back to the generic relocation loop to 284756deab07SRod Evans * collect the associated error. 284856deab07SRod Evans */ 284956deab07SRod Evans if ((mpp = find_segment((caddr_t)roffset, lmp)) == NULL) 285056deab07SRod Evans return (0); 285156deab07SRod Evans 285256deab07SRod Evans /* 285356deab07SRod Evans * If this relocation is against a segment that does not provide write 285456deab07SRod Evans * access, set the write permission for all non-writable mappings. 285556deab07SRod Evans */ 285656deab07SRod Evans if (((mpp->mr_prot & PROT_WRITE) == 0) && textrel && 285756deab07SRod Evans ((set_prot(lmp, mpp, 1) == 0) || 285856deab07SRod Evans (aplist_append(textrel, mpp, AL_CNT_TEXTREL) == NULL))) 285956deab07SRod Evans return (0); 286056deab07SRod Evans 286156deab07SRod Evans /* 286256deab07SRod Evans * Perform the actual relocation. Note, for backward compatibility, 286356deab07SRod Evans * SPARC relocations are added to the offset contents (there was a time 286456deab07SRod Evans * when the offset was used to contain the addend, rather than using 286556deab07SRod Evans * the addend itself). 286656deab07SRod Evans */ 286756deab07SRod Evans #if defined(__sparc) 286856deab07SRod Evans *((ulong_t *)roffset) += base + ((M_RELOC *)rbgn)->r_addend; 286956deab07SRod Evans #elif defined(__amd64) 287056deab07SRod Evans *((ulong_t *)roffset) = base + ((M_RELOC *)rbgn)->r_addend; 287156deab07SRod Evans #else 287256deab07SRod Evans *((ulong_t *)roffset) += base; 287356deab07SRod Evans #endif 287456deab07SRod Evans return (1); 287556deab07SRod Evans } 287656deab07SRod Evans 287756deab07SRod Evans /* 287856deab07SRod Evans * When a generic relocation loop realizes that it's dealing with relative 287956deab07SRod Evans * relocations, but no DT_RELCOUNT .dynamic tag is present, this tighter loop 288056deab07SRod Evans * is entered as an optimization. 288156deab07SRod Evans */ 288256deab07SRod Evans ulong_t 288356deab07SRod Evans elf_reloc_relative(ulong_t rbgn, ulong_t rend, ulong_t rsize, ulong_t base, 288456deab07SRod Evans Rt_map *lmp, APlist **textrel) 288556deab07SRod Evans { 288656deab07SRod Evans char rtype; 288756deab07SRod Evans 288856deab07SRod Evans do { 288956deab07SRod Evans if (_elf_reloc_relative(rbgn, base, lmp, textrel) == 0) 289056deab07SRod Evans break; 289156deab07SRod Evans 289256deab07SRod Evans rbgn += rsize; 289356deab07SRod Evans if (rbgn >= rend) 289456deab07SRod Evans break; 289556deab07SRod Evans 289656deab07SRod Evans /* 289756deab07SRod Evans * Make sure the next type is a relative relocation. 289856deab07SRod Evans */ 289956deab07SRod Evans rtype = ELF_R_TYPE(((M_RELOC *)rbgn)->r_info, M_MACH); 290056deab07SRod Evans 290156deab07SRod Evans } while (rtype == M_R_RELATIVE); 290256deab07SRod Evans 290356deab07SRod Evans return (rbgn); 290456deab07SRod Evans } 290556deab07SRod Evans 290656deab07SRod Evans /* 290756deab07SRod Evans * This is the tightest loop for RELATIVE relocations for those objects built 290856deab07SRod Evans * with the DT_RELACOUNT .dynamic entry. 290956deab07SRod Evans */ 291056deab07SRod Evans ulong_t 291156deab07SRod Evans elf_reloc_relative_count(ulong_t rbgn, ulong_t rcount, ulong_t rsize, 291256deab07SRod Evans ulong_t base, Rt_map *lmp, APlist **textrel) 291356deab07SRod Evans { 291456deab07SRod Evans for (; rcount; rcount--) { 291556deab07SRod Evans if (_elf_reloc_relative(rbgn, base, lmp, textrel) == 0) 291656deab07SRod Evans break; 291756deab07SRod Evans 291856deab07SRod Evans rbgn += rsize; 291956deab07SRod Evans } 292056deab07SRod Evans return (rbgn); 292156deab07SRod Evans } 2922