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