xref: /titanic_41/usr/src/cmd/sgs/libld/common/map.c (revision 5a59a8b3d86e67dbe75588879c46e3629f40efec)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  *	Copyright (c) 1988 AT&T
24  *	  All Rights Reserved
25  *
26  *
27  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
28  * Use is subject to license terms.
29  */
30 #pragma ident	"%Z%%M%	%I%	%E% SMI"
31 
32 /*
33  * Map file parsing.
34  */
35 #include	<fcntl.h>
36 #include	<string.h>
37 #include	<stdio.h>
38 #include	<unistd.h>
39 #include	<sys/stat.h>
40 #include	<errno.h>
41 #include	<limits.h>
42 #include	<dirent.h>
43 #include	<ctype.h>
44 #include	<elfcap.h>
45 #include	"msg.h"
46 #include	"debug.h"
47 #include	"_libld.h"
48 
49 #ifdef _ELF64
50 #define	STRTOADDR	strtoull
51 #define	XWORD_MAX	ULLONG_MAX
52 #else	/* Elf32 */
53 #define	STRTOADDR	strtoul
54 #define	XWORD_MAX	UINT_MAX
55 #endif /* _ELF64 */
56 
57 typedef enum {
58 	TK_STRING,	TK_COLON,	TK_SEMICOLON,	TK_EQUAL,
59 	TK_ATSIGN,	TK_DASH,	TK_LEFTBKT,	TK_RIGHTBKT,
60 	TK_PIPE,	TK_EOF
61 } Token;			/* Possible return values from gettoken. */
62 
63 
64 static char	*Mapspace;	/* Malloc space holding map file. */
65 static ulong_t	Line_num;	/* Current map file line number. */
66 static char	*Start_tok;	/* First character of current token. */
67 static char	*nextchr;	/* Next char in mapfile to examine. */
68 
69 /*
70  * Convert a string to lowercase.
71  */
72 static void
73 lowercase(char *str)
74 {
75 	while (*str = tolower(*str))
76 		str++;
77 }
78 
79 /*
80  * Get a token from the mapfile.
81  */
82 static Token
83 gettoken(const char *mapfile)
84 {
85 	static char	oldchr = '\0';	/* Char at end of current token. */
86 	char		*end;		/* End of the current token. */
87 
88 	/* Cycle through the characters looking for tokens. */
89 	for (;;) {
90 		if (oldchr != '\0') {
91 			*nextchr = oldchr;
92 			oldchr = '\0';
93 		}
94 		if (!isascii(*nextchr) ||
95 		    (!isprint(*nextchr) && !isspace(*nextchr) &&
96 		    (*nextchr != '\0'))) {
97 			eprintf(ERR_FATAL, MSG_INTL(MSG_MAP_ILLCHAR),
98 			    mapfile, EC_XWORD(Line_num), *((uchar_t *)nextchr));
99 			/* LINTED */
100 			return ((Token)S_ERROR);
101 		}
102 		switch (*nextchr) {
103 		case '\0':	/* End of file. */
104 			return (TK_EOF);
105 		case ' ':	/* White space. */
106 		case '\t':
107 			nextchr++;
108 			break;
109 		case '\n':	/* White space too, but bump line number. */
110 			nextchr++;
111 			Line_num++;
112 			break;
113 		case '#':	/* Comment. */
114 			while (*nextchr != '\n' && *nextchr != '\0')
115 				nextchr++;
116 			break;
117 		case ':':
118 			nextchr++;
119 			return (TK_COLON);
120 		case ';':
121 			nextchr++;
122 			return (TK_SEMICOLON);
123 		case '=':
124 			nextchr++;
125 			return (TK_EQUAL);
126 		case '@':
127 			nextchr++;
128 			return (TK_ATSIGN);
129 		case '-':
130 			nextchr++;
131 			return (TK_DASH);
132 		case '|':
133 			nextchr++;
134 			return (TK_PIPE);
135 		case '{':
136 			nextchr++;
137 			return (TK_LEFTBKT);
138 		case '}':
139 			nextchr++;
140 			return (TK_RIGHTBKT);
141 		case '"':
142 			Start_tok = ++nextchr;
143 			if (((end = strpbrk(nextchr,
144 			    MSG_ORIG(MSG_MAP_TOK_1))) == NULL) ||
145 			    (*end != '"')) {
146 				eprintf(ERR_FATAL, MSG_INTL(MSG_MAP_NOTERM),
147 				    mapfile, EC_XWORD(Line_num));
148 				/* LINTED */
149 				return ((Token)S_ERROR);
150 			}
151 			*end = '\0';
152 			nextchr = end + 1;
153 			return (TK_STRING);
154 		default:	/* string. */
155 			Start_tok = nextchr;		/* CSTYLED */
156 			end = strpbrk(nextchr, MSG_ORIG(MSG_MAP_TOK_2));
157 			if (end == NULL)
158 				nextchr = Start_tok + strlen(Start_tok);
159 			else {
160 				nextchr = end;
161 				oldchr = *nextchr;
162 				*nextchr = '\0';
163 			}
164 			return (TK_STRING);
165 		}
166 	}
167 }
168 
169 /*
170  * Process a hardware/software capabilities segment declaration definition.
171  *	hwcap_1	= val,... [ OVERRIDE ]
172  *	sfcap_1	= val,... [ OVERRIDE ]
173  *
174  * The values can be defined as a list of machine specify tokens, or numerics.
175  * Tokens are representations of the sys/auxv_$MACH.h capabilities, for example:
176  *
177  *	#define AV_386_FPU 0x0001	is represented as	FPU
178  *	#define AV_386_TSC 0x0002	 "    "    "   " 	TSC
179  *
180  * Or, the above two capabilities could be represented as V0x3.  Note, the
181  * OVERRIDE flag is used to insure that only those values provided via this
182  * mapfile entry are recorded in the final image, ie. this overrides any
183  * hardware capabilities that may be defined in the objects read as part of this
184  * link-edit.  Specifying:
185  *
186  *	V0x0 OVERRIDE
187  *
188  * effectively removes any capabilities information from the final image.
189  */
190 static uintptr_t
191 map_cap(const char *mapfile, Word type, Ofl_desc *ofl)
192 {
193 	Token	tok;			/* Current token. */
194 	Xword	number;
195 	int	used = 0;
196 
197 	while ((tok = gettoken(mapfile)) != TK_SEMICOLON) {
198 		/* LINTED */
199 		if (tok == (Token)S_ERROR)
200 			return (S_ERROR);
201 		if (tok == TK_EOF) {
202 			eprintf(ERR_FATAL, MSG_INTL(MSG_MAP_PREMEOF),
203 			    mapfile, EC_XWORD(Line_num));
204 			return (S_ERROR);
205 		}
206 		if (tok != TK_STRING) {
207 			eprintf(ERR_FATAL, MSG_INTL(MSG_MAP_EXPSEGATT),
208 			    mapfile, EC_XWORD(Line_num));
209 			return (S_ERROR);
210 		}
211 
212 		lowercase(Start_tok);
213 
214 		/*
215 		 * First, determine if the token represents the reserved
216 		 * OVERRIDE keyword.
217 		 */
218 		if (strncmp(Start_tok, MSG_ORIG(MSG_MAP_OVERRIDE),
219 		    MSG_MAP_OVERRIDE_SIZE) == 0) {
220 			if (type == CA_SUNW_HW_1)
221 				ofl->ofl_flags1 |= FLG_OF1_OVHWCAP;
222 			else
223 				ofl->ofl_flags1 |= FLG_OF1_OVSFCAP;
224 			used++;
225 			continue;
226 		}
227 
228 		/*
229 		 * Next, determine if the token represents a machine specific
230 		 * hardware capability, or a generic software capability.
231 		 */
232 		if (type == CA_SUNW_HW_1) {
233 			if ((number = (Xword)hwcap_1_str2val(Start_tok,
234 			    M_MACH)) != 0) {
235 				ofl->ofl_hwcap_1 |= number;
236 				used++;
237 				continue;
238 			}
239 		} else {
240 			if ((number = (Xword)sfcap_1_str2val(Start_tok,
241 			    M_MACH)) != 0) {
242 				ofl->ofl_sfcap_1 |= number;
243 				used++;
244 				continue;
245 			}
246 		}
247 
248 		/*
249 		 * Next, determine if the token represents a numeric value.
250 		 */
251 		if (Start_tok[0] == 'v') {
252 			char		*end_tok;
253 
254 			errno = 0;
255 			number = (Xword)strtoul(&Start_tok[1], &end_tok, 0);
256 			if (errno) {
257 				int	err = errno;
258 				eprintf(ERR_FATAL,
259 				    MSG_INTL(MSG_MAP_BADCAPVAL),
260 				    mapfile, EC_XWORD(Line_num), Start_tok,
261 				    strerror(err));
262 				return (S_ERROR);
263 			}
264 			if (end_tok != strchr(Start_tok, '\0')) {
265 				eprintf(ERR_FATAL, MSG_INTL(MSG_MAP_BADCAPVAL),
266 				    mapfile, EC_XWORD(Line_num), Start_tok,
267 				    MSG_INTL(MSG_MAP_NOBADFRM));
268 				return (S_ERROR);
269 			}
270 
271 			if (type == CA_SUNW_HW_1)
272 				ofl->ofl_hwcap_1 |= number;
273 			else
274 				ofl->ofl_sfcap_1 |= number;
275 			used++;
276 			continue;
277 		}
278 
279 		/*
280 		 * We have an unknown token.
281 		 */
282 		used++;
283 		eprintf(ERR_FATAL, MSG_INTL(MSG_MAP_UNKCAPATTR),
284 		    mapfile, EC_XWORD(Line_num), Start_tok);
285 		return (S_ERROR);
286 	}
287 
288 	/*
289 	 * Catch any empty declarations, and indicate any software capabilities
290 	 * have been initialized if necessary.
291 	 */
292 	if (used == 0) {
293 		eprintf(ERR_WARNING, MSG_INTL(MSG_MAP_EMPTYCAP),
294 		    mapfile, EC_XWORD(Line_num));
295 	} else if (type == CA_SUNW_SF_1) {
296 		Lword	badsf1;
297 
298 		/*
299 		 * Note, hardware capabilities, beyond the tokens that are
300 		 * presently known, can be accepted using the V0xXXX notation,
301 		 * and as these simply get or'd into the output image, we allow
302 		 * any values to be supplied.  Software capability tokens
303 		 * however, have an algorithm of acceptance and update (see
304 		 * sf1_cap() in files.c).  Therefore only allow software
305 		 * capabilities that are known.
306 		 */
307 		if ((badsf1 = (ofl->ofl_sfcap_1 & ~SF1_SUNW_MASK)) != 0) {
308 			eprintf(ERR_WARNING, MSG_INTL(MSG_MAP_BADSF1),
309 			    mapfile, EC_XWORD(Line_num), EC_LWORD(badsf1));
310 			ofl->ofl_sfcap_1 &= SF1_SUNW_MASK;
311 		}
312 		if (ofl->ofl_sfcap_1 == SF1_SUNW_FPUSED) {
313 			eprintf(ERR_WARNING, MSG_INTL(MSG_FIL_BADSF1),
314 			    mapfile, EC_XWORD(Line_num),
315 			    EC_LWORD(SF1_SUNW_FPUSED));
316 			ofl->ofl_sfcap_1 = 0;
317 		}
318 	}
319 	return (1);
320 }
321 
322 /*
323  * Process a mapfile segment declaration definition.
324  *	segment_name	= segment_attribute;
325  * 	segment_attribute : segment_type  segment_flags  virtual_addr
326  *			    physical_addr  length alignment
327  */
328 static uintptr_t
329 map_equal(const char *mapfile, Sg_desc *sgp, Ofl_desc *ofl)
330 {
331 	Token	tok;			/* Current token. */
332 	Boolean	b_type  = FALSE;	/* True if seg types found. */
333 	Boolean	b_flags = FALSE;	/* True if seg flags found. */
334 	Boolean	b_len   = FALSE;	/* True if seg length found. */
335 	Boolean	b_round = FALSE;	/* True if seg rounding found. */
336 	Boolean	b_vaddr = FALSE;	/* True if seg virtual addr found. */
337 	Boolean	b_paddr = FALSE;	/* True if seg physical addr found. */
338 	Boolean	b_align = FALSE;	/* True if seg alignment found. */
339 
340 	while ((tok = gettoken(mapfile)) != TK_SEMICOLON) {
341 		/* LINTED */
342 		if (tok == (Token)S_ERROR)
343 			return (S_ERROR);
344 		if (tok == TK_EOF) {
345 			eprintf(ERR_FATAL, MSG_INTL(MSG_MAP_PREMEOF),
346 			    mapfile, EC_XWORD(Line_num));
347 			return (S_ERROR);
348 		}
349 		if (tok != TK_STRING) {
350 			eprintf(ERR_FATAL, MSG_INTL(MSG_MAP_EXPSEGATT),
351 			    mapfile, EC_XWORD(Line_num));
352 			return (S_ERROR);
353 		}
354 
355 		lowercase(Start_tok);
356 
357 		/*
358 		 * Segment type.  Presently there can only be multiple
359 		 * PT_LOAD and PT_NOTE segments, other segment types are
360 		 * only defined in seg_desc[].
361 		 */
362 		if (strcmp(Start_tok, MSG_ORIG(MSG_MAP_LOAD)) == 0) {
363 			if (b_type) {
364 				eprintf(ERR_FATAL, MSG_INTL(MSG_MAP_MOREONCE),
365 				    mapfile, EC_XWORD(Line_num),
366 				    MSG_INTL(MSG_MAP_SEGTYP));
367 				return (S_ERROR);
368 			}
369 			if ((sgp->sg_flags & FLG_SG_TYPE) &&
370 			    (sgp->sg_phdr.p_type != PT_LOAD))
371 				eprintf(ERR_WARNING, MSG_INTL(MSG_MAP_REDEFATT),
372 				    mapfile, EC_XWORD(Line_num),
373 				    MSG_INTL(MSG_MAP_SEGTYP), sgp->sg_name);
374 			sgp->sg_phdr.p_type = PT_LOAD;
375 			sgp->sg_flags |= FLG_SG_TYPE;
376 			b_type = TRUE;
377 		} else if (strcmp(Start_tok, MSG_ORIG(MSG_MAP_STACK)) == 0) {
378 			if (b_type) {
379 				eprintf(ERR_FATAL, MSG_INTL(MSG_MAP_MOREONCE),
380 				    mapfile, EC_XWORD(Line_num),
381 				    MSG_INTL(MSG_MAP_SEGTYP));
382 				return (S_ERROR);
383 			}
384 			sgp->sg_phdr.p_type = PT_SUNWSTACK;
385 			sgp->sg_flags |= (FLG_SG_TYPE|FLG_SG_EMPTY);
386 			b_type = TRUE;
387 		} else if (strcmp(Start_tok, MSG_ORIG(MSG_MAP_NOTE)) == 0) {
388 			if (b_type) {
389 				eprintf(ERR_FATAL, MSG_INTL(MSG_MAP_MOREONCE),
390 				    mapfile, EC_XWORD(Line_num),
391 				    MSG_INTL(MSG_MAP_SEGTYP));
392 				return (S_ERROR);
393 			}
394 			if ((sgp->sg_flags & FLG_SG_TYPE) &&
395 			    (sgp->sg_phdr.p_type != PT_NOTE))
396 				eprintf(ERR_WARNING, MSG_INTL(MSG_MAP_REDEFATT),
397 				    mapfile, EC_XWORD(Line_num),
398 				    MSG_INTL(MSG_MAP_SEGTYP), sgp->sg_name);
399 			sgp->sg_phdr.p_type = PT_NOTE;
400 			sgp->sg_flags |= FLG_SG_TYPE;
401 			b_type = TRUE;
402 		}
403 
404 
405 		/* Segment Flags. */
406 
407 		else if (*Start_tok == '?') {
408 			Word	tmp_flags = 0;
409 			char	*flag_tok = Start_tok + 1;
410 
411 			if (b_flags) {
412 				eprintf(ERR_FATAL, MSG_INTL(MSG_MAP_MOREONCE),
413 				    mapfile, EC_XWORD(Line_num),
414 				    MSG_INTL(MSG_MAP_SEGFLAG));
415 				return (S_ERROR);
416 			}
417 
418 			/*
419 			 * If ? has nothing following leave the flags cleared,
420 			 * otherwise or in any flags specified.
421 			 */
422 			if (*flag_tok) {
423 				while (*flag_tok) {
424 					switch (*flag_tok) {
425 					case 'r':
426 						tmp_flags |= PF_R;
427 						break;
428 					case 'w':
429 						tmp_flags |= PF_W;
430 						break;
431 					case 'x':
432 						tmp_flags |= PF_X;
433 						break;
434 					case 'e':
435 						sgp->sg_flags |= FLG_SG_EMPTY;
436 						break;
437 					case 'o':
438 						sgp->sg_flags |= FLG_SG_ORDER;
439 						ofl->ofl_flags |=
440 							FLG_OF_SEGORDER;
441 						break;
442 					case 'n':
443 						sgp->sg_flags |= FLG_SG_NOHDR;
444 						break;
445 					default:
446 						eprintf(ERR_FATAL,
447 						    MSG_INTL(MSG_MAP_UNKSEGFLG),
448 						    mapfile, EC_XWORD(Line_num),
449 						    *flag_tok);
450 						return (S_ERROR);
451 					}
452 					flag_tok++;
453 				}
454 			}
455 			/*
456 			 * Warn when changing flags except when we're
457 			 * adding or removing "X" from a RW PT_LOAD
458 			 * segment.
459 			 */
460 			if ((sgp->sg_flags & FLG_SG_FLAGS) &&
461 			    (sgp->sg_phdr.p_flags != tmp_flags) &&
462 			    !(sgp->sg_phdr.p_type == PT_LOAD &&
463 			    (tmp_flags & (PF_R|PF_W)) == (PF_R|PF_W) &&
464 			    (tmp_flags ^ sgp->sg_phdr.p_flags) == PF_X)) {
465 				eprintf(ERR_WARNING, MSG_INTL(MSG_MAP_REDEFATT),
466 				    mapfile, EC_XWORD(Line_num),
467 				    MSG_INTL(MSG_MAP_SEGFLAG), sgp->sg_name);
468 			}
469 			sgp->sg_flags |= FLG_SG_FLAGS;
470 			sgp->sg_phdr.p_flags = tmp_flags;
471 			b_flags = TRUE;
472 		}
473 
474 
475 		/* Segment address, length, alignment or rounding number. */
476 
477 		else if ((Start_tok[0] == 'l') || (Start_tok[0] == 'v') ||
478 		    (Start_tok[0] == 'a') || (Start_tok[0] == 'p') ||
479 		    (Start_tok[0] == 'r')) {
480 			char		*end_tok;
481 			Xword		number;
482 
483 			if ((number = (Xword)STRTOADDR(&Start_tok[1], &end_tok,
484 			    0))	>= XWORD_MAX) {
485 				eprintf(ERR_FATAL, MSG_INTL(MSG_MAP_SEGADDR),
486 				    mapfile, EC_XWORD(Line_num), Start_tok,
487 				    MSG_INTL(MSG_MAP_EXCLIMIT));
488 				return (S_ERROR);
489 			}
490 
491 			if (end_tok != strchr(Start_tok, '\0')) {
492 				eprintf(ERR_FATAL, MSG_INTL(MSG_MAP_SEGADDR),
493 				    mapfile, EC_XWORD(Line_num), Start_tok,
494 				    MSG_INTL(MSG_MAP_NOBADFRM));
495 				return (S_ERROR);
496 			}
497 
498 			switch (*Start_tok) {
499 			case 'l':
500 				if (b_len) {
501 					eprintf(ERR_FATAL,
502 					    MSG_INTL(MSG_MAP_MOREONCE),
503 					    mapfile, EC_XWORD(Line_num),
504 					    MSG_INTL(MSG_MAP_SEGLEN));
505 					return (S_ERROR);
506 				}
507 				if ((sgp->sg_flags & FLG_SG_LENGTH) &&
508 				    (sgp->sg_length != number))
509 					eprintf(ERR_WARNING,
510 					    MSG_INTL(MSG_MAP_REDEFATT),
511 					    mapfile, EC_XWORD(Line_num),
512 					    MSG_INTL(MSG_MAP_SEGLEN),
513 					    sgp->sg_name);
514 				sgp->sg_length = number;
515 				sgp->sg_flags |= FLG_SG_LENGTH;
516 				b_len = TRUE;
517 				break;
518 			case 'r':
519 				if (b_round) {
520 					eprintf(ERR_FATAL,
521 					    MSG_INTL(MSG_MAP_MOREONCE),
522 					    mapfile, EC_XWORD(Line_num),
523 					    MSG_INTL(MSG_MAP_SEGROUND));
524 					return (S_ERROR);
525 				}
526 				if ((sgp->sg_flags & FLG_SG_ROUND) &&
527 				    (sgp->sg_round != number))
528 					eprintf(ERR_WARNING,
529 					    MSG_INTL(MSG_MAP_REDEFATT),
530 					    mapfile, EC_XWORD(Line_num),
531 					    MSG_INTL(MSG_MAP_SEGROUND),
532 					    sgp->sg_name);
533 				sgp->sg_round = number;
534 				sgp->sg_flags |= FLG_SG_ROUND;
535 				b_round = TRUE;
536 				break;
537 			case 'v':
538 				if (b_vaddr) {
539 					eprintf(ERR_FATAL,
540 					    MSG_INTL(MSG_MAP_MOREONCE),
541 					    mapfile, EC_XWORD(Line_num),
542 					    MSG_INTL(MSG_MAP_SEGVADDR));
543 					return (S_ERROR);
544 				}
545 				if ((sgp->sg_flags & FLG_SG_VADDR) &&
546 				    (sgp->sg_phdr.p_vaddr != number))
547 					eprintf(ERR_WARNING,
548 					    MSG_INTL(MSG_MAP_REDEFATT),
549 					    mapfile, EC_XWORD(Line_num),
550 					    MSG_INTL(MSG_MAP_SEGVADDR),
551 					    sgp->sg_name);
552 				/* LINTED */
553 				sgp->sg_phdr.p_vaddr = (Addr)number;
554 				sgp->sg_flags |= FLG_SG_VADDR;
555 				ofl->ofl_flags1 |= FLG_OF1_VADDR;
556 				b_vaddr = TRUE;
557 				break;
558 			case 'p':
559 				if (b_paddr) {
560 					eprintf(ERR_FATAL,
561 					    MSG_INTL(MSG_MAP_MOREONCE),
562 					    mapfile, EC_XWORD(Line_num),
563 					    MSG_INTL(MSG_MAP_SEGPHYS));
564 					return (S_ERROR);
565 				}
566 				if ((sgp->sg_flags & FLG_SG_PADDR) &&
567 				    (sgp->sg_phdr.p_paddr != number))
568 					eprintf(ERR_WARNING,
569 					    MSG_INTL(MSG_MAP_REDEFATT),
570 					    mapfile, EC_XWORD(Line_num),
571 					    MSG_INTL(MSG_MAP_SEGPHYS),
572 					    sgp->sg_name);
573 				/* LINTED */
574 				sgp->sg_phdr.p_paddr = (Addr)number;
575 				sgp->sg_flags |= FLG_SG_PADDR;
576 				b_paddr = TRUE;
577 				break;
578 			case 'a':
579 				if (b_align) {
580 					eprintf(ERR_FATAL,
581 					    MSG_INTL(MSG_MAP_MOREONCE),
582 					    mapfile, EC_XWORD(Line_num),
583 					    MSG_INTL(MSG_MAP_SEGALIGN));
584 					return (S_ERROR);
585 				}
586 				if ((sgp->sg_flags & FLG_SG_ALIGN) &&
587 				    (sgp->sg_phdr.p_align != number))
588 					eprintf(ERR_WARNING,
589 					    MSG_INTL(MSG_MAP_REDEFATT),
590 					    mapfile, EC_XWORD(Line_num),
591 					    MSG_INTL(MSG_MAP_SEGALIGN),
592 					    sgp->sg_name);
593 				/* LINTED */
594 				sgp->sg_phdr.p_align = (Xword)number;
595 				sgp->sg_flags |= FLG_SG_ALIGN;
596 				b_align = TRUE;
597 				break;
598 			}
599 		} else {
600 			eprintf(ERR_FATAL, MSG_INTL(MSG_MAP_UNKSEGATT),
601 			    mapfile, EC_XWORD(Line_num), Start_tok);
602 			return (S_ERROR);
603 		}
604 	}
605 
606 	/*
607 	 * Segment reservations are only allowable for executables. In addition
608 	 * they must have an associated address, size, no permisions,
609 	 * and are only meaningful for LOAD segments (the last failure
610 	 * we can correct, hence the warning condition).
611 	 */
612 	if ((sgp->sg_flags & FLG_SG_EMPTY) &&
613 	    (sgp->sg_phdr.p_type != PT_SUNWSTACK)) {
614 		if (!(ofl->ofl_flags & FLG_OF_EXEC)) {
615 			eprintf(ERR_FATAL, MSG_INTL(MSG_MAP_SEGEMPEXE),
616 			    mapfile, EC_XWORD(Line_num));
617 			return (S_ERROR);
618 		}
619 		if (sgp->sg_phdr.p_flags != 0) {
620 			eprintf(ERR_FATAL, MSG_INTL(MSG_MAP_SEGEMNOPERM),
621 				mapfile, EC_XWORD(Line_num),
622 				EC_WORD(sgp->sg_phdr.p_flags));
623 			return (S_ERROR);
624 		}
625 		if ((sgp->sg_flags & (FLG_SG_LENGTH | FLG_SG_VADDR)) !=
626 		    (FLG_SG_LENGTH | FLG_SG_VADDR)) {
627 			eprintf(ERR_FATAL, MSG_INTL(MSG_MAP_SEGEMPATT),
628 			    mapfile, EC_XWORD(Line_num));
629 			return (S_ERROR);
630 		}
631 		if (sgp->sg_phdr.p_type != PT_LOAD) {
632 			eprintf(ERR_WARNING, MSG_INTL(MSG_MAP_SEGEMPLOAD),
633 			    mapfile, EC_XWORD(Line_num));
634 			sgp->sg_phdr.p_type = PT_LOAD;
635 		}
636 	}
637 
638 	/*
639 	 * All segment attributes have now been scanned.  Certain flags do not
640 	 * make sense if this is not a loadable segment, fix if necessary.
641 	 * Note, if the segment is of type PT_NULL it must be new, and any
642 	 * defaults will be applied back in map_parse().
643 	 * When clearing an attribute leave the flag set as an indicator for
644 	 * later entries re-specifying the same segment.
645 	 */
646 	if (sgp->sg_phdr.p_type != PT_NULL && sgp->sg_phdr.p_type != PT_LOAD) {
647 		const char *fmt;
648 
649 		if (sgp->sg_phdr.p_type == PT_SUNWSTACK)
650 			fmt = MSG_INTL(MSG_MAP_NOSTACK1);
651 		else
652 			fmt = MSG_INTL(MSG_MAP_NONLOAD);
653 
654 		if ((sgp->sg_flags & FLG_SG_FLAGS) &&
655 		    (sgp->sg_phdr.p_type != PT_SUNWSTACK)) {
656 			if (sgp->sg_phdr.p_flags != 0) {
657 				eprintf(ERR_WARNING, MSG_INTL(MSG_MAP_NONLOAD),
658 				    mapfile, EC_XWORD(Line_num),
659 				    MSG_INTL(MSG_MAP_SEGFLAG));
660 				sgp->sg_phdr.p_flags = 0;
661 			}
662 		}
663 		if (sgp->sg_flags & FLG_SG_LENGTH)
664 			if (sgp->sg_length != 0) {
665 				eprintf(ERR_WARNING,
666 				    fmt, mapfile, EC_XWORD(Line_num),
667 				    MSG_INTL(MSG_MAP_SEGLEN));
668 				sgp->sg_length = 0;
669 			}
670 		if (sgp->sg_flags & FLG_SG_ROUND)
671 			if (sgp->sg_round != 0) {
672 				eprintf(ERR_WARNING,
673 				    fmt, mapfile, EC_XWORD(Line_num),
674 				    MSG_INTL(MSG_MAP_SEGROUND));
675 				sgp->sg_round = 0;
676 			}
677 		if (sgp->sg_flags & FLG_SG_VADDR) {
678 			if (sgp->sg_phdr.p_vaddr != 0) {
679 				eprintf(ERR_WARNING,
680 				    fmt, mapfile, EC_XWORD(Line_num),
681 				    MSG_INTL(MSG_MAP_SEGVADDR));
682 				sgp->sg_phdr.p_vaddr = 0;
683 			}
684 		}
685 		if (sgp->sg_flags & FLG_SG_PADDR)
686 			if (sgp->sg_phdr.p_paddr != 0) {
687 				eprintf(ERR_WARNING,
688 				    fmt, mapfile, EC_XWORD(Line_num),
689 				    MSG_INTL(MSG_MAP_SEGPHYS));
690 				sgp->sg_phdr.p_paddr = 0;
691 			}
692 		if (sgp->sg_flags & FLG_SG_ALIGN)
693 			if (sgp->sg_phdr.p_align != 0) {
694 				eprintf(ERR_WARNING,
695 				    fmt, mapfile, EC_XWORD(Line_num),
696 				    MSG_INTL(MSG_MAP_SEGALIGN));
697 				sgp->sg_phdr.p_align = 0;
698 			}
699 	}
700 	return (1);
701 }
702 
703 
704 /*
705  * Process a mapfile mapping directives definition.
706  * 	segment_name : section_attribute [ : file_name ]
707  * 	segment_attribute : section_name section_type section_flags;
708  */
709 static uintptr_t
710 map_colon(const char *mapfile, Ent_desc *enp)
711 {
712 	Token		tok;		/* Current token. */
713 
714 	Boolean		b_name = FALSE;
715 	Boolean		b_type = FALSE;
716 	Boolean		b_attr = FALSE;
717 	Boolean		b_bang = FALSE;
718 	static	Xword	index = 0;
719 
720 
721 	while ((tok = gettoken(mapfile)) != TK_COLON && tok != TK_SEMICOLON) {
722 		/* LINTED */
723 		if (tok == (Token)S_ERROR)
724 			return (S_ERROR);
725 		if (tok == TK_EOF) {
726 			eprintf(ERR_FATAL, MSG_INTL(MSG_MAP_PREMEOF),
727 			    mapfile, EC_XWORD(Line_num));
728 			return (S_ERROR);
729 		}
730 
731 		/* Segment type. */
732 
733 		if (*Start_tok == '$') {
734 			if (b_type) {
735 				eprintf(ERR_FATAL, MSG_INTL(MSG_MAP_MOREONCE),
736 				    mapfile, EC_XWORD(Line_num),
737 				    MSG_INTL(MSG_MAP_SECTYP));
738 				return (S_ERROR);
739 			}
740 			b_type = TRUE;
741 			Start_tok++;
742 			lowercase(Start_tok);
743 			if (strcmp(Start_tok, MSG_ORIG(MSG_STR_PROGBITS)) == 0)
744 				enp->ec_type = SHT_PROGBITS;
745 			else if (strcmp(Start_tok,
746 			    MSG_ORIG(MSG_STR_SYMTAB)) == 0)
747 				enp->ec_type = SHT_SYMTAB;
748 			else if (strcmp(Start_tok,
749 			    MSG_ORIG(MSG_STR_DYNSYM)) == 0)
750 				enp->ec_type = SHT_DYNSYM;
751 			else if (strcmp(Start_tok,
752 			    MSG_ORIG(MSG_STR_STRTAB)) == 0)
753 				enp->ec_type = SHT_STRTAB;
754 			else if ((strcmp(Start_tok,
755 			    MSG_ORIG(MSG_STR_REL)) == 0) ||
756 			    (strcmp(Start_tok, MSG_ORIG(MSG_STR_RELA)) == 0))
757 				enp->ec_type = M_REL_SHT_TYPE;
758 			else if (strcmp(Start_tok, MSG_ORIG(MSG_STR_HASH)) == 0)
759 				enp->ec_type = SHT_HASH;
760 			else if (strcmp(Start_tok, MSG_ORIG(MSG_STR_LIB)) == 0)
761 				enp->ec_type = SHT_SHLIB;
762 			else if (strcmp(Start_tok,
763 			    MSG_ORIG(MSG_STR_LD_DYNAMIC)) == 0)
764 				enp->ec_type = SHT_DYNAMIC;
765 			else if (strcmp(Start_tok, MSG_ORIG(MSG_STR_NOTE)) == 0)
766 				enp->ec_type = SHT_NOTE;
767 			else if (strcmp(Start_tok,
768 			    MSG_ORIG(MSG_STR_NOBITS)) == 0)
769 				enp->ec_type = SHT_NOBITS;
770 			else {
771 				eprintf(ERR_FATAL, MSG_INTL(MSG_MAP_UNKSECTYP),
772 				    mapfile, EC_XWORD(Line_num), Start_tok);
773 				return (S_ERROR);
774 			}
775 
776 		/*
777 		 * Segment flags.
778 		 * If a segment flag is specified then the appropriate bit is
779 		 * set in the ec_attrmask, the ec_attrbits fields determine
780 		 * whether the attrmask fields must be tested true or false
781 		 * ie.	for  ?A the attrmask is set and the attrbit is set,
782 		 *	for ?!A the attrmask is set and the attrbit is clear.
783 		 */
784 		} else if (*Start_tok == '?') {
785 			if (b_attr) {
786 				eprintf(ERR_FATAL, MSG_INTL(MSG_MAP_MOREONCE),
787 				    mapfile, EC_XWORD(Line_num),
788 				    MSG_INTL(MSG_MAP_SECFLAG));
789 				return (S_ERROR);
790 			}
791 			b_attr = TRUE;
792 			b_bang = FALSE;
793 			Start_tok++;
794 			lowercase(Start_tok);
795 			for (; *Start_tok != '\0'; Start_tok++)
796 				switch (*Start_tok) {
797 				case '!':
798 					if (b_bang) {
799 						eprintf(ERR_FATAL,
800 						    MSG_INTL(MSG_MAP_BADFLAG),
801 						    mapfile, EC_XWORD(Line_num),
802 						    Start_tok);
803 						return (S_ERROR);
804 					}
805 					b_bang = TRUE;
806 					break;
807 				case 'a':
808 					if (enp->ec_attrmask & SHF_ALLOC) {
809 						eprintf(ERR_FATAL,
810 						    MSG_INTL(MSG_MAP_BADFLAG),
811 						    mapfile, EC_XWORD(Line_num),
812 						    Start_tok);
813 						return (S_ERROR);
814 					}
815 					enp->ec_attrmask |= SHF_ALLOC;
816 					if (!b_bang)
817 						enp->ec_attrbits |= SHF_ALLOC;
818 					b_bang = FALSE;
819 					break;
820 				case 'w':
821 					if (enp->ec_attrmask & SHF_WRITE) {
822 						eprintf(ERR_FATAL,
823 						    MSG_INTL(MSG_MAP_BADFLAG),
824 						    mapfile, EC_XWORD(Line_num),
825 						    Start_tok);
826 						return (S_ERROR);
827 					}
828 					enp->ec_attrmask |= SHF_WRITE;
829 					if (!b_bang)
830 						enp->ec_attrbits |= SHF_WRITE;
831 					b_bang = FALSE;
832 					break;
833 				case 'x':
834 					if (enp->ec_attrmask & SHF_EXECINSTR) {
835 						eprintf(ERR_FATAL,
836 						    MSG_INTL(MSG_MAP_BADFLAG),
837 						    mapfile, EC_XWORD(Line_num),
838 						    Start_tok);
839 						return (S_ERROR);
840 					}
841 					enp->ec_attrmask |= SHF_EXECINSTR;
842 					if (!b_bang)
843 					    enp->ec_attrbits |= SHF_EXECINSTR;
844 					b_bang = FALSE;
845 					break;
846 				default:
847 					eprintf(ERR_FATAL,
848 					    MSG_INTL(MSG_MAP_BADFLAG),
849 					    mapfile, EC_XWORD(Line_num),
850 					    Start_tok);
851 					return (S_ERROR);
852 				}
853 		/*
854 		 * Section name.
855 		 */
856 		} else {
857 			if (b_name) {
858 				eprintf(ERR_FATAL, MSG_INTL(MSG_MAP_MOREONCE),
859 				    mapfile, EC_XWORD(Line_num),
860 				    MSG_INTL(MSG_MAP_SECNAME));
861 				return (S_ERROR);
862 			}
863 			b_name = TRUE;
864 			if ((enp->ec_name =
865 			    libld_malloc(strlen(Start_tok) + 1)) == 0)
866 				return (S_ERROR);
867 			(void) strcpy((char *)enp->ec_name, Start_tok);
868 			/*
869 			 * get the index for text reordering
870 			 */
871 			/* LINTED */
872 			enp->ec_ndx = (Word)++index;
873 		}
874 	}
875 	if (tok == TK_COLON) {
876 		/*
877 		 * File names.
878 		 */
879 		while ((tok = gettoken(mapfile)) != TK_SEMICOLON) {
880 			char	*file;
881 
882 			/* LINTED */
883 			if (tok == (Token)S_ERROR)
884 				return (S_ERROR);
885 			if (tok == TK_EOF) {
886 				eprintf(ERR_FATAL, MSG_INTL(MSG_MAP_PREMEOF),
887 				    mapfile, EC_XWORD(Line_num));
888 				return (S_ERROR);
889 			}
890 			if (tok != TK_STRING) {
891 				eprintf(ERR_FATAL, MSG_INTL(MSG_MAP_MALFORM),
892 				    mapfile, EC_XWORD(Line_num));
893 				return (S_ERROR);
894 			}
895 			if ((file =
896 			    libld_malloc(strlen(Start_tok) + 1)) == 0)
897 				return (S_ERROR);
898 			(void) strcpy(file, Start_tok);
899 			if (list_appendc(&(enp->ec_files), file) == 0)
900 				return (S_ERROR);
901 		}
902 	}
903 	return (1);
904 }
905 
906 /*
907  * Obtain a pseudo input file descriptor to assign to a mapfile.  This is
908  * required any time a symbol is generated.  First traverse the input file
909  * descriptors looking for a match.  As all mapfile processing occurs before
910  * any real input file processing this list is going to be small and we don't
911  * need to do any filename clash checking.
912  */
913 static Ifl_desc *
914 map_ifl(const char *mapfile, Ofl_desc *ofl)
915 {
916 	Ifl_desc	*ifl;
917 	Listnode	*lnp;
918 
919 	for (LIST_TRAVERSE(&ofl->ofl_objs, lnp, ifl))
920 		if (strcmp(ifl->ifl_name, mapfile) == 0)
921 			return (ifl);
922 
923 	if ((ifl = libld_calloc(sizeof (Ifl_desc), 1)) == 0)
924 		return ((Ifl_desc *)S_ERROR);
925 	ifl->ifl_name = mapfile;
926 	ifl->ifl_flags = (FLG_IF_MAPFILE | FLG_IF_NEEDED | FLG_IF_FILEREF);
927 	if ((ifl->ifl_ehdr = libld_calloc(sizeof (Ehdr), 1)) == 0)
928 		return ((Ifl_desc *)S_ERROR);
929 	ifl->ifl_ehdr->e_type = ET_REL;
930 
931 	if (list_appendc(&ofl->ofl_objs, ifl) == 0)
932 		return ((Ifl_desc *)S_ERROR);
933 	else
934 		return (ifl);
935 }
936 
937 /*
938  * Process a mapfile size symbol definition.
939  * 	segment_name @ symbol_name;
940  */
941 static uintptr_t
942 map_atsign(const char *mapfile, Sg_desc *sgp, Ofl_desc *ofl)
943 {
944 	Sym		*sym;		/* New symbol pointer */
945 	Sym_desc	*sdp;		/* New symbol node pointer */
946 	Ifl_desc	*ifl;		/* Dummy input file structure */
947 	Token		tok;		/* Current token. */
948 	avl_index_t	where;
949 
950 	if ((tok = gettoken(mapfile)) != TK_STRING) {
951 		/* LINTED */
952 		if (tok != (Token)S_ERROR)
953 			eprintf(ERR_FATAL, MSG_INTL(MSG_MAP_EXPSYM_1),
954 			    mapfile, EC_XWORD(Line_num));
955 		return (S_ERROR);
956 	}
957 
958 	if (sgp->sg_sizesym != NULL) {
959 		eprintf(ERR_FATAL, MSG_INTL(MSG_MAP_SEGSIZE), mapfile,
960 			EC_XWORD(Line_num), sgp->sg_name);
961 		return (S_ERROR);
962 	}
963 
964 	/*
965 	 * Make sure we have a pseudo file descriptor to associate to the
966 	 * symbol.
967 	 */
968 	if ((ifl = map_ifl(mapfile, ofl)) == (Ifl_desc *)S_ERROR)
969 		return (S_ERROR);
970 
971 	/*
972 	 * Make sure the symbol doesn't already exist.  It is possible that the
973 	 * symbol has been scoped or versioned, in which case it does exist
974 	 * but we can freely update it here.
975 	 */
976 	if ((sdp = sym_find(Start_tok, SYM_NOHASH, &where, ofl)) == NULL) {
977 		char	*name;
978 		Word hval;
979 
980 		if ((name = libld_malloc(strlen(Start_tok) + 1)) == 0)
981 			return (S_ERROR);
982 		(void) strcpy(name, Start_tok);
983 
984 		if ((sym = libld_calloc(sizeof (Sym), 1)) == 0)
985 			return (S_ERROR);
986 		sym->st_shndx = SHN_ABS;
987 		sym->st_size = 0;
988 		sym->st_info = ELF_ST_INFO(STB_GLOBAL, STT_OBJECT);
989 
990 		DBG_CALL(Dbg_map_size_new(name));
991 		/* LINTED */
992 		hval = (Word)elf_hash(name);
993 		if ((sdp = sym_enter(name, sym, hval, ifl, ofl, 0, SHN_ABS,
994 		    (FLG_SY_SPECSEC | FLG_SY_GLOBREF), 0, &where)) ==
995 		    (Sym_desc *)S_ERROR)
996 			return (S_ERROR);
997 		sdp->sd_flags &= ~FLG_SY_CLEAN;
998 		DBG_CALL(Dbg_map_symbol(&def_ehdr, sdp));
999 	} else {
1000 		sym = sdp->sd_sym;
1001 
1002 		if (sym->st_shndx == SHN_UNDEF) {
1003 			sdp->sd_shndx = sym->st_shndx = SHN_ABS;
1004 			sdp->sd_flags |= FLG_SY_SPECSEC;
1005 			sym->st_size = 0;
1006 			sym->st_info = ELF_ST_INFO(STB_GLOBAL, STT_OBJECT);
1007 
1008 			sdp->sd_flags &= ~FLG_SY_MAPREF;
1009 
1010 			DBG_CALL(Dbg_map_size_old(&def_ehdr, sdp));
1011 		} else {
1012 			eprintf(ERR_FATAL, MSG_INTL(MSG_MAP_SYMDEF), mapfile,
1013 			    EC_XWORD(Line_num), demangle(sdp->sd_name),
1014 			    sdp->sd_file->ifl_name);
1015 			return (S_ERROR);
1016 		}
1017 	}
1018 
1019 	/*
1020 	 * Assign the symbol to the segment.
1021 	 */
1022 	sgp->sg_sizesym = sdp;
1023 
1024 	if (gettoken(mapfile) != TK_SEMICOLON) {
1025 		/* LINTED */
1026 		if (tok != (Token)S_ERROR)
1027 			eprintf(ERR_FATAL, MSG_INTL(MSG_MAP_EXPSCOL),
1028 			    mapfile, EC_XWORD(Line_num));
1029 		return (S_ERROR);
1030 	} else
1031 		return (1);
1032 }
1033 
1034 
1035 static uintptr_t
1036 map_pipe(const char *mapfile, Sg_desc *sgp)
1037 {
1038 	char		*sec_name;	/* section name */
1039 	Token		tok;		/* current token. */
1040 	Sec_order	*sc_order;
1041 	static Word	index = 0;	/* used to maintain a increasing */
1042 					/* 	index for section ordering. */
1043 
1044 	if ((tok = gettoken(mapfile)) != TK_STRING) {
1045 		/* LINTED */
1046 		if (tok != (Token)S_ERROR)
1047 			eprintf(ERR_FATAL, MSG_INTL(MSG_MAP_EXPSEC), mapfile,
1048 			    EC_XWORD(Line_num));
1049 		return (S_ERROR);
1050 	}
1051 
1052 	if ((sec_name = libld_malloc(strlen(Start_tok) + 1)) == 0)
1053 		return (S_ERROR);
1054 	(void) strcpy(sec_name, Start_tok);
1055 
1056 	if ((sc_order = libld_malloc(sizeof (Sec_order))) == 0)
1057 		return (S_ERROR);
1058 
1059 	sc_order->sco_secname = sec_name;
1060 	sc_order->sco_index = ++index;
1061 
1062 	if (list_appendc(&(sgp->sg_secorder), sc_order) == 0)
1063 		return (S_ERROR);
1064 
1065 	DBG_CALL(Dbg_map_pipe(sgp, sec_name, index));
1066 
1067 	if ((tok = gettoken(mapfile)) != TK_SEMICOLON) {
1068 		/* LINTED */
1069 		if (tok != (Token)S_ERROR)
1070 			eprintf(ERR_FATAL, MSG_INTL(MSG_MAP_EXPSCOL),
1071 			    mapfile, EC_XWORD(Line_num));
1072 		return (S_ERROR);
1073 	}
1074 
1075 	return (1);
1076 }
1077 
1078 
1079 /*
1080  * Process a mapfile library specification definition.
1081  * 	shared_object_name - shared object definition
1082  *	shared object definition : [ shared object type [ = SONAME ]]
1083  *					[ versions ];
1084  */
1085 static uintptr_t
1086 map_dash(const char *mapfile, char *name, Ofl_desc *ofl)
1087 {
1088 	char		*version;
1089 	Token		tok;
1090 	Sdf_desc	*sdf;
1091 	Sdv_desc	*sdv;
1092 	enum {
1093 	    MD_NONE = 0,
1094 	    MD_SPECVERS,
1095 	    MD_ADDVERS,
1096 	    MD_NEEDED
1097 	}		dolkey = MD_NONE;
1098 
1099 
1100 	/*
1101 	 * If a shared object definition for this file already exists use it,
1102 	 * otherwise allocate a new descriptor.
1103 	 */
1104 	if ((sdf = sdf_find(name, &ofl->ofl_socntl)) == 0) {
1105 		if ((sdf = sdf_add(name, &ofl->ofl_socntl)) ==
1106 		    (Sdf_desc *)S_ERROR)
1107 			return (S_ERROR);
1108 		sdf->sdf_rfile = mapfile;
1109 	}
1110 
1111 	/*
1112 	 * Get the shared object descriptor string.
1113 	 */
1114 	while ((tok = gettoken(mapfile)) != TK_SEMICOLON) {
1115 		/* LINTED */
1116 		if (tok == (Token)S_ERROR)
1117 			return (S_ERROR);
1118 		if (tok == TK_EOF) {
1119 			eprintf(ERR_FATAL, MSG_INTL(MSG_MAP_PREMEOF),
1120 			    mapfile, EC_XWORD(Line_num));
1121 			return (S_ERROR);
1122 		}
1123 		if ((tok != TK_STRING) && (tok != TK_EQUAL)) {
1124 			eprintf(ERR_FATAL, MSG_INTL(MSG_MAP_EXPSO),
1125 			    mapfile, EC_XWORD(Line_num));
1126 			return (S_ERROR);
1127 		}
1128 
1129 		/*
1130 		 * Determine if the library type is accompanied with a SONAME
1131 		 * definition.
1132 		 */
1133 		if (tok == TK_EQUAL) {
1134 			if ((tok = gettoken(mapfile)) != TK_STRING) {
1135 				/* LINTED */
1136 				if (tok == (Token)S_ERROR)
1137 					return (S_ERROR);
1138 				else {
1139 					eprintf(ERR_FATAL,
1140 					    MSG_INTL(MSG_MAP_EXPSO), mapfile,
1141 					    EC_XWORD(Line_num));
1142 					return (S_ERROR);
1143 				}
1144 			}
1145 			switch (dolkey) {
1146 			case MD_NEEDED:
1147 				if (sdf->sdf_flags & FLG_SDF_SONAME) {
1148 					eprintf(ERR_WARNING,
1149 					    MSG_INTL(MSG_MAP_MULSONAME),
1150 					    mapfile, EC_XWORD(Line_num), name,
1151 					    sdf->sdf_soname, Start_tok);
1152 					dolkey = MD_NONE;
1153 					continue;
1154 				}
1155 				if ((sdf->sdf_soname =
1156 				    libld_malloc(strlen(Start_tok) + 1)) == 0)
1157 					return (S_ERROR);
1158 				(void) strcpy((char *)sdf->sdf_soname,
1159 					Start_tok);
1160 				sdf->sdf_flags |= FLG_SDF_SONAME;
1161 				break;
1162 			case MD_SPECVERS:
1163 			case MD_ADDVERS:
1164 				if ((sdv = libld_calloc(
1165 				    sizeof (Sdv_desc), 1)) == 0)
1166 					return (S_ERROR);
1167 
1168 				if (dolkey == MD_SPECVERS)
1169 					sdf->sdf_flags |= FLG_SDF_SPECVER;
1170 				else
1171 					sdf->sdf_flags |= FLG_SDF_ADDVER;
1172 
1173 				if ((sdf->sdf_flags & (FLG_SDF_SPECVER |
1174 				    FLG_SDF_ADDVER)) == (FLG_SDF_SPECVER |
1175 				    FLG_SDF_ADDVER)) {
1176 					eprintf(ERR_FATAL,
1177 					    MSG_INTL(MSG_MAP_INCOMFLG),
1178 					    mapfile, EC_XWORD(Line_num),
1179 					    sdf->sdf_name);
1180 					return (S_ERROR);
1181 				}
1182 				if ((version =
1183 				    libld_malloc(strlen(Start_tok) + 1)) == 0)
1184 					return (S_ERROR);
1185 				(void) strcpy(version, Start_tok);
1186 				sdv->sdv_name = version;
1187 				sdv->sdv_ref = mapfile;
1188 				if (list_appendc(&sdf->sdf_verneed, sdv) == 0)
1189 					return (S_ERROR);
1190 				break;
1191 			case MD_NONE:
1192 				eprintf(ERR_FATAL, MSG_INTL(MSG_MAP_UNEXTOK),
1193 				    mapfile, EC_XWORD(Line_num), '=');
1194 				return (S_ERROR);
1195 			}
1196 			dolkey = MD_NONE;
1197 			continue;
1198 		}
1199 
1200 		/*
1201 		 * A shared object type has been specified.  This may also be
1202 		 * accompanied by an SONAME redefinition (see above).
1203 		 */
1204 		if (*Start_tok == '$') {
1205 			if (dolkey != MD_NONE) {
1206 				eprintf(ERR_FATAL, MSG_INTL(MSG_MAP_UNEXTOK),
1207 				    mapfile, EC_XWORD(Line_num), '$');
1208 				return (S_ERROR);
1209 			}
1210 			Start_tok++;
1211 			lowercase(Start_tok);
1212 			if (strcmp(Start_tok,
1213 			    MSG_ORIG(MSG_MAP_NEED)) == 0)
1214 				dolkey = MD_NEEDED;
1215 			else if (strcmp(Start_tok,
1216 			    MSG_ORIG(MSG_MAP_SPECVERS)) == 0)
1217 				dolkey = MD_SPECVERS;
1218 			else if (strcmp(Start_tok,
1219 			    MSG_ORIG(MSG_MAP_ADDVERS)) == 0)
1220 				dolkey = MD_ADDVERS;
1221 			else {
1222 				eprintf(ERR_FATAL, MSG_INTL(MSG_MAP_UNKSOTYP),
1223 				    mapfile, EC_XWORD(Line_num), Start_tok);
1224 				return (S_ERROR);
1225 			}
1226 			continue;
1227 		}
1228 
1229 		/*
1230 		 * shared object version requirement.
1231 		 */
1232 		if ((version = libld_malloc(strlen(Start_tok) + 1)) == 0)
1233 			return (S_ERROR);
1234 		(void) strcpy(version, Start_tok);
1235 		if ((sdv = libld_calloc(sizeof (Sdv_desc), 1)) == 0)
1236 			return (S_ERROR);
1237 		sdv->sdv_name = version;
1238 		sdv->sdv_ref = mapfile;
1239 		sdf->sdf_flags |= FLG_SDF_SELECT;
1240 		if (list_appendc(&sdf->sdf_vers, sdv) == 0)
1241 			return (S_ERROR);
1242 	}
1243 
1244 	DBG_CALL(Dbg_map_dash(name, sdf));
1245 	return (1);
1246 }
1247 
1248 
1249 /*
1250  * Process a symbol definition list
1251  * 	version name {
1252  *		local:
1253  *		hidden:
1254  *		    symbol { =	(FUNC | OBJECT)
1255  *				(PARENT | EXTERN)
1256  *				($ABS | $COMMON) A V
1257  *			   };
1258  *			*;
1259  *		global:
1260  *		default:
1261  *		symbolic:
1262  *		protected:
1263  *		    symbol { =	(FUNC | OBJECT)
1264  *				(PARENT | EXTERN)
1265  *				(DIRECT | NODIRECT)
1266  *				([FILTER | AUXILIARY] name)
1267  *				($ABS | $COMMON) A V
1268  *			   };
1269  *	} [references];
1270  */
1271 #define	SYMNO		50		/* Symbol block allocation amount */
1272 #define	FLG_SCOPE_LOCL	0		/* local scope flag */
1273 #define	FLG_SCOPE_GLOB	1		/* global scope flag */
1274 #define	FLG_SCOPE_SYMB	2		/* symbolic scope flag */
1275 #define	FLG_SCOPE_ELIM	3		/* eliminate symbol from symtabs */
1276 
1277 static uintptr_t
1278 map_version(const char *mapfile, char *name, Ofl_desc *ofl)
1279 {
1280 	Token		tok;
1281 	Sym		*sym;
1282 	int		scope = FLG_SCOPE_GLOB;
1283 	Ver_desc	*vdp;
1284 	Word		hash;
1285 	Ifl_desc	*ifl;
1286 	avl_index_t	where;
1287 
1288 	/*
1289 	 * If we're generating segments within the image then any symbol
1290 	 * reductions will be processed (ie. applied to relocations and symbol
1291 	 * table entries).  Otherwise (when creating a relocatable object) any
1292 	 * versioning information is simply recorded for use in a later
1293 	 * (segment generating) link-edit.
1294 	 */
1295 	if (ofl->ofl_flags & FLG_OF_RELOBJ)
1296 		ofl->ofl_flags |= FLG_OF_VERDEF;
1297 
1298 	/*
1299 	 * If this is a new mapfile reference generate an input file descriptor
1300 	 * to represent it.  Otherwise this must simply be a new version within
1301 	 * the mapfile we've previously been processing, in this case continue
1302 	 * to use the original input file descriptor.
1303 	 */
1304 	if ((ifl = map_ifl(mapfile, ofl)) == (Ifl_desc *)S_ERROR)
1305 		return (S_ERROR);
1306 
1307 	/*
1308 	 * If no version descriptors have yet been set up, initialize a base
1309 	 * version to represent the output file itself.  This `base' version
1310 	 * catches any internally generated symbols (_end, _etext, etc.) and
1311 	 * serves to initialize the output version descriptor count.
1312 	 */
1313 	if (ofl->ofl_vercnt == 0) {
1314 		if (vers_base(ofl) == (Ver_desc *)S_ERROR)
1315 			return (S_ERROR);
1316 	}
1317 
1318 	/*
1319 	 * If this definition has an associated version name then generate a
1320 	 * new version descriptor and an associated version symbol index table.
1321 	 */
1322 	if (name) {
1323 		ofl->ofl_flags |= FLG_OF_VERDEF;
1324 
1325 		/*
1326 		 * Traverse the present version descriptor list to see if there
1327 		 * is already one of the same name, otherwise create a new one.
1328 		 */
1329 		/* LINTED */
1330 		hash = (Word)elf_hash(name);
1331 		if ((vdp = vers_find(name, hash, &ofl->ofl_verdesc)) == 0) {
1332 			if ((vdp = vers_desc(name, hash,
1333 			    &ofl->ofl_verdesc)) == (Ver_desc *)S_ERROR)
1334 				return (S_ERROR);
1335 		}
1336 
1337 		/*
1338 		 * Initialize any new version with an index, the file from which
1339 		 * it was first referenced, and a WEAK flag (indicates that
1340 		 * there are no symbols assigned to it yet).
1341 		 */
1342 		if (vdp->vd_ndx == 0) {
1343 			/* LINTED */
1344 			vdp->vd_ndx = (Half)++ofl->ofl_vercnt;
1345 			vdp->vd_file = ifl;
1346 			vdp->vd_flags = VER_FLG_WEAK;
1347 		}
1348 	} else {
1349 		/*
1350 		 * If a version definition hasn't been specified assign any
1351 		 * symbols to the base version.
1352 		 */
1353 		vdp = (Ver_desc *)ofl->ofl_verdesc.head->data;
1354 	}
1355 
1356 	/*
1357 	 * Scan the mapfile entry picking out scoping and symbol definitions.
1358 	 */
1359 	while ((tok = gettoken(mapfile)) != TK_RIGHTBKT) {
1360 		Sym_desc * 	sdp;
1361 		Word		shndx = SHN_UNDEF;
1362 		uchar_t 	type = STT_NOTYPE;
1363 		Addr		value = 0, size = 0;
1364 		char		*_name, *filtee = 0;
1365 		Word		sym_flags = 0;
1366 		Half		sym_flags1 = 0;
1367 		uint_t		filter = 0, dftflag;
1368 
1369 		if ((tok != TK_STRING) && (tok != TK_COLON)) {
1370 			eprintf(ERR_FATAL, MSG_INTL(MSG_MAP_EXPSYM_2),
1371 			    mapfile, EC_XWORD(Line_num));
1372 			return (S_ERROR);
1373 		}
1374 
1375 		if ((_name = libld_malloc(strlen(Start_tok) + 1)) == 0)
1376 			return (S_ERROR);
1377 		(void) strcpy(_name, Start_tok);
1378 
1379 		if ((tok != TK_COLON) &&
1380 		    /* LINTED */
1381 		    (tok = gettoken(mapfile)) == (Token)S_ERROR)
1382 			return (S_ERROR);
1383 
1384 		/*
1385 		 * Turn off the WEAK flag to indicate that definitions are
1386 		 * associated with this version.  It would probably be more
1387 		 * accurate to only remove this flag with the specification of
1388 		 * global symbols, however setting it here allows enough slop
1389 		 * to compensate for the various user inputs we've seen so far.
1390 		 * Only if a closed version is specified (i.e., "SUNW_1.x {};")
1391 		 * will a user get a weak version (which is how we document the
1392 		 * creation of weak versions).
1393 		 */
1394 		vdp->vd_flags &= ~VER_FLG_WEAK;
1395 
1396 		switch (tok) {
1397 		case TK_COLON:
1398 			/*
1399 			 * Establish a new scope.  All symbols added by this
1400 			 * mapfile are actually global entries. They will be
1401 			 * reduced to locals during sym_update().
1402 			 */
1403 			if ((strcmp(MSG_ORIG(MSG_STR_LOCAL),
1404 			    _name) == 0) ||
1405 			    (strcmp(MSG_ORIG(MSG_MAP_HIDDEN), _name) == 0))
1406 				scope = FLG_SCOPE_LOCL;
1407 			else if ((strcmp(MSG_ORIG(MSG_MAP_GLOBAL),
1408 			    _name) == 0) ||
1409 			    (strcmp(MSG_ORIG(MSG_MAP_DEFAULT), _name) == 0))
1410 				scope = FLG_SCOPE_GLOB;
1411 			else if ((strcmp(MSG_ORIG(MSG_STR_SYMBOLIC),
1412 			    _name) == 0) ||
1413 			    (strcmp(MSG_ORIG(MSG_MAP_PROTECTED), _name) == 0))
1414 				scope = FLG_SCOPE_SYMB;
1415 			else if (strcmp(MSG_ORIG(MSG_STR_ELIMINATE), _name)
1416 			    == 0)
1417 				scope = FLG_SCOPE_ELIM;
1418 			else {
1419 				eprintf(ERR_FATAL, MSG_INTL(MSG_MAP_UNKSYMSCO),
1420 				    mapfile, EC_XWORD(Line_num), _name);
1421 				return (S_ERROR);
1422 			}
1423 			continue;
1424 
1425 		case TK_EQUAL:
1426 			/*
1427 			 * A full blown symbol definition follows.
1428 			 * Determine the symbol type and any virtual address or
1429 			 * alignment specified and then fall through to process
1430 			 * the entire symbols information.
1431 			 */
1432 			while ((tok = gettoken(mapfile)) != TK_SEMICOLON) {
1433 
1434 				/*
1435 				 * If we had previously seen a filter or
1436 				 * auxiliary filter requirement, the next string
1437 				 * is the filtee itself.
1438 				 */
1439 				if (filter) {
1440 					if (filtee) {
1441 					    eprintf(ERR_FATAL,
1442 						MSG_INTL(MSG_MAP_MULTFILTEE),
1443 						mapfile, EC_XWORD(Line_num),
1444 						_name);
1445 					    return (S_ERROR);
1446 					}
1447 					if ((filtee = libld_malloc(
1448 					    strlen(Start_tok) + 1)) == 0)
1449 						return (S_ERROR);
1450 					(void) strcpy(filtee, Start_tok);
1451 					filter = 0;
1452 					continue;
1453 				}
1454 
1455 				/*
1456 				 * Determine any Value or Size attributes.
1457 				 */
1458 				lowercase(Start_tok);
1459 				if (Start_tok[0] == 'v' ||
1460 				    Start_tok[0] == 's') {
1461 					char		*end_tok;
1462 					Lword		number;
1463 
1464 					if ((number = (Lword)STRTOADDR(
1465 					    &Start_tok[1], &end_tok, 0)) ==
1466 					    XWORD_MAX) {
1467 						eprintf(ERR_FATAL,
1468 						    MSG_INTL(MSG_MAP_SEGADDR),
1469 						    mapfile, EC_XWORD(Line_num),
1470 						    Start_tok,
1471 						    MSG_INTL(MSG_MAP_EXCLIMIT));
1472 						return (S_ERROR);
1473 					}
1474 
1475 					if (end_tok !=
1476 					    strchr(Start_tok, '\0')) {
1477 						eprintf(ERR_FATAL,
1478 						    MSG_INTL(MSG_MAP_SEGADDR),
1479 						    mapfile, EC_XWORD(Line_num),
1480 						    Start_tok,
1481 						    MSG_INTL(MSG_MAP_NOBADFRM));
1482 						return (S_ERROR);
1483 					}
1484 
1485 					switch (*Start_tok) {
1486 					case 'v':
1487 					    if (value) {
1488 						eprintf(ERR_FATAL,
1489 						    MSG_INTL(MSG_MAP_MOREONCE),
1490 						    mapfile, EC_XWORD(Line_num),
1491 						    MSG_INTL(MSG_MAP_SYMVAL));
1492 						return (S_ERROR);
1493 					    }
1494 					    /* LINTED */
1495 					    value = (Addr)number;
1496 					    break;
1497 					case 's':
1498 					    if (size) {
1499 						eprintf(ERR_FATAL,
1500 						    MSG_INTL(MSG_MAP_MOREONCE),
1501 						    mapfile, EC_XWORD(Line_num),
1502 						    MSG_INTL(MSG_MAP_SYMSIZE));
1503 						return (S_ERROR);
1504 					    }
1505 					    /* LINTED */
1506 					    size = (Addr)number;
1507 					    break;
1508 					}
1509 
1510 				} else if (strcmp(Start_tok,
1511 				    MSG_ORIG(MSG_MAP_FUNCTION)) == 0) {
1512 					shndx = SHN_ABS;
1513 					sym_flags |= FLG_SY_SPECSEC;
1514 					type = STT_FUNC;
1515 				} else if (strcmp(Start_tok,
1516 				    MSG_ORIG(MSG_MAP_DATA)) == 0) {
1517 					shndx = SHN_ABS;
1518 					sym_flags |= FLG_SY_SPECSEC;
1519 					type = STT_OBJECT;
1520 				} else if (strcmp(Start_tok,
1521 				    MSG_ORIG(MSG_MAP_COMMON)) == 0) {
1522 					shndx = SHN_COMMON;
1523 					sym_flags |= FLG_SY_SPECSEC;
1524 					type = STT_OBJECT;
1525 				} else if (strcmp(Start_tok,
1526 				    MSG_ORIG(MSG_MAP_PARENT)) == 0) {
1527 					sym_flags |= FLG_SY_PARENT;
1528 					ofl->ofl_flags |= FLG_OF_SYMINFO;
1529 				} else if (strcmp(Start_tok,
1530 				    MSG_ORIG(MSG_MAP_EXTERN)) == 0) {
1531 					sym_flags |= FLG_SY_EXTERN;
1532 					ofl->ofl_flags |= FLG_OF_SYMINFO;
1533 				} else if (strcmp(Start_tok,
1534 				    MSG_ORIG(MSG_MAP_DIRECT)) == 0) {
1535 					sym_flags1 |= FLG_SY1_DIR;
1536 					ofl->ofl_flags |= FLG_OF_SYMINFO;
1537 				} else if (strcmp(Start_tok,
1538 				    MSG_ORIG(MSG_MAP_NODIRECT)) == 0) {
1539 					sym_flags1 |= FLG_SY1_NDIR;
1540 					ofl->ofl_flags |= FLG_OF_SYMINFO;
1541 					ofl->ofl_flags1 |= FLG_OF1_NDIRECT;
1542 					ofl->ofl_dtflags_1 |= DF_1_NODIRECT;
1543 				} else if (strcmp(Start_tok,
1544 				    MSG_ORIG(MSG_MAP_FILTER)) == 0) {
1545 					dftflag = filter = FLG_SY_STDFLTR;
1546 					sym_flags |= FLG_SY_STDFLTR;
1547 					ofl->ofl_flags |= FLG_OF_SYMINFO;
1548 					continue;
1549 				} else if (strcmp(Start_tok,
1550 				    MSG_ORIG(MSG_MAP_AUXILIARY)) == 0) {
1551 					dftflag = filter = FLG_SY_AUXFLTR;
1552 					sym_flags |= FLG_SY_AUXFLTR;
1553 					ofl->ofl_flags |= FLG_OF_SYMINFO;
1554 					continue;
1555 				} else {
1556 					eprintf(ERR_FATAL,
1557 					    MSG_INTL(MSG_MAP_UNKSYMDEF),
1558 					    mapfile, EC_XWORD(Line_num),
1559 					    Start_tok);
1560 					return (S_ERROR);
1561 				}
1562 			}
1563 			/* FALLTHROUGH */
1564 
1565 		case TK_SEMICOLON:
1566 			/*
1567 			 * The special auto-reduction directive `*' can be
1568 			 * specified in local scope and indicates that all
1569 			 * symbols processed that are not explicitly defined to
1570 			 * be global are to be reduced to local scope in the
1571 			 * output image.  This also applies that a version
1572 			 * definition is created as the user has effectively
1573 			 * defined an interface.
1574 			 */
1575 			if (*_name == '*') {
1576 				if (scope == FLG_SCOPE_LOCL)
1577 					ofl->ofl_flags |=
1578 					    (FLG_OF_AUTOLCL | FLG_OF_VERDEF);
1579 				else if (scope == FLG_SCOPE_ELIM) {
1580 					ofl->ofl_flags |= FLG_OF_VERDEF;
1581 					ofl->ofl_flags1 |= FLG_OF1_AUTOELM;
1582 				}
1583 				continue;
1584 			}
1585 
1586 			/*
1587 			 * Add the new symbol.  It should be noted that all
1588 			 * symbols added by the mapfile start out with global
1589 			 * scope, thus they will fall through the normal symbol
1590 			 * resolution process.  Symbols defined as locals will
1591 			 * be reduced in scope after all input file processing.
1592 			 */
1593 			/* LINTED */
1594 			hash = (Word)elf_hash(_name);
1595 			DBG_CALL(Dbg_map_version(name, _name, scope));
1596 			if ((sdp = sym_find(_name, hash, &where,
1597 			    ofl)) == NULL) {
1598 				if ((sym = libld_calloc(sizeof (Sym), 1)) == 0)
1599 					return (S_ERROR);
1600 
1601 				/*
1602 				 * Make sure any parent or external declarations
1603 				 * fall back to references.
1604 				 */
1605 				if (sym_flags & (FLG_SY_PARENT | FLG_SY_EXTERN))
1606 					sym->st_shndx = shndx = SHN_UNDEF;
1607 				else
1608 					sym->st_shndx = (Half)shndx;
1609 
1610 				sym->st_value = value;
1611 				sym->st_size = size;
1612 				sym->st_info = ELF_ST_INFO(STB_GLOBAL, type);
1613 
1614 				if ((sdp = sym_enter(_name, sym, hash, ifl,
1615 				    ofl, 0, shndx, sym_flags, sym_flags1,
1616 				    &where)) == (Sym_desc *)S_ERROR)
1617 					return (S_ERROR);
1618 
1619 				sdp->sd_flags &= ~FLG_SY_CLEAN;
1620 
1621 				/*
1622 				 * Identify any references.  FLG_SY_MAPREF is
1623 				 * turned off once a relocatable object with
1624 				 * the same symbol is found, thus the existance
1625 				 * of FLG_SY_MAPREF at symbol validation is
1626 				 * used to flag undefined/mispelt entries.
1627 				 */
1628 				if (sym->st_shndx == SHN_UNDEF)
1629 					sdp->sd_flags |=
1630 					    (FLG_SY_MAPREF | FLG_SY_GLOBREF);
1631 
1632 			} else {
1633 				int	conflict = 0;
1634 
1635 				sym = sdp->sd_sym;
1636 
1637 				/*
1638 				 * If this symbol already exists, make sure this
1639 				 * definition doesn't conflict with the former.
1640 				 * Provided it doesn't, multiple definitions can
1641 				 * augment each other.
1642 				 */
1643 				if (sym->st_value) {
1644 					if (value && (sym->st_value != value))
1645 						conflict = 1;
1646 				} else
1647 					sym->st_value = value;
1648 
1649 				if (sym->st_size) {
1650 					if (size && (sym->st_size != size))
1651 						conflict = 2;
1652 				} else
1653 					sym->st_size = size;
1654 
1655 				if (ELF_ST_TYPE(sym->st_info) != STT_NOTYPE) {
1656 					if ((type != STT_NOTYPE) &&
1657 					    (ELF_ST_TYPE(sym->st_info) != type))
1658 						conflict = 3;
1659 				} else
1660 					sym->st_info =
1661 					    ELF_ST_INFO(STB_GLOBAL, type);
1662 
1663 				if (sym->st_shndx != SHN_UNDEF) {
1664 					if ((shndx != SHN_UNDEF) &&
1665 					    (sym->st_shndx != shndx))
1666 						conflict = 4;
1667 				} else
1668 					sdp->sd_shndx = sym->st_shndx = shndx;
1669 
1670 				if ((sdp->sd_flags1 & FLG_SY1_LOCL) &&
1671 				    ((scope != FLG_SCOPE_LOCL) &&
1672 				    (scope != FLG_SCOPE_ELIM)))
1673 					conflict = 5;
1674 				if ((sdp->sd_flags1 & FLG_SY1_GLOB) &&
1675 				    (scope != FLG_SCOPE_GLOB) &&
1676 				    (scope != FLG_SCOPE_SYMB))
1677 					conflict = 6;
1678 				if ((sdp->sd_flags1 & FLG_SY1_GLOB) &&
1679 				    (sdp->sd_aux->sa_overndx !=
1680 				    VER_NDX_GLOBAL) &&
1681 				    (vdp->vd_ndx != VER_NDX_GLOBAL) &&
1682 				    (sdp->sd_aux->sa_overndx != vdp->vd_ndx))
1683 					conflict = 7;
1684 
1685 				if (conflict) {
1686 					eprintf(ERR_FATAL,
1687 					    MSG_INTL(MSG_MAP_SYMDEF), mapfile,
1688 					    EC_XWORD(Line_num), demangle(_name),
1689 					    sdp->sd_file->ifl_name);
1690 					return (S_ERROR);
1691 				}
1692 
1693 				/*
1694 				 * If this mapfile entry supplies a definition,
1695 				 * indicate that the symbol is now used.
1696 				 */
1697 				if (shndx != SHN_UNDEF)
1698 					sdp->sd_flags |= FLG_SY_MAPUSED;
1699 			}
1700 
1701 			/*
1702 			 * Indicate the new symbols scope.
1703 			 */
1704 			if (scope == FLG_SCOPE_LOCL) {
1705 				sdp->sd_flags1 |= FLG_SY1_LOCL;
1706 				sdp->sd_sym->st_other = STV_HIDDEN;
1707 				if (ofl->ofl_flags1 & FLG_OF1_REDLSYM)
1708 					sdp->sd_flags1 |= FLG_SY1_ELIM;
1709 
1710 			} else if (scope == FLG_SCOPE_ELIM) {
1711 				sdp->sd_flags1 |= (FLG_SY1_LOCL | FLG_SY1_ELIM);
1712 				sdp->sd_sym->st_other = STV_HIDDEN;
1713 			} else {
1714 				sdp->sd_flags |= sym_flags;
1715 				sdp->sd_flags1 |= (sym_flags1 | FLG_SY1_GLOB);
1716 
1717 				if (scope == FLG_SCOPE_SYMB) {
1718 					sdp->sd_flags1 |= FLG_SY1_PROT;
1719 					sdp->sd_sym->st_other = STV_PROTECTED;
1720 				}
1721 
1722 				/*
1723 				 * Record the present version index for later
1724 				 * potential versioning.
1725 				 */
1726 				if ((sdp->sd_aux->sa_overndx == 0) ||
1727 				    (sdp->sd_aux->sa_overndx == VER_NDX_GLOBAL))
1728 					sdp->sd_aux->sa_overndx = vdp->vd_ndx;
1729 				vdp->vd_flags |= FLG_VER_REFER;
1730 			}
1731 
1732 			/*
1733 			 * If we've encountered a symbol definition simulate
1734 			 * that an input file has been processed - this allows
1735 			 * things like filters to be created purely from a
1736 			 * mapfile.
1737 			 */
1738 			if (type != STT_NOTYPE)
1739 				ofl->ofl_objscnt++;
1740 			DBG_CALL(Dbg_map_symbol(&def_ehdr, sdp));
1741 
1742 			/*
1743 			 * If this symbol has an associated filtee, record the
1744 			 * filtee string and associate the string index with the
1745 			 * symbol.  This is used later to associate the syminfo
1746 			 * information with the necessary .dynamic entry.
1747 			 */
1748 			if (filter && (filtee == 0)) {
1749 				eprintf(ERR_FATAL, MSG_INTL(MSG_MAP_NOFILTER),
1750 				    mapfile, EC_XWORD(Line_num), _name);
1751 				return (S_ERROR);
1752 			}
1753 
1754 			if (filtee) {
1755 				Dfltr_desc *	dftp;
1756 				Sfltr_desc	sft;
1757 				Aliste		off = 0, _off;
1758 
1759 				/*
1760 				 * Make sure we don't duplicate any filtee
1761 				 * strings, and create a new descriptor if
1762 				 * necessary.
1763 				 */
1764 				for (ALIST_TRAVERSE(ofl->ofl_dtsfltrs, _off,
1765 				    dftp)) {
1766 					if ((dftflag != dftp->dft_flag) ||
1767 					    (strcmp(dftp->dft_str, filtee)))
1768 						continue;
1769 					off = _off;
1770 					break;
1771 				}
1772 				if (off == 0) {
1773 					Dfltr_desc	dft;
1774 
1775 					dft.dft_str = filtee;
1776 					dft.dft_flag = dftflag;
1777 					dft.dft_ndx = 0;
1778 
1779 					if ((dftp =
1780 					    alist_append(&(ofl->ofl_dtsfltrs),
1781 					    &dft, sizeof (Dfltr_desc),
1782 					    AL_CNT_DFLTR)) == 0)
1783 						return (S_ERROR);
1784 
1785 					off = (Aliste)((char *)dftp -
1786 					    (char *)ofl->ofl_dtsfltrs);
1787 				}
1788 
1789 				/*
1790 				 * Create a new filter descriptor for this
1791 				 * symbol.
1792 				 */
1793 				sft.sft_sdp = sdp;
1794 				sft.sft_off = off;
1795 
1796 				if (alist_append(&(ofl->ofl_symfltrs),
1797 				    &sft, sizeof (Sfltr_desc),
1798 				    AL_CNT_SFLTR) == 0)
1799 					return (S_ERROR);
1800 			}
1801 			break;
1802 
1803 		default:
1804 			eprintf(ERR_FATAL, MSG_INTL(MSG_MAP_EXPSCOL),
1805 			    mapfile, EC_XWORD(Line_num));
1806 			return (S_ERROR);
1807 		}
1808 	}
1809 
1810 	/*
1811 	 * Determine if any version references are provided after the close
1812 	 * bracket.
1813 	 */
1814 	while ((tok = gettoken(mapfile)) != TK_SEMICOLON) {
1815 		Ver_desc	*_vdp;
1816 		char		*_name;
1817 
1818 		if (tok != TK_STRING) {
1819 			/* LINTED */
1820 			if (tok != (Token)S_ERROR)
1821 				eprintf(ERR_FATAL, MSG_INTL(MSG_MAP_EXPVERS),
1822 				    mapfile, EC_XWORD(Line_num));
1823 			return (S_ERROR);
1824 		}
1825 
1826 		name = Start_tok;
1827 		if (vdp->vd_ndx == VER_NDX_GLOBAL) {
1828 			eprintf(ERR_WARNING, MSG_INTL(MSG_MAP_UNEXDEP),
1829 			    mapfile, EC_XWORD(Line_num), name);
1830 			continue;
1831 		}
1832 
1833 		/*
1834 		 * Generate a new version descriptor if it doesn't already
1835 		 * exist.
1836 		 */
1837 		/* LINTED */
1838 		hash = (Word)elf_hash(name);
1839 		if ((_vdp = vers_find(name, hash, &ofl->ofl_verdesc)) == 0) {
1840 			if ((_name = libld_malloc(strlen(name) + 1)) == 0)
1841 				return (S_ERROR);
1842 			(void) strcpy(_name, name);
1843 
1844 			if ((_vdp = vers_desc(_name, hash,
1845 			    &ofl->ofl_verdesc)) == (Ver_desc *)S_ERROR)
1846 				return (S_ERROR);
1847 		}
1848 
1849 		/*
1850 		 * Add the new version descriptor to the parent version
1851 		 * descriptors reference list.  Indicate the version descriptors
1852 		 * first reference (used for error disgnostics if undefined
1853 		 * version dependencies remain).
1854 		 */
1855 		if (vers_find(name, hash, &vdp->vd_deps) == 0)
1856 			if (list_appendc(&vdp->vd_deps, _vdp) == 0)
1857 				return (S_ERROR);
1858 
1859 		if (_vdp->vd_ref == 0)
1860 			_vdp->vd_ref = vdp;
1861 	}
1862 	return (1);
1863 }
1864 
1865 /*
1866  * Sort the segment list by increasing virtual address.
1867  */
1868 uintptr_t
1869 sort_seg_list(Ofl_desc *ofl)
1870 {
1871 	List 		seg1, seg2;
1872 	Listnode	*lnp1, *lnp2, *lnp3;
1873 	Sg_desc		*sgp1, *sgp2;
1874 
1875 	seg1.head = seg1.tail = seg2.head = seg2.tail = NULL;
1876 
1877 	/*
1878 	 * Add the .phdr and .interp segments to our list. These segments must
1879 	 * occur before any PT_LOAD segments (refer exec/elf/elf.c).
1880 	 */
1881 	for (LIST_TRAVERSE(&ofl->ofl_segs, lnp1, sgp1)) {
1882 		Word	type = sgp1->sg_phdr.p_type;
1883 
1884 		if ((type == PT_PHDR) || (type == PT_INTERP))
1885 			if (list_appendc(&seg1, sgp1) == 0)
1886 				return (S_ERROR);
1887 	}
1888 
1889 	/*
1890 	 * Add the loadable segments to another list in sorted order.
1891 	 */
1892 	for (LIST_TRAVERSE(&ofl->ofl_segs, lnp1, sgp1)) {
1893 		DBG_CALL(Dbg_map_sort_orig(sgp1));
1894 		if (sgp1->sg_phdr.p_type != PT_LOAD)
1895 			continue;
1896 		if (!(sgp1->sg_flags & FLG_SG_VADDR) ||
1897 		    (sgp1->sg_flags & FLG_SG_EMPTY)) {
1898 			if (list_appendc(&seg2, sgp1) == 0)
1899 				return (S_ERROR);
1900 		} else {
1901 			if (seg2.head == NULL) {
1902 				if (list_appendc(&seg2, sgp1) == 0)
1903 					return (S_ERROR);
1904 				continue;
1905 			}
1906 			lnp3 = NULL;
1907 			for (LIST_TRAVERSE(&seg2, lnp2, sgp2)) {
1908 				if (!(sgp2->sg_flags & FLG_SG_VADDR) ||
1909 				    (sgp2->sg_flags & FLG_SG_EMPTY)) {
1910 					if (lnp3 == NULL) {
1911 						if (list_prependc(&seg2,
1912 						    sgp1) == 0)
1913 							return (S_ERROR);
1914 					} else {
1915 						if (list_insertc(&seg2,
1916 						    sgp1, lnp3) == 0)
1917 							return (S_ERROR);
1918 					}
1919 					lnp3 = NULL;
1920 					break;
1921 				}
1922 				if (sgp1->sg_phdr.p_vaddr <
1923 				    sgp2->sg_phdr.p_vaddr) {
1924 					if (lnp3 == NULL) {
1925 						if (list_prependc(&seg2,
1926 						    sgp1) == 0)
1927 							return (S_ERROR);
1928 					} else {
1929 						if (list_insertc(&seg2,
1930 						    sgp1, lnp3) == 0)
1931 							return (S_ERROR);
1932 					}
1933 					lnp3 = NULL;
1934 					break;
1935 				} else if (sgp1->sg_phdr.p_vaddr >
1936 				    sgp2->sg_phdr.p_vaddr) {
1937 					lnp3 = lnp2;
1938 				} else {
1939 					eprintf(ERR_FATAL,
1940 					    MSG_INTL(MSG_MAP_SEGSAME),
1941 					    sgp1->sg_name, sgp2->sg_name);
1942 					return (S_ERROR);
1943 				}
1944 			}
1945 			if (lnp3 != NULL)
1946 				if (list_appendc(&seg2, sgp1) == 0)
1947 					return (S_ERROR);
1948 		}
1949 	}
1950 
1951 	/*
1952 	 * add the sorted loadable segments to our list
1953 	 */
1954 	for (LIST_TRAVERSE(&seg2, lnp1, sgp1)) {
1955 		if (list_appendc(&seg1, sgp1) == 0)
1956 			return (S_ERROR);
1957 	}
1958 
1959 	/*
1960 	 * add all other segments to our list
1961 	 */
1962 	for (LIST_TRAVERSE(&ofl->ofl_segs, lnp1, sgp1)) {
1963 		Word	type = sgp1->sg_phdr.p_type;
1964 
1965 		if ((type != PT_PHDR) && (type != PT_INTERP) &&
1966 		    (type != PT_LOAD))
1967 			if (list_appendc(&seg1, sgp1) == 0)
1968 				return (S_ERROR);
1969 	}
1970 	ofl->ofl_segs.head = ofl->ofl_segs.tail = NULL;
1971 
1972 	/*
1973 	 * Now rebuild the original list and process all of the
1974 	 * segment/section ordering information if present.
1975 	 */
1976 	for (LIST_TRAVERSE(&seg1, lnp1, sgp1)) {
1977 		DBG_CALL(Dbg_map_sort_fini(sgp1));
1978 		if (list_appendc(&ofl->ofl_segs, sgp1) == 0)
1979 			return (S_ERROR);
1980 	}
1981 	return (1);
1982 }
1983 
1984 
1985 
1986 /*
1987  * Parse the mapfile.
1988  */
1989 uintptr_t
1990 map_parse(const char *mapfile, Ofl_desc *ofl)
1991 {
1992 	struct stat	stat_buf;	/* stat of mapfile */
1993 	int		mapfile_fd;	/* descriptor for mapfile */
1994 	Listnode	*lnp1;		/* node pointer */
1995 	Listnode	*lnp2;		/* node pointer */
1996 	Sg_desc		*sgp1;		/* seg descriptor being manipulated */
1997 	Sg_desc		*sgp2;		/* temp segment descriptor pointer */
1998 	Ent_desc	*enp;		/* Segment entrance criteria. */
1999 	Token		tok;		/* current token. */
2000 	Listnode	*e_next = NULL;
2001 					/* next place for entrance criterion */
2002 	Boolean		new_segment;	/* If true, defines new segment. */
2003 	char		*name;
2004 	static	int	num_stack = 0;	/* number of stack segment */
2005 	int		err;
2006 
2007 	DBG_CALL(Dbg_map_parse(mapfile));
2008 
2009 	/*
2010 	 * Determine if we're dealing with a file or a directory.
2011 	 */
2012 	if (stat(mapfile, &stat_buf) == -1) {
2013 		err = errno;
2014 		eprintf(ERR_FATAL, MSG_INTL(MSG_SYS_STAT), mapfile,
2015 		    strerror(err));
2016 		return (S_ERROR);
2017 	}
2018 	if (S_ISDIR(stat_buf.st_mode)) {
2019 		DIR		*dirp;
2020 		struct dirent	*denp;
2021 
2022 		/*
2023 		 * Open the directory and interpret each visible file as a
2024 		 * mapfile.
2025 		 */
2026 		if ((dirp = opendir(mapfile)) == 0)
2027 			return (1);
2028 
2029 		while ((denp = readdir(dirp)) != NULL) {
2030 			char	path[PATH_MAX];
2031 
2032 			/*
2033 			 * Ignore any hidden filenames.  Construct the full
2034 			 * pathname to the new mapfile.
2035 			 */
2036 			if (*denp->d_name == '.')
2037 				continue;
2038 			(void) snprintf(path, PATH_MAX, MSG_ORIG(MSG_STR_PATH),
2039 			    mapfile, denp->d_name);
2040 			if (map_parse(path, ofl) == S_ERROR)
2041 				return (S_ERROR);
2042 		}
2043 		(void) closedir(dirp);
2044 		return (1);
2045 	} else if (!S_ISREG(stat_buf.st_mode)) {
2046 		eprintf(ERR_FATAL, MSG_INTL(MSG_SYS_NOTREG), mapfile);
2047 		return (S_ERROR);
2048 	}
2049 
2050 	/*
2051 	 * We read the entire mapfile into memory.
2052 	 */
2053 	if ((Mapspace = libld_malloc(stat_buf.st_size + 1)) == 0)
2054 		return (S_ERROR);
2055 	if ((mapfile_fd = open(mapfile, O_RDONLY)) == -1) {
2056 		err = errno;
2057 		eprintf(ERR_FATAL, MSG_INTL(MSG_SYS_OPEN), mapfile,
2058 		    strerror(err));
2059 		return (S_ERROR);
2060 	}
2061 
2062 	if (read(mapfile_fd, Mapspace, stat_buf.st_size) != stat_buf.st_size) {
2063 		err = errno;
2064 		eprintf(ERR_FATAL, MSG_INTL(MSG_SYS_READ), mapfile,
2065 		    strerror(err));
2066 		return (S_ERROR);
2067 	}
2068 	Mapspace[stat_buf.st_size] = '\0';
2069 	nextchr = Mapspace;
2070 
2071 	/*
2072 	 * Set up any global variables, the line number counter and file name.
2073 	 */
2074 	Line_num = 1;
2075 
2076 	/*
2077 	 * We now parse the mapfile until the gettoken routine returns EOF.
2078 	 */
2079 	while ((tok = gettoken(mapfile)) != TK_EOF) {
2080 		int	ndx = -1;
2081 
2082 		/*
2083 		 * Don't know which segment yet.
2084 		 */
2085 		sgp1 = NULL;
2086 
2087 		/*
2088 		 * At this point we are at the beginning of a line, and the
2089 		 * variable `Start_tok' points to the first string on the line.
2090 		 * All mapfile entries start with some string token except it
2091 		 * is possible for a scoping definition to start with `{'.
2092 		 */
2093 		if (tok == TK_LEFTBKT) {
2094 			if (map_version(mapfile, (char *)0, ofl) == S_ERROR)
2095 				return (S_ERROR);
2096 			continue;
2097 		}
2098 		if (tok != TK_STRING) {
2099 			/* LINTED */
2100 			if (tok != (Token)S_ERROR)
2101 				eprintf(ERR_FATAL, MSG_INTL(MSG_MAP_EXPSEGNAM),
2102 				    mapfile, EC_XWORD(Line_num));
2103 			return (S_ERROR);
2104 		}
2105 
2106 		/*
2107 		 * Save the initial token.
2108 		 */
2109 		if ((name = libld_malloc(strlen(Start_tok) + 1)) == 0)
2110 			return (S_ERROR);
2111 		(void) strcpy(name, Start_tok);
2112 
2113 		/*
2114 		 * Now check the second character on the line.  The special `-'
2115 		 * and `{' characters do not involve any segment manipulation so
2116 		 * we handle them first.
2117 		 */
2118 		if ((tok = gettoken(mapfile)) == TK_DASH) {
2119 			if (map_dash(mapfile, name, ofl) == S_ERROR)
2120 				return (S_ERROR);
2121 			continue;
2122 		}
2123 		if (tok == TK_LEFTBKT) {
2124 			if (map_version(mapfile, name, ofl) == S_ERROR)
2125 				return (S_ERROR);
2126 			continue;
2127 		}
2128 
2129 		/*
2130 		 * If we're here we need to interpret the first string as a
2131 		 * segment name.  Find the segment named in the token.
2132 		 */
2133 		for (LIST_TRAVERSE(&ofl->ofl_segs, lnp1, sgp2)) {
2134 			ndx++;
2135 			if (strcmp(sgp2->sg_name, name) == 0) {
2136 				sgp1 = sgp2;
2137 				sgp2->sg_flags &= ~FLG_SG_DISABLED;
2138 				new_segment = FALSE;
2139 				break;
2140 			}
2141 		}
2142 
2143 		/*
2144 		 * If the second token is a '|' then we had better
2145 		 * of found a segment.  It is illegal to perform
2146 		 * section within segment ordering before the segment
2147 		 * has been declared.
2148 		 */
2149 		if (tok == TK_PIPE) {
2150 			if (sgp1 == NULL) {
2151 				eprintf(ERR_FATAL, MSG_INTL(MSG_MAP_SECINSEG),
2152 				    mapfile, EC_XWORD(Line_num), name);
2153 				return (S_ERROR);
2154 			} else {
2155 				if (map_pipe(mapfile, sgp1) == S_ERROR)
2156 					return (S_ERROR);
2157 				continue;
2158 			}
2159 		}
2160 
2161 		/*
2162 		 * If segment is still NULL then it does not exist.  Create a
2163 		 * new segment, and leave its values as 0 so that map_equal()
2164 		 * can detect changing attributes.
2165 		 */
2166 		if (sgp1 == NULL) {
2167 			if ((sgp1 = libld_calloc(sizeof (Sg_desc),
2168 			    1)) == 0)
2169 				return (S_ERROR);
2170 			sgp1->sg_phdr.p_type = PT_NULL;
2171 			sgp1->sg_name = name;
2172 			new_segment = TRUE;
2173 			ndx = -1;
2174 		}
2175 
2176 		if ((strcmp(sgp1->sg_name, MSG_ORIG(MSG_STR_INTERP)) == 0) ||
2177 		    (strcmp(sgp1->sg_name, MSG_ORIG(MSG_STR_LD_DYNAMIC)) ==
2178 		    0)) {
2179 			eprintf(ERR_FATAL, MSG_INTL(MSG_MAP_SEGRESV),
2180 			    mapfile, EC_XWORD(Line_num));
2181 			return (S_ERROR);
2182 		}
2183 
2184 		/*
2185 		 * Now check the second token from the input line.
2186 		 */
2187 		if (tok == TK_EQUAL) {
2188 			if (strcmp(sgp1->sg_name,
2189 			    MSG_ORIG(MSG_STR_HWCAP_1)) == 0) {
2190 				if (map_cap(mapfile, CA_SUNW_HW_1,
2191 				    ofl) == S_ERROR)
2192 					return (S_ERROR);
2193 				Dbg_cap_mapfile(CA_SUNW_HW_1, ofl->ofl_hwcap_1,
2194 				    M_MACH);
2195 			} else if (strcmp(sgp1->sg_name,
2196 			    MSG_ORIG(MSG_STR_SFCAP_1)) == 0) {
2197 				if (map_cap(mapfile, CA_SUNW_SF_1,
2198 				    ofl) == S_ERROR)
2199 					return (S_ERROR);
2200 				Dbg_cap_mapfile(CA_SUNW_SF_1, ofl->ofl_sfcap_1,
2201 				    M_MACH);
2202 			} else {
2203 				if (map_equal(mapfile, sgp1, ofl) == S_ERROR)
2204 					return (S_ERROR);
2205 				ofl->ofl_flags |= FLG_OF_SEGSORT;
2206 				DBG_CALL(Dbg_map_equal(new_segment));
2207 			}
2208 		} else if (tok == TK_COLON) {
2209 			/*
2210 			 * If this is an existing segment reservation, sections
2211 			 * can't be assigned to it.
2212 			 */
2213 			if ((new_segment == FALSE) &&
2214 			    (sgp1->sg_flags & FLG_SG_EMPTY)) {
2215 				eprintf(ERR_FATAL, MSG_INTL(MSG_MAP_SEGEMPSEC),
2216 				    mapfile, EC_XWORD(Line_num));
2217 				return (S_ERROR);
2218 			}
2219 
2220 			/*
2221 			 * We are looking at a new entrance criteria line.
2222 			 * Note that entrance criteria are added in the order
2223 			 * they are found in the map file, but are placed
2224 			 * before any default criteria.
2225 			 */
2226 			if ((enp = libld_calloc(sizeof (Ent_desc), 1)) == 0)
2227 				return (S_ERROR);
2228 			enp->ec_segment = sgp1;
2229 			if (e_next == NULL) {
2230 				if ((e_next = list_prependc(&ofl->ofl_ents,
2231 				    enp)) == 0)
2232 					return (S_ERROR);
2233 			} else {
2234 				if ((e_next = list_insertc(&ofl->ofl_ents,
2235 				    enp, e_next)) == 0)
2236 					return (S_ERROR);
2237 			}
2238 
2239 			if (map_colon(mapfile, enp) == S_ERROR)
2240 				return (S_ERROR);
2241 			ofl->ofl_flags |= FLG_OF_SEGSORT;
2242 			DBG_CALL(Dbg_map_ent(new_segment, enp, ofl));
2243 		} else if (tok == TK_ATSIGN) {
2244 			if (map_atsign(mapfile, sgp1, ofl) == S_ERROR)
2245 				return (S_ERROR);
2246 			DBG_CALL(Dbg_map_atsign(new_segment));
2247 		} else {
2248 			/* LINTED */
2249 			if (tok != (Token)S_ERROR) {
2250 				eprintf(ERR_FATAL, MSG_INTL(MSG_MAP_EXPEQU),
2251 				    mapfile, EC_XWORD(Line_num));
2252 				return (S_ERROR);
2253 			}
2254 		}
2255 
2256 		/*
2257 		 * Having completed parsing an entry in the map file determine
2258 		 * if the segment to which it applies is new.
2259 		 */
2260 		if (new_segment) {
2261 			int	src_type, dst_type;
2262 
2263 			/*
2264 			 * If specific fields have not been supplied via
2265 			 * map_equal(), make sure defaults are supplied.
2266 			 */
2267 			if (sgp1->sg_phdr.p_type == PT_NULL) {
2268 				sgp1->sg_phdr.p_type = PT_LOAD;
2269 				sgp1->sg_flags |= FLG_SG_TYPE;
2270 			}
2271 			if ((sgp1->sg_phdr.p_type == PT_LOAD) &&
2272 				(!(sgp1->sg_flags & FLG_SG_FLAGS))) {
2273 				sgp1->sg_phdr.p_flags = PF_R + PF_W + PF_X;
2274 				sgp1->sg_flags |= FLG_SG_FLAGS;
2275 			}
2276 
2277 			/*
2278 			 * Determine where the new segment should be inserted
2279 			 * in the seg_desc[] list.  Presently the user can
2280 			 * only add a LOAD or NOTE segment.  Note that these
2281 			 * segments must be added after any PT_PHDR and
2282 			 * PT_INTERP (refer Generic ABI, Page 5-4).
2283 			 */
2284 			switch (sgp1->sg_phdr.p_type) {
2285 			case PT_LOAD:
2286 				if (sgp1->sg_flags & FLG_SG_EMPTY)
2287 					src_type = 4;
2288 				else
2289 					src_type = 3;
2290 				break;
2291 			case PT_SUNWSTACK:
2292 				src_type = 8;
2293 				if (++num_stack >= 2) {
2294 					/*
2295 					 * Currently the number of sunw_stack
2296 					 * segment is limited to 1.
2297 					 */
2298 					eprintf(ERR_WARNING,
2299 					    MSG_INTL(MSG_MAP_NOSTACK2),
2300 					    mapfile, EC_XWORD(Line_num));
2301 					continue;
2302 				}
2303 				break;
2304 			case PT_NOTE:
2305 				src_type = 9;
2306 				break;
2307 			default:
2308 				eprintf(ERR_FATAL, MSG_INTL(MSG_MAP_UNKSEGTYP),
2309 				    mapfile, EC_XWORD(Line_num),
2310 				    EC_WORD(sgp1->sg_phdr.p_type));
2311 				return (S_ERROR);
2312 			}
2313 			lnp2 = NULL;
2314 			for (LIST_TRAVERSE(&ofl->ofl_segs, lnp1, sgp2)) {
2315 				ndx++;
2316 				switch (sgp2->sg_phdr.p_type) {
2317 				case PT_PHDR:
2318 					dst_type = 0;
2319 					break;
2320 				case PT_INTERP:
2321 					dst_type = 1;
2322 					break;
2323 				case PT_SUNWCAP:
2324 					dst_type = 2;
2325 					break;
2326 				case PT_LOAD:
2327 					dst_type = 3;
2328 					break;
2329 				case PT_DYNAMIC:
2330 					dst_type = 5;
2331 					break;
2332 				case PT_SUNWDTRACE:
2333 					dst_type = 6;
2334 					break;
2335 				case PT_SHLIB:
2336 					dst_type = 7;
2337 					break;
2338 				case PT_SUNWSTACK:
2339 					dst_type = 8;
2340 					break;
2341 				case PT_NOTE:
2342 					dst_type = 9;
2343 					break;
2344 				case PT_SUNWBSS:
2345 					dst_type = 10;
2346 					break;
2347 				case PT_TLS:
2348 					dst_type = 11;
2349 					break;
2350 				case PT_NULL:
2351 					dst_type = 12;
2352 					break;
2353 				default:
2354 					eprintf(ERR_FATAL,
2355 					    MSG_INTL(MSG_MAP_UNKSEGTYP),
2356 					    mapfile, EC_XWORD(Line_num),
2357 					    EC_WORD(sgp2->sg_phdr.p_type));
2358 					return (S_ERROR);
2359 				}
2360 				if (src_type <= dst_type) {
2361 					if (lnp2 == NULL) {
2362 						if (list_prependc(
2363 						    &ofl->ofl_segs, sgp1) == 0)
2364 							return (S_ERROR);
2365 					} else {
2366 						if (list_insertc(&ofl->ofl_segs,
2367 						    sgp1, lnp2) == 0)
2368 							return (S_ERROR);
2369 					}
2370 					break;
2371 				}
2372 				lnp2 = lnp1;
2373 			}
2374 		}
2375 		DBG_CALL(Dbg_map_seg(ofl->ofl_e_machine, ndx, sgp1));
2376 	}
2377 
2378 	/*
2379 	 * If the output file is a static file without an interpreter
2380 	 * and if any virtual address is specified, then assume $n flag
2381 	 * for backward compatiblity.
2382 	 */
2383 	if (!(ofl->ofl_flags & FLG_OF_DYNAMIC) &&
2384 	    !(ofl->ofl_flags & FLG_OF_RELOBJ) &&
2385 	    !(ofl->ofl_osinterp) &&
2386 	    (ofl->ofl_flags1 & FLG_OF1_VADDR))
2387 		ofl->ofl_flags1 |= FLG_OF1_NOHDR;
2388 
2389 	/*
2390 	 * If the output file is a relocatable file,
2391 	 * then ?N have no effect. Knock it off.
2392 	 */
2393 	if (ofl->ofl_flags & FLG_OF_RELOBJ)
2394 		ofl->ofl_flags1 &= ~FLG_OF1_NOHDR;
2395 
2396 	return (1);
2397 }
2398