xref: /netbsd-src/external/gpl3/binutils/dist/ld/deffilep.y (revision 48fb7bfab72acd4281a53bbee5ccf3f809019e75)
1 %{ /* deffilep.y - parser for .def files */
2 
3 /*   Copyright 1995, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2005, 2006,
4      2007, 2009 Free Software Foundation, Inc.
5 
6      This file is part of GNU Binutils.
7 
8      This program is free software; you can redistribute it and/or modify
9      it under the terms of the GNU General Public License as published by
10      the Free Software Foundation; either version 3 of the License, or
11      (at your option) any later version.
12 
13      This program is distributed in the hope that it will be useful,
14      but WITHOUT ANY WARRANTY; without even the implied warranty of
15      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16      GNU General Public License for more details.
17 
18      You should have received a copy of the GNU General Public License
19      along with this program; if not, write to the Free Software
20      Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
21      MA 02110-1301, USA.  */
22 
23 #include "sysdep.h"
24 #include "libiberty.h"
25 #include "safe-ctype.h"
26 #include "bfd.h"
27 #include "ld.h"
28 #include "ldmisc.h"
29 #include "deffile.h"
30 
31 #define TRACE 0
32 
33 #define ROUND_UP(a, b) (((a)+((b)-1))&~((b)-1))
34 
35 /* Remap normal yacc parser interface names (yyparse, yylex, yyerror, etc),
36    as well as gratuitiously global symbol names, so we can have multiple
37    yacc generated parsers in ld.  Note that these are only the variables
38    produced by yacc.  If other parser generators (bison, byacc, etc) produce
39    additional global names that conflict at link time, then those parser
40    generators need to be fixed instead of adding those names to this list.  */
41 
42 #define	yymaxdepth def_maxdepth
43 #define	yyparse	def_parse
44 #define	yylex	def_lex
45 #define	yyerror	def_error
46 #define	yylval	def_lval
47 #define	yychar	def_char
48 #define	yydebug	def_debug
49 #define	yypact	def_pact
50 #define	yyr1	def_r1
51 #define	yyr2	def_r2
52 #define	yydef	def_def
53 #define	yychk	def_chk
54 #define	yypgo	def_pgo
55 #define	yyact	def_act
56 #define	yyexca	def_exca
57 #define yyerrflag def_errflag
58 #define yynerrs	def_nerrs
59 #define	yyps	def_ps
60 #define	yypv	def_pv
61 #define	yys	def_s
62 #define	yy_yys	def_yys
63 #define	yystate	def_state
64 #define	yytmp	def_tmp
65 #define	yyv	def_v
66 #define	yy_yyv	def_yyv
67 #define	yyval	def_val
68 #define	yylloc	def_lloc
69 #define yyreds	def_reds		/* With YYDEBUG defined.  */
70 #define yytoks	def_toks		/* With YYDEBUG defined.  */
71 #define yylhs	def_yylhs
72 #define yylen	def_yylen
73 #define yydefred def_yydefred
74 #define yydgoto	def_yydgoto
75 #define yysindex def_yysindex
76 #define yyrindex def_yyrindex
77 #define yygindex def_yygindex
78 #define yytable	 def_yytable
79 #define yycheck	 def_yycheck
80 
81 typedef struct def_pool_str {
82   struct def_pool_str *next;
83   char data[1];
84 } def_pool_str;
85 
86 static def_pool_str *pool_strs = NULL;
87 
88 static char *def_pool_alloc (size_t sz);
89 static char *def_pool_strdup (const char *str);
90 static void def_pool_free (void);
91 
92 static void def_description (const char *);
93 static void def_exports (const char *, const char *, int, int, const char *);
94 static void def_heapsize (int, int);
95 static void def_import (const char *, const char *, const char *, const char *,
96 			int, const char *);
97 static void def_image_name (const char *, int, int);
98 static void def_section (const char *, int);
99 static void def_section_alt (const char *, const char *);
100 static void def_stacksize (int, int);
101 static void def_version (int, int);
102 static void def_directive (char *);
103 static void def_aligncomm (char *str, int align);
104 static int def_parse (void);
105 static int def_error (const char *);
106 static int def_lex (void);
107 
108 static int lex_forced_token = 0;
109 static const char *lex_parse_string = 0;
110 static const char *lex_parse_string_end = 0;
111 
112 %}
113 
114 %union {
115   char *id;
116   const char *id_const;
117   int number;
118   char *digits;
119 };
120 
121 %token NAME LIBRARY DESCRIPTION STACKSIZE_K HEAPSIZE CODE DATAU DATAL
122 %token SECTIONS EXPORTS IMPORTS VERSIONK BASE CONSTANTU CONSTANTL
123 %token PRIVATEU PRIVATEL ALIGNCOMM
124 %token READ WRITE EXECUTE SHARED NONAMEU NONAMEL DIRECTIVE EQUAL
125 %token <id> ID
126 %token <digits> DIGITS
127 %type  <number> NUMBER
128 %type  <digits> opt_digits
129 %type  <number> opt_base opt_ordinal
130 %type  <number> attr attr_list opt_number exp_opt_list exp_opt
131 %type  <id> opt_name opt_name2 opt_equal_name anylang_id opt_id
132 %type  <id> opt_equalequal_name
133 %type  <id_const> keyword_as_name
134 
135 %%
136 
137 start: start command
138 	| command
139 	;
140 
141 command:
142 		NAME opt_name opt_base { def_image_name ($2, $3, 0); }
143 	|	LIBRARY opt_name opt_base { def_image_name ($2, $3, 1); }
144 	|	DESCRIPTION ID { def_description ($2);}
145 	|	STACKSIZE_K NUMBER opt_number { def_stacksize ($2, $3);}
146 	|	HEAPSIZE NUMBER opt_number { def_heapsize ($2, $3);}
147 	|	CODE attr_list { def_section ("CODE", $2);}
148 	|	DATAU attr_list  { def_section ("DATA", $2);}
149 	|	SECTIONS seclist
150 	|	EXPORTS explist
151 	|	IMPORTS implist
152 	|	VERSIONK NUMBER { def_version ($2, 0);}
153 	|	VERSIONK NUMBER '.' NUMBER { def_version ($2, $4);}
154 	|	DIRECTIVE ID { def_directive ($2);}
155 	|	ALIGNCOMM anylang_id ',' NUMBER { def_aligncomm ($2, $4);}
156 	;
157 
158 
159 explist:
160 		/* EMPTY */
161 	|	expline
162 	|	explist expline
163 	;
164 
165 expline:
166 		/* The opt_comma is necessary to support both the usual
167 		  DEF file syntax as well as .drectve syntax which
168 		  mandates <expsym>,<expoptlist>.  */
169 		opt_name2 opt_equal_name opt_ordinal opt_comma exp_opt_list opt_comma opt_equalequal_name
170 			{ def_exports ($1, $2, $3, $5, $7); }
171 	;
172 exp_opt_list:
173 		/* The opt_comma is necessary to support both the usual
174 		   DEF file syntax as well as .drectve syntax which
175 		   allows for comma separated opt list.  */
176 		exp_opt opt_comma exp_opt_list { $$ = $1 | $3; }
177 	|	{ $$ = 0; }
178 	;
179 exp_opt:
180 		NONAMEU		{ $$ = 1; }
181 	|	NONAMEL		{ $$ = 1; }
182 	|	CONSTANTU	{ $$ = 2; }
183 	|	CONSTANTL	{ $$ = 2; }
184 	|	DATAU		{ $$ = 4; }
185 	|	DATAL		{ $$ = 4; }
186 	|	PRIVATEU	{ $$ = 8; }
187 	|	PRIVATEL	{ $$ = 8; }
188 	;
189 implist:
190 		implist impline
191 	|	impline
192 	;
193 
194 impline:
195                ID '=' ID '.' ID '.' ID opt_equalequal_name
196                  { def_import ($1, $3, $5, $7, -1, $8); }
197        |       ID '=' ID '.' ID '.' NUMBER opt_equalequal_name
198 				 { def_import ($1, $3, $5,  0, $7, $8); }
199        |       ID '=' ID '.' ID opt_equalequal_name
200                  { def_import ($1, $3,  0, $5, -1, $6); }
201        |       ID '=' ID '.' NUMBER opt_equalequal_name
202                  { def_import ($1, $3,  0,  0, $5, $6); }
203        |       ID '.' ID '.' ID opt_equalequal_name
204                  { def_import( 0, $1, $3, $5, -1, $6); }
205        |       ID '.' ID opt_equalequal_name
206                  { def_import ( 0, $1,  0, $3, -1, $4); }
207 ;
208 
209 seclist:
210 		seclist secline
211 	|	secline
212 	;
213 
214 secline:
215 	ID attr_list { def_section ($1, $2);}
216 	| ID ID { def_section_alt ($1, $2);}
217 	;
218 
219 attr_list:
220 	attr_list opt_comma attr { $$ = $1 | $3; }
221 	| attr { $$ = $1; }
222 	;
223 
224 opt_comma:
225 	','
226 	|
227 	;
228 opt_number: ',' NUMBER { $$=$2;}
229 	|	   { $$=-1;}
230 	;
231 
232 attr:
233 		READ	{ $$ = 1;}
234 	|	WRITE	{ $$ = 2;}
235 	|	EXECUTE	{ $$=4;}
236 	|	SHARED	{ $$=8;}
237 	;
238 
239 
240 keyword_as_name: BASE { $$ = "BASE"; }
241 	 | CODE { $$ = "CODE"; }
242 	 | CONSTANTU { $$ = "CONSTANT"; }
243 	 | CONSTANTL { $$ = "constant"; }
244 	 | DATAU { $$ = "DATA"; }
245 	 | DATAL { $$ = "data"; }
246 	 | DESCRIPTION { $$ = "DESCRIPTION"; }
247 	 | DIRECTIVE { $$ = "DIRECTIVE"; }
248 	 | EXECUTE { $$ = "EXECUTE"; }
249 	 | EXPORTS { $$ = "EXPORTS"; }
250 	 | HEAPSIZE { $$ = "HEAPSIZE"; }
251 	 | IMPORTS { $$ = "IMPORTS"; }
252 /* Disable LIBRARY keyword as valid symbol-name.  This is necessary
253    for libtool, which places this command after EXPORTS command.
254    This behavior is illegal by specification, but sadly required by
255    by compatibility reasons.
256    See PR binutils/13710
257 	 | LIBRARY { $$ = "LIBRARY"; } */
258 	 | NAME { $$ = "NAME"; }
259 	 | NONAMEU { $$ = "NONAME"; }
260 	 | NONAMEL { $$ = "noname"; }
261 	 | PRIVATEU { $$ = "PRIVATE"; }
262 	 | PRIVATEL { $$ = "private"; }
263 	 | READ { $$ = "READ"; }
264 	 | SHARED  { $$ = "SHARED"; }
265 	 | STACKSIZE_K { $$ = "STACKSIZE"; }
266 	 | VERSIONK { $$ = "VERSION"; }
267 	 | WRITE { $$ = "WRITE"; }
268 	 ;
269 
270 opt_name2: ID { $$ = $1; }
271 	| '.' keyword_as_name
272 	  {
273 	    char *name = xmalloc (strlen ($2) + 2);
274 	    sprintf (name, ".%s", $2);
275 	    $$ = name;
276 	  }
277 	| '.' opt_name2
278 	  {
279 	    char *name = def_pool_alloc (strlen ($2) + 2);
280 	    sprintf (name, ".%s", $2);
281 	    $$ = name;
282 	  }
283 	| keyword_as_name '.' opt_name2
284 	  {
285 	    char *name = def_pool_alloc (strlen ($1) + 1 + strlen ($3) + 1);
286 	    sprintf (name, "%s.%s", $1, $3);
287 	    $$ = name;
288 	  }
289 	| ID '.' opt_name2
290 	  {
291 	    char *name = def_pool_alloc (strlen ($1) + 1 + strlen ($3) + 1);
292 	    sprintf (name, "%s.%s", $1, $3);
293 	    $$ = name;
294 	  }
295 	;
296 
297 opt_name: opt_name2 { $$ = $1; }
298 	|		{ $$ = ""; }
299 	;
300 
301 opt_equalequal_name: EQUAL ID	{ $$ = $2; }
302 	|							{ $$ = 0; }
303 	;
304 
305 opt_ordinal:
306 	  '@' NUMBER     { $$ = $2;}
307 	|                { $$ = -1;}
308 	;
309 
310 opt_equal_name:
311           '=' opt_name2	{ $$ = $2; }
312         | 		{ $$ =  0; }
313 	;
314 
315 opt_base: BASE	'=' NUMBER	{ $$ = $3;}
316 	|	{ $$ = -1;}
317 	;
318 
319 anylang_id: ID		{ $$ = $1; }
320 	| '.' ID
321 	  {
322 	    char *id = def_pool_alloc (strlen ($2) + 2);
323 	    sprintf (id, ".%s", $2);
324 	    $$ = id;
325 	  }
326 	| anylang_id '.' opt_digits opt_id
327 	  {
328 	    char *id = def_pool_alloc (strlen ($1) + 1 + strlen ($3) + strlen ($4) + 1);
329 	    sprintf (id, "%s.%s%s", $1, $3, $4);
330 	    $$ = id;
331 	  }
332 	;
333 
334 opt_digits: DIGITS	{ $$ = $1; }
335 	|		{ $$ = ""; }
336 	;
337 
338 opt_id: ID		{ $$ = $1; }
339 	|		{ $$ = ""; }
340 	;
341 
342 NUMBER: DIGITS		{ $$ = strtoul ($1, 0, 0); }
343 
344 %%
345 
346 /*****************************************************************************
347  API
348  *****************************************************************************/
349 
350 static FILE *the_file;
351 static const char *def_filename;
352 static int linenumber;
353 static def_file *def;
354 static int saw_newline;
355 
356 struct directive
357   {
358     struct directive *next;
359     char *name;
360     int len;
361   };
362 
363 static struct directive *directives = 0;
364 
365 def_file *
366 def_file_empty (void)
367 {
368   def_file *rv = xmalloc (sizeof (def_file));
369   memset (rv, 0, sizeof (def_file));
370   rv->is_dll = -1;
371   rv->base_address = (bfd_vma) -1;
372   rv->stack_reserve = rv->stack_commit = -1;
373   rv->heap_reserve = rv->heap_commit = -1;
374   rv->version_major = rv->version_minor = -1;
375   return rv;
376 }
377 
378 def_file *
379 def_file_parse (const char *filename, def_file *add_to)
380 {
381   struct directive *d;
382 
383   the_file = fopen (filename, "r");
384   def_filename = filename;
385   linenumber = 1;
386   if (!the_file)
387     {
388       perror (filename);
389       return 0;
390     }
391   if (add_to)
392     {
393       def = add_to;
394     }
395   else
396     {
397       def = def_file_empty ();
398     }
399 
400   saw_newline = 1;
401   if (def_parse ())
402     {
403       def_file_free (def);
404       fclose (the_file);
405       def_pool_free ();
406       return 0;
407     }
408 
409   fclose (the_file);
410 
411   while ((d = directives) != NULL)
412     {
413 #if TRACE
414       printf ("Adding directive %08x `%s'\n", d->name, d->name);
415 #endif
416       def_file_add_directive (def, d->name, d->len);
417       directives = d->next;
418       free (d->name);
419       free (d);
420     }
421   def_pool_free ();
422 
423   return def;
424 }
425 
426 void
427 def_file_free (def_file *fdef)
428 {
429   int i;
430 
431   if (!fdef)
432     return;
433   if (fdef->name)
434     free (fdef->name);
435   if (fdef->description)
436     free (fdef->description);
437 
438   if (fdef->section_defs)
439     {
440       for (i = 0; i < fdef->num_section_defs; i++)
441 	{
442 	  if (fdef->section_defs[i].name)
443 	    free (fdef->section_defs[i].name);
444 	  if (fdef->section_defs[i].class)
445 	    free (fdef->section_defs[i].class);
446 	}
447       free (fdef->section_defs);
448     }
449 
450   if (fdef->exports)
451     {
452       for (i = 0; i < fdef->num_exports; i++)
453 	{
454 	  if (fdef->exports[i].internal_name
455 	      && fdef->exports[i].internal_name != fdef->exports[i].name)
456 	    free (fdef->exports[i].internal_name);
457 	  if (fdef->exports[i].name)
458 	    free (fdef->exports[i].name);
459 	  if (fdef->exports[i].its_name)
460 	    free (fdef->exports[i].its_name);
461 	}
462       free (fdef->exports);
463     }
464 
465   if (fdef->imports)
466     {
467       for (i = 0; i < fdef->num_imports; i++)
468 	{
469 	  if (fdef->imports[i].internal_name
470 	      && fdef->imports[i].internal_name != fdef->imports[i].name)
471 	    free (fdef->imports[i].internal_name);
472 	  if (fdef->imports[i].name)
473 	    free (fdef->imports[i].name);
474 	  if (fdef->imports[i].its_name)
475 	    free (fdef->imports[i].its_name);
476 	}
477       free (fdef->imports);
478     }
479 
480   while (fdef->modules)
481     {
482       def_file_module *m = fdef->modules;
483 
484       fdef->modules = fdef->modules->next;
485       free (m);
486     }
487 
488   while (fdef->aligncomms)
489     {
490       def_file_aligncomm *c = fdef->aligncomms;
491 
492       fdef->aligncomms = fdef->aligncomms->next;
493       free (c->symbol_name);
494       free (c);
495     }
496 
497   free (fdef);
498 }
499 
500 #ifdef DEF_FILE_PRINT
501 void
502 def_file_print (FILE *file, def_file *fdef)
503 {
504   int i;
505 
506   fprintf (file, ">>>> def_file at 0x%08x\n", fdef);
507   if (fdef->name)
508     fprintf (file, "  name: %s\n", fdef->name ? fdef->name : "(unspecified)");
509   if (fdef->is_dll != -1)
510     fprintf (file, "  is dll: %s\n", fdef->is_dll ? "yes" : "no");
511   if (fdef->base_address != (bfd_vma) -1)
512     fprintf (file, "  base address: 0x%08x\n", fdef->base_address);
513   if (fdef->description)
514     fprintf (file, "  description: `%s'\n", fdef->description);
515   if (fdef->stack_reserve != -1)
516     fprintf (file, "  stack reserve: 0x%08x\n", fdef->stack_reserve);
517   if (fdef->stack_commit != -1)
518     fprintf (file, "  stack commit: 0x%08x\n", fdef->stack_commit);
519   if (fdef->heap_reserve != -1)
520     fprintf (file, "  heap reserve: 0x%08x\n", fdef->heap_reserve);
521   if (fdef->heap_commit != -1)
522     fprintf (file, "  heap commit: 0x%08x\n", fdef->heap_commit);
523 
524   if (fdef->num_section_defs > 0)
525     {
526       fprintf (file, "  section defs:\n");
527 
528       for (i = 0; i < fdef->num_section_defs; i++)
529 	{
530 	  fprintf (file, "    name: `%s', class: `%s', flags:",
531 		   fdef->section_defs[i].name, fdef->section_defs[i].class);
532 	  if (fdef->section_defs[i].flag_read)
533 	    fprintf (file, " R");
534 	  if (fdef->section_defs[i].flag_write)
535 	    fprintf (file, " W");
536 	  if (fdef->section_defs[i].flag_execute)
537 	    fprintf (file, " X");
538 	  if (fdef->section_defs[i].flag_shared)
539 	    fprintf (file, " S");
540 	  fprintf (file, "\n");
541 	}
542     }
543 
544   if (fdef->num_exports > 0)
545     {
546       fprintf (file, "  exports:\n");
547 
548       for (i = 0; i < fdef->num_exports; i++)
549 	{
550 	  fprintf (file, "    name: `%s', int: `%s', ordinal: %d, flags:",
551 		   fdef->exports[i].name, fdef->exports[i].internal_name,
552 		   fdef->exports[i].ordinal);
553 	  if (fdef->exports[i].flag_private)
554 	    fprintf (file, " P");
555 	  if (fdef->exports[i].flag_constant)
556 	    fprintf (file, " C");
557 	  if (fdef->exports[i].flag_noname)
558 	    fprintf (file, " N");
559 	  if (fdef->exports[i].flag_data)
560 	    fprintf (file, " D");
561 	  fprintf (file, "\n");
562 	}
563     }
564 
565   if (fdef->num_imports > 0)
566     {
567       fprintf (file, "  imports:\n");
568 
569       for (i = 0; i < fdef->num_imports; i++)
570 	{
571 	  fprintf (file, "    int: %s, from: `%s', name: `%s', ordinal: %d\n",
572 		   fdef->imports[i].internal_name,
573 		   fdef->imports[i].module,
574 		   fdef->imports[i].name,
575 		   fdef->imports[i].ordinal);
576 	}
577     }
578 
579   if (fdef->version_major != -1)
580     fprintf (file, "  version: %d.%d\n", fdef->version_major, fdef->version_minor);
581 
582   fprintf (file, "<<<< def_file at 0x%08x\n", fdef);
583 }
584 #endif
585 
586 /* Helper routine to check for identity of string pointers,
587    which might be NULL.  */
588 
589 static int
590 are_names_equal (const char *s1, const char *s2)
591 {
592   if (!s1 && !s2)
593     return 0;
594   if (!s1 || !s2)
595     return (!s1 ? -1 : 1);
596   return strcmp (s1, s2);
597 }
598 
599 static int
600 cmp_export_elem (const def_file_export *e, const char *ex_name,
601 		 const char *in_name, const char *its_name,
602 		 int ord)
603 {
604   int r;
605 
606   if ((r = are_names_equal (ex_name, e->name)) != 0)
607     return r;
608   if ((r = are_names_equal (in_name, e->internal_name)) != 0)
609     return r;
610   if ((r = are_names_equal (its_name, e->its_name)) != 0)
611     return r;
612   return (ord - e->ordinal);
613 }
614 
615 /* Search the position of the identical element, or returns the position
616    of the next higher element. If last valid element is smaller, then MAX
617    is returned.  */
618 
619 static int
620 find_export_in_list (def_file_export *b, int max,
621 		     const char *ex_name, const char *in_name,
622 		     const char *its_name, int ord, int *is_ident)
623 {
624   int e, l, r, p;
625 
626   *is_ident = 0;
627   if (!max)
628     return 0;
629   if ((e = cmp_export_elem (b, ex_name, in_name, its_name, ord)) <= 0)
630     {
631       if (!e)
632         *is_ident = 1;
633       return 0;
634     }
635   if (max == 1)
636     return 1;
637   if ((e = cmp_export_elem (b + (max - 1), ex_name, in_name, its_name, ord)) > 0)
638     return max;
639   else if (!e || max == 2)
640     {
641       if (!e)
642 	*is_ident = 1;
643       return max - 1;
644     }
645   l = 0; r = max - 1;
646   while (l < r)
647     {
648       p = (l + r) / 2;
649       e = cmp_export_elem (b + p, ex_name, in_name, its_name, ord);
650       if (!e)
651         {
652           *is_ident = 1;
653           return p;
654         }
655       else if (e < 0)
656         r = p - 1;
657       else if (e > 0)
658         l = p + 1;
659     }
660   if ((e = cmp_export_elem (b + l, ex_name, in_name, its_name, ord)) > 0)
661     ++l;
662   else if (!e)
663     *is_ident = 1;
664   return l;
665 }
666 
667 def_file_export *
668 def_file_add_export (def_file *fdef,
669 		     const char *external_name,
670 		     const char *internal_name,
671 		     int ordinal,
672 		     const char *its_name,
673 		     int *is_dup)
674 {
675   def_file_export *e;
676   int pos;
677   int max_exports = ROUND_UP(fdef->num_exports, 32);
678 
679   if (internal_name && !external_name)
680     external_name = internal_name;
681   if (external_name && !internal_name)
682     internal_name = external_name;
683 
684   /* We need to avoid duplicates.  */
685   *is_dup = 0;
686   pos = find_export_in_list (fdef->exports, fdef->num_exports,
687 		     external_name, internal_name,
688 		     its_name, ordinal, is_dup);
689 
690   if (*is_dup != 0)
691     return (fdef->exports + pos);
692 
693   if (fdef->num_exports >= max_exports)
694     {
695       max_exports = ROUND_UP(fdef->num_exports + 1, 32);
696       if (fdef->exports)
697 	fdef->exports = xrealloc (fdef->exports,
698 				 max_exports * sizeof (def_file_export));
699       else
700 	fdef->exports = xmalloc (max_exports * sizeof (def_file_export));
701     }
702 
703   e = fdef->exports + pos;
704   if (pos != fdef->num_exports)
705     memmove (&e[1], e, (sizeof (def_file_export) * (fdef->num_exports - pos)));
706   memset (e, 0, sizeof (def_file_export));
707   e->name = xstrdup (external_name);
708   e->internal_name = xstrdup (internal_name);
709   e->its_name = (its_name ? xstrdup (its_name) : NULL);
710   e->ordinal = ordinal;
711   fdef->num_exports++;
712   return e;
713 }
714 
715 def_file_module *
716 def_get_module (def_file *fdef, const char *name)
717 {
718   def_file_module *s;
719 
720   for (s = fdef->modules; s; s = s->next)
721     if (strcmp (s->name, name) == 0)
722       return s;
723 
724   return NULL;
725 }
726 
727 static def_file_module *
728 def_stash_module (def_file *fdef, const char *name)
729 {
730   def_file_module *s;
731 
732   if ((s = def_get_module (fdef, name)) != NULL)
733       return s;
734   s = xmalloc (sizeof (def_file_module) + strlen (name));
735   s->next = fdef->modules;
736   fdef->modules = s;
737   s->user_data = 0;
738   strcpy (s->name, name);
739   return s;
740 }
741 
742 static int
743 cmp_import_elem (const def_file_import *e, const char *ex_name,
744 		 const char *in_name, const char *module,
745 		 int ord)
746 {
747   int r;
748 
749   if ((r = are_names_equal (module, (e->module ? e->module->name : NULL))))
750     return r;
751   if ((r = are_names_equal (ex_name, e->name)) != 0)
752     return r;
753   if ((r = are_names_equal (in_name, e->internal_name)) != 0)
754     return r;
755   if (ord != e->ordinal)
756     return (ord < e->ordinal ? -1 : 1);
757   return 0;
758 }
759 
760 /* Search the position of the identical element, or returns the position
761    of the next higher element. If last valid element is smaller, then MAX
762    is returned.  */
763 
764 static int
765 find_import_in_list (def_file_import *b, int max,
766 		     const char *ex_name, const char *in_name,
767 		     const char *module, int ord, int *is_ident)
768 {
769   int e, l, r, p;
770 
771   *is_ident = 0;
772   if (!max)
773     return 0;
774   if ((e = cmp_import_elem (b, ex_name, in_name, module, ord)) <= 0)
775     {
776       if (!e)
777         *is_ident = 1;
778       return 0;
779     }
780   if (max == 1)
781     return 1;
782   if ((e = cmp_import_elem (b + (max - 1), ex_name, in_name, module, ord)) > 0)
783     return max;
784   else if (!e || max == 2)
785     {
786       if (!e)
787         *is_ident = 1;
788       return max - 1;
789     }
790   l = 0; r = max - 1;
791   while (l < r)
792     {
793       p = (l + r) / 2;
794       e = cmp_import_elem (b + p, ex_name, in_name, module, ord);
795       if (!e)
796         {
797           *is_ident = 1;
798           return p;
799         }
800       else if (e < 0)
801         r = p - 1;
802       else if (e > 0)
803         l = p + 1;
804     }
805   if ((e = cmp_import_elem (b + l, ex_name, in_name, module, ord)) > 0)
806     ++l;
807   else if (!e)
808     *is_ident = 1;
809   return l;
810 }
811 
812 def_file_import *
813 def_file_add_import (def_file *fdef,
814 		     const char *name,
815 		     const char *module,
816 		     int ordinal,
817 		     const char *internal_name,
818 		     const char *its_name,
819 		     int *is_dup)
820 {
821   def_file_import *i;
822   int pos;
823   int max_imports = ROUND_UP (fdef->num_imports, 16);
824 
825   /* We need to avoid here duplicates.  */
826   *is_dup = 0;
827   pos = find_import_in_list (fdef->imports, fdef->num_imports,
828 			     name,
829 			     (!internal_name ? name : internal_name),
830 			     module, ordinal, is_dup);
831   if (*is_dup != 0)
832     return fdef->imports + pos;
833 
834   if (fdef->num_imports >= max_imports)
835     {
836       max_imports = ROUND_UP (fdef->num_imports+1, 16);
837 
838       if (fdef->imports)
839 	fdef->imports = xrealloc (fdef->imports,
840 				 max_imports * sizeof (def_file_import));
841       else
842 	fdef->imports = xmalloc (max_imports * sizeof (def_file_import));
843     }
844   i = fdef->imports + pos;
845   if (pos != fdef->num_imports)
846     memmove (&i[1], i, (sizeof (def_file_import) * (fdef->num_imports - pos)));
847   memset (i, 0, sizeof (def_file_import));
848   if (name)
849     i->name = xstrdup (name);
850   if (module)
851     i->module = def_stash_module (fdef, module);
852   i->ordinal = ordinal;
853   if (internal_name)
854     i->internal_name = xstrdup (internal_name);
855   else
856     i->internal_name = i->name;
857   i->its_name = (its_name ? xstrdup (its_name) : NULL);
858   fdef->num_imports++;
859 
860   return i;
861 }
862 
863 struct
864 {
865   char *param;
866   int token;
867 }
868 diropts[] =
869 {
870   { "-heap", HEAPSIZE },
871   { "-stack", STACKSIZE_K },
872   { "-attr", SECTIONS },
873   { "-export", EXPORTS },
874   { "-aligncomm", ALIGNCOMM },
875   { 0, 0 }
876 };
877 
878 void
879 def_file_add_directive (def_file *my_def, const char *param, int len)
880 {
881   def_file *save_def = def;
882   const char *pend = param + len;
883   char * tend = (char *) param;
884   int i;
885 
886   def = my_def;
887 
888   while (param < pend)
889     {
890       while (param < pend
891 	     && (ISSPACE (*param) || *param == '\n' || *param == 0))
892 	param++;
893 
894       if (param == pend)
895 	break;
896 
897       /* Scan forward until we encounter any of:
898           - the end of the buffer
899 	  - the start of a new option
900 	  - a newline seperating options
901           - a NUL seperating options.  */
902       for (tend = (char *) (param + 1);
903 	   (tend < pend
904 	    && !(ISSPACE (tend[-1]) && *tend == '-')
905 	    && *tend != '\n' && *tend != 0);
906 	   tend++)
907 	;
908 
909       for (i = 0; diropts[i].param; i++)
910 	{
911 	  len = strlen (diropts[i].param);
912 
913 	  if (tend - param >= len
914 	      && strncmp (param, diropts[i].param, len) == 0
915 	      && (param[len] == ':' || param[len] == ' '))
916 	    {
917 	      lex_parse_string_end = tend;
918 	      lex_parse_string = param + len + 1;
919 	      lex_forced_token = diropts[i].token;
920 	      saw_newline = 0;
921 	      if (def_parse ())
922 		continue;
923 	      break;
924 	    }
925 	}
926 
927       if (!diropts[i].param)
928 	{
929 	  char saved;
930 
931 	  saved = * tend;
932 	  * tend = 0;
933 	  /* xgettext:c-format */
934 	  einfo (_("Warning: .drectve `%s' unrecognized\n"), param);
935 	  * tend = saved;
936 	}
937 
938       lex_parse_string = 0;
939       param = tend;
940     }
941 
942   def = save_def;
943   def_pool_free ();
944 }
945 
946 /* Parser Callbacks.  */
947 
948 static void
949 def_image_name (const char *name, int base, int is_dll)
950 {
951   /* If a LIBRARY or NAME statement is specified without a name, there is nothing
952      to do here.  We retain the output filename specified on command line.  */
953   if (*name)
954     {
955       const char* image_name = lbasename (name);
956 
957       if (image_name != name)
958 	einfo ("%s:%d: Warning: path components stripped from %s, '%s'\n",
959 	       def_filename, linenumber, is_dll ? "LIBRARY" : "NAME",
960 	       name);
961       if (def->name)
962 	free (def->name);
963       /* Append the default suffix, if none specified.  */
964       if (strchr (image_name, '.') == 0)
965 	{
966 	  const char * suffix = is_dll ? ".dll" : ".exe";
967 
968 	  def->name = xmalloc (strlen (image_name) + strlen (suffix) + 1);
969 	  sprintf (def->name, "%s%s", image_name, suffix);
970         }
971       else
972 	def->name = xstrdup (image_name);
973     }
974 
975   /* Honor a BASE address statement, even if LIBRARY string is empty.  */
976   def->base_address = base;
977   def->is_dll = is_dll;
978 }
979 
980 static void
981 def_description (const char *text)
982 {
983   int len = def->description ? strlen (def->description) : 0;
984 
985   len += strlen (text) + 1;
986   if (def->description)
987     {
988       def->description = xrealloc (def->description, len);
989       strcat (def->description, text);
990     }
991   else
992     {
993       def->description = xmalloc (len);
994       strcpy (def->description, text);
995     }
996 }
997 
998 static void
999 def_stacksize (int reserve, int commit)
1000 {
1001   def->stack_reserve = reserve;
1002   def->stack_commit = commit;
1003 }
1004 
1005 static void
1006 def_heapsize (int reserve, int commit)
1007 {
1008   def->heap_reserve = reserve;
1009   def->heap_commit = commit;
1010 }
1011 
1012 static void
1013 def_section (const char *name, int attr)
1014 {
1015   def_file_section *s;
1016   int max_sections = ROUND_UP (def->num_section_defs, 4);
1017 
1018   if (def->num_section_defs >= max_sections)
1019     {
1020       max_sections = ROUND_UP (def->num_section_defs+1, 4);
1021 
1022       if (def->section_defs)
1023 	def->section_defs = xrealloc (def->section_defs,
1024 				      max_sections * sizeof (def_file_import));
1025       else
1026 	def->section_defs = xmalloc (max_sections * sizeof (def_file_import));
1027     }
1028   s = def->section_defs + def->num_section_defs;
1029   memset (s, 0, sizeof (def_file_section));
1030   s->name = xstrdup (name);
1031   if (attr & 1)
1032     s->flag_read = 1;
1033   if (attr & 2)
1034     s->flag_write = 1;
1035   if (attr & 4)
1036     s->flag_execute = 1;
1037   if (attr & 8)
1038     s->flag_shared = 1;
1039 
1040   def->num_section_defs++;
1041 }
1042 
1043 static void
1044 def_section_alt (const char *name, const char *attr)
1045 {
1046   int aval = 0;
1047 
1048   for (; *attr; attr++)
1049     {
1050       switch (*attr)
1051 	{
1052 	case 'R':
1053 	case 'r':
1054 	  aval |= 1;
1055 	  break;
1056 	case 'W':
1057 	case 'w':
1058 	  aval |= 2;
1059 	  break;
1060 	case 'X':
1061 	case 'x':
1062 	  aval |= 4;
1063 	  break;
1064 	case 'S':
1065 	case 's':
1066 	  aval |= 8;
1067 	  break;
1068 	}
1069     }
1070   def_section (name, aval);
1071 }
1072 
1073 static void
1074 def_exports (const char *external_name,
1075 	     const char *internal_name,
1076 	     int ordinal,
1077 	     int flags,
1078 	     const char *its_name)
1079 {
1080   def_file_export *dfe;
1081   int is_dup = 0;
1082 
1083   if (!internal_name && external_name)
1084     internal_name = external_name;
1085 #if TRACE
1086   printf ("def_exports, ext=%s int=%s\n", external_name, internal_name);
1087 #endif
1088 
1089   dfe = def_file_add_export (def, external_name, internal_name, ordinal,
1090 			     its_name, &is_dup);
1091 
1092   /* We might check here for flag redefinition and warn.  For now we
1093      ignore duplicates silently.  */
1094   if (is_dup)
1095     return;
1096 
1097   if (flags & 1)
1098     dfe->flag_noname = 1;
1099   if (flags & 2)
1100     dfe->flag_constant = 1;
1101   if (flags & 4)
1102     dfe->flag_data = 1;
1103   if (flags & 8)
1104     dfe->flag_private = 1;
1105 }
1106 
1107 static void
1108 def_import (const char *internal_name,
1109 	    const char *module,
1110 	    const char *dllext,
1111 	    const char *name,
1112 	    int ordinal,
1113 	    const char *its_name)
1114 {
1115   char *buf = 0;
1116   const char *ext = dllext ? dllext : "dll";
1117   int is_dup = 0;
1118 
1119   buf = xmalloc (strlen (module) + strlen (ext) + 2);
1120   sprintf (buf, "%s.%s", module, ext);
1121   module = buf;
1122 
1123   def_file_add_import (def, name, module, ordinal, internal_name, its_name,
1124 		       &is_dup);
1125   free (buf);
1126 }
1127 
1128 static void
1129 def_version (int major, int minor)
1130 {
1131   def->version_major = major;
1132   def->version_minor = minor;
1133 }
1134 
1135 static void
1136 def_directive (char *str)
1137 {
1138   struct directive *d = xmalloc (sizeof (struct directive));
1139 
1140   d->next = directives;
1141   directives = d;
1142   d->name = xstrdup (str);
1143   d->len = strlen (str);
1144 }
1145 
1146 static void
1147 def_aligncomm (char *str, int align)
1148 {
1149   def_file_aligncomm *c, *p;
1150 
1151   p = NULL;
1152   c = def->aligncomms;
1153   while (c != NULL)
1154     {
1155       int e = strcmp (c->symbol_name, str);
1156       if (!e)
1157 	{
1158 	  /* Not sure if we want to allow here duplicates with
1159 	     different alignments, but for now we keep them.  */
1160 	  e = (int) c->alignment - align;
1161 	  if (!e)
1162 	    return;
1163 	}
1164       if (e > 0)
1165         break;
1166       c = (p = c)->next;
1167     }
1168 
1169   c = xmalloc (sizeof (def_file_aligncomm));
1170   c->symbol_name = xstrdup (str);
1171   c->alignment = (unsigned int) align;
1172   if (!p)
1173     {
1174       c->next = def->aligncomms;
1175       def->aligncomms = c;
1176     }
1177   else
1178     {
1179       c->next = p->next;
1180       p->next = c;
1181     }
1182 }
1183 
1184 static int
1185 def_error (const char *err)
1186 {
1187   einfo ("%P: %s:%d: %s\n",
1188 	 def_filename ? def_filename : "<unknown-file>", linenumber, err);
1189   return 0;
1190 }
1191 
1192 
1193 /* Lexical Scanner.  */
1194 
1195 #undef TRACE
1196 #define TRACE 0
1197 
1198 /* Never freed, but always reused as needed, so no real leak.  */
1199 static char *buffer = 0;
1200 static int buflen = 0;
1201 static int bufptr = 0;
1202 
1203 static void
1204 put_buf (char c)
1205 {
1206   if (bufptr == buflen)
1207     {
1208       buflen += 50;		/* overly reasonable, eh?  */
1209       if (buffer)
1210 	buffer = xrealloc (buffer, buflen + 1);
1211       else
1212 	buffer = xmalloc (buflen + 1);
1213     }
1214   buffer[bufptr++] = c;
1215   buffer[bufptr] = 0;		/* not optimal, but very convenient.  */
1216 }
1217 
1218 static struct
1219 {
1220   char *name;
1221   int token;
1222 }
1223 tokens[] =
1224 {
1225   { "BASE", BASE },
1226   { "CODE", CODE },
1227   { "CONSTANT", CONSTANTU },
1228   { "constant", CONSTANTL },
1229   { "DATA", DATAU },
1230   { "data", DATAL },
1231   { "DESCRIPTION", DESCRIPTION },
1232   { "DIRECTIVE", DIRECTIVE },
1233   { "EXECUTE", EXECUTE },
1234   { "EXPORTS", EXPORTS },
1235   { "HEAPSIZE", HEAPSIZE },
1236   { "IMPORTS", IMPORTS },
1237   { "LIBRARY", LIBRARY },
1238   { "NAME", NAME },
1239   { "NONAME", NONAMEU },
1240   { "noname", NONAMEL },
1241   { "PRIVATE", PRIVATEU },
1242   { "private", PRIVATEL },
1243   { "READ", READ },
1244   { "SECTIONS", SECTIONS },
1245   { "SEGMENTS", SECTIONS },
1246   { "SHARED", SHARED },
1247   { "STACKSIZE", STACKSIZE_K },
1248   { "VERSION", VERSIONK },
1249   { "WRITE", WRITE },
1250   { 0, 0 }
1251 };
1252 
1253 static int
1254 def_getc (void)
1255 {
1256   int rv;
1257 
1258   if (lex_parse_string)
1259     {
1260       if (lex_parse_string >= lex_parse_string_end)
1261 	rv = EOF;
1262       else
1263 	rv = *lex_parse_string++;
1264     }
1265   else
1266     {
1267       rv = fgetc (the_file);
1268     }
1269   if (rv == '\n')
1270     saw_newline = 1;
1271   return rv;
1272 }
1273 
1274 static int
1275 def_ungetc (int c)
1276 {
1277   if (lex_parse_string)
1278     {
1279       lex_parse_string--;
1280       return c;
1281     }
1282   else
1283     return ungetc (c, the_file);
1284 }
1285 
1286 static int
1287 def_lex (void)
1288 {
1289   int c, i, q;
1290 
1291   if (lex_forced_token)
1292     {
1293       i = lex_forced_token;
1294       lex_forced_token = 0;
1295 #if TRACE
1296       printf ("lex: forcing token %d\n", i);
1297 #endif
1298       return i;
1299     }
1300 
1301   c = def_getc ();
1302 
1303   /* Trim leading whitespace.  */
1304   while (c != EOF && (c == ' ' || c == '\t') && saw_newline)
1305     c = def_getc ();
1306 
1307   if (c == EOF)
1308     {
1309 #if TRACE
1310       printf ("lex: EOF\n");
1311 #endif
1312       return 0;
1313     }
1314 
1315   if (saw_newline && c == ';')
1316     {
1317       do
1318 	{
1319 	  c = def_getc ();
1320 	}
1321       while (c != EOF && c != '\n');
1322       if (c == '\n')
1323 	return def_lex ();
1324       return 0;
1325     }
1326 
1327   /* Must be something else.  */
1328   saw_newline = 0;
1329 
1330   if (ISDIGIT (c))
1331     {
1332       bufptr = 0;
1333       while (c != EOF && (ISXDIGIT (c) || (c == 'x')))
1334 	{
1335 	  put_buf (c);
1336 	  c = def_getc ();
1337 	}
1338       if (c != EOF)
1339 	def_ungetc (c);
1340       yylval.digits = def_pool_strdup (buffer);
1341 #if TRACE
1342       printf ("lex: `%s' returns DIGITS\n", buffer);
1343 #endif
1344       return DIGITS;
1345     }
1346 
1347   if (ISALPHA (c) || strchr ("$:-_?@", c))
1348     {
1349       bufptr = 0;
1350       q = c;
1351       put_buf (c);
1352       c = def_getc ();
1353 
1354       if (q == '@')
1355 	{
1356           if (ISBLANK (c) ) /* '@' followed by whitespace.  */
1357 	    return (q);
1358           else if (ISDIGIT (c)) /* '@' followed by digit.  */
1359             {
1360 	      def_ungetc (c);
1361               return (q);
1362 	    }
1363 #if TRACE
1364 	  printf ("lex: @ returns itself\n");
1365 #endif
1366 	}
1367 
1368       while (c != EOF && (ISALNUM (c) || strchr ("$:-_?/@<>", c)))
1369 	{
1370 	  put_buf (c);
1371 	  c = def_getc ();
1372 	}
1373       if (c != EOF)
1374 	def_ungetc (c);
1375       if (ISALPHA (q)) /* Check for tokens.  */
1376 	{
1377           for (i = 0; tokens[i].name; i++)
1378 	    if (strcmp (tokens[i].name, buffer) == 0)
1379 	      {
1380 #if TRACE
1381 	        printf ("lex: `%s' is a string token\n", buffer);
1382 #endif
1383 	        return tokens[i].token;
1384 	      }
1385 	}
1386 #if TRACE
1387       printf ("lex: `%s' returns ID\n", buffer);
1388 #endif
1389       yylval.id = def_pool_strdup (buffer);
1390       return ID;
1391     }
1392 
1393   if (c == '\'' || c == '"')
1394     {
1395       q = c;
1396       c = def_getc ();
1397       bufptr = 0;
1398 
1399       while (c != EOF && c != q)
1400 	{
1401 	  put_buf (c);
1402 	  c = def_getc ();
1403 	}
1404       yylval.id = def_pool_strdup (buffer);
1405 #if TRACE
1406       printf ("lex: `%s' returns ID\n", buffer);
1407 #endif
1408       return ID;
1409     }
1410 
1411   if ( c == '=')
1412     {
1413       c = def_getc ();
1414       if (c == '=')
1415         {
1416 #if TRACE
1417           printf ("lex: `==' returns EQUAL\n");
1418 #endif
1419 		  return EQUAL;
1420         }
1421       def_ungetc (c);
1422 #if TRACE
1423       printf ("lex: `=' returns itself\n");
1424 #endif
1425       return '=';
1426     }
1427   if (c == '.' || c == ',')
1428     {
1429 #if TRACE
1430       printf ("lex: `%c' returns itself\n", c);
1431 #endif
1432       return c;
1433     }
1434 
1435   if (c == '\n')
1436     {
1437       linenumber++;
1438       saw_newline = 1;
1439     }
1440 
1441   /*printf ("lex: 0x%02x ignored\n", c); */
1442   return def_lex ();
1443 }
1444 
1445 static char *
1446 def_pool_alloc (size_t sz)
1447 {
1448   def_pool_str *e;
1449 
1450   e = (def_pool_str *) xmalloc (sizeof (def_pool_str) + sz);
1451   e->next = pool_strs;
1452   pool_strs = e;
1453   return e->data;
1454 }
1455 
1456 static char *
1457 def_pool_strdup (const char *str)
1458 {
1459   char *s;
1460   size_t len;
1461   if (!str)
1462     return NULL;
1463   len = strlen (str) + 1;
1464   s = def_pool_alloc (len);
1465   memcpy (s, str, len);
1466   return s;
1467 }
1468 
1469 static void
1470 def_pool_free (void)
1471 {
1472   def_pool_str *p;
1473   while ((p = pool_strs) != NULL)
1474     {
1475       pool_strs = p->next;
1476       free (p);
1477     }
1478 }
1479