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