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