2008-12-15 Paul Pluzhnikov <ppluzhnikov@google.com>
[deliverable/binutils-gdb.git] / gold / yyscript.y
index 33023dc52be93cdebd5c3bb1dc852f3c6493b026..52493202695f0c9a48085f77db3e4460193a8097 100644 (file)
@@ -1,4 +1,4 @@
-/* yyscript.y -- linker script grammer for gold.  */
+/* yyscript.y -- linker script grammar for gold.  */
 
 /* Copyright 2006, 2007, 2008 Free Software Foundation, Inc.
    Written by Ian Lance Taylor <iant@google.com>.
@@ -30,6 +30,7 @@
 #include <stddef.h>
 #include <stdint.h>
 #include <stdlib.h>
+#include <string.h>
 
 #include "script-c.h"
 
@@ -60,6 +61,8 @@
   struct Parser_output_section_header output_section_header;
   /* An output section trailer.  */
   struct Parser_output_section_trailer output_section_trailer;
+  /* A section constraint.  */
+  enum Section_constraint constraint;
   /* A complete input section specification.  */
   struct Input_section_spec input_section_spec;
   /* A list of wildcard specifications, with exclusions.  */
@@ -68,6 +71,8 @@
   struct Wildcard_section wildcard_section;
   /* A list of strings.  */
   String_list_ptr string_list;
+  /* Information for a program header.  */
+  struct Phdr_info phdr_info;
   /* Used for version scripts and within VERSION {}.  */
   struct Version_dependency_list* deplist;
   struct Version_expression_list* versyms;
 %token PARSING_LINKER_SCRIPT
 %token PARSING_VERSION_SCRIPT
 %token PARSING_DEFSYM
+%token PARSING_DYNAMIC_LIST
 
 /* Non-terminal types, where needed.  */
 
 %type <expr> opt_at opt_align opt_subalign opt_fill
 %type <output_section_header> section_header
 %type <output_section_trailer> section_trailer
+%type <constraint> opt_constraint
+%type <string_list> opt_phdr
 %type <integer> data_length
 %type <input_section_spec> input_section_no_keep
 %type <wildcard_sections> wildcard_sections
 %type <wildcard_section> wildcard_file wildcard_section
 %type <string_list> exclude_names
 %type <string> wildcard_name
+%type <integer> phdr_type
+%type <phdr_info> phdr_info
 %type <versyms> vers_defns
 %type <versnode> vers_tag
 %type <deplist> verdep
@@ -213,6 +223,7 @@ top:
          PARSING_LINKER_SCRIPT linker_script
        | PARSING_VERSION_SCRIPT version_script
        | PARSING_DEFSYM defsym_expr
+        | PARSING_DYNAMIC_LIST dynamic_list_expr
        ;
 
 /* A file contains a list of commands.  */
@@ -223,12 +234,20 @@ linker_script:
 
 /* A command which may appear at top level of a linker script.  */
 file_cmd:
-         GROUP
+         FORCE_COMMON_ALLOCATION
+           { script_set_common_allocation(closure, 1); }
+       | GROUP
            { script_start_group(closure); }
          '(' input_list ')'
            { script_end_group(closure); }
+       | INHIBIT_COMMON_ALLOCATION
+           { script_set_common_allocation(closure, 0); }
+       | INPUT '(' input_list ')'
         | OPTION '(' string ')'
            { script_parse_option(closure, $3.value, $3.length); }
+       | PHDRS '{' phdrs_defs '}'
+       | SEARCH_DIR '(' string ')'
+           { script_add_search_dir(closure, $3.value, $3.length); }
        | SECTIONS '{'
            { script_start_sections(closure); }
          sections_block '}'
@@ -239,6 +258,7 @@ file_cmd:
             { script_pop_lex_mode(closure); }
        | file_or_sections_cmd
        | ignore_cmd
+       | ';'
        ;
 
 /* Top level commands which we ignore.  The GNU linker uses these to
@@ -287,12 +307,14 @@ section_block_cmd:
 section_header:
            { script_push_lex_into_expression_mode(closure); }
          opt_address_and_section_type opt_at opt_align opt_subalign
+           { script_pop_lex_mode(closure); }
+         opt_constraint
            {
              $$.address = $2;
              $$.load_address = $3;
              $$.align = $4;
              $$.subalign = $5;
-             script_pop_lex_mode(closure);
+             $$.constraint = $7;
            }
        ;
 
@@ -340,13 +362,24 @@ opt_subalign:
            { $$ = $3; }
        ;
 
+/* A section constraint.  */
+opt_constraint:
+         /* empty */
+           { $$ = CONSTRAINT_NONE; }
+       | ONLY_IF_RO
+           { $$ = CONSTRAINT_ONLY_IF_RO; }
+       | ONLY_IF_RW
+           { $$ = CONSTRAINT_ONLY_IF_RW; }
+       | SPECIAL
+           { $$ = CONSTRAINT_SPECIAL; }
+       ;
+
 /* The trailer of an output section in a SECTIONS block.  */
 section_trailer:
-           { script_push_lex_into_expression_mode(closure); }
          opt_memspec opt_at_memspec opt_phdr opt_fill opt_comma
            {
-             $$.fill = $5;
-             script_pop_lex_mode(closure);
+             $$.fill = $4;
+             $$.phdrs = $3;
            }
        ;
 
@@ -367,13 +400,15 @@ opt_at_memspec:
 /* The program segment an output section should go into.  */
 opt_phdr:
          opt_phdr ':' string
-           { yyerror(closure, "program headers are not supported"); }
+           { $$ = script_string_list_push_back($1, $3.value, $3.length); }
        | /* empty */
+           { $$ = NULL; }
        ;
 
-/* The value to use to fill an output section.  */
+/* The value to use to fill an output section.  FIXME: This does not
+   handle a string of arbitrary length.  */
 opt_fill:
-         '=' exp
+         '=' parse_exp
            { $$ = $2; }
        | /* empty */
            { $$ = NULL; }
@@ -404,6 +439,7 @@ section_cmd:
                 some ELF linker scripts use it although it does
                 nothing, we accept it and ignore it.  */
            }
+       | SORT_BY_NAME '(' CONSTRUCTORS ')'
        | ';'
        ;
 
@@ -567,6 +603,64 @@ file_or_sections_cmd:
            { script_add_assertion(closure, $3, $5.value, $5.length); }
        ;
 
+/* A list of program header definitions.  */
+phdrs_defs:
+         phdrs_defs phdr_def
+       | /* empty */
+       ;
+
+/* A program header definition.  */
+phdr_def:
+         string phdr_type phdr_info ';'
+           { script_add_phdr(closure, $1.value, $1.length, $2, &$3); }
+       ;
+
+/* A program header type.  The GNU linker accepts a general expression
+   here, but that would be a pain because we would have to dig into
+   the expression structure.  It's unlikely that anybody uses anything
+   other than a string or a number here, so that is all we expect.  */
+phdr_type:
+         string
+           { $$ = script_phdr_string_to_type(closure, $1.value, $1.length); }
+       | INTEGER
+           { $$ = $1; }
+       ;
+
+/* Additional information for a program header.  */
+phdr_info:
+         /* empty */
+           { memset(&$$, 0, sizeof(struct Phdr_info)); }
+       | string phdr_info
+           {
+             $$ = $2;
+             if ($1.length == 7 && strncmp($1.value, "FILEHDR", 7) == 0)
+               $$.includes_filehdr = 1;
+             else
+               yyerror(closure, "PHDRS syntax error");
+           }
+       | PHDRS phdr_info
+           {
+             $$ = $2;
+             $$.includes_phdrs = 1;
+           }
+       | string '(' INTEGER ')' phdr_info
+           {
+             $$ = $5;
+             if ($1.length == 5 && strncmp($1.value, "FLAGS", 5) == 0)
+               {
+                 $$.is_flags_valid = 1;
+                 $$.flags = $3;
+               }
+             else
+               yyerror(closure, "PHDRS syntax error");
+           }
+       | AT '(' parse_exp ')' phdr_info
+           {
+             $$ = $5;
+             $$.load_address = $3;
+           }
+       ;
+
 /* Set a symbol to a value.  */
 assignment:
          string '=' parse_exp
@@ -720,9 +814,15 @@ exp:
        | BLOCK '(' exp ')'
            { $$ = script_exp_function_align(script_exp_string(".", 1), $3); }
        | DATA_SEGMENT_ALIGN '(' exp ',' exp ')'
-           { $$ = script_exp_function_data_segment_align($3, $5); }
+           {
+             script_data_segment_align(closure);
+             $$ = script_exp_function_data_segment_align($3, $5);
+           }
        | DATA_SEGMENT_RELRO_END '(' exp ',' exp ')'
-           { $$ = script_exp_function_data_segment_relro_end($3, $5); }
+           {
+             script_data_segment_relro_end(closure);
+             $$ = script_exp_function_data_segment_relro_end($3, $5);
+           }
        | DATA_SEGMENT_END '(' exp ')'
            { $$ = script_exp_function_data_segment_end($3); }
        | SEGMENT_START '(' string ',' exp ')'
@@ -739,6 +839,24 @@ defsym_expr:
            { script_set_symbol(closure, $1.value, $1.length, $3, 0, 0); }
        ;
 
+/* Handle the --dynamic-list option.  A dynamic list has the format
+   { sym1; sym2; extern "C++" { namespace::sym3 }; };
+   We store the symbol we see in the "local" list; that is where
+   Command_line::in_dynamic_list() will look to do its check.
+   TODO(csilvers): More than one of these brace-lists can appear, and
+   should just be merged and treated as a single list.  */
+dynamic_list_expr: dynamic_list_nodes ;
+
+dynamic_list_nodes:
+         dynamic_list_node
+       | dynamic_list_nodes dynamic_list_node
+        ;
+
+dynamic_list_node:
+          '{' vers_defns ';' '}' ';'
+            { script_new_vers_node (closure, NULL, $2); }
+        ;
+
 /* A version script.  */
 version_script:
          vers_nodes
This page took 0.026399 seconds and 4 git commands to generate.