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