changeset 2978:a77a2fdc9d9e

PSARC 2006/595 link-editor support library interface - ld_open() 6479848 Enhancements to the linker support interface needed. 6482058 lari(1) could be faster, and handle per-symbol filters better 6482974 defining virtual address of text segment can result in an invalid data segment 6476734 crle(1m) "-l" as described fails system, crle cores trying to fix /a/var/ld/ld.config in failsafe
author rie
date Tue, 24 Oct 2006 09:55:12 -0700
parents 5ad12f577bed
children 6d134878cca1
files usr/src/cmd/sgs/crle/common/crle.msg usr/src/cmd/sgs/include/debug.h usr/src/cmd/sgs/include/libld.h usr/src/cmd/sgs/lari/lari.pl usr/src/cmd/sgs/libld/common/_libld.h usr/src/cmd/sgs/libld/common/args.c usr/src/cmd/sgs/libld/common/files.c usr/src/cmd/sgs/libld/common/ldlibs.c usr/src/cmd/sgs/libld/common/libld.msg usr/src/cmd/sgs/libld/common/libs.c usr/src/cmd/sgs/libld/common/llib-lld usr/src/cmd/sgs/libld/common/support.c usr/src/cmd/sgs/libld/common/update.c usr/src/cmd/sgs/liblddbg/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/shdr.c usr/src/cmd/sgs/liblddbg/common/support.c usr/src/cmd/sgs/packages/common/SUNWonld-README usr/src/cmd/sgs/rtld/common/object.c usr/src/head/link.h
diffstat 22 files changed, 615 insertions(+), 280 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/cmd/sgs/crle/common/crle.msg	Tue Oct 24 01:13:19 2006 -0700
+++ b/usr/src/cmd/sgs/crle/common/crle.msg	Tue Oct 24 09:55:12 2006 -0700
@@ -1,6 +1,3 @@
-#
-# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
 #
 # CDDL HEADER START
 #
@@ -21,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"
 
 
@@ -38,24 +40,43 @@
 			 [-i name] [-I name] [-l dir] [-o dir ] [-s dir] \
 			 [-t ELF|AOUT] [-u] [-v]\n\
 			 \t[-64]\t\tprocess 64-bit objects\n\
-			 \t[-a name]\tadd an alternative name\n\
-			 \t[-A name]\tadd an optional alternative name\n\
+			 \t[-a name]\tdefine an alternative object name\n\
+			 \t[-A name]\tdefine an optional alternative object \
+			  name\n\
 			 \t[-c conf]\tspecify configuration file\n\
-			 \t[-e env]\tadd a replaceable environment variable\n\
-			 \t[-E env]\tadd an permanent environment variable\n\
+			 \t[-e env]\tdefine a replaceable environment \
+			  variable\n\
+			 \t[-E env]\tdefine a permanent environment variable\n\
 			 \t[-f flags]\tspecify flags for -G and -I\n\
-			 \t[-g name]\tadd group name\n\
-			 \t[-G name]\tadd group name and create \
+			 \t[-g name]\tdefine a group object name\n\
+			 \t[-G name]\tdefine a group object name and create \
 			  alternatives\n\
-			 \t[-i name]\tadd individual name\n\
-			 \t[-I name]\tadd individual name and create \
-			  alternative\n\
-			 \t[-l dir]\tadd default search directory\n\
+			 \t[-i name]\tdefine an individual object name\n\
+			 \t[-I name]\tdefine an individual object name and \
+			  create an\n\
+			 \t\t\talternative\n\
+			 \t[-l dir]\tdefine a default search directory\n\
 			 \t[-o dir]\tuse directory for alternative objects\n\
-			 \t[-s dir]\tadd trusted search directory\n\
+			 \t[-s dir]\tdefine a  trusted search directory\n\
 			 \t[-t ELF|AOUT]\ttoggle object type for -l and -s\n\
 			 \t[-u]\t\tupdate existing configuration file\n\
-			 \t[-v]\t\tprovide verbose processing information\n"
+			 \t[-v]\t\tprovide verbose processing information\n\
+			 \n\
+			 \tNote: without the -u option, the information \
+			  defined by the options\n\
+			 \tto crle() result in the replacement of any existing \
+			  configuration\n\
+			 \tfile, or default search paths.  With the -u option, \
+			  the information\n\
+			 \tdefined by the options to crle() is appended to any \
+			  existing\n\
+			 \tconfiguration file, or default search paths.\n\
+			 \n\
+			 \tSet the environment variable LD_NOCONFIG=yes to \
+			  disable the processing\n\
+			 \tof any configuration file information.  \
+			  See ld.so.1(1).\n"
+
 
 @ MSG_ARG_ILLEGAL	"%s: option %s has illegal argument `%s'\n"
 @ MSG_ARG_MULT		"%s: argument %s specified multiple times\n"
@@ -68,14 +89,14 @@
 @ MSG_ARG_UPDATE	"%s: %s: version [%d] of configuration file provides \
 			 limited update (-u) and command-line regeneration \
 			 capabilities: best effort in effect\n"
-@ MSG_ARG_UPDATEVER	"%s: %s: file version [%d] newer than crle version \
-			[%d]. Unable to update\n"
-@ MSG_ARG_PRINTVER	"%s: %s: file version [%d] newer than crle version \
+@ MSG_ARG_UPDATEVER	"%s: %s: file version [%d] newer than crle() version \
+			[%d].  Unable to update\n"
+@ MSG_ARG_PRINTVER	"%s: %s: file version [%d] newer than crle() version \
 			[%d]. Displayed information may be incomplete\n"
 @ MSG_ARG_CLASS		"%s: %s: 32-bit file is incompatible with -64 \
 			 option\n"
 @ MSG_ARG_WRONGARCH	"%s: %s: %s %s file is incompatible with \
-			%s %s version of crle\n"
+			%s %s version of crle()\n"
 
 @ MSG_WARN_ENV		"%s: warning: %.*s: environment variable \
 			 multiply-defined, first definition taken\n"
--- a/usr/src/cmd/sgs/include/debug.h	Tue Oct 24 01:13:19 2006 -0700
+++ b/usr/src/cmd/sgs/include/debug.h	Tue Oct 24 09:55:12 2006 -0700
@@ -228,6 +228,7 @@
 #define	Dbg_file_lazyload	Dbg64_file_lazyload
 #define	Dbg_file_ldso		Dbg64_file_ldso
 #define	Dbg_file_mode_promote	Dbg64_file_mode_promote
+#define	Dbg_file_modified	Dbg64_file_modified
 #define	Dbg_file_needed		Dbg64_file_needed
 #define	Dbg_file_output		Dbg64_file_output
 #define	Dbg_file_preload	Dbg64_file_preload
@@ -422,6 +423,7 @@
 #define	Dbg_file_lazyload	Dbg32_file_lazyload
 #define	Dbg_file_ldso		Dbg32_file_ldso
 #define	Dbg_file_mode_promote	Dbg32_file_mode_promote
+#define	Dbg_file_modified	Dbg32_file_modified
 #define	Dbg_file_needed		Dbg32_file_needed
 #define	Dbg_file_output		Dbg32_file_output
 #define	Dbg_file_preload	Dbg32_file_preload
@@ -640,6 +642,8 @@
 extern	void	Dbg_file_ldso(Rt_map *, char **, auxv_t *, const char *,
 		    Aliste);
 extern	void	Dbg_file_mode_promote(Rt_map *, int);
+extern	void	Dbg_file_modified(Lm_list *, const char *, const char *,
+		    const char *, int, int, Elf *, Elf *);
 extern	void	Dbg_file_needed(Rt_map *, const char *);
 extern	void	Dbg_file_output(Ofl_desc *);
 extern	void	Dbg_file_preload(Lm_list *, const char *);
@@ -728,7 +732,7 @@
 extern	void	Dbg_seg_os(Ofl_desc *, Os_desc *, int);
 extern	void	Dbg_seg_title(Lm_list *);
 
-extern	void	Dbg_shdr_modified(Lm_list *, Half, Shdr *, Shdr *,
+extern	void	Dbg_shdr_modified(Lm_list *, const char *, Half, Shdr *, Shdr *,
 		    const char *);
 
 extern	void	Dbg_statistics_ar(Ofl_desc *);
--- a/usr/src/cmd/sgs/include/libld.h	Tue Oct 24 01:13:19 2006 -0700
+++ b/usr/src/cmd/sgs/include/libld.h	Tue Oct 24 09:55:12 2006 -0700
@@ -973,6 +973,7 @@
 	LDS_INPUT_DONE,
 	LDS_START,
 	LDS_ATEXIT,
+	LDS_OPEN,
 	LDS_FILE,
 	LDS_INSEC,
 	LDS_SEC,
@@ -1063,7 +1064,7 @@
 extern uintptr_t	ld_init_strings(Ofl_desc *);
 extern uintptr_t	ld_make_sections(Ofl_desc *);
 extern void		ld_ofl_cleanup(Ofl_desc *);
-extern Ifl_desc		*ld_process_open(const char *, const char *, int,
+extern Ifl_desc		*ld_process_open(const char *, const char *, int *,
 			    Ofl_desc *, Half, Rej_desc *);
 extern uintptr_t	ld_reloc_init(Ofl_desc *);
 extern uintptr_t	ld_reloc_process(Ofl_desc *);
--- a/usr/src/cmd/sgs/lari/lari.pl	Tue Oct 24 01:13:19 2006 -0700
+++ b/usr/src/cmd/sgs/lari/lari.pl	Tue Oct 24 09:55:12 2006 -0700
@@ -30,18 +30,20 @@
 #
 
 # Define all global variables (required for strict)
-use vars  qw($Prog $DestDir $ObjRef $ObjFlag $ObjSize $TmpDir $LddArgs);
-use vars  qw($Glob $Intp $Cpyr $Prot $Extn $Self $Filt $Dirc $Plta $User $Func);
-use vars  qw($Objt $UndefSym $IgnSyms $Rtld $MultSyms $CrtSyms $GlobWeak);
-use vars  qw($DbgSeed %opt %Symbols %Objects %Versioned %DemSyms);
-use vars  qw($Platform $Nodi $Osft $Oaft $Ssft $Saft $Msft);
+use vars  qw($Prog $DestDir $ObjRef $ObjFlag $ObjSize $TmpDir $LddArgs $SymFlag);
+use vars  qw($Glob $Intp $Dirc $Cpyr $Prot $Extn $Self $Gfte $Plta $User $Func);
+use vars  qw($Sfte $Afte $Objt $Nodi $Osft $Oaft $Ssft $Saft $Msft);
+use vars  qw($Rtld $GlobWeak $MultSyms $CrtSyms $Platform $DbgSeed %opt);
+
+# Global arrays that must be cleared for multi input file use.
+use vars  qw(%Symbols %Objects %Versioned %DemSyms %ObjFltrs %SymFltes);
 
 use strict;
 
 use Getopt::Std;
 use File::Basename;
 
-# Pattern match to skip objects.
+# Pattern match to skip the runtime linker.
 $Rtld = qr{
 	/lib/ld\.so\.1 |
 	/usr/lib/ld\.so\.1 |
@@ -83,27 +85,17 @@
 	 )$
 }x;
 
-# Pattern match to remove undefined, NOTY and versioning symbols.
-$UndefSym = qr{ ^(?:
-	UNDEF
-	)$
-}x;
-
-$IgnSyms = qr{ ^(?:
-	NOTY |
-	ABS
-	)$
-}x;
-
 # Symbol flags.
 $Glob = 0x00001;	# symbol is global
+$Sfte = 0x00002;	# symbol is a filtee backing a standard filter
+$Afte = 0x00004;	# symbol is a filtee backing a auxiliary filter
+$Gfte = 0x00008;	# symbol bound as a filtee
 $Intp = 0x00010;	# symbol originates for explicit interposer
 $Dirc = 0x00020;	# symbol bound to directly
 $Cpyr = 0x00040;	# symbol bound to copy-relocation reference
 $Prot = 0x00080;	# symbol is protected (symbolic)
 $Extn = 0x00100;	# symbol has been bound to from an external reference
 $Self = 0x00200;	# symbol has been bound to from the same object
-$Filt = 0x00400;	# symbol bound to a filtee
 $Plta = 0x00800;	# symbol bound to executables plt address
 $User = 0x01000;	# symbol binding originates from user (dlsym) request
 $Func = 0x02000;	# symbol is of type function
@@ -113,7 +105,7 @@
 $Osft = 0x10000;	# symbol is an standard object filter
 $Oaft = 0x20000;	# symbol is an auxiliary object filter
 $Ssft = 0x40000;	# symbol is a per-symbol standard filter
-$Saft = 0x80000;	# symbol is a per-symbol auxilary filter
+$Saft = 0x80000;	# symbol is a per-symbol auxiliary filter
 $Msft = 0xf0000;	# filter mask
 
 # Offsets into $Symbols{$SymName}{$Obj} array.
@@ -121,6 +113,8 @@
 $ObjFlag =	1;
 $ObjSize =	2;
 
+# Offset into $SymFltr{$SymName}{$Filtee} array.
+$SymFlag = 	0;
 
 # Establish locale
 use POSIX qw(locale_h);
@@ -146,7 +140,7 @@
 	}
 }
 
-# Cleanup any temporary files on interruption
+# Cleanup any temporary files on interruption.
 sub Cleanup {
 	my ($Sig) = @_;
 
@@ -172,8 +166,7 @@
 	print STDERR
 	    gettext("\t[-a]     print diagnostics for all symbols\n");
 	print STDERR
-	    gettext("\t[-b]     print diagnostics for multiple-bound " .
-		"symbols\n");
+	    gettext("\t[-b]     limit diagnostics to bound symbols\n");
 	print STDERR
 	    gettext("\t[-C]     print demangled symbol names also\n");
 	print STDERR
@@ -185,7 +178,7 @@
 	print STDERR
 	    gettext("\t[-m]     create mapfiles for interface requirements\n");
 	print STDERR
-	    gettext("\t[-o]     print overhead information\n");
+	    gettext("\t[-o]     limit diagnostics to overhead information\n");
 	print STDERR
 	    gettext("\t[-s]     save bindings information created by ldd(1)\n");
 	print STDERR
@@ -358,7 +351,7 @@
 				next;
 			}
 
-			# If we're decending into a platform directory, ignore
+			# If we're descending into a platform directory, ignore
 			# any inappropriate platform specific files.  These
 			# files can have dependencies that in turn bring in the
 			# appropriate platform specific file, resulting in more
@@ -524,6 +517,9 @@
 		%Symbols = ();
 		%Objects = ();
 		%Versioned = ();
+		%DemSyms = ();
+		%ObjFltrs = ();
+		%SymFltes = ();
 	}
 
 	# As debugging output can be significant, read a line at a time.
@@ -531,45 +527,6 @@
 	while (defined(my $Line = <$FileHandle>)) {
 		chomp($Line);
 
-		# If we find a relationship between a filter and filtee, save
-		# it, we'll come back to this once we've gathered everybodies
-		# symbols.
-		if ($Line =~ /;  filtered by /) {
-			my ($Filtee) = $Line;
-			my ($Filter) = $Line;
-
-			# Separate the filter and filtee names, ignore the
-			# runtime linker.
-			$Filtee =~ s/^.*: file=(.*);  filtered by .*/$1/;
-			if ($Filtee =~ $Rtld) {
-				next;
-			}
-			$Filter =~ s/^.*;  filtered by //;
-			$Filtees{$Filtee}{$Filter} = 1;
-			next;
-		}
-
-		# If we find a configuration alternative, determine whether it
-		# is for one of our filtees, and if so record it.
-		if ($Line =~ / configuration alternate found:/) {
-			my ($Orig) = $Line;
-			my ($Altr) = $Line;
-
-			# Separate the original and alternative names.
-			$Orig =~ s/^.*: file=(.*)  .*$/$1/;
-			$Altr =~ s/^.* configuration alternate found: (.*)$/$1/;
-
-			for my $Filtee (keys(%Filtees)) {
-				if ($Filtee ne $Orig) {
-					next;
-				}
-				for my $Filter (keys(%{$Filtees{$Filtee}})) {
-					$Filtees{$Altr}{$Filter} = 1;
-				}
-			}
-			next;
-		}
-
 		# Collect the symbols from any file analyzed.
 		if ($Line =~ /^.*: file=(.*);  analyzing .*/) {
 			GetAllSymbols($1);
@@ -602,7 +559,7 @@
 			# of the reference, "(0x1234...)", but in the case of a
 			# user lookup it's the string "(dlsym)".  If we don't
 			# find this offset information we've been given a debug
-			# file that didn't user the "datail" token, in which case
+			# file that didn't use the "detail" token, in which case
 			# we're not getting all the information we need.
 			if ($Fields[$Offset] =~ /^\((.*)\)/) {
 				if ($1 eq 'dlsym') {
@@ -680,8 +637,8 @@
 				$Objects{$DstFile}{$SymName} |= $Cpyr;
 			}
 			if ($BndInfo =~ /filtee/) {
-				$Symbols{$SymName}{$DstFile}[$ObjFlag] |= $Filt;
-				$Objects{$DstFile}{$SymName} |= $Filt;
+				$Symbols{$SymName}{$DstFile}[$ObjFlag] |= $Gfte;
+				$Objects{$DstFile}{$SymName} |= $Gfte;
 			}
 			if ($BndInfo =~ /interpose/) {
 				$Symbols{$SymName}{$DstFile}[$ObjFlag] |= $Intp;
@@ -699,40 +656,107 @@
 	}
 	close($FileHandle);
 
-	# Now that we've processed all objects, complete any auxiliary filtee
-	# tagging.  For each filtee, determine which of the symbols it exports
-	# are also defined in its filters.  If a filtee is bound to, the
+	# Now that we've processed all objects, traverse the set of object
+	# filters that have been captured from parsing any FILTER and AUXILIARY
+	# dynamic tags.  For each filtee, determine which of the symbols it
+	# exports are also defined in the filter.  If a filter is bound to, the
 	# runtime linkers diagnostics will indicate a filtee binding.  However,
 	# some of the filtee symbols may not be bound to, so here we mark them
 	# all so as to remove them from any interesting output.
-	for my $Filtee (keys(%Filtees)) {
+	for my $Filter (keys(%ObjFltrs)) {
+
+		# Determine the filtees that are associated with this filter.
+		for my $Filtee (keys(%{$ObjFltrs{$Filter}})) {
+			my ($FileName);
+
+			# Reduce the filtee to a simple file name.  Then, try
+			# and associate this simple file name with the objects
+			# that have been processed.  These objects are typically
+			# recorded with a full path name.
+			chomp($FileName = `basename $Filtee`);
+			for my $Obj (keys(%Objects)) {
+				if ($Obj =~ /\/$FileName$/) {
+					$Filtee = $Obj;
+					last;
+				}
+			}
+
+			if (!exists($Objects{$Filtee})) {
+				next;
+			}
+
+			# Traverse the symbols of the filtee (these are
+			# typically a smaller set than the filter) and if the
+			# symbol is defined by the filter tag the symbol as a
+			# filtee.
+			for my $SymName (keys(%{$Objects{$Filtee}})) {
+				my ($OFlag, $FFlag);
+
+				# Ignore the usual stuff.
+				if (($SymName =~ $MultSyms) ||
+				    ($SymName =~ $CrtSyms)) {
+					next;
+				}
 
-		# Standard filters aren't captured at all, as nothing can bind
-		# to them.
-		if (!exists($Objects{$Filtee})) {
+				if (!$Symbols{$SymName}{$Filter}) {
+					next;
+				}
+
+				# Determine the type of filter.
+				$OFlag = $Symbols{$SymName}{$Filter}[$ObjFlag];
+
+				# Specifically identify the type of filtee we
+				# have and remove any generic filtee flag.
+				if ($OFlag & ($Osft | $Ssft)) {
+					$FFlag = $Sfte;
+				} else {
+					$FFlag = $Afte;
+				}
+
+				$Symbols{$SymName}{$Filtee}[$ObjFlag] |= $FFlag;
+				$Symbols{$SymName}{$Filtee}[$ObjFlag] &= ~$Gfte;
+			}
+		}
+	}
+
+	# Traverse the set of per-symbol filters making sure we've tagged any
+	# associated filtee symbols, as we did above for object filters.
+	for my $Filtee (keys(%SymFltes)) {
+		my ($FullPath) = $Filtee;
+		my ($FileName);
+
+		# Reduce the filtee to a simple file name.  Then, try and
+		# associate this simple file name with the objects that have
+		# been processed.  These objects are typically recorded with a
+		# full path name.
+		chomp($FileName = `basename $Filtee`);
+		for my $Obj (keys(%Objects)) {
+			if ($Obj =~ /\/$FileName$/) {
+				$FullPath = $Obj;
+				last;
+			}
+		}
+
+		if (!exists($Objects{$FullPath})) {
 			next;
 		}
 
-		# Determine what symbols this filtee offers.
-		foreach my $SymName (keys(%{$Objects{$Filtee}})) {
+		for my $SymName (keys(%{$SymFltes{$Filtee}})) {
+			my ($OFlag, $FFlag);
+
+			# Determine the type of filter.
+			$OFlag = $SymFltes{$Filtee}{$SymName}[$SymFlag];
 
-			# Ignore the usual reserved stuff.
-			if (!$opt{a} && (($SymName =~ $MultSyms) ||
-			    ($SymName =~ $CrtSyms))) {
-				next;
+			# Specifically identify the type of filtee we have and
+			# remove any generic filtee flag.
+			if ($OFlag & $Ssft) {
+				$FFlag = $Sfte;
+			} else {
+				$FFlag = $Afte;
 			}
 
-			# Determine whether this symbol exists in our filter.
-			for my $Filter (keys(%{$Filtees{$Filtee}})) {
-				if (!$Symbols{$SymName}{$Filter}) {
-					next;
-				}
-				if (!($Symbols{$SymName}{$Filter}[$ObjFlag] &
-				    $Msft)) {
-					next;
-				}
-				$Symbols{$SymName}{$Filtee}[$ObjFlag] |= $Filt;
-			}
+			$Symbols{$SymName}{$FullPath}[$ObjFlag] |= $FFlag;
+			$Symbols{$SymName}{$FullPath}[$ObjFlag] &= ~$Gfte;
 		}
 	}
 
@@ -777,7 +801,7 @@
 				# symbols that have been bound to from an
 				# external object, or must be global to enable
 				# a binding to an interposing definition.
-				# Skip bindings to ourself as these are
+				# Skip bindings to ourself, as these are
 				# candidates for demoting to local.
 				if (!($Flag & ($Extn | $Intp))) {
 					next;
@@ -880,11 +904,14 @@
 				# If we haven't been asked for all symbols, only
 				# print those reserved symbols that have been
 				# bound to, as the number of reserved symbols
-				# can be quite excessive.
+				# can be quite excessive.  Also, remove any
+				# standard filters, as nothing can bind to these
+				# symbols anyway.
 				if (!$opt{a} && ((($SymName =~ $MultSyms) &&
 				    (($Flag & ($Extn | $Self)) == 0)) ||
 				    (($SymName =~ $CrtSyms) && (($Flag &
-				    ($Extn | $Self | $Prot)) == 0)))) {
+				    ($Extn | $Self | $Prot)) == 0)) ||
+				    ($Flag & ($Ssft | $Osft)))) {
 					next;
 				}
 
@@ -925,7 +952,7 @@
 					$Str = $Str . 'C';
 				}
 				# Is this symbol part of filtee.
-				if ($Flag & $Filt) {
+				if ($Flag & ($Sfte | $Afte | $Gfte)) {
 					$Str = $Str . 'F';
 				}
 				# Is this symbol protected (in which case there
@@ -947,7 +974,7 @@
 				if ($Flag & $Msft) {
 					$Str = $Str . 'R';
 				}
-				# Does this definition explicity define no
+				# Does this definition explicitly define no
 				# direct binding.
 				if ($Flag & $Nodi) {
 					$Str = $Str . 'N';
@@ -995,24 +1022,33 @@
 {
 	my ($SymName) = @_;
 	my ($ObjCnt, $GFlags, $BndCnt, $FltCnt, $NodiCnt, $RdirCnt, $ExRef);
+	my ($TotCnt);
 
 	# Scan all definitions of this symbol, thus determining the definition
 	# count, the number of filters, redirections, executable references
 	# (copy-relocations, or plt addresses), no-direct bindings, and the
 	# number of definitions that have been bound to.
 	$ObjCnt = $GFlags = $BndCnt = $FltCnt =
-		$NodiCnt = $RdirCnt = $ExRef = 0;
+	    $NodiCnt = $RdirCnt = $ExRef = $TotCnt = 0;
 	foreach my $Obj (keys(%{$Symbols{$SymName}})) {
 		my ($Flag) = $Symbols{$SymName}{$Obj}[$ObjFlag];
 
+		$TotCnt++;
+
 		# Ignore standard filters when determining the symbol count, as
 		# a standard filter can never be bound to.
 		if (($Flag & ($Osft | $Ssft)) == 0) {
 			$ObjCnt++;
 		}
 
+		# If we're only looking at interesting objects, then standard
+		# filters are ignored, so suppress any standard filtee tagging.
+		if (!$opt{a}) {
+			$Flag = $Symbols{$SymName}{$Obj}[$ObjFlag] &= ~$Sfte;
+		}
+
 		$GFlags |= $Flag;
-		if ($Flag & $Filt) {
+		if ($Flag & ($Sfte | $Afte | $Gfte)) {
 			$FltCnt++;
 		}
 		if ($Flag & $Nodi) {
@@ -1044,7 +1080,7 @@
 	# If we want all symbols, return the count.  If we want all bound
 	# symbols, return the count provided it is non-zero.
 	if ($opt{a} && (!$opt{b} || ($BndCnt > 0))) {
-		return $ObjCnt;
+		return $TotCnt;
 	}
 
 	# Single instance symbol definitions aren't very interesting.
@@ -1117,13 +1153,18 @@
 # object has been versioned.
 sub GetAllSymbols {
 	my ($Obj) = @_;
-	my (@Elfd, @Elfs, @Elfr, $Type, $Exec, $FileHandle);
+	my ($Type, $FileHandle);
 	my (%AddrToName, %NameToAddr);
+	my ($Exec) = 0;
 	my ($Vers) = 0;
 	my ($Symb) = 0;
 	my ($Copy) = 0;
 	my ($Interpose) = 0;
 	my ($Fltr) = 0;
+	my ($Ehdr) = 0;
+	my ($Dyn) = 0;
+	my ($Rel) = 0;
+	my ($Info) = 0;
 
 	# Determine whether we've already retrieved this object's symbols.
 	# Also, ignore the runtime linker, it's on a separate link-map, and
@@ -1139,76 +1180,135 @@
 		return;
 	}
 
-	# Get the dynamic information.
-	@Elfd = split(/\n/, `LC_ALL=C elfdump -d '$Obj' 2> /dev/null`);
+	# Get as much ELF information as we can from elfdump(1).  A second
+	# invocation of elfdump(1) is required to obtain the symbol table, whose
+	# processing can be affected by states determined during this pass.
+	#
+	# The information required:
+	#	-e	ELF header provides the file type
+	#	-d	dynamic information provides filter names 
+	#	-r	relocations provide for copy relocations
+	#	-y	symbol information section provide pre-symbol filters
+	#		and direct binding information
+	#
+	# As this information can be quite large, process the elfdump(1) output
+	# through a pipe.
+	open($FileHandle, "LC_ALL=C elfdump -edry '$Obj' 2> /dev/null |");
 
-	# If there's no information, it's possible we've been given a debug
-	# output file and are processing it from a location from which the
-	# dependencies specified in the debug file aren't accessible.
-	if (!@Elfd) {
-		printf STDERR gettext("%s: %s: unable to process ELF file\n"),
-		    $Prog, $Obj;
+	while (defined(my $Line = <$FileHandle>)) {
+		my (@Fields);
+
+		chomp($Line);
 
-		# Add the file to our list, so that we don't create the same
-		# message again.  Processing should continue so that we can
-		# flush out as many error messages as possible.
-		$Objects{$Obj}{"DoesNotExist"} = 0;
-		return;
-	}
+		# Each collection of data is preceded with a title that
+		# starts in column 0.  Items of data all have some form of
+		# indentation.
+		if ($Line =~ /^[A-Z]/) {
+			if ($Line =~ /^ELF Header/) {
+				$Ehdr = 1;
+				$Dyn = $Rel = $Info = 0;
+			} elsif ($Line =~ /^Dynamic Section:/) {
+				$Dyn = 1;
+				$Ehdr = $Rel = $Info = 0;
+			} elsif ($Line =~ /^Relocation Section:/) {
+				$Rel = 1;
+				$Ehdr = $Dyn = $Info = 0;
+			} elsif ($Line =~ /^Syminfo Section:/) {
+				$Info = 1;
+				$Ehdr = $Dyn = $Rel = 0;
+			} else {
+				$Ehdr = $Dyn = $Rel = $Info = 0;
+			}
+			next;
+		}
 
-	# If we're processing a filter there's no need to save any symbols, as
-	# no bindings will occur to this object.
-	#
-	# Determine whether we've got a symbolicly bound object.  With newer
-	# linkers all symbols will be marked as protected ("P"), but with older
-	# linkers this state could only be intuited from the symbolic dynamic
-	# tag.
-	foreach my $Line (@Elfd) {
-		my (@Fields);
-		@Fields = split(' ', $Line);
+		# Inspect the ELF header.
+		if ($Ehdr eq 1) {
+			# Determine the ELF file type from the e_type element.
+			if ($Line =~ /e_type:/) {
+				if ($Line =~ /ET_EXEC/) {
+					$Exec = 1;
+				}
 
-		# Determine if the FILTER tag is set.
-		if ($#Fields == 3) {
-			if ($Fields[1] eq "FILTER") {
-				$Fltr |= $Osft;
+				# There's nothing of interest left in the ELF
+				# header, so skip processing other entries.
+				$Ehdr = 0;
 				next;
 			}
-			if ($Fields[1] eq "AUXILIARY") {
-				$Fltr |= $Oaft;
+		}
+
+		# Inspect the .dynamic section.
+		if ($Dyn eq 1) {
+			@Fields = split(' ', $Line);
+
+			# Determine if the FILTER or AUXILIARY tag is set.
+			if ($#Fields == 3) {
+				my ($Flte) = 0;
+
+				if ($Fields[1] eq 'FILTER') {
+					$Fltr |= $Osft;
+					$Flte = 1;
+				}
+				elsif ($Fields[1] eq 'AUXILIARY') {
+					$Fltr |= $Oaft;
+					$Flte = 1;
+				}
+				if ($Flte eq 1) {
+					my (@Filtees) = split(':', $Fields[3]);
+
+					for my $Filtee (@Filtees) {
+						if ($Filtee =~ $Rtld) {
+							next;
+						}
+						$ObjFltrs{$Obj}{$Filtee} = 1;
+					}
+				}
+				next;
+			}
+
+			# We're only interested in the FLAGS entry.
+			if (($#Fields < 4) || ($Fields[1] !~ /^FLAGS/)) {
+				next;
+			}
+
+			# Determine whether we've got a symbolicly bound object.
+			# With newer link-editors, all symbols will be marked as
+			# protected ("P"), but with older link-editors this
+			# state could only be inferred from the symbolic dynamic
+			# tag.
+			if (($Fields[1] eq 'FLAGS') &&
+			    ($Line =~ / SYMBOLIC /)) {
+				$Symb = 1;
+				next;
+			}
+
+			# Determine whether this object is an interposer.
+			if (($Fields[1] eq 'FLAGS_1') &&
+			    ($Line =~ / INTERPOSE /)) {
+				$Interpose = 1;
 				next;
 			}
 			next;
 		}
 
-		# We're only interested in the FLAGS entry.
-		if (($#Fields < 4) || ($Fields[1] !~ "^FLAGS")) {
-			next;
-		}
-		if (($Fields[1] eq "FLAGS") && ($Line =~ " SYMBOLIC ")) {
-			$Symb = 1;
-			next;
-		}
-		if (($Fields[1] eq "FLAGS_1") && ($Line =~ " INTERPOSE ")) {
-			$Interpose = 1;
-		}
-	}
+		# Inspect the relocation information.  As we're only looking
+		# for copy relocations, this processing is only necessary for
+		# executables.
+		if ($Rel eq 1) {
+			my ($SymName);
 
-	# If this file is a dynamic executable, determine if this object has
-	# any copy relocations so that any associated bindings can be labeled
-	# more meaningfully.
-	$Type = `LC_ALL=C file '$Obj'`;
-	if ($Type =~ /executable/) {
-		$Exec = 1;
-		# Obtain any copy relocations.
-		@Elfr = split(/\n/, `LC_ALL=C elfdump -r '$Obj' 2>&1`);
-
-		foreach my $Rel (@Elfr) {
-			my ($SymName, @Fields);
-
-			if ($Rel !~ / R_[A-Z0-9]+_COPY /) {
+			if ($Exec eq 0) {
+				$Rel = 0;
 				next;
 			}
-			@Fields = split(' ', $Rel);
+
+			# Obtain any copy relocations.
+			if ($Line !~ / R_[A-Z0-9]+_COPY /) {
+				next;
+			}
+
+			@Fields = split(' ', $Line);
+
 			# Intel relocation records don't contain an addend,
 			# where as every other supported platform does.
 			if ($Fields[0] eq 'R_386_COPY') {
@@ -1221,48 +1321,114 @@
 			$Objects{$Obj}{$SymName} |= $Cpyr;
 			$Copy = 1;
 		}
-	} else {
-		$Exec = 0;
+
+		# Inspect the .SUNW_syminfo section.
+		if ($Info eq 1) {
+			my ($SymName);
+			my ($Flags) = 0;
+
+			@Fields = split(' ', $Line);
+
+			# Binding attributes are in the second column.
+			if ($#Fields < 1) {
+				next;
+			}
+			if ($Fields[1] =~ /N/) {
+				$Flags |= $Nodi;
+			}
+			if ($Fields[1] =~ /F/) {
+				$Flags |= $Ssft;
+			}
+			if ($Fields[1] =~ /A/) {
+				$Flags |= $Saft;
+			}
+
+			# Determine the symbol name based upon the number of
+			# fields.
+			if ($Flags) {
+				$SymName = $Fields[$#Fields];
+				$Symbols{$SymName}{$Obj}[$ObjFlag] |= $Flags;
+				$Objects{$Obj}{$SymName} |= $Flags;
+			}
+
+			# If this is a filter, we need to tag the associated
+			# filtee symbol.  However, the filtee might not have
+			# been processed yet, so save this information for later.
+			$Flags &= ~$Nodi;
+			if ($Flags) {
+				my ($Filtee) = $Fields[$#Fields - 1];
+
+				if ($Filtee =~ $Rtld) {
+					next;
+				}
+				$SymFltes{$Filtee}{$SymName}[$SymFlag] = $Flags;
+			}
+		}
 	}
 
-	# Obtain the dynamic symbol table for this object.  Symbol tables can
-	# be quite large, so open the elfump command through a pipe.
+	close($FileHandle);
+
+	# If there's no expected information, it's possible we've been given a
+	# debug output file and are processing the file from a location from
+	# which the dependencies specified in the debug file aren't accessible.
+	if ($Dyn eq 0) {
+		printf STDERR gettext("%s: %s: unable to process ELF file\n"),
+		    $Prog, $Obj;
+
+		# Add the file to our list, so that we don't create the same
+		# message again.  Processing should continue so that we can
+		# flush out as many error messages as possible.
+		$Objects{$Obj}{"DoesNotExist"} = 0;
+		return;
+	}
+
+	# Process elfdump(1) once more to obtain the .dynsym symbol table.
 	open($FileHandle, "LC_ALL=C elfdump -sN.dynsym '$Obj' 2> /dev/null |");
 
-	# Now process all symbols.
 	while (defined(my $Line = <$FileHandle>)) {
 		chomp($Line);
 
 		my (@Fields) = split(' ', $Line);
 		my ($Flags);
 
-		# We're only interested in defined non-reserved symbol entries.
-		# Note, ABS and NOTY symbols of non-zero size have been known to
-		# occur, so capture them.
+		# We're only interested in defined symbol entries.  Unless
+		# we've been asked for all symbols, ignore any ABS or NOTY
+		# symbols.  The former are typically reserved symbols or
+		# versioning names.  The latter are labels that are not bound
+		# to.  Note, ABS and NOTY symbols of non-zero size have been
+		# known to occur, so capture them.
 		if (($#Fields < 8) || ($Fields[4] !~ $GlobWeak) ||
-		    ($Fields[7] =~ $UndefSym) || (!$opt{a} &&
-		    ($Fields[7] =~ $IgnSyms) && (oct($Fields[2]) eq 0))) {
+		    ($Fields[7] eq 'UNDEF') ||
+		    (!$opt{a} && (oct($Fields[2]) eq 0) &&
+		    ((($Fields[7] eq 'ABS') && ($Fields[3] eq 'OBJT')) ||
+		    ($Fields[3] eq 'NOTY')))) {
 			next;
 		}
 
-		# If we're found copy relocations, save the address and names
-		# of any OBJT definitions, together with the copy symbol.
-		if ($Copy && ($Fields[3] eq 'OBJT')) {
+		# If we're found copy relocations, save the address of all OBJT
+		# definitions, together with the copy symbol.  These definitions
+		# are used to determine whether the copy symbol has any aliases
+		# (ie. __iob and _iob).
+		if (($Copy eq 1) && ($Fields[3] eq 'OBJT')) {
 			push(@{$AddrToName{$Fields[1]}}, $Fields[8]);
-		}
-		if (($Symbols{$Fields[8]}{$Obj}) &&
-		    ($Symbols{$Fields[8]}{$Obj}[$ObjFlag] & $Cpyr)) {
-			$NameToAddr{$Fields[8]} = $Fields[1];
+
+			if (($Symbols{$Fields[8]}{$Obj}) &&
+			    ($Symbols{$Fields[8]}{$Obj}[$ObjFlag] & $Cpyr)) {
+				$NameToAddr{$Fields[8]} = $Fields[1];
+			}
 		}
 
+		# Identify this symbol as global, and associate it with any
+		# object filtering.
+		$Flags = $Glob | $Fltr;
+
 		# If the symbol visibility is protected, this is an internal
-		# symbolic binding (NOTE, an INTERNAL visibility for a global
+		# symbolic binding.  Note, an INTERNAL visibility for a global
 		# symbol is invalid, but for a while ld(1) was setting this
-		# attribute mistakenly for protected).
-		# If this is a dynamic executable, mark its symbols as protected
-		# (they can't be interposed on any more than symbols defined
+		# attribute mistakenly for protected.  If this is a dynamic
+		# executable, mark its symbols as protected.  These symbols
+		# can't be interposed on any more than symbols defined as
 		# protected within shared objects).
-		$Flags = $Glob | $Fltr;
 		if (($Fields[5] =~ /^[IP]$/) || $Symb || $Exec) {
 			$Flags |= $Prot;
 		}
@@ -1273,8 +1439,8 @@
 		}
 
 		# Identify the symbol as a function or data type, and for the
-		# latter, capture the symbol size.  Ignore the standard
-		# symbolic labels, as we don't want to type them.
+		# latter, capture the symbol size.  Ignore the standard symbolic
+		# labels, as we don't want to type them.
 		if ($Fields[8] !~ $MultSyms) {
 			if ($Fields[3] =~ /^FUNC$/) {
 				$Flags |= $Func;
@@ -1303,41 +1469,8 @@
 	}
 	close($FileHandle);
 
-	# Obtain any symbol information table for this object.  Symbol tables can
-	# be quite large, so open the elfump command through a pipe.
-	open($FileHandle, "LC_ALL=C elfdump -y '$Obj' 2> /dev/null |");
-
-	# Now process all symbols.
-	while (defined(my $Line = <$FileHandle>)) {
-		chomp($Line);
-
-		my (@Fields) = split(' ', $Line);
-		my ($Flags) = 0;
-
-		# Binding attributes are in the second column.
-		if ($#Fields < 1) {
-			next;
-		}
-		if ($Fields[1] =~ /N/) {
-			$Flags |= $Nodi
-		}
-		if ($Fields[1] =~ /F/) {
-			$Flags |= $Ssft;
-		}
-		if ($Fields[1] =~ /A/) {
-			$Flags |= $Saft;
-		}
-
-		# Determine the symbol name based upon the number of fields.
-		if ($Flags && $Symbols{$Fields[$#Fields]}{$Obj}) {
-			$Symbols{$Fields[$#Fields]}{$Obj}[$ObjFlag] |= $Flags;
-			$Objects{$Obj}{$Fields[$#Fields]} |= $Flags;
-		}
-	}
-	close($FileHandle);
-
-	# If this symbol has already been marked as a copy-relocation reference,
-	# see if this symbol has any aliases, which should also be marked.
+	# Process any copy relocation symbols to see if the copy symbol has any
+	# aliases, which should also be marked as copy relocations.
 	if ($Copy) {
 		foreach my $SymName (keys(%NameToAddr)) {
 			my ($Addr) = $NameToAddr{$SymName};
--- a/usr/src/cmd/sgs/libld/common/_libld.h	Tue Oct 24 01:13:19 2006 -0700
+++ b/usr/src/cmd/sgs/libld/common/_libld.h	Tue Oct 24 09:55:12 2006 -0700
@@ -284,6 +284,7 @@
 #define	ld_sort_seg_list	ld64_sort_seg_list
 #define	ld_sunwmove_preprocess	ld64_sunwmove_preprocess
 #define	ld_sup_atexit		ld64_sup_atexit
+#define	ld_sup_open		ld64_sup_open
 #define	ld_sup_file		ld64_sup_file
 #define	ld_sup_loadso		ld64_sup_loadso
 #define	ld_sup_input_done	ld64_sup_input_done
@@ -380,6 +381,7 @@
 #define	ld_sort_seg_list	ld32_sort_seg_list
 #define	ld_sunwmove_preprocess	ld32_sunwmove_preprocess
 #define	ld_sup_atexit		ld32_sup_atexit
+#define	ld_sup_open		ld32_sup_open
 #define	ld_sup_file		ld32_sup_file
 #define	ld_sup_loadso		ld32_sup_loadso
 #define	ld_sup_input_done	ld32_sup_input_done
@@ -503,6 +505,9 @@
 extern uintptr_t	ld_sort_seg_list(Ofl_desc *);
 extern uintptr_t	ld_sunwmove_preprocess(Ofl_desc *);
 extern void		ld_sup_atexit(Ofl_desc *, int);
+extern void		ld_sup_open(Ofl_desc *, const char **, const char **,
+			    int *, int, Elf **, Elf *ref, size_t,
+			    const Elf_Kind);
 extern void		ld_sup_file(Ofl_desc *, const char *, const Elf_Kind,
 			    int flags, Elf *);
 extern uintptr_t	ld_sup_loadso(Ofl_desc *, const char *);
--- a/usr/src/cmd/sgs/libld/common/args.c	Tue Oct 24 01:13:19 2006 -0700
+++ b/usr/src/cmd/sgs/libld/common/args.c	Tue Oct 24 09:55:12 2006 -0700
@@ -1511,9 +1511,10 @@
 
 		DBG_CALL(Dbg_args_files(ofl->ofl_lml, optind, path));
 
-		ifl = ld_process_open(path, path, fd, ofl,
+		ifl = ld_process_open(path, path, &fd, ofl,
 		    (FLG_IF_CMDLINE | FLG_IF_NEEDED), &rej);
-		(void) close(fd);
+		if (fd != -1)
+			(void) close(fd);
 		if (ifl == (Ifl_desc *)S_ERROR)
 			return (S_ERROR);
 
--- a/usr/src/cmd/sgs/libld/common/files.c	Tue Oct 24 01:13:19 2006 -0700
+++ b/usr/src/cmd/sgs/libld/common/files.c	Tue Oct 24 09:55:12 2006 -0700
@@ -2058,18 +2058,39 @@
  * archive (see libs.c: ld_process_archive()).
  */
 Ifl_desc *
-ld_process_open(const char *path, const char *file, int fd, Ofl_desc *ofl,
+ld_process_open(const char *opath, const char *ofile, int *fd, Ofl_desc *ofl,
     Half flags, Rej_desc *rej)
 {
-	Elf	*elf;
+	Elf		*elf;
+	const char	*npath = opath;
+	const char	*nfile = ofile;
 
-	if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
-		eprintf(ofl->ofl_lml, ERR_ELF, MSG_INTL(MSG_ELF_BEGIN), path);
+	if ((elf = elf_begin(*fd, ELF_C_READ, NULL)) == NULL) {
+		eprintf(ofl->ofl_lml, ERR_ELF, MSG_INTL(MSG_ELF_BEGIN), npath);
 		ofl->ofl_flags |= FLG_OF_FATAL;
 		return (0);
 	}
 
-	return (ld_process_ifl(path, file, fd, elf, flags, ofl, rej));
+	/*
+	 * Determine whether the support library wishes to process this open.
+	 * The support library may return:
+	 *   .	a different ELF descriptor (in which case they should have
+	 *	closed the original)
+	 *   .	a different file descriptor (in which case they should have
+	 *	closed the original)
+	 *   .	a different path and file name (presumably associated with
+	 *	a different file descriptor)
+	 *
+	 * A file descriptor of -1, or and ELF descriptor of zero indicates
+	 * the file should be ignored.
+	 */
+	ld_sup_open(ofl, &npath, &nfile, fd, flags, &elf, NULL, 0,
+	    elf_kind(elf));
+
+	if ((*fd == -1) || (elf == NULL))
+		return (0);
+
+	return (ld_process_ifl(npath, nfile, *fd, elf, flags, ofl, rej));
 }
 
 /*
@@ -2121,8 +2142,9 @@
 		if ((_path = libld_malloc(strlen(path) + 1)) == 0)
 			return ((Ifl_desc *)S_ERROR);
 		(void) strcpy(_path, path);
-		ifl = ld_process_open(_path, &_path[dlen], fd, ofl, NULL, rej);
-		(void) close(fd);
+		ifl = ld_process_open(_path, &_path[dlen], &fd, ofl, NULL, rej);
+		if (fd != -1)
+			(void) close(fd);
 		return (ifl);
 	}
 }
@@ -2197,9 +2219,10 @@
 			} else {
 				Rej_desc	_rej = { 0 };
 
-				ifl = ld_process_open(file, ++slash, fd, ofl,
+				ifl = ld_process_open(file, ++slash, &fd, ofl,
 				    NULL, &_rej);
-				(void) close(fd);
+				if (fd != -1)
+					(void) close(fd);
 
 				if (ifl == (Ifl_desc *)S_ERROR) {
 					return (S_ERROR);
--- a/usr/src/cmd/sgs/libld/common/ldlibs.c	Tue Oct 24 01:13:19 2006 -0700
+++ b/usr/src/cmd/sgs/libld/common/ldlibs.c	Tue Oct 24 09:55:12 2006 -0700
@@ -203,9 +203,10 @@
 				return ((Ifl_desc *)S_ERROR);
 			(void) strcpy(_path, path);
 
-			ifl = ld_process_open(_path, &_path[dlen], fd, ofl,
+			ifl = ld_process_open(_path, &_path[dlen], &fd, ofl,
 			    FLG_IF_NEEDED, rej);
-			(void) close(fd);
+			if (fd != -1)
+				(void) close(fd);
 			return (ifl);
 
 		} else if (errno != ENOENT) {
@@ -232,9 +233,10 @@
 			return ((Ifl_desc *)S_ERROR);
 		(void) strcpy(_path, path);
 
-		ifl = ld_process_open(_path, &_path[dlen], fd, ofl,
+		ifl = ld_process_open(_path, &_path[dlen], &fd, ofl,
 		    FLG_IF_NEEDED, rej);
-		(void) close(fd);
+		if (fd != -1)
+			(void) close(fd);
 		return (ifl);
 
 	} else if (errno != ENOENT) {
--- a/usr/src/cmd/sgs/libld/common/libld.msg	Tue Oct 24 01:13:19 2006 -0700
+++ b/usr/src/cmd/sgs/libld/common/libld.msg	Tue Oct 24 09:55:12 2006 -0700
@@ -717,12 +717,14 @@
 
 @ MSG_SUP_START_64	"ld_start64"
 @ MSG_SUP_ATEXIT_64	"ld_atexit64"
+@ MSG_SUP_OPEN_64	"ld_open64"
 @ MSG_SUP_FILE_64	"ld_file64"
 @ MSG_SUP_INSEC_64	"ld_input_section64"
 @ MSG_SUP_SEC_64	"ld_section64"
 
 @ MSG_SUP_START		"ld_start"
 @ MSG_SUP_ATEXIT	"ld_atexit"
+@ MSG_SUP_OPEN		"ld_open"
 @ MSG_SUP_FILE		"ld_file"
 @ MSG_SUP_INSEC		"ld_input_section"
 @ MSG_SUP_SEC		"ld_section"
--- a/usr/src/cmd/sgs/libld/common/libs.c	Tue Oct 24 01:13:19 2006 -0700
+++ b/usr/src/cmd/sgs/libld/common/libs.c	Tue Oct 24 09:55:12 2006 -0700
@@ -402,6 +402,7 @@
 					ofl->ofl_flags |= FLG_OF_FATAL;
 					return (0);
 				}
+
 				if ((arelf = elf_begin(fd, ELF_C_READ,
 				    adp->ad_elf)) == NULL) {
 					eprintf(ofl->ofl_lml, ERR_ELF,
@@ -430,6 +431,17 @@
 					return (S_ERROR);
 				(void) snprintf(arpath, len,
 				    MSG_ORIG(MSG_FMT_ARMEM), name, arname);
+
+				/*
+				 * Determine whether the support library wishes
+				 * to process this open.  See comments in
+				 * ld_process_open().
+				 */
+				ld_sup_open(ofl, (const char **)&arpath,
+				    (const char **)&arname, &fd,
+				    (FLG_IF_EXTRACT | FLG_IF_NEEDED),
+				    &arelf, adp->ad_elf, arsym->as_off,
+				    elf_kind(arelf));
 			}
 
 			/*
@@ -484,7 +496,7 @@
 			DBG_CALL(Dbg_syms_ar_resolve(ofl->ofl_lml, ndx, arsym,
 			    arname, allexrt));
 			if ((err = (uintptr_t)ld_process_ifl(arpath, NULL, fd,
-			    arelf, FLG_IF_EXTRACT | FLG_IF_NEEDED, ofl,
+			    arelf, (FLG_IF_EXTRACT | FLG_IF_NEEDED), ofl,
 			    &_rej)) == S_ERROR)
 				return (S_ERROR);
 
--- a/usr/src/cmd/sgs/libld/common/llib-lld	Tue Oct 24 01:13:19 2006 -0700
+++ b/usr/src/cmd/sgs/libld/common/llib-lld	Tue Oct 24 09:55:12 2006 -0700
@@ -50,10 +50,10 @@
 void		ld32_ofl_cleanup(Ofl_desc *);
 void		ld64_ofl_cleanup(Ofl_desc *);
 
-Ifl_desc	*ld32_process_open(const char *, const char *, int, Ofl_desc *,
-		    Elf32_Half, Rej_desc *);
-Ifl_desc	*ld64_process_open(const char *, const char *, int, Ofl_desc *,
-		    Elf64_Half, Rej_desc *);
+Ifl_desc	*ld32_process_open(const char *, const char *, int *,
+		    Ofl_desc *, Elf32_Half, Rej_desc *);
+Ifl_desc	*ld64_process_open(const char *, const char *, int *,
+		    Ofl_desc *, Elf64_Half, Rej_desc *);
 
 uintptr_t	ld32_reloc_init(Ofl_desc *);
 uintptr_t	ld64_reloc_init(Ofl_desc *);
--- a/usr/src/cmd/sgs/libld/common/support.c	Tue Oct 24 01:13:19 2006 -0700
+++ b/usr/src/cmd/sgs/libld/common/support.c	Tue Oct 24 09:55:12 2006 -0700
@@ -45,12 +45,14 @@
 #if	defined(_ELF64)
 	{MSG_ORIG(MSG_SUP_START_64),	{ 0, 0 }},	/* LDS_START */
 	{MSG_ORIG(MSG_SUP_ATEXIT_64),	{ 0, 0 }},	/* LDS_ATEXIT */
+	{MSG_ORIG(MSG_SUP_OPEN_64),	{ 0, 0 }},	/* LDS_OPEN */
 	{MSG_ORIG(MSG_SUP_FILE_64),	{ 0, 0 }},	/* LDS_FILE */
 	{MSG_ORIG(MSG_SUP_INSEC_64),	{ 0, 0 }},	/* LDS_INSEC */
 	{MSG_ORIG(MSG_SUP_SEC_64),	{ 0, 0 }}	/* LDS_SEC */
 #else	/* Elf32 */
 	{MSG_ORIG(MSG_SUP_START),	{ 0, 0 }},	/* LDS_START */
 	{MSG_ORIG(MSG_SUP_ATEXIT),	{ 0, 0 }},	/* LDS_ATEXIT */
+	{MSG_ORIG(MSG_SUP_OPEN),	{ 0, 0 }},	/* LDS_OPEN */
 	{MSG_ORIG(MSG_SUP_FILE),	{ 0, 0 }},	/* LDS_FILE */
 	{MSG_ORIG(MSG_SUP_INSEC),	{ 0, 0 }},	/* LDS_INSEC */
 	{MSG_ORIG(MSG_SUP_SEC),		{ 0, 0 }}	/* LDS_SEC */
@@ -143,6 +145,68 @@
 }
 
 void
+ld_sup_open(Ofl_desc *ofl, const char **opath, const char **ofile, int *ofd,
+    int flags, Elf **oelf, Elf *ref, size_t off, const Elf_Kind ekind)
+{
+	Func_list	*flp;
+	Listnode	*lnp;
+	const char	*npath = *opath;
+	const char	*nfile = *ofile;
+	Elf		*nelf = *oelf;
+	int		nfd = *ofd;
+
+	for (LIST_TRAVERSE(&support[LDS_OPEN].sup_funcs, lnp, flp)) {
+		int	_flags = 0;
+
+		/*
+		 * This interface was introduced in VERSION3.  Only call this
+		 * function for libraries reporting support for version 3 or
+		 * above.
+		 */
+		if (flp->fl_version < LD_SUP_VERSION3)
+			continue;
+
+		if (!(flags & FLG_IF_CMDLINE))
+			_flags |= LD_SUP_DERIVED;
+		if (!(flags & FLG_IF_NEEDED))
+			_flags |= LD_SUP_INHERITED;
+		if (flags & FLG_IF_EXTRACT)
+			_flags |= LD_SUP_EXTRACTED;
+
+		/*
+		 * If the present object is an extracted archive member, make
+		 * sure the archive offset is reset so that the caller can
+		 * obtain an ELF descriptor to the same member (an elf_begin()
+		 * moves the offset to the next member).
+		 */
+		if (flags & FLG_IF_EXTRACT)
+			(void) elf_rand(ref, off);
+
+		DBG_CALL(Dbg_support_action(ofl->ofl_lml, flp->fl_obj,
+		    support[LDS_OPEN].sup_name, LDS_OPEN, *opath));
+		(*flp->fl_fptr)(&npath, &nfile, &nfd, _flags, &nelf, ref, off,
+		    ekind);
+	}
+
+	/*
+	 * If the file descriptor, ELF descriptor, or file names have been
+	 * modified, then diagnose the differences and return the new data.
+	 * As a basic test, make sure the support library hasn't nulled out
+	 * data ld(1) will try and dereference.
+	 */
+	if ((npath != *opath) || (nfd != *ofd) || (nelf != *oelf)) {
+		Dbg_file_modified(ofl->ofl_lml, flp->fl_obj, *opath, npath,
+		    *ofd, nfd, *oelf, nelf);
+		if (npath)
+			*opath = npath;
+		if (nfile)
+			*ofile = nfile;
+		*ofd = nfd;
+		*oelf = nelf;
+	}
+}
+
+void
 ld_sup_file(Ofl_desc *ofl, const char *ifile, const Elf_Kind ekind, int flags,
     Elf *elf)
 {
@@ -203,8 +267,8 @@
 	 * return the new section header.
 	 */
 	if (nshdr != *oshdr) {
-		Dbg_shdr_modified(ofl->ofl_lml, ifl->ifl_ehdr->e_machine,
-		    *oshdr, nshdr, sname);
+		Dbg_shdr_modified(ofl->ofl_lml, flp->fl_obj,
+		    ifl->ifl_ehdr->e_machine, *oshdr, nshdr, sname);
 		*oshdr = nshdr;
 	}
 	return (0);
--- a/usr/src/cmd/sgs/libld/common/update.c	Tue Oct 24 01:13:19 2006 -0700
+++ b/usr/src/cmd/sgs/libld/common/update.c	Tue Oct 24 09:55:12 2006 -0700
@@ -3200,8 +3200,8 @@
 		/*
 		 * Adjust the address offset and p_align if needed.
 		 */
-		if (!((ofl->ofl_flags1 & FLG_OF1_VADDR) ||
-			(ofl->ofl_dtflags_1 & DF_1_NOHDR))) {
+		if (((sgp->sg_flags & FLG_SG_VADDR) == 0) &&
+		    ((ofl->ofl_dtflags_1 & DF_1_NOHDR) == 0)) {
 			if (phdr->p_align != 0)
 				vaddr += phdr->p_offset % phdr->p_align;
 			else
--- a/usr/src/cmd/sgs/liblddbg/common/files.c	Tue Oct 24 01:13:19 2006 -0700
+++ b/usr/src/cmd/sgs/liblddbg/common/files.c	Tue Oct 24 09:55:12 2006 -0700
@@ -681,3 +681,37 @@
 	else
 		dbg_print(lml, MSG_INTL(MSG_FIL_SKIP_2), nname);
 }
+
+void
+Dbg_file_modified(Lm_list *lml, const char *obj, const char *oname,
+    const char *nname, int ofd, int nfd, Elf *oelf, Elf *nelf)
+{
+	const char	*str;
+
+	if (DBG_NOTCLASS(DBG_C_FILES | DBG_C_SUPPORT))
+		return;
+	if (DBG_NOTDETAIL())
+		return;
+
+	Dbg_util_nl(lml, DBG_NL_STD);
+	dbg_print(lml, MSG_INTL(MSG_FIL_MODIFIED), oname, obj);
+
+	if (nname != oname)
+		dbg_print(lml, MSG_INTL(MSG_FIL_NAMECHANGE), nname);
+	if (nfd != ofd) {
+		if (nfd == -1)
+			str = MSG_INTL(MSG_FIL_IGNORE);
+		else
+			str = MSG_ORIG(MSG_STR_EMPTY);
+		dbg_print(lml, MSG_INTL(MSG_FIL_FDCHANGE), ofd, nfd, str);
+	}
+	if (nelf != oelf) {
+		if (nelf == 0)
+			str = MSG_INTL(MSG_FIL_IGNORE);
+		else
+			str = MSG_ORIG(MSG_STR_EMPTY);
+		dbg_print(lml, MSG_INTL(MSG_FIL_ELFCHANGE), EC_NATPTR(oelf),
+		    EC_NATPTR(nelf), str);
+	}
+	Dbg_util_nl(lml, DBG_NL_STD);
+}
--- a/usr/src/cmd/sgs/liblddbg/common/liblddbg.msg	Tue Oct 24 01:13:19 2006 -0700
+++ b/usr/src/cmd/sgs/liblddbg/common/liblddbg.msg	Tue Oct 24 09:55:12 2006 -0700
@@ -435,6 +435,12 @@
 @ MSG_FIL_CONFIG_ERR_5	"incompatible ELF class, byte order, or machine \
 			 architecture"
 
+@ MSG_FIL_MODIFIED	"file=%s; open modified by support library: %s"
+@ MSG_FIL_NAMECHANGE	"    name changed to: %s"
+@ MSG_FIL_FDCHANGE	"    file descriptor changed from: %d to: %d %s"
+@ MSG_FIL_ELFCHANGE	"    ELF descriptor changed from: 0x%llx to: 0x%llx %s"
+@ MSG_FIL_IGNORE	" (file will be ignored)"
+
 @ MSG_CNTL_TITLE	"control list processing complete: moving lmco 0x%llx \
 			 to lmco 0x%llx"
 
@@ -522,9 +528,10 @@
 
 # Section header messages
 
-@ MSG_SHD_MODIFIED	"section=%s; section header modified by support library"
-@ MSG_SHD_ORIG		" original:"
-@ MSG_SHD_NEW		" new:"
+@ MSG_SHD_MODIFIED	"section=%s; section header modified by support \
+			 library: %s"
+@ MSG_SHD_ORIG		"  original:"
+@ MSG_SHD_NEW		"  new:"
 
 # Section messages
 
--- a/usr/src/cmd/sgs/liblddbg/common/llib-llddbg	Tue Oct 24 01:13:19 2006 -0700
+++ b/usr/src/cmd/sgs/liblddbg/common/llib-llddbg	Tue Oct 24 09:55:12 2006 -0700
@@ -129,6 +129,10 @@
 void	Dbg64_file_ldso(Rt_map *, char **, auxv_t *, const char *, Aliste);
 void	Dbg32_file_mode_promote(Rt_map *, int);
 void	Dbg64_file_mode_promote(Rt_map *, int);
+void	Dbg32_file_modified(Lm_list *, const char *, const char *, const char *,
+	    int, int, Elf *, Elf *);
+void	Dbg64_file_modified(Lm_list *, const char *, const char *, const char *,
+	    int, int, Elf *, Elf *);
 void	Dbg32_file_needed(Rt_map *, const char *);
 void	Dbg64_file_needed(Rt_map *, const char *);
 void	Dbg32_file_output(Ofl_desc *);
@@ -297,8 +301,10 @@
 void    Dbg32_seg_title(Lm_list *);
 void    Dbg64_seg_title(Lm_list *);
 
-void	Dbg32_shdr_modified(Lm_list *, Half, Shdr *, Shdr *, const char *);
-void	Dbg64_shdr_modified(Lm_list *, Half, Shdr *, Shdr *, const char *);
+void	Dbg32_shdr_modified(Lm_list *, const char *, Half, Shdr *, Shdr *,
+	    const char *);
+void	Dbg64_shdr_modified(Lm_list *, const char *, Half, Shdr *, Shdr *,
+	    const char *);
 
 void	Dbg32_statistics_ar(Ofl_desc *);
 void	Dbg64_statistics_ar(Ofl_desc *);
--- a/usr/src/cmd/sgs/liblddbg/common/mapfile-vers	Tue Oct 24 01:13:19 2006 -0700
+++ b/usr/src/cmd/sgs/liblddbg/common/mapfile-vers	Tue Oct 24 09:55:12 2006 -0700
@@ -38,7 +38,7 @@
 #	Policy for Shared Library Version Names and Interface Definitions
 
 
-SUNWprivate_4.53 {
+SUNWprivate_4.54 {
 	global:
 		dbg_desc = NODIRECT;	# interposed - ld.so.1(1)
 		dbg_print = NODIRECT;	# interposed - ld(1) and ld.so.1(1)
@@ -131,6 +131,8 @@
 		Dbg64_file_ldso;
 		Dbg32_file_mode_promote;
 		Dbg64_file_mode_promote;
+		Dbg32_file_modified;
+		Dbg64_file_modified;
 		Dbg32_file_needed;
 		Dbg64_file_needed;
 		Dbg32_file_output;
--- a/usr/src/cmd/sgs/liblddbg/common/shdr.c	Tue Oct 24 01:13:19 2006 -0700
+++ b/usr/src/cmd/sgs/liblddbg/common/shdr.c	Tue Oct 24 09:55:12 2006 -0700
@@ -48,16 +48,16 @@
 }
 
 void
-Dbg_shdr_modified(Lm_list *lml, Half mach, Shdr *oshdr, Shdr *nshdr,
-    const char *name)
+Dbg_shdr_modified(Lm_list *lml, const char *obj, Half mach, Shdr *oshdr,
+    Shdr *nshdr, const char *name)
 {
-	if (DBG_NOTCLASS(DBG_C_SECTIONS))
+	if (DBG_NOTCLASS(DBG_C_SECTIONS | DBG_C_SUPPORT))
 		return;
 	if (DBG_NOTDETAIL())
 		return;
 
 	Dbg_util_nl(lml, DBG_NL_STD);
-	dbg_print(lml, MSG_INTL(MSG_SHD_MODIFIED), name);
+	dbg_print(lml, MSG_INTL(MSG_SHD_MODIFIED), name, obj);
 
 	dbg_print(lml, MSG_INTL(MSG_SHD_ORIG));
 	Elf_shdr(lml, mach, oshdr);
--- a/usr/src/cmd/sgs/liblddbg/common/support.c	Tue Oct 24 01:13:19 2006 -0700
+++ b/usr/src/cmd/sgs/liblddbg/common/support.c	Tue Oct 24 09:55:12 2006 -0700
@@ -69,7 +69,7 @@
 
 	if (ndx == LDS_START)
 		str = MSG_INTL(MSG_SUP_OUTFILE);
-	else if (ndx == LDS_FILE)
+	else if ((ndx == LDS_OPEN) || (ndx == LDS_FILE))
 		str = MSG_INTL(MSG_SUP_INFILE);
 	else if (ndx == LDS_INSEC)
 		str = MSG_INTL(MSG_SUP_INSEC);
--- a/usr/src/cmd/sgs/packages/common/SUNWonld-README	Tue Oct 24 01:13:19 2006 -0700
+++ b/usr/src/cmd/sgs/packages/common/SUNWonld-README	Tue Oct 24 09:55:12 2006 -0700
@@ -1136,3 +1136,10 @@
 6475375 symbol search optimization to reduce rescans
 6475497 elfdump(1) is misreporting sh_link
 6477132 ld.so.1: memory leak when running set*id application
+6479848 Enhancements to the linker support interface needed. (D)
+	PSARC/2006/595 link-editor support library interface - ld_open()
+6482058 lari(1) could be faster, and handle per-symbol filters better
+6482974 defining virtual address of text segment can result in an invalid data
+	segment
+6476734 crle(1m) "-l" as described fails system, crle cores trying to fix
+	/a/var/ld/ld.config in failsafe
--- a/usr/src/cmd/sgs/rtld/common/object.c	Tue Oct 24 01:13:19 2006 -0700
+++ b/usr/src/cmd/sgs/rtld/common/object.c	Tue Oct 24 09:55:12 2006 -0700
@@ -144,7 +144,7 @@
 	 * Proceed to process the input file.
 	 */
 	DBG_CALL(Dbg_util_nl(lml, DBG_NL_STD));
-	if (ld_process_open(name, name, fd, (Ofl_desc *)olmp->rt_priv,
+	if (ld_process_open(name, name, &fd, (Ofl_desc *)olmp->rt_priv,
 	    NULL, &rej) == (Ifl_desc *)S_ERROR)
 		return (0);
 	return (olmp);
--- a/usr/src/head/link.h	Tue Oct 24 01:13:19 2006 -0700
+++ b/usr/src/head/link.h	Tue Oct 24 09:55:12 2006 -0700
@@ -46,18 +46,23 @@
  */
 #ifdef __STDC__
 extern uint_t	ld_version(uint_t);
+extern void	ld_input_done(uint_t *);
+
 extern void	ld_start(const char *, const Elf32_Half, const char *);
 extern void	ld_atexit(int);
+extern void	ld_open(const char **, const char **, int *, int, Elf **,
+			Elf *, size_t, const Elf_Kind);
 extern void	ld_file(const char *, const Elf_Kind, int, Elf *);
 extern void	ld_input_section(const char *, Elf32_Shdr **, Elf32_Word,
 			Elf_Data *, Elf *, uint_t *);
-extern void	ld_input_done(uint_t *);
 extern void	ld_section(const char *, Elf32_Shdr *, Elf32_Word,
 			Elf_Data *, Elf *);
 
 #if defined(_LP64) || defined(_LONGLONG_TYPE)
 extern void	ld_start64(const char *, const Elf64_Half, const char *);
 extern void	ld_atexit64(int);
+extern void	ld_open64(const char **, const char **, int *, int, Elf **,
+			Elf *, size_t, const Elf_Kind);
 extern void	ld_file64(const char *, const Elf_Kind, int, Elf *);
 extern void	ld_input_section64(const char *, Elf64_Shdr **, Elf64_Word,
 			Elf_Data *, Elf *, uint_t *);
@@ -67,39 +72,46 @@
 #endif /* (defined(_LP64) || defined(_LONGLONG_TYPE) */
 #else
 extern void	ld_version();
+extern void	ld_input_done();
+
 extern void	ld_start();
 extern void	ld_atexit();
+extern void	ld_open();
 extern void	ld_file();
 extern void	ld_input_section();
-extern void	ld_input_done();
 extern void	ld_section();
 
 #if defined(_LP64) || defined(_LONGLONG_TYPE)
 extern void	ld_start64();
 extern void	ld_atexit64();
+extern void	ld_open64();
 extern void	ld_file64();
+extern void	ld_input_section64();
 extern void	ld_section64();
 
 #endif /* (defined(_LP64) || defined(_LONGLONG_TYPE) */
 #endif /* __STDC__ */
 
 /*
- * ld_version() version values
+ * ld_version() version values.
  */
 #define	LD_SUP_VNONE	0
 #define	LD_SUP_VERSION1	1
 #define	LD_SUP_VERSION2	2
-#define	LD_SUP_VCURRENT	LD_SUP_VERSION2
-
+#define	LD_SUP_VERSION3	3
+#define	LD_SUP_VCURRENT	LD_SUP_VERSION3
 
 /*
- * flags passed to ld support calls
+ * Flags passed to ld support calls.
  */
 #define	LD_SUP_DERIVED		0x1	/* derived filename */
 #define	LD_SUP_INHERITED	0x2	/* file inherited from .so DT_NEEDED */
 #define	LD_SUP_EXTRACTED	0x4	/* file extracted from archive */
 #endif
 
+/*
+ * Runtime link-map identifiers.
+ */
 #define	LM_ID_BASE		0x00
 #define	LM_ID_LDSO		0x01
 #define	LM_ID_BRAND		0x02	/* marks branded objs in rd_loadobj_t */
@@ -109,9 +121,8 @@
 
 #define	LM_ID_NEWLM		0xff	/* create a new link-map */
 
-
 /*
- * Run-Time Link-Edit Auditing
+ * Runtime Link-Edit Auditing.
  */
 #define	LAV_NONE		0
 #define	LAV_VERSION1		1