xref: /titanic_51/usr/src/cmd/sgs/rtld/common/setup.c (revision ebb8ac078e9265f87093fbb363e8c2cbc6ee13e6)
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