-/* 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>.
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
+#include <string.h>
#include "script-c.h"
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. */
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
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. */
/* 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 '}'
{ script_pop_lex_mode(closure); }
| file_or_sections_cmd
| ignore_cmd
+ | ';'
;
/* Top level commands which we ignore. The GNU linker uses these to
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;
}
;
{ $$ = $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;
}
;
/* 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; }
some ELF linker scripts use it although it does
nothing, we accept it and ignore it. */
}
+ | SORT_BY_NAME '(' CONSTRUCTORS ')'
| ';'
;
{ 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
| 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 ')'
{ 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