6262333 init section of .so dlopened from audit interface not being called
authorrie
Tue, 18 Apr 2006 08:51:16 -0700
changeset 1824 9cc314774a20
parent 1823 6b91807505b7
child 1825 275e36049f94
6262333 init section of .so dlopened from audit interface not being called
usr/src/cmd/sgs/elfdump/Makefile.com
usr/src/cmd/sgs/include/debug.h
usr/src/cmd/sgs/include/rtld.h
usr/src/cmd/sgs/ld/common/lintsup.c
usr/src/cmd/sgs/libconv/Makefile.com
usr/src/cmd/sgs/libconv/common/dynamic.c
usr/src/cmd/sgs/libconv/common/dynamic.msg
usr/src/cmd/sgs/libcrle/Makefile.com
usr/src/cmd/sgs/libdl/common/llib-ldl
usr/src/cmd/sgs/libdl/common/mapfile-vers
usr/src/cmd/sgs/libelf/common/lintsup.c
usr/src/cmd/sgs/libelf/common/llib-lelf
usr/src/cmd/sgs/libld/Makefile.com
usr/src/cmd/sgs/libld/common/files.c
usr/src/cmd/sgs/liblddbg/common/liblddbg.msg
usr/src/cmd/sgs/liblddbg/common/llib-llddbg
usr/src/cmd/sgs/liblddbg/common/mapfile-vers
usr/src/cmd/sgs/liblddbg/common/unused.c
usr/src/cmd/sgs/liblddbg/common/util.c
usr/src/cmd/sgs/librtld_db/Makefile.com
usr/src/cmd/sgs/packages/common/SUNWonld-README
usr/src/cmd/sgs/pvs/Makefile.com
usr/src/cmd/sgs/rtld/amd64/Makefile
usr/src/cmd/sgs/rtld/common/_rtld.h
usr/src/cmd/sgs/rtld/common/analyze.c
usr/src/cmd/sgs/rtld/common/dlfcns.c
usr/src/cmd/sgs/rtld/common/elf.c
usr/src/cmd/sgs/rtld/common/external.c
usr/src/cmd/sgs/rtld/common/globals.c
usr/src/cmd/sgs/rtld/common/locale.c
usr/src/cmd/sgs/rtld/common/mapfile-vers
usr/src/cmd/sgs/rtld/common/mutex.c
usr/src/cmd/sgs/rtld/common/remove.c
usr/src/cmd/sgs/rtld/common/setup.c
usr/src/cmd/sgs/rtld/common/tls.c
usr/src/cmd/sgs/rtld/common/util.c
usr/src/cmd/sgs/rtld/i386/Makefile
usr/src/cmd/sgs/rtld/mdbmod/common/rtld.c
usr/src/cmd/sgs/rtld/mdbmod/common/rtld.msg
usr/src/cmd/sgs/rtld/sparc/Makefile
usr/src/cmd/sgs/rtld/sparcv9/Makefile
usr/src/cmd/sgs/rtld/sparcv9/sparc_elf.c
--- a/usr/src/cmd/sgs/elfdump/Makefile.com	Tue Apr 18 07:10:32 2006 -0700
+++ b/usr/src/cmd/sgs/elfdump/Makefile.com	Tue Apr 18 08:51:16 2006 -0700
@@ -46,7 +46,7 @@
 MAPFILE=	../common/mapfile-vers
 
 CPPFLAGS=	-I. -I../common -I../../include -I../../include/$(MACH) \
-		-I$(SRCBASE)/uts/$(ARCH)/sys \
+		-I$(SRCBASE)/lib/libc/inc -I$(SRCBASE)/uts/$(ARCH)/sys \
 		$(CPPFLAGS.master)
 LLDFLAGS =	$(VAR_ELFDUMP_LLDFLAGS)
 LLDFLAGS64 =	$(VAR_LD_LLDFLAGS64)
--- a/usr/src/cmd/sgs/include/debug.h	Tue Apr 18 07:10:32 2006 -0700
+++ b/usr/src/cmd/sgs/include/debug.h	Tue Apr 18 08:51:16 2006 -0700
@@ -353,6 +353,7 @@
 #define	Dbg_util_edge_in	Dbg64_util_edge_in
 #define	Dbg_util_edge_out	Dbg64_util_edge_out
 #define	Dbg_util_intoolate	Dbg64_util_intoolate
+#define	Dbg_util_lcinterface	Dbg64_util_lcinterface
 #define	Dbg_util_nl		Dbg64_util_nl
 #define	Dbg_util_no_init	Dbg64_util_no_init
 #define	Dbg_util_scc_entry	Dbg64_util_scc_entry
@@ -361,7 +362,7 @@
 #define	Dbg_util_wait		Dbg64_util_wait
 
 #define	Dbg_unused_file		Dbg64_unused_file
-#define	Dbg_unused_rtldinfo	Dbg64_unused_rtldinfo
+#define	Dbg_unused_lcinterface	Dbg64_unused_lcinterface
 #define	Dbg_unused_sec		Dbg64_unused_sec
 #define	Dbg_unused_unref	Dbg64_unused_unref
 
@@ -544,6 +545,7 @@
 #define	Dbg_util_edge_in	Dbg32_util_edge_in
 #define	Dbg_util_edge_out	Dbg32_util_edge_out
 #define	Dbg_util_intoolate	Dbg32_util_intoolate
+#define	Dbg_util_lcinterface	Dbg32_util_lcinterface
 #define	Dbg_util_nl		Dbg32_util_nl
 #define	Dbg_util_no_init	Dbg32_util_no_init
 #define	Dbg_util_scc_entry	Dbg32_util_scc_entry
@@ -552,7 +554,7 @@
 #define	Dbg_util_wait		Dbg32_util_wait
 
 #define	Dbg_unused_file		Dbg32_unused_file
-#define	Dbg_unused_rtldinfo	Dbg32_unused_rtldinfo
+#define	Dbg_unused_lcinterface	Dbg32_unused_lcinterface
 #define	Dbg_unused_sec		Dbg32_unused_sec
 #define	Dbg_unused_unref	Dbg32_unused_unref
 
@@ -777,6 +779,7 @@
 		    int, int);
 extern	void	Dbg_util_edge_out(Rt_map *, Rt_map *);
 extern	void	Dbg_util_intoolate(Rt_map *);
+extern	void	Dbg_util_lcinterface(Rt_map *, int, char *);
 extern	void	Dbg_util_nl(Lm_list *, int);
 extern	void	Dbg_util_no_init(Rt_map *);
 extern	void	Dbg_util_str(Lm_list *, const char *);
@@ -785,7 +788,7 @@
 extern	void	Dbg_util_wait(Rt_map *, Rt_map *, int);
 
 extern	void	Dbg_unused_file(Lm_list *, const char *, int, uint_t);
-extern	void	Dbg_unused_rtldinfo(Rt_map *);
+extern	void	Dbg_unused_lcinterface(Rt_map *, Rt_map *, int);
 extern	void	Dbg_unused_sec(Lm_list *, Is_desc *);
 extern	void	Dbg_unused_unref(Rt_map *, const char *);
 
--- a/usr/src/cmd/sgs/include/rtld.h	Tue Apr 18 07:10:32 2006 -0700
+++ b/usr/src/cmd/sgs/include/rtld.h	Tue Apr 18 08:51:16 2006 -0700
@@ -30,7 +30,7 @@
 #pragma ident	"%Z%%M%	%I%	%E% SMI"
 
 /*
- * Global include file for the runtime linker support library.
+ * Global include file for the runtime linker.
  */
 #include <time.h>
 #include <sgs.h>
@@ -39,6 +39,7 @@
 #include <machdep.h>
 #include <sys/avl.h>
 #include <alist.h>
+#include <libc_int.h>
 
 #ifdef	_SYSCALL32
 #include <inttypes.h>
@@ -83,14 +84,13 @@
 /*
  * Private structure for communication between rtld_db and rtld.
  *
- * 	We must bump the version number whenever a update in one of
- *	the structures/fields that rtld_db reads is updated.  This hopefully
- *	permits rtld_db implementations of the future recognize corefiles
- *	produced on older system and deal accordingly.
+ * We must bump the version number when ever an update in one of the
+ * structures/fields that rtld_db reads is updated.  This hopefully permits
+ * rtld_db implementations of the future to recognize core files produced on
+ * older systems and deal with these core files accordingly.
  *
- *	As of version 'RTLD_DB_VERSION <= 2' the following fields
- *	were valid for core file examination (basically the public
- *	Link_map):
+ * As of version 'RTLD_DB_VERSION <= 2' the following fields were valid for core
+ * file examination (basically the public Link_map):
  *
  *		ADDR()
  *		NAME()
@@ -98,7 +98,7 @@
  *		NEXT()
  *		PREV()
  *
- *	Valid fields for RTLD_DB_VERSION3
+ * Valid fields for RTLD_DB_VERSION3
  *
  *		PATHNAME()
  *		PADSTART()
@@ -107,18 +107,18 @@
  *		FLAGS()
  *		FLAGS1()
  *
- *	Valid fields for RTLD_DB_VERSION4
+ * Valid fields for RTLD_DB_VERSION4
  *
  *		TLSMODID()
  *
- *	Valid fields for RTLD_DB_VERSION5
+ * Valid fields for RTLD_DB_VERSION5
  *
  *		Added rtld_flags & FLG_RT_RELOCED to stable flags range
  *
  */
 #define	R_RTLDDB_VERSION1	1	/* base version level - used for core */
 					/*	file examination */
-#define	R_RTLDDB_VERSION2	2	/* minor revision - not relavant for */
+#define	R_RTLDDB_VERSION2	2	/* minor revision - not relevant for */
 					/*	core files */
 #define	R_RTLDDB_VERSION3	3
 #define	R_RTLDDB_VERSION4	4
@@ -141,6 +141,25 @@
 } Rtld_db_priv32;
 #endif	/* _SYSCALL32 */
 
+/*
+ * External function definitions.  ld.so.1 must convey information to libc in
+ * regards to threading.  libc also provides routines for atexit() and message
+ * localization.  libc provides the necessary interfaces via its RTLDINFO
+ * structure and/or later _ld_libc() calls.
+ *
+ * These external functions are maintained for each link-map list, and used
+ * where appropriate.  The functions are associated with the object that
+ * provided them, so that should the object be deleted (say, from an alternative
+ * link-map), the functions can be removed.
+ */
+typedef struct {
+	Rt_map	*lc_lmp;			/* function provider */
+	union {
+		int		(*lc_func)();	/* external function pointer */
+		uintptr_t	lc_val;		/* external value */
+		char    	*lc_ptr;	/* external character pointer */
+	} lc_un;
+} Lc_desc;
 
 /*
  * Link map list definition.  Link-maps are used to describe each loaded object.
@@ -248,10 +267,7 @@
 	/*
 	 * END: Exposed to rtld_db - don't move, don't delete
 	 */
-	int		(*lm_peh)();	/* atexit() preexec_exit_handlers */
-	Rt_map		*lm_peh_lmp;	/* and object that contributed them */
-	Rt_map		*lm_info_lmp;	/* the first object with rtld_info */
-	Alist		*lm_rtldinfo;	/* list of RTLDINFO tables */
+	Alist		*lm_rti;	/* list of RTLDINFO tables */
 	Audit_list	*lm_alp;	/* audit list descripter */
 	avl_tree_t	*lm_fpavl;	/* avl tree of objects loaded */
 	Alist		*lm_lists;	/* active and pending link-map lists */
@@ -260,8 +276,10 @@
 	uint_t		lm_obj;		/* total number of objs on link-map */
 	uint_t		lm_init;	/* new obj since last init processing */
 	uint_t		lm_lazy;	/* obj with pending lazy dependencies */
+	uint_t		lm_tls;		/* new obj that require TLS */
 	uint_t		lm_lmid;	/* unique link-map list identifier, */
 	char		*lm_lmidstr;	/* and associated diagnostic string */
+	Lc_desc		lm_lcs[CI_MAX];	/* external libc functions */
 };
 
 #ifdef	_SYSCALL32
@@ -276,10 +294,7 @@
 	/*
 	 * END: Exposed to rtld_db - don't move, don't delete
 	 */
-	Elf32_Addr	lm_peh;
-	Elf32_Addr	lm_peh_lmp;
-	Elf32_Addr	lm_info_lmp;
-	Elf32_Addr	lm_alp;
+	Elf32_Addr	lm_rti;
 	Elf32_Addr	lm_fpavl;
 	Elf32_Addr	lm_lists;
 	Elf32_Addr	lm_environ;
@@ -287,8 +302,10 @@
 	uint_t		lm_obj;
 	uint_t		lm_init;
 	uint_t		lm_lazy;
+	uint_t		lm_tls;
 	uint_t		lm_lmid;
 	Elf32_Addr	lm_lmidstr;
+	Elf32_Addr	lm_lcs[CI_MAX];
 };
 #endif /* _SYSCALL32 */
 
@@ -662,6 +679,8 @@
 #define	FL1_RT_SYMAFLTR	0x00008000	/*	or auxiliary filter */
 #define	MSK_RT_FILTER	0x0000f000	/* mask for all filter possibilites */
 
+#define	FL1_RT_TLSADD	0x00010000	/* objects TLS has been registered */
+
 /*
  * The following range of bits are reserved to hold LML_TFLG_AUD_ values
  * (although the definitions themselves aren't used anywhere).
--- a/usr/src/cmd/sgs/ld/common/lintsup.c	Tue Apr 18 07:10:32 2006 -0700
+++ b/usr/src/cmd/sgs/ld/common/lintsup.c	Tue Apr 18 08:51:16 2006 -0700
@@ -33,11 +33,11 @@
  */
 
 #include <stdlib.h>
-#include <debug.h>
+#include <stdio.h>
 #include "msg.h"
 
 void
 exit(int status)
 {
-	dbg_print(0, _ld_msg((Msg)&__ld_msg[0]), status);
+	(void) printf("%s: %d\n", _ld_msg((Msg)&__ld_msg[0]), status);
 }
--- a/usr/src/cmd/sgs/libconv/Makefile.com	Tue Apr 18 07:10:32 2006 -0700
+++ b/usr/src/cmd/sgs/libconv/Makefile.com	Tue Apr 18 08:51:16 2006 -0700
@@ -82,7 +82,7 @@
 
 PICS=		$(OBJECTS:%=pics/%)
 
-CPPFLAGS +=	-I$(ELFCAP) $(VAR_LIBCONV_CPPFLAGS)
+CPPFLAGS +=	-I$(SRCBASE)/lib/libc/inc -I$(ELFCAP) $(VAR_LIBCONV_CPPFLAGS)
 ARFLAGS=	cr
 
 AS_CPPFLAGS=	-P -D_ASM $(CPPFLAGS)
--- a/usr/src/cmd/sgs/libconv/common/dynamic.c	Tue Apr 18 07:10:32 2006 -0700
+++ b/usr/src/cmd/sgs/libconv/common/dynamic.c	Tue Apr 18 08:51:16 2006 -0700
@@ -327,6 +327,12 @@
 	return ((const char *)string);
 }
 
+/*
+ * Note, conv_bnd_obj() is called with either:
+ *	LML_FLG_OBJADDED (possibly with LML_FLG_OBJREEVAL added), or
+ *	LML_FLG_OBJDELETED, or
+ *	LML_FLG_ATEXIT.
+ */
 #define	BINDOSZ	MSG_GBL_OSQBRKT_SIZE + \
 		MSG_BND_ADDED_SIZE + \
 		MSG_BND_REEVAL_SIZE + \
@@ -344,8 +350,9 @@
 		{ 0,			0 }
 	};
 
-	if (flags == 0)
-		return (MSG_ORIG(MSG_STR_EMPTY));
+	if ((flags & (LML_FLG_OBJADDED | LML_FLG_OBJREEVAL |
+	    LML_FLG_OBJDELETED | LML_FLG_ATEXIT)) == 0)
+		return (MSG_ORIG(MSG_BND_REVISIT));
 
 	/*
 	 * Note, we're not worried about unknown flags for this family, only
--- a/usr/src/cmd/sgs/libconv/common/dynamic.msg	Tue Apr 18 07:10:32 2006 -0700
+++ b/usr/src/cmd/sgs/libconv/common/dynamic.msg	Tue Apr 18 08:51:16 2006 -0700
@@ -135,6 +135,8 @@
 @ MSG_BND_REEVAL	" OBJECTS-REEVALUATED "
 @ MSG_BND_DELETED	" OBJECTS-DELETED "
 @ MSG_BND_ATEXIT	" ATEXIT-PROCESSING "
+@ MSG_BND_REVISIT	"(revisiting)"
+
 @ MSG_STR_EMPTY		""
 
 @ MSG_GBL_ZERO		"0"
--- a/usr/src/cmd/sgs/libcrle/Makefile.com	Tue Apr 18 07:10:32 2006 -0700
+++ b/usr/src/cmd/sgs/libcrle/Makefile.com	Tue Apr 18 08:51:16 2006 -0700
@@ -2,9 +2,8 @@
 # CDDL HEADER START
 #
 # The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (the "License").  You may not use this file except in compliance
-# with the License.
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
 #
 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 # or http://www.opensolaris.org/os/licensing.
@@ -21,7 +20,7 @@
 #
 
 #
-# Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # ident	"%Z%%M%	%I%	%E% SMI"
@@ -55,6 +54,7 @@
 LINTFLAGS +=	-u
 LINTFLAGS64 +=	-u
 
+CPPFLAGS +=	-I$(SRCBASE)/lib/libc/inc
 DYNFLAGS +=	$(VERSREF) $(CONVLIBDIR) -lconv \
 		$(MAPOPTS) $(USE_PROTO)
 
--- a/usr/src/cmd/sgs/libdl/common/llib-ldl	Tue Apr 18 07:10:32 2006 -0700
+++ b/usr/src/cmd/sgs/libdl/common/llib-ldl	Tue Apr 18 08:51:16 2006 -0700
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -23,7 +22,7 @@
 /* PROTOLIB1 */
 
 /*
- * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -41,5 +40,4 @@
 int	dladdr1(void *, Dl_info *, void **, int);
 int	dldump(const char *, const char *, int);
 int	dlinfo(void *, int, void *);
-void	_ld_concurrency(void *);
 void	_ld_libc(void *);
--- a/usr/src/cmd/sgs/libdl/common/mapfile-vers	Tue Apr 18 07:10:32 2006 -0700
+++ b/usr/src/cmd/sgs/libdl/common/mapfile-vers	Tue Apr 18 08:51:16 2006 -0700
@@ -1,13 +1,9 @@
-#
-# Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
 #
 # CDDL HEADER START
 #
 # The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (the "License").  You may not use this file except in compliance
-# with the License.
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
 #
 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 # or http://www.opensolaris.org/os/licensing.
@@ -22,6 +18,11 @@
 #
 # CDDL HEADER END
 #
+
+#
+# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
 # ident	"%Z%%M%	%I%	%E% SMI"
 
 SUNW_1.4 {
@@ -50,7 +51,6 @@
 
 SUNWprivate_1.1 {
     global:
-	_ld_concurrency = FUNCTION;
 	_ld_libc = FUNCTION;
 	_dlinfo = FUNCTION;
 	_dldump = FUNCTION;
--- a/usr/src/cmd/sgs/libelf/common/lintsup.c	Tue Apr 18 07:10:32 2006 -0700
+++ b/usr/src/cmd/sgs/libelf/common/lintsup.c	Tue Apr 18 08:51:16 2006 -0700
@@ -32,3 +32,4 @@
 #include <malloc.h>
 #include <link.h>
 #include <sgs.h>
+#include <_libelf.h>
--- a/usr/src/cmd/sgs/libelf/common/llib-lelf	Tue Apr 18 07:10:32 2006 -0700
+++ b/usr/src/cmd/sgs/libelf/common/llib-lelf	Tue Apr 18 08:51:16 2006 -0700
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -23,7 +22,7 @@
 /* PROTOLIB1 */
 
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved. 
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved. 
  * Use is subject to license terms.
  */ 
 
@@ -106,6 +105,7 @@
 GElf_Cap *	gelf_getcap(Elf_Data *, int, GElf_Cap *);
 int		gelf_update_cap(Elf_Data *, int, GElf_Cap *);
 
+GElf_Xword	_gelf_getdyndtflags_1(Elf *);
 
 /*
  * Class-Independent Elf Symbols
--- a/usr/src/cmd/sgs/libld/Makefile.com	Tue Apr 18 07:10:32 2006 -0700
+++ b/usr/src/cmd/sgs/libld/Makefile.com	Tue Apr 18 08:51:16 2006 -0700
@@ -75,8 +75,9 @@
 DLLIB =		$(VAR_DL_LIB)
 package	:=	DLLIB = $(VAR_PKG_DL_LIB)
 
-CPPFLAGS +=	-DUSE_LIBLD_MALLOC -I$(SRCBASE)/uts/common/krtld \
-		    -I$(ELFCAP) $(VAR_LIBLD_CPPFLAGS)
+CPPFLAGS +=	-DUSE_LIBLD_MALLOC -I$(SRCBASE)/lib/libc/inc \
+		    -I$(SRCBASE)/uts/common/krtld -I$(ELFCAP) \
+		    $(VAR_LIBLD_CPPFLAGS)
 LDLIBS +=	$(CONVLIBDIR) $(CONV_LIB) $(LDDBGLIBDIR) $(LDDBG_LIB) \
 		    $(ELFLIBDIR) -lelf $(DLLIB) -lc
 
--- a/usr/src/cmd/sgs/libld/common/files.c	Tue Apr 18 07:10:32 2006 -0700
+++ b/usr/src/cmd/sgs/libld/common/files.c	Tue Apr 18 08:51:16 2006 -0700
@@ -353,7 +353,7 @@
 {
 	Cap	*cdata;
 
-	Dbg_cap_sec_title(ofl);
+	DBG_CALL(Dbg_cap_sec_title(ofl));
 
 	for (cdata = (Cap *)cisp->is_indata->d_buf;
 	    cdata->c_tag != CA_SUNW_NULL; cdata++) {
--- a/usr/src/cmd/sgs/liblddbg/common/liblddbg.msg	Tue Apr 18 07:10:32 2006 -0700
+++ b/usr/src/cmd/sgs/liblddbg/common/liblddbg.msg	Tue Apr 18 08:51:16 2006 -0700
@@ -545,7 +545,7 @@
 @ MSG_USD_UNREF		"file=%s  unreferenced: unused dependency of %s"
 @ MSG_USD_FILECYCLIC	"file=%s  unused: cyclic group [%d] member: \
 			 unreferenced outside of group"
-@ MSG_USD_RTLDINFO	"file=%s  unused RTLDINFO: using RTLDINFO \
+@ MSG_USD_LCINTERFACE	"file=%s  unused interface [%s]: using interface \
 			 from previously loaded object: file=%s"
 
 # Segment messages
@@ -688,6 +688,8 @@
 @ MSG_UTL_SCC_SUBI	"reverse load-order"
 @ MSG_UTL_SCC_SUBF	"load-order"
 
+@ MSG_UTL_LCINTERFACE	"file=%s;  provides interface [%s]: 0x%llx"
+
 # Generic strings
 
 @ MSG_STR_IGNORE	"ignored"
@@ -1204,3 +1206,17 @@
 # Syminfo formats
 
 @ MSG_SYMINFO_UNKFLAG	" 0x%x"
+
+# Lc_interface interface tags.
+
+@ MSG_CI_NULL		"NULL"
+@ MSG_CI_VERSION	"VERSION"
+@ MSG_CI_ATEXIT		"ATEXIT"
+@ MSG_CI_LCMESSAGES	"LCMESSAGES"
+@ MSG_CI_BIND_GUARD	"BIND_GUARD"
+@ MSG_CI_BIND_CLEAR	"BIND_CLEAR"
+@ MSG_CI_THR_SELF	"THR_SELF"
+@ MSG_CI_TLS_MODADD	"TLS_MODADD"
+@ MSG_CI_TLS_MODREM	"TLS_MODREM"
+@ MSG_CI_TLS_STATMOD	"TLS_STATMOD"
+@ MSG_CI_THRINIT	"THRINIT"
--- a/usr/src/cmd/sgs/liblddbg/common/llib-llddbg	Tue Apr 18 07:10:32 2006 -0700
+++ b/usr/src/cmd/sgs/liblddbg/common/llib-llddbg	Tue Apr 18 08:51:16 2006 -0700
@@ -388,6 +388,8 @@
 void	Dbg64_util_edge_out(Rt_map *, Rt_map *);
 void	Dbg32_util_intoolate(Rt_map *);
 void	Dbg64_util_intoolate(Rt_map *);
+void    Dbg32_util_lcinterface(Rt_map *, int, char *);
+void    Dbg64_util_lcinterface(Rt_map *, int, char *);
 void	Dbg32_util_nl(Lm_list *, int);
 void	Dbg64_util_nl(Lm_list *, int);
 void	Dbg32_util_no_init(Rt_map *);
@@ -403,8 +405,8 @@
 
 void	Dbg32_unused_file(Lm_list *, const char *, int, uint_t);
 void	Dbg64_unused_file(Lm_list *, const char *, int, uint_t);
-void	Dbg32_unused_rtldinfo(Rt_map *);
-void	Dbg64_unused_rtldinfo(Rt_map *);
+void    Dbg32_unused_lcinterface(Rt_map *, Rt_map *, int);
+void    Dbg64_unused_lcinterface(Rt_map *, Rt_map *, int);
 void	Dbg32_unused_sec(Lm_list *, Is_desc *);
 void	Dbg64_unused_sec(Lm_list *, Is_desc *);
 void	Dbg32_unused_unref(Rt_map *, const char *);
--- a/usr/src/cmd/sgs/liblddbg/common/mapfile-vers	Tue Apr 18 07:10:32 2006 -0700
+++ b/usr/src/cmd/sgs/liblddbg/common/mapfile-vers	Tue Apr 18 08:51:16 2006 -0700
@@ -38,7 +38,7 @@
 #	Policy for Shared Library Version Names and Interface Definitions
 
 
-SUNWprivate_4.50 {
+SUNWprivate_4.51 {
 	global:
 		dbg_desc = NODIRECT;	# interposed - ld.so.1(1)
 		dbg_print = NODIRECT;	# interposed - ld(1) and ld.so.1(1)
@@ -371,6 +371,8 @@
 		Dbg64_util_edge_in;
 		Dbg32_util_edge_out;
 		Dbg64_util_edge_out;
+		Dbg32_util_lcinterface;
+		Dbg64_util_lcinterface;
 		Dbg32_util_intoolate;
 		Dbg64_util_intoolate;
 		Dbg32_util_nl;
@@ -388,8 +390,8 @@
 
 		Dbg32_unused_file;
 		Dbg64_unused_file;
-		Dbg32_unused_rtldinfo;
-		Dbg64_unused_rtldinfo;
+		Dbg32_unused_lcinterface;
+		Dbg64_unused_lcinterface;
 		Dbg32_unused_sec;
 		Dbg64_unused_sec;
 		Dbg32_unused_unref;
--- a/usr/src/cmd/sgs/liblddbg/common/unused.c	Tue Apr 18 07:10:32 2006 -0700
+++ b/usr/src/cmd/sgs/liblddbg/common/unused.c	Tue Apr 18 08:51:16 2006 -0700
@@ -30,18 +30,6 @@
 #include	"libld.h"
 
 void
-Dbg_unused_rtldinfo(Rt_map *lmp)
-{
-	Lm_list	*lml = LIST(lmp);
-
-	if (DBG_NOTCLASS(DBG_C_UNUSED))
-		return;
-
-	dbg_print(lml, MSG_INTL(MSG_USD_RTLDINFO), NAME(lmp),
-	    NAME(lml->lm_info_lmp));
-}
-
-void
 Dbg_unused_unref(Rt_map *lmp, const char *depend)
 {
 	if (DBG_NOTCLASS(DBG_C_UNUSED))
--- a/usr/src/cmd/sgs/liblddbg/common/util.c	Tue Apr 18 07:10:32 2006 -0700
+++ b/usr/src/cmd/sgs/liblddbg/common/util.c	Tue Apr 18 08:51:16 2006 -0700
@@ -313,6 +313,56 @@
 	dbg_print(lml, MSG_INTL(MSG_UTL_COLLECT), ndx, NAME(lmp), str);
 }
 
+static const Msg	tags[] = {
+	MSG_CI_NULL,		/* MSG_ORIG(MSG_CI_NULL) */
+	MSG_CI_VERSION,		/* MSG_ORIG(MSG_CI_VERSION) */
+	MSG_CI_ATEXIT,		/* MSG_ORIG(MSG_CI_ATEXIT) */
+	MSG_CI_LCMESSAGES,	/* MSG_ORIG(MSG_CI_LCMESSAGES) */
+	MSG_CI_BIND_GUARD,	/* MSG_ORIG(MSG_CI_BIND_GUARD) */
+	MSG_CI_BIND_CLEAR,	/* MSG_ORIG(MSG_CI_BIND_CLEAR) */
+	MSG_CI_THR_SELF,	/* MSG_ORIG(MSG_CI_THR_SELF) */
+	MSG_CI_TLS_MODADD,	/* MSG_ORIG(MSG_CI_TLS_MODADD) */
+	MSG_CI_TLS_MODREM,	/* MSG_ORIG(MSG_CI_TLS_MODREM) */
+	MSG_CI_TLS_STATMOD,	/* MSG_ORIG(MSG_CI_TLS_STATMOD) */
+	MSG_CI_THRINIT		/* MSG_ORIG(MSG_CI_THRINIT) */
+};
+
+void
+Dbg_util_lcinterface(Rt_map *lmp, int tag, char *val)
+{
+	const char	*str;
+	static char	string[CONV_INV_STRSIZE];
+
+	if (DBG_NOTDETAIL())
+		return;
+
+	if (tag < CI_MAX)
+		str = MSG_ORIG(tags[tag]);
+	else
+		str = conv_invalid_val(string, CONV_INV_STRSIZE, tag, 0);
+
+	dbg_print(LIST(lmp), MSG_INTL(MSG_UTL_LCINTERFACE), NAME(lmp), str,
+	    EC_NATPTR(val));
+}
+
+void
+Dbg_unused_lcinterface(Rt_map *nlmp, Rt_map *olmp, int tag)
+{
+	const char	*str;
+	static char	string[CONV_INV_STRSIZE];
+
+	if (DBG_NOTCLASS(DBG_C_UNUSED))
+		return;
+
+	if (tag < CI_MAX)
+		str = MSG_ORIG(tags[tag]);
+	else
+		str = conv_invalid_val(string, CONV_INV_STRSIZE, tag, 0);
+
+	dbg_print(LIST(nlmp), MSG_INTL(MSG_USD_LCINTERFACE), NAME(nlmp), str,
+	    NAME(olmp));
+}
+
 /*
  * Generic new line generator.  To prevent multiple newlines from being
  * generated, a flag is maintained in the global debug descriptor.  This flag
--- a/usr/src/cmd/sgs/librtld_db/Makefile.com	Tue Apr 18 07:10:32 2006 -0700
+++ b/usr/src/cmd/sgs/librtld_db/Makefile.com	Tue Apr 18 08:51:16 2006 -0700
@@ -39,6 +39,7 @@
 
 MAPFILE=	../common/mapfile-vers
 
+CPPFLAGS +=	-I$(SRCBASE)/lib/libc/inc
 DYNFLAGS +=	-M$(MAPFILE) $(VERSREF)
 LDLIBS +=	$(CONVLIBDIR) $(CONV_LIB) -lc
 
--- a/usr/src/cmd/sgs/packages/common/SUNWonld-README	Tue Apr 18 07:10:32 2006 -0700
+++ b/usr/src/cmd/sgs/packages/common/SUNWonld-README	Tue Apr 18 08:51:16 2006 -0700
@@ -1098,3 +1098,4 @@
 6327926 ld does not set etext symbol correctly for AMD64 medium model (D)
 6390410 64-bit LD_PROFILE can fail: relocation error when binding profile plt
 6382945 AMD64-GCC: dbx: internal error: dwarf reference attribute out of bounds
+6262333 init section of .so dlopened from audit interface not being called
--- a/usr/src/cmd/sgs/pvs/Makefile.com	Tue Apr 18 07:10:32 2006 -0700
+++ b/usr/src/cmd/sgs/pvs/Makefile.com	Tue Apr 18 08:51:16 2006 -0700
@@ -38,6 +38,7 @@
 
 MAPFILE=	../common/mapfile-vers
 
+CPPFLAGS +=	-I$(SRCBASE)/lib/libc/inc
 LLDFLAGS =	'-R$$ORIGIN/../lib'
 LLDFLAGS64 =	'-R$$ORIGIN/../../lib/$(MACH64)'
 LDFLAGS +=	$(VERSREF) $(USE_PROTO) -M$(MAPFILE) $(LLDFLAGS)
--- a/usr/src/cmd/sgs/rtld/amd64/Makefile	Tue Apr 18 07:10:32 2006 -0700
+++ b/usr/src/cmd/sgs/rtld/amd64/Makefile	Tue Apr 18 08:51:16 2006 -0700
@@ -32,8 +32,8 @@
 # secondary lists (less frequently used code, ie. a.out support).
 
 P_COMOBJS=	debugdata.o \
-		analyze.o	elf.o		globals.o	malloc.o \
-		mutex.o		paths.o		setup.o		util.o \
+		analyze.o	elf.o		external.o	globals.o \
+		malloc.o 	paths.o		setup.o		util.o \
 		dlfcns.o	config_elf.o	locale.o	tsort.o \
 		getcwd.o	remove.o	move.o		tls.o \
 		cap.o
--- a/usr/src/cmd/sgs/rtld/common/_rtld.h	Tue Apr 18 07:10:32 2006 -0700
+++ b/usr/src/cmd/sgs/rtld/common/_rtld.h	Tue Apr 18 08:51:16 2006 -0700
@@ -309,6 +309,7 @@
 #define	RT_FL2_FTL2WARN	0x00000080	/* convert fatal to warning messages */
 #define	RT_FL2_BINDNOW	0x00000100	/* LD_BIND_NOW in effect */
 #define	RT_FL2_BINDLAZY	0x00000200	/* disable RTLD_NOW (and LD_BIND_NOW) */
+#define	RT_FL2_PLMSETUP	0x00000400	/* primary link-map set up complete */
 
 /*
  * Information flags for env_info.
@@ -320,7 +321,15 @@
 					/*	from configuration file */
 
 /*
- * Binding flags for the bindguard routines
+ * RTLDINFO descriptor.
+ */
+typedef struct {
+	Rt_map		*rti_lmp;	/* RTLDINFO provider */
+	Lc_interface	*rti_info;	/* RTLDINFO data */
+} Rti_desc;
+
+/*
+ * Binding flags for the bindguard routines.
  */
 #define	THR_FLG_RTLD	0x00000001	/* rtldlock bind_guard() flag */
 #define	THR_FLG_MASK	THR_FLG_RTLD	/* mask for all THR_FLG flags */
@@ -398,6 +407,8 @@
 /*
  * Data declarations.
  */
+extern Lc_desc		glcs[];		/* global external interfaces */
+
 extern Rt_lock		rtldlock;	/* rtld lock */
 
 extern List		dynlm_list;	/* dynamic list of link-maps */
@@ -479,8 +490,6 @@
 extern const char	*err_strs[];	/* diagnostic error string headers */
 extern const char	*nosym_str;	/* MSG_GEN_NOSYM message cache */
 
-extern void		(*thrinit)();	/* thread initialization */
-
 extern ulong_t		hwcap;		/* hardware capabilities */
 extern ulong_t		sfcap;		/* software capabilities */
 
@@ -601,8 +610,10 @@
 extern int		rt_cond_wait(Rt_cond *, Rt_lock *);
 extern int		rt_bind_guard(int);
 extern int		rt_bind_clear(int);
+extern int		rt_get_extern(Lm_list *, Rt_map *);
 extern int		rt_mutex_lock(Rt_lock *);
 extern int		rt_mutex_unlock(Rt_lock *);
+extern void		rt_thr_init(Lm_list *);
 extern thread_t		rt_thr_self(void);
 extern void		rtld_db_dlactivity(Lm_list *);
 extern void		rtld_db_preinit(Lm_list *);
@@ -617,9 +628,8 @@
 			    char **, int, uid_t, uid_t, gid_t, gid_t, void *,
 			    int, uint_t);
 extern void		tls_assign_soffset(Rt_map *);
-extern void		tls_setroutines(Lm_list *, void *, void *, void *);
-extern void		tls_modactivity(Rt_map *, uint_t);
-extern int		tls_report_modules();
+extern void		tls_modaddrem(Rt_map *, uint_t);
+extern int		tls_statmod(Lm_list *, Rt_map *);
 extern Rt_map		**tsort(Rt_map *, int, int);
 extern void		unused(Lm_list *);
 extern int		update_mode(Rt_map *, int, int);
--- a/usr/src/cmd/sgs/rtld/common/analyze.c	Tue Apr 18 07:10:32 2006 -0700
+++ b/usr/src/cmd/sgs/rtld/common/analyze.c	Tue Apr 18 08:51:16 2006 -0700
@@ -290,36 +290,11 @@
 		lml->lm_flags |= LML_FLG_OBJADDED;
 
 		/*
-		 * None of the following processing is necessary under ldd().
+		 * Process any move data (not necessary under ldd()).
 		 */
-		if ((lml->lm_flags & LML_FLG_TRC_ENABLE) == 0) {
-			/*
-			 * Process any move data.
-			 */
-			if (FLAGS(lmp) & FLG_RT_MOVE)
-				move_data(lmp);
-
-			/*
-			 * Process any DT_SUNW_RTLDINFO information now the
-			 * object is relocated, and remove the RTLDINFO
-			 * infrastructure as it won't be needed anymore.
-			 *
-			 * We wait until lmp == lm_info_lmp, as it's at this
-			 * stage we know the object contributing RTLDINFO has
-			 * been properly relocated.
-			 */
-			if ((FCT(lmp) == &elf_fct) && (lml->lm_rtldinfo) &&
-			    (lmp == lml->lm_info_lmp)) {
-				Aliste		off;
-				Lc_interface **	funcs;
-
-				for (ALIST_TRAVERSE(lml->lm_rtldinfo,
-				    off, funcs))
-					get_lcinterface(lmp, *funcs);
-				free(lml->lm_rtldinfo);
-				lml->lm_rtldinfo = 0;
-			}
-		}
+		if ((FLAGS(lmp) & FLG_RT_MOVE) &&
+		    ((lml->lm_flags & LML_FLG_TRC_ENABLE) == 0))
+			move_data(lmp);
 
 		/*
 		 * Determine if this object is a filter, and if a load filter
@@ -1196,7 +1171,7 @@
 					    &added) == 0)
 						return (0);
 					if (added)
-					    DBG_CALL(Dbg_file_skip(LIST(nlmp),
+					    DBG_CALL(Dbg_file_skip(LIST(clmp),
 						NAME(nlmp), nname));
 					fdesc->fd_nname = nname;
 					fdesc->fd_lmp = nlmp;
@@ -1231,7 +1206,7 @@
 				if ((nname[0] == '/') && (fpavl_insert(lml,
 				    nlmp, nname, 0) == 0))
 					return (0);
-				DBG_CALL(Dbg_file_skip(LIST(nlmp), NAME(nlmp),
+				DBG_CALL(Dbg_file_skip(LIST(clmp), NAME(nlmp),
 				    nname));
 			}
 			fdesc->fd_nname = nname;
@@ -1599,12 +1574,6 @@
 	 */
 	FLAGS(nlmp) |= FLG_RT_NEWLOAD;
 
-	/*
-	 * Report module loads to TLS module activity.
-	 */
-	if (nlmp)
-		tls_modactivity(nlmp, TM_FLG_MODADD);
-
 	return (nlmp);
 }
 
--- a/usr/src/cmd/sgs/rtld/common/dlfcns.c	Tue Apr 18 07:10:32 2006 -0700
+++ b/usr/src/cmd/sgs/rtld/common/dlfcns.c	Tue Apr 18 08:51:16 2006 -0700
@@ -605,45 +605,6 @@
 	    (path ? path : MSG_ORIG(MSG_STR_ZERO)), mode));
 
 	/*
-	 * Check for magic link-map list values:
-	 *
-	 *  LM_ID_BASE:		Operate on the PRIMARY (executables) link map
-	 *  LM_ID_LDSO:		Operation on ld.so.1's link map
-	 *  LM_ID_NEWLM: 	Create a new link-map.
-	 */
-	if (lml == (Lm_list *)LM_ID_NEWLM) {
-		if ((lml = calloc(sizeof (Lm_list), 1)) == 0)
-			return (0);
-
-		/*
-		 * Establish the new link-map flags from the callers and those
-		 * explicitly provided.
-		 */
-		lml->lm_tflags = LIST(clmp)->lm_tflags;
-		if (flags & FLG_RT_AUDIT) {
-			/*
-			 * Unset any auditing flags - an auditor shouldn't be
-			 * audited.  Insure all audit dependencies are loaded.
-			 */
-			lml->lm_tflags &= ~LML_TFLG_AUD_MASK;
-			lml->lm_tflags |=
-			    (LML_TFLG_NOLAZYLD | LML_TFLG_LOADFLTR);
-			lml->lm_flags |= LML_FLG_NOAUDIT;
-		}
-
-		if ((list_append(&dynlm_list, lml) == 0) ||
-		    (newlmid(lml) == 0)) {
-			free(lml);
-			return (0);
-		}
-	} else if ((uintptr_t)lml < LM_ID_NUM) {
-		if ((uintptr_t)lml == LM_ID_BASE)
-			lml = &lml_main;
-		else if ((uintptr_t)lml == LM_ID_LDSO)
-			lml = &lml_rtld;
-	}
-
-	/*
 	 * If the path specified is null then we're operating on global
 	 * objects.  Associate a dummy handle with the link-map list.
 	 */
@@ -782,9 +743,51 @@
 {
 	Rt_map	*dlmp = 0;
 	Grp_hdl	*ghp;
+	int	objcnt;
 
 	/*
-	 * Determine the link-map that has just been loaded.
+	 * Check for magic link-map list values:
+	 *
+	 *  LM_ID_BASE:		Operate on the PRIMARY (executables) link map
+	 *  LM_ID_LDSO:		Operation on ld.so.1's link map
+	 *  LM_ID_NEWLM: 	Create a new link-map.
+	 */
+	if (lml == (Lm_list *)LM_ID_NEWLM) {
+		if ((lml = calloc(sizeof (Lm_list), 1)) == 0)
+			return (0);
+
+		/*
+		 * Establish the new link-map flags from the callers and those
+		 * explicitly provided.
+		 */
+		lml->lm_tflags = LIST(clmp)->lm_tflags;
+		if (flags & FLG_RT_AUDIT) {
+			/*
+			 * Unset any auditing flags - an auditor shouldn't be
+			 * audited.  Insure all audit dependencies are loaded.
+			 */
+			lml->lm_tflags &= ~LML_TFLG_AUD_MASK;
+			lml->lm_tflags |=
+			    (LML_TFLG_NOLAZYLD | LML_TFLG_LOADFLTR);
+			lml->lm_flags |= LML_FLG_NOAUDIT;
+		}
+
+		if ((list_append(&dynlm_list, lml) == 0) ||
+		    (newlmid(lml) == 0)) {
+			free(lml);
+			return (0);
+		}
+	} else if ((uintptr_t)lml < LM_ID_NUM) {
+		if ((uintptr_t)lml == LM_ID_BASE)
+			lml = &lml_main;
+		else if ((uintptr_t)lml == LM_ID_LDSO)
+			lml = &lml_rtld;
+	}
+
+	objcnt = lml->lm_obj;
+
+	/*
+	 * Open the required object on the associated link-map list.
 	 */
 	if ((ghp = dlmopen_core(lml, path, mode, clmp, flags,
 	    (orig | PN_SER_DLOPEN))) != 0) {
@@ -802,7 +805,7 @@
 	 * trigger used() processing on return from a dlopen().
 	 */
 	if (loaded && dlmp)
-		*loaded = LIST(dlmp)->lm_init;
+		*loaded = lml->lm_obj - objcnt;
 
 	load_completion(dlmp, clmp);
 	return (ghp);
@@ -1236,7 +1239,6 @@
 	}
 
 	load_completion(llmp, clmp);
-
 	return (error);
 }
 
--- a/usr/src/cmd/sgs/rtld/common/elf.c	Tue Apr 18 07:10:32 2006 -0700
+++ b/usr/src/cmd/sgs/rtld/common/elf.c	Tue Apr 18 08:51:16 2006 -0700
@@ -2075,9 +2075,9 @@
 	 * dynamic structure.
 	 */
 	if (ld) {
-		uint_t	dyncnt = 0;
-		Xword	pltpadsz = 0;
-		void	*rtldinfo;
+		uint_t		dyncnt = 0;
+		Xword		pltpadsz = 0;
+		Rti_desc	*rti;
 
 		/* CSTYLED */
 		for ( ; ld->d_tag != DT_NULL; ++ld, dyncnt++) {
@@ -2322,29 +2322,22 @@
 				pltpadsz = ld->d_un.d_val;
 				break;
 			case DT_SUNW_RTLDINF:
-				if ((lml->lm_info_lmp != 0) &&
-				    (lml->lm_info_lmp != lmp)) {
-					DBG_CALL(Dbg_unused_rtldinfo(lmp));
-					break;
-				}
-				lml->lm_info_lmp = lmp;
-				rtldinfo = (void *)(ld->d_un.d_ptr + base);
-
 				/*
-				 * We maintain a list of DT_SUNW_RTLDINFO
-				 * structures for a given object.  This permits
-				 * the RTLDINFO structures to be grouped
-				 * functionly inside of a shared object.
-				 *
-				 * For example, we could have one for
-				 * thread_init, and another for atexit
-				 * reservations.
+				 * Maintain a list of RTLDINFO structures.
+				 * Typically, libc is the only supplier, and
+				 * only one structure is provided.  However,
+				 * multiple suppliers and multiple structures
+				 * are supported.  For example, one structure
+				 * may provide thread_init, and another
+				 * structure may provide atexit reservations.
 				 */
-				if (alist_append(&lml->lm_rtldinfo, &rtldinfo,
-				    sizeof (void *), AL_CNT_RTLDINFO) == 0) {
+				if ((rti = alist_append(&lml->lm_rti, 0,
+				    sizeof (Rti_desc), AL_CNT_RTLDINFO)) == 0) {
 					remove_so(0, lmp);
 					return (0);
 				}
+				rti->rti_lmp = lmp;
+				rti->rti_info = (void *)(ld->d_un.d_ptr + base);
 				break;
 			case DT_DEPRECATED_SPARC_REGISTER:
 			case M_DT_REGISTER:
@@ -2604,14 +2597,15 @@
 			if (pptr->p_align > align)
 				align = pptr->p_align;
 
-		} else if (pptr->p_type == PT_DYNAMIC)
+		} else if (pptr->p_type == PT_DYNAMIC) {
 			mld = (Dyn *)(pptr->p_vaddr);
-		else if (pptr->p_type == PT_TLS)
+		} else if ((pptr->p_type == PT_TLS) && pptr->p_memsz) {
 			tlph = pptr;
-		else if (pptr->p_type == PT_SUNWCAP)
+		} else if (pptr->p_type == PT_SUNWCAP) {
 			cap = (Cap *)(pptr->p_vaddr);
-		else if (pptr->p_type == PT_SUNW_UNWIND)
+		} else if (pptr->p_type == PT_SUNW_UNWIND) {
 			unwindph = pptr;
+		}
 	}
 
 #if defined(MAP_ALIGN)
@@ -2770,6 +2764,7 @@
 	if (tlph) {
 		PTTLS(lmp) = phdr + (tlph - phdr0);
 		tls_assign_soffset(lmp);
+		lml->lm_tls++;
 	}
 
 	if (unwindph)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/sgs/rtld/common/external.c	Tue Apr 18 08:51:16 2006 -0700
@@ -0,0 +1,527 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+/*
+ * Implementation of all external interfaces between ld.so.1 and libc.
+ *
+ * This file started as a set of routines that provided synchronization and
+ * locking operations using calls to libthread.  libthread has merged with libc,
+ * and things have gotten a little simpler.  This file continues to establish
+ * and redirect various events within ld.so.1 to interfaces within libc.
+ *
+ * Until libc is loaded and relocated, any external interfaces are captured
+ * locally.  Each link-map list maintains its own set of external vectors, as
+ * each link-map list typically provides its own libc.  Although this per-link-
+ * map list vectoring provides a degree of flexibility, there is a protocol
+ * expected when calling various libc interfaces.
+ *
+ * i.	Any new alternative link-map list should call CI_THRINIT, and then call
+ *	CI_TLS_MODADD to register any TLS for each object of that link-map list
+ *	(this item is labeled i. as auditors can be the first objects loaded,
+ *	and they exist on their own lik-map list).
+ *
+ * ii.	For the primary link-map list, CI_TLS_STATMOD must be called first to
+ *	register any static TLS.  This routine is called regardless of there
+ *	being any TLS, as this routine also establishes the link-map list as the
+ *	primary list and fixes the association of uberdata).  CI_THRINIT should
+ *	then be called.
+ *
+ * iii.	Any objects added to an existing link-map list (primary or alternative)
+ *	should call CI_TLS_MODADD to register any additional TLS.
+ *
+ * These events are established by:
+ *
+ * i.	Typically, libc is loaded as part of the primary dependencies of any
+ *	link-map list (since the Unified Process Model (UPM), libc can't be
+ *	lazily loaded).  To minimize the possibility of loading and registering
+ *	objects, and then tearing them down (because of a relocation error),
+ *	external vectors are established as part of load_completion().  This
+ *	routine is called on completion of any operation that can cause objects
+ *	to be loaded.  This point of control insures the objects have been fully
+ *	analyzed and relocated, and moved to their controlling link-map list.
+ *	The external vectors are established prior to any .inits being fired.
+ *
+ * ii.	Calls to CI_THRINIT, and CI_TLS_MODADD also occur as part of
+ *	load_completion().  CI_THRINIT is only called once for each link-map
+ *	control list.
+ *
+ * iii.	Calls to CI_TLS_STATMOD, and CI_THRINIT occur for the primary link-map
+ *	list in the final stages of setup().
+ *
+ * The interfaces provide by libc can be divided into two families.  The first
+ * family consists of those interfaces that should be called from the link-map
+ * list.  It's possible that these interfaces convey state concerning the
+ * link-map list they are part of:
+ *
+ *	CI_ATEXIT
+ *	CI TLS_MODADD
+ *	CI_TLS_MODREM
+ *	CI_TLS_STATMOD
+ *	CI_THRINIT
+ *
+ * The second family are global in nature, that is, the link-map list from
+ * which they are called provides no state information.  In fact, for
+ * CI_BIND_GUARD, the calling link-map isn't even known.  The link-map can only
+ * be deduced after ld.so.1's global lock has been obtained.  Therefore, the
+ * following interfaces are also maintained as global:
+ *
+ *	CI_LCMESSAGES
+ *	CI_BIND_GUARD
+ *	CI_BIND_CLEAR
+ *	CI_THR_SELF
+ *
+ * Note, it is possible that these global interfaces are obtained from an
+ * alternative link-map list that gets torn down because of a processing
+ * failure (unlikely, because the link-map list components must be analyzed
+ * and relocated prior to load_completion(), but perhaps the tear down is still
+ * a possibility).  Thus the global interfaces may have to be replaced.  Once
+ * the interfaces have been obtained from the primary link-map, they can
+ * remain fixed, as the primary link-map isn't going to go anywhere.
+ *
+ * The last wrinkle in the puzzle is what happens if an alternative link-map
+ * is loaded with no libc dependency?  In this case, the alternative objects
+ * can not call CI_THRINIT, can not be allowed to use TLS, and will not receive
+ * any atexit processing.
+ *
+ * The history of these external interfaces is defined by their version:
+ *
+ * TI_VERSION == 1
+ *	Under this model libthread provided rw_rwlock/rw_unlock, through which
+ *	all rt_mutex_lock/rt_mutex_unlock calls were vectored.
+ *	Under libc/libthread these interfaces provided _sigon/_sigoff (unlike
+ *	lwp/libthread that provided signal blocking via bind_guard/bind_clear).
+ *
+ * TI_VERSION == 2
+ *	Under this model only libthreads bind_guard/bind_clear and thr_self
+ *	interfaces were used.  Both libthreads blocked signals under the
+ *	bind_guard/bind_clear interfaces.   Lower level locking is derived
+ *	from internally bound _lwp_ interfaces.  This removes recursive
+ *	problems encountered when obtaining locking interfaces from libthread.
+ *	The use of mutexes over reader/writer locks also enables the use of
+ *	condition variables for controlling thread concurrency (allows access
+ *	to objects only after their .init has completed).
+ *
+ * NOTE, the TI_VERSION indicated the ti_interface version number, where the
+ * ti_interface was a large vector of functions passed to both libc (to override
+ * the thread stub interfaces) and ld.so.1.  ld.so.1 used only a small subset of
+ * these interfaces.
+ *
+ * CI_VERSION == 1
+ *	Introduced with CI_VERSION & CI_ATEXIT
+ *
+ * CI_VERSION == 2 (Solaris 8 update 2).
+ *	Added support for CI_LCMESSAGES
+ *
+ * CI_VERSION == 3 (Solaris 9).
+ *	Added the following versions to the CI table:
+ *
+ *		CI_BIND_GUARD, CI_BIND_CLEAR, CI_THR_SELF
+ *		CI_TLS_MODADD, CI_TLS_MOD_REMOVE, CI_TLS_STATMOD
+ *
+ *	This version introduced the DT_SUNW_RTLDINFO structure as a mechanism
+ *	to handshake with ld.so.1.
+ *
+ * CI_VERSION == 4 (Solaris 10).
+ *	Added the CI_THRINIT handshake as part of the libc/libthread unified
+ *	process model.  libc now initializes the current thread pointer from
+ *	this interface (and no longer relies on the INITFIRST flag - which
+ *	others have started to camp out on).
+ *
+ * Release summary:
+ *
+ *	Solaris 8	CI_ATEXIT via _ld_libc()
+ *			TI_* via _ld_concurrency()
+ *
+ *	Solaris 9	CI_ATEXIT and CI_LCMESSAGES via _ld_libc()
+ *			CI_* via RTLDINFO and _ld_libc()  - new libthread
+ *			TI_* via _ld_concurrency()  - old libthread
+ *
+ *	Solaris 10	CI_ATEXIT and CI_LCMESSAGES via _ld_libc()
+ *			CI_* via RTLDINFO and _ld_libc()  - new libthread
+ */
+#include	"_synonyms.h"
+
+#include	<sys/debug.h>
+#include	<synch.h>
+#include	<signal.h>
+#include	<thread.h>
+#include	<synch.h>
+#include	<strings.h>
+#include	<stdio.h>
+#include	<debug.h>
+#include	<libc_int.h>
+#include	"_elf.h"
+#include	"_rtld.h"
+
+/*
+ * This interface provides the unified process model communication between
+ * ld.so.1 and libc.  This interface is supplied through RTLDINFO.
+ */
+void
+get_lcinterface(Rt_map *lmp, Lc_interface *funcs)
+{
+	int		tag, threaded = 0;
+	Lm_list		*lml;
+	Lc_desc		*lcp;
+
+	if ((lmp == 0) || (funcs == 0))
+		return;
+
+	lml = LIST(lmp);
+	lcp = &lml->lm_lcs[0];
+
+	DBG_CALL(Dbg_util_nl(lml, DBG_NL_STD));
+
+	for (tag = funcs->ci_tag; tag; tag = (++funcs)->ci_tag) {
+		char	*gptr;
+		char	*lptr = funcs->ci_un.ci_ptr;
+
+		DBG_CALL(Dbg_util_lcinterface(lmp, tag, lptr));
+
+		if (tag >= CI_MAX)
+			continue;
+
+		/*
+		 * Maintain all interfaces on a per-link-map basis.  Note, for
+		 * most interfaces, only the first interface is used for any
+		 * link-map list.  This prevents accidents with developers who
+		 * manage to load two different versions of libc.
+		 */
+		if ((lcp[tag].lc_lmp) &&
+		    (tag != CI_LCMESSAGES) && (tag != CI_VERSION)) {
+			DBG_CALL(Dbg_unused_lcinterface(lmp,
+			    lcp[tag].lc_lmp, tag));
+			continue;
+		}
+
+		lcp[tag].lc_un.lc_ptr = lptr;
+		lcp[tag].lc_lmp = lmp;
+
+		gptr = glcs[tag].lc_un.lc_ptr;
+
+		/*
+		 * Process any interfaces that must be maintained on a global
+		 * basis.
+		 */
+		switch (tag) {
+		case CI_ATEXIT:
+			break;
+
+		case CI_LCMESSAGES:
+			/*
+			 * At startup, ld.so.1 can establish a locale from one
+			 * of the locale family of environment variables (see
+			 * ld_str_env() and readenv_user()).  During process
+			 * execution the locale can also be changed by the user.
+			 * This interface is called from libc should the locale
+			 * be modified.  Presently, only one global locale is
+			 * maintained for all link-map lists, and only objects
+			 * on the primrary link-map may change this locale.
+			 */
+			if ((lml->lm_flags & LML_FLG_BASELM) &&
+			    ((gptr == 0) || (strcmp(gptr, lptr) != 0))) {
+				/*
+				 * If we've obtained a message locale (typically
+				 * supplied via libc's setlocale()), then
+				 * register the locale for use in dgettext() so
+				 * as to reestablish the locale for ld.so.1's
+				 * messages.
+				 */
+				if (gptr) {
+					free((void *)gptr);
+					rtld_flags |= RT_FL_NEWLOCALE;
+				}
+				glcs[tag].lc_un.lc_ptr = strdup(lptr);
+
+				/*
+				 * Clear any cached messages.
+				 */
+				err_strs[ERR_NONE] = 0;
+				err_strs[ERR_WARNING] = 0;
+				err_strs[ERR_FATAL] = 0;
+				err_strs[ERR_ELF] = 0;
+
+				nosym_str = 0;
+			}
+			break;
+
+		case CI_BIND_GUARD:
+		case CI_BIND_CLEAR:
+		case CI_THR_SELF:
+			/*
+			 * If the global vector is unset, or this is the primary
+			 * link-map, set the global vector.
+			 */
+			if ((gptr == 0) || (lml->lm_flags & LML_FLG_BASELM))
+				glcs[tag].lc_un.lc_ptr = lptr;
+
+			/* FALLTHROUGH */
+
+		case CI_TLS_MODADD:
+		case CI_TLS_MODREM:
+		case CI_TLS_STATMOD:
+		case CI_THRINIT:
+			threaded++;
+			break;
+
+		case CI_VERSION:
+			if ((rtld_flags2 & RT_FL2_RTLDSEEN) == 0) {
+				rtld_flags2 |= RT_FL2_RTLDSEEN;
+
+				if (funcs->ci_un.ci_val >= CI_V_FOUR) {
+					Listnode	*lnp;
+					Lm_list		*lml2;
+
+					rtld_flags2 |= RT_FL2_UNIFPROC;
+
+					/*
+					 * We might have seen auditor which is
+					 * not dependent on libc.  Such an
+					 * auditor's link map list has
+					 * LML_FLG_HOLDLOCK set.  This lock
+					 * needs to be dropped.  Refer to
+					 * audit_setup() in audit.c.
+					 */
+					if ((rtld_flags2 & RT_FL2_HASAUDIT) ==
+					    0)
+					break;
+
+					/*
+					 * Yes, we did. Take care of them.
+					 */
+					for (LIST_TRAVERSE(&dynlm_list, lnp,
+					    lml2)) {
+						Rt_map *map =
+						    (Rt_map *)lml2->lm_head;
+
+						if (FLAGS(map) & FLG_RT_AUDIT) {
+							lml2->lm_flags &=
+							    ~LML_FLG_HOLDLOCK;
+						}
+					}
+				}
+			}
+			break;
+
+		default:
+			break;
+		}
+	}
+
+	if (threaded == 0)
+		return;
+
+	/*
+	 * If a version of libc gives us only a subset of the TLS interfaces -
+	 * it's confused and we discard the whole lot.
+	 */
+	if ((lcp[CI_TLS_MODADD].lc_un.lc_func &&
+	    lcp[CI_TLS_MODREM].lc_un.lc_func &&
+	    lcp[CI_TLS_STATMOD].lc_un.lc_func) == 0) {
+		lcp[CI_TLS_MODADD].lc_un.lc_func = 0;
+		lcp[CI_TLS_MODREM].lc_un.lc_func = 0;
+		lcp[CI_TLS_STATMOD].lc_un.lc_func = 0;
+	}
+
+	/*
+	 * Indicate that we're now thread capable, and enable concurrency if
+	 * requested.
+	 */
+	if ((rtld_flags & RT_FL_NOCONCUR) == 0)
+		rtld_flags |= RT_FL_CONCUR;
+	if ((lml->lm_flags & LML_FLG_RTLDLM) == 0)
+		rtld_flags |= RT_FL_THREADS;
+}
+
+/*
+ * At this point we know we have a set of objects that have been fully analyzed
+ * and relocated.  Prior to the next major step of running .init sections (ie.
+ * running user code), retrieve any RTLDINFO interfaces.
+ */
+int
+rt_get_extern(Lm_list *lml, Rt_map *lmp)
+{
+	if (lml->lm_rti) {
+		Aliste		off;
+		Rti_desc	*rti;
+
+		for (ALIST_TRAVERSE(lml->lm_rti, off, rti))
+			get_lcinterface(rti->rti_lmp, rti->rti_info);
+
+		free(lml->lm_rti);
+		lml->lm_rti = 0;
+	}
+
+	/*
+	 * Perform some sanity checks.  If we have TLS requirements we better
+	 * have the associated external interfaces.
+	 */
+	if (lml->lm_tls && (lml->lm_lcs[CI_TLS_STATMOD].lc_un.lc_func == 0)) {
+		eprintf(lml, ERR_FATAL, MSG_INTL(MSG_ERR_TLS_NOTLS),
+		    NAME(lmp));
+		return (0);
+	}
+	return (1);
+}
+
+static int	bindmask = 0;
+
+int
+rt_bind_guard(int bindflag)
+{
+	int	(*fptr)(int);
+
+	if ((fptr = glcs[CI_BIND_GUARD].lc_un.lc_func) != NULL) {
+		return ((*fptr)(bindflag));
+	} else {
+		if ((bindflag & bindmask) == 0) {
+			bindmask |= bindflag;
+			return (1);
+		}
+		return (0);
+	}
+}
+
+int
+rt_bind_clear(int bindflag)
+{
+	int	(*fptr)(int);
+
+	if ((fptr = glcs[CI_BIND_CLEAR].lc_un.lc_func) != NULL) {
+		return ((*fptr)(bindflag));
+	} else {
+		if (bindflag == 0)
+			return (bindmask);
+		else {
+			bindmask &= ~bindflag;
+			return (0);
+		}
+	}
+}
+
+/*
+ * Make sure threads have been initialized.  This interface is called once for
+ * each link-map list.
+ */
+void
+rt_thr_init(Lm_list *lml)
+{
+	void	(*fptr)(void);
+
+	if ((fptr = (void (*)())lml->lm_lcs[CI_THRINIT].lc_un.lc_func) != 0) {
+		lml->lm_lcs[CI_THRINIT].lc_un.lc_func = 0;
+		leave((Lm_list *)0);
+		(*fptr)();
+		(void) enter();
+	}
+}
+
+thread_t
+rt_thr_self()
+{
+	thread_t	(*fptr)(void);
+
+	if ((fptr = (thread_t (*)())glcs[CI_THR_SELF].lc_un.lc_func) != NULL)
+		return ((*fptr)());
+
+	return (1);
+}
+
+int
+rt_mutex_lock(Rt_lock * mp)
+{
+	return (_lwp_mutex_lock((lwp_mutex_t *)mp));
+}
+
+int
+rt_mutex_unlock(Rt_lock * mp)
+{
+	return (_lwp_mutex_unlock((lwp_mutex_t *)mp));
+}
+
+Rt_cond *
+rt_cond_create()
+{
+	return (calloc(1, sizeof (Rt_cond)));
+}
+
+int
+rt_cond_wait(Rt_cond * cvp, Rt_lock * mp)
+{
+	return (_lwp_cond_wait(cvp, (lwp_mutex_t *)mp));
+}
+
+int
+rt_cond_broadcast(Rt_cond * cvp)
+{
+	return (_lwp_cond_broadcast(cvp));
+}
+
+#ifdef	EXPAND_RELATIVE
+
+/*
+ * Mutex interfaces to resolve references from any objects extracted from
+ * libc_pic.a.  Note, as ld.so.1 is essentially single threaded these can be
+ * noops.
+ */
+#pragma weak lmutex_lock = __mutex_lock
+#pragma weak _private_mutex_lock = __mutex_lock
+#pragma weak mutex_lock = __mutex_lock
+#pragma weak _mutex_lock = __mutex_lock
+/* ARGSUSED */
+int
+__mutex_lock(mutex_t *mp)
+{
+	return (0);
+}
+
+#pragma weak lmutex_unlock = __mutex_unlock
+#pragma weak _private_mutex_unlock = __mutex_unlock
+#pragma weak mutex_unlock = __mutex_unlock
+#pragma weak _mutex_unlock = __mutex_unlock
+/* ARGSUSED */
+int
+__mutex_unlock(mutex_t *mp)
+{
+	return (0);
+}
+
+/*
+ * This is needed to satisfy sysconf() (case _SC_THREAD_STACK_MIN)
+ */
+#pragma weak thr_min_stack = _thr_min_stack
+size_t
+_thr_min_stack()
+{
+#ifdef _LP64
+	return (8 * 1024);
+#else
+	return (4 * 1024);
+#endif
+}
+
+#endif	/* EXPAND_RELATIVE */
--- a/usr/src/cmd/sgs/rtld/common/globals.c	Tue Apr 18 07:10:32 2006 -0700
+++ b/usr/src/cmd/sgs/rtld/common/globals.c	Tue Apr 18 08:51:16 2006 -0700
@@ -59,8 +59,6 @@
 
 Reglist *	reglist = 0;			/* list of register symbols */
 
-void		(*thrinit)() = 0;		/* thread initialization */
-
 ulong_t		hwcap = 0;			/* hardware capabilities */
 ulong_t		sfcap = 0;			/* software capabilities */
 
@@ -99,6 +97,8 @@
 /*
  * Various other global data.
  */
+Lc_desc		glcs[CI_MAX];		/* global external interfaces */
+
 const char	*procname = (const char *)0;
 const char	*rtldname = MSG_ORIG(MSG_FIL_RTLD);
 
@@ -117,8 +117,6 @@
 					/*	is all) */
 Audit_desc	*auditors = 0;		/* global auditors (LD_AUDIT) */
 
-const char	*locale = 0;		/* locale environment definition */
-
 const char	*rpl_audit = 0;		/* replaceable LD_AUDIT string */
 const char	*rpl_debug = 0;		/* replaceable LD_DEBUG string */
 const char	*rpl_ldflags = 0;	/* replaceable LD_FLAGS string */
--- a/usr/src/cmd/sgs/rtld/common/locale.c	Tue Apr 18 07:10:32 2006 -0700
+++ b/usr/src/cmd/sgs/rtld/common/locale.c	Tue Apr 18 08:51:16 2006 -0700
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -19,8 +18,9 @@
  *
  * CDDL HEADER END
  */
+
 /*
- * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 #pragma ident	"%Z%%M%	%I%	%E% SMI"
@@ -153,7 +153,7 @@
 	dom->dom_msghdr = (Msghdr *)-1;
 
 	(void) snprintf(path, PATH_MAX, MSG_ORIG(MSG_FMT_MSGFILE),
-		locale, domain);
+		glcs[CI_LCMESSAGES].lc_un.lc_ptr, domain);
 
 	if ((fd = open(path, O_RDONLY, 0)) == -1)
 		return;
@@ -222,7 +222,7 @@
 	Domain		*_domain;
 	int		cnt;
 
-	if (locale == 0)
+	if (glcs[CI_LCMESSAGES].lc_un.lc_val == 0)
 		return (msgid);
 
 	/*
--- a/usr/src/cmd/sgs/rtld/common/mapfile-vers	Tue Apr 18 07:10:32 2006 -0700
+++ b/usr/src/cmd/sgs/rtld/common/mapfile-vers	Tue Apr 18 08:51:16 2006 -0700
@@ -60,7 +60,6 @@
 		_dlsym;
 		 dlsym;
 
-		_ld_concurrency;	# Provides libthread initialization
 		_ld_libc;		# provides libc initialization
 
 		_elf_rtbndr;		# dbx expects to find these
--- a/usr/src/cmd/sgs/rtld/common/mutex.c	Tue Apr 18 07:10:32 2006 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,524 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- */
-/*
- *	Copyright 2001-2003 Sun Microsystems, Inc.  All rights reserved.
- *	Use is subject to license terms.
- */
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
-/*
- * Implementation of all threads interfaces between ld.so.1 and libthread.
- *
- * In a non-threaded environment all thread interfaces are vectored to noops.
- * When called via _ld_concurrency() from libthread these vectors are reassigned
- * to real threads interfaces.  Two models are supported:
- *
- * TI_VERSION == 1
- *	Under this model libthread provides rw_rwlock/rw_unlock, through which
- *	we vector all rt_mutex_lock/rt_mutex_unlock calls.
- *	Under lib/libthread these interfaces provided _sigon/_sigoff (unlike
- *	lwp/libthread that provided signal blocking via bind_guard/bind_clear.
- *
- * TI_VERSION == 2
- *	Under this model only libthreads bind_guard/bind_clear and thr_self
- *	interfaces are used.  Both libthreads block signals under the
- *	bind_guard/bind_clear interfaces.   Lower level locking is derived
- *	from internally bound _lwp_ interfaces.  This removes recursive
- *	problems encountered when obtaining locking interfaces from libthread.
- *	The use of mutexes over reader/writer locks also enables the use of
- *	condition variables for controlling thread concurrency (allows access to
- *	objects only after their .init has completed).
- *
- * CI_VERSION == 1
- *	introduced with CI_VERSION & CI_ATEXIT
- *
- * CI_VERSION == 2
- *	add support for CI_LCMESSAGES
- *
- * CI_VERSION == 3
- *	Add the following versions to the CI table:
- *
- *		CI_BIND_GUARD, CI_BIND_CLEAR, CI_THR_SELF
- *		CI_TLS_MODADD, CI_TLS_MOD_REMOVE, CI_TLS_STATMOD
- *
- *	It was also at this level that the DT_SUNW_RTLDINFO structure
- *	was introduced as a mechanism to handshake with ld.so.1
- *
- * CI_VERSION == 4
- *	  Added the CI_THRINIT handshake as part of the libc/libthread
- *	  merge project.  libc now initializes the current thread pointer
- *	  (%g7 for sparc) as part of this and no longer relies on the
- *	  INITFIRST flag (which others have started to camp out on).
- */
-#include	"_synonyms.h"
-
-#include	<synch.h>
-#include	<signal.h>
-#include	<thread.h>
-#include	<synch.h>
-#include	<strings.h>
-#include	<stdio.h>
-#include	"thr_int.h"
-#include	"_elf.h"
-#include	"_rtld.h"
-
-/*
- * Define our own local mutex functions.
- */
-static int	bindmask = THR_FLG_RTLD;
-
-static int
-_rt_bind_guard(int bit)
-{
-	if ((bit & bindmask) == 0) {
-		bindmask |= bit;
-		return (1);
-	}
-	return (0);
-}
-
-static int
-_rt_bind_clear(int bit)
-{
-	if (bit == 0)
-		return (bindmask);
-	else {
-		bindmask &= ~bit;
-		return (0);
-	}
-}
-
-static int
-_rt_thr_self()
-{
-	return (1);
-}
-
-static int
-_rt_null()
-{
-	return (0);
-}
-
-#if	(defined(DEBUG) || defined(SGS_PRE_UNIFIED_PROCESS))
-/*
- * These three routines are used to protect the locks that ld.so.1 has.
- * They are passed to pthread_atfork() and used during a fork1() to make
- * sure we do not do a fork while a lock is being held.
- */
-static void
-prepare_atfork(void)
-{
-	(void) rt_bind_guard(THR_FLG_MASK);
-	(void) rt_mutex_lock(&rtldlock);
-}
-
-static void
-child_atfork(void)
-{
-	(void) rt_mutex_unlock(&rtldlock);
-	(void) rt_bind_clear(THR_FLG_MASK);
-}
-
-static void
-parent_atfork(void)
-{
-	(void) rt_mutex_unlock(&rtldlock);
-	(void) rt_bind_clear(THR_FLG_MASK);
-}
-#endif
-
-/*
- * Define the maximum number of thread interfaces ld.so.1 is interested in,
- * this is a subset of the total number of interfaces communicated between
- * libthread and libc.
- */
-#define	STI_MAX			11
-
-/*
- * Define our own thread jump table.
- */
-#define	RT_BIND_GUARD		0
-#define	RT_BIND_CLEAR		1
-#define	RT_THR_SELF		2
-#define	RT_MUTEX_LOCK		3
-#define	RT_MUTEX_UNLOCK		4
-#define	RT_COND_WAIT		5
-#define	RT_COND_BROAD		6
-
-#define	SRT_MAX			7
-
-static int (*	thr_jmp_table[SRT_MAX])() = {
-	_rt_bind_guard,				/* RT_BIND_GUARD */
-	_rt_bind_clear,				/* RT_BIND_CLEAR */
-	_rt_thr_self,				/* RT_THR_SELF */
-	_rt_null,				/* RT_MUTEX_LOCK */
-	_rt_null,				/* RT_MUTEX_UNLOCK */
-	_rt_null,				/* RT_COND_WAIT */
-	_rt_null				/* RT_COND_BROAD */
-};
-
-#if	(defined(DEBUG) || defined(SGS_PRE_UNIFIED_PROCESS))
-static int (*	thr_def_table[SRT_MAX])() = {
-	_rt_bind_guard,				/* RT_BIND_GUARD */
-	_rt_bind_clear,				/* RT_BIND_CLEAR */
-	_rt_thr_self,				/* RT_THR_SELF */
-	_rt_null,				/* RT_MUTEX_LOCK */
-	_rt_null,				/* RT_MUTEX_UNLOCK */
-	_rt_null,				/* RT_COND_WAIT */
-	_rt_null				/* RT_COND_BROAD */
-};
-#endif
-
-/*
- * The interface with the threads library which is supplied through libdl.so.1.
- * A non-null argument allows a function pointer array to be passed to us which
- * is used to re-initialize the linker concurrency table.  A null argument
- * causes the table to be reset to the defaults.
- */
-void
-/* ARGSUSED */
-_ld_concurrency(void * ptr)
-{
-#if	(defined(DEBUG) || defined(SGS_PRE_UNIFIED_PROCESS))
-	int		tag;
-	Thr_interface *	funcs = ptr;
-
-	if (funcs) {
-		int (*	table[STI_MAX])();
-
-		/*
-		 * Collect all the threads interfaces we're interested in.
-		 */
-		table[TI_LATFORK] = NULL;
-		for (tag = funcs->ti_tag; tag; tag = (++funcs)->ti_tag) {
-			if (tag < STI_MAX)
-				table[tag] = funcs->ti_un.ti_func;
-		}
-
-		/*
-		 * At this point we've re-entered ld.so.1 from libthreads .init.
-		 * All locks are down.  Exercise any common thread interfaces
-		 * before we remap ld.so.1 to use them, this allows us to be
-		 * re-entered to resolve .plt's without exercising locks.
-		 */
-		(void) (*table[TI_BIND_GUARD])(THR_FLG_RTLD);
-		(void) (*table[TI_BIND_CLEAR])(THR_FLG_RTLD);
-		(void) (*table[TI_THRSELF])();
-
-		/*
-		 * Prepare atfork, if necessary.
-		 */
-		if (table[TI_LATFORK])
-			(void) (*table[TI_LATFORK])(prepare_atfork,
-			    parent_atfork, child_atfork);
-
-		/*
-		 * Establish what interfaces are available for this version of
-		 * libthread and make them live.
-		 */
-		if (table[TI_VERSION] == (int (*)())1) {
-			/*
-			 * Restrict ourselves to the readers/writers locks.
-			 */
-			(void) (*table[TI_LRW_WRLOCK])(&rtldlock);
-			(void) (*table[TI_LRW_UNLOCK])(&rtldlock);
-
-			thr_jmp_table[RT_MUTEX_LOCK] = table[TI_LRW_WRLOCK];
-			thr_jmp_table[RT_MUTEX_UNLOCK] = table[TI_LRW_UNLOCK];
-		} else {
-			/*
-			 * Go directly to our internal interfaces.
-			 */
-			thr_jmp_table[RT_MUTEX_LOCK] = _lwp_mutex_lock;
-			thr_jmp_table[RT_MUTEX_UNLOCK] = _lwp_mutex_unlock;
-			thr_jmp_table[RT_COND_WAIT] = _lwp_cond_wait;
-			thr_jmp_table[RT_COND_BROAD] = _lwp_cond_broadcast;
-
-			/*
-			 * If concurrency is requested inable it now.
-			 */
-			if ((rtld_flags & RT_FL_NOCONCUR) == 0)
-				rtld_flags |= RT_FL_CONCUR;
-		}
-
-		/*
-		 * Make all common interfaces go live.
-		 */
-		thr_jmp_table[RT_BIND_CLEAR] = table[TI_BIND_CLEAR];
-		thr_jmp_table[RT_BIND_GUARD] = table[TI_BIND_GUARD];
-		thr_jmp_table[RT_THR_SELF] = table[TI_THRSELF];
-
-		rtld_flags |= RT_FL_THREADS;
-
-	} else {
-		/*
-		 * If libthread were to be dlclosed() we'd get here to reset
-		 * our interfaces back to the internal noops (as libthread
-		 * typically can't be dlclosed() it's unlikely we'll ever
-		 * exercise this.  If a bindlock is currently in place clear it.
-		 */
-		if (rt_bind_clear(0x0) & THR_FLG_RTLD) {
-			(void) rt_mutex_unlock(&rtldlock);
-			(void) rt_bind_clear(THR_FLG_RTLD);
-		}
-		rtld_flags &= ~RT_FL_THREADS;
-		for (tag = 0; tag < SRT_MAX; tag++)
-			thr_jmp_table[tag] = thr_def_table[tag];
-	}
-#endif
-}
-
-void
-get_lcinterface(Rt_map *lmp, Lc_interface *funcs)
-{
-	int		tag;
-	char		*nlocale;
-	void		*tlsmodadd = 0;
-	void		*tlsmodrem = 0;
-	void		*tlsstatmod = 0;
-	Lm_list		*lml, *lml2;
-	Listnode	*lnp;
-
-	if (!funcs || !lmp)
-		return;
-
-	lml = LIST(lmp);
-
-	for (tag = funcs->ci_tag; tag; tag = (++funcs)->ci_tag) {
-		switch (tag) {
-		case CI_ATEXIT:
-			/*
-			 * If we obtained a _preexec_exit_handlers()
-			 * call back (typically supplied via libc's
-			 * .init) then register it for use in dlclose().
-			 */
-			if (lml->lm_peh == 0) {
-				lml->lm_peh = funcs->ci_un.ci_func;
-				lml->lm_peh_lmp = lmp;
-			}
-			break;
-		case CI_LCMESSAGES:
-			/*
-			 * If we've obtained a message locale (typically
-			 * supplied via libc's setlocale()) then
-			 * register it for use in dgettext() to
-			 * reestablish a locale for ld.so.1's messages.
-			 */
-			if (lml->lm_flags & LML_FLG_BASELM) {
-				nlocale = funcs->ci_un.ci_ptr;
-				if ((locale == 0) ||
-				    strcmp(locale, nlocale)) {
-					if (locale) {
-						free((void *)locale);
-						rtld_flags |= RT_FL_NEWLOCALE;
-					}
-					locale = strdup(nlocale);
-
-					/*
-					 * Clear any cached messages.
-					 */
-					err_strs[ERR_NONE] = 0;
-					err_strs[ERR_WARNING] = 0;
-					err_strs[ERR_FATAL] = 0;
-					err_strs[ERR_ELF] = 0;
-
-					nosym_str = 0;
-				}
-			}
-			break;
-		case CI_BIND_GUARD:
-			thr_jmp_table[RT_BIND_GUARD] =
-				(int(*)())funcs->ci_un.ci_ptr;
-			/*
-			 * Go directly to our internal interfaces.
-			 */
-			thr_jmp_table[RT_MUTEX_LOCK] = _lwp_mutex_lock;
-			thr_jmp_table[RT_MUTEX_UNLOCK] = _lwp_mutex_unlock;
-			thr_jmp_table[RT_COND_WAIT] = _lwp_cond_wait;
-			thr_jmp_table[RT_COND_BROAD] = _lwp_cond_broadcast;
-
-			/*
-			 * If concurrency is requested inable it now.
-			 */
-			if ((rtld_flags & RT_FL_NOCONCUR) == 0)
-				rtld_flags |= RT_FL_CONCUR;
-			rtld_flags |= RT_FL_THREADS;
-			break;
-		case CI_BIND_CLEAR:
-			thr_jmp_table[RT_BIND_CLEAR] =
-				(int(*)()) funcs->ci_un.ci_ptr;
-			break;
-		case CI_THR_SELF:
-			thr_jmp_table[RT_THR_SELF] =
-				(int(*)()) funcs->ci_un.ci_ptr;
-			break;
-		case CI_TLS_MODADD:
-			tlsmodadd = funcs->ci_un.ci_ptr;
-			break;
-		case CI_TLS_MODREM:
-			tlsmodrem = funcs->ci_un.ci_ptr;
-			break;
-		case CI_TLS_STATMOD:
-			tlsstatmod = funcs->ci_un.ci_ptr;
-			break;
-#ifdef	CI_THRINIT
-		case CI_THRINIT:
-			thrinit = (void(*)())funcs->ci_un.ci_ptr;
-			break;
-#endif
-#ifdef	CI_V_FOUR
-		case CI_VERSION:
-			if ((rtld_flags2 & RT_FL2_RTLDSEEN) == 0) {
-			    rtld_flags2 |= RT_FL2_RTLDSEEN;
-			    if (funcs->ci_un.ci_val >= CI_V_FOUR) {
-				rtld_flags2 |= RT_FL2_UNIFPROC;
-
-				/*
-				 * We might have seen auditor which
-				 * is not dependent on libc. Such auditor's
-				 * link map list has LML_FLG_HOLDLOCK on.
-				 * It needs to be dropped. Refer to:
-				 *	audit_setup() in audit.c.
-				 */
-				if ((rtld_flags2 & RT_FL2_HASAUDIT) == 0)
-					break;
-
-				/*
-				 * Yes, we did. Take care of them.
-				 */
-				for (LIST_TRAVERSE(&dynlm_list, lnp, lml2)) {
-					Rt_map *map = (Rt_map *)lml2->lm_head;
-
-					if (FLAGS(map) & FLG_RT_AUDIT) {
-						lml2->lm_flags &=
-							~LML_FLG_HOLDLOCK;
-					}
-				}
-			    }
-			}
-			break;
-#endif
-		default:
-			break;
-		}
-	}
-	if (tlsmodadd && tlsmodrem && tlsstatmod)
-		tls_setroutines(lml, tlsmodadd, tlsmodrem, tlsstatmod);
-}
-
-/*
- * Define the local interface for each of the threads interfaces.
- */
-thread_t
-rt_thr_self()
-{
-	return ((* thr_jmp_table[RT_THR_SELF])());
-}
-
-int
-rt_mutex_lock(Rt_lock * mp)
-{
-	return ((* thr_jmp_table[RT_MUTEX_LOCK])(mp));
-}
-
-int
-rt_mutex_unlock(Rt_lock * mp)
-{
-	return ((* thr_jmp_table[RT_MUTEX_UNLOCK])(mp));
-}
-
-int
-rt_bind_guard(int bindflag)
-{
-	return ((* thr_jmp_table[RT_BIND_GUARD])(bindflag));
-}
-
-int
-rt_bind_clear(int bindflag)
-{
-	return ((* thr_jmp_table[RT_BIND_CLEAR])(bindflag));
-}
-
-Rt_cond *
-rt_cond_create()
-{
-	return (calloc(1, sizeof (Rt_cond)));
-}
-
-int
-rt_cond_wait(Rt_cond * cvp, Rt_lock * mp)
-{
-	return ((* thr_jmp_table[RT_COND_WAIT])(cvp, mp));
-}
-
-int
-rt_cond_broadcast(Rt_cond * cvp)
-{
-	return ((* thr_jmp_table[RT_COND_BROAD])(cvp));
-}
-
-#ifdef	EXPAND_RELATIVE
-
-/*
- * Mutex interfaces to resolve references from any objects extracted from
- * libc_pic.a.  Note, as ld.so.1 is essentially single threaded these can be
- * noops.
- */
-
-#pragma weak lmutex_lock = __mutex_lock
-#pragma weak _private_mutex_lock = __mutex_lock
-#pragma weak mutex_lock = __mutex_lock
-#pragma weak _mutex_lock = __mutex_lock
-/* ARGSUSED */
-int
-__mutex_lock(mutex_t *mp)
-{
-	return (0);
-}
-
-#pragma weak lmutex_unlock = __mutex_unlock
-#pragma weak _private_mutex_unlock = __mutex_unlock
-#pragma weak mutex_unlock = __mutex_unlock
-#pragma weak _mutex_unlock = __mutex_unlock
-/* ARGSUSED */
-int
-__mutex_unlock(mutex_t *mp)
-{
-	return (0);
-}
-
-/*
- * This is needed to satisfy sysconf() (case _SC_THREAD_STACK_MIN)
- */
-#pragma weak thr_min_stack = _thr_min_stack
-size_t
-_thr_min_stack()
-{
-#ifdef _LP64
-	return (8 * 1024);
-#else
-	return (4 * 1024);
-#endif
-}
-
-#endif	/* EXPAND_RELATIVE */
--- a/usr/src/cmd/sgs/rtld/common/remove.c	Tue Apr 18 07:10:32 2006 -0700
+++ b/usr/src/cmd/sgs/rtld/common/remove.c	Tue Apr 18 08:51:16 2006 -0700
@@ -76,11 +76,12 @@
 	Rt_map			**_tobj;
 	Lc_addr_range_t		*addr, *_addr;
 	int			error;
+	int			(*fptr)(Lc_addr_range_t *, uint_t);
 
 	/*
 	 * Has a callback been established?
 	 */
-	if (lml->lm_peh == 0)
+	if ((fptr = lml->lm_lcs[CI_ATEXIT].lc_un.lc_func) == NULL)
 		return (0);
 
 	/*
@@ -120,9 +121,7 @@
 	_addr->lb = _addr->ub = 0;
 
 	leave(LIST(*tobj));
-
-	error = (* lml->lm_peh)(addr, (num - 1));
-
+	error = (*fptr)(addr, (num - 1));
 	(void) enter();
 
 	/*
@@ -191,11 +190,11 @@
 			free(lml->lm_lists);
 
 		/*
-		 * Cleanup rtldinfo in the case where it was allocated but
-		 * not called (see _relocate_so()).
+		 * Cleanup any pending RTLDINFO in the case where it was
+		 * allocated but not called (see _relocate_lmc()).
 		 */
-		if (lml->lm_rtldinfo)
-			free(lml->lm_rtldinfo);
+		if (lml->lm_rti)
+			free(lml->lm_rti);
 		if (lml->lm_fpavl) {
 			/*
 			 * As we are freeing the link-map list, all nodes must
@@ -235,13 +234,25 @@
 		lm_delete(lml, lmp);
 
 	/*
-	 * If this object contributed the preexec_exit_handler() routine for
-	 * the current link-map list, mark the list as no-longer containing a
-	 * preexec_exit_handler() routine.
+	 * If this object contributed any local external vectors for the current
+	 * link-map list, remove the vectors.  If this object contributed any
+	 * global external vectors we should find some new candidates, or leave
+	 * this object lying around.
 	 */
-	if (lml && (lml->lm_peh_lmp == lmp)) {
-		lml->lm_peh = 0;
-		lml->lm_peh_lmp = 0;
+	if (lml) {
+		int	tag;
+
+		for (tag = 0; tag < CI_MAX; tag++) {
+			if (lml->lm_lcs[tag].lc_lmp == lmp) {
+				lml->lm_lcs[tag].lc_lmp = 0;
+				lml->lm_lcs[tag].lc_un.lc_val = 0;
+			}
+			if (glcs[tag].lc_lmp == lmp) {
+				ASSERT(glcs[tag].lc_lmp != 0);
+				glcs[tag].lc_lmp = 0;
+				glcs[tag].lc_un.lc_val = 0;
+			}
+		}
 	}
 
 	DBG_CALL(Dbg_file_delete(lmp));
@@ -1291,7 +1302,7 @@
 			 * Complete the link-map deletion if appropriate.
 			 */
 			if (FLAGS(lmp) & FLG_RT_DELETE) {
-				tls_modactivity(lmp, TM_FLG_MODREM);
+				tls_modaddrem(lmp, TM_FLG_MODREM);
 				remove_so(LIST(lmp), lmp);
 			}
 		}
--- a/usr/src/cmd/sgs/rtld/common/setup.c	Tue Apr 18 07:10:32 2006 -0700
+++ b/usr/src/cmd/sgs/rtld/common/setup.c	Tue Apr 18 08:51:16 2006 -0700
@@ -176,6 +176,7 @@
 	size_t		eaddr, esize;
 	char		*str, *argvname;
 	Mmap		*mmaps;
+	Word		lmflags;
 
 	/*
 	 * Now that ld.so has relocated itself, initialize our own 'environ' so
@@ -612,14 +613,16 @@
 					mmaps[mmapcnt].m_perm = perm;
 					mmapcnt++;
 
-				} else if (pptr->p_type == PT_DYNAMIC)
+				} else if (pptr->p_type == PT_DYNAMIC) {
 					dyn = (Dyn *)(pptr->p_vaddr + base);
-				else if (pptr->p_type == PT_TLS)
+				} else if ((pptr->p_type == PT_TLS) &&
+				    pptr->p_memsz) {
 					tlsphdr = pptr;
-				else if (pptr->p_type == PT_SUNW_UNWIND)
+				} else if (pptr->p_type == PT_SUNW_UNWIND) {
 					unwindphdr = pptr;
-				else if (pptr->p_type == PT_SUNWCAP)
+				} else if (pptr->p_type == PT_SUNWCAP) {
 					cap = (Cap *)(pptr->p_vaddr + base);
+				}
 				pptr = (Phdr *)((ulong_t)pptr + phsize);
 			}
 
@@ -639,6 +642,7 @@
 			if (tlsphdr) {
 				PTTLS(mlmp) = tlsphdr;
 				tls_assign_soffset(mlmp);
+				lml_main.lm_tls++;
 			}
 			if (unwindphdr)
 				PTUNWIND(mlmp) = unwindphdr;
@@ -948,7 +952,6 @@
 	 * loaded.
 	 */
 	if ((rtld_flags & RT_FL_CONFGEN) == 0) {
-		Word	lmflags;
 
 		DBG_CALL(Dbg_util_nl(&lml_main, DBG_NL_STD));
 
@@ -956,29 +959,6 @@
 			return (0);
 
 		/*
-		 * Sort the .init sections of all objects we've added.  If
-		 * we're tracing we only need to execute this under ldd(1)
-		 * with the -i or -u options.
-		 */
-		lmflags = lml_main.lm_flags;
-		if (((lmflags & LML_FLG_TRC_ENABLE) == 0) ||
-		    (lmflags & (LML_FLG_TRC_INIT | LML_FLG_TRC_UNREF))) {
-			if ((tobj = tsort(mlmp, LIST(mlmp)->lm_init,
-			    RT_SORT_REV)) == (Rt_map **)S_ERROR)
-				return (0);
-		}
-
-		/*
-		 * If we are tracing we're done.  This is the one legitimate use
-		 * of a direct call to rtldexit() rather than return, as we
-		 * don't want to return and jump to the application.
-		 */
-		if (lmflags & LML_FLG_TRC_ENABLE) {
-			unused(&lml_main);
-			rtldexit(&lml_main, 0);
-		}
-
-		/*
 		 * Inform the debuggers we're here and stable.  Newer debuggers
 		 * can indicate their presence by setting the DT_DEBUG entry in
 		 * the dynamic executable (see elf_new_lm()).  In this case call
@@ -993,20 +973,20 @@
 			r_debug.rtd_rdebug.r_flags |= RD_FL_ODBG;
 			(void) getpid();
 		}
-
-		/*
-		 * Initialize any initial TLS storage.
-		 */
-		if (tls_report_modules() == 0)
-			return (0);
 	}
 
 	/*
-	 * Call any necessary auditing routines, clean up any file descriptors
-	 * and such, and then fire all dependencies .init sections.
+	 * Indicate preinit activity, and call any auditing routines.  These
+	 * routines are called before initializing any threads via libc, or
+	 * before collecting the complete set of .inits on the primary link-map.
+	 * Although most libc interfaces are encapsulated in local routines
+	 * within libc, they have been known to escape (ie. call a .plt).  As
+	 * the appcert auditor uses preinit as a trigger to establish some
+	 * external interfaces to the main link-maps libc, we need to activate
+	 * this trigger before exercising any code within libc.  Additionally,
+	 * I wouldn't put it past an auditor to add additional objects to the
+	 * primary link-map.  Hence, we collect .inits after the audit call.
 	 */
-	rtld_flags |= RT_FL_APPLIC;
-
 	rd_event(&lml_main, RD_PREINIT, 0);
 
 	if ((lml_main.lm_tflags | FLAGS1(mlmp)) & LML_TFLG_AUD_ACTIVITY)
@@ -1014,6 +994,59 @@
 	if ((lml_main.lm_tflags | FLAGS1(mlmp)) & LML_TFLG_AUD_PREINIT)
 		audit_preinit(mlmp);
 
+	/*
+	 * If we're creating initial configuration information, we're done
+	 * now that the auditing step has been called.
+	 */
+	if (rtld_flags & RT_FL_CONFGEN) {
+		leave(LIST(mlmp));
+		return (mlmp);
+	}
+
+	/*
+	 * Sort the .init sections of all objects we've added.  If we're
+	 * tracing we only need to execute this under ldd(1) with the -i or -u
+	 * options.
+	 */
+	lmflags = lml_main.lm_flags;
+	if (((lmflags & LML_FLG_TRC_ENABLE) == 0) ||
+	    (lmflags & (LML_FLG_TRC_INIT | LML_FLG_TRC_UNREF))) {
+		if ((tobj = tsort(mlmp, LIST(mlmp)->lm_init,
+		    RT_SORT_REV)) == (Rt_map **)S_ERROR)
+			return (0);
+	}
+
+	/*
+	 * If we are tracing we're done.  This is the one legitimate use of a
+	 * direct call to rtldexit() rather than return, as we don't want to
+	 * return and jump to the application.
+	 */
+	if (lmflags & LML_FLG_TRC_ENABLE) {
+		unused(&lml_main);
+		rtldexit(&lml_main, 0);
+	}
+
+	/*
+	 * Establish any static TLS for this primary link-map.  Note, regardless
+	 * of whether TLS is available, an initial handshake occurs with libc to
+	 * indicate we're processing the primary link-map.  Having identified
+	 * the primary link-map, initialize threads.
+	 */
+	if (rt_get_extern(&lml_main, mlmp) == 0)
+		return (0);
+	if (tls_statmod(&lml_main, mlmp) == 0)
+		return (0);
+
+	rt_thr_init(&lml_main);
+
+	rtld_flags2 |= RT_FL2_PLMSETUP;
+	rtld_flags |= RT_FL_APPLIC;
+
+	/*
+	 * Fire all dependencies .init sections.  Identify any unused
+	 * dependencies, and leave the runtime linker - effectively calling
+	 * the dynamic executables entry point.
+	 */
 	call_array(PREINITARRAY(mlmp), (uint_t)PREINITARRAYSZ(mlmp), mlmp,
 		SHT_PREINIT_ARRAY);
 
--- a/usr/src/cmd/sgs/rtld/common/tls.c	Tue Apr 18 07:10:32 2006 -0700
+++ b/usr/src/cmd/sgs/rtld/common/tls.c	Tue Apr 18 08:51:16 2006 -0700
@@ -36,13 +36,7 @@
 #include <msg.h>
 #include <debug.h>
 
-
-static void (*	fptr_tls_modadd)(TLS_modinfo *) = 0;
-static void (*	fptr_tls_modrem)(TLS_modinfo *) = 0;
-static void (*	fptr_tls_statmods)(TLS_modinfo **, unsigned long) = 0;
-
-static int	tlsinitialized = 0;
-static unsigned long tls_static_size = 0;	/* static TLS buffer size */
+static ulong_t	tls_static_size = 0;	/* static TLS buffer size */
 
 #define	TLSBLOCKCNT	16	/* number of blocks of tmi_bits to allocate */
 				/* at a time. */
@@ -54,16 +48,15 @@
 
 static Tlsmodid	tmid = {0, 0, 0};
 
-unsigned long
+ulong_t
 tls_getmodid()
 {
 	ulong_t		ndx;
 	ulong_t		i;
 
 	if (tmid.tmi_bits == 0) {
-		if ((tmid.tmi_bits =
-		    (uint_t *)calloc(TLSBLOCKCNT, sizeof (uint_t))) == 0)
-			return ((unsigned long)-1);
+		if ((tmid.tmi_bits = calloc(TLSBLOCKCNT, sizeof (uint_t))) == 0)
+			return ((ulong_t)-1);
 		tmid.tmi_bits[0] = 1;
 		tmid.tmi_lowfree = 1;
 		tmid.tmi_cnt = TLSBLOCKCNT;
@@ -91,12 +84,13 @@
 	/*
 	 * All bits taken - must allocate a new block
 	 */
-	if ((tmid.tmi_bits = (uint_t *)realloc(tmid.tmi_bits,
+	if ((tmid.tmi_bits = realloc(tmid.tmi_bits,
 	    ((tmid.tmi_cnt * sizeof (uint_t)) +
 	    (TLSBLOCKCNT * sizeof (uint_t))))) == 0)
-		return ((unsigned long)-1);
+		return ((ulong_t)-1);
+
 	/*
-	 * clear out the tail of the new allocation
+	 * Clear out the tail of the new allocation.
 	 */
 	bzero(&(tmid.tmi_bits[tmid.tmi_cnt]), TLSBLOCKCNT * sizeof (uint_t));
 	tmid.tmi_bits[tmid.tmi_cnt] = 1;
@@ -107,9 +101,8 @@
 	return (ndx);
 }
 
-
 void
-tls_freemodid(unsigned long modid)
+tls_freemodid(ulong_t modid)
 {
 	ulong_t	i;
 	uint_t	j;
@@ -123,54 +116,21 @@
 		tmid.tmi_lowfree = modid;
 }
 
-
 void
-tls_setroutines(Lm_list *lml, void * modadd, void * modrem, void * statmod)
+tls_modaddrem(Rt_map *lmp, uint_t flag)
 {
-	/*
-	 * If a version of libc/libthread gives us only a subset
-	 * of the TLS interfaces - it's confused and we discard
-	 * the whole lot.
-	 */
-	if (!modadd || !modrem || !statmod)
-		return;
+	Lm_list		*lml = LIST(lmp);
+	TLS_modinfo	tmi;
+	Phdr		*tlsphdr;
+	void		(*fptr)(TLS_modinfo *);
 
-	if ((fptr_tls_modadd == 0) || (lml->lm_flags & LML_FLG_BASELM))
-		fptr_tls_modadd = (void(*)(TLS_modinfo *)) modadd;
-	if ((fptr_tls_modrem == 0) || (lml->lm_flags & LML_FLG_BASELM))
-		fptr_tls_modrem = (void(*)(TLS_modinfo *)) modrem;
-	/*
-	 * The 'statmods' interface is only relevent for the
-	 * primary link-map - ignore all other instances.
-	 */
-	if (lml->lm_flags & LML_FLG_BASELM)
-		fptr_tls_statmods =
-			(void(*)(TLS_modinfo **, unsigned long)) statmod;
-}
-
-
-void
-tls_modactivity(Rt_map * lmp, uint_t flag)
-{
-	TLS_modinfo	tmi;
-	Phdr *		tlsphdr;
-	void (*		fptr)(TLS_modinfo *);
-
-	if (flag & TM_FLG_MODADD)
-		fptr = fptr_tls_modadd;
-	else
-		fptr = fptr_tls_modrem;
-
-	/*
-	 * We only report TLS modactivity for the primary link-map
-	 * after all the objects have been loaded and we've reported
-	 * the STATIC tls modlist (see tls_report_modules()).
-	 */
-	if (((tlsinitialized == 0) &&
-	    (LIST(lmp)->lm_flags & LML_FLG_BASELM)) ||
-	    (fptr == 0) || (lmp == 0) || (FCT(lmp) != &elf_fct) ||
-	    (PTTLS(lmp) == 0))
+	if (flag & TM_FLG_MODADD) {
+		fptr = (void (*)())lml->lm_lcs[CI_TLS_MODADD].lc_un.lc_func;
+	} else if (FLAGS1(lmp) & FL1_RT_TLSADD) {
+		fptr = (void (*)())lml->lm_lcs[CI_TLS_MODREM].lc_un.lc_func;
+	} else {
 		return;
+	}
 
 	tlsphdr = PTTLS(lmp);
 
@@ -178,86 +138,67 @@
 	tmi.tm_modname = PATHNAME(lmp);
 	tmi.tm_modid = TLSMODID(lmp);
 	tmi.tm_tlsblock = (void *)(tlsphdr->p_vaddr);
+
 	if (!(FLAGS(lmp) & FLG_RT_FIXED))
 		tmi.tm_tlsblock = (void *)((uintptr_t)tmi.tm_tlsblock +
 			ADDR(lmp));
+
 	tmi.tm_filesz = tlsphdr->p_filesz;
 	tmi.tm_memsz = tlsphdr->p_memsz;
 	tmi.tm_flags = 0;
 	tmi.tm_stattlsoffset = 0;
 
 	DBG_CALL(Dbg_tls_modactivity(LIST(lmp), &tmi, flag));
-	fptr(&tmi);
+	(*fptr)(&tmi);
 
 	/*
-	 * Free up the moduleid
+	 * Tag that this link-map has registered its TLS, and free up the
+	 * moduleid
 	 */
+	FLAGS1(lmp) |= FL1_RT_TLSADD;
+
 	if (flag & TM_FLG_MODREM)
 		tls_freemodid(TLSMODID(lmp));
 }
 
-
 void
-tls_assign_soffset(Rt_map * lmp)
+tls_assign_soffset(Rt_map *lmp)
 {
-	if (PTTLS(lmp) == 0)
-		return;
-
 	/*
 	 * Only objects on the primary link-map list are associated
 	 * with the STATIC tls block.
 	 */
-	if (LIST(lmp)->lm_flags & LML_FLG_BASELM) {
+	if ((LIST(lmp)->lm_flags & LML_FLG_BASELM) &&
+	    ((rtld_flags2 & RT_FL2_PLMSETUP) == 0)) {
 		tls_static_size += S_ROUND(PTTLS(lmp)->p_memsz, M_TLSSTATALIGN);
 		TLSSTATOFF(lmp) = tls_static_size;
 	}
 
 	/*
-	 * Everyone get's a dynamic TLS modid
+	 * Everyone get's a dynamic TLS modid.
 	 */
 	TLSMODID(lmp) = tls_getmodid();
 }
 
 int
-tls_report_modules()
+tls_statmod(Lm_list *lml, Rt_map *lmp)
 {
-	Rt_map		*lmp;
-	uint_t		tlsmodcnt, tlsmodndx;
-	TLS_modinfo	**tlsmodlist;
-	TLS_modinfo	*tlsbuflist;
+	uint_t		tlsmodndx, tlsmodcnt = lml->lm_tls;
+	TLS_modinfo	**tlsmodlist, *tlsbuflist;
 	Phdr		*tlsphdr;
+	void		(*fptr)(TLS_modinfo **, ulong_t);
 
-	tlsinitialized++;
-	/*
-	 * Scan through all objects to determine how many have TLS storage.
-	 */
-	tlsmodcnt = 0;
-	for (lmp = lml_main.lm_head; lmp; lmp = (Rt_map *)NEXT(lmp)) {
-		if ((FCT(lmp) != &elf_fct) ||
-		    (PTTLS(lmp) == 0) || (PTTLS(lmp)->p_memsz == 0))
-			continue;
-		tlsmodcnt++;
-
-		if (fptr_tls_statmods)
-			continue;
-
-		/*
-		 * If a module has TLS - but the TLS interfaces are not present
-		 * (no libthread?). Then this is a fatal condition.
-		 */
-		eprintf(&lml_main, ERR_FATAL, MSG_INTL(MSG_ERR_TLS_NOTLS),
-		    NAME(lmp));
-		return (0);
-	}
+	fptr = (void (*)())lml->lm_lcs[CI_TLS_STATMOD].lc_un.lc_func;
 
 	/*
 	 * If we don't have any TLS modules - report that and return.
 	 */
 	if (tlsmodcnt == 0) {
-		if (fptr_tls_statmods != 0)
-			fptr_tls_statmods(0, 0);
+		if (fptr)
+			(*fptr)(0, 0);
 		return (1);
 	}
+	lml->lm_tls = 0;
 
 	/*
 	 * Allocate a buffer to report the TLS modules, the buffer consists of:
@@ -268,12 +209,13 @@
 	 * The ptrs are initialized to the bufs - except the last
 	 * one which null terminates the array.
 	 */
-	if ((tlsmodlist = calloc((sizeof (TLS_modinfo *) * tlsmodcnt + 1) +
+	if ((tlsmodlist = calloc((sizeof (TLS_modinfo *) * (tlsmodcnt + 1)) +
 	    (sizeof (TLS_modinfo) * tlsmodcnt), 1)) == 0)
 		return (0);
 
 	tlsbuflist = (TLS_modinfo *)((uintptr_t)tlsmodlist +
-		((tlsmodcnt + 1) * sizeof (TLS_modinfo *)));
+	    ((tlsmodcnt + 1) * sizeof (TLS_modinfo *)));
+
 	for (tlsmodndx = 0; tlsmodndx < tlsmodcnt; tlsmodndx++)
 		tlsmodlist[tlsmodndx] = &tlsbuflist[tlsmodndx];
 
@@ -281,7 +223,7 @@
 	 * Account for the initial dtv ptr in the TLSSIZE calculation.
 	 */
 	tlsmodndx = 0;
-	for (lmp = lml_main.lm_head; lmp; lmp = (Rt_map *)NEXT(lmp)) {
+	for (lmp = lml->lm_head; lmp; lmp = (Rt_map *)NEXT(lmp)) {
 		if ((FCT(lmp) != &elf_fct) ||
 		    (PTTLS(lmp) == 0) || (PTTLS(lmp)->p_memsz == 0))
 			continue;
@@ -290,23 +232,23 @@
 
 		tlsmodlist[tlsmodndx]->tm_modname = PATHNAME(lmp);
 		tlsmodlist[tlsmodndx]->tm_modid = TLSMODID(lmp);
-		tlsmodlist[tlsmodndx]->tm_tlsblock =
-			(void *)(tlsphdr->p_vaddr);
-		if (!(FLAGS(lmp) & FLG_RT_FIXED))
-			tlsmodlist[tlsmodndx]->tm_tlsblock =
-				(void *)((uintptr_t)tlsmodlist[
-				tlsmodndx]->tm_tlsblock + ADDR(lmp));
+		tlsmodlist[tlsmodndx]->tm_tlsblock = (void *)(tlsphdr->p_vaddr);
+
+		if (!(FLAGS(lmp) & FLG_RT_FIXED)) {
+			tlsmodlist[tlsmodndx]->tm_tlsblock = (void *)
+			    ((uintptr_t)tlsmodlist[tlsmodndx]->tm_tlsblock +
+			    ADDR(lmp));
+		}
 		tlsmodlist[tlsmodndx]->tm_filesz = tlsphdr->p_filesz;
 		tlsmodlist[tlsmodndx]->tm_memsz = tlsphdr->p_memsz;
 		tlsmodlist[tlsmodndx]->tm_flags = TM_FLG_STATICTLS;
-		tlsmodlist[tlsmodndx]->tm_stattlsoffset =
-			TLSSTATOFF(lmp);
+		tlsmodlist[tlsmodndx]->tm_stattlsoffset = TLSSTATOFF(lmp);
 		tlsmodndx++;
 	}
 
 	DBG_CALL(Dbg_tls_static_block(&lml_main, (void *)tlsmodlist,
 	    tls_static_size));
-	fptr_tls_statmods(tlsmodlist, tls_static_size);
+	(*fptr)(tlsmodlist, tls_static_size);
 
 	/*
 	 * We're done with the list - clean it up.
--- a/usr/src/cmd/sgs/rtld/common/util.c	Tue Apr 18 07:10:32 2006 -0700
+++ b/usr/src/cmd/sgs/rtld/common/util.c	Tue Apr 18 08:51:16 2006 -0700
@@ -50,6 +50,7 @@
 #include	<conv.h>
 #include	"_rtld.h"
 #include	"_audit.h"
+#include	"_elf.h"
 #include	"msg.h"
 
 static int ld_flags_env(const char *, Word *, Word *, uint_t, int);
@@ -137,7 +138,7 @@
 void
 rd_event(Lm_list *lml, rd_event_e event, r_state_e state)
 {
-	void	(*fptr)();
+	void	(*fptr)(Lm_list *);
 
 	switch (event) {
 	case RD_PREINIT:
@@ -594,7 +595,7 @@
 	 * Call the .*array[] entries
 	 */
 	for (ndx = start; ndx != stop; ndx += incr) {
-		void (*	fptr)() = (void(*)())array[ndx];
+		void (*fptr)(void) = (void(*)())array[ndx];
 
 		DBG_CALL(Dbg_util_call_array(lmp, (void *)fptr, ndx, shtype));
 
@@ -627,21 +628,6 @@
 	}
 
 	/*
-	 * If a 'thread initialization' is pending - call it now before any
-	 * .init code is fired.  Also clear the thrinit() to mark it as done.
-	 * Note, this is called for each link-map list, which is what libc
-	 * expects.
-	 */
-	if (thrinit) {
-		void	(*_thrinit)() = thrinit;
-
-		thrinit = 0;
-		leave((Lm_list *)0);
-		_thrinit();
-		(void) enter();
-	}
-
-	/*
 	 * Traverse the tobj array firing each objects init.
 	 */
 	for (_tobj = _nobj = tobj, _nobj++; *_tobj != NULL; _tobj++, _nobj++) {
@@ -763,7 +749,7 @@
 		 */
 		if ((rtld_flags & RT_FL_CONCUR) ||
 		    (FLAGS(lmp) & FLG_RT_INITDONE)) {
-			void	(*fptr)() = FINI(lmp);
+			void	(*fptr)(void) = FINI(lmp);
 
 			if (FINIARRAY(lmp) || fptr) {
 				/*
@@ -880,6 +866,11 @@
 	 * Traverse any alternative link-map lists.
 	 */
 	for (LIST_TRAVERSE(&dynlm_list, lnp, lml)) {
+		/*
+		 * Ignore the base-link-map list, which has already been
+		 * processed, and the runtime linkers link-map list, which is
+		 * typically processed last.
+		 */
 		if (lml->lm_flags & (LML_FLG_BASELM | LML_FLG_RTLDLM))
 			continue;
 
@@ -920,9 +911,10 @@
  * and from any internal dl*() requests.
  */
 void
-load_completion(Rt_map * nlmp, Rt_map * clmp)
+load_completion(Rt_map *nlmp, Rt_map *clmp)
 {
 	Rt_map	**tobj = 0;
+	Lm_list	*nlml, *clml;
 
 	/*
 	 * Establish any .init processing.  Note, in a world of lazy loading,
@@ -932,26 +924,58 @@
 	 * any tsorting starts from the nlmp (new link-maps) pointer and not
 	 * necessarily from the link-map that may have satisfied the request.
 	 *
-	 * Note, if the caller is an auditor, and the destination isn't, then
-	 * don't run any .inits.  This scenario is typical of an auditor trying
-	 * to inspect another link-map for symbols.  Allow this inspection
-	 * without running any code on the inspected link-map, as running this
-	 * code may reenter the auditor, who has not yet finished their own
+	 * Note, the primary link-map has an initialization phase where dynamic
+	 * .init firing is suppressed.  This provides for a simple and clean
+	 * handshake with the primary link-maps libc, which is important for
+	 * establishing uberdata.  In addition, auditors often obtain handles
+	 * to primary link-map objects as the objects are loaded, so as to
+	 * inspect the link-map for symbols.  This inspection is allowed without
+	 * running any code on the primary link-map, as running this code may
+	 * reenter the auditor, who may not yet have finished its own
 	 * initialization.
 	 */
-	if (nlmp && ((clmp == 0) ||
-	    ((LIST(clmp)->lm_flags & LML_FLG_NOAUDIT) == 0) ||
-	    (LIST(clmp) == LIST(nlmp)))) {
+	if (nlmp)
+		nlml = LIST(nlmp);
+	if (clmp)
+		clml = LIST(clmp);
+
+	if (nlmp && nlml->lm_init &&
+	    ((nlml != &lml_main) || (rtld_flags2 & RT_FL2_PLMSETUP))) {
 		if ((tobj = tsort(nlmp, LIST(nlmp)->lm_init,
 		    RT_SORT_REV)) == (Rt_map **)S_ERROR)
 			tobj = 0;
 	}
 
 	/*
+	 * Make sure any alternative link-map retrieves any external interfaces
+	 * and initializes threads.
+	 */
+	if (nlmp && (nlml != &lml_main)) {
+		(void) rt_get_extern(nlml, nlmp);
+		rt_thr_init(nlml);
+	}
+
+	/*
+	 * Traverse the list of new link-maps and register any dynamic TLS.
+	 * This storage is established for any objects not on the primary
+	 * link-map, and for any objects added to the primary link-map after
+	 * static TLS has been registered.
+	 */
+	if (nlmp && nlml->lm_tls &&
+	    ((nlml != &lml_main) || (rtld_flags2 & RT_FL2_PLMSETUP))) {
+		Rt_map	*lmp;
+
+		for (lmp = nlmp; lmp; lmp = (Rt_map *)NEXT(lmp)) {
+			if (PTTLS(lmp) && PTTLS(lmp)->p_memsz)
+				tls_modaddrem(lmp, TM_FLG_MODADD);
+		}
+		nlml->lm_tls = 0;
+	}
+
+	/*
 	 * Indicate the link-map list is consistent.
 	 */
-	if (clmp &&
-	    ((LIST(clmp)->lm_tflags | FLAGS1(clmp)) & LML_TFLG_AUD_ACTIVITY))
+	if (clmp && ((clml->lm_tflags | FLAGS1(clmp)) & LML_TFLG_AUD_ACTIVITY))
 		audit_activity(clmp, LA_ACT_CONSISTENT);
 
 	/*
@@ -1255,7 +1279,6 @@
 	 * Indicate each new link-map has been moved to the previous link-map
 	 * control list.
 	 */
-
 	for (lmp = nlmc->lc_head; lmp; lmp = (Rt_map *)NEXT(lmp))
 		CNTL(lmp) = plmco;
 
@@ -1446,9 +1469,9 @@
     Word *lmtflags, uint_t env_flags, int aout)
 {
 	u_longlong_t	variable = 0;
-	unsigned short	select = 0;
-	const char **str;
-	Word val = 0;
+	ushort_t	select = 0;
+	const char	**str;
+	Word		val = 0;
 
 	/*
 	 * Determine whether we're dealing with a replaceable or permanent
@@ -2160,7 +2183,7 @@
     int aout)
 {
 	const char	*s2;
-	static	size_t	loc = 0;
+	static		size_t	loc = 0;
 
 	if (*s1++ != 'L')
 		return;
@@ -2175,14 +2198,14 @@
 		if (strncmp(s2, MSG_ORIG(MSG_LC_ALL), MSG_LC_ALL_SIZE) == 0) {
 			s2 += MSG_LC_ALL_SIZE;
 			if ((*s2 != '\0') && (loc < LOC_ALL)) {
-				locale = s2;
+				glcs[CI_LCMESSAGES].lc_un.lc_ptr = (char *)s2;
 				loc = LOC_ALL;
 			}
 		} else if (strncmp(s2, MSG_ORIG(MSG_LC_MESSAGES),
 		    MSG_LC_MESSAGES_SIZE) == 0) {
 			s2 += MSG_LC_MESSAGES_SIZE;
 			if ((*s2 != '\0') && (loc < LOC_MESG)) {
-				locale = s2;
+				glcs[CI_LCMESSAGES].lc_un.lc_ptr = (char *)s2;
 				loc = LOC_MESG;
 			}
 		}
@@ -2192,7 +2215,7 @@
 	s2 = s1;
 	if ((*s2++ == 'A') && (*s2++ == 'N') && (*s2++ == 'G') &&
 	    (*s2++ == '=') && (*s2 != '\0') && (loc < LOC_LANG)) {
-		locale = s2;
+		glcs[CI_LCMESSAGES].lc_un.lc_ptr = (char *)s2;
 		loc = LOC_LANG;
 		return;
 	}
@@ -2242,6 +2265,8 @@
 int
 readenv_user(const char ** envp, Word *lmflags, Word *lmtflags, int aout)
 {
+	char	*locale;
+
 	if (envp == (const char **)0)
 		return (0);
 
@@ -2277,12 +2302,12 @@
 	 * Duplicate the string so that new locale setting can generically
 	 * cleanup any previous locales.
 	 */
-	if (locale) {
+	if ((locale = glcs[CI_LCMESSAGES].lc_un.lc_ptr) != 0) {
 		if (((*locale == 'C') && (*(locale + 1) == '\0')) ||
 		    (strcmp(locale, MSG_ORIG(MSG_TKN_POSIX)) == 0))
-			locale = 0;
+			glcs[CI_LCMESSAGES].lc_un.lc_ptr = 0;
 		else
-			locale = strdup(locale);
+			glcs[CI_LCMESSAGES].lc_un.lc_ptr = strdup(locale);
 	}
 	return (0);
 }
@@ -2377,16 +2402,15 @@
 #define	FLG_UT_DOTSEEN	0x0008	/* dot appeared in format spec */
 
 /*
- * This macro is for use from within doprf only.  it's to be used
- * for checking the output buffer size and placing characters into
- * the buffer.
+ * This macro is for use from within doprf only.  It is to be used for checking
+ * the output buffer size and placing characters into the buffer.
  */
 #define	PUTC(c) \
 	{ \
-		register char tmpc; \
+		char tmpc; \
 		\
 		tmpc = (c); \
-		if ((bufsiz) && ((bp + 1) >= bufend)) { \
+		if (bufsiz && (bp >= bufend)) { \
 			prf->pr_cur = bp; \
 			if (dowrite(prf) == 0) \
 				return (0); \
@@ -2594,6 +2618,7 @@
 			}
 		}
 	}
+
 	PUTC('\0');
 	prf->pr_cur = bp;
 	return (1);
--- a/usr/src/cmd/sgs/rtld/i386/Makefile	Tue Apr 18 07:10:32 2006 -0700
+++ b/usr/src/cmd/sgs/rtld/i386/Makefile	Tue Apr 18 08:51:16 2006 -0700
@@ -32,8 +32,8 @@
 # secondary lists (less frequently used code, ie. profiling support).
 
 P_COMOBJS=	debugdata.o \
-		analyze.o	elf.o		globals.o	malloc.o \
-		mutex.o		paths.o		setup.o		util.o \
+		analyze.o	elf.o		external.o	globals.o \
+		malloc.o	paths.o		setup.o		util.o \
 		dlfcns.o	config_elf.o	locale.o	tsort.o \
 		getcwd.o	remove.o	move.o		tls.o \
 		cap.o
--- a/usr/src/cmd/sgs/rtld/mdbmod/common/rtld.c	Tue Apr 18 07:10:32 2006 -0700
+++ b/usr/src/cmd/sgs/rtld/mdbmod/common/rtld.c	Tue Apr 18 08:51:16 2006 -0700
@@ -972,7 +972,7 @@
 	}
 
 	mdb_printf(MSG_ORIG(MSG_LMLIST_LINE1), lml.lm_head, lml.lm_tail);
-	mdb_printf(MSG_ORIG(MSG_LMLIST_LINE2), lml.lm_alp, lml.lm_peh_lmp);
+	mdb_printf(MSG_ORIG(MSG_LMLIST_LINE2), lml.lm_alp, lml.lm_rti);
 	mdb_printf(MSG_ORIG(MSG_LMLIST_LINE3), lml.lm_handle, lml.lm_obj,
 	    lml.lm_init, lml.lm_lazy);
 
--- a/usr/src/cmd/sgs/rtld/mdbmod/common/rtld.msg	Tue Apr 18 07:10:32 2006 -0700
+++ b/usr/src/cmd/sgs/rtld/mdbmod/common/rtld.msg	Tue Apr 18 08:51:16 2006 -0700
@@ -1,13 +1,9 @@
-#
-# Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
 #
 # CDDL HEADER START
 #
 # The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (the "License").  You may not use this file except in compliance
-# with the License.
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
 #
 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 # or http://www.opensolaris.org/os/licensing.
@@ -22,6 +18,11 @@
 #
 # CDDL HEADER END
 #
+
+#
+# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
 # pragma ident	"%Z%%M%	%I%	%E% SMI"
 # 
 
@@ -344,13 +345,13 @@
 @ MSG_LMLIST_LINE0	"   lists: 0x%0?p Alist[used %u: total %u]\n"
 
 @ MSG_LMC_LINE1		"Lm_cntl: 0x%p\n"
-@ MSG_LMC_LINE2		"   head: 0x%0?p\t     tail: 0x%0?p\n"
-@ MSG_LMC_LINE3		"  flags: 0x%08x\t      now: 0x%0?p\n"
+@ MSG_LMC_LINE2		"   head: 0x%0?p\t      tail: 0x%0?p\n"
+@ MSG_LMC_LINE3		"  flags: 0x%08x\t       now: 0x%0?p\n"
 @ MSG_LMC_LINE4		"         [ %#b ]\n"
 
-@ MSG_LMLIST_LINE1	"    head: 0x%0?p\t     tail: 0x%0?p\n"
-@ MSG_LMLIST_LINE2	"   audit: 0x%0?p\t  preexec: 0x%0?p\n"
-@ MSG_LMLIST_LINE3	"  handle: 0x%0?p\t      obj: %4d  init: %4d  \
+@ MSG_LMLIST_LINE1	"    head: 0x%0?p\t      tail: 0x%0?p\n"
+@ MSG_LMLIST_LINE2	"   audit: 0x%0?p\t  rtldinfo: 0x%0?p\n"
+@ MSG_LMLIST_LINE3	"  handle: 0x%0?p\t       obj: %4d  init: %4d  \
 			 lazy: %4d\n"
 @ MSG_LMLIST_LINE4	"   flags: 0x%08x\n"
 @ MSG_LMLIST_LINE5	"  tflags: 0x%08x\n"
--- a/usr/src/cmd/sgs/rtld/sparc/Makefile	Tue Apr 18 07:10:32 2006 -0700
+++ b/usr/src/cmd/sgs/rtld/sparc/Makefile	Tue Apr 18 08:51:16 2006 -0700
@@ -30,8 +30,8 @@
 # secondary lists (less frequently used code, ie. a.out support).
 
 P_COMOBJS=	debugdata.o \
-		analyze.o	elf.o		globals.o	malloc.o \
-		mutex.o		paths.o		setup.o		util.o \
+		analyze.o	elf.o		external.o	globals.o \
+		malloc.o	paths.o		setup.o		util.o \
 		dlfcns.o	config_elf.o	locale.o	tsort.o \
 		getcwd.o	remove.o	move.o		tls.o \
 		cap.o
--- a/usr/src/cmd/sgs/rtld/sparcv9/Makefile	Tue Apr 18 07:10:32 2006 -0700
+++ b/usr/src/cmd/sgs/rtld/sparcv9/Makefile	Tue Apr 18 08:51:16 2006 -0700
@@ -30,8 +30,8 @@
 # secondary lists (less frequently used code, ie. a.out support).
 
 P_COMOBJS=	debugdata.o \
-		analyze.o	elf.o		globals.o	malloc.o \
-		mutex.o		paths.o		setup.o		util.o \
+		analyze.o	elf.o		external.o	globals.o \
+		malloc.o	paths.o		setup.o		util.o \
 		dlfcns.o	config_elf.o	locale.o	tsort.o \
 		getcwd.o	remove.o	move.o		tls.o \
 		cap.o
--- a/usr/src/cmd/sgs/rtld/sparcv9/sparc_elf.c	Tue Apr 18 07:10:32 2006 -0700
+++ b/usr/src/cmd/sgs/rtld/sparcv9/sparc_elf.c	Tue Apr 18 08:51:16 2006 -0700
@@ -328,60 +328,58 @@
 
 /*
  * Relocate the instructions given by the VAL64_TO_G1 macro above.
+ * The arguments parallel those of do_reloc().
  *
  * entry:
+ *	off - Address of 1st instruction in sequence.
+ *	value - Value being relocated (addend)
+ *	sym - Name of value being relocated.
  *	lml - link map list
- *	dyndata - Value being relocated (addend)
- *	code_base - Address of 1st instruction in sequence.
  *
  * exit:
  *	Returns TRUE for success, FALSE for failure.
  */
 static int
-reloc_val64_to_g1(Lm_list *lml, Addr *dyndata, Byte *code_base)
+reloc_val64_to_g1(Byte *off, Addr *value, const char *sym, Lm_list *lml)
 {
-	Xword	symvalue;
+	Xword	tmp_value;
 
 	/*
 	 * relocating:
-	 *	sethi	%hh(dyndata), %g5
+	 *	sethi	%hh(value), %g5
 	 */
-	symvalue = (Xword)dyndata;
-	if (do_reloc(R_SPARC_HH22, code_base,
-	    &symvalue, MSG_ORIG(MSG_SYM_LADYNDATA),
+	tmp_value = (Xword)value;
+	if (do_reloc(R_SPARC_HH22, off, &tmp_value, sym,
 	    MSG_ORIG(MSG_SPECFIL_DYNPLT), lml) == 0) {
 		return (0);
 	}
 
 	/*
 	 * relocating:
-	 *	or	%g5, %hm(dyndata), %g5
+	 *	or	%g5, %hm(value), %g5
 	 */
-	symvalue = (Xword)dyndata;
-	if (do_reloc(R_SPARC_HM10, code_base + 4,
-	    &symvalue, MSG_ORIG(MSG_SYM_LADYNDATA),
+	tmp_value = (Xword)value;
+	if (do_reloc(R_SPARC_HM10, off + 4, &tmp_value, sym,
 	    MSG_ORIG(MSG_SPECFIL_DYNPLT), lml) == 0) {
 		return (0);
 	}
 
 	/*
 	 * relocating:
-	 *	sethi	%lm(dyndata), %g1
+	 *	sethi	%lm(value), %g1
 	 */
-	symvalue = (Xword)dyndata;
-	if (do_reloc(R_SPARC_LM22, code_base + 12,
-	    &symvalue, MSG_ORIG(MSG_SYM_LADYNDATA),
+	tmp_value = (Xword)value;
+	if (do_reloc(R_SPARC_LM22, off + 12, &tmp_value, sym,
 	    MSG_ORIG(MSG_SPECFIL_DYNPLT), lml) == 0) {
 		return (0);
 	}
 
 	/*
 	 * relocating:
-	 *	or	%g1, %lo(dyndata), %g1
+	 *	or	%g1, %lo(value), %g1
 	 */
-	symvalue = (Xword)dyndata;
-	if (do_reloc(R_SPARC_LO10, code_base + 16,
-	    &symvalue, MSG_ORIG(MSG_SYM_LADYNDATA),
+	tmp_value = (Xword)value;
+	if (do_reloc(R_SPARC_LO10, off + 16, &tmp_value, sym,
 	    MSG_ORIG(MSG_SPECFIL_DYNPLT), lml) == 0) {
 		return (0);
 	}
@@ -434,10 +432,11 @@
 		 *	VAL64_TO_G1(dyndata)
 		 *	VAL64_TO_G1(&elf_plt_trace)
 		 */
-		if (!(reloc_val64_to_g1(lml, dyndata,
-					(Byte *) (dyn_plt + 0x14)) &&
-			reloc_val64_to_g1(lml, (Addr *)&elf_plt_trace,
-					(Byte *) (dyn_plt + 0x30)))) {
+		if (!(reloc_val64_to_g1((Byte *) (dyn_plt + 0x14), dyndata,
+					MSG_ORIG(MSG_SYM_LADYNDATA), lml) &&
+			reloc_val64_to_g1((Byte *) (dyn_plt + 0x30),
+					(Addr *)&elf_plt_trace,
+					MSG_ORIG(MSG_SYM_ELFPLTTRACE), lml))) {
 			*fail = 1;
 			return (0);
 		}