1%{
2/* Parser for linker scripts.
3   Copyright (C) 2001-2011 Red Hat, Inc.
4   This file is part of Red Hat elfutils.
5   Written by Ulrich Drepper <drepper@redhat.com>, 2001.
6
7   Red Hat elfutils is free software; you can redistribute it and/or modify
8   it under the terms of the GNU General Public License as published by the
9   Free Software Foundation; version 2 of the License.
10
11   Red Hat elfutils is distributed in the hope that it will be useful, but
12   WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14   General Public License for more details.
15
16   You should have received a copy of the GNU General Public License along
17   with Red Hat elfutils; if not, write to the Free Software Foundation,
18   Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
19
20   Red Hat elfutils is an included package of the Open Invention Network.
21   An included package of the Open Invention Network is a package for which
22   Open Invention Network licensees cross-license their patents.  No patent
23   license is granted, either expressly or impliedly, by designation as an
24   included package.  Should you wish to participate in the Open Invention
25   Network licensing program, please visit www.openinventionnetwork.com
26   <http://www.openinventionnetwork.com>.  */
27
28#ifdef HAVE_CONFIG_H
29# include <config.h>
30#endif
31
32#include <assert.h>
33#include <error.h>
34#include <libintl.h>
35#include <stdbool.h>
36#include <stdint.h>
37#include <stdio.h>
38#include <stdlib.h>
39#include <string.h>
40
41#include <system.h>
42#include <ld.h>
43
44/* The error handler.  */
45static void yyerror (const char *s);
46
47/* Some helper functions we need to construct the data structures
48   describing information from the file.  */
49static struct expression *new_expr (int tag);
50static struct input_section_name *new_input_section_name (const char *name,
51							  bool sort_flag);
52static struct input_rule *new_input_rule (int tag);
53static struct output_rule *new_output_rule (int tag);
54static struct assignment *new_assignment (const char *variable,
55					  struct expression *expression,
56					  bool provide_flag);
57static void new_segment (int mode, struct output_rule *output_rule);
58static struct filename_list *new_filename_listelem (const char *string);
59static void add_inputfiles (struct filename_list *fnames);
60static struct id_list *new_id_listelem (const char *str);
61 static struct filename_list *mark_as_needed (struct filename_list *listp);
62static struct version *new_version (struct id_list *local,
63				    struct id_list *global);
64static struct version *merge_versions (struct version *one,
65				       struct version *two);
66static void add_versions (struct version *versions);
67
68extern int yylex (void);
69%}
70
71%union {
72  uintmax_t num;
73  enum expression_tag op;
74  char *str;
75  struct expression *expr;
76  struct input_section_name *sectionname;
77  struct filemask_section_name *filemask_section_name;
78  struct input_rule *input_rule;
79  struct output_rule *output_rule;
80  struct assignment *assignment;
81  struct filename_list *filename_list;
82  struct version *version;
83  struct id_list *id_list;
84}
85
86%token kADD_OP
87%token kALIGN
88%token kAS_NEEDED
89%token kENTRY
90%token kEXCLUDE_FILE
91%token <str> kFILENAME
92%token kGLOBAL
93%token kGROUP
94%token <str> kID
95%token kINPUT
96%token kINTERP
97%token kKEEP
98%token kLOCAL
99%token <num> kMODE
100%token kMUL_OP
101%token <num> kNUM
102%token kOUTPUT_FORMAT
103%token kPAGESIZE
104%token kPROVIDE
105%token kSEARCH_DIR
106%token kSEGMENT
107%token kSIZEOF_HEADERS
108%token kSORT
109%token kVERSION
110%token kVERSION_SCRIPT
111
112%left '|'
113%left '&'
114%left ADD_OP
115%left MUL_OP '*'
116
117%type <op> kADD_OP
118%type <op> kMUL_OP
119%type <str> filename_id
120%type <str> filename_id_star
121%type <str> exclude_opt
122%type <expr> expr
123%type <sectionname> sort_opt_name
124%type <filemask_section_name> sectionname
125%type <input_rule> inputsection
126%type <input_rule> inputsections
127%type <output_rule> outputsection
128%type <output_rule> outputsections
129%type <assignment> assignment
130%type <filename_list> filename_id_list
131%type <filename_list> filename_id_listelem
132%type <version> versionlist
133%type <version> version
134%type <version> version_stmt_list
135%type <version> version_stmt
136%type <id_list> filename_id_star_list
137
138%expect 16
139
140%%
141
142script_or_version:
143		  file
144		| kVERSION_SCRIPT versionlist
145		    { add_versions ($2); }
146		;
147
148file:		  file content
149		| content
150		;
151
152content:	  kENTRY '(' kID ')' ';'
153		    {
154		      if (likely (ld_state.entry == NULL))
155			ld_state.entry = $3;
156		    }
157		| kSEARCH_DIR '(' filename_id ')' ';'
158		    {
159		      ld_new_searchdir ($3);
160		    }
161		| kPAGESIZE '(' kNUM ')' ';'
162		    {
163		      if (likely (ld_state.pagesize == 0))
164			ld_state.pagesize = $3;
165		    }
166		| kINTERP '(' filename_id ')' ';'
167		    {
168		      if (likely (ld_state.interp == NULL)
169			  && ld_state.file_type != dso_file_type)
170			ld_state.interp = $3;
171		    }
172		| kSEGMENT kMODE '{' outputsections '}'
173		    {
174		      new_segment ($2, $4);
175		    }
176		| kSEGMENT error '{' outputsections '}'
177		    {
178		      fputs_unlocked (gettext ("mode for segment invalid\n"),
179				      stderr);
180		      new_segment (0, $4);
181		    }
182		| kGROUP '(' filename_id_list ')'
183		    {
184		      /* First little optimization.  If there is only one
185			 file in the group don't do anything.  */
186		      if ($3 != $3->next)
187			{
188			  $3->next->group_start = 1;
189			  $3->group_end = 1;
190			}
191		      add_inputfiles ($3);
192		    }
193		| kINPUT '(' filename_id_list ')'
194		    { add_inputfiles ($3); }
195		| kAS_NEEDED '(' filename_id_list ')'
196		    { add_inputfiles (mark_as_needed ($3)); }
197		| kVERSION '{' versionlist '}'
198		    { add_versions ($3); }
199		| kOUTPUT_FORMAT '(' filename_id ')'
200		    { /* XXX TODO */ }
201		;
202
203outputsections:	  outputsections outputsection
204		    {
205		      $2->next = $1->next;
206		      $$ = $1->next = $2;
207		    }
208		| outputsection
209		    { $$ = $1; }
210		;
211
212outputsection:	  assignment ';'
213		    {
214		      $$ = new_output_rule (output_assignment);
215		      $$->val.assignment = $1;
216		    }
217		| kID '{' inputsections '}'
218		    {
219		      $$ = new_output_rule (output_section);
220		      $$->val.section.name = $1;
221		      $$->val.section.input = $3->next;
222		      if (ld_state.strip == strip_debug
223			  && ebl_debugscn_p (ld_state.ebl, $1))
224			$$->val.section.ignored = true;
225		      else
226			$$->val.section.ignored = false;
227		      $3->next = NULL;
228		    }
229		| kID ';'
230		    {
231		      /* This is a short cut for "ID { *(ID) }".  */
232		      $$ = new_output_rule (output_section);
233		      $$->val.section.name = $1;
234		      $$->val.section.input = new_input_rule (input_section);
235		      $$->val.section.input->next = NULL;
236		      $$->val.section.input->val.section =
237			(struct filemask_section_name *)
238			  obstack_alloc (&ld_state.smem,
239					 sizeof (struct filemask_section_name));
240		      $$->val.section.input->val.section->filemask = NULL;
241		      $$->val.section.input->val.section->excludemask = NULL;
242		      $$->val.section.input->val.section->section_name =
243			new_input_section_name ($1, false);
244		      $$->val.section.input->val.section->keep_flag = false;
245		      if (ld_state.strip == strip_debug
246			  && ebl_debugscn_p (ld_state.ebl, $1))
247			$$->val.section.ignored = true;
248		      else
249			$$->val.section.ignored = false;
250		    }
251		;
252
253assignment:	  kID '=' expr
254		    { $$ = new_assignment ($1, $3, false); }
255		| kPROVIDE '(' kID '=' expr ')'
256		    { $$ = new_assignment ($3, $5, true); }
257		;
258
259inputsections:	  inputsections inputsection
260		    {
261		      $2->next = $1->next;
262		      $$ = $1->next = $2;
263		    }
264		| inputsection
265		    { $$ = $1; }
266		;
267
268inputsection:	  sectionname
269		    {
270		      $$ = new_input_rule (input_section);
271		      $$->val.section = $1;
272		    }
273		| kKEEP '(' sectionname ')'
274		    {
275		      $3->keep_flag = true;
276
277		      $$ = new_input_rule (input_section);
278		      $$->val.section = $3;
279		    }
280		| assignment ';'
281		    {
282		      $$ = new_input_rule (input_assignment);
283		      $$->val.assignment = $1;
284		    }
285		;
286
287sectionname:	  filename_id_star '(' exclude_opt sort_opt_name ')'
288		    {
289		      $$ = (struct filemask_section_name *)
290			obstack_alloc (&ld_state.smem, sizeof (*$$));
291		      $$->filemask = $1;
292		      $$->excludemask = $3;
293		      $$->section_name = $4;
294		      $$->keep_flag = false;
295		    }
296		;
297
298sort_opt_name:	  kID
299		    { $$ = new_input_section_name ($1, false); }
300		| kSORT '(' kID ')'
301		    { $$ = new_input_section_name ($3, true); }
302		;
303
304exclude_opt:	  kEXCLUDE_FILE '(' filename_id ')'
305		    { $$ = $3; }
306		|
307		    { $$ = NULL; }
308		;
309
310expr:		  kALIGN '(' expr ')'
311		    {
312		      $$ = new_expr (exp_align);
313		      $$->val.child = $3;
314		    }
315		| '(' expr ')'
316		    { $$ = $2; }
317		| expr '*' expr
318		    {
319		      $$ = new_expr (exp_mult);
320		      $$->val.binary.left = $1;
321		      $$->val.binary.right = $3;
322		    }
323		| expr kMUL_OP expr
324		    {
325		      $$ = new_expr ($2);
326		      $$->val.binary.left = $1;
327		      $$->val.binary.right = $3;
328		    }
329		| expr kADD_OP expr
330		    {
331		      $$ = new_expr ($2);
332		      $$->val.binary.left = $1;
333		      $$->val.binary.right = $3;
334		    }
335		| expr '&' expr
336		    {
337		      $$ = new_expr (exp_and);
338		      $$->val.binary.left = $1;
339		      $$->val.binary.right = $3;
340		    }
341		| expr '|' expr
342		    {
343		      $$ = new_expr (exp_or);
344		      $$->val.binary.left = $1;
345		      $$->val.binary.right = $3;
346		    }
347		| kNUM
348		    {
349		      $$ = new_expr (exp_num);
350		      $$->val.num = $1;
351		    }
352		| kID
353		    {
354		      $$ = new_expr (exp_id);
355		      $$->val.str = $1;
356		    }
357		| kSIZEOF_HEADERS
358		    { $$ = new_expr (exp_sizeof_headers); }
359		| kPAGESIZE
360		    { $$ = new_expr (exp_pagesize); }
361		;
362
363filename_id_list: filename_id_list comma_opt filename_id_listelem
364		    {
365		      $3->next = $1->next;
366		      $$ = $1->next = $3;
367		    }
368		| filename_id_listelem
369		    { $$ = $1; }
370		;
371
372comma_opt:	  ','
373		|
374		;
375
376filename_id_listelem: kGROUP '(' filename_id_list ')'
377		    {
378		      /* First little optimization.  If there is only one
379			 file in the group don't do anything.  */
380		      if ($3 != $3->next)
381			{
382			  $3->next->group_start = 1;
383			  $3->group_end = 1;
384			}
385		      $$ = $3;
386		    }
387		| kAS_NEEDED '(' filename_id_list ')'
388		    { $$ = mark_as_needed ($3); }
389		| filename_id
390		    { $$ = new_filename_listelem ($1); }
391		;
392
393
394versionlist:	  versionlist version
395		    {
396		      $2->next = $1->next;
397		      $$ = $1->next = $2;
398		    }
399		| version
400		    { $$ = $1; }
401		;
402
403version:	  '{' version_stmt_list '}' ';'
404		    {
405		      $2->versionname = "";
406		      $2->parentname = NULL;
407		      $$ = $2;
408		    }
409		| filename_id '{' version_stmt_list '}' ';'
410		    {
411		      $3->versionname = $1;
412		      $3->parentname = NULL;
413		      $$ = $3;
414		    }
415		| filename_id '{' version_stmt_list '}' filename_id ';'
416		    {
417		      $3->versionname = $1;
418		      $3->parentname = $5;
419		      $$ = $3;
420		    }
421		;
422
423version_stmt_list:
424		  version_stmt_list version_stmt
425		    { $$ = merge_versions ($1, $2); }
426		| version_stmt
427		    { $$ = $1; }
428		;
429
430version_stmt:	  kGLOBAL filename_id_star_list
431		    { $$ = new_version (NULL, $2); }
432		| kLOCAL filename_id_star_list
433		    { $$ = new_version ($2, NULL); }
434		;
435
436filename_id_star_list:
437		  filename_id_star_list filename_id_star ';'
438		    {
439		      struct id_list *newp = new_id_listelem ($2);
440		      newp->next = $1->next;
441		      $$ = $1->next = newp;
442		    }
443		| filename_id_star ';'
444		    { $$ = new_id_listelem ($1); }
445		;
446
447filename_id:	  kFILENAME
448		    { $$ = $1; }
449		| kID
450		    { $$ = $1; }
451		;
452
453filename_id_star: filename_id
454		    { $$ = $1; }
455		| '*'
456		    { $$ = NULL; }
457		;
458
459%%
460
461static void
462yyerror (const char *s)
463{
464  error (0, 0, (ld_scan_version_script
465		? gettext ("while reading version script '%s': %s at line %d")
466		: gettext ("while reading linker script '%s': %s at line %d")),
467	 ldin_fname, gettext (s), ldlineno);
468}
469
470
471static struct expression *
472new_expr (int tag)
473{
474  struct expression *newp = (struct expression *)
475    obstack_alloc (&ld_state.smem, sizeof (*newp));
476
477  newp->tag = tag;
478  return newp;
479}
480
481
482static struct input_section_name *
483new_input_section_name (const char *name, bool sort_flag)
484{
485  struct input_section_name *newp = (struct input_section_name *)
486    obstack_alloc (&ld_state.smem, sizeof (*newp));
487
488  newp->name = name;
489  newp->sort_flag = sort_flag;
490  return newp;
491}
492
493
494static struct input_rule *
495new_input_rule (int tag)
496{
497  struct input_rule *newp = (struct input_rule *)
498    obstack_alloc (&ld_state.smem, sizeof (*newp));
499
500  newp->tag = tag;
501  newp->next = newp;
502  return newp;
503}
504
505
506static struct output_rule *
507new_output_rule (int tag)
508{
509  struct output_rule *newp = (struct output_rule *)
510    memset (obstack_alloc (&ld_state.smem, sizeof (*newp)),
511	    '\0', sizeof (*newp));
512
513  newp->tag = tag;
514  newp->next = newp;
515  return newp;
516}
517
518
519static struct assignment *
520new_assignment (const char *variable, struct expression *expression,
521		bool provide_flag)
522{
523  struct assignment *newp = (struct assignment *)
524    obstack_alloc (&ld_state.smem, sizeof (*newp));
525
526  newp->variable = variable;
527  newp->expression = expression;
528  newp->sym = NULL;
529  newp->provide_flag = provide_flag;
530
531  /* Insert the symbol into a hash table.  We will later have to matc*/
532  return newp;
533}
534
535
536static void
537new_segment (int mode, struct output_rule *output_rule)
538{
539  struct output_segment *newp;
540
541  newp
542    = (struct output_segment *) obstack_alloc (&ld_state.smem, sizeof (*newp));
543  newp->mode = mode;
544  newp->next = newp;
545
546  newp->output_rules = output_rule->next;
547  output_rule->next = NULL;
548
549  /* Enqueue the output segment description.  */
550  if (ld_state.output_segments == NULL)
551    ld_state.output_segments = newp;
552  else
553    {
554      newp->next = ld_state.output_segments->next;
555      ld_state.output_segments = ld_state.output_segments->next = newp;
556    }
557
558  /* If the output file should be stripped of all symbol set the flag
559     in the structures of all output sections.  */
560  if (mode == 0 && ld_state.strip == strip_all)
561    {
562      struct output_rule *runp;
563
564      for (runp = newp->output_rules; runp != NULL; runp = runp->next)
565	if (runp->tag == output_section)
566	  runp->val.section.ignored = true;
567    }
568}
569
570
571static struct filename_list *
572new_filename_listelem (const char *string)
573{
574  struct filename_list *newp;
575
576  /* We use calloc and not the obstack since this object can be freed soon.  */
577  newp = (struct filename_list *) xcalloc (1, sizeof (*newp));
578  newp->name = string;
579  newp->next = newp;
580  return newp;
581}
582
583
584static struct filename_list *
585mark_as_needed (struct filename_list *listp)
586{
587  struct filename_list *runp = listp;
588  do
589    {
590      runp->as_needed = true;
591      runp = runp->next;
592    }
593  while (runp != listp);
594
595  return listp;
596}
597
598
599static void
600add_inputfiles (struct filename_list *fnames)
601{
602  assert (fnames != NULL);
603
604  if (ld_state.srcfiles == NULL)
605    ld_state.srcfiles = fnames;
606  else
607    {
608      struct filename_list *first = ld_state.srcfiles->next;
609
610      ld_state.srcfiles->next = fnames->next;
611      fnames->next = first;
612      ld_state.srcfiles->next = fnames;
613    }
614}
615
616
617static _Bool
618special_char_p (const char *str)
619{
620  while (*str != '\0')
621    {
622      if (__builtin_expect (*str == '*', 0)
623	  || __builtin_expect (*str == '?', 0)
624	  || __builtin_expect (*str == '[', 0))
625	return true;
626
627      ++str;
628    }
629
630  return false;
631}
632
633
634static struct id_list *
635new_id_listelem (const char *str)
636{
637  struct id_list *newp;
638
639  newp = (struct id_list *) obstack_alloc (&ld_state.smem, sizeof (*newp));
640  if (str == NULL)
641    newp->u.id_type = id_all;
642  else if (__builtin_expect (special_char_p (str), false))
643    newp->u.id_type = id_wild;
644  else
645    newp->u.id_type = id_str;
646  newp->id = str;
647  newp->next = newp;
648
649  return newp;
650}
651
652
653static struct version *
654new_version (struct id_list *local, struct id_list *global)
655{
656  struct version *newp;
657
658  newp = (struct version *) obstack_alloc (&ld_state.smem, sizeof (*newp));
659  newp->next = newp;
660  newp->local_names = local;
661  newp->global_names = global;
662  newp->versionname = NULL;
663  newp->parentname = NULL;
664
665  return newp;
666}
667
668
669static struct version *
670merge_versions (struct version *one, struct version *two)
671{
672  assert (two->local_names == NULL || two->global_names == NULL);
673
674  if (two->local_names != NULL)
675    {
676      if (one->local_names == NULL)
677	one->local_names = two->local_names;
678      else
679	{
680	  two->local_names->next = one->local_names->next;
681	  one->local_names = one->local_names->next = two->local_names;
682	}
683    }
684  else
685    {
686      if (one->global_names == NULL)
687	one->global_names = two->global_names;
688      else
689	{
690	  two->global_names->next = one->global_names->next;
691	  one->global_names = one->global_names->next = two->global_names;
692	}
693    }
694
695  return one;
696}
697
698
699static void
700add_id_list (const char *versionname, struct id_list *runp, _Bool local)
701{
702  struct id_list *lastp = runp;
703
704  if (runp == NULL)
705    /* Nothing to do.  */
706    return;
707
708  /* Convert into a simple single-linked list.  */
709  runp = runp->next;
710  assert (runp != NULL);
711  lastp->next = NULL;
712
713  do
714    if (runp->u.id_type == id_str)
715      {
716	struct id_list *curp;
717	struct id_list *defp;
718	unsigned long int hval = elf_hash (runp->id);
719
720	curp = runp;
721	runp = runp->next;
722
723	defp = ld_version_str_tab_find (&ld_state.version_str_tab, hval, curp);
724	if (defp != NULL)
725	  {
726	    /* There is already a version definition for this symbol.  */
727	    while (strcmp (defp->u.s.versionname, versionname) != 0)
728	      {
729		if (defp->next == NULL)
730		  {
731		    /* No version like this so far.  */
732		    defp->next = curp;
733		    curp->u.s.local = local;
734		    curp->u.s.versionname = versionname;
735		    curp->next = NULL;
736		    defp = NULL;
737		    break;
738		  }
739
740		defp = defp->next;
741	      }
742
743	    if (defp != NULL && defp->u.s.local != local)
744	      error (EXIT_FAILURE, 0, versionname[0] == '\0'
745		     ? gettext ("\
746symbol '%s' is declared both local and global for unnamed version")
747		     : gettext ("\
748symbol '%s' is declared both local and global for version '%s'"),
749		     runp->id, versionname);
750	  }
751	else
752	  {
753	    /* This is the first version definition for this symbol.  */
754	    ld_version_str_tab_insert (&ld_state.version_str_tab, hval, curp);
755
756	    curp->u.s.local = local;
757	    curp->u.s.versionname = versionname;
758	    curp->next = NULL;
759	  }
760      }
761    else if (runp->u.id_type == id_all)
762      {
763	if (local)
764	  {
765	    if (ld_state.default_bind_global)
766	      error (EXIT_FAILURE, 0,
767		     gettext ("default visibility set as local and global"));
768	    ld_state.default_bind_local = true;
769	  }
770	else
771	  {
772	    if (ld_state.default_bind_local)
773	      error (EXIT_FAILURE, 0,
774		     gettext ("default visibility set as local and global"));
775	    ld_state.default_bind_global = true;
776	  }
777
778	runp = runp->next;
779      }
780    else
781      {
782	assert (runp->u.id_type == id_wild);
783	/* XXX TBI */
784	abort ();
785      }
786  while (runp != NULL);
787}
788
789
790static void
791add_versions (struct version *versions)
792{
793  struct version *lastp = versions;
794
795  if (versions == NULL)
796    return;
797
798  /* Convert into a simple single-linked list.  */
799  versions = versions->next;
800  assert (versions != NULL);
801  lastp->next = NULL;
802
803  do
804    {
805      add_id_list (versions->versionname, versions->local_names, true);
806      add_id_list (versions->versionname, versions->global_names, false);
807
808      versions = versions->next;
809    }
810  while (versions != NULL);
811}
812