PSARC 2006/526 SHT_SUNW_LDYNSYM - default local symbol addition
authorab196087
Tue, 19 Sep 2006 15:38:37 -0700
changeset 2766 897bcb036a29
parent 2765 185055ef5a96
child 2767 06c926d616c5
PSARC 2006/526 SHT_SUNW_LDYNSYM - default local symbol addition 4934427 runtime linker should load up static symbol names visible to dladdr()
usr/src/cmd/sgs/dump/common/dump.c
usr/src/cmd/sgs/elfdump/common/elfdump.c
usr/src/cmd/sgs/include/i386/machdep.h
usr/src/cmd/sgs/include/libld.h
usr/src/cmd/sgs/include/sparc/machdep.h
usr/src/cmd/sgs/libconv/common/dynamic.c
usr/src/cmd/sgs/libconv/common/dynamic.msg
usr/src/cmd/sgs/libconv/common/sections.c
usr/src/cmd/sgs/libconv/common/sections.msg
usr/src/cmd/sgs/libld/common/args.c
usr/src/cmd/sgs/libld/common/libld.msg
usr/src/cmd/sgs/libld/common/outfile.c
usr/src/cmd/sgs/libld/common/sections.c
usr/src/cmd/sgs/libld/common/syms.c
usr/src/cmd/sgs/libld/common/update.c
usr/src/cmd/sgs/librtld/common/dynamic.c
usr/src/cmd/sgs/librtld_db/rdb_demo/common/ps.c
usr/src/cmd/sgs/pvs/common/pvs.c
usr/src/cmd/sgs/rtld/common/_elf.h
usr/src/cmd/sgs/rtld/common/elf.c
usr/src/cmd/sgs/rtld/common/object.c
usr/src/cmd/sgs/rtld/i386/_setup.c
usr/src/uts/common/sys/elf.h
usr/src/uts/common/sys/link.h
--- a/usr/src/cmd/sgs/dump/common/dump.c	Tue Sep 19 15:34:23 2006 -0700
+++ b/usr/src/cmd/sgs/dump/common/dump.c	Tue Sep 19 15:38:37 2006 -0700
@@ -1142,6 +1142,7 @@
 			case DT_PREINIT_ARRAYSZ:
 			case DT_SUNW_RTLDINF:
 			case DT_SUNW_CAP:
+			case DT_SUNW_SYMTAB:
 			case DT_PLTPAD:
 			case DT_MOVETAB:
 			case DT_SYMINFO:
@@ -1202,6 +1203,7 @@
 			case DT_SYMINENT:
 			case DT_VERNEEDNUM:
 			case DT_SPARC_REGISTER:
+			case DT_SUNW_SYMSZ:
 				(void) printf(pdyn_Fmtptr,
 					EC_XWORD(p_dyn.d_un.d_val));
 				break;
--- a/usr/src/cmd/sgs/elfdump/common/elfdump.c	Tue Sep 19 15:34:23 2006 -0700
+++ b/usr/src/cmd/sgs/elfdump/common/elfdump.c	Tue Sep 19 15:38:37 2006 -0700
@@ -1077,7 +1077,8 @@
 		uint_t		symnshxndx;
 
 		if ((shdr->sh_type != SHT_SYMTAB) &&
-		    (shdr->sh_type != SHT_DYNSYM))
+		    (shdr->sh_type != SHT_DYNSYM) &&
+		    (shdr->sh_type != SHT_SUNW_LDYNSYM))
 			continue;
 		if (name && strcmp(name, secname))
 			continue;
--- a/usr/src/cmd/sgs/include/i386/machdep.h	Tue Sep 19 15:34:23 2006 -0700
+++ b/usr/src/cmd/sgs/include/i386/machdep.h	Tue Sep 19 15:38:37 2006 -0700
@@ -309,13 +309,14 @@
 #define	M_ID_UNWIND	0x06
 #define	M_ID_SYMINFO	0x07
 #define	M_ID_HASH	0x08
-#define	M_ID_DYNSYM	0x09
-#define	M_ID_DYNSTR	0x0a
-#define	M_ID_VERSION	0x0b
-#define	M_ID_REL	0x0c
-#define	M_ID_PLT	0x0d			/* SHF_ALLOC + SHF_EXECISNTR */
-#define	M_ID_TEXT	0x0e
-#define	M_ID_DATA	0x0f
+#define	M_ID_LDYNSYM	0x09			/* always right before DYNSYM */
+#define	M_ID_DYNSYM	0x0a
+#define	M_ID_DYNSTR	0x0b
+#define	M_ID_VERSION	0x0c
+#define	M_ID_REL	0x0d
+#define	M_ID_PLT	0x0e			/* SHF_ALLOC + SHF_EXECISNTR */
+#define	M_ID_TEXT	0x0f
+#define	M_ID_DATA	0x10
 
 /*	M_ID_USER	0x02			dual entry - listed above */
 #define	M_ID_GOT	0x03			/* SHF_ALLOC + SHF_WRITE */
--- a/usr/src/cmd/sgs/include/libld.h	Tue Sep 19 15:34:23 2006 -0700
+++ b/usr/src/cmd/sgs/include/libld.h	Tue Sep 19 15:38:37 2006 -0700
@@ -208,8 +208,10 @@
 	Word		ofl_entercnt;	/* no. of global symbols entered */
 	Word		ofl_globcnt;	/* no. of global symbols to output */
 	Word		ofl_scopecnt;	/* no. of scoped symbols to output */
+	Word		ofl_dynscopecnt; /* no. scoped syms in .SUNW_ldynsym */
 	Word		ofl_elimcnt;	/* no. of eliminated symbols */
-	Word		ofl_locscnt;	/* no. of local symbols to output */
+	Word		ofl_locscnt;	/* no. of local symbols in .symtab */
+	Word		ofl_dynlocscnt;	/* no. local symbols in .SUNW_ldynsym */
 	Word		ofl_dynshdrcnt;	/* no. of output section in .dynsym */
 	Word		ofl_shdrcnt;	/* no. of output sections */
 	Str_tbl		*ofl_shdrsttab;	/* Str_tbl for shdr strtab */
@@ -239,6 +241,7 @@
 	Is_desc		*ofl_issunwbss;	/* .SUNW_bss input section (globals) */
 	Os_desc		*ofl_osdynamic;	/* .dynamic output section */
 	Os_desc		*ofl_osdynsym;	/* .dynsym output section */
+	Os_desc		*ofl_osldynsym;	/* .SUNW_ldynsym output section */
 	Os_desc		*ofl_osdynstr;	/* .dynstr output section */
 	Os_desc		*ofl_osgot;	/* .got output section */
 	Os_desc		*ofl_oshash;	/* .hash output section */
@@ -256,6 +259,7 @@
 	Os_desc		*ofl_ossymtab;	/* .symtab output section */
 	Os_desc		*ofl_ossymshndx; /* .symtab_shndx output section */
 	Os_desc		*ofl_osdynshndx; /* .dynsym_shndx output section */
+	Os_desc		*ofl_osldynshndx; /* .SUNW_ldynsym_shndx output sec */
 	Os_desc		*ofl_osverdef;	/* .version definition output section */
 	Os_desc		*ofl_osverneed;	/* .version needed output section */
 	Os_desc		*ofl_osversym;	/* .version symbol ndx output section */
@@ -291,7 +295,7 @@
 #define	FLG_OF_DYNLIBS	0x00001000	/* dynamic input allowed: -Bdynamic */
 #define	FLG_OF_SYMBOLIC	0x00002000	/* bind global symbols: -Bsymbolic */
 #define	FLG_OF_ADDVERS	0x00004000	/* add version stamp: -Qy */
-#define	FLG_OF_MEMORY	0x00008000	/* produce a memory model */
+#define	FLG_OF_NOLDYNSYM 0x00008000	/* -znoldynsym set */
 #define	FLG_OF_SEGORDER	0x00010000	/* segment ordering is required */
 #define	FLG_OF_SEGSORT	0x00020000	/* segment sorting is required */
 #define	FLG_OF_TEXTREL	0x00040000	/* text relocations have been found */
@@ -347,6 +351,7 @@
 					/*	section */
 #define	FLG_OF1_TLSOREL	0x00100000	/* output relocation against .tlsbss */
 					/*	section */
+#define	FLG_OF1_MEMORY	0x00200000	/* produce a memory model */
 #define	FLG_OF1_VADDR	0x01000000	/* vaddr was explicitly set */
 #define	FLG_OF1_EXTRACT	0x02000000	/* archive member has been extracted */
 #define	FLG_OF1_RESCAN	0x04000000	/* any archives should be rescanned */
@@ -359,6 +364,23 @@
 					/*	exported interfaces. */
 
 /*
+ * Test to see if the output file would allow the presence of
+ * a .dynsym section.
+ */
+#define	OFL_ALLOW_DYNSYM(ofl) ((ofl->ofl_flags & \
+	(FLG_OF_DYNAMIC | FLG_OF_RELOBJ)) == FLG_OF_DYNAMIC)
+
+/*
+ * Test to see if the output file would allow the presence of
+ * a .SUNW_ldynsym section. The requirements are that a .dynsym
+ * is allowed, and -znoldynsym has not been specified. Note that
+ * even if the answer is True (1), we will only generate one if there
+ * are local symbols that require it.
+ */
+#define	OFL_ALLOW_LDYNSYM(ofl) ((ofl->ofl_flags & \
+	(FLG_OF_DYNAMIC | FLG_OF_RELOBJ | FLG_OF_NOLDYNSYM)) == FLG_OF_DYNAMIC)
+
+/*
  * Relocation (active & output) processing structure - transparent to common
  * code.
  */
--- a/usr/src/cmd/sgs/include/sparc/machdep.h	Tue Sep 19 15:34:23 2006 -0700
+++ b/usr/src/cmd/sgs/include/sparc/machdep.h	Tue Sep 19 15:38:37 2006 -0700
@@ -319,10 +319,11 @@
 #define	M_ID_CAP	0x03
 #define	M_ID_SYMINFO	0x04
 #define	M_ID_HASH	0x05
-#define	M_ID_DYNSYM	0x06
-#define	M_ID_DYNSTR	0x07
-#define	M_ID_VERSION	0x08
-#define	M_ID_REL	0x09
+#define	M_ID_LDYNSYM	0x06			/* always right before DYNSYM */
+#define	M_ID_DYNSYM	0x07
+#define	M_ID_DYNSTR	0x08
+#define	M_ID_VERSION	0x09
+#define	M_ID_REL	0x0a
 #define	M_ID_TEXT	0x0b			/* SHF_ALLOC + SHF_EXECINSTR */
 #define	M_ID_DATA	0x0c
 
--- a/usr/src/cmd/sgs/libconv/common/dynamic.c	Tue Sep 19 15:34:23 2006 -0700
+++ b/usr/src/cmd/sgs/libconv/common/dynamic.c	Tue Sep 19 15:38:37 2006 -0700
@@ -263,6 +263,10 @@
 			return (MSG_ORIG(MSG_DYN_SUNW_FILTER));
 		else if (tag == DT_SUNW_CAP)
 			return (MSG_ORIG(MSG_DYN_SUNW_CAP));
+		else if (tag == DT_SUNW_SYMTAB)
+			return (MSG_ORIG(MSG_DYN_SUNW_SYMTAB));
+		else if (tag == DT_SUNW_SYMSZ)
+			return (MSG_ORIG(MSG_DYN_SUNW_SYMSZ));
 
 		/*
 		 * SUNW: DT_VALRNGLO - DT_VALRNGHI range.
--- a/usr/src/cmd/sgs/libconv/common/dynamic.msg	Tue Sep 19 15:34:23 2006 -0700
+++ b/usr/src/cmd/sgs/libconv/common/dynamic.msg	Tue Sep 19 15:38:37 2006 -0700
@@ -93,6 +93,8 @@
 @ MSG_DYN_SUNW_RTLDINF	"SUNW_RTLDINF"
 @ MSG_DYN_SUNW_FILTER	"SUNW_FILTER"
 @ MSG_DYN_SUNW_CAP	"SUNW_CAP"
+@ MSG_DYN_SUNW_SYMTAB	"SUNW_SYMTAB"
+@ MSG_DYN_SUNW_SYMSZ	"SUNW_SYMSZ"
 
 @ MSG_DF_ORIGIN		"ORIGIN"
 @ MSG_DF_SYMBOLIC	"SYMBOLIC"
--- a/usr/src/cmd/sgs/libconv/common/sections.c	Tue Sep 19 15:34:23 2006 -0700
+++ b/usr/src/cmd/sgs/libconv/common/sections.c	Tue Sep 19 15:38:37 2006 -0700
@@ -65,22 +65,24 @@
 #endif
 
 static const Msg usecs[SHT_HISUNW - SHT_LOSUNW + 1] = {
-	MSG_SHT_SUNW_dof,		MSG_SHT_SUNW_cap,
-	MSG_SHT_SUNW_SIGNATURE,		MSG_SHT_SUNW_ANNOTATE,
-	MSG_SHT_SUNW_DEBUGSTR,		MSG_SHT_SUNW_DEBUG,
-	MSG_SHT_SUNW_move,		MSG_SHT_SUNW_COMDAT,
-	MSG_SHT_SUNW_syminfo,		MSG_SHT_SUNW_verdef,
-	MSG_SHT_SUNW_verneed,		MSG_SHT_SUNW_versym
+	MSG_SHT_SUNW_LDYNSYM,		MSG_SHT_SUNW_dof,
+	MSG_SHT_SUNW_cap,		MSG_SHT_SUNW_SIGNATURE,
+	MSG_SHT_SUNW_ANNOTATE,		MSG_SHT_SUNW_DEBUGSTR,
+	MSG_SHT_SUNW_DEBUG,		MSG_SHT_SUNW_move,
+	MSG_SHT_SUNW_COMDAT,		MSG_SHT_SUNW_syminfo,
+	MSG_SHT_SUNW_verdef,		MSG_SHT_SUNW_verneed,
+	MSG_SHT_SUNW_versym
 };
 static const Msg usecs_alt[SHT_HISUNW - SHT_LOSUNW + 1] = {
-	MSG_SHT_SUNW_dof_ALT,		MSG_SHT_SUNW_cap_ALT,
-	MSG_SHT_SUNW_SIGNATURE_ALT,	MSG_SHT_SUNW_ANNOTATE_ALT,
-	MSG_SHT_SUNW_DEBUGSTR_ALT,	MSG_SHT_SUNW_DEBUG_ALT,
-	MSG_SHT_SUNW_move_ALT,		MSG_SHT_SUNW_COMDAT_ALT,
-	MSG_SHT_SUNW_syminfo_ALT,	MSG_SHT_SUNW_verdef_ALT,
-	MSG_SHT_SUNW_verneed_ALT,	MSG_SHT_SUNW_versym_ALT
+	MSG_SHT_SUNW_LDYNSYM_ALT,	MSG_SHT_SUNW_dof_ALT,
+	MSG_SHT_SUNW_cap_ALT,		MSG_SHT_SUNW_SIGNATURE_ALT,
+	MSG_SHT_SUNW_ANNOTATE_ALT,	MSG_SHT_SUNW_DEBUGSTR_ALT,
+	MSG_SHT_SUNW_DEBUG_ALT,		MSG_SHT_SUNW_move_ALT,
+	MSG_SHT_SUNW_COMDAT_ALT,	MSG_SHT_SUNW_syminfo_ALT,
+	MSG_SHT_SUNW_verdef_ALT,	MSG_SHT_SUNW_verneed_ALT,
+	MSG_SHT_SUNW_versym_ALT
 };
-#if	(SHT_LOSUNW != SHT_SUNW_dof)
+#if	(SHT_LOSUNW != SHT_SUNW_LDYNSYM)
 #error	"SHT_LOSUNW has moved"
 #endif
 
--- a/usr/src/cmd/sgs/libconv/common/sections.msg	Tue Sep 19 15:34:23 2006 -0700
+++ b/usr/src/cmd/sgs/libconv/common/sections.msg	Tue Sep 19 15:38:37 2006 -0700
@@ -62,6 +62,8 @@
 @ MSG_SHT_SYMTAB_SHNDX		"[ SHT_SYMTAB_SHNDX ]"
 @ MSG_SHT_SYMTAB_SHNDX_ALT	"SHDX"
 
+@ MSG_SHT_SUNW_LDYNSYM		"[ SHT_SUNW_LDYNSYM ]"
+@ MSG_SHT_SUNW_LDYNSYM_ALT	"LDYNSYM"
 @ MSG_SHT_SUNW_dof		"[ SHT_SUNW_dof ]"
 @ MSG_SHT_SUNW_dof_ALT		"DOF "
 @ MSG_SHT_SUNW_cap		"[ SHT_SUNW_cap ]"
--- a/usr/src/cmd/sgs/libld/common/args.c	Tue Sep 19 15:34:23 2006 -0700
+++ b/usr/src/cmd/sgs/libld/common/args.c	Tue Sep 19 15:38:37 2006 -0700
@@ -717,6 +717,18 @@
 
 		case 'b':
 			bflag = TRUE;
+
+			/*
+			 * This is a hack, and may be undone later.
+			 * The -b option is only used to build the Unix
+			 * kernel and its related kernel-mode modules.
+			 * We do not want those files to get a .SUNW_ldynsym
+			 * section. At least for now, the kernel makes no
+			 * use of .SUNW_ldynsym, and we do not want to use
+			 * the space to hold it. Therefore, we overload
+			 * the use of -b to also imply -znoldynsym.
+			 */
+			ofl->ofl_flags |= FLG_OF_NOLDYNSYM;
 			break;
 
 		case 'c':
@@ -1040,7 +1052,9 @@
 			} else if (strcmp(optarg,
 			    MSG_ORIG(MSG_ARG_IGNORE)) == 0) {
 				ofl->ofl_flags1 |= FLG_OF1_IGNPRC;
-
+			} else if (strcmp(optarg,
+			    MSG_ORIG(MSG_ARG_NOLDYNSYM)) == 0) {
+				ofl->ofl_flags |= FLG_OF_NOLDYNSYM;
 			/*
 			 * The following options just need validation as they
 			 * are interpreted on the second pass through the
--- a/usr/src/cmd/sgs/libld/common/libld.msg	Tue Sep 19 15:34:23 2006 -0700
+++ b/usr/src/cmd/sgs/libld/common/libld.msg	Tue Sep 19 15:38:37 2006 -0700
@@ -385,7 +385,7 @@
 @ MSG_ELF_ARSYM		"file %s ignored: unable to locate archive symbol table"
 
 @ MSG_ELF_VERSYM	"file %s: version symbol section entry mismatch:\n\t\
-			 (section %s entries=%d; section %s entires=%d)"
+			 (section %s entries=%d; section %s entries=%d)"
 
 @ MSG_ELF_NOGROUPSECT	"file %s: section %s: SHF_GROUP flag set, but no \
 			 corresponding SHT_GROUP section found"
@@ -550,7 +550,6 @@
 @ MSG_ELF_NEWPHDR	"file %s: elf_newphdr"
 @ MSG_ELF_STRPTR	"file %s: elf_strptr"
 @ MSG_ELF_UPDATE	"file %s: elf_update"
-@ MSG_ELF_FSIZE		"file %s: elf_fsize"
 
 
 @ MSG_REJ_MACH		"file %s: wrong ELF machine type: %s"
@@ -604,6 +603,8 @@
 @ MSG_SCN_DYNSTR	".dynstr"
 @ MSG_SCN_DYNSYM	".dynsym"
 @ MSG_SCN_DYNSYM_SHNDX	".dynsym_shndx"
+@ MSG_SCN_LDYNSYM	".SUNW_ldynsym"
+@ MSG_SCN_LDYNSYM_SHNDX	".SUNW_ldynsym_shndx"
 @ MSG_SCN_EX_SHARED	".ex_shared"
 @ MSG_SCN_EX_RANGES	".exception_ranges"
 @ MSG_SCN_EXCL		".excl"
@@ -1062,6 +1063,7 @@
 @ MSG_ARG_LD32		"ld32="
 @ MSG_ARG_LD64		"ld64="
 @ MSG_ARG_RESCAN	"rescan"
+@ MSG_ARG_NOLDYNSYM	"noldynsym"
 
 @ MSG_ARG_HELP		"help"
 @ MSG_ARG_GROUP		"group"
--- a/usr/src/cmd/sgs/libld/common/outfile.c	Tue Sep 19 15:34:23 2006 -0700
+++ b/usr/src/cmd/sgs/libld/common/outfile.c	Tue Sep 19 15:38:37 2006 -0700
@@ -371,6 +371,7 @@
 	Elf_Data	*tlsdata = 0;
 	Aliste		off;
 	Word		flags = ofl->ofl_flags;
+	Word		flags1 = ofl->ofl_flags1;
 	size_t		ndx = 0, fndx = 0;
 	Elf_Cmd		cmd;
 	Boolean		fixalign = FALSE;
@@ -380,12 +381,12 @@
 	 * If DF_1_NOHDR was set in map_parse() or FLG_OF1_VADDR was set,
 	 * we need to do alignment adjustment.
 	 */
-	if ((ofl->ofl_flags1 & FLG_OF1_VADDR) ||
+	if ((flags1 & FLG_OF1_VADDR) ||
 	    (ofl->ofl_dtflags_1 & DF_1_NOHDR)) {
 		fixalign = TRUE;
 	}
 
-	if (flags & FLG_OF_MEMORY) {
+	if (flags1 & FLG_OF1_MEMORY) {
 		cmd = ELF_C_IMAGE;
 		fd = 0;
 	} else {
@@ -671,7 +672,7 @@
 	/*
 	 * If we need to generate a memory model, pad the image.
 	 */
-	if (flags & FLG_OF_MEMORY) {
+	if (flags1 & FLG_OF1_MEMORY) {
 		if (pad_outfile(ofl) == S_ERROR)
 			return (S_ERROR);
 	}
--- a/usr/src/cmd/sgs/libld/common/sections.c	Tue Sep 19 15:34:23 2006 -0700
+++ b/usr/src/cmd/sgs/libld/common/sections.c	Tue Sep 19 15:38:37 2006 -0700
@@ -62,6 +62,9 @@
 	Listnode	*lnp;
 	Ifl_desc	*ifl;
 	Rel_cache	*rcp;
+	int		allow_ldynsym;
+
+	allow_ldynsym = OFL_ALLOW_LDYNSYM(ofl);
 
 	for (LIST_TRAVERSE(&ofl->ofl_objs, lnp, ifl)) {
 		uint_t	num, discard;
@@ -136,6 +139,15 @@
 					err = st_delstring(ofl->ofl_strtab,
 					    sdp->sd_name);
 					assert(err != -1);
+					if (allow_ldynsym &&
+					    (ELF_ST_TYPE(symp->st_info) ==
+					    STT_FILE)) {
+						ofl->ofl_dynlocscnt--;
+						err = st_delstring(
+							ofl->ofl_dynstrtab,
+							sdp->sd_name);
+						assert(err != -1);
+					}
 				}
 				sdp->sd_flags |= FLG_SY_ISDISC;
 				continue;
@@ -173,11 +185,19 @@
 					if ((ofl->ofl_flags1 &
 					    FLG_OF1_REDLSYM) == 0) {
 						ofl->ofl_locscnt--;
-
 						err = st_delstring(
 						    ofl->ofl_strtab,
 						    sdp->sd_name);
 						assert(err != -1);
+						if (allow_ldynsym &&
+						    (ELF_ST_TYPE(symp->st_info)
+							== STT_FUNC)) {
+							ofl->ofl_dynlocscnt--;
+							err = st_delstring(
+							    ofl->ofl_dynstrtab,
+							    sdp->sd_name);
+							assert(err != -1);
+						}
 					}
 					sdp->sd_flags |= FLG_SY_ISDISC;
 				}
@@ -200,6 +220,15 @@
 					assert(err != -1);
 
 					sdp->sd_flags1 |= FLG_SY1_ELIM;
+					if (allow_ldynsym &&
+					    (ELF_ST_TYPE(symp->st_info) ==
+						STT_FUNC)) {
+						ofl->ofl_dynscopecnt--;
+						err = st_delstring(
+							ofl->ofl_dynstrtab,
+							sdp->sd_name);
+						assert(err != -1);
+					}
 				}
 				DBG_CALL(Dbg_syms_discarded(ofl->ofl_lml,
 				    sdp, sdp->sd_isc));
@@ -262,6 +291,238 @@
 }
 
 /*
+ * Allocate Elf_Data, Shdr, and Is_desc structures for a new
+ * section.
+ *
+ * entry:
+ *	ofl - Output file descriptor
+ *	shtype - SHT_ type code for section.
+ *	shname - String giving the name for the new section.
+ *	entcnt - # of items contained in the data part of the new section.
+ *		This value is multiplied against the known element size
+ *		for the section type to determine the size of the data
+ *		area for the section. It is only meaningful in cases where
+ *		the section type has a non-zero element size. In other cases,
+ *		the caller must set the size fields in the *ret_data and
+ *		*ret_shdr structs manually.
+ *	ret_isec, ret_shdr, ret_data - Address of pointers to
+ *		receive address of newly allocated structs.
+ *
+ * exit:
+ *	On error, returns S_ERROR. On success, returns (1), and the
+ *	ret_ pointers have been updated to point at the new structures,
+ *	which has been filled in. To finish the task, the caller must
+ *	update any fields within the supplied descriptors that differ
+ *	from its needs, and then call ld_place_section().
+ */
+static uintptr_t
+new_section(Ofl_desc *ofl, Word shtype, const char *shname, Xword entcnt,
+	Is_desc **ret_isec, Shdr **ret_shdr, Elf_Data **ret_data)
+{
+	typedef struct sec_info {
+		Word d_type;
+		Word align;	/* Used in both data and section header */
+		Word sh_flags;
+		Word sh_entsize;
+	} SEC_INFO_T;
+
+	const SEC_INFO_T	*sec_info;
+
+	Shdr		*shdr;
+	Elf_Data	*data;
+	Is_desc		*isec;
+	size_t		size;
+
+	/*
+	 * For each type of section, we have a distinct set of
+	 * SEC_INFO_T values. This macro defines a static structure
+	 * containing those values and generates code to set the sec_info
+	 * pointer to refer to it. The pointer in sec_info remains valid
+	 * outside of the declaration scope because the info_s struct is static.
+	 */
+#define	SET_SEC_INFO(d_type, d_align, sh_flags, sh_entsize) \
+	{ \
+		static const SEC_INFO_T info_s = { d_type, d_align, sh_flags, \
+		    sh_entsize}; \
+		sec_info = &info_s; \
+	}
+
+	switch (shtype) {
+	case SHT_PROGBITS:
+		/*
+		 * SHT_PROGBITS sections contain are used for many
+		 * different sections. Alignments and flags differ.
+		 * Some have a standard entsize, and others don't.
+		 * We set some defaults here, but there is no expectation
+		 * that they are correct or complete for any specific
+		 * purpose. The caller must provide the correct values.
+		 */
+		SET_SEC_INFO(ELF_T_BYTE, M_WORD_ALIGN, SHF_ALLOC, 0)
+		break;
+
+	case SHT_SYMTAB:
+		SET_SEC_INFO(ELF_T_SYM, M_WORD_ALIGN, 0, sizeof (Sym))
+		break;
+
+	case SHT_DYNSYM:
+	case SHT_SUNW_LDYNSYM:
+		SET_SEC_INFO(ELF_T_SYM, M_WORD_ALIGN, SHF_ALLOC, sizeof (Sym))
+		break;
+
+	case SHT_STRTAB:
+		/*
+		 * A string table may or may not be allocable, depending
+		 * on context, so we leave that flag unset and leave it to
+		 * the caller to add it if necessary.
+		 *
+		 * String tables do not have a standard entsize, so
+		 * we set it to 0.
+		 */
+		SET_SEC_INFO(ELF_T_BYTE, 1, SHF_STRINGS, 0)
+		break;
+
+	case SHT_RELA:
+		/*
+		 * Relocations with an addend (Everything except 32-bit X86).
+		 * The caller is expected to set all section header flags.
+		 */
+		SET_SEC_INFO(ELF_T_RELA, M_WORD_ALIGN, 0, sizeof (Rela))
+		break;
+
+	case SHT_REL:
+		/*
+		 * Relocations without an addend (32-bit X86 only).
+		 * The caller is expected to set all section header flags.
+		 */
+		SET_SEC_INFO(ELF_T_REL, M_WORD_ALIGN, 0, sizeof (Rel))
+		break;
+
+	case SHT_HASH:
+		SET_SEC_INFO(ELF_T_WORD, M_WORD_ALIGN, SHF_ALLOC, sizeof (Word))
+		break;
+
+	case SHT_DYNAMIC:
+		/*
+		 * A dynamic section may or may not be allocable, depending
+		 * on context, so we leave that flag unset and leave it to
+		 * the caller to add it if necessary.
+		 */
+		SET_SEC_INFO(ELF_T_DYN, M_WORD_ALIGN, SHF_WRITE, sizeof (Dyn))
+		break;
+
+	case SHT_NOBITS:
+		/*
+		 * SHT_NOBITS is used for BSS-type sections. The size and
+		 * alignment depend on the specific use and must be adjusted
+		 * by the caller.
+		 */
+		SET_SEC_INFO(ELF_T_BYTE, 0, SHF_ALLOC | SHF_WRITE, 0)
+		break;
+
+	case SHT_INIT_ARRAY:
+	case SHT_FINI_ARRAY:
+	case SHT_PREINIT_ARRAY:
+		SET_SEC_INFO(ELF_T_ADDR, sizeof (Addr), SHF_ALLOC | SHF_WRITE,
+		    sizeof (Addr))
+		break;
+
+	case SHT_SYMTAB_SHNDX:
+		/*
+		 * Note that these sections are created to be associated
+		 * with both symtab and dynsym symbol tables. However, they
+		 * are non-allocable in all cases, because the runtime
+		 * linker has no need for this information. It is purely
+		 * informational, used by elfdump(1), debuggers, etc.
+		 */
+		SET_SEC_INFO(ELF_T_WORD, M_WORD_ALIGN, 0, sizeof (Word));
+		break;
+
+	case SHT_SUNW_cap:
+		SET_SEC_INFO(ELF_T_CAP, M_WORD_ALIGN, SHF_ALLOC, sizeof (Cap));
+		break;
+
+	case SHT_SUNW_move:
+		/*
+		 * The sh_info field of the SHT_*_syminfo section points
+		 * to the header index of the associated .dynamic section,
+		 * so we also set SHF_INFO_LINK.
+		 */
+		SET_SEC_INFO(ELF_T_BYTE, sizeof (Lword),
+		    SHF_ALLOC | SHF_WRITE, sizeof (Move));
+		break;
+
+	case SHT_SUNW_syminfo:
+		/*
+		 * The sh_info field of the SHT_*_syminfo section points
+		 * to the header index of the associated .dynamic section,
+		 * so we also set SHF_INFO_LINK.
+		 */
+		SET_SEC_INFO(ELF_T_BYTE, M_WORD_ALIGN,
+		    SHF_ALLOC | SHF_INFO_LINK, sizeof (Syminfo));
+		break;
+
+	case SHT_SUNW_verneed:
+	case SHT_SUNW_verdef:
+		/*
+		 * The info for verneed and versym happen to be the same.
+		 * The entries in these sections are not of uniform size,
+		 * so we set the entsize to 0.
+		 */
+		SET_SEC_INFO(ELF_T_BYTE, M_WORD_ALIGN, SHF_ALLOC, 0);
+		break;
+
+	case SHT_SUNW_versym:
+		SET_SEC_INFO(ELF_T_BYTE, M_WORD_ALIGN, SHF_ALLOC,
+		    sizeof (Versym));
+		break;
+
+	default:
+		/* Should not happen: fcn called with unknown section type */
+		assert(0);
+		return (S_ERROR);
+	}
+#undef	SET_SEC_INFO
+
+	size = entcnt * sec_info->sh_entsize;
+
+	/*
+	 * Allocate and initialize the Elf_Data structure.
+	 */
+	if ((data = libld_calloc(sizeof (Elf_Data), 1)) == 0)
+		return (S_ERROR);
+	data->d_type = sec_info->d_type;
+	data->d_size = size;
+	data->d_align = sec_info->align;
+	data->d_version = ofl->ofl_dehdr->e_version;
+
+	/*
+	 * Allocate and initialize the Shdr structure.
+	 */
+	if ((shdr = libld_calloc(sizeof (Shdr), 1)) == 0)
+		return (S_ERROR);
+	shdr->sh_type = shtype;
+	shdr->sh_size = size;
+	shdr->sh_flags = sec_info->sh_flags;
+	shdr->sh_addralign = sec_info->align;
+	shdr->sh_entsize = sec_info->sh_entsize;
+
+	/*
+	 * Allocate and initialize the Is_desc structure.
+	 */
+	if ((isec = libld_calloc(1, sizeof (Is_desc))) == 0)
+		return (S_ERROR);
+	isec->is_name = shname;
+	isec->is_shdr = shdr;
+	isec->is_indata = data;
+
+
+	*ret_isec = isec;
+	*ret_shdr = shdr;
+	*ret_data = data;
+	return (1);
+}
+
+/*
  * Build a .bss section for allocation of tentative definitions.  Any `static'
  * .bss definitions would have been associated to their own .bss sections and
  * thus collected from the input files.  `global' .bss definitions are tagged
@@ -280,34 +541,20 @@
 	Xword		rsize = (Xword)ofl->ofl_relocbsssz;
 
 	/*
-	 * Allocate and initialize the Elf_Data structure.
+	 * Allocate header structs. We will set the name ourselves below,
+	 * and there is no entcnt for a BSS. So, the shname and entcnt
+	 * arguments are 0.
 	 */
-	if ((data = libld_calloc(sizeof (Elf_Data), 1)) == 0)
+	if (new_section(ofl, SHT_NOBITS, NULL, 0,
+	    &isec, &shdr, &data) == S_ERROR)
 		return (S_ERROR);
-	data->d_type = ELF_T_BYTE;
+
 	data->d_size = (size_t)size;
 	data->d_align = (size_t)align;
-	data->d_version = ofl->ofl_dehdr->e_version;
 
-	/*
-	 * Allocate and initialize the Shdr structure.
-	 */
-	if ((shdr = libld_calloc(sizeof (Shdr), 1)) == 0)
-		return (S_ERROR);
-	shdr->sh_type = SHT_NOBITS;
-	shdr->sh_flags = SHF_ALLOC | SHF_WRITE;
 	shdr->sh_size = size;
 	shdr->sh_addralign = align;
 
-	/*
-	 * Allocate and initialize the Is_desc structure.
-	 */
-	if ((isec = libld_calloc(1, sizeof (Is_desc))) == 0)
-		return (S_ERROR);
-
-	isec->is_shdr = shdr;
-	isec->is_indata = data;
-
 	if (which == MAKE_TLS) {
 		isec->is_name = MSG_ORIG(MSG_SCN_TBSS);
 		ident = M_ID_TLSBSS;
@@ -383,37 +630,12 @@
 	for (LIST_TRAVERSE(list, lnp, sdp))
 		entcount++;
 
-	/*
-	 * Allocate and initialize the Elf_Data structure.
-	 */
-	if (((data = libld_calloc(sizeof (Elf_Data), 1)) == 0) ||
-	    ((data->d_buf = libld_calloc(sizeof (Addr), entcount)) == 0))
+	if (new_section(ofl, shtype, sectname, entcount, &isec, &shdr, &data) ==
+	    S_ERROR)
 		return (S_ERROR);
 
-	data->d_type = ELF_T_ADDR;
-	data->d_size = sizeof (Addr) * entcount;
-	data->d_align = sizeof (Addr);
-	data->d_version = ofl->ofl_dehdr->e_version;
-
-	/*
-	 * Allocate and initialize the Shdr structure.
-	 */
-	if ((shdr = libld_calloc(sizeof (Shdr), 1)) == 0)
+	if ((data->d_buf = libld_calloc(sizeof (Addr), entcount)) == 0)
 		return (S_ERROR);
-	shdr->sh_type = shtype;
-	shdr->sh_size = (Xword)data->d_size;
-	shdr->sh_entsize = sizeof (Addr);
-	shdr->sh_addralign = (Xword)data->d_align;
-	shdr->sh_flags = SHF_ALLOC | SHF_WRITE;
-
-	/*
-	 * Allocate and initialize the Is_desc structure.
-	 */
-	if ((isec = libld_calloc(1, sizeof (Is_desc))) == 0)
-		return (S_ERROR);
-	isec->is_name = sectname;
-	isec->is_shdr = shdr;
-	isec->is_indata = data;
 
 	if (ld_place_section(ofl, isec, M_ID_ARRAY, 0) == (Os_desc *)S_ERROR)
 		return (S_ERROR);
@@ -479,35 +701,18 @@
 	Elf_Data	*data;
 	Is_desc		*isec;
 
-	/*
-	 * Allocate and initialize the Elf_Data structure.
-	 */
-	if ((data = libld_calloc(sizeof (Elf_Data), 1)) == 0)
+	if (new_section(ofl, SHT_PROGBITS, MSG_ORIG(MSG_SCN_COMMENT), 0,
+	    &isec, &shdr, &data) == S_ERROR)
 		return (S_ERROR);
-	data->d_type = ELF_T_BYTE;
+
 	data->d_buf = (void *)ofl->ofl_sgsid;
 	data->d_size = strlen(ofl->ofl_sgsid) + 1;
 	data->d_align = 1;
-	data->d_version = ofl->ofl_dehdr->e_version;
 
-	/*
-	 * Allocate and initialize the Shdr structure.
-	 */
-	if ((shdr = libld_calloc(sizeof (Shdr), 1)) == 0)
-		return (S_ERROR);
-	shdr->sh_type = SHT_PROGBITS;
 	shdr->sh_size = (Xword)data->d_size;
+	shdr->sh_flags = 0;
 	shdr->sh_addralign = 1;
 
-	/*
-	 * Allocate and initialize the Is_desc structure.
-	 */
-	if ((isec = libld_calloc(1, sizeof (Is_desc))) == 0)
-		return (S_ERROR);
-	isec->is_name = MSG_ORIG(MSG_SCN_COMMENT);
-	isec->is_shdr = shdr;
-	isec->is_indata = data;
-
 	return ((uintptr_t)ld_place_section(ofl, isec, M_ID_NOTE, 0));
 }
 
@@ -531,42 +736,13 @@
 	Word		flags = ofl->ofl_flags;
 	int		unused = 0;
 
-	/*
-	 * Allocate and initialize the Shdr structure.
-	 */
-	if ((shdr = libld_calloc(sizeof (Shdr), 1)) == 0)
+	if (new_section(ofl, SHT_DYNAMIC, MSG_ORIG(MSG_SCN_DYNAMIC), 0,
+	    &isec, &shdr, &data) == S_ERROR)
 		return (S_ERROR);
-	shdr->sh_type = SHT_DYNAMIC;
-	shdr->sh_flags = SHF_WRITE;
+
+	/* new_section() does not set SHF_ALLOC. Add it if needed */
 	if (!(flags & FLG_OF_RELOBJ))
 		shdr->sh_flags |= SHF_ALLOC;
-	shdr->sh_addralign = M_WORD_ALIGN;
-	if ((shdr->sh_entsize = (Xword)elf_fsize(ELF_T_DYN, 1,
-	    ofl->ofl_dehdr->e_version)) == 0) {
-		eprintf(ofl->ofl_lml, ERR_ELF, MSG_INTL(MSG_ELF_FSIZE),
-		    ofl->ofl_name);
-		return (S_ERROR);
-	}
-
-	/*
-	 * Allocate and initialize the Elf_Data structure.
-	 */
-	if ((data = libld_calloc(sizeof (Elf_Data), 1)) == 0)
-		return (S_ERROR);
-	data->d_type = ELF_T_DYN;
-	data->d_size = 0;
-	data->d_align = M_WORD_ALIGN;
-	data->d_version = ofl->ofl_dehdr->e_version;
-
-	/*
-	 * Allocate and initialize the Is_desc structure.
-	 */
-	if ((isec = libld_calloc(1, sizeof (Is_desc))) ==
-	    (Is_desc *)0)
-		return (S_ERROR);
-	isec->is_name = MSG_ORIG(MSG_SCN_DYNAMIC);
-	isec->is_shdr = shdr;
-	isec->is_indata = data;
 
 	osp = ofl->ofl_osdynamic = ld_place_section(ofl, isec, M_ID_DYNAMIC, 0);
 
@@ -732,6 +908,15 @@
 		 */
 		cnt += 6;
 
+		/*
+		 * If we are including local functions at the head of
+		 * the dynsym, then also reserve entries for DT_SUNW_SYMTAB
+		 * and DT_SUNW_SYMSZ.
+		 */
+		if (!(ofl->ofl_flags & FLG_OF_NOLDYNSYM) &&
+		    ((ofl->ofl_dynlocscnt + ofl->ofl_dynscopecnt) > 0))
+			cnt += 2;
+
 		if ((flags & (FLG_OF_VERDEF | FLG_OF_NOVERSEC)) ==
 		    FLG_OF_VERDEF)
 			cnt += 2;		/* DT_VERDEF & DT_VERDEFNUM */
@@ -790,7 +975,7 @@
 			cnt += 3;
 
 		/*
-		 * Allocate one DT_REGISTER entry for ever register symbol.
+		 * Allocate one DT_REGISTER entry for every register symbol.
 		 */
 		cnt += ofl->ofl_regsymcnt;
 
@@ -856,35 +1041,15 @@
 	size_t		size = (size_t)ofl->ofl_gotcnt * M_GOT_ENTSIZE;
 	size_t		rsize = (size_t)ofl->ofl_relocgotsz;
 
-	/*
-	 * Allocate and initialize the Elf_Data structure.
-	 */
-	if ((data = libld_calloc(sizeof (Elf_Data), 1)) == 0)
-		return (S_ERROR);
-	data->d_type = ELF_T_BYTE;
-	data->d_size = size;
-	data->d_align = M_WORD_ALIGN;
-	data->d_version = ofl->ofl_dehdr->e_version;
-
-	/*
-	 * Allocate and initialize the Shdr structure.
-	 */
-	if ((shdr = libld_calloc(sizeof (Shdr), 1)) == 0)
+	if (new_section(ofl, SHT_PROGBITS, MSG_ORIG(MSG_SCN_GOT), 0,
+	    &isec, &shdr, &data) == S_ERROR)
 		return (S_ERROR);
-	shdr->sh_type = SHT_PROGBITS;
-	shdr->sh_flags = SHF_ALLOC | SHF_WRITE;
-	shdr->sh_size = (Xword)size;
-	shdr->sh_addralign = M_WORD_ALIGN;
-	shdr->sh_entsize = M_GOT_ENTSIZE;
+
+	data->d_size = size;
 
-	/*
-	 * Allocate and initialize the Is_desc structure.
-	 */
-	if ((isec = libld_calloc(1, sizeof (Is_desc))) == 0)
-		return (S_ERROR);
-	isec->is_name = MSG_ORIG(MSG_SCN_GOT);
-	isec->is_shdr = shdr;
-	isec->is_indata = data;
+	shdr->sh_flags |= SHF_WRITE;
+	shdr->sh_size = (Xword)size;
+	shdr->sh_entsize = M_GOT_ENTSIZE;
 
 	if ((ofl->ofl_osgot = ld_place_section(ofl, isec, M_ID_GOT, 0)) ==
 	    (Os_desc *)S_ERROR)
@@ -940,32 +1105,13 @@
 
 	size = strlen(iname) + 1;
 
-	/*
-	 * Allocate and initialize the Elf_Data structure.
-	 */
-	if ((data = libld_calloc(sizeof (Elf_Data), 1)) == 0)
+	if (new_section(ofl, SHT_PROGBITS, MSG_ORIG(MSG_SCN_INTERP), 0,
+	    &isec, &shdr, &data) == S_ERROR)
 		return (S_ERROR);
-	data->d_type = ELF_T_BYTE;
-	data->d_size = size;
-	data->d_version = ofl->ofl_dehdr->e_version;
 
-	/*
-	 * Allocate and initialize the Shdr structure.
-	 */
-	if ((shdr = libld_calloc(sizeof (Shdr), 1)) == 0)
-		return (S_ERROR);
-	shdr->sh_type = SHT_PROGBITS;
-	shdr->sh_flags = SHF_ALLOC;
+	data->d_size = size;
 	shdr->sh_size = (Xword)size;
-
-	/*
-	 * Allocate and initialize the Is_desc structure.
-	 */
-	if ((isec = libld_calloc(1, sizeof (Is_desc))) == 0)
-		return (S_ERROR);
-	isec->is_name = MSG_ORIG(MSG_SCN_INTERP);
-	isec->is_shdr = shdr;
-	isec->is_indata = data;
+	data->d_align = shdr->sh_addralign = 1;
 
 	ofl->ofl_osinterp = ld_place_section(ofl, isec, M_ID_INTERP, 0);
 	return ((uintptr_t)ofl->ofl_osinterp);
@@ -995,46 +1141,11 @@
 		return (1);
 	size++;				/* Add CA_SUNW_NULL */
 
-	/*
-	 * Allocate and initialize the Elf_Data structure.
-	 */
-	if ((data = libld_calloc(sizeof (Elf_Data), 1)) == 0)
-		return (S_ERROR);
-	data->d_type = ELF_T_CAP;
-	data->d_version = ofl->ofl_dehdr->e_version;
-	data->d_align = M_WORD_ALIGN;
-
-	/*
-	 * Allocate and initialize the Shdr structure.
-	 */
-	if ((shdr = libld_calloc(sizeof (Shdr), 1)) == 0)
+	if (new_section(ofl, SHT_SUNW_cap, MSG_ORIG(MSG_SCN_SUNWCAP), size,
+	    &isec, &shdr, &data) == S_ERROR)
 		return (S_ERROR);
-	shdr->sh_type = SHT_SUNW_cap;
-	shdr->sh_flags = SHF_ALLOC;
-	shdr->sh_addralign = M_WORD_ALIGN;
-	if ((shdr->sh_entsize = (Xword)elf_fsize(ELF_T_CAP, 1,
-	    ofl->ofl_dehdr->e_version)) == 0) {
-		eprintf(ofl->ofl_lml, ERR_ELF, MSG_INTL(MSG_ELF_FSIZE),
-		    ofl->ofl_name);
-		return (S_ERROR);
-	}
 
-	/*
-	 * Allocate and initialize the Is_desc structure.
-	 */
-	if ((isec = libld_calloc(1, sizeof (Is_desc))) == 0)
-		return (S_ERROR);
-	isec->is_name = MSG_ORIG(MSG_SCN_SUNWCAP);
-	isec->is_shdr = shdr;
-	isec->is_indata = data;
-
-	/*
-	 * Determine the size of the section, and create the data.
-	 */
-	size = size * (size_t)shdr->sh_entsize;
-	shdr->sh_size = (Xword)size;
-	data->d_size = size;
-	if ((data->d_buf = libld_malloc(size)) == 0)
+	if ((data->d_buf = libld_malloc(shdr->sh_size)) == 0)
 		return (S_ERROR);
 
 	cap = (Cap *)data->d_buf;
@@ -1053,7 +1164,7 @@
 
 	/*
 	 * If we're not creating a relocatable object, save the output section
-	 * to trigger the creation of an associated  a program header.
+	 * to trigger the creation of an associated program header.
 	 */
 	osec = ld_place_section(ofl, isec, M_ID_CAP, 0);
 	if ((ofl->ofl_flags & FLG_OF_RELOBJ) == 0)
@@ -1083,36 +1194,18 @@
 	size += sizeof (Word);
 #endif
 
-	/*
-	 * Allocate and initialize the Elf_Data structure.
-	 */
-	if ((data = libld_calloc(sizeof (Elf_Data), 1)) == 0)
+	if (new_section(ofl, SHT_PROGBITS, MSG_ORIG(MSG_SCN_PLT), 0,
+	    &isec, &shdr, &data) == S_ERROR)
 		return (S_ERROR);
-	data->d_type = ELF_T_BYTE;
+
 	data->d_size = size;
 	data->d_align = M_PLT_ALIGN;
-	data->d_version = ofl->ofl_dehdr->e_version;
 
-	/*
-	 * Allocate and initialize the Shdr structure.
-	 */
-	if ((shdr = libld_calloc(sizeof (Shdr), 1)) == 0)
-		return (S_ERROR);
-	shdr->sh_type = SHT_PROGBITS;
 	shdr->sh_flags = M_PLT_SHF_FLAGS;
 	shdr->sh_size = (Xword)size;
 	shdr->sh_addralign = M_PLT_ALIGN;
 	shdr->sh_entsize = M_PLT_ENTSIZE;
 
-	/*
-	 * Allocate and initialize the Is_desc structure.
-	 */
-	if ((isec = libld_calloc(1, sizeof (Is_desc))) == (Is_desc *)0)
-		return (S_ERROR);
-	isec->is_name = MSG_ORIG(MSG_SCN_PLT);
-	isec->is_shdr = shdr;
-	isec->is_indata = data;
-
 	if ((ofl->ofl_osplt = ld_place_section(ofl, isec, M_ID_PLT, 0)) ==
 	    (Os_desc *)S_ERROR)
 		return (S_ERROR);
@@ -1138,37 +1231,12 @@
 	size_t		cnt;
 
 	/*
-	 * Allocate and initialize the Elf_Data structure.
+	 * Allocate section header structures. We set entcnt to 0
+	 * because it's going to change after we place this section.
 	 */
-	if ((data = libld_calloc(sizeof (Elf_Data), 1)) == 0)
-		return (S_ERROR);
-	data->d_type = ELF_T_WORD;
-	data->d_align = M_WORD_ALIGN;
-	data->d_version = ofl->ofl_dehdr->e_version;
-
-	/*
-	 * Allocate and initialize the Shdr structure.
-	 */
-	if ((shdr = libld_calloc(sizeof (Shdr), 1)) == 0)
+	if (new_section(ofl, SHT_HASH, MSG_ORIG(MSG_SCN_HASH), 0,
+	    &isec, &shdr, &data) == S_ERROR)
 		return (S_ERROR);
-	shdr->sh_type = SHT_HASH;
-	shdr->sh_flags = SHF_ALLOC;
-	shdr->sh_addralign = M_WORD_ALIGN;
-	if ((shdr->sh_entsize = (Xword)elf_fsize(ELF_T_WORD, 1,
-	    ofl->ofl_dehdr->e_version)) == 0) {
-		eprintf(ofl->ofl_lml, ERR_ELF, MSG_INTL(MSG_ELF_FSIZE),
-		    ofl->ofl_name);
-		return (S_ERROR);
-	}
-
-	/*
-	 * Allocate and initialize the Is_desc structure.
-	 */
-	if ((isec = libld_calloc(1, sizeof (Is_desc))) == 0)
-		return (S_ERROR);
-	isec->is_name = MSG_ORIG(MSG_SCN_HASH);
-	isec->is_shdr = shdr;
-	isec->is_indata = data;
 
 	/*
 	 * Place the section first since it will affect the local symbol
@@ -1221,36 +1289,12 @@
 	Word		symcnt;
 
 	/*
-	 * Allocate and initialize the Elf_Data structure.
+	 * Create the section headers. Note that we supply an ent_cnt
+	 * of 0. We won't know the count until the section has been placed.
 	 */
-	if ((data = libld_calloc(sizeof (Elf_Data), 1)) == 0)
-		return (S_ERROR);
-	data->d_type = ELF_T_SYM;
-	data->d_align = M_WORD_ALIGN;
-	data->d_version = ofl->ofl_dehdr->e_version;
-
-	/*
-	 * Allocate and initialize the Shdr structure.
-	 */
-	if ((shdr = libld_calloc(sizeof (Shdr), 1)) == 0)
+	if (new_section(ofl, SHT_SYMTAB, MSG_ORIG(MSG_SCN_SYMTAB), 0,
+	    &isec, &shdr, &data) == S_ERROR)
 		return (S_ERROR);
-	shdr->sh_type = SHT_SYMTAB;
-	shdr->sh_addralign = M_WORD_ALIGN;
-	if ((shdr->sh_entsize = (Xword)elf_fsize(ELF_T_SYM, 1,
-	    ofl->ofl_dehdr->e_version)) == 0) {
-		eprintf(ofl->ofl_lml, ERR_ELF, MSG_INTL(MSG_ELF_FSIZE),
-		    ofl->ofl_name);
-		return (S_ERROR);
-	}
-
-	/*
-	 * Allocate and initialize the Is_desc structure.
-	 */
-	if ((isec = libld_calloc(1, sizeof (Is_desc))) == 0)
-		return (S_ERROR);
-	isec->is_name = MSG_ORIG(MSG_SCN_SYMTAB);
-	isec->is_shdr = shdr;
-	isec->is_indata = data;
 
 	/*
 	 * Place the section first since it will affect the local symbol
@@ -1269,21 +1313,11 @@
 		Shdr		*xshdr;
 		Elf_Data	*xdata;
 
-		if ((xdata = libld_calloc(sizeof (Elf_Data), 1)) == 0)
-			return (S_ERROR);
-		xdata->d_type = ELF_T_WORD;
-		xdata->d_align = M_WORD_ALIGN;
-		xdata->d_version = ofl->ofl_dehdr->e_version;
-		if ((xshdr = libld_calloc(sizeof (Shdr), 1)) == 0)
+		if (new_section(ofl, SHT_SYMTAB_SHNDX,
+		    MSG_ORIG(MSG_SCN_SYMTAB_SHNDX), 0, &xisec,
+		    &xshdr, &xdata) == S_ERROR)
 			return (S_ERROR);
-		xshdr->sh_type = SHT_SYMTAB_SHNDX;
-		xshdr->sh_addralign = M_WORD_ALIGN;
-		xshdr->sh_entsize = sizeof (Word);
-		if ((xisec = libld_calloc(1, sizeof (Is_desc))) == 0)
-			return (S_ERROR);
-		xisec->is_name = MSG_ORIG(MSG_SCN_SYMTAB_SHNDX);
-		xisec->is_shdr = xshdr;
-		xisec->is_indata = xdata;
+
 		if ((ofl->ofl_ossymshndx = ld_place_section(ofl, xisec,
 		    M_ID_SYMTAB_NDX, 0)) == (Os_desc *)S_ERROR)
 			return (S_ERROR);
@@ -1323,51 +1357,38 @@
 static uintptr_t
 make_dynsym(Ofl_desc *ofl)
 {
-	Shdr		*shdr;
-	Elf_Data	*data;
-	Is_desc		*isec;
+	Shdr		*shdr, *lshdr;
+	Elf_Data	*data, *ldata;
+	Is_desc		*isec, *lisec;
 	size_t		size;
 	Xword		cnt;
+	int		need_ldynsym;
 
-	/*
-	 * Allocate and initialize the Elf_Data structure.
-	 */
-	if ((data = libld_calloc(sizeof (Elf_Data), 1)) == 0)
-		return (S_ERROR);
-	data->d_type = ELF_T_SYM;
-	data->d_align = M_WORD_ALIGN;
-	data->d_version = ofl->ofl_dehdr->e_version;
+	need_ldynsym = !(ofl->ofl_flags & FLG_OF_NOLDYNSYM) &&
+	    ((ofl->ofl_dynlocscnt + ofl->ofl_dynscopecnt) > 0);
 
 	/*
-	 * Allocate and initialize the Shdr structure.
+	 * Create the section headers. Note that we supply an ent_cnt
+	 * of 0. We won't know the count until the section has been placed.
 	 */
-	if ((shdr = libld_calloc(sizeof (Shdr), 1)) == 0)
+	if (need_ldynsym && new_section(ofl, SHT_SUNW_LDYNSYM,
+	    MSG_ORIG(MSG_SCN_LDYNSYM), 0, &lisec, &lshdr, &ldata) == S_ERROR)
 		return (S_ERROR);
-	shdr->sh_type = SHT_DYNSYM;
-	shdr->sh_flags = SHF_ALLOC;
-	shdr->sh_addralign = M_WORD_ALIGN;
-	if ((shdr->sh_entsize = (Xword)elf_fsize(ELF_T_SYM, 1,
-	    ofl->ofl_dehdr->e_version)) == 0) {
-		eprintf(ofl->ofl_lml, ERR_ELF, MSG_INTL(MSG_ELF_FSIZE),
-		    ofl->ofl_name);
+
+	if (new_section(ofl, SHT_DYNSYM, MSG_ORIG(MSG_SCN_DYNSYM), 0,
+	    &isec, &shdr, &data) == S_ERROR)
 		return (S_ERROR);
-	}
 
 	/*
-	 * Allocate and initialize the Is_desc structure.
-	 */
-	if ((isec = libld_calloc(1, sizeof (Is_desc))) == 0)
-		return (S_ERROR);
-	isec->is_name = MSG_ORIG(MSG_SCN_DYNSYM);
-	isec->is_shdr = shdr;
-	isec->is_indata = data;
-
-	/*
-	 * Place the section first since it will affect the local symbol
+	 * Place the section(s) first since it will affect the local symbol
 	 * count.
 	 */
-	if ((ofl->ofl_osdynsym = ld_place_section(ofl, isec, M_ID_DYNSYM, 0)) ==
-	    (Os_desc *)S_ERROR)
+	if (need_ldynsym &&
+	    ((ofl->ofl_osldynsym = ld_place_section(ofl, lisec,
+	    M_ID_LDYNSYM, 0)) == (Os_desc *)S_ERROR))
+		return (S_ERROR);
+	if ((ofl->ofl_osdynsym = ld_place_section(ofl, isec, M_ID_DYNSYM, 0))
+	    == (Os_desc *)S_ERROR)
 		return (S_ERROR);
 
 	/*
@@ -1382,57 +1403,75 @@
 	data->d_size = size;
 	shdr->sh_size = (Xword)size;
 
+	/*
+	 * An ldynsym contains local function symbols. It is not
+	 * used for linking, but if present, serves to allow better
+	 * stack traces to be generated in contexts where the symtab
+	 * is not available. (dladdr(), or stripped executable/library files).
+	 */
+	if (need_ldynsym) {
+		cnt = 1 + ofl->ofl_dynlocscnt + ofl->ofl_dynscopecnt;
+		size = (size_t)cnt * shdr->sh_entsize;
+
+		ldata->d_size = size;
+		lshdr->sh_size = (Xword)size;
+	}
+
 	return (1);
 }
 
 /*
- * Build a SHT_SYMTAB_SHNDX for the .dynsym
+ * Helper routine for make_dynsym_shndx. Builds a
+ * a SHT_SYMTAB_SHNDX for dynsym or ldynsym, without knowing
+ * which one it is.
  */
 static uintptr_t
-make_dynsym_shndx(Ofl_desc *ofl)
+make_dyn_shndx(Ofl_desc *ofl, const char *shname, Os_desc *symtab,
+    Os_desc **ret_os)
 {
 	Is_desc		*isec;
 	Is_desc		*dynsymisp;
 	Shdr		*shdr, *dynshdr;
 	Elf_Data	*data;
 
-	/*
-	 * Allocate the Elf_Data structure.
-	 */
-	if ((data = libld_calloc(sizeof (Elf_Data), 1)) == 0)
-		return (S_ERROR);
-	data->d_type = ELF_T_WORD;
-	data->d_align = M_WORD_ALIGN;
-	data->d_version = ofl->ofl_dehdr->e_version;
+	dynsymisp = (Is_desc *)symtab->os_isdescs.head->data;
+	dynshdr = dynsymisp->is_shdr;
 
-	/*
-	 * Allocate the Shdr structure.
-	 */
-	if ((shdr = libld_calloc(sizeof (Shdr), 1)) == 0)
+	if (new_section(ofl, SHT_SYMTAB_SHNDX, shname,
+	    (dynshdr->sh_size / dynshdr->sh_entsize),
+	    &isec, &shdr, &data) == S_ERROR)
 		return (S_ERROR);
-	shdr->sh_type = SHT_SYMTAB_SHNDX;
-	shdr->sh_addralign = M_WORD_ALIGN;
-	shdr->sh_entsize = sizeof (Word);
 
-	/*
-	 * Allocate the Is_desc structure.
-	 */
-	if ((isec = libld_calloc(1, sizeof (Is_desc))) == 0)
-		return (S_ERROR);
-	isec->is_name = MSG_ORIG(MSG_SCN_DYNSYM_SHNDX);
-	isec->is_shdr = shdr;
-	isec->is_indata = data;
-
-	if ((ofl->ofl_osdynshndx = ld_place_section(ofl, isec,
+	if ((*ret_os = ld_place_section(ofl, isec,
 	    M_ID_DYNSYM_NDX, 0)) == (Os_desc *)S_ERROR)
 		return (S_ERROR);
 
-	assert(ofl->ofl_osdynsym);
-	dynsymisp = (Is_desc *)ofl->ofl_osdynsym->os_isdescs.head->data;
-	dynshdr = dynsymisp->is_shdr;
-	shdr->sh_size = (Xword)((dynshdr->sh_size / dynshdr->sh_entsize) *
-		sizeof (Word));
-	data->d_size = shdr->sh_size;
+	assert(*ret_os);
+
+	return (1);
+}
+
+/*
+ * Build a SHT_SYMTAB_SHNDX for the .dynsym, and .SUNW_ldynsym
+ */
+static uintptr_t
+make_dynsym_shndx(Ofl_desc *ofl)
+{
+	/*
+	 * If there is an ldynsym, generate a section for its extended
+	 * index section as well.
+	 */
+	if (!(ofl->ofl_flags & FLG_OF_NOLDYNSYM) &&
+	    ((ofl->ofl_dynlocscnt + ofl->ofl_dynscopecnt) > 0)) {
+		if (make_dyn_shndx(ofl, MSG_ORIG(MSG_SCN_LDYNSYM_SHNDX),
+		    ofl->ofl_osldynsym, &ofl->ofl_osldynshndx) == S_ERROR)
+			return (S_ERROR);
+	}
+
+	/* The Generate a section for the dynsym */
+	if (make_dyn_shndx(ofl, MSG_ORIG(MSG_SCN_DYNSYM_SHNDX),
+	    ofl->ofl_osdynsym, &ofl->ofl_osdynshndx) == S_ERROR)
+		return (S_ERROR);
 
 	return (1);
 }
@@ -1449,32 +1488,9 @@
 	Is_desc		*isec;
 	size_t		size;
 
-	/*
-	 * Allocate the Elf_Data structure.
-	 */
-	if ((data = libld_calloc(sizeof (Elf_Data), 1)) == 0)
+	if (new_section(ofl, SHT_STRTAB, MSG_ORIG(MSG_SCN_SHSTRTAB),
+	    0, &isec, &shdr, &data) == S_ERROR)
 		return (S_ERROR);
-	data->d_type = ELF_T_BYTE;
-	data->d_align = 1;
-	data->d_version = ofl->ofl_dehdr->e_version;
-
-	/*
-	 * Allocate the Shdr structure.
-	 */
-	if ((shdr = libld_calloc(sizeof (Shdr), 1)) == 0)
-		return (S_ERROR);
-	shdr->sh_type = SHT_STRTAB;
-	shdr->sh_flags |= SHF_STRINGS;
-	shdr->sh_addralign = 1;
-
-	/*
-	 * Allocate the Is_desc structure.
-	 */
-	if ((isec = libld_calloc(1, sizeof (Is_desc))) == 0)
-		return (S_ERROR);
-	isec->is_name = MSG_ORIG(MSG_SCN_SHSTRTAB);
-	isec->is_shdr = shdr;
-	isec->is_indata = data;
 
 	/*
 	 * Place the section first, as it may effect the number of section
@@ -1515,34 +1531,13 @@
 	size = st_getstrtab_sz(ofl->ofl_strtab);
 	assert(size > 0);
 
-	/*
-	 * Allocate the Elf_Data structure.
-	 */
-	if ((data = libld_calloc(sizeof (Elf_Data), 1)) == 0)
+	if (new_section(ofl, SHT_STRTAB, MSG_ORIG(MSG_SCN_STRTAB),
+	    0, &isec, &shdr, &data) == S_ERROR)
 		return (S_ERROR);
-	data->d_size = size;
-	data->d_type = ELF_T_BYTE;
-	data->d_align = 1;
-	data->d_version = ofl->ofl_dehdr->e_version;
 
-	/*
-	 * Allocate the Shdr structure.
-	 */
-	if ((shdr = libld_calloc(sizeof (Shdr), 1)) == 0)
-		return (S_ERROR);
+	/* Set the size of the data area */
+	data->d_size = size;
 	shdr->sh_size = (Xword)size;
-	shdr->sh_addralign = 1;
-	shdr->sh_type = SHT_STRTAB;
-	shdr->sh_flags |= SHF_STRINGS;
-
-	/*
-	 * Allocate and initialize the Is_desc structure.
-	 */
-	if ((isec = libld_calloc(1, sizeof (Is_desc))) == 0)
-		return (S_ERROR);
-	isec->is_name = MSG_ORIG(MSG_SCN_STRTAB);
-	isec->is_shdr = shdr;
-	isec->is_indata = data;
 
 	ofl->ofl_osstrtab = ld_place_section(ofl, isec, M_ID_STRTAB, 0);
 	return ((uintptr_t)ofl->ofl_osstrtab);
@@ -1560,6 +1555,18 @@
 	size_t		size;
 
 	/*
+	 * If this dynstr is to contain local symbols, and if we
+	 * have scope reduced global symbols to put there, then
+	 * account for the STT_FILE symbol that precedes those symbols.
+	 */
+	if (!(ofl->ofl_flags & FLG_OF_NOLDYNSYM) && ofl->ofl_dynscopecnt) {
+		if (st_insert(ofl->ofl_dynstrtab, ofl->ofl_name) == -1)
+			return (S_ERROR);
+		ofl->ofl_dynscopecnt++;
+	}
+
+
+	/*
 	 * Account for any local, named register symbols.  These locals are
 	 * required for reference from DT_REGISTER .dynamic entries.
 	 */
@@ -1599,37 +1606,17 @@
 	size = st_getstrtab_sz(ofl->ofl_dynstrtab);
 	assert(size > 0);
 
-	/*
-	 * Allocate the Elf_Data structure.
-	 */
-	if ((data = libld_calloc(sizeof (Elf_Data), 1)) == 0)
+	if (new_section(ofl, SHT_STRTAB, MSG_ORIG(MSG_SCN_DYNSTR),
+	    0, &isec, &shdr, &data) == S_ERROR)
 		return (S_ERROR);
-	data->d_type = ELF_T_BYTE;
-	data->d_size = size;
-	data->d_align = 1;
-	data->d_version = ofl->ofl_dehdr->e_version;
 
-	/*
-	 * Allocate the Shdr structure.
-	 */
-	if ((shdr = libld_calloc(sizeof (Shdr), 1)) == 0)
-		return (S_ERROR);
+	/* Make it allocable if necessary */
 	if (!(ofl->ofl_flags & FLG_OF_RELOBJ))
-		shdr->sh_flags = SHF_ALLOC;
-
-	shdr->sh_type = SHT_STRTAB;
-	shdr->sh_flags |= SHF_STRINGS;
-	shdr->sh_size = (Xword)size;
-	shdr->sh_addralign = 1;
+		shdr->sh_flags |= SHF_ALLOC;
 
-	/*
-	 * Allocate and initialize the Is_desc structure.
-	 */
-	if ((isec = libld_calloc(1, sizeof (Is_desc))) == 0)
-		return (S_ERROR);
-	isec->is_name = MSG_ORIG(MSG_SCN_DYNSTR);
-	isec->is_shdr = shdr;
-	isec->is_indata = data;
+	/* Set the size of the data area */
+	data->d_size = size;
+	shdr->sh_size = (Xword)size;
 
 	ofl->ofl_osdynstr = ld_place_section(ofl, isec, M_ID_DYNSTR, 0);
 	return ((uintptr_t)ofl->ofl_osdynstr);
@@ -1691,29 +1678,14 @@
 	/* LINTED */
 	ofl->ofl_relocsz += (Xword)size;
 
-	/*
-	 * Allocate and initialize the Elf_Data structure.
-	 */
-	if ((data = libld_calloc(sizeof (Elf_Data), 1)) == 0)
+	if (new_section(ofl, M_REL_SHT_TYPE, sectname, 0, &isec, &shdr, &data)
+	    == S_ERROR)
 		return (S_ERROR);
-	data->d_type = M_REL_ELF_TYPE;
-	data->d_size = size;
-	data->d_align = M_WORD_ALIGN;
-	data->d_version = ofl->ofl_dehdr->e_version;
 
-	/*
-	 * Allocate and initialize the Shdr structure.
-	 */
-	if ((shdr = libld_calloc(sizeof (Shdr), 1)) == 0)
-		return (S_ERROR);
-	shdr->sh_type = M_REL_SHT_TYPE;
+	data->d_size = size;
+
 	shdr->sh_size = (Xword)size;
-	shdr->sh_addralign = M_WORD_ALIGN;
-	shdr->sh_entsize = relsize;
-
-	if ((ofl->ofl_flags & FLG_OF_DYNAMIC) &&
-	    !(ofl->ofl_flags & FLG_OF_RELOBJ) &&
-	    (sh_flags & SHF_ALLOC))
+	if (OFL_ALLOW_DYNSYM(ofl) && (sh_flags & SHF_ALLOC))
 		shdr->sh_flags = SHF_ALLOC;
 
 	if (osp) {
@@ -1724,17 +1696,6 @@
 		shdr->sh_flags |= SHF_INFO_LINK;
 	}
 
-
-	/*
-	 * Allocate and initialize the Is_desc structure.
-	 */
-	if ((isec = libld_calloc(1, sizeof (Is_desc))) == 0)
-		return (S_ERROR);
-	isec->is_shdr = shdr;
-	isec->is_indata = data;
-	isec->is_name = sectname;
-
-
 	/*
 	 * Associate this relocation section to the section its going to
 	 * relocate.
@@ -1791,36 +1752,18 @@
 	Shdr		*shdr;
 	Elf_Data	*data;
 	Is_desc		*isec;
-	size_t		size = ofl->ofl_verneedsz;
-
-	/*
-	 * Allocate and initialize the Elf_Data structure.
-	 */
-	if ((data = libld_calloc(sizeof (Elf_Data), 1)) == 0)
-		return (S_ERROR);
-	data->d_type = ELF_T_BYTE;
-	data->d_size = size;
-	data->d_align = M_WORD_ALIGN;
-	data->d_version = ofl->ofl_dehdr->e_version;
 
 	/*
-	 * Allocate and initialize the Shdr structure.
+	 * verneed sections do not have a constant element size, so the
+	 * value of ent_cnt specified here (0) is meaningless.
 	 */
-	if ((shdr = libld_calloc(sizeof (Shdr), 1)) == 0)
+	if (new_section(ofl, SHT_SUNW_verneed, MSG_ORIG(MSG_SCN_SUNWVERSION),
+			0, &isec, &shdr, &data) == S_ERROR)
 		return (S_ERROR);
-	shdr->sh_type = (Word)SHT_SUNW_verneed;
-	shdr->sh_flags = SHF_ALLOC;
-	shdr->sh_size = (Xword)size;
-	shdr->sh_addralign = M_WORD_ALIGN;
 
-	/*
-	 * Allocate and initialize the Is_desc structure.
-	 */
-	if ((isec = libld_calloc(1, sizeof (Is_desc))) == 0)
-		return (S_ERROR);
-	isec->is_name = MSG_ORIG(MSG_SCN_SUNWVERSION);
-	isec->is_shdr = shdr;
-	isec->is_indata = data;
+	/* During version processing we calculated the total size. */
+	data->d_size = ofl->ofl_verneedsz;
+	shdr->sh_size = (Xword)ofl->ofl_verneedsz;
 
 	ofl->ofl_osverneed = ld_place_section(ofl, isec, M_ID_VERSION, 0);
 	return ((uintptr_t)ofl->ofl_osverneed);
@@ -1839,7 +1782,6 @@
 	Elf_Data	*data;
 	Is_desc		*isec;
 	Ver_desc	*vdp;
-	size_t		size;
 
 	/*
 	 * Reserve a string table entry for the base version dependency (other
@@ -1847,7 +1789,6 @@
 	 * accounted for during symbol processing).
 	 */
 	vdp = (Ver_desc *)ofl->ofl_verdesc.head->data;
-	size = strlen(vdp->vd_name) + 1;
 
 	if (ofl->ofl_flags & FLG_OF_DYNAMIC) {
 		if (st_insert(ofl->ofl_dynstrtab, vdp->vd_name) == -1)
@@ -1858,36 +1799,16 @@
 	}
 
 	/*
-	 * During version processing we calculated the total number of entries.
-	 * Allocate and initialize the Elf_Data structure.
-	 */
-	size = ofl->ofl_verdefsz;
-
-	if ((data = libld_calloc(sizeof (Elf_Data), 1)) == 0)
-		return (S_ERROR);
-	data->d_type = ELF_T_BYTE;
-	data->d_size = size;
-	data->d_align = M_WORD_ALIGN;
-	data->d_version = ofl->ofl_dehdr->e_version;
-
-	/*
-	 * Allocate and initialize the Shdr structure.
+	 * verdef sections do not have a constant element size, so the
+	 * value of ent_cnt specified here (0) is meaningless.
 	 */
-	if ((shdr = libld_calloc(sizeof (Shdr), 1)) == 0)
+	if (new_section(ofl, SHT_SUNW_verdef, MSG_ORIG(MSG_SCN_SUNWVERSION),
+			0, &isec, &shdr, &data) == S_ERROR)
 		return (S_ERROR);
-	shdr->sh_type = (Word)SHT_SUNW_verdef;
-	shdr->sh_flags = SHF_ALLOC;
-	shdr->sh_size = (Xword)size;
-	shdr->sh_addralign = M_WORD_ALIGN;
 
-	/*
-	 * Allocate and initialize the Is_desc structure.
-	 */
-	if ((isec = libld_calloc(1, sizeof (Is_desc))) == 0)
-		return (S_ERROR);
-	isec->is_name = MSG_ORIG(MSG_SCN_SUNWVERSION);
-	isec->is_shdr = shdr;
-	isec->is_indata = data;
+	/* During version processing we calculated the total size. */
+	data->d_size = ofl->ofl_verdefsz;
+	shdr->sh_size = (Xword)ofl->ofl_verdefsz;
 
 	ofl->ofl_osverdef = ld_place_section(ofl, isec, M_ID_VERSION, 0);
 	return ((uintptr_t)ofl->ofl_osverdef);
@@ -1899,49 +1820,19 @@
  * provides additional symbol information.
  */
 static Os_desc *
-make_sym_sec(Ofl_desc *ofl, const char *sectname, Word entsize,
-    Word stype, int ident)
+make_sym_sec(Ofl_desc *ofl, const char *sectname, Word stype, int ident)
 {
 	Shdr		*shdr;
 	Elf_Data	*data;
 	Is_desc		*isec;
 
 	/*
-	 * Allocate and initialize the Elf_Data structures for the symbol index
-	 * array.
+	 * We don't know the size of this section yet, so set it to 0.
+	 * It gets filled in after the dynsym is sized.
 	 */
-	if ((data = libld_calloc(sizeof (Elf_Data), 1)) == 0)
-		return ((Os_desc *)S_ERROR);
-	data->d_type = ELF_T_BYTE;
-	data->d_align = M_WORD_ALIGN;
-	data->d_version = ofl->ofl_dehdr->e_version;
-
-	/*
-	 * Allocate and initialize the Shdr structure.
-	 */
-	if ((shdr = libld_calloc(sizeof (Shdr), 1)) == 0)
+	if (new_section(ofl, stype, sectname, 0, &isec, &shdr, &data) ==
+	    S_ERROR)
 		return ((Os_desc *)S_ERROR);
-	shdr->sh_type = (Word)stype;
-	shdr->sh_flags = SHF_ALLOC;
-	shdr->sh_addralign = M_WORD_ALIGN;
-	shdr->sh_entsize = entsize;
-
-	if (stype == SHT_SUNW_syminfo) {
-		/*
-		 * The sh_info field of the SHT_*_syminfo section points
-		 * to the header index of the associated .dynamic section.
-		 */
-		shdr->sh_flags |= SHF_INFO_LINK;
-	}
-
-	/*
-	 * Allocate and initialize the Is_desc structure.
-	 */
-	if ((isec = libld_calloc(1, sizeof (Is_desc))) == 0)
-		return ((Os_desc *)S_ERROR);
-	isec->is_name = sectname;
-	isec->is_shdr = shdr;
-	isec->is_indata = data;
 
 	return (ld_place_section(ofl, isec, ident, 0));
 }
@@ -1957,35 +1848,21 @@
 	Is_desc		*isec;
 
 	/*
-	 * Allocate and initialize the Elf_Data structure.
+	 * Allocate header structs. We will set the name ourselves below,
+	 * and there is no entcnt for a BSS. So, the shname and entcnt
+	 * arguments are 0.
 	 */
-	if ((data = libld_calloc(sizeof (Elf_Data), 1)) == 0)
+	if (new_section(ofl, SHT_NOBITS, MSG_ORIG(MSG_SCN_SUNWBSS), 0,
+	    &isec, &shdr, &data) == S_ERROR)
 		return (S_ERROR);
-	data->d_type = ELF_T_BYTE;
+
 	data->d_size = size;
 	data->d_align = align;
-	data->d_version = ofl->ofl_dehdr->e_version;
 
-	/*
-	 * Allocate and initialize the Shdr structure.
-	 */
-	if ((shdr = libld_calloc(sizeof (Shdr), 1)) == 0)
-		return (S_ERROR);
-	shdr->sh_type = SHT_NOBITS;
-	shdr->sh_flags = SHF_ALLOC | SHF_WRITE;
 	shdr->sh_size = (Xword)size;
 	shdr->sh_addralign = align;
 
 	/*
-	 * Allocate and initialize the Is_desc structure.
-	 */
-	if ((isec = libld_calloc(1, sizeof (Is_desc))) == 0)
-		return (S_ERROR);
-	isec->is_name = MSG_ORIG(MSG_SCN_SUNWBSS);
-	isec->is_shdr = shdr;
-	isec->is_indata = data;
-
-	/*
 	 * Retain this .sunwbss input section as this will be where global
 	 * symbol references are added.
 	 */
@@ -2007,39 +1884,20 @@
 	Is_desc		*isec;
 	Os_desc		*osp;
 
-	/*
-	 * Allocate and initialize the Elf_Data structure.
-	 */
-	if ((data = libld_calloc(sizeof (Elf_Data), 1)) == 0)
+	if (new_section(ofl, SHT_PROGBITS, MSG_ORIG(MSG_SCN_SUNWDATA1), 0,
+	    &isec, &shdr, &data) == S_ERROR)
 		return (S_ERROR);
-	data->d_type = ELF_T_BYTE;
+
+	shdr->sh_flags |= SHF_WRITE;
 	data->d_size = size;
+	shdr->sh_size = (Xword)size;
+	if (align != 0) {
+		data->d_align = align;
+		shdr->sh_addralign = align;
+	}
+
 	if ((data->d_buf = libld_calloc(size, 1)) == 0)
 		return (S_ERROR);
-	data->d_align = (size_t)M_WORD_ALIGN;
-	data->d_version = ofl->ofl_dehdr->e_version;
-
-	/*
-	 * Allocate and initialize the Shdr structure.
-	 */
-	if ((shdr = libld_calloc(sizeof (Shdr), 1)) == 0)
-		return (S_ERROR);
-	shdr->sh_type = SHT_PROGBITS;
-	shdr->sh_flags = SHF_ALLOC | SHF_WRITE;
-	shdr->sh_size = (Xword)size;
-	if (align == 0)
-		shdr->sh_addralign = M_WORD_ALIGN;
-	else
-		shdr->sh_addralign = align;
-
-	/*
-	 * Allocate and initialize the Is_desc structure.
-	 */
-	if ((isec = libld_calloc(1, sizeof (Is_desc))) == 0)
-		return (S_ERROR);
-	isec->is_name = MSG_ORIG(MSG_SCN_SUNWDATA1);
-	isec->is_shdr = shdr;
-	isec->is_indata = data;
 
 	/*
 	 * Retain this .sunwdata1 input section as this will
@@ -2067,50 +1925,17 @@
 	Shdr		*shdr;
 	Elf_Data	*data;
 	Is_desc		*isec;
-	size_t		size;
 	Listnode	*lnp1;
 	Psym_info	*psym;
 	int 		cnt = 1;
 
-	/*
-	 * Generate the move input sections and output sections
-	 */
-	size = mv_nums * sizeof (Move);
-
-	/*
-	 * Allocate and initialize the Elf_Data structure.
-	 */
-	if ((data = libld_calloc(sizeof (Elf_Data), 1)) == 0)
-		return (S_ERROR);
-	data->d_type = ELF_T_BYTE;
-	if ((data->d_buf = libld_calloc(size, 1)) == 0)
-		return (S_ERROR);
-	data->d_size = size;
-	data->d_align = sizeof (Lword);
-	data->d_version = ofl->ofl_dehdr->e_version;
 
-	/*
-	 * Allocate and initialize the Shdr structure.
-	 */
-	if ((shdr = libld_calloc(sizeof (Shdr), 1)) == 0)
+	if (new_section(ofl, SHT_SUNW_move, MSG_ORIG(MSG_SCN_SUNWMOVE),
+	    mv_nums, &isec, &shdr, &data) == S_ERROR)
 		return (S_ERROR);
-	shdr->sh_link = 0;
-	shdr->sh_info = 0;
-	shdr->sh_type = SHT_SUNW_move;
-	shdr->sh_size = (Xword)size;
-	shdr->sh_flags = SHF_ALLOC | SHF_WRITE;
-	shdr->sh_addralign = sizeof (Lword);
-	shdr->sh_entsize = sizeof (Move);
 
-	/*
-	 * Allocate and initialize the Is_desc structure.
-	 */
-	if ((isec = libld_calloc(1, sizeof (Is_desc))) == 0)
+	if ((data->d_buf = libld_calloc(data->d_size, 1)) == 0)
 		return (S_ERROR);
-	isec->is_name = MSG_ORIG(MSG_SCN_SUNWMOVE);
-	isec->is_shdr = shdr;
-	isec->is_indata = data;
-	isec->is_file = 0;
 
 	/*
 	 * Copy move entries
@@ -2206,18 +2031,18 @@
 		if (make_verdef(ofl) == S_ERROR)
 			return (S_ERROR);
 		if ((ofl->ofl_osversym = make_sym_sec(ofl,
-		    MSG_ORIG(MSG_SCN_SUNWVERSYM), sizeof (Versym),
-		    SHT_SUNW_versym, M_ID_VERSION)) == (Os_desc*)S_ERROR)
+		    MSG_ORIG(MSG_SCN_SUNWVERSYM), SHT_SUNW_versym,
+		    M_ID_VERSION)) == (Os_desc*)S_ERROR)
 			return (S_ERROR);
 	}
 
 	/*
-	 * Create a syminfo section is necessary.
+	 * Create a syminfo section if necessary.
 	 */
 	if (ofl->ofl_flags & FLG_OF_SYMINFO) {
 		if ((ofl->ofl_ossyminfo = make_sym_sec(ofl,
-		    MSG_ORIG(MSG_SCN_SUNWSYMINFO), sizeof (Syminfo),
-		    SHT_SUNW_syminfo, M_ID_SYMINFO)) == (Os_desc *)S_ERROR)
+		    MSG_ORIG(MSG_SCN_SUNWSYMINFO), SHT_SUNW_syminfo,
+		    M_ID_SYMINFO)) == (Os_desc *)S_ERROR)
 			return (S_ERROR);
 	}
 
@@ -2342,13 +2167,14 @@
 		size_t		size;
 		ulong_t		cnt;
 
-		if ((flags & FLG_OF_RELOBJ) || (flags & FLG_OF_STATIC))
+		if (flags & (FLG_OF_RELOBJ | FLG_OF_STATIC)) {
 			isec = (Is_desc *)ofl->ofl_ossymtab->
 				os_isdescs.head->data;
-		else
+		} else {
 			isec = (Is_desc *)ofl->ofl_osdynsym->
 				os_isdescs.head->data;
-		cnt = isec->is_shdr->sh_size / isec->is_shdr->sh_entsize;
+		}
+		cnt = (isec->is_shdr->sh_size / isec->is_shdr->sh_entsize);
 
 		if (ofl->ofl_osversym) {
 			isec = (Is_desc *)ofl->ofl_osversym->os_isdescs.
@@ -2384,34 +2210,13 @@
 	Elf_Data	*data;
 	Is_desc		*isec;
 
-	/*
-	 * Allocate and initialize the Elf_Data structure.
-	 */
-	if ((data = libld_calloc(sizeof (Elf_Data), 1)) == 0)
+	if (new_section(ofl, SHT_PROGBITS, MSG_ORIG(MSG_SCN_DATA), 0,
+	    &isec, &shdr, &data) == S_ERROR)
 		return ((Is_desc *)S_ERROR);
-	data->d_type = ELF_T_BYTE;
-	data->d_size = size;
-	data->d_align = M_WORD_ALIGN;
-	data->d_version = ofl->ofl_dehdr->e_version;
 
-	/*
-	 * Allocate and initialize the Shdr structure.
-	 */
-	if ((shdr = libld_calloc(sizeof (Shdr), 1)) == 0)
-		return ((Is_desc *)S_ERROR);
-	shdr->sh_type = SHT_PROGBITS;
-	shdr->sh_flags = SHF_ALLOC | SHF_WRITE;
+	data->d_size = size;
 	shdr->sh_size = (Xword)size;
-	shdr->sh_addralign = M_WORD_ALIGN;
-
-	/*
-	 * Allocate and initialize the Is_desc structure.
-	 */
-	if ((isec = libld_calloc(1, sizeof (Is_desc))) == (Is_desc *)0)
-		return ((Is_desc *)S_ERROR);
-	isec->is_name = MSG_ORIG(MSG_SCN_DATA);
-	isec->is_shdr = shdr;
-	isec->is_indata = data;
+	shdr->sh_flags |= SHF_WRITE;
 
 	if (ld_place_section(ofl, isec, M_ID_DATA, 0) == (Os_desc *)S_ERROR)
 		return ((Is_desc *)S_ERROR);
@@ -2473,38 +2278,18 @@
 	if (size < sizeof (ret_template))
 		size = sizeof (ret_template);
 
-	/*
-	 * Allocate and initialize the Elf_Data structure.  Fill the buffer
-	 * with the appropriate return instruction.
-	 */
-	if (((data = libld_calloc(sizeof (Elf_Data), 1)) == 0) ||
-	    ((data->d_buf = libld_calloc(size, 1)) == 0))
+	if (new_section(ofl, SHT_PROGBITS, MSG_ORIG(MSG_SCN_TEXT), 0,
+	    &isec, &shdr, &data) == S_ERROR)
 		return ((Is_desc *)S_ERROR);
-	data->d_type = ELF_T_BYTE;
-	data->d_size = size;
-	data->d_align = M_WORD_ALIGN;
-	data->d_version = ofl->ofl_dehdr->e_version;
-
-	(void) memcpy(data->d_buf, ret_template, sizeof (ret_template));
 
-	/*
-	 * Allocate and initialize the Shdr structure.
-	 */
-	if ((shdr = libld_calloc(sizeof (Shdr), 1)) == 0)
-		return ((Is_desc *)S_ERROR);
-	shdr->sh_type = SHT_PROGBITS;
-	shdr->sh_flags = SHF_ALLOC | SHF_EXECINSTR;
+	data->d_size = size;
 	shdr->sh_size = (Xword)size;
-	shdr->sh_addralign = M_WORD_ALIGN;
+	shdr->sh_flags |= SHF_EXECINSTR;
 
-	/*
-	 * Allocate and initialize the Is_desc structure.
-	 */
-	if ((isec = libld_calloc(1, sizeof (Is_desc))) == (Is_desc *)0)
+	/* Fill the buffer with the appropriate return instruction. */
+	if ((data->d_buf = libld_calloc(size, 1)) == 0)
 		return ((Is_desc *)S_ERROR);
-	isec->is_name = MSG_ORIG(MSG_SCN_TEXT);
-	isec->is_shdr = shdr;
-	isec->is_indata = data;
+	(void) memcpy(data->d_buf, ret_template, sizeof (ret_template));
 
 	if (ld_place_section(ofl, isec, M_ID_TEXT, 0) == (Os_desc *)S_ERROR)
 		return ((Is_desc *)S_ERROR);
--- a/usr/src/cmd/sgs/libld/common/syms.c	Tue Sep 19 15:34:23 2006 -0700
+++ b/usr/src/cmd/sgs/libld/common/syms.c	Tue Sep 19 15:38:37 2006 -0700
@@ -466,7 +466,7 @@
 			 * implicit shared object.
 			 */
 			if (ifl->ifl_vercnt) {
-				Ver_index *	vip;
+				Ver_index	*vip;
 				Half		vndx = ifl->ifl_versym[ndx];
 
 				sap->sa_dverndx = vndx;
@@ -745,9 +745,7 @@
 uintptr_t
 ld_sym_spec(Ofl_desc *ofl)
 {
-	Word		flags = ofl->ofl_flags;
-
-	if (!(flags & FLG_OF_RELOBJ)) {
+	if (!(ofl->ofl_flags & FLG_OF_RELOBJ)) {
 
 		DBG_CALL(Dbg_syms_spec_title(ofl->ofl_lml));
 
@@ -781,8 +779,7 @@
 		    FLG_SY1_GLOB, ofl) == S_ERROR)
 			return (S_ERROR);
 
-		if ((flags & (FLG_OF_DYNAMIC | FLG_OF_RELOBJ)) ==
-		    FLG_OF_DYNAMIC)
+		if (OFL_ALLOW_DYNSYM(ofl))
 			if (sym_add_spec(MSG_ORIG(MSG_SYM_PLKTBL),
 			    MSG_ORIG(MSG_SYM_PLKTBL_U), SDAUX_ID_PLT,
 			    FLG_SY1_GLOB, ofl) == S_ERROR)
@@ -958,6 +955,7 @@
 	Xword		lbssalign = 0, lbsssize = 0;
 #endif
 	int		ret;
+	int		allow_ldynsym;
 
 	/*
 	 * If a symbol is undefined and this link-edit calls for no undefined
@@ -992,6 +990,7 @@
 	if ((oflags & FLG_OF_VERDEF) && (ofl->ofl_vercnt > VER_NDX_GLOBAL))
 		verdesc = FLG_OF_FATAL;
 
+	allow_ldynsym = OFL_ALLOW_LDYNSYM(ofl);
 	/*
 	 * Collect and validate the globals from the internal symbol table.
 	 */
@@ -1319,6 +1318,13 @@
 				    sym->st_name) && (st_insert(ofl->ofl_strtab,
 				    sdp->sd_name) == -1))
 					return (S_ERROR);
+				if (allow_ldynsym && sym->st_name &&
+				    (ELF_ST_TYPE(sym->st_info) == STT_FUNC)) {
+					ofl->ofl_dynscopecnt++;
+					if (st_insert(ofl->ofl_dynstrtab,
+					    sdp->sd_name) == -1)
+						return (S_ERROR);
+				}
 			}
 		} else {
 			ofl->ofl_globcnt++;
@@ -1636,6 +1642,7 @@
 	 * index array.
 	 */
 	if (local) {
+		int allow_ldynsym = OFL_ALLOW_LDYNSYM(ofl);
 		for (sym++, ndx = 1; ndx < local; sym++, ndx++) {
 			Word		shndx, sdflags = FLG_SY_CLEAN;
 			const char	*name;
@@ -1827,6 +1834,15 @@
 				    sym->st_name) && (st_insert(ofl->ofl_strtab,
 				    sdp->sd_name) == -1))
 					return (S_ERROR);
+
+				if (allow_ldynsym && sym->st_name &&
+				    ((type == STT_FUNC) ||
+				    (type == STT_FILE))) {
+					ofl->ofl_dynlocscnt++;
+					if (st_insert(ofl->ofl_dynstrtab,
+					    sdp->sd_name) == -1)
+						return (S_ERROR);
+				}
 			}
 		}
 	}
--- a/usr/src/cmd/sgs/libld/common/update.c	Tue Sep 19 15:34:23 2006 -0700
+++ b/usr/src/cmd/sgs/libld/common/update.c	Tue Sep 19 15:38:37 2006 -0700
@@ -41,7 +41,7 @@
 #include	"_libld.h"
 
 /*
- * Comparison routine used by qsort() for sorting of the global yymbol list
+ * Comparison routine used by qsort() for sorting of the global symbol list
  * based off of the hashbuckets the symbol will eventually be deposited in.
  */
 static int
@@ -77,13 +77,17 @@
 	Addr		tlsbssaddr = 0;
 	Addr 		sunwbssaddr = 0, sunwdata1addr;
 	int		start_set = 0;
-	Sym		_sym = {0}, *sym, *symtab = 0, *dynsym = 0;
+	Sym		_sym = {0}, *sym, *symtab = 0;
+	Sym		*dynsym = 0, *ldynsym = 0;
 	Word		symtab_ndx = 0;	/* index into .symtab */
-	Word		dynsym_ndx = 0;	/* index into .dynsym */
+	Word		ldynsym_ndx = 0;	/* index into .SUNW_ldynsym */
+	Word		dynsym_ndx = 0;		/* index into .dynsym */
 	Word		scopesym_ndx = 0; /* index into scoped symbols */
-	Word		*symndx = 0;	/* Symbol index (for relocation use) */
+	Word		ldynscopesym_ndx = 0; /* index to ldynsym scoped syms */
+	Word		*symndx;	/* Symbol index (for relocation use) */
 	Word		*symshndx = 0;	/* .symtab_shndx table */
 	Word		*dynshndx = 0;	/* .dynsym_shndx table */
+	Word		*ldynshndx = 0;	/* .SUNW_ldynsym_shndx table */
 	Str_tbl		*shstrtab;
 	Str_tbl		*strtab;
 	Str_tbl		*dynstr;
@@ -118,10 +122,19 @@
 		if (ofl->ofl_ossymshndx)
 		    symshndx = (Word *)ofl->ofl_ossymshndx->os_outdata->d_buf;
 	}
-	if ((flags & FLG_OF_DYNAMIC) && !(flags & FLG_OF_RELOBJ)) {
+	if (OFL_ALLOW_DYNSYM(ofl)) {
 		dynsym = (Sym *)ofl->ofl_osdynsym->os_outdata->d_buf;
 		dynsym[dynsym_ndx++] = _sym;
 		/*
+		 * If we are also constructing a .SUNW_ldynsym section
+		 * to contain local function symbols, then set it up too.
+		 */
+		if (ofl->ofl_osldynsym) {
+			ldynsym = (Sym *)ofl->ofl_osldynsym->os_outdata->d_buf;
+			ldynsym[ldynsym_ndx++] = _sym;
+		}
+
+		/*
 		 * Initialize the hash table.
 		 */
 		hashtab = (Word *)(ofl->ofl_oshash->os_outdata->d_buf);
@@ -132,6 +145,8 @@
 		    ofl->ofl_lregsymcnt + 1;
 		if (ofl->ofl_osdynshndx)
 		    dynshndx = (Word *)ofl->ofl_osdynshndx->os_outdata->d_buf;
+		if (ofl->ofl_osldynshndx)
+		    ldynshndx = (Word *)ofl->ofl_osldynshndx->os_outdata->d_buf;
 	}
 
 	/*
@@ -173,7 +188,7 @@
 	DBG_CALL(Dbg_syms_sec_title(ofl->ofl_lml));
 
 	/*
-	 * Add the output file name to the first .symtab symbol.
+	 * Put output file name to the first .symtab and .SUNW_ldynsym symbol.
 	 */
 	if (symtab) {
 		(void) st_setstring(strtab, ofl->ofl_name, &stoff);
@@ -189,6 +204,21 @@
 		if (versym && !dynsym)
 			versym[1] = 0;
 	}
+	if (ldynsym && ofl->ofl_dynscopecnt) {
+		(void) st_setstring(dynstr, ofl->ofl_name, &stoff);
+		sym = &ldynsym[ldynsym_ndx];
+		/* LINTED */
+		sym->st_name = stoff;
+		sym->st_value = 0;
+		sym->st_size = 0;
+		sym->st_info = ELF_ST_INFO(STB_LOCAL, STT_FILE);
+		sym->st_other = 0;
+		sym->st_shndx = SHN_ABS;
+
+		/* Scoped symbols get filled in global loop below */
+		ldynscopesym_ndx = ldynsym_ndx + 1;
+		ldynsym_ndx += ofl->ofl_dynscopecnt;
+	}
 
 	/*
 	 * If we are to display GOT summary information, then allocate
@@ -474,6 +504,8 @@
 			Gotndx		*gnp;
 			unsigned char	type;
 			Word		*_symshndx;
+			int		enter_in_symtab, enter_in_ldynsym;
+			int		update_done;
 
 			sdp = ifl->ifl_oldndx[lndx];
 			sym = sdp->sd_sym;
@@ -524,13 +556,16 @@
 			 * we still need to update any local symbols that are
 			 * used during relocation.
 			 */
+			enter_in_symtab = symtab &&
+			    (!(ofl->ofl_flags1 & FLG_OF1_REDLSYM) ||
+			    (sdp->sd_psyminfo));
+			enter_in_ldynsym = ldynsym && sdp->sd_name &&
+			    ((type == STT_FUNC) || (type == STT_FILE));
 			_symshndx = 0;
-			if (symtab && (!(ofl->ofl_flags1 & FLG_OF1_REDLSYM) ||
-			    (sdp->sd_psyminfo))) {
+			if (enter_in_symtab) {
 				if (!dynsym)
 					sdp->sd_symndx = *symndx;
 				symtab[symtab_ndx] = *sym;
-
 				/*
 				 * Provided this isn't an unnamed register
 				 * symbol, update its name.
@@ -547,9 +582,24 @@
 				sdp->sd_sym = sym = &symtab[symtab_ndx++];
 
 				if ((sdp->sd_flags & FLG_SY_SPECSEC) &&
-				    (sym->st_shndx == SHN_ABS))
+				    (sym->st_shndx == SHN_ABS) &&
+				    !enter_in_ldynsym)
 					continue;
-			} else {
+			} else if (enter_in_ldynsym) {
+				/*
+				 * Not using symtab, but we do have ldynsym
+				 * available.
+				 */
+				ldynsym[ldynsym_ndx] = *sym;
+				(void) st_setstring(dynstr, sdp->sd_name,
+					&stoff);
+				ldynsym[ldynsym_ndx].st_name = stoff;
+
+				sdp->sd_flags &= ~FLG_SY_CLEAN;
+				if (ldynshndx)
+					_symshndx = &ldynshndx[ldynsym_ndx];
+				sdp->sd_sym = sym = &ldynsym[ldynsym_ndx++];
+			} else {	/* Not using symtab or ldynsym */
 				/*
 				 * If this symbol requires modifying to provide
 				 * for a relocation or move table update, make
@@ -570,10 +620,11 @@
 			/*
 			 * Update the symbols contents if necessary.
 			 */
+			update_done = 0;
 			if (type == STT_FILE) {
 				sdp->sd_shndx = sym->st_shndx = SHN_ABS;
 				sdp->sd_flags |= FLG_SY_SPECSEC;
-				continue;
+				update_done = 1;
 			}
 
 			/*
@@ -581,14 +632,14 @@
 			 * initialized symbols, then update the address here.
 			 */
 			if (ofl->ofl_issunwdata1 &&
-			    (sdp->sd_flags & FLG_SY_PAREXPN)) {
+			    (sdp->sd_flags & FLG_SY_PAREXPN) && !update_done) {
 				static	Addr	laddr = 0;
 
 				sym->st_shndx = sunwdata1ndx;
 				sdp->sd_isc = ofl->ofl_issunwdata1;
-				if (ofl->ofl_flags & FLG_OF_RELOBJ)
+				if (ofl->ofl_flags & FLG_OF_RELOBJ) {
 					sym->st_value = sunwdata1addr;
-				else {
+				} else {
 					sym->st_value = laddr;
 					laddr += sym->st_size;
 				}
@@ -599,7 +650,7 @@
 			 * If this isn't an UNDEF symbol (ie. an input section
 			 * is associated), update the symbols value and index.
 			 */
-			if ((isc = sdp->sd_isc) != 0) {
+			if (((isc = sdp->sd_isc) != 0) && !update_done) {
 				Word	sectndx;
 
 				osp = isc->is_osdesc;
@@ -613,9 +664,10 @@
 					 * the TLS segment.
 					 */
 					if ((ELF_ST_TYPE(sym->st_info) ==
-					    STT_TLS) && (ofl->ofl_tlsphdr))
+					    STT_TLS) && (ofl->ofl_tlsphdr)) {
 						sym->st_value -=
 						    ofl->ofl_tlsphdr->p_vaddr;
+					}
 				}
 				/* LINTED */
 				if ((sdp->sd_shndx = sectndx =
@@ -629,6 +681,25 @@
 					sym->st_shndx = sectndx;
 				}
 			}
+
+			/*
+			 * If entering the symbol in both the symtab and the
+			 * ldynsym, then the one in symtab needs to be
+			 * copied to ldynsym. If it is only in the ldynsym,
+			 * then the code above already set it up and we have
+			 * nothing more to do here.
+			 */
+			if (enter_in_symtab && enter_in_ldynsym) {
+				ldynsym[ldynsym_ndx] = *sym;
+				(void) st_setstring(dynstr, sdp->sd_name,
+					&stoff);
+				ldynsym[ldynsym_ndx].st_name = stoff;
+
+				if (_symshndx && ldynshndx)
+					ldynshndx[ldynsym_ndx] = *_symshndx;
+
+				ldynsym_ndx++;
+			}
 		}
 	}
 
@@ -897,7 +968,7 @@
 		Sym		*sym;
 		Sym_aux		*sap;
 		Half		spec;
-		int		local = 0, enter_in_symtab;
+		int		local = 0, dynlocal = 0, enter_in_symtab;
 		Listnode	*lnp2;
 		Gotndx		*gnp;
 		Word		sectndx;
@@ -953,10 +1024,15 @@
 			else
 				sdp->sd_symndx = 0;
 
-			if (sdp->sd_flags1 & FLG_SY1_ELIM)
+			if (sdp->sd_flags1 & FLG_SY1_ELIM) {
 				enter_in_symtab = 0;
-		} else
+			} else if (ldynsym && sdp->sd_sym->st_name &&
+			    (ELF_ST_TYPE(sdp->sd_sym->st_info) == STT_FUNC)) {
+				dynlocal = 1;
+			}
+		} else {
 			sdp->sd_symndx = *symndx;
+		}
 
 		/*
 		 * Copy basic symbol and string information.
@@ -1146,7 +1222,7 @@
 		 * first, followed by the .dynsym, thus the `sym' value will
 		 * remain as the .dynsym value when the .dynsym is present.
 		 * This ensures that any versioning symbols st_name value will
-		 * be appropriate for the string table used to by version
+		 * be appropriate for the string table used by version
 		 * entries.
 		 */
 		if (enter_in_symtab) {
@@ -1156,42 +1232,45 @@
 				_symndx = scopesym_ndx;
 			else
 				_symndx = symtab_ndx;
+
 			symtab[_symndx] = *sdp->sd_sym;
 			sdp->sd_sym = sym = &symtab[_symndx];
 			(void) st_setstring(strtab, name, &stoff);
 			sym->st_name = stoff;
 		}
+		if (dynlocal) {
+			ldynsym[ldynscopesym_ndx] = *sdp->sd_sym;
+			sdp->sd_sym = sym = &ldynsym[ldynscopesym_ndx];
+			(void) st_setstring(dynstr, name, &stoff);
+			ldynsym[ldynscopesym_ndx].st_name = stoff;
+		}
 
 		if (dynsym && !local) {
 			dynsym[dynsym_ndx] = *sdp->sd_sym;
-
 			/*
 			 * Provided this isn't an unnamed register symbol,
 			 * update its name and hash value.
 			 */
 			if (((sdp->sd_flags & FLG_SY_REGSYM) == 0) ||
 			    dynsym[dynsym_ndx].st_name) {
-				(void) st_setstring(dynstr, name, &stoff);
-				dynsym[dynsym_ndx].st_name = stoff;
-				if (stoff) {
-					Word	_hashndx;
-					hashval =
-					    sap->sa_hash % ofl->ofl_hashbkts;
-					/* LINTED */
-					if (_hashndx = hashbkt[hashval]) {
-						while (hashchain[_hashndx])
-							_hashndx =
-							    hashchain[_hashndx];
-						hashchain[_hashndx] =
-						    sdp->sd_symndx;
-					} else
-						hashbkt[hashval] =
-						    sdp->sd_symndx;
+			    (void) st_setstring(dynstr, name, &stoff);
+			    dynsym[dynsym_ndx].st_name = stoff;
+			    if (stoff) {
+				Word _hashndx;
+				hashval = sap->sa_hash % ofl->ofl_hashbkts;
+				/* LINTED */
+				if (_hashndx = hashbkt[hashval]) {
+				    while (hashchain[_hashndx])
+					_hashndx = hashchain[_hashndx];
+					hashchain[_hashndx] = sdp->sd_symndx;
+				} else {
+					hashbkt[hashval] = sdp->sd_symndx;
 				}
+			    }
 			}
 			sdp->sd_sym = sym = &dynsym[dynsym_ndx];
 		}
-		if (!enter_in_symtab && (!dynsym || local)) {
+		if (!enter_in_symtab && (!dynsym || (local && !dynlocal))) {
 			if (!(sdp->sd_flags & FLG_SY_UPREQD))
 				continue;
 			sym = sdp->sd_sym;
@@ -1219,15 +1298,23 @@
 				    libld_calloc(sizeof (Wk_desc), 1)) == 0)
 					return ((Addr)S_ERROR);
 
-				if (enter_in_symtab)
+				if (enter_in_symtab) {
 					if (local)
 						wkp->wk_symtab =
 						    &symtab[scopesym_ndx];
 					else
 						wkp->wk_symtab =
 						    &symtab[symtab_ndx];
-				if (dynsym && !local)
-					wkp->wk_dynsym = &dynsym[dynsym_ndx];
+				}
+				if (dynsym) {
+					if (!local) {
+						wkp->wk_dynsym =
+						    &dynsym[dynsym_ndx];
+					} else if (dynlocal) {
+						wkp->wk_dynsym =
+						    &ldynsym[ldynscopesym_ndx];
+					}
+				}
 				wkp->wk_weak = sdp;
 				wkp->wk_alias = _sdp;
 
@@ -1239,8 +1326,13 @@
 						scopesym_ndx++;
 					else
 						symtab_ndx++;
-				if (dynsym && !local)
-					dynsym_ndx++;
+				if (dynsym) {
+					if (!local) {
+						dynsym_ndx++;
+					} else if (dynlocal) {
+						ldynscopesym_ndx++;
+					}
+				}
 				continue;
 			}
 		}
@@ -1446,11 +1538,13 @@
 		 * .symtab entry.
 		 */
 		sdp->sd_shndx = sectndx;
-		if (enter_in_symtab && dynsym && !local) {
-			symtab[symtab_ndx].st_value = sym->st_value;
-			symtab[symtab_ndx].st_size = sym->st_size;
-			symtab[symtab_ndx].st_info = sym->st_info;
-			symtab[symtab_ndx].st_other = sym->st_other;
+		if (enter_in_symtab && dynsym && (!local || dynlocal)) {
+			Word _symndx = dynlocal ? scopesym_ndx : symtab_ndx;
+
+			symtab[_symndx].st_value = sym->st_value;
+			symtab[_symndx].st_size = sym->st_size;
+			symtab[_symndx].st_info = sym->st_info;
+			symtab[_symndx].st_other = sym->st_other;
 		}
 
 
@@ -1472,17 +1566,34 @@
 			}
 		}
 
-		if (dynsym && !local) {
+		if (dynsym && (!local || dynlocal)) {
+			/*
+			 * dynsym and ldynsym are distinct tables, so
+			 * we use indirection to access the right one
+			 * and the related extended section index array.
+			 */
+			Word	_symndx;
+			Sym	*_dynsym;
+			Word	*_dynshndx;
+
+			if (!local) {
+				_symndx = dynsym_ndx++;
+				_dynsym = dynsym;
+				_dynshndx = dynshndx;
+			} else {
+				_symndx = ldynscopesym_ndx++;
+				_dynsym = ldynsym;
+				_dynshndx = ldynshndx;
+			}
 			if (((sdp->sd_flags & FLG_SY_SPECSEC) == 0) &&
 			    (sectndx >= SHN_LORESERVE)) {
-				assert(dynshndx != 0);
-				dynshndx[dynsym_ndx] = sectndx;
-				dynsym[dynsym_ndx].st_shndx = SHN_XINDEX;
+				assert(_dynshndx != 0);
+				_dynshndx[_symndx] = sectndx;
+				_dynsym[_symndx].st_shndx = SHN_XINDEX;
 			} else {
 				/* LINTED */
-				dynsym[dynsym_ndx].st_shndx = (Half)sectndx;
+				_dynsym[_symndx].st_shndx = (Half)sectndx;
 			}
-			dynsym_ndx++;
 		}
 
 		DBG_CALL(Dbg_syms_new(ofl, sym, sdp));
@@ -1551,7 +1662,11 @@
 	DBG_CALL(Dbg_got_display(ofl, 0, 0));
 
 	/*
-	 * Update the section headers information.
+	 * Update the section headers information. sh_info is
+	 * supposed to contain the offset at which the first
+	 * global symbol resides in the symbol table, while
+	 * sh_link contains the section index of the associated
+	 * string table.
 	 */
 	if (symtab) {
 		Shdr *	shdr = ofl->ofl_ossymtab->os_shdr;
@@ -1569,7 +1684,7 @@
 	if (dynsym) {
 		Shdr *	shdr = ofl->ofl_osdynsym->os_shdr;
 
-		shdr->sh_info = ofl->ofl_dynshdrcnt + ofl->ofl_lregsymcnt + 1;
+		shdr->sh_info = 1 + ofl->ofl_dynshdrcnt + ofl->ofl_lregsymcnt;
 		/* LINTED */
 		shdr->sh_link = (Word)elf_ndxscn(ofl->ofl_osdynstr->os_scn);
 
@@ -1582,6 +1697,39 @@
 				(Word)elf_ndxscn(ofl->ofl_osdynsym->os_scn);
 		}
 	}
+	if (ldynsym) {
+		Shdr *	shdr = ofl->ofl_osldynsym->os_shdr;
+
+		/* ldynsym has no globals, so give index one past the end */
+		shdr->sh_info = ldynsym_ndx;
+
+		/*
+		 * The ldynsym and dynsym must be adjacent. The
+		 * idea is that rtld should be able to start with
+		 * the ldynsym and march straight through the end
+		 * of dynsym, seeing them as a single symbol table,
+		 * despite the fact that they are in distinct sections.
+		 * Ensure that this happened correctly.
+		 *
+		 * Note that I use ldynsym_ndx here instead of the
+		 * computation I used to set the section size
+		 * (1 + ofl->ofl_dynlocscnt + ofl->ofl_dynscopecnt).
+		 * The two will agree, unless we somehow miscounted symbols
+		 * or failed to insert them all. Using ldynsym_ndx here
+		 * catches that error in addition to checking for adjacency.
+		 */
+		assert(dynsym == (ldynsym + ldynsym_ndx));
+
+
+		/* LINTED */
+		shdr->sh_link = (Word)elf_ndxscn(ofl->ofl_osdynstr->os_scn);
+
+		if (ldynshndx) {
+			shdr = ofl->ofl_osldynshndx->os_shdr;
+			shdr->sh_link =
+				(Word)elf_ndxscn(ofl->ofl_osldynsym->os_scn);
+		}
+	}
 
 	/*
 	 * Used by ld.so.1 only.
@@ -1745,6 +1893,26 @@
 		dyn->d_un.d_ptr = shdr->sh_entsize;
 		dyn++;
 
+		if (ofl->ofl_osldynsym) {
+			/*
+			 * We have arranged for the .SUNW_ldynsym data to be
+			 * immediately in front of the .dynsym data.
+			 * This means that you could start at the top
+			 * of .SUNW_ldynsym and see the data for both tables
+			 * without a break. This is the view we want to
+			 * provide for DT_SUNW_SYMTAB, which is why we
+			 * add the lengths together.
+			 */
+			Shdr *lshdr = ofl->ofl_osldynsym->os_shdr;
+			dyn->d_tag = DT_SUNW_SYMTAB;
+			dyn->d_un.d_ptr = lshdr->sh_addr;
+			dyn++;
+
+			dyn->d_tag = DT_SUNW_SYMSZ;
+			dyn->d_un.d_val = lshdr->sh_size + shdr->sh_size;
+			dyn++;
+		}
+
 		/*
 		 * Reserve the DT_CHECKSUM entry.  Its value will be filled in
 		 * after the complete image is built.
@@ -2432,7 +2600,7 @@
 	 * Determine the index of the symbol table that will be referenced by
 	 * the relocation entries.
 	 */
-	if ((flags & (FLG_OF_DYNAMIC|FLG_OF_RELOBJ)) == FLG_OF_DYNAMIC)
+	if (OFL_ALLOW_DYNSYM(ofl))
 		/* LINTED */
 		ndx = (Word) elf_ndxscn(ofl->ofl_osdynsym->os_scn);
 	else if (!(flags & FLG_OF_STRIP) || (flags & FLG_OF_RELOBJ))
@@ -2807,8 +2975,7 @@
 		 * figured out by now.
 		 */
 		if (phdr->p_type == PT_DYNAMIC) {
-			if ((flags & (FLG_OF_DYNAMIC | FLG_OF_RELOBJ)) ==
-			    FLG_OF_DYNAMIC) {
+			if (OFL_ALLOW_DYNSYM(ofl)) {
 				Shdr *	shdr = ofl->ofl_osdynamic->os_shdr;
 
 				phdr->p_vaddr = shdr->sh_addr;
--- a/usr/src/cmd/sgs/librtld/common/dynamic.c	Tue Sep 19 15:34:23 2006 -0700
+++ b/usr/src/cmd/sgs/librtld/common/dynamic.c	Tue Sep 19 15:38:37 2006 -0700
@@ -111,11 +111,13 @@
 		case DT_CONFIG:
 		case DT_DEPAUDIT:
 		case DT_AUDIT:
+		case DT_SUNW_SYMSZ:
 			break;
 		case DT_PLTGOT:
 		case DT_HASH:
 		case DT_STRTAB:
 		case DT_SYMTAB:
+		case DT_SUNW_SYMTAB:
 		case DT_INIT:
 		case DT_FINI:
 		case DT_VERSYM:
--- a/usr/src/cmd/sgs/librtld_db/rdb_demo/common/ps.c	Tue Sep 19 15:34:23 2006 -0700
+++ b/usr/src/cmd/sgs/librtld_db/rdb_demo/common/ps.c	Tue Sep 19 15:38:37 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.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2000 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"
@@ -53,7 +52,7 @@
 
 #if	!defined(_LP64)
 static void
-gelf_sym_to_elf32(GElf_Sym * src, Elf32_Sym * dst)
+gelf_sym_to_elf32(GElf_Sym *src, Elf32_Sym *dst)
 {
 	dst->st_name	= src->st_name;
 	/* LINTED */
@@ -68,14 +67,13 @@
 #endif
 
 static void
-get_ldbase(struct ps_prochandle * procp)
+get_ldbase(struct ps_prochandle *procp)
 {
 	int		pauxvfd;
 	char		pname[MAXPATHLEN];
 	struct stat	stbuf;
-	void *		auxvptr;
-	void *		auxvtail;
-	auxv_t *	auxvp;
+	void		*auxvptr, *auxvtail;
+	auxv_t		*auxvp;
 	uint_t		entsize;
 
 	(void) snprintf(pname, MAXPATHLEN, "/proc/%d/auxv", procp->pp_pid);
@@ -127,7 +125,7 @@
 }
 
 retc_t
-ps_init(int pctlfd, int pstatusfd, pid_t pid, struct ps_prochandle * procp)
+ps_init(int pctlfd, int pstatusfd, pid_t pid, struct ps_prochandle *procp)
 {
 	rd_notify_t	rd_notify;
 	char		procname[MAXPATHLEN];
@@ -228,7 +226,7 @@
 
 
 retc_t
-ps_close(struct ps_prochandle * ph)
+ps_close(struct ps_prochandle *ph)
 {
 	delete_all_breakpoints(ph);
 	if (ph->pp_auxvp)
@@ -239,7 +237,7 @@
 
 
 ps_err_e
-ps_pauxv(struct ps_prochandle * ph, const auxv_t ** auxvp)
+ps_pauxv(struct ps_prochandle *ph, const auxv_t **auxvp)
 {
 	*auxvp = ph->pp_auxvp;
 	return (PS_OK);
@@ -247,7 +245,7 @@
 
 
 ps_err_e
-ps_pdmodel(struct ps_prochandle * ph, int * dm)
+ps_pdmodel(struct ps_prochandle *ph, int *dm)
 {
 	pstatus_t	pstatus;
 
@@ -260,8 +258,7 @@
 
 
 ps_err_e
-ps_pread(struct ps_prochandle * ph, psaddr_t addr, void * buf,
-	size_t size)
+ps_pread(struct ps_prochandle *ph, psaddr_t addr, void *buf, size_t size)
 {
 	/* LINTED */
 	if (pread(ph->pp_asfd, buf, size, (off_t)addr) != size)
@@ -272,8 +269,7 @@
 
 
 ps_err_e
-ps_pwrite(struct ps_prochandle * ph, psaddr_t addr, const void * buf,
-	size_t size)
+ps_pwrite(struct ps_prochandle *ph, psaddr_t addr, const void *buf, size_t size)
 {
 	/* LINTED */
 	if (pwrite(ph->pp_asfd, buf, size, (off_t)addr) != size)
@@ -284,11 +280,10 @@
 
 
 ps_err_e
-ps_pglobal_sym(struct ps_prochandle * ph,
-	const char * object_name, const char * sym_name,
-	ps_sym_t * symp)
+ps_pglobal_sym(struct ps_prochandle *ph, const char *object_name,
+    const char *sym_name, ps_sym_t *symp)
 {
-	map_info_t *	mip;
+	map_info_t	*mip;
 	GElf_Sym	gsym;
 
 	if ((mip = str_to_map(ph, object_name)) == 0)
@@ -308,12 +303,11 @@
 
 
 ps_err_e
-ps_pglobal_lookup(struct ps_prochandle * ph,
-	const char * object_name, const char * sym_name,
-	ulong_t * sym_addr)
+ps_pglobal_lookup(struct ps_prochandle *ph, const char *object_name,
+    const char *sym_name, ulong_t *sym_addr)
 {
 	GElf_Sym	sym;
-	map_info_t *	mip;
+	map_info_t	*mip;
 
 	if ((mip = str_to_map(ph, object_name)) == 0)
 		return (PS_ERR);
@@ -328,8 +322,7 @@
 
 
 ps_err_e
-ps_lgetregs(struct ps_prochandle * ph, lwpid_t lid,
-	prgregset_t gregset)
+ps_lgetregs(struct ps_prochandle *ph, lwpid_t lid, prgregset_t gregset)
 {
 	char		procname[MAXPATHLEN];
 	int		lwpfd;
@@ -352,10 +345,10 @@
 
 
 void
-ps_plog(const char * fmt, ...)
+ps_plog(const char *fmt, ...)
 {
 	va_list		args;
-	static FILE *	log_fp = 0;
+	static FILE	*log_fp = 0;
 
 	if (log_fp == 0) {
 		char		log_fname[256];
@@ -377,3 +370,9 @@
 	fputc('\n', log_fp);
 	fflush(log_fp);
 }
+
+ps_err_e
+ps_pbrandname(struct ps_prochandle *P, char *buf, size_t len)
+{
+	return (PS_ERR);
+}
--- a/usr/src/cmd/sgs/pvs/common/pvs.c	Tue Sep 19 15:34:23 2006 -0700
+++ b/usr/src/cmd/sgs/pvs/common/pvs.c	Tue Sep 19 15:38:37 2006 -0700
@@ -806,14 +806,24 @@
 			/*
 			 * Remember the version sections and symbol table.
 			 */
-			if ((shdr.sh_type == SHT_SUNW_verdef) && dflag)
-				_cache_def = _cache;
-			else if ((shdr.sh_type == SHT_SUNW_verneed) && rflag)
-				_cache_need = _cache;
-			else if ((shdr.sh_type == SHT_SUNW_versym) && sflag)
-				_cache_sym = _cache;
-			else if ((shdr.sh_type == SHT_SYMTAB) && lflag)
-				_cache_loc = _cache;
+			switch (shdr.sh_type) {
+			case SHT_SUNW_verdef:
+				if (dflag)
+					_cache_def = _cache;
+				break;
+			case SHT_SUNW_verneed:
+				if (rflag)
+					_cache_need = _cache;
+				break;
+			case SHT_SUNW_versym:
+				if (sflag)
+					_cache_sym = _cache;
+				break;
+			case SHT_SYMTAB:
+				if (lflag)
+					_cache_loc = _cache;
+				break;
+			}
 		}
 
 		/*
--- a/usr/src/cmd/sgs/rtld/common/_elf.h	Tue Sep 19 15:34:23 2006 -0700
+++ b/usr/src/cmd/sgs/rtld/common/_elf.h	Tue Sep 19 15:38:37 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.
@@ -24,7 +23,7 @@
  *	  All Rights Reserved
  *
  *
- *	Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ *	Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  *	Use is subject to license terms.
  */
 
@@ -87,6 +86,7 @@
  */
 typedef struct _rt_elf_private {
 	void		*e_symtab;	/* symbol table */
+	void		*e_sunwsymtab;	/* symtab augmented with local fcns */
 	uint_t		*e_hash;	/* hash table */
 	char		*e_strtab;	/* string table */
 	void		*e_reloc;	/* relocation table */
@@ -94,6 +94,7 @@
 	void		*e_pltreserve;	/* ia64: DT_IA_64_PLTRESERVE */
 	void		*e_dynplt;	/* dynamic plt table - used by prof */
 	void		*e_jmprel;	/* plt relocations */
+	ulong_t		e_sunwsymsz;	/* size of w_sunwsymtab */
 	ulong_t		e_pltrelsize;	/* size of PLT relocation entries */
 	ulong_t		e_relsz;	/* size of relocs */
 	ulong_t		e_relent;	/* size of base reloc entry */
@@ -120,6 +121,7 @@
  */
 #define	ELFPRV(X)	((X)->rt_priv)
 #define	SYMTAB(X)	(((Rt_elfp *)(X)->rt_priv)->e_symtab)
+#define	SUNWSYMTAB(X)	(((Rt_elfp *)(X)->rt_priv)->e_sunwsymtab)
 #define	HASH(X)		(((Rt_elfp *)(X)->rt_priv)->e_hash)
 #define	STRTAB(X)	(((Rt_elfp *)(X)->rt_priv)->e_strtab)
 #define	REL(X)		(((Rt_elfp *)(X)->rt_priv)->e_reloc)
@@ -129,6 +131,7 @@
 #define	MOVETAB(X)	(((Rt_elfp *)(X)->rt_priv)->e_movetab)
 #define	DYNPLT(X)	(((Rt_elfp *)(X)->rt_priv)->e_dynplt)
 #define	JMPREL(X)	(((Rt_elfp *)(X)->rt_priv)->e_jmprel)
+#define	SUNWSYMSZ(X)	(((Rt_elfp *)(X)->rt_priv)->e_sunwsymsz)
 #define	PTTLS(X)	(((Rt_elfp *)(X)->rt_priv)->e_pttls)
 #define	PTUNWIND(X)	(((Rt_elfp *)(X)->rt_priv)->e_ptunwind)
 #define	TLSSTATOFF(X)	(((Rt_elfp *)(X)->rt_priv)->e_tlsstatoff)
--- a/usr/src/cmd/sgs/rtld/common/elf.c	Tue Sep 19 15:34:23 2006 -0700
+++ b/usr/src/cmd/sgs/rtld/common/elf.c	Tue Sep 19 15:38:37 2006 -0700
@@ -1926,8 +1926,7 @@
 	 * symbol binding information.
 	 */
 	if ((sip = SYMINFO(ilmp)) != 0)
-		/* LINTED */
-		sip = (Syminfo *)((char *)sip + (ndx * SYMINENT(ilmp)));
+		sip += ndx;
 
 	/*
 	 * If this is a direct binding request, but the symbol definition has
@@ -2085,6 +2084,13 @@
 			case DT_SYMTAB:
 				SYMTAB(lmp) = (void *)(ld->d_un.d_ptr + base);
 				break;
+			case DT_SUNW_SYMTAB:
+				SUNWSYMTAB(lmp) =
+				    (void *)(ld->d_un.d_ptr + base);
+				break;
+			case DT_SUNW_SYMSZ:
+				SUNWSYMSZ(lmp) = ld->d_un.d_val;
+				break;
 			case DT_STRTAB:
 				STRTAB(lmp) = (void *)(ld->d_un.d_ptr + base);
 				break;
@@ -2379,6 +2385,37 @@
 	}
 
 	/*
+	 * A dynsym contains only global functions. We want to have
+	 * a version of it that also includes local functions, so that
+	 * dladdr() will be able to report names for local functions
+	 * when used to generate a stack trace for a stripped file.
+	 * This version of the dynsym is provided via DT_SUNW_SYMTAB.
+	 *
+	 * In producing DT_SUNW_SYMTAB, ld uses a non-obvious trick
+	 * in order to avoid having to have two copies of the global
+	 * symbols held in DT_SYMTAB: The local symbols are placed in
+	 * a separate section than the globals in the dynsym, but the
+	 * linker conspires to put the data for these two sections adjacent
+	 * to each other. DT_SUNW_SYMTAB points at the top of the local
+	 * symbols, and DT_SUNW_SYMSZ is the combined length of both tables.
+	 *
+	 * If the two sections are not adjacent, then something went wrong
+	 * at link time. We use ASSERT to kill the process if this is
+	 * a debug build. In a production build, we will silently ignore
+	 * the presence of the .ldynsym and proceed. We can detect this
+	 * situation by checking to see that DT_SYMTAB lies in
+	 * the range given by DT_SUNW_SYMTAB/DT_SUNW_SYMSZ.
+	 */
+	if ((SUNWSYMTAB(lmp) != NULL) &&
+	    (((char *)SYMTAB(lmp) <= (char *)SUNWSYMTAB(lmp)) ||
+	    (((char *)SYMTAB(lmp) >=
+	    (SUNWSYMSZ(lmp) + (char *)SUNWSYMTAB(lmp)))))) {
+		ASSERT(0);
+		SUNWSYMTAB(lmp) = NULL;
+		SUNWSYMSZ(lmp) = 0;
+	}
+
+	/*
 	 * If configuration file use hasn't been disabled, and a configuration
 	 * file hasn't already been set via an environment variable, see if any
 	 * application specific configuration file is specified.  An LD_CONFIG
@@ -2929,14 +2966,32 @@
 	int		_flags;
 
 	/*
-	 * If we don't have a .hash table there are no symbols to look at.
+	 * If SUNWSYMTAB() is non-NULL, then it sees a special version of
+	 * the dynsym that starts with any local function symbols that exist in
+	 * the library and then moves to the data held in SYMTAB(). In this
+	 * case, SUNWSYMSZ tells us how long the symbol table is. The
+	 * availability of local function symbols will enhance the results
+	 * we can provide.
+	 *
+	 * If SUNWSYMTAB() is NULL, then SYMTAB() references a dynsym that
+	 * contains only global symbols. In that case, the length of
+	 * the symbol table comes from the nchain field of the related
+	 * symbol lookup hash table.
 	 */
-	if (HASH(lmp) == 0)
-		return;
-
-	cnt = HASH(lmp)[1];
 	str = STRTAB(lmp);
-	sym = SYMTAB(lmp);
+	if (SUNWSYMSZ(lmp) == NULL) {
+		sym = SYMTAB(lmp);
+		/*
+		 * If we don't have a .hash table there are no symbols
+		 * to look at.
+		 */
+		if (HASH(lmp) == 0)
+			return;
+		cnt = HASH(lmp)[1];
+	} else {
+		sym = SUNWSYMTAB(lmp);
+		cnt = SUNWSYMSZ(lmp) / SYMENT(lmp);
+	}
 
 	if (FLAGS(lmp) & FLG_RT_FIXED)
 		base = 0;
@@ -2946,7 +3001,19 @@
 	for (_sym = 0, _value = 0, sym++, ndx = 1; ndx < cnt; ndx++, sym++) {
 		ulong_t	value;
 
-		if (sym->st_shndx == SHN_UNDEF)
+		/*
+		 * Skip expected symbol types that are not functions
+		 * or data:
+		 *	- A symbol table starts with an undefined symbol
+		 *		in slot 0. If we are using SUNWSYMTAB(),
+		 *		there will be a second undefined symbol
+		 *		right before the globals.
+		 *	- The local part of SUNWSYMTAB() contains a
+		 *		series of function symbols. Each section
+		 *		starts with an initial STT_FILE symbol.
+		 */
+		if ((sym->st_shndx == SHN_UNDEF) ||
+		    (ELF_ST_TYPE(sym->st_info) == STT_FILE))
 			continue;
 
 		value = sym->st_value + base;
--- a/usr/src/cmd/sgs/rtld/common/object.c	Tue Sep 19 15:34:23 2006 -0700
+++ b/usr/src/cmd/sgs/rtld/common/object.c	Tue Sep 19 15:38:37 2006 -0700
@@ -68,8 +68,8 @@
 	ofl->ofl_dehdr = &dehdr;
 
 	ofl->ofl_flags =
-	    (FLG_OF_DYNAMIC | FLG_OF_SHAROBJ | FLG_OF_STRIP | FLG_OF_MEMORY);
-	ofl->ofl_flags1 = FLG_OF1_RELDYN | FLG_OF1_TEXTOFF;
+	    (FLG_OF_DYNAMIC | FLG_OF_SHAROBJ | FLG_OF_STRIP);
+	ofl->ofl_flags1 = FLG_OF1_RELDYN | FLG_OF1_TEXTOFF | FLG_OF1_MEMORY;
 	ofl->ofl_lml = lml;
 
 	/*
--- a/usr/src/cmd/sgs/rtld/i386/_setup.c	Tue Sep 19 15:34:23 2006 -0700
+++ b/usr/src/cmd/sgs/rtld/i386/_setup.c	Tue Sep 19 15:38:37 2006 -0700
@@ -83,7 +83,6 @@
 	uid_t		uid = -1, euid = -1;
 	gid_t		gid = -1, egid = -1;
 	char		*_platform = 0, *_execname = 0, *_emulator = 0;
-	int		_branded = 0;
 	int		auxflags = -1;
 	/*
 	 * Scan the bootstrap structure to pick up the basics.
@@ -179,7 +178,6 @@
 		case AT_SUN_EMULATOR:
 			/* name of emulation library, if any */
 			_emulator = auxv->a_un.a_ptr;
-			_branded = 1;
 			break;
 #endif
 		}
--- a/usr/src/uts/common/sys/elf.h	Tue Sep 19 15:34:23 2006 -0700
+++ b/usr/src/uts/common/sys/elf.h	Tue Sep 19 15:38:37 2006 -0700
@@ -401,7 +401,8 @@
 #define	SHT_NUM			19
 
 #define	SHT_LOOS		0x60000000	/* OS specific range */
-#define	SHT_LOSUNW		0x6ffffff4
+#define	SHT_LOSUNW		0x6ffffff3
+#define	SHT_SUNW_LDYNSYM	0x6ffffff3
 #define	SHT_SUNW_dof		0x6ffffff4
 #define	SHT_SUNW_cap		0x6ffffff5
 #define	SHT_SUNW_SIGNATURE	0x6ffffff6
--- a/usr/src/uts/common/sys/link.h	Tue Sep 19 15:34:23 2006 -0700
+++ b/usr/src/uts/common/sys/link.h	Tue Sep 19 15:38:37 2006 -0700
@@ -117,6 +117,10 @@
 #define	DT_SUNW_FILTER		0x6000000f	/* symbol filter name */
 #define	DT_SUNW_CAP		0x60000010	/* hardware/software */
 						/*	capabilities */
+#define	DT_SUNW_SYMTAB		0x60000011	/* symtab with local fcn */
+						/*	symbols immediately */
+						/*	preceding DT_SYMTAB */
+#define	DT_SUNW_SYMSZ		0x60000012	/* Size of SUNW_SYMTAB table */
 #define	DT_HIOS			0x6ffff000
 
 /*