Home | History | Annotate | Download | only in src
      1 %{
      2 /* Parser for linker scripts.
      3    Copyright (C) 2001, 2002, 2003, 2004 Red Hat, Inc.
      4    Written by Ulrich Drepper <drepper (at) 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 *
    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 *
    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 *
    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 *
    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 *
    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
    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 *
    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
    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
    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 *
    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 *
    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 *
    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
    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
    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