17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 55aefb655Srie * Common Development and Distribution License (the "License"). 65aefb655Srie * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 215aefb655Srie 227c478bd9Sstevel@tonic-gate /* 23*1007fd6fSAli Bahrami * Copyright (c) 1994, 2010, Oracle and/or its affiliates. All rights reserved. 247c478bd9Sstevel@tonic-gate */ 255aefb655Srie 267c478bd9Sstevel@tonic-gate #include <stdio.h> 277c478bd9Sstevel@tonic-gate #include <dlfcn.h> 287c478bd9Sstevel@tonic-gate #include <libelf.h> 297c478bd9Sstevel@tonic-gate #include <link.h> 305aefb655Srie #include <debug.h> 317c478bd9Sstevel@tonic-gate #include "msg.h" 327c478bd9Sstevel@tonic-gate #include "_libld.h" 337c478bd9Sstevel@tonic-gate 347c478bd9Sstevel@tonic-gate /* 357c478bd9Sstevel@tonic-gate * Table which defines the default functions to be called by the library 367c478bd9Sstevel@tonic-gate * SUPPORT (-S <libname>). These functions can be redefined by the 377c478bd9Sstevel@tonic-gate * ld_support_loadso() routine. 387c478bd9Sstevel@tonic-gate */ 397c478bd9Sstevel@tonic-gate static Support_list support[LDS_NUM] = { 4057ef7aa9SRod Evans {MSG_ORIG(MSG_SUP_VERSION), NULL}, /* LDS_VERSION */ 4157ef7aa9SRod Evans {MSG_ORIG(MSG_SUP_INPUT_DONE), NULL}, /* LDS_INPUT_DONE */ 425aefb655Srie #if defined(_ELF64) 4357ef7aa9SRod Evans {MSG_ORIG(MSG_SUP_START_64), NULL}, /* LDS_START */ 4457ef7aa9SRod Evans {MSG_ORIG(MSG_SUP_ATEXIT_64), NULL}, /* LDS_ATEXIT */ 4557ef7aa9SRod Evans {MSG_ORIG(MSG_SUP_OPEN_64), NULL}, /* LDS_OPEN */ 4657ef7aa9SRod Evans {MSG_ORIG(MSG_SUP_FILE_64), NULL}, /* LDS_FILE */ 4757ef7aa9SRod Evans {MSG_ORIG(MSG_SUP_INSEC_64), NULL}, /* LDS_INSEC */ 4857ef7aa9SRod Evans {MSG_ORIG(MSG_SUP_SEC_64), NULL} /* LDS_SEC */ 497c478bd9Sstevel@tonic-gate #else /* Elf32 */ 5057ef7aa9SRod Evans {MSG_ORIG(MSG_SUP_START), NULL}, /* LDS_START */ 5157ef7aa9SRod Evans {MSG_ORIG(MSG_SUP_ATEXIT), NULL}, /* LDS_ATEXIT */ 5257ef7aa9SRod Evans {MSG_ORIG(MSG_SUP_OPEN), NULL}, /* LDS_OPEN */ 5357ef7aa9SRod Evans {MSG_ORIG(MSG_SUP_FILE), NULL}, /* LDS_FILE */ 5457ef7aa9SRod Evans {MSG_ORIG(MSG_SUP_INSEC), NULL}, /* LDS_INSEC */ 5557ef7aa9SRod Evans {MSG_ORIG(MSG_SUP_SEC), NULL} /* LDS_SEC */ 567c478bd9Sstevel@tonic-gate #endif 577c478bd9Sstevel@tonic-gate }; 587c478bd9Sstevel@tonic-gate 597c478bd9Sstevel@tonic-gate /* 607c478bd9Sstevel@tonic-gate * Loads in a support shared object specified using the SGS_SUPPORT environment 617c478bd9Sstevel@tonic-gate * variable or the -S ld option, and determines which interface functions are 627c478bd9Sstevel@tonic-gate * provided by that object. 637c478bd9Sstevel@tonic-gate */ 647c478bd9Sstevel@tonic-gate uintptr_t 655aefb655Srie ld_sup_loadso(Ofl_desc *ofl, const char *obj) 667c478bd9Sstevel@tonic-gate { 672926dd2eSrie void *handle, (*fptr)(); 682926dd2eSrie uint_t interface, version = LD_SUP_VERSION1; 697c478bd9Sstevel@tonic-gate 707c478bd9Sstevel@tonic-gate /* 717c478bd9Sstevel@tonic-gate * Load the required support library. If we are unable to load it fail 727c478bd9Sstevel@tonic-gate * with a fatal error. 737c478bd9Sstevel@tonic-gate */ 742926dd2eSrie if ((handle = dlopen(obj, (RTLD_LAZY | RTLD_FIRST))) == NULL) { 75*1007fd6fSAli Bahrami ld_eprintf(ofl, ERR_FATAL, MSG_INTL(MSG_SUP_NOLOAD), 765aefb655Srie obj, dlerror()); 777c478bd9Sstevel@tonic-gate return (S_ERROR); 787c478bd9Sstevel@tonic-gate } 797c478bd9Sstevel@tonic-gate 802926dd2eSrie for (interface = 0; interface < LDS_NUM; interface++) { 8157ef7aa9SRod Evans Func_list fl; 8257ef7aa9SRod Evans 832926dd2eSrie if ((fptr = (void (*)())dlsym(handle, 842926dd2eSrie support[interface].sup_name)) == NULL) 852926dd2eSrie continue; 867c478bd9Sstevel@tonic-gate 875aefb655Srie DBG_CALL(Dbg_support_load(ofl->ofl_lml, obj, 882926dd2eSrie support[interface].sup_name)); 895aefb655Srie 902926dd2eSrie if (interface == LDS_VERSION) { 91d2d5cf7cSAli Bahrami DBG_CALL(Dbg_support_action(ofl->ofl_lml, obj, 922926dd2eSrie support[LDS_VERSION].sup_name, LDS_VERSION, 0)); 932926dd2eSrie 94d2d5cf7cSAli Bahrami version = ((uint_t(*)())fptr)(LD_SUP_VCURRENT); 95d2d5cf7cSAli Bahrami 96d2d5cf7cSAli Bahrami /* 97d2d5cf7cSAli Bahrami * If version is LD_SUP_VNONE, unload the support 98d2d5cf7cSAli Bahrami * library and act as if it was never requested. 99d2d5cf7cSAli Bahrami * This provides the support library with a mechanism 100d2d5cf7cSAli Bahrami * for opting out of the process. 101d2d5cf7cSAli Bahrami * 102d2d5cf7cSAli Bahrami * Note that this depends on LDS_VERSION being the 103d2d5cf7cSAli Bahrami * first item in support[]. If this were not true, 104d2d5cf7cSAli Bahrami * then other functions from the library might be 105d2d5cf7cSAli Bahrami * entered into the function lists, and unloading 106d2d5cf7cSAli Bahrami * the object would cause corruption. 107d2d5cf7cSAli Bahrami */ 108d2d5cf7cSAli Bahrami assert(LDS_VERSION == 0); 109d2d5cf7cSAli Bahrami if (version == LD_SUP_VNONE) { 110d2d5cf7cSAli Bahrami DBG_CALL(Dbg_support_vnone(ofl->ofl_lml, 111d2d5cf7cSAli Bahrami obj)); 112d2d5cf7cSAli Bahrami (void) dlclose(handle); 113d2d5cf7cSAli Bahrami return (1); 114d2d5cf7cSAli Bahrami } 115d2d5cf7cSAli Bahrami 116d2d5cf7cSAli Bahrami /* 117d2d5cf7cSAli Bahrami * If the support library has a version higher 118d2d5cf7cSAli Bahrami * than we support, we are unable to accept it. 119d2d5cf7cSAli Bahrami */ 120d2d5cf7cSAli Bahrami if (version > LD_SUP_VCURRENT) { 121*1007fd6fSAli Bahrami ld_eprintf(ofl, ERR_FATAL, 1225c02782fSAli Bahrami MSG_INTL(MSG_SUP_BADVERSION), obj, 1232926dd2eSrie LD_SUP_VCURRENT, version); 1247c478bd9Sstevel@tonic-gate (void) dlclose(handle); 1257c478bd9Sstevel@tonic-gate return (S_ERROR); 1267c478bd9Sstevel@tonic-gate } 1277c478bd9Sstevel@tonic-gate } 128d2d5cf7cSAli Bahrami 12957ef7aa9SRod Evans fl.fl_obj = obj; 13057ef7aa9SRod Evans fl.fl_fptr = fptr; 13157ef7aa9SRod Evans fl.fl_version = version; 13257ef7aa9SRod Evans if (alist_append(&support[interface].sup_funcs, &fl, 13357ef7aa9SRod Evans sizeof (Func_list), AL_CNT_SUPPORT) == NULL) 1347c478bd9Sstevel@tonic-gate return (S_ERROR); 1357c478bd9Sstevel@tonic-gate } 1367c478bd9Sstevel@tonic-gate return (1); 1377c478bd9Sstevel@tonic-gate } 1387c478bd9Sstevel@tonic-gate 1397c478bd9Sstevel@tonic-gate /* 1407c478bd9Sstevel@tonic-gate * Wrapper routines for the ld support library calls. 1417c478bd9Sstevel@tonic-gate */ 1427c478bd9Sstevel@tonic-gate void 1435aefb655Srie ld_sup_start(Ofl_desc *ofl, const Half etype, const char *caller) 1447c478bd9Sstevel@tonic-gate { 1457c478bd9Sstevel@tonic-gate Func_list *flp; 14657ef7aa9SRod Evans Aliste idx; 1477c478bd9Sstevel@tonic-gate 14857ef7aa9SRod Evans for (ALIST_TRAVERSE(support[LDS_START].sup_funcs, idx, flp)) { 1495aefb655Srie DBG_CALL(Dbg_support_action(ofl->ofl_lml, flp->fl_obj, 1505aefb655Srie support[LDS_START].sup_name, LDS_START, ofl->ofl_name)); 1515aefb655Srie (*flp->fl_fptr)(ofl->ofl_name, etype, caller); 1527c478bd9Sstevel@tonic-gate } 1537c478bd9Sstevel@tonic-gate } 1547c478bd9Sstevel@tonic-gate 1557c478bd9Sstevel@tonic-gate void 1565aefb655Srie ld_sup_atexit(Ofl_desc *ofl, int ecode) 1577c478bd9Sstevel@tonic-gate { 1587c478bd9Sstevel@tonic-gate Func_list *flp; 15957ef7aa9SRod Evans Aliste idx; 1607c478bd9Sstevel@tonic-gate 16157ef7aa9SRod Evans for (ALIST_TRAVERSE(support[LDS_ATEXIT].sup_funcs, idx, flp)) { 1625aefb655Srie DBG_CALL(Dbg_support_action(ofl->ofl_lml, flp->fl_obj, 1637c478bd9Sstevel@tonic-gate support[LDS_ATEXIT].sup_name, LDS_ATEXIT, 0)); 1645aefb655Srie (*flp->fl_fptr)(ecode); 1657c478bd9Sstevel@tonic-gate } 1667c478bd9Sstevel@tonic-gate } 1677c478bd9Sstevel@tonic-gate 1687c478bd9Sstevel@tonic-gate void 1693906e0c2Srie ld_sup_open(Ofl_desc *ofl, const char **opath, const char **ofile, int *ofd, 1703906e0c2Srie int flags, Elf **oelf, Elf *ref, size_t off, const Elf_Kind ekind) 1713906e0c2Srie { 1723906e0c2Srie Func_list *flp; 17357ef7aa9SRod Evans Aliste idx; 17457ef7aa9SRod Evans 17557ef7aa9SRod Evans for (ALIST_TRAVERSE(support[LDS_OPEN].sup_funcs, idx, flp)) { 1763906e0c2Srie const char *npath = *opath; 1773906e0c2Srie const char *nfile = *ofile; 1783906e0c2Srie Elf *nelf = *oelf; 1793906e0c2Srie int nfd = *ofd; 1803906e0c2Srie int _flags = 0; 1813906e0c2Srie 1823906e0c2Srie /* 1833906e0c2Srie * This interface was introduced in VERSION3. Only call this 1843906e0c2Srie * function for libraries reporting support for version 3 or 1853906e0c2Srie * above. 1863906e0c2Srie */ 1873906e0c2Srie if (flp->fl_version < LD_SUP_VERSION3) 1883906e0c2Srie continue; 1893906e0c2Srie 1903906e0c2Srie if (!(flags & FLG_IF_CMDLINE)) 1913906e0c2Srie _flags |= LD_SUP_DERIVED; 1923906e0c2Srie if (!(flags & FLG_IF_NEEDED)) 1933906e0c2Srie _flags |= LD_SUP_INHERITED; 1943906e0c2Srie if (flags & FLG_IF_EXTRACT) 1953906e0c2Srie _flags |= LD_SUP_EXTRACTED; 1963906e0c2Srie 1973906e0c2Srie /* 1983906e0c2Srie * If the present object is an extracted archive member, make 1993906e0c2Srie * sure the archive offset is reset so that the caller can 2003906e0c2Srie * obtain an ELF descriptor to the same member (an elf_begin() 2013906e0c2Srie * moves the offset to the next member). 2023906e0c2Srie */ 2033906e0c2Srie if (flags & FLG_IF_EXTRACT) 2043906e0c2Srie (void) elf_rand(ref, off); 2053906e0c2Srie 2063906e0c2Srie DBG_CALL(Dbg_support_action(ofl->ofl_lml, flp->fl_obj, 2073906e0c2Srie support[LDS_OPEN].sup_name, LDS_OPEN, *opath)); 2083906e0c2Srie (*flp->fl_fptr)(&npath, &nfile, &nfd, _flags, &nelf, ref, off, 2093906e0c2Srie ekind); 2103906e0c2Srie 2113906e0c2Srie /* 21257ef7aa9SRod Evans * If the file descriptor, ELF descriptor, or file names have 21357ef7aa9SRod Evans * been modified, then diagnose the differences and return the 21457ef7aa9SRod Evans * new data. As a basic test, make sure the support library 21557ef7aa9SRod Evans * hasn't nulled out data ld(1) will try and dereference. 2163906e0c2Srie */ 2173906e0c2Srie if ((npath != *opath) || (nfd != *ofd) || (nelf != *oelf)) { 21808278a5eSRod Evans DBG_CALL(Dbg_file_modified(ofl->ofl_lml, flp->fl_obj, 21908278a5eSRod Evans *opath, npath, *ofd, nfd, *oelf, nelf)); 2203906e0c2Srie if (npath) 2213906e0c2Srie *opath = npath; 2223906e0c2Srie if (nfile) 2233906e0c2Srie *ofile = nfile; 2243906e0c2Srie *ofd = nfd; 2253906e0c2Srie *oelf = nelf; 2263906e0c2Srie } 2273906e0c2Srie } 22857ef7aa9SRod Evans } 2293906e0c2Srie 2303906e0c2Srie void 2315aefb655Srie ld_sup_file(Ofl_desc *ofl, const char *ifile, const Elf_Kind ekind, int flags, 2325aefb655Srie Elf *elf) 2337c478bd9Sstevel@tonic-gate { 2347c478bd9Sstevel@tonic-gate Func_list *flp; 23557ef7aa9SRod Evans Aliste idx; 2367c478bd9Sstevel@tonic-gate 23757ef7aa9SRod Evans for (ALIST_TRAVERSE(support[LDS_FILE].sup_funcs, idx, flp)) { 2387c478bd9Sstevel@tonic-gate int _flags = 0; 2397c478bd9Sstevel@tonic-gate 2407c478bd9Sstevel@tonic-gate if (!(flags & FLG_IF_CMDLINE)) 2417c478bd9Sstevel@tonic-gate _flags |= LD_SUP_DERIVED; 2427c478bd9Sstevel@tonic-gate if (!(flags & FLG_IF_NEEDED)) 2437c478bd9Sstevel@tonic-gate _flags |= LD_SUP_INHERITED; 2447c478bd9Sstevel@tonic-gate if (flags & FLG_IF_EXTRACT) 2457c478bd9Sstevel@tonic-gate _flags |= LD_SUP_EXTRACTED; 2467c478bd9Sstevel@tonic-gate 2475aefb655Srie DBG_CALL(Dbg_support_action(ofl->ofl_lml, flp->fl_obj, 2487c478bd9Sstevel@tonic-gate support[LDS_FILE].sup_name, LDS_FILE, ifile)); 2497c478bd9Sstevel@tonic-gate (*flp->fl_fptr)(ifile, ekind, _flags, elf); 2507c478bd9Sstevel@tonic-gate } 2517c478bd9Sstevel@tonic-gate } 2527c478bd9Sstevel@tonic-gate 2537c478bd9Sstevel@tonic-gate uintptr_t 2547010c12aSrie ld_sup_input_section(Ofl_desc *ofl, Ifl_desc *ifl, const char *sname, 2557010c12aSrie Shdr **oshdr, Word ndx, Elf_Scn *scn, Elf *elf) 2567c478bd9Sstevel@tonic-gate { 2577c478bd9Sstevel@tonic-gate Func_list *flp; 25857ef7aa9SRod Evans Aliste idx; 2597c478bd9Sstevel@tonic-gate uint_t flags = 0; 2607c478bd9Sstevel@tonic-gate Elf_Data *data = NULL; 26157ef7aa9SRod Evans 26257ef7aa9SRod Evans for (ALIST_TRAVERSE(support[LDS_INSEC].sup_funcs, idx, flp)) { 2637010c12aSrie Shdr *nshdr = *oshdr; 2647c478bd9Sstevel@tonic-gate 2657c478bd9Sstevel@tonic-gate /* 2662926dd2eSrie * This interface was introduced in VERSION2. Only call this 2672926dd2eSrie * function for libraries reporting support for version 2 or 2682926dd2eSrie * above. 2697c478bd9Sstevel@tonic-gate */ 2707c478bd9Sstevel@tonic-gate if (flp->fl_version < LD_SUP_VERSION2) 2717c478bd9Sstevel@tonic-gate continue; 2722926dd2eSrie 2737c478bd9Sstevel@tonic-gate if ((data == NULL) && 2747c478bd9Sstevel@tonic-gate ((data = elf_getdata(scn, NULL)) == NULL)) { 275*1007fd6fSAli Bahrami ld_eprintf(ofl, ERR_ELF, MSG_INTL(MSG_ELF_GETDATA), 276*1007fd6fSAli Bahrami ifl->ifl_name); 2777c478bd9Sstevel@tonic-gate return (S_ERROR); 2787c478bd9Sstevel@tonic-gate } 2797c478bd9Sstevel@tonic-gate 2805aefb655Srie DBG_CALL(Dbg_support_action(ofl->ofl_lml, flp->fl_obj, 2812926dd2eSrie support[LDS_INSEC].sup_name, LDS_INSEC, sname)); 2827010c12aSrie (*flp->fl_fptr)(sname, &nshdr, ndx, data, elf, &flags); 2837010c12aSrie 2847010c12aSrie /* 28557ef7aa9SRod Evans * If the section header has been re-allocated (known to occur 28657ef7aa9SRod Evans * with libCCexcept.so), then diagnose the section header 28757ef7aa9SRod Evans * difference and return the new section header. 2887010c12aSrie */ 2897010c12aSrie if (nshdr != *oshdr) { 29008278a5eSRod Evans Ehdr *ehdr = ifl->ifl_ehdr; 29108278a5eSRod Evans 29208278a5eSRod Evans DBG_CALL(Dbg_shdr_modified(ofl->ofl_lml, flp->fl_obj, 29308278a5eSRod Evans ehdr->e_ident[EI_OSABI], ehdr->e_machine, ndx, 29408278a5eSRod Evans *oshdr, nshdr, sname)); 2957010c12aSrie *oshdr = nshdr; 2967c478bd9Sstevel@tonic-gate } 29757ef7aa9SRod Evans } 2987c478bd9Sstevel@tonic-gate return (0); 2997c478bd9Sstevel@tonic-gate } 3007c478bd9Sstevel@tonic-gate 3017c478bd9Sstevel@tonic-gate void 3025aefb655Srie ld_sup_section(Ofl_desc *ofl, const char *scn, Shdr *shdr, Word ndx, 3037c478bd9Sstevel@tonic-gate Elf_Data *data, Elf *elf) 3047c478bd9Sstevel@tonic-gate { 3057c478bd9Sstevel@tonic-gate Func_list *flp; 30657ef7aa9SRod Evans Aliste idx; 3077c478bd9Sstevel@tonic-gate 30857ef7aa9SRod Evans for (ALIST_TRAVERSE(support[LDS_SEC].sup_funcs, idx, flp)) { 3095aefb655Srie DBG_CALL(Dbg_support_action(ofl->ofl_lml, flp->fl_obj, 3102926dd2eSrie support[LDS_SEC].sup_name, LDS_SEC, scn)); 3117c478bd9Sstevel@tonic-gate (*flp->fl_fptr)(scn, shdr, ndx, data, elf); 3127c478bd9Sstevel@tonic-gate } 3137c478bd9Sstevel@tonic-gate } 3147c478bd9Sstevel@tonic-gate 3157c478bd9Sstevel@tonic-gate void 3165aefb655Srie ld_sup_input_done(Ofl_desc *ofl) 3177c478bd9Sstevel@tonic-gate { 3187c478bd9Sstevel@tonic-gate Func_list *flp; 31957ef7aa9SRod Evans Aliste idx; 3207c478bd9Sstevel@tonic-gate uint_t flags = 0; 3217c478bd9Sstevel@tonic-gate 32257ef7aa9SRod Evans for (ALIST_TRAVERSE(support[LDS_INPUT_DONE].sup_funcs, idx, flp)) { 3237c478bd9Sstevel@tonic-gate /* 3242926dd2eSrie * This interface was introduced in VERSION2. Only call this 3252926dd2eSrie * function for libraries reporting support for version 2 or 3262926dd2eSrie * above. 3277c478bd9Sstevel@tonic-gate */ 3287c478bd9Sstevel@tonic-gate if (flp->fl_version < LD_SUP_VERSION2) 3297c478bd9Sstevel@tonic-gate continue; 3302926dd2eSrie 3315aefb655Srie DBG_CALL(Dbg_support_action(ofl->ofl_lml, flp->fl_obj, 3327c478bd9Sstevel@tonic-gate support[LDS_INPUT_DONE].sup_name, LDS_INPUT_DONE, 0)); 3337c478bd9Sstevel@tonic-gate (*flp->fl_fptr)(&flags); 3347c478bd9Sstevel@tonic-gate } 3357c478bd9Sstevel@tonic-gate } 336