changeset 11734:d29dc9c2b6c5

6916788 ld version 2 mapfile syntax PSARC/2009/688 Human readable and extensible ld mapfile syntax
author Ali Bahrami <Ali.Bahrami@Sun.COM>
date Mon, 22 Feb 2010 09:19:31 -0700
parents b63a4234e08a
children 3234f117f7ad
files usr/src/cmd/sgs/Makefile.com usr/src/cmd/sgs/elfdump/Makefile.com usr/src/cmd/sgs/elfedit/Makefile.com usr/src/cmd/sgs/elfedit/common/elfedit.c usr/src/cmd/sgs/elfwrap/Makefile.com usr/src/cmd/sgs/gprof/Makefile.com usr/src/cmd/sgs/include/conv.h usr/src/cmd/sgs/include/debug.h usr/src/cmd/sgs/include/elfedit.h usr/src/cmd/sgs/include/i386/machdep_x86.h usr/src/cmd/sgs/include/libld.h usr/src/cmd/sgs/include/sgs.h usr/src/cmd/sgs/include/sparc/machdep_sparc.h usr/src/cmd/sgs/lari/lari.pl usr/src/cmd/sgs/ldd/common/ldd.c usr/src/cmd/sgs/ldprof/Makefile.com usr/src/cmd/sgs/libconv/Makefile.com usr/src/cmd/sgs/libconv/common/c_literal.c usr/src/cmd/sgs/libconv/common/cap.c usr/src/cmd/sgs/libconv/common/cap.msg usr/src/cmd/sgs/libconv/common/entry.c usr/src/cmd/sgs/libconv/common/entry.msg usr/src/cmd/sgs/libconv/common/lintsup.c usr/src/cmd/sgs/libconv/common/llib-lconv usr/src/cmd/sgs/libconv/common/map.c usr/src/cmd/sgs/libconv/common/map.msg usr/src/cmd/sgs/libconv/common/segments.c usr/src/cmd/sgs/libconv/common/segments.msg usr/src/cmd/sgs/libld/Makefile.com usr/src/cmd/sgs/libld/common/_libld.h usr/src/cmd/sgs/libld/common/_map.h usr/src/cmd/sgs/libld/common/args.c usr/src/cmd/sgs/libld/common/debug.c usr/src/cmd/sgs/libld/common/entry.c usr/src/cmd/sgs/libld/common/files.c usr/src/cmd/sgs/libld/common/ldentry.c usr/src/cmd/sgs/libld/common/ldmain.c usr/src/cmd/sgs/libld/common/libld.intel.msg usr/src/cmd/sgs/libld/common/libld.msg usr/src/cmd/sgs/libld/common/libld.sparc.msg usr/src/cmd/sgs/libld/common/machrel.amd.c usr/src/cmd/sgs/libld/common/machrel.intel.c usr/src/cmd/sgs/libld/common/machrel.sparc.c usr/src/cmd/sgs/libld/common/map.c usr/src/cmd/sgs/libld/common/map_core.c usr/src/cmd/sgs/libld/common/map_support.c usr/src/cmd/sgs/libld/common/map_v2.c usr/src/cmd/sgs/libld/common/order.c usr/src/cmd/sgs/libld/common/outfile.c usr/src/cmd/sgs/libld/common/place.c usr/src/cmd/sgs/libld/common/sections.c usr/src/cmd/sgs/libld/common/syms.c usr/src/cmd/sgs/libld/common/unwind.c usr/src/cmd/sgs/libld/common/update.c usr/src/cmd/sgs/liblddbg/common/cap.c usr/src/cmd/sgs/liblddbg/common/debug.c usr/src/cmd/sgs/liblddbg/common/entry.c usr/src/cmd/sgs/liblddbg/common/liblddbg.msg usr/src/cmd/sgs/liblddbg/common/llib-llddbg usr/src/cmd/sgs/liblddbg/common/map.c usr/src/cmd/sgs/liblddbg/common/mapfile-vers usr/src/cmd/sgs/liblddbg/common/sections.c usr/src/cmd/sgs/liblddbg/common/segments.c usr/src/cmd/sgs/libldstab/Makefile.com usr/src/cmd/sgs/nm/amd64/Makefile usr/src/cmd/sgs/nm/i386/Makefile usr/src/cmd/sgs/nm/sparc/Makefile usr/src/cmd/sgs/nm/sparcv9/Makefile usr/src/cmd/sgs/packages/common/SUNWonld-README usr/src/cmd/sgs/prof/Makefile.com usr/src/cmd/sgs/rtld/common/debug.c usr/src/cmd/sgs/rtld/common/object.c usr/src/cmd/sgs/rtld/common/rtld.msg usr/src/common/elfcap/elfcap.c usr/src/common/elfcap/elfcap.h usr/src/lib/libwrap/mapfile usr/src/uts/common/sys/elf.h usr/src/uts/common/sys/link.h
diffstat 78 files changed, 11166 insertions(+), 3068 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/cmd/sgs/Makefile.com	Sun Feb 21 21:37:22 2010 -0800
+++ b/usr/src/cmd/sgs/Makefile.com	Mon Feb 22 09:19:31 2010 -0700
@@ -19,7 +19,7 @@
 # CDDL HEADER END
 #
 #
-# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 
@@ -50,10 +50,15 @@
 CFLAGS +=	$(CCVERBOSE) $(DEBUG) $(XFFLAG)
 CFLAGS64 +=	$(CCVERBOSE) $(DEBUG) $(XFFLAG)
 
+#
+# Location of the shared elfcap code
+#
+ELFCAP=		$(SRC)/common/elfcap
+
 # Reassign CPPFLAGS so that local search paths are used before any parent
 # $ROOT paths.
 CPPFLAGS =	-I. -I../common -I../../include -I../../include/$(MACH) \
-		$(VAR_CPPFLAGS) $(CPPFLAGS.master)
+		$(VAR_CPPFLAGS) $(CPPFLAGS.master) -I$(ELFCAP)
 
 # PICS64 is unique to our environment
 $(PICS64) :=	sparc_CFLAGS += -xregs=no%appl -K pic
@@ -91,6 +96,7 @@
 LDDBGLIBDIR =	-L$(SGSHOME)/liblddbg/$(MACH)
 LDDBGLIBDIR64 =	-L$(SGSHOME)/liblddbg/$(MACH64)
 
+
 # The cmd/Makefile.com and lib/Makefile.com define TEXT_DOMAIN.  We don't need
 # this definition as the sgs utilities obtain their domain via sgsmsg(1l).
 
--- a/usr/src/cmd/sgs/elfdump/Makefile.com	Sun Feb 21 21:37:22 2010 -0800
+++ b/usr/src/cmd/sgs/elfdump/Makefile.com	Mon Feb 22 09:19:31 2010 -0700
@@ -20,7 +20,7 @@
 #
 
 #
-# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 
@@ -49,7 +49,7 @@
 
 CPPFLAGS=	-I. -I../common -I../../include -I../../include/$(MACH) \
 		-I$(SRCBASE)/lib/libc/inc -I$(SRCBASE)/uts/$(ARCH)/sys \
-		$(CPPFLAGS.master)
+		$(CPPFLAGS.master) -I$(ELFCAP)
 LLDFLAGS =	$(VAR_ELFDUMP_LLDFLAGS)
 LLDFLAGS64 =	$(VAR_LD_LLDFLAGS64)
 LDFLAGS +=	$(VERSREF) $(USE_PROTO) $(MAPOPT) $(LLDFLAGS)
--- a/usr/src/cmd/sgs/elfedit/Makefile.com	Sun Feb 21 21:37:22 2010 -0800
+++ b/usr/src/cmd/sgs/elfedit/Makefile.com	Mon Feb 22 09:19:31 2010 -0700
@@ -20,7 +20,7 @@
 #
 
 #
-# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 
@@ -43,7 +43,7 @@
 
 CPPFLAGS=	-I. -I../common -I../../include -I../../include/$(MACH) \
 		-I$(SRCBASE)/lib/libc/inc -I$(SRCBASE)/uts/$(ARCH)/sys \
-		$(CPPFLAGS.master)
+		$(CPPFLAGS.master) -I$(ELFCAP)
 LLDFLAGS =	$(VAR_ELFEDIT_LLDFLAGS)
 LLDFLAGS64 =	$(VAR_ELFEDIT_LLDFLAGS64)
 LDFLAGS +=	$(VERSREF) $(USE_PROTO) -M$(MAPFILE) $(LLDFLAGS)
--- a/usr/src/cmd/sgs/elfedit/common/elfedit.c	Sun Feb 21 21:37:22 2010 -0800
+++ b/usr/src/cmd/sgs/elfedit/common/elfedit.c	Mon Feb 22 09:19:31 2010 -0700
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -2224,90 +2224,6 @@
 
 
 /*
- * Given the pointer to the character following a '\' character in
- * a C style literal, return the ASCII character code it represents,
- * and advance the string pointer to the character following the last
- * character in the escape sequence.
- *
- * entry:
- *	str - Address of string pointer to first character following
- *		the backslash.
- *
- * exit:
- *	If the character is not valid, an error is thrown and this routine
- *	does not return to its caller. Otherwise, it returns the ASCII
- *	code for the translated character, and *str has been advanced.
- */
-static int
-translate_c_esc(char **str)
-{
-	char *s = *str;
-	int	ch;
-	int	i;
-
-	ch = *s++;
-	switch (ch) {
-	case 'a':
-		ch = '\a';
-		break;
-	case 'b':
-		ch = '\b';
-		break;
-	case 'f':
-		ch = '\f';
-		break;
-	case 'n':
-		ch = '\n';
-		break;
-	case 'r':
-		ch = '\r';
-		break;
-	case 't':
-		ch = '\t';
-		break;
-	case 'v':
-		ch = '\v';
-		break;
-
-	case '0':
-	case '1':
-	case '2':
-	case '3':
-	case '4':
-	case '5':
-	case '6':
-	case '7':
-		/* Octal constant: There can be up to 3 digits */
-		ch -= '0';
-		for (i = 0; i < 2; i++) {
-			if ((*s < '0') || (*s > '7'))
-				break;
-			ch = (ch << 3) + (*s++ - '0');
-		}
-		break;
-
-	/*
-	 * There are some cases where ch already has the desired value.
-	 * These cases exist simply to remove the special meaning that
-	 * character would otherwise have. We need to match them to
-	 * prevent them from falling into the default error case.
-	 */
-	case '\\':
-	case '\'':
-	case '"':
-		break;
-
-	default:
-		elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_BADCESC), ch);
-		break;
-	}
-
-	*str = s;
-	return (ch);
-}
-
-
-/*
  * Prepare a GETTOK_STATE struct for gettok().
  *
  * entry:
@@ -2430,7 +2346,12 @@
 			}
 
 			if (quote_ch == '"') {
-				*str++ = translate_c_esc(&look);
+				int ch = conv_translate_c_esc(&look);
+
+				if (ch == -1)
+					elfedit_msg(ELFEDIT_MSG_ERR,
+					    MSG_INTL(MSG_ERR_BADCESC), *look);
+				*str++ = ch;
 				look--;		/* for() will advance by 1 */
 				continue;
 			}
--- a/usr/src/cmd/sgs/elfwrap/Makefile.com	Sun Feb 21 21:37:22 2010 -0800
+++ b/usr/src/cmd/sgs/elfwrap/Makefile.com	Mon Feb 22 09:19:31 2010 -0700
@@ -20,11 +20,9 @@
 #
 
 #
-# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
-# ident	"%Z%%M%	%I%	%E% SMI"
-#
 
 PROG=		elfwrap
 
@@ -50,7 +48,7 @@
 MAPFILES =	$(MAPFILE.NGB)
 MAPOPTS =	$(MAPFILES:%=-M%)
 
-CPPFLAGS =	-I. -I../common -I../../include $(CPPFLAGS.master)
+CPPFLAGS =	-I. -I../common -I../../include $(CPPFLAGS.master) -I$(ELFCAP)
 LLDFLAGS =
 LLDFLAGS64 =
 LDFLAGS +=	$(VERSREF) $(USE_PROTO) $(MAPOPTS) $(LLDFLAGS)
--- a/usr/src/cmd/sgs/gprof/Makefile.com	Sun Feb 21 21:37:22 2010 -0800
+++ b/usr/src/cmd/sgs/gprof/Makefile.com	Mon Feb 22 09:19:31 2010 -0700
@@ -19,9 +19,7 @@
 # CDDL HEADER END
 #
 #
-# ident	"%Z%%M%	%I%	%E% SMI"
-#
-# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # cmd/sgs/gprof/Makefile.com
@@ -41,7 +39,7 @@
 
 INCLIST=	-I../common -I../../include -I../../include/$(MACH)
 DEFLIST=	-DELF_OBJ -DELF
-CPPFLAGS=	$(INCLIST) $(DEFLIST) $(CPPFLAGS.master)
+CPPFLAGS=	$(INCLIST) $(DEFLIST) $(CPPFLAGS.master) -I$(ELFCAP)
 CFLAGS +=	$(CCVERBOSE)
 C99MODE=	$(C99_ENABLE)
 LDLIBS +=	$(CONVLIBDIR) $(CONV_LIB) $(ELFLIBDIR) -lelf
--- a/usr/src/cmd/sgs/include/conv.h	Sun Feb 21 21:37:22 2010 -0800
+++ b/usr/src/cmd/sgs/include/conv.h	Mon Feb 22 09:19:31 2010 -0700
@@ -23,7 +23,7 @@
  *	Copyright (c) 1988 AT&T
  *	  All Rights Reserved
  *
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -200,7 +200,7 @@
 } Conv_grpdesc_flags_buf_t;
 
 /* conv_seg_flags() */
-#define	CONV_SEG_FLAGS_BUFSIZE		196
+#define	CONV_SEG_FLAGS_BUFSIZE		241
 typedef union {
 	Conv_inv_buf_t			inv_buf;
 	char				buf[CONV_SEG_FLAGS_BUFSIZE];
@@ -354,6 +354,20 @@
 	char				buf[CONV_VER_FLAGS_BUFSIZE];
 } Conv_ver_flags_buf_t;
 
+/* conv_ent_flags() */
+#define	CONV_ENT_FLAGS_BUFSIZE		69
+typedef union {
+	Conv_inv_buf_t			inv_buf;
+	char				buf[CONV_ENT_FLAGS_BUFSIZE];
+} Conv_ent_flags_buf_t;
+
+/* conv_ent_files_flags() */
+#define	CONV_ENT_FILES_FLAGS_BUFSIZE		89
+typedef union {
+	Conv_inv_buf_t			inv_buf;
+	char				buf[CONV_ENT_FILES_FLAGS_BUFSIZE];
+} Conv_ent_files_flags_buf_t;
+
 /*
  * conv_time()
  *
@@ -718,6 +732,7 @@
 extern	Boolean		conv_strproc_extract_value(char *, size_t, int,
 			    const char **);
 extern	int		conv_sys_eclass(void);
+extern	int		conv_translate_c_esc(char **);
 
 /*
  * Generic core formatting and iteration functionality
@@ -824,9 +839,14 @@
 extern	const char	*conv_ehdr_vers(Word, Conv_fmt_flags_t,
 			    Conv_inv_buf_t *);
 extern	const char	*conv_elfdata_type(Elf_Type, Conv_inv_buf_t *);
+extern	const char	*conv_ent_flags(ec_flags_t, Conv_ent_flags_buf_t *);
+extern	const char	*conv_ent_files_flags(Word,  Conv_fmt_flags_t fmt_flags,
+			    Conv_ent_files_flags_buf_t *);
 extern	const char	*conv_grphdl_flags(uint_t, Conv_grphdl_flags_buf_t *);
 extern	const char	*conv_grpdesc_flags(uint_t, Conv_grpdesc_flags_buf_t *);
 extern	Isa_desc	*conv_isalist(void);
+extern	const char	*conv_mapfile_version(Word, Conv_fmt_flags_t,
+			    Conv_inv_buf_t *);
 extern	const char	*conv_phdr_flags(uchar_t, Word, Conv_fmt_flags_t,
 			    Conv_phdr_flags_buf_t *);
 extern	const char	*conv_phdr_type(uchar_t, Half, Word, Conv_fmt_flags_t,
@@ -844,7 +864,7 @@
 			    Conv_inv_buf_t *);
 extern	const char	*conv_sec_type(uchar_t, Half, Word, Conv_fmt_flags_t,
 			    Conv_inv_buf_t *);
-extern	const char	*conv_seg_flags(Half, Conv_seg_flags_buf_t *);
+extern	const char	*conv_seg_flags(sg_flags_t, Conv_seg_flags_buf_t *);
 extern	void		conv_str_to_c_literal(const char *buf, size_t n,
 			    Conv_str_to_c_literal_func_t *cb_func,
 			    void *uvalue);
--- a/usr/src/cmd/sgs/include/debug.h	Sun Feb 21 21:37:22 2010 -0800
+++ b/usr/src/cmd/sgs/include/debug.h	Mon Feb 22 09:19:31 2010 -0700
@@ -134,12 +134,6 @@
 #define	DBG_BINFO_REF_MSK	0xf000
 
 
-#define	DBG_CAP_INITIAL		0
-#define	DBG_CAP_IGNORE		1
-#define	DBG_CAP_OLD		2
-#define	DBG_CAP_NEW		3
-#define	DBG_CAP_RESOLVED	4
-
 #define	DBG_REL_START		1
 #define	DBG_REL_FINISH		2
 #define	DBG_REL_NONE		3
@@ -154,6 +148,26 @@
 #define	DBG_BNDREJ_NUM		DBG_BNDREJ_SINGLE
 
 /*
+ * Dbg_state_str() is used to obtain commonly used "state transition"
+ * strings used in various debugging output.
+ */
+#define	DBG_STATE_ADD		0	/* add */
+#define	DBG_STATE_CURRENT	1	/* current */
+#define	DBG_STATE_EXCLUDE	2	/* exclude */
+#define	DBG_STATE_IGNORED	3	/* ignored */
+#define	DBG_STATE_MOD_BEFORE	4	/* modify (before) */
+#define	DBG_STATE_MOD_AFTER	5	/* modify (after) */
+#define	DBG_STATE_NEW 		6	/* new */
+#define	DBG_STATE_NEW_IMPLICIT	7	/* new (implicit) */
+#define	DBG_STATE_OUT		8	/* out */
+#define	DBG_STATE_RESET		9	/* reset */
+#define	DBG_STATE_RESOLVED	10	/* resolved */
+
+#define	DBG_STATE_NUM		11
+typedef uint_t dbg_state_t;
+extern	const char *Dbg_state_str(dbg_state_t);
+
+/*
  * Define a debug descriptor, and a user macro that inspects the descriptor as
  * a means of triggering a class of diagnostic output.
  */
@@ -169,6 +183,11 @@
 
 extern	Dbg_desc	*dbg_desc;
 
+/*
+ * Macros used to avoid calls to liblddbg unless debugging is enabled.
+ * liblddbg is lazy loaded --- this prevents it from happening unless
+ * it will actually be used.
+ */
 #define	DBG_ENABLED	(dbg_desc->d_class)
 #define	DBG_CALL(func)	if (DBG_ENABLED) func
 
@@ -241,6 +260,9 @@
 extern	int		Dbg_setup(dbg_setup_caller_t, const char *,
 			    Dbg_desc *, const char **);
 
+/* Call dbg_print() to produce linker version output */
+extern void		Dbg_version(void);
+
 /* Call dbg_print() to produce help output */
 extern	void		Dbg_help(void);
 
@@ -258,11 +280,13 @@
 #define	Dbg_bind_reject		Dbg64_bind_reject
 #define	Dbg_bind_weak		Dbg64_bind_weak
 
+#define	Dbg_cap_entry		Dbg64_cap_entry
+#define	Dbg_cap_entry2		Dbg64_cap_entry2
 #define	Dbg_cap_val_hw1		Dbg64_cap_val_hw1
 #define	Dbg_cap_hw_candidate	Dbg64_cap_hw_candidate
 #define	Dbg_cap_hw_filter	Dbg64_cap_hw_filter
-#define	Dbg_cap_mapfile		Dbg64_cap_mapfile
-#define	Dbg_cap_sec_entry	Dbg64_cap_sec_entry
+#define	Dbg_cap_mapfile_title	Dbg64_cap_mapfile_title
+#define	Dbg_cap_out_title	Dbg64_cap_out_title
 #define	Dbg_cap_sec_title	Dbg64_cap_sec_title
 
 #define	Dbg_cb_iphdr_enter	Dbg64_cb_iphdr_enter
@@ -324,17 +348,22 @@
 #define	Dbg_libs_yp		Dbg64_libs_yp
 #define	Dbg_libs_ylu		Dbg64_libs_ylu
 
-#define	Dbg_map_dash		Dbg64_map_dash
+#define	Dbg_map_cexp_id		Dbg64_map_cexp_id
+#define	Dbg_map_dv		Dbg64_map_dv
+#define	Dbg_map_dv_entry	Dbg64_map_dv_entry
 #define	Dbg_map_ent		Dbg64_map_ent
+#define	Dbg_map_ent_ord_title	Dbg64_map_ent_ord_title
+#define	Dbg_map_hdr_noalloc	Dbg64_map_hdr_noalloc
 #define	Dbg_map_parse		Dbg64_map_parse
-#define	Dbg_map_pipe		Dbg64_map_pipe
+#define	Dbg_map_pass		Dbg64_map_pass
+#define	Dbg_map_post_title	Dbg64_map_post_title
 #define	Dbg_map_seg		Dbg64_map_seg
-#define	Dbg_map_set_atsign	Dbg64_map_set_atsign
-#define	Dbg_map_set_equal	Dbg64_map_set_equal
+#define	Dbg_map_seg_order	Dbg64_map_seg_order
+#define	Dbg_map_seg_os_order	Dbg64_map_seg_os_order
 #define	Dbg_map_size_new	Dbg64_map_size_new
 #define	Dbg_map_size_old	Dbg64_map_size_old
-#define	Dbg_map_sort		Dbg64_map_sort
 #define	Dbg_map_sort_seg	Dbg64_map_sort_seg
+#define	Dbg_map_sort_title	Dbg64_map_sort_title
 #define	Dbg_map_symbol		Dbg64_map_symbol
 #define	Dbg_map_version		Dbg64_map_version
 
@@ -473,11 +502,13 @@
 #define	Dbg_bind_reject		Dbg32_bind_reject
 #define	Dbg_bind_weak		Dbg32_bind_weak
 
+#define	Dbg_cap_entry		Dbg32_cap_entry
+#define	Dbg_cap_entry2		Dbg32_cap_entry2
 #define	Dbg_cap_val_hw1		Dbg32_cap_val_hw1
 #define	Dbg_cap_hw_candidate	Dbg32_cap_hw_candidate
 #define	Dbg_cap_hw_filter	Dbg32_cap_hw_filter
-#define	Dbg_cap_mapfile		Dbg32_cap_mapfile
-#define	Dbg_cap_sec_entry	Dbg32_cap_sec_entry
+#define	Dbg_cap_mapfile_title	Dbg32_cap_mapfile_title
+#define	Dbg_cap_out_title	Dbg32_cap_out_title
 #define	Dbg_cap_sec_title	Dbg32_cap_sec_title
 
 #define	Dbg_cb_iphdr_enter	Dbg32_cb_iphdr_enter
@@ -539,17 +570,22 @@
 #define	Dbg_libs_yp		Dbg32_libs_yp
 #define	Dbg_libs_ylu		Dbg32_libs_ylu
 
-#define	Dbg_map_dash		Dbg32_map_dash
+#define	Dbg_map_cexp_id		Dbg32_map_cexp_id
+#define	Dbg_map_dv		Dbg32_map_dv
+#define	Dbg_map_dv_entry	Dbg32_map_dv_entry
 #define	Dbg_map_ent		Dbg32_map_ent
+#define	Dbg_map_ent_ord_title	Dbg32_map_ent_ord_title
+#define	Dbg_map_hdr_noalloc	Dbg32_map_hdr_noalloc
 #define	Dbg_map_parse		Dbg32_map_parse
-#define	Dbg_map_pipe		Dbg32_map_pipe
+#define	Dbg_map_pass		Dbg32_map_pass
+#define	Dbg_map_post_title	Dbg32_map_post_title
 #define	Dbg_map_seg		Dbg32_map_seg
-#define	Dbg_map_set_atsign	Dbg32_map_set_atsign
-#define	Dbg_map_set_equal	Dbg32_map_set_equal
+#define	Dbg_map_seg_order	Dbg32_map_seg_order
+#define	Dbg_map_seg_os_order	Dbg32_map_seg_os_order
 #define	Dbg_map_size_new	Dbg32_map_size_new
 #define	Dbg_map_size_old	Dbg32_map_size_old
-#define	Dbg_map_sort		Dbg32_map_sort
 #define	Dbg_map_sort_seg	Dbg32_map_sort_seg
+#define	Dbg_map_sort_title	Dbg32_map_sort_title
 #define	Dbg_map_symbol		Dbg32_map_symbol
 #define	Dbg_map_version		Dbg32_map_version
 
@@ -718,10 +754,12 @@
 extern	void	Dbg_bind_reject(Rt_map *, Rt_map *, const char *, int);
 extern	void	Dbg_bind_weak(Rt_map *, Addr, Addr, const char *);
 
+extern	void	Dbg_cap_entry(Lm_list *, dbg_state_t, Xword, Xword, Half);
+extern	void	Dbg_cap_entry2(Lm_list *, dbg_state_t, Xword, CapMask *, Half);
 extern	void	Dbg_cap_hw_candidate(Lm_list *, const char *);
 extern	void	Dbg_cap_hw_filter(Lm_list *, const char *, Rt_map *);
-extern	void	Dbg_cap_mapfile(Lm_list *, Xword, Xword, Half);
-extern	void	Dbg_cap_sec_entry(Lm_list *, uint_t, Xword, Xword, Half);
+extern	void	Dbg_cap_mapfile_title(Lm_list *, Lineno);
+extern	void	Dbg_cap_out_title(Lm_list *);
 extern	void	Dbg_cap_sec_title(Lm_list *, const char *);
 extern	void	Dbg_cap_val_hw1(Lm_list *, Xword, Half);
 
@@ -734,7 +772,7 @@
 		Dbg_demangle_name(const char *);
 
 extern	void	Dbg_ent_entry(Lm_list *, uchar_t, Half, Ent_desc *);
-extern	void	Dbg_ent_print(Lm_list *, uchar_t, Half, Alist *, Boolean);
+extern	void	Dbg_ent_print(Lm_list *, uchar_t, Half, APlist *);
 
 extern	void	Dbg_file_analyze(Rt_map *);
 extern	void	Dbg_file_aout(Lm_list *, const char *, Addr, size_t,
@@ -794,17 +832,26 @@
 extern	void	Dbg_libs_yp(Lm_list *, const char *);
 extern	void	Dbg_libs_ylu(Lm_list *, const char *, const char *, int);
 
-extern	void	Dbg_map_dash(Lm_list *, const char *);
-extern	void	Dbg_map_ent(Lm_list *, Boolean, Ent_desc *, Ofl_desc *);
-extern	void	Dbg_map_parse(Lm_list *, const char *);
-extern	void	Dbg_map_pipe(Lm_list *, Sg_desc *, const char *, const Word);
-extern	void	Dbg_map_seg(Ofl_desc *, int, Sg_desc *);
-extern	void	Dbg_map_set_atsign(Boolean);
-extern	void	Dbg_map_set_equal(Boolean);
-extern	void	Dbg_map_size_new(Lm_list *, const char *);
-extern	void	Dbg_map_size_old(Ofl_desc *, Sym_desc *);
-extern	void	Dbg_map_sort(Lm_list *);
-extern	void	Dbg_map_sort_seg(Lm_list *, Sg_desc *, int);
+extern	void	Dbg_map_cexp_id(Lm_list *, Boolean, const char *, Lineno,
+		    const char *);
+extern	void	Dbg_map_dv(Lm_list *, const char *, Lineno);
+extern	void	Dbg_map_dv_entry(Lm_list *, Lineno, int, const char *);
+extern	void	Dbg_map_ent(Lm_list *, Ent_desc *, Ofl_desc *, Lineno);
+extern	void	Dbg_map_ent_ord_title(Lm_list *, const char *);
+extern	void	Dbg_map_hdr_noalloc(Lm_list *, Lineno);
+extern	void	Dbg_map_parse(Lm_list *, const char *, int);
+extern	void	Dbg_map_pass(Lm_list *, Boolean, const char *, Lineno,
+		    const char *);
+extern	void	Dbg_map_post_title(Lm_list *);
+extern	void	Dbg_map_seg(Ofl_desc *, dbg_state_t, int, Sg_desc *, Lineno);
+extern	void	Dbg_map_seg_order(Ofl_desc *, uchar_t, Half, dbg_state_t,
+		    Lineno);
+extern	void	Dbg_map_seg_os_order(Lm_list *, Sg_desc *, const char *,
+		    Word, Lineno);
+extern	void	Dbg_map_size_new(Lm_list *, const char *, const char *, Lineno);
+extern	void	Dbg_map_size_old(Ofl_desc *, Sym_desc *, const char *, Lineno);
+extern	void	Dbg_map_sort_title(Lm_list *, Boolean);
+extern	void	Dbg_map_sort_seg(Lm_list *, uchar_t, Half, Sg_desc *);
 extern	void	Dbg_map_symbol(Ofl_desc *, Sym_desc *);
 extern	void	Dbg_map_version(Lm_list *, const char *, const char *, int);
 
@@ -859,7 +906,8 @@
 extern	void	Dbg_sec_strtab(Lm_list *, Os_desc *, Str_tbl *);
 extern	void	Dbg_sec_unsup_strmerge(Lm_list *, Is_desc *);
 
-extern	void	Dbg_seg_desc_entry(Lm_list *, uchar_t, Half, int, Sg_desc *);
+extern	void	Dbg_seg_desc_entry(Lm_list *, uchar_t, Half, int, Sg_desc *,
+		    Boolean);
 extern	void	Dbg_seg_entry(Ofl_desc *, int, Sg_desc *);
 extern	void	Dbg_seg_list(Lm_list *, uchar_t, Half, APlist *);
 extern	void	Dbg_seg_os(Ofl_desc *, Os_desc *, int);
--- a/usr/src/cmd/sgs/include/elfedit.h	Sun Feb 21 21:37:22 2010 -0800
+++ b/usr/src/cmd/sgs/include/elfedit.h	Mon Feb 22 09:19:31 2010 -0700
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -356,7 +356,7 @@
  *	cpldata - Completion data, to be passed to elfedit_cpl_match()
  *		or the helper functions built on it to register alternative
  *		strings.
- *	argc, argv - The tokens from the start of the line throught
+ *	argc, argv - The tokens from the start of the line through
  *		the one needing completion, which will always
  *		be cmdcpl_argv[cmdcpl_argc - 1].
  *	num_opt - A count of the optional arguments (those starting with
--- a/usr/src/cmd/sgs/include/i386/machdep_x86.h	Sun Feb 21 21:37:22 2010 -0800
+++ b/usr/src/cmd/sgs/include/i386/machdep_x86.h	Mon Feb 22 09:19:31 2010 -0700
@@ -23,7 +23,7 @@
  *	Copyright (c) 1988 AT&T
  *	  All Rights Reserved
  *
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  *
  * Global include file for all sgs ia32 based machine dependent macros,
@@ -202,12 +202,14 @@
 #define	M_PLT_SHF_FLAGS	(SHF_ALLOC | SHF_EXECINSTR)
 
 /*
- * Make data segment information transparent to the common code.
+ * Make default data segment and stack flags transparent to the common code.
  */
 #ifdef _ELF64
 #define	M_DATASEG_PERM	(PF_R | PF_W)
+#define	M_STACK_PERM	(PF_R | PF_W)
 #else
 #define	M_DATASEG_PERM	(PF_R | PF_W | PF_X)
+#define	M_STACK_PERM	(PF_R | PF_W | PF_X)
 #endif
 
 /*
--- a/usr/src/cmd/sgs/include/libld.h	Sun Feb 21 21:37:22 2010 -0800
+++ b/usr/src/cmd/sgs/include/libld.h	Mon Feb 22 09:19:31 2010 -0700
@@ -23,7 +23,7 @@
  *	Copyright (c) 1988 AT&T
  *	  All Rights Reserved
  *
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -37,6 +37,7 @@
 #include <string_table.h>
 #include <sys/avl.h>
 #include <alist.h>
+#include <elfcap.h>
 
 #ifdef	__cplusplus
 extern "C" {
@@ -164,6 +165,29 @@
 
 
 /*
+ * Bitmasks for a single capability. Capabilities come from input objects,
+ * augmented or replaced by mapfile directives. In addition, mapfile directives
+ * can be used to exclude bits that would otherwise be set in the output object.
+ */
+typedef struct {
+	elfcap_mask_t	cm_value;	/* Bitmask value */
+	elfcap_mask_t	cm_exclude;	/* Bits to remove from final object */
+} CapMask;
+
+/*
+ * Combine the bitmask in a CapMask with the exclusion mask and
+ * return the resulting final value.
+ */
+#define	CAPMASK_VALUE(_cbmp) ((_cbmp)->cm_value & ~(_cbmp)->cm_exclude)
+
+typedef struct {
+	CapMask		c_hw_1;		/* CA_SUNW_HW_1 capabilities */
+	CapMask		c_sf_1;		/* CA_SUNW_SF_1 capabilities */
+	CapMask		c_hw_2;		/* CA_SUNW_HW_2 capabilities */
+} Outcapset;
+
+
+/*
  * Output file processing structure
  */
 typedef Lword ofl_flag_t;
@@ -180,7 +204,10 @@
 	size_t		ofl_size;	/* image size */
 	APlist		*ofl_maps;	/* list of input mapfiles */
 	APlist		*ofl_segs;	/* list of segments */
-	Alist		*ofl_ents;	/* list of entrance descriptors */
+	APlist		*ofl_segs_order; /* SEGMENT_ORDER segments */
+	avl_tree_t	ofl_segs_avl;	/* O(log N) access to named segments */
+	APlist		*ofl_ents;	/* list of entrance descriptors */
+	avl_tree_t	ofl_ents_avl;	/* O(log N) access to named ent. desc */
 	APlist		*ofl_objs;	/* relocatable object file list */
 	Word		ofl_objscnt;	/* 	and count */
 	APlist		*ofl_ars;	/* archive library list */
@@ -310,8 +337,7 @@
 	char		*ofl_audit;	/* object auditing required (-p) */
 	Alist		*ofl_symfltrs;	/* per-symbol filtees and their */
 	Alist		*ofl_dtsfltrs;	/*	associated .dynamic/.dynstrs */
-	Xword		ofl_hwcap_1;	/* hardware capabilities */
-	Xword		ofl_sfcap_1;	/* software capabilities */
+	Outcapset	ofl_ocapset;	/* object capabilities */
 	Lm_list		*ofl_lml;	/* runtime link-map list */
 	Gottable	*ofl_gottable;	/* debugging got information */
 	Rlxrel_cache	ofl_sr_cache;	/* Cache last result from */
@@ -337,8 +363,9 @@
 #define	FLG_OF_SYMBOLIC	0x00002000	/* bind global symbols: -Bsymbolic */
 #define	FLG_OF_ADDVERS	0x00004000	/* add version stamp: -Qy */
 #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_IS_ORDER	0x00010000	/* input section ordering within a */
+					/*	segment is required */
+#define	FLG_OF_EC_FILES	0x00020000	/* Ent_desc exist w/non-NULL ec_files */
 #define	FLG_OF_TEXTREL	0x00040000	/* text relocations have been found */
 #define	FLG_OF_MULDEFS	0x00080000	/* multiple symbols are allowed */
 #define	FLG_OF_TLSPHDR	0x00100000	/* a TLS program header is required */
@@ -366,7 +393,7 @@
 #define	FLG_OF_AUTOELM	0x002000000000	/* automatically eliminate */
 					/*	unspecified global symbols */
 #define	FLG_OF_REDLSYM	0x004000000000	/* reduce local symbols */
-#define	FLG_OF_SECORDER	0x008000000000	/* section ordering is required */
+#define	FLG_OF_OS_ORDER	0x008000000000	/* output section ordering required */
 #define	FLG_OF_OSABI	0x010000000000	/* tag object as ELFOSABI_SOLARIS */
 #define	FLG_OF_ADJOSCNT	0x020000000000	/* ajust ofl_shdrcnt to accommodate */
 					/*	discarded sections */
@@ -377,49 +404,51 @@
  * archive descriptor so that they may be reset should the archive require a
  * rescan to try and resolve undefined symbols.
  */
-#define	FLG_OF1_ALLEXRT	0x00000001	/* extract all members from an */
+#define	FLG_OF1_ALLEXRT	0x0000000001	/* extract all members from an */
 					/*	archive file */
-#define	FLG_OF1_WEAKEXT	0x00000002	/* allow archive extraction to */
+#define	FLG_OF1_WEAKEXT	0x0000000002	/* allow archive extraction to */
 					/*	resolve weak references */
-#define	MSK_OF1_ARCHIVE	0x00000003	/* archive flags mask */
+#define	MSK_OF1_ARCHIVE	0x0000000003	/* archive flags mask */
+
+#define	FLG_OF1_NOINTRP	0x0000000008	/* -z nointerp flag set */
+#define	FLG_OF1_ZDIRECT	0x0000000010	/* -z direct flag set */
+#define	FLG_OF1_NDIRECT	0x0000000020	/* no-direct bindings specified */
 
-#define	FLG_OF1_NOINTRP	0x00000008	/* -z nointerp flag set */
-#define	FLG_OF1_ZDIRECT	0x00000010	/* -z direct flag set */
-#define	FLG_OF1_NDIRECT	0x00000020	/* no-direct bindings specified */
-#define	FLG_OF1_OVHWCAP	0x00000040	/* override any input hardware or */
-#define	FLG_OF1_OVSFCAP	0x00000080	/*	software capabilities */
-#define	FLG_OF1_RELDYN	0x00000100	/* process .dynamic in rel obj */
-#define	FLG_OF1_NRLXREL	0x00000200	/* -z norelaxreloc flag set */
-#define	FLG_OF1_RLXREL	0x00000400	/* -z relaxreloc flag set */
-#define	FLG_OF1_IGNORE	0x00000800	/* ignore unused dependencies */
+#define	FLG_OF1_RELDYN	0x0000000100	/* process .dynamic in rel obj */
+#define	FLG_OF1_NRLXREL	0x0000000200	/* -z norelaxreloc flag set */
+#define	FLG_OF1_RLXREL	0x0000000400	/* -z relaxreloc flag set */
+#define	FLG_OF1_IGNORE	0x0000000800	/* ignore unused dependencies */
 
-#define	FLG_OF1_NOSGHND	0x00001000	/* -z nosighandler flag set */
-#define	FLG_OF1_TEXTOFF 0x00002000	/* text relocations are ok */
-#define	FLG_OF1_ABSEXEC	0x00004000	/* -zabsexec set */
-#define	FLG_OF1_LAZYLD	0x00008000	/* lazy loading of objects enabled */
-#define	FLG_OF1_GRPPRM	0x00010000	/* dependencies are to have */
+#define	FLG_OF1_NOSGHND	0x0000001000	/* -z nosighandler flag set */
+#define	FLG_OF1_TEXTOFF 0x0000002000	/* text relocations are ok */
+#define	FLG_OF1_ABSEXEC	0x0000004000	/* -zabsexec set */
+#define	FLG_OF1_LAZYLD	0x0000008000	/* lazy loading of objects enabled */
+#define	FLG_OF1_GRPPRM	0x0000010000	/* dependencies are to have */
 					/*	GROUPPERM enabled */
-#define	FLG_OF1_OVRFLW	0x00020000	/* size exceeds 32-bit limitation */
+#define	FLG_OF1_OVRFLW	0x0000020000	/* size exceeds 32-bit limitation */
 					/*	of 32-bit libld */
-#define	FLG_OF1_NOPARTI	0x00040000	/* -znopartial set */
-#define	FLG_OF1_BSSOREL	0x00080000	/* output relocation against bss */
+#define	FLG_OF1_NOPARTI	0x0000040000	/* -znopartial set */
+#define	FLG_OF1_BSSOREL	0x0000080000	/* output relocation against bss */
 					/*	section */
-#define	FLG_OF1_TLSOREL	0x00100000	/* output relocation against .tlsbss */
+#define	FLG_OF1_TLSOREL	0x0000100000	/* output relocation against .tlsbss */
 					/*	section */
-#define	FLG_OF1_MEMORY	0x00200000	/* produce a memory model */
-#define	FLG_OF1_NGLBDIR	0x00400000	/* no DT_1_DIRECT flag allowed */
-#define	FLG_OF1_ENCDIFF	0x00800000	/* Host running linker has different */
+#define	FLG_OF1_MEMORY	0x0000200000	/* produce a memory model */
+#define	FLG_OF1_NGLBDIR	0x0000400000	/* no DT_1_DIRECT flag allowed */
+#define	FLG_OF1_ENCDIFF	0x0000800000	/* Host running linker has different */
 					/*	byte order than output object */
-#define	FLG_OF1_VADDR	0x01000000	/* user segment defines a vaddr */
-#define	FLG_OF1_EXTRACT	0x02000000	/* archive member has been extracted */
-#define	FLG_OF1_RESCAN	0x04000000	/* any archives should be rescanned */
-#define	FLG_OF1_IGNPRC	0x08000000	/* ignore processing required */
-#define	FLG_OF1_NCSTTAB	0x10000000	/* -znocompstrtab set */
-#define	FLG_OF1_DONE	0x20000000	/* link-editor processing complete */
-#define	FLG_OF1_NONREG	0x40000000	/* non-regular file specified as */
+#define	FLG_OF1_VADDR	0x0001000000	/* a segment defines explicit vaddr */
+#define	FLG_OF1_EXTRACT	0x0002000000	/* archive member has been extracted */
+#define	FLG_OF1_RESCAN	0x0004000000	/* any archives should be rescanned */
+#define	FLG_OF1_IGNPRC	0x0008000000	/* ignore processing required */
+#define	FLG_OF1_NCSTTAB	0x0010000000	/* -znocompstrtab set */
+#define	FLG_OF1_DONE	0x0020000000	/* link-editor processing complete */
+#define	FLG_OF1_NONREG	0x0040000000	/* non-regular file specified as */
 					/*	the output file */
-#define	FLG_OF1_ALNODIR	0x80000000	/* establish NODIRECT for all */
+#define	FLG_OF1_ALNODIR	0x0080000000	/* establish NODIRECT for all */
 					/*	exported interfaces. */
+#define	FLG_OF1_OVHWCAP1 0x0100000000	/* override CA_SUNW_HW_1 capabilities */
+#define	FLG_OF1_OVSFCAP1 0x0200000000	/* override CA_SUNW_SF_1 capabilities */
+#define	FLG_OF1_OVHWCAP2 0x0400000000	/* override CA_SUNW_HW_2 capabilities */
 
 /*
  * Test to see if the output file would allow the presence of
@@ -665,7 +694,7 @@
 #define	FLG_IS_RELUPD	0x0008		/* symbol defined here may have moved */
 #define	FLG_IS_SECTREF	0x0010		/* section has been referenced */
 #define	FLG_IS_GDATADEF	0x0020		/* section contains global data sym */
-#define	FLG_IS_EXTERNAL	0x0040		/* isp from an user file */
+#define	FLG_IS_EXTERNAL	0x0040		/* isp from a user file */
 #define	FLG_IS_INSTRMRG	0x0080		/* Usable SHF_MERGE|SHF_STRINGS sec */
 #define	FLG_IS_GNSTRMRG	0x0100		/* Generated mergeable string section */
 #define	FLG_IS_GROUPS	0x0200		/* section has groups to process */
@@ -733,76 +762,99 @@
 #define	FLG_OS_SECTREF		0x04	/* isps are not affected by -zignore */
 
 /*
- * Types of segment index.
+ * The sg_id field of the segment descriptor is used to establish the default
+ * order for program headers and segments in the output object. Segments are
+ * ordered according to the following SGID values that classify them based on
+ * their attributes. The initial set of built in segments are in this order,
+ * and new mapfile defined segments are inserted into these groups. Within a
+ * given SGID group, the position of new segments depends on the syntax
+ * version of the mapfile that creates them. Version 1 (original sysv)
+ * mapfiles place the new segment at the head of their group (reverse creation
+ * order). The newer syntax places them at the end, following the others
+ * (creation order).
+ *
+ * Note that any new segments must always be added after PT_PHDR and
+ * PT_INTERP (refer Generic ABI, Page 5-4).
  */
-typedef enum {
-	LD_PHDR,
-	LD_INTERP,
-	LD_SUNWCAP,
-	LD_TEXT,
-	LD_DATA,
-	LD_BSS,
+#define	SGID_PHDR	0	/* PT_PHDR */
+#define	SGID_INTERP	1	/* PT_INTERP */
+#define	SGID_SUNWCAP	2	/* PT_SUNWCAP */
+#define	SGID_TEXT	3	/* PT_LOAD */
+#define	SGID_DATA	4	/* PT_LOAD */
+#define	SGID_BSS	5	/* PT_LOAD */
 #if	defined(_ELF64)
-	LD_LRODATA,		/* (amd64-only) */
-	LD_LDATA,		/* (amd64-only) */
+#define	SGID_LRODATA	6	/* PT_LOAD (amd64-only) */
+#define	SGID_LDATA	7	/* PT_LOAD (amd64-only) */
 #endif
-	LD_DYN,
-	LD_DTRACE,
-	LD_TLS,
-	LD_UNWIND,
-	LD_NOTE,
-	LD_EXTRA,
-	LD_NUM
-} Segment_id;
+#define	SGID_TEXT_EMPTY	8	/* PT_LOAD, reserved (?E in version 1 syntax) */
+#define	SGID_NULL_EMPTY	9	/* PT_NULL, reserved (?E in version 1 syntax) */
+#define	SGID_DYN	10	/* PT_DYNAMIC */
+#define	SGID_DTRACE	11	/* PT_SUNWDTRACE */
+#define	SGID_TLS	12	/* PT_TLS */
+#define	SGID_UNWIND	13	/* PT_SUNW_UNWIND */
+#define	SGID_SUNWSTACK	14	/* PT_SUNWSTACK */
+#define	SGID_NOTE	15	/* PT_NOTE */
+#define	SGID_NULL	16	/* PT_NULL,  mapfile defined empty phdr slots */
+				/*	for use by post processors */
+#define	SGID_EXTRA	17	/* PT_NULL (final catchall) */
 
+typedef Half sg_flags_t;
 struct sg_desc {			/* output segment descriptor */
-	Segment_id	sg_id;		/* segment identifier (for sorting) */
+	Word		sg_id;		/* segment identifier (for sorting) */
 	Phdr		sg_phdr;	/* segment header for output file */
-	const char	*sg_name;	/* segment name */
+	const char	*sg_name;	/* segment name for PT_LOAD, PT_NOTE, */
+					/*	and PT_NULL, otherwise NULL */
 	Xword		sg_round;	/* data rounding required (mapfile) */
 	Xword		sg_length;	/* maximum segment length; if 0 */
 					/*	segment is not specified */
 	APlist		*sg_osdescs;	/* list of output section descriptors */
-	APlist		*sg_secorder;	/* list specifying section ordering */
-					/*	for the segment */
-	Half		sg_flags;
-	Sym_desc	*sg_sizesym;	/* size symbol for this segment */
-	Xword		sg_addralign;	/* LCM of sh_addralign */
+	APlist		*sg_is_order;	/* list of entry criteria */
+					/*	giving input section order */
+	Alist		*sg_os_order;	/* list specifying output section */
+					/*	ordering for the segment */
+	sg_flags_t	sg_flags;
+	APlist		*sg_sizesym;	/* size symbols for this segment */
+	Xword		sg_align;	/* LCM of sh_addralign */
 	Elf_Scn		*sg_fscn;	/* the SCN of the first section. */
+	avl_node_t	sg_avlnode;	/* AVL book-keeping */
 };
 
-#define	FLG_SG_VADDR	0x0001		/* vaddr segment attribute set */
-#define	FLG_SG_PADDR	0x0002		/* paddr segment attribute set */
-#define	FLG_SG_LENGTH	0x0004		/* length segment attribute set */
-#define	FLG_SG_ALIGN	0x0008		/* align segment attribute set */
-#define	FLG_SG_ROUND	0x0010		/* round segment attribute set */
-#define	FLG_SG_FLAGS	0x0020		/* flags segment attribute set */
-#define	FLG_SG_TYPE	0x0040		/* type segment attribute set */
-#define	FLG_SG_ORDER	0x0080		/* has ordering been turned on for */
-					/* 	this segment. */
-					/*	i.e. ?[O] option in mapfile */
-#define	FLG_SG_NOHDR	0x0100		/* don't map ELF or phdrs into */
-					/* 	this segment */
-#define	FLG_SG_EMPTY	0x0200		/* an empty segment specification */
+#define	FLG_SG_P_VADDR		0x0001	/* p_vaddr segment attribute set */
+#define	FLG_SG_P_PADDR		0x0002	/* p_paddr segment attribute set */
+#define	FLG_SG_LENGTH		0x0004	/* length segment attribute set */
+#define	FLG_SG_P_ALIGN		0x0008	/* p_align segment attribute set */
+#define	FLG_SG_ROUND		0x0010	/* round segment attribute set */
+#define	FLG_SG_P_FLAGS		0x0020	/* p_flags segment attribute set */
+#define	FLG_SG_P_TYPE		0x0040	/* p_type segment attribute set */
+#define	FLG_SG_IS_ORDER		0x0080	/* input section ordering is required */
+					/* 	for this segment. */
+#define	FLG_SG_NOHDR		0x0100	/* don't map ELF or phdrs into */
+					/*	this segment */
+#define	FLG_SG_EMPTY		0x0200	/* an empty segment specification */
 					/*	no input sections will be */
 					/*	associated to this section */
-#define	FLG_SG_KEY	0x0400		/* segment requires sort keys */
-#define	FLG_SG_DISABLED	0x0800		/* this segment is disabled */
-#define	FLG_SG_PHREQ	0x1000		/* this segment requires a program */
+#define	FLG_SG_KEY		0x0400	/* segment requires sort keys */
+#define	FLG_SG_NODISABLE	0x0800	/* FLG_SG_DISABLED is not allowed on */
+					/*	this segment */
+#define	FLG_SG_DISABLED		0x1000	/* this segment is disabled */
+#define	FLG_SG_PHREQ		0x2000	/* this segment requires a program */
 					/* header */
+#define	FLG_SG_ORDERED		0x4000	/* SEGMENT_ORDER segment */
 
 struct sec_order {
 	const char	*sco_secname;	/* section name to be ordered */
-	Word		sco_index;	/* ordering index for section */
 	Half		sco_flags;
 };
 
 #define	FLG_SGO_USED	0x0001		/* was ordering used? */
 
+typedef Half ec_flags_t;
 struct ent_desc {			/* input section entrance criteria */
-	APlist		*ec_files;	/* files from which to accept */
+	const char	*ec_name;	/* entrace criteria name, or NULL */
+	Alist		*ec_files;	/* files from which to accept */
 					/*	sections */
-	const char	*ec_name;	/* name to match (NULL if none) */
+	const char	*ec_is_name;	/* input section name to match */
+					/*	(NULL if none) */
 	Word		ec_type;	/* section type */
 	Word		ec_attrmask;	/* section attribute mask (AWX) */
 	Word		ec_attrbits;	/* sections attribute bits */
@@ -811,11 +863,35 @@
 					/*	meeting this criteria should */
 					/*	inserted. Used for reordering */
 					/*	of sections. */
-	Half		ec_flags;
+	ec_flags_t	ec_flags;
+	avl_node_t	ec_avlnode;	/* AVL book-keeping */
 };
 
 #define	FLG_EC_BUILTIN	0x0001		/* built in descriptor */
 #define	FLG_EC_USED	0x0002		/* entrance criteria met? */
+#define	FLG_EC_CATCHALL	0x0004		/* Catches any section */
+
+/*
+ * Ent_desc_file is the type of element maintained in the ec_files Alist
+ * of an entrance criteria descriptor. Each item maintains one file
+ * path, and a set of flags that specify the type of comparison it implies,
+ * and other information about it. The comparison type is maintained in
+ * the bottom byte of the flags.
+ */
+#define	TYP_ECF_MASK		0x00ff  /* Comparison type mask */
+#define	TYP_ECF_PATH		0	/* Compare to file path */
+#define	TYP_ECF_BASENAME	1	/* Compare to file basename */
+#define	TYP_ECF_OBJNAME		2	/* Compare to regular file basename, */
+					/*	 or to archive member name */
+#define	TYP_ECF_NUM		3
+
+#define	FLG_ECF_ARMEMBER	0x0100	/* name includes archive member */
+
+typedef struct {
+	Word		edf_flags;	/* Type of comparison */
+	const char	*edf_name;	/* String to compare to */
+	size_t		edf_name_len;	/* strlen(edf_name) */
+} Ent_desc_file;
 
 /*
  * One structure is allocated for a move entry, and associated to the symbol
@@ -1178,6 +1254,13 @@
  */
 #define	FLG_ARD_EXTRACT	0x00010000	/* archive member has been extracted */
 
+/* Mapfile versions supported by libld */
+#define	MFV_NONE	0	/* Not a valid version */
+#define	MFV_SYSV	1	/* Original System V syntax */
+#define	MFV_SOLARIS	2	/* Solaris mapfile syntax */
+#define	MFV_NUM		3	/* # of mapfile versions */
+
+
 /*
  * Function Declarations.
  */
--- a/usr/src/cmd/sgs/include/sgs.h	Sun Feb 21 21:37:22 2010 -0800
+++ b/usr/src/cmd/sgs/include/sgs.h	Mon Feb 22 09:19:31 2010 -0700
@@ -24,7 +24,7 @@
  *	  All Rights Reserved
  *
  *
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  *
  * Global include file for all sgs.
@@ -130,6 +130,14 @@
 	ERR_NUM				/* Must be last */
 } Error;
 
+/*
+ * Type used to represent line numbers within files, and a corresponding
+ * printing macro for it.
+ */
+typedef ulong_t Lineno;
+#define	EC_LINENO(_x) EC_XWORD(_x)			/* "llu" */
+
+
 #if defined(_LP64) && !defined(_ELF64)
 #define	S_ERROR		(~(uint_t)0)
 #else
--- a/usr/src/cmd/sgs/include/sparc/machdep_sparc.h	Sun Feb 21 21:37:22 2010 -0800
+++ b/usr/src/cmd/sgs/include/sparc/machdep_sparc.h	Mon Feb 22 09:19:31 2010 -0700
@@ -23,7 +23,7 @@
  *	Copyright (c) 1988 AT&T
  *	  All Rights Reserved
  *
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  *
  * Global include file for all sgs SPARC machine dependent macros, constants
@@ -186,9 +186,15 @@
 #define	M_PLT_SHF_FLAGS	(SHF_ALLOC | SHF_WRITE | SHF_EXECINSTR)
 
 /*
- * Make data segment information transparent to the common code.
+ * Make default data segment and stack flags transparent to the common code.
  */
 #define	M_DATASEG_PERM	(PF_R | PF_W | PF_X)
+#ifdef _ELF64
+#define	M_STACK_PERM	(PF_R | PF_W)
+#else
+#define	M_STACK_PERM	(PF_R | PF_W | PF_X)
+#endif
+
 
 /*
  * Define a set of identifies for special sections.  These allow the sections
--- a/usr/src/cmd/sgs/lari/lari.pl	Sun Feb 21 21:37:22 2010 -0800
+++ b/usr/src/cmd/sgs/lari/lari.pl	Mon Feb 22 09:19:31 2010 -0700
@@ -21,7 +21,7 @@
 #
 
 #
-# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # Link Analysis of Runtime Interfaces.
@@ -584,10 +584,14 @@
 				}
 				$Offset++;
 			}
-			# The symbol being bound, "... symbol `.*' ...".
+			# The symbol being bound. Over the years, we have used
+			# a ` quoting style, and more recently a ' style.
+			# Match either of:
+			#	"... symbol `.*' ...".
+			#	"... symbol '.*' ...".
 			while ($Fields[$Offset]) {
-				if ($Fields[$Offset] =~ /^\`(.*)\'$/) {
-					$SymName = $1;
+				if ($Fields[$Offset] =~ /^(\`|\')(.*)\'$/) {
+					$SymName = $2;
 					$Offset++;
 					last;
 				}
--- a/usr/src/cmd/sgs/ldd/common/ldd.c	Sun Feb 21 21:37:22 2010 -0800
+++ b/usr/src/cmd/sgs/ldd/common/ldd.c	Mon Feb 22 09:19:31 2010 -0700
@@ -22,7 +22,7 @@
  *	  All Rights Reserved
  *
  *
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -532,8 +532,9 @@
 
 	/*
 	 * If there is a dynamic section, then check for the DF_1_NOHDR
-	 * flag, and bail if it is present. Those objects are created using
-	 * the ?N mapfile option: The ELF header and program headers are
+	 * flag, and bail if it is present. Such objects are created using
+	 * a mapfile option (?N in the version 1 syntax, or HDR_NOALLOC
+	 * otherwise). The ELF header and program headers are
 	 * not mapped as part of the first segment, and virtual addresses
 	 * are computed without them. If ldd tries to interpret such
 	 * a file, it will become confused and generate bad output or
--- a/usr/src/cmd/sgs/ldprof/Makefile.com	Sun Feb 21 21:37:22 2010 -0800
+++ b/usr/src/cmd/sgs/ldprof/Makefile.com	Mon Feb 22 09:19:31 2010 -0700
@@ -19,7 +19,7 @@
 # CDDL HEADER END
 #
 #
-# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 
@@ -46,7 +46,7 @@
 		-I$(SRCBASE)/uts/common/krtld \
 		-I$(SRC)/common/sgsrtcid \
 		-I$(SRCBASE)/uts/$(ARCH)/sys \
-		$(CPPFLAGS.master)
+		$(CPPFLAGS.master) -I$(ELFCAP)
 CFLAGS +=	$(C_PICFLAGS)
 
 lint :=		ZRECORD =
--- a/usr/src/cmd/sgs/libconv/Makefile.com	Sun Feb 21 21:37:22 2010 -0800
+++ b/usr/src/cmd/sgs/libconv/Makefile.com	Mon Feb 22 09:19:31 2010 -0700
@@ -20,7 +20,7 @@
 #
 
 #
-# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 
@@ -40,12 +40,13 @@
 		deftag.o 		demangle.o \
 		dl.o			dwarf.o \
 		dwarf_ehe.o 		dynamic.o \
-		elf.o			globals.o \
-		group.o 		lddstub.o \
+		elf.o			entry.o \
+		globals.o		group.o \
+ 		lddstub.o		map.o \
 		phdr.o			relocate.o \
- 		relocate_i386.o 	relocate_amd64.o \
- 		relocate_sparc.o 	sections.o \
-   		segments.o    		strproc.o \
+ 		relocate_i386.o		relocate_amd64.o \
+		relocate_sparc.o	sections.o \
+		segments.o    		strproc.o \
 		symbols.o  		syminfo.o \
   		tokens.o  		time.o \
 		version.o
@@ -60,10 +61,11 @@
 		deftag_msg.o		demangle_msg.o \
 		dl_msg.o		dwarf_msg.o \
 		dwarf_ehe_msg.o 	dynamic_msg.o \
-		elf_msg.o 		globals_msg.o \
-		group_msg.o 		lddstub_msg.o \
+		elf_msg.o 		entry_msg.o \
+		globals_msg.o		group_msg.o \
+ 		map_msg.o		lddstub_msg.o \
 		phdr_msg.o 		relocate_amd64_msg.o \
-		relocate_i386_msg.o 	relocate_sparc_msg.o \
+		relocate_i386_msg.o	relocate_sparc_msg.o \
 		sections_msg.o 		segments_msg.o \
 		symbols_msg.o 		symbols_sparc_msg.o \
 		syminfo_msg.o 		time_msg.o \
@@ -73,8 +75,6 @@
 OBJECTS =	$(COMOBJS) $(COMOBJS32) $(COMOBJS64) $(ELFCAP_OBJS) \
 		$(ASOBJS) $(BLTOBJS)
 
-ELFCAP=		$(SRC)/common/elfcap
-
 #
 # This library is unusual since it's a static archive of PIC objects.
 # Since static archives should never contain CTF data (regardless of
--- a/usr/src/cmd/sgs/libconv/common/c_literal.c	Sun Feb 21 21:37:22 2010 -0800
+++ b/usr/src/cmd/sgs/libconv/common/c_literal.c	Mon Feb 22 09:19:31 2010 -0700
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -137,3 +137,85 @@
 		}
 	}
 }
+
+/*
+ * Given the pointer to the character following a '\' character in
+ * a C style literal, return the ASCII character code it represents,
+ * and advance the string pointer to the character following the last
+ * character in the escape sequence.
+ *
+ * entry:
+ *	str - Address of string pointer to first character following
+ *		the backslash.
+ *
+ * exit:
+ *	If the character is not valid, -1 is returned. Otherwise
+ *	it returns the ASCII code for the translated character, and
+ *	*str has been advanced.
+ */
+int
+conv_translate_c_esc(char **str)
+{
+	char	*s = *str;
+	int	ch, i;
+
+	ch = *s++;
+	switch (ch) {
+	case 'a':
+		ch = '\a';
+		break;
+	case 'b':
+		ch = '\b';
+		break;
+	case 'f':
+		ch = '\f';
+		break;
+	case 'n':
+		ch = '\n';
+		break;
+	case 'r':
+		ch = '\r';
+		break;
+	case 't':
+		ch = '\t';
+		break;
+	case 'v':
+		ch = '\v';
+		break;
+
+	case '0':
+	case '1':
+	case '2':
+	case '3':
+	case '4':
+	case '5':
+	case '6':
+	case '7':
+		/* Octal constant: There can be up to 3 digits */
+		ch -= '0';
+		for (i = 0; i < 2; i++) {
+			if ((*s < '0') || (*s > '7'))
+				break;
+			ch = (ch << 3) + (*s++ - '0');
+		}
+		break;
+
+	/*
+	 * There are some cases where ch already has the desired value.
+	 * These cases exist simply to remove the special meaning that
+	 * character would otherwise have. We need to match them to
+	 * prevent them from falling into the default error case.
+	 */
+	case '\\':
+	case '\'':
+	case '"':
+		break;
+
+	default:
+		ch = -1;
+		break;
+	}
+
+	*str = s;
+	return (ch);
+}
--- a/usr/src/cmd/sgs/libconv/common/cap.c	Sun Feb 21 21:37:22 2010 -0800
+++ b/usr/src/cmd/sgs/libconv/common/cap.c	Mon Feb 22 09:19:31 2010 -0700
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -36,13 +36,16 @@
 const conv_ds_t **
 conv_cap_tag_strings(Conv_fmt_flags_t fmt_flags)
 {
+#if	(CA_SUNW_NUM != (CA_SUNW_HW_2 + 1))
+#error	"CA_SUNW_NUM has grown"
+#endif
 	static const Msg	tags_cf[] = {
 		MSG_CA_SUNW_NULL_CF,	MSG_CA_SUNW_HW_1_CF,
-		MSG_CA_SUNW_SF_1_CF
+		MSG_CA_SUNW_SF_1_CF,	MSG_CA_SUNW_HW_2_CF
 	};
 	static const Msg	tags_nf[] = {
 		MSG_CA_SUNW_NULL_NF,	MSG_CA_SUNW_HW_1_NF,
-		MSG_CA_SUNW_SF_1_NF
+		MSG_CA_SUNW_SF_1_NF,	MSG_CA_SUNW_HW_2_NF,
 	};
 	static const conv_ds_msg_t ds_tags_cf = {
 	    CONV_DS_MSG_INIT(ELFCLASSNONE, tags_cf) };
--- a/usr/src/cmd/sgs/libconv/common/cap.msg	Sun Feb 21 21:37:22 2010 -0800
+++ b/usr/src/cmd/sgs/libconv/common/cap.msg	Mon Feb 22 09:19:31 2010 -0700
@@ -1,5 +1,5 @@
 #
-# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # CDDL HEADER START
@@ -30,6 +30,8 @@
 @ MSG_CA_SUNW_HW_1_NF			"hw_1"
 @ MSG_CA_SUNW_SF_1_CF		"CA_SUNW_SF_1"			# 2
 @ MSG_CA_SUNW_SF_1_NF			"sf_1"
+@ MSG_CA_SUNW_HW_2_CF		"CA_SUNW_HW_2"			# 3
+@ MSG_CA_SUNW_HW_2_NF			"hw_2"
 
 @ MSG_GBL_ZERO		"0"
 @ MSG_GBL_OSQBRKT	"0x%llx  [ "
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/sgs/libconv/common/entry.c	Mon Feb 22 09:19:31 2010 -0700
@@ -0,0 +1,140 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * String conversion routine for segment flags.
+ */
+#include	<string.h>
+#include	<libld.h>
+#include	"_conv.h"
+#include	"entry_msg.h"
+
+#define	ENTSZ	CONV_EXPN_FIELD_DEF_PREFIX_SIZE + \
+		MSG_FLG_EC_BUILTIN_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
+		MSG_FLG_EC_USED_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
+		MSG_FLG_EC_CATCHALL_SIZE + CONV_EXPN_FIELD_DEF_SEP_SIZE + \
+		CONV_INV_BUFSIZE + CONV_EXPN_FIELD_DEF_SUFFIX_SIZE
+
+/*
+ * Ensure that Conv_ent_flags_buf_t is large enough:
+ *
+ * ENTSZ is the real minimum size of the buffer required by conv_ent_flags().
+ * However, Conv_ent_flags_buf_t uses CONV_ENT_FLAGS_BUFSIZE to set the
+ * buffer size. We do things this way because the definition of ENTSZ uses
+ * information that is not available in the environment of other programs
+ * that include the conv.h header file.
+ */
+#if (CONV_ENT_FLAGS_BUFSIZE != ENTSZ) && !defined(__lint)
+#define	REPORT_BUFSIZE ENTSZ
+#include "report_bufsize.h"
+#error "CONV_ENT_FLAGS_BUFSIZE does not match ENTSZ"
+#endif
+
+const char *
+conv_ent_flags(ec_flags_t flags, Conv_ent_flags_buf_t *ent_flags_buf)
+{
+	static Val_desc vda[] = {
+		{ FLG_EC_BUILTIN,	MSG_FLG_EC_BUILTIN },
+		{ FLG_EC_USED,		MSG_FLG_EC_USED },
+		{ FLG_EC_CATCHALL,	MSG_FLG_EC_CATCHALL },
+		{ 0,			0 }
+	};
+	static CONV_EXPN_FIELD_ARG conv_arg = {
+	    NULL, sizeof (ent_flags_buf->buf) };
+
+	if (flags == 0)
+		return (MSG_ORIG(MSG_GBL_ZERO));
+
+	conv_arg.buf = ent_flags_buf->buf;
+	conv_arg.oflags = conv_arg.rflags = flags;
+	(void) conv_expn_field(&conv_arg, vda, 0);
+
+	return ((const char *)ent_flags_buf->buf);
+}
+
+
+#define	ECFSZ	CONV_EXPN_FIELD_DEF_PREFIX_SIZE + \
+		MSG_TYP_ECF_PATH_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
+		MSG_TYP_ECF_BASENAME_SIZE + CONV_EXPN_FIELD_DEF_SEP_SIZE + \
+		MSG_TYP_ECF_OBJNAME_SIZE + CONV_EXPN_FIELD_DEF_SEP_SIZE + \
+		MSG_FLG_ECF_ARMEMBER_SIZE + CONV_EXPN_FIELD_DEF_SEP_SIZE + \
+		CONV_INV_BUFSIZE + CONV_EXPN_FIELD_DEF_SUFFIX_SIZE
+
+/*
+ * Ensure that Conv_ent_flags_buf_t is large enough:
+ *
+ * ENTSZ is the real minimum size of the buffer required by conv_ent_flags().
+ * However, Conv_ent_flags_buf_t uses CONV_ENT_FLAGS_BUFSIZE to set the
+ * buffer size. We do things this way because the definition of ENTSZ uses
+ * information that is not available in the environment of other programs
+ * that include the conv.h header file.
+ */
+#if (CONV_ENT_FILES_FLAGS_BUFSIZE != ECFSZ) && !defined(__lint)
+#define	REPORT_BUFSIZE ECFSZ
+#include "report_bufsize.h"
+#error "CONV_ENT_FILES_FLAGS_BUFSIZE does not match ECFSZ"
+#endif
+
+/*
+ * Make a string representation of the End_desc_file edf_flags field.
+ */
+const char *
+conv_ent_files_flags(Word flags, Conv_fmt_flags_t fmt_flags,
+    Conv_ent_files_flags_buf_t *flags_buf)
+{
+	static const Msg	types[] = {
+		MSG_TYP_ECF_PATH, MSG_TYP_ECF_BASENAME, MSG_TYP_ECF_OBJNAME
+	};
+#if TYP_ECF_NUM != (TYP_ECF_OBJNAME + 1)
+#error "types has grown"
+#endif
+
+	static Val_desc vda[] = {
+		{ FLG_ECF_ARMEMBER,	MSG_FLG_ECF_ARMEMBER },
+		{ 0,			0 }
+	};
+
+	static const char *leading_str_arr[2];
+	static CONV_EXPN_FIELD_ARG conv_arg = {
+	    NULL, sizeof (flags_buf->buf), leading_str_arr };
+
+	Word	type_idx;
+
+	type_idx = flags & TYP_ECF_MASK;
+	if (type_idx < TYP_ECF_NUM) {
+		leading_str_arr[0] = MSG_ORIG(types[type_idx]);
+		flags &= ~TYP_ECF_MASK;
+	} else {
+		leading_str_arr[0] = NULL;
+	}
+
+	conv_arg.buf = flags_buf->buf;
+	conv_arg.oflags = conv_arg.rflags = flags;
+
+	(void) conv_expn_field(&conv_arg, vda, fmt_flags);
+
+	return (conv_arg.buf);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/sgs/libconv/common/entry.msg	Mon Feb 22 09:19:31 2010 -0700
@@ -0,0 +1,36 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+@ MSG_FLG_EC_BUILTIN		"FLG_EC_BUILTIN"
+@ MSG_FLG_EC_USED		"FLG_EC_USED"
+@ MSG_FLG_EC_CATCHALL		"FLG_EC_CATCHALL"
+
+@ MSG_TYP_ECF_PATH		"TYP_ECF_PATH"
+@ MSG_TYP_ECF_BASENAME		"TYP_ECF_BASENAME"
+@ MSG_TYP_ECF_OBJNAME		"TYP_ECF_OBJNAME"
+@ MSG_FLG_ECF_ARMEMBER		"FLG_ECF_ARMEMBER"
+
+@ MSG_GBL_ZERO			"0"
--- a/usr/src/cmd/sgs/libconv/common/lintsup.c	Sun Feb 21 21:37:22 2010 -0800
+++ b/usr/src/cmd/sgs/libconv/common/lintsup.c	Mon Feb 22 09:19:31 2010 -0700
@@ -22,7 +22,7 @@
 /* PROTOLIB1 */
 
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -66,9 +66,11 @@
 #include "dwarf_msg.h"
 #include "dynamic_msg.h"
 #include "elf_msg.h"
+#include "entry_msg.h"
 #include "globals_msg.h"
 #include "group_msg.h"
 #include "lddstub_msg.h"
+#include "map_msg.h"
 #include "phdr_msg.h"
 #include "relocate_amd64_msg.h"
 #include "relocate_i386_msg.h"
@@ -99,9 +101,11 @@
 	USE(_sgs_msg_libconv_dwarf);
 	USE(_sgs_msg_libconv_dynamic);
 	USE(_sgs_msg_libconv_elf);
+	USE(_sgs_msg_libconv_entry);
 	USE(_sgs_msg_libconv_globals);
 	USE(_sgs_msg_libconv_group);
 	USE(_sgs_msg_libconv_lddstub);
+	USE(_sgs_msg_libconv_map);
 	USE(_sgs_msg_libconv_phdr);
 	USE(_sgs_msg_libconv_relocate_amd64);
 	USE(_sgs_msg_libconv_relocate_i386);
--- a/usr/src/cmd/sgs/libconv/common/llib-lconv	Sun Feb 21 21:37:22 2010 -0800
+++ b/usr/src/cmd/sgs/libconv/common/llib-lconv	Mon Feb 22 09:19:31 2010 -0700
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 /* LINTLIBRARY */
@@ -136,9 +136,13 @@
 		    Conv_inv_buf_t *);
 const char	*conv_ehdr_vers(Word, Conv_fmt_flags_t, Conv_inv_buf_t *);
 const char	*conv_elfdata_type(Elf_Type, Conv_inv_buf_t *);
+const char	*conv_ent_flags(ec_flags_t, Conv_ent_flags_buf_t *);
+const char	*conv_ent_filcmp(Word, Conv_fmt_flags_t, Conv_inv_buf_t *);
 const char	*conv_grphdl_flags(uint_t, Conv_grphdl_flags_buf_t *);
 const char	*conv_grpdesc_flags(uint_t, Conv_grpdesc_flags_buf_t *);
 Isa_desc	*conv_isalist(void);
+const char	*conv_mapfile_version(Word, Conv_fmt_flags_t,
+		    Conv_inv_buf_t *);
 const char	*conv_phdr_flags(uchar_t, Word, Conv_fmt_flags_t,
 		    Conv_phdr_flags_buf_t *);
 const char	*conv_phdr_type(uchar_t, Half, Word, Conv_fmt_flags_t,
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/sgs/libconv/common/map.c	Mon Feb 22 09:19:31 2010 -0700
@@ -0,0 +1,52 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * String conversion routines for mapfile related items.
+ * These items are not ELF constructs. However, we have a need
+ * to display them.
+ */
+#include	<stdio.h>
+#include	<_conv.h>
+#include	<map_msg.h>
+
+const char *
+conv_mapfile_version(Word version, Conv_fmt_flags_t fmt_flags,
+    Conv_inv_buf_t *inv_buf)
+{
+	static const Msg	versions[] = {
+		MSG_VER_NONE,	MSG_VER_SYSV,	MSG_VER_SOLARIS
+	};
+#if MFV_NUM != (MFV_SOLARIS + 1)
+#error "NT_NUM has grown. Update mapfile versions[]"
+#endif
+	static const conv_ds_msg_t ds_versions = {
+	    CONV_DS_MSG_INIT(MFV_NONE, versions) };
+	static const conv_ds_t	*ds[] = { CONV_DS_ADDR(ds_versions), NULL };
+
+	return (conv_map_ds(ELFOSABI_NONE, EM_NONE, version, ds, fmt_flags,
+	    inv_buf));
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/sgs/libconv/common/map.msg	Mon Feb 22 09:19:31 2010 -0700
@@ -0,0 +1,29 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+@ MSG_VER_NONE		"none"
+@ MSG_VER_SYSV		"SysV"
+@ MSG_VER_SOLARIS	"Solaris"
--- a/usr/src/cmd/sgs/libconv/common/segments.c	Sun Feb 21 21:37:22 2010 -0800
+++ b/usr/src/cmd/sgs/libconv/common/segments.c	Mon Feb 22 09:19:31 2010 -0700
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -33,19 +33,21 @@
 #include	"segments_msg.h"
 
 #define	SEGSZ	CONV_EXPN_FIELD_DEF_PREFIX_SIZE + \
-		MSG_FLG_SG_VADDR_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
-		MSG_FLG_SG_PADDR_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
+		MSG_FLG_SG_P_VADDR_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
+		MSG_FLG_SG_P_PADDR_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
 		MSG_FLG_SG_LENGTH_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
-		MSG_FLG_SG_ALIGN_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
+		MSG_FLG_SG_P_ALIGN_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
 		MSG_FLG_SG_ROUND_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
-		MSG_FLG_SG_FLAGS_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
-		MSG_FLG_SG_TYPE_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
-		MSG_FLG_SG_ORDER_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
+		MSG_FLG_SG_P_FLAGS_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
+		MSG_FLG_SG_P_TYPE_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
+		MSG_FLG_SG_IS_ORDER_SIZE + CONV_EXPN_FIELD_DEF_SEP_SIZE + \
 		MSG_FLG_SG_NOHDR_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
 		MSG_FLG_SG_EMPTY_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
 		MSG_FLG_SG_KEY_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
+		MSG_FLG_SG_NODISABLE_SIZE + CONV_EXPN_FIELD_DEF_SEP_SIZE + \
 		MSG_FLG_SG_DISABLED_SIZE + CONV_EXPN_FIELD_DEF_SEP_SIZE + \
 		MSG_FLG_SG_PHREQ_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
+		MSG_FLG_SG_ORDERED_SIZE	+ CONV_EXPN_FIELD_DEF_SEP_SIZE + \
 		CONV_INV_BUFSIZE + CONV_EXPN_FIELD_DEF_SUFFIX_SIZE
 
 /*
@@ -64,22 +66,24 @@
 #endif
 
 const char *
-conv_seg_flags(Half flags, Conv_seg_flags_buf_t *seg_flags_buf)
+conv_seg_flags(sg_flags_t flags, Conv_seg_flags_buf_t *seg_flags_buf)
 {
 	static Val_desc vda[] = {
-		{ FLG_SG_VADDR,		MSG_FLG_SG_VADDR },
-		{ FLG_SG_PADDR,		MSG_FLG_SG_PADDR },
+		{ FLG_SG_P_VADDR,	MSG_FLG_SG_P_VADDR },
+		{ FLG_SG_P_PADDR,	MSG_FLG_SG_P_PADDR },
 		{ FLG_SG_LENGTH,	MSG_FLG_SG_LENGTH },
-		{ FLG_SG_ALIGN,		MSG_FLG_SG_ALIGN },
+		{ FLG_SG_P_ALIGN,	MSG_FLG_SG_P_ALIGN },
 		{ FLG_SG_ROUND,		MSG_FLG_SG_ROUND },
-		{ FLG_SG_FLAGS,		MSG_FLG_SG_FLAGS },
-		{ FLG_SG_TYPE,		MSG_FLG_SG_TYPE },
-		{ FLG_SG_ORDER,		MSG_FLG_SG_ORDER },
+		{ FLG_SG_P_FLAGS,	MSG_FLG_SG_P_FLAGS },
+		{ FLG_SG_P_TYPE,	MSG_FLG_SG_P_TYPE },
+		{ FLG_SG_IS_ORDER,	MSG_FLG_SG_IS_ORDER },
 		{ FLG_SG_NOHDR,		MSG_FLG_SG_NOHDR },
 		{ FLG_SG_EMPTY,		MSG_FLG_SG_EMPTY },
 		{ FLG_SG_KEY,		MSG_FLG_SG_KEY },
+		{ FLG_SG_NODISABLE,	MSG_FLG_SG_NODISABLE },
 		{ FLG_SG_DISABLED,	MSG_FLG_SG_DISABLED },
 		{ FLG_SG_PHREQ,		MSG_FLG_SG_PHREQ },
+		{ FLG_SG_ORDERED,	MSG_FLG_SG_ORDERED },
 		{ 0,			0 }
 	};
 	static CONV_EXPN_FIELD_ARG conv_arg = {
--- a/usr/src/cmd/sgs/libconv/common/segments.msg	Sun Feb 21 21:37:22 2010 -0800
+++ b/usr/src/cmd/sgs/libconv/common/segments.msg	Mon Feb 22 09:19:31 2010 -0700
@@ -20,23 +20,24 @@
 #
 
 #
-# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
-# ident	"%Z%%M%	%I%	%E% SMI"
 
-@ MSG_FLG_SG_VADDR	"FLG_SG_VADDR"
-@ MSG_FLG_SG_PADDR	"FLG_SG_PADDR"
+@ MSG_FLG_SG_P_VADDR	"FLG_SG_P_VADDR"
+@ MSG_FLG_SG_P_PADDR	"FLG_SG_P_PADDR"
 @ MSG_FLG_SG_LENGTH	"FLG_SG_LENGTH"
-@ MSG_FLG_SG_ALIGN	"FLG_SG_ALIGN"
+@ MSG_FLG_SG_P_ALIGN	"FLG_SG_P_ALIGN"
 @ MSG_FLG_SG_ROUND	"FLG_SG_ROUND"
-@ MSG_FLG_SG_FLAGS	"FLG_SG_FLAGS"
-@ MSG_FLG_SG_TYPE	"FLG_SG_TYPE"
-@ MSG_FLG_SG_ORDER	"FLG_SG_ORDER"
+@ MSG_FLG_SG_P_FLAGS	"FLG_SG_P_FLAGS"
+@ MSG_FLG_SG_P_TYPE	"FLG_SG_P_TYPE"
+@ MSG_FLG_SG_IS_ORDER	"FLG_SG_IS_ORDER"
 @ MSG_FLG_SG_NOHDR	"FLG_SG_NOHDR"
 @ MSG_FLG_SG_EMPTY	"FLG_SG_EMPTY"
 @ MSG_FLG_SG_KEY	"FLG_SG_KEY"
+@ MSG_FLG_SG_NODISABLE	"FLG_SG_NODISABLE"
 @ MSG_FLG_SG_DISABLED	"FLG_SG_DISABLED"
 @ MSG_FLG_SG_PHREQ	"FLG_SG_PHREQ"
+@ MSG_FLG_SG_ORDERED	"FLG_SG_ORDERED"
 
 @ MSG_GBL_ZERO		"0"
--- a/usr/src/cmd/sgs/libld/Makefile.com	Sun Feb 21 21:37:22 2010 -0800
+++ b/usr/src/cmd/sgs/libld/Makefile.com	Mon Feb 22 09:19:31 2010 -0700
@@ -19,7 +19,7 @@
 # CDDL HEADER END
 #
 #
-# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 
@@ -30,17 +30,19 @@
 
 COMOBJS32 =	args32.o	entry32.o	exit32.o	groups32.o \
 		ldentry32.o	ldlibs32.o	ldmachdep32.o	ldmain32.o \
-		libs32.o	files32.o	map32.o		order32.o \
-		outfile32.o	place32.o	relocate32.o	resolve32.o \
-		sections32.o	sunwmove32.o	support32.o	syms32.o \
-		update32.o	unwind32.o	version32.o	wrap32.o
+		libs32.o	files32.o	map32.o		map_core32.o \
+		map_support32.o	map_v232.o	order32.o	outfile32.o \
+		place32.o	relocate32.o	resolve32.o	sections32.o \
+		sunwmove32.o	support32.o	syms32.o	update32.o \
+		unwind32.o	version32.o	wrap32.o
 
 COMOBJS64 =	args64.o	entry64.o	exit64.o	groups64.o \
 		ldentry64.o	ldlibs64.o	ldmachdep64.o	ldmain64.o \
-		libs64.o	files64.o	map64.o		order64.o \
-		outfile64.o 	place64.o	relocate64.o	resolve64.o \
-		sections64.o	sunwmove64.o	support64.o	syms64.o \
-		update64.o	unwind64.o	version64.o	wrap64.o
+		libs64.o	files64.o	map64.o		map_core64.o \
+		map_support64.o	map_v264.o	order64.o	outfile64.o \
+ 		place64.o	relocate64.o	resolve64.o	sections64.o \
+		sunwmove64.o	support64.o	syms64.o	update64.o \
+		unwind64.o	version64.o	wrap64.o
 
 TOOLOBJS =	alist.o		assfail.o	findprime.o	string_table.o \
 		strhash.o
@@ -83,7 +85,6 @@
 include 	$(SRC)/cmd/sgs/Makefile.com
 
 SRCDIR =	../common
-ELFCAP=		$(SRC)/common/elfcap
 
 
 # Location of the shared relocation engines maintained under usr/src/uts.
@@ -94,8 +95,7 @@
 
 
 CPPFLAGS +=	-DUSE_LIBLD_MALLOC -I$(SRCBASE)/lib/libc/inc \
-		    -I$(SRCBASE)/uts/common/krtld -I$(ELFCAP) \
-		    -I$(SRCBASE)/uts/sparc \
+		    -I$(SRCBASE)/uts/common/krtld -I$(SRCBASE)/uts/sparc \
 		    $(VAR_LIBLD_CPPFLAGS)
 LDLIBS +=	$(CONVLIBDIR) $(CONV_LIB) $(LDDBGLIBDIR) $(LDDBG_LIB) \
 		    $(ELFLIBDIR) -lelf $(DLLIB) -lc
--- a/usr/src/cmd/sgs/libld/common/_libld.h	Sun Feb 21 21:37:22 2010 -0800
+++ b/usr/src/cmd/sgs/libld/common/_libld.h	Mon Feb 22 09:19:31 2010 -0700
@@ -23,7 +23,7 @@
  *	Copyright (c) 1988 AT&T
  *	  All Rights Reserved
  *
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -68,6 +68,7 @@
 	Xword		m_segm_origin;	/* Default 1st segment origin */
 	Xword		m_segm_aorigin;	/* Alternative 1st segment origin */
 	Word		m_dataseg_perm;	/* data segment permission mask */
+	Word		m_stack_perm;	/* ABI default stack permission mask */
 	Word		m_word_align;	/* alignment to use for Word sections */
 	const char	*m_def_interp;	/* Def. interpreter for dyn objects */
 
@@ -314,7 +315,7 @@
  * strings that will be created in the .dynstr, with .dynamic entries.
  */
 typedef struct {
-	char		*dft_str;	/* dynstr string */
+	const char	*dft_str;	/* dynstr string */
 	Word		dft_flag;	/* auxiliary/filtee type */
 	Half		dft_ndx;	/* eventual ndx into .dynamic */
 } Dfltr_desc;
@@ -359,8 +360,10 @@
 #define	AL_CNT_OS_ISDESCS_BA	4	/* os_isdesc: BEFORE|AFTER */
 #define	AL_CNT_OS_ISDESCS	60	/* os_isdesc: ORDERED|DEFAULT */
 
+#define	AL_CNT_SG_IS_ORDER	40	/* sg_is_order */
 #define	AL_CNT_SG_OSDESC	40	/* sg_osdescs */
 #define	AL_CNT_SG_SECORDER	40	/* sg_secorder */
+#define	AL_CNT_SG_SIZESYM	1	/* sg_sizesym */
 
 #define	AL_CNT_SDP_GOT		1	/* sd_GOTndxs */
 #define	AL_CNT_SDP_MOVE		1	/* sd_move */
@@ -533,6 +536,34 @@
 } Isd_node;
 
 /*
+ * Type used to break down an input file path into its component parts,
+ * as used by ld_place_section() to compare an input file path to
+ * entrance criteria ec_files file strings.
+ *
+ * We define a path in the usual Unix '/' separated manner, augmented
+ * with an optional archive member suffix enclosed in parenthesis:
+ *
+ *	/dir/.../dir/basename(armember)
+ *
+ * The basename is the final path component, and includes the archive
+ * member, if present. The meaning of "object name" depends on whether or
+ * not the file comes from an archive or not. If not an archive, it is the
+ * same as the basename. If an archive, it is the name of the archive member
+ * from within the file.
+ *
+ * Variables of this type are initialized with ld_place_path_info_init().
+ */
+typedef struct {
+	const char	*ppi_path;	/* Full path */
+	const char	*ppi_bname;	/* basename(ppi_path) */
+	const char	*ppi_oname;	/* object name: Not NULL terminated */
+	Boolean		ppi_isar;	/* TRUE if path has archive member */
+	size_t		ppi_path_len;	/* strlen(ppi_path) */
+	size_t		ppi_bname_len;	/* strlen(ppi_bname) */
+	size_t		ppi_oname_len;	/* strlen(ppi_oname) */
+} Place_path_info;
+
+/*
  * Local data items.
  */
 extern char		*Plibpath;
@@ -577,6 +608,7 @@
 #define	ld_bswap_Xword		ld64_bswap_Xword
 #define	ld_disp_errmsg		ld64_disp_errmsg
 #define	ld_ent_check		ld64_ent_check
+#define	ld_ent_lookup		ld64_ent_lookup
 #define	ld_exit			ld64_exit
 #define	ld_find_library		ld64_find_library
 #define	ld_finish_libs		ld64_finish_libs
@@ -593,8 +625,10 @@
 #define	ld_make_text		ld64_make_text
 #define	ld_map_out		ld64_map_out
 #define	ld_map_parse		ld64_map_parse
+#define	ld_map_post_process	ld64_map_post_process
 #define	ld_open_outfile		ld64_open_outfile
 #define	ld_os_first_isdesc	ld64_os_first_isdesc
+#define	ld_place_path_info_init	ld64_place_path_info_init
 #define	ld_place_section	ld64_place_section
 #define	ld_process_archive	ld64_process_archive
 #define	ld_process_files	ld64_process_files
@@ -610,8 +644,8 @@
 #define	ld_reloc_targval_get	ld64_reloc_targval_get
 #define	ld_reloc_targval_set	ld64_reloc_targval_set
 #define	ld_sec_validate		ld64_sec_validate
+#define	ld_seg_lookup		ld64_seg_lookup
 #define	ld_sort_ordered		ld64_sort_ordered
-#define	ld_sort_seg_list	ld64_sort_seg_list
 #define	ld_stt_section_sym_name	ld64_stt_section_sym_name
 #define	ld_sunw_ldmach		ld64_sunw_ldmach
 #define	ld_sup_atexit		ld64_sup_atexit
@@ -665,6 +699,7 @@
 #define	ld_bswap_Xword		ld32_bswap_Xword
 #define	ld_disp_errmsg		ld32_disp_errmsg
 #define	ld_ent_check		ld32_ent_check
+#define	ld_ent_lookup		ld32_ent_lookup
 #define	ld_exit			ld32_exit
 #define	ld_find_library		ld32_find_library
 #define	ld_finish_libs		ld32_finish_libs
@@ -681,8 +716,10 @@
 #define	ld_make_text		ld32_make_text
 #define	ld_map_out		ld32_map_out
 #define	ld_map_parse		ld32_map_parse
+#define	ld_map_post_process	ld32_map_post_process
 #define	ld_open_outfile		ld32_open_outfile
 #define	ld_os_first_isdesc	ld32_os_first_isdesc
+#define	ld_place_path_info_init	ld32_place_path_info_init
 #define	ld_place_section	ld32_place_section
 #define	ld_process_archive	ld32_process_archive
 #define	ld_process_files	ld32_process_files
@@ -698,8 +735,8 @@
 #define	ld_reloc_targval_get	ld32_reloc_targval_get
 #define	ld_reloc_targval_set	ld32_reloc_targval_set
 #define	ld_sec_validate		ld32_sec_validate
+#define	ld_seg_lookup		ld32_seg_lookup
 #define	ld_sort_ordered		ld32_sort_ordered
-#define	ld_sort_seg_list	ld32_sort_seg_list
 #define	ld_stt_section_sym_name	ld32_stt_section_sym_name
 #define	ld_sunw_ldmach		ld32_sunw_ldmach
 #define	ld_sup_atexit		ld32_sup_atexit
@@ -763,6 +800,8 @@
 extern void		ld_disp_errmsg(const char *, Rel_desc *, Ofl_desc *);
 
 extern void		ld_ent_check(Ofl_desc *);
+extern Ent_desc		*ld_ent_lookup(Ofl_desc *, const char *name,
+			    avl_index_t *where);
 extern int		ld_exit(Ofl_desc *);
 
 extern uintptr_t	ld_find_library(const char *, Ofl_desc *);
@@ -786,13 +825,16 @@
 extern uintptr_t	ld_make_sunwmove(Ofl_desc *, int);
 extern Is_desc		*ld_make_text(Ofl_desc *, size_t);
 extern void		ld_map_out(Ofl_desc *);
-extern uintptr_t	ld_map_parse(const char *, Ofl_desc *);
+extern Boolean		ld_map_parse(const char *, Ofl_desc *);
+extern Boolean		ld_map_post_process(Ofl_desc *);
 
 extern uintptr_t	ld_open_outfile(Ofl_desc *);
 
 extern Is_desc		*ld_os_first_isdesc(Os_desc *);
-extern Os_desc		*ld_place_section(Ofl_desc *, Is_desc *, int,
-			    const char *);
+extern Place_path_info	*ld_place_path_info_init(Ofl_desc *, Ifl_desc *,
+			    Place_path_info *);
+extern Os_desc		*ld_place_section(Ofl_desc *, Is_desc *,
+			    Place_path_info *path_info,  int, const char *);
 extern uintptr_t	ld_process_archive(const char *, int, Ar_desc *,
 			    Ofl_desc *);
 extern uintptr_t	ld_process_files(Ofl_desc *, int, char **);
@@ -802,7 +844,8 @@
 extern uintptr_t	ld_process_move(Ofl_desc *);
 extern Ifl_desc		*ld_process_open(const char *, const char *, int *,
 			    Ofl_desc *, Word, Rej_desc *);
-extern uintptr_t	ld_process_ordered(Ifl_desc *, Ofl_desc *, Word);
+extern uintptr_t	ld_process_ordered(Ofl_desc *, Ifl_desc *,
+			    Place_path_info *path_info,  Word);
 extern uintptr_t	ld_process_sym_reloc(Ofl_desc *, Rel_desc *, Rel *,
 			    Is_desc *, const char *, Word);
 
@@ -815,9 +858,10 @@
 extern int		ld_reloc_targval_set(Ofl_desc *, Rel_desc *,
 			    uchar_t *, Xword);
 
+extern Sg_desc		*ld_seg_lookup(Ofl_desc *, const char *,
+			    avl_index_t *where);
 extern void		ld_sec_validate(Ofl_desc *);
 extern uintptr_t	ld_sort_ordered(Ofl_desc *);
-extern uintptr_t	ld_sort_seg_list(Ofl_desc *);
 extern Half		ld_sunw_ldmach();
 extern void		ld_sup_atexit(Ofl_desc *, int);
 extern void		ld_sup_open(Ofl_desc *, const char **, const char **,
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/sgs/libld/common/_map.h	Mon Feb 22 09:19:31 2010 -0700
@@ -0,0 +1,367 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Local include file for libld mapfile subsystem.
+ */
+
+#ifndef	_MAP_DOT_H
+#define	_MAP_DOT_H
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+/*
+ * Macro used to size name buffer corresponding to a NULL terminated array
+ * of structures each of which contains a name string. Macro is used per-name.
+ * 2 extra characters are allowed per item to allow for a ', ' delimiter
+ * or NULL termination.
+ */
+#define	KW_NAME_SIZE(_size) (_size##_SIZE + 2)
+
+/*
+ * Variant of isspace() that excludes newline characters. Requires <ctype.h>.
+ */
+#define	isspace_nonl(_s) (isspace(_s) && ((_s) != '\n'))
+
+/*
+ * Type used to insert NULL characters in the mapfile text and later
+ * back them out and restore the original character. The mapfile text
+ * is held in a single string, so when we want to access sub-strings,
+ * it is necessary to temporarily insert NULLs to prevent the entire
+ * mapfile from that point forward being output.
+ */
+typedef struct {
+	char	*np_ptr;	/* Address patched with NULL character */
+	char	np_ch;		/* Character originally found at *np_ptr */
+} ld_map_npatch_t;
+
+/*
+ * ld_map_gettoken() uses a table of 128 bytes to determine how to
+ * process a token starting with any 7-bit ASCII value. The table is
+ * indexed by the character code, and returns one of the TK_* token values.
+ */
+typedef const char mf_tokdisp_t[128];
+
+/*
+ * The definition of an unquoted identifier differs based on the mapfile
+ * version. Rather than write a separate function to locate identifiers
+ * for each version, we use a single function that relies on a per-character
+ * table that encodes which characters can start an identifier, and which
+ * can continue one, for each supported mapfile version.
+ *
+ * Two bits are used for each version, one for the start attribute, and the
+ * other for continuation. The first two bits are not used (version 0), the
+ * next 2 are used for version 1, the following 2 for version 2, and so on.
+ */
+#define	TKID_ATTR_B_START	1
+#define	TKID_ATTR_B_CONT	2
+
+#define	TKID_ATTR_START(_ver)	(TKID_ATTR_B_START << (_ver * 2))
+#define	TKID_ATTR_CONT(_ver)	(TKID_ATTR_B_CONT << (_ver * 2))
+
+/* Convenience macros for chars that both start and continue an identifier */
+#define	TKID_ATTR(_ver) ((TKID_ATTR_B_START | TKID_ATTR_B_CONT) << (_ver * 2))
+
+/*
+ * State for a mapfile held in memory.
+ */
+typedef struct {
+	Ofl_desc	*mf_ofl;	/* Output descriptor being processed */
+	char		*mf_name;	/* Mapfile name */
+	Ifl_desc	*mf_ifl;	/* NULL, or pseudo input file */
+					/*	descriptor from ld_map_ifl() */
+	char		*mf_text;	/* Text of mapfile */
+	char		*mf_next;	/* Next char in mapfile to examine */
+	const char	*mf_tokdisp;	/* mf_tokdisp_t dispatch table to use */
+	Lineno		mf_lineno;	/* Line # within mf_text */
+	int		mf_version;	/* Mapfile syntax version */
+	int		mf_tkid_start;	/* TKID bitvalue for characters that */
+					/*	start an unquoted identifier */
+	int		mf_tkid_cont;	/* TKID bitvalue for characters that */
+					/*	continue an unquoted ident. */
+	int		mf_next_ch;	/* 0, or character read from *mf_next */
+					/*	prior to inserting NULL */
+	Aliste		mf_ec_insndx;	/* Insert index for entrance criteria */
+					/*	Each mapfile starts at the */
+					/*	top, inserting each ec in the */
+					/*	file in the order seen. */
+} Mapfile;
+
+/*
+ * A very large percentage of mapfile errors start with the
+ * calling sequence:
+ *	eprintf(ofl->ofl_lml, ERR_XXX, format, mf->mf_name,
+ *		mf->mf_lineno...)
+ * The mf_fatal() and mf_warn() varadic macros are used to supply all
+ * of boilerplate, resulting in visually simpler code.
+ *
+ * mf_fatal0()/mf_warn0() are used when the format does not require any
+ * additional arguments and the varargs list is empty. The GNU cpp has a
+ * syntax for eliminating the extra comma (, ##__VA_ARGS__), but this isn't
+ * supported by the Sun compilers yet.
+ */
+#define	mf_fatal0(_mf, _fmt) \
+	eprintf((_mf)->mf_ofl->ofl_lml, ERR_FATAL, _fmt, (_mf)->mf_name, \
+	    EC_LINENO((_mf)->mf_lineno))
+#define	mf_fatal(_mf, _fmt, ...) \
+	eprintf((_mf)->mf_ofl->ofl_lml, ERR_FATAL, _fmt, (_mf)->mf_name, \
+	    EC_LINENO((_mf)->mf_lineno), __VA_ARGS__)
+
+#define	mf_warn0(_mf, _fmt) \
+	eprintf((_mf)->mf_ofl->ofl_lml, ERR_WARNING, _fmt, (_mf)->mf_name, \
+	    EC_LINENO((_mf)->mf_lineno))
+#define	mf_warn(_mf, _fmt, ...) \
+	eprintf((_mf)->mf_ofl->ofl_lml, ERR_WARNING, _fmt, (_mf)->mf_name, \
+	    EC_LINENO((_mf)->mf_lineno), __VA_ARGS__)
+
+/* Possible return values from ld_map_gettoken */
+typedef enum {
+	TK_ERROR =	-1,	/* Error in lexical analysis */
+	TK_EOF =	0,	/* End of file: Requires TK_F_EOFOK to be set */
+				/*	or EOF results in TK_ERROR */
+	TK_STRING =	1,	/* String literal */
+	TK_COLON =	2,	/* : */
+	TK_SEMICOLON =	3,	/* ; */
+	TK_EQUAL =	4,	/* = */
+	TK_PLUSEQ =	5,	/* += */
+	TK_MINUSEQ =	6,	/* -= */
+	TK_ATSIGN =	7,	/* @ */
+	TK_DASH =	8,	/* - */
+	TK_LEFTBKT =	9,	/* { */
+	TK_RIGHTBKT =	10,	/* } */
+	TK_PIPE =	11,	/* | */
+	TK_INT =	12,	/* Integer value: Unsigned machine word */
+	TK_STAR =	13,	/* * */
+	TK_BANG =	14,	/* ! */
+
+	/*
+	 * Items below this point are for the use of ld_map_gettoken().
+	 * They indicate a character that requires the lexical analyzer
+	 * to carry out some additional computation (OPeration), resulting
+	 * in one of the simple token types above, which is returned to
+	 * the caller. The TK_OP_ tokens are implementation details that are
+	 * never returned to a caller of ld_map_gettoken().
+	 */
+	TK_OP_EOF,		/* end of file */
+	TK_OP_ILLCHR,		/* unprintable illegal character */
+	TK_OP_BADCHR,		/* printable but unexpected character */
+	TK_OP_WS,		/* whitespace */
+	TK_OP_NL,		/* newline */
+	TK_OP_SIMQUOTE,		/* simple quoting */
+	TK_OP_CQUOTE,		/* quoting with C string literal escapes */
+	TK_OP_CMT,		/* Comment */
+	TK_OP_CDIR,		/* Control directive */
+	TK_OP_NUM,		/* Decimial, hex, or octal value */
+	TK_OP_ID,		/* unquoted identifier using syntax rules */
+				/*	appropriate for mapfile version */
+	TK_OP_CEQUAL,		/* One of += or -= */
+} Token;
+
+/*
+ * Type used by ld_map_gettoken() to return values for token types that
+ * have them.
+ */
+typedef union {
+	char	*tkv_str;		/* TK_STRING */
+	struct {			/* TK_INT */
+		char	*tkvi_str;	/* String making up integer */
+		size_t	tkvi_cnt;	/* # characters in tkvi_str */
+		Xword	tkvi_value;	/* Resulting value */
+	} tkv_int;
+} ld_map_tkval_t;
+
+/*
+ * Values for gettoken() flags argument. These flags are used to
+ * alter gettoken() default behavior under certain conditions.
+ */
+#define	TK_F_EOFOK	1	/* Quietly return TK_EOF instead of normal */
+				/* 	TK_ERROR "premature EOF" error */
+#define	TK_F_STRLC	2	/* TK_STRING: Convert string to lowercase */
+#define	TK_F_KEYWORD	4	/* For directives and attributes: Disallow */
+				/*	quoted TK_STRING tokens */
+
+/*
+ * Possible return values from ld_map_strtoxword()
+ */
+typedef enum {
+	STRTOXWORD_OK,		/* Operation successful */
+	STRTOXWORD_TOOBIG,	/* Otherwise valid value is too large */
+	STRTOXWORD_BAD		/* String not recognized as an integer */
+} ld_map_strtoxword_t;
+
+/*
+ * Possible return values from ld_map_seg_insert()
+ */
+typedef enum {
+	SEG_INS_OK = 0,		/* Segment was inserted */
+	SEG_INS_FAIL = 1,	/* Segment not inserted --- fatal */
+	SEG_INS_SKIP = 2	/* Segment not inserted --- ignore */
+} ld_map_seg_ins_t;
+
+/*
+ * Enumeration of different symbol scope possible in a mapfile
+ */
+typedef enum {
+	FLG_SCOPE_HIDD,		/* symbol defined hidden/local */
+	FLG_SCOPE_DFLT,		/* symbol defined default/global */
+	FLG_SCOPE_PROT,		/* symbol defined protected/symbolic */
+	FLG_SCOPE_EXPT,		/* symbol defined exported */
+	FLG_SCOPE_SNGL,		/* symbol defined singleton */
+	FLG_SCOPE_ELIM		/* symbol defined eliminate */
+} ld_map_scope_t;
+
+/* State of a mapfile symbol version */
+typedef struct {
+	const char	*mv_name;	/* NULL, or version name */
+	Ver_desc	*mv_vdp;	/* Descriptor for version */
+	ld_map_scope_t	mv_scope;	/* Current scope type */
+	size_t		mv_errcnt;	/* Count of errors against version */
+} ld_map_ver_t;
+
+/* State of a mapfile symbol definition */
+typedef struct {
+	const char	*ms_name;	/* symbol name */
+	sd_flag_t	ms_sdflags;	/* 0 / mapfile set flags */
+	Word		ms_shndx;	/* SHN_UNDEF / mapfile set sec index */
+	uchar_t 	ms_type;	/* STT_NOTYPE / mapfile set type */
+	Addr		ms_value;	/* user set value, if ms_value_set */
+	Addr		ms_size;	/* 0 / mapfile set size */
+	const char	*ms_filtee;	/* NULL or filtee name */
+	Boolean		ms_value_set;	/* TRUE if ms_value set, even if to 0 */
+	Word		ms_dft_flag;	/* 0, or type of filter in ms_filtee */
+} ld_map_sym_t;
+
+#if	defined(_ELF64)
+
+#define	ld_map_cap_sanitize	ld64_map_cap_sanitize
+#define	ld_map_cap_set_ovflag	ld64_map_cap_set_ovflag
+#define	ld_map_dv		ld64_map_dv
+#define	ld_map_dv_entry		ld64_map_dv_entry
+#define	ld_map_gettoken		ld64_map_gettoken
+#define	ld_map_ifl		ld64_map_ifl
+#define	ld_map_parse_v1		ld64_map_parse_v1
+#define	ld_map_parse_v2		ld64_map_parse_v2
+#define	ld_map_seg_alloc	ld64_map_seg_alloc
+#define	ld_map_seg_ent_add	ld64_map_seg_ent_add
+#define	ld_map_seg_ent_files	ld64_map_seg_ent_files
+#define	ld_map_seg_index	ld64_map_seg_index
+#define	ld_map_seg_insert	ld64_map_seg_insert
+#define	ld_map_seg_lookup	ld64_map_seg_lookup
+#define	ld_map_seg_os_order_add	ld64_map_seg_os_order_add
+#define	ld_map_seg_size_symbol	ld64_map_seg_size_symbol
+#define	ld_map_seg_stack	ld64_map_seg_stack
+#define	ld_map_strtoxword	ld64_map_strtoxword
+#define	ld_map_sym_enter	ld64_map_sym_enter
+#define	ld_map_sym_filtee	ld64_map_sym_filtee
+#define	ld_map_sym_scope	ld64_map_sym_scope
+#define	ld_map_sym_autoreduce	ld64_map_sym_autoreduce
+#define	ld_map_sym_ver_fini	ld64_map_sym_ver_fini
+#define	ld_map_sym_ver_init	ld64_map_sym_ver_init
+#define	ld_map_tokenstr		ld64_map_tokenstr
+
+#else
+
+#define	ld_map_cap_sanitize	ld32_map_cap_sanitize
+#define	ld_map_cap_set_ovflag	ld32_map_cap_set_ovflag
+#define	ld_map_dv		ld32_map_dv
+#define	ld_map_dv_entry		ld32_map_dv_entry
+#define	ld_map_gettoken		ld32_map_gettoken
+#define	ld_map_ifl		ld32_map_ifl
+#define	ld_map_parse_v1		ld32_map_parse_v1
+#define	ld_map_parse_v2		ld32_map_parse_v2
+#define	ld_map_seg_alloc	ld32_map_seg_alloc
+#define	ld_map_seg_ent_add	ld32_map_seg_ent_add
+#define	ld_map_seg_ent_files	ld32_map_seg_ent_files
+#define	ld_map_seg_index	ld32_map_seg_index
+#define	ld_map_seg_insert	ld32_map_seg_insert
+#define	ld_map_seg_lookup	ld32_map_seg_lookup
+#define	ld_map_seg_os_order_add	ld32_map_seg_os_order_add
+#define	ld_map_seg_size_symbol	ld32_map_seg_size_symbol
+#define	ld_map_seg_stack	ld32_map_seg_stack
+#define	ld_map_strtoxword	ld32_map_strtoxword
+#define	ld_map_sym_enter	ld32_map_sym_enter
+#define	ld_map_sym_filtee	ld32_map_sym_filtee
+#define	ld_map_sym_scope	ld32_map_sym_scope
+#define	ld_map_sym_autoreduce	ld32_map_sym_autoreduce
+#define	ld_map_sym_ver_fini	ld32_map_sym_ver_fini
+#define	ld_map_sym_ver_init	ld32_map_sym_ver_init
+#define	ld_map_tokenstr		ld32_map_tokenstr
+
+#endif
+
+/*
+ * Core functions used to parse mapfiles
+ */
+extern void		ld_map_lowercase(char *);
+extern Token		ld_map_gettoken(Mapfile *, int, ld_map_tkval_t *);
+extern Boolean		ld_map_parse_v1(Mapfile *);
+extern Boolean		ld_map_parse_v2(Mapfile *);
+extern ld_map_strtoxword_t ld_map_strtoxword(const char *restrict,
+			    char **restrict, Xword *);
+extern const char	*ld_map_tokenstr(Token, ld_map_tkval_t *,
+			    Conv_inv_buf_t *);
+
+/*
+ * Support code shared between the different mapfile parsing code, used to
+ * provide a common implementation manipulating link-editor state.
+ */
+extern Boolean		ld_map_cap_sanitize(Mapfile *, Word, CapMask *);
+extern void		ld_map_cap_set_ovflag(Mapfile *, Word);
+extern void		*ld_map_kwfind(const char *, void *, size_t, size_t);
+extern char		*ld_map_kwnames(void *, size_t, size_t, char *, size_t);
+extern Sdf_desc		*ld_map_dv(Mapfile *, const char *);
+extern Boolean		ld_map_dv_entry(Mapfile *, Sdf_desc *, Boolean,
+			    const char *);
+extern Ifl_desc		*ld_map_ifl(Mapfile *);
+extern Sg_desc		*ld_map_seg_alloc(const char *, Word, sg_flags_t);
+extern Ent_desc		*ld_map_seg_ent_add(Mapfile *, Sg_desc *, const char *);
+extern Boolean		ld_map_seg_ent_files(Mapfile *mf, Ent_desc *,
+			    Word, const char *);
+extern Xword		ld_map_seg_index(Mapfile *, Sg_desc *);
+extern ld_map_seg_ins_t	ld_map_seg_insert(Mapfile *, dbg_state_t, Sg_desc *,
+			    avl_index_t where);
+extern Boolean		ld_map_seg_os_order_add(Mapfile *, Sg_desc *,
+			    const char *);
+extern Boolean		ld_map_seg_size_symbol(Mapfile *, Sg_desc *, Token,
+			    const char *symname);
+extern Sg_desc		*ld_map_seg_stack(Mapfile *);
+extern Boolean		ld_map_sym_enter(Mapfile *, ld_map_ver_t *,
+			    ld_map_sym_t *);
+extern void		ld_map_sym_filtee(Mapfile *, ld_map_ver_t *,
+			    ld_map_sym_t *, Word, const char *);
+extern void		ld_map_sym_scope(Mapfile *, const char *,
+			    ld_map_ver_t *);
+extern void		ld_map_sym_autoreduce(Mapfile *, ld_map_ver_t *);
+extern Boolean		ld_map_sym_ver_fini(Mapfile *, ld_map_ver_t *);
+extern Boolean		ld_map_sym_ver_init(Mapfile *, char *, ld_map_ver_t *);
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif /* _MAP_DOT_H */
--- a/usr/src/cmd/sgs/libld/common/args.c	Sun Feb 21 21:37:22 2010 -0800
+++ b/usr/src/cmd/sgs/libld/common/args.c	Mon Feb 22 09:19:31 2010 -0700
@@ -23,7 +23,7 @@
  *	Copyright (c) 1988 AT&T
  *	  All Rights Reserved
  *
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -636,46 +636,20 @@
 		return (S_ERROR);
 
 	/*
-	 * Process any mapfiles after establishing the entrance criteria as
-	 * the user may be redefining or adding sections/segments.
+	 * Process mapfiles. Mapfile can redefine or add sections/segments,
+	 * so this must come after the default entrance criteria are established
+	 * (above).
 	 */
 	if (ofl->ofl_maps) {
 		const char	*name;
 		Aliste		idx;
-		Is_desc		*isp;
 
 		for (APLIST_TRAVERSE(ofl->ofl_maps, idx, name))
-			if (ld_map_parse(name, ofl) == S_ERROR)
-				return (S_ERROR);
-
-		if (ofl->ofl_flags & FLG_OF_SEGSORT)
-			if (ld_sort_seg_list(ofl) == S_ERROR)
+			if (!ld_map_parse(name, ofl))
 				return (S_ERROR);
 
-		/*
-		 * Mapfiles may have been used to create symbol definitions
-		 * with backing storage.  Although the backing storage is
-		 * associated with an input section, the association of the
-		 * section to an output section (and segment) is initially
-		 * deferred.  Now that all mapfile processing is complete, any
-		 * entrance criteria requirements have been processed, and
-		 * these backing storage sections can be associated with the
-		 * appropriate output section (and segment).
-		 */
-		if (ofl->ofl_maptext || ofl->ofl_mapdata)
-			DBG_CALL(Dbg_sec_backing(ofl->ofl_lml));
-
-		for (APLIST_TRAVERSE(ofl->ofl_maptext, idx, isp)) {
-			if (ld_place_section(ofl, isp,
-			    ld_targ.t_id.id_text, NULL) == (Os_desc *)S_ERROR)
-				return (S_ERROR);
-		}
-
-		for (APLIST_TRAVERSE(ofl->ofl_mapdata, idx, isp)) {
-			if (ld_place_section(ofl, isp,
-			    ld_targ.t_id.id_data, NULL) == (Os_desc *)S_ERROR)
-				return (S_ERROR);
-		}
+		if (!ld_map_post_process(ofl))
+			return (S_ERROR);
 	}
 
 	/*
@@ -1934,10 +1908,10 @@
 			return (S_ERROR);
 
 	/*
-	 * If segment ordering was specified (using mapfile) verify things
-	 * are ok.
+	 * If input section ordering was specified within some segment
+	 * using a mapfile, verify that the expected sections were seen.
 	 */
-	if (ofl->ofl_flags & FLG_OF_SEGORDER)
+	if (ofl->ofl_flags & FLG_OF_IS_ORDER)
 		ld_ent_check(ofl);
 
 	return (1);
--- a/usr/src/cmd/sgs/libld/common/debug.c	Sun Feb 21 21:37:22 2010 -0800
+++ b/usr/src/cmd/sgs/libld/common/debug.c	Mon Feb 22 09:19:31 2010 -0700
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -122,9 +122,11 @@
 	}
 
 	/*
-	 * Now that the output file is established, generate help
-	 * output if the user specified the debug help token.
+	 * Now that the output file is established, identify the linker
+	 * package, and generate help output if the user specified the
+	 * debug help token.
 	 */
+	Dbg_version();
 	if (dbg_desc->d_extra & DBG_E_HELP)
 		Dbg_help();
 
--- a/usr/src/cmd/sgs/libld/common/entry.c	Sun Feb 21 21:37:22 2010 -0800
+++ b/usr/src/cmd/sgs/libld/common/entry.c	Mon Feb 22 09:19:31 2010 -0700
@@ -23,7 +23,7 @@
  *	Copyright (c) 1988 AT&T
  *	  All Rights Reserved
  *
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -36,16 +36,15 @@
 #include	"_libld.h"
 
 /*
- * The loader uses a `segment descriptor' list to describe the output
- * segments it can potentially create. This list is initially seeded
- * using the templates contained in the sg_desc[] array below. Additional
- * segments may be added using a mapfile.
+ * The link-editor uses a segment descriptor list to describe the program
+ * headers, and related output segments, it can potentially create. This
+ * list is initially seeded using the templates contained in the sg_desc
+ * array below. Additional segments may be added using a mapfile.
  *
- * The entries in sg_desc[] must be put in the order defined by the
- * Segment_id enum, such that a given LD_XXX value can serve as
- * an index into sg_desc[] for the corresponding descriptor.
+ * The entries in sg_desc must be put in the order defined by the
+ * Segment_id enum.
  *
- * The entries in sg_desc[] are initialized using the SG_DESC_INIT macro
+ * The entries in sg_desc are initialized using the SG_DESC_INIT macro
  * for two reasons:
  *
  *	1) The first field of the Sg_desc struct is a program header
@@ -54,110 +53,275 @@
  *		to handle this transparently.
  *	2) Most of the fields in the Sg_desc entries are set to 0.
  *		Use of a macro allows us to hide the clutter.
+ *
+ * If a given program header can be referenced via an entrance criteria
+ * (i.e. can serve as a segment), then it must be given a unique sg_name.
+ * Program headers that cannot be a segment (PHDR, INTERP, DYNAMIC, etc)
+ * must have a NULL sg_name --- their program header type identifies them.
  */
 #ifdef _ELF64
 #define	SG_DESC_INIT(id, p_type, p_flags, sg_name, sg_flags) \
 	{ id, { p_type, p_flags, 0, 0, 0, 0, 0, 0}, \
-	    sg_name, 0, 0, NULL, NULL, sg_flags, NULL, 0, NULL}
+	    sg_name, 0, 0, NULL, NULL, NULL, sg_flags, NULL, 0, NULL}
 #else
 #define	SG_DESC_INIT(id, p_type, p_flags, sg_name, sg_flags) \
 	{ id, { p_type, 0, 0, 0, 0, 0, p_flags, 0}, \
-	    sg_name, 0, 0, NULL, NULL, sg_flags, NULL, 0, NULL}
+	    sg_name, 0, 0, NULL, NULL, NULL, sg_flags, NULL, 0, NULL}
 #endif
 
-static const Sg_desc sg_desc[LD_NUM] = {
-	SG_DESC_INIT(LD_PHDR, PT_PHDR, PF_R + PF_X, MSG_ORIG(MSG_ENT_PHDR),
-	    (FLG_SG_TYPE | FLG_SG_FLAGS)),
-
-	SG_DESC_INIT(LD_INTERP, PT_INTERP, PF_R, MSG_ORIG(MSG_ENT_INTERP),
-	    (FLG_SG_TYPE | FLG_SG_FLAGS)),
+/*
+ * Predefined segment descriptors:
+ *
+ * The C language guarantees that a structure containing only fields of
+ * identical type is indistinguishable from a simple array containing
+ * the same number of items of the same type. They will have the same
+ * size, alignment, and internal layout:
+ *
+ * -	A pointer to one is equivalent to a pointer to the other, and you
+ *	can cast safely between them.
+ *
+ * -	You can put both into a union, and access the elements within
+ *	either way (by index, or by name).
+ *
+ * We use this fact here to create an "array" of predefined segment
+ * descriptors, assigning each one a mnemonic name that can be used to point
+ * at it from a predefined entrance criteria descriptor (below). These
+ * segments are positioned in the default order that will result in the
+ * output object, unless a mapfile alters things.
+ */
+typedef struct {
+	Sg_desc	psg_phdr;
+	Sg_desc psg_interp;
+	Sg_desc psg_sunwcap;
+	Sg_desc psg_text;
+	Sg_desc psg_data;
+	Sg_desc psg_bss;
+#if	defined(_ELF64)
+	Sg_desc	psg_lrodata;	/* (amd64-only) */
+	Sg_desc psg_ldata;	/* (amd64-only) */
+#endif
+	Sg_desc	psg_dynamic;
+	Sg_desc	psg_sunwdtrace;
+	Sg_desc	psg_tls;
+	Sg_desc	psg_unwind;
+	Sg_desc	psg_sunwstack;
+	Sg_desc	psg_note;
+	Sg_desc	psg_extra;
+} predef_seg_t;
 
-	SG_DESC_INIT(LD_SUNWCAP, PT_SUNWCAP, PF_R, MSG_ORIG(MSG_ENT_SUNWCAP),
-	    (FLG_SG_TYPE | FLG_SG_FLAGS)),
+static const size_t predef_seg_nelts =
+	(sizeof (predef_seg_t) / sizeof (Sg_desc));
 
-	SG_DESC_INIT(LD_TEXT, PT_LOAD, PF_R + PF_X, MSG_ORIG(MSG_ENT_TEXT),
-	    (FLG_SG_TYPE | FLG_SG_FLAGS)),
+static predef_seg_t sg_desc = {
+	/* psg_phdr */
+	SG_DESC_INIT(SGID_PHDR, PT_PHDR, PF_R + PF_X, NULL,
+	    (FLG_SG_P_TYPE | FLG_SG_P_FLAGS)),
+
+	/* psg_interp */
+	SG_DESC_INIT(SGID_INTERP, PT_INTERP, PF_R, NULL,
+	    (FLG_SG_P_TYPE | FLG_SG_P_FLAGS)),
 
-	SG_DESC_INIT(LD_DATA, PT_LOAD, 0, MSG_ORIG(MSG_ENT_DATA),
-	    (FLG_SG_TYPE | FLG_SG_FLAGS)),
+	/* psg_sunwcap */
+	SG_DESC_INIT(SGID_SUNWCAP, PT_SUNWCAP, PF_R, NULL,
+	    (FLG_SG_P_TYPE | FLG_SG_P_FLAGS)),
+
+	/* psg_text */
+	SG_DESC_INIT(SGID_TEXT, PT_LOAD, PF_R + PF_X, MSG_ORIG(MSG_ENT_TEXT),
+	    (FLG_SG_P_TYPE | FLG_SG_P_FLAGS)),
 
-	SG_DESC_INIT(LD_BSS, PT_LOAD, 0, MSG_ORIG(MSG_ENT_BSS),
-	    (FLG_SG_TYPE | FLG_SG_FLAGS | FLG_SG_DISABLED)),
+	/* psg_data */
+	SG_DESC_INIT(SGID_DATA, PT_LOAD, 0, MSG_ORIG(MSG_ENT_DATA),
+	    (FLG_SG_P_TYPE | FLG_SG_P_FLAGS)),
+
+	/* psg_bss */
+	SG_DESC_INIT(SGID_BSS, PT_LOAD, 0, MSG_ORIG(MSG_ENT_BSS),
+	    (FLG_SG_P_TYPE | FLG_SG_P_FLAGS | FLG_SG_DISABLED)),
 
 #if	defined(_ELF64)
-	/* (amd64-only) */
-	SG_DESC_INIT(LD_LRODATA, PT_LOAD, PF_R, MSG_ORIG(MSG_ENT_LRODATA),
-	    (FLG_SG_TYPE | FLG_SG_FLAGS)),
+	/* psg_lrodata (amd64-only ) */
+	SG_DESC_INIT(SGID_LRODATA, PT_LOAD, PF_R, MSG_ORIG(MSG_ENT_LRODATA),
+	    (FLG_SG_P_TYPE | FLG_SG_P_FLAGS)),
 
-	/* (amd64-only) */
-	SG_DESC_INIT(LD_LDATA, PT_LOAD, 0, MSG_ORIG(MSG_ENT_LDATA),
-	    (FLG_SG_TYPE | FLG_SG_FLAGS)),
+	/* psg_ldata (amd64-only ) */
+	SG_DESC_INIT(SGID_LDATA, PT_LOAD, 0, MSG_ORIG(MSG_ENT_LDATA),
+	    (FLG_SG_P_TYPE | FLG_SG_P_FLAGS)),
 #endif
-	SG_DESC_INIT(LD_DYN, PT_DYNAMIC, 0, MSG_ORIG(MSG_ENT_DYNAMIC),
-	    (FLG_SG_TYPE | FLG_SG_FLAGS)),
+	/* psg_dynamic */
+	SG_DESC_INIT(SGID_DYN, PT_DYNAMIC, 0, NULL,
+	    (FLG_SG_P_TYPE | FLG_SG_P_FLAGS)),
+
+	/* psg_sunwdtrace */
+	SG_DESC_INIT(SGID_DTRACE, PT_SUNWDTRACE, 0, NULL,
+	    (FLG_SG_P_TYPE | FLG_SG_P_FLAGS)),
+
+	/* psg_tls */
+	SG_DESC_INIT(SGID_TLS, PT_TLS, PF_R, NULL,
+	    (FLG_SG_P_TYPE | FLG_SG_P_FLAGS)),
 
-	SG_DESC_INIT(LD_DTRACE, PT_SUNWDTRACE, 0, MSG_ORIG(MSG_ENT_DTRACE),
-	    (FLG_SG_TYPE | FLG_SG_FLAGS)),
+	/* psg_unwind */
+	SG_DESC_INIT(SGID_UNWIND, PT_SUNW_UNWIND, PF_R, NULL,
+	    (FLG_SG_P_TYPE | FLG_SG_P_FLAGS)),
 
-	SG_DESC_INIT(LD_TLS, PT_TLS, PF_R, MSG_ORIG(MSG_ENT_TLS),
-	    (FLG_SG_TYPE | FLG_SG_FLAGS)),
+	/* psg_sunwstack */
+	SG_DESC_INIT(SGID_SUNWSTACK, PT_SUNWSTACK, 0, NULL,
+	    (FLG_SG_P_TYPE | FLG_SG_P_FLAGS | FLG_SG_DISABLED)),
+
+	/* psg_note */
+	SG_DESC_INIT(SGID_NOTE, PT_NOTE, 0, MSG_ORIG(MSG_ENT_NOTE),
+	    FLG_SG_P_TYPE),
 
-	SG_DESC_INIT(LD_UNWIND, PT_SUNW_UNWIND, PF_R, MSG_ORIG(MSG_ENT_UNWIND),
-	    (FLG_SG_TYPE | FLG_SG_FLAGS)),
-
-	SG_DESC_INIT(LD_NOTE, PT_NOTE, 0, MSG_ORIG(MSG_ENT_NOTE), FLG_SG_TYPE),
-
-	SG_DESC_INIT(LD_EXTRA, PT_NULL, 0, MSG_ORIG(MSG_ENT_EXTRA), FLG_SG_TYPE)
+	/*
+	 * psg_extra
+	 *
+	 * This segment is referenced by the final entrance criteria descriptor
+	 * to catch any segment not otherwise placed. It cannot be disabled
+	 * via a mapfile.
+	 */
+	SG_DESC_INIT(SGID_EXTRA, PT_NULL, 0, MSG_ORIG(MSG_ENT_EXTRA),
+	    (FLG_SG_P_TYPE | FLG_SG_NODISABLE))
 };
+#undef SG_DESC_INIT
 
 /*
  * The processing of input files by the link-editor involves matching the
- * files sections to an `entrance descriptor definition'.  The entrance
- * criteria can be modified further using a mapfile.  Each entrance criteria
- * is associated with a segment descriptor, thus a mapping of input sections
- * to output segments is maintained.
+ * input file sections against an ordered list of entrance criteria
+ * descriptors. The following template defines the built in entrance criteria
+ * list. This list can be augmented using a mapfile. Each entrance criteria
+ * is associated with a segment descriptor, providing the means for mapping
+ * input sections to output segments.
  *
- * Note the trick used for the ec_segment field, which is supposed to be a
- * pointer to a segment descriptor.  We initialize this with the index of the
- * descriptor, and then turn it into an actual pointer at runtime, once memory
- * has been allocated and the templates copied.
+ * As with the segment descriptors, the EC_DESC_INIT macro is used
+ * to reduce boilerplate clutter.
  */
+#define	EC_DESC_INIT(ec_type, ec_attrmask, ec_attrbits, _seg_field, ec_flags) \
+	{ NULL, NULL, NULL, ec_type, ec_attrmask, ec_attrbits, \
+	    &sg_desc.psg_ ## _seg_field, 0, FLG_EC_BUILTIN | ec_flags }
+
 static const Ent_desc	ent_desc[] = {
-	{NULL, MSG_ORIG(MSG_ENT_NOTE), SHT_NOTE, 0, 0,
-		(Sg_desc *)LD_NOTE, 0, FLG_EC_BUILTIN},
+	EC_DESC_INIT(SHT_NOTE, 0, 0, note, 0),
+
+
+#if	defined(_ELF64)		/* (amd64-only) */
+	EC_DESC_INIT(0, SHF_ALLOC + SHF_WRITE + SHF_AMD64_LARGE,
+	    SHF_ALLOC + SHF_AMD64_LARGE, lrodata, 0),
+#endif
+	EC_DESC_INIT(0, SHF_ALLOC + SHF_WRITE, SHF_ALLOC, text, 0),
+
+	EC_DESC_INIT(SHT_NOBITS, SHF_ALLOC + SHF_WRITE, SHF_ALLOC + SHF_WRITE,
+	    bss, 0),
 
 #if	defined(_ELF64)		/* (amd64-only) */
-	{NULL, MSG_ORIG(MSG_ENT_LRODATA), NULL,
-		SHF_ALLOC + SHF_WRITE + SHF_AMD64_LARGE,
-		SHF_ALLOC + SHF_AMD64_LARGE,
-		(Sg_desc *)LD_LRODATA, 0, FLG_EC_BUILTIN},
+	EC_DESC_INIT(SHT_NOBITS, SHF_ALLOC + SHF_WRITE + SHF_AMD64_LARGE,
+	    SHF_ALLOC + SHF_WRITE + SHF_AMD64_LARGE, data, 0),
+
+	EC_DESC_INIT(0, SHF_ALLOC + SHF_WRITE + SHF_AMD64_LARGE,
+	    SHF_ALLOC + SHF_WRITE + SHF_AMD64_LARGE, ldata, 0),
 #endif
-	{NULL, MSG_ORIG(MSG_ENT_TEXT), NULL,
-		SHF_ALLOC + SHF_WRITE, SHF_ALLOC,
-		(Sg_desc *)LD_TEXT, 0, FLG_EC_BUILTIN},
+	EC_DESC_INIT(0, SHF_ALLOC + SHF_WRITE, SHF_ALLOC + SHF_WRITE, data, 0),
+
+	/*
+	 * Final catchall rule sends remaining sections to "extra"
+	 * NULL segment, which has been tagged as FLG_SG_NODISABLE,
+	 * and which will therefore always accept them.
+	 */
+	EC_DESC_INIT(0, 0, 0, extra, FLG_EC_CATCHALL)
+};
+#undef EC_DESC_INIT
 
-	{NULL, MSG_ORIG(MSG_ENT_BSS), SHT_NOBITS,
-		SHF_ALLOC + SHF_WRITE, SHF_ALLOC + SHF_WRITE,
-		(Sg_desc *)LD_BSS, 0, FLG_EC_BUILTIN},
+/*
+ * AVL comparison function for Sg_desc items in ofl_segs_avl.
+ *
+ * entry:
+ *	n1, n2 - pointers to nodes to be compared
+ *
+ * exit:
+ *	Returns -1 if (n1 < n2), 0 if they are equal, and 1 if (n1 > n2)
+ */
+static int
+ofl_segs_avl_cmp(const void *n1, const void *n2)
+{
+	int		rc;
+
+	rc = strcmp(((Sg_desc *)n1)->sg_name, ((Sg_desc *)n2)->sg_name);
+
+	if (rc > 0)
+		return (1);
+	if (rc < 0)
+		return (-1);
+	return (0);
+}
+
+/*
+ * AVL comparison function for Ent_desc items in ofl_ents_avl.
+ *
+ * entry:
+ *	n1, n2 - pointers to nodes to be compared
+ *
+ * exit:
+ *	Returns -1 if (n1 < n2), 0 if they are equal, and 1 if (n1 > n2)
+ */
+static int
+ofl_ents_avl_cmp(const void *n1, const void *n2)
+{
+	int		rc;
 
-#if	defined(_ELF64)		/* (amd64-only) */
-	{NULL, MSG_ORIG(MSG_ENT_LBSS), SHT_NOBITS,
-		SHF_ALLOC + SHF_WRITE + SHF_AMD64_LARGE,
-		SHF_ALLOC + SHF_WRITE + SHF_AMD64_LARGE,
-		(Sg_desc *)LD_DATA, 0, FLG_EC_BUILTIN},
+	/*
+	 * There are entrance criteria nodes with NULL pointer names,
+	 * but they are never entered into the AVL tree. Hence, we can
+	 * assume that both nodes have names.
+	 */
+	rc = strcmp(((Ent_desc *)n1)->ec_name, ((Ent_desc *)n2)->ec_name);
+
+	if (rc > 0)
+		return (1);
+	if (rc < 0)
+		return (-1);
+	return (0);
+}
+
+/*
+ * Lookup a segment descriptor by name.
+ *
+ * entry:
+ *	ofl - Output descriptor
+ *	name - Name of desired segment
+ *
+ * exit:
+ *	On success, returns pointer to descriptor. On failure, returns NULL.
+ */
+Sg_desc *
+ld_seg_lookup(Ofl_desc *ofl, const char *name, avl_index_t *where)
+{
+	Sg_desc		sg;
 
-	{NULL, MSG_ORIG(MSG_ENT_LDATA), NULL,
-		SHF_ALLOC + SHF_WRITE + SHF_AMD64_LARGE,
-		SHF_ALLOC + SHF_WRITE + SHF_AMD64_LARGE,
-		(Sg_desc *)LD_LDATA, 0, FLG_EC_BUILTIN},
-#endif
-	{NULL, MSG_ORIG(MSG_ENT_DATA), NULL,
-		SHF_ALLOC + SHF_WRITE, SHF_ALLOC + SHF_WRITE,
-		(Sg_desc *)LD_DATA, 0, FLG_EC_BUILTIN},
+	sg.sg_name = name;
+	return (avl_find(&ofl->ofl_segs_avl, &sg, where));
+}
+
 
-	{NULL, MSG_ORIG(MSG_ENT_EXTRA), 0, 0, 0,
-		(Sg_desc *)LD_EXTRA, 0, FLG_EC_BUILTIN}
-};
+/*
+ * Look up an entrance criteria record by name
+ *
+ * entry:
+ *	mf - Mapfile descriptor
+ *	name - Name of entrance criteria to locate
+ *
+ * exit:
+ *	On success, a pointer to the entrace criteria record is
+ *	returned. On failure, NULL is returned.
+ *
+ * note:
+ *	Entrance criteria are not required to have names. Only
+ *	named entrance criteria can be looked up via this method.
+ */
+Ent_desc *
+ld_ent_lookup(Ofl_desc *ofl, const char *name, avl_index_t *where)
+{
+	Ent_desc	en;
+
+	en.ec_name = name;
+	return (avl_find(&ofl->ofl_ents_avl, &en, where));
+}
 
 /*
  * Initialize new entrance and segment descriptors and add them as lists to
@@ -166,7 +330,8 @@
 uintptr_t
 ld_ent_setup(Ofl_desc *ofl, Xword segalign)
 {
-	const Ent_desc	*oenp;
+	Ent_desc	*enp;
+	predef_seg_t	*psegs;
 	Sg_desc		*sgp;
 	size_t		idx;
 
@@ -185,6 +350,15 @@
 	avl_create(&ofl->ofl_symavl, &ld_sym_avl_comp, sizeof (Sym_avlnode),
 	    SGSOFFSETOF(Sym_avlnode, sav_node));
 
+	/* Initialize segment AVL tree */
+	avl_create(&ofl->ofl_segs_avl, ofl_segs_avl_cmp,
+	    sizeof (Sg_desc), SGSOFFSETOF(Sg_desc, sg_avlnode));
+
+	/* Initialize entrance criteria AVL tree */
+	avl_create(&ofl->ofl_ents_avl, ofl_ents_avl_cmp, sizeof (Ent_desc),
+	    SGSOFFSETOF(Ent_desc, ec_avlnode));
+
+
 	/*
 	 * Allocate and initialize writable copies of both the entrance and
 	 * segment descriptors.
@@ -193,12 +367,13 @@
 	 * elements than are needed. For now, we are willing to overallocate
 	 * a small amount to simplify the code.
 	 */
-	if ((sgp = libld_malloc(sizeof (sg_desc))) == NULL)
+	if ((psegs = libld_malloc(sizeof (sg_desc))) == NULL)
 		return (S_ERROR);
-	(void) memcpy(sgp, sg_desc, sizeof (sg_desc));
+	(void) memcpy(psegs, &sg_desc, sizeof (sg_desc));
+	sgp = (Sg_desc *) psegs;
 
 	/*
-	 * The data segment permissions can differ:
+	 * The data segment and stack permissions can differ:
 	 *
 	 *	- Architecural/ABI per-platform differences
 	 *	- Whether the object is built statically or dynamically
@@ -206,16 +381,17 @@
 	 * Those segments so affected have their program header flags
 	 * set here at runtime, rather than in the sg_desc templates above.
 	 */
-	sgp[LD_DATA].sg_phdr.p_flags = ld_targ.t_m.m_dataseg_perm;
-	sgp[LD_BSS].sg_phdr.p_flags = ld_targ.t_m.m_dataseg_perm;
-	sgp[LD_DYN].sg_phdr.p_flags = ld_targ.t_m.m_dataseg_perm;
-	sgp[LD_DTRACE].sg_phdr.p_flags = ld_targ.t_m.m_dataseg_perm;
+	psegs->psg_data.sg_phdr.p_flags = ld_targ.t_m.m_dataseg_perm;
+	psegs->psg_bss.sg_phdr.p_flags = ld_targ.t_m.m_dataseg_perm;
+	psegs->psg_dynamic.sg_phdr.p_flags = ld_targ.t_m.m_dataseg_perm;
+	psegs->psg_sunwdtrace.sg_phdr.p_flags = ld_targ.t_m.m_dataseg_perm;
 #if	defined(_ELF64)
-	sgp[LD_LDATA].sg_phdr.p_flags = ld_targ.t_m.m_dataseg_perm;
-	sgp[LD_DTRACE].sg_phdr.p_flags |= PF_X;
+	psegs->psg_ldata.sg_phdr.p_flags = ld_targ.t_m.m_dataseg_perm;
+	psegs->psg_sunwdtrace.sg_phdr.p_flags |= PF_X;
 #endif
+	psegs->psg_sunwstack.sg_phdr.p_flags = ld_targ.t_m.m_stack_perm;
 	if ((ofl->ofl_flags & FLG_OF_DYNAMIC) == 0)
-		sgp[LD_DATA].sg_phdr.p_flags |= PF_X;
+		psegs->psg_data.sg_phdr.p_flags |= PF_X;
 
 	/*
 	 * Traverse the new entrance descriptor list converting the segment
@@ -223,45 +399,82 @@
 	 * descriptor list.  Add each entrance descriptor to the output file
 	 * list.
 	 */
-	for (idx = 0, oenp = ent_desc;
-	    idx < (sizeof (ent_desc) / sizeof (ent_desc[0])); idx++, oenp++) {
-		Ent_desc	*nenp;
+	if ((enp = libld_malloc(sizeof (ent_desc))) == NULL)
+		return (S_ERROR);
+	(void) memcpy(enp, ent_desc, sizeof (ent_desc));
+	for (idx = 0; idx < (sizeof (ent_desc) / sizeof (ent_desc[0])); idx++,
+	    enp++) {
 
 #if	defined(_ELF64)
 		/* Don't use the amd64 entry conditions for non-amd64 targets */
-		if ((oenp->ec_attrmask & SHF_AMD64_LARGE) &&
+		if ((enp->ec_attrmask & SHF_AMD64_LARGE) &&
 		    (ld_targ.t_m.m_mach != EM_AMD64))
 			continue;
 #endif
-		if ((nenp = alist_append(&(ofl->ofl_ents), oenp,
-		    sizeof (Ent_desc), AL_CNT_OFL_ENTRANCE)) == NULL)
+		if (aplist_append(&ofl->ofl_ents, enp,
+		    AL_CNT_OFL_ENTRANCE) == NULL)
 			return (S_ERROR);
 
-		nenp->ec_segment = &sgp[(long)oenp->ec_segment];
+		/*
+		 * The segment pointer is currently pointing at a template
+		 * segment descriptor in sg_desc. Compute its array index,
+		 * and then use that index to compute the address of the
+		 * corresponding descriptor in the writable copy.
+		 */
+		enp->ec_segment =
+		    &sgp[(enp->ec_segment - (Sg_desc *) &sg_desc)];
 	}
 
 	/*
-	 * Traverse the new segment descriptor list adding each entry to the
-	 * segment descriptor list.  For each loadable segment initialize
-	 * a default alignment (ld(1) and ld.so.1 initialize this differently).
+	 * Add each segment descriptor to the segment descriptor list. The
+	 * ones with non-NULL sg_name are also entered into the AVL tree.
+	 * For each loadable segment initialize a default alignment. Note
+	 * that ld(1) and ld.so.1 initialize this differently.
 	 */
-	for (idx = 0; idx < LD_NUM; idx++, sgp++) {
+	for (idx = 0; idx < predef_seg_nelts; idx++, sgp++) {
 		Phdr	*phdr = &(sgp->sg_phdr);
 
 #if	defined(_ELF64)
 		/* Ignore amd64 segment templates for non-amd64 targets */
-		switch (idx) {
-		case LD_LRODATA:
-		case LD_LDATA:
+		switch (sgp->sg_id) {
+		case SGID_LRODATA:
+		case SGID_LDATA:
 			if ((ld_targ.t_m.m_mach != EM_AMD64))
 				continue;
 		}
 #endif
+		if (phdr->p_type == PT_LOAD)
+			phdr->p_align = segalign;
+
 		if ((aplist_append(&ofl->ofl_segs, sgp,
 		    AL_CNT_SEGMENTS)) == NULL)
 			return (S_ERROR);
-		if (phdr->p_type == PT_LOAD)
-			phdr->p_align = segalign;
+
+#ifdef NDEBUG			/* assert() is enabled */
+		/*
+		 * Enforce the segment name rule: Any segment that can
+		 * be referenced by an entrance descriptor must have
+		 * a name. Any segment that cannot, must have a NULL
+		 * name pointer.
+		 */
+		switch (phdr->p_type) {
+		case PT_LOAD:
+		case PT_NOTE:
+		case PT_NULL:
+			assert(sgp->sg_name != NULL);
+			break;
+		default:
+			assert(sgp->sg_name == NULL);
+			break;
+		}
+#endif
+
+		/*
+		 * Add named segment descriptors to the AVL tree to
+		 * provide O(logN) lookups.
+		 */
+		if (sgp->sg_name != NULL)
+			avl_add(&ofl->ofl_segs_avl, sgp);
 	}
 
 	return (1);
--- a/usr/src/cmd/sgs/libld/common/files.c	Sun Feb 21 21:37:22 2010 -0800
+++ b/usr/src/cmd/sgs/libld/common/files.c	Mon Feb 22 09:19:31 2010 -0700
@@ -23,7 +23,7 @@
  *	Copyright (c) 1988 AT&T
  *	  All Rights Reserved
  *
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -240,15 +240,17 @@
 static void
 sf1_cap(Ofl_desc *ofl, Xword val, Ifl_desc *ifl, Is_desc *cisp)
 {
+#define	FP_FLAGS	(SF1_SUNW_FPKNWN | SF1_SUNW_FPUSED)
+
 	Xword	badval;
 
 	/*
 	 * If a mapfile has established definitions to override any input
 	 * capabilities, ignore any new input capabilities.
 	 */
-	if (ofl->ofl_flags1 & FLG_OF1_OVSFCAP) {
-		Dbg_cap_sec_entry(ofl->ofl_lml, DBG_CAP_IGNORE, CA_SUNW_SF_1,
-		    val, ld_targ.t_m.m_mach);
+	if (ofl->ofl_flags1 & FLG_OF1_OVSFCAP1) {
+		DBG_CALL(Dbg_cap_entry(ofl->ofl_lml, DBG_STATE_IGNORED,
+		    CA_SUNW_SF_1, val, ld_targ.t_m.m_mach));
 		return;
 	}
 
@@ -284,7 +286,7 @@
 		    EC_XWORD(badval));
 		val &= SF1_SUNW_MASK;
 	}
-	if ((val & (SF1_SUNW_FPKNWN | SF1_SUNW_FPUSED)) == SF1_SUNW_FPUSED) {
+	if ((val & FP_FLAGS) == SF1_SUNW_FPUSED) {
 		eprintf(ofl->ofl_lml, ERR_WARNING, MSG_INTL(MSG_FIL_BADSF1),
 		    ifl->ifl_name, EC_WORD(cisp->is_scnndx), cisp->is_name,
 		    EC_XWORD(val));
@@ -307,7 +309,8 @@
 		 * The runtime linker will refuse to use this dependency.
 		 */
 		if ((val & SF1_SUNW_ADDR32) && (ofl->ofl_flags & FLG_OF_EXEC) &&
-		    ((ofl->ofl_sfcap_1 & SF1_SUNW_ADDR32) == 0)) {
+		    ((ofl->ofl_ocapset.c_sf_1.cm_value &
+		    SF1_SUNW_ADDR32) == 0)) {
 			eprintf(ofl->ofl_lml, ERR_WARNING,
 			    MSG_INTL(MSG_FIL_EXADDR32SF1), ifl->ifl_name,
 			    EC_WORD(cisp->is_scnndx), cisp->is_name);
@@ -316,35 +319,49 @@
 		return;
 	}
 
-	Dbg_cap_sec_entry(ofl->ofl_lml, DBG_CAP_OLD, CA_SUNW_SF_1,
-	    ofl->ofl_sfcap_1, ld_targ.t_m.m_mach);
-	Dbg_cap_sec_entry(ofl->ofl_lml, DBG_CAP_NEW, CA_SUNW_SF_1,
-	    val, ld_targ.t_m.m_mach);
+	if (DBG_ENABLED) {
+		Dbg_cap_entry2(ofl->ofl_lml, DBG_STATE_CURRENT, CA_SUNW_SF_1,
+		    &ofl->ofl_ocapset.c_sf_1, ld_targ.t_m.m_mach);
+		Dbg_cap_entry(ofl->ofl_lml, DBG_STATE_NEW, CA_SUNW_SF_1,
+		    val, ld_targ.t_m.m_mach);
+	}
 
 	/*
 	 * Determine the resolution of the present frame pointer and the
 	 * new input relocatable objects frame pointer.
 	 */
-	if ((ofl->ofl_sfcap_1 & (SF1_SUNW_FPKNWN | SF1_SUNW_FPUSED)) ==
-	    (SF1_SUNW_FPKNWN | SF1_SUNW_FPUSED)) {
+	if ((ofl->ofl_ocapset.c_sf_1.cm_value & FP_FLAGS) == FP_FLAGS) {
 		/*
 		 * If the new relocatable object isn't using a frame pointer,
 		 * reduce the present state to unused.
 		 */
-		if ((val & (SF1_SUNW_FPKNWN | SF1_SUNW_FPUSED)) !=
-		    (SF1_SUNW_FPKNWN | SF1_SUNW_FPUSED))
-			ofl->ofl_sfcap_1 &= ~SF1_SUNW_FPUSED;
+		if ((val & FP_FLAGS) != FP_FLAGS)
+			ofl->ofl_ocapset.c_sf_1.cm_value &= ~SF1_SUNW_FPUSED;
+
+		/*
+		 * Having processed the frame pointer bits, remove them from
+		 * the value so they don't get OR'd in below.
+		 */
+		val &= ~FP_FLAGS;
 
-	} else if ((ofl->ofl_sfcap_1 & SF1_SUNW_FPKNWN) == 0) {
+	} else if ((ofl->ofl_ocapset.c_sf_1.cm_value & SF1_SUNW_FPKNWN) == 0) {
 		/*
-		 * If the present state is unknown, take the new relocatable
-		 * object frame pointer usage.
+		 * If the present frame pointer state is unknown, mask it out
+		 * and allow the values from the new relocatable object
+		 * to overwrite them.
 		 */
-		ofl->ofl_sfcap_1 = val;
+		ofl->ofl_ocapset.c_sf_1.cm_value &= ~FP_FLAGS;
+	} else {
+		/* Do not take the frame pointer flags from the object */
+		val &= ~FP_FLAGS;
 	}
 
-	Dbg_cap_sec_entry(ofl->ofl_lml, DBG_CAP_RESOLVED, CA_SUNW_SF_1,
-	    ofl->ofl_sfcap_1, ld_targ.t_m.m_mach);
+	ofl->ofl_ocapset.c_sf_1.cm_value |= val;
+
+	DBG_CALL(Dbg_cap_entry2(ofl->ofl_lml, DBG_STATE_RESOLVED, CA_SUNW_SF_1,
+	    &ofl->ofl_ocapset.c_sf_1, ld_targ.t_m.m_mach));
+
+#undef FP_FLAGS
 }
 
 /*
@@ -360,9 +377,9 @@
 	 * If a mapfile has established definitions to override any input
 	 * capabilities, ignore any new input capabilities.
 	 */
-	if (ofl->ofl_flags1 & FLG_OF1_OVHWCAP) {
-		Dbg_cap_sec_entry(ofl->ofl_lml, DBG_CAP_IGNORE, CA_SUNW_HW_1,
-		    val, ld_targ.t_m.m_mach);
+	if (ofl->ofl_flags1 & FLG_OF1_OVHWCAP1) {
+		DBG_CALL(Dbg_cap_entry(ofl->ofl_lml, DBG_STATE_IGNORED,
+		    CA_SUNW_HW_1, val, ld_targ.t_m.m_mach));
 		return;
 	}
 
@@ -373,15 +390,17 @@
 	if (val == 0)
 		return;
 
-	Dbg_cap_sec_entry(ofl->ofl_lml, DBG_CAP_OLD, CA_SUNW_HW_1,
-	    ofl->ofl_hwcap_1, ld_targ.t_m.m_mach);
-	Dbg_cap_sec_entry(ofl->ofl_lml, DBG_CAP_NEW, CA_SUNW_HW_1, val,
-	    ld_targ.t_m.m_mach);
+	if (DBG_ENABLED) {
+		Dbg_cap_entry2(ofl->ofl_lml, DBG_STATE_CURRENT, CA_SUNW_HW_1,
+		    &ofl->ofl_ocapset.c_hw_1, ld_targ.t_m.m_mach);
+		Dbg_cap_entry(ofl->ofl_lml, DBG_STATE_NEW, CA_SUNW_HW_1, val,
+		    ld_targ.t_m.m_mach);
+	}
 
-	ofl->ofl_hwcap_1 |= val;
+	ofl->ofl_ocapset.c_hw_1.cm_value |= val;
 
-	Dbg_cap_sec_entry(ofl->ofl_lml, DBG_CAP_RESOLVED, CA_SUNW_HW_1,
-	    ofl->ofl_hwcap_1, ld_targ.t_m.m_mach);
+	DBG_CALL(Dbg_cap_entry2(ofl->ofl_lml, DBG_STATE_RESOLVED, CA_SUNW_HW_1,
+	    &ofl->ofl_ocapset.c_hw_1, ld_targ.t_m.m_mach));
 }
 
 /*
@@ -1608,6 +1627,14 @@
 	uintptr_t	error;
 	Is_desc		*vdfisp, *vndisp, *vsyisp, *sifisp, *capisp;
 	Sdf_desc	*sdf;
+	Place_path_info	path_info_buf, *path_info;
+
+	/*
+	 * Path information buffer used by ld_place_section() and related
+	 * routines. This information is used to evaluate entrance criteria
+	 * with non-empty file matching lists (ec_files).
+	 */
+	path_info = ld_place_path_info_init(ofl, ifl, &path_info_buf);
 
 	/*
 	 * First process the .shstrtab section so that later sections can
@@ -1895,7 +1922,7 @@
 		 * output section.
 		 */
 		if ((isp->is_flags & FLG_IS_ORDERED) == 0) {
-			if (ld_place_section(ofl, isp,
+			if (ld_place_section(ofl, isp, path_info,
 			    isp->is_keyident, NULL) == (Os_desc *)S_ERROR)
 				return (S_ERROR);
 			continue;
@@ -1926,7 +1953,8 @@
 				continue;
 
 			/* ld_process_ordered() calls ld_place_section() */
-			if (ld_process_ordered(ifl, ofl, ndx) == S_ERROR)
+			if (ld_process_ordered(ofl, ifl, path_info, ndx) ==
+			    S_ERROR)
 				return (S_ERROR);
 
 			/* If we've done them all, stop searching */
--- a/usr/src/cmd/sgs/libld/common/ldentry.c	Sun Feb 21 21:37:22 2010 -0800
+++ b/usr/src/cmd/sgs/libld/common/ldentry.c	Mon Feb 22 09:19:31 2010 -0700
@@ -23,7 +23,7 @@
  *	Copyright (c) 1988 AT&T
  *	  All Rights Reserved
  *
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -197,23 +197,27 @@
 	 *  one for criterias where a filename is used and the other
 	 *  for those without a filename.
 	 */
-	for (ALIST_TRAVERSE(ofl->ofl_ents, ndx, enp)) {
-		const char	*file;
-
-		if (((enp->ec_segment->sg_flags & FLG_SG_ORDER) == 0) ||
+	for (APLIST_TRAVERSE(ofl->ofl_ents, ndx, enp)) {
+		/*
+		 * No warning if any of the following hold:
+		 * -	The segment has no entrance criteria requiring
+		 *	input section sorting (FLG_SG_IS_ORDER not set).
+		 * -	The entrance criteria was used to place a section.
+		 * -	The specific entrance criteria does not require sorting
+		 */
+		if (((enp->ec_segment->sg_flags & FLG_SG_IS_ORDER) == 0) ||
 		    (enp->ec_flags & FLG_EC_USED) || (enp->ec_ordndx == 0))
 			continue;
 
 
-		if (enp->ec_files &&
-		    ((file = enp->ec_files->apl_data[0]) != NULL)) {
+		if (alist_nitems(enp->ec_files) > 0) {
 			eprintf(ofl->ofl_lml, ERR_WARNING,
 			    MSG_INTL(MSG_ENT_NOSEC_1), enp->ec_segment->sg_name,
-			    enp->ec_name, file);
+			    enp->ec_is_name);
 		} else {
 			eprintf(ofl->ofl_lml, ERR_WARNING,
 			    MSG_INTL(MSG_ENT_NOSEC_2), enp->ec_segment->sg_name,
-			    enp->ec_name);
+			    enp->ec_is_name);
 		}
 	}
 }
--- a/usr/src/cmd/sgs/libld/common/ldmain.c	Sun Feb 21 21:37:22 2010 -0800
+++ b/usr/src/cmd/sgs/libld/common/ldmain.c	Mon Feb 22 09:19:31 2010 -0700
@@ -23,7 +23,7 @@
  *	Copyright (c) 1988 AT&T
  *	  All Rights Reserved
  *
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -212,7 +212,7 @@
 
 	DBG_CALL(Dbg_ent_print(ofl->ofl_lml,
 	    ofl->ofl_dehdr->e_ident[EI_OSABI], ofl->ofl_dehdr->e_machine,
-	    ofl->ofl_ents, (ofl->ofl_flags & FLG_OF_DYNAMIC) != 0));
+	    ofl->ofl_ents));
 	DBG_CALL(Dbg_seg_list(ofl->ofl_lml,
 	    ofl->ofl_dehdr->e_ident[EI_OSABI], ofl->ofl_dehdr->e_machine,
 	    ofl->ofl_segs));
@@ -332,7 +332,7 @@
 	 * for any directives that have not been matched.
 	 * Also, if SHF_ORDERED sections exist, set up sort key values.
 	 */
-	if (ofl->ofl_flags & (FLG_OF_SECORDER | FLG_OF_KEY))
+	if (ofl->ofl_flags & (FLG_OF_OS_ORDER | FLG_OF_KEY))
 		ld_sec_validate(ofl);
 
 	/*
--- a/usr/src/cmd/sgs/libld/common/libld.intel.msg	Sun Feb 21 21:37:22 2010 -0800
+++ b/usr/src/cmd/sgs/libld/common/libld.intel.msg	Mon Feb 22 09:19:31 2010 -0700
@@ -20,11 +20,9 @@
 #
 
 #
-# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
-# ident	"%Z%%M%	%I%	%E% SMI"
-#
 
 @ _START_
 
@@ -35,7 +33,7 @@
 			 instruction sequence"
 
 @ MSG_PLT_PLT0FAIL	"creation of PLT entry plt0 failed"
-@ MSG_PLT_PLTNFAIL	"creation of PLT[%d] for symbol `%s' failed"
+@ MSG_PLT_PLTNFAIL	"creation of PLT[%d] for symbol '%s' failed"
 
 @ MSG_UNW_BADCIEVERS	"unwind table: file %s: section %s: \
 			 bad cie version %d: offset 0x%llx\n"
--- a/usr/src/cmd/sgs/libld/common/libld.msg	Sun Feb 21 21:37:22 2010 -0800
+++ b/usr/src/cmd/sgs/libld/common/libld.msg	Mon Feb 22 09:19:31 2010 -0700
@@ -20,7 +20,7 @@
 #
 
 #
-# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 
@@ -52,7 +52,7 @@
 #	usage: ld [-6:abc:.....] file(s)
 #        	[-a]            create an absolute file
 #        	[-b]            do not do special PIC relocations in a.out
-#        	[-c file]       record configuration `file'
+#        	[-c file]       record configuration 'file'
 #
 @ MSG_ARG_USAGE		"usage: ld [-%s] file(s)\n"
 @ MSG_ARG_DETAIL_3	"\t[-32]\t\tenforce a 32-bit link-edit\n"
@@ -74,12 +74,12 @@
 @ MSG_ARG_DETAIL_CBS	"\t[-B symbolic]\tbind external references to \
 			 definitions when creating\n\
 			 \t\t\tshared objects\n"
-@ MSG_ARG_DETAIL_C	"\t[-c name]\trecord configuration file `name'\n"
+@ MSG_ARG_DETAIL_C	"\t[-c name]\trecord configuration file 'name'\n"
 @ MSG_ARG_DETAIL_CC	"\t[-C]\t\tdemangle C++ symbol name diagnostics\n"
 @ MSG_ARG_DETAIL_D	"\t[-d y | n]\toperate in dynamic|static mode\n"
 @ MSG_ARG_DETAIL_CD	"\t[-D token,...]\tprint diagnostic messages\n"
 @ MSG_ARG_DETAIL_E	"\t[-e epsym], [--entry epsym]\n\
-			 \t\t\tuse `epsym' as entry point address\n"
+			 \t\t\tuse 'epsym' as entry point address\n"
 @ MSG_ARG_DETAIL_F	"\t[-f name], [--auxiliary name]\n\
 			 \t\t\tspecify library for which this file is an \
 			 auxiliary\n\t\t\tfilter\n"
@@ -88,20 +88,20 @@
 @ MSG_ARG_DETAIL_CG	"\t[-G], [-shared]\n\
 			 \t\t\tcreate a shared object\n"
 @ MSG_ARG_DETAIL_H	"\t[-h name], [--soname name]\n\
-			 \t\t\tuse `name' as internal shared object identifier\n"
+			 \t\t\tuse 'name' as internal shared object identifier\n"
 @ MSG_ARG_DETAIL_I	"\t[-i]\t\tignore LD_LIBRARY_PATH setting\n"
-@ MSG_ARG_DETAIL_CI	"\t[-I name]\tuse `name' as path of interpreter\n"
+@ MSG_ARG_DETAIL_CI	"\t[-I name]\tuse 'name' as path of interpreter\n"
 @ MSG_ARG_DETAIL_L	"\t[-l x], [--library x]\n\
 			 \t\t\tsearch for libx.so or libx.a\n"
 @ MSG_ARG_DETAIL_CL	"\t[-L path], [--library-path path]\n\
-			 \t\t\tsearch for libraries in directory `path'\n"
+			 \t\t\tsearch for libraries in directory 'path'\n"
 @ MSG_ARG_DETAIL_M	"\t[-m]\t\tprint memory map\n"
 @ MSG_ARG_DETAIL_CM	"\t[-M mapfile]\tuse processing directives contained \
-			 in `mapfile'\n"
+			 in 'mapfile'\n"
 @ MSG_ARG_DETAIL_CN	"\t[-N string]\tcreate a dynamic dependency for \
-			 `string'\n"
+			 'string'\n"
 @ MSG_ARG_DETAIL_O	"\t[-o outfile], [--output outfile]\n\
-			 \t\t\tname the output file `outfile'\n"
+			 \t\t\tname the output file 'outfile'\n"
 @ MSG_ARG_DETAIL_P	"\t[-p auditlib]\tidentify audit library to accompany \
 			 this object\n"
 @ MSG_ARG_DETAIL_CP	"\t[-P auditlib]\tidentify audit library for \
@@ -121,10 +121,10 @@
 @ MSG_ARG_DETAIL_T	"\t[-t]\t\tdo not warn of multiply-defined symbols \
 			 that have\n\t\t\tdifferent sizes or alignments\n"
 @ MSG_ARG_DETAIL_U	"\t[-u symname], [--undefined symname]\n\
-			 \t\t\tcreate an undefined symbol `symname'\n"
+			 \t\t\tcreate an undefined symbol 'symname'\n"
 @ MSG_ARG_DETAIL_CV	"\t[-V], [--version]\n\
 			 \t\t\tprint version information\n"
-@ MSG_ARG_DETAIL_CY	"\t[-Y P,dirlist]\tuse `dirlist' as a default path \
+@ MSG_ARG_DETAIL_CY	"\t[-Y P,dirlist]\tuse 'dirlist' as a default path \
 			 when searching for\n\
 			 \t\t\tlibraries\n"
 @ MSG_ARG_DETAIL_ZA	"\t[-z absexec]\twhen building an executable absolute \
@@ -170,7 +170,7 @@
 			 \t\t\tbe executed before the .init section of any \
 			 other\n\t\t\tobjects\n"
 @ MSG_ARG_DETAIL_ZINT	"\t[-z interpose]\
-			 \tdynamic object is to be an `interposer' on direct\n\
+			 \tdynamic object is to be an 'interposer' on direct\n\
 			 \t\t\tbindings\n"
 @ MSG_ARG_DETAIL_ZLAZY	"\t[-z lazyload | nolazyload]\n\
 			 \t\t\tenable|disable delayed loading of shared \
@@ -273,7 +273,7 @@
 @ MSG_REL_UNSUPSZ	"relocation error: %s: file %s: symbol %s: \
 			 offset size (%d bytes) is not supported"
 @ MSG_REL_INVALOFFSET	"relocation error: %s: file %s section [%u]%s: \
-			 invalid offset symbol `%s': offset 0x%llx"
+			 invalid offset symbol '%s': offset 0x%llx"
 @ MSG_REL_INVALRELT	"relocation error: file %s: section [%u]%s: \
 			 invalid relocation type: 0x%x"
 @ MSG_REL_EMPTYSEC	"relocation error: %s: file %s: symbol %s: \
@@ -376,12 +376,12 @@
 @ MSG_FIL_MULINC_1	"file %s: attempted multiple inclusion of file"
 @ MSG_FIL_MULINC_2	"file %s: linked to %s: attempted multiple inclusion \
 			 of file"
-@ MSG_FIL_SOINSTAT	"input of shared object `%s' in static mode"
+@ MSG_FIL_SOINSTAT	"input of shared object '%s' in static mode"
 @ MSG_FIL_INVALSEC	"file %s: section [%u]%s has invalid type %s"
 @ MSG_FIL_NOTFOUND	"file %s: required by %s, not found"
 @ MSG_FIL_MALSTR	"file %s: section [%u]%s: malformed string table, \
 			 initial or final byte"
-@ MSG_FIL_PTHTOLONG	"`%s/%s' pathname too long"
+@ MSG_FIL_PTHTOLONG	"'%s/%s' pathname too long"
 @ MSG_FIL_EXCLUDE	"file %s: section [%u]%s contains both SHF_EXCLUDE and \
 			 SHF_ALLOC flags: SHF_EXCLUDE ignored"
 @ MSG_FIL_INTERRUPT	"file %s: creation interrupted: %s"
@@ -400,8 +400,6 @@
 @ MSG_FIL_UNKCAP	"file %s: section [%u]%s: unknown capability tag: %d"
 @ MSG_FIL_BADSF1	"file %s: section [%u]%s: unknown software \
 			 capabilities: 0x%llx; ignored"
-@ MSG_MAPFIL_BADSF1	"file %s: line %llu: unknown software \
-			 capabilities: 0x%llx; ignored"
 @ MSG_FIL_INADDR32SF1	"file %s: section [%u]%s: software capability ADDR32: is \
 			 ineffective when building 32-bit object; ignored"
 @ MSG_FIL_EXADDR32SF1	"file %s: section [%u]%s: software capability ADDR32: \
@@ -413,9 +411,9 @@
 
 # Recording name conflicts
 
-@ MSG_REC_OPTCNFLT	"recording name conflict: file `%s' and %s provide \
+@ MSG_REC_OPTCNFLT	"recording name conflict: file '%s' and %s provide \
 			 identical dependency names: %s"
-@ MSG_REC_OBJCNFLT	"recording name conflict: file `%s' and file `%s' \
+@ MSG_REC_OBJCNFLT	"recording name conflict: file '%s' and file '%s' \
 			 provide identical dependency names: %s  %s"
 @ MSG_REC_CNFLTHINT	"(possible multiple inclusion of the same file)"
 
@@ -447,26 +445,26 @@
 
 # Section processing errors
 
-@ MSG_SCN_NONALLOC	"%s: non-allocatable section `%s' directed to a \
-			 loadable segment"
+@ MSG_SCN_NONALLOC	"%s: non-allocatable section '%s' directed to a \
+			 loadable segment: %s"
 
 # Symbol processing errors
 
-@ MSG_SYM_NOSECDEF	"symbol `%s' in file %s has no section definition"
-@ MSG_SYM_INVSEC	"symbol `%s' in file %s associated with invalid \
+@ MSG_SYM_NOSECDEF	"symbol '%s' in file %s has no section definition"
+@ MSG_SYM_INVSEC	"symbol '%s' in file %s associated with invalid \
 			 section[%lld]"
-@ MSG_SYM_TLS		"symbol `%s' in file %s (STT_TLS), is defined \
+@ MSG_SYM_TLS		"symbol '%s' in file %s (STT_TLS), is defined \
 			 in a non-SHF_TLS section"
-@ MSG_SYM_BADADDR	"symbol `%s' in file %s: section [%u]%s: size %#llx: \
+@ MSG_SYM_BADADDR	"symbol '%s' in file %s: section [%u]%s: size %#llx: \
 			 symbol (address %#llx, size %#llx) lies outside \
 			 of containing section"
-@ MSG_SYM_BADADDR_ROTXT	"symbol `%s' in file %s: readonly text section \
+@ MSG_SYM_BADADDR_ROTXT	"symbol '%s' in file %s: readonly text section \
 			 [%u]%s: size %#llx: symbol (address %#llx, \
 			 size %#llx) lies outside of containing section"
-@ MSG_SYM_MULDEF	"symbol `%s' is multiply-defined:"
-@ MSG_SYM_CONFVIS	"symbol `%s' has conflicting visibilities:"
-@ MSG_SYM_DIFFTYPE	"symbol `%s' has differing types:"
-@ MSG_SYM_DIFFATTR	"symbol `%s' has differing %s:\n\
+@ MSG_SYM_MULDEF	"symbol '%s' is multiply-defined:"
+@ MSG_SYM_CONFVIS	"symbol '%s' has conflicting visibilities:"
+@ MSG_SYM_DIFFTYPE	"symbol '%s' has differing types:"
+@ MSG_SYM_DIFFATTR	"symbol '%s' has differing %s:\n\
 			 \t(file %s value=0x%llx; file %s value=0x%llx);"
 @ MSG_SYM_FILETYPES	"\t(file %s type=%s; file %s type=%s);"
 @ MSG_SYM_VISTYPES	"\t(file %s visibility=%s; file %s visibility=%s);"
@@ -480,10 +478,10 @@
 			 ignored:\n\t(file %s value=%s);"
 @ MSG_SYM_NONGLOB	"global symbol %s has non-global binding:\n\
 			 \t(file %s value=%s);"
-@ MSG_SYM_RESERVE	"reserved symbol `%s' already defined in file %s"
-@ MSG_SYM_NOTNULL	"undefined symbol `%s' with non-zero value encountered \
+@ MSG_SYM_RESERVE	"reserved symbol '%s' already defined in file %s"
+@ MSG_SYM_NOTNULL	"undefined symbol '%s' with non-zero value encountered \
 			 from file %s"
-@ MSG_SYM_DUPSORTADDR	"section %s: symbol `%s' and symbol `%s' have the \
+@ MSG_SYM_DUPSORTADDR	"section %s: symbol '%s' and symbol '%s' have the \
 			 same address: %#llx: remove duplicate with \
 			 NOSORTSYM mapfile directive"
 
@@ -497,7 +495,7 @@
 			 associated symbol size is unknown %s"
 @ MSG_PSYM_NOSTATIC	"and partial initialization cannot be deferred to \
 			 a static object"
-@ MSG_MOVE_OVERLAP	"file %s: section [%u]%s: symbol `%s' overlapping move \
+@ MSG_MOVE_OVERLAP	"file %s: section [%u]%s: symbol '%s' overlapping move \
 			 initialization: start=0x%llx, length=0x%llx: \
 			 start=0x%llx, length=0x%llx"
 @ MSG_PSYM_EXPREASON1	"output file is static object"
@@ -551,42 +549,43 @@
 @ MSG_SYM_UND_BNDLOCAL	"%-35s %s  (symbol scope specifies local binding)"
 
 @ MSG_SYM_ENTRY		"entry point"
-@ MSG_SYM_UNDEF		"%s symbol `%s' is undefined"
-@ MSG_SYM_EXTERN	"%s symbol `%s' is undefined  (symbol belongs to \
+@ MSG_SYM_UNDEF		"%s symbol '%s' is undefined"
+@ MSG_SYM_EXTERN	"%s symbol '%s' is undefined  (symbol belongs to \
 			 dependency %s)"
-@ MSG_SYM_NOCRT		"symbol `%s' not found, but %s section exists - \
+@ MSG_SYM_NOCRT		"symbol '%s' not found, but %s section exists - \
 			 possible link-edit without using the compiler driver"
 
 # Output file update messages
 
-@ MSG_UPD_NOREADSEG	"No read-only segments found.  Setting `_etext' to 0"
-@ MSG_UPD_NORDWRSEG	"No read-write segments found.  Setting `_edata' to 0"
-@ MSG_UPD_NOSEG		"Setting `end' and `_end' to 0"
+@ MSG_UPD_NOREADSEG	"No read-only segments found.  Setting '_etext' to 0"
+@ MSG_UPD_NORDWRSEG	"No read-write segments found.  Setting '_edata' to 0"
+@ MSG_UPD_NOSEG		"Setting 'end' and '_end' to 0"
 
 @ MSG_UPD_SEGOVERLAP	"%s: segment address overlap;\n\
 			 \tprevious segment ending at address 0x%llx overlaps\n\
-			 \tuser defined segment `%s' starting at address 0x%llx"
+			 \tuser defined segment '%s' starting at address 0x%llx"
 @ MSG_UPD_LARGSIZE	"%s: segment %s calculated size 0x%llx\n\
 			 \tis larger than user-defined size 0x%llx"
 
 @ MSG_UPD_NOBITS	"NOBITS section found before end of initialized data"
+@ MSG_SEG_FIRNOTLOAD	"First segment has type %s, PT_LOAD required: %s"
 
 
 # Version processing messages
 
 @ MSG_VER_HIGHER	"file %s: version revision %d is higher than \
 			 expected %d"
-@ MSG_VER_NOEXIST	"file %s: version `%s' does not exist:\n\
+@ MSG_VER_NOEXIST	"file %s: version '%s' does not exist:\n\
 			 \trequired by file %s"
-@ MSG_VER_UNDEF		"version `%s' undefined, referenced by version `%s':\n\
+@ MSG_VER_UNDEF		"version '%s' undefined, referenced by version '%s':\n\
 			 \trequired by file %s"
-@ MSG_VER_UNAVAIL	"file %s: version `%s' is unavailable:\n\
+@ MSG_VER_UNAVAIL	"file %s: version '%s' is unavailable:\n\
 			 \trequired by file %s"
-@ MSG_VER_DEFINED	"version symbol `%s' already defined in file %s"
-@ MSG_VER_INVALNDX	"version symbol `%s' from file %s has an invalid \
+@ MSG_VER_DEFINED	"version symbol '%s' already defined in file %s"
+@ MSG_VER_INVALNDX	"version symbol '%s' from file %s has an invalid \
 			 version index (%d)"
-@ MSG_VER_ADDVERS	"unused $ADDVERS specification from file `%s' \
-			 for object `%s'\nversion(s):"
+@ MSG_VER_ADDVERS	"unused $ADDVERS specification from file '%s' \
+			 for object '%s'\nversion(s):"
 @ MSG_VER_ADDVER	"\t%s"
 @ MSG_VER_CYCLIC	"following versions generate cyclic dependency:"
 
@@ -638,14 +637,29 @@
 @ MSG_REJ_UNKFILE	"file %s: unknown file type"
 @ MSG_REJ_HWCAP_1	"file %s: hardware capability unsupported: %s"
 
+
 @ _END_
 
 
 # The following strings represent reserved names.  Reference to these strings
 # is via the MSG_ORIG() macro, and thus translations are not required.
 
+@ MSG_STR_EOF		"<eof>"
+@ MSG_STR_ERROR		"<error>"
 @ MSG_STR_EMPTY		""
+@ MSG_QSTR_BANG		"'!'"
 @ MSG_STR_COLON		":"
+@ MSG_QSTR_COLON	"':'"
+@ MSG_QSTR_SEMICOLON	"';'"
+@ MSG_QSTR_EQUAL	"'='"
+@ MSG_QSTR_PLUSEQ	"'+='"
+@ MSG_QSTR_MINUSEQ	"'-='"
+@ MSG_QSTR_ATSIGN	"'@'"
+@ MSG_QSTR_DASH		"'-'"
+@ MSG_QSTR_LEFTBKT	"'{'"
+@ MSG_QSTR_RIGHTBKT	"'}'"
+@ MSG_QSTR_PIPE		"'|'"
+@ MSG_QSTR_STAR		"'*'"
 @ MSG_STR_DOT		"."
 @ MSG_STR_SLASH		"/"
 @ MSG_STR_DYNAMIC	"(.dynamic)"
@@ -656,10 +670,25 @@
 @ MSG_STR_OSREL		"$OSREL"
 @ MSG_STR_UU_REAL_U	"__real_"
 @ MSG_STR_UU_WRAP_U	"__wrap_"
+@ MSG_STR_UELF32	"_ELF32"
+@ MSG_STR_UELF64	"_ELF64"
+@ MSG_STR_USPARC	"_sparc"
+@ MSG_STR_UX86		"_x86"
+@ MSG_STR_TRUE		"true"
+
+@ MSG_STR_CDIR_ADD	"$add"
+@ MSG_STR_CDIR_CLEAR	"$clear"
+@ MSG_STR_CDIR_ERROR	"$error"
+@ MSG_STR_CDIR_MFVER	"$mapfile_version"
+@ MSG_STR_CDIR_IF	"$if"
+@ MSG_STR_CDIR_ELIF	"$elif"
+@ MSG_STR_CDIR_ELSE	"$else"
+@ MSG_STR_CDIR_ENDIF	"$endif"
+
 
 @ MSG_FMT_ARMEM		"%s(%s)"
 @ MSG_FMT_COLPATH	"%s:%s"
-@ MSG_FMT_SYMNAM	"`%s'"
+@ MSG_FMT_SYMNAM	"'%s'"
 @ MSG_FMT_NULLSYMNAM	"%s[%d]"
 @ MSG_FMT_STRCAT	"%s%s"
 
@@ -738,24 +767,15 @@
 @ MSG_SCN_GCC_X_TBL	".gcc_except_table"
 @ MSG_SCN_JCR		".jcr"
 
-# Entry criteria strings (segment names)
+# Segment names for segments referenced by entrance criteria
 
 @ MSG_ENT_BSS		"bss"
 @ MSG_ENT_DATA		"data"
-@ MSG_ENT_DTRACE	"dtrace"
-@ MSG_ENT_DYNAMIC	"dynamic"
 @ MSG_ENT_EXTRA		"extra"
-@ MSG_ENT_INTERP	"interp"
-@ MSG_ENT_LBSS		"lbss"
 @ MSG_ENT_LDATA		"ldata"
 @ MSG_ENT_LRODATA	"lrodata"
 @ MSG_ENT_NOTE		"note"
-@ MSG_ENT_PHDR		"phdr"
 @ MSG_ENT_TEXT		"text"
-@ MSG_ENT_TLS		"tls"
-@ MSG_ENT_UNWIND	"unwind"
-
-@ MSG_ENT_SUNWCAP	"SUNW_cap"
 
 # Symbol names
 
@@ -830,7 +850,7 @@
 @ MSG_MARG_INCOMP	"%s and %s are incompatible"
 @ MSG_ARG_MTONCE	"option %s appears more than once, first setting taken"
 @ MSG_MARG_MTONCE	"%s appears more than once, first setting taken"
-@ MSG_ARG_ILLEGAL	"option %s has illegal argument `%s'"
+@ MSG_ARG_ILLEGAL	"option %s has illegal argument '%s'"
 @ MSG_ARG_YP		"option -YP and -Y%c may not be specified concurrently"
 @ MSG_ARG_STRIP		"%s specified with %s; only debugging \
 			 information stripped"
@@ -838,7 +858,7 @@
 @ MSG_ARG_NOFLTR	"option %s is only meaningful when building a filter"
 @ MSG_ARG_NODEFLIB	"the default library search path has been suppressed, \
 			 but no runpaths have been specified via %s"
-@ MSG_ARG_NOENTRY	"entry point symbol `%s' is undefined"
+@ MSG_ARG_NOENTRY	"entry point symbol '%s' is undefined"
 @ MSG_ARG_UNSUPPORTED	"option %s is no longer supported; ignored"
 
 @ MSG_ARG_FLAGS		"flags processing errors"
@@ -934,9 +954,9 @@
 #
 @ MSG_ENT_MUL_ENTRY_2	"\t\t\t\t\t\t\t%s\n"
 
-@ MSG_ENT_NOSEC_1	"mapfile: %s segment: section `%s' does not appear \
-			 in file `%s'"
-@ MSG_ENT_NOSEC_2	"mapfile: %s segment: section `%s' does not appear \
+@ MSG_ENT_NOSEC_1	"mapfile: %s segment: section '%s' does not appear \
+			 in mapfile specified input file(s)"
+@ MSG_ENT_NOSEC_2	"mapfile: %s segment: section '%s' does not appear \
 			 in any input file"
 
 # Library messages
@@ -948,80 +968,95 @@
 
 # Mapfile processing messages
 
-@ MSG_MAP_BADFLAG	"%s: %lld: badly formed section flags `%s'"
-@ MSG_MAP_REDEFATT	"%s: %lld: redefining %s attribute for `%s'"
-@ MSG_MAP_PREMEOF	"%s: %lld: premature EOF"
-@ MSG_MAP_ILLCHAR	"%s: %lld: illegal character `\\%03o'"
-@ MSG_MAP_MALFORM	"%s: %lld: malformed entry"
-@ MSG_MAP_NONLOAD	"%s: %lld: %s not allowed on non-LOAD segments"
-@ MSG_MAP_NOSTACK1	"%s: %lld: %s not allowed on STACK segment"
-@ MSG_MAP_NOSTACK2	"%s: %lld: multiple STACK segments are not allowed"
-@ MSG_MAP_MOREONCE	"%s: %lld: %s set more than once on same line"
-@ MSG_MAP_NOTERM	"%s: %lld: string does not terminate with a `\"'"
-@ MSG_MAP_SECINSEG	"%s: %lld: section within segment ordering done on \
-			 a non-existent segment `%s'"
-@ MSG_MAP_UNEXDEP	"%s: %lld: dependency `%s' unexpected; ignored"
-@ MSG_MAP_UNEXTOK	"%s: %lld: unexpected occurrence of `%c' token"
+@ MSG_MAP_BADAUTORED	"%s: %llu: auto-reduction ('*') can only be used in \
+			 hidden/local, or eliminate scope"
+@ MSG_MAP_BADFLAG	"%s: %llu: badly formed section flags '%s'"
+@ MSG_MAP_BADBNAME	"%s: %llu: basename cannot contain path \
+			 separator ('/'): %s"
+@ MSG_MAP_BADONAME	"%s: %llu: object name cannot contain path \
+			 separator ('/'): %s"
+@ MSG_MAP_REDEFATT	"%s: %llu: redefining %s attribute for '%s'"
+@ MSG_MAP_PREMEOF	"%s: %llu: premature EOF"
+@ MSG_MAP_ILLCHAR	"%s: %llu: illegal character '\\%03o'"
+@ MSG_MAP_MALFORM	"%s: %llu: malformed entry"
+@ MSG_MAP_NONLOAD	"%s: %llu: %s not allowed on non-LOAD segments"
+@ MSG_MAP_NOSTACK1	"%s: %llu: %s not allowed on STACK segment"
+@ MSG_MAP_MOREONCE	"%s: %llu: %s set more than once on same line"
+@ MSG_MAP_NOTERM	"%s: %llu: unterminated quoted string: %s"
+@ MSG_MAP_SECINSEG	"%s: %llu: section within segment ordering done on \
+			 a non-existent segment '%s'"
+@ MSG_MAP_UNEXINHERIT	"%s: %llu: unnamed version cannot inherit from other \
+			 versions: %s"
+@ MSG_MAP_UNEXTOK	"%s: %llu: unexpected occurrence of '%c' token"
 
-@ MSG_MAP_SEGEMPLOAD	"%s: %lld: empty segment must be of type LOAD or NULL"
-@ MSG_MAP_SEGEMPEXE	"%s: %lld: a LOAD empty segment definition is only \
+@ MSG_MAP_SEGEMPLOAD	"%s: %llu: empty segment must be of type LOAD or NULL"
+@ MSG_MAP_SEGEMPEXE	"%s: %llu: a LOAD empty segment definition is only \
 			 allowed when creating a dynamic executable"
-@ MSG_MAP_SEGEMPATT	"%s: %lld: a LOAD empty segment must have an address \
+@ MSG_MAP_SEGEMPATT	"%s: %llu: a LOAD empty segment must have an address \
 			 and size"
-@ MSG_MAP_SEGEMPNOATT	"%s: %lld: a NULL empty segment must not have an address \
-			 or size"
-@ MSG_MAP_SEGEMPSEC	"%s: %lld: empty segment can not have sections \
+@ MSG_MAP_SEGEMPNOATT	"%s: %llu: a NULL empty segment must not have an \
+			 address or size"
+@ MSG_MAP_SEGEMPSEC	"%s: %llu: empty segment can not have sections \
 			 assigned to it"
-@ MSG_MAP_SEGEMNOPERM	"%s: %lld: empty segment must not have \
+@ MSG_MAP_SEGEMNOPERM	"%s: %llu: empty segment must not have \
 			 p_flags set: 0x%x"
 
-@ MSG_MAP_UNKSYMSCO	"%s: %lld: unknown symbol scope definition `%s'"
-@ MSG_MAP_UNKSYMDEF	"%s: %lld: unknown symbol definition `%s'"
-@ MSG_MAP_UNKSEGTYP	"%s: %lld: unknown internal segment type %d"
-@ MSG_MAP_UNKSOTYP	"%s: %lld: unknown shared object type `%s'"
-@ MSG_MAP_UNKSEGATT	"%s: %lld: unknown segment attribute `%s'"
-@ MSG_MAP_UNKSEGFLG	"%s: %lld: unknown segment flag `?%c'"
-@ MSG_MAP_UNKSECTYP	"%s: %lld: unknown section type `%s'"
+@ MSG_MAP_CNTADDRORDER	"%s: %llu: segment cannot have an explicit address \
+			 and also be in the SEGMENT_ORDER list: %s"
+@ MSG_MAP_CNTDISSEG	"%s: %llu: segment cannot be disabled: %s"
+@ MSG_MAP_DUPNAMENT	"%s: %llu: cannot redefine entrance criteria: %s"
+@ MSG_MAP_DUPORDSEG	"%s: %llu: segment is already in %s list: %s"
+@ MSG_MAP_DUP_OS_ORD	"%s: %llu: section is already in OS_ORDER list: %s"
+@ MSG_MAP_DUP_IS_ORD	"%s: %llu: entrance criteria is already in \
+			 IS_ORDER list: %s"
+@ MSG_MAP_UNKENT	"%s: %llu: unknown entrance criteria \
+			 (ASSIGN_SECTION): %s"
+@ MSG_MAP_UNKSEG	"%s: %llu: unknown segment: %s"
+@ MSG_MAP_UNKSYMDEF	"%s: %llu: unknown symbol definition: %s"
+@ MSG_MAP_UNKSEGTYP	"%s: %llu: unknown internal segment type %d"
+@ MSG_MAP_UNKSOTYP	"%s: %llu: unknown shared object type: %s"
+@ MSG_MAP_UNKSEGATT	"%s: %llu: unknown segment attribute: %s"
+@ MSG_MAP_UNKSEGFLG	"%s: %llu: unknown segment flag: ?%c"
+@ MSG_MAP_UNKSECTYP	"%s: %llu: unknown section type: %s"
 
-@ MSG_MAP_SEGSIZE	"%s: %lld: segment `%s' already has a size symbol"
-@ MSG_MAP_SEGADDR	"%s: %lld: segment address or length `%s' %s"
-@ MSG_MAP_BADCAPVAL	"%s: %lld: bad capability value `%s': %s"
-@ MSG_MAP_UNKCAPATTR	"%s: %lld: unknown capability attribute `%s'"
-@ MSG_MAP_EMPTYCAP	"%s: %lld: empty capability definition; ignored"
-@ MSG_MAP_SEGRESV	"%s: %lld: segments `interp' or `dynamic' may not be \
-			 changed"
-
-@ MSG_MAP_SYMDEF1	"%s: %lld: symbol `%s' is already defined in file: \
-			 %s: %s"
-@ MSG_MAP_SYMDEF2	"%s: %lld: symbol `%s': %s"
+@ MSG_MAP_SEGSIZE	"%s: %lld: existing segment size symbols cannot \
+			 be reset: %s"
+@ MSG_MAP_SEGADDR	"%s: %llu: segment address or length '%s' %s"
+@ MSG_MAP_BADCAPVAL	"%s: %llu: bad capability value: %s"
+@ MSG_MAP_UNKCAPATTR	"%s: %llu: unknown capability attribute '%s'"
+@ MSG_MAP_EMPTYCAP	"%s: %llu: empty capability definition; ignored"
 
-@ MSG_MAP_EXPSCOL	"%s: %lld: expected a `;'"
-@ MSG_MAP_EXPEQU	"%s: %lld: expected a `=', `:', `|', or `@'"
-@ MSG_MAP_EXPSEGATT	"%s: %lld: expected one or more segment attributes \
-			 after an `='"
-@ MSG_MAP_EXPSEGNAM	"%s: %lld: expected a segment name at the beginning \
+@ MSG_MAP_SYMDEF1	"%s: %llu: symbol '%s' is already defined in file: \
+			 %s: %s"
+@ MSG_MAP_SYMDEF2	"%s: %llu: symbol '%s': %s"
+
+@ MSG_MAP_EXPSCOL	"%s: %llu: expected a ';'"
+@ MSG_MAP_EXPEQU	"%s: %llu: expected a '=', ':', '|', or '@'"
+@ MSG_MAP_EXPSEGATT	"%s: %llu: expected one or more segment attributes \
+			 after an '='"
+@ MSG_MAP_EXPSEGNAM	"%s: %llu: expected a segment name at the beginning \
 			 of a line"
-@ MSG_MAP_EXPSYM_1	"%s: %lld: expected a symbol name after `@'"
-@ MSG_MAP_EXPSYM_2	"%s: %lld: expected a symbol name after `{'"
-@ MSG_MAP_EXPSEC	"%s: %lld: expected a section name after `|'"
-@ MSG_MAP_EXPSO		"%s: %lld: expected a shared object definition \
-			 after `-'"
-@ MSG_MAP_EXPVERS	"%s: %lld: expected a `;' or version reference \
-			 after `}'"
-@ MSG_MAP_MULTFILTEE	"%s: %lld: multiple filtee definitions are unsupported"
-@ MSG_MAP_NOFILTER	"%s: %lld: filtee definition required"
-@ MSG_MAP_BADSF1	"%s: %lld: unknown software capabilities: 0x%llx; \
+@ MSG_MAP_EXPSEGTYPE	"%s: %llu: %s segment cannot be used with %s \
+			 directive: %s"
+@ MSG_MAP_EXPSYM_1	"%s: %llu: expected a symbol name after '@'"
+@ MSG_MAP_EXPSYM_2	"%s: %llu: expected a symbol name after '{'"
+@ MSG_MAP_EXPSEC	"%s: %llu: expected a section name after '|'"
+@ MSG_MAP_EXPSO		"%s: %llu: expected a shared object definition \
+			 after '-'"
+@ MSG_MAP_MULTFILTEE	"%s: %llu: multiple filtee definitions are unsupported"
+@ MSG_MAP_NOFILTER	"%s: %llu: filtee definition required"
+@ MSG_MAP_BADSF1	"%s: %llu: unknown software capabilities: 0x%llx; \
 			 ignored"
-@ MSG_MAP_INADDR32SF1	"%s: %lld: software capability ADDR32: is ineffective \
+@ MSG_MAP_INADDR32SF1	"%s: %llu: software capability ADDR32: is ineffective \
 			 when building 32-bit object: ignored"
-@ MSG_MAP_NOINTPOSE	"%s: %lld: interposition symbols can only be defined \
+@ MSG_MAP_NOINTPOSE	"%s: %llu: interposition symbols can only be defined \
 			 when building a dynamic executable"
-@ MSG_MAP_NOEXVLSZ	"%s: %lld: value and size attributes are incompatible \
+@ MSG_MAP_NOEXVLSZ	"%s: %llu: value and size attributes are incompatible \
 			 with extern or parent symbols"
-@ MSG_MAP_FLTR_ONLYAVL	"%s: %lld: symbol filtering is only available when \
+@ MSG_MAP_FLTR_ONLYAVL	"%s: %llu: symbol filtering is only available when \
 			 building a shared object"
 
-@ MSG_MAP_SEGSAME	"segments `%s' and `%s' have the same assigned \
+@ MSG_MAP_SEGSAME	"segments '%s' and '%s' have the same assigned \
 			 virtual address"
 @ MSG_MAP_EXCLIMIT	"exceeds internal limit"
 @ MSG_MAP_NOBADFRM	"number is badly formed"
@@ -1059,6 +1094,98 @@
 @ MSG_MAP_SECORDER	"section ordering requested, but no matching section \
 			 found: segment: %s section: %s"
 
+
+# Mapfile Directives
+
+@ MSG_MAP_EXP_ATTR	"%s: %llu: expected attribute name (%s), or \
+			 terminator (';', '}'): %s"
+@ MSG_MAP_EXP_CAPMASK	"%s: %llu: expected capability name, integer value, or \
+			 terminator (';', '}'): %s"
+@ MSG_MAP_EXP_CAPNAME	"%s: %llu: expected name, or terminator (';', '}'): %s"
+@ MSG_MAP_EXP_CAPID	"%s: %llu: expected name, or '{' following %s: %s"
+@ MSG_MAP_EXP_CAPHW	"%s: %llu: expected hardware capability, or \
+			 terminator (';', '}'): %s"
+@ MSG_MAP_EXP_CAPSF	"%s: %llu: expected software capability, or \
+			 terminator (';', '}'): %s"
+@ MSG_MAP_EXP_EQ	"%s: %llu: expected '=' following %s: %s"
+@ MSG_MAP_EXP_EQ_ALL	"%s: %llu: expected '=', '+=', or '-=' following %s: %s"
+@ MSG_MAP_EXP_EQ_PEQ	"%s: %llu: expected '=' following %s: %s"
+@ MSG_MAP_EXP_DIR	"%s: %llu: expected mapfile directive (%s): %s"
+@ MSG_MAP_SFLG_EXBANG	"%s: %llu: '!' appears without corresponding flag"
+@ MSG_MAP_EXP_FILNAM	"%s: %llu: expected file name following %s: %s"
+@ MSG_MAP_EXP_FILPATH	"%s: %llu: expected file path following %s: %s"
+@ MSG_MAP_EXP_INT	"%s: %llu: expected integer value following %s: %s"
+@ MSG_MAP_EXP_LBKT	"%s: %llu: expected '{' following %s: %s"
+@ MSG_MAP_EXP_OBJNAM	"%s: %llu: expected object name following %s: %s"
+@ MSG_MAP_SFLG_ONEBANG	"%s: %llu: '!' can only be specified once per flag"
+@ MSG_MAP_EXP_SECFLAG	"%s: %llu: expected section flag (%s), '!', or \
+			 terminator (';', '}'): %s"
+@ MSG_MAP_EXP_SECNAM	"%s: %llu: expected section name following %s: %s"
+@ MSG_MAP_EXP_SEGFLAG	"%s: %llu: expected segment flag (%s), or \
+			 terminator (';', '}'): %s"
+@ MSG_MAP_EXP_ECNAM	"%s: %llu: expected entrance criteria (ASSIGN_SECTION) \
+			 name, or terminator (';', '}'): %s"
+@ MSG_MAP_EXP_SEGNAM	"%s: %llu: expected segment name following %s: %s"
+@ MSG_MAP_EXP_SEM	"%s: %llu: expected ';' to terminate %s: %s"
+@ MSG_MAP_EXP_SEMLBKT	"%s: %llu: expected ';' or '{' following %s: %s"
+@ MSG_MAP_EXP_SEMRBKT	"%s: %llu: expected ';' or '}' to terminate %s: %s"
+@ MSG_MAP_EXP_SHTYPE	"%s: %llu: expected section type: %s"
+@ MSG_MAP_EXP_SYM	"%s: %llu: expected symbol name, symbol scope, \
+			 or '*': %s"
+@ MSG_MAP_EXP_SYMEND	"%s: %llu: expected inherited version name, or \
+			 terminator (';'): %s"
+@ MSG_MAP_EXP_SYMDELIM	"%s: %llu: expected one of ':', ';', or '{': %s"
+@ MSG_MAP_EXP_SYMFLAG	"%s: %llu: expected symbol flag (%s), or \
+			 terminator (';', '}'): %s"
+@ MSG_MAP_EXP_SYMNAM	"%s: %llu: expected symbol name following %s: %s"
+@ MSG_MAP_EXP_SYMSCOPE	"%s: %llu: expected symbol scope (%s): %s"
+@ MSG_MAP_EXP_SYMTYPE	"%s: %llu: expected symbol type (%s): %s"
+@ MSG_MAP_EXP_VERSION	"%s: %llu: expected version name following %s: %s"
+@ MSG_MAP_BADEXTRA	"%s: %llu: unexpected text found following %s directive"
+@ MSG_MAP_VALUELIMIT	"%s: %llu: numeric value exceeds word size: %s"
+@ MSG_MAP_MALVALUE	"%s: %llu: malformed numeric value: %s"
+@ MSG_MAP_BADVALUETAIL	"%s: %llu: unexpected characters following numeric \
+			 constant: %s"
+@ MSG_MAP_WSNEEDED	"%s: %llu: whitespace needed before token: %s"
+@ MSG_MAP_BADCHAR	"%s: %llu: unexpected text: %s"
+@ MSG_MAP_BADKWQUOTE	"%s: %llu: mapfile keywords should not be quoted: %s"
+@ MSG_MAP_CDIR_NOTBOL	"%s: %llu: mapfile control directive not at start of \
+			 line: %s"
+@ MSG_MAP_NOATTR	"%s: %llu: %s specified no attributes (empty {})"
+@ MSG_MAP_NOVALUES	"%s: %llu: %s specified without values"
+@ MSG_MAP_INTERR	"<internal error>"
+@ MSG_MAP_ISORDVER	"%s: %llu: version 0 mapfile ?O flag and version 1 \
+			 segment IS_ORDER attribute are mutually exclusive: %s"
+@ MSG_MAP_SYMATTR	"symbol attributes";
+
+# Mapfile Control Directives
+
+@ MSG_MAP_CDIR_BADVDIR	"%s: %llu: $mapfile_version directive must specify \
+			 version 2 or higher: %d"
+@ MSG_MAP_CDIR_BADVER	"%s: %llu: unknown mapfile version: %d"
+@ MSG_MAP_CDIR_REPVER	"%s: %llu: $mapfile_version must be first directive \
+			 in file"
+@ MSG_MAP_CDIR_REQARG	"%s: %llu: %s directive requires an argument"
+@ MSG_MAP_CDIR_REQNOARG	"%s: %llu: %s directive does not accept arguments"
+@ MSG_MAP_CDIR_BAD	"%s: %llu: unrecognized mapfile control directive"
+@ MSG_MAP_CDIR_NOIF	"%s: %llu: %s directive used without opening $if"
+@ MSG_MAP_CDIR_ELSE	"%s: %llu: %s directive preceded by $else on line %d"
+@ MSG_MAP_CDIR_NOEND	"%s: %llu: EOF encountered without closing $endif \
+			 for $if on line %d"
+@ MSG_MAP_CDIR_ERROR	"%s: %llu: error: %s"
+
+
+# Mapfile Conditional Expressions
+
+@ MSG_MAP_CEXP_TOKERR	"%s: %llu: syntax error in conditional expression at: %s"
+@ MSG_MAP_CEXP_SEMERR	"%s: %llu: malformed conditional expression"
+@ MSG_MAP_CEXP_BADOPUSE	"%s: %llu: invalid operator use in conditional \
+			 expression"
+@ MSG_MAP_CEXP_UNBALPAR	"%s: %llu: unbalanced parenthesis in conditional \
+			 expression"
+@ MSG_MAP_BADCESC	"%s: %llu: unrecognized escape in double quoted \
+			 token: \\%c\n"
+
 # Generic error diagnostic labels
 
 @ MSG_STR_NULL		"(null)"
@@ -1096,13 +1223,10 @@
 @ MSG_STR_STRNL		"%s\n"
 @ MSG_STR_NL		"\n"
 
-@ MSG_STR_INTERP	"interp"
 @ MSG_STR_LD_DYNAMIC	"dynamic"
 @ MSG_STR_SYMBOLIC	"symbolic"
 @ MSG_STR_ELIMINATE	"eliminate"
 @ MSG_STR_LOCAL		"local"
-@ MSG_STR_EXPORTED	"exported"
-@ MSG_STR_SINGLETON	"singleton"
 @ MSG_STR_PROGBITS	"progbits"
 @ MSG_STR_SYMTAB	"symtab"
 @ MSG_STR_DYNSYM	"dynsym"
@@ -1276,14 +1400,11 @@
 
 # Mapfile tokens
 
-@ MSG_MAP_TOK_1		"\"\n"
-@ MSG_MAP_TOK_2		" \"\t\n:;=#"
 @ MSG_MAP_LOAD		"load"
 @ MSG_MAP_NOTE		"note"
 @ MSG_MAP_NULL		"null"
 @ MSG_MAP_STACK		"stack"
 @ MSG_MAP_ADDVERS	"addvers"
-@ MSG_MAP_GLOBAL	"global"
 @ MSG_MAP_FUNCTION	"function"
 @ MSG_MAP_DATA		"data"
 @ MSG_MAP_COMMON	"common"
@@ -1291,9 +1412,6 @@
 @ MSG_MAP_EXTERN	"extern"
 @ MSG_MAP_DIRECT	"direct"
 @ MSG_MAP_NODIRECT	"nodirect"
-@ MSG_MAP_DEFAULT	"default"
-@ MSG_MAP_PROTECTED	"protected"
-@ MSG_MAP_HIDDEN	"hidden"
 @ MSG_MAP_FILTER	"filter"
 @ MSG_MAP_AUXILIARY	"auxiliary"
 @ MSG_MAP_OVERRIDE	"override"
@@ -1301,5 +1419,71 @@
 @ MSG_MAP_DYNSORT	"dynsort"
 @ MSG_MAP_NODYNSORT	"nodynsort"
 
+@ MSG_MAPKW_ALIGN		"ALIGN"
+@ MSG_MAPKW_ALLOC		"ALLOC"
+@ MSG_MAPKW_ALLOW		"ALLOW"
+@ MSG_MAPKW_AMD64_LARGE		"AMD64_LARGE"
+@ MSG_MAPKW_ASSIGN_SECTION	"ASSIGN_SECTION"
+@ MSG_MAPKW_AUX			"AUXILIARY"
+@ MSG_MAPKW_CAPABILITY		"CAPABILITY"
+@ MSG_MAPKW_COMMON		"COMMON"
+@ MSG_MAPKW_DATA		"DATA"
+@ MSG_MAPKW_DEFAULT		"DEFAULT"
+@ MSG_MAPKW_DEPEND_VERSIONS	"DEPEND_VERSIONS"
+@ MSG_MAPKW_DIRECT		"DIRECT"
+@ MSG_MAPKW_DISABLE		"DISABLE"
+@ MSG_MAPKW_DYNSORT		"DYNSORT"
+@ MSG_MAPKW_ELIMINATE		"ELIMINATE"
+@ MSG_MAPKW_EXECUTE		"EXECUTE"
+@ MSG_MAPKW_EXPORTED		"EXPORTED"
+@ MSG_MAPKW_EXTERN		"EXTERN"
+@ MSG_MAPKW_FILTER		"FILTER"
+@ MSG_MAPKW_FILE_BASENAME	"FILE_BASENAME"
+@ MSG_MAPKW_FILE_PATH		"FILE_PATH"
+@ MSG_MAPKW_FILE_OBJNAME	"FILE_OBJNAME"
+@ MSG_MAPKW_FUNCTION		"FUNCTION"
+@ MSG_MAPKW_FLAGS		"FLAGS"
+@ MSG_MAPKW_GLOBAL		"GLOBAL"
+@ MSG_MAPKW_INTERPOSE		"INTERPOSE"
+@ MSG_MAPKW_HIDDEN		"HIDDEN"
+@ MSG_MAPKW_HDR_NOALLOC		"HDR_NOALLOC"
+@ MSG_MAPKW_HW			"HW"
+@ MSG_MAPKW_HW_1		"HW_1"
+@ MSG_MAPKW_HW_2		"HW_2"
+@ MSG_MAPKW_IS_NAME		"IS_NAME"
+@ MSG_MAPKW_IS_ORDER		"IS_ORDER"
+@ MSG_MAPKW_LOAD_SEGMENT	"LOAD_SEGMENT"
+@ MSG_MAPKW_LOCAL		"LOCAL"
+@ MSG_MAPKW_MACHINE		"MACHINE"
+@ MSG_MAPKW_MAX_SIZE		"MAX_SIZE"
+@ MSG_MAPKW_NOHDR		"NOHDR"
+@ MSG_MAPKW_NODIRECT		"NODIRECT"
+@ MSG_MAPKW_NODYNSORT		"NODYNSORT"
+@ MSG_MAPKW_NOTE_SEGMENT	"NOTE_SEGMENT"
+@ MSG_MAPKW_NULL_SEGMENT	"NULL_SEGMENT"
+@ MSG_MAPKW_OS_ORDER		"OS_ORDER"
+@ MSG_MAPKW_PADDR		"PADDR"
+@ MSG_MAPKW_PARENT		"PARENT"
+@ MSG_MAPKW_PHDR_ADD_NULL	"PHDR_ADD_NULL"
+@ MSG_MAPKW_PLATFORM		"PLATFORM"
+@ MSG_MAPKW_PROTECTED		"PROTECTED"
+@ MSG_MAPKW_READ		"READ"
+@ MSG_MAPKW_ROUND		"ROUND"
+@ MSG_MAPKW_REQUIRE		"REQUIRE"
+@ MSG_MAPKW_SEGMENT_ORDER	"SEGMENT_ORDER"
+@ MSG_MAPKW_SF			"SF"
+@ MSG_MAPKW_SF_1		"SF_1"
+@ MSG_MAPKW_SINGLETON		"SINGLETON"
+@ MSG_MAPKW_SIZE		"SIZE"
+@ MSG_MAPKW_SIZE_SYMBOL		"SIZE_SYMBOL"
+@ MSG_MAPKW_STACK		"STACK"
+@ MSG_MAPKW_SYMBOL_SCOPE	"SYMBOL_SCOPE"
+@ MSG_MAPKW_SYMBOL_VERSION	"SYMBOL_VERSION"
+@ MSG_MAPKW_SYMBOLIC		"SYMBOLIC"
+@ MSG_MAPKW_TYPE		"TYPE"
+@ MSG_MAPKW_VADDR		"VADDR"
+@ MSG_MAPKW_VALUE		"VALUE"
+@ MSG_MAPKW_WRITE		"WRITE"
+
+
 @ MSG_STR_DTRACE	"PT_SUNWDTRACE"
-
--- a/usr/src/cmd/sgs/libld/common/libld.sparc.msg	Sun Feb 21 21:37:22 2010 -0800
+++ b/usr/src/cmd/sgs/libld/common/libld.sparc.msg	Mon Feb 22 09:19:31 2010 -0700
@@ -20,10 +20,9 @@
 #
 
 #
-# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
-# ident	"%Z%%M%	%I%	%E% SMI"
 
 @ _START_
 
@@ -45,22 +44,22 @@
 @ MSG_REL_BADGOTFIX	"relocation error: %s: file %s: symbol %s: \
 			 internal gotop_fixups error"
 @ MSG_REL_ASSIGNGOT	"internal error: assign_got() invalid got index \
-			 0x%llx for symbol `%s'"
-@ MSG_REL_SMALLGOT	"too many symbols require `small' PIC references:\n\
+			 0x%llx for symbol '%s'"
+@ 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\
+			 (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');"
-@ MSG_SYM_INCOMPREG2	"register symbol `%s' used incompatibly:\n\
+			 \t(file %s symbol '%s', file %s symbol '%s');"
+@ MSG_SYM_INCOMPREG2	"register symbol '%s' used incompatibly:\n\
 			 \t(file %s value=%s, file %s value=%s);"
 @ MSG_SYM_INCOMPREG3	"register %s local symbol visibility incompatible:\n\
-			 \t(file %s symbol `%s', file %s symbol `%s');"
-@ MSG_SYM_MULTINIREG	"register %s symbol `%s' multiply-initialized:\n\
+			 \t(file %s symbol '%s', file %s symbol '%s');"
+@ MSG_SYM_MULTINIREG	"register %s symbol '%s' multiply-initialized:\n\
 			 \t(file %s shndx=ABS, file %s shndx=ABS);"
 
 @ MSG_SYM_BADSCRATCH	"file %s: section %s: symbol[%d]: %s: malformed \
--- a/usr/src/cmd/sgs/libld/common/machrel.amd.c	Sun Feb 21 21:37:22 2010 -0800
+++ b/usr/src/cmd/sgs/libld/common/machrel.amd.c	Mon Feb 22 09:19:31 2010 -0700
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -1540,6 +1540,7 @@
 			M_SEGM_ORIGIN,		/* m_segm_origin */
 			M_SEGM_AORIGIN,		/* m_segm_aorigin */
 			M_DATASEG_PERM,		/* m_dataseg_perm */
+			M_STACK_PERM,		/* m_stack_perm */
 			M_WORD_ALIGN,		/* m_word_align */
 			MSG_ORIG(MSG_PTH_RTLD_AMD64), /* m_def_interp */
 
--- a/usr/src/cmd/sgs/libld/common/machrel.intel.c	Sun Feb 21 21:37:22 2010 -0800
+++ b/usr/src/cmd/sgs/libld/common/machrel.intel.c	Mon Feb 22 09:19:31 2010 -0700
@@ -24,7 +24,7 @@
  *	Copyright (c) 1988 AT&T
  *	  All Rights Reserved
  *
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -1637,6 +1637,7 @@
 			M_SEGM_ORIGIN,		/* m_segm_origin */
 			M_SEGM_AORIGIN,		/* m_segm_aorigin */
 			M_DATASEG_PERM,		/* m_dataseg_perm */
+			M_STACK_PERM,		/* m_stack_perm */
 			M_WORD_ALIGN,		/* m_word_align */
 			MSG_ORIG(MSG_PTH_RTLD),	/* m_def_interp */
 
--- a/usr/src/cmd/sgs/libld/common/machrel.sparc.c	Sun Feb 21 21:37:22 2010 -0800
+++ b/usr/src/cmd/sgs/libld/common/machrel.sparc.c	Mon Feb 22 09:19:31 2010 -0700
@@ -23,7 +23,7 @@
  *	Copyright (c) 1988 AT&T
  *	  All Rights Reserved
  *
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -2168,6 +2168,7 @@
 			M_SEGM_ORIGIN,		/* m_segm_origin */
 			M_SEGM_AORIGIN,		/* m_segm_aorigin */
 			M_DATASEG_PERM,		/* m_dataseg_perm */
+			M_STACK_PERM,		/* m_stack_perm */
 			M_WORD_ALIGN,		/* m_word_align */
 						/* m_def_interp */
 #if	defined(_ELF64)
--- a/usr/src/cmd/sgs/libld/common/map.c	Sun Feb 21 21:37:22 2010 -0800
+++ b/usr/src/cmd/sgs/libld/common/map.c	Mon Feb 22 09:19:31 2010 -0700
@@ -23,166 +23,26 @@
  *	Copyright (c) 1988 AT&T
  *	  All Rights Reserved
  *
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
 /*
- * Map file parsing.
+ * Map file parsing (Original SysV syntax).
  */
-#include	<fcntl.h>
 #include	<string.h>
+#include	<strings.h>
 #include	<stdio.h>
 #include	<unistd.h>
-#include	<sys/stat.h>
 #include	<errno.h>
 #include	<limits.h>
-#include	<dirent.h>
 #include	<ctype.h>
 #include	<elfcap.h>
 #include	<debug.h>
 #include	"msg.h"
 #include	"_libld.h"
-
-#if	defined(_ELF64)
-#define	STRTOADDR	strtoull
-#define	XWORD_MAX	ULLONG_MAX
-#else	/* Elf32 */
-#define	STRTOADDR	strtoul
-#define	XWORD_MAX	UINT_MAX
-#endif	/* _ELF64 */
-
-/* Possible return values from gettoken */
-typedef enum {
-	TK_ERROR =	-1,	/* Error in lexical analysis */
-	TK_STRING =	0,
-	TK_COLON =	1,
-	TK_SEMICOLON =	2,
-	TK_EQUAL =	3,
-	TK_ATSIGN =	4,
-	TK_DASH =	5,
-	TK_LEFTBKT =	6,
-	TK_RIGHTBKT =	7,
-	TK_PIPE =	8,
-	TK_EOF =	9
-} Token;
-
-
-static char	*Mapspace;	/* Malloc space holding mapfile. */
-static ulong_t	Line_num;	/* Current mapfile line number. */
-static char	*Start_tok;	/* First character of current token. */
-static char	*nextchr;	/* Next char in mapfile to examine. */
-
-/*
- * Convert a string to lowercase.
- */
-static void
-lowercase(char *str)
-{
-	while (*str = tolower(*str))
-		str++;
-}
-
-/*
- * Get a token from the mapfile.
- *
- * entry:
- *	ofl - Output file descriptor
- *	mapfile - Name of mapfile
- *	eof_ok - If False, end of file causes a premature EOF error to be
- *		issued. If True, TK_EOF is returned quietly.
- */
-static Token
-gettoken(Ofl_desc *ofl, const char *mapfile, int eof_ok)
-{
-	static char	oldchr = '\0';	/* Char at end of current token. */
-	char		*end;		/* End of the current token. */
+#include	"_map.h"
 
-	/* Cycle through the characters looking for tokens. */
-	for (;;) {
-		if (oldchr != '\0') {
-			*nextchr = oldchr;
-			oldchr = '\0';
-		}
-		if (!isascii(*nextchr) ||
-		    (!isprint(*nextchr) && !isspace(*nextchr) &&
-		    (*nextchr != '\0'))) {
-			eprintf(ofl->ofl_lml, ERR_FATAL,
-			    MSG_INTL(MSG_MAP_ILLCHAR), mapfile,
-			    EC_XWORD(Line_num), *((uchar_t *)nextchr));
-			return (TK_ERROR);
-		}
-		switch (*nextchr) {
-		case '\0':	/* End of file. */
-			if (!eof_ok)
-				eprintf(ofl->ofl_lml, ERR_FATAL,
-				    MSG_INTL(MSG_MAP_PREMEOF), mapfile,
-				    EC_XWORD(Line_num));
-			return (TK_EOF);
-
-		case ' ':	/* White space. */
-		case '\t':
-			nextchr++;
-			break;
-		case '\n':	/* White space too, but bump line number. */
-			nextchr++;
-			Line_num++;
-			break;
-		case '#':	/* Comment. */
-			while (*nextchr != '\n' && *nextchr != '\0')
-				nextchr++;
-			break;
-		case ':':
-			nextchr++;
-			return (TK_COLON);
-		case ';':
-			nextchr++;
-			return (TK_SEMICOLON);
-		case '=':
-			nextchr++;
-			return (TK_EQUAL);
-		case '@':
-			nextchr++;
-			return (TK_ATSIGN);
-		case '-':
-			nextchr++;
-			return (TK_DASH);
-		case '|':
-			nextchr++;
-			return (TK_PIPE);
-		case '{':
-			nextchr++;
-			return (TK_LEFTBKT);
-		case '}':
-			nextchr++;
-			return (TK_RIGHTBKT);
-		case '"':
-			Start_tok = ++nextchr;
-			if (((end = strpbrk(nextchr,
-			    MSG_ORIG(MSG_MAP_TOK_1))) == NULL) ||
-			    (*end != '"')) {
-				eprintf(ofl->ofl_lml, ERR_FATAL,
-				    MSG_INTL(MSG_MAP_NOTERM), mapfile,
-				    EC_XWORD(Line_num));
-				return (TK_ERROR);
-			}
-			*end = '\0';
-			nextchr = end + 1;
-			return (TK_STRING);
-		default:	/* string. */
-			Start_tok = nextchr;		/* CSTYLED */
-			end = strpbrk(nextchr, MSG_ORIG(MSG_MAP_TOK_2));
-			if (end == NULL)
-				nextchr = Start_tok + strlen(Start_tok);
-			else {
-				nextchr = end;
-				oldchr = *nextchr;
-				*nextchr = '\0';
-			}
-			return (TK_STRING);
-		}
-	}
-}
 
 /*
  * Process a hardware/software capabilities segment declaration definition.
@@ -205,88 +65,60 @@
  *
  * effectively removes any capabilities information from the final image.
  */
-static uintptr_t
-map_cap(const char *mapfile, Word type, Ofl_desc *ofl)
+static Boolean
+map_cap(Mapfile *mf, Word type, CapMask *capmask)
 {
-	Token	tok;			/* Current token. */
-	Xword	number;
-	int	used = 0;
+	Token		tok;		/* Current token. */
+	Xword		number;
+	int		used = 0;
+	Ofl_desc	*ofl = mf->mf_ofl;
+	ld_map_tkval_t	tkv;		/* Value of token */
+	elfcap_mask_t	value = 0;
 
-	while ((tok = gettoken(ofl, mapfile, 0)) != TK_SEMICOLON) {
+	if (DBG_ENABLED) {
+		Dbg_cap_mapfile_title(ofl->ofl_lml, mf->mf_lineno);
+		Dbg_cap_entry2(ofl->ofl_lml, DBG_STATE_CURRENT, CA_SUNW_HW_1,
+		    capmask, ld_targ.t_m.m_mach);
+	}
+
+	while ((tok = ld_map_gettoken(mf, TK_F_STRLC, &tkv)) !=
+	    TK_SEMICOLON) {
 		if (tok != TK_STRING) {
 			if (tok != TK_ERROR)
-				eprintf(ofl->ofl_lml, ERR_FATAL,
-				    MSG_INTL(MSG_MAP_EXPSEGATT), mapfile,
-				    EC_XWORD(Line_num));
-			return (S_ERROR);
+				mf_fatal0(mf, MSG_INTL(MSG_MAP_EXPSEGATT));
+			return (FALSE);
 		}
 
-		lowercase(Start_tok);
-
 		/*
 		 * First, determine if the token represents the reserved
 		 * OVERRIDE keyword.
 		 */
-		if (strncmp(Start_tok, MSG_ORIG(MSG_MAP_OVERRIDE),
+		if (strncmp(tkv.tkv_str, MSG_ORIG(MSG_MAP_OVERRIDE),
 		    MSG_MAP_OVERRIDE_SIZE) == 0) {
-			if (type == CA_SUNW_HW_1)
-				ofl->ofl_flags1 |= FLG_OF1_OVHWCAP;
-			else
-				ofl->ofl_flags1 |= FLG_OF1_OVSFCAP;
+			ld_map_cap_set_ovflag(mf, type);
+			used++;
+			continue;
+		}
+
+		/* Is the token a symbolic capability name? */
+		if ((number = (Xword)elfcap_tag_from_str(ELFCAP_STYLE_LC,
+		    type, tkv.tkv_str, ld_targ.t_m.m_mach)) != 0) {
+			value |= number;
 			used++;
 			continue;
 		}
 
 		/*
-		 * Next, determine if the token represents a machine specific
-		 * hardware capability, or a generic software capability.
-		 */
-		if (type == CA_SUNW_HW_1) {
-			if ((number = (Xword)elfcap_hw1_from_str(
-			    ELFCAP_STYLE_LC, Start_tok,
-			    ld_targ.t_m.m_mach)) != 0) {
-				ofl->ofl_hwcap_1 |= number;
-				used++;
-				continue;
-			}
-		} else {
-			if ((number = (Xword)elfcap_sf1_from_str(
-			    ELFCAP_STYLE_LC, Start_tok,
-			    ld_targ.t_m.m_mach)) != 0) {
-				ofl->ofl_sfcap_1 |= number;
-				used++;
-				continue;
-			}
-		}
-
-		/*
-		 * Next, determine if the token represents a numeric value.
+		 * Is the token a numeric value?
 		 */
-		if (Start_tok[0] == 'v') {
-			char		*end_tok;
-
-			errno = 0;
-			number = (Xword)strtoul(&Start_tok[1], &end_tok, 0);
-			if (errno) {
-				int	err = errno;
-				eprintf(ofl->ofl_lml, ERR_FATAL,
-				    MSG_INTL(MSG_MAP_BADCAPVAL),
-				    mapfile, EC_XWORD(Line_num), Start_tok,
-				    strerror(err));
-				return (S_ERROR);
+		if (tkv.tkv_str[0] == 'v') {
+			if (ld_map_strtoxword(&tkv.tkv_str[1], NULL,
+			    &number) != STRTOXWORD_OK) {
+				mf_fatal(mf, MSG_INTL(MSG_MAP_BADCAPVAL),
+				    tkv.tkv_str);
+				return (FALSE);
 			}
-			if (end_tok != strchr(Start_tok, '\0')) {
-				eprintf(ofl->ofl_lml, ERR_FATAL,
-				    MSG_INTL(MSG_MAP_BADCAPVAL), mapfile,
-				    EC_XWORD(Line_num), Start_tok,
-				    MSG_INTL(MSG_MAP_NOBADFRM));
-				return (S_ERROR);
-			}
-
-			if (type == CA_SUNW_HW_1)
-				ofl->ofl_hwcap_1 |= number;
-			else
-				ofl->ofl_sfcap_1 |= number;
+			value |= number;
 			used++;
 			continue;
 		}
@@ -295,78 +127,161 @@
 		 * We have an unknown token.
 		 */
 		used++;
-		eprintf(ofl->ofl_lml, ERR_FATAL, MSG_INTL(MSG_MAP_UNKCAPATTR),
-		    mapfile, EC_XWORD(Line_num), Start_tok);
-		return (S_ERROR);
+		mf_fatal(mf, MSG_INTL(MSG_MAP_UNKCAPATTR), tkv.tkv_str);
+		return (FALSE);
+	}
+
+	/* Catch empty declarations */
+	if (used == 0) {
+		mf_warn0(mf, MSG_INTL(MSG_MAP_EMPTYCAP));
+		return (TRUE);
+	}
+
+	Dbg_cap_entry(ofl->ofl_lml, DBG_STATE_NEW, type, value,
+	    ld_targ.t_m.m_mach);
+	capmask->cm_value |= value;
+
+	/* Sanity check the resulting bits */
+	if (!ld_map_cap_sanitize(mf, type, capmask))
+		return (FALSE);
+
+	DBG_CALL(Dbg_cap_entry2(ofl->ofl_lml, DBG_STATE_RESOLVED, type,
+	    capmask, ld_targ.t_m.m_mach));
+
+	return (TRUE);
+}
+
+/*
+ * Parse the flags for a segment definition. Called by map_equal().
+ *
+ * entry:
+ *	mf - Mapfile descriptor
+ *	sgp - Segment being defined
+ *	b_flags - Address of b_flags variable from map_equal().
+ *		*bflags is TRUE if flags have already been seen in, the
+ *		current segment definition directive, and FALSE otherwise.
+ *	flag_tok - Flags string, starting with the '?' character.
+ *
+ * exit:
+ *	On success, the flags have been parsed and the segment updated,
+ *	*b_flags is set to TRUE, and TRUE is returned. On error, FALSE
+ *	is returned.
+ */
+static Boolean
+map_equal_flags(Mapfile *mf, Sg_desc *sgp, Boolean *b_flags,
+    const char *flag_tok)
+{
+	Word	tmp_flags = 0;
+
+	if (*b_flags) {
+		mf_fatal(mf, MSG_INTL(MSG_MAP_MOREONCE),
+		    MSG_INTL(MSG_MAP_SEGFLAG));
+		return (FALSE);
+	}
+
+	/* Skip over the leading '?' character */
+	flag_tok++;
+
+	/*
+	 * If ? has nothing following leave the flags cleared,
+	 * otherwise OR in any flags specified.
+	 */
+	while (*flag_tok) {
+		switch (*flag_tok) {
+		case 'r':
+			tmp_flags |= PF_R;
+			break;
+		case 'w':
+			tmp_flags |= PF_W;
+			break;
+		case 'x':
+			tmp_flags |= PF_X;
+			break;
+		case 'e':
+			sgp->sg_flags |= FLG_SG_EMPTY;
+			break;
+		case 'o':
+			/*
+			 * The version 1 ?O option is incompatible with
+			 * the version 2 SEGMENT IS_ORDER attribute.
+			 */
+			if (aplist_nitems(sgp->sg_is_order) > 0) {
+				mf_fatal(mf, MSG_INTL(MSG_MAP_ISORDVER),
+				    sgp->sg_name);
+				return (FALSE);
+			}
+
+			/*
+			 * Set FLG_SG_IS_ORDER to indicate that segment has
+			 * had the ?O flag set by a version 1 mapfile.
+			 */
+			sgp->sg_flags |= FLG_SG_IS_ORDER;
+			break;
+		case 'n':
+			/*
+			 * If segment ends up as the first loadable segment,
+			 * it will not include the the ELF and program headers.
+			 */
+			sgp->sg_flags |= FLG_SG_NOHDR;
+			break;
+		default:
+			mf_fatal(mf, MSG_INTL(MSG_MAP_UNKSEGFLG), *flag_tok);
+			return (FALSE);
+		}
+		flag_tok++;
 	}
 
 	/*
-	 * Catch any empty declarations, and indicate any software capabilities
-	 * have been initialized if necessary.
+	 * Warn when changing flags except when we're adding or removing "X"
+	 * from a RW PT_LOAD segment.
 	 */
-	if (used == 0) {
-		eprintf(ofl->ofl_lml, ERR_WARNING, MSG_INTL(MSG_MAP_EMPTYCAP),
-		    mapfile, EC_XWORD(Line_num));
-	} else if (type == CA_SUNW_SF_1) {
-		Lword	badsf1;
+	if ((sgp->sg_flags & FLG_SG_P_FLAGS) &&
+	    (sgp->sg_phdr.p_flags != tmp_flags) &&
+	    !(sgp->sg_phdr.p_type == PT_LOAD &&
+	    (tmp_flags & (PF_R|PF_W)) == (PF_R|PF_W) &&
+	    (tmp_flags ^ sgp->sg_phdr.p_flags) == PF_X))
+		mf_warn(mf, MSG_INTL(MSG_MAP_REDEFATT),
+		    MSG_INTL(MSG_MAP_SEGFLAG), sgp->sg_name);
 
-		/*
-		 * Note, hardware capabilities, beyond the tokens that are
-		 * presently known, can be accepted using the V0xXXX notation,
-		 * and as these simply get or'd into the output image, we allow
-		 * any values to be supplied.  Software capability tokens
-		 * however, have an algorithm of acceptance and update (see
-		 * sf1_cap() in files.c).  Therefore only allow software
-		 * capabilities that are known.
-		 */
-		if ((badsf1 = (ofl->ofl_sfcap_1 & ~SF1_SUNW_MASK)) != 0) {
-			eprintf(ofl->ofl_lml, ERR_WARNING,
-			    MSG_INTL(MSG_MAP_BADSF1), mapfile,
-			    EC_XWORD(Line_num), EC_LWORD(badsf1));
-			ofl->ofl_sfcap_1 &= SF1_SUNW_MASK;
-		}
-		if ((ofl->ofl_sfcap_1 &
-		    (SF1_SUNW_FPKNWN | SF1_SUNW_FPUSED)) == SF1_SUNW_FPUSED) {
-			eprintf(ofl->ofl_lml, ERR_WARNING,
-			    MSG_INTL(MSG_MAPFIL_BADSF1), mapfile,
-			    EC_XWORD(Line_num), EC_LWORD(SF1_SUNW_FPUSED));
-			ofl->ofl_sfcap_1 &= ~SF1_SUNW_FPUSED;
-		}
-#if	!defined(_ELF64)
-		/*
-		 * The SF1_SUNW_ADDR32 software capability is only meaningful
-		 * when building a 64-bit object.  Warn the user, and remove the
-		 * setting, if we're building a 32-bit object.
-		 */
-		if (ofl->ofl_sfcap_1 & SF1_SUNW_ADDR32) {
-			eprintf(ofl->ofl_lml, ERR_WARNING,
-			    MSG_INTL(MSG_MAP_INADDR32SF1), mapfile,
-			    EC_XWORD(Line_num));
-			ofl->ofl_sfcap_1 &= ~SF1_SUNW_ADDR32;
-		}
-#endif
-	}
-	return (1);
+	sgp->sg_flags |= FLG_SG_P_FLAGS;
+	sgp->sg_phdr.p_flags = tmp_flags;
+	*b_flags = TRUE;
+
+	return (TRUE);
 }
 
 /*
- * Common segment error checking.
+ * Read an address (value) or size Xword from a TK_STRING token value
+ * where the first letter of the string is a letter ('v', 'l', 's', ...)
+ * followed by the numeric value.
+ *
+ * entry:
+ *	mf - Mapfile descriptor
+ *	tkv - TK_STRING token to parse
+ *	value - Address of variable to receive the resulting value.
+ *
+ * exit:
+ *	Returns TRUE for success. On failure, issues an error message
+ *	and returns FALSE.
  */
 static Boolean
-seg_check(const char *mapfile, Sg_desc *sgp, Ofl_desc *ofl, Boolean b_type,
-    Word p_type)
+valuetoxword(Mapfile *mf, ld_map_tkval_t *tkv, Xword *value)
 {
-	if (b_type) {
-		eprintf(ofl->ofl_lml, ERR_FATAL, MSG_INTL(MSG_MAP_MOREONCE),
-		    mapfile, EC_XWORD(Line_num), MSG_INTL(MSG_MAP_SEGTYP));
-		return (FALSE);
+	switch (ld_map_strtoxword(&tkv->tkv_str[1], NULL, value)) {
+	case STRTOXWORD_OK:
+		return (TRUE);
+
+	case STRTOXWORD_TOOBIG:
+		mf_fatal(mf, MSG_INTL(MSG_MAP_SEGADDR), tkv->tkv_str,
+		    MSG_INTL(MSG_MAP_EXCLIMIT));
+		break;
+	default:
+		mf_fatal(mf, MSG_INTL(MSG_MAP_SEGADDR), tkv->tkv_str,
+		    MSG_INTL(MSG_MAP_NOBADFRM));
+		break;
 	}
-	if ((sgp->sg_flags & FLG_SG_TYPE) && (sgp->sg_phdr.p_type != p_type)) {
-		eprintf(ofl->ofl_lml, ERR_WARNING, MSG_INTL(MSG_MAP_REDEFATT),
-		    mapfile, EC_XWORD(Line_num), MSG_INTL(MSG_MAP_SEGTYP),
-		    sgp->sg_name);
-	}
-	return (TRUE);
+
+	return (FALSE);
 }
 
 /*
@@ -375,10 +290,35 @@
  * 	segment_attribute : segment_type  segment_flags  virtual_addr
  *			    physical_addr  length alignment
  */
-static uintptr_t
-map_equal(const char *mapfile, Sg_desc *sgp, Ofl_desc *ofl)
+static Boolean
+map_equal(Mapfile *mf, Sg_desc *sgp)
 {
+	/*
+	 * Segment type.  Users are permitted to define PT_LOAD,
+	 * PT_NOTE, PT_SUNWSTACK and PT_NULL segments.  Other segment
+	 * types are only defined in seg_desc[].
+	 */
+	typedef struct {
+		const char	*name;	/* Name for segment type  */
+		Word		p_type;	/* PT_ constant corresponding to name */
+		sg_flags_t	sg_flags; /* Seg descriptor flags to apply */
+	} seg_types_t;
+
+	static seg_types_t seg_type_arr[] = {
+		{ MSG_ORIG(MSG_MAP_LOAD),	PT_LOAD,	FLG_SG_P_TYPE },
+		{ MSG_ORIG(MSG_MAP_STACK),	PT_SUNWSTACK,
+		    FLG_SG_P_TYPE | FLG_SG_EMPTY },
+		{ MSG_ORIG(MSG_MAP_NULL),	PT_NULL,	FLG_SG_P_TYPE },
+		{ MSG_ORIG(MSG_MAP_NOTE),	PT_NOTE,	FLG_SG_P_TYPE },
+
+		/* Array must be NULL terminated */
+		{ NULL }
+	};
+
+
+	seg_types_t	*seg_type;
 	Token	tok;			/* Current token. */
+	ld_map_tkval_t	tkv;		/* Value of token */
 	Boolean	b_type  = FALSE;	/* True if seg types found. */
 	Boolean	b_flags = FALSE;	/* True if seg flags found. */
 	Boolean	b_len   = FALSE;	/* True if seg length found. */
@@ -387,166 +327,69 @@
 	Boolean	b_paddr = FALSE;	/* True if seg physical addr found. */
 	Boolean	b_align = FALSE;	/* True if seg alignment found. */
 
-	while ((tok = gettoken(ofl, mapfile, 0)) != TK_SEMICOLON) {
+	while ((tok = ld_map_gettoken(mf, TK_F_STRLC, &tkv)) !=
+	    TK_SEMICOLON) {
 		if (tok != TK_STRING) {
 			if (tok != TK_ERROR)
-				eprintf(ofl->ofl_lml, ERR_FATAL,
-				    MSG_INTL(MSG_MAP_EXPSEGATT), mapfile,
-				    EC_XWORD(Line_num));
-			return (S_ERROR);
-		}
-
-		lowercase(Start_tok);
-
-		/*
-		 * Segment type.  Users are permitted to define PT_LOAD,
-		 * PT_NOTE, PT_STACK and PT_NULL segments.  Other segment types
-		 * are only defined in seg_desc[].
-		 */
-		if (strcmp(Start_tok, MSG_ORIG(MSG_MAP_LOAD)) == 0) {
-			if ((b_type = seg_check(mapfile, sgp, ofl, b_type,
-			    PT_LOAD)) == FALSE)
-				return (S_ERROR);
-
-			sgp->sg_phdr.p_type = PT_LOAD;
-			sgp->sg_flags |= FLG_SG_TYPE;
-
-		} else if (strcmp(Start_tok, MSG_ORIG(MSG_MAP_STACK)) == 0) {
-			if ((b_type = seg_check(mapfile, sgp, ofl, b_type,
-			    PT_SUNWSTACK)) == FALSE)
-				return (S_ERROR);
-
-			sgp->sg_phdr.p_type = PT_SUNWSTACK;
-			sgp->sg_flags |= (FLG_SG_TYPE | FLG_SG_EMPTY);
-
-		} else if (strcmp(Start_tok, MSG_ORIG(MSG_MAP_NULL)) == 0) {
-			if ((b_type = seg_check(mapfile, sgp, ofl, b_type,
-			    PT_NULL)) == FALSE)
-				return (S_ERROR);
-
-			sgp->sg_phdr.p_type = PT_NULL;
-			sgp->sg_flags |= FLG_SG_TYPE;
-
-		} else if (strcmp(Start_tok, MSG_ORIG(MSG_MAP_NOTE)) == 0) {
-			if ((b_type = seg_check(mapfile, sgp, ofl, b_type,
-			    PT_NOTE)) == FALSE)
-				return (S_ERROR);
-
-			sgp->sg_phdr.p_type = PT_NOTE;
-			sgp->sg_flags |= FLG_SG_TYPE;
+				mf_fatal0(mf, MSG_INTL(MSG_MAP_EXPSEGATT));
+			return (FALSE);
 		}
 
-		/* Segment Flags. */
-
-		else if (*Start_tok == '?') {
-			Word	tmp_flags = 0;
-			char	*flag_tok = Start_tok + 1;
-
-			if (b_flags) {
-				eprintf(ofl->ofl_lml, ERR_FATAL,
-				    MSG_INTL(MSG_MAP_MOREONCE), mapfile,
-				    EC_XWORD(Line_num),
-				    MSG_INTL(MSG_MAP_SEGFLAG));
-				return (S_ERROR);
-			}
+		/*
+		 * If it is the name of a segment type, set the type
+		 * and flags fields in the descriptor.
+		 */
+		for (seg_type = seg_type_arr; seg_type->name; seg_type++) {
+			if (strcmp(tkv.tkv_str, seg_type->name) == 0) {
+				if (b_type) {
+					mf_fatal(mf, MSG_INTL(MSG_MAP_MOREONCE),
+					    MSG_INTL(MSG_MAP_SEGTYP));
+					return (FALSE);
+				}
+				if ((sgp->sg_flags & FLG_SG_P_TYPE) &&
+				    (sgp->sg_phdr.p_type != seg_type->p_type)) {
+					mf_warn(mf, MSG_INTL(MSG_MAP_REDEFATT),
+					    MSG_INTL(MSG_MAP_SEGTYP),
+					    sgp->sg_name);
+				}
 
-			/*
-			 * If ? has nothing following leave the flags cleared,
-			 * otherwise or in any flags specified.
-			 */
-			if (*flag_tok) {
-				while (*flag_tok) {
-					switch (*flag_tok) {
-					case 'r':
-						tmp_flags |= PF_R;
-						break;
-					case 'w':
-						tmp_flags |= PF_W;
-						break;
-					case 'x':
-						tmp_flags |= PF_X;
-						break;
-					case 'e':
-						sgp->sg_flags |= FLG_SG_EMPTY;
-						break;
-					case 'o':
-						sgp->sg_flags |= FLG_SG_ORDER;
-						ofl->ofl_flags |=
-						    FLG_OF_SEGORDER;
-						break;
-					case 'n':
-						sgp->sg_flags |= FLG_SG_NOHDR;
-						break;
-					default:
-						eprintf(ofl->ofl_lml, ERR_FATAL,
-						    MSG_INTL(MSG_MAP_UNKSEGFLG),
-						    mapfile, EC_XWORD(Line_num),
-						    *flag_tok);
-						return (S_ERROR);
-					}
-					flag_tok++;
-				}
+				sgp->sg_phdr.p_type = seg_type->p_type;
+				sgp->sg_flags |= seg_type->sg_flags;
+				break;
 			}
-			/*
-			 * Warn when changing flags except when we're
-			 * adding or removing "X" from a RW PT_LOAD
-			 * segment.
-			 */
-			if ((sgp->sg_flags & FLG_SG_FLAGS) &&
-			    (sgp->sg_phdr.p_flags != tmp_flags) &&
-			    !(sgp->sg_phdr.p_type == PT_LOAD &&
-			    (tmp_flags & (PF_R|PF_W)) == (PF_R|PF_W) &&
-			    (tmp_flags ^ sgp->sg_phdr.p_flags) == PF_X)) {
-				eprintf(ofl->ofl_lml, ERR_WARNING,
-				    MSG_INTL(MSG_MAP_REDEFATT), mapfile,
-				    EC_XWORD(Line_num),
-				    MSG_INTL(MSG_MAP_SEGFLAG), sgp->sg_name);
-			}
-			sgp->sg_flags |= FLG_SG_FLAGS;
-			sgp->sg_phdr.p_flags = tmp_flags;
-			b_flags = TRUE;
+		}
+		if (seg_type->name != NULL)	/* Matched segment type */
+			continue;		/* next token */
+
+		/* Segment Flags */
+		if (*tkv.tkv_str == '?') {
+			if (!map_equal_flags(mf, sgp, &b_flags, tkv.tkv_str))
+				return (FALSE);
+			continue;		/* next token */
 		}
 
 
-		/* Segment address, length, alignment or rounding number. */
-
-		else if ((Start_tok[0] == 'l') || (Start_tok[0] == 'v') ||
-		    (Start_tok[0] == 'a') || (Start_tok[0] == 'p') ||
-		    (Start_tok[0] == 'r')) {
-			char		*end_tok;
-			Xword		number;
+		/* Segment address, length, alignment or rounding number */
+		if ((tkv.tkv_str[0] == 'l') || (tkv.tkv_str[0] == 'v') ||
+		    (tkv.tkv_str[0] == 'a') || (tkv.tkv_str[0] == 'p') ||
+		    (tkv.tkv_str[0] == 'r')) {
+			Xword	number;
 
-			if ((number = (Xword)STRTOADDR(&Start_tok[1], &end_tok,
-			    0))	>= XWORD_MAX) {
-				eprintf(ofl->ofl_lml, ERR_FATAL,
-				    MSG_INTL(MSG_MAP_SEGADDR), mapfile,
-				    EC_XWORD(Line_num), Start_tok,
-				    MSG_INTL(MSG_MAP_EXCLIMIT));
-				return (S_ERROR);
-			}
+			if (!valuetoxword(mf, &tkv, &number))
+				return (FALSE);
 
-			if (end_tok != strchr(Start_tok, '\0')) {
-				eprintf(ofl->ofl_lml, ERR_FATAL,
-				    MSG_INTL(MSG_MAP_SEGADDR), mapfile,
-				    EC_XWORD(Line_num), Start_tok,
-				    MSG_INTL(MSG_MAP_NOBADFRM));
-				return (S_ERROR);
-			}
-
-			switch (*Start_tok) {
+			switch (*tkv.tkv_str) {
 			case 'l':
 				if (b_len) {
-					eprintf(ofl->ofl_lml, ERR_FATAL,
+					mf_fatal(mf,
 					    MSG_INTL(MSG_MAP_MOREONCE),
-					    mapfile, EC_XWORD(Line_num),
 					    MSG_INTL(MSG_MAP_SEGLEN));
-					return (S_ERROR);
+					return (FALSE);
 				}
 				if ((sgp->sg_flags & FLG_SG_LENGTH) &&
 				    (sgp->sg_length != number))
-					eprintf(ofl->ofl_lml, ERR_WARNING,
+					mf_warn(mf,
 					    MSG_INTL(MSG_MAP_REDEFATT),
-					    mapfile, EC_XWORD(Line_num),
 					    MSG_INTL(MSG_MAP_SEGLEN),
 					    sgp->sg_name);
 				sgp->sg_length = number;
@@ -555,17 +398,15 @@
 				break;
 			case 'r':
 				if (b_round) {
-					eprintf(ofl->ofl_lml, ERR_FATAL,
+					mf_fatal(mf,
 					    MSG_INTL(MSG_MAP_MOREONCE),
-					    mapfile, EC_XWORD(Line_num),
 					    MSG_INTL(MSG_MAP_SEGROUND));
-					return (S_ERROR);
+					return (FALSE);
 				}
 				if ((sgp->sg_flags & FLG_SG_ROUND) &&
 				    (sgp->sg_round != number))
-					eprintf(ofl->ofl_lml, ERR_WARNING,
+					mf_warn(mf,
 					    MSG_INTL(MSG_MAP_REDEFATT),
-					    mapfile, EC_XWORD(Line_num),
 					    MSG_INTL(MSG_MAP_SEGROUND),
 					    sgp->sg_name);
 				sgp->sg_round = number;
@@ -574,73 +415,69 @@
 				break;
 			case 'v':
 				if (b_vaddr) {
-					eprintf(ofl->ofl_lml, ERR_FATAL,
+					mf_fatal(mf,
 					    MSG_INTL(MSG_MAP_MOREONCE),
-					    mapfile, EC_XWORD(Line_num),
 					    MSG_INTL(MSG_MAP_SEGVADDR));
-					return (S_ERROR);
+					return (FALSE);
 				}
-				if ((sgp->sg_flags & FLG_SG_VADDR) &&
+				if ((sgp->sg_flags & FLG_SG_P_VADDR) &&
 				    (sgp->sg_phdr.p_vaddr != number))
-					eprintf(ofl->ofl_lml, ERR_WARNING,
+					mf_warn(mf,
 					    MSG_INTL(MSG_MAP_REDEFATT),
-					    mapfile, EC_XWORD(Line_num),
 					    MSG_INTL(MSG_MAP_SEGVADDR),
 					    sgp->sg_name);
 				/* LINTED */
 				sgp->sg_phdr.p_vaddr = (Addr)number;
-				sgp->sg_flags |= FLG_SG_VADDR;
-				ofl->ofl_flags1 |= FLG_OF1_VADDR;
-				ofl->ofl_flags |= FLG_OF_SEGSORT;
+				sgp->sg_flags |= FLG_SG_P_VADDR;
 				b_vaddr = TRUE;
 				break;
 			case 'p':
 				if (b_paddr) {
-					eprintf(ofl->ofl_lml, ERR_FATAL,
+					mf_fatal(mf,
 					    MSG_INTL(MSG_MAP_MOREONCE),
-					    mapfile, EC_XWORD(Line_num),
 					    MSG_INTL(MSG_MAP_SEGPHYS));
-					return (S_ERROR);
+					return (FALSE);
 				}
-				if ((sgp->sg_flags & FLG_SG_PADDR) &&
+				if ((sgp->sg_flags & FLG_SG_P_PADDR) &&
 				    (sgp->sg_phdr.p_paddr != number))
-					eprintf(ofl->ofl_lml, ERR_WARNING,
+					mf_warn(mf,
 					    MSG_INTL(MSG_MAP_REDEFATT),
-					    mapfile, EC_XWORD(Line_num),
 					    MSG_INTL(MSG_MAP_SEGPHYS),
 					    sgp->sg_name);
 				/* LINTED */
 				sgp->sg_phdr.p_paddr = (Addr)number;
-				sgp->sg_flags |= FLG_SG_PADDR;
+				sgp->sg_flags |= FLG_SG_P_PADDR;
 				b_paddr = TRUE;
 				break;
 			case 'a':
 				if (b_align) {
-					eprintf(ofl->ofl_lml, ERR_FATAL,
+					mf_fatal(mf,
 					    MSG_INTL(MSG_MAP_MOREONCE),
-					    mapfile, EC_XWORD(Line_num),
 					    MSG_INTL(MSG_MAP_SEGALIGN));
-					return (S_ERROR);
+					return (FALSE);
 				}
-				if ((sgp->sg_flags & FLG_SG_ALIGN) &&
+				if ((sgp->sg_flags & FLG_SG_P_ALIGN) &&
 				    (sgp->sg_phdr.p_align != number))
-					eprintf(ofl->ofl_lml, ERR_WARNING,
+					mf_warn(mf,
 					    MSG_INTL(MSG_MAP_REDEFATT),
-					    mapfile, EC_XWORD(Line_num),
 					    MSG_INTL(MSG_MAP_SEGALIGN),
 					    sgp->sg_name);
 				/* LINTED */
 				sgp->sg_phdr.p_align = (Xword)number;
-				sgp->sg_flags |= FLG_SG_ALIGN;
+				sgp->sg_flags |= FLG_SG_P_ALIGN;
 				b_align = TRUE;
 				break;
 			}
-		} else {
-			eprintf(ofl->ofl_lml, ERR_FATAL,
-			    MSG_INTL(MSG_MAP_UNKSEGATT), mapfile,
-			    EC_XWORD(Line_num), Start_tok);
-			return (S_ERROR);
+
+			continue;		/* next token */
 		}
+
+		/*
+		 * If we reach the bottom of this loop, we have an
+		 * unrecognized token.
+		 */
+		mf_fatal(mf, MSG_INTL(MSG_MAP_UNKSEGATT), tkv.tkv_str);
+		return (FALSE);
 	}
 
 	/*
@@ -650,7 +487,8 @@
 	 * PT_LOAD reservations are only allowed within executables, as the
 	 * reservation must be established through exec() as part of initial
 	 * process loading.  In addition, PT_LOAD reservations must have an
-	 * associated address and size.
+	 * associated address and size. Note: This is an obsolete feature,
+	 * not supported by the newer mapfile syntax.
 	 *
 	 * PT_NULL program headers are established for later use by applications
 	 * such as the post-optimizer.  PT_NULL headers should have no other
@@ -663,40 +501,32 @@
 		 * Any style of empty segment should have no permissions.
 		 */
 		if (sgp->sg_phdr.p_flags != 0) {
-			eprintf(ofl->ofl_lml, ERR_FATAL,
-			    MSG_INTL(MSG_MAP_SEGEMNOPERM), mapfile,
-			    EC_XWORD(Line_num),
+			mf_fatal(mf, MSG_INTL(MSG_MAP_SEGEMNOPERM),
 			    EC_WORD(sgp->sg_phdr.p_flags));
-			return (S_ERROR);
+			return (FALSE);
 		}
 
 		if (sgp->sg_phdr.p_type == PT_LOAD) {
-			if ((ofl->ofl_flags & FLG_OF_EXEC) == 0) {
-				eprintf(ofl->ofl_lml, ERR_FATAL,
-				    MSG_INTL(MSG_MAP_SEGEMPEXE), mapfile,
-				    EC_XWORD(Line_num));
-				return (S_ERROR);
+			if ((mf->mf_ofl->ofl_flags & FLG_OF_EXEC) == 0) {
+				mf_fatal0(mf, MSG_INTL(MSG_MAP_SEGEMPEXE));
+				return (FALSE);
 			}
-			if ((sgp->sg_flags & (FLG_SG_LENGTH | FLG_SG_VADDR)) !=
-			    (FLG_SG_LENGTH | FLG_SG_VADDR)) {
-				eprintf(ofl->ofl_lml, ERR_FATAL,
-				    MSG_INTL(MSG_MAP_SEGEMPATT), mapfile,
-				    EC_XWORD(Line_num));
-				return (S_ERROR);
+			if ((sgp->sg_flags &
+			    (FLG_SG_LENGTH | FLG_SG_P_VADDR)) !=
+			    (FLG_SG_LENGTH | FLG_SG_P_VADDR)) {
+				mf_fatal0(mf, MSG_INTL(MSG_MAP_SEGEMPATT));
+				return (FALSE);
 			}
 		} else if (sgp->sg_phdr.p_type == PT_NULL) {
-			if ((sgp->sg_flags & (FLG_SG_LENGTH | FLG_SG_VADDR)) &&
+			if ((sgp->sg_flags &
+			    (FLG_SG_LENGTH | FLG_SG_P_VADDR)) &&
 			    ((sgp->sg_length != 0) ||
 			    (sgp->sg_phdr.p_vaddr != 0))) {
-				eprintf(ofl->ofl_lml, ERR_FATAL,
-				    MSG_INTL(MSG_MAP_SEGEMPNOATT), mapfile,
-				    EC_XWORD(Line_num));
-				return (S_ERROR);
+				mf_fatal0(mf, MSG_INTL(MSG_MAP_SEGEMPNOATT));
+				return (FALSE);
 			}
 		} else {
-			eprintf(ofl->ofl_lml, ERR_WARNING,
-			    MSG_INTL(MSG_MAP_SEGEMPLOAD), mapfile,
-			    EC_XWORD(Line_num));
+			mf_warn0(mf, MSG_INTL(MSG_MAP_SEGEMPLOAD));
 			sgp->sg_phdr.p_type = PT_LOAD;
 		}
 	}
@@ -705,9 +535,9 @@
 	 * All segment attributes have now been scanned.  Certain flags do not
 	 * make sense if this is not a loadable segment, fix if necessary.
 	 * Note, if the segment is of type PT_NULL it must be new, and any
-	 * defaults will be applied back in ld_map_parse().
-	 * When clearing an attribute leave the flag set as an indicator for
-	 * later entries re-specifying the same segment.
+	 * defaults will be applied by ld_map_seg_insert(). When clearing an
+	 * attribute leave the flag set as an indicator for later entries
+	 * re-specifying the same segment.
 	 */
 	if ((sgp->sg_phdr.p_type != PT_NULL) &&
 	    (sgp->sg_phdr.p_type != PT_LOAD)) {
@@ -718,126 +548,129 @@
 		else
 			fmt = MSG_INTL(MSG_MAP_NONLOAD);
 
-		if ((sgp->sg_flags & FLG_SG_FLAGS) &&
+		if ((sgp->sg_flags & FLG_SG_P_FLAGS) &&
 		    (sgp->sg_phdr.p_type != PT_SUNWSTACK)) {
 			if (sgp->sg_phdr.p_flags != 0) {
-				eprintf(ofl->ofl_lml, ERR_WARNING,
-				    MSG_INTL(MSG_MAP_NONLOAD), mapfile,
-				    EC_XWORD(Line_num),
+				mf_warn(mf, MSG_INTL(MSG_MAP_NONLOAD),
 				    MSG_INTL(MSG_MAP_SEGFLAG));
 				sgp->sg_phdr.p_flags = 0;
 			}
 		}
 		if (sgp->sg_flags & FLG_SG_LENGTH)
 			if (sgp->sg_length != 0) {
-				eprintf(ofl->ofl_lml, ERR_WARNING,
-				    fmt, mapfile, EC_XWORD(Line_num),
-				    MSG_INTL(MSG_MAP_SEGLEN));
+				mf_warn(mf, fmt, MSG_INTL(MSG_MAP_SEGLEN));
 				sgp->sg_length = 0;
 			}
 		if (sgp->sg_flags & FLG_SG_ROUND)
 			if (sgp->sg_round != 0) {
-				eprintf(ofl->ofl_lml, ERR_WARNING,
-				    fmt, mapfile, EC_XWORD(Line_num),
-				    MSG_INTL(MSG_MAP_SEGROUND));
+				mf_warn(mf, fmt, MSG_INTL(MSG_MAP_SEGROUND));
 				sgp->sg_round = 0;
 			}
-		if (sgp->sg_flags & FLG_SG_VADDR) {
+		if (sgp->sg_flags & FLG_SG_P_VADDR) {
 			if (sgp->sg_phdr.p_vaddr != 0) {
-				eprintf(ofl->ofl_lml, ERR_WARNING,
-				    fmt, mapfile, EC_XWORD(Line_num),
-				    MSG_INTL(MSG_MAP_SEGVADDR));
+				mf_warn(mf, fmt, MSG_INTL(MSG_MAP_SEGVADDR));
 				sgp->sg_phdr.p_vaddr = 0;
 			}
 		}
-		if (sgp->sg_flags & FLG_SG_PADDR)
+		if (sgp->sg_flags & FLG_SG_P_PADDR)
 			if (sgp->sg_phdr.p_paddr != 0) {
-				eprintf(ofl->ofl_lml, ERR_WARNING,
-				    fmt, mapfile, EC_XWORD(Line_num),
-				    MSG_INTL(MSG_MAP_SEGPHYS));
+				mf_warn(mf, fmt, MSG_INTL(MSG_MAP_SEGPHYS));
 				sgp->sg_phdr.p_paddr = 0;
 			}
-		if (sgp->sg_flags & FLG_SG_ALIGN)
+		if (sgp->sg_flags & FLG_SG_P_ALIGN)
 			if (sgp->sg_phdr.p_align != 0) {
-				eprintf(ofl->ofl_lml, ERR_WARNING,
-				    fmt, mapfile, EC_XWORD(Line_num),
-				    MSG_INTL(MSG_MAP_SEGALIGN));
+				mf_warn(mf, fmt, MSG_INTL(MSG_MAP_SEGALIGN));
 				sgp->sg_phdr.p_align = 0;
 			}
 	}
-	return (1);
+	return (TRUE);
 }
 
 
 /*
  * Process a mapfile mapping directives definition.
+ *
  * 	segment_name : section_attribute [ : file_name ]
- * 	segment_attribute : section_name section_type section_flags;
+ *
+ * Where segment_attribute is one of: section_name section_type section_flags;
  */
-static uintptr_t
-map_colon(Ofl_desc *ofl, const char *mapfile, Ent_desc *enp)
+static Boolean
+map_colon(Mapfile *mf, Ent_desc *enp)
 {
-	Token		tok;		/* Current token. */
-
+	Token		tok;
+	ld_map_tkval_t	tkv;
 	Boolean		b_name = FALSE;
 	Boolean		b_type = FALSE;
 	Boolean		b_attr = FALSE;
 	Boolean		b_bang = FALSE;
-	static	Xword	index = 0;
 
 
-	while (((tok = gettoken(ofl, mapfile, 0)) != TK_COLON) &&
+	/*
+	 * Start out assuming that this entrance criteria will be empty,
+	 * and therefore match anything. We clear the CATCHALL flag below
+	 * if this turns out not to be the case.
+	 */
+	enp->ec_flags |= FLG_EC_CATCHALL;
+
+	while (((tok = ld_map_gettoken(mf, 0, &tkv)) != TK_COLON) &&
 	    (tok != TK_SEMICOLON)) {
-		if ((tok == TK_ERROR) || (tok == TK_EOF))
-			return (S_ERROR);
+		if (tok == TK_ERROR)
+			return (FALSE);
+		if (tok != TK_STRING) {
+			mf_fatal0(mf, MSG_INTL(MSG_MAP_MALFORM));
+			return (FALSE);
+		}
 
 		/* Segment type. */
 
-		if (*Start_tok == '$') {
+		if (*tkv.tkv_str == '$') {
 			if (b_type) {
-				eprintf(ofl->ofl_lml, ERR_FATAL,
-				    MSG_INTL(MSG_MAP_MOREONCE), mapfile,
-				    EC_XWORD(Line_num),
+				mf_fatal(mf, MSG_INTL(MSG_MAP_MOREONCE),
 				    MSG_INTL(MSG_MAP_SECTYP));
-				return (S_ERROR);
+				return (FALSE);
 			}
 			b_type = TRUE;
-			Start_tok++;
-			lowercase(Start_tok);
-			if (strcmp(Start_tok, MSG_ORIG(MSG_STR_PROGBITS)) == 0)
+			tkv.tkv_str++;
+			ld_map_lowercase(tkv.tkv_str);
+			if (strcmp(tkv.tkv_str, MSG_ORIG(MSG_STR_PROGBITS)) ==
+			    0)
 				enp->ec_type = SHT_PROGBITS;
-			else if (strcmp(Start_tok,
+			else if (strcmp(tkv.tkv_str,
 			    MSG_ORIG(MSG_STR_SYMTAB)) == 0)
 				enp->ec_type = SHT_SYMTAB;
-			else if (strcmp(Start_tok,
+			else if (strcmp(tkv.tkv_str,
 			    MSG_ORIG(MSG_STR_DYNSYM)) == 0)
 				enp->ec_type = SHT_DYNSYM;
-			else if (strcmp(Start_tok,
+			else if (strcmp(tkv.tkv_str,
 			    MSG_ORIG(MSG_STR_STRTAB)) == 0)
 				enp->ec_type = SHT_STRTAB;
-			else if ((strcmp(Start_tok,
+			else if ((strcmp(tkv.tkv_str,
 			    MSG_ORIG(MSG_STR_REL)) == 0) ||
-			    (strcmp(Start_tok, MSG_ORIG(MSG_STR_RELA)) == 0))
+			    (strcmp(tkv.tkv_str, MSG_ORIG(MSG_STR_RELA)) == 0))
 				enp->ec_type = ld_targ.t_m.m_rel_sht_type;
-			else if (strcmp(Start_tok, MSG_ORIG(MSG_STR_HASH)) == 0)
+			else if (strcmp(tkv.tkv_str, MSG_ORIG(MSG_STR_HASH)) ==
+			    0)
 				enp->ec_type = SHT_HASH;
-			else if (strcmp(Start_tok, MSG_ORIG(MSG_STR_LIB)) == 0)
+			else if (strcmp(tkv.tkv_str, MSG_ORIG(MSG_STR_LIB)) ==
+			    0)
 				enp->ec_type = SHT_SHLIB;
-			else if (strcmp(Start_tok,
+			else if (strcmp(tkv.tkv_str,
 			    MSG_ORIG(MSG_STR_LD_DYNAMIC)) == 0)
 				enp->ec_type = SHT_DYNAMIC;
-			else if (strcmp(Start_tok, MSG_ORIG(MSG_STR_NOTE)) == 0)
+			else if (strcmp(tkv.tkv_str, MSG_ORIG(MSG_STR_NOTE)) ==
+			    0)
 				enp->ec_type = SHT_NOTE;
-			else if (strcmp(Start_tok,
+			else if (strcmp(tkv.tkv_str,
 			    MSG_ORIG(MSG_STR_NOBITS)) == 0)
 				enp->ec_type = SHT_NOBITS;
 			else {
-				eprintf(ofl->ofl_lml, ERR_FATAL,
-				    MSG_INTL(MSG_MAP_UNKSECTYP), mapfile,
-				    EC_XWORD(Line_num), Start_tok);
-				return (S_ERROR);
+				mf_fatal(mf, MSG_INTL(MSG_MAP_UNKSECTYP),
+				    tkv.tkv_str);
+				return (FALSE);
 			}
 
+			enp->ec_flags &= ~FLG_EC_CATCHALL;
+
 		/*
 		 * Segment flags.
 		 * If a segment flag is specified then the appropriate bit is
@@ -846,37 +679,33 @@
 		 * ie.	for  ?A the attrmask is set and the attrbit is set,
 		 *	for ?!A the attrmask is set and the attrbit is clear.
 		 */
-		} else if (*Start_tok == '?') {
+		} else if (*tkv.tkv_str == '?') {
 			if (b_attr) {
-				eprintf(ofl->ofl_lml, ERR_FATAL,
-				    MSG_INTL(MSG_MAP_MOREONCE), mapfile,
-				    EC_XWORD(Line_num),
+				mf_fatal(mf, MSG_INTL(MSG_MAP_MOREONCE),
 				    MSG_INTL(MSG_MAP_SECFLAG));
-				return (S_ERROR);
+				return (FALSE);
 			}
 			b_attr = TRUE;
 			b_bang = FALSE;
-			Start_tok++;
-			lowercase(Start_tok);
-			for (; *Start_tok != '\0'; Start_tok++)
-				switch (*Start_tok) {
+			tkv.tkv_str++;
+			ld_map_lowercase(tkv.tkv_str);
+			for (; *tkv.tkv_str != '\0'; tkv.tkv_str++)
+				switch (*tkv.tkv_str) {
 				case '!':
 					if (b_bang) {
-						eprintf(ofl->ofl_lml, ERR_FATAL,
+						mf_fatal(mf,
 						    MSG_INTL(MSG_MAP_BADFLAG),
-						    mapfile, EC_XWORD(Line_num),
-						    Start_tok);
-						return (S_ERROR);
+						    tkv.tkv_str);
+						return (FALSE);
 					}
 					b_bang = TRUE;
 					break;
 				case 'a':
 					if (enp->ec_attrmask & SHF_ALLOC) {
-						eprintf(ofl->ofl_lml, ERR_FATAL,
+						mf_fatal(mf,
 						    MSG_INTL(MSG_MAP_BADFLAG),
-						    mapfile, EC_XWORD(Line_num),
-						    Start_tok);
-						return (S_ERROR);
+						    tkv.tkv_str);
+						return (FALSE);
 					}
 					enp->ec_attrmask |= SHF_ALLOC;
 					if (!b_bang)
@@ -885,11 +714,10 @@
 					break;
 				case 'w':
 					if (enp->ec_attrmask & SHF_WRITE) {
-						eprintf(ofl->ofl_lml, ERR_FATAL,
+						mf_fatal(mf,
 						    MSG_INTL(MSG_MAP_BADFLAG),
-						    mapfile, EC_XWORD(Line_num),
-						    Start_tok);
-						return (S_ERROR);
+						    tkv.tkv_str);
+						return (FALSE);
 					}
 					enp->ec_attrmask |= SHF_WRITE;
 					if (!b_bang)
@@ -898,11 +726,10 @@
 					break;
 				case 'x':
 					if (enp->ec_attrmask & SHF_EXECINSTR) {
-						eprintf(ofl->ofl_lml, ERR_FATAL,
+						mf_fatal(mf,
 						    MSG_INTL(MSG_MAP_BADFLAG),
-						    mapfile, EC_XWORD(Line_num),
-						    Start_tok);
-						return (S_ERROR);
+						    tkv.tkv_str);
+						return (FALSE);
 					}
 					enp->ec_attrmask |= SHF_EXECINSTR;
 					if (!b_bang)
@@ -911,236 +738,115 @@
 					b_bang = FALSE;
 					break;
 				default:
-					eprintf(ofl->ofl_lml, ERR_FATAL,
+					mf_fatal(mf,
 					    MSG_INTL(MSG_MAP_BADFLAG),
-					    mapfile, EC_XWORD(Line_num),
-					    Start_tok);
-					return (S_ERROR);
+					    tkv.tkv_str);
+					return (FALSE);
 				}
+			if (enp->ec_attrmask != 0)
+				enp->ec_flags &= ~FLG_EC_CATCHALL;
+
 		/*
 		 * Section name.
 		 */
 		} else {
 			if (b_name) {
-				eprintf(ofl->ofl_lml, ERR_FATAL,
-				    MSG_INTL(MSG_MAP_MOREONCE), mapfile,
-				    EC_XWORD(Line_num),
+				mf_fatal(mf, MSG_INTL(MSG_MAP_MOREONCE),
 				    MSG_INTL(MSG_MAP_SECNAME));
-				return (S_ERROR);
+				return (FALSE);
 			}
 			b_name = TRUE;
-			if ((enp->ec_name =
-			    libld_malloc(strlen(Start_tok) + 1)) == NULL)
-				return (S_ERROR);
-			(void) strcpy((char *)enp->ec_name, Start_tok);
-			/*
-			 * Set the index for text reordering.
-			 */
-			enp->ec_ordndx = ++index;
+			enp->ec_is_name = tkv.tkv_str;
+			enp->ec_flags &= ~FLG_EC_CATCHALL;
 		}
 	}
 	if (tok == TK_COLON) {
 		/*
 		 * File names.
 		 */
-		while ((tok = gettoken(ofl, mapfile, 0)) != TK_SEMICOLON) {
-			char	*file;
+		while ((tok = ld_map_gettoken(mf, 0, &tkv)) != TK_SEMICOLON) {
+			Word	ecf_type;
 
 			if (tok != TK_STRING) {
 				if (tok != TK_ERROR)
-					eprintf(ofl->ofl_lml, ERR_FATAL,
-					    MSG_INTL(MSG_MAP_MALFORM), mapfile,
-					    EC_XWORD(Line_num));
-				return (S_ERROR);
+					mf_fatal0(mf,
+					    MSG_INTL(MSG_MAP_MALFORM));
+				return (FALSE);
 			}
-			if ((file =
-			    libld_malloc(strlen(Start_tok) + 1)) == NULL)
-				return (S_ERROR);
-			(void) strcpy(file, Start_tok);
 
-			if (aplist_append(&(enp->ec_files), file,
-			    AL_CNT_EC_FILES) == NULL)
-				return (S_ERROR);
+			/*
+			 * A leading '*' means that this should be a basename
+			 * comparison rather than a full path. It's not a glob
+			 * wildcard, although it looks like one.
+			 */
+			if (tkv.tkv_str[0] == '*') {
+				ecf_type = TYP_ECF_BASENAME;
+				tkv.tkv_str++;
+			} else {
+				ecf_type = TYP_ECF_PATH;
+			}
+			if (!ld_map_seg_ent_files(mf, enp, ecf_type,
+			    tkv.tkv_str))
+				return (FALSE);
+			enp->ec_flags &= ~FLG_EC_CATCHALL;
 		}
 	}
-	return (1);
-}
-
-/*
- * Obtain a pseudo input file descriptor to assign to a mapfile.  This is
- * required any time a symbol is generated.  Traverse the input file
- * descriptors looking for a match.  As all mapfile processing occurs before
- * any real input file processing this list is going to be small and we don't
- * need to do any filename clash checking.
- */
-static Ifl_desc *
-map_ifl(const char *mapfile, Ofl_desc *ofl)
-{
-	Ifl_desc	*ifl;
-	Aliste		idx;
-
-	for (APLIST_TRAVERSE(ofl->ofl_objs, idx, ifl))
-		if (strcmp(ifl->ifl_name, mapfile) == 0)
-			return (ifl);
-
-	if ((ifl = libld_calloc(sizeof (Ifl_desc), 1)) == NULL)
-		return ((Ifl_desc *)S_ERROR);
-	ifl->ifl_name = mapfile;
-	ifl->ifl_flags = (FLG_IF_MAPFILE | FLG_IF_NEEDED | FLG_IF_FILEREF);
-	if ((ifl->ifl_ehdr = libld_calloc(sizeof (Ehdr), 1)) == NULL)
-		return ((Ifl_desc *)S_ERROR);
-	ifl->ifl_ehdr->e_type = ET_REL;
-
-	if (aplist_append(&ofl->ofl_objs, ifl, AL_CNT_OFL_OBJS) == NULL)
-		return ((Ifl_desc *)S_ERROR);
-	else
-		return (ifl);
+	return (TRUE);
 }
 
 /*
  * Process a mapfile size symbol definition.
  * 	segment_name @ symbol_name;
  */
-static uintptr_t
-map_atsign(const char *mapfile, Sg_desc *sgp, Ofl_desc *ofl)
+static Boolean
+map_atsign(Mapfile *mf, Sg_desc *sgp)
 {
-	Sym		*sym;		/* New symbol pointer */
-	Sym_desc	*sdp;		/* New symbol node pointer */
-	Ifl_desc	*ifl;		/* Dummy input file structure */
 	Token		tok;		/* Current token. */
-	avl_index_t	where;
+	ld_map_tkval_t	tkv;		/* Value of token */
 
-	if ((tok = gettoken(ofl, mapfile, 0)) != TK_STRING) {
+	if ((tok = ld_map_gettoken(mf, 0, &tkv)) != TK_STRING) {
 		if (tok != TK_ERROR)
-			eprintf(ofl->ofl_lml, ERR_FATAL,
-			    MSG_INTL(MSG_MAP_EXPSYM_1), mapfile,
-			    EC_XWORD(Line_num));
-		return (S_ERROR);
-	}
-
-	if (sgp->sg_sizesym != NULL) {
-		eprintf(ofl->ofl_lml, ERR_FATAL, MSG_INTL(MSG_MAP_SEGSIZE),
-		    mapfile, EC_XWORD(Line_num), sgp->sg_name);
-		return (S_ERROR);
+			mf_fatal0(mf, MSG_INTL(MSG_MAP_EXPSYM_1));
+		return (FALSE);
 	}
 
-	/*
-	 * Make sure we have a pseudo file descriptor to associate to the
-	 * symbol.
-	 */
-	if ((ifl = map_ifl(mapfile, ofl)) == (Ifl_desc *)S_ERROR)
-		return (S_ERROR);
+	/* Add the symbol to the segment */
+	if (!ld_map_seg_size_symbol(mf, sgp, TK_PLUSEQ, tkv.tkv_str))
+		return (FALSE);
 
-	/*
-	 * Make sure the symbol doesn't already exist.  It is possible that the
-	 * symbol has been scoped or versioned, in which case it does exist
-	 * but we can freely update it here.
-	 */
-	if ((sdp = ld_sym_find(Start_tok, SYM_NOHASH, &where, ofl)) == NULL) {
-		char	*name;
-		Word hval;
-
-		if ((name = libld_malloc(strlen(Start_tok) + 1)) == NULL)
-			return (S_ERROR);
-		(void) strcpy(name, Start_tok);
-
-		if ((sym = libld_calloc(sizeof (Sym), 1)) == NULL)
-			return (S_ERROR);
-		sym->st_shndx = SHN_ABS;
-		sym->st_size = 0;
-		sym->st_info = ELF_ST_INFO(STB_GLOBAL, STT_OBJECT);
 
-		DBG_CALL(Dbg_map_size_new(ofl->ofl_lml, name));
-		/* LINTED */
-		hval = (Word)elf_hash(name);
-		if ((sdp = ld_sym_enter(name, sym, hval, ifl, ofl, 0, SHN_ABS,
-		    (FLG_SY_SPECSEC | FLG_SY_GLOBREF), &where)) ==
-		    (Sym_desc *)S_ERROR)
-			return (S_ERROR);
-		sdp->sd_flags &= ~FLG_SY_CLEAN;
-		DBG_CALL(Dbg_map_symbol(ofl, sdp));
-	} else {
-		sym = sdp->sd_sym;
-
-		if (sym->st_shndx == SHN_UNDEF) {
-			sdp->sd_shndx = sym->st_shndx = SHN_ABS;
-			sdp->sd_flags |= FLG_SY_SPECSEC;
-			sym->st_size = 0;
-			sym->st_info = ELF_ST_INFO(STB_GLOBAL, STT_OBJECT);
-
-			sdp->sd_flags &= ~FLG_SY_MAPREF;
-
-			DBG_CALL(Dbg_map_size_old(ofl, sdp));
-		} else {
-			eprintf(ofl->ofl_lml, ERR_FATAL,
-			    MSG_INTL(MSG_MAP_SYMDEF1), mapfile,
-			    EC_XWORD(Line_num), demangle(sdp->sd_name),
-			    sdp->sd_file->ifl_name,
-			    MSG_INTL(MSG_MAP_DIFF_SYMMUL));
-			return (S_ERROR);
-		}
+	if (ld_map_gettoken(mf, 0, &tkv) != TK_SEMICOLON) {
+		if (tok != TK_ERROR)
+			mf_fatal0(mf, MSG_INTL(MSG_MAP_EXPSCOL));
+		return (FALSE);
 	}
 
-	/*
-	 * Assign the symbol to the segment.
-	 */
-	sgp->sg_sizesym = sdp;
-
-	if (gettoken(ofl, mapfile, 0) != TK_SEMICOLON) {
-		if (tok != TK_ERROR)
-			eprintf(ofl->ofl_lml, ERR_FATAL,
-			    MSG_INTL(MSG_MAP_EXPSCOL), mapfile,
-			    EC_XWORD(Line_num));
-		return (S_ERROR);
-	}
-
-	return (1);
+	return (TRUE);
 }
 
 
-static uintptr_t
-map_pipe(Ofl_desc *ofl, const char *mapfile, Sg_desc *sgp)
+static Boolean
+map_pipe(Mapfile *mf, Sg_desc *sgp)
 {
-	char		*sec_name;	/* section name */
 	Token		tok;		/* current token. */
-	Sec_order	*sc_order;
-	static Word	index = 0;	/* used to maintain a increasing */
-					/* 	index for section ordering. */
+	ld_map_tkval_t	tkv;		/* Value of token */
 
-	if ((tok = gettoken(ofl, mapfile, 0)) != TK_STRING) {
+	if ((tok = ld_map_gettoken(mf, 0, &tkv)) != TK_STRING) {
 		if (tok != TK_ERROR)
-			eprintf(ofl->ofl_lml, ERR_FATAL,
-			    MSG_INTL(MSG_MAP_EXPSEC), mapfile,
-			    EC_XWORD(Line_num));
-		return (S_ERROR);
+			mf_fatal0(mf, MSG_INTL(MSG_MAP_EXPSEC));
+		return (FALSE);
 	}
 
-	if ((sec_name = libld_malloc(strlen(Start_tok) + 1)) == NULL)
-		return (S_ERROR);
-	(void) strcpy(sec_name, Start_tok);
-
-	if ((sc_order = libld_malloc(sizeof (Sec_order))) == NULL)
-		return (S_ERROR);
-
-	sc_order->sco_secname = sec_name;
-	sc_order->sco_index = ++index;
+	if (!ld_map_seg_os_order_add(mf, sgp, tkv.tkv_str))
+		return (FALSE);
 
-	if (aplist_append(&sgp->sg_secorder, sc_order,
-	    AL_CNT_SG_SECORDER) == NULL)
-		return (S_ERROR);
-
-	ofl->ofl_flags |= FLG_OF_SECORDER;
-	DBG_CALL(Dbg_map_pipe(ofl->ofl_lml, sgp, sec_name, index));
-
-	if ((tok = gettoken(ofl, mapfile, 0)) != TK_SEMICOLON) {
+	if ((tok = ld_map_gettoken(mf, 0, &tkv)) != TK_SEMICOLON) {
 		if (tok != TK_ERROR)
-			eprintf(ofl->ofl_lml, ERR_FATAL,
-			    MSG_INTL(MSG_MAP_EXPSCOL), mapfile,
-			    EC_XWORD(Line_num));
-		return (S_ERROR);
+			mf_fatal0(mf, MSG_INTL(MSG_MAP_EXPSCOL));
+		return (FALSE);
 	}
 
-	return (1);
+	return (TRUE);
 }
 
 /*
@@ -1149,40 +855,29 @@
  *	shared object definition : [ shared object type [ = SONAME ]]
  *					[ versions ];
  */
-static uintptr_t
-map_dash(const char *mapfile, char *name, Ofl_desc *ofl)
+static Boolean
+map_dash(Mapfile *mf, char *name)
 {
-	char		*version;
 	Token		tok;
 	Sdf_desc	*sdf;
-	Sdv_desc	sdv;
+	ld_map_tkval_t	tkv;		/* Value of token */
 	enum {
 	    MD_NONE = 0,
 	    MD_ADDVERS,
 	}		dolkey = MD_NONE;
 
-
-	/*
-	 * If a shared object definition for this file already exists use it,
-	 * otherwise allocate a new descriptor.
-	 */
-	if ((sdf = sdf_find(name, ofl->ofl_socntl)) == NULL) {
-		if ((sdf = sdf_add(name, &ofl->ofl_socntl)) ==
-		    (Sdf_desc *)S_ERROR)
-			return (S_ERROR);
-		sdf->sdf_rfile = mapfile;
-	}
+	/* Get descriptor for dependency */
+	if ((sdf = ld_map_dv(mf, name)) == NULL)
+		return (FALSE);
 
 	/*
 	 * Get the shared object descriptor string.
 	 */
-	while ((tok = gettoken(ofl, mapfile, 0)) != TK_SEMICOLON) {
+	while ((tok = ld_map_gettoken(mf, 0, &tkv)) != TK_SEMICOLON) {
 		if ((tok != TK_STRING) && (tok != TK_EQUAL)) {
 			if (tok != TK_ERROR)
-				eprintf(ofl->ofl_lml, ERR_FATAL,
-				    MSG_INTL(MSG_MAP_EXPSO), mapfile,
-				    EC_XWORD(Line_num));
-			return (S_ERROR);
+				mf_fatal0(mf, MSG_INTL(MSG_MAP_EXPSO));
+			return (FALSE);
 		}
 
 		/*
@@ -1190,36 +885,22 @@
 		 * definition.
 		 */
 		if (tok == TK_EQUAL) {
-			if ((tok = gettoken(ofl, mapfile, 0)) != TK_STRING) {
+			if ((tok = ld_map_gettoken(mf, 0, &tkv)) !=
+			    TK_STRING) {
 				if (tok != TK_ERROR)
-					eprintf(ofl->ofl_lml, ERR_FATAL,
-					    MSG_INTL(MSG_MAP_EXPSO), mapfile,
-					    EC_XWORD(Line_num));
-				return (S_ERROR);
+					mf_fatal0(mf,
+					    MSG_INTL(MSG_MAP_EXPSO));
+				return (FALSE);
 			}
 			switch (dolkey) {
 			case MD_ADDVERS:
-				sdf->sdf_flags |= FLG_SDF_ADDVER;
-
-				if ((version = libld_malloc(
-				    strlen(Start_tok) + 1)) == NULL)
-					return (S_ERROR);
-				(void) strcpy(version, Start_tok);
-
-				sdv.sdv_name = version;
-				sdv.sdv_ref = mapfile;
-				sdv.sdv_flags = 0;
-
-				if (alist_append(&sdf->sdf_verneed, &sdv,
-				    sizeof (Sdv_desc),
-				    AL_CNT_SDF_VERSIONS) == NULL)
-					return (S_ERROR);
+				if (!ld_map_dv_entry(mf, sdf, TRUE,
+				    tkv.tkv_str))
+					return (FALSE);
 				break;
 			case MD_NONE:
-				eprintf(ofl->ofl_lml, ERR_FATAL,
-				    MSG_INTL(MSG_MAP_UNEXTOK), mapfile,
-				    EC_XWORD(Line_num), '=');
-				return (S_ERROR);
+				mf_fatal(mf, MSG_INTL(MSG_MAP_UNEXTOK), '=');
+				return (FALSE);
 			}
 			dolkey = MD_NONE;
 			continue;
@@ -1229,23 +910,20 @@
 		 * A shared object type has been specified.  This may also be
 		 * accompanied by an SONAME redefinition (see above).
 		 */
-		if (*Start_tok == '$') {
+		if (*tkv.tkv_str == '$') {
 			if (dolkey != MD_NONE) {
-				eprintf(ofl->ofl_lml, ERR_FATAL,
-				    MSG_INTL(MSG_MAP_UNEXTOK), mapfile,
-				    EC_XWORD(Line_num), '$');
-				return (S_ERROR);
+				mf_fatal(mf, MSG_INTL(MSG_MAP_UNEXTOK), '$');
+				return (FALSE);
 			}
-			Start_tok++;
-			lowercase(Start_tok);
-			if (strcmp(Start_tok,
-			    MSG_ORIG(MSG_MAP_ADDVERS)) == 0)
+			tkv.tkv_str++;
+			ld_map_lowercase(tkv.tkv_str);
+			if (strcmp(tkv.tkv_str, MSG_ORIG(MSG_MAP_ADDVERS)) ==
+			    0) {
 				dolkey = MD_ADDVERS;
-			else {
-				eprintf(ofl->ofl_lml, ERR_FATAL,
-				    MSG_INTL(MSG_MAP_UNKSOTYP), mapfile,
-				    EC_XWORD(Line_num), Start_tok);
-				return (S_ERROR);
+			} else {
+				mf_fatal(mf, MSG_INTL(MSG_MAP_UNKSOTYP),
+				    tkv.tkv_str);
+				return (FALSE);
 			}
 			continue;
 		}
@@ -1253,23 +931,11 @@
 		/*
 		 * shared object version requirement.
 		 */
-		if ((version = libld_malloc(strlen(Start_tok) + 1)) == NULL)
-			return (S_ERROR);
-		(void) strcpy(version, Start_tok);
-
-		sdf->sdf_flags |= FLG_SDF_SELECT;
-
-		sdv.sdv_name = version;
-		sdv.sdv_ref = mapfile;
-		sdv.sdv_flags = 0;
-
-		if (alist_append(&sdf->sdf_vers, &sdv, sizeof (Sdv_desc),
-		    AL_CNT_SDF_VERSIONS) == NULL)
-			return (S_ERROR);
+		if (!ld_map_dv_entry(mf, sdf, FALSE, tkv.tkv_str))
+			return (FALSE);
 	}
 
-	DBG_CALL(Dbg_map_dash(ofl->ofl_lml, name));
-	return (1);
+	return (TRUE);
 }
 
 
@@ -1285,126 +951,42 @@
  * } [ dependency ];
  *
  */
-#define	FLG_SCOPE_HIDD	0		/* symbol defined hidden/local */
-#define	FLG_SCOPE_DFLT	1		/* symbol defined default/global */
-#define	FLG_SCOPE_PROT	2		/* symbol defined protected/symbolic */
-#define	FLG_SCOPE_EXPT	3		/* symbol defined exported */
-#define	FLG_SCOPE_SNGL	4		/* symbol defined singleton */
-#define	FLG_SCOPE_ELIM	5		/* symbol defined eliminate */
-
-static uintptr_t
-map_version(const char *mapfile, char *name, Ofl_desc *ofl)
+static Boolean
+map_version(Mapfile *mf, char *name)
 {
 	Token		tok;
-	Sym		*sym;
-	int		scope = FLG_SCOPE_DFLT, errcnt = 0;
-	Ver_desc	*vdp;
-	Word		hash;
-	Ifl_desc	*ifl;
-	avl_index_t	where;
-
-	/*
-	 * If we're generating segments within the image then any symbol
-	 * reductions will be processed (ie. applied to relocations and symbol
-	 * table entries).  Otherwise (when creating a relocatable object) any
-	 * versioning information is simply recorded for use in a later
-	 * (segment generating) link-edit.
-	 */
-	if (ofl->ofl_flags & FLG_OF_RELOBJ)
-		ofl->ofl_flags |= FLG_OF_VERDEF;
-
-	/*
-	 * If this is a new mapfile reference generate an input file descriptor
-	 * to represent it.  Otherwise this must simply be a new version within
-	 * the mapfile we've previously been processing, in this case continue
-	 * to use the original input file descriptor.
-	 */
-	if ((ifl = map_ifl(mapfile, ofl)) == (Ifl_desc *)S_ERROR)
-		return (S_ERROR);
-
-	/*
-	 * If no version descriptors have yet been set up, initialize a base
-	 * version to represent the output file itself.  This `base' version
-	 * catches any internally generated symbols (_end, _etext, etc.) and
-	 * serves to initialize the output version descriptor count.
-	 */
-	if (ofl->ofl_vercnt == 0) {
-		if (ld_vers_base(ofl) == (Ver_desc *)S_ERROR)
-			return (S_ERROR);
-	}
+	ld_map_tkval_t	tkv;		/* Value of token */
+	ld_map_ver_t	mv;
+	ld_map_sym_t	ms;
+	Ofl_desc	*ofl = mf->mf_ofl;
 
-	/*
-	 * If this definition has an associated version name then generate a
-	 * new version descriptor and an associated version symbol index table.
-	 */
-	if (name) {
-		ofl->ofl_flags |= FLG_OF_VERDEF;
-
-		/*
-		 * Traverse the present version descriptor list to see if there
-		 * is already one of the same name, otherwise create a new one.
-		 */
-		/* LINTED */
-		hash = (Word)elf_hash(name);
-		if (((vdp = ld_vers_find(name, hash,
-		    ofl->ofl_verdesc)) == NULL) &&
-		    ((vdp = ld_vers_desc(name, hash,
-		    &ofl->ofl_verdesc)) == (Ver_desc *)S_ERROR))
-			return (S_ERROR);
-
-		/*
-		 * Initialize any new version with an index, the file from which
-		 * it was first referenced, and a WEAK flag (indicates that
-		 * there are no symbols assigned to it yet).
-		 */
-		if (vdp->vd_ndx == 0) {
-			/* LINTED */
-			vdp->vd_ndx = (Half)++ofl->ofl_vercnt;
-			vdp->vd_file = ifl;
-			vdp->vd_flags = VER_FLG_WEAK;
-		}
-	} else {
-		/*
-		 * If a version definition hasn't been specified assign any
-		 * symbols to the base version.
-		 */
-		vdp = (Ver_desc *)ofl->ofl_verdesc->apl_data[0];
-	}
+	/* Establish the version descriptor and related data */
+	if (!ld_map_sym_ver_init(mf, name, &mv))
+		return (FALSE);
 
 	/*
 	 * Scan the mapfile entry picking out scoping and symbol definitions.
 	 */
-	while ((tok = gettoken(ofl, mapfile, 0)) != TK_RIGHTBKT) {
-		Sym_desc	*sdp;
-		Word		shndx = SHN_UNDEF;
-		uchar_t 	type = STT_NOTYPE;
-		Addr		value = 0, size = 0;
-		char		*_name, *filtee = NULL;
-		sd_flag_t	sdflags = 0;
-		uint_t		filter = 0, novalue = 1, dftflag;
-		const char	*conflict;
+	while ((tok = ld_map_gettoken(mf, 0, &tkv)) != TK_RIGHTBKT) {
+		uint_t		filter = 0;
 
-		if ((tok != TK_STRING) && (tok != TK_COLON)) {
-			if (tok == TK_ERROR)
-				eprintf(ofl->ofl_lml, ERR_FATAL,
-				    MSG_INTL(MSG_MAP_EXPSYM_2), mapfile,
-				    EC_XWORD(Line_num));
-			if ((tok == TK_ERROR) || (tok == TK_EOF))
-				return (S_ERROR);
-			errcnt++;
+		if (tok != TK_STRING) {
+			if (tok == TK_ERROR) {
+				mf_fatal0(mf, MSG_INTL(MSG_MAP_EXPSYM_2));
+				return (FALSE);
+			}
+			mv.mv_errcnt++;
 			continue;
 		}
 
-		if ((_name = libld_malloc(strlen(Start_tok) + 1)) == NULL)
-			return (S_ERROR);
-		(void) strcpy(_name, Start_tok);
+		/* The default value for all the symbol attributes is 0 */
+		(void) memset(&ms, 0, sizeof (ms));
+		ms.ms_name = tkv.tkv_str;
 
-		if (tok != TK_COLON) {
-			tok = gettoken(ofl, mapfile, 0);
-			if ((tok == TK_ERROR) || (tok == TK_EOF)) {
-				errcnt++;
-				continue;
-			}
+		tok = ld_map_gettoken(mf, 0, &tkv);
+		if (tok == TK_ERROR) {
+			mv.mv_errcnt++;
+			continue;
 		}
 
 		/*
@@ -1417,56 +999,11 @@
 		 * will a user get a weak version (which is how we document the
 		 * creation of weak versions).
 		 */
-		vdp->vd_flags &= ~VER_FLG_WEAK;
+		mv.mv_vdp->vd_flags &= ~VER_FLG_WEAK;
 
 		switch (tok) {
 		case TK_COLON:
-			/*
-			 * Establish a new scope.  All symbols added by this
-			 * mapfile are actually global entries, and are assigned
-			 * the scope that is presently in effect.
-			 *
-			 * If a protected/symbolic scope is detected, remember
-			 * this.  If a protected/symbolic scope is the only
-			 * scope defined in this (or any other mapfiles), then
-			 * the mode -Bsymbolic is established.
-			 */
-			if ((strcmp(MSG_ORIG(MSG_MAP_DEFAULT), _name) == 0) ||
-			    (strcmp(MSG_ORIG(MSG_MAP_GLOBAL), _name) == 0)) {
-				scope = FLG_SCOPE_DFLT;
-				ofl->ofl_flags |= FLG_OF_MAPGLOB;
-
-			} else if ((strcmp(MSG_ORIG(MSG_MAP_HIDDEN),
-			    _name) == 0) ||
-			    (strcmp(MSG_ORIG(MSG_STR_LOCAL), _name) == 0)) {
-				scope = FLG_SCOPE_HIDD;
-
-			} else if ((strcmp(MSG_ORIG(MSG_MAP_PROTECTED),
-			    _name) == 0) ||
-			    (strcmp(MSG_ORIG(MSG_STR_SYMBOLIC), _name) == 0)) {
-				scope = FLG_SCOPE_PROT;
-				ofl->ofl_flags |= FLG_OF_MAPSYMB;
-
-			} else if (strcmp(MSG_ORIG(MSG_STR_EXPORTED),
-			    _name) == 0) {
-				scope = FLG_SCOPE_EXPT;
-
-			} else if (strcmp(MSG_ORIG(MSG_STR_SINGLETON),
-			    _name) == 0) {
-				scope = FLG_SCOPE_SNGL;
-				ofl->ofl_flags |= FLG_OF_MAPGLOB;
-
-			} else if (strcmp(MSG_ORIG(MSG_STR_ELIMINATE),
-			    _name) == 0) {
-				scope = FLG_SCOPE_ELIM;
-
-			} else {
-				eprintf(ofl->ofl_lml, ERR_FATAL,
-				    MSG_INTL(MSG_MAP_UNKSYMSCO), mapfile,
-				    EC_XWORD(Line_num), _name);
-				errcnt++;
-				break;
-			}
+			ld_map_sym_scope(mf, ms.ms_name, &mv);
 			continue;
 
 		case TK_EQUAL:
@@ -1476,29 +1013,24 @@
 			 * alignment specified and then fall through to process
 			 * the entire symbols information.
 			 */
-			while ((tok = gettoken(ofl, mapfile, 0)) !=
+			while ((tok = ld_map_gettoken(mf, 0, &tkv)) !=
 			    TK_SEMICOLON) {
-				if ((tok == TK_ERROR) || (tok == TK_EOF))
-					return (S_ERROR);
+				if (tok == TK_ERROR)
+					return (FALSE);
+				if (tok != TK_STRING) {
+					mf_fatal0(mf,
+					    MSG_INTL(MSG_MAP_MALFORM));
+					return (FALSE);
+				}
+
 				/*
-				 * If we had previously seen a filter or
-				 * auxiliary filter requirement, the next string
-				 * is the filtee itself.
+				 * If we had previously seen AUX or FILTER,
+				 * the next string is the filtee itself.
+				 * Add it, and clear the filter flag.
 				 */
 				if (filter) {
-					if (filtee) {
-					    /* BEGIN CSTYLED */
-					    eprintf(ofl->ofl_lml, ERR_FATAL,
-						MSG_INTL(MSG_MAP_MULTFILTEE),
-						mapfile, EC_XWORD(Line_num));
-					    errcnt++;
-					    continue;
-					    /* END CSTYLED */
-					}
-					if ((filtee = libld_malloc(
-					    strlen(Start_tok) + 1)) == NULL)
-						return (S_ERROR);
-					(void) strcpy(filtee, Start_tok);
+					ld_map_sym_filtee(mf, &mv, &ms,
+					    filter, tkv.tkv_str);
 					filter = 0;
 					continue;
 				}
@@ -1506,190 +1038,139 @@
 				/*
 				 * Determine any Value or Size attributes.
 				 */
-				lowercase(Start_tok);
-
-				if (Start_tok[0] == 'v' ||
-				    Start_tok[0] == 's') {
-					char		*end_tok;
-					Lword		number;
+				ld_map_lowercase(tkv.tkv_str);
 
-					if ((number = (Lword)STRTOADDR(
-					    &Start_tok[1], &end_tok, 0)) ==
-					    XWORD_MAX) {
-						eprintf(ofl->ofl_lml, ERR_FATAL,
-						    MSG_INTL(MSG_MAP_SEGADDR),
-						    mapfile, EC_XWORD(Line_num),
-						    Start_tok,
-						    MSG_INTL(MSG_MAP_EXCLIMIT));
-						errcnt++;
-						continue;
+				if (tkv.tkv_str[0] == 'v' ||
+				    tkv.tkv_str[0] == 's') {
+					Xword	number;
+
+					if (!valuetoxword(mf, &tkv, &number)) {
+						mv.mv_errcnt++;
+						return (FALSE);
 					}
 
-					if (end_tok !=
-					    strchr(Start_tok, '\0')) {
-						eprintf(ofl->ofl_lml, ERR_FATAL,
-						    MSG_INTL(MSG_MAP_SEGADDR),
-						    mapfile, EC_XWORD(Line_num),
-						    Start_tok,
-						    MSG_INTL(MSG_MAP_NOBADFRM));
-						errcnt++;
-						continue;
-					}
-
-					switch (*Start_tok) {
+					switch (*tkv.tkv_str) {
 					case 'v':
 					    /* BEGIN CSTYLED */
-					    if (value) {
-						eprintf(ofl->ofl_lml, ERR_FATAL,
+					    if (ms.ms_value) {
+						mf_fatal(mf,
 						    MSG_INTL(MSG_MAP_MOREONCE),
-						    mapfile, EC_XWORD(Line_num),
 						    MSG_INTL(MSG_MAP_SYMVAL));
-						errcnt++;
+						mv.mv_errcnt++;
 						continue;
 					    }
 					    /* LINTED */
-					    value = (Addr)number;
-					    novalue = 0;
+					    ms.ms_value = (Addr)number;
+					    ms.ms_value_set = TRUE;
 					    break;
 					    /* END CSTYLED */
 					case 's':
 					    /* BEGIN CSTYLED */
-					    if (size) {
-						eprintf(ofl->ofl_lml, ERR_FATAL,
+					    if (ms.ms_size) {
+						mf_fatal(mf,
 						    MSG_INTL(MSG_MAP_MOREONCE),
-						    mapfile, EC_XWORD(Line_num),
 						    MSG_INTL(MSG_MAP_SYMSIZE));
-						errcnt++;
+						mv.mv_errcnt++;
 						continue;
 					    }
 					    /* LINTED */
-					    size = (Addr)number;
+					    ms.ms_size = (Addr)number;
 					    break;
 					    /* END CSTYLED */
 					}
 
-				} else if (strcmp(Start_tok,
+				} else if (strcmp(tkv.tkv_str,
 				    MSG_ORIG(MSG_MAP_FUNCTION)) == 0) {
-					shndx = SHN_ABS;
-					sdflags |= FLG_SY_SPECSEC;
-					type = STT_FUNC;
-				} else if (strcmp(Start_tok,
+					ms.ms_shndx = SHN_ABS;
+					ms.ms_sdflags |= FLG_SY_SPECSEC;
+					ms.ms_type = STT_FUNC;
+				} else if (strcmp(tkv.tkv_str,
 				    MSG_ORIG(MSG_MAP_DATA)) == 0) {
-					shndx = SHN_ABS;
-					sdflags |= FLG_SY_SPECSEC;
-					type = STT_OBJECT;
-				} else if (strcmp(Start_tok,
+					ms.ms_shndx = SHN_ABS;
+					ms.ms_sdflags |= FLG_SY_SPECSEC;
+					ms.ms_type = STT_OBJECT;
+				} else if (strcmp(tkv.tkv_str,
 				    MSG_ORIG(MSG_MAP_COMMON)) == 0) {
-					shndx = SHN_COMMON;
-					sdflags |= FLG_SY_SPECSEC;
-					type = STT_OBJECT;
-				} else if (strcmp(Start_tok,
+					ms.ms_shndx = SHN_COMMON;
+					ms.ms_sdflags |= FLG_SY_SPECSEC;
+					ms.ms_type = STT_OBJECT;
+				} else if (strcmp(tkv.tkv_str,
 				    MSG_ORIG(MSG_MAP_PARENT)) == 0) {
-					sdflags |= FLG_SY_PARENT;
+					ms.ms_sdflags |= FLG_SY_PARENT;
 					ofl->ofl_flags |= FLG_OF_SYMINFO;
-				} else if (strcmp(Start_tok,
+				} else if (strcmp(tkv.tkv_str,
 				    MSG_ORIG(MSG_MAP_EXTERN)) == 0) {
-					sdflags |= FLG_SY_EXTERN;
+					ms.ms_sdflags |= FLG_SY_EXTERN;
 					ofl->ofl_flags |= FLG_OF_SYMINFO;
-				} else if (strcmp(Start_tok,
+				} else if (strcmp(tkv.tkv_str,
 				    MSG_ORIG(MSG_MAP_DIRECT)) == 0) {
-					sdflags |= FLG_SY_DIR;
+					ms.ms_sdflags |= FLG_SY_DIR;
 					ofl->ofl_flags |= FLG_OF_SYMINFO;
-				} else if (strcmp(Start_tok,
+				} else if (strcmp(tkv.tkv_str,
 				    MSG_ORIG(MSG_MAP_NODIRECT)) == 0) {
-					sdflags |= FLG_SY_NDIR;
+					ms.ms_sdflags |= FLG_SY_NDIR;
 					ofl->ofl_flags |= FLG_OF_SYMINFO;
 					ofl->ofl_flags1 |=
 					    (FLG_OF1_NDIRECT | FLG_OF1_NGLBDIR);
-				} else if (strcmp(Start_tok,
+				} else if (strcmp(tkv.tkv_str,
 				    MSG_ORIG(MSG_MAP_FILTER)) == 0) {
+					/* Next token is the filtee */
+					filter = FLG_SY_STDFLTR;
+					continue;
+				} else if (strcmp(tkv.tkv_str,
+				    MSG_ORIG(MSG_MAP_AUXILIARY)) == 0) {
+					/* Next token is the filtee */
+					filter = FLG_SY_AUXFLTR;
+					continue;
+				} else if (strcmp(tkv.tkv_str,
+				    MSG_ORIG(MSG_MAP_INTERPOSE)) == 0) {
 					/* BEGIN CSTYLED */
-					if (!(ofl->ofl_flags &
-					    FLG_OF_SHAROBJ)) {
-					    eprintf(ofl->ofl_lml, ERR_FATAL,
-						MSG_INTL(MSG_MAP_FLTR_ONLYAVL),
-						mapfile, EC_XWORD(Line_num));
-					    errcnt++;
+					if (!(ofl->ofl_flags & FLG_OF_EXEC)) {
+					    mf_fatal0(mf,
+						MSG_INTL(MSG_MAP_NOINTPOSE));
+					    mv.mv_errcnt++;
 					    break;
 					}
 					/* END CSTYLED */
-					dftflag = filter = FLG_SY_STDFLTR;
-					sdflags |= FLG_SY_STDFLTR;
-					ofl->ofl_flags |= FLG_OF_SYMINFO;
-					continue;
-				} else if (strcmp(Start_tok,
-				    MSG_ORIG(MSG_MAP_AUXILIARY)) == 0) {
-					/* BEGIN CSTYLED */
-					if (!(ofl->ofl_flags &
-					    FLG_OF_SHAROBJ)) {
-					    eprintf(ofl->ofl_lml, ERR_FATAL,
-						MSG_INTL(MSG_MAP_FLTR_ONLYAVL),
-						mapfile, EC_XWORD(Line_num));
-					    errcnt++;
-					    break;
-					}
-					/* END CSTYLED */
-					dftflag = filter = FLG_SY_AUXFLTR;
-					sdflags |= FLG_SY_AUXFLTR;
-					ofl->ofl_flags |= FLG_OF_SYMINFO;
-					continue;
-				} else if (strcmp(Start_tok,
-				    MSG_ORIG(MSG_MAP_INTERPOSE)) == 0) {
-					/* BEGIN CSTYLED */
-					if (!(ofl->ofl_flags & FLG_OF_EXEC)) {
-					    eprintf(ofl->ofl_lml, ERR_FATAL,
-						MSG_INTL(MSG_MAP_NOINTPOSE),
-						mapfile, EC_XWORD(Line_num));
-					    errcnt++;
-					    break;
-					}
-					/* END CSTYLED */
-					sdflags |= FLG_SY_INTPOSE;
+					ms.ms_sdflags |= FLG_SY_INTPOSE;
 					ofl->ofl_flags |= FLG_OF_SYMINFO;
 					ofl->ofl_dtflags_1 |= DF_1_SYMINTPOSE;
 					continue;
-				} else if (strcmp(Start_tok,
+				} else if (strcmp(tkv.tkv_str,
 				    MSG_ORIG(MSG_MAP_DYNSORT)) == 0) {
-					sdflags |= FLG_SY_DYNSORT;
-					sdflags &= ~FLG_SY_NODYNSORT;
+					ms.ms_sdflags |= FLG_SY_DYNSORT;
+					ms.ms_sdflags &= ~FLG_SY_NODYNSORT;
 					continue;
-				} else if (strcmp(Start_tok,
+				} else if (strcmp(tkv.tkv_str,
 				    MSG_ORIG(MSG_MAP_NODYNSORT)) == 0) {
-					sdflags &= ~FLG_SY_DYNSORT;
-					sdflags |= FLG_SY_NODYNSORT;
+					ms.ms_sdflags &= ~FLG_SY_DYNSORT;
+					ms.ms_sdflags |= FLG_SY_NODYNSORT;
 					continue;
 				} else {
-					eprintf(ofl->ofl_lml, ERR_FATAL,
+					mf_fatal(mf,
 					    MSG_INTL(MSG_MAP_UNKSYMDEF),
-					    mapfile, EC_XWORD(Line_num),
-					    Start_tok);
-					errcnt++;
+					    tkv.tkv_str);
+					mv.mv_errcnt++;
 					continue;
 				}
 			}
 			/* FALLTHROUGH */
 
 		case TK_SEMICOLON:
+			/* Auto-reduction directive ('*')? */
+			if (*ms.ms_name == '*') {
+				ld_map_sym_autoreduce(mf, &mv);
+				continue;
+			}
+
 			/*
-			 * The special auto-reduction directive `*' can be
-			 * specified in hidden/local, and eliminate scope.  This
-			 * directive indicates that all symbols processed that
-			 * are not explicitly defined to be global are to be
-			 * reduced to hidden/local scope in, or eliminated from,
-			 * the output image.
-			 *
-			 * An auto-reduction directive also implies that a
-			 * version definition be created, as the user has
-			 * effectively defined an interface.
+			 * Catch the error where the AUX or FILTER keyword
+			 * was used, but the filtee wasn't supplied.
 			 */
-			if (*_name == '*') {
-				if (scope == FLG_SCOPE_HIDD)
-					ofl->ofl_flags |=
-					    (FLG_OF_VERDEF | FLG_OF_AUTOLCL);
-				else if (scope == FLG_SCOPE_ELIM) {
-					ofl->ofl_flags |=
-					    (FLG_OF_VERDEF | FLG_OF_AUTOELM);
-				}
+			if (filter && (ms.ms_filtee == NULL)) {
+				mf_fatal(mf, MSG_INTL(MSG_MAP_NOFILTER),
+				    ms.ms_name);
+				mv.mv_errcnt++;
 				continue;
 			}
 
@@ -1700,767 +1181,100 @@
 			 * resolution process.  Symbols defined as locals will
 			 * be reduced in scope after all input file processing.
 			 */
-			/* LINTED */
-			hash = (Word)elf_hash(_name);
-			DBG_CALL(Dbg_map_version(ofl->ofl_lml, name, _name,
-			    scope));
-			if ((sdp = ld_sym_find(_name, hash, &where,
-			    ofl)) == NULL) {
-				if ((sym =
-				    libld_calloc(sizeof (Sym), 1)) == NULL)
-					return (S_ERROR);
-
-				/*
-				 * Make sure any parent or external declarations
-				 * fall back to references.
-				 */
-				if (sdflags & (FLG_SY_PARENT | FLG_SY_EXTERN)) {
-					/*
-					 * Turn it into a reference by setting
-					 * the section index to UNDEF.
-					 */
-					sym->st_shndx = shndx = SHN_UNDEF;
-
-					/*
-					 * It is wrong to to specify size
-					 * or value for an external symbol.
-					 */
-					if ((novalue == 0) || (size != 0)) {
-						eprintf(ofl->ofl_lml, ERR_FATAL,
-						    MSG_INTL(MSG_MAP_NOEXVLSZ),
-						    mapfile,
-						    EC_XWORD(Line_num));
-						errcnt++;
-						continue;
-					}
-				} else {
-					sym->st_shndx = (Half)shndx;
-				}
-
-				sym->st_value = value;
-				sym->st_size = size;
-				sym->st_info = ELF_ST_INFO(STB_GLOBAL, type);
-
-				if ((sdp = ld_sym_enter(_name, sym, hash,
-				    ifl, ofl, 0, shndx, sdflags,
-				    &where)) == (Sym_desc *)S_ERROR)
-					return (S_ERROR);
-
-				sdp->sd_flags &= ~FLG_SY_CLEAN;
-
-				/*
-				 * Identify any references.  FLG_SY_MAPREF is
-				 * turned off once a relocatable object with
-				 * the same symbol is found, thus the existence
-				 * of FLG_SY_MAPREF at symbol validation is
-				 * used to flag undefined/misspelled entries.
-				 */
-				if (sym->st_shndx == SHN_UNDEF)
-					sdp->sd_flags |=
-					    (FLG_SY_MAPREF | FLG_SY_GLOBREF);
-
-			} else {
-				conflict = NULL;
-				sym = sdp->sd_sym;
-
-				/*
-				 * If this symbol already exists, make sure this
-				 * definition doesn't conflict with the former.
-				 * Provided it doesn't, multiple definitions
-				 * from different mapfiles can augment each
-				 * other.
-				 */
-				/* BEGIN CSTYLED */
-				if (sym->st_value) {
-				    if (value && (sym->st_value != value))
-					conflict =
-					    MSG_INTL(MSG_MAP_DIFF_SYMVAL);
-				} else {
-					sym->st_value = value;
-				}
-				if (sym->st_size) {
-				    if (size && (sym->st_size != size))
-					conflict = MSG_INTL(MSG_MAP_DIFF_SYMSZ);
-				} else {
-					sym->st_size = size;
-				}
-				if (ELF_ST_TYPE(sym->st_info) != STT_NOTYPE) {
-				    if ((type != STT_NOTYPE) &&
-					(ELF_ST_TYPE(sym->st_info) != type))
-					    conflict =
-						MSG_INTL(MSG_MAP_DIFF_SYMTYP);
-				} else {
-					sym->st_info =
-					    ELF_ST_INFO(STB_GLOBAL, type);
-				}
-				if (sym->st_shndx != SHN_UNDEF) {
-				    if ((shndx != SHN_UNDEF) &&
-					(sym->st_shndx != shndx))
-					    conflict =
-						MSG_INTL(MSG_MAP_DIFF_SYMNDX);
-				} else {
-					sym->st_shndx = sdp->sd_shndx = shndx;
-				}
-				/* END CSTYLED */
-
-				if ((sdp->sd_flags & MSK_SY_GLOBAL) &&
-				    (sdp->sd_aux->sa_overndx !=
-				    VER_NDX_GLOBAL) &&
-				    (vdp->vd_ndx != VER_NDX_GLOBAL) &&
-				    (sdp->sd_aux->sa_overndx != vdp->vd_ndx)) {
-					conflict =
-					    MSG_INTL(MSG_MAP_DIFF_SYMVER);
-				}
-
-				if (conflict) {
-					eprintf(ofl->ofl_lml, ERR_FATAL,
-					    MSG_INTL(MSG_MAP_SYMDEF1), mapfile,
-					    EC_XWORD(Line_num), demangle(_name),
-					    sdp->sd_file->ifl_name, conflict);
-					errcnt++;
-					continue;
-				}
-
-				/*
-				 * If this mapfile entry supplies a definition,
-				 * indicate that the symbol is now used.
-				 */
-				if (shndx != SHN_UNDEF)
-					sdp->sd_flags |= FLG_SY_MAPUSED;
-			}
-
-			/*
-			 * A symbol declaration that defines a size but no
-			 * value is processed as a request to create an
-			 * associated backing section.  The intent behind this
-			 * functionality is to provide OBJT definitions within
-			 * filters that are not ABS.  ABS symbols don't allow
-			 * copy-relocations to be established to filter OBJT
-			 * definitions.
-			 */
-			if ((shndx == SHN_ABS) && size && novalue) {
-				/* Create backing section if not there */
-				if (sdp->sd_isc == NULL) {
-					Is_desc	*isp;
-
-					if (type == STT_OBJECT) {
-						if ((isp = ld_make_data(ofl,
-						    size)) ==
-						    (Is_desc *)S_ERROR)
-							return (S_ERROR);
-					} else {
-						if ((isp = ld_make_text(ofl,
-						    size)) ==
-						    (Is_desc *)S_ERROR)
-							return (S_ERROR);
-					}
-
-					sdp->sd_isc = isp;
-					isp->is_file = ifl;
-				}
-
-				/*
-				 * Now that backing storage has been created,
-				 * associate the symbol descriptor.  Remove the
-				 * symbols special section tag so that it will
-				 * be assigned the correct section index as part
-				 * of update symbol processing.
-				 */
-				sdp->sd_flags &= ~FLG_SY_SPECSEC;
-				sdflags &= ~FLG_SY_SPECSEC;
-			}
-
-			/*
-			 * Indicate the new symbols scope.  Although the
-			 * symbols st_other field will eventually be updated as
-			 * part of writing out the final symbol, update the
-			 * st_other field here to trigger better diagnostics
-			 * during symbol validation (for example, undefined
-			 * references that are defined symbolic in a mapfile).
-			 */
-			if (scope == FLG_SCOPE_HIDD) {
-				/*
-				 * This symbol needs to be reduced to local.
-				 */
-				if (ofl->ofl_flags & FLG_OF_REDLSYM) {
-					sdp->sd_flags |=
-					    (FLG_SY_HIDDEN | FLG_SY_ELIM);
-					sdp->sd_sym->st_other = STV_ELIMINATE;
-				} else {
-					sdp->sd_flags |= FLG_SY_HIDDEN;
-					sdp->sd_sym->st_other = STV_HIDDEN;
-				}
-			} else if (scope == FLG_SCOPE_ELIM) {
-				/*
-				 * This symbol needs to be eliminated.  Note,
-				 * the symbol is also tagged as local to trigger
-				 * any necessary relocation processing prior
-				 * to the symbol being eliminated.
-				 */
-				sdp->sd_flags |= (FLG_SY_HIDDEN | FLG_SY_ELIM);
-				sdp->sd_sym->st_other = STV_ELIMINATE;
-
-			} else {
-				/*
-				 * This symbol is explicitly defined to remain
-				 * global.
-				 */
-				sdp->sd_flags |= sdflags;
-
-				/*
-				 * Qualify any global scope.
-				 */
-				if (scope == FLG_SCOPE_SNGL) {
-					sdp->sd_flags |=
-					    (FLG_SY_SINGLE | FLG_SY_NDIR);
-					sdp->sd_sym->st_other = STV_SINGLETON;
-				} else if (scope == FLG_SCOPE_PROT) {
-					sdp->sd_flags |= FLG_SY_PROTECT;
-					sdp->sd_sym->st_other = STV_PROTECTED;
-				} else if (scope == FLG_SCOPE_EXPT) {
-					sdp->sd_flags |= FLG_SY_EXPORT;
-					sdp->sd_sym->st_other = STV_EXPORTED;
-				} else
-					sdp->sd_flags |= FLG_SY_DEFAULT;
-
-				/*
-				 * Record the present version index for later
-				 * potential versioning.
-				 */
-				if ((sdp->sd_aux->sa_overndx == 0) ||
-				    (sdp->sd_aux->sa_overndx == VER_NDX_GLOBAL))
-					sdp->sd_aux->sa_overndx = vdp->vd_ndx;
-				vdp->vd_flags |= FLG_VER_REFER;
-			}
-
-			conflict = NULL;
-
-			/*
-			 * Carry out some validity checks to ensure incompatible
-			 * symbol characteristics have not been defined.
-			 * These checks are carried out after symbols are added
-			 * or resolved, to catch single instance, and
-			 * multi-instance definition inconsistencies.
-			 */
-			if ((sdp->sd_flags & (FLG_SY_HIDDEN | FLG_SY_ELIM)) &&
-			    ((scope != FLG_SCOPE_HIDD) &&
-			    (scope != FLG_SCOPE_ELIM))) {
-				conflict = MSG_INTL(MSG_MAP_DIFF_SYMLCL);
-
-			} else if ((sdp->sd_flags &
-			    (FLG_SY_SINGLE | FLG_SY_EXPORT)) &&
-			    ((scope != FLG_SCOPE_DFLT) &&
-			    (scope != FLG_SCOPE_EXPT) &&
-			    (scope != FLG_SCOPE_SNGL))) {
-				conflict = MSG_INTL(MSG_MAP_DIFF_SYMGLOB);
-
-			} else if ((sdp->sd_flags & FLG_SY_PROTECT) &&
-			    ((scope != FLG_SCOPE_DFLT) &&
-			    (scope != FLG_SCOPE_PROT))) {
-				conflict = MSG_INTL(MSG_MAP_DIFF_SYMPROT);
-
-			} else if ((sdp->sd_flags & FLG_SY_NDIR) &&
-			    (scope == FLG_SCOPE_PROT)) {
-				conflict = MSG_INTL(MSG_MAP_DIFF_PROTNDIR);
-
-			} else if ((sdp->sd_flags & FLG_SY_DIR) &&
-			    (scope == FLG_SCOPE_SNGL)) {
-				conflict = MSG_INTL(MSG_MAP_DIFF_SNGLDIR);
-			}
-
-			if (conflict) {
-				/*
-				 * Select the conflict message from either a
-				 * single instance or multi-instance definition.
-				 */
-				if (sdp->sd_file->ifl_name == mapfile) {
-					eprintf(ofl->ofl_lml, ERR_FATAL,
-					    MSG_INTL(MSG_MAP_SYMDEF2), mapfile,
-					    EC_XWORD(Line_num), demangle(_name),
-					    conflict);
-				} else {
-					eprintf(ofl->ofl_lml, ERR_FATAL,
-					    MSG_INTL(MSG_MAP_SYMDEF1), mapfile,
-					    EC_XWORD(Line_num), demangle(_name),
-					    sdp->sd_file->ifl_name, conflict);
-				}
-				errcnt++;
-				continue;
-			}
-
-			/*
-			 * Indicate that this symbol has been explicitly
-			 * contributed from a mapfile.
-			 */
-			sdp->sd_flags |= (FLG_SY_MAPFILE | FLG_SY_EXPDEF);
-
-			/*
-			 * If we've encountered a symbol definition simulate
-			 * that an input file has been processed - this allows
-			 * things like filters to be created purely from a
-			 * mapfile.
-			 */
-			if (type != STT_NOTYPE)
-				ofl->ofl_objscnt++;
-			DBG_CALL(Dbg_map_symbol(ofl, sdp));
-
-			/*
-			 * If this symbol has an associated filtee, record the
-			 * filtee string and associate the string index with the
-			 * symbol.  This is used later to associate the syminfo
-			 * information with the necessary .dynamic entry.
-			 */
-			if (filter && (filtee == NULL)) {
-				eprintf(ofl->ofl_lml, ERR_FATAL,
-				    MSG_INTL(MSG_MAP_NOFILTER), mapfile,
-				    EC_XWORD(Line_num), _name);
-				errcnt++;
-				continue;
-			}
-
-			if (filtee) {
-				Dfltr_desc *	dftp;
-				Sfltr_desc	sft;
-				Aliste		idx, _idx, nitems;
-
-				/*
-				 * Make sure we don't duplicate any filtee
-				 * strings, and create a new descriptor if
-				 * necessary.
-				 */
-				idx = nitems = alist_nitems(ofl->ofl_dtsfltrs);
-				for (ALIST_TRAVERSE(ofl->ofl_dtsfltrs, _idx,
-				    dftp)) {
-					if ((dftflag != dftp->dft_flag) ||
-					    (strcmp(dftp->dft_str, filtee)))
-						continue;
-					idx = _idx;
-					break;
-				}
-				if (idx == nitems) {
-					Dfltr_desc	dft;
-
-					dft.dft_str = filtee;
-					dft.dft_flag = dftflag;
-					dft.dft_ndx = 0;
-
-					/*
-					 * The following append puts the new
-					 * item at the offset contained in
-					 * idx, because we know idx contains
-					 * the index of the next available slot.
-					 */
-					if (alist_append(&ofl->ofl_dtsfltrs,
-					    &dft, sizeof (Dfltr_desc),
-					    AL_CNT_OFL_DTSFLTRS) == NULL)
-						return (S_ERROR);
-				}
-
-				/*
-				 * Create a new filter descriptor for this
-				 * symbol.
-				 */
-				sft.sft_sdp = sdp;
-				sft.sft_idx = idx;
-
-				if (alist_append(&ofl->ofl_symfltrs,
-				    &sft, sizeof (Sfltr_desc),
-				    AL_CNT_OFL_SYMFLTRS) == NULL)
-					return (S_ERROR);
-			}
+			if (!ld_map_sym_enter(mf, &mv, &ms))
+				return (FALSE);
 			break;
 
 		default:
-			eprintf(ofl->ofl_lml, ERR_FATAL,
-			    MSG_INTL(MSG_MAP_EXPSCOL), mapfile,
-			    EC_XWORD(Line_num));
-			errcnt++;
+			mf_fatal0(mf, MSG_INTL(MSG_MAP_EXPSCOL));
+			mv.mv_errcnt++;
 			continue;
 		}
 	}
 
-	if (errcnt)
-		return (S_ERROR);
+	if (mv.mv_errcnt)
+		return (FALSE);
 
 	/*
 	 * Determine if any version references are provided after the close
-	 * bracket.
+	 * bracket, parsing up to the terminating ';'.
 	 */
-	while ((tok = gettoken(ofl, mapfile, 0)) != TK_SEMICOLON) {
-		Ver_desc	*_vdp;
-		char		*_name;
-
-		if (tok != TK_STRING) {
-			if (tok != TK_ERROR)
-				eprintf(ofl->ofl_lml, ERR_FATAL,
-				    MSG_INTL(MSG_MAP_EXPVERS), mapfile,
-				    EC_XWORD(Line_num));
-			return (S_ERROR);
-		}
-
-		name = Start_tok;
-		if (vdp->vd_ndx == VER_NDX_GLOBAL) {
-			eprintf(ofl->ofl_lml, ERR_WARNING,
-			    MSG_INTL(MSG_MAP_UNEXDEP), mapfile,
-			    EC_XWORD(Line_num), name);
-			continue;
-		}
+	if (!ld_map_sym_ver_fini(mf, &mv))
+		return (FALSE);
 
-		/*
-		 * Generate a new version descriptor if it doesn't already
-		 * exist.
-		 */
-		/* LINTED */
-		hash = (Word)elf_hash(name);
-		if ((_vdp = ld_vers_find(name, hash,
-		    ofl->ofl_verdesc)) == NULL) {
-			if ((_name = libld_malloc(strlen(name) + 1)) == NULL)
-				return (S_ERROR);
-			(void) strcpy(_name, name);
-
-			if ((_vdp = ld_vers_desc(_name, hash,
-			    &ofl->ofl_verdesc)) == (Ver_desc *)S_ERROR)
-				return (S_ERROR);
-		}
-
-		/*
-		 * Add the new version descriptor to the parent version
-		 * descriptors reference list.  Indicate the version descriptors
-		 * first reference (used for error disgnostics if undefined
-		 * version dependencies remain).
-		 */
-		if (ld_vers_find(name, hash, vdp->vd_deps) == NULL)
-			if (aplist_append(&vdp->vd_deps, _vdp,
-			    AL_CNT_VERDESCS) == NULL)
-				return (S_ERROR);
-
-		if (_vdp->vd_ref == NULL)
-			_vdp->vd_ref = vdp;
-	}
-	return (1);
+	return (TRUE);
 }
 
 /*
- * If a user has provided segment definitions via a mapfile, and these segments
- * have been assigned virtual addresses, sort the associated segments by
- * increasing virtual address.
- *
- * Only PT_LOAD segments can be assigned a virtual address.  These segments can
- * be one of two types:
- *
- *  -	Standard segments for text, data or bss.  These segments will have been
- *	inserted before the default text (first PT_LOAD) segment.
- *
- *  -	Empty (reservation) segments.  These segment will have been inserted at
- *	the end of any default PT_LOAD segments.
- *
- * Any standard segments that are assigned a virtual address will be sorted,
- * and as their definitions precede any default PT_LOAD segments, these segments
- * will be assigned sections before any defaults.
- *
- * Any reservation segments are also sorted amoung themselves, as these segments
- * must still follow the standard default segments.
+ * Parse the mapfile --- Sysv syntax
  */
-uintptr_t
-ld_sort_seg_list(Ofl_desc *ofl)
+Boolean
+ld_map_parse_v1(Mapfile *mf)
 {
-	APlist	*seg1 = NULL, *seg2 = NULL;
-	Sg_desc	*sgp1;
-	Aliste	idx1;
-
-#define	FIRST_SEGMENT(type) \
-	((type == PT_PHDR) || (type == PT_INTERP) || (type == PT_SUNWCAP))
-
-	/*
-	 * Add the .phdr and .interp segments to our list.  These segments must
-	 * occur before any PT_LOAD segments (refer exec/elf/elf.c).  Also add
-	 * the capabilities segment.  This isn't essential, but the capabilities
-	 * section is one of the first in an object.
-	 */
-	for (APLIST_TRAVERSE(ofl->ofl_segs, idx1, sgp1)) {
-		Word	type = sgp1->sg_phdr.p_type;
-
-		if (FIRST_SEGMENT(type)) {
-			if (aplist_append(&seg1, sgp1, AL_CNT_SEGMENTS) == NULL)
-				return (S_ERROR);
-		}
-	}
-
-	/*
-	 * Add the loadable segments to another list in sorted order.
-	 */
-	DBG_CALL(Dbg_map_sort(ofl->ofl_lml));
-	for (APLIST_TRAVERSE(ofl->ofl_segs, idx1, sgp1)) {
-		DBG_CALL(Dbg_map_sort_seg(ofl->ofl_lml, sgp1, 1));
-
-		if (sgp1->sg_phdr.p_type != PT_LOAD)
-			continue;
-
-		/*
-		 * If the loadable segment does not contain a vaddr, simply
-		 * append it to the new list.
-		 */
-		if ((sgp1->sg_flags & FLG_SG_VADDR) == 0) {
-			if (aplist_append(&seg2, sgp1, AL_CNT_SEGMENTS) == NULL)
-				return (S_ERROR);
-
-		} else {
-			Aliste		idx2;
-			Sg_desc		*sgp2;
-			int		inserted = 0;
-
-			/*
-			 * Traverse the segment list we are creating, looking
-			 * for a segment that defines a vaddr.
-			 */
-			for (APLIST_TRAVERSE(seg2, idx2, sgp2)) {
-				/*
-				 * Any real segments that contain vaddr's need
-				 * to be sorted.  Any reservation segments also
-				 * need to be sorted.  However, any reservation
-				 * segments should be placed after any real
-				 * segments.
-				 */
-				if (((sgp2->sg_flags &
-				    (FLG_SG_VADDR | FLG_SG_EMPTY)) == 0) &&
-				    (sgp1->sg_flags & FLG_SG_EMPTY))
-					continue;
-
-				if ((sgp2->sg_flags & FLG_SG_VADDR) &&
-				    ((sgp2->sg_flags & FLG_SG_EMPTY) ==
-				    (sgp1->sg_flags & FLG_SG_EMPTY))) {
-					if (sgp1->sg_phdr.p_vaddr ==
-					    sgp2->sg_phdr.p_vaddr) {
-						eprintf(ofl->ofl_lml, ERR_FATAL,
-						    MSG_INTL(MSG_MAP_SEGSAME),
-						    sgp1->sg_name,
-						    sgp2->sg_name);
-						return (S_ERROR);
-					}
-
-					if (sgp1->sg_phdr.p_vaddr >
-					    sgp2->sg_phdr.p_vaddr)
-						continue;
-				}
-
-				/*
-				 * Insert this segment before the segment on
-				 * the seg2 list.
-				 */
-				if (aplist_insert(&seg2, sgp1, AL_CNT_SEGMENTS,
-				    idx2) == NULL)
-					return (S_ERROR);
-				inserted = 1;
-				break;
-			}
-
-			/*
-			 * If the segment being inspected has not been inserted
-			 * in the segment list, simply append it to the list.
-			 */
-			if ((inserted == 0) && (aplist_append(&seg2,
-			    sgp1, AL_CNT_SEGMENTS) == NULL))
-				return (S_ERROR);
-		}
-	}
-
-	/*
-	 * Add the sorted loadable segments to our initial segment list.
-	 */
-	for (APLIST_TRAVERSE(seg2, idx1, sgp1)) {
-		if (aplist_append(&seg1, sgp1, AL_CNT_SEGMENTS) == NULL)
-			return (S_ERROR);
-	}
-
-	/*
-	 * Add all other segments to our list.
-	 */
-	for (APLIST_TRAVERSE(ofl->ofl_segs, idx1, sgp1)) {
-		Word	type = sgp1->sg_phdr.p_type;
-
-		if (!FIRST_SEGMENT(type) && (type != PT_LOAD)) {
-			if (aplist_append(&seg1, sgp1, AL_CNT_SEGMENTS) == NULL)
-				return (S_ERROR);
-		}
-	}
-	free((void *)ofl->ofl_segs);
-	ofl->ofl_segs = NULL;
-
-	/*
-	 * Now rebuild the original list and process all of the
-	 * segment/section ordering information if present.
-	 */
-	for (APLIST_TRAVERSE(seg1, idx1, sgp1)) {
-		DBG_CALL(Dbg_map_sort_seg(ofl->ofl_lml, sgp1, 0));
-		if (aplist_append(&ofl->ofl_segs, sgp1,
-		    AL_CNT_SEGMENTS) == NULL)
-			return (S_ERROR);
-	}
-
-#undef	FIRST_SEGMENT
-
-	return (1);
-}
-
-/*
- * Parse the mapfile.
- */
-uintptr_t
-ld_map_parse(const char *mapfile, Ofl_desc *ofl)
-{
-	struct stat	stat_buf;	/* stat of mapfile */
-	int		mapfile_fd;	/* descriptor for mapfile */
 	Sg_desc		*sgp1;		/* seg descriptor being manipulated */
-	Sg_desc		*sgp2;		/* temp segment descriptor pointer */
-	Ent_desc	*enp;		/* Segment entrance criteria. */
+	Ent_desc	*enp;		/* segment entrance criteria. */
 	Token		tok;		/* current token. */
-	Aliste		endx = 0;	/* next place for entrance criterion */
-	Boolean		new_segment;	/* If true, defines new segment. */
+	Boolean		new_segment;	/* If true, defines new segment */
 	char		*name;
-	static	int	num_stack = 0;	/* number of stack segment */
-	int		err;
-
-	DBG_CALL(Dbg_map_parse(ofl->ofl_lml, mapfile));
-
-	/*
-	 * Determine if we're dealing with a file or a directory.
-	 */
-	if (stat(mapfile, &stat_buf) == -1) {
-		err = errno;
-		eprintf(ofl->ofl_lml, ERR_FATAL, MSG_INTL(MSG_SYS_STAT),
-		    mapfile, strerror(err));
-		return (S_ERROR);
-	}
-	if (S_ISDIR(stat_buf.st_mode)) {
-		DIR		*dirp;
-		struct dirent	*denp;
-
-		/*
-		 * Open the directory and interpret each visible file as a
-		 * mapfile.
-		 */
-		if ((dirp = opendir(mapfile)) == NULL)
-			return (1);
-
-		while ((denp = readdir(dirp)) != NULL) {
-			char	path[PATH_MAX];
-
-			/*
-			 * Ignore any hidden filenames.  Construct the full
-			 * pathname to the new mapfile.
-			 */
-			if (*denp->d_name == '.')
-				continue;
-			(void) snprintf(path, PATH_MAX, MSG_ORIG(MSG_STR_PATH),
-			    mapfile, denp->d_name);
-			if (ld_map_parse(path, ofl) == S_ERROR)
-				return (S_ERROR);
-		}
-		(void) closedir(dirp);
-		return (1);
-	} else if (!S_ISREG(stat_buf.st_mode)) {
-		eprintf(ofl->ofl_lml, ERR_FATAL, MSG_INTL(MSG_SYS_NOTREG),
-		    mapfile);
-		return (S_ERROR);
-	}
-
-	/*
-	 * We read the entire mapfile into memory.
-	 */
-	if ((Mapspace = libld_malloc(stat_buf.st_size + 1)) == NULL)
-		return (S_ERROR);
-	if ((mapfile_fd = open(mapfile, O_RDONLY)) == -1) {
-		err = errno;
-		eprintf(ofl->ofl_lml, ERR_FATAL, MSG_INTL(MSG_SYS_OPEN),
-		    mapfile, strerror(err));
-		return (S_ERROR);
-	}
-
-	if (read(mapfile_fd, Mapspace, stat_buf.st_size) != stat_buf.st_size) {
-		err = errno;
-		eprintf(ofl->ofl_lml, ERR_FATAL, MSG_INTL(MSG_SYS_READ),
-		    mapfile, strerror(err));
-		return (S_ERROR);
-	}
-	Mapspace[stat_buf.st_size] = '\0';
-	nextchr = Mapspace;
-
-	/*
-	 * Set up any global variables, the line number counter and file name.
-	 */
-	Line_num = 1;
+	Ofl_desc	*ofl = mf->mf_ofl;
+	ld_map_tkval_t	tkv;		/* Value of token */
+	avl_index_t 	where;
 
 	/*
 	 * We now parse the mapfile until the gettoken routine returns EOF.
 	 */
-	while ((tok = gettoken(ofl, mapfile, 1)) != TK_EOF) {
-		Aliste	idx;
-		int	ndx;
-
-		/*
-		 * Don't know which segment yet.
-		 */
-		sgp1 = NULL;
+	while ((tok = ld_map_gettoken(mf, TK_F_EOFOK, &tkv)) != TK_EOF) {
+		Xword	ndx;
 
 		/*
 		 * At this point we are at the beginning of a line, and the
-		 * variable `Start_tok' points to the first string on the line.
+		 * variable tkv.tkv_str points to the first string on the line.
 		 * All mapfile entries start with some string token except it
 		 * is possible for a scoping definition to start with `{'.
 		 */
 		if (tok == TK_LEFTBKT) {
-			if (map_version(mapfile, (char *)0, ofl) == S_ERROR)
-				return (S_ERROR);
+			if (!map_version(mf, NULL))
+				return (FALSE);
 			continue;
 		}
 		if (tok != TK_STRING) {
 			if (tok != TK_ERROR)
-				eprintf(ofl->ofl_lml, ERR_FATAL,
-				    MSG_INTL(MSG_MAP_EXPSEGNAM), mapfile,
-				    EC_XWORD(Line_num));
-			return (S_ERROR);
+				mf_fatal0(mf, MSG_INTL(MSG_MAP_EXPSEGNAM));
+			return (FALSE);
 		}
 
 		/*
 		 * Save the initial token.
 		 */
-		if ((name = libld_malloc(strlen(Start_tok) + 1)) == NULL)
-			return (S_ERROR);
-		(void) strcpy(name, Start_tok);
+		name = tkv.tkv_str;
 
 		/*
 		 * Now check the second character on the line.  The special `-'
 		 * and `{' characters do not involve any segment manipulation so
 		 * we handle them first.
 		 */
-		tok = gettoken(ofl, mapfile, 0);
-		if ((tok == TK_ERROR) || (tok == TK_EOF))
-			return (S_ERROR);
+		tok = ld_map_gettoken(mf, 0, &tkv);
+		if (tok == TK_ERROR)
+			return (FALSE);
 		if (tok == TK_DASH) {
-			if (map_dash(mapfile, name, ofl) == S_ERROR)
-				return (S_ERROR);
+			if (!map_dash(mf, name))
+				return (FALSE);
 			continue;
 		}
 		if (tok == TK_LEFTBKT) {
-			if (map_version(mapfile, name, ofl) == S_ERROR)
-				return (S_ERROR);
+			if (!map_version(mf, name))
+				return (FALSE);
 			continue;
 		}
 
 		/*
 		 * If we're here we need to interpret the first string as a
-		 * segment name.  Find the segment named in the token.
+		 * segment name.  Is this an already known segment?
 		 */
-		ndx = 0;
-		for (APLIST_TRAVERSE(ofl->ofl_segs, idx, sgp2)) {
-			if (strcmp(sgp2->sg_name, name) == 0) {
-				sgp1 = sgp2;
-				sgp2->sg_flags &= ~FLG_SG_DISABLED;
-				new_segment = FALSE;
-				break;
-			}
-			ndx++;
-		}
+		sgp1 = ld_seg_lookup(mf->mf_ofl, name, &where);
+		new_segment = sgp1 == NULL;
+		if (!new_segment)
+			sgp1->sg_flags &= ~FLG_SG_DISABLED;
 
 		/*
 		 * If the second token is a '|' then we had better have found a
@@ -2469,229 +1283,181 @@
 		 */
 		if (tok == TK_PIPE) {
 			if (sgp1 == NULL) {
-				eprintf(ofl->ofl_lml, ERR_FATAL,
-				    MSG_INTL(MSG_MAP_SECINSEG), mapfile,
-				    EC_XWORD(Line_num), name);
-				return (S_ERROR);
-			} else {
-				if (map_pipe(ofl, mapfile, sgp1) == S_ERROR)
-					return (S_ERROR);
-				continue;
+				mf_fatal(mf, MSG_INTL(MSG_MAP_SECINSEG),
+				    name);
+				return (FALSE);
 			}
+			if (!map_pipe(mf, sgp1))
+				return (FALSE);
+			continue;
 		}
 
 		/*
-		 * If segment is still NULL then it does not exist.  Create a
-		 * new segment, and leave its values as 0 so that map_equal()
-		 * can detect changing attributes.
+		 * If segment does not exist, allocate a descriptor with
+		 * its values set to 0 so that map_equal() can detect
+		 * changing attributes.
 		 */
-		if (sgp1 == NULL) {
-			if ((sgp1 =
-			    libld_calloc(sizeof (Sg_desc), 1)) == NULL)
-				return (S_ERROR);
-			sgp1->sg_phdr.p_type = PT_NULL;
-			sgp1->sg_name = name;
-			new_segment = TRUE;
-		}
-
-		if ((strcmp(sgp1->sg_name, MSG_ORIG(MSG_STR_INTERP)) == 0) ||
-		    (strcmp(sgp1->sg_name, MSG_ORIG(MSG_STR_LD_DYNAMIC)) ==
-		    0)) {
-			eprintf(ofl->ofl_lml, ERR_FATAL,
-			    MSG_INTL(MSG_MAP_SEGRESV), mapfile,
-			    EC_XWORD(Line_num));
-			return (S_ERROR);
-		}
+		if (new_segment &&
+		    ((sgp1 = ld_map_seg_alloc(name, PT_NULL, 0)) == NULL))
+			return (FALSE);
 
 		/*
 		 * Now check the second token from the input line.
 		 */
-		if (tok == TK_EQUAL) {
+		switch (tok) {
+		case TK_EQUAL:		/* Create/modify segment */
+			/*
+			 * We use the same syntax for hardware/software
+			 * capabilities as we do for segments. If the
+			 * "segment name" matches one of these, then
+			 * process the capabilities instead of treating it
+			 * as a segment. Note that no dynamic memory has
+			 * been allocated for the segment descriptor yet,
+			 * so we can bail without leaking memory.
+			 */
 			if (strcmp(sgp1->sg_name,
 			    MSG_ORIG(MSG_STR_HWCAP_1)) == 0) {
-				if (map_cap(mapfile, CA_SUNW_HW_1,
-				    ofl) == S_ERROR)
-					return (S_ERROR);
-				DBG_CALL(Dbg_cap_mapfile(ofl->ofl_lml,
-				    CA_SUNW_HW_1, ofl->ofl_hwcap_1,
-				    ld_targ.t_m.m_mach));
+				if (!map_cap(mf, CA_SUNW_HW_1,
+				    &ofl->ofl_ocapset.c_hw_1))
+					return (FALSE);
+				continue;
+
+			}
+			if (strcmp(sgp1->sg_name,
+			    MSG_ORIG(MSG_STR_SFCAP_1)) == 0) {
+				if (!map_cap(mf, CA_SUNW_SF_1,
+				    &ofl->ofl_ocapset.c_sf_1))
+					return (FALSE);
 				continue;
 
-			} else if (strcmp(sgp1->sg_name,
-			    MSG_ORIG(MSG_STR_SFCAP_1)) == 0) {
-				if (map_cap(mapfile, CA_SUNW_SF_1,
-				    ofl) == S_ERROR)
-					return (S_ERROR);
-				DBG_CALL(Dbg_cap_mapfile(ofl->ofl_lml,
-				    CA_SUNW_SF_1, ofl->ofl_sfcap_1,
-				    ld_targ.t_m.m_mach));
-				continue;
+			}
+
+			/*
+			 * If not a new segment, show the initial value
+			 * before modifying it.
+			 */
+			if (!new_segment && DBG_ENABLED) {
+				ndx = ld_map_seg_index(mf, sgp1);
+				Dbg_map_seg(ofl, DBG_STATE_MOD_BEFORE,
+				    ndx, sgp1, mf->mf_lineno);
+			}
+
+			/* Process the segment */
+			if (!map_equal(mf, sgp1))
+				return (FALSE);
 
-			} else {
-				if (map_equal(mapfile, sgp1, ofl) == S_ERROR)
-					return (S_ERROR);
-				DBG_CALL(Dbg_map_set_equal(new_segment));
-			}
-		} else if (tok == TK_COLON) {
 			/*
-			 * If this is an existing segment reservation, sections
-			 * can't be assigned to it.
+			 * Special case for STACK "segments":
+			 *
+			 * The ability to modify the stack flags was added
+			 * long after this sysv syntax was designed. It was
+			 * fit into the existing syntax by treating it as a
+			 * segment. However, there can only be one stack program
+			 * header, while segment syntax requires user to supply
+			 * a name. This is confusing, and it allows the user to
+			 * attempt to create more than one stack segment. The
+			 * original implementation had a test to catch this.
+			 *
+			 * If this is a stack segment, locate the real stack
+			 * descriptor and transfer the flags to it. We then
+			 * free the allocated descriptor without inserting it.
+			 * The end result is that all stack segments simply
+			 * alter the one stack descriptor, and the segment
+			 * name is ignored.
 			 */
-			if ((new_segment == FALSE) &&
-			    (sgp1->sg_flags & FLG_SG_EMPTY)) {
-				eprintf(ofl->ofl_lml, ERR_FATAL,
-				    MSG_INTL(MSG_MAP_SEGEMPSEC), mapfile,
-				    EC_XWORD(Line_num));
-				return (S_ERROR);
+			if (sgp1->sg_phdr.p_type == PT_SUNWSTACK) {
+				Sg_desc	*stack = ld_map_seg_stack(mf);
+
+				if (sgp1->sg_flags & FLG_SG_P_FLAGS)
+					stack->sg_phdr.p_flags =
+					    sgp1->sg_phdr.p_flags;
+				free(sgp1);
+
+				DBG_CALL(Dbg_map_seg(ofl,
+				    DBG_STATE_MOD_AFTER, ndx, sgp1,
+				    mf->mf_lineno));
+				break;
 			}
 
 			/*
-			 * We are looking at a new entrance criteria line.
-			 * Note that entrance criteria are added in the order
-			 * they are found in the mapfile, but are placed before
-			 * any default criteria.
+			 * If this is a new segment, finish its initialization
+			 * and insert it into the segment list.
 			 */
-			if ((enp = alist_insert(&(ofl->ofl_ents), NULL,
-			    sizeof (Ent_desc), AL_CNT_OFL_ENTRANCE,
-			    endx)) == NULL)
-				return (S_ERROR);
-
-			enp->ec_segment = sgp1;
-			endx++;
-
-			if (map_colon(ofl, mapfile, enp) == S_ERROR)
-				return (S_ERROR);
-			DBG_CALL(Dbg_map_ent(ofl->ofl_lml, new_segment,
-			    enp, ofl));
-		} else if (tok == TK_ATSIGN) {
-			if (map_atsign(mapfile, sgp1, ofl) == S_ERROR)
-				return (S_ERROR);
-			DBG_CALL(Dbg_map_set_atsign(new_segment));
-		} else if (tok != TK_ERROR) {
-			eprintf(ofl->ofl_lml, ERR_FATAL,
-			    MSG_INTL(MSG_MAP_EXPEQU), mapfile,
-			    EC_XWORD(Line_num));
-			return (S_ERROR);
-		}
+			if (new_segment) {
+				switch (ld_map_seg_insert(mf, DBG_STATE_NEW,
+				    sgp1, where)) {
+				case SEG_INS_SKIP:
+					continue;
+				case SEG_INS_FAIL:
+					return (FALSE);
+				}
+			} else {
+				/* Not new. Show what's changed */
+				DBG_CALL(Dbg_map_seg(ofl,
+				    DBG_STATE_MOD_AFTER, ndx, sgp1,
+				    mf->mf_lineno));
+			}
+			break;
 
-		/*
-		 * Having completed parsing an entry in the mapfile determine
-		 * if the segment to which it applies is new.
-		 */
-		if (new_segment) {
+		case TK_COLON:		/* Section to segment mapping */
 			/*
-			 * If specific fields have not been supplied via
-			 * map_equal(), make sure defaults are supplied.
+			 * If this is a new segment, finish its initialization
+			 * and insert it into the segment list.
+			 *
+			 * If it is not a new segment, ensure that it is
+			 * not an empty segment reservation, as sections
+			 * cannot be assigned to those.
 			 */
-			if (((sgp1->sg_flags & FLG_SG_TYPE) == 0) &&
-			    (sgp1->sg_phdr.p_type == PT_NULL)) {
-				/*
-				 * Default to a loadable segment.
-				 */
-				sgp1->sg_phdr.p_type = PT_LOAD;
-				sgp1->sg_flags |= FLG_SG_TYPE;
-			}
-			if (sgp1->sg_phdr.p_type == PT_LOAD) {
-				if ((sgp1->sg_flags & FLG_SG_FLAGS) == 0) {
-					/*
-					 * Default to read/write and execute.
-					 */
-					sgp1->sg_phdr.p_flags =
-					    PF_R + PF_W + PF_X;
-					sgp1->sg_flags |= FLG_SG_FLAGS;
+			if (new_segment) {
+				switch (ld_map_seg_insert(mf,
+				    DBG_STATE_NEW_IMPLICIT, sgp1, where)) {
+				case SEG_INS_SKIP:
+					continue;
+				case SEG_INS_FAIL:
+					return (FALSE);
 				}
-				if ((sgp1->sg_flags & FLG_SG_ALIGN) == 0) {
-					/*
-					 * Default to segment alignment
-					 */
-					sgp1->sg_phdr.p_align =
-					    ld_targ.t_m.m_segm_align;
-					sgp1->sg_flags |= FLG_SG_ALIGN;
-				}
+			} else if (sgp1->sg_flags & FLG_SG_EMPTY) {
+				mf_fatal0(mf, MSG_INTL(MSG_MAP_SEGEMPSEC));
+				return (FALSE);
 			}
 
 			/*
-			 * Determine where the new item should be inserted in
-			 * the segment descriptor list.  Presently the user can
-			 * only add the following:
-			 *
-			 *  PT_LOAD	added before the text segment.
-			 *  PT_NULL/empty PT_LOAD
-			 *		added after the data/bss segments, thus
-			 *		we add before the dynamic segment.
-			 *  PT_SUNWSTACK
-			 *		added before the final note segment.
-			 *  PT_NOTE	added before the final note segment.
-			 *
-			 * Note that any new segments must always be added
-			 * after any PT_PHDR and PT_INTERP (refer Generic ABI,
-			 * Page 5-4).
+			 * Create new entrance criteria descriptor, and
+			 * process the mapping directive.
+			 */
+			enp = ld_map_seg_ent_add(mf, sgp1, NULL);
+			if ((enp == NULL) || !map_colon(mf, enp))
+				return (FALSE);
+			DBG_CALL(Dbg_map_ent(ofl->ofl_lml, enp, ofl,
+			    mf->mf_lineno));
+			break;
+
+		case TK_ATSIGN:		/* Section size symbol */
+			/*
+			 * If this is a new segment, finish its initialization
+			 * and insert it into the segment list.
 			 */
-			switch (sgp1->sg_phdr.p_type) {
-			case PT_LOAD:
-			case PT_NULL:
-				if (sgp1->sg_flags & FLG_SG_EMPTY)
-					sgp1->sg_id = LD_DYN;
-				else
-					sgp1->sg_id = LD_TEXT;
-				break;
-			case PT_SUNWSTACK:
-				sgp1->sg_id = LD_NOTE;
-				if (++num_stack >= 2) {
-					/*
-					 * Currently the number of sunw_stack
-					 * segment is limited to 1.
-					 */
-					eprintf(ofl->ofl_lml, ERR_WARNING,
-					    MSG_INTL(MSG_MAP_NOSTACK2),
-					    mapfile, EC_XWORD(Line_num));
+			if (new_segment) {
+				switch (ld_map_seg_insert(mf,
+				    DBG_STATE_NEW_IMPLICIT, sgp1, where)) {
+				case SEG_INS_SKIP:
 					continue;
+				case SEG_INS_FAIL:
+					return (FALSE);
 				}
-				break;
-			case PT_NOTE:
-				sgp1->sg_id = LD_NOTE;
-				break;
-			default:
-				eprintf(ofl->ofl_lml, ERR_FATAL,
-				    MSG_INTL(MSG_MAP_UNKSEGTYP), mapfile,
-				    EC_XWORD(Line_num),
-				    EC_WORD(sgp1->sg_phdr.p_type));
-				return (S_ERROR);
 			}
+			if (!map_atsign(mf, sgp1))
+				return (FALSE);
+			break;
 
-			ndx = 0;
-			for (APLIST_TRAVERSE(ofl->ofl_segs, idx, sgp2)) {
-				if (sgp1->sg_id > sgp2->sg_id) {
-					ndx++;
-					continue;
-				}
+		case TK_ERROR:
+			return (FALSE);		/* Error was already issued */
 
-				if (aplist_insert(&ofl->ofl_segs, sgp1,
-				    AL_CNT_SEGMENTS, idx) == NULL)
-					return (S_ERROR);
-				break;
-			}
+		default:
+			mf_fatal0(mf, MSG_INTL(MSG_MAP_EXPEQU));
+			return (FALSE);
 		}
-		DBG_CALL(Dbg_map_seg(ofl, ndx, sgp1));
 	}
 
-	/*
-	 * If the output file is a static file without an interpreter, and
-	 * if any virtual address is specified, then set the ?N flag for
-	 * backward compatibility.
-	 */
-	if (!(ofl->ofl_flags & FLG_OF_DYNAMIC) &&
-	    !(ofl->ofl_flags & FLG_OF_RELOBJ) &&
-	    !(ofl->ofl_osinterp) &&
-	    (ofl->ofl_flags1 & FLG_OF1_VADDR))
-		ofl->ofl_dtflags_1 |= DF_1_NOHDR;
-
-	/*
-	 * If the output file is a relocatable file, then ?N has no effect.
-	 * Make sure this flag isn't set.
-	 */
-	if (ofl->ofl_flags & FLG_OF_RELOBJ)
-		ofl->ofl_dtflags_1 &= ~DF_1_NOHDR;
-
-	return (1);
+	return (TRUE);
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/sgs/libld/common/map_core.c	Mon Feb 22 09:19:31 2010 -0700
@@ -0,0 +1,2838 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ *	Copyright (c) 1988 AT&T
+ *	  All Rights Reserved
+ *
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Map file parsing (Shared Core Code).
+ */
+#include	<fcntl.h>
+#include	<stdio.h>
+#include	<unistd.h>
+#include	<sys/stat.h>
+#include	<errno.h>
+#include	<limits.h>
+#include	<dirent.h>
+#include	<ctype.h>
+#include	<debug.h>
+#include	"msg.h"
+#include	"_libld.h"
+#include	"_map.h"
+
+/*
+ * There are two styles of mapfile supported by the link-editor:
+ *
+ * 1)	The original System V defined syntax, as augmented at Sun
+ *	from Solaris 2.0 through Solaris 10. This style is also known
+ *	as version 1.
+ *
+ * 2)	A newer syntax, currently at version 2.
+ *
+ * The original syntax uses special characters (=, :, -, |, etc) as
+ * operators to indicate the operation being specified. Over the years,
+ * this syntax has been problematic:
+ *
+ * 1)	Too cryptic: It's hard for people to remember which character
+ *	means what.
+ *
+ * 2)	Limited expansion potential: There only a few special characters
+ *	available on the keyboard for new features, and it is difficult to
+ *	add options to existing ones.
+ *
+ * Adding new features into this framework (2) have the effect of
+ * making the syntax even more cryptic (1). The newer syntax addresses
+ * these issues by moving to an extendible identifier based syntax that
+ * allows new features to be added without complicating old ones.
+ *
+ * The new syntax uses the following terminology:
+ *
+ * -	Control directives are the directives that start with a '$'.
+ *	They control how the mapfile is interpreted. We use the 'cdir_'
+ *	prefix on functions and variables related to these directives.
+ *
+ * -	Conditional Expressions are the expressions found in $if and $elif
+ *	control directives. They evaluate to boolean true/false values.
+ *	We use the 'cexp_' prefix for functions and variables related to
+ *	these expressions.
+ *
+ * -	Regular Directives are names (SYMBOL, VERSION, etc) that convey
+ *	directions to the link-editor for building the output object.
+ *
+ * This file contains core code used by both mapfile styles: File management,
+ * lexical analysis, and other shared core functionality. It also contains
+ * the code for control directives, as they are intrinsically part of
+ * lexical analysis --- this is disabled when processing Sysv mapfiles.
+ */
+
+/*
+ * We use a stack of cdir_level_t structs to manage $if/$elif/$else/$endif
+ * processing. At each level, we keep track of the information needed to
+ * determine whether or not to process nested input lines or skip them,
+ * along with information needed to report errors.
+ */
+typedef struct {
+	Lineno		cdl_if_lineno;	/* Line number of opening $if */
+	Lineno		cdl_else_lineno; /* 0, or line on which $else seen */
+	int		cdl_done;	/* True if no longer accepts input */
+	int		cdl_pass;	/* True if currently accepting input */
+} cdir_level_t;
+
+/* Operators in the expressions accepted by $if/$elif */
+typedef enum {
+	CEXP_OP_NONE,		/* Not an operator */
+	CEXP_OP_AND,		/* && */
+	CEXP_OP_OR,		/* || */
+	CEXP_OP_NEG,		/* ! */
+	CEXP_OP_OPAR,		/* ( */
+	CEXP_OP_CPAR		/* ) */
+} cexp_op_t;
+
+/*
+ * Type of conditional expression identifier AVL tree nodes
+ */
+typedef struct cexp_name_node {
+	avl_node_t	ceid_avlnode;	/* AVL book-keeping */
+	const char	*ceid_name;	/* boolean identifier name */
+} cexp_id_node_t;
+
+
+/*
+ * Declare a "stack" type, containing a pointer to data, a count of
+ * allocated, and currently used items in the stack. The data type
+ * is specified as the _type argument.
+ */
+#define	STACK(_type) \
+	struct { \
+		_type	*stk_s;		/* Stack array */ \
+		size_t	stk_n;		/* Current stack depth */ \
+		size_t	stk_n_alloc;	/* # of elements pointed at by s */ \
+	}
+
+/*
+ * The following type represents a "generic" stack, where the data
+ * type is (void). This type is never instantiated. However, it has
+ * the same struct layout as any other STACK(), and is therefore a good
+ * generic type that can be used for stack_resize().
+ */
+typedef STACK(void) generic_stack_t;
+
+/*
+ * Ensure that the stack has enough room to push one more item
+ */
+#define	STACK_RESERVE(_stack, _n_default) \
+	(((_stack).stk_n < (_stack).stk_n_alloc) || \
+	stack_resize((generic_stack_t *)&(_stack).stk_s, _n_default, \
+	sizeof (*(_stack).stk_s)))
+
+/*
+ * Reset a stack to empty.
+ */
+#define	STACK_RESET(_stack) (_stack).stk_n = 0;
+
+/*
+ * True if stack is empty, False otherwise.
+ */
+#define	STACK_IS_EMPTY(_stack) ((_stack).stk_n == 0)
+
+/*
+ * Push a value onto a stack. Caller must ensure that stack has room.
+ * This macro is intended to be used as the LHS of an assignment, the
+ * RHS of which is the value:
+ *
+ *	STACK_PUSH(stack) = value;
+ */
+#define	STACK_PUSH(_stack) (_stack).stk_s[(_stack).stk_n++]
+
+/*
+ * Pop a value off a stack.  Caller must ensure
+ * that stack is not empty.
+ */
+#define	STACK_POP(_stack) ((_stack).stk_s[--(_stack).stk_n])
+
+/*
+ * Access top element on stack without popping. Caller must ensure
+ * that stack is not empty.
+ */
+#define	STACK_TOP(_stack) (((_stack).stk_s)[(_stack).stk_n - 1])
+
+/*
+ * Initial sizes used for the stacks: The stacks are allocated on demand
+ * to these sizes, and then doubled as necessary until they are large enough.
+ *
+ * The ideal size would be large enough that only a single allocation
+ * occurs, and our defaults should generally have that effect. However,
+ * in doing so, we run the risk of a latent error in the resize code going
+ * undetected until triggered by a large task in the field. For this reason,
+ * we set the sizes to the smallest size possible when compiled for debug.
+ */
+#ifdef DEBUG
+#define	CDIR_STACK_INIT		1
+#define	CEXP_OP_STACK_INIT	1
+#define	CEXP_VAL_STACK_INIT	1
+#else
+#define	CDIR_STACK_INIT 	16
+#define	CEXP_OP_STACK_INIT	8
+#define	CEXP_VAL_STACK_INIT	(CEXP_OP_STACK_INIT * 2) /* 2 vals per binop */
+#endif
+
+
+/*
+ * Persistent state maintained by map module in between calls.
+ *
+ * This is kept as static file scope data, because it is only used
+ * when libld is called by ld, and not by rtld. If that should change,
+ * the code is designed so that it can become reentrant easily:
+ *
+ * -	Add a pointer to the output descriptor to a structure of this type,
+ *	allocated dynamically on the first call to ld_map_parse().
+ * -	Change all references to lms to instead reference the pointer in
+ *	the output descriptor.
+ *
+ * Until then, it is simpler not to expose these details.
+ */
+typedef struct {
+	int	lms_cdir_valid;	/* Allow control dir. on entry to gettoken() */
+	STACK(cdir_level_t)	lms_cdir_stack;	/* Conditional input level */
+	STACK(cexp_op_t)	lms_cexp_op_stack; /* Cond. expr operators */
+	STACK(uchar_t)		lms_cexp_val_stack; /* Cond. expr values */
+	avl_tree_t		*lms_cexp_id;
+} ld_map_state_t;
+static ld_map_state_t lms;
+
+
+/*
+ * Version 1 (SysV) syntax dispatch table for ld_map_gettoken(). For each
+ * of the 7-bit ASCII characters, determine how the lexical analyzer
+ * should behave.
+ *
+ * This table must be kept in sync with tkid_attr[] below.
+ *
+ * Identifier Note:
+ * The Linker and Libraries Guide states that the original syntax uses
+ * C identifier rules, allowing '.' to be treated as a letter. However,
+ * the implementation is considerably looser than that: Any character
+ * with an ASCII code (0-127) which is printable and not used to start
+ * another token is allowed to start an identifier, and they are terminated
+ * by any of: space, double quote, tab, newline, ':', ';', '=', or '#'.
+ * The original code has been replaced, but this table encodes the same
+ * rules, to ensure backward compatibility.
+ */
+static const mf_tokdisp_t gettok_dispatch_v1 = {
+	TK_OP_EOF,			/* 0 - NUL */
+	TK_OP_ILLCHR,			/* 1 - SOH */
+	TK_OP_ILLCHR,			/* 2 - STX */
+	TK_OP_ILLCHR,			/* 3 - ETX */
+	TK_OP_ILLCHR,			/* 4 - EOT */
+	TK_OP_ILLCHR,			/* 5 - ENQ */
+	TK_OP_ILLCHR,			/* 6 - ACK */
+	TK_OP_ILLCHR,			/* 7 - BEL */
+	TK_OP_ILLCHR,			/* 8 - BS */
+	TK_OP_WS,			/* 9 - HT */
+	TK_OP_NL,			/* 10 - NL */
+	TK_OP_WS,			/* 11 - VT */
+	TK_OP_WS,			/* 12 - FF */
+	TK_OP_WS,			/* 13 - CR */
+	TK_OP_ILLCHR,			/* 14 - SO */
+	TK_OP_ILLCHR,			/* 15 - SI */
+	TK_OP_ILLCHR,			/* 16 - DLE */
+	TK_OP_ILLCHR,			/* 17 - DC1 */
+	TK_OP_ILLCHR,			/* 18 - DC2 */
+	TK_OP_ILLCHR,			/* 19 - DC3 */
+	TK_OP_ILLCHR,			/* 20 - DC4 */
+	TK_OP_ILLCHR,			/* 21 - NAK */
+	TK_OP_ILLCHR,			/* 22 - SYN */
+	TK_OP_ILLCHR,			/* 23 - ETB */
+	TK_OP_ILLCHR,			/* 24 - CAN */
+	TK_OP_ILLCHR,			/* 25 - EM */
+	TK_OP_ILLCHR,			/* 26 - SUB */
+	TK_OP_ILLCHR,			/* 27 - ESC */
+	TK_OP_ILLCHR,			/* 28 - FS */
+	TK_OP_ILLCHR,			/* 29 - GS */
+	TK_OP_ILLCHR,			/* 30 - RS */
+	TK_OP_ILLCHR,			/* 31 - US */
+	TK_OP_WS,			/* 32 - SP */
+	TK_OP_ID,			/* 33 - ! */
+	TK_OP_SIMQUOTE,			/* 34 - " */
+	TK_OP_CMT,			/* 35 - # */
+	TK_OP_ID,			/* 36 - $ */
+	TK_OP_ID,			/* 37 - % */
+	TK_OP_ID,			/* 38 - & */
+	TK_OP_ID,			/* 39 - ' */
+	TK_OP_ID,			/* 40 - ( */
+	TK_OP_ID,			/* 41 - ) */
+	TK_OP_ID,			/* 42 - * */
+	TK_OP_ID,			/* 43 - + */
+	TK_OP_ID,			/* 44 - , */
+	TK_DASH,			/* 45 - - */
+	TK_OP_ID,			/* 46 - . */
+	TK_OP_ID,			/* 47 - / */
+	TK_OP_ID,			/* 48 - 0 */
+	TK_OP_ID,			/* 49 - 1 */
+	TK_OP_ID,			/* 50 - 2 */
+	TK_OP_ID,			/* 51 - 3 */
+	TK_OP_ID,			/* 52 - 4 */
+	TK_OP_ID,			/* 53 - 5 */
+	TK_OP_ID,			/* 54 - 6 */
+	TK_OP_ID,			/* 55 - 7 */
+	TK_OP_ID,			/* 56 - 8 */
+	TK_OP_ID,			/* 57 - 9 */
+	TK_COLON,			/* 58 - : */
+	TK_SEMICOLON,			/* 59 - ; */
+	TK_OP_ID,			/* 60 - < */
+	TK_EQUAL,			/* 61 - = */
+	TK_OP_ID,			/* 62 - > */
+	TK_OP_ID,			/* 63 - ? */
+	TK_ATSIGN,			/* 64 - @ */
+	TK_OP_ID,			/* 65 - A */
+	TK_OP_ID,			/* 66 - B */
+	TK_OP_ID,			/* 67 - C */
+	TK_OP_ID,			/* 68 - D */
+	TK_OP_ID,			/* 69 - E */
+	TK_OP_ID,			/* 70 - F */
+	TK_OP_ID,			/* 71 - G */
+	TK_OP_ID,			/* 72 - H */
+	TK_OP_ID,			/* 73 - I */
+	TK_OP_ID,			/* 74 - J */
+	TK_OP_ID,			/* 75 - K */
+	TK_OP_ID,			/* 76 - L */
+	TK_OP_ID,			/* 77 - M */
+	TK_OP_ID,			/* 78 - N */
+	TK_OP_ID,			/* 79 - O */
+	TK_OP_ID,			/* 80 - P */
+	TK_OP_ID,			/* 81 - Q */
+	TK_OP_ID,			/* 82 - R */
+	TK_OP_ID,			/* 83 - S */
+	TK_OP_ID,			/* 84 - T */
+	TK_OP_ID,			/* 85 - U */
+	TK_OP_ID,			/* 86 - V */
+	TK_OP_ID,			/* 87 - W */
+	TK_OP_ID,			/* 88 - X */
+	TK_OP_ID,			/* 89 - Y */
+	TK_OP_ID,			/* 90 - Z */
+	TK_OP_ID,			/* 91 - [ */
+	TK_OP_ID,			/* 92 - \ */
+	TK_OP_ID,			/* 93 - ] */
+	TK_OP_ID,			/* 94 - ^ */
+	TK_OP_ID,			/* 95 - _ */
+	TK_OP_ID,			/* 96 - ` */
+	TK_OP_ID,			/* 97 - a */
+	TK_OP_ID,			/* 98 - b */
+	TK_OP_ID,			/* 99 - c */
+	TK_OP_ID,			/* 100 - d */
+	TK_OP_ID,			/* 101 - e */
+	TK_OP_ID,			/* 102 - f */
+	TK_OP_ID,			/* 103 - g */
+	TK_OP_ID,			/* 104 - h */
+	TK_OP_ID,			/* 105 - i */
+	TK_OP_ID,			/* 106 - j */
+	TK_OP_ID,			/* 107 - k */
+	TK_OP_ID,			/* 108 - l */
+	TK_OP_ID,			/* 109 - m */
+	TK_OP_ID,			/* 110 - n */
+	TK_OP_ID,			/* 111 - o */
+	TK_OP_ID,			/* 112 - p */
+	TK_OP_ID,			/* 113 - q */
+	TK_OP_ID,			/* 114 - r */
+	TK_OP_ID,			/* 115 - s */
+	TK_OP_ID,			/* 116 - t */
+	TK_OP_ID,			/* 117 - u */
+	TK_OP_ID,			/* 118 - v */
+	TK_OP_ID,			/* 119 - w */
+	TK_OP_ID,			/* 120 - x */
+	TK_OP_ID,			/* 121 - y */
+	TK_OP_ID,			/* 122 - z */
+	TK_LEFTBKT,			/* 123 - { */
+	TK_PIPE,			/* 124 - | */
+	TK_RIGHTBKT,			/* 125 - } */
+	TK_OP_ID,			/* 126 - ~ */
+	TK_OP_ILLCHR,			/* 127 - DEL */
+};
+
+/*
+ * Version 2 syntax dispatch table for ld_map_gettoken(). For each of the
+ * 7-bit ASCII characters, determine how the lexical analyzer should behave.
+ *
+ * This table must be kept in sync with tkid_attr[] below.
+ *
+ * Identifier Note:
+ * We define a letter as being one of the character [A-Z], [a-z], or [_%/.]
+ * A digit is the numbers [0-9], or [$-]. An unquoted identifier is defined
+ * as a letter, followed by any number of letters or digits. This is a loosened
+ * version of the C definition of an identifier. The extra characters not
+ * allowed by C are common in section names and/or file paths.
+ */
+static const mf_tokdisp_t gettok_dispatch_v2 = {
+	TK_OP_EOF,			/* 0 - NUL */
+	TK_OP_ILLCHR,			/* 1 - SOH */
+	TK_OP_ILLCHR,			/* 2 - STX */
+	TK_OP_ILLCHR,			/* 3 - ETX */
+	TK_OP_ILLCHR,			/* 4 - EOT */
+	TK_OP_ILLCHR,			/* 5 - ENQ */
+	TK_OP_ILLCHR,			/* 6 - ACK */
+	TK_OP_ILLCHR,			/* 7 - BEL */
+	TK_OP_ILLCHR,			/* 8 - BS */
+	TK_OP_WS,			/* 9 - HT */
+	TK_OP_NL,			/* 10 - NL */
+	TK_OP_WS,			/* 11 - VT */
+	TK_OP_WS,			/* 12 - FF */
+	TK_OP_WS,			/* 13 - CR */
+	TK_OP_ILLCHR,			/* 14 - SO */
+	TK_OP_ILLCHR,			/* 15 - SI */
+	TK_OP_ILLCHR,			/* 16 - DLE */
+	TK_OP_ILLCHR,			/* 17 - DC1 */
+	TK_OP_ILLCHR,			/* 18 - DC2 */
+	TK_OP_ILLCHR,			/* 19 - DC3 */
+	TK_OP_ILLCHR,			/* 20 - DC4 */
+	TK_OP_ILLCHR,			/* 21 - NAK */
+	TK_OP_ILLCHR,			/* 22 - SYN */
+	TK_OP_ILLCHR,			/* 23 - ETB */
+	TK_OP_ILLCHR,			/* 24 - CAN */
+	TK_OP_ILLCHR,			/* 25 - EM */
+	TK_OP_ILLCHR,			/* 26 - SUB */
+	TK_OP_ILLCHR,			/* 27 - ESC */
+	TK_OP_ILLCHR,			/* 28 - FS */
+	TK_OP_ILLCHR,			/* 29 - GS */
+	TK_OP_ILLCHR,			/* 30 - RS */
+	TK_OP_ILLCHR,			/* 31 - US */
+	TK_OP_WS,			/* 32 - SP */
+	TK_BANG,			/* 33 - ! */
+	TK_OP_CQUOTE,			/* 34 - " */
+	TK_OP_CMT,			/* 35 - # */
+	TK_OP_CDIR,			/* 36 - $ */
+	TK_OP_ID,			/* 37 - % */
+	TK_OP_BADCHR,			/* 38 - & */
+	TK_OP_SIMQUOTE,			/* 39 - ' */
+	TK_OP_BADCHR,			/* 40 - ( */
+	TK_OP_BADCHR,			/* 41 - ) */
+	TK_STAR,			/* 42 - * */
+	TK_OP_CEQUAL,			/* 43 - + */
+	TK_OP_BADCHR,			/* 44 - , */
+	TK_OP_CEQUAL,			/* 45 - - */
+	TK_OP_ID,			/* 46 - . */
+	TK_OP_ID,			/* 47 - / */
+	TK_OP_NUM,			/* 48 - 0 */
+	TK_OP_NUM,			/* 49 - 1 */
+	TK_OP_NUM,			/* 50 - 2 */
+	TK_OP_NUM,			/* 51 - 3 */
+	TK_OP_NUM,			/* 52 - 4 */
+	TK_OP_NUM,			/* 53 - 5 */
+	TK_OP_NUM,			/* 54 - 6 */
+	TK_OP_NUM,			/* 55 - 7 */
+	TK_OP_NUM,			/* 56 - 8 */
+	TK_OP_NUM,			/* 57 - 9 */
+	TK_COLON,			/* 58 - : */
+	TK_SEMICOLON,			/* 59 - ; */
+	TK_OP_BADCHR,			/* 60 - < */
+	TK_EQUAL,			/* 61 - = */
+	TK_OP_BADCHR,			/* 62 - > */
+	TK_OP_BADCHR,			/* 63 - ? */
+	TK_OP_BADCHR,			/* 64 - @ */
+	TK_OP_ID,			/* 65 - A */
+	TK_OP_ID,			/* 66 - B */
+	TK_OP_ID,			/* 67 - C */
+	TK_OP_ID,			/* 68 - D */
+	TK_OP_ID,			/* 69 - E */
+	TK_OP_ID,			/* 70 - F */
+	TK_OP_ID,			/* 71 - G */
+	TK_OP_ID,			/* 72 - H */
+	TK_OP_ID,			/* 73 - I */
+	TK_OP_ID,			/* 74 - J */
+	TK_OP_ID,			/* 75 - K */
+	TK_OP_ID,			/* 76 - L */
+	TK_OP_ID,			/* 77 - M */
+	TK_OP_ID,			/* 78 - N */
+	TK_OP_ID,			/* 79 - O */
+	TK_OP_ID,			/* 80 - P */
+	TK_OP_ID,			/* 81 - Q */
+	TK_OP_ID,			/* 82 - R */
+	TK_OP_ID,			/* 83 - S */
+	TK_OP_ID,			/* 84 - T */
+	TK_OP_ID,			/* 85 - U */
+	TK_OP_ID,			/* 86 - V */
+	TK_OP_ID,			/* 87 - W */
+	TK_OP_ID,			/* 88 - X */
+	TK_OP_ID,			/* 89 - Y */
+	TK_OP_ID,			/* 90 - Z */
+	TK_OP_BADCHR,			/* 91 - [ */
+	TK_OP_BADCHR,			/* 92 - \ */
+	TK_OP_BADCHR,			/* 93 - ] */
+	TK_OP_BADCHR,			/* 94 - ^ */
+	TK_OP_ID,			/* 95 - _ */
+	TK_OP_BADCHR,			/* 96 - ` */
+	TK_OP_ID,			/* 97 - a */
+	TK_OP_ID,			/* 98 - b */
+	TK_OP_ID,			/* 99 - c */
+	TK_OP_ID,			/* 100 - d */
+	TK_OP_ID,			/* 101 - e */
+	TK_OP_ID,			/* 102 - f */
+	TK_OP_ID,			/* 103 - g */
+	TK_OP_ID,			/* 104 - h */
+	TK_OP_ID,			/* 105 - i */
+	TK_OP_ID,			/* 106 - j */
+	TK_OP_ID,			/* 107 - k */
+	TK_OP_ID,			/* 108 - l */
+	TK_OP_ID,			/* 109 - m */
+	TK_OP_ID,			/* 110 - n */
+	TK_OP_ID,			/* 111 - o */
+	TK_OP_ID,			/* 112 - p */
+	TK_OP_ID,			/* 113 - q */
+	TK_OP_ID,			/* 114 - r */
+	TK_OP_ID,			/* 115 - s */
+	TK_OP_ID,			/* 116 - t */
+	TK_OP_ID,			/* 117 - u */
+	TK_OP_ID,			/* 118 - v */
+	TK_OP_ID,			/* 119 - w */
+	TK_OP_ID,			/* 120 - x */
+	TK_OP_ID,			/* 121 - y */
+	TK_OP_ID,			/* 122 - z */
+	TK_LEFTBKT,			/* 123 - { */
+	TK_OP_BADCHR,			/* 124 - | */
+	TK_RIGHTBKT,			/* 125 - } */
+	TK_OP_BADCHR,			/* 126 - ~ */
+	TK_OP_ILLCHR,			/* 127 - DEL */
+};
+
+
+/*
+ * Table used to identify unquoted identifiers. Each element of this array
+ * contains a bitmask indicating whether the character it represents starts,
+ * or continues an identifier, for each supported mapfile syntax version.
+ */
+static const char tkid_attr[128] = {
+	0,					/* 0 - NUL */
+	TKID_ATTR_CONT(1),			/* 1 - SOH */
+	TKID_ATTR_CONT(1),			/* 2 - STX */
+	TKID_ATTR_CONT(1),			/* 3 - ETX */
+	TKID_ATTR_CONT(1),			/* 4 - EOT */
+	TKID_ATTR_CONT(1),			/* 5 - ENQ */
+	TKID_ATTR_CONT(1),			/* 6 - ACK */
+	TKID_ATTR_CONT(1),			/* 7 - BEL */
+	TKID_ATTR_CONT(1),			/* 8 - BS */
+	0,					/* 9 - HT */
+	0,					/* 10 - NL */
+	TKID_ATTR_CONT(1),			/* 11 - VT */
+	TKID_ATTR_CONT(1),			/* 12 - FF */
+	TKID_ATTR_CONT(1),			/* 13 - CR */
+	TKID_ATTR_CONT(1),			/* 14 - SO */
+	TKID_ATTR_CONT(1),			/* 15 - SI */
+	TKID_ATTR_CONT(1),			/* 16 - DLE */
+	TKID_ATTR_CONT(1),			/* 17 - DC1 */
+	TKID_ATTR_CONT(1),			/* 18 - DC2 */
+	TKID_ATTR_CONT(1),			/* 19 - DC3 */
+	TKID_ATTR_CONT(1),			/* 20 - DC4 */
+	TKID_ATTR_CONT(1),			/* 21 - NAK */
+	TKID_ATTR_CONT(1),			/* 22 - SYN */
+	TKID_ATTR_CONT(1),			/* 23 - ETB */
+	TKID_ATTR_CONT(1),			/* 24 - CAN */
+	TKID_ATTR_CONT(1),			/* 25 - EM */
+	TKID_ATTR_CONT(1),			/* 26 - SUB */
+	TKID_ATTR_CONT(1),			/* 27 - ESC */
+	TKID_ATTR_CONT(1),			/* 28 - FS */
+	TKID_ATTR_CONT(1),			/* 29 - GS */
+	TKID_ATTR_CONT(1),			/* 30 - RS */
+	TKID_ATTR_CONT(1),			/* 31 - US */
+	0,					/* 32 - SP */
+	TKID_ATTR(1),				/* 33 - ! */
+	0,					/* 34 - " */
+	0,					/* 35 - # */
+	TKID_ATTR(1) | TKID_ATTR_CONT(2),	/* 36 - $ */
+	TKID_ATTR(1) | TKID_ATTR_CONT(2),	/* 37 - % */
+	TKID_ATTR(1),				/* 38 - & */
+	TKID_ATTR(1),				/* 39 - ' */
+	TKID_ATTR(1),				/* 40 - ( */
+	TKID_ATTR(1),				/* 41 - ) */
+	TKID_ATTR(1),				/* 42 - * */
+	TKID_ATTR(1),				/* 43 - + */
+	TKID_ATTR(1),				/* 44 - , */
+	TKID_ATTR_CONT(1) | TKID_ATTR_CONT(2),	/* 45 - - */
+	TKID_ATTR(1) | TKID_ATTR(2),		/* 46 - . */
+	TKID_ATTR(1) | TKID_ATTR(2),		/* 47 - / */
+	TKID_ATTR(1) | TKID_ATTR_CONT(2),	/* 48 - 0 */
+	TKID_ATTR(1) | TKID_ATTR_CONT(2),	/* 49 - 1 */
+	TKID_ATTR(1) | TKID_ATTR_CONT(2),	/* 50 - 2 */
+	TKID_ATTR(1) | TKID_ATTR_CONT(2),	/* 51 - 3 */
+	TKID_ATTR(1) | TKID_ATTR_CONT(2),	/* 52 - 4 */
+	TKID_ATTR(1) | TKID_ATTR_CONT(2),	/* 53 - 5 */
+	TKID_ATTR(1) | TKID_ATTR_CONT(2),	/* 54 - 6 */
+	TKID_ATTR(1) | TKID_ATTR_CONT(2),	/* 55 - 7 */
+	TKID_ATTR(1) | TKID_ATTR_CONT(2),	/* 56 - 8 */
+	TKID_ATTR(1) | TKID_ATTR_CONT(2),	/* 57 - 9 */
+	0,					/* 58 - : */
+	0,					/* 59 - ; */
+	TKID_ATTR(1),				/* 60 - < */
+	0,					/* 61 - = */
+	TKID_ATTR(1),				/* 62 - > */
+	TKID_ATTR(1),				/* 63 - ? */
+	TKID_ATTR_CONT(1),			/* 64 - @ */
+	TKID_ATTR(1) | TKID_ATTR(2),		/* 65 - A */
+	TKID_ATTR(1) | TKID_ATTR(2),		/* 66 - B */
+	TKID_ATTR(1) | TKID_ATTR(2),		/* 67 - C */
+	TKID_ATTR(1) | TKID_ATTR(2),		/* 68 - D */
+	TKID_ATTR(1) | TKID_ATTR(2),		/* 69 - E */
+	TKID_ATTR(1) | TKID_ATTR(2),		/* 70 - F */
+	TKID_ATTR(1) | TKID_ATTR(2),		/* 71 - G */
+	TKID_ATTR(1) | TKID_ATTR(2),		/* 72 - H */
+	TKID_ATTR(1) | TKID_ATTR(2),		/* 73 - I */
+	TKID_ATTR(1) | TKID_ATTR(2),		/* 74 - J */
+	TKID_ATTR(1) | TKID_ATTR(2),		/* 75 - K */
+	TKID_ATTR(1) | TKID_ATTR(2),		/* 76 - L */
+	TKID_ATTR(1) | TKID_ATTR(2),		/* 77 - M */
+	TKID_ATTR(1) | TKID_ATTR(2),		/* 78 - N */
+	TKID_ATTR(1) | TKID_ATTR(2),		/* 79 - O */
+	TKID_ATTR(1) | TKID_ATTR(2),		/* 80 - P */
+	TKID_ATTR(1) | TKID_ATTR(2),		/* 81 - Q */
+	TKID_ATTR(1) | TKID_ATTR(2),		/* 82 - R */
+	TKID_ATTR(1) | TKID_ATTR(2),		/* 83 - S */
+	TKID_ATTR(1) | TKID_ATTR(2),		/* 84 - T */
+	TKID_ATTR(1) | TKID_ATTR(2),		/* 85 - U */
+	TKID_ATTR(1) | TKID_ATTR(2),		/* 86 - V */
+	TKID_ATTR(1) | TKID_ATTR(2),		/* 87 - W */
+	TKID_ATTR(1) | TKID_ATTR(2),		/* 88 - X */
+	TKID_ATTR(1) | TKID_ATTR(2),		/* 89 - Y */
+	TKID_ATTR(1) | TKID_ATTR(2),		/* 90 - Z */
+	TKID_ATTR(1),				/* 91 - [ */
+	TKID_ATTR(1),				/* 92 - \ */
+	TKID_ATTR(1),				/* 93 - ] */
+	TKID_ATTR(1),				/* 94 - ^ */
+	TKID_ATTR(1) | TKID_ATTR(2),		/* 95 - _ */
+	TKID_ATTR(1),				/* 96 - ` */
+	TKID_ATTR(1) | TKID_ATTR(2),		/* 97 - a */
+	TKID_ATTR(1) | TKID_ATTR(2),		/* 98 - b */
+	TKID_ATTR(1) | TKID_ATTR(2),		/* 99 - c */
+	TKID_ATTR(1) | TKID_ATTR(2),		/* 100 - d */
+	TKID_ATTR(1) | TKID_ATTR(2),		/* 101 - e */
+	TKID_ATTR(1) | TKID_ATTR(2),		/* 102 - f */
+	TKID_ATTR(1) | TKID_ATTR(2),		/* 103 - g */
+	TKID_ATTR(1) | TKID_ATTR(2),		/* 104 - h */
+	TKID_ATTR(1) | TKID_ATTR(2),		/* 105 - i */
+	TKID_ATTR(1) | TKID_ATTR(2),		/* 106 - j */
+	TKID_ATTR(1) | TKID_ATTR(2),		/* 107 - k */
+	TKID_ATTR(1) | TKID_ATTR(2),		/* 108 - l */
+	TKID_ATTR(1) | TKID_ATTR(2),		/* 109 - m */
+	TKID_ATTR(1) | TKID_ATTR(2),		/* 110 - n */
+	TKID_ATTR(1) | TKID_ATTR(2),		/* 111 - o */
+	TKID_ATTR(1) | TKID_ATTR(2),		/* 112 - p */
+	TKID_ATTR(1) | TKID_ATTR(2),		/* 113 - q */
+	TKID_ATTR(1) | TKID_ATTR(2),		/* 114 - r */
+	TKID_ATTR(1) | TKID_ATTR(2),		/* 115 - s */
+	TKID_ATTR(1) | TKID_ATTR(2),		/* 116 - t */
+	TKID_ATTR(1) | TKID_ATTR(2),		/* 117 - u */
+	TKID_ATTR(1) | TKID_ATTR(2),		/* 118 - v */
+	TKID_ATTR(1) | TKID_ATTR(2),		/* 119 - w */
+	TKID_ATTR(1) | TKID_ATTR(2),		/* 120 - x */
+	TKID_ATTR(1) | TKID_ATTR(2),		/* 121 - y */
+	TKID_ATTR(1) | TKID_ATTR(2),		/* 122 - z */
+	TKID_ATTR_CONT(1),			/* 123 - { */
+	TKID_ATTR_CONT(1),			/* 124 - | */
+	TKID_ATTR_CONT(1),			/* 125 - } */
+	TKID_ATTR(1),				/* 126 - ~ */
+	TKID_ATTR_CONT(1),			/* 127 - DEL */
+};
+
+
+/*
+ * Advance the given string pointer to the next newline character,
+ * or the terminating NULL if there is none.
+ */
+inline static void
+advance_to_eol(char **str)
+{
+	char	*s = *str;
+
+	while ((*s != '\n') && (*s != '\0'))
+		s++;
+	*str = s;
+}
+
+/*
+ * Insert a NULL patch at the given address
+ */
+inline static void
+null_patch_set(char *str, ld_map_npatch_t *np)
+{
+	np->np_ptr = str;
+	np->np_ch = *str;
+	*str = '\0';
+}
+
+/*
+ * Undo a NULL patch
+ */
+inline static void
+null_patch_undo(ld_map_npatch_t *np)
+{
+	*np->np_ptr = np->np_ch;
+}
+
+/*
+ * Insert a NULL patch at the end of the line containing str.
+ */
+static void
+null_patch_eol(char *str, ld_map_npatch_t *np)
+{
+	advance_to_eol(&str);
+	null_patch_set(str, np);
+}
+
+/*
+ * Locate the end of an unquoted identifier.
+ *
+ * entry:
+ *	mf - Mapfile descriptor, positioned to first character
+ *		of identifier.
+ *
+ * exit:
+ *	If the item pointed at by mf is not an identifier, returns NULL.
+ *	Otherwise, returns pointer to character after the last character
+ *	of the identifier.
+ */
+inline static char *
+ident_delimit(Mapfile *mf)
+{
+	char		*str = mf->mf_next;
+	ld_map_npatch_t	np;
+	int		c = *str++;
+
+	/* If not a valid start character, report the error */
+	if ((c & 0x80) || !(tkid_attr[c] & mf->mf_tkid_start)) {
+		null_patch_set(str, &np);
+		mf_fatal(mf, MSG_INTL(MSG_MAP_BADCHAR), str);
+		null_patch_undo(&np);
+		return (NULL);
+	}
+
+	/* Keep going until we hit a non-continuing character */
+	for (c = *str; !(c & 0x80) && (tkid_attr[c] & mf->mf_tkid_cont);
+	    c = *++str)
+		;
+
+	return (str);
+}
+
+/*
+ * Allocate memory for a stack.
+ *
+ * entry:
+ *	stack - Pointer to stack for which memory is required, cast
+ *		to the generic stack type.
+ *	n_default - Size to use for initial allocation.
+ *	elt_size - sizeof(elt), where elt is the actual stack data type.
+ *
+ * exit:
+ *	Returns (1) on success. On error (memory allocation), a message
+ *	is printed and False (0) is returned.
+ *
+ * note:
+ *	The caller casts the pointer to their actual datatype-specific stack
+ *	to be a (generic_stack_t *). The C language will give all stack
+ *	structs the same size and layout as long as the underlying platform
+ *	uses a single integral type for pointers. Hence, this cast is safe,
+ *	and lets a generic routine modify data-specific types without being
+ *	aware of those types.
+ */
+static Boolean
+stack_resize(generic_stack_t *stack, size_t n_default, size_t elt_size)
+{
+	size_t	new_n_alloc;
+	void	*newaddr;
+
+	/* Use initial size first, and double the allocation on each call */
+	new_n_alloc = (stack->stk_n_alloc == 0) ?
+	    n_default : (stack->stk_n_alloc * 2);
+
+	newaddr = libld_realloc(stack->stk_s, new_n_alloc * elt_size);
+	if (newaddr == NULL)
+		return (FALSE);
+
+	stack->stk_s = newaddr;
+	stack->stk_n_alloc = new_n_alloc;
+	return (TRUE);
+}
+
+/*
+ * AVL comparison function for cexp_id_node_t items.
+ *
+ * entry:
+ *      n1, n2 - pointers to nodes to be compared
+ *
+ * exit:
+ *      Returns -1 if (n1 < n2), 0 if they are equal, and 1 if (n1 > n2)
+ */
+static int
+cexp_ident_cmp(const void *n1, const void *n2)
+{
+	int	rc;
+
+	rc = strcmp(((cexp_id_node_t *)n1)->ceid_name,
+	    ((cexp_id_node_t *)n2)->ceid_name);
+
+	if (rc > 0)
+		return (1);
+	if (rc < 0)
+		return (-1);
+	return (0);
+}
+
+
+/*
+ * Returns True (1) if name is in the conditional expression identifier
+ * AVL tree, and False (0) otherwise.
+ */
+static int
+cexp_ident_test(const char *name)
+{
+	cexp_id_node_t	node;
+
+	node.ceid_name = name;
+	return (avl_find(lms.lms_cexp_id, &node, 0) != NULL);
+}
+
+/*
+ * Add a new boolean identifier to the conditional expression identifier
+ * AVL tree.
+ *
+ * entry:
+ *	mf - If non-NULL, the mapfile descriptor for the mapfile
+ *		containing the $add directive. NULL if this is an
+ *		initialization call.
+ *	name - Name of identifier. Must point at stable storage that will
+ *		not be moved or modified by the caller following this call.
+ *
+ * exit:
+ *	On success, True (1) is returned and name has been entered.
+ *	On failure, False (0) is returned and an error has been printed.
+ */
+static int
+cexp_ident_add(Mapfile *mf, const char *name)
+{
+	cexp_id_node_t	*node;
+
+	if (mf != NULL) {
+		DBG_CALL(Dbg_map_cexp_id(mf->mf_ofl->ofl_lml, 1,
+		    mf->mf_name, mf->mf_lineno, name));
+
+		/* If is already known, don't do it again */
+		if (cexp_ident_test(name))
+			return (1);
+	}
+
+	if ((node = libld_calloc(sizeof (*node), 1)) == NULL)
+		return (0);
+	node->ceid_name = name;
+	avl_add(lms.lms_cexp_id, node);
+	return (1);
+}
+
+/*
+ * Remove a boolean identifier from the conditional expression identifier
+ * AVL tree.
+ *
+ * entry:
+ *	mf - Mapfile descriptor
+ *	name - Name of identifier.
+ *
+ * exit:
+ *	If the name was in the tree, it has been removed. If not,
+ *	then this routine quietly returns.
+ */
+static void
+cexp_ident_clear(Mapfile *mf, const char *name)
+{
+	cexp_id_node_t	node;
+	cexp_id_node_t	*real_node;
+
+	DBG_CALL(Dbg_map_cexp_id(mf->mf_ofl->ofl_lml, 0,
+	    mf->mf_name, mf->mf_lineno, name));
+
+	node.ceid_name = name;
+	real_node = avl_find(lms.lms_cexp_id, &node, 0);
+	if (real_node != NULL)
+		avl_remove(lms.lms_cexp_id, real_node);
+}
+
+/*
+ * Initialize the AVL tree that holds the names of the currently defined
+ * boolean identifiers for conditional expressions ($if/$elif).
+ *
+ * entry:
+ *	ofl - Output file descriptor
+ *
+ * exit:
+ *	On success, TRUE (1) is returned and lms.lms_cexp_id is ready for use.
+ *	On failure, FALSE (0) is returned.
+ */
+static Boolean
+cexp_ident_init(void)
+{
+	/* If already done, use it */
+	if (lms.lms_cexp_id != NULL)
+		return (TRUE);
+
+	lms.lms_cexp_id = libld_calloc(sizeof (*lms.lms_cexp_id), 1);
+	if (lms.lms_cexp_id == NULL)
+		return (FALSE);
+	avl_create(lms.lms_cexp_id, cexp_ident_cmp, sizeof (cexp_id_node_t),
+	    SGSOFFSETOF(cexp_id_node_t, ceid_avlnode));
+
+
+	/* ELFCLASS */
+	if (cexp_ident_add(NULL, (ld_targ.t_m.m_class == ELFCLASS32) ?
+	    MSG_ORIG(MSG_STR_UELF32) : MSG_ORIG(MSG_STR_UELF64)) == 0)
+		return (FALSE);
+
+	/* Machine */
+	switch (ld_targ.t_m.m_mach) {
+	case EM_386:
+	case EM_AMD64:
+		if (cexp_ident_add(NULL, MSG_ORIG(MSG_STR_UX86)) == 0)
+			return (FALSE);
+		break;
+
+	case EM_SPARC:
+	case EM_SPARCV9:
+		if (cexp_ident_add(NULL, MSG_ORIG(MSG_STR_USPARC)) == 0)
+			return (FALSE);
+		break;
+	}
+
+	/* true is always defined */
+	if (cexp_ident_add(NULL, MSG_ORIG(MSG_STR_TRUE)) == 0)
+		return (FALSE);
+
+	return (TRUE);
+}
+
+/*
+ * Validate the string starting at mf->mf_next as being a
+ * boolean conditional expression identifier.
+ *
+ * entry:
+ *	mf - Mapfile descriptor
+ *	len - NULL, or address of variable to receive strlen() of identifier
+ *	directive - If (len == NULL), string giving name of directive being
+ *		processed. Ignored if (len != NULL).
+ *
+ * exit:
+ *	On success:
+ *	-	If len is NULL, a NULL is inserted following the final
+ *		character of the identifier, and the remainder of the string
+ *		is tested to ensure it is empty, or only contains whitespace.
+ *	-	If len is non-NULL, *len is set to the number of characters
+ *		in the identifier, and the rest of the string is not modified.
+ *	-	TRUE (1) is returned
+ *
+ *	On failure, returns FALSE (0).
+ */
+static Boolean
+cexp_ident_validate(Mapfile *mf, size_t *len, const char *directive)
+{
+	char	*tail;
+
+	if ((tail = ident_delimit(mf)) == NULL)
+		return (FALSE);
+
+	/*
+	 * If len is non-NULL, we simple count the number of characters
+	 * consumed by the identifier and are done. If len is NULL, then
+	 * ensure there's nothing left but whitespace, and NULL terminate
+	 * the identifier to remove it.
+	 */
+	if (len != NULL) {
+		*len = tail - mf->mf_next;
+	} else if (*tail != '\0') {
+		*tail++ = '\0';
+		while (isspace(*tail))
+			tail++;
+		if (*tail != '\0') {
+			mf_fatal(mf, MSG_INTL(MSG_MAP_BADEXTRA), directive);
+			return (FALSE);
+		}
+	}
+
+	return (TRUE);
+}
+
+/*
+ * Push a new operator onto the conditional expression operator stack.
+ *
+ * entry:
+ *	mf - Mapfile descriptor
+ *	op - Operator to push
+ *
+ * exit:
+ *	On success, TRUE (1) is returned, otherwise FALSE (0).
+ */
+static Boolean
+cexp_push_op(cexp_op_t op)
+{
+	if (STACK_RESERVE(lms.lms_cexp_op_stack, CEXP_OP_STACK_INIT) == 0)
+		return (FALSE);
+
+	STACK_PUSH(lms.lms_cexp_op_stack) = op;
+	return (TRUE);
+}
+
+/*
+ * Evaluate the basic operator (non-paren) at the top of lms.lms_cexp_op_stack,
+ * and push the results on lms.lms_cexp_val_stack.
+ *
+ * exit:
+ *	On success, returns TRUE (1). On error, FALSE (0) is returned,
+ *	and the caller is responsible for issuing the error.
+ */
+static Boolean
+cexp_eval_op(void)
+{
+	cexp_op_t	op;
+	uchar_t		val;
+
+	op = STACK_POP(lms.lms_cexp_op_stack);
+	switch (op) {
+	case CEXP_OP_AND:
+		if (lms.lms_cexp_val_stack.stk_n < 2)
+			return (FALSE);
+		val = STACK_POP(lms.lms_cexp_val_stack);
+		STACK_TOP(lms.lms_cexp_val_stack) = val &&
+		    STACK_TOP(lms.lms_cexp_val_stack);
+		break;
+
+	case CEXP_OP_OR:
+		if (lms.lms_cexp_val_stack.stk_n < 2)
+			return (FALSE);
+		val = STACK_POP(lms.lms_cexp_val_stack);
+		STACK_TOP(lms.lms_cexp_val_stack) = val ||
+		    STACK_TOP(lms.lms_cexp_val_stack);
+		break;
+
+	case CEXP_OP_NEG:
+		if (lms.lms_cexp_val_stack.stk_n < 1)
+			return (FALSE);
+		STACK_TOP(lms.lms_cexp_val_stack) =
+		    !STACK_TOP(lms.lms_cexp_val_stack);
+		break;
+	default:
+		return (FALSE);
+	}
+
+	return (TRUE);
+}
+
+/*
+ * Evaluate an expression for a $if/$elif control directive.
+ *
+ * entry:
+ *	mf - Mapfile descriptor for NULL terminated string
+ *		containing the expression.
+ *
+ * exit:
+ *	The contents of str are modified by this routine.
+ *	One of the following values are returned:
+ *		-1	Syntax error encountered (an error is printed)
+ *		0	The expression evaluates to False
+ *		1	The expression evaluates to True.
+ *
+ * note:
+ *	A simplified version of Dijkstra's Shunting Yard algorithm is used
+ *	to convert this syntax into postfix form and then evaluate it.
+ *	Our version has no functions and a tiny set of operators.
+ *
+ *	The expressions consist of boolean identifiers, which can be
+ *	combined using the following operators, listed from highest
+ *	precedence to least:
+ *
+ *		Operator	Meaning
+ *		-------------------------------------------------
+ *		(expr)		sub-expression, non-associative
+ *		!		logical negation, prefix, left associative
+ *		&&  ||		logical and/or, binary, left associative
+ *
+ *	The operands manipulated by these operators are names, consisting of
+ *	a sequence of letters and digits. The first character must be a letter.
+ *	Underscore (_) and period (.) are also considered to be characters.
+ *	An operand is considered True if it is found in our set of known
+ *	names (lms.lms_cexp_id), and False otherwise.
+ *
+ *	The Shunting Yard algorithm works using two stacks, one for operators,
+ *	and a second for operands. The infix input expression is tokenized from
+ *	left to right and processed in order. Issues of associativity and
+ *	precedence are managed by reducing (poping and evaluating) items with
+ *	higer precedence before pushing additional tokens with lower precedence.
+ */
+static int
+cexp_eval_expr(Mapfile *mf)
+{
+	char		*ident;
+	size_t		len;
+	cexp_op_t	new_op = CEXP_OP_AND;	/* to catch binop at start */
+	ld_map_npatch_t	np;
+	char		*str = mf->mf_next;
+
+	STACK_RESET(lms.lms_cexp_op_stack);
+	STACK_RESET(lms.lms_cexp_val_stack);
+
+	for (; *str; str++) {
+
+		/* Skip whitespace */
+		while (isspace(*str))
+			str++;
+		if (!*str)
+			break;
+
+		switch (*str) {
+		case '&':
+		case '|':
+			if (*(str + 1) != *str)
+				goto token_error;
+			if ((new_op != CEXP_OP_NONE) &&
+			    (new_op != CEXP_OP_CPAR)) {
+				mf_fatal0(mf, MSG_INTL(MSG_MAP_CEXP_BADOPUSE));
+				return (-1);
+			}
+			str++;
+
+			/*
+			 * As this is a left associative binary operator, we
+			 * need to process all operators of equal or higher
+			 * precedence before pushing the new operator.
+			 */
+			while (!STACK_IS_EMPTY(lms.lms_cexp_op_stack)) {
+				cexp_op_t op = STACK_TOP(lms.lms_cexp_op_stack);
+
+
+				if ((op != CEXP_OP_AND) && (op != CEXP_OP_OR) &&
+				    (op != CEXP_OP_NEG))
+					break;
+
+				if (!cexp_eval_op())
+					goto semantic_error;
+			}
+
+			new_op = (*str == '&') ? CEXP_OP_AND : CEXP_OP_OR;
+			if (!cexp_push_op(new_op))
+				return (-1);
+			break;
+
+		case '!':
+			new_op = CEXP_OP_NEG;
+			if (!cexp_push_op(new_op))
+				return (-1);
+			break;
+
+		case '(':
+			new_op = CEXP_OP_OPAR;
+			if (!cexp_push_op(new_op))
+				return (-1);
+			break;
+
+		case ')':
+			new_op = CEXP_OP_CPAR;
+
+			/* Evaluate the operator stack until reach '(' */
+			while (!STACK_IS_EMPTY(lms.lms_cexp_op_stack) &&
+			    (STACK_TOP(lms.lms_cexp_op_stack) != CEXP_OP_OPAR))
+				if (!cexp_eval_op())
+					goto semantic_error;
+
+			/*
+			 * If the top of operator stack is not an open paren,
+			 * when we have an error. In this case, the operator
+			 * stack will be empty due to the loop above.
+			 */
+			if (STACK_IS_EMPTY(lms.lms_cexp_op_stack))
+				goto unbalpar_error;
+			lms.lms_cexp_op_stack.stk_n--;   /* Pop OPAR */
+			break;
+
+		default:
+			/* Ensure there's room to push another operand */
+			if (STACK_RESERVE(lms.lms_cexp_val_stack,
+			    CEXP_VAL_STACK_INIT) == 0)
+				return (0);
+			new_op = CEXP_OP_NONE;
+
+			/*
+			 * Operands cannot be numbers. However, we accept two
+			 * special cases: '0' means false, and '1' is true.
+			 * This is done to support the common C idiom of
+			 * '#if 1' and '#if 0' to conditionalize code under
+			 * development.
+			 */
+			if ((*str == '0') || (*str == '1')) {
+				STACK_PUSH(lms.lms_cexp_val_stack) =
+				    (*str == '1');
+				break;
+			}
+
+			/* Look up the identifier */
+			ident = mf->mf_next = str;
+			if (!cexp_ident_validate(mf, &len, NULL))
+				return (-1);
+			str += len - 1;	  /* loop will advance past final ch */
+			null_patch_set(&ident[len], &np);
+			STACK_PUSH(lms.lms_cexp_val_stack) =
+			    cexp_ident_test(ident);
+			null_patch_undo(&np);
+
+			break;
+		}
+	}
+
+	/* Evaluate the operator stack until empty */
+	while (!STACK_IS_EMPTY(lms.lms_cexp_op_stack)) {
+		if (STACK_TOP(lms.lms_cexp_op_stack) == CEXP_OP_OPAR)
+			goto unbalpar_error;
+
+		if (!cexp_eval_op())
+			goto semantic_error;
+	}
+
+	/* There should be exactly one value left */
+	if (lms.lms_cexp_val_stack.stk_n != 1)
+		goto semantic_error;
+
+	/* Final value is the result */
+	return (lms.lms_cexp_val_stack.stk_s[0]);
+
+	/* Errors issued more than once are handled below, accessed via goto */
+
+token_error:			/* unexpected characters in input stream */
+	mf_fatal(mf, MSG_INTL(MSG_MAP_CEXP_TOKERR), str);
+	return (-1);
+
+semantic_error:			/* valid tokens, but in invalid arrangement */
+	mf_fatal0(mf, MSG_INTL(MSG_MAP_CEXP_SEMERR));
+	return (-1);
+
+unbalpar_error:			/* Extra or missing parenthesis */
+	mf_fatal0(mf, MSG_INTL(MSG_MAP_CEXP_UNBALPAR));
+	return (-1);
+}
+
+/*
+ * Process a mapfile control directive. These directives start with
+ * the dollar character, and are used to manage details of the mapfile
+ * itself, such as version and conditional input.
+ *
+ * entry:
+ *	mf - Mapfile descriptor
+ *
+ * exit:
+ *	Returns TRUE (1) for success, and FALSE (0) on error. In the
+ *	error case, a descriptive error is issued.
+ */
+static Boolean
+cdir_process(Mapfile *mf)
+{
+	typedef enum {			/* Directive types */
+		CDIR_T_UNKNOWN = 0,	/* Unrecognized control directive */
+		CDIR_T_ADD,		/* $add */
+		CDIR_T_CLEAR,		/* $clear */
+		CDIR_T_ERROR,		/* $error */
+		CDIR_T_VERSION,		/* $mapfile_version */
+		CDIR_T_IF,		/* $if */
+		CDIR_T_ELIF,		/* $elif */
+		CDIR_T_ELSE,		/* $else */
+		CDIR_T_ENDIF,		/* $endif */
+	} cdir_t;
+
+	typedef enum {		/* Types of arguments accepted by directives */
+		ARG_T_NONE,	/* Directive takes no arguments */
+		ARG_T_EXPR,	/* Directive takes a conditional expression */
+		ARG_T_ID,	/* Conditional expression identifier */
+		ARG_T_STR,	/* Non-empty string */
+		ARG_T_IGN	/* Ignore the argument */
+	} cdir_arg_t;
+
+	typedef struct {
+		const char	*md_name;	/* Directive name */
+		size_t		md_size;	/* strlen(md_name) */
+		cdir_arg_t	md_arg;		/* Type of arguments */
+		cdir_t		md_op;		/* CDIR_T_ code */
+	} cdir_match_t;
+
+	/* Control Directives: The most likely items are listed first */
+	static cdir_match_t match_data[] = {
+		{ MSG_ORIG(MSG_STR_CDIR_IF),	MSG_STR_CDIR_IF_SIZE,
+		    ARG_T_EXPR,			CDIR_T_IF },
+		{ MSG_ORIG(MSG_STR_CDIR_ENDIF),	MSG_STR_CDIR_ENDIF_SIZE,
+		    ARG_T_NONE,			CDIR_T_ENDIF },
+		{ MSG_ORIG(MSG_STR_CDIR_ELSE),	MSG_STR_CDIR_ELSE_SIZE,
+		    ARG_T_NONE,			CDIR_T_ELSE },
+		{ MSG_ORIG(MSG_STR_CDIR_ELIF),	MSG_STR_CDIR_ELIF_SIZE,
+		    ARG_T_EXPR,			CDIR_T_ELIF },
+		{ MSG_ORIG(MSG_STR_CDIR_ERROR),	MSG_STR_CDIR_ERROR_SIZE,
+		    ARG_T_STR,			CDIR_T_ERROR },
+		{ MSG_ORIG(MSG_STR_CDIR_ADD),	MSG_STR_CDIR_ADD_SIZE,
+		    ARG_T_ID,			CDIR_T_ADD },
+		{ MSG_ORIG(MSG_STR_CDIR_CLEAR),	MSG_STR_CDIR_CLEAR_SIZE,
+		    ARG_T_ID,			CDIR_T_CLEAR },
+		{ MSG_ORIG(MSG_STR_CDIR_MFVER),	MSG_STR_CDIR_MFVER_SIZE,
+		    ARG_T_IGN,			CDIR_T_VERSION },
+
+		{ NULL,				0,
+		    ARG_T_IGN,			CDIR_T_UNKNOWN }
+	};
+
+	cdir_match_t	*mdptr;
+	char		*tail;
+	int		expr_eval;	/* Result of evaluating ARG_T_EXPR */
+	Mapfile		arg_mf;
+	cdir_level_t	*level;
+	int		pass, parent_pass;	/* Currently accepting input */
+
+restart:
+	/* Is the immediate context passing input? */
+	pass = STACK_IS_EMPTY(lms.lms_cdir_stack) ||
+	    STACK_TOP(lms.lms_cdir_stack).cdl_pass;
+
+	/* Is the surrounding (parent) context passing input? */
+	parent_pass = (lms.lms_cdir_stack.stk_n <= 1) ||
+	    lms.lms_cdir_stack.stk_s[lms.lms_cdir_stack.stk_n - 2].cdl_pass;
+
+
+	for (mdptr = match_data; mdptr->md_name; mdptr++) {
+		/* Prefix must match, or we move on */
+		if (strncmp(mf->mf_next, mdptr->md_name,
+		    mdptr->md_size) != 0)
+			continue;
+		tail = mf->mf_next + mdptr->md_size;
+
+		/*
+		 * If there isn't whitespace, or a NULL terminator following
+		 * the prefix, then even though our prefix matched, the actual
+		 * token is longer, and we don't have a match.
+		 */
+		if (!isspace(*tail) && (*tail != '\0'))
+			continue;
+
+		/* We have matched a valid control directive */
+		break;
+	}
+
+	/* Advance input to end of the current line */
+	advance_to_eol(&mf->mf_next);
+
+	/*
+	 * Set up a temporary mapfile descriptor to reference the
+	 * argument string. The benefit of this second block, is that
+	 * we can advance the real one to the next line now, which allows
+	 * us to return at any time knowing that the input has been moved
+	 * to the proper spot. This simplifies the error cases.
+	 *
+	 * If we had a match, tail points at the start of the string.
+	 * Otherwise, we want to point at the end of the line.
+	 */
+	arg_mf = *mf;
+	if (mdptr->md_name == NULL)
+		arg_mf.mf_text = arg_mf.mf_next;
+	else
+		arg_mf.mf_text = arg_mf.mf_next = tail;
+
+	/*
+	 * Null terminate the arguments, and advance the main mapfile
+	 * state block to the next line.
+	 */
+	if (*mf->mf_next == '\n') {
+		*mf->mf_next++ = '\0';
+		mf->mf_lineno++;
+	}
+
+	/* Skip leading whitespace to arguments */
+	while (isspace(*arg_mf.mf_next))
+		arg_mf.mf_next++;
+
+	/* Strip off any comment present on the line */
+	for (tail = arg_mf.mf_next; *tail; tail++)
+		if (*tail == '#') {
+			*tail = '\0';
+			break;
+		}
+
+	/*
+	 * Process the arguments as necessary depending on their type.
+	 * If this control directive is nested inside a surrounding context
+	 * that is not currently passing text, then we skip the argument
+	 * evaluation. This follows the behavior of the C preprocessor,
+	 * which only examines enough to detect the operation within
+	 * a disabled section, without issuing errors about the arguments.
+	 */
+	if (pass || (parent_pass && (mdptr->md_op == CDIR_T_ELIF))) {
+		switch (mdptr->md_arg) {
+		case ARG_T_NONE:
+			if (*arg_mf.mf_next == '\0')
+				break;
+			/* Args are present, but not wanted */
+			mf_fatal(&arg_mf, MSG_INTL(MSG_MAP_CDIR_REQNOARG),
+			    mdptr->md_name);
+			return (FALSE);
+
+		case ARG_T_EXPR:
+			/* Ensure that arguments are present */
+			if (*arg_mf.mf_next == '\0')
+				goto error_reqarg;
+			expr_eval = cexp_eval_expr(&arg_mf);
+			if (expr_eval == -1)
+				return (FALSE);
+			break;
+
+		case ARG_T_ID:
+			/* Ensure that arguments are present */
+			if (*arg_mf.mf_next == '\0')
+				goto error_reqarg;
+			if (!cexp_ident_validate(&arg_mf, NULL,
+			    mdptr->md_name))
+				return (FALSE);
+			break;
+
+		case ARG_T_STR:
+			/* Ensure that arguments are present */
+			if (*arg_mf.mf_next == '\0')
+				goto error_reqarg;
+			/* Remove trailing whitespace */
+			tail = arg_mf.mf_next + strlen(arg_mf.mf_next);
+			while ((tail > arg_mf.mf_next) &&
+			    isspace(*(tail -1)))
+				tail--;
+			*tail = '\0';
+			break;
+		}
+	}
+
+	/*
+	 * Carry out the specified control directive:
+	 */
+	if (!STACK_IS_EMPTY(lms.lms_cdir_stack))
+		level = &STACK_TOP(lms.lms_cdir_stack);
+
+	switch (mdptr->md_op) {
+	case CDIR_T_UNKNOWN:		/* Unrecognized control directive */
+		if (!pass)
+			break;
+		mf_fatal0(&arg_mf, MSG_INTL(MSG_MAP_CDIR_BAD));
+		return (FALSE);
+
+	case CDIR_T_ADD:
+		if (pass && !cexp_ident_add(&arg_mf, arg_mf.mf_next))
+			return (FALSE);
+		break;
+
+	case CDIR_T_CLEAR:
+		if (pass)
+			cexp_ident_clear(&arg_mf, arg_mf.mf_next);
+		break;
+
+	case CDIR_T_ERROR:
+		if (!pass)
+			break;
+		mf_fatal(&arg_mf, MSG_INTL(MSG_MAP_CDIR_ERROR),
+		    arg_mf.mf_next);
+		return (FALSE);
+
+	case CDIR_T_VERSION:
+		/*
+		 * A $mapfile_version control directive can only appear
+		 * as the first directive in a mapfile, and is used to
+		 * determine the syntax for the rest of the file. It's
+		 * too late to be using it here.
+		 */
+		if (!pass)
+			break;
+		mf_fatal0(&arg_mf, MSG_INTL(MSG_MAP_CDIR_REPVER));
+		return (FALSE);
+
+	case CDIR_T_IF:
+		/* Push a new level on the conditional input stack */
+		if (STACK_RESERVE(lms.lms_cdir_stack, CDIR_STACK_INIT) == 0)
+			return (FALSE);
+		level = &lms.lms_cdir_stack.stk_s[lms.lms_cdir_stack.stk_n++];
+		level->cdl_if_lineno = arg_mf.mf_lineno;
+		level->cdl_else_lineno = 0;
+
+		/*
+		 * If previous level is not passing, this level is disabled.
+		 * Otherwise, the expression value determines what happens.
+		 */
+		if (pass) {
+			level->cdl_done = level->cdl_pass = expr_eval;
+		} else {
+			level->cdl_done = 1;
+			level->cdl_pass = 0;
+		}
+		break;
+
+	case CDIR_T_ELIF:
+		/* $elif requires an open $if construct */
+		if (STACK_IS_EMPTY(lms.lms_cdir_stack)) {
+			mf_fatal(&arg_mf, MSG_INTL(MSG_MAP_CDIR_NOIF),
+			    MSG_ORIG(MSG_STR_CDIR_ELIF));
+			return (FALSE);
+		}
+
+		/* $elif cannot follow $else */
+		if (level->cdl_else_lineno > 0) {
+			mf_fatal(&arg_mf, MSG_INTL(MSG_MAP_CDIR_ELSE),
+			    MSG_ORIG(MSG_STR_CDIR_ELIF),
+			    EC_LINENO(level->cdl_else_lineno));
+			return (FALSE);
+		}
+
+		/*
+		 * Accept text from $elif if the level isn't already
+		 * done and the expression evaluates to true.
+		 */
+		level->cdl_pass = !level->cdl_done && expr_eval;
+		if (level->cdl_pass)
+			level->cdl_done = 1;
+		break;
+
+	case CDIR_T_ELSE:
+		/* $else requires an open $if construct */
+		if (STACK_IS_EMPTY(lms.lms_cdir_stack)) {
+			mf_fatal(&arg_mf, MSG_INTL(MSG_MAP_CDIR_NOIF),
+			    MSG_ORIG(MSG_STR_CDIR_ELSE));
+			return (FALSE);
+		}
+
+		/* There can only be one $else in the chain */
+		if (level->cdl_else_lineno > 0) {
+			mf_fatal(&arg_mf, MSG_INTL(MSG_MAP_CDIR_ELSE),
+			    MSG_ORIG(MSG_STR_CDIR_ELSE),
+			    EC_LINENO(level->cdl_else_lineno));
+			return (FALSE);
+		}
+		level->cdl_else_lineno = arg_mf.mf_lineno;
+
+		/* Accept text from $else if the level isn't already done */
+		level->cdl_pass = !level->cdl_done;
+		level->cdl_done = 1;
+		break;
+
+	case CDIR_T_ENDIF:
+		/* $endif requires an open $if construct */
+		if (STACK_IS_EMPTY(lms.lms_cdir_stack)) {
+			mf_fatal(&arg_mf, MSG_INTL(MSG_MAP_CDIR_NOIF),
+			    MSG_ORIG(MSG_STR_CDIR_ENDIF));
+			return (FALSE);
+		}
+		if (--lms.lms_cdir_stack.stk_n > 0)
+			level = &STACK_TOP(lms.lms_cdir_stack);
+		break;
+
+	default:
+		return (FALSE);
+	}
+
+	/* Evaluating the control directive above can change pass status */
+	expr_eval = STACK_IS_EMPTY(lms.lms_cdir_stack) ||
+	    STACK_TOP(lms.lms_cdir_stack).cdl_pass;
+	if (expr_eval != pass) {
+		pass = expr_eval;
+		DBG_CALL(Dbg_map_pass(arg_mf.mf_ofl->ofl_lml, pass,
+		    arg_mf.mf_name, arg_mf.mf_lineno, mdptr->md_name));
+	}
+
+	/*
+	 * At this point, we have processed a control directive,
+	 * updated our conditional state stack, and the input is
+	 * positioned at the start of the line following the directive.
+	 * If the current level is accepting input, then give control
+	 * back to ld_map_gettoken() to resume its normal operation.
+	 */
+	if (pass)
+		return (TRUE);
+
+	/*
+	 * The current level is not accepting input. Only another
+	 * control directive can change this, so read and discard input
+	 * until we encounter one of the following:
+	 *
+	 * EOF:			Return and let ld_map_gettoken() report it
+	 * Control Directive:	Restart this function / evaluate new directive
+	 */
+	while (*mf->mf_next != '\0') {
+		/* Skip leading whitespace */
+		while (isspace_nonl(*mf->mf_next))
+			mf->mf_next++;
+
+		/*
+		 * Control directives start with a '$'. If we hit
+		 * one, restart the function at this point
+		 */
+		if (*mf->mf_next == '$')
+			goto restart;
+
+		/* Not a control directive, so advance input to next line */
+		advance_to_eol(&mf->mf_next);
+		if (*mf->mf_next == '\n') {
+			mf->mf_lineno++;
+			mf->mf_next++;
+		}
+	}
+
+	assert(mf->mf_next == '\0');
+	return (TRUE);
+
+	/*
+	 * Control directives that require an argument that is not present
+	 * jump here to report the error and exit.
+	 */
+error_reqarg:
+	mf_fatal(&arg_mf, MSG_INTL(MSG_MAP_CDIR_REQARG), mdptr->md_name);
+	return (FALSE);
+
+}
+
+#ifndef _ELF64
+/*
+ * Convert a string to lowercase.
+ */
+void
+ld_map_lowercase(char *str)
+{
+	while (*str = tolower(*str))
+		str++;
+}
+#endif
+
+/*
+ * Wrappper on strtoul()/strtoull(), adapted to return an Xword.
+ *
+ * entry:
+ *	str - Pointer to string to be converted.
+ *	endptr - As documented for strtoul(3C). Either NULL, or
+ *		address of pointer to receive the address of the first
+ *		unused character in str (called "final" in strtoul(3C)).
+ *	ret_value - Address of Xword variable to receive result.
+ *
+ * exit:
+ *	On success, *ret_value receives the result, *endptr is updated if
+ *	endptr is non-NULL, and STRTOXWORD_OK is returned.
+ *	On failure, STRTOXWORD_TOBIG is returned if an otherwise valid
+ *	value was too large, and STRTOXWORD_BAD is returned if the string
+ *	is malformed.
+ */
+ld_map_strtoxword_t
+ld_map_strtoxword(const char *restrict str, char **restrict endptr,
+    Xword *ret_value)
+{
+#if	defined(_ELF64)			/* _ELF64 */
+#define	FUNC		strtoull	/* Function to use */
+#define	FUNC_MAX	ULLONG_MAX	/* Largest value returned by FUNC */
+#define	XWORD_MAX	ULLONG_MAX	/* Largest Xword value */
+	uint64_t	value;		/* Variable of FUNC return type  */
+#else					/* _ELF32 */
+#define	FUNC		strtoul
+#define	FUNC_MAX	ULONG_MAX
+#define	XWORD_MAX	UINT_MAX
+	ulong_t		value;
+#endif
+
+	char	*endptr_local;		/* Used if endptr is NULL */
+
+	if (endptr == NULL)
+		endptr = &endptr_local;
+
+	errno = 0;
+	value = FUNC(str, endptr, 0);
+	if ((errno != 0) || (str == *endptr)) {
+		if (value  == FUNC_MAX)
+			return (STRTOXWORD_TOOBIG);
+		else
+			return (STRTOXWORD_BAD);
+	}
+
+	/*
+	 * If this is a 64-bit linker building an ELFCLASS32 object,
+	 * the FUNC return type is a 64-bit value, while an Xword is
+	 * 32-bit. It is possible for FUNC to be able to convert a value
+	 * too large for our return type.
+	 */
+#if FUNC_MAX != XWORD_MAX
+	if (value > XWORD_MAX)
+		return (STRTOXWORD_TOOBIG);
+#endif
+
+	*ret_value = value;
+	return (STRTOXWORD_OK);
+
+#undef FUNC
+#undef FUNC_MAX
+#undef XWORD_MAC
+}
+
+/*
+ * Convert the unsigned integer value at the current mapfile input
+ * into binary form. All numeric values in mapfiles are treated as
+ * unsigned integers of the appropriate width for an address on the
+ * given target. Values can be decimal, hex, or octal.
+ *
+ * entry:
+ *	str - String to process.
+ *	value - Address of variable to receive resulting value.
+ *	notail - If TRUE, an error is issued if non-whitespace
+ *		characters other than '#' (comment) are found following
+ *		the numeric value before the end of line.
+ *
+ * exit:
+ *	On success:
+ *		- *str is advanced to the next character following the value
+ *		- *value receives the value
+ *		- Returns TRUE (1).
+ *	On failure, returns FALSE (0).
+ */
+static Boolean
+ld_map_getint(Mapfile *mf, ld_map_tkval_t *value, Boolean notail)
+{
+	ld_map_strtoxword_t	s2xw_ret;
+	ld_map_npatch_t	np;
+	char		*endptr;
+	char		*errstr = mf->mf_next;
+
+	value->tkv_int.tkvi_str = mf->mf_next;
+	s2xw_ret = ld_map_strtoxword(mf->mf_next, &endptr,
+	    &value->tkv_int.tkvi_value);
+	if (s2xw_ret != STRTOXWORD_OK) {
+		null_patch_eol(mf->mf_next, &np);
+		if (s2xw_ret == STRTOXWORD_TOOBIG)
+			mf_fatal(mf, MSG_INTL(MSG_MAP_VALUELIMIT), errstr);
+		else
+			mf_fatal(mf, MSG_INTL(MSG_MAP_MALVALUE), errstr);
+		null_patch_undo(&np);
+		return (FALSE);
+	}
+
+	/* Advance position to item following value, skipping whitespace */
+	value->tkv_int.tkvi_cnt = endptr - mf->mf_next;
+	mf->mf_next = endptr;
+	while (isspace_nonl(*mf->mf_next))
+		mf->mf_next++;
+
+	/* If requested, ensure there's nothing left */
+	if (notail && (*mf->mf_next != '\n') && (*mf->mf_next != '#') &&
+	    (*mf->mf_next != '\0')) {
+		null_patch_eol(mf->mf_next, &np);
+		mf_fatal(mf, MSG_INTL(MSG_MAP_BADVALUETAIL), errstr);
+		null_patch_undo(&np);
+		return (FALSE);
+	}
+
+	return (TRUE);
+}
+
+/*
+ * Convert a an unquoted identifier into a TK_STRING token, using the
+ * rules for syntax version in use. Used exclusively by ld_map_gettoken().
+ *
+ * entry:
+ *	mf - Mapfile descriptor, positioned to the first character of
+ *		the string.
+ *	flags - Bitmask of options to control ld_map_gettoken()s behavior
+ *	tkv- Address of pointer to variable to receive token value.
+ *
+ * exit:
+ *	On success, mf is advanced past the token, tkv is updated with
+ *	the string, and TK_STRING is returned. On error, TK_ERROR is returned.
+ */
+inline static Token
+gettoken_ident(Mapfile *mf, int flags, ld_map_tkval_t *tkv)
+{
+	char	*end;
+	Token	tok;
+	ld_map_npatch_t	np;
+
+	tkv->tkv_str = mf->mf_next;
+	if ((end = ident_delimit(mf)) == NULL)
+		return (TK_ERROR);
+	mf->mf_next = end;
+
+	/*
+	 * One advantage of reading the entire mapfile into memory is that
+	 * we can access the strings within it without having to allocate
+	 * more memory or make copies. In order to do that, we need to NULL
+	 * terminate this identifier. That is going to overwrite the
+	 * following character. The problem this presents is that the next
+	 * character may well be the first character of a subsequent token.
+	 * The solution to this is:
+	 *
+	 * 1)	Disallow the case where the next character is able to
+	 *	start a string. This is not legal mapfile syntax anyway,
+	 *	so catching it here simplifies matters.
+	 * 2)	Copy the character into the special mf->mf_next_ch
+	 * 3)	The next call to ld_map_gettoken() checks mf->mf_next_ch,
+	 *	and if it is non-0, uses it instead of dereferencing the
+	 *	mf_next pointer.
+	 */
+	tok = (*mf->mf_next & 0x80) ?
+	    TK_OP_ILLCHR : mf->mf_tokdisp[*mf->mf_next];
+	switch (tok) {
+	case TK_OP_BADCHR:
+		null_patch_eol(mf->mf_next, &np);
+		mf_fatal(mf, MSG_INTL(MSG_MAP_BADCHAR), mf->mf_next);
+		null_patch_undo(&np);
+		return (TK_ERROR);
+
+	case TK_OP_SIMQUOTE:
+	case TK_OP_CQUOTE:
+	case TK_OP_CDIR:
+	case TK_OP_NUM:
+	case TK_OP_ID:
+		null_patch_eol(mf->mf_next, &np);
+		mf_fatal(mf, MSG_INTL(MSG_MAP_WSNEEDED), mf->mf_next);
+		null_patch_undo(&np);
+		return (TK_ERROR);
+	}
+
+	/* Null terminate, saving the replaced character */
+	mf->mf_next_ch = *mf->mf_next;
+	*mf->mf_next = '\0';
+
+	if (flags & TK_F_STRLC)
+		ld_map_lowercase(tkv->tkv_str);
+	return (TK_STRING);
+}
+
+/*
+ * Convert a quoted string into a TK_STRING token, using simple
+ * quoting rules:
+ *	- Start and end quotes must be present and match
+ *	- There are no special characters or escape sequences.
+ * This function is used exclusively by ld_map_gettoken().
+ *
+ * entry:
+ *	mf - Mapfile descriptor, positioned to the opening quote character.
+ *	flags - Bitmask of options to control ld_map_gettoken()s behavior
+ *	tkv- Address of pointer to variable to receive token value.
+ *
+ * exit:
+ *	On success, mf is advanced past the token, tkv is updated with
+ *	the string, and TK_STRING is returned. On error, TK_ERROR is returned.
+ */
+inline static Token
+gettoken_simquote_str(Mapfile *mf, int flags, ld_map_tkval_t *tkv)
+{
+	char	*str, *end;
+	char	quote;
+
+	str = mf->mf_next++;
+	quote = *str;
+	end = mf->mf_next;
+	while ((*end != '\0') && (*end != '\n') && (*end != quote))
+		end++;
+	if (*end != quote) {
+		ld_map_npatch_t	np;
+
+		null_patch_eol(end, &np);
+		mf_fatal(mf, MSG_INTL(MSG_MAP_NOTERM), str);
+		null_patch_undo(&np);
+		return (TK_ERROR);
+	}
+
+	/*
+	 * end is pointing at the closing quote. We can turn that into NULL
+	 * termination for the string without needing to restore it later.
+	 */
+	*end = '\0';
+	mf->mf_next = end + 1;
+	tkv->tkv_str = str + 1;		/* Skip opening quote */
+	if (flags & TK_F_STRLC)
+		ld_map_lowercase(tkv->tkv_str);
+	return (TK_STRING);
+}
+
+/*
+ * Convert a quoted string into a TK_STRING token, using C string literal
+ * quoting rules:
+ *	- Start and end quotes must be present and match
+ *	- Backslash is an escape, used to introduce  special characters
+ * This function is used exclusively by ld_map_gettoken().
+ *
+ * entry:
+ *	mf - Mapfile descriptor, positioned to the opening quote character.
+ *	flags - Bitmask of options to control ld_map_gettoken()s behavior
+ *	tkv- Address of pointer to variable to receive token value.
+ *
+ * exit:
+ *	On success, mf is advanced past the token, tkv is updated with
+ *	the string, and TK_STRING is returned. On error, TK_ERROR is returned.
+ */
+inline static Token
+gettoken_cquote_str(Mapfile *mf, int flags, ld_map_tkval_t *tkv)
+{
+	char	*str, *cur, *end;
+	char	quote;
+	int	c;
+
+	/*
+	 * This function goes through the quoted string and copies
+	 * it on top of itself, replacing escape sequences with the
+	 * characters they denote. There is always enough room for this,
+	 * because escapes are multi-character sequences that are converted
+	 * to single character results.
+	 */
+	str = mf->mf_next++;
+	quote = *str;
+	cur = end = mf->mf_next;
+	for (c = *end++; (c != '\0') && (c != '\n') && (c != quote);
+	    c = *end++) {
+		if (c == '\\') {
+			c = conv_translate_c_esc(&end);
+			if (c == -1) {
+				mf_fatal(mf, MSG_INTL(MSG_MAP_BADCESC), *end);
+				return (TK_ERROR);
+			}
+		}
+		*cur++ = c;
+	}
+	*cur = '\0';		/* terminate the result */
+	if (c != quote) {
+		ld_map_npatch_t	np;
+
+		null_patch_eol(end, &np);
+		mf_fatal(mf, MSG_INTL(MSG_MAP_NOTERM), str);
+		null_patch_undo(&np);
+		return (TK_ERROR);
+	}
+
+	/* end is pointing one character past the closing quote */
+	mf->mf_next = end;
+	tkv->tkv_str = str + 1;		/* Skip opening quote */
+	if (flags & TK_F_STRLC)
+		ld_map_lowercase(tkv->tkv_str);
+	return (TK_STRING);
+}
+
+/*
+ * Get a token from the mapfile.
+ *
+ * entry:
+ *	mf - Mapfile descriptor
+ *	flags - Bitmask of options to control ld_map_gettoken()s behavior
+ *	tkv- Address of pointer to variable to receive token value.
+ *
+ * exit:
+ *	Returns one of the TK_* values, to report the result. If the resulting
+ *	token has a value (TK_STRING / TK_INT), and tkv is non-NULL, tkv
+ *	is filled in with the resulting value.
+ */
+Token
+ld_map_gettoken(Mapfile *mf, int flags, ld_map_tkval_t *tkv)
+{
+	int		cdir_allow, ch;
+	Token		tok;
+	ld_map_npatch_t	np;
+
+	/*
+	 * Mapfile control directives all start with a '$' character. However,
+	 * they are only valid when they are the first thing on a line. That
+	 * happens on the first call to ld_map_gettoken() for a new a new
+	 * mapfile, as tracked with lms.lms_cdir_valid, and immediately
+	 * following each newline seen in the file.
+	 */
+	cdir_allow = lms.lms_cdir_valid;
+	lms.lms_cdir_valid = 0;
+
+	/* Cycle through the characters looking for tokens. */
+	for (;;) {
+		/*
+		 * Process the next character. This is normally *mf->mf_next,
+		 * but if mf->mf_next_ch is non-0, then it contains the
+		 * character, and *mf->mf_next contains a NULL termination
+		 * from the TK_STRING token returned on the previous call.
+		 *
+		 * gettoken_ident() ensures that this is never done to
+		 * a character that starts a string.
+		 */
+		if (mf->mf_next_ch == 0) {
+			ch = *mf->mf_next;
+		} else {
+			ch = mf->mf_next_ch;
+			mf->mf_next_ch = 0;	/* Reset */
+		}
+
+		/* Map the character to a dispatch action */
+		tok = (ch & 0x80) ? TK_OP_ILLCHR : mf->mf_tokdisp[ch];
+
+		/*
+		 * Items that require processing are identified as OP tokens.
+		 * We process them, and return a result non-OP token.
+		 *
+		 * Non-OP tokens are single character tokens, and we return
+		 * them immediately.
+		 */
+		switch (tok) {
+		case TK_OP_EOF:
+			/* If EOFOK is set, quietly report it as TK_EOF */
+			if ((flags & TK_F_EOFOK) != 0)
+				return (TK_EOF);
+
+			/* Treat it as a standard error */
+			mf_fatal0(mf, MSG_INTL(MSG_MAP_PREMEOF));
+			return (TK_ERROR);
+
+		case TK_OP_ILLCHR:
+			mf_fatal(mf, MSG_INTL(MSG_MAP_ILLCHAR), ch);
+			mf->mf_next++;
+			return (TK_ERROR);
+
+		case TK_OP_BADCHR:
+			tk_op_badchr:
+			null_patch_eol(mf->mf_next, &np);
+			mf_fatal(mf, MSG_INTL(MSG_MAP_BADCHAR), mf->mf_next);
+			null_patch_undo(&np);
+			mf->mf_next++;
+			return (TK_ERROR);
+
+		case TK_OP_WS:	/* White space */
+			mf->mf_next++;
+			break;
+
+		case TK_OP_NL:	/* White space too, but bump line number. */
+			mf->mf_next++;
+			mf->mf_lineno++;
+			cdir_allow = 1;
+			break;
+
+		case TK_OP_SIMQUOTE:
+			if (flags & TK_F_KEYWORD)
+				goto tk_op_badkwquote;
+			return (gettoken_simquote_str(mf, flags, tkv));
+
+		case TK_OP_CQUOTE:
+			if (flags & TK_F_KEYWORD) {
+			tk_op_badkwquote:
+				null_patch_eol(mf->mf_next, &np);
+				mf_fatal(mf, MSG_INTL(MSG_MAP_BADKWQUOTE),
+				    mf->mf_next);
+				null_patch_undo(&np);
+				mf->mf_next++;
+				return (TK_ERROR);
+			}
+			return (gettoken_cquote_str(mf, flags, tkv));
+
+		case TK_OP_CMT:
+			advance_to_eol(&mf->mf_next);
+			break;
+
+		case TK_OP_CDIR:
+			/*
+			 * Control directives are only valid at the start
+			 * of a line.
+			 */
+			if (!cdir_allow) {
+				null_patch_eol(mf->mf_next, &np);
+				mf_fatal(mf, MSG_INTL(MSG_MAP_CDIR_NOTBOL),
+				    mf->mf_next);
+				null_patch_undo(&np);
+				mf->mf_next++;
+				return (TK_ERROR);
+			}
+			if (!cdir_process(mf))
+				return (TK_ERROR);
+			break;
+
+		case TK_OP_NUM:	/* Decimal, hex(0x...), or octal (0...) value */
+			if (!ld_map_getint(mf, tkv, FALSE))
+				return (TK_ERROR);
+			return (TK_INT);
+
+		case TK_OP_ID:		/* Unquoted identifier */
+			return (gettoken_ident(mf, flags, tkv));
+
+		case TK_OP_CEQUAL:	/* += or -= */
+			if (*(mf->mf_next + 1) != '=')
+				goto tk_op_badchr;
+			tok = (ch == '+') ? TK_PLUSEQ : TK_MINUSEQ;
+			mf->mf_next += 2;
+			return (tok);
+
+		default:	/* Non-OP token */
+			mf->mf_next++;
+			return (tok);
+		}
+	}
+
+	/*NOTREACHED*/
+	assert(0);
+	return (TK_ERROR);
+}
+
+/*
+ * Given a token and value returned by ld_map_gettoken(), return a string
+ * representation of it suitable for use in an error message.
+ *
+ * entry:
+ *	tok - Token code. Must not be an OP-token
+ *	tkv - Token value
+ */
+const char *
+ld_map_tokenstr(Token tok, ld_map_tkval_t *tkv, Conv_inv_buf_t *inv_buf)
+{
+	size_t	cnt;
+
+	switch (tok) {
+	case TK_ERROR:
+		return (MSG_ORIG(MSG_STR_ERROR));
+	case TK_EOF:
+		return (MSG_ORIG(MSG_STR_EOF));
+	case TK_STRING:
+		return (tkv->tkv_str);
+	case TK_COLON:
+		return (MSG_ORIG(MSG_QSTR_COLON));
+	case TK_SEMICOLON:
+		return (MSG_ORIG(MSG_QSTR_SEMICOLON));
+	case TK_EQUAL:
+		return (MSG_ORIG(MSG_QSTR_EQUAL));
+	case TK_PLUSEQ:
+		return (MSG_ORIG(MSG_QSTR_PLUSEQ));
+	case TK_MINUSEQ:
+		return (MSG_ORIG(MSG_QSTR_MINUSEQ));
+	case TK_ATSIGN:
+		return (MSG_ORIG(MSG_QSTR_ATSIGN));
+	case TK_DASH:
+		return (MSG_ORIG(MSG_QSTR_DASH));
+	case TK_LEFTBKT:
+		return (MSG_ORIG(MSG_QSTR_LEFTBKT));
+	case TK_RIGHTBKT:
+		return (MSG_ORIG(MSG_QSTR_RIGHTBKT));
+	case TK_PIPE:
+		return (MSG_ORIG(MSG_QSTR_PIPE));
+	case TK_INT:
+		cnt = tkv->tkv_int.tkvi_cnt;
+		if (cnt >= sizeof (inv_buf->buf))
+			cnt = sizeof (inv_buf->buf) - 1;
+		(void) memcpy(inv_buf->buf, tkv->tkv_int.tkvi_str, cnt);
+		inv_buf->buf[cnt] = '\0';
+		return (inv_buf->buf);
+	case TK_STAR:
+		return (MSG_ORIG(MSG_QSTR_STAR));
+	case TK_BANG:
+		return (MSG_ORIG(MSG_QSTR_BANG));
+	default:
+		assert(0);
+		break;
+	}
+
+	/*NOTREACHED*/
+	return (MSG_INTL(MSG_MAP_INTERR));
+}
+
+/*
+ * Advance the input to the first non-empty line, and determine
+ * the mapfile version. The version is specified by the mapfile
+ * using a $mapfile_version directive. The original System V
+ * syntax lacks this directive, and we use that fact to identify
+ * such files. SysV mapfile are implicitly defined to have version 1.
+ *
+ * entry:
+ *	ofl - Output file descriptor
+ *	mf - Mapfile block
+ *
+ * exit:
+ *	On success, updates mf->mf_version, and returns TRUE (1).
+ *	On failure, returns FALSE (0).
+ */
+static Boolean
+mapfile_version(Mapfile *mf)
+{
+	char	*line_start = mf->mf_next;
+	Boolean	cont = TRUE;
+	Boolean	status = TRUE;	/* Assume success */
+	Token	tok;
+
+	mf->mf_version = MFV_SYSV;
+
+	/*
+	 * Cycle through the characters looking for tokens. Although the
+	 * true version is not known yet, we use the v2 dispatch table.
+	 * It contains control directives, which we need for this search,
+	 * and the other TK_OP_ tokens we will recognize and act on are the
+	 * same for both tables.
+	 *
+	 * It is important not to process any tokens that would lead to
+	 * a non-OP token:
+	 *
+	 * -	The version is required to interpret them
+	 * -	Our mapfile descriptor is not fully initialized,
+	 *	attempts to run that code will crash the program.
+	 */
+	while (cont) {
+		/* Map the character to a dispatch action */
+		tok = (*mf->mf_next & 0x80) ?
+		    TK_OP_ILLCHR : gettok_dispatch_v2[*mf->mf_next];
+
+		switch (tok) {
+		case TK_OP_WS:	/* White space */
+			mf->mf_next++;
+			break;
+
+		case TK_OP_NL:	/* White space too, but bump line number. */
+			mf->mf_next++;
+			mf->mf_lineno++;
+			break;
+
+		case TK_OP_CMT:
+			advance_to_eol(&mf->mf_next);
+			break;
+
+		case TK_OP_CDIR:
+			/*
+			 * Control directives are only valid at the start
+			 * of a line. However, as we have not yet seen
+			 * a token, we do not need to test for this, and
+			 * can safely assume that we are at the start.
+			 */
+			if (!strncasecmp(mf->mf_next,
+			    MSG_ORIG(MSG_STR_CDIR_MFVER),
+			    MSG_STR_CDIR_MFVER_SIZE) &&
+			    isspace_nonl(*(mf->mf_next +
+			    MSG_STR_CDIR_MFVER_SIZE))) {
+				ld_map_tkval_t	ver;
+
+				mf->mf_next += MSG_STR_CDIR_MFVER_SIZE + 1;
+				if (!ld_map_getint(mf, &ver, TRUE)) {
+					status = cont = FALSE;
+					break;
+				}
+				/*
+				 * Is it a valid version? Note that we
+				 * intentionally do not allow you to
+				 * specify version 1 using the $mapfile_version
+				 * syntax, because that's reserved to version
+				 * 2 and up.
+				 */
+				if ((ver.tkv_int.tkvi_value < 2) ||
+				    (ver.tkv_int.tkvi_value >= MFV_NUM)) {
+					const char *fmt;
+
+					fmt = (ver.tkv_int.tkvi_value < 2) ?
+					    MSG_INTL(MSG_MAP_CDIR_BADVDIR) :
+					    MSG_INTL(MSG_MAP_CDIR_BADVER);
+					mf_fatal(mf, fmt,
+					    EC_WORD(ver.tkv_int.tkvi_value));
+					status = cont = FALSE;
+					break;
+				}
+				mf->mf_version = ver.tkv_int.tkvi_value;
+				cont = FALSE; /* Version recovered. All done */
+				break;
+			}
+			/*
+			 * Not a version directive. Reset the current position
+			 * to the start of the current line and stop here.
+			 * SysV syntax applies.
+			 */
+			mf->mf_next = line_start;
+			cont = FALSE;
+			break;
+
+		default:
+			/*
+			 * If we see anything else, then stop at this point.
+			 * The file has System V syntax (version 1), and the
+			 * next token should be interpreted as such.
+			 */
+			cont = FALSE;
+			break;
+		}
+	}
+
+	return (status);
+}
+
+/*
+ * Parse the mapfile.
+ */
+Boolean
+ld_map_parse(const char *mapfile, Ofl_desc *ofl)
+{
+	struct stat	stat_buf;	/* stat of mapfile */
+	int		mapfile_fd;	/* descriptor for mapfile */
+	int		err;
+	Mapfile		*mf;		/* Mapfile descriptor */
+	size_t		name_len;	/* strlen(mapfile) */
+
+	/*
+	 * Determine if we're dealing with a file or a directory.
+	 */
+	if (stat(mapfile, &stat_buf) == -1) {
+		err = errno;
+		eprintf(ofl->ofl_lml, ERR_FATAL, MSG_INTL(MSG_SYS_STAT),
+		    mapfile, strerror(err));
+		return (FALSE);
+	}
+	if (S_ISDIR(stat_buf.st_mode)) {
+		DIR		*dirp;
+		struct dirent	*denp;
+
+		/*
+		 * Open the directory and interpret each visible file as a
+		 * mapfile.
+		 */
+		if ((dirp = opendir(mapfile)) == NULL)
+			return (TRUE);
+
+		while ((denp = readdir(dirp)) != NULL) {
+			char	path[PATH_MAX];
+
+			/*
+			 * Ignore any hidden filenames.  Construct the full
+			 * pathname to the new mapfile.
+			 */
+			if (*denp->d_name == '.')
+				continue;
+			(void) snprintf(path, PATH_MAX, MSG_ORIG(MSG_STR_PATH),
+			    mapfile, denp->d_name);
+			if (!ld_map_parse(path, ofl))
+				return (FALSE);
+		}
+		(void) closedir(dirp);
+		return (TRUE);
+	} else if (!S_ISREG(stat_buf.st_mode)) {
+		eprintf(ofl->ofl_lml, ERR_FATAL, MSG_INTL(MSG_SYS_NOTREG),
+		    mapfile);
+		return (FALSE);
+	}
+
+	/* Open file */
+	if ((mapfile_fd = open(mapfile, O_RDONLY)) == -1) {
+		err = errno;
+		eprintf(ofl->ofl_lml, ERR_FATAL, MSG_INTL(MSG_SYS_OPEN),
+		    mapfile, strerror(err));
+		return (FALSE);
+	}
+
+	/*
+	 * Allocate enough memory to hold the state block, mapfile name,
+	 * and mapfile text. Text has alignment 1, so it can follow the
+	 * state block without padding.
+	 */
+	name_len = strlen(mapfile) + 1;
+	mf = libld_malloc(sizeof (*mf) + name_len + stat_buf.st_size + 1);
+	if (mf == NULL)
+		return (FALSE);
+	mf->mf_ofl = ofl;
+	mf->mf_name = (char *)(mf + 1);
+	(void) strcpy(mf->mf_name, mapfile);
+	mf->mf_text = mf->mf_name + name_len;
+	if (read(mapfile_fd, mf->mf_text, stat_buf.st_size) !=
+	    stat_buf.st_size) {
+		err = errno;
+		eprintf(ofl->ofl_lml, ERR_FATAL, MSG_INTL(MSG_SYS_READ),
+		    mapfile, strerror(err));
+		(void) close(mapfile_fd);
+		return (FALSE);
+	}
+	(void) close(mapfile_fd);
+	mf->mf_text[stat_buf.st_size] = '\0';
+	mf->mf_next = mf->mf_text;
+	mf->mf_lineno = 1;
+	mf->mf_next_ch = 0;		/* No "lookahead" character yet */
+	mf->mf_ec_insndx = 0;		/* Insert entrace criteria at top */
+
+	/*
+	 * Read just enough from the mapfile to determine the version,
+	 * and then dispatch to the appropriate code for further processing
+	 */
+	if (!mapfile_version(mf))
+		return (FALSE);
+
+	/*
+	 * Start and continuation masks for unquoted identifier at this
+	 * mapfile version level.
+	 */
+	mf->mf_tkid_start = TKID_ATTR_START(mf->mf_version);
+	mf->mf_tkid_cont = TKID_ATTR_CONT(mf->mf_version);
+
+	DBG_CALL(Dbg_map_parse(ofl->ofl_lml, mapfile, mf->mf_version));
+
+	switch (mf->mf_version) {
+	case MFV_SYSV:
+		mf->mf_tokdisp = gettok_dispatch_v1;
+		if (!ld_map_parse_v1(mf))
+			return (FALSE);
+		break;
+
+	case MFV_SOLARIS:
+		mf->mf_tokdisp = gettok_dispatch_v2;
+		STACK_RESET(lms.lms_cdir_stack);
+
+		/*
+		 * If the conditional expression identifier tree has not been
+		 * initialized, set it up. This is only done on the first
+		 * mapfile, because the identifier control directives accumulate
+		 * across all the mapfiles.
+		 */
+		if ((lms.lms_cexp_id == NULL) && !cexp_ident_init())
+			return (FALSE);
+
+		/*
+		 * Tell ld_map_gettoken() we will accept a '$' as starting a
+		 * control directive on the first call. Normally, they are
+		 * only allowed after a newline.
+		 */
+		lms.lms_cdir_valid = 1;
+
+		if (!ld_map_parse_v2(mf))
+			return (FALSE);
+
+		/* Did we leave any open $if control directives? */
+		if (!STACK_IS_EMPTY(lms.lms_cdir_stack)) {
+			while (!STACK_IS_EMPTY(lms.lms_cdir_stack)) {
+				cdir_level_t *level =
+				    &STACK_POP(lms.lms_cdir_stack);
+
+				mf_fatal(mf, MSG_INTL(MSG_MAP_CDIR_NOEND),
+				    EC_LINENO(level->cdl_if_lineno));
+			}
+			return (FALSE);
+		}
+		break;
+	}
+
+	return (TRUE);
+}
+
+/*
+ * Sort the segment list. This is necessary if a mapfile has set explicit
+ * virtual addresses for segments, or defined a SEGMENT_ORDER directive.
+ *
+ * Only PT_LOAD segments can be assigned a virtual address.  These segments can
+ * be one of two types:
+ *
+ *  -	Standard segments for text, data or bss.  These segments will have been
+ *	inserted before the default text (first PT_LOAD) segment.
+ *
+ *  -	Empty (reservation) segments.  These segment will have been inserted at
+ *	the end of any default PT_LOAD segments.
+ *
+ * Any standard segments that are assigned a virtual address will be sorted,
+ * and as their definitions precede any default PT_LOAD segments, these segments
+ * will be assigned sections before any defaults.
+ *
+ * Any reservation segments are also sorted amoung themselves, as these segments
+ * must still follow the standard default segments.
+ */
+static Boolean
+sort_seg_list(Ofl_desc *ofl)
+{
+	APlist	*sort_segs = NULL, *load_segs = NULL;
+	Sg_desc	*sgp1;
+	Aliste	idx1;
+	Aliste	nsegs;
+
+
+	/*
+	 * We know the number of elements in the sorted list will be
+	 * the same as the original, so use this as the initial allocation
+	 * size for the replacement aplist.
+	 */
+	nsegs = aplist_nitems(ofl->ofl_segs);
+
+
+	/* Add the items below SGID_TEXT to the list */
+	for (APLIST_TRAVERSE(ofl->ofl_segs, idx1, sgp1)) {
+		if (sgp1->sg_id >= SGID_TEXT)
+			break;
+
+		if (aplist_append(&sort_segs, sgp1, nsegs) == NULL)
+				return (FALSE);
+	}
+
+	/*
+	 * If there are any SEGMENT_ORDER items, add them, and set their
+	 * FLG_SG_ORDERED flag to identify them in debug output, and to
+	 * prevent them from being added again below.
+	 */
+	for (APLIST_TRAVERSE(ofl->ofl_segs_order, idx1, sgp1)) {
+		if (aplist_append(&sort_segs, sgp1, nsegs) == NULL)
+			return (FALSE);
+		sgp1->sg_flags |= FLG_SG_ORDERED;
+	}
+
+	/*
+	 * Add the loadable segments to another list in sorted order.
+	 */
+	DBG_CALL(Dbg_map_sort_title(ofl->ofl_lml, TRUE));
+	for (APLIST_TRAVERSE(ofl->ofl_segs, idx1, sgp1)) {
+		DBG_CALL(Dbg_map_sort_seg(ofl->ofl_lml, ELFOSABI_SOLARIS,
+		    ld_targ.t_m.m_mach, sgp1));
+
+		/* Only interested in PT_LOAD items not in SEGMENT_ORDER list */
+		if ((sgp1->sg_phdr.p_type != PT_LOAD) ||
+		    (sgp1->sg_flags & FLG_SG_ORDERED))
+			continue;
+
+		/*
+		 * If the loadable segment does not contain a vaddr, simply
+		 * append it to the new list.
+		 */
+		if ((sgp1->sg_flags & FLG_SG_P_VADDR) == 0) {
+			if (aplist_append(&load_segs, sgp1, AL_CNT_SEGMENTS) ==
+			    NULL)
+				return (FALSE);
+
+		} else {
+			Aliste		idx2;
+			Sg_desc		*sgp2;
+			int		inserted = 0;
+
+			/*
+			 * Traverse the segment list we are creating, looking
+			 * for a segment that defines a vaddr.
+			 */
+			for (APLIST_TRAVERSE(load_segs, idx2, sgp2)) {
+				/*
+				 * Any real segments that contain vaddr's need
+				 * to be sorted.  Any reservation segments also
+				 * need to be sorted.  However, any reservation
+				 * segments should be placed after any real
+				 * segments.
+				 */
+				if (((sgp2->sg_flags &
+				    (FLG_SG_P_VADDR | FLG_SG_EMPTY)) == 0) &&
+				    (sgp1->sg_flags & FLG_SG_EMPTY))
+					continue;
+
+				if ((sgp2->sg_flags & FLG_SG_P_VADDR) &&
+				    ((sgp2->sg_flags & FLG_SG_EMPTY) ==
+				    (sgp1->sg_flags & FLG_SG_EMPTY))) {
+					if (sgp1->sg_phdr.p_vaddr ==
+					    sgp2->sg_phdr.p_vaddr) {
+						eprintf(ofl->ofl_lml, ERR_FATAL,
+						    MSG_INTL(MSG_MAP_SEGSAME),
+						    sgp1->sg_name,
+						    sgp2->sg_name);
+						return (FALSE);
+					}
+
+					if (sgp1->sg_phdr.p_vaddr >
+					    sgp2->sg_phdr.p_vaddr)
+						continue;
+				}
+
+				/*
+				 * Insert this segment before the segment on
+				 * the load_segs list.
+				 */
+				if (aplist_insert(&load_segs, sgp1,
+				    AL_CNT_SEGMENTS, idx2) == NULL)
+					return (FALSE);
+				inserted = 1;
+				break;
+			}
+
+			/*
+			 * If the segment being inspected has not been inserted
+			 * in the segment list, simply append it to the list.
+			 */
+			if ((inserted == 0) && (aplist_append(&load_segs,
+			    sgp1, AL_CNT_SEGMENTS) == NULL))
+				return (FALSE);
+		}
+	}
+
+	/*
+	 * Add the sorted loadable segments to our initial segment list.
+	 */
+	for (APLIST_TRAVERSE(load_segs, idx1, sgp1)) {
+		if (aplist_append(&sort_segs, sgp1, AL_CNT_SEGMENTS) == NULL)
+			return (FALSE);
+	}
+
+	/*
+	 * Add all other segments to our list.
+	 */
+	for (APLIST_TRAVERSE(ofl->ofl_segs, idx1, sgp1)) {
+		if ((sgp1->sg_id < SGID_TEXT) ||
+		    (sgp1->sg_phdr.p_type == PT_LOAD) ||
+		    (sgp1->sg_flags & FLG_SG_ORDERED))
+			continue;
+
+		if (aplist_append(&sort_segs, sgp1, AL_CNT_SEGMENTS) == NULL)
+			return (FALSE);
+	}
+
+	/*
+	 * Free the original list, and the pt_load list, and use
+	 * the new list as the segment list.
+	 */
+	free(ofl->ofl_segs);
+	if (load_segs) free(load_segs);
+	ofl->ofl_segs = sort_segs;
+
+	if (DBG_ENABLED) {
+		Dbg_map_sort_title(ofl->ofl_lml, FALSE);
+		for (APLIST_TRAVERSE(ofl->ofl_segs, idx1, sgp1)) {
+			Dbg_map_sort_seg(ofl->ofl_lml, ELFOSABI_SOLARIS,
+			    ld_targ.t_m.m_mach, sgp1);
+			}
+		}
+
+	return (TRUE);
+}
+
+/*
+ * After all mapfiles have been processed, this routine is used to
+ * finish any remaining mapfile related work.
+ *
+ * exit:
+ *	Returns TRUE on success, and FALSE on failure.
+ */
+Boolean
+ld_map_post_process(Ofl_desc *ofl)
+{
+	Aliste		idx, idx2;
+	Is_desc		*isp;
+	Sg_desc		*sgp;
+	Ent_desc	*enp;
+	Sg_desc		*first_seg = NULL;
+
+
+	DBG_CALL(Dbg_map_post_title(ofl->ofl_lml));
+
+	/*
+	 * Per-segment processing:
+	 * -	Identify segments with explicit virtual address
+	 * -	Details of input and output section order
+	 */
+	for (APLIST_TRAVERSE(ofl->ofl_segs, idx, sgp)) {
+		/*
+		 * We are looking for segments. Program headers that represent
+		 * segments are required to have a non-NULL name pointer,
+		 * while that those that do not are required to have a
+		 * NULL name pointer.
+		 */
+		if (sgp->sg_name == NULL)
+			continue;
+
+		/* Remember the first non-disabled segment */
+		if ((first_seg == NULL) && !(sgp->sg_flags & FLG_SG_DISABLED))
+			first_seg = sgp;
+
+		/*
+		 * If a segment has an explicit virtual address, we will
+		 * need to sort the segments.
+		 */
+		if (sgp->sg_flags & FLG_SG_P_VADDR)
+			ofl->ofl_flags1 |= FLG_OF1_VADDR;
+
+		/*
+		 * The FLG_OF_OS_ORDER flag enables the code that does
+		 * output section ordering. Set if the segment has
+		 * a non-empty output section order list.
+		 */
+		if (alist_nitems(sgp->sg_os_order) > 0)
+			ofl->ofl_flags |= FLG_OF_OS_ORDER;
+
+		/*
+		 * The version 1 and version 2 syntaxes for input section
+		 * ordering are different and incompatible enough that we
+		 * only allow the use of one or the other for a given segment:
+		 *
+		 * v1)	The version 1 syntax has the user set the ?O flag on
+		 *	the segment. If this is done, all input sections placed
+		 *	via an entrance criteria that has a section name are to
+		 *	be sorted, using the order of the entrance criteria
+		 *	as the sort key.
+		 *
+		 * v2)	The version 2 syntax has the user specify a name for
+		 * 	the entry criteria, and then provide a list of entry
+		 * 	criteria names via the IS_ORDER segment attribute.
+		 * 	Sections placed via the criteria listed in IS_ORDER
+		 * 	are sorted, and the others are not.
+		 *
+		 * Regardless of the syntax version used, the section sorting
+		 * code expects the following:
+		 *
+		 * -	Segments requiring input section sorting have the
+		 *	FLG_SG_IS_ORDER flag set
+		 *
+		 * -	Entrance criteria referencing the segment that
+		 *	participate in input section sorting have a non-zero
+		 *	sort key in their ec_ordndx field.
+		 *
+		 * At this point, the following are true:
+		 *
+		 * -	All entrance criteria have ec_ordndx set to 0.
+		 * -	Segments that require the version 1 behavior have
+		 *	the FLG_SG_IS_ORDER flag set, and the segments
+		 *	sg_is_order list is empty.
+		 * -	Segments that require the version 2 behavior do not
+		 *	have FLG_SG_IS_ORDER set, and the sg_is_order list is
+		 *	non-empty. This list contains the names of the entrance
+		 *	criteria that will participate in input section sorting,
+		 *	and their relative order in the list provides the
+		 *	sort key to use.
+		 *
+		 * We must detect these two cases, set the FLG_SG_IS_ORDER
+		 * flag as necessary, and fill in all entrance criteria
+		 * sort keys. If any input section sorting is to be done,
+		 * we also set the FLG_OF_IS_ORDER flag on the output descriptor
+		 * to enable the code that does that work.
+		 */
+
+		/* Version 1: ?O flag? */
+		if (sgp->sg_flags & FLG_SG_IS_ORDER) {
+			Word	index = 0;
+
+			ofl->ofl_flags |= FLG_OF_IS_ORDER;
+			DBG_CALL(Dbg_map_ent_ord_title(ofl->ofl_lml,
+			    sgp->sg_name));
+
+			/*
+			 * Give each user defined entrance criteria for this
+			 * segment that specifies a section name a
+			 * monotonically increasing sort key.
+			 */
+			for (APLIST_TRAVERSE(ofl->ofl_ents, idx2, enp))
+				if ((enp->ec_segment == sgp) &&
+				    (enp->ec_is_name != NULL) &&
+				    ((enp->ec_flags & FLG_EC_BUILTIN) == 0))
+					enp->ec_ordndx = ++index;
+			continue;
+		}
+
+		/* Version 2: SEGMENT IS_ORDER list? */
+		if (aplist_nitems(sgp->sg_is_order) > 0) {
+			Word	index = 0;
+
+			ofl->ofl_flags |= FLG_OF_IS_ORDER;
+			DBG_CALL(Dbg_map_ent_ord_title(ofl->ofl_lml,
+			    sgp->sg_name));
+
+			/*
+			 * Give each entrance criteria in the sg_is_order
+			 * list a monotonically increasing sort key.
+			 */
+			for (APLIST_TRAVERSE(sgp->sg_is_order, idx2, enp)) {
+				enp->ec_ordndx = ++index;
+				enp->ec_segment->sg_flags |= FLG_SG_IS_ORDER;
+			}
+		}
+	}
+
+	/* Sort the segment descriptors if necessary */
+	if (((ofl->ofl_flags1 & FLG_OF1_VADDR) ||
+	    (aplist_nitems(ofl->ofl_segs_order) > 0)) &&
+	    !sort_seg_list(ofl))
+		return (FALSE);
+
+	/*
+	 * If the output file is a static file without an interpreter, and
+	 * if any virtual address is specified, then set the NOHDR flag for
+	 * backward compatibility.
+	 */
+	if (!(ofl->ofl_flags & (FLG_OF_DYNAMIC | FLG_OF_RELOBJ)) &&
+	    !(ofl->ofl_osinterp) && (ofl->ofl_flags1 & FLG_OF1_VADDR))
+		ofl->ofl_dtflags_1 |= DF_1_NOHDR;
+
+	if (ofl->ofl_flags & FLG_OF_RELOBJ) {
+		/*
+		 * NOHDR has no effect on a relocatable file.
+		 * Make sure this flag isn't set.
+		 */
+		ofl->ofl_dtflags_1 &= ~DF_1_NOHDR;
+	} else if (first_seg != NULL) {
+		/*
+		 * DF_1_NOHDR might have been set globally by the HDR_NOALLOC
+		 * directive. If not, then we want to check the per-segment
+		 * flag for the first loadable segment and propagate it
+		 * if set.
+		 */
+		if ((ofl->ofl_dtflags_1 & DF_1_NOHDR) == 0) {
+			/*
+			 * If we sorted the segments, the first segment
+			 * may have changed.
+			 */
+			if ((ofl->ofl_flags1 & FLG_OF1_VADDR) ||
+			    (aplist_nitems(ofl->ofl_segs_order) > 0)) {
+				for (APLIST_TRAVERSE(ofl->ofl_segs, idx, sgp)) {
+					if (sgp->sg_name == NULL)
+						continue;
+					if ((sgp->sg_flags & FLG_SG_DISABLED) ==
+					    0) {
+						first_seg = sgp;
+						break;
+					}
+				}
+			}
+
+			/*
+			 * If the per-segment NOHDR flag is set on our first
+			 * segment, then make it take effect.
+			 */
+			if (first_seg->sg_flags & FLG_SG_NOHDR)
+				ofl->ofl_dtflags_1 |= DF_1_NOHDR;
+		}
+
+		/*
+		 * For executable and shared objects, the first segment must
+		 * be loadable unless NOHDR was specified, because the ELF
+		 * header must simultaneously lie at offset 0 of the file and
+		 * be included in the first loadable segment. This isn't
+		 * possible if some other segment type starts the file
+		 */
+		if (!(ofl->ofl_dtflags_1 & DF_1_NOHDR) &&
+		    (first_seg->sg_phdr.p_type != PT_LOAD)) {
+			Conv_inv_buf_t	inv_buf;
+
+			eprintf(ofl->ofl_lml, ERR_FATAL,
+			    MSG_INTL(MSG_SEG_FIRNOTLOAD),
+			    conv_phdr_type(ELFOSABI_SOLARIS, ld_targ.t_m.m_mach,
+			    first_seg->sg_phdr.p_type, 0, &inv_buf),
+			    first_seg->sg_name);
+			return (FALSE);
+		}
+	}
+
+	/*
+	 * Mapfiles may have been used to create symbol definitions
+	 * with backing storage.  Although the backing storage is
+	 * associated with an input section, the association of the
+	 * section to an output section (and segment) is initially
+	 * deferred.  Now that all mapfile processing is complete, any
+	 * entrance criteria requirements have been processed, and
+	 * these backing storage sections can be associated with the
+	 * appropriate output section (and segment).
+	 */
+	if (ofl->ofl_maptext || ofl->ofl_mapdata)
+		DBG_CALL(Dbg_sec_backing(ofl->ofl_lml));
+
+	for (APLIST_TRAVERSE(ofl->ofl_maptext, idx, isp)) {
+		if (ld_place_section(ofl, isp, NULL,
+		    ld_targ.t_id.id_text, NULL) == (Os_desc *)S_ERROR)
+			return (FALSE);
+	}
+
+	for (APLIST_TRAVERSE(ofl->ofl_mapdata, idx, isp)) {
+		if (ld_place_section(ofl, isp, NULL,
+		    ld_targ.t_id.id_data, NULL) == (Os_desc *)S_ERROR)
+			return (FALSE);
+	}
+
+	return (TRUE);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/sgs/libld/common/map_support.c	Mon Feb 22 09:19:31 2010 -0700
@@ -0,0 +1,1488 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ *	Copyright (c) 1988 AT&T
+ *	  All Rights Reserved
+ *
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Map file parsing (Shared Support Code).
+ */
+#include	<stdio.h>
+#include	<errno.h>
+#include	"msg.h"
+#include	"_libld.h"
+#include	"_map.h"
+
+/*
+ * Given a NULL terminated array of structures of arbitrary type, where
+ * each struct contains (among other fields) a character pointer field
+ * giving that struct a unique name, return the address of the struct
+ * that matches the given name.
+ *
+ * entry:
+ *	name - "Keyword" name to be found.
+ *	array - Base address of array
+ *	name_offset - Offset of the name field within the struct
+ *		type used by this array, as generated via
+ *		SGSOFFSETOF().
+ *	elt_size - sizeof the basic array element type
+ *
+ * exit:
+ *	Using a case insensitive comparison, name is compared to the
+ *	name of each element of the array. The address of the first
+ *	match found is returned. If the desired name is not found,
+ *	NULL is returned.
+ *
+ * note:
+ *	This routine is completely type-unsafe. The upside is that this
+ *	single routine is able to search arrays of arbitrary type, leaving
+ *	the caller free to structure their array in any way that is convenient
+ *	to solve the problem at hand.
+ */
+#ifndef _ELF64
+void *
+ld_map_kwfind(const char *name, void *array, size_t name_offset,
+    size_t elt_size)
+{
+	for (; ; array = elt_size + (char *)array) {
+		/* LINTED E_BAD_PTR_CAST_ALIGN */
+		const char *arr_name = *((const char **)
+		    (name_offset + (const char *) array));
+
+		if (arr_name == NULL)
+			return (NULL);
+
+		if (strcasecmp(name, arr_name) == 0)
+			return (array);
+	}
+
+	/*NOTREACHED*/
+	assert(0);
+	return (NULL);
+}
+#endif
+
+/*
+ * Given the same NULL terminated array accepted by ld_map_kwfind(), format
+ * the strings into a comma separated list of names.
+ *
+ * entry:
+ *	array - Base address of array
+ *	name_offset - Offset of the name field within the struct
+ *		type used by this array, as generated via
+ *		SGSOFFSETOF().
+ *	elt_size - sizeof the basic array element type
+ *	buf - Buffer to receive output
+ *	bufsize - sizeof(buf)
+ *
+ * exit:
+ *	As many of the names as will fit are formatted into buf. If all the
+ *	names do not fit, the remainder are quietly clipped. The caller must
+ *	ensure that there is sufficient room. buf is returned, for convenience
+ *	in using this function as an argument for printing.
+ */
+#ifndef _ELF64
+char *
+ld_map_kwnames(void *array, size_t name_offset, size_t elt_size, char *buf,
+    size_t bufsize)
+{
+	size_t	cnt = 0;
+	size_t	len;
+	char	*str = buf;
+
+	for (; bufsize > 1; array = elt_size + (char *)array, cnt++) {
+		/* LINTED E_BAD_PTR_CAST_ALIGN */
+		const char *arr_name = *((const char **)
+		    (name_offset + (const char *) array));
+
+		if (arr_name == NULL)
+			break;
+
+		if (cnt > 0) {
+			if (bufsize < 3)
+				break;
+			*str++ = ',';
+			*str++ = ' ';
+			bufsize -= 2;
+			*(str + 1) = '\0';
+		}
+
+		len = strlcpy(str, arr_name, bufsize);
+		if (len >= bufsize)
+			break;
+		str += len;
+		bufsize -= len;
+	}
+
+	return (buf);
+}
+#endif
+
+/*
+ * Create a pseudo input file descriptor to represent the specified Mapfile.
+ * An input descriptor is required any time a symbol is generated.
+ *
+ * entry:
+ *	mf - Mapfile descriptor.
+ *
+ * exit:
+ *	If an input descriptor was already created for this mapfile
+ *	by a previous call, it is returned. Otherwise, a new descriptor
+ *	is created, entered into the mapfile descriptor, and returned.
+ *
+ *	Success is indicated by a non-NULL return value, failure by NULL.
+ */
+Ifl_desc *
+ld_map_ifl(Mapfile *mf)
+{
+	Ifl_desc	*ifl;
+
+	/*
+	 * If we've already created a pseudo input descriptor for this
+	 * mapfile, reuse it.
+	 */
+	if (mf->mf_ifl != NULL)
+		return (mf->mf_ifl);
+
+	if ((ifl = libld_calloc(sizeof (Ifl_desc), 1)) == NULL)
+		return (NULL);
+	ifl->ifl_name = mf->mf_name;
+	ifl->ifl_flags = (FLG_IF_MAPFILE | FLG_IF_NEEDED | FLG_IF_FILEREF);
+	if ((ifl->ifl_ehdr = libld_calloc(sizeof (Ehdr), 1)) == NULL)
+		return (NULL);
+	ifl->ifl_ehdr->e_type = ET_REL;
+
+	if (aplist_append(&mf->mf_ofl->ofl_objs, ifl, AL_CNT_OFL_OBJS) == NULL)
+		return (NULL);
+
+	mf->mf_ifl = ifl;
+	return (mf->mf_ifl);
+}
+
+/*
+ * Given a capability tag type, set the override bit in the output descriptor.
+ * This prevents the use of capability values of that type from the input
+ * objects.
+ */
+void
+ld_map_cap_set_ovflag(Mapfile *mf, Word type)
+{
+	/*
+	 * Map capability tag to the corresponding output descriptor
+	 * override flag.
+	 */
+	static ofl_flag_t override_flag[CA_SUNW_NUM] = {
+		0, 			/* CA_SUNW_NULL */
+		FLG_OF1_OVHWCAP1,	/* CA_SUNW_HW_1 */
+		FLG_OF1_OVSFCAP1,	/* CA_SUNW_SF_1 */
+		FLG_OF1_OVHWCAP2	/* CA_SUNW_HW_2 */
+	};
+#if CA_SUNW_NUM != (CA_SUNW_HW_2 + 1)
+#error "CA_SUNW_NUM has grown"
+#endif
+
+	mf->mf_ofl->ofl_flags1 |= override_flag[type];
+}
+
+/*
+ * Sanity check the given capability bitmask.
+ */
+Boolean
+ld_map_cap_sanitize(Mapfile *mf, Word type, CapMask *capmask)
+{
+	elfcap_mask_t	mask;
+
+	switch (type) {
+	case CA_SUNW_SF_1:
+		/*
+		 * Unlike hardware capabilities, we do not allow setting
+		 * software capability bits that do not have known definitions.
+		 * Software capability tokens have to be validated as a unit
+		 * as the bits can affect each others meaning (see sf1_cap()
+		 * in files.c).
+		 */
+		if ((mask = (capmask->cm_value & ~SF1_SUNW_MASK)) != 0) {
+			mf_warn(mf, MSG_INTL(MSG_MAP_BADSF1),
+			    EC_XWORD(mask));
+			capmask->cm_value &= SF1_SUNW_MASK;
+		}
+		if ((capmask->cm_value &
+		    (SF1_SUNW_FPKNWN | SF1_SUNW_FPUSED)) == SF1_SUNW_FPUSED) {
+			mf_warn(mf, MSG_INTL(MSG_MAP_BADSF1),
+			    EC_XWORD(SF1_SUNW_FPUSED));
+			capmask->cm_value &= ~SF1_SUNW_FPUSED;
+		}
+#if	!defined(_ELF64)
+		/*
+		 * The SF1_SUNW_ADDR32 software capability is only meaningful
+		 * when building a 64-bit object.  Warn the user, and remove the
+		 * setting, if we're building a 32-bit object.
+		 */
+		if (capmask->cm_value & SF1_SUNW_ADDR32) {
+			mf_warn0(mf, MSG_INTL(MSG_MAP_INADDR32SF1));
+			capmask->cm_value &= ~SF1_SUNW_ADDR32;
+		}
+#endif
+	}
+
+	return (TRUE);
+}
+
+/*
+ * Return the shared object control definition structure (ofl_socntl)
+ * for the specified object, creating one if necessary.
+ *
+ * entry:
+ *	mf - Mapfile descriptor
+ *	obj_name - Name of object
+ *
+ * exit:
+ *	Returns the pointer to the definition structure, or NULL on error.
+ */
+Sdf_desc *
+ld_map_dv(Mapfile *mf, const char *obj_name)
+{
+	Sdf_desc	*sdf;
+
+	/*
+	 * If a shared object definition for this file already exists use it,
+	 * otherwise allocate a new descriptor.
+	 */
+	if ((sdf = sdf_find(obj_name, mf->mf_ofl->ofl_socntl)) == NULL) {
+		if ((sdf = sdf_add(obj_name, &mf->mf_ofl->ofl_socntl)) ==
+		    (Sdf_desc *)S_ERROR)
+			return (NULL);
+		sdf->sdf_rfile = mf->mf_name;
+	}
+
+	DBG_CALL(Dbg_map_dv(mf->mf_ofl->ofl_lml, sdf->sdf_name,
+	    mf->mf_lineno));
+	return (sdf);
+}
+
+
+Boolean
+ld_map_dv_entry(Mapfile *mf, Sdf_desc *sdf, Boolean require,
+    const char *version)
+{
+	Sdv_desc	sdv;
+
+	sdv.sdv_name = version;
+	sdv.sdv_ref = mf->mf_name;
+	sdv.sdv_flags = 0;
+
+
+	if (require) {
+		/*
+		 * Add a VERNEED entry for the specified version
+		 * from this object:
+		 *
+		 *	MapfileVersion	Syntax
+		 *	----------------------------------------
+		 *	1		obj - $ADDVERS=version;
+		 *	2		DEPENDENCY obj { REQUIRE=version };
+		 */
+		sdf->sdf_flags |= FLG_SDF_ADDVER;
+
+		if (alist_append(&sdf->sdf_verneed, &sdv, sizeof (Sdv_desc),
+		    AL_CNT_SDF_VERSIONS) == NULL)
+			return (FALSE);
+	} else {		/* Allow */
+		/*
+		 * Allow linking to symbols found in this version, or
+		 * from the versions it inherits from.
+		 *
+		 *	MapfileVersion	Syntax
+		 *	----------------------------------------
+		 *	1		obj - version;
+		 *	2		DEPENDENCY obj { ALLOW=version };
+		 */
+		sdf->sdf_flags |= FLG_SDF_SELECT;
+
+		if (alist_append(&sdf->sdf_vers, &sdv, sizeof (Sdv_desc),
+		    AL_CNT_SDF_VERSIONS) == NULL)
+			return (FALSE);
+	}
+
+	DBG_CALL(Dbg_map_dv_entry(mf->mf_ofl->ofl_lml, mf->mf_lineno,
+	    require, version));
+
+	return (TRUE);
+}
+
+/*
+ * Given a segment descriptor, return its index.
+ *
+ * entry:
+ *	mf - Mapfile descriptor
+ *	sgp - Segment for which index is desired
+ *
+ * exit:
+ *	Index of segment is returned.
+ */
+Xword
+ld_map_seg_index(Mapfile *mf, Sg_desc *sgp)
+{
+	Aliste		idx;
+	Sg_desc		*sgp2;
+	Ofl_desc	*ofl = mf->mf_ofl;
+
+	for (APLIST_TRAVERSE(ofl->ofl_segs, idx, sgp2))
+		if (sgp == sgp2)
+			break;
+
+	return (idx);
+}
+
+/*
+ * Add a section name to the output section sort list for the given
+ * segment.
+ *
+ * entry:
+ *	mf - Mapfile descriptor
+ *	sgp - Segment in question
+ *	sec_name - Name of section to be added.
+ *
+ * exit:
+ *	Returns TRUE for success, FALSE for failure.
+ */
+Boolean
+ld_map_seg_os_order_add(Mapfile *mf, Sg_desc *sgp, const char *sec_name)
+{
+	Aliste		idx;
+	Sec_order	*scop;
+
+	/*
+	 * Make sure it's not already on the list
+	 */
+	for (ALIST_TRAVERSE(sgp->sg_os_order, idx, scop))
+		if (strcmp(scop->sco_secname, sec_name) == 0) {
+			mf_fatal(mf, MSG_INTL(MSG_MAP_DUP_OS_ORD), sec_name);
+			return (FALSE);
+		}
+
+
+	scop = alist_append(&sgp->sg_os_order, NULL, sizeof (Sec_order),
+	    AL_CNT_SG_SECORDER);
+	if (scop == NULL)
+		return (FALSE);
+
+	scop->sco_secname = sec_name;
+
+	DBG_CALL(Dbg_map_seg_os_order(mf->mf_ofl->ofl_lml, sgp, sec_name,
+	    alist_nitems(sgp->sg_os_order), mf->mf_lineno));
+
+	/*
+	 * Output section ordering is a relatively expensive operation,
+	 * and one that is generally not used. In order to avoid needless
+	 * work, the FLG_OF_OS_ORDER must be set when it will be needed.
+	 * The section we just added needs this flag to be set. However,
+	 * it is possible that a subsequent mapfile directive may come
+	 * along and clear the order list, making it unnecessary.
+	 *
+	 * Instead of setting it here, we do a final pass over the segments
+	 * in ld_map_finalize() and set it there if a segment with sorting
+	 * requirements is seen.
+	 */
+
+	return (TRUE);
+}
+
+/*
+ * Add a size symbol to a segment
+ *
+ * entry:
+ *	mf - Mapfile descriptor
+ *	sgp - Segment descriptor
+ *	eq_tol - Type of assignment: TK_EQUAL, or TK_PLUSEQ
+ *	symname - Name of symbol. Must be in stable static storage
+ *		that can be retained.
+ *
+ * exit:
+ *	On success, the symbol has been added and TRUE is returned.
+ *	Otherwise an error is reported and FALSE is returned.
+ */
+Boolean
+ld_map_seg_size_symbol(Mapfile *mf, Sg_desc *sgp, Token eq_tok,
+    const char *symname)
+{
+	Sym		*sym;		/* New symbol pointer */
+	Sym_desc	*sdp;		/* New symbol node pointer */
+	Ifl_desc	*ifl;		/* Dummy input file structure */
+	avl_index_t	where;
+	Ofl_desc	*ofl = mf->mf_ofl;
+
+	/*
+	 * We don't allow resetting the list of size symbols, so if the
+	 * operator is TK_EQUAL and the list is not empty, issue an error.
+	 *
+	 * If we want to lift this restriction, we would have to save the
+	 * size symbols and enter them from ld_map_post_process(). Doing that
+	 * well would require a significant overhead in saved error reporting
+	 * state, and interactions with the same symbols created by symbol
+	 * directives. As size symbols are of little practical use, and are
+	 * maintained primarily for backward compatibility with SysV, we have
+	 * decided not to do that, but to create the symbols as the mapfiles
+	 * are processed, and to disallow later attempts to remove them.
+	 */
+	if ((eq_tok == TK_EQUAL) && (aplist_nitems(sgp->sg_sizesym) > 0)) {
+		mf_fatal(mf, MSG_INTL(MSG_MAP_SEGSIZE), sgp->sg_name);
+		return (FALSE);
+	}
+
+	/*
+	 * Make sure we have a pseudo file descriptor to associate to the
+	 * symbol.
+	 */
+	if ((ifl = ld_map_ifl(mf)) == NULL)
+		return (FALSE);
+
+	/*
+	 * Make sure the symbol doesn't already exist.  It is possible that the
+	 * symbol has been scoped or versioned, in which case it does exist
+	 * but we can freely update it here.
+	 */
+	if ((sdp = ld_sym_find(symname, SYM_NOHASH, &where, ofl)) == NULL) {
+		Word hval;
+
+		if ((sym = libld_calloc(sizeof (Sym), 1)) == NULL)
+			return (FALSE);
+		sym->st_shndx = SHN_ABS;
+		sym->st_size = 0;
+		sym->st_info = ELF_ST_INFO(STB_GLOBAL, STT_OBJECT);
+
+		DBG_CALL(Dbg_map_size_new(ofl->ofl_lml, symname,
+		    sgp->sg_name, mf->mf_lineno));
+		/* LINTED */
+		hval = (Word)elf_hash(symname);
+		if ((sdp = ld_sym_enter(symname, sym, hval, ifl, ofl, 0,
+		    SHN_ABS, (FLG_SY_SPECSEC | FLG_SY_GLOBREF), &where)) ==
+		    (Sym_desc *)S_ERROR)
+			return (FALSE);
+		sdp->sd_flags &= ~FLG_SY_CLEAN;
+		DBG_CALL(Dbg_map_symbol(ofl, sdp));
+	} else {
+		sym = sdp->sd_sym;
+
+		if (sym->st_shndx == SHN_UNDEF) {
+			sdp->sd_shndx = sym->st_shndx = SHN_ABS;
+			sdp->sd_flags |= FLG_SY_SPECSEC;
+			sym->st_size = 0;
+			sym->st_info = ELF_ST_INFO(STB_GLOBAL, STT_OBJECT);
+
+			sdp->sd_flags &= ~FLG_SY_MAPREF;
+
+			DBG_CALL(Dbg_map_size_old(ofl, sdp,
+			    sgp->sg_name, mf->mf_lineno));
+		} else {
+			mf_fatal(mf, MSG_INTL(MSG_MAP_SYMDEF1),
+			    demangle(sdp->sd_name), sdp->sd_file->ifl_name,
+			    MSG_INTL(MSG_MAP_DIFF_SYMMUL));
+			return (FALSE);
+		}
+	}
+
+	/*
+	 * Assign the symbol to the segment.
+	 */
+	if (aplist_append(&sgp->sg_sizesym, sdp, AL_CNT_SG_SIZESYM) == NULL)
+		return (FALSE);
+
+	return (TRUE);
+}
+
+/*
+ * Allocate a zeroed segment descriptor.
+ *
+ * exit:
+ *	Returns pointer to the descriptor on success, NULL on failure.
+ *	The contents of the returned descriptor have been zeroed.
+ *	The returned descriptor is not added to the segment list
+ *	(ofl_segs). That is done using ld_map_seg_insert().
+ */
+Sg_desc *
+ld_map_seg_alloc(const char *name, Word p_type, sg_flags_t sg_flags)
+{
+	Sg_desc	*sgp;
+
+	if ((sgp = libld_calloc(sizeof (Sg_desc), 1)) == NULL)
+		return (NULL);
+	sgp->sg_phdr.p_type = p_type;
+	sgp->sg_name = name;
+	sgp->sg_flags = sg_flags;
+
+	return (sgp);
+}
+
+/*
+ * Return the PT_SUNWSTACK segment descriptor from the ofl_segs list.
+ * This segment is part of the default set and cannot be removed, so
+ * this routine will always succeed.
+ *
+ * exit:
+ *	The descriptor is located, a DBG_STATE_MOD_BEFORE debug
+ *	message issued, the FLG_SG_DISABLED flag is cleared, and the
+ *	descriptor pointer returned.
+ */
+Sg_desc *
+ld_map_seg_stack(Mapfile *mf)
+{
+	Ofl_desc	*ofl = mf->mf_ofl;
+	Sg_desc		*sgp;
+	Aliste		idx;
+
+	/*
+	 * The stack is established by exec(), using the executable's program
+	 * headers, before any sharable objects are loaded. If there is a
+	 * PT_SUNWSTACK program header, exec() will act on it. As such, stack
+	 * program headers are normally only applicable to executables.
+	 *
+	 * However, ELF allows a sharable object with an interpreter to
+	 * be executed directly, and in this extremely rare case, the
+	 * PT_SUNWSTACK program header would have meaning. Rather than
+	 * second guess user intent, we simply create it on demand for any
+	 * dynamic object, trusting that the user has a good reason for it.
+	 */
+	for (APLIST_TRAVERSE(ofl->ofl_segs, idx, sgp))
+		if (sgp->sg_phdr.p_type == PT_SUNWSTACK) {
+			DBG_CALL(Dbg_map_seg(mf->mf_ofl, DBG_STATE_MOD_BEFORE,
+			    idx, sgp, mf->mf_lineno));
+			sgp->sg_flags &= ~FLG_SG_DISABLED;
+			return (sgp);
+		}
+
+	/*NOTREACHED*/
+	return (NULL);
+}
+
+/*
+ * Finish the initialization of a new segment descriptor allocated by
+ * ld_map_seg_alloc(), and enter it into the segment list.
+ *
+ * entry:
+ *	mf - Mapfile descriptor
+ *	seg_type - One of DBG_SEG_NEW or DBG_SEG_NEW_IMPLICIT
+ *	ins_head - If TRUE, the new segment goes at the front of
+ *		others of its type. If FALSE, it goes at the end.
+ *	sgp - Segment descriptor to enter.
+ *	where - Insertion point, initialized by a previous (failed) call to
+ *		ld_seg_lookup(). Ignored if the segment has a NULL sg_name.
+ *
+ * exit:
+ *	On success, returns SEG_INS_OK. A non-fatal error is indicated with
+ *	a return value of SEG_INS_SKIP, in which case the descriptor is
+ *	not entered, but the user is expected to discard it and continue
+ *	running. On failure, returns SEG_INS_FAIL.
+ *
+ * note:
+ *	This routine will modify the contents of the descriptor referenced
+ *	by sgp_tmpl before allocating the new descriptor. The caller must
+ *	not expect it to be unmodified.
+ */
+ld_map_seg_ins_t
+ld_map_seg_insert(Mapfile *mf, dbg_state_t dbg_state, Sg_desc *sgp,
+    avl_index_t where)
+{
+	Ofl_desc	*ofl = mf->mf_ofl;
+	Aliste		idx;
+	Sg_desc		*sgp2;		/* temp segment descriptor pointer */
+	int		ins_head;
+	Xword		sg_ndx;
+
+	/*
+	 * If specific fields have not been supplied via
+	 * map_equal(), make sure defaults are supplied.
+	 */
+	if (((sgp->sg_flags & FLG_SG_P_TYPE) == 0) &&
+	    (sgp->sg_phdr.p_type == PT_NULL)) {
+		/*
+		 * Default to a loadable segment.
+		 */
+		sgp->sg_phdr.p_type = PT_LOAD;
+		sgp->sg_flags |= FLG_SG_P_TYPE;
+	}
+	if (sgp->sg_phdr.p_type == PT_LOAD) {
+		if ((sgp->sg_flags & FLG_SG_P_FLAGS) == 0) {
+			/*
+			 * Default to read/write and execute.
+			 */
+			sgp->sg_phdr.p_flags = PF_R + PF_W + PF_X;
+			sgp->sg_flags |= FLG_SG_P_FLAGS;
+		}
+		if ((sgp->sg_flags & FLG_SG_P_ALIGN) == 0) {
+			/*
+			 * Default to segment alignment
+			 */
+			sgp->sg_phdr.p_align = ld_targ.t_m.m_segm_align;
+			sgp->sg_flags |= FLG_SG_P_ALIGN;
+		}
+	}
+
+	/*
+	 * Determine where the new item should be inserted in
+	 * the segment descriptor list.
+	 */
+	switch (sgp->sg_phdr.p_type) {
+	case PT_LOAD:
+		if (sgp->sg_flags & FLG_SG_EMPTY)
+			sgp->sg_id = SGID_TEXT_EMPTY;
+		else
+			sgp->sg_id = SGID_TEXT;
+		break;
+	case PT_NULL:
+		if (sgp->sg_flags & FLG_SG_EMPTY)
+			sgp->sg_id = SGID_NULL_EMPTY;
+		else
+			sgp->sg_id = SGID_NULL;
+		break;
+	case PT_NOTE:
+		sgp->sg_id = SGID_NOTE;
+		break;
+	default:
+		mf_fatal(mf, MSG_INTL(MSG_MAP_UNKSEGTYP),
+		    EC_WORD(sgp->sg_phdr.p_type));
+		return (SEG_INS_FAIL);
+	}
+
+	/*
+	 * Add the descriptor to the segment list. In the v1 syntax,
+	 * new sections are added at the head of their type, while in
+	 * the newer syntax, they go at the end of their type.
+	 */
+	sg_ndx = 0;
+	ins_head = (mf->mf_version == MFV_SYSV);
+	for (APLIST_TRAVERSE(ofl->ofl_segs, idx, sgp2)) {
+		if (ins_head) {	/* Insert before the others of its type */
+			if (sgp->sg_id > sgp2->sg_id) {
+				sg_ndx++;
+				continue;
+			}
+		} else {	/* Insert after the others of its type */
+			if (sgp->sg_id >= sgp2->sg_id) {
+				sg_ndx++;
+				continue;
+			}
+		}
+		break;
+	}
+	if (aplist_insert(&ofl->ofl_segs, sgp, AL_CNT_SEGMENTS, idx) == NULL)
+		return (SEG_INS_FAIL);
+	if (sgp->sg_name != NULL)
+		avl_insert(&ofl->ofl_segs_avl, sgp, where);
+
+	DBG_CALL(Dbg_map_seg(ofl, dbg_state, sg_ndx, sgp, mf->mf_lineno));
+	return (SEG_INS_OK);
+}
+
+/*
+ * Add an entrance criteria record for the specified segment
+ *
+ * entry:
+ *	mf - Mapfile descriptor
+ *	sgp - Segment for which a new entrance criteria record is needed
+ *	name - NULL, or name by which the entrance criteria can be referenced.
+ *
+ * exit:
+ *	On success, a pointer to the new entrace criteria record is
+ *	returned, the contents of which have been zeroed. On failure,
+ *	NULL is returned.
+ */
+Ent_desc *
+ld_map_seg_ent_add(Mapfile *mf, Sg_desc *sgp, const char *name)
+{
+	Ent_desc	*enp;
+	avl_index_t	where;
+	Ofl_desc	*ofl = mf->mf_ofl;
+
+	if ((name != NULL) &&
+	    (ld_ent_lookup(mf->mf_ofl, name, &where) != NULL)) {
+		mf_fatal(mf, MSG_INTL(MSG_MAP_DUPNAMENT), name);
+		return (NULL);
+	}
+
+	/* Allocate and initialize the entrace criteria descriptor */
+	if ((enp = libld_calloc(1, sizeof (*enp))) == NULL)
+		return (NULL);
+	enp->ec_name = name;
+	enp->ec_segment = sgp;	 /* Tie criteria to segment */
+
+
+	/*
+	 * Insert into the APlist. The mf_ec_insndx field for each mapfile
+	 * starts at 0, and is incremented with each insertion. This means
+	 * that the entrance criteria for each mapfile go to the head of
+	 * the list, but that within a single mapfile, they are inserted in
+	 * the order they are seen.
+	 */
+	if (aplist_insert(&ofl->ofl_ents, enp, AL_CNT_OFL_ENTRANCE,
+	    mf->mf_ec_insndx) == NULL)
+		return (NULL);
+	mf->mf_ec_insndx++;
+
+	/*
+	 * If the entrance criteria is named insert it into the AVL tree
+	 * as well. This provides O(logN) lookups by name.
+	 */
+	if (name != NULL)
+		avl_insert(&ofl->ofl_ents_avl, enp, where);
+
+	return (enp);
+}
+
+Boolean
+ld_map_seg_ent_files(Mapfile *mf, Ent_desc *enp, Word ecf_type, const char *str)
+{
+	Ent_desc_file	edf;
+
+	/*
+	 * The v1 sysv syntax can let an empty string get in, consisting of
+	 * just a '*' where the '*' is interpreted as 'basename'.
+	 */
+	if (str[0] == '\0') {
+		mf_fatal0(mf, MSG_INTL(MSG_MAP_MALFORM));
+		return (FALSE);
+	}
+
+	/* Basename or objname string must not contain a path separator (/) */
+	if ((ecf_type != TYP_ECF_PATH) && (strchr(str, '/') != NULL)) {
+		const char *msg = (ecf_type == TYP_ECF_BASENAME) ?
+		    MSG_INTL(MSG_MAP_BADBNAME) : MSG_INTL(MSG_MAP_BADONAME);
+
+		mf_fatal(mf, msg, str);
+		return (FALSE);
+	}
+
+	edf.edf_flags = ecf_type;
+	edf.edf_name = str;
+	edf.edf_name_len = strlen(edf.edf_name);
+
+	/* Does it have an archive member suffix? */
+	if ((edf.edf_name[edf.edf_name_len - 1] == ')') &&
+	    (strrchr(edf.edf_name, '(') != NULL))
+		edf.edf_flags |= FLG_ECF_ARMEMBER;
+
+	if (alist_append(&enp->ec_files, &edf, sizeof (edf),
+	    AL_CNT_EC_FILES) == NULL)
+		return (FALSE);
+
+	/*
+	 * Note that an entrance criteria requiring file name matching exists
+	 * in the system. This is used by ld_place_path_info_init() to
+	 * skip Place_pathinfo initialization in cases where there are
+	 * no entrance criteria that will use the results.
+	 */
+	mf->mf_ofl->ofl_flags |= FLG_OF_EC_FILES;
+
+	return (TRUE);
+}
+
+/*
+ * Prepare an ld_map_ver_t structure for a new mapfile defined version.
+ *
+ * exit:
+ *	Returns TRUE for success, FALSE for failure.
+ */
+Boolean
+ld_map_sym_ver_init(Mapfile *mf, char *name, ld_map_ver_t *mv)
+{
+	Word		hash;
+	Ofl_desc	*ofl = mf->mf_ofl;
+
+	mv->mv_name = name;
+	mv->mv_scope = FLG_SCOPE_DFLT;
+	mv->mv_errcnt = 0;
+
+	/*
+	 * If we're generating segments within the image then any symbol
+	 * reductions will be processed (ie. applied to relocations and symbol
+	 * table entries).  Otherwise (when creating a relocatable object) any
+	 * versioning information is simply recorded for use in a later
+	 * (segment generating) link-edit.
+	 */
+	if (ofl->ofl_flags & FLG_OF_RELOBJ)
+		ofl->ofl_flags |= FLG_OF_VERDEF;
+
+	/*
+	 * If no version descriptors have yet been set up, initialize a base
+	 * version to represent the output file itself.  This `base' version
+	 * catches any internally generated symbols (_end, _etext, etc.) and
+	 * serves to initialize the output version descriptor count.
+	 */
+	if (ofl->ofl_vercnt == 0) {
+		if (ld_vers_base(ofl) == (Ver_desc *)S_ERROR)
+			return (FALSE);
+	}
+
+	/*
+	 * If this definition has an associated version name then generate a
+	 * new version descriptor and an associated version symbol index table.
+	 */
+	if (name) {
+		ofl->ofl_flags |= FLG_OF_VERDEF;
+
+		/*
+		 * Traverse the present version descriptor list to see if there
+		 * is already one of the same name, otherwise create a new one.
+		 */
+		/* LINTED */
+		hash = (Word)elf_hash(name);
+		if (((mv->mv_vdp = ld_vers_find(name, hash,
+		    ofl->ofl_verdesc)) == NULL) &&
+		    ((mv->mv_vdp = ld_vers_desc(name, hash,
+		    &ofl->ofl_verdesc)) == (Ver_desc *)S_ERROR))
+			return (FALSE);
+
+		/*
+		 * Initialize any new version with an index, the file from
+		 * which it was first referenced, and a WEAK flag (indicates
+		 * that there are no symbols assigned to it yet).
+		 */
+		if (mv->mv_vdp->vd_ndx == 0) {
+			/* LINTED */
+			mv->mv_vdp->vd_ndx = (Half)++ofl->ofl_vercnt;
+			mv->mv_vdp->vd_file = ld_map_ifl(mf);
+			mv->mv_vdp->vd_flags = VER_FLG_WEAK;
+		}
+	} else {
+		/*
+		 * If a version definition hasn't been specified assign any
+		 * symbols to the base version.
+		 */
+		mv->mv_vdp = (Ver_desc *)ofl->ofl_verdesc->apl_data[0];
+	}
+
+	return (TRUE);
+}
+
+/*
+ * Change the current scope for the given version.
+ *
+ * entry:
+ *	mf - Mapfile descriptor
+ *	scope_name - Name for new scope
+ *	mv - Information related to version being defined
+ *
+ * exit:
+ *	On success, mv is updated to change the current scope.
+ *	On failure, mv->errcnt is incremented, and mv is otherwise unaltered.
+ */
+void
+ld_map_sym_scope(Mapfile *mf, const char *scope_name, ld_map_ver_t *mv)
+{
+	typedef struct {
+		const char	*name;		/* scope keyword string */
+		ld_map_scope_t	type;		/* Resulting type */
+		ofl_flag_t	ofl_flags;	/* 0, or ofl flags to add */
+	} scope_t;
+
+	/*
+	 * Valid symbol scope keywords
+	 *
+	 * All symbols added by a mapfile are actually global entries, and
+	 * are assigned the scope that is presently in effect.
+	 *
+	 * If a protected/symbolic scope is detected, remember this. If
+	 * a protected/symbolic scope is the only scope defined in this
+	 * (or any other mapfiles), then the mode -Bsymbolic is established.
+	 */
+	static scope_t scope_list[] = {
+		{ MSG_ORIG(MSG_MAPKW_DEFAULT), FLG_SCOPE_DFLT, FLG_OF_MAPGLOB },
+		{ MSG_ORIG(MSG_MAPKW_ELIMINATE), FLG_SCOPE_ELIM, 0 },
+		{ MSG_ORIG(MSG_MAPKW_EXPORTED), FLG_SCOPE_EXPT, 0 },
+		{ MSG_ORIG(MSG_MAPKW_HIDDEN), FLG_SCOPE_HIDD, 0 },
+		{ MSG_ORIG(MSG_MAPKW_GLOBAL), FLG_SCOPE_DFLT, FLG_OF_MAPGLOB },
+		{ MSG_ORIG(MSG_MAPKW_LOCAL), FLG_SCOPE_HIDD, 0 },
+		{ MSG_ORIG(MSG_MAPKW_PROTECTED),
+		    FLG_SCOPE_PROT, FLG_OF_MAPSYMB },
+		{ MSG_ORIG(MSG_MAPKW_SINGLETON),
+		    FLG_SCOPE_SNGL, FLG_OF_MAPGLOB },
+		{ MSG_ORIG(MSG_MAPKW_SYMBOLIC),
+		    FLG_SCOPE_PROT, FLG_OF_MAPSYMB },
+
+		/* List must be null terminated */
+		{ 0 }
+	};
+
+	/*
+	 * Size of buffer needed to format the names in scope_list[]. Must
+	 * be kept in sync with scope_list.
+	 */
+	static size_t scope_list_bufsize =
+	    KW_NAME_SIZE(MSG_MAPKW_DEFAULT) +
+	    KW_NAME_SIZE(MSG_MAPKW_ELIMINATE) +
+	    KW_NAME_SIZE(MSG_MAPKW_EXPORTED) +
+	    KW_NAME_SIZE(MSG_MAPKW_HIDDEN) +
+	    KW_NAME_SIZE(MSG_MAPKW_GLOBAL) +
+	    KW_NAME_SIZE(MSG_MAPKW_LOCAL) +
+	    KW_NAME_SIZE(MSG_MAPKW_PROTECTED) +
+	    KW_NAME_SIZE(MSG_MAPKW_SINGLETON) +
+	    KW_NAME_SIZE(MSG_MAPKW_SYMBOLIC);
+
+	scope_t	*scope;
+
+	scope = ld_map_kwfind(scope_name, scope_list,
+	    SGSOFFSETOF(scope_t, name), sizeof (scope_list[0]));
+	if (scope == NULL) {
+		char buf[scope_list_bufsize];
+
+		mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_SYMSCOPE),
+		    ld_map_kwnames(scope_list, SGSOFFSETOF(scope_t, name),
+		    sizeof (scope[0]), buf, scope_list_bufsize), scope_name);
+		mv->mv_errcnt++;
+		return;
+	}
+
+	mv->mv_scope = scope->type;
+	mf->mf_ofl->ofl_flags |= scope->ofl_flags;
+}
+
+/*
+ * Process the special auto-reduction directive ('*'). It can be specified
+ * in hidden/local, and eliminate scope. This directive indicates that all
+ * symbols processed that are not explicitly defined to be global are to be
+ * reduced to hidden/local scope in, or eliminated from, the output image.
+ *
+ * An auto-reduction directive also implies that a version definition must
+ * be created, as the user has effectively defined an interface.
+ */
+void
+ld_map_sym_autoreduce(Mapfile *mf, ld_map_ver_t *mv)
+{
+	switch (mv->mv_scope) {
+	case FLG_SCOPE_HIDD:
+		mf->mf_ofl->ofl_flags |= (FLG_OF_VERDEF | FLG_OF_AUTOLCL);
+		break;
+	case FLG_SCOPE_ELIM:
+		mf->mf_ofl->ofl_flags |= (FLG_OF_VERDEF | FLG_OF_AUTOELM);
+		break;
+	default:
+		/*
+		 * Auto reduction has been applied to a scope that doesn't
+		 * support it. This should be a fatal error, but we limit
+		 * it to a warning for version 1 mapfiles. For years, we
+		 * quietly ignored this case, so there may be mapfiles in
+		 * production use that we do not wish to break.
+		 */
+		if (mf->mf_version == 1) {
+			mf_warn0(mf, MSG_INTL(MSG_MAP_BADAUTORED));
+		} else {
+			mf_fatal0(mf, MSG_INTL(MSG_MAP_BADAUTORED));
+			mv->mv_errcnt++;
+		}
+	}
+}
+
+/*
+ * Add a standard or auxiliary filter to the given symbol
+ *
+ * entry:
+ *	mf - Mapfile descriptor
+ *	mv - Information related to version being defined
+ *	ms - Information related to symbol being defined
+ *	dft_flag - One of FLG_SY_STDFLTR or FLG_SY_AUXFLTR,
+ *		specifying the type of filter.
+ *	filtee - String giving filtee to be added
+ *
+ * exit:
+ *	On success, the filtee is added. On failure, mv->errcnt is
+ *	incremented, and mv/ms are otherwise unaltered.
+ */
+void
+ld_map_sym_filtee(Mapfile *mf, ld_map_ver_t *mv, ld_map_sym_t *ms,
+    Word dft_flag, const char *filtee)
+{
+	/*
+	 * A given symbol can only be tied to a single filter, be it
+	 * a standard filter, or auxiliary.
+	 */
+	if (ms->ms_filtee) {
+		mf_fatal0(mf, MSG_INTL(MSG_MAP_MULTFILTEE));
+		mv->mv_errcnt++;
+		return;
+	}
+
+	/* Symbol filtering is only for sharable objects */
+	if (!(mf->mf_ofl->ofl_flags & FLG_OF_SHAROBJ)) {
+		mf_fatal0(mf, MSG_INTL(MSG_MAP_FLTR_ONLYAVL));
+		mv->mv_errcnt++;
+		return;
+	}
+
+	ms->ms_filtee = filtee;
+	ms->ms_dft_flag = dft_flag;
+	ms->ms_sdflags |= dft_flag;
+	mf->mf_ofl->ofl_flags |= FLG_OF_SYMINFO;
+}
+
+/*
+ * Enter a mapfile defined symbol into the given version
+ *
+ * entry:
+ *	mf - Mapfile descriptor
+ *	ms - Information related to symbol being added to version
+ *
+ * exit:
+ *	On success, returns TRUE. On failure that requires an immediate
+ *	halt, returns FALSE.
+ *
+ *	On failure that requires eventual halt, but for which it would
+ *	be OK to continue parsing in hopes of flushing out additional
+ *	problems, increments mv->mv_errcnt, and returns TRUE.
+ */
+Boolean
+ld_map_sym_enter(Mapfile *mf, ld_map_ver_t *mv, ld_map_sym_t *ms)
+{
+	Ofl_desc	*ofl = mf->mf_ofl;
+	Word		hash;
+	avl_index_t	where;
+	Sym		*sym;
+	Sym_desc	*sdp;
+	const char	*conflict;
+
+	/*
+	 * Add the new symbol.  It should be noted that all
+	 * symbols added by the mapfile start out with global
+	 * scope, thus they will fall through the normal symbol
+	 * resolution process.  Symbols defined as locals will
+	 * be reduced in scope after all input file processing.
+	 */
+	/* LINTED */
+	hash = (Word)elf_hash(ms->ms_name);
+	DBG_CALL(Dbg_map_version(ofl->ofl_lml, mv->mv_name, ms->ms_name,
+	    mv->mv_scope));
+	if ((sdp = ld_sym_find(ms->ms_name, hash, &where, ofl)) == NULL) {
+		if ((sym = libld_calloc(sizeof (Sym), 1)) == NULL)
+			return (FALSE);
+
+		/*
+		 * Make sure any parent or external declarations
+		 * fall back to references.
+		 */
+		if (ms->ms_sdflags & (FLG_SY_PARENT | FLG_SY_EXTERN)) {
+			/*
+			 * Turn it into a reference by setting
+			 * the section index to UNDEF.
+			 */
+			sym->st_shndx = ms->ms_shndx = SHN_UNDEF;
+
+			/*
+			 * It is wrong to specify size or value for an
+			 * external symbol.
+			 */
+			if (ms->ms_value_set || (ms->ms_size != 0)) {
+				mf_fatal0(mf, MSG_INTL(MSG_MAP_NOEXVLSZ));
+				mv->mv_errcnt++;
+				return (TRUE);
+			}
+		} else {
+			sym->st_shndx = (Half)ms->ms_shndx;
+		}
+
+		sym->st_value = ms->ms_value;
+		sym->st_size = ms->ms_size;
+		sym->st_info = ELF_ST_INFO(STB_GLOBAL, ms->ms_type);
+
+		if ((sdp = ld_sym_enter(ms->ms_name, sym, hash,
+		    ld_map_ifl(mf), ofl, 0, ms->ms_shndx, ms->ms_sdflags,
+		    &where)) == (Sym_desc *)S_ERROR)
+			return (FALSE);
+
+		sdp->sd_flags &= ~FLG_SY_CLEAN;
+
+		/*
+		 * Identify any references.  FLG_SY_MAPREF is
+		 * turned off once a relocatable object with
+		 * the same symbol is found, thus the existence
+		 * of FLG_SY_MAPREF at symbol validation is
+		 * used to flag undefined/misspelled entries.
+		 */
+		if (sym->st_shndx == SHN_UNDEF)
+			sdp->sd_flags |= (FLG_SY_MAPREF | FLG_SY_GLOBREF);
+
+	} else {
+		conflict = NULL;
+		sym = sdp->sd_sym;
+
+		/*
+		 * If this symbol already exists, make sure this
+		 * definition doesn't conflict with the former.
+		 * Provided it doesn't, multiple definitions
+		 * from different mapfiles can augment each
+		 * other.
+		 */
+		/* BEGIN CSTYLED */
+		if (sym->st_value) {
+			if (ms->ms_value && (sym->st_value != ms->ms_value))
+				conflict = MSG_INTL(MSG_MAP_DIFF_SYMVAL);
+		} else {
+			sym->st_value = ms->ms_value;
+		}
+		if (sym->st_size) {
+			if (ms->ms_size && (sym->st_size != ms->ms_size))
+				conflict = MSG_INTL(MSG_MAP_DIFF_SYMSZ);
+		} else {
+			sym->st_size = ms->ms_size;
+		}
+		if (ELF_ST_TYPE(sym->st_info) != STT_NOTYPE) {
+			if ((ms->ms_type != STT_NOTYPE) &&
+			    (ELF_ST_TYPE(sym->st_info) != ms->ms_type))
+				conflict = MSG_INTL(MSG_MAP_DIFF_SYMTYP);
+		} else {
+			sym->st_info = ELF_ST_INFO(STB_GLOBAL, ms->ms_type);
+		}
+		if (sym->st_shndx != SHN_UNDEF) {
+			if ((ms->ms_shndx != SHN_UNDEF) &&
+			    (sym->st_shndx != ms->ms_shndx))
+				conflict = MSG_INTL(MSG_MAP_DIFF_SYMNDX);
+		} else {
+			sym->st_shndx = sdp->sd_shndx = ms->ms_shndx;
+		}
+		/* END CSTYLED */
+
+		if ((sdp->sd_flags & MSK_SY_GLOBAL) &&
+		    (sdp->sd_aux->sa_overndx != VER_NDX_GLOBAL) &&
+		    (mv->mv_vdp->vd_ndx != VER_NDX_GLOBAL) &&
+		    (sdp->sd_aux->sa_overndx != mv->mv_vdp->vd_ndx)) {
+			conflict = MSG_INTL(MSG_MAP_DIFF_SYMVER);
+		}
+
+		if (conflict) {
+			mf_fatal(mf, MSG_INTL(MSG_MAP_SYMDEF1),
+			    demangle(ms->ms_name),
+			    sdp->sd_file->ifl_name, conflict);
+			mv->mv_errcnt++;
+			return (TRUE);
+		}
+
+		/*
+		 * If this mapfile entry supplies a definition,
+		 * indicate that the symbol is now used.
+		 */
+		if (ms->ms_shndx != SHN_UNDEF)
+			sdp->sd_flags |= FLG_SY_MAPUSED;
+	}
+
+	/*
+	 * A symbol declaration that defines a size but no
+	 * value is processed as a request to create an
+	 * associated backing section.  The intent behind this
+	 * functionality is to provide OBJT definitions within
+	 * filters that are not ABS.  ABS symbols don't allow
+	 * copy-relocations to be established to filter OBJT
+	 * definitions.
+	 */
+	if ((ms->ms_shndx == SHN_ABS) && ms->ms_size && !ms->ms_value_set) {
+		/* Create backing section if not there */
+		if (sdp->sd_isc == NULL) {
+			Is_desc	*isp;
+
+			if (ms->ms_type == STT_OBJECT) {
+				if ((isp = ld_make_data(ofl, ms->ms_size)) ==
+				    (Is_desc *)S_ERROR)
+					return (FALSE);
+			} else {
+				if ((isp = ld_make_text(ofl, ms->ms_size)) ==
+				    (Is_desc *)S_ERROR)
+					return (FALSE);
+			}
+
+			sdp->sd_isc = isp;
+			isp->is_file = ld_map_ifl(mf);
+		}
+
+		/*
+		 * Now that backing storage has been created,
+		 * associate the symbol descriptor.  Remove the
+		 * symbols special section tag so that it will
+		 * be assigned the correct section index as part
+		 * of update symbol processing.
+		 */
+		sdp->sd_flags &= ~FLG_SY_SPECSEC;
+		ms->ms_sdflags &= ~FLG_SY_SPECSEC;
+	}
+
+	/*
+	 * Indicate the new symbols scope.  Although the
+	 * symbols st_other field will eventually be updated as
+	 * part of writing out the final symbol, update the
+	 * st_other field here to trigger better diagnostics
+	 * during symbol validation (for example, undefined
+	 * references that are defined symbolic in a mapfile).
+	 */
+	if (mv->mv_scope == FLG_SCOPE_HIDD) {
+		/*
+		 * This symbol needs to be reduced to local.
+		 */
+		if (ofl->ofl_flags & FLG_OF_REDLSYM) {
+			sdp->sd_flags |= (FLG_SY_HIDDEN | FLG_SY_ELIM);
+			sdp->sd_sym->st_other = STV_ELIMINATE;
+		} else {
+			sdp->sd_flags |= FLG_SY_HIDDEN;
+			sdp->sd_sym->st_other = STV_HIDDEN;
+		}
+	} else if (mv->mv_scope == FLG_SCOPE_ELIM) {
+		/*
+		 * This symbol needs to be eliminated.  Note,
+		 * the symbol is also tagged as local to trigger
+		 * any necessary relocation processing prior
+		 * to the symbol being eliminated.
+		 */
+		sdp->sd_flags |= (FLG_SY_HIDDEN | FLG_SY_ELIM);
+		sdp->sd_sym->st_other = STV_ELIMINATE;
+
+	} else {
+		/*
+		 * This symbol is explicitly defined to remain
+		 * global.
+		 */
+		sdp->sd_flags |= ms->ms_sdflags;
+
+		/*
+		 * Qualify any global scope.
+		 */
+		if (mv->mv_scope == FLG_SCOPE_SNGL) {
+			sdp->sd_flags |= (FLG_SY_SINGLE | FLG_SY_NDIR);
+			sdp->sd_sym->st_other = STV_SINGLETON;
+		} else if (mv->mv_scope == FLG_SCOPE_PROT) {
+			sdp->sd_flags |= FLG_SY_PROTECT;
+			sdp->sd_sym->st_other = STV_PROTECTED;
+		} else if (mv->mv_scope == FLG_SCOPE_EXPT) {
+			sdp->sd_flags |= FLG_SY_EXPORT;
+			sdp->sd_sym->st_other = STV_EXPORTED;
+		} else
+			sdp->sd_flags |= FLG_SY_DEFAULT;
+
+		/*
+		 * Record the present version index for later
+		 * potential versioning.
+		 */
+		if ((sdp->sd_aux->sa_overndx == 0) ||
+		    (sdp->sd_aux->sa_overndx == VER_NDX_GLOBAL))
+			sdp->sd_aux->sa_overndx = mv->mv_vdp->vd_ndx;
+		mv->mv_vdp->vd_flags |= FLG_VER_REFER;
+	}
+
+	conflict = NULL;
+
+	/*
+	 * Carry out some validity checks to ensure incompatible
+	 * symbol characteristics have not been defined.
+	 * These checks are carried out after symbols are added
+	 * or resolved, to catch single instance, and
+	 * multi-instance definition inconsistencies.
+	 */
+	if ((sdp->sd_flags & (FLG_SY_HIDDEN | FLG_SY_ELIM)) &&
+	    ((mv->mv_scope != FLG_SCOPE_HIDD) &&
+	    (mv->mv_scope != FLG_SCOPE_ELIM))) {
+		conflict = MSG_INTL(MSG_MAP_DIFF_SYMLCL);
+
+	} else if ((sdp->sd_flags &
+	    (FLG_SY_SINGLE | FLG_SY_EXPORT)) &&
+	    ((mv->mv_scope != FLG_SCOPE_DFLT) &&
+	    (mv->mv_scope != FLG_SCOPE_EXPT) &&
+	    (mv->mv_scope != FLG_SCOPE_SNGL))) {
+		conflict = MSG_INTL(MSG_MAP_DIFF_SYMGLOB);
+
+	} else if ((sdp->sd_flags & FLG_SY_PROTECT) &&
+	    ((mv->mv_scope != FLG_SCOPE_DFLT) &&
+	    (mv->mv_scope != FLG_SCOPE_PROT))) {
+		conflict = MSG_INTL(MSG_MAP_DIFF_SYMPROT);
+
+	} else if ((sdp->sd_flags & FLG_SY_NDIR) &&
+	    (mv->mv_scope == FLG_SCOPE_PROT)) {
+		conflict = MSG_INTL(MSG_MAP_DIFF_PROTNDIR);
+
+	} else if ((sdp->sd_flags & FLG_SY_DIR) &&
+	    (mv->mv_scope == FLG_SCOPE_SNGL)) {
+		conflict = MSG_INTL(MSG_MAP_DIFF_SNGLDIR);
+	}
+
+	if (conflict) {
+		/*
+		 * Select the conflict message from either a
+		 * single instance or multi-instance definition.
+		 */
+		if (sdp->sd_file->ifl_name == mf->mf_name) {
+			mf_fatal(mf, MSG_INTL(MSG_MAP_SYMDEF2),
+			    demangle(ms->ms_name), conflict);
+		} else {
+			mf_fatal(mf, MSG_INTL(MSG_MAP_SYMDEF1),
+			    demangle(ms->ms_name),
+			    sdp->sd_file->ifl_name, conflict);
+		}
+		mv->mv_errcnt++;
+		return (TRUE);
+	}
+
+	/*
+	 * Indicate that this symbol has been explicitly
+	 * contributed from a mapfile.
+	 */
+	sdp->sd_flags |= (FLG_SY_MAPFILE | FLG_SY_EXPDEF);
+
+	/*
+	 * If we've encountered a symbol definition simulate
+	 * that an input file has been processed - this allows
+	 * things like filters to be created purely from a
+	 * mapfile.
+	 */
+	if (ms->ms_type != STT_NOTYPE)
+		ofl->ofl_objscnt++;
+	DBG_CALL(Dbg_map_symbol(ofl, sdp));
+
+	/*
+	 * If this symbol has an associated filtee, record the
+	 * filtee string and associate the string index with the
+	 * symbol.  This is used later to associate the syminfo
+	 * information with the necessary .dynamic entry.
+	 */
+	if (ms->ms_filtee) {
+		Dfltr_desc *	dftp;
+		Sfltr_desc	sft;
+		Aliste		idx, _idx, nitems;
+
+		/*
+		 * Make sure we don't duplicate any filtee
+		 * strings, and create a new descriptor if
+		 * necessary.
+		 */
+		idx = nitems = alist_nitems(ofl->ofl_dtsfltrs);
+		for (ALIST_TRAVERSE(ofl->ofl_dtsfltrs, _idx, dftp)) {
+			if ((ms->ms_dft_flag != dftp->dft_flag) ||
+			    (strcmp(dftp->dft_str, ms->ms_filtee)))
+				continue;
+			idx = _idx;
+			break;
+		}
+		if (idx == nitems) {
+			Dfltr_desc	dft;
+
+			dft.dft_str = ms->ms_filtee;
+			dft.dft_flag = ms->ms_dft_flag;
+			dft.dft_ndx = 0;
+
+			/*
+			 * The following append puts the new
+			 * item at the offset contained in
+			 * idx, because we know idx contains
+			 * the index of the next available slot.
+			 */
+			if (alist_append(&ofl->ofl_dtsfltrs, &dft,
+			    sizeof (Dfltr_desc), AL_CNT_OFL_DTSFLTRS) == NULL)
+				return (FALSE);
+		}
+
+		/*
+		 * Create a new filter descriptor for this
+		 * symbol.
+		 */
+		sft.sft_sdp = sdp;
+		sft.sft_idx = idx;
+
+		if (alist_append(&ofl->ofl_symfltrs, &sft, sizeof (Sfltr_desc),
+		    AL_CNT_OFL_SYMFLTRS) == NULL)
+			return (FALSE);
+	}
+
+	return (TRUE);
+}
+
+/*
+ * In both the version 1 and version 2 syntaxes, a version definition
+ * can have 0 or more inherited versions following the closing '}',
+ * terminated by a ';'.
+ *
+ * Add the inherited names, and return when the terminator is seen.
+ */
+Boolean
+ld_map_sym_ver_fini(Mapfile *mf, ld_map_ver_t *mv)
+{
+	Token		tok;
+	ld_map_tkval_t	tkv;		/* Value of token */
+	Boolean		done = FALSE;
+	Conv_inv_buf_t	inv_buf;
+	const char	*name;
+	Ver_desc	*vdp;
+	Word		hash;
+
+	/*
+	 * Read version names until we encounter the ';' terminator.
+	 */
+	while (!done) {
+		switch (tok = ld_map_gettoken(mf, 0, &tkv)) {
+		case TK_ERROR:
+			return (FALSE);
+
+		case TK_STRING:
+			name = tkv.tkv_str;
+
+			/* The unnamed global scope can't inherit */
+			if (mv->mv_vdp->vd_ndx == VER_NDX_GLOBAL) {
+				mf_fatal(mf, MSG_INTL(MSG_MAP_UNEXINHERIT),
+				    name);
+				return (FALSE);
+			}
+
+			/*
+			 * Generate a new version descriptor if it doesn't
+			 * already exist.
+			 */
+			/* LINTED */
+			hash = (Word)elf_hash(name);
+			vdp = ld_vers_find(name, hash, mf->mf_ofl->ofl_verdesc);
+			if ((vdp == NULL) && ((vdp = ld_vers_desc(name, hash,
+			    &mf->mf_ofl->ofl_verdesc)) == (Ver_desc *)S_ERROR))
+				return (FALSE);
+
+			/*
+			 * Add the new version descriptor to the parent version
+			 * descriptors reference list.  Indicate the version
+			 * descriptors first reference (used for error diags
+			 * if undefined version dependencies remain).
+			 */
+			if (ld_vers_find(name, hash, mv->mv_vdp->vd_deps) ==
+			    NULL)
+				if (aplist_append(&mv->mv_vdp->vd_deps, vdp,
+				    AL_CNT_VERDESCS) == NULL)
+					return (FALSE);
+
+			if (vdp->vd_ref == NULL)
+				vdp->vd_ref = mv->mv_vdp;
+			break;
+
+		case TK_SEMICOLON:
+			done = TRUE;
+			break;
+
+		default:
+			mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_SYMEND),
+			    ld_map_tokenstr(tok, &tkv, &inv_buf));
+			return (FALSE);
+		}
+	}
+
+	return (TRUE);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/sgs/libld/common/map_v2.c	Mon Feb 22 09:19:31 2010 -0700
@@ -0,0 +1,3183 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Map file parsing, Version 2 syntax (solaris).
+ */
+#include	<stdio.h>
+#include	<unistd.h>
+#include	<ctype.h>
+#include	<sys/elf_amd64.h>   /* SHF_AMD64_LARGE */
+#include	<elfcap.h>
+#include	"msg.h"
+#include	"_libld.h"
+#include	"_map.h"
+
+/*
+ * Use a case insensitive string match when looking up capability mask
+ * values by name, and omit the AV_ prefix.
+ */
+#define	ELFCAP_STYLE ELFCAP_STYLE_LC | ELFCAP_STYLE_F_ICMP
+
+/*
+ * Signature for functions used to parse top level mapfile directives
+ */
+typedef Token (*dir_func_t)(Mapfile *mf);
+
+/*
+ * Signature for functions used to parse attribute level assignments
+ *	mf - Mapfile descriptor
+ *	eq_tok - One of the equal tokens (TK_EQUAL, TK_PLUSEQ, TK_MINUSEQ)
+ *		or TK_ERROR. See the comment for attr_fmt_t below.
+ *	uvalue - An arbitrary pointer "user value" passed by the
+ *		caller to parse_attributes() for use by the function.
+ */
+typedef Token (* attr_func_t)(Mapfile *mf, Token eq_tok, void *uvalue);
+
+/*
+ * Signature for gettoken_str() err_func argument. This is a function
+ * called to issue an appropriate error message.
+ *
+ * The gts prefix stands for "Get Token Str"
+ */
+typedef void (* gts_efunc_t)(Mapfile *mf, Token tok, ld_map_tkval_t *tkv);
+
+/*
+ * The attr_fmt_t tells parse_attributes how far to go in parsing
+ * an attribute before it calls the at_func function to take over:
+ *
+ *	ATTR_FMT_NAME - Parse the name, and immediately call the function.
+ *		This is useful in cases where there is more than
+ *		one possible syntax for a given attribute. The value of
+ *		eq_tok passed to the at_func function will be TK_ERROR,
+ *		reflecting the fact that it has no meaning in this context.
+ *
+ *	ATTR_FMT_EQ - Parse the name, and the following '=', and then call
+ *		the function. The value passed to the at_func function for
+ *		eq_tok will be TK_EQUAL.
+ *
+ *	ATTR_FMT_EQ_PEQ - Parse the name, and a following equal token which
+ *		can be '=' or '+=', and then call the function. The value
+ *		passed to the at_func function for eq_tok will be one of
+ *		TK_EQUAL, or TK_PLUSEQ.
+ *
+ *	ATTR_FMT_EQ_ALL - Parse the name, and a following equal token which
+ *		can be any of the three forms (=, +=, -=), and then call
+ *		the function. The value passed to the at_func function for
+ *		eq_tok will be one of TK_EQUAL, TK_PLUSEQ, or TK_MINUSEQ.
+ */
+typedef enum {
+	ATTR_FMT_NAME,
+	ATTR_FMT_EQ,
+	ATTR_FMT_EQ_PEQ,
+	ATTR_FMT_EQ_ALL,
+} attr_fmt_t;
+
+/*
+ * Type used to describe a set of valid attributes to parse_attributes():
+ *	at_name - Name of attribute
+ *	at_func - Function to call when attribute is recognized,
+ *	at_all_eq - True if attribute allows the '+=' and '-=' forms of
+ *		assignment token, and False to only allow '='.
+ *
+ * The array of these structs passed to parse_attributes() must be
+ * NULL terminated (the at_name field must be set to NULL).
+ */
+typedef struct {
+	const char	*at_name;	/* Name of attribute */
+	attr_func_t	at_func;	/* Function to call */
+	attr_fmt_t	at_fmt;		/* How much to parse before calling */
+					/*	at_func */
+} attr_t;
+
+/*
+ * Mapfile version and symbol state are separate but related concepts
+ * that are best represented using two different types. However, our
+ * style of passing a single uvalue via parse_attributes() makes it
+ * convenient to be able to reference them from a single address.
+ */
+typedef struct {
+	ld_map_ver_t	ss_mv;
+	ld_map_sym_t	ss_ms;
+} symbol_state_t;
+
+/*
+ * Process an expected equal operator. Deals with the fact that we
+ * have three variants.
+ *
+ * entry:
+ *	mf - Mapfile descriptor
+ *	eq_type - Types of equal operators accepted. One of ATTR_FMT_EQ,
+ *		ATTR_FMT_EQ_PEQ, or ATTR_FMT_EQ_ALL.
+ *	lhs - Name that appears on the left hand side of the expected
+ *		equal operator.
+ *
+ * exit:
+ *	Returns one of TK_EQUAL, TK_PLUSEQ, TK_MINUSEQ, or TK_ERROR.
+ */
+static Token
+gettoken_eq(Mapfile *mf, attr_fmt_t eq_type, const char *lhs)
+{
+	Token		tok;
+	ld_map_tkval_t	tkv;
+	const char	*err;
+	Conv_inv_buf_t	inv_buf;
+
+	switch (tok = ld_map_gettoken(mf, 0, &tkv)) {
+	case TK_ERROR:
+	case TK_EQUAL:
+		return (tok);
+
+	case TK_PLUSEQ:
+		switch (eq_type) {
+		case ATTR_FMT_EQ_PEQ:
+		case ATTR_FMT_EQ_ALL:
+			return (tok);
+		}
+		break;
+
+	case TK_MINUSEQ:
+		if (eq_type == ATTR_FMT_EQ_ALL)
+			return (tok);
+		break;
+	}
+
+	switch (eq_type) {
+	case ATTR_FMT_EQ:
+		err = MSG_INTL(MSG_MAP_EXP_EQ);
+		break;
+	case ATTR_FMT_EQ_PEQ:
+		err = MSG_INTL(MSG_MAP_EXP_EQ_PEQ);
+		break;
+	case ATTR_FMT_EQ_ALL:
+		err = MSG_INTL(MSG_MAP_EXP_EQ_ALL);
+		break;
+	default:
+		/*NOTREACHED*/
+		assert(0);
+	}
+	mf_fatal(mf, err, lhs, ld_map_tokenstr(tok, &tkv, &inv_buf));
+	return (TK_ERROR);
+}
+
+/*
+ * Apply one of the three equal tokens to a bitmask value
+ *
+ * entry:
+ *	dst - Address of bitmask variable to alter
+ *	eq_tok - One of TK_EQUAL, TK_PLUSEQ, TK_MINUSEQ, representing
+ *		the operation to carry out.
+ *	value - Value for right hand side
+ *
+ * exit:
+ *	The operation has been carried out:
+ *
+ *	TK_EQUAL - *dst is set to value
+ *	TK_PLUSEQ - Bits in value have been set in *dst
+ *	TK_MINUSEQ - Bits in value have been removed from *dst
+ */
+static void
+setflags_eq(Word *dst, Token eq_tok, Word value)
+{
+	switch (eq_tok) {
+	case TK_EQUAL:
+		*dst = value;
+		break;
+	case TK_PLUSEQ:
+		*dst |= value;
+		break;
+	case TK_MINUSEQ:
+		*dst &= ~value;
+		break;
+	default:
+		/*NOTREACHED*/
+		assert(0);
+	}
+}
+
+/*
+ * Apply one of the three equal tokens to a capabilities CapMask.
+ *
+ * entry:
+ *	mf - Mapfile descriptor
+ *	capmask - Address of CapMask variable to alter
+ *	eq_tok - One of TK_EQUAL, TK_PLUSEQ, TK_MINUSEQ, representing
+ *		the operation to carry out.
+ *	type - Capability type (CA_SUNW_*)
+ *	value - Value for right hand side
+ *	title - True if a title is needed, False otherwise.
+ *
+ * exit:
+ *	On success, returns TRUE (1), otherwise FALSE (0)
+ */
+static Boolean
+set_capmask(Mapfile *mf, CapMask *capmask, Token eq_tok,
+    Word type, elfcap_mask_t value, Boolean title)
+{
+	if (title)
+		DBG_CALL(Dbg_cap_mapfile_title(mf->mf_ofl->ofl_lml,
+		    mf->mf_lineno));
+	DBG_CALL(Dbg_cap_entry2(mf->mf_ofl->ofl_lml, DBG_STATE_CURRENT,
+	    type, capmask, ld_targ.t_m.m_mach));
+
+	switch (eq_tok) {
+	case TK_EQUAL:
+		capmask->cm_value = value;
+		capmask->cm_exclude = 0;
+		ld_map_cap_set_ovflag(mf, type);
+		DBG_CALL(Dbg_cap_entry2(mf->mf_ofl->ofl_lml,
+		    DBG_STATE_RESET, type, capmask, ld_targ.t_m.m_mach));
+		break;
+	case TK_PLUSEQ:
+		DBG_CALL(Dbg_cap_entry(mf->mf_ofl->ofl_lml, DBG_STATE_ADD,
+		    type, value, ld_targ.t_m.m_mach));
+		capmask->cm_value |= value;
+		capmask->cm_exclude &= ~value;
+		break;
+	case TK_MINUSEQ:
+		DBG_CALL(Dbg_cap_entry(mf->mf_ofl->ofl_lml, DBG_STATE_EXCLUDE,
+		    type, value, ld_targ.t_m.m_mach));
+		capmask->cm_value &= ~value;
+		capmask->cm_exclude |= value;
+		break;
+	default:
+		/*NOTREACHED*/
+		assert(0);
+	}
+
+	/* Sanity check the resulting bits */
+	if (!ld_map_cap_sanitize(mf, type, capmask))
+		return (FALSE);
+
+	/* Report the final configuration */
+	DBG_CALL(Dbg_cap_entry2(mf->mf_ofl->ofl_lml,
+	    DBG_STATE_RESOLVED, type, capmask, ld_targ.t_m.m_mach));
+
+	return (TRUE);
+}
+
+/*
+ * Process the next token, which is expected to start an optional
+ * nesting of attributes (';' or '{').
+ *
+ * entry:
+ *	mf - Mapfile descriptor
+ *	lhs - Name of the directive or attribute being processed.
+ *
+ * exit:
+ *	Returns TK_SEMICOLON or TK_LEFTBKT for success, and TK_ERROR otherwise.
+ */
+static Token
+gettoken_optattr(Mapfile *mf, const char *lhs)
+{
+	Token		tok;
+	ld_map_tkval_t	tkv;
+	Conv_inv_buf_t	inv_buf;
+
+	switch (tok = ld_map_gettoken(mf, 0, &tkv)) {
+	case TK_ERROR:
+	case TK_SEMICOLON:
+	case TK_LEFTBKT:
+		return (tok);
+	}
+
+	mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_SEMLBKT), lhs,
+	    ld_map_tokenstr(tok, &tkv, &inv_buf));
+	return (TK_ERROR);
+}
+
+/*
+ * Process the next token, which is expected to be a line terminator
+ * (';' or '}').
+ *
+ * entry:
+ *	mf - Mapfile descriptor
+ *	lhs - Name of the directive or attribute being processed.
+ *
+ * exit:
+ *	Returns TK_SEMICOLON or TK_RIGHTBKT for success, and TK_ERROR otherwise.
+ */
+static Token
+gettoken_term(Mapfile *mf, const char *lhs)
+{
+	Token		tok;
+	ld_map_tkval_t	tkv;
+	Conv_inv_buf_t	inv_buf;
+
+	switch (tok = ld_map_gettoken(mf, 0, &tkv)) {
+	case TK_ERROR:
+	case TK_SEMICOLON:
+	case TK_RIGHTBKT:
+		return (tok);
+	}
+
+	mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_SEMRBKT), lhs,
+	    ld_map_tokenstr(tok, &tkv, &inv_buf));
+	return (TK_ERROR);
+}
+
+/*
+ * Process the next token, which is expected to be a semicolon.
+ *
+ * entry:
+ *	mf - Mapfile descriptor
+ *	lhs - Name of the directive or attribute being processed.
+ *
+ * exit:
+ *	Returns TK_SEMICOLON for success, and TK_ERROR otherwise.
+ */
+static Token
+gettoken_semicolon(Mapfile *mf, const char *lhs)
+{
+	Token		tok;
+	ld_map_tkval_t	tkv;
+	Conv_inv_buf_t	inv_buf;
+
+	switch (tok = ld_map_gettoken(mf, 0, &tkv)) {
+	case TK_ERROR:
+	case TK_SEMICOLON:
+		return (tok);
+	}
+
+	mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_SEM), lhs,
+	    ld_map_tokenstr(tok, &tkv, &inv_buf));
+	return (TK_ERROR);
+}
+
+/*
+ * Process the next token, which is expected to be a '{'
+ *
+ * entry:
+ *	mf - Mapfile descriptor
+ *	lhs - Name of the item directly to the left of the expected left
+ *		bracket.
+ *
+ * exit:
+ *	Returns TK_LEFTBKT for success, and TK_ERROR otherwise.
+ */
+static Token
+gettoken_leftbkt(Mapfile *mf, const char *lhs)
+{
+	Token		tok;
+	ld_map_tkval_t	tkv;
+	Conv_inv_buf_t	inv_buf;
+
+	switch (tok = ld_map_gettoken(mf, 0, &tkv)) {
+	case TK_ERROR:
+	case TK_LEFTBKT:
+		return (tok);
+	}
+
+	mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_LBKT), lhs,
+	    ld_map_tokenstr(tok, &tkv, &inv_buf));
+	return (TK_ERROR);
+}
+
+/*
+ * Process the next token, which is expected to be an integer
+ *
+ * entry:
+ *	mf - Mapfile descriptor
+ *	lhs - Name of the directive or attribute being processed.
+ *	tkv - Address of token value struct to be filled in
+ *
+ * exit:
+ *	Updates *tkv and returns TK_INT for success, TK_ERROR otherwise.
+ */
+static Token
+gettoken_int(Mapfile *mf, const char *lhs, ld_map_tkval_t *tkv)
+{
+	Token		tok;
+	Conv_inv_buf_t	inv_buf;
+
+	switch (tok = ld_map_gettoken(mf, 0, tkv)) {
+	case TK_ERROR:
+	case TK_INT:
+		return (tok);
+	}
+
+	mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_INT), lhs,
+	    ld_map_tokenstr(tok, tkv, &inv_buf));
+	return (TK_ERROR);
+}
+
+/*
+ * Process the next token, which is expected to be a string
+ *
+ * entry:
+ *	mf - Mapfile descriptor
+ *	lhs - Name of the directive or attribute being processed.
+ *	tkv - Address of token value struct to be filled in
+ *	err_func - Function to call if an error occurs
+ *
+ * exit:
+ *	Updates *tkv and returns TK_STRING for success. Calls the
+ *	supplied err_func function and returns TK_ERROR otherwise.
+ */
+static Token
+gettoken_str(Mapfile *mf, int flags, ld_map_tkval_t *tkv, gts_efunc_t efunc)
+{
+	Token		tok;
+
+	switch (tok = ld_map_gettoken(mf, flags, tkv)) {
+	case TK_ERROR:
+	case TK_STRING:
+		return (tok);
+	}
+
+	/* User supplied function reports the error */
+	(* efunc)(mf, tok, tkv);
+
+	return (TK_ERROR);
+}
+
+/*
+ * Given a construct of the following common form:
+ *
+ *	item_name {
+ *		attribute = ...;
+ *		...
+ *	}
+ *
+ * where the caller has detected the item_name and opening bracket,
+ * parse the construct and call the attribute functions for each
+ * attribute detected, stopping when the closing '}' is seen.
+ *
+ * entry:
+ *	mf - Mapfile descriptor
+ *	item_name - Already detected name of item for which attributes
+ *		are being parsed.
+ *	attr_list - NULL terminated array of attr_t structures describing the
+ *		valid attributes for the item.
+ *	expect_str - Comma separated string listing the names of expected
+ *		attributes.
+ *	uvalue - User value, passed to the attribute functions without
+ *		examination by parse_attributes(), usable for maintaining
+ *		shared state between the caller and the functions.
+ *
+ * exit:
+ *	parse_attributes() reads the attribute name and equality token,
+ *	and then calls the attribute function given by the attr_list array
+ *	to handle everything up to and including the terminating ';'.
+ *	This continues until the closing '}' is seen.
+ *
+ *	If everything is successful, TK_RIGHTBKT is returned. Otherwise,
+ *	a suitable error is issued and TK_ERROR is returned.
+ */
+static Token
+parse_attributes(Mapfile *mf, const char *item_name, attr_t *attr_list,
+    size_t attr_list_bufsize, void *uvalue)
+{
+	attr_t		*attr;
+	Token		tok, op_tok;
+	ld_map_tkval_t	tkv;
+	int		done;
+	int		attr_cnt = 0;
+	Conv_inv_buf_t	inv_buf;
+
+	/* Read attributes until the closing '}' is seen */
+	for (done = 0; done == 0; ) {
+		switch (tok = ld_map_gettoken(mf, TK_F_KEYWORD, &tkv)) {
+		case TK_ERROR:
+			return (TK_ERROR);
+
+		case TK_STRING:
+			attr = ld_map_kwfind(tkv.tkv_str, attr_list,
+			    SGSOFFSETOF(attr_t, at_name), sizeof (attr[0]));
+			if (attr == NULL)
+				goto bad_attr;
+
+			/*
+			 * Depending on the value of at_fmt, there are
+			 * fout different actions to take:
+			 *	ATTR_FMT_NAME - Call at_func function
+			 *	ATTR_FMT_EQ - Read and verify a TK_EQUAL
+			 *	ATTR_FMT_EQ_PEQ - Read and verify a TK_EQUAL
+			 *		or TK_PLUSEQ.
+			 *	ATTR_FMT_EQ_ALL - Read/Verify one of the
+			 *		three possible equal tokens
+			 *		(TK_EQUAL, TK_PLUSEQ, TK_MINUSEQ).
+			 */
+			if (attr->at_fmt == ATTR_FMT_NAME) {
+				/* Arbitrary value to pass to at_func */
+				op_tok = TK_ERROR;
+			} else {
+				/* Read/Verify appropriate equal operator */
+				op_tok = gettoken_eq(mf, attr->at_fmt,
+				    attr->at_name);
+				if (op_tok == TK_ERROR)
+					return (TK_ERROR);
+			}
+
+			/* Call the associated function */
+			switch (tok = attr->at_func(mf, op_tok, uvalue)) {
+			default:
+				return (TK_ERROR);
+			case TK_SEMICOLON:
+				break;
+			case TK_RIGHTBKT:
+				done = 1;
+				break;
+			}
+			attr_cnt++;
+			break;
+
+		case TK_RIGHTBKT:
+			done = 1;
+			break;
+
+		case TK_SEMICOLON:
+			break;		/* Ignore empty statement */
+
+		default:
+		bad_attr:
+			{
+				char buf[attr_list_bufsize];
+
+				mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_ATTR),
+				    ld_map_kwnames(attr_list,
+				    SGSOFFSETOF(attr_t, at_name),
+				    sizeof (attr[0]), buf, attr_list_bufsize),
+				    ld_map_tokenstr(tok, &tkv, &inv_buf));
+			}
+			return (TK_ERROR);
+		}
+	}
+
+	/* Make sure there was at least one attribute between the {} brackets */
+	if (attr_cnt == 0) {
+		mf_fatal(mf, MSG_INTL(MSG_MAP_NOATTR), item_name);
+		return (TK_ERROR);
+	}
+
+	return (tok);
+}
+
+/*
+ * Read whitespace delimited segment flags from the input and convert into
+ * bitmask of PF_ values they represent. Flags are terminated by a semicolon
+ * or right bracket.
+ *
+ * entry:
+ *	mf - Mapfile descriptor
+ *	flags - Address of variable to be set to resulting flags value
+ *
+ * exit:
+ *	Returns the terminator token (TK_SEMICOLON or TK_LEFTBKT) on success,
+ *	and TK_ERROR otherwise.
+ */
+static Token
+parse_segment_flags(Mapfile *mf, Xword *flags)
+{
+	/*
+	 * Map flag names to their values. Since DATA and STACK have
+	 * platform dependent values, we have to determine them at runtime.
+	 * We indicate this by setting the top bit.
+	 */
+#define	PF_DATA		0x80000000
+#define	PF_STACK	0x80000001
+	typedef struct {
+		const char	*name;
+		Word		value;
+	} segflag_t;
+	static segflag_t flag_list[] = {
+		{ MSG_ORIG(MSG_MAPKW_DATA),	PF_DATA },
+		{ MSG_ORIG(MSG_MAPKW_EXECUTE),	PF_X },
+		{ MSG_ORIG(MSG_MAPKW_READ),	PF_R },
+		{ MSG_ORIG(MSG_MAPKW_STACK),	PF_STACK },
+		{ MSG_ORIG(MSG_MAPKW_WRITE),	PF_W },
+
+		/* List must be null terminated */
+		{ 0 },
+	};
+
+	/*
+	 * Size of buffer needed to format the names in flag_list[]. Must
+	 * be kept in sync with flag_list.
+	 */
+	static size_t	flag_list_bufsize =
+	    KW_NAME_SIZE(MSG_MAPKW_DATA) +
+	    KW_NAME_SIZE(MSG_MAPKW_EXECUTE) +
+	    KW_NAME_SIZE(MSG_MAPKW_READ) +
+	    KW_NAME_SIZE(MSG_MAPKW_STACK) +
+	    KW_NAME_SIZE(MSG_MAPKW_WRITE);
+
+	Token		tok;
+	ld_map_tkval_t	tkv;
+	segflag_t	*flag;
+	size_t		cnt = 0;
+	int		done;
+	Conv_inv_buf_t	inv_buf;
+
+	*flags = 0;
+
+	/* Read attributes until the ';' terminator is seen */
+	for (done = 0; done == 0; ) {
+		switch (tok = ld_map_gettoken(mf, TK_F_KEYWORD, &tkv)) {
+		case TK_ERROR:
+			return (TK_ERROR);
+
+		case TK_STRING:
+			flag = ld_map_kwfind(tkv.tkv_str, flag_list,
+			    SGSOFFSETOF(segflag_t, name),
+			    sizeof (flag_list[0]));
+			if (flag == NULL)
+				goto bad_flag;
+			switch (flag->value) {
+			case PF_DATA:
+				*flags |= ld_targ.t_m.m_dataseg_perm;
+				break;
+			case PF_STACK:
+				*flags |= ld_targ.t_m.m_stack_perm;
+				break;
+			default:
+				*flags |= flag->value;
+			}
+			cnt++;
+			break;
+
+		case TK_INT:
+			/*
+			 * Accept 0 for notational convenience, but refuse
+			 * any other value. Note that we don't actually have
+			 * to set the flags to 0 here, because there are
+			 * already initialized to that before the main loop.
+			 */
+			if (tkv.tkv_int.tkvi_value != 0)
+				goto bad_flag;
+			cnt++;
+			break;
+
+		case TK_SEMICOLON:
+		case TK_RIGHTBKT:
+			done = 1;
+			break;
+
+		default:
+		bad_flag:
+			{
+				char buf[flag_list_bufsize];
+
+				mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_SEGFLAG),
+				    ld_map_kwnames(flag_list,
+				    SGSOFFSETOF(segflag_t, name),
+				    sizeof (flag[0]), buf, flag_list_bufsize),
+				    ld_map_tokenstr(tok, &tkv, &inv_buf));
+			}
+			return (TK_ERROR);
+		}
+	}
+
+	/* Make sure there was at least one flag */
+	if (cnt == 0) {
+		mf_fatal(mf, MSG_INTL(MSG_MAP_NOVALUES),
+		    MSG_ORIG(MSG_MAPKW_FLAGS));
+		return (TK_ERROR);
+	}
+
+	return (tok);
+
+#undef PF_DATA
+#undef PF_STACK
+}
+
+
+/*
+ * Parse one of the capabilities attributes that corresponds directly
+ * to a capabilities bitmask value (HW_xxx, SF_xxx). Values can be
+ * integers, or symbolic names that correspond to the capabilities mask
+ * in question.
+ *
+ * entry:
+ *	mf - Mapfile descriptor
+ *	eq_tok - One of TK_EQUAL, TK_PLUSEQ, TK_MINUSEQ, representing
+ *		the operation to carry out.
+ *	capmask - CapMask from output descriptor for capability being processed.
+ *	type - Capability type (CA_SUNW_*)
+ *	elfcap_from_str_func - pointer to elfcap-string-to-value function
+ *		for capability being processed.
+ *
+ * exit:
+ *	Returns TK_SEMICOLON or TK_RIGHTBKT for success, and TK_ERROR otherwise.
+ */
+static Token
+parse_cap_mask(Mapfile *mf, Token eq_tok, CapMask *capmask,
+    Word type, elfcap_from_str_func_t *elfcap_from_str_func)
+{
+	int		done;
+	Token		tok;
+	ld_map_tkval_t	tkv;
+	Conv_inv_buf_t	inv_buf;
+	elfcap_mask_t	value = 0;
+	uint64_t	v;
+
+	for (done = 0; done == 0; ) {
+		switch (tok = ld_map_gettoken(mf, TK_F_KEYWORD, &tkv)) {
+		case TK_ERROR:
+			return (TK_ERROR);
+
+		case TK_STRING:
+			if ((v = (* elfcap_from_str_func)(ELFCAP_STYLE,
+			    tkv.tkv_str, ld_targ.t_m.m_mach)) != 0) {
+				value |= v;
+				break;
+			}
+			goto bad_flag;
+
+		case TK_INT:
+			value |= tkv.tkv_int.tkvi_value;
+			break;
+
+		case TK_SEMICOLON:
+		case TK_RIGHTBKT:
+			done = 1;
+			break;
+
+		default:
+		bad_flag:
+			mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_CAPMASK),
+			    ld_map_tokenstr(tok, &tkv, &inv_buf));
+			return (TK_ERROR);
+		}
+	}
+
+	if (!set_capmask(mf, capmask, eq_tok, type, value, TRUE))
+		return (TK_ERROR);
+	return (tok);
+}
+
+/*
+ * XXXRIEXXX
+ *
+ * This routine is the name version of parse_cap_mask. You need to
+ * add the argument that corresponds to capmask. Also, remove the
+ * ARGSUSED lint comment.
+ */
+/*
+ * Parse one of the capabilities attributes that manages lists of names
+ * (CA_SUNW_PLATFORM, CA_SUNW_MACHINE).
+ *
+ * entry:
+ *	mf - Mapfile descriptor
+ *	eq_tok - One of TK_EQUAL, TK_PLUSEQ, TK_MINUSEQ, representing
+ *		the operation to carry out.
+ *	type - Capability type (CA_SUNW_*)
+ *
+ * exit:
+ *	Returns TK_SEMICOLON or TK_RIGHTBKT for success, and TK_ERROR otherwise.
+ */
+/*ARGSUSED*/
+static Token
+parse_cap_list(Mapfile *mf, Token eq_tok, Word type)
+{
+	int		done;
+	Token		tok;
+	ld_map_tkval_t	tkv;
+	Conv_inv_buf_t	inv_buf;
+
+	/*
+	 * XXXRIEXXX
+	 *
+	 * If eq_tok is TK_EQUAL, you must clear the value and exclude lists,
+	 * and set the 'override' bit so that the capability from the input
+	 * objects is ignored. See set_capmask() for the logic used for
+	 * bitmasks.
+	 */
+	for (done = 0; done == 0; ) {
+		switch (tok = ld_map_gettoken(mf, 0, &tkv)) {
+		case TK_ERROR:
+			return (TK_ERROR);
+
+		case TK_STRING:
+			/*
+			 * XXXRIEXXX
+			 *
+			 * The name is in tkv.tkv_str. If eq_tok is TK_MINUSEQ,
+			 * you add the name to the exclude list, and remove it
+			 * from the value list. Otherwise, you add it to the
+			 * value list and remove it from the exclude list.
+			 */
+			break;
+
+		case TK_SEMICOLON:
+		case TK_RIGHTBKT:
+			done = 1;
+			break;
+
+		default:
+			mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_CAPNAME),
+			    ld_map_tokenstr(tok, &tkv, &inv_buf));
+			return (TK_ERROR);
+		}
+	}
+
+	return (tok);
+}
+
+/*
+ * CAPABILITY [capid] { HW = hwcap_flags...
+ * -------------------------^
+ */
+/* ARGSUSED 2 */
+static Token
+at_cap_hw(Mapfile *mf, Token eq_tok, void *uvalue)
+{
+	int		done;
+	Token		tok;
+	ld_map_tkval_t	tkv;
+	Conv_inv_buf_t	inv_buf;
+	Word		hw1 = 0, hw2 = 0;
+	uint64_t	v;
+
+	for (done = 0; done == 0; ) {
+		switch (tok = ld_map_gettoken(mf, TK_F_KEYWORD, &tkv)) {
+		case TK_ERROR:
+			return (TK_ERROR);
+
+		case TK_STRING:
+			if ((v = elfcap_hw1_from_str(ELFCAP_STYLE,
+			    tkv.tkv_str, ld_targ.t_m.m_mach)) != 0) {
+				hw1 |= v;
+				break;
+			}
+			if ((v = elfcap_hw2_from_str(ELFCAP_STYLE,
+			    tkv.tkv_str, ld_targ.t_m.m_mach)) != 0) {
+				hw2 |= v;
+				break;
+			}
+			goto bad_flag;
+
+		case TK_SEMICOLON:
+		case TK_RIGHTBKT:
+			done = 1;
+			break;
+
+		default:
+		bad_flag:
+			mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_CAPHW),
+			    ld_map_tokenstr(tok, &tkv, &inv_buf));
+			return (TK_ERROR);
+		}
+	}
+
+	if (!set_capmask(mf, &mf->mf_ofl->ofl_ocapset.c_hw_1, eq_tok,
+	    CA_SUNW_HW_1, hw1, TRUE))
+		return (TK_ERROR);
+	if (!set_capmask(mf, &mf->mf_ofl->ofl_ocapset.c_hw_2, eq_tok,
+	    CA_SUNW_HW_2, hw2, FALSE))
+		return (TK_ERROR);
+	return (tok);
+}
+
+/*
+ * CAPABILITY [capid] { HW_1 = value ;
+ * ---------------------------^
+ */
+/* ARGSUSED 2 */
+static Token
+at_cap_hw_1(Mapfile *mf, Token eq_tok, void *uvalue)
+{
+	return (parse_cap_mask(mf, eq_tok, &mf->mf_ofl->ofl_ocapset.c_hw_1,
+	    CA_SUNW_HW_1, elfcap_hw1_from_str));
+}
+
+/*
+ * CAPABILITY [capid] { HW_2 = value ;
+ * ---------------------------^
+ */
+/* ARGSUSED 2 */
+static Token
+at_cap_hw_2(Mapfile *mf, Token eq_tok, void *uvalue)
+{
+	return (parse_cap_mask(mf, eq_tok, &mf->mf_ofl->ofl_ocapset.c_hw_2,
+	    CA_SUNW_HW_2, elfcap_hw2_from_str));
+}
+
+/*
+ * CAPABILITY [capid] { SF = sfcap_flags...
+ * -------------------------^
+ */
+/* ARGSUSED 2 */
+static Token
+at_cap_sf(Mapfile *mf, Token eq_tok, void *uvalue)
+{
+	int		done;
+	Token		tok;
+	ld_map_tkval_t	tkv;
+	Conv_inv_buf_t	inv_buf;
+	Word		sf1 = 0;
+	uint64_t	v;
+
+	for (done = 0; done == 0; ) {
+		switch (tok = ld_map_gettoken(mf, TK_F_KEYWORD, &tkv)) {
+		case TK_ERROR:
+			return (TK_ERROR);
+
+		case TK_STRING:
+			if ((v = elfcap_sf1_from_str(ELFCAP_STYLE,
+			    tkv.tkv_str, ld_targ.t_m.m_mach)) != 0) {
+				sf1 |= v;
+				break;
+			}
+			goto bad_flag;
+
+		case TK_SEMICOLON:
+		case TK_RIGHTBKT:
+			done = 1;
+			break;
+
+		default:
+		bad_flag:
+			mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_CAPSF),
+			    ld_map_tokenstr(tok, &tkv, &inv_buf));
+			return (TK_ERROR);
+		}
+	}
+
+	if (!set_capmask(mf, &mf->mf_ofl->ofl_ocapset.c_sf_1, eq_tok,
+	    CA_SUNW_SF_1, sf1, TRUE))
+		return (TK_ERROR);
+
+	return (tok);
+}
+
+/*
+ * CAPABILITY [capid] { SF_1 = value ;
+ * ---------------------------^
+ */
+/* ARGSUSED 2 */
+static Token
+at_cap_sf_1(Mapfile *mf, Token eq_tok, void *uvalue)
+{
+	return (parse_cap_mask(mf, eq_tok, &mf->mf_ofl->ofl_ocapset.c_sf_1,
+	    CA_SUNW_SF_1, elfcap_sf1_from_str));
+}
+
+/*
+ * CAPABILITY [capid] { MACHINE = value ;
+ * ------------------------------^
+ */
+/* ARGSUSED 2 */
+static Token
+at_cap_mach(Mapfile *mf, Token eq_tok, void *uvalue)
+{
+	/*
+	 * XXXRIEXXX
+	 *
+	 * Add the missing argument, and replace the 0 with
+	 * CA_SUNW_MACH.
+	 */
+	return (parse_cap_list(mf, eq_tok, /* cap-list-goes-here, */
+	    /* CA_SUNW_MACH */0));
+}
+
+/*
+ * CAPABILITY [capid] { PLATFORM = value ;
+ * -------------------------------^
+ */
+/* ARGSUSED 2 */
+static Token
+at_cap_plat(Mapfile *mf, Token eq_tok, void *uvalue)
+{
+	/*
+	 * XXXRIEXXX
+	 *
+	 * Add the missing argument, and replace the 0 with
+	 * CA_SUNW_PLAT.
+	 */
+	return (parse_cap_list(mf, eq_tok, /* cap-list-goes-here, */
+	    /* CA_SUNW_PLAT */0));
+}
+
+/*
+ * Top Level Directive:
+ *
+ * CAPABILITY [capid] { ...
+ * ----------^
+ */
+static Token
+dir_capability(Mapfile *mf)
+{
+	/* CAPABILITY attributes */
+	static attr_t attr_list[] = {
+		{ MSG_ORIG(MSG_MAPKW_HW),	at_cap_hw, ATTR_FMT_EQ_ALL },
+		{ MSG_ORIG(MSG_MAPKW_HW_1),	at_cap_hw_1, ATTR_FMT_EQ_ALL },
+		{ MSG_ORIG(MSG_MAPKW_HW_2),	at_cap_hw_2, ATTR_FMT_EQ_ALL },
+
+		{ MSG_ORIG(MSG_MAPKW_MACHINE),	at_cap_mach, ATTR_FMT_EQ_ALL },
+		{ MSG_ORIG(MSG_MAPKW_PLATFORM),	at_cap_plat, ATTR_FMT_EQ_ALL },
+
+		{ MSG_ORIG(MSG_MAPKW_SF),	at_cap_sf, ATTR_FMT_EQ_ALL },
+		{ MSG_ORIG(MSG_MAPKW_SF_1),	at_cap_sf_1, ATTR_FMT_EQ_ALL },
+		/* List must be null terminated */
+		{ 0 }
+	};
+
+	/*
+	 * Size of buffer needed to format the names in attr_list[]. Must
+	 * be kept in sync with attr_list.
+	 */
+	static size_t	attr_list_bufsize =
+	    KW_NAME_SIZE(MSG_MAPKW_HW) +
+	    KW_NAME_SIZE(MSG_MAPKW_HW_1) +
+	    KW_NAME_SIZE(MSG_MAPKW_HW_2) +
+	    KW_NAME_SIZE(MSG_MAPKW_MACHINE) +
+	    KW_NAME_SIZE(MSG_MAPKW_PLATFORM) +
+	    KW_NAME_SIZE(MSG_MAPKW_SF) +
+	    KW_NAME_SIZE(MSG_MAPKW_SF_1);
+
+	const char	*capid = NULL;
+	Token		tok;
+	ld_map_tkval_t	tkv;
+	Conv_inv_buf_t	inv_buf;
+
+	/*
+	 * The first token can be one of:
+	 * -	An opening '{'
+	 * -	A name, followed by a '{', or a ';'.
+	 * Read this initial sequence.
+	 */
+
+	switch (tok = ld_map_gettoken(mf, 0, &tkv)) {
+	case TK_ERROR:
+		return (TK_ERROR);
+
+	case TK_STRING:
+		/*
+		 * XXXRIEXXX
+		 *
+		 * The ID name is in tkv.tkv_str. It needs to be saved,
+		 * and eventually converted into a CA_SUNW_ID entry.
+		 */
+		capid = tkv.tkv_str;
+
+		/*
+		 * The name can be followed by an opening '{', or a
+		 * terminating ';'
+		 */
+		switch (tok = gettoken_optattr(mf, capid)) {
+		case TK_SEMICOLON:
+			return (TK_SEMICOLON);
+		case TK_LEFTBKT:
+			break;
+		default:
+			return (TK_ERROR);
+		}
+		break;
+
+	case TK_LEFTBKT:
+		/* Directive has no capid, but does supply attributes */
+		break;
+
+	default:
+		mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_CAPID),
+		    MSG_ORIG(MSG_MAPKW_CAPABILITY),
+		    ld_map_tokenstr(tok, &tkv, &inv_buf));
+		return (TK_ERROR);
+	}
+
+	/* Parse the attributes */
+	if (parse_attributes(mf, MSG_ORIG(MSG_MAPKW_CAPABILITY),
+	    attr_list, attr_list_bufsize, NULL) == TK_ERROR)
+		return (TK_ERROR);
+
+	/* Terminating ';' */
+	return (gettoken_semicolon(mf, MSG_ORIG(MSG_MAPKW_CAPABILITY)));
+}
+
+/*
+ * at_dv_allow(): Value for ALLOW= is not a version string
+ */
+static void
+gts_efunc_at_dv_allow(Mapfile *mf, Token tok, ld_map_tkval_t *tkv)
+{
+	Conv_inv_buf_t	inv_buf;
+
+	mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_VERSION),
+	    MSG_ORIG(MSG_MAPKW_ALLOW), ld_map_tokenstr(tok, tkv, &inv_buf));
+}
+
+/*
+ * DEPEND_VERSIONS object_name { ALLOW = version
+ * -------------------------------------^
+ */
+/* ARGSUSED 1 */
+static Token
+at_dv_allow(Mapfile *mf, Token eq_tok, void *uvalue)
+{
+	ld_map_tkval_t	tkv;
+
+	if (gettoken_str(mf, 0, &tkv, gts_efunc_at_dv_allow) == TK_ERROR)
+		return (TK_ERROR);
+
+	/* Enter the version. uvalue points at the Sdf_desc descriptor */
+	if (!ld_map_dv_entry(mf, uvalue, FALSE, tkv.tkv_str))
+		return (TK_ERROR);
+
+	/* terminator */
+	return (gettoken_term(mf, MSG_ORIG(MSG_MAPKW_ALLOW)));
+}
+
+/*
+ * at_dv_allow(): Value for REQUIRE= is not a version string
+ */
+static void
+gts_efunc_at_dv_require(Mapfile *mf, Token tok, ld_map_tkval_t *tkv)
+{
+	Conv_inv_buf_t	inv_buf;
+
+	mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_VERSION),
+	    MSG_ORIG(MSG_MAPKW_REQUIRE), ld_map_tokenstr(tok, tkv, &inv_buf));
+}
+
+/*
+ * DEPEND_VERSIONS object_name { REQURE = version
+ * --------------------------------------^
+ */
+/* ARGSUSED 1 */
+static Token
+at_dv_require(Mapfile *mf, Token eq_tok, void *uvalue)
+{
+	ld_map_tkval_t	tkv;
+
+	/* version_name */
+	if (gettoken_str(mf, 0, &tkv, gts_efunc_at_dv_require) == TK_ERROR)
+		return (TK_ERROR);
+
+	/* Enter the version. uvalue points at the Sdf_desc descriptor */
+	if (!ld_map_dv_entry(mf, uvalue, TRUE, tkv.tkv_str))
+		return (TK_ERROR);
+
+	/* terminator */
+	return (gettoken_term(mf, MSG_ORIG(MSG_MAPKW_REQUIRE)));
+}
+
+/*
+ * dir_depend_versions(): Expected object name is not present
+ */
+static void
+gts_efunc_dir_depend_versions(Mapfile *mf, Token tok, ld_map_tkval_t *tkv)
+{
+	Conv_inv_buf_t	inv_buf;
+
+	mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_OBJNAM),
+	    MSG_ORIG(MSG_MAPKW_DEPEND_VERSIONS),
+	    ld_map_tokenstr(tok, tkv, &inv_buf));
+}
+
+/*
+ * Top Level Directive:
+ *
+ * DEPEND_VERSIONS object_name { ATTR = ...
+ * ---------------^
+ */
+static Token
+dir_depend_versions(Mapfile *mf)
+{
+	/* DEPEND_VERSIONS attributes */
+	static attr_t attr_list[] = {
+		{ MSG_ORIG(MSG_MAPKW_ALLOW),	at_dv_allow,	ATTR_FMT_EQ },
+		{ MSG_ORIG(MSG_MAPKW_REQUIRE),	at_dv_require,	ATTR_FMT_EQ },
+
+		/* List must be null terminated */
+		{ 0 }
+	};
+
+	/*
+	 * Size of buffer needed to format the names in attr_list[]. Must
+	 * be kept in sync with attr_list.
+	 */
+	static size_t	attr_list_bufsize =
+	    KW_NAME_SIZE(MSG_MAPKW_ALLOW) +
+	    KW_NAME_SIZE(MSG_MAPKW_REQUIRE);
+
+	ld_map_tkval_t	tkv;
+	Sdf_desc	*sdf;
+
+	/* object_name */
+	if (gettoken_str(mf, 0, &tkv, gts_efunc_dir_depend_versions) ==
+	    TK_ERROR)
+		return (TK_ERROR);
+
+	/* Get descriptor for dependency */
+	if ((sdf = ld_map_dv(mf, tkv.tkv_str)) == NULL)
+		return (TK_ERROR);
+
+	/* Opening '{' token */
+	if (gettoken_leftbkt(mf, tkv.tkv_str) == TK_ERROR)
+		return (TK_ERROR);
+
+	/* Parse the attributes */
+	if (parse_attributes(mf, MSG_ORIG(MSG_MAPKW_DEPEND_VERSIONS),
+	    attr_list, attr_list_bufsize, sdf) == TK_ERROR)
+		return (TK_ERROR);
+
+	/* Terminating ';' */
+	return (gettoken_semicolon(mf, MSG_ORIG(MSG_MAPKW_DEPEND_VERSIONS)));
+}
+
+/*
+ * Top Level Directive:
+ *
+ * HDR_NOALLOC ;
+ * -----------^
+ */
+static Token
+dir_hdr_noalloc(Mapfile *mf)
+{
+	mf->mf_ofl->ofl_dtflags_1 |= DF_1_NOHDR;
+	DBG_CALL(Dbg_map_hdr_noalloc(mf->mf_ofl->ofl_lml, mf->mf_lineno));
+
+	/* ';' terminator token */
+	return (gettoken_semicolon(mf, MSG_ORIG(MSG_MAPKW_HDR_NOALLOC)));
+}
+
+/*
+ * Top Level Directive:
+ *
+ * PHDR_ADD_NULL = cnt ;
+ * -------------^
+ */
+static Token
+dir_phdr_add_null(Mapfile *mf)
+{
+	Sg_desc		*sgp;
+	ld_map_tkval_t	tkv;		/* Value of token */
+
+	/* '=' token */
+	if (gettoken_eq(mf, ATTR_FMT_EQ,
+	    MSG_ORIG(MSG_MAPKW_PHDR_ADD_NULL)) == TK_ERROR)
+		return (TK_ERROR);
+
+	/* integer token */
+	if (gettoken_int(mf, MSG_ORIG(MSG_MAPKW_PHDR_ADD_NULL), &tkv) ==
+	    TK_ERROR)
+		return (TK_ERROR);
+
+	while (tkv.tkv_int.tkvi_value-- > 0) {
+		if ((sgp = ld_map_seg_alloc(NULL, PT_NULL,
+		    FLG_SG_P_TYPE | FLG_SG_EMPTY)) == NULL)
+			return (TK_ERROR);
+		if (ld_map_seg_insert(mf, DBG_STATE_NEW, sgp, 0) ==
+		    SEG_INS_FAIL)
+			return (TK_ERROR);
+	}
+
+	/* ';' terminator token */
+	return (gettoken_semicolon(mf, MSG_ORIG(MSG_MAPKW_PHDR_ADD_NULL)));
+}
+
+/*
+ * segment_directive segment_name { ALIGN = value
+ * ----------------------------------------^
+ */
+/* ARGSUSED 1 */
+static Token
+at_seg_align(Mapfile *mf, Token eq_tok, void *uvalue)
+{
+	Sg_desc		*sgp = uvalue;
+	ld_map_tkval_t	tkv;
+
+	/* value */
+	if (gettoken_int(mf, MSG_ORIG(MSG_MAPKW_ALIGN), &tkv) == TK_ERROR)
+		return (TK_ERROR);
+
+	sgp->sg_phdr.p_align = tkv.tkv_int.tkvi_value;
+	sgp->sg_flags |= FLG_SG_P_ALIGN;
+
+	/* terminator */
+	return (gettoken_term(mf, MSG_ORIG(MSG_MAPKW_ALIGN)));
+}
+
+/*
+ * at_seg_assign_file_basename(): Value for FILE_BASENAME= is not a file name
+ */
+static void
+gts_efunc_at_seg_assign_file_basename(Mapfile *mf, Token tok,
+    ld_map_tkval_t *tkv)
+{
+	Conv_inv_buf_t	inv_buf;
+
+	mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_FILNAM),
+	    MSG_ORIG(MSG_MAPKW_FILE_BASENAME),
+	    ld_map_tokenstr(tok, tkv, &inv_buf));
+}
+
+/*
+ * segment_directive segment_name { ASSIGN { FILE_BASENAME = file_name
+ * ---------------------------------------------------------^
+ */
+/* ARGSUSED 1 */
+static Token
+at_seg_assign_file_basename(Mapfile *mf, Token eq_tok, void *uvalue)
+{
+	Ent_desc	*enp = uvalue;
+	ld_map_tkval_t	tkv;
+
+	/* file_name */
+	if (gettoken_str(mf, 0, &tkv, gts_efunc_at_seg_assign_file_basename) ==
+	    TK_ERROR)
+		return (TK_ERROR);
+
+	if (!ld_map_seg_ent_files(mf, enp, TYP_ECF_BASENAME, tkv.tkv_str))
+		return (TK_ERROR);
+
+	/* terminator */
+	return (gettoken_term(mf, MSG_ORIG(MSG_MAPKW_FILE_BASENAME)));
+}
+
+/*
+ * at_seg_assign_file_objname(): Value for FILE_OBJNAME= is not an object name
+ */
+static void
+gts_efunc_at_seg_assign_file_objname(Mapfile *mf, Token tok,
+    ld_map_tkval_t *tkv)
+{
+	Conv_inv_buf_t	inv_buf;
+
+	mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_OBJNAM),
+	    MSG_ORIG(MSG_MAPKW_FILE_OBJNAME),
+	    ld_map_tokenstr(tok, tkv, &inv_buf));
+}
+
+/*
+ * segment_directive segment_name { ASSIGN { FILE_OBJNAME = name
+ * --------------------------------------------------------^
+ */
+/* ARGSUSED 1 */
+static Token
+at_seg_assign_file_objname(Mapfile *mf, Token eq_tok, void *uvalue)
+{
+	Ent_desc	*enp = uvalue;
+	ld_map_tkval_t	tkv;
+
+	/* file_objname */
+	if (gettoken_str(mf, 0, &tkv, gts_efunc_at_seg_assign_file_objname) ==
+	    TK_ERROR)
+		return (TK_ERROR);
+
+	if (!ld_map_seg_ent_files(mf, enp, TYP_ECF_OBJNAME, tkv.tkv_str))
+		return (TK_ERROR);
+
+	/* terminator */
+	return (gettoken_term(mf, MSG_ORIG(MSG_MAPKW_FILE_OBJNAME)));
+}
+
+/*
+ * at_seg_assign_file_path(): Value for FILE_PATH= is not a file path
+ */
+static void
+gts_efunc_at_seg_assign_file_path(Mapfile *mf, Token tok, ld_map_tkval_t *tkv)
+{
+	Conv_inv_buf_t	inv_buf;
+
+	mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_FILPATH),
+	    MSG_ORIG(MSG_MAPKW_FILE_PATH),
+	    ld_map_tokenstr(tok, tkv, &inv_buf));
+}
+
+/*
+ * segment_directive segment_name { ASSIGN { FILE_PATH = file_path
+ * -----------------------------------------------------^
+ */
+/* ARGSUSED 1 */
+static Token
+at_seg_assign_file_path(Mapfile *mf, Token eq_tok, void *uvalue)
+{
+	Ent_desc	*enp = uvalue;
+	ld_map_tkval_t	tkv;
+
+	/* file_path */
+	if (gettoken_str(mf, 0, &tkv, gts_efunc_at_seg_assign_file_path) ==
+	    TK_ERROR)
+		return (TK_ERROR);
+
+	if (!ld_map_seg_ent_files(mf, enp, TYP_ECF_PATH, tkv.tkv_str))
+		return (TK_ERROR);
+
+	/* terminator */
+	return (gettoken_term(mf, MSG_ORIG(MSG_MAPKW_FILE_PATH)));
+}
+
+/*
+ * segment_directive segment_name { ASSIGN { FLAGS = ... ;
+ * -------------------------------------------------^
+ */
+/* ARGSUSED 1 */
+static Token
+at_seg_assign_flags(Mapfile *mf, Token eq_tok, void *uvalue)
+{
+	typedef struct {
+		const char	*name;
+		Word		value;
+	} secflag_t;
+	static secflag_t flag_list[] = {
+		{ MSG_ORIG(MSG_MAPKW_ALLOC),		SHF_ALLOC },
+		{ MSG_ORIG(MSG_MAPKW_EXECUTE),		SHF_EXECINSTR },
+		{ MSG_ORIG(MSG_MAPKW_WRITE),		SHF_WRITE },
+		{ MSG_ORIG(MSG_MAPKW_AMD64_LARGE),	SHF_AMD64_LARGE },
+
+		/* List must be null terminated */
+		{ 0 },
+	};
+
+	/*
+	 * Size of buffer needed to format the names in flag_list[]. Must
+	 * be kept in sync with flag_list.
+	 */
+	static size_t	flag_list_bufsize =
+	    KW_NAME_SIZE(MSG_MAPKW_ALLOC) +
+	    KW_NAME_SIZE(MSG_MAPKW_EXECUTE) +
+	    KW_NAME_SIZE(MSG_MAPKW_WRITE) +
+	    KW_NAME_SIZE(MSG_MAPKW_AMD64_LARGE);
+
+	Ent_desc	*enp = uvalue;
+	int		bcnt = 0, cnt = 0;
+	secflag_t	*flag;
+	int		done;
+	Token		tok;
+	ld_map_tkval_t	tkv;
+	Conv_inv_buf_t	inv_buf;
+
+	/* Read and process tokens until the closing terminator is seen */
+	for (done = 0; done == 0; ) {
+		switch (tok = ld_map_gettoken(mf, 0, &tkv)) {
+		case TK_ERROR:
+			return (TK_ERROR);
+
+		case TK_BANG:
+			/* Ensure ! only specified once per flag */
+			if (bcnt != 0) {
+				mf_fatal0(mf, MSG_INTL(MSG_MAP_SFLG_ONEBANG));
+				return (TK_ERROR);
+			}
+			bcnt++;
+			break;
+
+		case TK_STRING:
+			flag = ld_map_kwfind(tkv.tkv_str, flag_list,
+			    SGSOFFSETOF(secflag_t, name), sizeof (flag[0]));
+			if (flag == NULL)
+				goto bad_flag;
+			cnt++;
+			enp->ec_attrmask |= flag->value;
+			if (bcnt == 0)
+				enp->ec_attrbits |=  flag->value;
+			bcnt = 0;
+			break;
+
+		case TK_RIGHTBKT:
+		case TK_SEMICOLON:
+			done = 1;
+			break;
+
+		default:
+		bad_flag:
+			{
+				char buf[flag_list_bufsize];
+
+				mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_SECFLAG),
+				    ld_map_kwnames(flag_list,
+				    SGSOFFSETOF(secflag_t, name),
+				    sizeof (flag[0]), buf, flag_list_bufsize),
+				    ld_map_tokenstr(tok, &tkv, &inv_buf));
+			}
+			return (TK_ERROR);
+		}
+	}
+
+	/*
+	 * Ensure that a trailing '!' was not left at the end of the line
+	 * without a corresponding flag to apply it to.
+	 */
+	if (bcnt != 0) {
+		mf_fatal0(mf, MSG_INTL(MSG_MAP_SFLG_EXBANG));
+		return (TK_ERROR);
+	}
+
+	/* Make sure there was at least one flag */
+	if (cnt == 0) {
+		mf_fatal(mf, MSG_INTL(MSG_MAP_NOVALUES),
+		    MSG_ORIG(MSG_MAPKW_FLAGS));
+		return (TK_ERROR);
+	}
+
+	return (tok);		/* Either TK_SEMICOLON or TK_RIGHTBKT */
+}
+
+/*
+ * at_seg_assign_is_name(): Value for IS_NAME= is not a section name
+ */
+static void
+gts_efunc_at_seg_assign_is_name(Mapfile *mf, Token tok, ld_map_tkval_t *tkv)
+{
+	Conv_inv_buf_t	inv_buf;
+
+	mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_SECNAM),
+	    MSG_ORIG(MSG_MAPKW_IS_NAME), ld_map_tokenstr(tok, tkv, &inv_buf));
+}
+
+/*
+ * segment_directive segment_name { ASSIGN { IS_NAME = section_name ;
+ * ---------------------------------------------------^
+ */
+/* ARGSUSED 1 */
+static Token
+at_seg_assign_is_name(Mapfile *mf, Token eq_tok, void *uvalue)
+{
+	Ent_desc	*enp = uvalue;
+	ld_map_tkval_t	tkv;
+
+	/* section_name */
+	if (gettoken_str(mf, 0, &tkv, gts_efunc_at_seg_assign_is_name) ==
+	    TK_ERROR)
+		return (TK_ERROR);
+	enp->ec_is_name = tkv.tkv_str;
+
+	/* terminator */
+	return (gettoken_term(mf, MSG_ORIG(MSG_MAPKW_IS_NAME)));
+}
+
+/*
+ * at_seg_assign_type(): Value for TYPE= is not a section type
+ */
+static void
+gts_efunc_at_seg_assign_type(Mapfile *mf, Token tok, ld_map_tkval_t *tkv)
+{
+	Conv_inv_buf_t	inv_buf;
+
+	mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_SHTYPE),
+	    ld_map_tokenstr(tok, tkv, &inv_buf));
+}
+
+/*
+ * segment_directive segment_name { ASSIGN { TYPE = section_type ;
+ * ------------------------------------------------^
+ */
+/* ARGSUSED 1 */
+static Token
+at_seg_assign_type(Mapfile *mf, Token eq_tok, void *uvalue)
+{
+	Ent_desc		*enp = uvalue;
+	ld_map_tkval_t		tkv;
+	conv_strtol_uvalue_t	conv_uvalue;
+
+	/* section type */
+	if (gettoken_str(mf, TK_F_KEYWORD, &tkv,
+	    gts_efunc_at_seg_assign_type) == TK_ERROR)
+		return (TK_ERROR);
+
+	/*
+	 * Use the libconv iteration facility to map the given name to
+	 * its value. This allows us to keep up with any new sections
+	 * without having to change this code.
+	 */
+	if (conv_iter_strtol_init(tkv.tkv_str, &conv_uvalue) != 0) {
+		conv_iter_ret_t	status;
+
+		/* Look at the canonical form */
+		status = conv_iter_sec_type(CONV_OSABI_ALL, CONV_MACH_ALL,
+		    CONV_FMT_ALT_CF, conv_iter_strtol, &conv_uvalue);
+
+		/* Failing that, look at the normal form */
+		if (status != CONV_ITER_DONE)
+			(void) conv_iter_sec_type(CONV_OSABI_ALL,
+			    CONV_MACH_ALL, CONV_FMT_ALT_NF, conv_iter_strtol,
+			    &conv_uvalue);
+
+		/* If we didn't match anything report error */
+		if (!conv_uvalue.csl_found) {
+			gts_efunc_at_seg_assign_type(mf, TK_STRING, &tkv);
+			return (TK_ERROR);
+		}
+	}
+
+	enp->ec_type = conv_uvalue.csl_value;
+
+	/* terminator */
+	return (gettoken_term(mf, MSG_ORIG(MSG_MAPKW_TYPE)));
+}
+
+/*
+ * segment_directive segment_name { ASSIGN { ...
+ * -----------------------------------------^
+ */
+/* ARGSUSED 1 */
+static Token
+at_seg_assign(Mapfile *mf, Token eq_tok, void *uvalue)
+{
+	/* segment_directive ASSIGN sub-attributes */
+	static attr_t attr_list[] = {
+		{ MSG_ORIG(MSG_MAPKW_FILE_BASENAME),
+		    at_seg_assign_file_basename,	ATTR_FMT_EQ },
+		{ MSG_ORIG(MSG_MAPKW_FILE_OBJNAME),
+		    at_seg_assign_file_objname,		ATTR_FMT_EQ },
+		{ MSG_ORIG(MSG_MAPKW_FILE_PATH),
+		    at_seg_assign_file_path,		ATTR_FMT_EQ },
+		{ MSG_ORIG(MSG_MAPKW_FLAGS),
+		    at_seg_assign_flags,		ATTR_FMT_EQ_ALL },
+		{ MSG_ORIG(MSG_MAPKW_IS_NAME),
+		    at_seg_assign_is_name,		ATTR_FMT_EQ },
+		{ MSG_ORIG(MSG_MAPKW_TYPE),
+		    at_seg_assign_type,			ATTR_FMT_EQ },
+
+		/* List must be null terminated */
+		{ 0 }
+	};
+
+	/*
+	 * Size of buffer needed to format the names in attr_list[]. Must
+	 * be kept in sync with attr_list.
+	 */
+	static size_t	attr_list_bufsize =
+	    KW_NAME_SIZE(MSG_MAPKW_FILE_BASENAME) +
+	    KW_NAME_SIZE(MSG_MAPKW_FILE_PATH) +
+	    KW_NAME_SIZE(MSG_MAPKW_FLAGS) +
+	    KW_NAME_SIZE(MSG_MAPKW_FILE_OBJNAME) +
+	    KW_NAME_SIZE(MSG_MAPKW_IS_NAME) +
+	    KW_NAME_SIZE(MSG_MAPKW_TYPE);
+
+	Sg_desc		*sgp = uvalue;
+	Token		tok;
+	ld_map_tkval_t	tkv;
+	Conv_inv_buf_t	inv_buf;
+	const char	*name = NULL;
+	Ent_desc	*enp;
+
+	/*
+	 * ASSIGN takes an optional name, plus attributes are optional,
+	 * so expect a name, an opening '{', or a ';'.
+	 */
+	tok = ld_map_gettoken(mf, 0, &tkv);
+	switch (tok) {
+	case TK_ERROR:
+		return (TK_ERROR);
+
+	case TK_STRING:
+		name = tkv.tkv_str;
+		tok = ld_map_gettoken(mf, 0, &tkv);
+		break;
+	}
+
+	/* Add a new entrance criteria descriptor to the segment */
+	if ((enp = ld_map_seg_ent_add(mf, sgp, name)) == NULL)
+		return (TK_ERROR);
+
+	/* Having handled the name, expect either '{' or ';' */
+	switch (tok) {
+	default:
+		mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_SEMLBKT),
+		    MSG_ORIG(MSG_MAPKW_ASSIGN_SECTION),
+		    ld_map_tokenstr(tok, &tkv, &inv_buf));
+		return (TK_ERROR);
+	case TK_ERROR:
+		return (TK_ERROR);
+	case TK_SEMICOLON:
+	case TK_RIGHTBKT:
+		/* No attributes: It will match anything */
+		enp->ec_flags |= FLG_EC_CATCHALL;
+		break;
+	case TK_LEFTBKT:
+		/* Parse the attributes */
+		if (parse_attributes(mf, MSG_ORIG(MSG_MAPKW_ASSIGN_SECTION),
+		    attr_list, attr_list_bufsize, enp) == TK_ERROR)
+			return (TK_ERROR);
+
+		/* Terminating ';',  or '}' which also terminates caller */
+		tok = gettoken_term(mf, MSG_ORIG(MSG_MAPKW_ASSIGN_SECTION));
+		if (tok == TK_ERROR)
+			return (TK_ERROR);
+		break;
+	}
+
+	DBG_CALL(Dbg_map_ent(mf->mf_ofl->ofl_lml, enp, mf->mf_ofl,
+	    mf->mf_lineno));
+	return (tok);
+}
+
+/*
+ * segment_directive segment_name { DISABLE ;
+ * ----------------------------------------^
+ */
+/* ARGSUSED 1 */
+static Token
+at_seg_disable(Mapfile *mf, Token eq_tok, void *uvalue)
+{
+	Sg_desc		*sgp = uvalue;
+
+	/* If the segment cannot be disabled, issue error */
+	if (sgp->sg_flags & FLG_SG_NODISABLE) {
+		mf_fatal(mf, MSG_INTL(MSG_MAP_CNTDISSEG), sgp->sg_name);
+		return (TK_ERROR);
+	}
+
+	/* Disable the segment */
+	sgp->sg_flags |= FLG_SG_DISABLED;
+
+	/* terminator */
+	return (gettoken_semicolon(mf, MSG_ORIG(MSG_MAPKW_DISABLE)));
+}
+
+/*
+ * segment_directive segment_name { FLAGS eq-op ...
+ * --------------------------------------------^
+ *
+ * Note that this routine is also used for the STACK directive,
+ * as STACK also manipulates a segment descriptor.
+ *
+ * STACK { FLAGS eq-op ... ;
+ * -------------------^
+ */
+/* ARGSUSED 2 */
+static Token
+at_seg_flags(Mapfile *mf, Token eq_tok, void *uvalue)
+{
+	Sg_desc		*sgp = uvalue;
+	Token		tok;
+	Xword		flags;
+
+	tok = parse_segment_flags(mf, &flags);
+	if (tok == TK_ERROR)
+		return (TK_ERROR);
+
+	setflags_eq(&sgp->sg_phdr.p_flags, eq_tok, flags);
+	sgp->sg_flags |= FLG_SG_P_FLAGS;
+
+	return (tok);
+}
+
+/*
+ * segment_directive segment_name { IS_ORDER eq_op value
+ * -----------------------------------------------^
+ */
+/* ARGSUSED 2 */
+static Token
+at_seg_is_order(Mapfile *mf, Token eq_tok, void *uvalue)
+{
+	Sg_desc		*sgp = uvalue;
+	Token		tok;
+	ld_map_tkval_t	tkv;
+	Conv_inv_buf_t	inv_buf;
+	int		done;
+	Aliste		idx;
+	Ent_desc	*enp, *enp2;
+
+	/*
+	 * The '=' form of assignment resets the list. The list contains
+	 * pointers to our mapfile text, so we do not have to free anything.
+	 */
+	if (eq_tok == TK_EQUAL)
+		aplist_reset(sgp->sg_is_order);
+
+	/*
+	 * One or more ASSIGN names, terminated by a semicolon.
+	 */
+	for (done = 0; done == 0; ) {
+		switch (tok = ld_map_gettoken(mf, 0, &tkv)) {
+		case TK_ERROR:
+			return (TK_ERROR);
+
+		case TK_STRING:
+			/*
+			 * The referenced entrance criteria must have
+			 * already been defined.
+			 */
+			enp = ld_ent_lookup(mf->mf_ofl, tkv.tkv_str, NULL);
+			if (enp == NULL) {
+				mf_fatal(mf, MSG_INTL(MSG_MAP_UNKENT),
+				    tkv.tkv_str);
+				return (TK_ERROR);
+			}
+
+			/*
+			 * Make sure it's not already on the list
+			 */
+			for (APLIST_TRAVERSE(sgp->sg_is_order, idx, enp2))
+				if (enp == enp2) {
+					mf_fatal(mf,
+					    MSG_INTL(MSG_MAP_DUP_IS_ORD),
+					    tkv.tkv_str);
+					return (TK_ERROR);
+				}
+
+			/* Put it at the end of the order list */
+			if (aplist_append(&sgp->sg_is_order, enp,
+			    AL_CNT_SG_IS_ORDER) == NULL)
+				return (TK_ERROR);
+			break;
+
+		case TK_SEMICOLON:
+		case TK_RIGHTBKT:
+			done = 1;
+			break;
+
+		default:
+			mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_ECNAM),
+			    ld_map_tokenstr(tok, &tkv, &inv_buf));
+			return (TK_ERROR);
+		}
+	}
+
+	return (tok);
+}
+
+/*
+ * segment_directive segment_name { MAX_SIZE = value
+ * -------------------------------------------^
+ */
+/* ARGSUSED 1 */
+static Token
+at_seg_max_size(Mapfile *mf, Token eq_tok, void *uvalue)
+{
+	Sg_desc		*sgp = uvalue;
+	ld_map_tkval_t	tkv;
+
+	/* value */
+	if (gettoken_int(mf, MSG_ORIG(MSG_MAPKW_MAX_SIZE), &tkv) == TK_ERROR)
+		return (TK_ERROR);
+
+	sgp->sg_length = tkv.tkv_int.tkvi_value;
+	sgp->sg_flags |= FLG_SG_LENGTH;
+
+	/* terminator */
+	return (gettoken_term(mf, MSG_ORIG(MSG_MAPKW_MAX_SIZE)));
+}
+
+/*
+ * segment_directive segment_name { NOHDR ;
+ * --------------------------------------^
+ */
+/* ARGSUSED 1 */
+static Token
+at_seg_nohdr(Mapfile *mf, Token eq_tok, void *uvalue)
+{
+	Sg_desc		*sgp = uvalue;
+
+	/*
+	 * Set the nohdr flag on the segment. If this segment is the
+	 * first loadable segment, the ELF and program headers will
+	 * not be included.
+	 *
+	 * The HDR_NOALLOC top level directive is preferred. This feature
+	 * exists to give 1:1 feature parity with version 1 mapfiles that
+	 * use the ?N segment flag and expect it to only take effect
+	 * if that segment ends up being first.
+	 */
+	sgp->sg_flags |= FLG_SG_NOHDR;
+
+	/* terminator */
+	return (gettoken_semicolon(mf, MSG_ORIG(MSG_MAPKW_NOHDR)));
+}
+
+/*
+ * segment_directive segment_name { OS_ORDER eq_op assign_name...
+ * -----------------------------------------------^
+ */
+/* ARGSUSED 2 */
+static Token
+at_seg_os_order(Mapfile *mf, Token eq_tok, void *uvalue)
+{
+	Sg_desc		*sgp = uvalue;
+	Token		tok;
+	ld_map_tkval_t	tkv;
+	Conv_inv_buf_t	inv_buf;
+	int		done;
+
+	/*
+	 * The '=' form of assignment resets the list. The list contains
+	 * pointers to our mapfile text, so we do not have to free anything.
+	 */
+	if (eq_tok == TK_EQUAL)
+		alist_reset(sgp->sg_os_order);
+
+	/*
+	 * One or more section names, terminated by a semicolon.
+	 */
+	for (done = 0; done == 0; ) {
+		switch (tok = ld_map_gettoken(mf, 0, &tkv)) {
+		case TK_ERROR:
+			return (TK_ERROR);
+
+		case TK_STRING:
+			if (!ld_map_seg_os_order_add(mf, sgp, tkv.tkv_str))
+				return (TK_ERROR);
+			break;
+
+		case TK_SEMICOLON:
+		case TK_RIGHTBKT:
+			done = 1;
+			break;
+
+		default:
+			mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_SECNAM),
+			    ld_map_tokenstr(tok, &tkv, &inv_buf));
+			return (TK_ERROR);
+		}
+	}
+
+	return (tok);
+}
+
+/*
+ * segment_directive segment_name { PADDR = paddr
+ * ----------------------------------------^
+ */
+/* ARGSUSED 1 */
+static Token
+at_seg_paddr(Mapfile *mf, Token eq_tok, void *uvalue)
+{
+	Sg_desc		*sgp = uvalue, *sgp2;
+	Aliste		idx;
+	ld_map_tkval_t	tkv;
+
+	/*
+	 * Ensure that the segment isn't in the segment order list.
+	 */
+	for (APLIST_TRAVERSE(mf->mf_ofl->ofl_segs_order, idx, sgp2))
+		if (sgp == sgp2) {
+			mf_fatal(mf,
+			    MSG_INTL(MSG_MAP_CNTADDRORDER), sgp->sg_name);
+			return (TK_ERROR);
+		}
+
+	/* value */
+	if (gettoken_int(mf, MSG_ORIG(MSG_MAPKW_PADDR), &tkv) == TK_ERROR)
+		return (TK_ERROR);
+
+	sgp->sg_phdr.p_paddr = tkv.tkv_int.tkvi_value;
+	sgp->sg_flags |= FLG_SG_P_PADDR;
+
+	/* terminator */
+	return (gettoken_term(mf, MSG_ORIG(MSG_MAPKW_PADDR)));
+}
+
+/*
+ * segment_directive segment_name { ROUND = value
+ * ----------------------------------------^
+ */
+/* ARGSUSED 1 */
+static Token
+at_seg_round(Mapfile *mf, Token eq_tok, void *uvalue)
+{
+	Sg_desc		*sgp = uvalue;
+	ld_map_tkval_t	tkv;
+
+	/* value */
+	if (gettoken_int(mf, MSG_ORIG(MSG_MAPKW_ROUND), &tkv) == TK_ERROR)
+		return (TK_ERROR);
+
+	sgp->sg_round = tkv.tkv_int.tkvi_value;
+	sgp->sg_flags |= FLG_SG_ROUND;
+
+	/* terminator */
+	return (gettoken_term(mf, MSG_ORIG(MSG_MAPKW_ROUND)));
+}
+
+/*
+ * segment_directive segment_name { SIZE_SYMBOL = symbol_name
+ * ----------------------------------------------^
+ */
+/* ARGSUSED 2 */
+static Token
+at_seg_size_symbol(Mapfile *mf, Token eq_tok, void *uvalue)
+{
+	Sg_desc		*sgp = uvalue;
+	Token		tok;
+	ld_map_tkval_t	tkv;
+	Conv_inv_buf_t	inv_buf;
+	int		done, cnt = 0;
+
+	/*
+	 * One or more symbol names, terminated by a semicolon.
+	 */
+	for (done = 0; done == 0; ) {
+		switch (tok = ld_map_gettoken(mf, 0, &tkv)) {
+		case TK_ERROR:
+			return (TK_ERROR);
+
+		case TK_STRING:
+			if (!ld_map_seg_size_symbol(mf, sgp, eq_tok,
+			    tkv.tkv_str))
+				return (TK_ERROR);
+			cnt++;
+
+			/*
+			 * If the operator is TK_EQUAL, turn it into
+			 * TK_PLUSEQ for any symbol names after the first.
+			 * These additional symbols are added, and are not
+			 * replacements for the first one.
+			 */
+			eq_tok = TK_PLUSEQ;
+			break;
+
+		case TK_SEMICOLON:
+		case TK_RIGHTBKT:
+			done = 1;
+			break;
+
+		default:
+			mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_SYMNAM),
+			    MSG_ORIG(MSG_MAPKW_SIZE_SYMBOL),
+			    ld_map_tokenstr(tok, &tkv, &inv_buf));
+			return (TK_ERROR);
+		}
+	}
+
+	/* Make sure there was at least one name */
+	if (cnt == 0) {
+		mf_fatal(mf, MSG_INTL(MSG_MAP_NOVALUES),
+		    MSG_ORIG(MSG_MAPKW_SIZE_SYMBOL));
+		return (TK_ERROR);
+	}
+
+	return (tok);
+}
+
+/*
+ * segment_directive segment_name { VADDR = vaddr
+ * ----------------------------------------^
+ */
+/* ARGSUSED 1 */
+static Token
+at_seg_vaddr(Mapfile *mf, Token eq_tok, void *uvalue)
+{
+	Sg_desc		*sgp = uvalue, *sgp2;
+	Aliste		idx;
+	ld_map_tkval_t	tkv;
+
+	/*
+	 * Ensure that the segment isn't in the segment order list.
+	 */
+	for (APLIST_TRAVERSE(mf->mf_ofl->ofl_segs_order, idx, sgp2))
+		if (sgp == sgp2) {
+			mf_fatal(mf,
+			    MSG_INTL(MSG_MAP_CNTADDRORDER), sgp->sg_name);
+			return (TK_ERROR);
+		}
+
+	/* value */
+	if (gettoken_int(mf, MSG_ORIG(MSG_MAPKW_VADDR), &tkv) == TK_ERROR)
+		return (TK_ERROR);
+
+	sgp->sg_phdr.p_vaddr = tkv.tkv_int.tkvi_value;
+	sgp->sg_flags |= FLG_SG_P_VADDR;
+
+	/* terminator */
+	return (gettoken_term(mf, MSG_ORIG(MSG_MAPKW_VADDR)));
+}
+
+/*
+ * Top Level Directive:
+ *
+ * {LOAD|NOTE|NULL}_SEGMENT segment_name { ...
+ * ------------------------^
+ *
+ * Common implementation body for the family of segment directives. These
+ * take the same syntax, and share a common subset of attributes. They differ
+ * in the type of segments they handle and the specific attributes accepted.
+ *
+ * entry:
+ *	mf - Mapfile descriptor ({LOAD|NOTE|NULL}_SEGMENT)
+ *	dir_name - Name of directive.
+ *	seg_type - Type of segment (PT_LOAD, PT_NOTE, PT_NULL).
+ *	attr_list - NULL terminated attribute array
+ *	attr_list_bufsize - Size of required buffer to format all the
+ *		names in attr_list.
+ *	gts_efunc - Error function to pass to gettoken_str() when trying
+ *		to obtain a segment name token.
+ */
+static Token
+dir_segment_inner(Mapfile *mf, const char *dir_name, Word seg_type,
+    attr_t *attr_list, size_t attr_list_bufsize, gts_efunc_t gts_efunc)
+{
+	Token		tok;
+	ld_map_tkval_t	tkv;
+	Sg_desc		*sgp;
+	Boolean		new_segment;
+	Xword		ndx;
+	avl_index_t	where;
+
+	/* segment_name */
+	if (gettoken_str(mf, 0, &tkv, gts_efunc) == TK_ERROR)
+		return (TK_ERROR);
+	sgp = ld_seg_lookup(mf->mf_ofl, tkv.tkv_str, &where);
+	new_segment = (sgp == NULL);
+
+	if (new_segment) {
+		/* Allocate a descriptor for new segment */
+		if ((sgp = ld_map_seg_alloc(tkv.tkv_str, seg_type,
+		    FLG_SG_P_TYPE)) == NULL)
+			return (TK_ERROR);
+	} else {
+		/* Make sure it's the right type of segment */
+		if (sgp->sg_phdr.p_type != seg_type) {
+			Conv_inv_buf_t	inv_buf;
+
+			mf_fatal(mf, MSG_INTL(MSG_MAP_EXPSEGTYPE),
+			    conv_phdr_type(ELFOSABI_SOLARIS, ld_targ.t_m.m_mach,
+			    sgp->sg_phdr.p_type, CONV_FMT_ALT_CF, &inv_buf),
+			    dir_name, tkv.tkv_str);
+			return (TK_ERROR);
+		}
+
+		/* If it was disabled, being referenced enables it */
+		sgp->sg_flags &= ~FLG_SG_DISABLED;
+
+		if (DBG_ENABLED) {
+			/*
+			 * Not a new segment, so show the initial value
+			 * before modifying it.
+			 */
+			ndx = ld_map_seg_index(mf, sgp);
+			DBG_CALL(Dbg_map_seg(mf->mf_ofl, DBG_STATE_MOD_BEFORE,
+			    ndx, sgp, mf->mf_lineno));
+		}
+	}
+
+	/*
+	 * Attributes are optional, so expect an opening '{', or a ';'.
+	 */
+	switch (tok = gettoken_optattr(mf, dir_name)) {
+	default:
+		tok = TK_ERROR;
+		break;
+	case TK_SEMICOLON:
+		break;
+	case TK_LEFTBKT:
+		/* Parse the attributes */
+		if (parse_attributes(mf, dir_name,
+		    attr_list, attr_list_bufsize, sgp) == TK_ERROR)
+			return (TK_ERROR);
+
+		/* Terminating ';' */
+		tok = gettoken_semicolon(mf, dir_name);
+		if (tok == TK_ERROR)
+			return (TK_ERROR);
+
+		break;
+	}
+
+	/*
+	 * If this is a new segment, finish its initialization
+	 * and insert it into the segment list.
+	 */
+	if (new_segment) {
+		if (ld_map_seg_insert(mf, DBG_STATE_NEW, sgp, where) ==
+		    SEG_INS_FAIL)
+			return (TK_ERROR);
+	} else {
+		/* Not new. Show what's changed */
+		DBG_CALL(Dbg_map_seg(mf->mf_ofl, DBG_STATE_MOD_AFTER,
+		    ndx, sgp, mf->mf_lineno));
+	}
+
+	return (tok);
+}
+
+/*
+ * dir_load_segment(): Expected loadable segment name is not present
+ */
+static void
+gts_efunc_dir_load_segment(Mapfile *mf, Token tok, ld_map_tkval_t *tkv)
+{
+	Conv_inv_buf_t	inv_buf;
+
+	mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_SEGNAM),
+	    MSG_ORIG(MSG_MAPKW_LOAD_SEGMENT),
+	    ld_map_tokenstr(tok, tkv, &inv_buf));
+}
+
+/*
+ * Top Level Directive:
+ *
+ * LOAD_SEGMENT segment_name { ...
+ * ------------^
+ */
+static Token
+dir_load_segment(Mapfile *mf)
+{
+	/* LOAD_SEGMENT attributes */
+	static attr_t attr_list[] = {
+		{ MSG_ORIG(MSG_MAPKW_ALIGN),	at_seg_align,	ATTR_FMT_EQ },
+		{ MSG_ORIG(MSG_MAPKW_ASSIGN_SECTION),
+		    at_seg_assign,	ATTR_FMT_NAME },
+		{ MSG_ORIG(MSG_MAPKW_DISABLE),	at_seg_disable,	ATTR_FMT_NAME },
+		{ MSG_ORIG(MSG_MAPKW_FLAGS),	at_seg_flags,
+		    ATTR_FMT_EQ_ALL },
+		{ MSG_ORIG(MSG_MAPKW_IS_ORDER),	at_seg_is_order,
+		    ATTR_FMT_EQ_PEQ },
+		{ MSG_ORIG(MSG_MAPKW_MAX_SIZE),	at_seg_max_size, ATTR_FMT_EQ },
+		{ MSG_ORIG(MSG_MAPKW_NOHDR),	at_seg_nohdr,	ATTR_FMT_NAME },
+		{ MSG_ORIG(MSG_MAPKW_OS_ORDER),	at_seg_os_order,
+		    ATTR_FMT_EQ_PEQ },
+		{ MSG_ORIG(MSG_MAPKW_PADDR),	at_seg_paddr,	ATTR_FMT_EQ },
+		{ MSG_ORIG(MSG_MAPKW_ROUND),	at_seg_round,	ATTR_FMT_EQ },
+		{ MSG_ORIG(MSG_MAPKW_SIZE_SYMBOL),
+		    at_seg_size_symbol,	ATTR_FMT_EQ_PEQ },
+		{ MSG_ORIG(MSG_MAPKW_VADDR),	at_seg_vaddr,	ATTR_FMT_EQ },
+
+		/* List must be null terminated */
+		{ 0 }
+	};
+
+	/*
+	 * Size of buffer needed to format the names in attr_list[]. Must
+	 * be kept in sync with attr_list.
+	 */
+	static size_t	attr_list_bufsize =
+	    KW_NAME_SIZE(MSG_MAPKW_ALIGN) +
+	    KW_NAME_SIZE(MSG_MAPKW_ASSIGN_SECTION) +
+	    KW_NAME_SIZE(MSG_MAPKW_DISABLE) +
+	    KW_NAME_SIZE(MSG_MAPKW_FLAGS) +
+	    KW_NAME_SIZE(MSG_MAPKW_IS_ORDER) +
+	    KW_NAME_SIZE(MSG_MAPKW_MAX_SIZE) +
+	    KW_NAME_SIZE(MSG_MAPKW_PADDR) +
+	    KW_NAME_SIZE(MSG_MAPKW_ROUND) +
+	    KW_NAME_SIZE(MSG_MAPKW_OS_ORDER) +
+	    KW_NAME_SIZE(MSG_MAPKW_SIZE_SYMBOL) +
+	    KW_NAME_SIZE(MSG_MAPKW_VADDR);
+
+	return (dir_segment_inner(mf, MSG_ORIG(MSG_MAPKW_LOAD_SEGMENT),
+	    PT_LOAD, attr_list, attr_list_bufsize, gts_efunc_dir_load_segment));
+
+}
+
+/*
+ * Common shared segment directive attributes
+ */
+static attr_t segment_core_attr_list[] = {
+	{ MSG_ORIG(MSG_MAPKW_ASSIGN_SECTION), at_seg_assign, ATTR_FMT_NAME },
+	{ MSG_ORIG(MSG_MAPKW_DISABLE),	at_seg_disable,	 ATTR_FMT_NAME },
+	{ MSG_ORIG(MSG_MAPKW_IS_ORDER),	at_seg_is_order, ATTR_FMT_EQ_PEQ },
+	{ MSG_ORIG(MSG_MAPKW_OS_ORDER),	at_seg_os_order, ATTR_FMT_EQ_PEQ },
+
+	/* List must be null terminated */
+	{ 0 }
+};
+
+/*
+ * Size of buffer needed to format the names in segment_core_attr_list[].
+ * Must be kept in sync with segment_core_attr_list.
+ */
+static size_t	segment_core_attr_list_bufsize =
+	KW_NAME_SIZE(MSG_MAPKW_ASSIGN_SECTION) +
+	KW_NAME_SIZE(MSG_MAPKW_DISABLE) +
+	KW_NAME_SIZE(MSG_MAPKW_IS_ORDER) +
+	KW_NAME_SIZE(MSG_MAPKW_OS_ORDER);
+
+/*
+ * dir_note_segment(): Expected note segment name is not present
+ */
+static void
+gts_efunc_dir_note_segment(Mapfile *mf, Token tok, ld_map_tkval_t *tkv)
+{
+	Conv_inv_buf_t	inv_buf;
+
+	mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_SEGNAM),
+	    MSG_ORIG(MSG_MAPKW_NOTE_SEGMENT),
+	    ld_map_tokenstr(tok, tkv, &inv_buf));
+}
+
+/*
+ * Top Level Directive:
+ *
+ * NOTE_SEGMENT segment_name { ...
+ * ------------^
+ */
+static Token
+dir_note_segment(Mapfile *mf)
+{
+	return (dir_segment_inner(mf, MSG_ORIG(MSG_MAPKW_NOTE_SEGMENT),
+	    PT_NOTE, segment_core_attr_list, segment_core_attr_list_bufsize,
+	    gts_efunc_dir_note_segment));
+
+}
+
+/*
+ * dir_null_segment(): Expected null segment name is not present
+ */
+static void
+gts_efunc_dir_null_segment(Mapfile *mf, Token tok, ld_map_tkval_t *tkv)
+{
+	Conv_inv_buf_t	inv_buf;
+
+	mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_SEGNAM),
+	    MSG_ORIG(MSG_MAPKW_NULL_SEGMENT),
+	    ld_map_tokenstr(tok, tkv, &inv_buf));
+}
+
+/*
+ * Top Level Directive:
+ *
+ * NULL_SEGMENT segment_name { ...
+ * ------------^
+ */
+static Token
+dir_null_segment(Mapfile *mf)
+{
+	return (dir_segment_inner(mf, MSG_ORIG(MSG_MAPKW_NULL_SEGMENT),
+	    PT_NULL, segment_core_attr_list, segment_core_attr_list_bufsize,
+	    gts_efunc_dir_null_segment));
+
+}
+
+/*
+ * Top Level Directive:
+ *
+ * SEGMENT_ORDER segment_name ... ;
+ */
+static Token
+dir_segment_order(Mapfile *mf)
+{
+	Token		tok;
+	ld_map_tkval_t	tkv;
+	Conv_inv_buf_t	inv_buf;
+	Aliste		idx;
+	Sg_desc		*sgp, *sgp2;
+	int		done;
+
+	/* Expect either a '=' or '+=' */
+	tok = gettoken_eq(mf, ATTR_FMT_EQ_PEQ,
+	    MSG_ORIG(MSG_MAPKW_SEGMENT_ORDER));
+	if (tok == TK_ERROR)
+		return (TK_ERROR);
+
+	DBG_CALL(Dbg_map_seg_order(mf->mf_ofl, ELFOSABI_SOLARIS,
+	    ld_targ.t_m.m_mach, DBG_STATE_MOD_BEFORE, mf->mf_lineno));
+
+	/*
+	 * The '=' form of assignment resets the list. The list contains
+	 * pointers to our mapfile text, so we do not have to free anything.
+	 */
+	if (tok == TK_EQUAL)
+		aplist_reset(mf->mf_ofl->ofl_segs_order);
+
+	/* Read segment names, and add to list until terminator (';') is seen */
+	for (done = 0; done == 0; ) {
+		switch (tok = ld_map_gettoken(mf, 0, &tkv)) {
+		case TK_ERROR:
+			return (TK_ERROR);
+
+		case TK_STRING:
+			/*
+			 * The segment must have already been defined.
+			 */
+			sgp = ld_seg_lookup(mf->mf_ofl, tkv.tkv_str, NULL);
+			if (sgp == NULL) {
+				mf_fatal(mf, MSG_INTL(MSG_MAP_UNKSEG),
+				    tkv.tkv_str);
+				return (TK_ERROR);
+			}
+
+			/*
+			 * Make sure it's not already on the list
+			 */
+			for (APLIST_TRAVERSE(mf->mf_ofl->ofl_segs_order,
+			    idx, sgp2))
+				if (sgp == sgp2) {
+					mf_fatal(mf,
+					    MSG_INTL(MSG_MAP_DUPORDSEG),
+					    MSG_ORIG(MSG_MAPKW_SEGMENT_ORDER),
+					    tkv.tkv_str);
+					return (TK_ERROR);
+				}
+
+			/*
+			 * It can't be ordered and also have an explicit
+			 * paddr or vaddr.
+			 */
+			if (sgp->sg_flags & (FLG_SG_P_PADDR | FLG_SG_P_VADDR)) {
+				mf_fatal(mf, MSG_INTL(MSG_MAP_CNTADDRORDER),
+				    sgp->sg_name);
+				return (TK_ERROR);
+			}
+
+
+			/* Put it at the end of the list */
+			if (aplist_append(&mf->mf_ofl->ofl_segs_order, sgp,
+			    AL_CNT_SG_IS_ORDER) == NULL)
+				return (TK_ERROR);
+			break;
+
+		case TK_SEMICOLON:
+			done = 1;
+			break;
+
+		default:
+			mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_SEGNAM),
+			    MSG_ORIG(MSG_MAPKW_SEGMENT_ORDER),
+			    ld_map_tokenstr(tok, &tkv, &inv_buf));
+			return (TK_ERROR);
+		}
+	}
+
+	DBG_CALL(Dbg_map_seg_order(mf->mf_ofl, ELFOSABI_SOLARIS,
+	    ld_targ.t_m.m_mach, DBG_STATE_MOD_AFTER, mf->mf_lineno));
+
+	return (tok);
+}
+
+/*
+ * Top Level Directive:
+ *
+ * STACK { ...
+ * -----^
+ */
+static Token
+dir_stack(Mapfile *mf)
+{
+	/* STACK attributes */
+	static attr_t attr_list[] = {
+		{ MSG_ORIG(MSG_MAPKW_FLAGS), at_seg_flags, ATTR_FMT_EQ_ALL },
+
+		/* List must be null terminated */
+		{ 0 }
+	};
+
+	/*
+	 * Size of buffer needed to format the names in attr_list[]. Must
+	 * be kept in sync with attr_list.
+	 */
+	static size_t	attr_list_bufsize =
+	    KW_NAME_SIZE(MSG_MAPKW_FLAGS);
+
+	Sg_desc	*sgp;
+	Token	tok;
+
+
+	/* Opening '{' token */
+	if (gettoken_leftbkt(mf, MSG_ORIG(MSG_MAPKW_STACK)) == TK_ERROR)
+		return (TK_ERROR);
+
+	/* Fetch the PT_SUNWSTACK segment descriptor */
+	sgp = ld_map_seg_stack(mf);
+
+	/* Parse the attributes */
+	if (parse_attributes(mf, MSG_ORIG(MSG_MAPKW_STACK),
+	    attr_list, attr_list_bufsize, sgp) == TK_ERROR)
+		return (TK_ERROR);
+
+	/* Terminating ';' */
+	tok = gettoken_semicolon(mf, MSG_ORIG(MSG_MAPKW_STACK));
+	if (tok == TK_ERROR)
+		return (TK_ERROR);
+
+	if (DBG_ENABLED) {
+		Xword ndx = ld_map_seg_index(mf, sgp);
+
+		Dbg_map_seg(mf->mf_ofl, DBG_STATE_MOD_AFTER, ndx, sgp,
+		    mf->mf_lineno);
+	}
+
+	return (tok);
+}
+
+/*
+ * at_sym_aux(): Value for AUXILIARY= is not an object name
+ */
+static void
+gts_efunc_at_sym_aux(Mapfile *mf, Token tok, ld_map_tkval_t *tkv)
+{
+	Conv_inv_buf_t	inv_buf;
+
+	mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_OBJNAM),
+	    MSG_ORIG(MSG_MAPKW_AUX), ld_map_tokenstr(tok, tkv, &inv_buf));
+}
+
+/*
+ * SYMBOL [version_name] { symbol_name { AUXILIARY = soname
+ * -------------------------------------------------^
+ */
+/* ARGSUSED 1 */
+static Token
+at_sym_aux(Mapfile *mf, Token eq_tok, void *uvalue)
+{
+	symbol_state_t	*ss = uvalue;
+	ld_map_tkval_t	tkv;
+
+	/* auxiliary filter soname */
+	if (gettoken_str(mf, 0, &tkv, gts_efunc_at_sym_aux) == TK_ERROR)
+		return (TK_ERROR);
+
+	ld_map_sym_filtee(mf, &ss->ss_mv, &ss->ss_ms, FLG_SY_AUXFLTR,
+	    tkv.tkv_str);
+
+	/* terminator */
+	return (gettoken_term(mf, MSG_ORIG(MSG_MAPKW_AUX)));
+}
+
+/*
+ * at_sym_filter(): Value for FILTER= is not an object name
+ */
+static void
+gts_efunc_at_sym_filter(Mapfile *mf, Token tok, ld_map_tkval_t *tkv)
+{
+	Conv_inv_buf_t	inv_buf;
+
+	mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_OBJNAM),
+	    MSG_ORIG(MSG_MAPKW_FILTER), ld_map_tokenstr(tok, tkv, &inv_buf));
+}
+
+/*
+ * SYMBOL [version_name] { symbol_name { FILTER = soname
+ * ----------------------------------------------^
+ */
+/* ARGSUSED 1 */
+static Token
+at_sym_filter(Mapfile *mf, Token eq_tok, void *uvalue)
+{
+	symbol_state_t	*ss = uvalue;
+	ld_map_tkval_t	tkv;
+
+	/* filter soname */
+	if (gettoken_str(mf, 0, &tkv, gts_efunc_at_sym_filter) == TK_ERROR)
+		return (TK_ERROR);
+
+	ld_map_sym_filtee(mf, &ss->ss_mv, &ss->ss_ms, FLG_SY_STDFLTR,
+	    tkv.tkv_str);
+
+	/* terminator */
+	return (gettoken_term(mf, MSG_ORIG(MSG_MAPKW_FILTER)));
+}
+
+/*
+ * SYMBOL [version_name] { symbol_name { FLAGS = ...
+ * ---------------------------------------------^
+ */
+/* ARGSUSED 1 */
+static Token
+at_sym_flags(Mapfile *mf, Token eq_tok, void *uvalue)
+{
+	typedef struct {
+		const char	*name;
+		sd_flag_t	value;
+	} symflag_t;
+
+	static symflag_t symflag_list[] = {
+		{ MSG_ORIG(MSG_MAPKW_DIRECT),		FLG_SY_DIR },
+		{ MSG_ORIG(MSG_MAPKW_DYNSORT),		FLG_SY_DYNSORT },
+		{ MSG_ORIG(MSG_MAPKW_EXTERN),		FLG_SY_EXTERN },
+		{ MSG_ORIG(MSG_MAPKW_INTERPOSE),	FLG_SY_INTPOSE },
+		{ MSG_ORIG(MSG_MAPKW_NODIRECT),		FLG_SY_NDIR },
+		{ MSG_ORIG(MSG_MAPKW_NODYNSORT),	FLG_SY_NODYNSORT },
+		{ MSG_ORIG(MSG_MAPKW_PARENT),		FLG_SY_PARENT },
+
+		/* List must be null terminated */
+		{ 0 }
+	};
+
+	/*
+	 * Size of buffer needed to format the names in flag_list[]. Must
+	 * be kept in sync with flag_list.
+	 */
+	static size_t	symflag_list_bufsize =
+	    KW_NAME_SIZE(MSG_MAPKW_DIRECT) +
+	    KW_NAME_SIZE(MSG_MAPKW_DYNSORT) +
+	    KW_NAME_SIZE(MSG_MAPKW_EXTERN) +
+	    KW_NAME_SIZE(MSG_MAPKW_INTERPOSE) +
+	    KW_NAME_SIZE(MSG_MAPKW_NODIRECT) +
+	    KW_NAME_SIZE(MSG_MAPKW_NODYNSORT) +
+	    KW_NAME_SIZE(MSG_MAPKW_PARENT);
+
+	symbol_state_t	*ss = uvalue;
+	int		done;
+	symflag_t	*symflag;
+	int		cnt = 0;
+	Token		tok;
+	ld_map_tkval_t	tkv;
+	Conv_inv_buf_t	inv_buf;
+	Ofl_desc	*ofl = mf->mf_ofl;
+
+	for (done = 0; done == 0; ) {
+		switch (tok = ld_map_gettoken(mf, TK_F_KEYWORD, &tkv)) {
+		case TK_ERROR:
+			return (TK_ERROR);
+
+		case TK_STRING:
+			symflag = ld_map_kwfind(tkv.tkv_str, symflag_list,
+			    SGSOFFSETOF(symflag_t, name), sizeof (symflag[0]));
+			if (symflag == NULL)
+				goto bad_flag;
+			cnt++;
+			/*
+			 * Apply the flag:
+			 *
+			 * Although tempting to make all of this table-driven
+			 * via added fields in symflag_t, there's enough
+			 * variation in what each flag does to make that
+			 * not quite worthwhile.
+			 *
+			 * Similarly, it is tempting to use common code to
+			 * to do this work from map_support.c. However, the
+			 * v1 code mixes unrelated things (flags, symbol types,
+			 * value, size, etc) in single cascading series of
+			 * strcmps, whereas our parsing separates those things
+			 * from each other. Merging the code would require doing
+			 * two strcmps for each item, or other complexity,
+			 * which I judge not to be worthwhile.
+			 */
+			switch (symflag->value) {
+			case FLG_SY_DIR:
+				ss->ss_ms.ms_sdflags |= FLG_SY_DIR;
+				ofl->ofl_flags |= FLG_OF_SYMINFO;
+				break;
+			case FLG_SY_DYNSORT:
+				ss->ss_ms.ms_sdflags |= FLG_SY_DYNSORT;
+				ss->ss_ms.ms_sdflags &= ~FLG_SY_NODYNSORT;
+				break;
+			case FLG_SY_EXTERN:
+				ss->ss_ms.ms_sdflags |= FLG_SY_EXTERN;
+				ofl->ofl_flags |= FLG_OF_SYMINFO;
+				break;
+			case FLG_SY_INTPOSE:
+				if (!(ofl->ofl_flags & FLG_OF_EXEC)) {
+					mf_fatal0(mf,
+					    MSG_INTL(MSG_MAP_NOINTPOSE));
+					ss->ss_mv.mv_errcnt++;
+					break;
+				}
+				ss->ss_ms.ms_sdflags |= FLG_SY_INTPOSE;
+				ofl->ofl_flags |= FLG_OF_SYMINFO;
+				ofl->ofl_dtflags_1 |= DF_1_SYMINTPOSE;
+				break;
+			case FLG_SY_NDIR:
+				ss->ss_ms.ms_sdflags |= FLG_SY_NDIR;
+				ofl->ofl_flags |= FLG_OF_SYMINFO;
+				ofl->ofl_flags1 |=
+				    (FLG_OF1_NDIRECT | FLG_OF1_NGLBDIR);
+				break;
+			case FLG_SY_NODYNSORT:
+				ss->ss_ms.ms_sdflags &= ~FLG_SY_DYNSORT;
+				ss->ss_ms.ms_sdflags |= FLG_SY_NODYNSORT;
+				break;
+			case FLG_SY_PARENT:
+				ss->ss_ms.ms_sdflags |= FLG_SY_PARENT;
+				ofl->ofl_flags |= FLG_OF_SYMINFO;
+				break;
+			}
+			break;
+		case TK_RIGHTBKT:
+		case TK_SEMICOLON:
+			done = 1;
+			break;
+
+		default:
+		bad_flag:
+			{
+				char buf[symflag_list_bufsize];
+
+				mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_SYMFLAG),
+				    ld_map_kwnames(symflag_list,
+				    SGSOFFSETOF(symflag_t, name),
+				    sizeof (symflag[0]), buf,
+				    symflag_list_bufsize),
+				    ld_map_tokenstr(tok, &tkv, &inv_buf));
+			}
+			return (TK_ERROR);
+		}
+	}
+
+	/* Make sure there was at least one flag specified */
+	if (cnt == 0) {
+		mf_fatal(mf, MSG_INTL(MSG_MAP_NOVALUES),
+		    MSG_ORIG(MSG_MAPKW_FLAGS));
+		return (TK_ERROR);
+	}
+
+	return (tok);		/* Either TK_SEMICOLON or TK_RIGHTBKT */
+}
+
+/*
+ * SYMBOL [version_name] { symbol_name { SIZE = value
+ * --------------------------------------------^
+ */
+/* ARGSUSED 1 */
+static Token
+at_sym_size(Mapfile *mf, Token eq_tok, void *uvalue)
+{
+	symbol_state_t	*ss = uvalue;
+	ld_map_tkval_t	tkv;
+
+	/* value */
+	if (gettoken_int(mf, MSG_ORIG(MSG_MAPKW_SIZE), &tkv) == TK_ERROR)
+		return (TK_ERROR);
+
+	ss->ss_ms.ms_size = tkv.tkv_int.tkvi_value;
+
+	/* terminator */
+	return (gettoken_term(mf, MSG_ORIG(MSG_MAPKW_SIZE)));
+}
+
+typedef struct {
+	const char	*name;		/* type name */
+	Word		ms_shndx;	/* symbol section index */
+	uchar_t		ms_type;	/* STT_ symbol type */
+} at_sym_type_t;
+
+static at_sym_type_t at_sym_type_list[] = {
+	{ MSG_ORIG(MSG_MAPKW_COMMON),	SHN_COMMON,	STT_OBJECT },
+	{ MSG_ORIG(MSG_MAPKW_DATA),	SHN_ABS,	STT_OBJECT },
+	{ MSG_ORIG(MSG_MAPKW_FUNCTION),	SHN_ABS,	STT_FUNC },
+
+	/* List must be null terminated */
+	{ 0 }
+};
+
+/*
+ * Size of buffer needed to format the names in at_sym_type_list[]. Must
+ * be kept in sync with at_sym_type_list.
+ */
+static size_t	at_sym_type_list_bufsize =
+    KW_NAME_SIZE(MSG_MAPKW_COMMON) +
+    KW_NAME_SIZE(MSG_MAPKW_DATA) +
+    KW_NAME_SIZE(MSG_MAPKW_FUNCTION);
+
+/*
+ * at_sym_type(): Value for TYPE= is not a symbol type
+ */
+static void
+gts_efunc_at_sym_type(Mapfile *mf, Token tok, ld_map_tkval_t *tkv)
+{
+	Conv_inv_buf_t	inv_buf;
+	char		buf[at_sym_type_list_bufsize];
+
+	mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_SYMTYPE),
+	    ld_map_kwnames(at_sym_type_list, SGSOFFSETOF(at_sym_type_t, name),
+	    sizeof (at_sym_type_list[0]), buf, at_sym_type_list_bufsize),
+	    ld_map_tokenstr(tok, tkv, &inv_buf));
+}
+
+/*
+ * SYMBOL [version_name] { symbol_name { TYPE = symbol_type
+ * --------------------------------------------^
+ */
+/* ARGSUSED 1 */
+static Token
+at_sym_type(Mapfile *mf, Token eq_tok, void *uvalue)
+{
+	symbol_state_t	*ss = uvalue;
+	at_sym_type_t	*type;
+	ld_map_tkval_t	tkv;
+
+	/* type keyword */
+	if (gettoken_str(mf, TK_F_KEYWORD, &tkv, gts_efunc_at_sym_type) ==
+	    TK_ERROR)
+		return (TK_ERROR);
+
+	type = ld_map_kwfind(tkv.tkv_str, at_sym_type_list,
+	    SGSOFFSETOF(at_sym_type_t, name), sizeof (type[0]));
+	if (type == NULL) {
+		gts_efunc_at_sym_type(mf, TK_STRING, &tkv);
+		return (TK_ERROR);
+	}
+
+	ss->ss_ms.ms_shndx = type->ms_shndx;
+	ss->ss_ms.ms_sdflags |= FLG_SY_SPECSEC;
+	ss->ss_ms.ms_type = type->ms_type;
+
+	/* terminator */
+	return (gettoken_term(mf, MSG_ORIG(MSG_MAPKW_TYPE)));
+}
+
+/*
+ * SYMBOL [version_name] { symbol_name { VALUE = value
+ * ---------------------------------------------^
+ */
+/* ARGSUSED 1 */
+static Token
+at_sym_value(Mapfile *mf, Token eq_tok, void *uvalue)
+{
+	symbol_state_t	*ss = uvalue;
+	ld_map_tkval_t	tkv;
+
+	/* value */
+	if (gettoken_int(mf, MSG_ORIG(MSG_MAPKW_VALUE), &tkv) == TK_ERROR)
+		return (TK_ERROR);
+
+	ss->ss_ms.ms_value = tkv.tkv_int.tkvi_value;
+	ss->ss_ms.ms_value_set = TRUE;
+
+
+	/* terminator */
+	return (gettoken_term(mf, MSG_ORIG(MSG_MAPKW_VALUE)));
+}
+
+/*
+ * Parse the attributes for a SCOPE or VERSION symbol directive.
+ *
+ * entry:
+ *	mf - Mapfile descriptor
+ *	dir_name - Name of directive.
+ *	ss - Pointer to symbol state block that has had its ss_nv
+ *		member initialzed via a call to ld_map_sym_ver_init().
+ *
+ * exit:
+ *	parse_symbol_attributes() returns TK_RIGHTBKT on success, and TK_ERROR
+ *	on failure.
+ */
+static Token
+parse_symbol_attributes(Mapfile *mf, const char *dir_name, symbol_state_t *ss)
+{
+	/* Symbol attributes */
+	static attr_t attr_list[] = {
+		{ MSG_ORIG(MSG_MAPKW_AUX),	at_sym_aux,	ATTR_FMT_EQ },
+		{ MSG_ORIG(MSG_MAPKW_FILTER),	at_sym_filter,	ATTR_FMT_EQ },
+		{ MSG_ORIG(MSG_MAPKW_FLAGS),	at_sym_flags,	ATTR_FMT_EQ },
+		{ MSG_ORIG(MSG_MAPKW_SIZE),	at_sym_size,	ATTR_FMT_EQ },
+		{ MSG_ORIG(MSG_MAPKW_TYPE),	at_sym_type,	ATTR_FMT_EQ },
+		{ MSG_ORIG(MSG_MAPKW_VALUE),	at_sym_value,	ATTR_FMT_EQ },
+
+		/* List must be null terminated */
+		{ 0 }
+	};
+
+	/*
+	 * Size of buffer needed to format the names in attr_list[]. Must
+	 * be kept in sync with attr_list.
+	 */
+	static size_t	attr_list_bufsize =
+	    KW_NAME_SIZE(MSG_MAPKW_AUX) +
+	    KW_NAME_SIZE(MSG_MAPKW_FILTER) +
+	    KW_NAME_SIZE(MSG_MAPKW_FLAGS) +
+	    KW_NAME_SIZE(MSG_MAPKW_SIZE) +
+	    KW_NAME_SIZE(MSG_MAPKW_TYPE) +
+	    KW_NAME_SIZE(MSG_MAPKW_VALUE);
+
+	Token		tok;
+	ld_map_tkval_t	tkv, tkv_sym;
+	int		done;
+	Conv_inv_buf_t	inv_buf;
+
+	/* Read attributes until the closing '}' is seen */
+	for (done = 0; done == 0; ) {
+		/*
+		 * We have to allow quotes around symbol names, but the
+		 * name we read may also be a symbol scope keyword. We won't
+		 * know which until we read the following token, and so have
+		 * to allow quotes for both. Hence, symbol scope names can
+		 * be quoted --- an unlikely occurrence and not worth
+		 * complicating the code.
+		 */
+		switch (tok = ld_map_gettoken(mf, 0, &tkv_sym)) {
+		case TK_ERROR:
+			return (TK_ERROR);
+
+		case TK_STRING:
+			/* Default value for all symbol attributes is 0 */
+			(void) memset(&ss->ss_ms, 0, sizeof (ss->ss_ms));
+			ss->ss_ms.ms_name = tkv_sym.tkv_str;
+
+			/*
+			 * Turn off the WEAK flag to indicate that definitions
+			 * are associated with this version. It would probably
+			 * be more accurate to only remove this flag with the
+			 * specification of global symbols, however setting it
+			 * here allows enough slop to compensate for the
+			 * various user inputs we've seen so far. Only if a
+			 * closed version is specified (i.e., "SUNW_1.x {};")
+			 * will a user get a weak version (which is how we
+			 * document the creation of weak versions).
+			 */
+			ss->ss_mv.mv_vdp->vd_flags &= ~VER_FLG_WEAK;
+
+			/*
+			 * The meaning of this name depends on the following
+			 * character:
+			 *
+			 *	:	Scope
+			 *	;	Symbol without attributes
+			 *	{	Symbol with attributes
+			 */
+			switch (tok = ld_map_gettoken(mf, 0, &tkv)) {
+			case TK_ERROR:
+				return (TK_ERROR);
+
+			case TK_COLON:
+				ld_map_sym_scope(mf, tkv_sym.tkv_str,
+				    &ss->ss_mv);
+				break;
+			case TK_LEFTBKT:
+				/* name is a symbol with attributes */
+				if (parse_attributes(mf, tkv_sym.tkv_str,
+				    attr_list, attr_list_bufsize, ss) ==
+				    TK_ERROR)
+					return (TK_ERROR);
+				/* Terminating ';', or '}' */
+				tok = gettoken_term(mf,
+				    MSG_INTL(MSG_MAP_SYMATTR));
+				if (tok == TK_ERROR)
+					return (TK_ERROR);
+				if (tok == TK_RIGHTBKT)
+					done = 1;
+
+				/* FALLTHROUGH */
+			case TK_SEMICOLON:
+				/*
+				 * Add the new symbol. It should be noted that
+				 * all symbols added by the mapfile start out
+				 * with global scope, thus they will fall
+				 * through the normal symbol resolution
+				 * process.  Symbols defined as locals will
+				 * be reduced in scope after all input file
+				 * processing.
+				 */
+				if (!ld_map_sym_enter(mf, &ss->ss_mv,
+				    &ss->ss_ms))
+					return (TK_ERROR);
+				break;
+			default:
+				mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_SYMDELIM),
+				    ld_map_tokenstr(tok, &tkv, &inv_buf));
+				return (TK_ERROR);
+			}
+			break;
+
+		case TK_RIGHTBKT:
+			done = 1;
+			break;
+
+		case TK_SEMICOLON:
+			break;		/* Ignore empty statement */
+
+		case TK_STAR:
+			/*
+			 * Turn off the WEAK flag, as explained above for
+			 * TK_STRING.
+			 */
+			ss->ss_mv.mv_vdp->vd_flags &= ~VER_FLG_WEAK;
+
+			ld_map_sym_autoreduce(mf, &ss->ss_mv);
+
+			/*
+			 * Following token must be ';' to terminate the stmt,
+			 * or '}' to terminate the whole directive.
+			 */
+			switch (tok = gettoken_term(mf, dir_name)) {
+			case TK_ERROR:
+				return (TK_ERROR);
+			case TK_RIGHTBKT:
+				done = 1;
+				break;
+			}
+			break;
+
+		default:
+			mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_SYM),
+			    ld_map_tokenstr(tok, &tkv_sym, &inv_buf));
+			return (TK_ERROR);
+		}
+	}
+
+	/*
+	 * In the SYMBOL directive, we keep parsing in the face of
+	 * errors that don't involve resources, to maximize what we
+	 * can report in a single invocation. If we encountered such
+	 * an error, act on the error(s) now.
+	 */
+	if (ss->ss_mv.mv_errcnt)
+		return (TK_ERROR);
+
+	return (tok);
+}
+
+
+/*
+ * Top Level Directive:
+ *
+ * SYMBOL_SCOPE { ...
+ * ------------^
+ */
+static Token
+dir_symbol_scope(Mapfile *mf)
+{
+	symbol_state_t	ss;
+
+	/* The first token must be a '{' */
+	if (gettoken_leftbkt(mf, MSG_ORIG(MSG_MAPKW_SYMBOL_SCOPE)) == TK_ERROR)
+		return (TK_ERROR);
+
+	/* Establish the version descriptor and related data */
+	if (!ld_map_sym_ver_init(mf, NULL, &ss.ss_mv))
+		return (TK_ERROR);
+
+	/* Read attributes until the closing '}' is seen */
+	if (parse_symbol_attributes(mf, MSG_ORIG(MSG_MAPKW_SYMBOL_SCOPE),
+	    &ss) == TK_ERROR)
+		return (TK_ERROR);
+
+	/* Terminating ';' */
+	return (gettoken_semicolon(mf, MSG_ORIG(MSG_MAPKW_SYMBOL_SCOPE)));
+}
+
+
+/*
+ * at_dv_allow(): Value for ALLOW= is not a version string
+ */
+static void
+gts_efunc_dir_symbol_version(Mapfile *mf, Token tok, ld_map_tkval_t *tkv)
+{
+	Conv_inv_buf_t	inv_buf;
+
+	mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_VERSION),
+	    MSG_ORIG(MSG_MAPKW_SYMBOL_VERSION),
+	    ld_map_tokenstr(tok, tkv, &inv_buf));
+}
+
+/*
+ * Top Level Directive:
+ *
+ * SYMBOL_VERSION version_name { ...
+ * --------------^
+ */
+static Token
+dir_symbol_version(Mapfile *mf)
+{
+
+	ld_map_tkval_t	tkv;
+	symbol_state_t	ss;
+
+	/* The first token must be a version name */
+	if (gettoken_str(mf, 0, &tkv, gts_efunc_dir_symbol_version) == TK_ERROR)
+		return (TK_ERROR);
+
+	/* The next token is expected to be '{' */
+	if (gettoken_leftbkt(mf, MSG_ORIG(MSG_MAPKW_SYMBOL_VERSION)) ==
+	    TK_ERROR)
+		return (TK_ERROR);
+
+	/* Establish the version descriptor and related data */
+	if (!ld_map_sym_ver_init(mf, tkv.tkv_str, &ss.ss_mv))
+		return (TK_ERROR);
+
+	/* Read attributes until the closing '}' is seen */
+	if (parse_symbol_attributes(mf, MSG_ORIG(MSG_MAPKW_SYMBOL_VERSION),
+	    &ss) == TK_ERROR)
+		return (TK_ERROR);
+
+	/*
+	 * Determine if any version references are provided after the close
+	 * bracket, parsing up to the terminating ';'.
+	 */
+	if (!ld_map_sym_ver_fini(mf, &ss.ss_mv))
+		return (TK_ERROR);
+
+	return (TK_SEMICOLON);
+}
+
+
+/*
+ * Parse the mapfile --- Solaris syntax
+ */
+Boolean
+ld_map_parse_v2(Mapfile *mf)
+{
+	/* Valid top level mapfile directives */
+	typedef struct {
+		const char	*name;	/* Directive */
+		dir_func_t	func;	/* Function to parse directive */
+	} tldir_t;
+
+
+	tldir_t dirlist[] = {
+		{ MSG_ORIG(MSG_MAPKW_CAPABILITY),	dir_capability },
+		{ MSG_ORIG(MSG_MAPKW_DEPEND_VERSIONS),	dir_depend_versions },
+		{ MSG_ORIG(MSG_MAPKW_HDR_NOALLOC),	dir_hdr_noalloc },
+		{ MSG_ORIG(MSG_MAPKW_LOAD_SEGMENT),	dir_load_segment },
+		{ MSG_ORIG(MSG_MAPKW_NOTE_SEGMENT),	dir_note_segment },
+		{ MSG_ORIG(MSG_MAPKW_NULL_SEGMENT),	dir_null_segment },
+		{ MSG_ORIG(MSG_MAPKW_PHDR_ADD_NULL),	dir_phdr_add_null },
+		{ MSG_ORIG(MSG_MAPKW_SEGMENT_ORDER),	dir_segment_order },
+		{ MSG_ORIG(MSG_MAPKW_STACK),		dir_stack },
+		{ MSG_ORIG(MSG_MAPKW_SYMBOL_SCOPE),	dir_symbol_scope },
+		{ MSG_ORIG(MSG_MAPKW_SYMBOL_VERSION),	dir_symbol_version },
+
+		/* List must be null terminated */
+		{ 0 }
+	};
+
+	/*
+	 * Size of buffer needed to format the names in dirlist[]. Must
+	 * be kept in sync with dirlist.
+	 */
+	static size_t dirlist_bufsize =
+	    KW_NAME_SIZE(MSG_MAPKW_CAPABILITY) +
+	    KW_NAME_SIZE(MSG_MAPKW_DEPEND_VERSIONS) +
+	    KW_NAME_SIZE(MSG_MAPKW_HDR_NOALLOC) +
+	    KW_NAME_SIZE(MSG_MAPKW_LOAD_SEGMENT) +
+	    KW_NAME_SIZE(MSG_MAPKW_NOTE_SEGMENT) +
+	    KW_NAME_SIZE(MSG_MAPKW_NULL_SEGMENT) +
+	    KW_NAME_SIZE(MSG_MAPKW_PHDR_ADD_NULL) +
+	    KW_NAME_SIZE(MSG_MAPKW_SEGMENT_ORDER) +
+	    KW_NAME_SIZE(MSG_MAPKW_STACK) +
+	    KW_NAME_SIZE(MSG_MAPKW_SYMBOL_SCOPE) +
+	    KW_NAME_SIZE(MSG_MAPKW_SYMBOL_VERSION);
+
+	Token		tok;		/* current token. */
+	ld_map_tkval_t	tkv;		/* Value of token */
+	tldir_t		*tldir;
+	Conv_inv_buf_t	inv_buf;
+
+	for (;;) {
+		tok = ld_map_gettoken(mf, TK_F_EOFOK | TK_F_KEYWORD, &tkv);
+		switch (tok) {
+		case TK_ERROR:
+			return (FALSE);
+		case TK_EOF:
+			return (TRUE);
+		case TK_SEMICOLON: /* Terminator, or empty directive: Ignore */
+			break;
+		case TK_STRING:
+			/* Map name to entry in dirlist[] */
+			tldir = ld_map_kwfind(tkv.tkv_str, dirlist,
+			    SGSOFFSETOF(tldir_t, name), sizeof (dirlist[0]));
+
+			/* Not a directive we know? */
+			if (tldir == NULL)
+				goto bad_dirtok;
+
+			/* Call the function associated with this directive */
+			if (tldir->func(mf) == TK_ERROR)
+				return (FALSE);
+			break;
+		default:
+		bad_dirtok:
+			{
+				char buf[dirlist_bufsize];
+
+				mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_DIR),
+				    ld_map_kwnames(dirlist,
+				    SGSOFFSETOF(tldir_t, name),
+				    sizeof (dirlist[0]), buf, dirlist_bufsize),
+				    ld_map_tokenstr(tok, &tkv, &inv_buf));
+			}
+			return (FALSE);
+		}
+	}
+
+	/*NOTREACHED*/
+	assert(0);
+	return (FALSE);
+}
--- a/usr/src/cmd/sgs/libld/common/order.c	Sun Feb 21 21:37:22 2010 -0800
+++ b/usr/src/cmd/sgs/libld/common/order.c	Mon Feb 22 09:19:31 2010 -0700
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -269,11 +269,11 @@
  * unsorted section.
  */
 static uintptr_t
-place_unordered(Ofl_desc *ofl, Is_desc *isp)
+place_unordered(Ofl_desc *ofl, Is_desc *isp, Place_path_info *path_info)
 {
 	isp->is_flags &= ~FLG_IS_ORDERED;
 	if (isp->is_osdesc == NULL)
-		return ((uintptr_t)ld_place_section(ofl, isp,
+		return ((uintptr_t)ld_place_section(ofl, isp, path_info,
 		    isp->is_keyident, NULL));
 	return ((uintptr_t)isp->is_osdesc);
 }
@@ -290,7 +290,8 @@
  * exit:
  */
 uintptr_t
-ld_process_ordered(Ifl_desc *ifl, Ofl_desc *ofl, Word ndx)
+ld_process_ordered(Ofl_desc *ofl, Ifl_desc *ifl, Place_path_info *path_info,
+    Word ndx)
 {
 	Is_desc		*isp2, *isp = ifl->ifl_isdesc[ndx];
 	Xword		shflags = isp->is_shdr->sh_flags;
@@ -315,7 +316,7 @@
 	 */
 	if ((error = is_keyshndx_ok(ifl, keyshndx)) != 0) {
 		DBG_CALL(Dbg_sec_order_error(ofl->ofl_lml, ifl, ndx, error));
-		return (place_unordered(ofl, isp));
+		return (place_unordered(ofl, isp, path_info));
 	}
 
 	/*
@@ -325,7 +326,7 @@
 	 */
 	if ((shflags & SHF_ORDERED) &&
 	    (validate_shf_ordered_dest(ofl, ifl, ndx, &alt_os_name) == FALSE))
-		return (place_unordered(ofl, isp));
+		return (place_unordered(ofl, isp, path_info));
 
 	/*
 	 * Place the section into its output section. It's possible that this
@@ -333,7 +334,8 @@
 	 * which case we're done.
 	 */
 	if ((osp = isp->is_osdesc) == NULL) {
-		osp = ld_place_section(ofl, isp, isp->is_keyident, alt_os_name);
+		osp = ld_place_section(ofl, isp, path_info, isp->is_keyident,
+		    alt_os_name);
 		if ((osp == (Os_desc *)S_ERROR) || (osp == NULL))
 			return ((uintptr_t)osp);
 	}
@@ -396,7 +398,7 @@
 		Os_desc		*osp;
 		Aliste		idx2;
 
-		for (APLIST_TRAVERSE(sgp->sg_secorder, idx2, scop)) {
+		for (ALIST_TRAVERSE(sgp->sg_os_order, idx2, scop)) {
 			if ((scop->sco_flags & FLG_SGO_USED) == 0) {
 				eprintf(ofl->ofl_lml, ERR_WARNING,
 				    MSG_INTL(MSG_MAP_SECORDER),
--- a/usr/src/cmd/sgs/libld/common/outfile.c	Sun Feb 21 21:37:22 2010 -0800
+++ b/usr/src/cmd/sgs/libld/common/outfile.c	Mon Feb 22 09:19:31 2010 -0700
@@ -23,7 +23,7 @@
  *	Copyright (c) 1988 AT&T
  *	  All Rights Reserved
  *
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -381,7 +381,7 @@
 	DBG_CALL(Dbg_basic_create(ofl->ofl_lml));
 
 	/*
-	 * If DF_1_NOHDR was set in map_parse() or FLG_OF1_VADDR was set,
+	 * If DF_1_NOHDR or FLG_OF1_VADDR were set,
 	 * we need to do alignment adjustment.
 	 */
 	if ((flags1 & FLG_OF1_VADDR) ||
@@ -476,6 +476,9 @@
 			} else if (ptype == PT_SUNWCAP) {
 				if (ofl->ofl_oscap)
 					nseg++;
+			} else if (ptype == PT_SUNWSTACK) {
+				if ((sgp->sg_flags & FLG_SG_DISABLED) == 0)
+					nseg++;
 			} else if (sgp->sg_flags & FLG_SG_EMPTY) {
 					nseg++;
 			} else if (sgp->sg_osdescs != NULL) {
@@ -499,14 +502,13 @@
 			ptloadidx++;
 
 			/*
-			 * If the first loadable segment has the ?N flag then
-			 * alignments of following segments need to be fixed,
+			 * If the first loadable segment is not supposed to
+			 * include the ELF or program headers,  alignments
+			 * of the following segments need to be fixed,
 			 * plus a .dynamic FLAGS1 setting is required.
 			 */
-			if (sgp->sg_flags & FLG_SG_NOHDR) {
+			if (ofl->ofl_dtflags_1 & DF_1_NOHDR)
 				fixalign = TRUE;
-				ofl->ofl_dtflags_1 |= DF_1_NOHDR;
-			}
 		}
 
 		shidx = 0;
@@ -606,7 +608,7 @@
 
 				if ((fixalign == TRUE) && (ptype == PT_LOAD) &&
 				    (shidx == 1) && (dataidx == 1))
-					data->d_align = sgp->sg_addralign;
+					data->d_align = sgp->sg_align;
 
 				/*
 				 * Save the first TLS data buffer, as this is
--- a/usr/src/cmd/sgs/libld/common/place.c	Sun Feb 21 21:37:22 2010 -0800
+++ b/usr/src/cmd/sgs/libld/common/place.c	Mon Feb 22 09:19:31 2010 -0700
@@ -23,7 +23,7 @@
  *	Copyright (c) 1988 AT&T
  *	  All Rights Reserved
  *
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -40,11 +40,11 @@
  * Each time a section is placed, the function set_addralign()
  * is called.  This function performs:
  *
- *  .	if the section is from an external file, check if this is empty or not.
+ * -	if the section is from an external file, check if this is empty or not.
  *	If not, we know the segment this section will belong needs a program
  *	header. (Of course, the program is needed only if this section falls
  *	into a loadable segment.)
- *  .	compute the Least Common Multiplier for setting the segment alignment.
+ * -	compute the Least Common Multiplier for setting the segment alignment.
  */
 static void
 set_addralign(Ofl_desc *ofl, Os_desc *osp, Is_desc *isp)
@@ -67,8 +67,8 @@
 	    (osp->os_sgdesc->sg_phdr).p_type != PT_LOAD)
 		return;
 
-	osp->os_sgdesc->sg_addralign =
-	    ld_lcm(osp->os_sgdesc->sg_addralign, shdr->sh_addralign);
+	osp->os_sgdesc->sg_align =
+	    ld_lcm(osp->os_sgdesc->sg_align, shdr->sh_addralign);
 }
 
 /*
@@ -418,12 +418,160 @@
 #undef	NSTR_CH2
 #undef	NSTR_CH3
 
+
+/*
+ * Initialize a path info buffer for use with ld_place_section().
+ *
+ * entry:
+ *	ofl - Output descriptor
+ *	ifl - Descriptor for input file, or NULL if there is none.
+ *	info - Address of buffer to be initialized.
+ *
+ * exit:
+ *	If this is an input file, and if the entrance criteria list
+ *	contains at least one criteria that has a non-empty file string
+ *	match list (ec_files), then the block pointed at by info is
+ *	initialized, and info is returned.
+ *
+ *	If there is no input file, and/or no entrance criteria containing
+ *	a non-empty ec_files list, then NULL is returned. This is not
+ *	an error --- the NULL is simply an optimization, understood by
+ *	ld_place_path(), that allows it to skip unnecessary work.
+ */
+Place_path_info *
+ld_place_path_info_init(Ofl_desc *ofl, Ifl_desc *ifl, Place_path_info *info)
+{
+	/*
+	 * Return NULL if there is no input file (internally generated section)
+	 * or if the entrance criteria list does not contain any items that will
+	 * need to be compared to the path (all the ec_files lists are empty).
+	 */
+	if ((ifl == NULL) || !(ofl->ofl_flags & FLG_OF_EC_FILES))
+		return (NULL);
+
+	info->ppi_path = ifl->ifl_name;
+	info->ppi_path_len = strlen(info->ppi_path);
+	info->ppi_isar = (ifl->ifl_flags & FLG_IF_EXTRACT) != 0;
+
+	/*
+	 * The basename is the final segment of the path, equivalent to
+	 * the path itself if there are no '/' delimiters.
+	 */
+	info->ppi_bname = strrchr(info->ppi_path, '/');
+	if (info->ppi_bname == NULL)
+		info->ppi_bname = info->ppi_path;
+	else
+		info->ppi_bname++;	/* Skip leading '/' */
+	info->ppi_bname_len =
+	    info->ppi_path_len - (info->ppi_bname - info->ppi_path);
+
+	/*
+	 * For an archive, the object name is the member name, which is
+	 * enclosed in () at the end of the name string. Otherwise, it is
+	 * the same as the basename.
+	 */
+	if (info->ppi_isar) {
+		info->ppi_oname = strrchr(info->ppi_bname, '(');
+		/* There must be an archive member suffix delimited by parens */
+		assert((info->ppi_bname[info->ppi_bname_len - 1] == ')') &&
+		    (info->ppi_oname != NULL));
+		info->ppi_oname++;	/* skip leading '(' */
+		info->ppi_oname_len = info->ppi_bname_len -
+		    (info->ppi_oname - info->ppi_bname + 1);
+	} else {
+		info->ppi_oname = info->ppi_bname;
+		info->ppi_oname_len = info->ppi_bname_len;
+	}
+
+	return (info);
+}
+
+/*
+ * Compare an input section path to the file comparison list the given
+ * entrance criteria.
+ *
+ * entry:
+ *	path_info - A non-NULL Place_path_info block for the file
+ *		containing the input section, initialized by
+ *		ld_place_path_info_init()
+ *	enp - Entrance criteria with a non-empty ec_files list of file
+ *		comparisons to be carried out.
+ *
+ * exit:
+ *	Return TRUE if a match is seen, and FALSE otherwise.
+ */
+static Boolean
+eval_ec_files(Place_path_info *path_info, Ent_desc *enp)
+{
+	Aliste		idx;
+	Ent_desc_file	*edfp;
+	size_t		cmp_len;
+	const char	*cmp_str;
+
+	for (ALIST_TRAVERSE(enp->ec_files, idx, edfp)) {
+		Word	type = edfp->edf_flags & TYP_ECF_MASK;
+
+		/*
+		 * Determine the starting character, and # of characters,
+		 * from the file path to compare against this entrance criteria
+		 * file string.
+		 */
+		if (type == TYP_ECF_OBJNAME) {
+			cmp_str = path_info->ppi_oname;
+			cmp_len = path_info->ppi_oname_len;
+		} else {
+			int ar_stat_diff = path_info->ppi_isar !=
+			    ((edfp->edf_flags & FLG_ECF_ARMEMBER) != 0);
+
+			/*
+			 * If the entrance criteria specifies an archive member
+			 * and the file does not, then there can be no match.
+			 */
+
+			if (ar_stat_diff && !path_info->ppi_isar)
+				continue;
+
+			if (type == TYP_ECF_PATH) {
+				cmp_str = path_info->ppi_path;
+				cmp_len = path_info->ppi_path_len;
+			} else {	/* TYP_ECF_BASENAME */
+				cmp_str = path_info->ppi_bname;
+				cmp_len = path_info->ppi_bname_len;
+			}
+
+			/*
+			 * If the entrance criteria does not specify an archive
+			 * member and the file does, then a match just requires
+			 * the paths (without the archive member) to match.
+			 * Reduce the length to not include the ar member or
+			 * the '(' that precedes it.
+			 */
+			if (ar_stat_diff && path_info->ppi_isar)
+				cmp_len = path_info->ppi_oname - cmp_str - 1;
+		}
+
+		/*
+		 * Compare the resulting string to the one from the
+		 * entrance criteria.
+		 */
+		if ((cmp_len == edfp->edf_name_len) &&
+		    (strncmp(edfp->edf_name, cmp_str, cmp_len) == 0))
+			return (TRUE);
+	}
+
+	return (FALSE);
+}
+
 /*
  * Place a section into the appropriate segment and output section.
  *
  * entry:
  *	ofl - File descriptor
  *	isp - Input section descriptor of section to be placed.
+ *	path_info - NULL, or pointer to Place_path_info buffer initialized
+ *		by ld_place_path_info_init() for the file associated to isp,
+ *		for use in processing entrance criteria with non-empty
+ *		file matching string list (ec_files)
  *	ident - Section identifier, used to order sections relative to
  *		others within the output segment.
  *	alt_os_name - If non-NULL, the name of the output section to place
@@ -431,8 +579,8 @@
  *		with the same name as the input section.
  */
 Os_desc *
-ld_place_section(Ofl_desc *ofl, Is_desc *isp, int ident,
-    const char *alt_os_name)
+ld_place_section(Ofl_desc *ofl, Is_desc *isp, Place_path_info *path_info,
+    int ident, const char *alt_os_name)
 {
 	Ent_desc	*enp;
 	Sg_desc		*sgp;
@@ -523,10 +671,32 @@
 	 * finding a segment, then sgp will be NULL.
 	 */
 	sgp = NULL;
-	for (ALIST_TRAVERSE(ofl->ofl_ents, idx1, enp)) {
-		if (enp->ec_segment &&
-		    (enp->ec_segment->sg_flags & FLG_SG_DISABLED))
+	for (APLIST_TRAVERSE(ofl->ofl_ents, idx1, enp)) {
+
+		/* Disabled segments are not available for assignment */
+		if (enp->ec_segment->sg_flags & FLG_SG_DISABLED)
 			continue;
+
+		/*
+		 * If an entrance criteria doesn't have any of its fields
+		 * set, it will match any section it is tested against.
+		 * We set the FLG_EC_CATCHALL flag on these, primarily because
+		 * it helps readers of our debug output to understand what
+		 * the criteria means --- otherwise the user would just see
+		 * that every field is 0, but might not understand the
+		 * significance of that.
+		 *
+		 * Given that we set this flag, we can use it here as an
+		 * optimization to short circuit all of the tests in this
+		 * loop. Note however, that if we did not do this, the end
+		 * result would be the same --- the empty criteria will sail
+		 * past the following tests and reach the end of the loop.
+		 */
+		if (enp->ec_flags & FLG_EC_CATCHALL) {
+			sgp = enp->ec_segment;
+			break;
+		}
+
 		if (enp->ec_type && (enp->ec_type != shdr->sh_type))
 			continue;
 		if (enp->ec_attrmask &&
@@ -534,52 +704,41 @@
 		    (enp->ec_attrmask & enp->ec_attrbits) !=
 		    (enp->ec_attrmask & shflags))
 			continue;
-		if (((enp->ec_flags & FLG_EC_BUILTIN) == 0) &&
-		    enp->ec_name && (strcmp(enp->ec_name, isp->is_name) != 0))
+		if (enp->ec_is_name &&
+		    (strcmp(enp->ec_is_name, isp->is_name) != 0))
 			continue;
-		if (enp->ec_files) {
-			Aliste	idx2;
-			char	*file;
-			int	found = 0;
-
-			if (isp->is_file == NULL)
-				continue;
-
-			for (APLIST_TRAVERSE(enp->ec_files, idx2, file)) {
-				const char	*name = isp->is_file->ifl_name;
-
-				if (file[0] == '*') {
-					const char	*basename;
 
-					basename = strrchr(name, '/');
-					if (basename == NULL)
-						basename = name;
-					else if (basename[1] != '\0')
-						basename++;
+		if ((alist_nitems(enp->ec_files) > 0) &&
+		    ((path_info == NULL) || !eval_ec_files(path_info, enp)))
+			continue;
 
-					if (strcmp(&file[1], basename) == 0) {
-						found++;
-						break;
-					}
-				} else {
-					if (strcmp(file, name) == 0) {
-						found++;
-						break;
-					}
-				}
-			}
-			if (!found)
-				continue;
-		}
+		/* All entrance criteria tests passed */
 		sgp = enp->ec_segment;
 		break;
 	}
 
-	if (sgp == NULL) {
-		enp = alist_item(ofl->ofl_ents,
-		    alist_nitems(ofl->ofl_ents) - 1);
-		sgp = enp->ec_segment;
-	}
+	/*
+	 * The final entrance criteria record is a FLG_EC_CATCHALL that points
+	 * at the final predefined segment "extra", and this final segment is
+	 * tagged FLG_SG_NODISABLE. Therefore, the above loop must always find
+	 * a segment.
+	 */
+	assert(sgp != NULL);
+
+	/*
+	 * Transfer the input section sorting key from the entrance criteria
+	 * to the input section. A non-zero value means that the section
+	 * will be sorted on this key amoung the other sections that have a
+	 * non-zero key. These sorted sections are collectively placed at the
+	 * head of the output section.
+	 *
+	 * If the sort key is 0, the section is placed after the sorted
+	 * sections in the order they are encountered.
+	 */
+	isp->is_ordndx = enp->ec_ordndx;
+
+	/* Remember that this entrance criteria has placed a section */
+	enp->ec_flags |= FLG_EC_USED;
 
 	/*
 	 * If our caller has supplied an alternative name for the output
@@ -605,13 +764,13 @@
 	 * This convention has also been followed for COMDAT and sections
 	 * identified though SHT_GROUP data.
 	 *
-	 * Strip out the % from the section name in all cases except:
-	 *
-	 *    i.	when '-r' is used without '-M', and
-	 *    ii.	when '-r' is used with '-M' but without the ?O flag.
+	 * Strip out the % from the section name for:
+	 *	- Non-relocatable objects
+	 *	- Relocatable objects if input section sorting is
+	 *	  in force for the segment in question.
 	 */
 	if (((ofl->ofl_flags & FLG_OF_RELOBJ) == 0) ||
-	    (sgp->sg_flags & FLG_SG_ORDER)) {
+	    (sgp->sg_flags & FLG_SG_IS_ORDER)) {
 		if ((sname = strchr(isp->is_name, '%')) != NULL) {
 			size_t	size = sname - isp->is_name;
 
@@ -621,7 +780,6 @@
 			oname[size] = '\0';
 			DBG_CALL(Dbg_sec_redirected(ofl->ofl_lml, isp, oname));
 		}
-		isp->is_ordndx = enp->ec_ordndx;
 	}
 
 	/*
@@ -654,8 +812,8 @@
 		isp->is_flags |= FLG_IS_COMDAT;
 		if ((ofl->ofl_flags1 & FLG_OF1_NRLXREL) == 0)
 			ofl->ofl_flags1 |= FLG_OF1_RLXREL;
-		Dbg_sec_gnu_comdat(ofl->ofl_lml, isp, TRUE,
-		    (ofl->ofl_flags1 & FLG_OF1_RLXREL) != 0);
+		DBG_CALL(Dbg_sec_gnu_comdat(ofl->ofl_lml, isp, TRUE,
+		    (ofl->ofl_flags1 & FLG_OF1_RLXREL) != 0));
 	}
 
 	/*
@@ -685,7 +843,8 @@
 		 */
 		if ((ofl->ofl_flags1 & FLG_OF1_NRLXREL) == 0) {
 			ofl->ofl_flags1 |= FLG_OF1_RLXREL;
-			Dbg_sec_gnu_comdat(ofl->ofl_lml, isp, FALSE, TRUE);
+			DBG_CALL(Dbg_sec_gnu_comdat(ofl->ofl_lml, isp,
+			    FALSE, TRUE));
 		}
 	}
 
@@ -695,23 +854,25 @@
 	 */
 	onamehash = sgs_str_hash(oname);
 
-	if (sgp->sg_flags & FLG_SG_ORDER)
-		enp->ec_flags |= FLG_EC_USED;
-
 	/*
-	 * Determine if section ordering is turned on. If so, return the
-	 * appropriate ordering index for the section. This information
-	 * is derived from the Sg_desc->sg_segorder list that was built
+	 * Determine if output section ordering is turned on. If so, return
+	 * the appropriate ordering index for the section. This information
+	 * is derived from the Sg_desc->sg_os_order list that was built
 	 * up from the Mapfile.
+	 *
+	 * A value of 0 for os_ndx means that the section is not sorted
+	 * (i.e. is not found in the sg_os_order). The items in sg_os_order
+	 * are in the desired sort order, so adding 1 to their alist index
+	 * gives a suitable index for sorting.
 	 */
 	os_ndx = 0;
-	if (sgp->sg_secorder) {
+	if (alist_nitems(sgp->sg_os_order) > 0) {
 		Sec_order	*scop;
 
-		for (APLIST_TRAVERSE(sgp->sg_secorder, idx1, scop)) {
+		for (ALIST_TRAVERSE(sgp->sg_os_order, idx1, scop)) {
 			if (strcmp(scop->sco_secname, oname) == 0) {
 				scop->sco_flags |= FLG_SGO_USED;
-				os_ndx = scop->sco_index;
+				os_ndx = idx1 + 1;
 				break;
 			}
 		}
@@ -782,7 +943,7 @@
 			 */
 
 			if (os_attach_isp(ofl, osp, isp,
-			    (sgp->sg_flags & FLG_SG_ORDER) != 0) == 0)
+			    (sgp->sg_flags & FLG_SG_IS_ORDER) != 0) == 0)
 				return ((Os_desc *)S_ERROR);
 
 			/*
@@ -952,7 +1113,7 @@
 	if ((sgp->sg_phdr.p_type == PT_LOAD) &&
 	    ((osp->os_shdr->sh_flags & SHF_ALLOC) == 0)) {
 		eprintf(ofl->ofl_lml, ERR_WARNING, MSG_INTL(MSG_SCN_NONALLOC),
-		    ofl->ofl_name, osp->os_name);
+		    ofl->ofl_name, osp->os_name, sgp->sg_name);
 		osp->os_shdr->sh_flags |= SHF_ALLOC;
 	}
 
--- a/usr/src/cmd/sgs/libld/common/sections.c	Sun Feb 21 21:37:22 2010 -0800
+++ b/usr/src/cmd/sgs/libld/common/sections.c	Mon Feb 22 09:19:31 2010 -0700
@@ -23,7 +23,7 @@
  *	Copyright (c) 1988 AT&T
  *	  All Rights Reserved
  *
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -771,7 +771,7 @@
 	 * Retain this .*bss input section as this will be where global symbol
 	 * references are added.
 	 */
-	if ((osp = ld_place_section(ofl, isec, ident, NULL)) ==
+	if ((osp = ld_place_section(ofl, isec, NULL, ident, NULL)) ==
 	    (Os_desc *)S_ERROR)
 		return (S_ERROR);
 
@@ -829,7 +829,7 @@
 	if ((data->d_buf = libld_calloc(sizeof (Addr), entcount)) == NULL)
 		return (S_ERROR);
 
-	if (ld_place_section(ofl, isec, ld_targ.t_id.id_array, NULL) ==
+	if (ld_place_section(ofl, isec, NULL, ld_targ.t_id.id_array, NULL) ==
 	    (Os_desc *)S_ERROR)
 		return (S_ERROR);
 
@@ -909,7 +909,7 @@
 	shdr->sh_flags = 0;
 	shdr->sh_addralign = 1;
 
-	return ((uintptr_t)ld_place_section(ofl, isec,
+	return ((uintptr_t)ld_place_section(ofl, isec, NULL,
 	    ld_targ.t_id.id_note, NULL));
 }
 
@@ -960,7 +960,7 @@
 		shdr->sh_flags |= SHF_ALLOC;
 
 	osp = ofl->ofl_osdynamic =
-	    ld_place_section(ofl, isec, ld_targ.t_id.id_dynamic, NULL);
+	    ld_place_section(ofl, isec, NULL, ld_targ.t_id.id_dynamic, NULL);
 
 	/*
 	 * Reserve entries for any needed dependencies.
@@ -1288,7 +1288,8 @@
 	shdr->sh_size = (Xword)size;
 	shdr->sh_entsize = ld_targ.t_m.m_got_entsize;
 
-	ofl->ofl_osgot = ld_place_section(ofl, isec, ld_targ.t_id.id_got, NULL);
+	ofl->ofl_osgot = ld_place_section(ofl, isec, NULL,
+	    ld_targ.t_id.id_got, NULL);
 	if (ofl->ofl_osgot == (Os_desc *)S_ERROR)
 		return (S_ERROR);
 
@@ -1343,11 +1344,30 @@
 	data->d_align = shdr->sh_addralign = 1;
 
 	ofl->ofl_osinterp =
-	    ld_place_section(ofl, isec, ld_targ.t_id.id_interp, NULL);
+	    ld_place_section(ofl, isec, NULL, ld_targ.t_id.id_interp, NULL);
 	return ((uintptr_t)ofl->ofl_osinterp);
 }
 
 /*
+ * Output debugging information for the given capability mask.
+ */
+static void
+dbg_capmask(Ofl_desc *ofl, Word type, CapMask *capmask)
+{
+	/*
+	 * If this capability has excluded bits, then show the current
+	 * internal state. Otherwise, don't bother, because it's identical
+	 * to the final output value.
+	 */
+	if (capmask->cm_exclude)
+		Dbg_cap_entry2(ofl->ofl_lml, DBG_STATE_CURRENT, type,
+		    capmask, ld_targ.t_m.m_mach);
+
+	Dbg_cap_entry(ofl->ofl_lml, DBG_STATE_OUT, type,
+	    CAPMASK_VALUE(capmask), ld_targ.t_m.m_mach);
+}
+
+/*
  * Build a hardware/software capabilities section.
  */
 static uintptr_t
@@ -1359,18 +1379,36 @@
 	Os_desc		*osec;
 	Cap		*cap;
 	size_t		size = 0;
+	elfcap_mask_t	hw_1, sf_1;
+
+	/* Final capability masks with excluded bits removed */
+	hw_1 = CAPMASK_VALUE(&ofl->ofl_ocapset.c_hw_1);
+	sf_1 = CAPMASK_VALUE(&ofl->ofl_ocapset.c_sf_1);
 
 	/*
 	 * Determine how many entries are required.
 	 */
-	if (ofl->ofl_hwcap_1)
+	if (hw_1)
 		size++;
-	if (ofl->ofl_sfcap_1)
+	if (sf_1)
 		size++;
 	if (size == 0)
 		return (1);
 	size++;				/* Add CA_SUNW_NULL */
 
+	if (DBG_ENABLED) {
+		Dbg_cap_out_title(ofl->ofl_lml);
+
+		if (hw_1)
+			dbg_capmask(ofl, CA_SUNW_HW_1,
+			    &ofl->ofl_ocapset.c_hw_1);
+
+		if (sf_1)
+			dbg_capmask(ofl, CA_SUNW_SF_1,
+			    &ofl->ofl_ocapset.c_sf_1);
+	}
+
+
 	if (new_section(ofl, SHT_SUNW_cap, MSG_ORIG(MSG_SCN_SUNWCAP), size,
 	    &isec, &shdr, &data) == S_ERROR)
 		return (S_ERROR);
@@ -1379,14 +1417,14 @@
 		return (S_ERROR);
 
 	cap = (Cap *)data->d_buf;
-	if (ofl->ofl_hwcap_1) {
+	if (hw_1) {
 		cap->c_tag = CA_SUNW_HW_1;
-		cap->c_un.c_val = ofl->ofl_hwcap_1;
+		cap->c_un.c_val = hw_1;
 		cap++;
 	}
-	if (ofl->ofl_sfcap_1) {
+	if (sf_1) {
 		cap->c_tag = CA_SUNW_SF_1;
-		cap->c_un.c_val = ofl->ofl_sfcap_1;
+		cap->c_un.c_val = sf_1;
 		cap++;
 	}
 	cap->c_tag = CA_SUNW_NULL;
@@ -1396,7 +1434,7 @@
 	 * If we're not creating a relocatable object, save the output section
 	 * to trigger the creation of an associated program header.
 	 */
-	osec = ld_place_section(ofl, isec, ld_targ.t_id.id_cap, NULL);
+	osec = ld_place_section(ofl, isec, NULL, ld_targ.t_id.id_cap, NULL);
 	if ((ofl->ofl_flags & FLG_OF_RELOBJ) == 0)
 		ofl->ofl_oscap = osec;
 
@@ -1435,7 +1473,8 @@
 	shdr->sh_addralign = ld_targ.t_m.m_plt_align;
 	shdr->sh_entsize = ld_targ.t_m.m_plt_entsize;
 
-	ofl->ofl_osplt = ld_place_section(ofl, isec, ld_targ.t_id.id_plt, NULL);
+	ofl->ofl_osplt = ld_place_section(ofl, isec, NULL,
+	    ld_targ.t_id.id_plt, NULL);
 	if (ofl->ofl_osplt == (Os_desc *)S_ERROR)
 		return (S_ERROR);
 
@@ -1472,7 +1511,7 @@
 	 * count.
 	 */
 	ofl->ofl_oshash =
-	    ld_place_section(ofl, isec, ld_targ.t_id.id_hash, NULL);
+	    ld_place_section(ofl, isec, NULL, ld_targ.t_id.id_hash, NULL);
 	if (ofl->ofl_oshash == (Os_desc *)S_ERROR)
 		return (S_ERROR);
 
@@ -1529,7 +1568,7 @@
 	 * Place the section first since it will affect the local symbol
 	 * count.
 	 */
-	if ((ofl->ofl_ossymtab = ld_place_section(ofl, isec,
+	if ((ofl->ofl_ossymtab = ld_place_section(ofl, isec, NULL,
 	    ld_targ.t_id.id_symtab, NULL)) == (Os_desc *)S_ERROR)
 		return (S_ERROR);
 
@@ -1547,7 +1586,7 @@
 		    &xshdr, &xdata) == S_ERROR)
 			return (S_ERROR);
 
-		if ((ofl->ofl_ossymshndx = ld_place_section(ofl, xisec,
+		if ((ofl->ofl_ossymshndx = ld_place_section(ofl, xisec, NULL,
 		    ld_targ.t_id.id_symtab_ndx, NULL)) == (Os_desc *)S_ERROR)
 			return (S_ERROR);
 	}
@@ -1632,11 +1671,11 @@
 	 * count.
 	 */
 	if (allow_ldynsym &&
-	    ((ofl->ofl_osldynsym = ld_place_section(ofl, lisec,
+	    ((ofl->ofl_osldynsym = ld_place_section(ofl, lisec, NULL,
 	    ld_targ.t_id.id_ldynsym, NULL)) == (Os_desc *)S_ERROR))
 		return (S_ERROR);
 	ofl->ofl_osdynsym =
-	    ld_place_section(ofl, isec, ld_targ.t_id.id_dynsym, NULL);
+	    ld_place_section(ofl, isec, NULL, ld_targ.t_id.id_dynsym, NULL);
 	if (ofl->ofl_osdynsym == (Os_desc *)S_ERROR)
 		return (S_ERROR);
 
@@ -1689,7 +1728,7 @@
 		    &isec, &shdr, &data) == S_ERROR)
 		return (S_ERROR);
 
-		if ((ofl->ofl_osdynsymsort = ld_place_section(ofl, isec,
+		if ((ofl->ofl_osdynsymsort = ld_place_section(ofl, isec, NULL,
 		    ld_targ.t_id.id_dynsort, NULL)) == (Os_desc *)S_ERROR)
 			return (S_ERROR);
 	}
@@ -1701,7 +1740,7 @@
 		    ofl->ofl_dyntlssortcnt, &isec, &shdr, &data) == S_ERROR)
 		return (S_ERROR);
 
-		if ((ofl->ofl_osdyntlssort = ld_place_section(ofl, isec,
+		if ((ofl->ofl_osdyntlssort = ld_place_section(ofl, isec, NULL,
 		    ld_targ.t_id.id_dynsort, NULL)) == (Os_desc *)S_ERROR)
 			return (S_ERROR);
 	}
@@ -1731,7 +1770,7 @@
 	    &isec, &shdr, &data) == S_ERROR)
 		return (S_ERROR);
 
-	if ((*ret_os = ld_place_section(ofl, isec,
+	if ((*ret_os = ld_place_section(ofl, isec, NULL,
 	    ld_targ.t_id.id_dynsym_ndx, NULL)) == (Os_desc *)S_ERROR)
 		return (S_ERROR);
 
@@ -1785,7 +1824,7 @@
 	 * headers to account for.
 	 */
 	ofl->ofl_osshstrtab =
-	    ld_place_section(ofl, isec, ld_targ.t_id.id_note, NULL);
+	    ld_place_section(ofl, isec, NULL, ld_targ.t_id.id_note, NULL);
 	if (ofl->ofl_osshstrtab == (Os_desc *)S_ERROR)
 		return (S_ERROR);
 
@@ -1829,7 +1868,7 @@
 	shdr->sh_size = (Xword)size;
 
 	ofl->ofl_osstrtab =
-	    ld_place_section(ofl, isec, ld_targ.t_id.id_strtab, NULL);
+	    ld_place_section(ofl, isec, NULL, ld_targ.t_id.id_strtab, NULL);
 	return ((uintptr_t)ofl->ofl_osstrtab);
 }
 
@@ -1909,7 +1948,7 @@
 	shdr->sh_size = (Xword)size;
 
 	ofl->ofl_osdynstr =
-	    ld_place_section(ofl, isec, ld_targ.t_id.id_dynstr, NULL);
+	    ld_place_section(ofl, isec, NULL, ld_targ.t_id.id_dynstr, NULL);
 	return ((uintptr_t)ofl->ofl_osdynstr);
 }
 
@@ -1987,7 +2026,7 @@
 		shdr->sh_flags |= SHF_INFO_LINK;
 	}
 
-	rosp = ld_place_section(ofl, isec, ld_targ.t_id.id_rel, NULL);
+	rosp = ld_place_section(ofl, isec, NULL, ld_targ.t_id.id_rel, NULL);
 	if (rosp == (Os_desc *)S_ERROR)
 		return (S_ERROR);
 
@@ -2054,7 +2093,7 @@
 	shdr->sh_size = (Xword)ofl->ofl_verneedsz;
 
 	ofl->ofl_osverneed =
-	    ld_place_section(ofl, isec, ld_targ.t_id.id_version, NULL);
+	    ld_place_section(ofl, isec, NULL, ld_targ.t_id.id_version, NULL);
 	return ((uintptr_t)ofl->ofl_osverneed);
 }
 
@@ -2101,7 +2140,7 @@
 	shdr->sh_size = (Xword)ofl->ofl_verdefsz;
 
 	ofl->ofl_osverdef =
-	    ld_place_section(ofl, isec, ld_targ.t_id.id_version, NULL);
+	    ld_place_section(ofl, isec, NULL, ld_targ.t_id.id_version, NULL);
 	return ((uintptr_t)ofl->ofl_osverdef);
 }
 
@@ -2125,7 +2164,7 @@
 	    S_ERROR)
 		return ((Os_desc *)S_ERROR);
 
-	return (ld_place_section(ofl, isec, ident, NULL));
+	return (ld_place_section(ofl, isec, NULL, ident, NULL));
 }
 
 /*
@@ -2160,7 +2199,7 @@
 	 * such global references are added and '-z nopartial' is in effect.
 	 */
 	ofl->ofl_isparexpn = isec;
-	osp = ld_place_section(ofl, isec, ld_targ.t_id.id_data, NULL);
+	osp = ld_place_section(ofl, isec, NULL, ld_targ.t_id.id_data, NULL);
 	if (osp == (Os_desc *)S_ERROR)
 		return (S_ERROR);
 
@@ -2206,7 +2245,7 @@
 			mdp->md_oidx = cnt++;
 	}
 
-	if ((ofl->ofl_osmove = ld_place_section(ofl, isec, 0, NULL)) ==
+	if ((ofl->ofl_osmove = ld_place_section(ofl, isec, NULL, 0, NULL)) ==
 	    (Os_desc *)S_ERROR)
 		return (S_ERROR);
 
@@ -2474,7 +2513,7 @@
 		goto return_s_error;
 
 	/* Add the new section to the output image */
-	if (ld_place_section(ofl, mstrsec, osp->os_identndx, NULL) ==
+	if (ld_place_section(ofl, mstrsec, NULL, osp->os_identndx, NULL) ==
 	    (Os_desc *)S_ERROR)
 		goto return_s_error;
 
@@ -2600,8 +2639,8 @@
 	}
 
 	/* Report how much space we saved in the output section */
-	Dbg_sec_genstr_compress(ofl->ofl_lml, osp->os_name, data_size,
-	    mstr_data->d_size);
+	DBG_CALL(Dbg_sec_genstr_compress(ofl->ofl_lml, osp->os_name, data_size,
+	    mstr_data->d_size));
 
 	st_destroy(mstrtab);
 	return (1);
@@ -2727,9 +2766,9 @@
 				}
 		}
 		if (rel_alpp != NULL)
-			free(rel_alpp);
+			libld_free(rel_alpp);
 		if (sym_alpp != NULL)
-			free(sym_alpp);
+			libld_free(sym_alpp);
 		if (error_seen != 0)
 			return (S_ERROR);
 	}
--- a/usr/src/cmd/sgs/libld/common/syms.c	Sun Feb 21 21:37:22 2010 -0800
+++ b/usr/src/cmd/sgs/libld/common/syms.c	Mon Feb 22 09:19:31 2010 -0700
@@ -24,7 +24,7 @@
  *	  All Rights Reserved
  *
  *
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -959,10 +959,6 @@
 		 * from any initial relocation processing that references this
 		 * symbol, or from the symbol validation processing.
 		 *
-		 * This routine is called either from any initial relocation
-		 * processing that references this symbol, or from the symbol
-		 * validation processing.
-		 *
 		 * A symbol is a candidate for auto-reduction/elimination if:
 		 *
 		 *  -	the symbol wasn't explicitly defined within a mapfile
--- a/usr/src/cmd/sgs/libld/common/unwind.c	Sun Feb 21 21:37:22 2010 -0800
+++ b/usr/src/cmd/sgs/libld/common/unwind.c	Mon Feb 22 09:19:31 2010 -0700
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -363,7 +363,7 @@
 	isp->is_shdr = shdr;
 	isp->is_indata = elfdata;
 
-	if ((ofl->ofl_unwindhdr = ld_place_section(ofl, isp,
+	if ((ofl->ofl_unwindhdr = ld_place_section(ofl, isp, NULL,
 	    ld_targ.t_id.id_unwindhdr, NULL)) == (Os_desc *)S_ERROR)
 		return (S_ERROR);
 
--- a/usr/src/cmd/sgs/libld/common/update.c	Sun Feb 21 21:37:22 2010 -0800
+++ b/usr/src/cmd/sgs/libld/common/update.c	Mon Feb 22 09:19:31 2010 -0700
@@ -23,7 +23,7 @@
  *	Copyright (c) 1988 AT&T
  *	  All Rights Reserved
  *
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -3215,7 +3215,7 @@
 	 */
 	if (ofl->ofl_flags & FLG_OF_EXEC) {
 #if	defined(_ELF64)
-		if (ofl->ofl_sfcap_1 & SF1_SUNW_ADDR32)
+		if (ofl->ofl_ocapset.c_sf_1.cm_value & SF1_SUNW_ADDR32)
 			vaddr = ld_targ.t_m.m_segm_aorigin;
 		else
 #endif
@@ -3228,9 +3228,10 @@
 	 */
 	DBG_CALL(Dbg_seg_title(ofl->ofl_lml));
 	for (APLIST_TRAVERSE(ofl->ofl_segs, idx1, sgp)) {
-		Phdr	*phdr = &(sgp->sg_phdr);
-		Xword 	p_align;
-		Aliste	idx2;
+		Phdr		*phdr = &(sgp->sg_phdr);
+		Xword 		p_align;
+		Aliste		idx2;
+		Sym_desc	*sdp;
 
 		segndx++;
 
@@ -3341,6 +3342,17 @@
 		}
 
 		/*
+		 * The sunwstack program is used to convey non-default
+		 * flags for the process stack. Only emit it if it would
+		 * change the default.
+		 */
+		if (phdr->p_type == PT_SUNWSTACK) {
+			if ((sgp->sg_flags & FLG_SG_DISABLED) == 0)
+				ofl->ofl_phdr[phdrndx++] = *phdr;
+			continue;
+		}
+
+		/*
 		 * As the TLS program header occurs after the loadable
 		 * headers in the segment descriptor table, all the address
 		 * information for the .tls output section will have been
@@ -3506,11 +3518,11 @@
 		}
 
 		/*
-		 * If a segment size symbol is required (specified via a
-		 * mapfile) update its value.
+		 * If segment size symbols are required (specified via a
+		 * mapfile) update their value.
 		 */
-		if (sgp->sg_sizesym != NULL)
-			sgp->sg_sizesym->sd_sym->st_value = phdr->p_memsz;
+		for (APLIST_TRAVERSE(sgp->sg_sizesym, idx2, sdp))
+			sdp->sd_sym->st_value = phdr->p_memsz;
 
 		/*
 		 * If no file content has been assigned to this segment (it
@@ -3522,11 +3534,11 @@
 
 		/*
 		 * If a virtual address has been specified for this segment
-		 * (presumably from a mapfile) use it and make sure the
-		 * previous segment does not run into this segment.
+		 * from a mapfile use it and make sure the previous segment
+		 * does not run into this segment.
 		 */
 		if (phdr->p_type == PT_LOAD) {
-			if ((sgp->sg_flags & FLG_SG_VADDR)) {
+			if ((sgp->sg_flags & FLG_SG_P_VADDR)) {
 				if (_phdr && (vaddr > phdr->p_vaddr) &&
 				    (phdr->p_type == PT_LOAD))
 					eprintf(ofl->ofl_lml, ERR_WARNING,
@@ -3545,7 +3557,7 @@
 		/*
 		 * Adjust the address offset and p_align if needed.
 		 */
-		if (((sgp->sg_flags & FLG_SG_VADDR) == 0) &&
+		if (((sgp->sg_flags & FLG_SG_P_VADDR) == 0) &&
 		    ((ofl->ofl_dtflags_1 & DF_1_NOHDR) == 0)) {
 			if (phdr->p_align != 0)
 				vaddr += phdr->p_offset % phdr->p_align;
--- a/usr/src/cmd/sgs/liblddbg/common/cap.c	Sun Feb 21 21:37:22 2010 -0800
+++ b/usr/src/cmd/sgs/liblddbg/common/cap.c	Mon Feb 22 09:19:31 2010 -0700
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -64,26 +64,9 @@
 	Dbg_util_nl(lml, DBG_NL_FRC);
 }
 
-static const Msg captype[] = {
-	MSG_STR_INITIAL,		/* MSG_INTL(MSG_STR_INITIAL) */
-	MSG_STR_IGNORE,			/* MSG_INTL(MSG_STR_IGNORE) */
-	MSG_STR_OLD,			/* MSG_INTL(MSG_STR_OLD) */
-	MSG_STR_NEW,			/* MSG_INTL(MSG_STR_NEW) */
-	MSG_STR_RESOLVED		/* MSG_INTL(MSG_STR_RESOLVED) */
-};
-
 void
-Dbg_cap_mapfile(Lm_list *lml, Xword tag, Xword val, Half mach)
-{
-	if (DBG_NOTCLASS(DBG_C_MAP | DBG_C_CAP))
-		return;
-
-	dbg_print(lml, MSG_INTL(MSG_MAP_CAP));
-	Dbg_cap_sec_entry(lml, DBG_CAP_INITIAL, tag, val, mach);
-}
-
-void
-Dbg_cap_sec_entry(Lm_list *lml, uint_t type, Xword tag, Xword val, Half mach)
+Dbg_cap_entry(Lm_list *lml, dbg_state_t dbg_state, Xword tag, Xword val,
+    Half mach)
 {
 	Conv_inv_buf_t		inv_buf;
 	Conv_cap_val_buf_t	cap_val_buf;
@@ -91,11 +74,40 @@
 	if (DBG_NOTCLASS(DBG_C_CAP))
 		return;
 
-	dbg_print(lml, MSG_INTL(MSG_CAP_SEC_ENTRY), MSG_INTL(captype[type]),
+	dbg_print(lml, MSG_INTL(MSG_CAP_ENTRY), Dbg_state_str(dbg_state),
 	    conv_cap_tag(tag, 0, &inv_buf), conv_cap_val(tag, val, mach,
 	    &cap_val_buf));
 }
 
+/*
+ * This version takes a pointer to a CapMask, and will report the exclusion
+ * bits if they exist.
+ */
+void
+Dbg_cap_entry2(Lm_list *lml, dbg_state_t dbg_state, Xword tag, CapMask *cmp,
+    Half mach)
+{
+	Conv_inv_buf_t		inv_buf;
+	Conv_cap_val_buf_t	cap_val_buf1, cap_val_buf2;
+
+	if (DBG_NOTCLASS(DBG_C_CAP))
+		return;
+
+	/* If there is no exclusion mask, use the simpler format */
+	if (cmp->cm_exclude == 0) {
+		dbg_print(lml, MSG_INTL(MSG_CAP_ENTRY),
+		    Dbg_state_str(dbg_state), conv_cap_tag(tag, 0, &inv_buf),
+		    conv_cap_val(tag, cmp->cm_value, mach, &cap_val_buf1));
+		return;
+	}
+
+
+	dbg_print(lml, MSG_INTL(MSG_CAP_ENTRY_EXC), Dbg_state_str(dbg_state),
+	    conv_cap_tag(tag, 0, &inv_buf),
+	    conv_cap_val(tag, cmp->cm_value, mach, &cap_val_buf1),
+	    conv_cap_val(tag, cmp->cm_exclude, mach, &cap_val_buf2));
+}
+
 void
 Dbg_cap_sec_title(Lm_list *lml, const char *name)
 {
@@ -107,6 +119,25 @@
 }
 
 void
+Dbg_cap_out_title(Lm_list *lml)
+{
+	if (DBG_NOTCLASS(DBG_C_CAP))
+		return;
+
+	Dbg_util_nl(lml, DBG_NL_STD);
+	dbg_print(lml, MSG_INTL(MSG_CAP_OUT_TITLE));
+}
+
+void
+Dbg_cap_mapfile_title(Lm_list *lml, Lineno lineno)
+{
+	if (DBG_NOTCLASS(DBG_C_MAP | DBG_C_CAP))
+		return;
+
+	dbg_print(lml, MSG_INTL(MSG_MAP_CAP), EC_LINENO(lineno));
+}
+
+void
 Elf_cap_title(Lm_list *lml)
 {
 	dbg_print(lml, MSG_INTL(MSG_CAP_ELF_TITLE));
--- a/usr/src/cmd/sgs/liblddbg/common/debug.c	Sun Feb 21 21:37:22 2010 -0800
+++ b/usr/src/cmd/sgs/liblddbg/common/debug.c	Mon Feb 22 09:19:31 2010 -0700
@@ -134,7 +134,7 @@
 void
 Dbg_help(void)
 {
-	Dbg_util_nl(0, DBG_NL_FRC);
+	Dbg_util_nl(0, DBG_NL_STD);
 	dbg_print(0, MSG_INTL(MSG_USE_R1_A));
 	dbg_print(0, MSG_INTL(MSG_USE_R1_B));
 	dbg_print(0, MSG_INTL(MSG_USE_R1_C));
@@ -282,6 +282,17 @@
 }
 
 /*
+ * Provide a debugging message showing the version of the linker package
+ */
+void
+Dbg_version(void)
+{
+	Dbg_util_nl(0, DBG_NL_STD);
+	dbg_print(0, MSG_ORIG(MSG_STR_LDVER), link_ver_string);
+	Dbg_util_nl(0, DBG_NL_STD);
+}
+
+/*
  * Messaging support - funnel everything through dgettext() as this provides
  * the real binding to libc.
  */
@@ -535,3 +546,31 @@
 	(void) printf(MSG_ORIG(MSG_STR_NL));
 	va_end(ap);
 }
+
+/*
+ * Return an internationalized state transition string. These are used by
+ * various debugging output.
+ */
+const char *
+Dbg_state_str(dbg_state_t type)
+{
+	static const Msg state[DBG_STATE_NUM] = {
+		MSG_STR_ADD,		/* MSG_INTL(MSG_STR_ADD)  */
+		MSG_STR_CURRENT,	/* MSG_INTL(MSG_STR_CURRENT) */
+		MSG_STR_EXCLUDE,	/* MSG_INTL(MSG_STR_EXCLUDE) */
+		MSG_STR_IGNORE,		/* MSG_INTL(MSG_STR_IGNORE) */
+		MSG_STR_MOD_BEFORE,	/* MSG_INTL(MSG_STR_MOD_BEFORE) */
+		MSG_STR_MOD_AFTER,	/* MSG_INTL(MSG_STR_MOD_AFTER) */
+		MSG_STR_NEW,		/* MSG_INTL(MSG_STR_NEW) */
+		MSG_STR_NEW_IMPLICIT,	/* MSG_INTL(MSG_STR_NEW_IMPLICIT) */
+		MSG_STR_OUT,		/* MSG_INTL(MSG_STR_OUT) */
+		MSG_STR_RESET,		/* MSG_INTL(MSG_STR_RESET) */
+		MSG_STR_RESOLVED,	/* MSG_INTL(MSG_STR_RESOLVED) */
+	};
+#if DBG_STATE_NUM != (DBG_STATE_RESOLVED + 1)
+#error DBG_SEG_NUM has changed. Update segtype[]
+#endif
+
+	assert(type < DBG_STATE_NUM);
+	return (MSG_INTL(state[type]));
+}
--- a/usr/src/cmd/sgs/liblddbg/common/entry.c	Sun Feb 21 21:37:22 2010 -0800
+++ b/usr/src/cmd/sgs/liblddbg/common/entry.c	Mon Feb 22 09:19:31 2010 -0700
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -34,27 +34,39 @@
 void
 Dbg_ent_entry(Lm_list *lml, uchar_t osabi, Half mach, Ent_desc *enp)
 {
-	Conv_inv_buf_t		inv_buf;
-	Conv_sec_flags_buf_t	sec_flags_buf;
+	union {
+		Conv_inv_buf_t			inv;
+		Conv_sec_flags_buf_t		sec_flags;
+		Conv_ent_flags_buf_t		ent_flags;
+		Conv_ent_files_flags_buf_t	ent_files_flags;
+	} buf;
 	Aliste			idx;
-	char			*cp;
+	Ent_desc_file		*edfp;
+
+	if (enp->ec_name != NULL)
+		dbg_print(lml, MSG_ORIG(MSG_ECR_NAME), enp->ec_name);
 
-	dbg_print(lml, MSG_ORIG(MSG_ECR_NAME),
-	    (enp->ec_name ? enp->ec_name : MSG_INTL(MSG_STR_NULL)),
-	    conv_sec_flags(osabi, mach, enp->ec_attrmask, 0, &sec_flags_buf));
+	dbg_print(lml, MSG_ORIG(MSG_ECR_FLAGS),
+	    conv_ent_flags(enp->ec_flags, &buf.ent_flags));
+
+	dbg_print(lml, MSG_ORIG(MSG_ECR_IS_NAME),
+	    (enp->ec_is_name ? enp->ec_is_name : MSG_INTL(MSG_STR_NULL)),
+	    conv_sec_flags(osabi, mach, enp->ec_attrmask, 0, &buf.sec_flags));
 
 	dbg_print(lml, MSG_ORIG(MSG_ECR_SEGMENT),
 	    (enp->ec_segment->sg_name ? enp->ec_segment->sg_name :
 	    MSG_INTL(MSG_STR_NULL)),
-	    conv_sec_flags(osabi, mach, enp->ec_attrbits, 0, &sec_flags_buf));
+	    conv_sec_flags(osabi, mach, enp->ec_attrbits, 0, &buf.sec_flags));
 
 	dbg_print(lml, MSG_ORIG(MSG_ECR_NDX), EC_WORD(enp->ec_ordndx),
-	    conv_sec_type(osabi, mach, enp->ec_type, 0, &inv_buf));
+	    conv_sec_type(osabi, mach, enp->ec_type, 0, &buf.inv));
 
 	if (enp->ec_files) {
 		dbg_print(lml, MSG_ORIG(MSG_ECR_FILES));
-		for (APLIST_TRAVERSE(enp->ec_files, idx, cp))
-			dbg_print(lml, MSG_ORIG(MSG_ECR_FILE), cp);
+		for (ALIST_TRAVERSE(enp->ec_files, idx, edfp))
+			dbg_print(lml, MSG_ORIG(MSG_ECR_FILE),
+			    conv_ent_files_flags(edfp->edf_flags, 0,
+			    &buf.ent_files_flags), edfp->edf_name);
 	}
 }
 
@@ -62,7 +74,7 @@
  * Print out all `entrance descriptor' entries.
  */
 void
-Dbg_ent_print(Lm_list *lml, uchar_t osabi, Half mach, Alist *alp, Boolean dmode)
+Dbg_ent_print(Lm_list *lml, uchar_t osabi, Half mach, APlist *alp)
 {
 	Ent_desc	*enp;
 	Aliste		ndx;
@@ -71,10 +83,9 @@
 		return;
 
 	Dbg_util_nl(lml, DBG_NL_STD);
-	dbg_print(lml, MSG_INTL(MSG_ECR_TITLE),
-	    (dmode ? MSG_INTL(MSG_ECR_DYNAMIC) : MSG_INTL(MSG_ECR_STATIC)));
+	dbg_print(lml, MSG_INTL(MSG_ECR_TITLE));
 
-	for (ALIST_TRAVERSE(alp, ndx, enp)) {
+	for (APLIST_TRAVERSE(alp, ndx, enp)) {
 		dbg_print(lml, MSG_INTL(MSG_ECR_DESC), EC_WORD(ndx));
 		Dbg_ent_entry(lml, osabi, mach, enp);
 	}
--- a/usr/src/cmd/sgs/liblddbg/common/liblddbg.msg	Sun Feb 21 21:37:22 2010 -0800
+++ b/usr/src/cmd/sgs/liblddbg/common/liblddbg.msg	Mon Feb 22 09:19:31 2010 -0700
@@ -496,7 +496,7 @@
 #         args             input arguments
 #         entry            entrance criteria descriptors
 #         got              GOT symbol information
-#         map              map file processing
+#         map              mapfile processing
 #         sections         input sections
 #         segments         output segments and address/offset processing;
 #                            detail flag shows associated sections
@@ -518,7 +518,7 @@
 @ MSG_USE_R9_C	"        got              GOT symbol information"
 
 # TRANSLATION_NOTE -- do not translate the first token "map".
-@ MSG_USE_R9_D	"        map              map file processing"
+@ MSG_USE_R9_D	"        map              mapfile processing"
 
 # TRANSLATION_NOTE -- do not translate the first token "sections".
 @ MSG_USE_R9_E	"        sections         input sections"
@@ -567,20 +567,20 @@
 # Bindings messages
 # NOTE: these are used by appcert(1) and lari(1), use care when changing.
 
-@ MSG_BND_BASIC		"binding file=%s to file=%s: symbol `%s'"
+@ MSG_BND_BASIC		"binding file=%s to file=%s: symbol '%s'"
 @ MSG_BND_PLT		"binding file=%s (%#llx:%#llx) at plt[%lld]:%s to \
-			 file=%s (%#llx:%#llx): symbol `%s'%s"
+			 file=%s (%#llx:%#llx): symbol '%s'%s"
 @ MSG_BND_DLSYM		"binding file=%s (dlsym) to file=%s \
-			 (%#llx:%#llx): symbol `%s'%s"
+			 (%#llx:%#llx): symbol '%s'%s"
 @ MSG_BND_DEFAULT	"binding file=%s (%#llx:%#llx) to file=%s \
-			 (%#llx:%#llx): symbol `%s'%s"
-@ MSG_BND_WEAK_1	"binding file=%s to 0x0 (undefined weak): symbol `%s'"
+			 (%#llx:%#llx): symbol '%s'%s"
+@ MSG_BND_WEAK_1	"binding file=%s to 0x0 (undefined weak): symbol '%s'"
 @ MSG_BND_WEAK_2	"binding file=%s (%#llx:%#llx) to 0x0 \
-			 (undefined weak): symbol `%s'"
+			 (undefined weak): symbol '%s'"
 
 # NOTE: the rejected message is used by lari(1), use care when changing.  This
 # message is formatted to conform to the pattern used by the MSG_BINFO messages.
-@ MSG_BND_REJECT	"binding file=%s to file=%s: symbol `%s'  \
+@ MSG_BND_REJECT	"binding file=%s to file=%s: symbol '%s'  \
 			 (rejected: %s)"
 @ MSG_BNDREJ_DIRECT	"attempt to directly bind to a NODIRECT definition"
 @ MSG_BNDREJ_GROUP	"attempt to bind within a group to a NODIRECT \
@@ -589,8 +589,8 @@
 			 following default search model"
 
 @ MSG_BND_PLTPAD_TO	"   pltpad: %#llx: file=%s bound to file=%s: \
-			 symbol `%s'"
-@ MSG_BND_PLTPAD_FROM	"   pltpad: %#llx: bound from file=%s: symbol `%s'"
+			 symbol '%s'"
+@ MSG_BND_PLTPAD_FROM	"   pltpad: %#llx: bound from file=%s: symbol '%s'"
 
 @ MSG_BND_PSUM_SPARCV9	"Summary of PLT types bound: 21d=%d, 24d=%d, u32=%d, \
 			 u44=%d, full=%d, far=%d, Total=%d"
@@ -618,16 +618,14 @@
 			 offset=0x%llx; symbol=%s; transitioned to: %s"
 @ MSG_REL_DISCARDED	"relocation against discarded section=%s from file=%s; \
 			 relocation type=%s offset=0x%llx; relocation discarded"
-@ MSG_REL_COPY		"copy data from file=%s to file=%s: symbol `%s'%s"
+@ MSG_REL_COPY		"copy data from file=%s to file=%s: symbol '%s'%s"
 @ MSG_REL_SLOPPYCOMDAT	"the following relocation references a discarded \
 			 section; relocation redirected to section %s in \
 			 file %s"
 
 # Entrance criteria messages
 
-@ MSG_ECR_TITLE		"%s Entrance Descriptor List (available)"
-@ MSG_ECR_DYNAMIC	"Dynamic"
-@ MSG_ECR_STATIC	"Static"
+@ MSG_ECR_TITLE		"Segment Entrance Criteria Descriptor List"
 @ MSG_ECR_DESC		"entrance descriptor[%u]"
 
 
@@ -776,31 +774,36 @@
 
 # Mapfile messages
 
-@ MSG_MAP_MAPFILE	"map file=%s"
-
-@ MSG_MAP_SEG_DECL_1	"segment declaration (=), segment added:"
-@ MSG_MAP_SEG_DECL_2	"segment declaration (=), segment updated:"
-@ MSG_MAP_SEG_DECL_3	"implicit segment declaration (:), segment added:"
-@ MSG_MAP_SEG_DECL_4	"implicit segment declaration (@), segment added:"
-@ MSG_MAP_SEG_DECL_5	"size-symbol declaration (@), segment updated:"
+@ MSG_MAP_MAPFILE	"mapfile=%s; version=%d (%s)"
+@ MSG_MAP_SEG		"segment directive; line=%llu; %s"
+@ MSG_MAP_SEG_ORDER	"segment order directive; line=%llu; list_cnt=%lld; %s"
+@ MSG_MAP_CAP		"capability directive; line=%llu"
+@ MSG_MAP_EC		"entrance criteria; line=%llu; added"
+@ MSG_MAP_OS_ORDER	"output section ordering; line=%llu; segment=%s \
+			 section=%s; index=%d"
+@ MSG_MAP_HDR_NOALLOC	"header noalloc directive; line=%llu; first loadable \
+			 segment will not contain ELF and program headers"
 
-@ MSG_MAP_CAP		"hardware/software declaration (=), capabilities added:"
-
-@ MSG_MAP_MAP_DIR	"mapping directive (:), entrance criteria added:"
-
-@ MSG_MAP_SEC_ORDER	"map section ordering, segment: %s section: \
-			 %s index: %d"
-
-@ MSG_MAP_SYM_SCOPE	"symbol scope definition ({})"
-@ MSG_MAP_SYM_SIZE	"size-symbol declaration (@), symbol=%s; %s"
+@ MSG_MAP_SYM_SCOPE	"symbol scope definition"
+@ MSG_MAP_SYM_SIZE	"size-symbol directive; line=%llu; segment=%s; \
+			 symbol=%s; %s"
 @ MSG_MAP_SYM_VER_1	"%s, %s; symbol=%s  (%s)"
 @ MSG_MAP_SYM_VER_2	"%s; symbol=%s  (%s)"
 
-@ MSG_MAP_CNT_DEF	"library control definition (-), %s; needed"
+@ MSG_MAP_DV		"depend versions directive; line=%llu, object=%s"
+@ MSG_MAP_DV_ENTRY	"%12.12s  %s; line=%llu"
 
-@ MSG_MAP_SORT_TITLE	"map file additions: segment sorting required (vaddr):" 
-@ MSG_MAP_SORT_ORIG	"  original=%s"
-@ MSG_MAP_SORT_FINAL	"    sorted=%s"
+@ MSG_MAP_SORT_TITLE	"mapfile additions: segment sorting required" 
+@ MSG_MAP_SORT_TITLE_O	"before:" 
+@ MSG_MAP_SORT_TITLE_S	"after:" 
+@ MSG_MAP_POST_TITLE	"mapfile post processing"
+@ MSG_MAP_ENT_ORD_TITLE	"set entrance criteria input section sort keys \
+			 (ec_ordndx); segment=%s"
+
+@ MSG_MAP_ID_ADD	"%s: %lld: enter conditional expression id: %s"
+@ MSG_MAP_ID_CLEAR	"%s: %lld: delete conditional expression id: %s"
+@ MSG_MAP_PASS		"%s: %lld: input enabled by %s"
+@ MSG_MAP_NOPASS	"%s: %lld: input disabled by %s"
 
 # Move messages
 
@@ -841,7 +844,7 @@
 
 # Section messages
 
-@ MSG_SEC_BACKING	"map file symbol definitions: create backing storage:"
+@ MSG_SEC_BACKING	"mapfile symbol definitions: create backing storage:"
 
 @ MSG_SEC_INPUT		"section=%s; input from file=%s"
 @ MSG_SEC_INPUT_GEN	"section=%s"
@@ -903,8 +906,8 @@
 
 # Segment messages
 
-@ MSG_SEG_DESC_INUSE	"Segment Descriptor List (in use)"
-@ MSG_SEG_DESC_AVAIL	"Segment Descriptor List (available)"
+@ MSG_SEG_DESC_INUSE	"Program Header / Segment Descriptor List (in use)"
+@ MSG_SEG_DESC_AVAIL	"Program Header / Segment Descriptor List (available)"
 
 
 # Support messages
@@ -969,7 +972,7 @@
 
 @ MSG_SYM_LAZY_RESCAN	"rescanning for lazy dependencies for symbol: %s"
 
-@ MSG_SYM_DUPSORTADDR	"section %s: symbol `%s' and symbol `%s' have the \
+@ MSG_SYM_DUPSORTADDR	"section %s: symbol '%s' and symbol '%s' have the \
 			 same address: %#llx"
 
 @ MSG_SYM_IGNGNUVER	"symbol=%s;  hash index=%d;  version=%d;  skipping \
@@ -1062,16 +1065,24 @@
 
 @ MSG_STR_IGNORE	"ignored"
 @ MSG_STR_ENTERED	"entered"
-@ MSG_STR_INITIAL	"initialized"
+@ MSG_STR_EXCLUDE	"exclude"
+@ MSG_STR_RESET		"reset"
 @ MSG_STR_IN		" in"
 @ MSG_STR_OUT		"out"
 @ MSG_STR_ACT		"act"
+@ MSG_STR_CURRENT	"current"
+@ MSG_STR_ADD		"add"
 @ MSG_STR_OLD		"old"
 @ MSG_STR_NEW		"new"
+@ MSG_STR_NEW_IMPLICIT	"new (implicit)"
 @ MSG_STR_RESOLVED	"resolved"
-@ MSG_STR_ADD		"adding"
+@ MSG_STR_ADDING	"adding"
 @ MSG_STR_UP_1		"updating"
 @ MSG_STR_UP_2		"updated"
+@ MSG_STR_ALLOW		"allow"
+@ MSG_STR_REQUIRE	"require"
+@ MSG_STR_MOD_BEFORE	"modify (before)"
+@ MSG_STR_MOD_AFTER	"modify (after)"
 
 @ MSG_STR_UNKNOWN	"<unknown>"
 @ MSG_STR_ORPHAN	"<orphan>"
@@ -1115,8 +1126,10 @@
 
 @ MSG_CAP_VAL_HW1	"hardware capabilities - %s"
 
-@ MSG_CAP_SEC_TITLE	"hardware/software capabilities; input file=%s"
-@ MSG_CAP_SEC_ENTRY	"%12.12s  %-15.15s  %s"
+@ MSG_CAP_SEC_TITLE	"capabilities; input file=%s"
+@ MSG_CAP_OUT_TITLE	"output capabilities"
+@ MSG_CAP_ENTRY	"%12.12s  %-15.15s  %s"
+@ MSG_CAP_ENTRY_EXC	"%12.12s  %-15.15s  %s, exclude %s"
 
 @ MSG_CAP_HW_CANDIDATE	"obj=%s;  hardware capabilities candidate"
 
@@ -1478,11 +1491,18 @@
 
 # Entrance criteria messages
 
-@ MSG_ECR_NAME		"  ec_name:       %-8s  ec_attrmask:  %s"
+@ MSG_ECR_NAME		"  ec_name:       %s"
+@ MSG_ECR_FLAGS		"  ec_flags:      %s"
+@ MSG_ECR_IS_NAME	"  ec_is_name:    %-8s  ec_attrmask:  %s"
 @ MSG_ECR_SEGMENT	"  ec_segment:    %-8s  ec_attrbits:  %s"
-@ MSG_ECR_NDX		"  ec_ndx:        %-8d  ec_type:      %s"
+@ MSG_ECR_NDX		"  ec_ordndx:     %-8d  ec_type:      %s"
 @ MSG_ECR_FILES		"  ec_files:"
-@ MSG_ECR_FILE		"    %s"
+@ MSG_ECR_FILE		"    %-21s  %s"
+
+@ MSG_MAP_SORT_SEG	"    %s"
+@ MSG_MAP_SORT_SEG_NAME	"    %-20s  %s"
+@ MSG_MAP_SORT_SEG_V	"    %-20s  %-20s  p_vaddr=0x%llx"
+@ MSG_MAP_SORT_SEG_O	"    %-20s  %-20s  order=%d"
 
 # Libs messages
 
@@ -1499,12 +1519,17 @@
 
 # Segment messages
 
-@ MSG_SEG_NAME		"segment[%d] sg_name:  %s"
+@ MSG_SEG_DESC		"segment[%d]"
+@ MSG_SEG_NAME		"    sg_name:      %s"
 @ MSG_SEG_LENGTH	"    sg_length:    %#llx"
+@ MSG_SEG_ROUND		"    sg_round:     %#llx"
+@ MSG_SEG_ALIGN		"    sg_align:     %#llx"
 @ MSG_SEG_FLAGS		"    sg_flags:     %s"
-@ MSG_SEG_SIZESYM	"    sg_sizesym:   %s"
-@ MSG_SEG_ORDER		"    sec_order:"
-@ MSG_SEG_SECTION	"       sec_name:    %-8s  sec_index:   %u"
+@ MSG_SEG_SIZESYM_TITLE	"    sg_sizesym:"
+@ MSG_SEG_SIZESYM	"        %s"
+@ MSG_SEG_IS_ORDER_TITLE "    sg_is_order:"
+@ MSG_SEG_OS_ORDER_TITLE "    sg_os_order:"
+@ MSG_SEG_LIST_ITEM	"        %s"
 
 # Section messages (used when expanding segment information)
 
@@ -1563,6 +1588,7 @@
 @ MSG_CNTL_ENTRY	"   [0x%llx]  %s"
 
 @ MSG_STR_NL		"\n"
+@ MSG_STR_LDVER		"Solaris Linkers: %s"
 
 @ MSG_FMT_INDEX		" [%d]"
 @ MSG_FMT_ISEC_NAME	"[%u]%s"
--- a/usr/src/cmd/sgs/liblddbg/common/llib-llddbg	Sun Feb 21 21:37:22 2010 -0800
+++ b/usr/src/cmd/sgs/liblddbg/common/llib-llddbg	Mon Feb 22 09:19:31 2010 -0700
@@ -31,6 +31,8 @@
 #include <debug.h>
 
 int	Dbg_setup(dbg_setup_caller_t, const char *, Dbg_desc *, const char **);
+void	Dbg_help(void);
+void	Dbg_version(void);
 const char *
 	Dbg_demangle_name(const char *);
 
@@ -71,16 +73,24 @@
 void	Dbg32_bind_weak(Rt_map *, Elf32_Addr, Elf32_Addr, const char *);
 void	Dbg64_bind_weak(Rt_map *, Elf64_Addr, Elf64_Addr, const char *);
 
+void	Dbg32_cap_entry(Lm_list *, uint_t, Elf32_Word, Elf32_Word,
+	    Elf32_Half);
+void	Dbg64_cap_entry(Lm_list *, uint_t, Elf64_Xword, Elf64_Xword,
+	    Elf64_Half);
+void	Dbg32_cap_entry2(Lm_list *, uint_t, Elf32_Word, CapMask *,
+	    Elf32_Half);
+void	Dbg64_cap_entry2(Lm_list *, uint_t, Elf64_Xword, CapMask *,
+	    Elf64_Half);
+void	Dbg32_cap_out_title(Lm_list *);
+void	Dbg64_cap_out_title(Lm_list *);
 void	Dbg32_cap_hw_candidate(Lm_list *, const char *);
 void	Dbg64_cap_hw_candidate(Lm_list *, const char *);
 void	Dbg32_cap_hw_filter(Lm_list *, const char *, Rt_map *);
 void	Dbg64_cap_hw_filter(Lm_list *, const char *, Rt_map *);
-void	Dbg32_cap_mapfile(Lm_list *, Elf32_Word, Elf32_Word, Elf32_Half);
-void	Dbg64_cap_mapfile(Lm_list *, Elf64_Xword, Elf64_Xword, Elf64_Half);
-void	Dbg32_cap_sec_entry(Lm_list *, uint_t, Elf32_Word, Elf32_Word,
-	    Elf32_Half);
-void	Dbg64_cap_sec_entry(Lm_list *, uint_t, Elf64_Xword, Elf64_Xword,
-	    Elf64_Half);
+void	Dbg32_cap_mapfile_title(Lm_list *, Lineno);
+void	Dbg64_cap_mapfile_title(Lm_list *, Lineno);
+void	Dbg32_cap_out_title(Lm_list *);
+void	Dbg64_cap_out_title(Lm_list *);
 void	Dbg32_cap_sec_title(Lm_list *, const char *);
 void	Dbg64_cap_sec_title(Lm_list *, const char *);
 void	Dbg32_cap_val_hw1(Lm_list *, Elf32_Word, Elf32_Half);
@@ -95,8 +105,8 @@
 void	Dbg32_cb_iphdr_unmap_ret(Lm_list *);
 void	Dbg64_cb_iphdr_unmap_ret(Lm_list *);
 
-void	Dbg32_ent_print(Lm_list *, uchar_t, Elf32_Half, Alist *, Boolean);
-void	Dbg64_ent_print(Lm_list *, uchar_t, Elf64_Half, Alist *, Boolean);
+void	Dbg32_ent_print(Lm_list *, uchar_t, Elf32_Half, APlist *);
+void	Dbg64_ent_print(Lm_list *, uchar_t, Elf64_Half, APlist *);
 
 void	Dbg32_file_analyze(Rt_map *);
 void	Dbg64_file_analyze64(Rt_map *);
@@ -203,28 +213,40 @@
 void	Dbg32_libs_ylu(Lm_list *, const char *, const char *, int);
 void	Dbg64_libs_ylu(Lm_list *, const char *, const char *, int);
 
-void	Dbg32_map_dash(Lm_list *, const char *);
-void	Dbg64_map_dash(Lm_list *, const char *);
-void	Dbg32_map_ent(Lm_list *, Boolean, Ent_desc *, Ofl_desc *);
-void	Dbg64_map_ent(Lm_list *, Boolean, Ent_desc *, Ofl_desc *);
-void	Dbg32_map_parse(Lm_list *, const char *);
-void	Dbg64_map_parse(Lm_list *, const char *);
-void	Dbg32_map_pipe(Lm_list *, Sg_desc *, const char *, Elf32_Word);
-void	Dbg64_map_pipe(Lm_list *, Sg_desc *, const char *, Elf64_Word);
-void	Dbg32_map_set_atsign(Boolean);
-void	Dbg64_map_set_atsign(Boolean);
-void	Dbg32_map_seg(Ofl_desc *, int, Sg_desc *);
-void	Dbg64_map_seg(Ofl_desc *, int, Sg_desc *);
-void	Dbg32_map_set_equal(Boolean);
-void	Dbg64_map_set_equal(Boolean);
-void	Dbg32_map_size_new(Lm_list *, const char *);
-void	Dbg64_map_size_new(Lm_list *, const char *);
-void	Dbg32_map_size_old(Ofl_desc *, Sym_desc *);
-void	Dbg64_map_size_old(Ofl_desc *, Sym_desc *);
-void	Dbg32_map_sort(Lm_list *);
-void	Dbg64_map_sort(Lm_list *);
-void	Dbg32_map_sort_seg(Lm_list *, Sg_desc *, int);
-void	Dbg64_map_sort_seg(Lm_list *, Sg_desc *, int);
+void	Dbg32_map_cexp_id(Lm_list *, Boolean, const char *, ulong_t,
+	    const char *);
+void	Dbg64_map_cexp_id(Lm_list *, Boolean, const char *, ulong_t,
+	    const char *);
+void	Dbg32_map_dv(Lm_list *, const char *, Lineno);
+void	Dbg64_map_dv(Lm_list *, const char *, Lineno);
+void	Dbg32_map_dv_entry(Lm_list *, Lineno, int, const char *);
+void	Dbg64_map_dv_entry(Lm_list *, Lineno, int, const char *);
+void	Dbg32_map_ent(Lm_list *, Ent_desc *, Ofl_desc *, Lineno);
+void	Dbg64_map_ent(Lm_list *, Ent_desc *, Ofl_desc *, Lineno);
+void	Dbg32_map_ent_ord_title(Lm_list *, const char *);
+void	Dbg64_map_ent_ord_title(Lm_list *, const char *);
+void	Dbg32_map_hdr_noalloc(Lm_list *, Lineno);
+void	Dbg64_map_hdr_noalloc(Lm_list *, Lineno);
+void	Dbg32_map_parse(Lm_list *, const char *, int);
+void	Dbg64_map_parse(Lm_list *, const char *, int);
+void	Dbg32_map_pass(Lm_list *, Boolean, const char *, ulong_t, const char *);
+void	Dbg64_map_pass(Lm_list *, Boolean, const char *, ulong_t, const char *);
+void	Dbg32_map_post_title(Lm_list *);
+void	Dbg64_map_post_title(Lm_list *);
+void	Dbg32_map_seg_os_order(Lm_list *, Sg_desc *, const char *,
+	    Elf32_Word, Lineno);
+void	Dbg64_map_seg_os_order(Lm_list *, Sg_desc *, const char *,
+	    Elf64_Word, Lineno);
+void	Dbg32_map_seg(Ofl_desc *, uint_t, int, Sg_desc *, Lineno);
+void	Dbg64_map_seg(Ofl_desc *, uint_t, int, Sg_desc *, Lineno);
+void	Dbg32_map_size_new(Lm_list *, const char *, const char *, Lineno);
+void	Dbg64_map_size_new(Lm_list *, const char *, const char *, Lineno);
+void	Dbg32_map_size_old(Ofl_desc *, Sym_desc *, const char *, Lineno);
+void	Dbg64_map_size_old(Ofl_desc *, Sym_desc *, const char *, Lineno);
+void	Dbg32_map_sort_title(Lm_list *, Boolean);
+void	Dbg64_map_sort_title(Lm_list *, Boolean);
+void	Dbg32_map_sort_seg(Lm_list *, uchar_t, Elf32_Half, Sg_desc *);
+void	Dbg64_map_sort_seg(Lm_list *, uchar_t, Elf64_Half, Sg_desc *);
 void	Dbg32_map_symbol(Ofl_desc *, Sym_desc *);
 void	Dbg64_map_symbol(Ofl_desc *, Sym_desc *);
 void	Dbg32_map_version(Lm_list *, const char *, const char *, int);
@@ -325,8 +347,10 @@
 void	Dbg32_sec_strtab(Lm_list *, Os_desc *, Str_tbl *);
 void	Dbg64_sec_strtab(Lm_list *, Os_desc *, Str_tbl *);
 
-void	Dbg32_seg_desc_entry(Lm_list *, uchar_t, Elf32_Half, int, Sg_desc *);
-void	Dbg64_seg_desc_entry(Lm_list *, uchar_t, Elf64_Half, int, Sg_desc *);
+void	Dbg32_seg_desc_entry(Lm_list *, uchar_t, Elf32_Half, int, Sg_desc *,
+	    Boolean);
+void	Dbg64_seg_desc_entry(Lm_list *, uchar_t, Elf64_Half, int, Sg_desc *,
+	    Boolean);
 void	Dbg32_seg_entry(Ofl_desc *, int, Sg_desc *);
 void	Dbg64_seg_entry(Ofl_desc *, int, Sg_desc *);
 void	Dbg32_seg_list(Lm_list *, uchar_t, Elf32_Half, APlist *);
--- a/usr/src/cmd/sgs/liblddbg/common/map.c	Sun Feb 21 21:37:22 2010 -0800
+++ b/usr/src/cmd/sgs/liblddbg/common/map.c	Mon Feb 22 09:19:31 2010 -0700
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -28,31 +28,39 @@
 #include	"_debug.h"
 #include	"libld.h"
 
-static const char
-	*Dbg_decl =	NULL;
 
+/*
+ * Report change in input enable status caused by evaluating
+ * $if/$elif control directives.
+ */
 void
-Dbg_map_set_atsign(Boolean new)
+Dbg_map_pass(Lm_list *lml, Boolean enable, const char *file,
+    Lineno lineno, const char *directive)
 {
+	const char *fmt;
+
 	if (DBG_NOTCLASS(DBG_C_MAP))
 		return;
 
-	if (new)
-		Dbg_decl = MSG_INTL(MSG_MAP_SEG_DECL_4);
-	else
-		Dbg_decl = MSG_INTL(MSG_MAP_SEG_DECL_5);
+	fmt = enable ? MSG_INTL(MSG_MAP_PASS) : MSG_INTL(MSG_MAP_NOPASS);
+	dbg_print(lml, fmt, file, EC_LINENO(lineno), directive);
 }
 
+/*
+ * Report entry/removal of boolean identifier from conditional expression
+ * known values.
+ */
 void
-Dbg_map_set_equal(Boolean new)
+Dbg_map_cexp_id(Lm_list *lml, Boolean add, const char *file,
+    Lineno lineno, const char *id)
 {
+	const char *fmt;
+
 	if (DBG_NOTCLASS(DBG_C_MAP))
 		return;
 
-	if (new)
-		Dbg_decl = MSG_INTL(MSG_MAP_SEG_DECL_1);
-	else
-		Dbg_decl = MSG_INTL(MSG_MAP_SEG_DECL_2);
+	fmt = add ? MSG_INTL(MSG_MAP_ID_ADD) : MSG_INTL(MSG_MAP_ID_CLEAR);
+	dbg_print(lml, fmt, file, EC_LINENO(lineno), id);
 }
 
 void
@@ -78,17 +86,20 @@
 }
 
 void
-Dbg_map_size_new(Lm_list *lml, const char *name)
+Dbg_map_size_new(Lm_list *lml, const char *symname, const char *segname,
+    Lineno lineno)
 {
 	if (DBG_NOTCLASS(DBG_C_MAP))
 		return;
 
-	dbg_print(lml, MSG_INTL(MSG_MAP_SYM_SIZE), Dbg_demangle_name(name),
-	    MSG_INTL(MSG_STR_ADD));
+	Dbg_util_nl(lml, DBG_NL_STD);
+	dbg_print(lml, MSG_INTL(MSG_MAP_SYM_SIZE), EC_LINENO(lineno), segname,
+	    Dbg_demangle_name(symname), MSG_INTL(MSG_STR_ADDING));
 }
 
 void
-Dbg_map_size_old(Ofl_desc *ofl, Sym_desc *sdp)
+Dbg_map_size_old(Ofl_desc *ofl, Sym_desc *sdp, const char *segname,
+    Lineno lineno)
 {
 	Conv_inv_buf_t	inv_buf;
 	Lm_list		*lml = ofl->ofl_lml;
@@ -96,8 +107,9 @@
 	if (DBG_NOTCLASS(DBG_C_MAP))
 		return;
 
-	dbg_print(lml, MSG_INTL(MSG_MAP_SYM_SIZE), sdp->sd_name,
-	    MSG_INTL(MSG_STR_UP_1));
+	Dbg_util_nl(lml, DBG_NL_STD);
+	dbg_print(lml, MSG_INTL(MSG_MAP_SYM_SIZE), EC_LINENO(lineno), segname,
+	    sdp->sd_name, MSG_INTL(MSG_STR_UP_1));
 
 	if (DBG_NOTDETAIL())
 		return;
@@ -125,95 +137,195 @@
 	    conv_def_tag(sdp->sd_ref, &inv_buf));
 }
 
+/*
+ * Object version dependency. In the v1 syntax, this is the 'dash' operator.
+ * In the v2 syntax, the DEPEND_VERSIONS directive.
+ */
 void
-Dbg_map_dash(Lm_list *lml, const char *name)
+Dbg_map_dv(Lm_list *lml, const char *obj_name, Lineno lineno)
 {
 	if (DBG_NOTCLASS(DBG_C_MAP))
 		return;
 
-	dbg_print(lml, MSG_INTL(MSG_MAP_CNT_DEF), name);
+	dbg_print(lml, MSG_INTL(MSG_MAP_DV), EC_LINENO(lineno), obj_name);
+}
+
+/*
+ * Add a version to an object dependency
+ */
+void
+Dbg_map_dv_entry(Lm_list *lml, Lineno lineno, int require, const char *version)
+{
+	const char *attr;
+
+	if (DBG_NOTCLASS(DBG_C_MAP))
+		return;
+
+	attr = require ? MSG_INTL(MSG_STR_REQUIRE) : MSG_INTL(MSG_STR_ALLOW);
+	dbg_print(lml, MSG_INTL(MSG_MAP_DV_ENTRY), attr, version,
+	    EC_LINENO(lineno));
 }
 
 void
-Dbg_map_sort(Lm_list *lml)
+Dbg_map_sort_title(Lm_list *lml, Boolean orig)
 {
 	if (DBG_NOTCLASS(DBG_C_MAP))
 		return;
 	if (DBG_NOTDETAIL())
 		return;
 
-	Dbg_util_nl(lml, DBG_NL_STD);
-	dbg_print(lml, MSG_INTL(MSG_MAP_SORT_TITLE));
+	if (orig) {
+		Dbg_util_nl(lml, DBG_NL_STD);
+		dbg_print(lml, MSG_INTL(MSG_MAP_SORT_TITLE));
+		dbg_print(lml, MSG_INTL(MSG_MAP_SORT_TITLE_O));
+	} else {
+		dbg_print(lml, MSG_INTL(MSG_MAP_SORT_TITLE_S));
+	}
 }
 
 void
-Dbg_map_sort_seg(Lm_list *lml, Sg_desc *sgp, int orig)
+Dbg_map_sort_seg(Lm_list *lml, uchar_t osabi, Half mach, Sg_desc *sgp)
 {
-	const char	*str;
+	const char	*type_str;
+	Conv_inv_buf_t	inv_buf;
 
 	if (DBG_NOTCLASS(DBG_C_MAP))
 		return;
 	if (DBG_NOTDETAIL())
 		return;
 
-	if (sgp->sg_name && *sgp->sg_name)
-		str = sgp->sg_name;
-	else
-		str = MSG_INTL(MSG_STR_NULL);
+	type_str = conv_phdr_type(osabi, mach, sgp->sg_phdr.p_type,
+	    0, &inv_buf);
 
-	if (orig)
-		dbg_print(lml, MSG_INTL(MSG_MAP_SORT_ORIG), str);
-	else
-		dbg_print(lml, MSG_INTL(MSG_MAP_SORT_FINAL), str);
+	if (sgp->sg_name) {
+		if (sgp->sg_flags & FLG_SG_P_VADDR) {
+			dbg_print(lml, MSG_ORIG(MSG_MAP_SORT_SEG_V),
+			    type_str, sgp->sg_name,
+			    EC_ADDR(sgp->sg_phdr.p_vaddr));
+		} else if (sgp->sg_flags & FLG_SG_ORDERED) {
+			/*
+			 * All FLG_SG_ORDERED have adjacent sg_id values
+			 * that start at SGID_TEXT. Subtract out the base
+			 * in order to present the order values based at 0.
+			 */
+			dbg_print(lml, MSG_ORIG(MSG_MAP_SORT_SEG_O),
+			    type_str, sgp->sg_name,
+			    EC_WORD(sgp->sg_id - SGID_TEXT));
+		} else {
+			dbg_print(lml, MSG_ORIG(MSG_MAP_SORT_SEG_NAME),
+			    type_str, sgp->sg_name);
+		}
+	} else {
+		dbg_print(lml, MSG_ORIG(MSG_MAP_SORT_SEG), type_str);
+	}
 }
 
 void
-Dbg_map_parse(Lm_list *lml, const char *file)
+Dbg_map_parse(Lm_list *lml, const char *file, int version)
+{
+	Conv_inv_buf_t	inv_buf;
+
+	if (DBG_NOTCLASS(DBG_C_MAP))
+		return;
+
+	Dbg_util_nl(lml, DBG_NL_STD);
+	dbg_print(lml, MSG_INTL(MSG_MAP_MAPFILE), file, EC_WORD(version),
+	    conv_mapfile_version(version, 0, &inv_buf));
+}
+
+void
+Dbg_map_ent(Lm_list *lml, Ent_desc *enp, Ofl_desc *ofl, Lineno lineno)
 {
 	if (DBG_NOTCLASS(DBG_C_MAP))
 		return;
 
 	Dbg_util_nl(lml, DBG_NL_STD);
-	dbg_print(lml, MSG_INTL(MSG_MAP_MAPFILE), file);
+	dbg_print(lml, MSG_INTL(MSG_MAP_EC), EC_LINENO(lineno));
+	Dbg_ent_entry(lml, ofl->ofl_dehdr->e_ident[EI_OSABI],
+	    ofl->ofl_dehdr->e_machine, enp);
 }
 
 void
-Dbg_map_ent(Lm_list *lml, Boolean new, Ent_desc *enp, Ofl_desc *ofl)
+Dbg_map_ent_ord_title(Lm_list *lml, const char *segname)
 {
 	if (DBG_NOTCLASS(DBG_C_MAP))
 		return;
 
-	dbg_print(lml, MSG_INTL(MSG_MAP_MAP_DIR));
-	Dbg_ent_entry(lml, ofl->ofl_dehdr->e_ident[EI_OSABI],
-	    ofl->ofl_dehdr->e_machine, enp);
-	if (new)
-		Dbg_decl = MSG_INTL(MSG_MAP_SEG_DECL_3);
+	Dbg_util_nl(lml, DBG_NL_STD);
+	dbg_print(lml, MSG_INTL(MSG_MAP_ENT_ORD_TITLE), segname);
 }
 
 void
-Dbg_map_pipe(Lm_list *lml, Sg_desc *sgp, const char *sec_name, const Word ndx)
+Dbg_map_seg_os_order(Lm_list *lml, Sg_desc *sgp, const char *sec_name,
+    Word ndx, Lineno lineno)
 {
 	if (DBG_NOTCLASS(DBG_C_MAP))
 		return;
 
-	dbg_print(lml, MSG_INTL(MSG_MAP_SEC_ORDER), sgp->sg_name, sec_name,
-	    EC_WORD(ndx));
+	dbg_print(lml, MSG_INTL(MSG_MAP_OS_ORDER), EC_LINENO(lineno),
+	    sgp->sg_name, sec_name, EC_WORD(ndx));
 }
 
 void
-Dbg_map_seg(Ofl_desc *ofl, int ndx, Sg_desc *sgp)
+Dbg_map_seg(Ofl_desc *ofl, dbg_state_t dbg_state, int ndx, Sg_desc *sgp,
+    Lineno lineno)
 {
 	Lm_list	*lml = ofl->ofl_lml;
 
 	if (DBG_NOTCLASS(DBG_C_MAP))
 		return;
 
-	if (Dbg_decl) {
-		dbg_print(lml, MSG_ORIG(MSG_FMT_STR), Dbg_decl);
-		Dbg_seg_desc_entry(ofl->ofl_lml,
-		    ofl->ofl_dehdr->e_ident[EI_OSABI],
-		    ofl->ofl_dehdr->e_machine, ndx, sgp);
-		Dbg_util_nl(lml, DBG_NL_STD);
-		Dbg_decl = NULL;
+	Dbg_util_nl(lml, DBG_NL_STD);
+	dbg_print(lml, MSG_INTL(MSG_MAP_SEG), EC_LINENO(lineno),
+	    Dbg_state_str(dbg_state));
+	Dbg_seg_desc_entry(ofl->ofl_lml, ofl->ofl_dehdr->e_ident[EI_OSABI],
+	    ofl->ofl_dehdr->e_machine, ndx, sgp, FALSE);
+	Dbg_util_nl(lml, DBG_NL_STD);
+}
+
+void
+Dbg_map_seg_order(Ofl_desc *ofl, uchar_t osabi, Half mach,
+    dbg_state_t dbg_state, Lineno lineno)
+{
+	Lm_list	*lml = ofl->ofl_lml;
+	Aliste		idx;
+	Sg_desc		*sgp;
+	Conv_inv_buf_t	inv_buf;
+	const char	*type_str;
+
+	if (DBG_NOTCLASS(DBG_C_MAP))
+		return;
+
+	Dbg_util_nl(lml, DBG_NL_STD);
+	dbg_print(lml, MSG_INTL(MSG_MAP_SEG_ORDER), EC_LINENO(lineno),
+	    EC_XWORD(aplist_nitems(ofl->ofl_segs_order)),
+	    Dbg_state_str(dbg_state));
+	for (APLIST_TRAVERSE(ofl->ofl_segs_order, idx, sgp)) {
+		type_str = conv_phdr_type(osabi, mach, sgp->sg_phdr.p_type,
+		    0, &inv_buf);
+		dbg_print(lml, MSG_ORIG(MSG_MAP_SORT_SEG_NAME), type_str,
+		    sgp->sg_name);
 	}
+	Dbg_util_nl(lml, DBG_NL_STD);
 }
+
+void
+Dbg_map_post_title(Lm_list *lml)
+{
+	if (DBG_NOTCLASS(DBG_C_MAP))
+		return;
+
+	Dbg_util_nl(lml, DBG_NL_STD);
+	dbg_print(lml, MSG_INTL(MSG_MAP_POST_TITLE));
+}
+
+
+void
+Dbg_map_hdr_noalloc(Lm_list *lml, Lineno lineno)
+{
+	if (DBG_NOTCLASS(DBG_C_MAP))
+		return;
+
+	Dbg_util_nl(lml, DBG_NL_STD);
+	dbg_print(lml, MSG_INTL(MSG_MAP_HDR_NOALLOC), EC_LINENO(lineno));
+}
--- a/usr/src/cmd/sgs/liblddbg/common/mapfile-vers	Sun Feb 21 21:37:22 2010 -0800
+++ b/usr/src/cmd/sgs/liblddbg/common/mapfile-vers	Mon Feb 22 09:19:31 2010 -0700
@@ -41,7 +41,7 @@
 # MAPFILE HEADER END
 #
 
-SUNWprivate_4.75 {
+SUNWprivate_4.76 {
 	global:
 		dbg_desc = NODIRECT;	# interposed - ld.so.1(1)
 		dbg_print = NODIRECT;	# interposed - ld(1) and ld.so.1(1)
@@ -69,6 +69,8 @@
 
 		Dbg_help;
 		Dbg_setup;
+		Dbg_state_str;
+		Dbg_version;
 
 		Dbg32_bind_global;
 		Dbg64_bind_global;
@@ -85,10 +87,14 @@
 		Dbg64_cap_hw_candidate;
 		Dbg32_cap_hw_filter;
 		Dbg64_cap_hw_filter;
-		Dbg32_cap_mapfile;
-		Dbg64_cap_mapfile;
-		Dbg32_cap_sec_entry;
-		Dbg64_cap_sec_entry;
+		Dbg32_cap_mapfile_title;
+		Dbg64_cap_mapfile_title;
+		Dbg32_cap_entry;
+		Dbg64_cap_entry;
+		Dbg32_cap_entry2;
+		Dbg64_cap_entry2;
+		Dbg32_cap_out_title;
+		Dbg64_cap_out_title;
 		Dbg32_cap_sec_title;
 		Dbg64_cap_sec_title;
 		Dbg32_cap_val_hw1;
@@ -208,28 +214,38 @@
 		Dbg32_libs_ylu;
 		Dbg64_libs_ylu;
 
-		Dbg32_map_dash;
-		Dbg64_map_dash;
+		Dbg32_map_cexp_id;
+		Dbg64_map_cexp_id;
+		Dbg32_map_dv;
+		Dbg64_map_dv;
+		Dbg32_map_dv_entry;
+		Dbg64_map_dv_entry;
 		Dbg32_map_ent;
 		Dbg64_map_ent;
+		Dbg32_map_ent_ord_title;
+		Dbg64_map_ent_ord_title;
+		Dbg32_map_hdr_noalloc;
+		Dbg64_map_hdr_noalloc;
 		Dbg32_map_parse;
 		Dbg64_map_parse;
-		Dbg32_map_pipe;
-		Dbg64_map_pipe;
-		Dbg32_map_set_atsign;
-		Dbg64_map_set_atsign;
+		Dbg32_map_pass;
+		Dbg64_map_pass;
+		Dbg32_map_post_title;
+		Dbg64_map_post_title;
 		Dbg32_map_seg;
 		Dbg64_map_seg;
-		Dbg32_map_set_equal;
-		Dbg64_map_set_equal;
+		Dbg32_map_seg_order;
+		Dbg64_map_seg_order;
+		Dbg32_map_seg_os_order;
+		Dbg64_map_seg_os_order;
 		Dbg32_map_size_new;
 		Dbg64_map_size_new;
 		Dbg32_map_size_old;
 		Dbg64_map_size_old;
-		Dbg32_map_sort;
-		Dbg64_map_sort;
 		Dbg32_map_sort_seg;
 		Dbg64_map_sort_seg;
+		Dbg32_map_sort_title;
+		Dbg64_map_sort_title;
 		Dbg32_map_symbol;
 		Dbg64_map_symbol;
 		Dbg32_map_version;
--- a/usr/src/cmd/sgs/liblddbg/common/sections.c	Sun Feb 21 21:37:22 2010 -0800
+++ b/usr/src/cmd/sgs/liblddbg/common/sections.c	Mon Feb 22 09:19:31 2010 -0700
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 #include	<stdio.h>
@@ -231,33 +231,21 @@
 void
 Dbg_sec_added(Lm_list *lml, Os_desc *osp, Sg_desc *sgp)
 {
-	const char	*str;
-
 	if (DBG_NOTCLASS(DBG_C_SECTIONS))
 		return;
 
-	if (sgp->sg_name && *sgp->sg_name)
-		str = sgp->sg_name;
-	else
-		str = MSG_INTL(MSG_STR_NULL);
-
-	dbg_print(lml, MSG_INTL(MSG_SEC_ADDED), osp->os_name, str);
+	dbg_print(lml, MSG_INTL(MSG_SEC_ADDED), osp->os_name,
+	    (sgp->sg_name ? sgp->sg_name : MSG_INTL(MSG_STR_NULL)));
 }
 
 void
 Dbg_sec_created(Lm_list *lml, Os_desc *osp, Sg_desc *sgp)
 {
-	const char	*str;
-
 	if (DBG_NOTCLASS(DBG_C_SECTIONS))
 		return;
 
-	if (sgp->sg_name && *sgp->sg_name)
-		str = sgp->sg_name;
-	else
-		str = MSG_INTL(MSG_STR_NULL);
-
-	dbg_print(lml, MSG_INTL(MSG_SEC_CREATED), osp->os_name, str);
+	dbg_print(lml, MSG_INTL(MSG_SEC_CREATED), osp->os_name,
+	    (sgp->sg_name ? sgp->sg_name : MSG_INTL(MSG_STR_NULL)));
 }
 
 void
--- a/usr/src/cmd/sgs/liblddbg/common/segments.c	Sun Feb 21 21:37:22 2010 -0800
+++ b/usr/src/cmd/sgs/liblddbg/common/segments.c	Mon Feb 22 09:19:31 2010 -0700
@@ -20,10 +20,11 @@
  */
 
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
+#include	<stdio.h>
 #include	"msg.h"
 #include	"_debug.h"
 #include	"libld.h"
@@ -33,39 +34,62 @@
  */
 void
 Dbg_seg_desc_entry(Lm_list *lml, uchar_t osabi, Half mach, int ndx,
-    Sg_desc *sgp)
+    Sg_desc *sgp, Boolean space_nl)
 {
 	Conv_seg_flags_buf_t	seg_flags_buf;
-	const char		*str;
+	Aliste			idx;
+	Sym_desc		*sdp;
 
-	if (sgp->sg_name && *sgp->sg_name)
-		str = sgp->sg_name;
-	else
-		str = MSG_INTL(MSG_STR_NULL);
+	if (space_nl)
+		Dbg_util_nl(lml, DBG_NL_STD);
+	dbg_print(lml, MSG_ORIG(MSG_SEG_DESC), ndx);
+	if (sgp->sg_name)
+		dbg_print(lml, MSG_ORIG(MSG_SEG_NAME), sgp->sg_name);
 
-	Dbg_util_nl(lml, DBG_NL_STD);
-	dbg_print(lml, MSG_ORIG(MSG_SEG_NAME), ndx, str);
+	dbg_print(lml, MSG_ORIG(MSG_SEG_FLAGS),
+	    conv_seg_flags(sgp->sg_flags, &seg_flags_buf));
 
 	Elf_phdr(lml, osabi, mach, &sgp->sg_phdr);
 
-	dbg_print(lml, MSG_ORIG(MSG_SEG_LENGTH), EC_ADDR(sgp->sg_length));
-	dbg_print(lml, MSG_ORIG(MSG_SEG_FLAGS),
-	    conv_seg_flags(sgp->sg_flags, &seg_flags_buf));
+	if (sgp->sg_flags & FLG_SG_P_ALIGN)
+		dbg_print(lml, MSG_ORIG(MSG_SEG_ALIGN),
+		    EC_ADDR(sgp->sg_align));
+
+	if (sgp->sg_flags & FLG_SG_LENGTH)
+		dbg_print(lml, MSG_ORIG(MSG_SEG_LENGTH),
+		    EC_ADDR(sgp->sg_length));
+
+	if (sgp->sg_flags & FLG_SG_ROUND)
+		dbg_print(lml, MSG_ORIG(MSG_SEG_ROUND),
+		    EC_ADDR(sgp->sg_round));
 
-	if (sgp->sg_sizesym && sgp->sg_sizesym->sd_name)
-		dbg_print(lml, MSG_ORIG(MSG_SEG_SIZESYM),
-		    Dbg_demangle_name(sgp->sg_sizesym->sd_name));
+	if (aplist_nitems(sgp->sg_sizesym) > 0) {
+		dbg_print(lml, MSG_ORIG(MSG_SEG_SIZESYM_TITLE));
+		for (APLIST_TRAVERSE(sgp->sg_sizesym, idx, sdp))
+			if (sdp->sd_name)
+				dbg_print(lml, MSG_ORIG(MSG_SEG_SIZESYM),
+				    Dbg_demangle_name(sdp->sd_name));
+	}
+	if (aplist_nitems(sgp->sg_is_order) > 0) {
+		Aliste		idx;
+		Ent_desc	*enp;
 
-	if (sgp->sg_secorder) {
+		dbg_print(lml, MSG_ORIG(MSG_SEG_IS_ORDER_TITLE));
+		for (APLIST_TRAVERSE(sgp->sg_is_order, idx, enp))
+			dbg_print(lml, MSG_ORIG(MSG_SEG_LIST_ITEM),
+			    enp->ec_name);
+	}
+	if (alist_nitems(sgp->sg_os_order) > 0) {
 		Aliste		idx;
 		Sec_order	*scop;
 
-		dbg_print(lml, MSG_ORIG(MSG_SEG_ORDER));
-		for (APLIST_TRAVERSE(sgp->sg_secorder, idx, scop))
-			dbg_print(lml, MSG_ORIG(MSG_SEG_SECTION),
-			    scop->sco_secname, EC_WORD(scop->sco_index));
+		dbg_print(lml, MSG_ORIG(MSG_SEG_OS_ORDER_TITLE));
+		for (ALIST_TRAVERSE(sgp->sg_os_order, idx, scop))
+			dbg_print(lml, MSG_ORIG(MSG_SEG_LIST_ITEM),
+			    scop->sco_secname);
 	}
-	Dbg_util_nl(lml, DBG_NL_STD);
+	if (space_nl)
+		Dbg_util_nl(lml, DBG_NL_STD);
 }
 
 void
@@ -85,7 +109,7 @@
 		return;
 
 	Dbg_seg_desc_entry(ofl->ofl_lml, ofl->ofl_dehdr->e_ident[EI_OSABI],
-	    ofl->ofl_dehdr->e_machine, ndx, sgp);
+	    ofl->ofl_dehdr->e_machine, ndx, sgp, TRUE);
 }
 
 /*
@@ -104,7 +128,7 @@
 	Dbg_util_nl(lml, DBG_NL_STD);
 	dbg_print(lml, MSG_INTL(MSG_SEG_DESC_AVAIL));
 	for (APLIST_TRAVERSE(apl, idx, sgp))
-		Dbg_seg_desc_entry(lml, osabi, mach, ndx++, sgp);
+		Dbg_seg_desc_entry(lml, osabi, mach, ndx++, sgp, TRUE);
 }
 
 /*
--- a/usr/src/cmd/sgs/libldstab/Makefile.com	Sun Feb 21 21:37:22 2010 -0800
+++ b/usr/src/cmd/sgs/libldstab/Makefile.com	Mon Feb 22 09:19:31 2010 -0700
@@ -19,7 +19,7 @@
 # CDDL HEADER END
 #
 #
-# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 
@@ -37,6 +37,8 @@
 SRCDIR =	../common
 SRCBASE=	../../../..
 
+CPPFLAGS +=	-I$(ELFCAP)
+
 LDLIBS +=	$(CONVLIBDIR) $(CONV_LIB) $(ELFLIBDIR) -lelf -lc
 DYNFLAGS +=	$(VERSREF)
 
--- a/usr/src/cmd/sgs/nm/amd64/Makefile	Sun Feb 21 21:37:22 2010 -0800
+++ b/usr/src/cmd/sgs/nm/amd64/Makefile	Mon Feb 22 09:19:31 2010 -0700
@@ -19,7 +19,7 @@
 # CDDL HEADER END
 #
 #
-# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 
@@ -39,7 +39,7 @@
 LDFLAGS +=	'-R$$ORIGIN/../../../lib/$(MACH64)'
 INCLIST=	-I../../include -I../../include/i386 \
 		-I$(SRCBASE)/uts/$(ARCH)/sys
-CPPFLAGS=	$(INCLIST) $(DEFLIST) $(CPPFLAGS.master)
+CPPFLAGS=	$(INCLIST) $(DEFLIST) $(CPPFLAGS.master) -I$(ELFCAP)
 LDLIBS +=	$(CONVLIBDIR64) $(CONV_LIB) $(ELFLIBDIR) -lelf
 LINTFLAGS64 +=	-x $(LDLIBS) -m64
 LINTSRCS=	$(SRCS)
--- a/usr/src/cmd/sgs/nm/i386/Makefile	Sun Feb 21 21:37:22 2010 -0800
+++ b/usr/src/cmd/sgs/nm/i386/Makefile	Mon Feb 22 09:19:31 2010 -0700
@@ -19,9 +19,7 @@
 # CDDL HEADER END
 #
 #
-# ident	"%Z%%M%	%I%	%E% SMI"
-#
-# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # cmd/sgs/nm/i386/Makefile
@@ -46,7 +44,7 @@
 INCLIST=	-I../../include -I../../include/i386 \
 		-I$(SRCBASE)/uts/$(ARCH)/sys
 DEFLIST=	-DTARGET=I386 -DI386=1 -D$(ARFORMAT) -DELF
-CPPFLAGS=	$(INCLIST) $(DEFLIST) $(CPPFLAGS.master)
+CPPFLAGS=	$(INCLIST) $(DEFLIST) $(CPPFLAGS.master) -I$(ELFCAP)
 LDLIBS +=	$(CONVLIBDIR) $(CONV_LIB) $(ELFLIBDIR) -lelf
 LINTFLAGS +=	-x $(LDLIBS)
 LINTSRCS=	$(SRCS)
--- a/usr/src/cmd/sgs/nm/sparc/Makefile	Sun Feb 21 21:37:22 2010 -0800
+++ b/usr/src/cmd/sgs/nm/sparc/Makefile	Mon Feb 22 09:19:31 2010 -0700
@@ -19,9 +19,7 @@
 # CDDL HEADER END
 #
 #
-# ident	"%Z%%M%	%I%	%E% SMI"
-#
-# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # cmd/sgs/nm/sparc/Makefile
@@ -46,7 +44,7 @@
 INCLIST=	-I../../include -I../../include/sparc \
 		-I$(SRCBASE)/uts/$(ARCH)/sys
 DEFLIST=	-DTARGET=SPARC -DSPARC=1 -D$(ARFORMAT) -DELF
-CPPFLAGS=	$(INCLIST) $(DEFLIST) $(CPPFLAGS.master)
+CPPFLAGS=	$(INCLIST) $(DEFLIST) $(CPPFLAGS.master)  -I$(ELFCAP)
 LDLIBS +=	$(CONVLIBDIR) $(CONV_LIB) $(ELFLIBDIR) -lelf
 LINTFLAGS=	-x $(LDLIBS)
 LINTSRCS=	$(SRCS)
--- a/usr/src/cmd/sgs/nm/sparcv9/Makefile	Sun Feb 21 21:37:22 2010 -0800
+++ b/usr/src/cmd/sgs/nm/sparcv9/Makefile	Mon Feb 22 09:19:31 2010 -0700
@@ -19,7 +19,7 @@
 # CDDL HEADER END
 #
 #
-# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # cmd/sgs/nm/sparcv9/Makefile
@@ -42,7 +42,7 @@
 INCLIST=	-I../../include -I../../include/sparc \
 		-I$(SRCBASE)/uts/$(ARCH)/sys
 DEFLIST=	-DTARGET=SPARC -DSPARC=1 -D$(ARFORMAT) -DELF
-CPPFLAGS=	$(INCLIST) $(DEFLIST) $(CPPFLAGS.master)
+CPPFLAGS=	$(INCLIST) $(DEFLIST) $(CPPFLAGS.master) -I$(ELFCAP)
 LDLIBS +=	$(CONVLIBDIR64) $(CONV_LIB) $(ELFLIBDIR) -lelf
 LINTFLAGS64=	-x $(LDLIBS) -m64
 LINTSRCS=	$(SRCS)
--- a/usr/src/cmd/sgs/packages/common/SUNWonld-README	Sun Feb 21 21:37:22 2010 -0800
+++ b/usr/src/cmd/sgs/packages/common/SUNWonld-README	Mon Feb 22 09:19:31 2010 -0700
@@ -1548,3 +1548,5 @@
 6923449 elfdump misinterprets _init/_fini symbols in dynamic section test
 6914728 Add dl_iterate_phdr() function to ld.so.1 (D)
 	PSARC/2010/015 dl_iterate_phdr
+6916788 ld version 2 mapfile syntax (D)
+	PSARC/2009/688 Human readable and extensible ld mapfile syntax
--- a/usr/src/cmd/sgs/prof/Makefile.com	Sun Feb 21 21:37:22 2010 -0800
+++ b/usr/src/cmd/sgs/prof/Makefile.com	Mon Feb 22 09:19:31 2010 -0700
@@ -19,9 +19,7 @@
 # CDDL HEADER END
 #
 #
-# ident	"%Z%%M%	%I%	%E% SMI"
-#
-# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # cmd/sgs/prof/Makefile.com
@@ -41,7 +39,7 @@
 
 INCLIST=	-I../common -I../../include -I../../include/$(MACH)
 
-CPPFLAGS=	$(INCLIST) $(DEFLIST) $(CPPFLAGS.master)
+CPPFLAGS=	$(INCLIST) $(DEFLIST) $(CPPFLAGS.master) -I$(ELFCAP)
 CFLAGS +=	$(CCVERBOSE)
 C99MODE=	$(C99_ENABLE)
 LDLIBS +=	$(CONVLIBDIR) $(CONV_LIB) $(ELFLIBDIR) -lelf
--- a/usr/src/cmd/sgs/rtld/common/debug.c	Sun Feb 21 21:37:22 2010 -0800
+++ b/usr/src/cmd/sgs/rtld/common/debug.c	Mon Feb 22 09:19:31 2010 -0700
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -145,9 +145,11 @@
 	dbg_ino = status.st_ino;
 
 	/*
-	 * Now that the output file is established, generate help
-	 * output if the user specified the debug help token.
+	 * Now that the output file is established, identify the linker
+	 * package, and generate help output if the user specified the
+	 * debug help token.
 	 */
+	Dbg_version();
 	if (dbp->d_extra & DBG_E_HELP)
 		Dbg_help();
 
--- a/usr/src/cmd/sgs/rtld/common/object.c	Sun Feb 21 21:37:22 2010 -0800
+++ b/usr/src/cmd/sgs/rtld/common/object.c	Mon Feb 22 09:19:31 2010 -0700
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -217,6 +217,7 @@
 	Fdesc			fd = { 0 };
 	Grp_hdl			*ghp;
 	Rej_desc		rej = { 0 };
+	elfcap_mask_t		cap_value;
 
 	DBG_CALL(Dbg_util_nl(lml, DBG_NL_STD));
 
@@ -230,7 +231,8 @@
 	 * hardware or software capabilities have been established, ensure that
 	 * they are appropriate for this platform.
 	 */
-	if ((ofl->ofl_hwcap_1) && (hwcap_check(ofl->ofl_hwcap_1, &rej) == 0)) {
+	cap_value = CAPMASK_VALUE(&ofl->ofl_ocapset.c_hw_1);
+	if (cap_value && (hwcap_check(cap_value, &rej) == 0)) {
 		if ((lml_main.lm_flags & LML_FLG_TRC_LDDSTUB) && lmp &&
 		    (FLAGS1(lmp) & FL1_RT_LDDSTUB) && (NEXT(lmp) == NULL)) {
 			(void) printf(MSG_INTL(MSG_LDD_GEN_HWCAP_1),
@@ -239,7 +241,8 @@
 		return (NULL);
 	}
 
-	if ((ofl->ofl_sfcap_1) && (sfcap_check(ofl->ofl_sfcap_1, &rej) == 0)) {
+	cap_value = CAPMASK_VALUE(&ofl->ofl_ocapset.c_sf_1);
+	if (cap_value && (sfcap_check(cap_value, &rej) == 0)) {
 		if ((lml_main.lm_flags & LML_FLG_TRC_LDDSTUB) && lmp &&
 		    (FLAGS1(lmp) & FL1_RT_LDDSTUB) && (NEXT(lmp) == NULL)) {
 			(void) printf(MSG_INTL(MSG_LDD_GEN_SFCAP_1),
--- a/usr/src/cmd/sgs/rtld/common/rtld.msg	Sun Feb 21 21:37:22 2010 -0800
+++ b/usr/src/cmd/sgs/rtld/common/rtld.msg	Mon Feb 22 09:19:31 2010 -0700
@@ -20,7 +20,7 @@
 #
 
 #
-# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 
@@ -125,7 +125,7 @@
 
 # Versioning diagnostics.
 
-@ MSG_VER_NFOUND	"%s: version `%s' not found (required by file %s)"
+@ MSG_VER_NFOUND	"%s: version '%s' not found (required by file %s)"
 
 
 # Diagnostics generated under the control of ldd(1).
--- a/usr/src/common/elfcap/elfcap.c	Sun Feb 21 21:37:22 2010 -0800
+++ b/usr/src/common/elfcap/elfcap.c	Mon Feb 22 09:19:31 2010 -0700
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -86,9 +86,6 @@
  * Order the capabilities by their numeric value. See SF1_SUNW_
  * values in sys/elf.h.
  */
-#if (ELFCAP_NUM_SF1 > 32)
-#error ELFCAP_NUM_SF1 is limited to no more than 32 items
-#endif
 static const elfcap_desc_t sf1[ELFCAP_NUM_SF1] = {
 	{						/* 0x00000001 */
 		SF1_SUNW_FPKNWN, STRDESC("SF1_SUNW_FPKNWN"),
@@ -110,9 +107,6 @@
  * Order the SPARC hardware capabilities to match their numeric value.  See
  * AV_SPARC_ values in sys/auxv_SPARC.h.
  */
-#if (ELFCAP_NUM_HW1_SPARC > 32)
-#error ELFCAP_NUM_HW1_SPARC is limited to no more than 32 items
-#endif
 static const elfcap_desc_t hw1_sparc[ELFCAP_NUM_HW1_SPARC] = {
 	{						/* 0x00000001 */
 		AV_SPARC_MUL32, STRDESC("AV_SPARC_MUL32"),
@@ -188,9 +182,6 @@
  * Order the Intel hardware capabilities to match their numeric value.  See
  * AV_386_ values in sys/auxv_386.h.
  */
-#if (ELFCAP_NUM_HW1_386 > 32)
-#error ELFCAP_NUM_HW1_386 is limited to no more than 32 items
-#endif
 static const elfcap_desc_t hw1_386[ELFCAP_NUM_HW1_386] = {
 	{						/* 0x00000001 */
 		AV_386_FPU, STRDESC("AV_386_FPU"),
@@ -327,7 +318,7 @@
 get_str_desc(elfcap_style_t style, const elfcap_desc_t *cdp,
     const elfcap_str_t **ret_str)
 {
-	switch (style) {
+	switch (ELFCAP_STYLE_MASK(style)) {
 	case ELFCAP_STYLE_FULL:
 		*ret_str = &cdp->c_full;
 		break;
@@ -350,7 +341,7 @@
  * capabilities descriptor.
  */
 static elfcap_err_t
-expand(elfcap_style_t style, uint64_t val, const elfcap_desc_t *cdp,
+expand(elfcap_style_t style, elfcap_mask_t val, const elfcap_desc_t *cdp,
     uint_t cnum, char *str, size_t slen, elfcap_fmt_t fmt)
 {
 	uint_t			cnt;
@@ -386,7 +377,7 @@
 		    ELFCAP_ERR_NONE))
 			return (err);
 
-		(void) snprintf(str, slen, "0x%llx", val);
+		(void) snprintf(str, slen, "0x%x", val);
 	}
 	return (ELFCAP_ERR_NONE);
 }
@@ -395,7 +386,7 @@
  * Expand a CA_SUNW_HW_1 value.
  */
 elfcap_err_t
-elfcap_hw1_to_str(elfcap_style_t style, uint64_t val, char *str,
+elfcap_hw1_to_str(elfcap_style_t style, elfcap_mask_t val, char *str,
     size_t len, elfcap_fmt_t fmt, ushort_t mach)
 {
 	/*
@@ -418,6 +409,25 @@
 }
 
 /*
+ * Expand a CA_SUNW_HW_2 value.  Presently, there are no values, this routine
+ * is simply a place holder for future development.
+ */
+elfcap_err_t
+/* ARGSUSED0 */
+elfcap_hw2_to_str(elfcap_style_t style, elfcap_mask_t val, char *str,
+    size_t len, elfcap_fmt_t fmt, ushort_t mach)
+{
+	/*
+	 * Initialize the string buffer, and validate the format request.
+	 */
+	*str = '\0';
+	if ((fmt < 0) || (fmt >= FORMAT_NELTS))
+		return (ELFCAP_ERR_INVFMT);
+
+	return (expand(style, val, NULL, 0, str, len, fmt));
+}
+
+/*
  * Expand a CA_SUNW_SF_1 value.  Note, that at present these capabilities are
  * common across all platforms.  The use of "mach" is therefore redundant, but
  * is retained for compatibility with the interface of elfcap_hw1_to_str(), and
@@ -425,7 +435,7 @@
  */
 elfcap_err_t
 /* ARGSUSED4 */
-elfcap_sf1_to_str(elfcap_style_t style, uint64_t val, char *str,
+elfcap_sf1_to_str(elfcap_style_t style, elfcap_mask_t val, char *str,
     size_t len, elfcap_fmt_t fmt, ushort_t mach)
 {
 	/*
@@ -442,21 +452,28 @@
  * Given a capability tag type and value, map it to a string representation.
  */
 elfcap_err_t
-elfcap_tag_to_str(elfcap_style_t style, uint64_t tag, uint64_t val,
+elfcap_tag_to_str(elfcap_style_t style, uint64_t tag, elfcap_mask_t val,
     char *str, size_t len, elfcap_fmt_t fmt, ushort_t mach)
 {
-	if (tag == CA_SUNW_HW_1)
+	switch (tag) {
+	case CA_SUNW_HW_1:
 		return (elfcap_hw1_to_str(style, val, str, len, fmt, mach));
-	if (tag == CA_SUNW_SF_1)
+
+	case CA_SUNW_SF_1:
 		return (elfcap_sf1_to_str(style, val, str, len, fmt, mach));
 
+	case CA_SUNW_HW_2:
+		return (elfcap_hw2_to_str(style, val, str, len, fmt, mach));
+
+	}
+
 	return (ELFCAP_ERR_UNKTAG);
 }
 
 /*
  * Determine a capabilities value from a capabilities string.
  */
-static uint64_t
+static elfcap_mask_t
 value(elfcap_style_t style, const char *str, const elfcap_desc_t *cdp,
     uint_t cnum)
 {
@@ -474,19 +491,25 @@
 
 		if ((err = get_str_desc(style, &cdp[num], &nstr)) != 0)
 			return (err);
-		if (strcmp(str, nstr->s_str) == 0)
-			return (cdp[num].c_val);
+		if (style & ELFCAP_STYLE_F_ICMP) {
+			if (strcasecmp(str, nstr->s_str) == 0)
+				return (cdp[num].c_val);
+		} else {
+			if (strcmp(str, nstr->s_str) == 0)
+				return (cdp[num].c_val);
+		}
 	}
+
 	return (0);
 }
 
-uint64_t
+elfcap_mask_t
 elfcap_sf1_from_str(elfcap_style_t style, const char *str, ushort_t mach)
 {
 	return (value(style, str, &sf1[0], ELFCAP_NUM_SF1));
 }
 
-uint64_t
+elfcap_mask_t
 elfcap_hw1_from_str(elfcap_style_t style, const char *str, ushort_t mach)
 {
 	if ((mach == EM_386) || (mach == EM_IA_64) || (mach == EM_AMD64))
@@ -498,6 +521,34 @@
 
 	return (0);
 }
+elfcap_mask_t
+/* ARGSUSED0 */
+elfcap_hw2_from_str(elfcap_style_t style, const char *str, ushort_t mach)
+{
+	return (0);
+}
+
+/*
+ * Given a capability tag type and value, return the capabilities values
+ * contained in the string.
+ */
+elfcap_mask_t
+elfcap_tag_from_str(elfcap_style_t style, uint64_t tag, const char *str,
+    ushort_t mach)
+{
+	switch (tag) {
+	case CA_SUNW_HW_1:
+		return (elfcap_hw1_from_str(style, str, mach));
+
+	case CA_SUNW_SF_1:
+		return (elfcap_sf1_from_str(style, str, mach));
+
+	case CA_SUNW_HW_2:
+		return (elfcap_hw2_from_str(style, str, mach));
+	}
+
+	return (0);
+}
 
 /*
  * These functions allow the caller to get direct access to the
--- a/usr/src/common/elfcap/elfcap.h	Sun Feb 21 21:37:22 2010 -0800
+++ b/usr/src/common/elfcap/elfcap.h	Mon Feb 22 09:19:31 2010 -0700
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -34,13 +34,26 @@
 #endif
 
 /*
+ * Type used to represent capability bitmasks. This 32-bit type cannot be
+ * widened without breaking the ability to use them in ELFCLASS32 objects.
+ */
+typedef uint32_t elfcap_mask_t;
+
+/*
  * The elfcap code handles mappings to and from several string styles.
  * The caller uses elfcap_style_t to specify the style to use.
+ *
+ * The bottom 16 bits are used to represent styles, and the upper 16
+ * bits are used for flags to modify default behavior.
  */
+#define	ELFCAP_STYLE_MASK(_style) (_style & 0xff)
+
 typedef enum {
 	ELFCAP_STYLE_FULL =	1,	/* Full formal name (e.g. AV_386_SSE) */
 	ELFCAP_STYLE_UC = 	2,	/* Informal upper case (e.g. SSE) */
-	ELFCAP_STYLE_LC = 	3	/* Informal lower case (e.g. sse) */
+	ELFCAP_STYLE_LC = 	3,	/* Informal lower case (e.g. sse) */
+
+	ELFCAP_STYLE_F_ICMP =	0x0100	 /* Use case insensitive strcmp */
 } elfcap_style_t;
 
 /*
@@ -64,7 +77,7 @@
  * and are intended to be ignored by the processing code.
  */
 typedef	struct {
-	uint64_t	c_val;		/* Bit value */
+	elfcap_mask_t	c_val;		/* Bit value */
 	elfcap_str_t	c_full;		/* ELFCAP_STYLE_FULL */
 	elfcap_str_t	c_uc;		/* ELFCAP_STYLE_UC */
 	elfcap_str_t	c_lc;		/* ELFCAP_STYLE_LC */
@@ -98,11 +111,6 @@
 /*
  * # of each type of capability known to the system. These values
  * must be kept in sync with the arrays found in elfcap.c.
- *
- * In ELFCLASS32, capability words are 32-bit, while ELFCLASS64 has
- * 64-bit words. For simplicity of code and documentation, our policy
- * is to limit each mask word to no more than 32 capabilities regardless of
- * the ELFCLASS.
  */
 #define	ELFCAP_NUM_SF1			3
 #define	ELFCAP_NUM_HW1_SPARC		17
@@ -114,26 +122,35 @@
  * "to str" function to generate the string description.
  */
 extern elfcap_err_t elfcap_tag_to_str(elfcap_style_t, uint64_t,
-    uint64_t, char *, size_t, elfcap_fmt_t, ushort_t);
+    elfcap_mask_t, char *, size_t, elfcap_fmt_t, ushort_t);
 
 /*
  * The functions that convert from a specific capability value to
  * a string representation all use the same common prototype.
  */
-typedef elfcap_err_t elfcap_to_str_func_t(elfcap_style_t, uint64_t, char *,
+typedef elfcap_err_t elfcap_to_str_func_t(elfcap_style_t, elfcap_mask_t, char *,
     size_t, elfcap_fmt_t, ushort_t);
 
 extern elfcap_to_str_func_t elfcap_hw1_to_str;
+extern elfcap_to_str_func_t elfcap_hw2_to_str;
 extern elfcap_to_str_func_t elfcap_sf1_to_str;
 
 /*
  * The reverse mapping: Given a string representation, turn it back into
  * integer form.
  */
-typedef uint64_t elfcap_from_str_func_t(elfcap_style_t,
+typedef elfcap_mask_t elfcap_from_str_func_t(elfcap_style_t,
     const char *, ushort_t mach);
 
+/*
+ * Given a capability section tag and string, call the proper underlying
+ * "from str" function to generate the numeric value.
+ */
+extern elfcap_mask_t elfcap_tag_from_str(elfcap_style_t, uint64_t,
+    const char *, ushort_t);
+
 extern elfcap_from_str_func_t elfcap_hw1_from_str;
+extern elfcap_from_str_func_t elfcap_hw2_from_str;
 extern elfcap_from_str_func_t elfcap_sf1_from_str;
 
 /*
--- a/usr/src/lib/libwrap/mapfile	Sun Feb 21 21:37:22 2010 -0800
+++ b/usr/src/lib/libwrap/mapfile	Mon Feb 22 09:19:31 2010 -0700
@@ -1,5 +1,5 @@
 #
-# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 
@@ -26,5 +26,4 @@
 	global:
 		allow_severity = extern;
 		deny_severity = extern;
-		*;
 };
--- a/usr/src/uts/common/sys/elf.h	Sun Feb 21 21:37:22 2010 -0800
+++ b/usr/src/uts/common/sys/elf.h	Mon Feb 22 09:19:31 2010 -0700
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -720,6 +720,8 @@
 #define	CA_SUNW_NULL	0
 #define	CA_SUNW_HW_1	1		/* first hardware capabilities entry */
 #define	CA_SUNW_SF_1	2		/* first software capabilities entry */
+#define	CA_SUNW_HW_2	3		/* second hardware capabilities entry */
+#define	CA_SUNW_NUM	4
 
 /*
  * Define software capabilities (CA_SUNW_SF_1 values).  Note, hardware
--- a/usr/src/uts/common/sys/link.h	Sun Feb 21 21:37:22 2010 -0800
+++ b/usr/src/uts/common/sys/link.h	Mon Feb 22 09:19:31 2010 -0700
@@ -23,7 +23,7 @@
  *	Copyright (c) 1988 AT&T
  *	  All Rights Reserved
  *
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -282,7 +282,7 @@
 #define	DF_1_IGNMULDEF	0x00040000	/* internal: krtld ignore muldefs */
 #define	DF_1_NOKSYMS	0x00080000	/* internal: don't export object's */
 					/*	symbols via /dev/ksyms */
-#define	DF_1_NOHDR	0x00100000	/* mapfile ?N:1st segment mapping */
+#define	DF_1_NOHDR	0x00100000	/* mapfile: 1st segment mapping */
 					/*	omits ELF & program headers */
 #define	DF_1_EDITED	0x00200000	/* object has been modified since */
 					/*	being built by 'ld' */