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