Home | History | Annotate | Download | only in src
      1 %{
      2 /* Parser for linker scripts.
      3    Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006 Red Hat, Inc.
      4    This file is part of Red Hat elfutils.
      5    Written by Ulrich Drepper <drepper (at) 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.  */
     45 static void yyerror (const char *s);
     46 
     47 /* Some helper functions we need to construct the data structures
     48    describing information from the file.  */
     49 static struct expression *new_expr (int tag);
     50 static struct input_section_name *new_input_section_name (const char *name,
     51 							  bool sort_flag);
     52 static struct input_rule *new_input_rule (int tag);
     53 static struct output_rule *new_output_rule (int tag);
     54 static struct assignment *new_assignment (const char *variable,
     55 					  struct expression *expression,
     56 					  bool provide_flag);
     57 static void new_segment (int mode, struct output_rule *output_rule);
     58 static struct filename_list *new_filename_listelem (const char *string);
     59 static void add_inputfiles (struct filename_list *fnames);
     60 static struct id_list *new_id_listelem (const char *str);
     61  static struct filename_list *mark_as_needed (struct filename_list *listp);
     62 static struct version *new_version (struct id_list *local,
     63 				    struct id_list *global);
     64 static struct version *merge_versions (struct version *one,
     65 				       struct version *two);
     66 static void add_versions (struct version *versions);
     67 
     68 extern 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 
    142 script_or_version:
    143 		  file
    144 		| kVERSION_SCRIPT versionlist
    145 		    { add_versions ($2); }
    146 		;
    147 
    148 file:		  file content
    149 		| content
    150 		;
    151 
    152 content:	  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 
    203 outputsections:	  outputsections outputsection
    204 		    {
    205 		      $2->next = $1->next;
    206 		      $$ = $1->next = $2;
    207 		    }
    208 		| outputsection
    209 		    { $$ = $1; }
    210 		;
    211 
    212 outputsection:	  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 
    253 assignment:	  kID '=' expr
    254 		    { $$ = new_assignment ($1, $3, false); }
    255 		| kPROVIDE '(' kID '=' expr ')'
    256 		    { $$ = new_assignment ($3, $5, true); }
    257 		;
    258 
    259 inputsections:	  inputsections inputsection
    260 		    {
    261 		      $2->next = $1->next;
    262 		      $$ = $1->next = $2;
    263 		    }
    264 		| inputsection
    265 		    { $$ = $1; }
    266 		;
    267 
    268 inputsection:	  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 
    287 sectionname:	  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 
    298 sort_opt_name:	  kID
    299 		    { $$ = new_input_section_name ($1, false); }
    300 		| kSORT '(' kID ')'
    301 		    { $$ = new_input_section_name ($3, true); }
    302 		;
    303 
    304 exclude_opt:	  kEXCLUDE_FILE '(' filename_id ')'
    305 		    { $$ = $3; }
    306 		|
    307 		    { $$ = NULL; }
    308 		;
    309 
    310 expr:		  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 
    363 filename_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 
    372 comma_opt:	  ','
    373 		|
    374 		;
    375 
    376 filename_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 
    394 versionlist:	  versionlist version
    395 		    {
    396 		      $2->next = $1->next;
    397 		      $$ = $1->next = $2;
    398 		    }
    399 		| version
    400 		    { $$ = $1; }
    401 		;
    402 
    403 version:	  '{' 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 
    423 version_stmt_list:
    424 		  version_stmt_list version_stmt
    425 		    { $$ = merge_versions ($1, $2); }
    426 		| version_stmt
    427 		    { $$ = $1; }
    428 		;
    429 
    430 version_stmt:	  kGLOBAL filename_id_star_list
    431 		    { $$ = new_version (NULL, $2); }
    432 		| kLOCAL filename_id_star_list
    433 		    { $$ = new_version ($2, NULL); }
    434 		;
    435 
    436 filename_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 
    447 filename_id:	  kFILENAME
    448 		    { $$ = $1; }
    449 		| kID
    450 		    { $$ = $1; }
    451 		;
    452 
    453 filename_id_star: filename_id
    454 		    { $$ = $1; }
    455 		| '*'
    456 		    { $$ = NULL; }
    457 		;
    458 
    459 %%
    460 
    461 static void
    462 yyerror (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 
    471 static struct expression *
    472 new_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 
    482 static struct input_section_name *
    483 new_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 
    494 static struct input_rule *
    495 new_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 
    506 static struct output_rule *
    507 new_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 
    519 static struct assignment *
    520 new_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 
    536 static void
    537 new_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 
    571 static struct filename_list *
    572 new_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 
    584 static struct filename_list *
    585 mark_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 
    599 static void
    600 add_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 
    617 static _Bool
    618 special_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 
    634 static struct id_list *
    635 new_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 
    653 static struct version *
    654 new_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 
    669 static struct version *
    670 merge_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 
    699 static void
    700 add_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 ("\
    746 symbol '%s' in declared both local and global for unnamed version")
    747 		     : gettext ("\
    748 symbol '%s' in 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 
    790 static void
    791 add_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       struct version *oldp;
    806 
    807       add_id_list (versions->versionname, versions->local_names, true);
    808       add_id_list (versions->versionname, versions->global_names, false);
    809 
    810       oldp = versions;
    811       versions = versions->next;
    812     }
    813   while (versions != NULL);
    814 }
    815