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 /* 231c1abfbcSRod Evans * Copyright (c) 1992, 2010, Oracle and/or its affiliates. All rights reserved. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267257d1b4Sraf /* 277257d1b4Sraf * Copyright (c) 1988 AT&T 287257d1b4Sraf * All Rights Reserved 297257d1b4Sraf */ 30*ebb8ac07SRobert Mustacchi /* 31*ebb8ac07SRobert Mustacchi * Copyright (c) 2012, Joyent, Inc. All rights reserved. 32*ebb8ac07SRobert Mustacchi */ 337257d1b4Sraf 347c478bd9Sstevel@tonic-gate /* 357c478bd9Sstevel@tonic-gate * Run time linker common setup. 367c478bd9Sstevel@tonic-gate * 377c478bd9Sstevel@tonic-gate * Called from _setup to get the process going at startup. 387c478bd9Sstevel@tonic-gate */ 397c478bd9Sstevel@tonic-gate 407c478bd9Sstevel@tonic-gate #include <stdlib.h> 417c478bd9Sstevel@tonic-gate #include <fcntl.h> 427c478bd9Sstevel@tonic-gate #include <stdio.h> 437c478bd9Sstevel@tonic-gate #include <sys/types.h> 447c478bd9Sstevel@tonic-gate #include <sys/stat.h> 457c478bd9Sstevel@tonic-gate #include <sys/mman.h> 467c478bd9Sstevel@tonic-gate #include <string.h> 477c478bd9Sstevel@tonic-gate #include <unistd.h> 487c478bd9Sstevel@tonic-gate #include <dlfcn.h> 497c478bd9Sstevel@tonic-gate #include <sys/sysconfig.h> 507c478bd9Sstevel@tonic-gate #include <sys/auxv.h> 515aefb655Srie #include <debug.h> 525aefb655Srie #include <conv.h> 537c478bd9Sstevel@tonic-gate #include "_rtld.h" 547c478bd9Sstevel@tonic-gate #include "_audit.h" 557c478bd9Sstevel@tonic-gate #include "_elf.h" 567c478bd9Sstevel@tonic-gate #include "_a.out.h" 577c478bd9Sstevel@tonic-gate #include "msg.h" 587c478bd9Sstevel@tonic-gate 597c478bd9Sstevel@tonic-gate 607c478bd9Sstevel@tonic-gate extern int _end, _edata, _etext; 617c478bd9Sstevel@tonic-gate extern void _init(void); 627c478bd9Sstevel@tonic-gate extern int _brk_unlocked(void *); 637c478bd9Sstevel@tonic-gate 647c478bd9Sstevel@tonic-gate #ifndef SGS_PRE_UNIFIED_PROCESS 657c478bd9Sstevel@tonic-gate /* needed for _brk_unlocked() */ 667c478bd9Sstevel@tonic-gate void *_nd = &_end; 677c478bd9Sstevel@tonic-gate #endif 687c478bd9Sstevel@tonic-gate 697c478bd9Sstevel@tonic-gate /* 7020272c2eSAli Bahrami * Counters that are incremented every time an object is mapped/unmapped. 7120272c2eSAli Bahrami * 7220272c2eSAli Bahrami * Note that exec() will usually map 2 objects before we receive control, 7320272c2eSAli Bahrami * but this can be 1 if ld.so.1 is executed directly. We count one of these 7420272c2eSAli Bahrami * here, and add another as necessary in setup(). 7520272c2eSAli Bahrami */ 7620272c2eSAli Bahrami u_longlong_t cnt_map = 1; 7720272c2eSAli Bahrami u_longlong_t cnt_unmap = 0; 7820272c2eSAli Bahrami 7920272c2eSAli Bahrami 8020272c2eSAli Bahrami /* 817c478bd9Sstevel@tonic-gate * Define for the executable's interpreter. 827c478bd9Sstevel@tonic-gate * Usually it is ld.so.1, but for the first release of ICL binaries 837c478bd9Sstevel@tonic-gate * it is libc.so.1. We keep this information so that we don't end 847c478bd9Sstevel@tonic-gate * up mapping libc twice if it is the interpreter. 857c478bd9Sstevel@tonic-gate */ 867c478bd9Sstevel@tonic-gate static Interp _interp; 877c478bd9Sstevel@tonic-gate 88dde769a2SRod Evans /* 89dde769a2SRod Evans * LD_PRELOAD objects. 90dde769a2SRod Evans */ 917c478bd9Sstevel@tonic-gate static int 92dde769a2SRod Evans preload(const char *str, Rt_map *mlmp, Rt_map **clmp) 937c478bd9Sstevel@tonic-gate { 9456deab07SRod Evans Alist *palp = NULL; 957c478bd9Sstevel@tonic-gate char *objs, *ptr, *next; 967c478bd9Sstevel@tonic-gate Word lmflags = lml_main.lm_flags; 97dde769a2SRod Evans int lddstub; 987c478bd9Sstevel@tonic-gate 995aefb655Srie DBG_CALL(Dbg_util_nl(&lml_main, DBG_NL_STD)); 1007c478bd9Sstevel@tonic-gate 10156deab07SRod Evans if ((objs = strdup(str)) == NULL) 1027c478bd9Sstevel@tonic-gate return (0); 1037c478bd9Sstevel@tonic-gate 1047c478bd9Sstevel@tonic-gate /* 105dde769a2SRod Evans * Determine if we've been called from lddstub. 1067c478bd9Sstevel@tonic-gate */ 107dde769a2SRod Evans lddstub = (lmflags & LML_FLG_TRC_ENABLE) && 108dde769a2SRod Evans (FLAGS1(*clmp) & FL1_RT_LDDSTUB); 1097c478bd9Sstevel@tonic-gate 110cc4ec439SRichard Lowe 111cc4ec439SRichard Lowe for (ptr = strtok_r(objs, MSG_ORIG(MSG_STR_DELIMIT), &next); 112cc4ec439SRichard Lowe ptr != NULL; 113cc4ec439SRichard Lowe ptr = strtok_r(NULL, MSG_ORIG(MSG_STR_DELIMIT), &next)) { 11456deab07SRod Evans Rt_map *nlmp = NULL; 115dde769a2SRod Evans uint_t flags; 1167c478bd9Sstevel@tonic-gate 1175aefb655Srie DBG_CALL(Dbg_file_preload(&lml_main, ptr)); 1187c478bd9Sstevel@tonic-gate 1197c478bd9Sstevel@tonic-gate /* 120dde769a2SRod Evans * Establish the flags for loading each object. If we're 121dde769a2SRod Evans * called via lddstub, then the first preloaded object is the 122dde769a2SRod Evans * object being inspected by ldd(1). This object should not be 123dde769a2SRod Evans * marked as an interposer, as this object is intended to act 124dde769a2SRod Evans * as the target object of the process. 125dde769a2SRod Evans */ 126dde769a2SRod Evans if (lddstub) 127dde769a2SRod Evans flags = FLG_RT_PRELOAD; 128dde769a2SRod Evans else 129dde769a2SRod Evans flags = (FLG_RT_PRELOAD | FLG_RT_OBJINTPO); 130dde769a2SRod Evans 131dde769a2SRod Evans /* 1327c478bd9Sstevel@tonic-gate * If this a secure application, then preload errors are 1337c478bd9Sstevel@tonic-gate * reduced to warnings, as the errors are non-fatal. 1347c478bd9Sstevel@tonic-gate */ 1357c478bd9Sstevel@tonic-gate if (rtld_flags & RT_FL_SECURE) 1367c478bd9Sstevel@tonic-gate rtld_flags2 |= RT_FL2_FTL2WARN; 137dde769a2SRod Evans if (expand_paths(*clmp, ptr, &palp, AL_CNT_NEEDED, 13856deab07SRod Evans PD_FLG_EXTLOAD, 0) != 0) 139dde769a2SRod Evans nlmp = load_one(&lml_main, ALIST_OFF_DATA, palp, *clmp, 140dde769a2SRod Evans MODE(mlmp), flags, 0, NULL); 1412020b2b6SRod Evans remove_alist(&palp, 0); 1427c478bd9Sstevel@tonic-gate if (rtld_flags & RT_FL_SECURE) 1437c478bd9Sstevel@tonic-gate rtld_flags2 &= ~RT_FL2_FTL2WARN; 144dde769a2SRod Evans if (nlmp && (bind_one(*clmp, nlmp, BND_NEEDED) == 0)) 14556deab07SRod Evans nlmp = NULL; 1467c478bd9Sstevel@tonic-gate 147dde769a2SRod Evans if (lddstub && nlmp) { 148dde769a2SRod Evans lddstub = 0; 149dde769a2SRod Evans 1507c478bd9Sstevel@tonic-gate /* 151dde769a2SRod Evans * Fabricate a binding between the target shared object 152dde769a2SRod Evans * and lddstub so that the target object isn't called 153dde769a2SRod Evans * out from unused() processing. 1547c478bd9Sstevel@tonic-gate */ 155dde769a2SRod Evans if (lmflags & 156dde769a2SRod Evans (LML_FLG_TRC_UNREF | LML_FLG_TRC_UNUSED)) { 157dde769a2SRod Evans if (bind_one(*clmp, nlmp, BND_REFER) == 0) 158dde769a2SRod Evans nlmp = NULL; 159dde769a2SRod Evans } 160dde769a2SRod Evans 161dde769a2SRod Evans /* 162dde769a2SRod Evans * By identifying lddstub as the caller, several 163dde769a2SRod Evans * confusing ldd() diagnostics get suppressed. These 164dde769a2SRod Evans * diagnostics would reveal how the target shared object 165dde769a2SRod Evans * was found from lddstub. Now that the real target is 166dde769a2SRod Evans * loaded, identify the target as the caller so that all 167dde769a2SRod Evans * ldd() diagnostics are enabled for subsequent objects. 168dde769a2SRod Evans */ 169dde769a2SRod Evans if (nlmp) 170dde769a2SRod Evans *clmp = nlmp; 171dde769a2SRod Evans } 172dde769a2SRod Evans 173dde769a2SRod Evans /* 174dde769a2SRod Evans * If no error occurred with loading this object, indicate that 175dde769a2SRod Evans * this link-map list contains an interposer. 176dde769a2SRod Evans */ 17756deab07SRod Evans if (nlmp == NULL) { 1787c478bd9Sstevel@tonic-gate if ((lmflags & LML_FLG_TRC_ENABLE) || 1797c478bd9Sstevel@tonic-gate (rtld_flags & RT_FL_SECURE)) 1807c478bd9Sstevel@tonic-gate continue; 1817c478bd9Sstevel@tonic-gate else 1827c478bd9Sstevel@tonic-gate return (0); 1837c478bd9Sstevel@tonic-gate } 184dde769a2SRod Evans if (flags & FLG_RT_OBJINTPO) 1857c478bd9Sstevel@tonic-gate lml_main.lm_flags |= LML_FLG_INTRPOSE; 1867c478bd9Sstevel@tonic-gate 187cc4ec439SRichard Lowe } 1887c478bd9Sstevel@tonic-gate 18956deab07SRod Evans free(palp); 1907c478bd9Sstevel@tonic-gate free(objs); 1917c478bd9Sstevel@tonic-gate return (1); 1927c478bd9Sstevel@tonic-gate } 1937c478bd9Sstevel@tonic-gate 1947c478bd9Sstevel@tonic-gate Rt_map * 19541072f3cSrie setup(char **envp, auxv_t *auxv, Word _flags, char *_platform, int _syspagsz, 19656deab07SRod Evans char *_rtldname, ulong_t ld_base, ulong_t interp_base, int fd, Phdr *phdr, 19756deab07SRod Evans char *execname, char **argv, uid_t uid, uid_t euid, gid_t gid, gid_t egid, 198*ebb8ac07SRobert Mustacchi void *aoutdyn, int auxflags, uint_t *hwcap) 1997c478bd9Sstevel@tonic-gate { 200dde769a2SRod Evans Rt_map *rlmp, *mlmp, *clmp, **tobj = NULL; 2017c478bd9Sstevel@tonic-gate Ehdr *ehdr; 202cb511613SAli Bahrami rtld_stat_t status; 20341072f3cSrie int features = 0, ldsoexec = 0; 2047c478bd9Sstevel@tonic-gate size_t eaddr, esize; 20541072f3cSrie char *str, *argvname; 20610a4fa49Srie Word lmflags; 20756deab07SRod Evans mmapobj_result_t *mpp; 20856deab07SRod Evans Fdesc fdr = { 0 }, fdm = { 0 }; 20956deab07SRod Evans Rej_desc rej = { 0 }; 2101c1abfbcSRod Evans APlist *ealp = NULL; 2117c478bd9Sstevel@tonic-gate 2127c478bd9Sstevel@tonic-gate /* 21341072f3cSrie * Now that ld.so has relocated itself, initialize our own 'environ' so 2142017c965SRod Evans * as to establish an address suitable for any libc requirements. 2157c478bd9Sstevel@tonic-gate */ 21641072f3cSrie _environ = (char **)((ulong_t)auxv - sizeof (char *)); 2177c478bd9Sstevel@tonic-gate _init(); 21841072f3cSrie _environ = envp; 2197c478bd9Sstevel@tonic-gate 22041072f3cSrie /* 2212017c965SRod Evans * Establish a base time. Total time diagnostics start from entering 2222017c965SRod Evans * ld.so.1 here, however the base time is reset each time the ld.so.1 2232017c965SRod Evans * is re-entered. Note also, there will be a large time associated 2242017c965SRod Evans * with the first diagnostic from ld.so.1, as bootstrapping ld.so.1 2252017c965SRod Evans * and establishing the liblddbg infrastructure takes some time. 2262017c965SRod Evans */ 2272017c965SRod Evans (void) gettimeofday(&DBG_TOTALTIME, NULL); 2282017c965SRod Evans DBG_DELTATIME = DBG_TOTALTIME; 2292017c965SRod Evans 2302017c965SRod Evans /* 23141072f3cSrie * Determine how ld.so.1 has been executed. 23241072f3cSrie */ 23356deab07SRod Evans if ((fd == -1) && (phdr == NULL)) { 23441072f3cSrie /* 23541072f3cSrie * If we received neither the AT_EXECFD nor the AT_PHDR aux 23641072f3cSrie * vector, ld.so.1 must have been invoked directly from the 23741072f3cSrie * command line. 23841072f3cSrie */ 23941072f3cSrie ldsoexec = 1; 24041072f3cSrie 24141072f3cSrie /* 24241072f3cSrie * AT_SUN_EXECNAME provides the most precise name, if it is 24341072f3cSrie * available, otherwise fall back to argv[0]. At this time, 24441072f3cSrie * there is no process name. 24541072f3cSrie */ 24641072f3cSrie if (execname) 24741072f3cSrie rtldname = execname; 24841072f3cSrie else if (argv[0]) 24941072f3cSrie rtldname = argv[0]; 25041072f3cSrie else 25141072f3cSrie rtldname = (char *)MSG_INTL(MSG_STR_UNKNOWN); 25241072f3cSrie } else { 25341072f3cSrie /* 25441072f3cSrie * Otherwise, we have a standard process. AT_SUN_EXECNAME 25541072f3cSrie * provides the most precise name, if it is available, 25641072f3cSrie * otherwise fall back to argv[0]. Provided the application 25741072f3cSrie * is already mapped, the process is the application, so 25841072f3cSrie * simplify the application name for use in any diagnostics. 25941072f3cSrie */ 26041072f3cSrie if (execname) 26141072f3cSrie argvname = execname; 26241072f3cSrie else if (argv[0]) 26341072f3cSrie argvname = execname = argv[0]; 26441072f3cSrie else 26541072f3cSrie argvname = execname = (char *)MSG_INTL(MSG_STR_UNKNOWN); 26641072f3cSrie 26741072f3cSrie if (fd == -1) { 26856deab07SRod Evans if ((str = strrchr(argvname, '/')) != NULL) 26941072f3cSrie procname = ++str; 27041072f3cSrie else 27141072f3cSrie procname = argvname; 27241072f3cSrie } 27341072f3cSrie 27441072f3cSrie /* 27541072f3cSrie * At this point, we don't know the runtime linkers full path 27641072f3cSrie * name. The _rtldname passed to us is the SONAME of the 27741072f3cSrie * runtime linker, which is typically /lib/ld.so.1 no matter 27841072f3cSrie * what the full path is. Use this for now, we'll reset the 27941072f3cSrie * runtime linkers name once the application is analyzed. 28041072f3cSrie */ 28141072f3cSrie if (_rtldname) { 28256deab07SRod Evans if ((str = strrchr(_rtldname, '/')) != NULL) 28341072f3cSrie rtldname = ++str; 28441072f3cSrie else 28541072f3cSrie rtldname = _rtldname; 28641072f3cSrie } else 28741072f3cSrie rtldname = (char *)MSG_INTL(MSG_STR_UNKNOWN); 28820272c2eSAli Bahrami 28920272c2eSAli Bahrami /* exec() brought in two objects for us. Count the second one */ 29020272c2eSAli Bahrami cnt_map++; 29141072f3cSrie } 29241072f3cSrie 29341072f3cSrie /* 29441072f3cSrie * Initialize any global variables. 29541072f3cSrie */ 2967c478bd9Sstevel@tonic-gate at_flags = _flags; 29708278a5eSRod Evans 29808278a5eSRod Evans if ((org_scapset->sc_plat = _platform) != NULL) 29908278a5eSRod Evans org_scapset->sc_platsz = strlen(_platform); 30008278a5eSRod Evans 30108278a5eSRod Evans if (org_scapset->sc_plat == NULL) 30208278a5eSRod Evans platform_name(org_scapset); 30308278a5eSRod Evans if (org_scapset->sc_mach == NULL) 30408278a5eSRod Evans machine_name(org_scapset); 3057c478bd9Sstevel@tonic-gate 3067c478bd9Sstevel@tonic-gate /* 3077c478bd9Sstevel@tonic-gate * If pagesize is unspecified find its value. 3087c478bd9Sstevel@tonic-gate */ 3097c478bd9Sstevel@tonic-gate if ((syspagsz = _syspagsz) == 0) 3107c478bd9Sstevel@tonic-gate syspagsz = _sysconfig(_CONFIG_PAGESIZE); 3117c478bd9Sstevel@tonic-gate 3127c478bd9Sstevel@tonic-gate /* 3137c478bd9Sstevel@tonic-gate * Add the unused portion of the last data page to the free space list. 3147c478bd9Sstevel@tonic-gate * The page size must be set before doing this. Here, _end refers to 3157c478bd9Sstevel@tonic-gate * the end of the runtime linkers bss. Note that we do not use the 3167c478bd9Sstevel@tonic-gate * unused data pages from any included .so's to supplement this free 3177c478bd9Sstevel@tonic-gate * space as badly behaved .os's may corrupt this data space, and in so 3187c478bd9Sstevel@tonic-gate * doing ruin our data. 3197c478bd9Sstevel@tonic-gate */ 3207c478bd9Sstevel@tonic-gate eaddr = S_DROUND((size_t)&_end); 3217c478bd9Sstevel@tonic-gate esize = eaddr % syspagsz; 3227c478bd9Sstevel@tonic-gate if (esize) { 3237c478bd9Sstevel@tonic-gate esize = syspagsz - esize; 3247c478bd9Sstevel@tonic-gate addfree((void *)eaddr, esize); 3257c478bd9Sstevel@tonic-gate } 3267c478bd9Sstevel@tonic-gate 3277c478bd9Sstevel@tonic-gate /* 3287c478bd9Sstevel@tonic-gate * Establish initial link-map list flags, and link-map list alists. 3297c478bd9Sstevel@tonic-gate */ 330dde769a2SRod Evans if (alist_append(&lml_main.lm_lists, NULL, sizeof (Lm_cntl), 33156deab07SRod Evans AL_CNT_LMLISTS) == NULL) 3327c478bd9Sstevel@tonic-gate return (0); 3337c478bd9Sstevel@tonic-gate lml_main.lm_flags |= LML_FLG_BASELM; 3345aefb655Srie lml_main.lm_lmid = LM_ID_BASE; 3355aefb655Srie lml_main.lm_lmidstr = (char *)MSG_ORIG(MSG_LMID_BASE); 3367c478bd9Sstevel@tonic-gate 337dde769a2SRod Evans if (alist_append(&lml_rtld.lm_lists, NULL, sizeof (Lm_cntl), 33856deab07SRod Evans AL_CNT_LMLISTS) == NULL) 3397c478bd9Sstevel@tonic-gate return (0); 3402020b2b6SRod Evans lml_rtld.lm_flags |= (LML_FLG_RTLDLM | LML_FLG_HOLDLOCK); 3412020b2b6SRod Evans lml_rtld.lm_tflags |= LML_TFLG_NOAUDIT; 3425aefb655Srie lml_rtld.lm_lmid = LM_ID_LDSO; 3435aefb655Srie lml_rtld.lm_lmidstr = (char *)MSG_ORIG(MSG_LMID_LDSO); 3447c478bd9Sstevel@tonic-gate 3457c478bd9Sstevel@tonic-gate /* 3467c478bd9Sstevel@tonic-gate * Determine whether we have a secure executable. 3477c478bd9Sstevel@tonic-gate */ 3487c478bd9Sstevel@tonic-gate security(uid, euid, gid, egid, auxflags); 3497c478bd9Sstevel@tonic-gate 3507c478bd9Sstevel@tonic-gate /* 3511c1abfbcSRod Evans * Make an initial pass of environment variables to pick off those 3521c1abfbcSRod Evans * related to locale processing. At the same time, collect and save 3531c1abfbcSRod Evans * any LD_XXXX variables for later processing. Note that this later 3541c1abfbcSRod Evans * processing will be skipped if ld.so.1 is invoked from the command 3551c1abfbcSRod Evans * line with -e LD_NOENVIRON. 3567c478bd9Sstevel@tonic-gate */ 3571c1abfbcSRod Evans if (envp && (readenv_user((const char **)envp, &ealp) == 1)) 3587c478bd9Sstevel@tonic-gate return (0); 3597c478bd9Sstevel@tonic-gate 3607c478bd9Sstevel@tonic-gate /* 3611c1abfbcSRod Evans * If ld.so.1 has been invoked directly, process its arguments. 3621c1abfbcSRod Evans */ 3631c1abfbcSRod Evans if (ldsoexec) { 3641c1abfbcSRod Evans /* 3651c1abfbcSRod Evans * Process any arguments that are specific to ld.so.1, and 3661c1abfbcSRod Evans * reorganize the process stack to effectively remove ld.so.1 3671c1abfbcSRod Evans * from the stack. Reinitialize the environment pointer, as 3681c1abfbcSRod Evans * this pointer may have been shifted after skipping ld.so.1's 3691c1abfbcSRod Evans * arguments. 3701c1abfbcSRod Evans */ 3711c1abfbcSRod Evans if (rtld_getopt(argv, &envp, &auxv, &(lml_main.lm_flags), 3721c1abfbcSRod Evans &(lml_main.lm_tflags), (aoutdyn != 0)) == 1) { 3731c1abfbcSRod Evans eprintf(&lml_main, ERR_NONE, MSG_INTL(MSG_USG_BADOPT)); 3741c1abfbcSRod Evans return (0); 3751c1abfbcSRod Evans } 3761c1abfbcSRod Evans _environ = envp; 3771c1abfbcSRod Evans 3781c1abfbcSRod Evans /* 3791c1abfbcSRod Evans * Open the object that ld.so.1 is to execute. 3801c1abfbcSRod Evans */ 3811c1abfbcSRod Evans argvname = execname = argv[0]; 3821c1abfbcSRod Evans 3831c1abfbcSRod Evans if ((fd = open(argvname, O_RDONLY)) == -1) { 3841c1abfbcSRod Evans int err = errno; 3851c1abfbcSRod Evans eprintf(&lml_main, ERR_FATAL, MSG_INTL(MSG_SYS_OPEN), 3861c1abfbcSRod Evans argvname, strerror(err)); 3871c1abfbcSRod Evans return (0); 3881c1abfbcSRod Evans } 3891c1abfbcSRod Evans } 3901c1abfbcSRod Evans 3911c1abfbcSRod Evans /* 3921c1abfbcSRod Evans * Having processed any ld.so.1 command line options, return to process 3931c1abfbcSRod Evans * any LD_XXXX environment variables. 3941c1abfbcSRod Evans */ 3951c1abfbcSRod Evans if (ealp) { 3961c1abfbcSRod Evans if (((rtld_flags & RT_FL_NOENVIRON) == 0) && 3971c1abfbcSRod Evans (procenv_user(ealp, &(lml_main.lm_flags), 3981c1abfbcSRod Evans &(lml_main.lm_tflags), (aoutdyn != 0)) == 1)) 3991c1abfbcSRod Evans return (0); 4001c1abfbcSRod Evans free(ealp); 4011c1abfbcSRod Evans } 4021c1abfbcSRod Evans 4031c1abfbcSRod Evans /* 40408278a5eSRod Evans * Initialize a hardware capability descriptor for use in comparing 40508278a5eSRod Evans * each loaded object. The aux vector must provide AF_SUN_HWCAPVERIFY, 40608278a5eSRod Evans * as prior to this setting any hardware capabilities that were found 4071c1abfbcSRod Evans * could not be relied upon. 40808278a5eSRod Evans */ 40908278a5eSRod Evans if (auxflags & AF_SUN_HWCAPVERIFY) { 41008278a5eSRod Evans rtld_flags2 |= RT_FL2_HWCAP; 411*ebb8ac07SRobert Mustacchi org_scapset->sc_hw_1 = (Xword)hwcap[0]; 412*ebb8ac07SRobert Mustacchi org_scapset->sc_hw_2 = (Xword)hwcap[1]; 41308278a5eSRod Evans } 41408278a5eSRod Evans 41508278a5eSRod Evans /* 4167c478bd9Sstevel@tonic-gate * Create a mapping descriptor for ld.so.1. We can determine our 4177c478bd9Sstevel@tonic-gate * two segments information from known symbols. 4187c478bd9Sstevel@tonic-gate */ 41956deab07SRod Evans if ((mpp = calloc(2, sizeof (mmapobj_result_t))) == NULL) 4207c478bd9Sstevel@tonic-gate return (0); 42156deab07SRod Evans mpp[0].mr_addr = (caddr_t)M_PTRUNC(ld_base); 42256deab07SRod Evans mpp[0].mr_msize = (caddr_t)&_etext - mpp[0].mr_addr; 42356deab07SRod Evans mpp[0].mr_fsize = mpp[0].mr_msize; 42456deab07SRod Evans mpp[0].mr_prot = (PROT_READ | PROT_EXEC); 4257c478bd9Sstevel@tonic-gate 42656deab07SRod Evans mpp[1].mr_addr = (caddr_t)M_PTRUNC((uintptr_t)&r_debug); 42756deab07SRod Evans mpp[1].mr_msize = (caddr_t)&_end - mpp[1].mr_addr; 42856deab07SRod Evans mpp[1].mr_fsize = (caddr_t)&_edata - mpp[1].mr_addr; 42956deab07SRod Evans mpp[1].mr_prot = (PROT_READ | PROT_WRITE | PROT_EXEC); 43056deab07SRod Evans 43156deab07SRod Evans if ((fdr.fd_nname = stravl_insert(_rtldname, 0, 0, 0)) == NULL) 4327c478bd9Sstevel@tonic-gate return (0); 43356deab07SRod Evans if ((rlmp = elf_new_lmp(&lml_rtld, ALIST_OFF_DATA, &fdr, 43456deab07SRod Evans (Addr)mpp->mr_addr, (size_t)((uintptr_t)eaddr - (uintptr_t)ld_base), 4352020b2b6SRod Evans NULL, NULL, NULL)) == NULL) 43656deab07SRod Evans return (0); 43756deab07SRod Evans 43856deab07SRod Evans MMAPS(rlmp) = mpp; 43956deab07SRod Evans MMAPCNT(rlmp) = 2; 44056deab07SRod Evans PADSTART(rlmp) = (ulong_t)mpp[0].mr_addr; 44156deab07SRod Evans PADIMLEN(rlmp) = (ulong_t)mpp[0].mr_addr + (ulong_t)mpp[1].mr_addr + 44256deab07SRod Evans (ulong_t)mpp[1].mr_msize; 44341072f3cSrie 4447c478bd9Sstevel@tonic-gate MODE(rlmp) |= (RTLD_LAZY | RTLD_NODELETE | RTLD_GLOBAL | RTLD_WORLD); 4457c478bd9Sstevel@tonic-gate FLAGS(rlmp) |= (FLG_RT_ANALYZED | FLG_RT_RELOCED | FLG_RT_INITDONE | 4467c478bd9Sstevel@tonic-gate FLG_RT_INITCLCT | FLG_RT_FINICLCT | FLG_RT_MODESET); 4477c478bd9Sstevel@tonic-gate 4487c478bd9Sstevel@tonic-gate /* 44941072f3cSrie * Initialize the runtime linkers information. 4507c478bd9Sstevel@tonic-gate */ 4517c478bd9Sstevel@tonic-gate interp = &_interp; 45256deab07SRod Evans interp->i_name = (char *)rtldname; 4537c478bd9Sstevel@tonic-gate interp->i_faddr = (caddr_t)ADDR(rlmp); 45441072f3cSrie ldso_plt_init(rlmp); 4557c478bd9Sstevel@tonic-gate 4567c478bd9Sstevel@tonic-gate /* 45756deab07SRod Evans * Map in the file, if exec has not already done so, or if the file 45856deab07SRod Evans * was passed as an argument to an explicit execution of ld.so.1 from 45956deab07SRod Evans * the command line. 4607c478bd9Sstevel@tonic-gate */ 4617c478bd9Sstevel@tonic-gate if (fd != -1) { 4627c478bd9Sstevel@tonic-gate /* 46356deab07SRod Evans * Map the file. Once the object is mapped we no longer need 46456deab07SRod Evans * the file descriptor. 4657c478bd9Sstevel@tonic-gate */ 466cb511613SAli Bahrami (void) rtld_fstat(fd, &status); 4671c1abfbcSRod Evans fdm.fd_oname = argvname; 46856deab07SRod Evans fdm.fd_ftp = map_obj(&lml_main, &fdm, status.st_size, argvname, 46956deab07SRod Evans fd, &rej); 47056deab07SRod Evans (void) close(fd); 47156deab07SRod Evans 47256deab07SRod Evans if (fdm.fd_ftp == NULL) { 473de777a60Sab196087 Conv_reject_desc_buf_t rej_buf; 474de777a60Sab196087 4755aefb655Srie eprintf(&lml_main, ERR_FATAL, 4765aefb655Srie MSG_INTL(err_reject[rej.rej_type]), argvname, 477ba2be530Sab196087 conv_reject_desc(&rej, &rej_buf, M_MACH)); 4787c478bd9Sstevel@tonic-gate return (0); 4797c478bd9Sstevel@tonic-gate } 4807c478bd9Sstevel@tonic-gate 4817c478bd9Sstevel@tonic-gate /* 48256deab07SRod Evans * Finish processing the loading of the file. 4837c478bd9Sstevel@tonic-gate */ 48456deab07SRod Evans if ((fdm.fd_nname = stravl_insert(argvname, 0, 0, 0)) == NULL) 48556deab07SRod Evans return (0); 48656deab07SRod Evans fdm.fd_dev = status.st_dev; 48756deab07SRod Evans fdm.fd_ino = status.st_ino; 48856deab07SRod Evans 4892020b2b6SRod Evans if ((mlmp = load_file(&lml_main, ALIST_OFF_DATA, NULL, &fdm, 49056deab07SRod Evans NULL)) == NULL) 4917c478bd9Sstevel@tonic-gate return (0); 4927c478bd9Sstevel@tonic-gate 49341072f3cSrie /* 49441072f3cSrie * We now have a process name for error diagnostics. 49541072f3cSrie */ 49656deab07SRod Evans if ((str = strrchr(argvname, '/')) != NULL) 49741072f3cSrie procname = ++str; 49841072f3cSrie else 49941072f3cSrie procname = argvname; 50041072f3cSrie 5017c478bd9Sstevel@tonic-gate if (ldsoexec) { 50256deab07SRod Evans mmapobj_result_t *mpp = MMAPS(mlmp); 50356deab07SRod Evans uint_t mnum, mapnum = MMAPCNT(mlmp); 50456deab07SRod Evans void *brkbase = NULL; 5057c478bd9Sstevel@tonic-gate 5067c478bd9Sstevel@tonic-gate /* 5077c478bd9Sstevel@tonic-gate * Since ld.so.1 was the primary executed object - the 5087c478bd9Sstevel@tonic-gate * brk() base has not yet been initialized, we need to 5097c478bd9Sstevel@tonic-gate * initialize it. For an executable, initialize it to 5107c478bd9Sstevel@tonic-gate * the end of the object. For a shared object (ET_DYN) 5117c478bd9Sstevel@tonic-gate * initialize it to the first page in memory. 5127c478bd9Sstevel@tonic-gate */ 51356deab07SRod Evans for (mnum = 0; mnum < mapnum; mnum++, mpp++) 51456deab07SRod Evans brkbase = mpp->mr_addr + mpp->mr_msize; 5157c478bd9Sstevel@tonic-gate 51656deab07SRod Evans if (brkbase == NULL) 51756deab07SRod Evans brkbase = (void *)syspagsz; 5187c478bd9Sstevel@tonic-gate 51956deab07SRod Evans if (_brk_unlocked(brkbase) == -1) { 5207c478bd9Sstevel@tonic-gate int err = errno; 52156deab07SRod Evans 5225aefb655Srie eprintf(&lml_main, ERR_FATAL, 5235aefb655Srie MSG_INTL(MSG_SYS_BRK), argvname, 5245aefb655Srie strerror(err)); 52556deab07SRod Evans return (0); 5267c478bd9Sstevel@tonic-gate } 5277c478bd9Sstevel@tonic-gate } 5287c478bd9Sstevel@tonic-gate } else { 5297c478bd9Sstevel@tonic-gate /* 5307c478bd9Sstevel@tonic-gate * Set up function ptr and arguments according to the type 5317c478bd9Sstevel@tonic-gate * of file class the executable is. (Currently only supported 5327c478bd9Sstevel@tonic-gate * types are ELF and a.out format.) Then create a link map 5337c478bd9Sstevel@tonic-gate * for the executable. 5347c478bd9Sstevel@tonic-gate */ 5357c478bd9Sstevel@tonic-gate if (aoutdyn) { 5367c478bd9Sstevel@tonic-gate #ifdef A_OUT 53756deab07SRod Evans mmapobj_result_t *mpp; 53856deab07SRod Evans 53956deab07SRod Evans /* 54056deab07SRod Evans * Create a mapping structure sufficient to describe 54156deab07SRod Evans * a single two segments. The ADDR() of the a.out is 54256deab07SRod Evans * established as 0, which is required but the AOUT 54356deab07SRod Evans * relocation code. 54456deab07SRod Evans */ 54556deab07SRod Evans if ((mpp = 54656deab07SRod Evans calloc(sizeof (mmapobj_result_t), 2)) == NULL) 54756deab07SRod Evans return (0); 54856deab07SRod Evans 54956deab07SRod Evans if ((fdm.fd_nname = 55056deab07SRod Evans stravl_insert(execname, 0, 0, 0)) == NULL) 55156deab07SRod Evans return (0); 55256deab07SRod Evans if ((mlmp = aout_new_lmp(&lml_main, ALIST_OFF_DATA, 5532020b2b6SRod Evans &fdm, 0, 0, aoutdyn, NULL, NULL)) == NULL) 5547c478bd9Sstevel@tonic-gate return (0); 5557c478bd9Sstevel@tonic-gate 5567c478bd9Sstevel@tonic-gate /* 55756deab07SRod Evans * Establish the true mapping information for the a.out. 5587c478bd9Sstevel@tonic-gate */ 55956deab07SRod Evans if (aout_get_mmap(&lml_main, mpp)) { 56056deab07SRod Evans free(mpp); 56156deab07SRod Evans return (0); 56256deab07SRod Evans } 56356deab07SRod Evans 56456deab07SRod Evans MSIZE(mlmp) = 56556deab07SRod Evans (size_t)(mpp[1].mr_addr + mpp[1].mr_msize) - 56656deab07SRod Evans S_ALIGN((size_t)mpp[0].mr_addr, syspagsz); 56756deab07SRod Evans MMAPS(mlmp) = mpp; 56856deab07SRod Evans MMAPCNT(mlmp) = 2; 56956deab07SRod Evans PADSTART(mlmp) = (ulong_t)mpp->mr_addr; 57056deab07SRod Evans PADIMLEN(mlmp) = mpp->mr_msize; 5717c478bd9Sstevel@tonic-gate 5727c478bd9Sstevel@tonic-gate /* 5737c478bd9Sstevel@tonic-gate * Disable any object configuration cache (BCP apps 5747c478bd9Sstevel@tonic-gate * bring in sbcp which can benefit from any object 5757c478bd9Sstevel@tonic-gate * cache, but both the app and sbcp can't use the same 5767c478bd9Sstevel@tonic-gate * objects). 5777c478bd9Sstevel@tonic-gate */ 5787c478bd9Sstevel@tonic-gate rtld_flags |= RT_FL_NOOBJALT; 5797c478bd9Sstevel@tonic-gate 5807c478bd9Sstevel@tonic-gate /* 5817c478bd9Sstevel@tonic-gate * Make sure no-direct bindings are in effect. 5827c478bd9Sstevel@tonic-gate */ 5837c478bd9Sstevel@tonic-gate lml_main.lm_tflags |= LML_TFLG_NODIRECT; 5847c478bd9Sstevel@tonic-gate #else 5855aefb655Srie eprintf(&lml_main, ERR_FATAL, 5865aefb655Srie MSG_INTL(MSG_ERR_REJ_UNKFILE), argvname); 5877c478bd9Sstevel@tonic-gate return (0); 5887c478bd9Sstevel@tonic-gate #endif 5897c478bd9Sstevel@tonic-gate } else if (phdr) { 59056deab07SRod Evans Phdr *pptr; 59141072f3cSrie Off i_offset = 0; 5927c478bd9Sstevel@tonic-gate Addr base = 0; 59356deab07SRod Evans ulong_t phsize; 59456deab07SRod Evans mmapobj_result_t *mpp, *fmpp, *hmpp = NULL; 59556deab07SRod Evans uint_t mapnum = 0; 59641072f3cSrie int i; 59756deab07SRod Evans size_t msize; 5987c478bd9Sstevel@tonic-gate 5997c478bd9Sstevel@tonic-gate /* 6007c478bd9Sstevel@tonic-gate * Using the executables phdr address determine the base 6017c478bd9Sstevel@tonic-gate * address of the input file. NOTE, this assumes the 6027c478bd9Sstevel@tonic-gate * program headers and elf header are part of the same 6037c478bd9Sstevel@tonic-gate * mapped segment. Although this has held for many 6047c478bd9Sstevel@tonic-gate * years now, it might be more flexible if the kernel 6057c478bd9Sstevel@tonic-gate * gave use the ELF headers start address, rather than 6067c478bd9Sstevel@tonic-gate * the Program headers. 6077c478bd9Sstevel@tonic-gate * 6087c478bd9Sstevel@tonic-gate * Determine from the ELF header if we're been called 6097c478bd9Sstevel@tonic-gate * from a shared object or dynamic executable. If the 6107c478bd9Sstevel@tonic-gate * latter, then any addresses within the object are used 6117c478bd9Sstevel@tonic-gate * as is. Addresses within shared objects must be added 6127c478bd9Sstevel@tonic-gate * to the process's base address. 6137c478bd9Sstevel@tonic-gate */ 6147c478bd9Sstevel@tonic-gate ehdr = (Ehdr *)((Addr)phdr - phdr->p_offset); 6157c478bd9Sstevel@tonic-gate phsize = ehdr->e_phentsize; 61641072f3cSrie if (ehdr->e_type == ET_DYN) 6177c478bd9Sstevel@tonic-gate base = (Addr)ehdr; 6187c478bd9Sstevel@tonic-gate 6197c478bd9Sstevel@tonic-gate /* 6207c478bd9Sstevel@tonic-gate * Allocate a mapping array to retain mapped segment 6217c478bd9Sstevel@tonic-gate * information. 6227c478bd9Sstevel@tonic-gate */ 62356deab07SRod Evans if ((fmpp = mpp = calloc(ehdr->e_phnum, 62456deab07SRod Evans sizeof (mmapobj_result_t))) == NULL) 6257c478bd9Sstevel@tonic-gate return (0); 6267c478bd9Sstevel@tonic-gate 6277c478bd9Sstevel@tonic-gate /* 6287c478bd9Sstevel@tonic-gate * Extract the needed information from the segment 6297c478bd9Sstevel@tonic-gate * headers. 6307c478bd9Sstevel@tonic-gate */ 6317c478bd9Sstevel@tonic-gate for (i = 0, pptr = phdr; i < ehdr->e_phnum; i++) { 6327c478bd9Sstevel@tonic-gate if (pptr->p_type == PT_INTERP) { 6337c478bd9Sstevel@tonic-gate i_offset = pptr->p_offset; 6347c478bd9Sstevel@tonic-gate interp->i_faddr = 6357c478bd9Sstevel@tonic-gate (caddr_t)interp_base; 6367c478bd9Sstevel@tonic-gate } 6377c478bd9Sstevel@tonic-gate if ((pptr->p_type == PT_LOAD) && 6387c478bd9Sstevel@tonic-gate (pptr->p_filesz || pptr->p_memsz)) { 6397c478bd9Sstevel@tonic-gate int perm = (PROT_READ | PROT_EXEC); 6407c478bd9Sstevel@tonic-gate size_t off; 6417c478bd9Sstevel@tonic-gate 64241072f3cSrie if (i_offset && pptr->p_filesz && 6437c478bd9Sstevel@tonic-gate (i_offset >= pptr->p_offset) && 6447c478bd9Sstevel@tonic-gate (i_offset <= 6457c478bd9Sstevel@tonic-gate (pptr->p_memsz + pptr->p_offset))) { 6467c478bd9Sstevel@tonic-gate interp->i_name = (char *) 6477c478bd9Sstevel@tonic-gate pptr->p_vaddr + i_offset - 6487c478bd9Sstevel@tonic-gate pptr->p_offset + base; 64941072f3cSrie i_offset = 0; 6507c478bd9Sstevel@tonic-gate } 65156deab07SRod Evans 65256deab07SRod Evans if (pptr->p_flags & PF_W) 6537c478bd9Sstevel@tonic-gate perm |= PROT_WRITE; 6547c478bd9Sstevel@tonic-gate 6557c478bd9Sstevel@tonic-gate /* 6567c478bd9Sstevel@tonic-gate * Retain segments mapping info. Round 6577c478bd9Sstevel@tonic-gate * each segment to a page boundary, as 6587c478bd9Sstevel@tonic-gate * this insures addresses are suitable 6597c478bd9Sstevel@tonic-gate * for mprotect() if required. 6607c478bd9Sstevel@tonic-gate */ 6617c478bd9Sstevel@tonic-gate off = pptr->p_vaddr + base; 66256deab07SRod Evans if (hmpp == NULL) { 66356deab07SRod Evans hmpp = mpp; 66456deab07SRod Evans mpp->mr_addr = (caddr_t)ehdr; 66556deab07SRod Evans } else 66656deab07SRod Evans mpp->mr_addr = (caddr_t)off; 6677c478bd9Sstevel@tonic-gate 66856deab07SRod Evans off -= (size_t)(uintptr_t)mpp->mr_addr; 66956deab07SRod Evans mpp->mr_msize = pptr->p_memsz + off; 67056deab07SRod Evans mpp->mr_fsize = pptr->p_filesz + off; 67156deab07SRod Evans mpp->mr_prot = perm; 67256deab07SRod Evans 67356deab07SRod Evans mpp++, mapnum++; 67410a4fa49Srie } 67556deab07SRod Evans 6767c478bd9Sstevel@tonic-gate pptr = (Phdr *)((ulong_t)pptr + phsize); 6777c478bd9Sstevel@tonic-gate } 6787c478bd9Sstevel@tonic-gate 67956deab07SRod Evans mpp--; 68056deab07SRod Evans msize = (size_t)(mpp->mr_addr + mpp->mr_msize) - 68156deab07SRod Evans S_ALIGN((size_t)fmpp->mr_addr, syspagsz); 6827c478bd9Sstevel@tonic-gate 68356deab07SRod Evans if ((fdm.fd_nname = 68456deab07SRod Evans stravl_insert(execname, 0, 0, 0)) == NULL) 6857c478bd9Sstevel@tonic-gate return (0); 6862020b2b6SRod Evans if ((mlmp = elf_new_lmp(&lml_main, ALIST_OFF_DATA, 6872020b2b6SRod Evans &fdm, (Addr)hmpp->mr_addr, msize, 6882020b2b6SRod Evans NULL, NULL, NULL)) == NULL) 689d326b23bSrie return (0); 690d326b23bSrie 69156deab07SRod Evans MMAPS(mlmp) = fmpp; 69256deab07SRod Evans MMAPCNT(mlmp) = mapnum; 69356deab07SRod Evans PADSTART(mlmp) = (ulong_t)fmpp->mr_addr; 69456deab07SRod Evans PADIMLEN(mlmp) = (ulong_t)fmpp->mr_addr + 69556deab07SRod Evans (ulong_t)mpp->mr_addr + (ulong_t)mpp->mr_msize; 6967c478bd9Sstevel@tonic-gate } 6977c478bd9Sstevel@tonic-gate } 6987c478bd9Sstevel@tonic-gate 6997c478bd9Sstevel@tonic-gate /* 70041072f3cSrie * Establish the interpretors name as that defined within the initial 70141072f3cSrie * object (executable). This provides for ORIGIN processing of ld.so.1 70256deab07SRod Evans * dependencies. Note, the NAME() of the object remains that which was 70356deab07SRod Evans * passed to us as the SONAME on execution. 7047c478bd9Sstevel@tonic-gate */ 70541072f3cSrie if (ldsoexec == 0) { 70641072f3cSrie size_t len = strlen(interp->i_name); 70741072f3cSrie 70856deab07SRod Evans if (expand(&interp->i_name, &len, 0, 0, 70908278a5eSRod Evans (PD_TKN_ISALIST | PD_TKN_CAP), rlmp) & PD_TKN_RESOLVED) 71056deab07SRod Evans fdr.fd_flags |= FLG_FD_RESOLVED; 71156deab07SRod Evans } 71256deab07SRod Evans fdr.fd_pname = interp->i_name; 71356deab07SRod Evans (void) fullpath(rlmp, &fdr); 71456deab07SRod Evans 71556deab07SRod Evans /* 71656deab07SRod Evans * The runtime linker acts as a filtee for various dl*() functions that 71756deab07SRod Evans * are defined in libc (and libdl). Make sure this standard name for 71856deab07SRod Evans * the runtime linker is also registered in the FullPathNode AVL tree. 71956deab07SRod Evans */ 72056deab07SRod Evans (void) fpavl_insert(&lml_rtld, rlmp, _rtldname, 0); 7217c478bd9Sstevel@tonic-gate 7227c478bd9Sstevel@tonic-gate /* 72341072f3cSrie * Having established the true runtime linkers name, simplify the name 72441072f3cSrie * for error diagnostics. 7257c478bd9Sstevel@tonic-gate */ 72656deab07SRod Evans if ((str = strrchr(PATHNAME(rlmp), '/')) != NULL) 72741072f3cSrie rtldname = ++str; 7287c478bd9Sstevel@tonic-gate else 72941072f3cSrie rtldname = PATHNAME(rlmp); 7307c478bd9Sstevel@tonic-gate 73141072f3cSrie /* 73241072f3cSrie * Expand the fullpath name of the application. This typically occurs 73341072f3cSrie * as a part of loading an object, but as the kernel probably mapped 73441072f3cSrie * it in, complete this processing now. 73541072f3cSrie */ 73641072f3cSrie (void) fullpath(mlmp, 0); 73741072f3cSrie 73841072f3cSrie /* 73941072f3cSrie * Some troublesome programs will change the value of argv[0]. Dupping 74041072f3cSrie * the process string protects us, and insures the string is left in 74141072f3cSrie * any core files. 74241072f3cSrie */ 74356deab07SRod Evans if ((str = (char *)strdup(procname)) == NULL) 74441072f3cSrie return (0); 74541072f3cSrie procname = str; 7467c478bd9Sstevel@tonic-gate 7477c478bd9Sstevel@tonic-gate FLAGS(mlmp) |= (FLG_RT_ISMAIN | FLG_RT_MODESET); 7487c478bd9Sstevel@tonic-gate FLAGS1(mlmp) |= FL1_RT_USED; 749dffec89cSrie 750dffec89cSrie /* 751dffec89cSrie * It's the responsibility of MAIN(crt0) to call it's _init and _fini 752dffec89cSrie * section, therefore null out any INIT/FINI so that this object isn't 753dffec89cSrie * collected during tsort processing. And, if the application has no 754dffec89cSrie * initarray or finiarray we can economize on establishing bindings. 755dffec89cSrie */ 75656deab07SRod Evans INIT(mlmp) = FINI(mlmp) = NULL; 75756deab07SRod Evans if ((INITARRAY(mlmp) == NULL) && (FINIARRAY(mlmp) == NULL)) 7587c478bd9Sstevel@tonic-gate FLAGS1(mlmp) |= FL1_RT_NOINIFIN; 7597c478bd9Sstevel@tonic-gate 7607c478bd9Sstevel@tonic-gate /* 7617c478bd9Sstevel@tonic-gate * Identify lddstub if necessary. 7627c478bd9Sstevel@tonic-gate */ 7637c478bd9Sstevel@tonic-gate if (lml_main.lm_flags & LML_FLG_TRC_LDDSTUB) 7647c478bd9Sstevel@tonic-gate FLAGS1(mlmp) |= FL1_RT_LDDSTUB; 7657c478bd9Sstevel@tonic-gate 76641072f3cSrie /* 76741072f3cSrie * Retain our argument information for use in dlinfo. 76841072f3cSrie */ 76941072f3cSrie argsinfo.dla_argv = argv--; 77041072f3cSrie argsinfo.dla_argc = (long)*argv; 77141072f3cSrie argsinfo.dla_envp = envp; 77241072f3cSrie argsinfo.dla_auxv = auxv; 77341072f3cSrie 7748cd45542Sraf (void) enter(0); 7757c478bd9Sstevel@tonic-gate 7767c478bd9Sstevel@tonic-gate /* 7777c478bd9Sstevel@tonic-gate * Add our two main link-maps to the dynlm_list 7787c478bd9Sstevel@tonic-gate */ 77957ef7aa9SRod Evans if (aplist_append(&dynlm_list, &lml_main, AL_CNT_DYNLIST) == NULL) 7807c478bd9Sstevel@tonic-gate return (0); 7817c478bd9Sstevel@tonic-gate 78257ef7aa9SRod Evans if (aplist_append(&dynlm_list, &lml_rtld, AL_CNT_DYNLIST) == NULL) 7837c478bd9Sstevel@tonic-gate return (0); 7847c478bd9Sstevel@tonic-gate 7857c478bd9Sstevel@tonic-gate /* 7867c478bd9Sstevel@tonic-gate * Reset the link-map counts for both lists. The init count is used to 7877c478bd9Sstevel@tonic-gate * track how many objects have pending init sections, this gets incre- 7887c478bd9Sstevel@tonic-gate * mented each time an object is relocated. Since ld.so.1 relocates 7897c478bd9Sstevel@tonic-gate * itself, it's init count will remain zero. 7907c478bd9Sstevel@tonic-gate * The object count is used to track how many objects have pending fini 7917c478bd9Sstevel@tonic-gate * sections, as ld.so.1 handles its own fini we can zero its count. 7927c478bd9Sstevel@tonic-gate */ 7937c478bd9Sstevel@tonic-gate lml_main.lm_obj = 1; 7947c478bd9Sstevel@tonic-gate lml_rtld.lm_obj = 0; 7957c478bd9Sstevel@tonic-gate 7967c478bd9Sstevel@tonic-gate /* 7977c478bd9Sstevel@tonic-gate * Initialize debugger information structure. Some parts of this 7987c478bd9Sstevel@tonic-gate * structure were initialized statically. 7997c478bd9Sstevel@tonic-gate */ 8007c478bd9Sstevel@tonic-gate r_debug.rtd_rdebug.r_map = (Link_map *)lml_main.lm_head; 8017c478bd9Sstevel@tonic-gate r_debug.rtd_rdebug.r_ldsomap = (Link_map *)lml_rtld.lm_head; 8027c478bd9Sstevel@tonic-gate r_debug.rtd_rdebug.r_ldbase = r_debug.rtd_rdebug.r_ldsomap->l_addr; 8037c478bd9Sstevel@tonic-gate r_debug.rtd_dynlmlst = &dynlm_list; 8047c478bd9Sstevel@tonic-gate 8057c478bd9Sstevel@tonic-gate /* 8067c478bd9Sstevel@tonic-gate * Determine the dev/inode information for the executable to complete 8077c478bd9Sstevel@tonic-gate * load_so() checking for those who might dlopen(a.out). 8087c478bd9Sstevel@tonic-gate */ 80956deab07SRod Evans if (rtld_stat(PATHNAME(mlmp), &status) == 0) { 8107c478bd9Sstevel@tonic-gate STDEV(mlmp) = status.st_dev; 8117c478bd9Sstevel@tonic-gate STINO(mlmp) = status.st_ino; 8127c478bd9Sstevel@tonic-gate } 8137c478bd9Sstevel@tonic-gate 8147c478bd9Sstevel@tonic-gate /* 8157c478bd9Sstevel@tonic-gate * Initialize any configuration information. 8167c478bd9Sstevel@tonic-gate */ 8177c478bd9Sstevel@tonic-gate if (!(rtld_flags & RT_FL_NOCFG)) { 8187c478bd9Sstevel@tonic-gate if ((features = elf_config(mlmp, (aoutdyn != 0))) == -1) 8197c478bd9Sstevel@tonic-gate return (0); 8201c1abfbcSRod Evans } 82108278a5eSRod Evans 8221c1abfbcSRod Evans #if defined(_ELF64) 8231c1abfbcSRod Evans /* 8241c1abfbcSRod Evans * If this is a 64-bit process, determine whether this process has 8251c1abfbcSRod Evans * restricted the process address space to 32-bits. Any dependencies 8261c1abfbcSRod Evans * that are restricted to a 32-bit address space can only be loaded if 8271c1abfbcSRod Evans * the executable has established this requirement. 8281c1abfbcSRod Evans */ 8291c1abfbcSRod Evans if (CAPSET(mlmp).sc_sf_1 & SF1_SUNW_ADDR32) 8301c1abfbcSRod Evans rtld_flags2 |= RT_FL2_ADDR32; 8311c1abfbcSRod Evans #endif 8321c1abfbcSRod Evans /* 8331c1abfbcSRod Evans * Establish any alternative capabilities, and validate this object 8341c1abfbcSRod Evans * if it defines it's own capabilities information. 8351c1abfbcSRod Evans */ 83608278a5eSRod Evans if (cap_alternative() == 0) 83708278a5eSRod Evans return (0); 8381c1abfbcSRod Evans 8391c1abfbcSRod Evans if (cap_check_lmp(mlmp, &rej) == 0) { 8401c1abfbcSRod Evans if (lml_main.lm_flags & LML_FLG_TRC_ENABLE) { 8411c1abfbcSRod Evans /* LINTED */ 8421c1abfbcSRod Evans (void) printf(MSG_INTL(ldd_warn[rej.rej_type]), 8431c1abfbcSRod Evans NAME(mlmp), rej.rej_str); 8441c1abfbcSRod Evans } else { 8451c1abfbcSRod Evans /* LINTED */ 8461c1abfbcSRod Evans eprintf(&lml_main, ERR_FATAL, 8471c1abfbcSRod Evans MSG_INTL(err_reject[rej.rej_type]), 8481c1abfbcSRod Evans NAME(mlmp), rej.rej_str); 8491c1abfbcSRod Evans return (0); 8501c1abfbcSRod Evans } 8517c478bd9Sstevel@tonic-gate } 8527c478bd9Sstevel@tonic-gate 8537c478bd9Sstevel@tonic-gate /* 8547c478bd9Sstevel@tonic-gate * Establish the modes of the initial object. These modes are 8557c478bd9Sstevel@tonic-gate * propagated to any preloaded objects and explicit shared library 85675e7992aSrie * dependencies. 85775e7992aSrie * 85875e7992aSrie * If we're generating a configuration file using crle(1), remove 85975e7992aSrie * any RTLD_NOW use, as we don't want to trigger any relocation proc- 86075e7992aSrie * essing during crle(1)'s first past (this would just be unnecessary 86175e7992aSrie * overhead). Any filters are explicitly loaded, and thus RTLD_NOW is 86275e7992aSrie * not required to trigger filter loading. 86375e7992aSrie * 86475e7992aSrie * Note, RTLD_NOW may have been established during analysis of the 86575e7992aSrie * application had the application been built -z now. 8667c478bd9Sstevel@tonic-gate */ 8677c478bd9Sstevel@tonic-gate MODE(mlmp) |= (RTLD_NODELETE | RTLD_GLOBAL | RTLD_WORLD); 86875e7992aSrie 86975e7992aSrie if (rtld_flags & RT_FL_CONFGEN) { 8707c478bd9Sstevel@tonic-gate MODE(mlmp) |= RTLD_CONFGEN; 87175e7992aSrie MODE(mlmp) &= ~RTLD_NOW; 87275e7992aSrie rtld_flags2 &= ~RT_FL2_BINDNOW; 87375e7992aSrie } 87475e7992aSrie 87541072f3cSrie if ((MODE(mlmp) & RTLD_NOW) == 0) { 8767c478bd9Sstevel@tonic-gate if (rtld_flags2 & RT_FL2_BINDNOW) 8777c478bd9Sstevel@tonic-gate MODE(mlmp) |= RTLD_NOW; 8787c478bd9Sstevel@tonic-gate else 8797c478bd9Sstevel@tonic-gate MODE(mlmp) |= RTLD_LAZY; 88041072f3cSrie } 8817c478bd9Sstevel@tonic-gate 8827c478bd9Sstevel@tonic-gate /* 8837c478bd9Sstevel@tonic-gate * If debugging was requested initialize things now that any cache has 8845aefb655Srie * been established. A user can specify LD_DEBUG=help to discover the 8855aefb655Srie * list of debugging tokens available without running the application. 8865aefb655Srie * However, don't allow this setting from a configuration file. 8875aefb655Srie * 8885aefb655Srie * Note, to prevent recursion issues caused by loading and binding the 8895aefb655Srie * debugging libraries themselves, a local debugging descriptor is 8905aefb655Srie * initialized. Once the debugging setup has completed, this local 8915aefb655Srie * descriptor is copied to the global descriptor which effectively 8925aefb655Srie * enables diagnostic output. 893dde769a2SRod Evans * 894dde769a2SRod Evans * Ignore any debugging request if we're being monitored by a process 895dde769a2SRod Evans * that expects the old getpid() initialization handshake. 8967c478bd9Sstevel@tonic-gate */ 897dde769a2SRod Evans if ((rpl_debug || prm_debug) && ((rtld_flags & RT_FL_DEBUGGER) == 0)) { 8982017c965SRod Evans Dbg_desc _dbg_desc = {0}; 8992017c965SRod Evans struct timeval total = DBG_TOTALTIME; 9002017c965SRod Evans struct timeval delta = DBG_DELTATIME; 9015aefb655Srie 9025aefb655Srie if (rpl_debug) { 903e23c41c9SAli Bahrami if (dbg_setup(rpl_debug, &_dbg_desc) == 0) 9045aefb655Srie return (0); 905e23c41c9SAli Bahrami if (_dbg_desc.d_extra & DBG_E_HELP_EXIT) 9065aefb655Srie rtldexit(&lml_main, 0); 9075aefb655Srie } 9087c478bd9Sstevel@tonic-gate if (prm_debug) 9095aefb655Srie (void) dbg_setup(prm_debug, &_dbg_desc); 9105aefb655Srie 9115aefb655Srie *dbg_desc = _dbg_desc; 9122017c965SRod Evans DBG_TOTALTIME = total; 9132017c965SRod Evans DBG_DELTATIME = delta; 9145aefb655Srie } 9157c478bd9Sstevel@tonic-gate 9167c478bd9Sstevel@tonic-gate /* 9177c478bd9Sstevel@tonic-gate * Now that debugging is enabled generate any diagnostics from any 9187c478bd9Sstevel@tonic-gate * previous events. 9197c478bd9Sstevel@tonic-gate */ 92008278a5eSRod Evans if (DBG_ENABLED) { 92108278a5eSRod Evans DBG_CALL(Dbg_cap_val(&lml_main, org_scapset, alt_scapset, 92208278a5eSRod Evans M_MACH)); 9235aefb655Srie DBG_CALL(Dbg_file_config_dis(&lml_main, config->c_name, 9245aefb655Srie features)); 9257c478bd9Sstevel@tonic-gate 9265aefb655Srie DBG_CALL(Dbg_file_ldso(rlmp, envp, auxv, 927cce0e03bSab196087 LIST(rlmp)->lm_lmidstr, ALIST_OFF_DATA)); 9287c478bd9Sstevel@tonic-gate 92956deab07SRod Evans if (THIS_IS_ELF(mlmp)) { 9305aefb655Srie DBG_CALL(Dbg_file_elf(&lml_main, PATHNAME(mlmp), 93156deab07SRod Evans ADDR(mlmp), MSIZE(mlmp), LIST(mlmp)->lm_lmidstr, 932cce0e03bSab196087 ALIST_OFF_DATA)); 9337c478bd9Sstevel@tonic-gate } else { 9345aefb655Srie DBG_CALL(Dbg_file_aout(&lml_main, PATHNAME(mlmp), 93556deab07SRod Evans ADDR(mlmp), MSIZE(mlmp), LIST(mlmp)->lm_lmidstr, 936cce0e03bSab196087 ALIST_OFF_DATA)); 9377c478bd9Sstevel@tonic-gate } 9387c478bd9Sstevel@tonic-gate } 9397c478bd9Sstevel@tonic-gate 9407c478bd9Sstevel@tonic-gate /* 9417c478bd9Sstevel@tonic-gate * Enable auditing. 9427c478bd9Sstevel@tonic-gate */ 9437c478bd9Sstevel@tonic-gate if (rpl_audit || prm_audit || profile_lib) { 9447c478bd9Sstevel@tonic-gate int ndx; 9457c478bd9Sstevel@tonic-gate const char *aud[3]; 9467c478bd9Sstevel@tonic-gate 9477c478bd9Sstevel@tonic-gate aud[0] = rpl_audit; 9487c478bd9Sstevel@tonic-gate aud[1] = prm_audit; 9497c478bd9Sstevel@tonic-gate aud[2] = profile_lib; 9507c478bd9Sstevel@tonic-gate 9517c478bd9Sstevel@tonic-gate /* 9527c478bd9Sstevel@tonic-gate * Any global auditing (set using LD_AUDIT or LD_PROFILE) that 9537c478bd9Sstevel@tonic-gate * can't be established is non-fatal. 9547c478bd9Sstevel@tonic-gate */ 95556deab07SRod Evans if ((auditors = calloc(1, sizeof (Audit_desc))) == NULL) 9567c478bd9Sstevel@tonic-gate return (0); 9577c478bd9Sstevel@tonic-gate 9587c478bd9Sstevel@tonic-gate for (ndx = 0; ndx < 3; ndx++) { 9597c478bd9Sstevel@tonic-gate if (aud[ndx]) { 96056deab07SRod Evans if ((auditors->ad_name = 96156deab07SRod Evans strdup(aud[ndx])) == NULL) 9627c478bd9Sstevel@tonic-gate return (0); 9637c478bd9Sstevel@tonic-gate rtld_flags2 |= RT_FL2_FTL2WARN; 96456d7adc6Srie (void) audit_setup(mlmp, auditors, 96556deab07SRod Evans PD_FLG_EXTLOAD, NULL); 9667c478bd9Sstevel@tonic-gate rtld_flags2 &= ~RT_FL2_FTL2WARN; 9677c478bd9Sstevel@tonic-gate } 9687c478bd9Sstevel@tonic-gate } 9697c478bd9Sstevel@tonic-gate lml_main.lm_tflags |= auditors->ad_flags; 9707c478bd9Sstevel@tonic-gate } 9717c478bd9Sstevel@tonic-gate if (AUDITORS(mlmp)) { 9727c478bd9Sstevel@tonic-gate /* 9737c478bd9Sstevel@tonic-gate * Any object required auditing (set with a DT_DEPAUDIT dynamic 9747c478bd9Sstevel@tonic-gate * entry) that can't be established is fatal. 9757c478bd9Sstevel@tonic-gate */ 9767247f888Srie if (FLAGS1(mlmp) & FL1_RT_GLOBAUD) { 9777247f888Srie /* 9787247f888Srie * If this object requires global auditing, use the 9797247f888Srie * local auditing information to set the global 9807247f888Srie * auditing descriptor. The effect is that a 9817247f888Srie * DT_DEPAUDIT act as an LD_AUDIT. 9827247f888Srie */ 98356deab07SRod Evans if ((auditors == NULL) && ((auditors = calloc(1, 98456deab07SRod Evans sizeof (Audit_desc))) == NULL)) 9857247f888Srie return (0); 9867247f888Srie 9877247f888Srie auditors->ad_name = AUDITORS(mlmp)->ad_name; 9889aa23310Srie if (audit_setup(mlmp, auditors, 0, NULL) == 0) 9897247f888Srie return (0); 9907247f888Srie lml_main.lm_tflags |= auditors->ad_flags; 9917247f888Srie 9927247f888Srie /* 9937247f888Srie * Clear the local auditor information. 9947247f888Srie */ 9957247f888Srie free((void *) AUDITORS(mlmp)); 99656deab07SRod Evans AUDITORS(mlmp) = NULL; 9977247f888Srie 9987247f888Srie } else { 9997247f888Srie /* 10007247f888Srie * Establish any local auditing. 10017247f888Srie */ 10029aa23310Srie if (audit_setup(mlmp, AUDITORS(mlmp), 0, NULL) == 0) 10037c478bd9Sstevel@tonic-gate return (0); 10047c478bd9Sstevel@tonic-gate 100556deab07SRod Evans AFLAGS(mlmp) |= AUDITORS(mlmp)->ad_flags; 10067c478bd9Sstevel@tonic-gate lml_main.lm_flags |= LML_FLG_LOCAUDIT; 10077c478bd9Sstevel@tonic-gate } 10087247f888Srie } 10097c478bd9Sstevel@tonic-gate 10107c478bd9Sstevel@tonic-gate /* 10117c478bd9Sstevel@tonic-gate * Explicitly add the initial object and ld.so.1 to those objects being 10127c478bd9Sstevel@tonic-gate * audited. Note, although the ld.so.1 link-map isn't auditable, 10137c478bd9Sstevel@tonic-gate * establish a cookie for ld.so.1 as this may be bound to via the 10147c478bd9Sstevel@tonic-gate * dl*() family. 10157c478bd9Sstevel@tonic-gate */ 101656deab07SRod Evans if ((lml_main.lm_tflags | AFLAGS(mlmp)) & LML_TFLG_AUD_MASK) { 10177c478bd9Sstevel@tonic-gate if (((audit_objopen(mlmp, mlmp) == 0) || 10187c478bd9Sstevel@tonic-gate (audit_objopen(mlmp, rlmp) == 0)) && 101956deab07SRod Evans (AFLAGS(mlmp) & LML_TFLG_AUD_MASK)) 10207c478bd9Sstevel@tonic-gate return (0); 10217c478bd9Sstevel@tonic-gate } 10227c478bd9Sstevel@tonic-gate 10237c478bd9Sstevel@tonic-gate /* 1024dde769a2SRod Evans * Map in any preloadable shared objects. Establish the caller as the 1025dde769a2SRod Evans * head of the main link-map list. In the case of being exercised from 1026dde769a2SRod Evans * lddstub, the caller gets reassigned to the first target shared object 1027dde769a2SRod Evans * so as to provide intuitive diagnostics from ldd(). 1028dde769a2SRod Evans * 1029dde769a2SRod Evans * Note, it is valid to preload a 4.x shared object with a 5.0 1030dde769a2SRod Evans * executable (or visa-versa), as this functionality is required by 1031dde769a2SRod Evans * ldd(1). 10327c478bd9Sstevel@tonic-gate */ 1033dde769a2SRod Evans clmp = mlmp; 1034dde769a2SRod Evans if (rpl_preload && (preload(rpl_preload, mlmp, &clmp) == 0)) 10357c478bd9Sstevel@tonic-gate return (0); 1036dde769a2SRod Evans if (prm_preload && (preload(prm_preload, mlmp, &clmp) == 0)) 10377c478bd9Sstevel@tonic-gate return (0); 10387c478bd9Sstevel@tonic-gate 10397c478bd9Sstevel@tonic-gate /* 10407c478bd9Sstevel@tonic-gate * Load all dependent (needed) objects. 10417c478bd9Sstevel@tonic-gate */ 10422020b2b6SRod Evans if (analyze_lmc(&lml_main, ALIST_OFF_DATA, mlmp, mlmp, NULL) == NULL) 10437c478bd9Sstevel@tonic-gate return (0); 10447c478bd9Sstevel@tonic-gate 10457c478bd9Sstevel@tonic-gate /* 10467c478bd9Sstevel@tonic-gate * Relocate all the dependencies we've just added. 10477c478bd9Sstevel@tonic-gate * 10487c478bd9Sstevel@tonic-gate * If this process has been established via crle(1), the environment 10497c478bd9Sstevel@tonic-gate * variable LD_CONFGEN will have been set. crle(1) may create this 10507c478bd9Sstevel@tonic-gate * process twice. The first time crle only needs to gather dependency 10517c478bd9Sstevel@tonic-gate * information. The second time, is to dldump() the images. 10527c478bd9Sstevel@tonic-gate * 10537c478bd9Sstevel@tonic-gate * If we're only gathering dependencies, relocation is unnecessary. 10547c478bd9Sstevel@tonic-gate * As crle(1) may be building an arbitrary family of objects, they may 10557c478bd9Sstevel@tonic-gate * not fully relocate either. Hence the relocation phase is not carried 10567c478bd9Sstevel@tonic-gate * out now, but will be called by crle(1) once all objects have been 10577c478bd9Sstevel@tonic-gate * loaded. 10587c478bd9Sstevel@tonic-gate */ 10597c478bd9Sstevel@tonic-gate if ((rtld_flags & RT_FL_CONFGEN) == 0) { 10607c478bd9Sstevel@tonic-gate 10615aefb655Srie DBG_CALL(Dbg_util_nl(&lml_main, DBG_NL_STD)); 10627c478bd9Sstevel@tonic-gate 10639aa23310Srie if (relocate_lmc(&lml_main, ALIST_OFF_DATA, mlmp, 10649aa23310Srie mlmp, NULL) == 0) 10657c478bd9Sstevel@tonic-gate return (0); 10667c478bd9Sstevel@tonic-gate 10677c478bd9Sstevel@tonic-gate /* 1068dde769a2SRod Evans * Inform the debuggers that basic process initialization is 1069dde769a2SRod Evans * complete, and that the state of ld.so.1 (link-map lists, 1070dde769a2SRod Evans * etc.) is stable. This handshake enables the debugger to 1071dde769a2SRod Evans * initialize themselves, and consequently allows the user to 1072dde769a2SRod Evans * set break points in .init code. 1073dde769a2SRod Evans * 1074dde769a2SRod Evans * Most new debuggers use librtld_db to monitor activity events. 1075dde769a2SRod Evans * Older debuggers indicated their presence by setting the 1076dde769a2SRod Evans * DT_DEBUG entry in the dynamic executable (see elf_new_lm()). 1077dde769a2SRod Evans * In this case, getpid() is called so that the debugger can 1078dde769a2SRod Evans * catch the system call. This old mechanism has some 1079dde769a2SRod Evans * restrictions, as getpid() should not be called prior to 1080dde769a2SRod Evans * basic process initialization being completed. This 1081dde769a2SRod Evans * restriction has become increasingly difficult to maintain, 1082dde769a2SRod Evans * as the use of auditors, LD_DEBUG, and the initialization 1083dde769a2SRod Evans * handshake with libc can result in "premature" getpid() 1084dde769a2SRod Evans * calls. The use of this getpid() handshake is expected to 1085dde769a2SRod Evans * disappear at some point in the future, and there is intent 1086dde769a2SRod Evans * to work towards that goal. 10877c478bd9Sstevel@tonic-gate */ 10887c478bd9Sstevel@tonic-gate rd_event(&lml_main, RD_DLACTIVITY, RT_CONSISTENT); 108912b8e62eSrie rd_event(&lml_rtld, RD_DLACTIVITY, RT_CONSISTENT); 10907c478bd9Sstevel@tonic-gate 10917c478bd9Sstevel@tonic-gate if (rtld_flags & RT_FL_DEBUGGER) { 10927c478bd9Sstevel@tonic-gate r_debug.rtd_rdebug.r_flags |= RD_FL_ODBG; 10937c478bd9Sstevel@tonic-gate (void) getpid(); 10947c478bd9Sstevel@tonic-gate } 10957c478bd9Sstevel@tonic-gate } 10967c478bd9Sstevel@tonic-gate 10977c478bd9Sstevel@tonic-gate /* 109810a4fa49Srie * Indicate preinit activity, and call any auditing routines. These 109910a4fa49Srie * routines are called before initializing any threads via libc, or 110010a4fa49Srie * before collecting the complete set of .inits on the primary link-map. 110110a4fa49Srie * Although most libc interfaces are encapsulated in local routines 110210a4fa49Srie * within libc, they have been known to escape (ie. call a .plt). As 110310a4fa49Srie * the appcert auditor uses preinit as a trigger to establish some 110410a4fa49Srie * external interfaces to the main link-maps libc, we need to activate 110510a4fa49Srie * this trigger before exercising any code within libc. Additionally, 110610a4fa49Srie * I wouldn't put it past an auditor to add additional objects to the 110710a4fa49Srie * primary link-map. Hence, we collect .inits after the audit call. 11087c478bd9Sstevel@tonic-gate */ 11097c478bd9Sstevel@tonic-gate rd_event(&lml_main, RD_PREINIT, 0); 11107c478bd9Sstevel@tonic-gate 11112020b2b6SRod Evans if (aud_activity || 11122020b2b6SRod Evans ((lml_main.lm_tflags | AFLAGS(mlmp)) & LML_TFLG_AUD_ACTIVITY)) 11137c478bd9Sstevel@tonic-gate audit_activity(mlmp, LA_ACT_CONSISTENT); 11142020b2b6SRod Evans if (aud_preinit || 11152020b2b6SRod Evans ((lml_main.lm_tflags | AFLAGS(mlmp)) & LML_TFLG_AUD_PREINIT)) 11167c478bd9Sstevel@tonic-gate audit_preinit(mlmp); 11177c478bd9Sstevel@tonic-gate 111810a4fa49Srie /* 111910a4fa49Srie * If we're creating initial configuration information, we're done 112010a4fa49Srie * now that the auditing step has been called. 112110a4fa49Srie */ 112210a4fa49Srie if (rtld_flags & RT_FL_CONFGEN) { 11238cd45542Sraf leave(LIST(mlmp), 0); 112410a4fa49Srie return (mlmp); 112510a4fa49Srie } 112610a4fa49Srie 112710a4fa49Srie /* 112810a4fa49Srie * Sort the .init sections of all objects we've added. If we're 112910a4fa49Srie * tracing we only need to execute this under ldd(1) with the -i or -u 113010a4fa49Srie * options. 113110a4fa49Srie */ 113210a4fa49Srie lmflags = lml_main.lm_flags; 113310a4fa49Srie if (((lmflags & LML_FLG_TRC_ENABLE) == 0) || 113410a4fa49Srie (lmflags & (LML_FLG_TRC_INIT | LML_FLG_TRC_UNREF))) { 113510a4fa49Srie if ((tobj = tsort(mlmp, LIST(mlmp)->lm_init, 113610a4fa49Srie RT_SORT_REV)) == (Rt_map **)S_ERROR) 113710a4fa49Srie return (0); 113810a4fa49Srie } 113910a4fa49Srie 114010a4fa49Srie /* 114110a4fa49Srie * If we are tracing we're done. This is the one legitimate use of a 114210a4fa49Srie * direct call to rtldexit() rather than return, as we don't want to 114310a4fa49Srie * return and jump to the application. 114410a4fa49Srie */ 114510a4fa49Srie if (lmflags & LML_FLG_TRC_ENABLE) { 114610a4fa49Srie unused(&lml_main); 114710a4fa49Srie rtldexit(&lml_main, 0); 114810a4fa49Srie } 114910a4fa49Srie 1150b71d513aSedp /* 1151b71d513aSedp * Check if this instance of the linker should have a primary link 1152b71d513aSedp * map. This flag allows multiple copies of the -same- -version- 1153b71d513aSedp * of the linker (and libc) to run in the same address space. 1154b71d513aSedp * 1155b71d513aSedp * Without this flag we only support one copy of the linker in a 1156b71d513aSedp * process because by default the linker will always try to 1157b71d513aSedp * initialize at one primary link map The copy of libc which is 115808278a5eSRod Evans * initialized on a primary link map will initialize global TLS 1159b71d513aSedp * data which can be shared with other copies of libc in the 1160b71d513aSedp * process. The problem is that if there is more than one copy 1161b71d513aSedp * of the linker, only one copy should link libc onto a primary 1162b71d513aSedp * link map, otherwise libc will attempt to re-initialize global 1163b71d513aSedp * TLS data. So when a copy of the linker is loaded with this 1164b71d513aSedp * flag set, it will not initialize any primary link maps since 116508278a5eSRod Evans * presumably another copy of the linker will do this. 1166b71d513aSedp * 1167b71d513aSedp * Note that this flag only allows multiple copies of the -same- 1168b71d513aSedp * -version- of the linker (and libc) to coexist. This approach 1169b71d513aSedp * will not work if we are trying to load different versions of 1170b71d513aSedp * the linker and libc into the same process. The reason for 1171b71d513aSedp * this is that the format of the global TLS data may not be 1172b71d513aSedp * the same for different versions of libc. In this case each 1173b71d513aSedp * different version of libc must have it's own primary link map 1174b71d513aSedp * and be able to maintain it's own TLS data. The only way this 1175b71d513aSedp * can be done is by carefully managing TLS pointers on transitions 1176b71d513aSedp * between code associated with each of the different linkers. 1177b71d513aSedp * Note that this is actually what is done for processes in lx 1178b71d513aSedp * branded zones. Although in the lx branded zone case, the 1179b71d513aSedp * other linker and libc are actually gld and glibc. But the 1180b71d513aSedp * same general TLS management mechanism used by the lx brand 1181b71d513aSedp * would apply to any attempts to run multiple versions of the 1182b71d513aSedp * solaris linker and libc in a single process. 1183b71d513aSedp */ 1184b71d513aSedp if (auxflags & AF_SUN_NOPLM) 1185b71d513aSedp rtld_flags2 |= RT_FL2_NOPLM; 118656deab07SRod Evans 118710a4fa49Srie /* 118810a4fa49Srie * Establish any static TLS for this primary link-map. Note, regardless 118910a4fa49Srie * of whether TLS is available, an initial handshake occurs with libc to 119010a4fa49Srie * indicate we're processing the primary link-map. Having identified 119110a4fa49Srie * the primary link-map, initialize threads. 119210a4fa49Srie */ 119310a4fa49Srie if (rt_get_extern(&lml_main, mlmp) == 0) 119410a4fa49Srie return (0); 1195b71d513aSedp 1196b71d513aSedp if ((rtld_flags2 & RT_FL2_NOPLM) == 0) { 119710a4fa49Srie if (tls_statmod(&lml_main, mlmp) == 0) 119810a4fa49Srie return (0); 119910a4fa49Srie rt_thr_init(&lml_main); 120010a4fa49Srie rtld_flags2 |= RT_FL2_PLMSETUP; 1201b71d513aSedp } else { 1202b71d513aSedp rt_thr_init(&lml_main); 1203b71d513aSedp } 1204b71d513aSedp 120510a4fa49Srie /* 120610a4fa49Srie * Fire all dependencies .init sections. Identify any unused 120710a4fa49Srie * dependencies, and leave the runtime linker - effectively calling 120810a4fa49Srie * the dynamic executables entry point. 120910a4fa49Srie */ 12107c478bd9Sstevel@tonic-gate call_array(PREINITARRAY(mlmp), (uint_t)PREINITARRAYSZ(mlmp), mlmp, 12117c478bd9Sstevel@tonic-gate SHT_PREINIT_ARRAY); 12127c478bd9Sstevel@tonic-gate 12137c478bd9Sstevel@tonic-gate if (tobj) 12147c478bd9Sstevel@tonic-gate call_init(tobj, DBG_INIT_SORT); 12157c478bd9Sstevel@tonic-gate 12167c478bd9Sstevel@tonic-gate rd_event(&lml_main, RD_POSTINIT, 0); 12177c478bd9Sstevel@tonic-gate 12187c478bd9Sstevel@tonic-gate unused(&lml_main); 12197c478bd9Sstevel@tonic-gate 12205aefb655Srie DBG_CALL(Dbg_util_call_main(mlmp)); 12217c478bd9Sstevel@tonic-gate 12222020b2b6SRod Evans rtld_flags |= (RT_FL_OPERATION | RT_FL_APPLIC); 12232020b2b6SRod Evans 12248cd45542Sraf leave(LIST(mlmp), 0); 12257c478bd9Sstevel@tonic-gate 12267c478bd9Sstevel@tonic-gate return (mlmp); 12277c478bd9Sstevel@tonic-gate } 1228