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