blob: c2f1971a2e22cb27d9c5f7fcddb75c76002aae7b [file] [log] [blame]
Ben Cheng25b3c042013-11-20 14:45:36 -08001%{
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}