changeset 5152:fa5ab16f3606

5035454 mixing -Kpic and -KPIC may cause SIGSEGV with -xarch=v9
author ab196087
date Mon, 01 Oct 2007 10:33:16 -0700
parents 099e03bc5cce
children 8508f39f49fe
files usr/src/cmd/sgs/include/conv.h usr/src/cmd/sgs/include/sparc/machdep.h usr/src/cmd/sgs/libconv/Makefile.targ usr/src/cmd/sgs/libconv/common/config.c usr/src/cmd/sgs/libconv/common/dl.c usr/src/cmd/sgs/libconv/common/dwarf_ehe.c usr/src/cmd/sgs/libconv/common/dynamic.c usr/src/cmd/sgs/libconv/common/elf.c usr/src/cmd/sgs/libconv/common/group.c usr/src/cmd/sgs/libconv/common/phdr.c usr/src/cmd/sgs/libconv/common/sections.c usr/src/cmd/sgs/libconv/common/segments.c usr/src/cmd/sgs/libconv/common/syminfo.c usr/src/cmd/sgs/libld/common/libld.sparc.msg usr/src/cmd/sgs/libld/common/machrel.sparc.c usr/src/cmd/sgs/liblddbg/common/liblddbg.msg usr/src/cmd/sgs/packages/common/SUNWonld-README usr/src/cmd/sgs/packages/inc.flg usr/src/cmd/sgs/tools/libconv_mk_report_bufsize.pl
diffstat 19 files changed, 298 insertions(+), 66 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/cmd/sgs/include/conv.h	Mon Oct 01 09:45:31 2007 -0700
+++ b/usr/src/cmd/sgs/include/conv.h	Mon Oct 01 10:33:16 2007 -0700
@@ -190,7 +190,7 @@
 
 
 /* conv_config_feat() */
-#define	CONV_CONFIG_FEAT_BUFSIZE	195
+#define	CONV_CONFIG_FEAT_BUFSIZE	194
 
 typedef union {
 	Conv32_inv_buf_t	inv_buf;
@@ -232,7 +232,7 @@
 
 
 /* conv_dl_flag() */
-#define	CONV_DL_FLAG_BUFSIZE		195
+#define	CONV_DL_FLAG_BUFSIZE		175
 
 typedef union {
 	Conv32_inv_buf_t	inv_buf;
--- a/usr/src/cmd/sgs/include/sparc/machdep.h	Mon Oct 01 09:45:31 2007 -0700
+++ b/usr/src/cmd/sgs/include/sparc/machdep.h	Mon Oct 01 10:33:16 2007 -0700
@@ -157,6 +157,7 @@
 					/* transition flags for got sizing */
 #define	M_GOT_LARGE	(Sword)(-M_GOT_MAXSMALL - 1)
 #define	M_GOT_SMALL	(Sword)(-M_GOT_MAXSMALL - 2)
+#define	M_GOT_MIXED	(Sword)(-M_GOT_MAXSMALL - 3)
 
 
 /*
--- a/usr/src/cmd/sgs/libconv/Makefile.targ	Mon Oct 01 09:45:31 2007 -0700
+++ b/usr/src/cmd/sgs/libconv/Makefile.targ	Mon Oct 01 10:33:16 2007 -0700
@@ -20,7 +20,7 @@
 #
 
 #
-# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # ident	"%Z%%M%	%I%	%E% SMI"
@@ -46,9 +46,21 @@
 		$(COMPILE.c) -DCAP_UPPERCASE -o $@ $(ELFCAP)/elfcap.c
 		$(POST_PROCESS_O)
 
+# This rule generates the report_bufsize.h include file used by libconv
+# code to ensure that their private buffer size calculations agree with
+# the public values exposed in sgs/include/conv.h. The limit value
+# supplied must be larger than the largest buffer used in libconv. There
+# is little penalty for making it very large, because the header file is
+# only included in error situations where the compilation will fail.
+#
+# We make this depend on Makefile.targ, because a change to Makefile.targ
+# can change the limit, in which case we want to force everything to rebuild.
+report_bufsize.h:	../Makefile.targ
+		perl ../../tools/libconv_mk_report_bufsize.pl 2000
+
 ../common/%.c:	%_msg.h
 
-%_msg.h:	$(SGSMSG) ../common/%.msg
+%_msg.h:	$(SGSMSG) ../common/%.msg report_bufsize.h
 		$(SGSMSG) $(SGSMSGFLAGS) -l -h $@ -d $@ $<
 
 $(SGSMSG):	FRC
--- a/usr/src/cmd/sgs/libconv/common/config.c	Mon Oct 01 09:45:31 2007 -0700
+++ b/usr/src/cmd/sgs/libconv/common/config.c	Mon Oct 01 10:33:16 2007 -0700
@@ -53,8 +53,10 @@
  * information that is not available in the environment of other programs
  * that include the conv.h header file.
  */
-#if (CONV_CONFIG_FEAT_BUFSIZE < FEATSZ) && !defined(__lint)
-#error "CONV_CONFIG_FEAT_BUFSIZE is not large enough"
+#if (CONV_CONFIG_FEAT_BUFSIZE != FEATSZ) && !defined(__lint)
+#define	REPORT_BUFSIZE FEATSZ
+#include "report_bufsize.h"
+#error "CONV_CONFIG_FEAT_BUFSIZE does not match FEATSZ"
 #endif
 
 /*
@@ -111,8 +113,10 @@
  * information that is not available in the environment of other programs
  * that include the conv.h header file.
  */
-#if (CONV_CONFIG_OBJ_BUFSIZE < FLAGSZ) && !defined(__lint)
-#error "CONV_CONFIG_OBJ_BUFSIZE is not large enough"
+#if (CONV_CONFIG_OBJ_BUFSIZE != FLAGSZ) && !defined(__lint)
+#define	REPORT_BUFSIZE FLAGSZ
+#include "report_bufsize.h"
+#error "CONV_CONFIG_OBJ_BUFSIZE does not match FLAGSZ"
 #endif
 
 /*
--- a/usr/src/cmd/sgs/libconv/common/dl.c	Mon Oct 01 09:45:31 2007 -0700
+++ b/usr/src/cmd/sgs/libconv/common/dl.c	Mon Oct 01 10:33:16 2007 -0700
@@ -51,8 +51,10 @@
  * information that is not available in the environment of other programs
  * that include the conv.h header file.
  */
-#if (CONV_DL_MODE_BUFSIZE < MODESZ) && !defined(__lint)
-#error "CONV_DL_MODE_BUFSIZE is not large enough"
+#if (CONV_DL_MODE_BUFSIZE != MODESZ) && !defined(__lint)
+#define	REPORT_BUFSIZE MODESZ
+#include "report_bufsize.h"
+#error "CONV_DL_MODE_BUFSIZE does not match MODESZ"
 #endif
 
 /*
@@ -129,8 +131,10 @@
  * information that is not available in the environment of other programs
  * that include the conv.h header file.
  */
-#if (CONV_DL_FLAG_BUFSIZE < FLAGSZ) && !defined(__lint)
-#error "CONV_DL_FLAG_BUFSIZE is not large enough"
+#if (CONV_DL_FLAG_BUFSIZE != FLAGSZ) && !defined(__lint)
+#define	REPORT_BUFSIZE FLAGSZ
+#include "report_bufsize.h"
+#error "CONV_DL_FLAG_BUFSIZE does not match FLAGSZ"
 #endif
 
 /*
--- a/usr/src/cmd/sgs/libconv/common/dwarf_ehe.c	Mon Oct 01 09:45:31 2007 -0700
+++ b/usr/src/cmd/sgs/libconv/common/dwarf_ehe.c	Mon Oct 01 10:33:16 2007 -0700
@@ -44,8 +44,10 @@
  * information that is not available in the environment of other programs
  * that include the conv.h header file.
  */
-#if (CONV_DWARF_EHE_BUFSIZE < FLAGSZ) && !defined(__lint)
-#error "CONV_DWARF_EHE_BUFSIZE is not large enough"
+#if (CONV_DWARF_EHE_BUFSIZE != FLAGSZ) && !defined(__lint)
+#define	REPORT_BUFSIZE FLAGSZ
+#include "report_bufsize.h"
+#error "CONV_DWARF_EHE_BUFSIZE does not match FLAGSZ"
 #endif
 
 const char *
--- a/usr/src/cmd/sgs/libconv/common/dynamic.c	Mon Oct 01 09:45:31 2007 -0700
+++ b/usr/src/cmd/sgs/libconv/common/dynamic.c	Mon Oct 01 10:33:16 2007 -0700
@@ -56,8 +56,10 @@
  * information that is not available in the environment of other programs
  * that include the conv.h header file.
  */
-#if CONV_DYN_POSFLAG1_BUFSIZE < POSSZ
-#error "CONV_DYN_POSFLAG1_BUFSIZE is not large enough"
+#if (CONV_DYN_POSFLAG1_BUFSIZE != POSSZ) && !defined(__lint)
+#define	REPORT_BUFSIZE POSSZ
+#include "report_bufsize.h"
+#error "CONV_DYN_POSFLAG1_BUFSIZE does not match POSSZ"
 #endif
 
 const char *
@@ -111,10 +113,11 @@
  * information that is not available in the environment of other programs
  * that include the conv.h header file.
  */
-#if CONV_DYN_FLAG_BUFSIZE < FLAGSZ
-#error "CONV_DYN_FLAG_BUFSIZE is not large enough"
+#if (CONV_DYN_FLAG_BUFSIZE != FLAGSZ) && !defined(__lint)
+#define	REPORT_BUFSIZE FLAGSZ
+#include "report_bufsize.h"
+#error "CONV_DYN_FLAG_BUFSIZE does not match FLAGSZ"
 #endif
-
 const char *
 conv_dyn_flag(Xword flags, Conv_fmt_flags_t fmt_flags,
     Conv_dyn_flag_buf_t *dyn_flag_buf)
@@ -181,8 +184,10 @@
  * information that is not available in the environment of other programs
  * that include the conv.h header file.
  */
-#if CONV_DYN_FLAG1_BUFSIZE < FLAG1SZ
-#error "CONV_DYN_FLAG1_BUFSIZE is not large enough"
+#if (CONV_DYN_FLAG1_BUFSIZE != FLAG1SZ) && !defined(__lint)
+#define	REPORT_BUFSIZE FLAG1SZ
+#include "report_bufsize.h"
+#error "CONV_DYN_FLAG1_BUFSIZE does not match FLAG1SZ"
 #endif
 
 const char *
@@ -244,8 +249,10 @@
  * information that is not available in the environment of other programs
  * that include the conv.h header file.
  */
-#if CONV_DYN_FEATURE1_BUFSIZE < FEATSZ
-#error "CONV_DYN_FEATURE1_BUFSIZE is not large enough"
+#if (CONV_DYN_FEATURE1_BUFSIZE != FEATSZ) && !defined(__lint)
+#define	REPORT_BUFSIZE FEATSZ
+#include "report_bufsize.h"
+#error "CONV_DYN_FEATURE1_BUFSIZE does not match FEATSZ"
 #endif
 
 const char *
@@ -455,8 +462,10 @@
  * information that is not available in the environment of other programs
  * that include the conv.h header file.
  */
-#if CONV_BND_TYPE_BUFSIZE < BINDTSZ
-#error "CONV_BND_TYPE_BUFSIZE is not large enough"
+#if (CONV_BND_TYPE_BUFSIZE != BINDTSZ) && !defined(__lint)
+#define	REPORT_BUFSIZE BINDTSZ
+#include "report_bufsize.h"
+#error "CONV_BND_TYPE_BUFSIZE does not match BINDTSZ"
 #endif
 
 const char *
@@ -501,8 +510,10 @@
  * information that is not available in the environment of other programs
  * that include the conv.h header file.
  */
-#if CONV_BND_OBJ_BUFSIZE < BINDOSZ
-#error "CONV_BND_OBJ_BUFSIZE is not large enough"
+#if (CONV_BND_OBJ_BUFSIZE != BINDOSZ) && !defined(__lint)
+#define	REPORT_BUFSIZE BINDOSZ
+#include "report_bufsize.h"
+#error "CONV_BND_OBJ_BUFSIZE does not match BINDOSZ"
 #endif
 
 const char *
--- a/usr/src/cmd/sgs/libconv/common/elf.c	Mon Oct 01 09:45:31 2007 -0700
+++ b/usr/src/cmd/sgs/libconv/common/elf.c	Mon Oct 01 10:33:16 2007 -0700
@@ -260,8 +260,10 @@
  * information that is not available in the environment of other programs
  * that include the conv.h header file.
  */
-#if CONV_EHDR_FLAGS_BUFSIZE < EFLAGSZ
-#error "CONV_EHDR_FLAGS_BUFSIZE is not large enough"
+#if (CONV_EHDR_FLAGS_BUFSIZE != EFLAGSZ) && !defined(__lint)
+#define	REPORT_BUFSIZE EFLAGSZ
+#include "report_bufsize.h"
+#error "CONV_EHDR_FLAGS_BUFSIZE does not match EFLAGSZ"
 #endif
 
 /*
--- a/usr/src/cmd/sgs/libconv/common/group.c	Mon Oct 01 09:45:31 2007 -0700
+++ b/usr/src/cmd/sgs/libconv/common/group.c	Mon Oct 01 10:33:16 2007 -0700
@@ -48,8 +48,10 @@
  * information that is not available in the environment of other programs
  * that include the conv.h header file.
  */
-#if (CONV_GRPHDL_FLAGS_BUFSIZE < HDLSZ) && !defined(__lint)
-#error "CONV_GRPHDL_FLAGS_BUFSIZE is not large enough"
+#if (CONV_GRPHDL_FLAGS_BUFSIZE != HDLSZ) && !defined(__lint)
+#define	REPORT_BUFSIZE HDLSZ
+#include "report_bufsize.h"
+#error "CONV_GRPHDL_FLAGS_BUFSIZE does not match HDLSZ"
 #endif
 
 /*
@@ -99,8 +101,10 @@
  * information that is not available in the environment of other programs
  * that include the conv.h header file.
  */
-#if (CONV_GRPDESC_FLAGS_BUFSIZE < DESCSZ) && !defined(__lint)
-#error "CONV_GRPDESC_FLAGS_BUFSIZE is not large enough"
+#if (CONV_GRPDESC_FLAGS_BUFSIZE != DESCSZ) && !defined(__lint)
+#define	REPORT_BUFSIZE DESCSZ
+#include "report_bufsize.h"
+#error "CONV_GRPDESC_FLAGS_BUFSIZE does not match DESCSZ"
 #endif
 
 /*
--- a/usr/src/cmd/sgs/libconv/common/phdr.c	Mon Oct 01 09:45:31 2007 -0700
+++ b/usr/src/cmd/sgs/libconv/common/phdr.c	Mon Oct 01 10:33:16 2007 -0700
@@ -115,8 +115,10 @@
  * information that is not available in the environment of other programs
  * that include the conv.h header file.
  */
-#if CONV_PHDR_FLAGS_BUFSIZE < PHDRSZ
-#error "CONV_PHDR_FLAGS_BUFSIZE is not large enough"
+#if (CONV_PHDR_FLAGS_BUFSIZE != PHDRSZ) && !defined(__lint)
+#define	REPORT_BUFSIZE PHDRSZ
+#include "report_bufsize.h"
+#error "CONV_PHDR_FLAGS_BUFSIZE does not match PHDRSZ"
 #endif
 
 const char *
--- a/usr/src/cmd/sgs/libconv/common/sections.c	Mon Oct 01 09:45:31 2007 -0700
+++ b/usr/src/cmd/sgs/libconv/common/sections.c	Mon Oct 01 10:33:16 2007 -0700
@@ -165,8 +165,10 @@
  * information that is not available in the environment of other programs
  * that include the conv.h header file.
  */
-#if CONV_SEC_FLAGS_BUFSIZE < FLAGSZ
-#error "CONV_SEC_FLAGS_BUFSIZE is not large enough"
+#if (CONV_SEC_FLAGS_BUFSIZE != FLAGSZ) && !defined(__lint)
+#define	REPORT_BUFSIZE FLAGSZ
+#include "report_bufsize.h"
+#error "CONV_SEC_FLAGS_BUFSIZE does not match FLAGSZ"
 #endif
 
 const char *
--- a/usr/src/cmd/sgs/libconv/common/segments.c	Mon Oct 01 09:45:31 2007 -0700
+++ b/usr/src/cmd/sgs/libconv/common/segments.c	Mon Oct 01 10:33:16 2007 -0700
@@ -58,8 +58,10 @@
  * information that is not available in the environment of other programs
  * that include the conv.h header file.
  */
-#if (CONV_SEG_FLAGS_BUFSIZE < SEGSZ) && !defined(__lint)
-#error "CONV_SEG_FLAGS_BUFSIZE is not large enough"
+#if (CONV_SEG_FLAGS_BUFSIZE != SEGSZ) && !defined(__lint)
+#define	REPORT_BUFSIZE SEGSZ
+#include "report_bufsize.h"
+#error "CONV_SEG_FLAGS_BUFSIZE does not match SEGSZ"
 #endif
 
 const char *
--- a/usr/src/cmd/sgs/libconv/common/syminfo.c	Mon Oct 01 09:45:31 2007 -0700
+++ b/usr/src/cmd/sgs/libconv/common/syminfo.c	Mon Oct 01 10:33:16 2007 -0700
@@ -52,8 +52,10 @@
  * is not available in the environment of other programs that include
  * the conv.h header file.
  */
-#if CONV_SYMINFO_FLAGS_BUFSIZE < FLAGSZ
-#error "CONV_SYMINFO_FLAGS_BUFSIZE is not large enough"
+#if (CONV_SYMINFO_FLAGS_BUFSIZE != FLAGSZ) && !defined(__lint)
+#define	REPORT_BUFSIZE FLAGSZ
+#include "report_bufsize.h"
+#error "CONV_SYMINFO_FLAGS_BUFSIZE does not match FLAGSZ"
 #endif
 
 const char *
--- a/usr/src/cmd/sgs/libld/common/libld.sparc.msg	Mon Oct 01 09:45:31 2007 -0700
+++ b/usr/src/cmd/sgs/libld/common/libld.sparc.msg	Mon Oct 01 10:33:16 2007 -0700
@@ -20,7 +20,7 @@
 #
 
 #
-# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # ident	"%Z%%M%	%I%	%E% SMI"
@@ -49,6 +49,10 @@
 @ MSG_REL_SMALLGOT	"too many symbols require `small' PIC references:\n\
 			 \thave %d, maximum %d -- recompile some \
 			 modules -K PIC."
+@ MSG_REL_MIXEDGOT	"too many symbols require mixed mode \
+			 (both `small' and `large') PIC references:\n\
+			 \thave %d, maximum %d -- recompile some \
+			 modules -K PIC."
 
 @ MSG_SYM_INCOMPREG1	"register %s symbol used incompatibly:\n\
 			 \t(file %s symbol `%s', file %s symbol `%s');"
--- a/usr/src/cmd/sgs/libld/common/machrel.sparc.c	Mon Oct 01 09:45:31 2007 -0700
+++ b/usr/src/cmd/sgs/libld/common/machrel.sparc.c	Mon Oct 01 10:33:16 2007 -0700
@@ -41,6 +41,7 @@
  */
 static Sword neggotoffset = 0;		/* off. of GOT table from GOT symbol */
 static Sword smlgotcnt = M_GOT_XNumber;	/* no. of small GOT symbols */
+static Sword mixgotcnt = 0;		/* # syms with both large/small GOT */
 
 Word
 ld_init_rel(Rel_desc *reld, void *reloc)
@@ -1788,6 +1789,7 @@
  * into the GOT, whereas large uses an unsigned 32-bit offset.
  */
 static	Sword small_index;	/* starting index for small GOT entries */
+static	Sword mixed_index;	/* starting index for mixed GOT entries */
 static	Sword large_index;	/* starting index for large GOT entries */
 
 uintptr_t
@@ -1812,6 +1814,10 @@
 			if (small_index == 0)
 				small_index = M_GOT_XNumber;
 			break;
+		case M_GOT_MIXED:
+			gnp->gn_gotndx = mixed_index;
+			mixed_index += gotents;
+			break;
 		case M_GOT_LARGE:
 			gnp->gn_gotndx = large_index;
 			large_index += gotents;
@@ -1886,26 +1892,56 @@
 	Listnode *	lnp, * plnp;
 	uint_t		gotents;
 
-	raddend = rsp->rel_raddend;
-	if (pgnp && (pgnp->gn_addend == raddend) && (pgnp->gn_gotref == gref)) {
-		/*
-		 * If an entry for this addend already exists, determine if it
-		 * should be changed to a SMALL got.
-		 */
-		if ((pgnp->gn_gotndx != M_GOT_SMALL) &&
-		    (rsp->rel_rtype == R_SPARC_GOT13)) {
-			smlgotcnt++;
-			pgnp->gn_gotndx = M_GOT_SMALL;
-			sdp->sd_flags |= FLG_SY_SMGOT;
-		}
-		return (1);
-	}
-
+	/* Some TLS requires two relocations with two GOT entries */
 	if ((gref == GOT_REF_TLSGD) || (gref == GOT_REF_TLSLD))
 		gotents = 2;
 	else
 		gotents = 1;
 
+	raddend = rsp->rel_raddend;
+	if (pgnp && (pgnp->gn_addend == raddend) && (pgnp->gn_gotref == gref)) {
+
+		/*
+		 * If an entry for this addend already exists, determine if it
+		 * has mixed mode GOT access (both PIC and pic).
+		 *
+		 * In order to be accessible by both large and small pic,
+		 * a mixed mode GOT must be located in the positive index
+		 * range above _GLOBAL_OFFSET_TABLE_, and in the range
+		 * reachable small pic. This is necessary because the large
+		 * PIC mode cannot use a negative offset. This implies that
+		 * there can be no more than (M_GOT_MAXSMALL/2 - M_GOT_XNumber)
+		 * such entries.
+		 */
+		switch (pgnp->gn_gotndx) {
+		case M_GOT_SMALL:
+			/*
+			 * This one was previously identified as a small
+			 * GOT. If this access is large, then convert
+			 * it to mixed.
+			 */
+			if (rsp->rel_rtype != R_SPARC_GOT13) {
+				pgnp->gn_gotndx = M_GOT_MIXED;
+				mixgotcnt += gotents;
+			}
+			break;
+
+		case M_GOT_LARGE:
+			/*
+			 * This one was previously identified as a large
+			 * GOT. If this access is small, convert it to mixed.
+			 */
+			if (rsp->rel_rtype == R_SPARC_GOT13) {
+				smlgotcnt += gotents;
+				mixgotcnt += gotents;
+				pgnp->gn_gotndx = M_GOT_MIXED;
+				sdp->sd_flags |= FLG_SY_SMGOT;
+			}
+			break;
+		}
+		return (1);
+	}
+
 	plnp = 0;
 	for (LIST_TRAVERSE(lst, lnp, _gnp)) {
 		if (_gnp->gn_addend > raddend)
@@ -1924,10 +1960,11 @@
 
 	if (rsp->rel_rtype == R_SPARC_GOT13) {
 		gnp->gn_gotndx = M_GOT_SMALL;
-		smlgotcnt++;
+		smlgotcnt += gotents;
 		sdp->sd_flags |= FLG_SY_SMGOT;
-	} else
+	} else {
 		gnp->gn_gotndx = M_GOT_LARGE;
+	}
 
 	if (gref == GOT_REF_TLSLD) {
 		ofl->ofl_tlsldgotndx = gnp;
@@ -1966,30 +2003,57 @@
 uintptr_t
 ld_allocate_got(Ofl_desc * ofl)
 {
+	const Sword	first_large_ndx = M_GOT_MAXSMALL / 2;
 	Sym_desc *	sdp;
 	Addr		addr;
 
 	/*
-	 * Sanity check -- is this going to fit at all?
+	 * Sanity check -- is this going to fit at all? There are two
+	 * limits to be concerned about:
+	 *	1) There is a limit on the number of small pic GOT indices,
+	 *		given by M_GOT_MAXSMALL.
+	 *	2) If there are more than (M_GOT_MAXSMALL/2 - M_GOT_XNumber)
+	 *		small GOT indices, there will be items at negative
+	 *		offsets from _GLOBAL_OFFSET_TABLE_. Items that are
+	 *		accessed via large (PIC) code cannot reach these
+	 *		negative slots, so mixed mode items must be in the
+	 *		non-negative range. This implies a limit of
+	 *		(M_GOT_MAXSMALL/2 - M_GOT_XNumber) mixed mode indices.
 	 */
-	if (smlgotcnt >= M_GOT_MAXSMALL) {
+	if (smlgotcnt > M_GOT_MAXSMALL) {
 		eprintf(ofl->ofl_lml, ERR_FATAL, MSG_INTL(MSG_REL_SMALLGOT),
 		    EC_WORD(smlgotcnt), M_GOT_MAXSMALL);
 		return (S_ERROR);
 	}
+	if (mixgotcnt > (first_large_ndx - M_GOT_XNumber)) {
+		eprintf(ofl->ofl_lml, ERR_FATAL, MSG_INTL(MSG_REL_MIXEDGOT),
+		    EC_WORD(mixgotcnt), first_large_ndx - M_GOT_XNumber);
+		return (S_ERROR);
+	}
 
 	/*
 	 * Set starting offset to be either 0, or a negative index into
 	 * the GOT based on the number of small symbols we've got.
 	 */
-	neggotoffset = ((smlgotcnt > (M_GOT_MAXSMALL / 2)) ?
-	    -((smlgotcnt - (M_GOT_MAXSMALL / 2))) : 0);
+	neggotoffset = ((smlgotcnt >= first_large_ndx) ?
+	    (first_large_ndx - smlgotcnt) : 0);
 
 	/*
-	 * Initialize the large and small got offsets (used in assign_got()).
+	 * Initialize the got offsets used by assign_got() to
+	 * locate GOT items:
+	 *	small - Starting index of items referenced only
+	 *		by small offsets (-Kpic).
+	 *	mixed - Starting index of items referenced
+	 *		by both large (-KPIC) and small (-Kpic).
+	 *	large - Indexes referenced only by large (-KPIC)
+	 *
+	 *  Small items can have negative indexes (i.e. lie below
+	 *	_GLOBAL_OFFSET_TABLE_). Mixed and large items must have
+	 *	non-negative offsets.
 	 */
-	small_index = neggotoffset == 0 ? M_GOT_XNumber : neggotoffset;
+	small_index = (neggotoffset == 0) ? M_GOT_XNumber : neggotoffset;
 	large_index = neggotoffset + smlgotcnt;
+	mixed_index = large_index - mixgotcnt;
 
 	/*
 	 * Assign bias to GOT symbols.
--- a/usr/src/cmd/sgs/liblddbg/common/liblddbg.msg	Mon Oct 01 09:45:31 2007 -0700
+++ b/usr/src/cmd/sgs/liblddbg/common/liblddbg.msg	Mon Oct 01 10:33:16 2007 -0700
@@ -1205,7 +1205,7 @@
 
 # Global offset table entries.
 
-@ MSG_GOT_INDEX		" [%ld]"
+@ MSG_GOT_INDEX		" [%d]"
 @ MSG_GOT_SMALL_PIC	"pic"
 @ MSG_GOT_BIG_PIC	"PIC"
 
--- a/usr/src/cmd/sgs/packages/common/SUNWonld-README	Mon Oct 01 09:45:31 2007 -0700
+++ b/usr/src/cmd/sgs/packages/common/SUNWonld-README	Mon Oct 01 10:33:16 2007 -0700
@@ -1261,3 +1261,4 @@
 6603313 dlclose() can fail to unload objects after fix for 6573641
 6234471 need a way to edit ELF objects
 	PSARC/2007/509 elfedit
+5035454 mixing -Kpic and -KPIC may cause SIGSEGV with -xarch=v9
--- a/usr/src/cmd/sgs/packages/inc.flg	Mon Oct 01 09:45:31 2007 -0700
+++ b/usr/src/cmd/sgs/packages/inc.flg	Mon Oct 01 10:33:16 2007 -0700
@@ -51,6 +51,7 @@
 	usr/src/cmd/sgs/messages \
 	usr/src/cmd/sgs/moe \
 	usr/src/cmd/sgs/elfdump \
+	usr/src/cmd/sgs/elfedit \
 	usr/src/cmd/sgs/pvs \
 	usr/src/cmd/sgs/rtld \
 	usr/src/cmd/sgs/rtld.4.x \
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/sgs/tools/libconv_mk_report_bufsize.pl	Mon Oct 01 10:33:16 2007 -0700
@@ -0,0 +1,114 @@
+#!/usr/bin/perl
+
+#
+# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#ident	"%Z%%M%	%I%	%E% SMI"
+
+use warnings;
+use strict;
+
+use vars qw($script $limit $i);
+
+$script = "libconv_mk_report_bufsize";
+
+
+# This perl script is used by the sgs/libconv makefile to generate an
+# include file named report_bufsize.h. That include file is used to
+# generate an error message that tells the programmer the required
+# size for a libconv buffer type.
+#
+# For details of how that generated file is supposed to be used, please
+# read the comment that is placed at the top of that file, the text of
+# which is found further down in this script.
+
+
+# Highest value to test for
+((scalar(@ARGV) == 1) && (($limit = int($ARGV[0])) > 0)) ||
+	die "usage: $script toplimit\n";
+
+open(OFILE, ">report_bufsize.h") ||
+	die "$script: Unable to create report_bufsize.h";
+
+
+print OFILE <<TEXT;
+/*
+ * This file was generated by $script,
+ * from the libconv Makefile.
+ *
+ * Many of the buffer types defined in sgs/include/conv.h are defined
+ * as a fixed integer rather than using the actual size calculation that
+ * would take the lengths of all the possible strings into consideration.
+ * The code that implements the conversion function does the proper
+ * calculation. It is important that these two values be the same.
+ *
+ * It is done this way because:
+ *
+ *	(1) The size calculation uses message length values only available
+ *		within the file that implements the conversion function.
+ *	(2) Separating the size calculation from the code that uses it
+ *		would increase the odds of not updating both, and is
+ *		therefore more error prone.
+ *
+ * If the public size in conv.h and the real size computed by the
+ * implementing module are not the same, memory corruption or wasted
+ * space will result. Therefore, the code is supposed to contain a
+ * preprocessor check that refuses to compile if they don't. This
+ * is easy to do, but when the sizes do not match, it can be tedious
+ * to determine the right size to set the conv.h value to. This file
+ * is used to help with that.
+ *
+ * Example: Suppose the external size declared in conv.h is
+ * CONV_DYN_FLAG_BUFSIZE, and the internal computed value based
+ * on the actual strings is FLAGSZ. The module would use the following
+ * to ensure they match:
+ *
+ *	#if CONV_DYN_FLAG_BUFSIZE != FLAGSZ
+ *	#define REPORT_BUFSIZE FLAGSZ
+ *	#include "report_bufsize.h"
+ *	#error "CONV_DYN_FLAG_BUFSIZE does not match FLAGSZ"
+ *	#endif 
+ *
+ * In the error case, report_bufsize.h is included. It will use a #warning
+ * preprocessor directive to show the current value of the REPORT_BUFSIZE
+ * macro. The programmer will therefore see a message giving the correct
+ * size of the value that should be defined in conv.h, followed by a
+ * #error line telling them which constant is at fault.
+ */
+
+#ifndef REPORT_BUFSIZE
+#error "REPORT_BUFSIZE must be defined before including report_bufsize.h"
+TEXT
+
+for ($i = 1; $i <= $limit; $i++) {
+	print OFILE "#elif REPORT_BUFSIZE == $i\n";
+	print OFILE "#warning \"The correct buffer size is $i\"\n";
+}
+
+print OFILE <<TEXT;
+#else
+#warning "report_bufsize.h encountered value larger than $limit. Please raise the limit and rerun"
+#endif
+TEXT
+
+close OFILE;