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