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