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