• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.  */
37 static void yyerror (const char *s);
38 
39 /* Some helper functions we need to construct the data structures
40    describing information from the file.  */
41 static struct expression *new_expr (int tag);
42 static struct input_section_name *new_input_section_name (const char *name,
43 							  bool sort_flag);
44 static struct input_rule *new_input_rule (int tag);
45 static struct output_rule *new_output_rule (int tag);
46 static struct assignment *new_assignment (const char *variable,
47 					  struct expression *expression,
48 					  bool provide_flag);
49 static void new_segment (int mode, struct output_rule *output_rule);
50 static struct filename_list *new_filename_listelem (const char *string);
51 static void add_inputfiles (struct filename_list *fnames);
52 static struct id_list *new_id_listelem (const char *str);
53  static struct filename_list *mark_as_needed (struct filename_list *listp);
54 static struct version *new_version (struct id_list *local,
55 				    struct id_list *global);
56 static struct version *merge_versions (struct version *one,
57 				       struct version *two);
58 static void add_versions (struct version *versions);
59 
60 extern 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 
134 script_or_version:
135 		  file
136 		| kVERSION_SCRIPT versionlist
137 		    { add_versions ($2); }
138 		;
139 
140 file:		  file content
141 		| content
142 		;
143 
144 content:	  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 
195 outputsections:	  outputsections outputsection
196 		    {
197 		      $2->next = $1->next;
198 		      $$ = $1->next = $2;
199 		    }
200 		| outputsection
201 		    { $$ = $1; }
202 		;
203 
204 outputsection:	  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 
245 assignment:	  kID '=' expr
246 		    { $$ = new_assignment ($1, $3, false); }
247 		| kPROVIDE '(' kID '=' expr ')'
248 		    { $$ = new_assignment ($3, $5, true); }
249 		;
250 
251 inputsections:	  inputsections inputsection
252 		    {
253 		      $2->next = $1->next;
254 		      $$ = $1->next = $2;
255 		    }
256 		| inputsection
257 		    { $$ = $1; }
258 		;
259 
260 inputsection:	  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 
279 sectionname:	  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 
290 sort_opt_name:	  kID
291 		    { $$ = new_input_section_name ($1, false); }
292 		| kSORT '(' kID ')'
293 		    { $$ = new_input_section_name ($3, true); }
294 		;
295 
296 exclude_opt:	  kEXCLUDE_FILE '(' filename_id ')'
297 		    { $$ = $3; }
298 		|
299 		    { $$ = NULL; }
300 		;
301 
302 expr:		  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 
355 filename_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 
364 comma_opt:	  ','
365 		|
366 		;
367 
368 filename_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 
386 versionlist:	  versionlist version
387 		    {
388 		      $2->next = $1->next;
389 		      $$ = $1->next = $2;
390 		    }
391 		| version
392 		    { $$ = $1; }
393 		;
394 
395 version:	  '{' 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 
415 version_stmt_list:
416 		  version_stmt_list version_stmt
417 		    { $$ = merge_versions ($1, $2); }
418 		| version_stmt
419 		    { $$ = $1; }
420 		;
421 
422 version_stmt:	  kGLOBAL filename_id_star_list
423 		    { $$ = new_version (NULL, $2); }
424 		| kLOCAL filename_id_star_list
425 		    { $$ = new_version ($2, NULL); }
426 		;
427 
428 filename_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 
439 filename_id:	  kFILENAME
440 		    { $$ = $1; }
441 		| kID
442 		    { $$ = $1; }
443 		;
444 
445 filename_id_star: filename_id
446 		    { $$ = $1; }
447 		| '*'
448 		    { $$ = NULL; }
449 		;
450 
451 %%
452 
453 static void
454 yyerror (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 
463 static struct expression *
new_expr(int tag)464 new_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 
474 static struct input_section_name *
new_input_section_name(const char * name,bool sort_flag)475 new_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 
486 static struct input_rule *
new_input_rule(int tag)487 new_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 
498 static struct output_rule *
new_output_rule(int tag)499 new_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 
511 static struct assignment *
new_assignment(const char * variable,struct expression * expression,bool provide_flag)512 new_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 
528 static void
new_segment(int mode,struct output_rule * output_rule)529 new_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 
563 static struct filename_list *
new_filename_listelem(const char * string)564 new_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 
576 static struct filename_list *
mark_as_needed(struct filename_list * listp)577 mark_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 
591 static void
add_inputfiles(struct filename_list * fnames)592 add_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 
609 static _Bool
special_char_p(const char * str)610 special_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 
626 static struct id_list *
new_id_listelem(const char * str)627 new_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 
645 static struct version *
new_version(struct id_list * local,struct id_list * global)646 new_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 
661 static struct version *
merge_versions(struct version * one,struct version * two)662 merge_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 
691 static void
add_id_list(const char * versionname,struct id_list * runp,_Bool local)692 add_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 ("\
738 symbol '%s' is declared both local and global for unnamed version '%s'")
739 		     : gettext ("\
740 symbol '%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 
782 static void
add_versions(struct version * versions)783 add_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