aboutsummaryrefslogtreecommitdiff
path: root/gold/yyscript.y
diff options
context:
space:
mode:
authorIan Lance Taylor <iant@google.com>2008-01-09 19:57:45 +0000
committerIan Lance Taylor <iant@google.com>2008-01-09 19:57:45 +0000
commite5756efb6d46f569d2e99d19f726b32b84f58bd7 (patch)
tree953c35bf025a640d99bccbd4acbce67dc8b677b5 /gold/yyscript.y
parentcda30489fc0f7870150158863780d67f5efedd90 (diff)
downloadgdb-e5756efb6d46f569d2e99d19f726b32b84f58bd7.zip
gdb-e5756efb6d46f569d2e99d19f726b32b84f58bd7.tar.gz
gdb-e5756efb6d46f569d2e99d19f726b32b84f58bd7.tar.bz2
Support assignments and expressions in linker scripts.
Diffstat (limited to 'gold/yyscript.y')
-rw-r--r--gold/yyscript.y228
1 files changed, 220 insertions, 8 deletions
diff --git a/gold/yyscript.y b/gold/yyscript.y
index 513241b..a1f954c 100644
--- a/gold/yyscript.y
+++ b/gold/yyscript.y
@@ -1,6 +1,6 @@
/* yyscript.y -- linker script grammer for gold. */
-/* Copyright 2006, 2007 Free Software Foundation, Inc.
+/* Copyright 2006, 2007, 2008 Free Software Foundation, Inc.
Written by Ian Lance Taylor <iant@google.com>.
This file is part of gold.
@@ -49,8 +49,12 @@
/* The values associated with tokens. */
%union {
- const char* string;
- int64_t integer;
+ /* A string. */
+ struct Parser_string string;
+ /* A number. */
+ uint64_t integer;
+ /* An expression. */
+ Expression_ptr expr;
}
/* Operators, including a precedence table for expressions. */
@@ -68,6 +72,9 @@
%left '+' '-'
%left '*' '/' '%'
+/* A fake operator used to indicate unary operator precedence. */
+%right UNARY
+
/* Constants. */
%token <string> STRING
@@ -82,6 +89,7 @@
%token ABSOLUTE
%token ADDR
%token ALIGN_K /* ALIGN */
+%token ALIGNOF
%token ASSERT_K /* ASSERT */
%token AS_NEEDED
%token AT
@@ -158,11 +166,31 @@
%token OPTION
+/* Special tokens used to tell the grammar what type of tokens we are
+ parsing. The token stream always begins with one of these tokens.
+ We do this because version scripts can appear embedded within
+ linker scripts, and because --defsym uses the expression
+ parser. */
+%token PARSING_LINKER_SCRIPT
+%token PARSING_VERSION_SCRIPT
+%token PARSING_DEFSYM
+
+/* Non-terminal types, where needed. */
+
+%type <expr> parse_exp exp
+
%%
+/* Read the special token to see what to read next. */
+top:
+ PARSING_LINKER_SCRIPT linker_script
+ | PARSING_VERSION_SCRIPT version_script
+ | PARSING_DEFSYM defsym_expr
+ ;
+
/* A file contains a list of commands. */
-file_list:
- file_list file_cmd
+linker_script:
+ linker_script file_cmd
| /* empty */
;
@@ -173,7 +201,7 @@ file_cmd:
'(' input_list ')'
{ script_end_group(closure); }
| OPTION '(' STRING ')'
- { script_parse_option(closure, $3); }
+ { script_parse_option(closure, $3.value, $3.length); }
| file_or_sections_cmd
| ignore_cmd
;
@@ -197,7 +225,7 @@ input_list:
/* An input file name. */
input_list_element:
STRING
- { script_add_file(closure, $1); }
+ { script_add_file(closure, $1.value, $1.length); }
| AS_NEEDED
{ script_start_as_needed(closure); }
'(' input_list ')'
@@ -208,7 +236,191 @@ input_list_element:
within a SECTIONS block. */
file_or_sections_cmd:
ENTRY '(' STRING ')'
- { script_set_entry(closure, $3); }
+ { script_set_entry(closure, $3.value, $3.length); }
+ | assignment end
+ ;
+
+/* Set a symbol to a value. */
+assignment:
+ STRING '=' parse_exp
+ { script_set_symbol(closure, $1.value, $1.length, $3, 0, 0); }
+ | STRING PLUSEQ parse_exp
+ {
+ Expression_ptr s = script_exp_string($1.value, $1.length);
+ Expression_ptr e = script_exp_binary_add(s, $3);
+ script_set_symbol(closure, $1.value, $1.length, e, 0, 0);
+ }
+ | STRING MINUSEQ parse_exp
+ {
+ Expression_ptr s = script_exp_string($1.value, $1.length);
+ Expression_ptr e = script_exp_binary_sub(s, $3);
+ script_set_symbol(closure, $1.value, $1.length, e, 0, 0);
+ }
+ | STRING MULTEQ parse_exp
+ {
+ Expression_ptr s = script_exp_string($1.value, $1.length);
+ Expression_ptr e = script_exp_binary_mult(s, $3);
+ script_set_symbol(closure, $1.value, $1.length, e, 0, 0);
+ }
+ | STRING DIVEQ parse_exp
+ {
+ Expression_ptr s = script_exp_string($1.value, $1.length);
+ Expression_ptr e = script_exp_binary_div(s, $3);
+ script_set_symbol(closure, $1.value, $1.length, e, 0, 0);
+ }
+ | STRING LSHIFTEQ parse_exp
+ {
+ Expression_ptr s = script_exp_string($1.value, $1.length);
+ Expression_ptr e = script_exp_binary_lshift(s, $3);
+ script_set_symbol(closure, $1.value, $1.length, e, 0, 0);
+ }
+ | STRING RSHIFTEQ parse_exp
+ {
+ Expression_ptr s = script_exp_string($1.value, $1.length);
+ Expression_ptr e = script_exp_binary_rshift(s, $3);
+ script_set_symbol(closure, $1.value, $1.length, e, 0, 0);
+ }
+ | STRING ANDEQ parse_exp
+ {
+ Expression_ptr s = script_exp_string($1.value, $1.length);
+ Expression_ptr e = script_exp_binary_bitwise_and(s, $3);
+ script_set_symbol(closure, $1.value, $1.length, e, 0, 0);
+ }
+ | STRING OREQ parse_exp
+ {
+ Expression_ptr s = script_exp_string($1.value, $1.length);
+ Expression_ptr e = script_exp_binary_bitwise_or(s, $3);
+ script_set_symbol(closure, $1.value, $1.length, e, 0, 0);
+ }
+ | PROVIDE '(' STRING '=' parse_exp ')'
+ { script_set_symbol(closure, $3.value, $3.length, $5, 1, 0); }
+ | PROVIDE_HIDDEN '(' STRING '=' parse_exp ')'
+ { script_set_symbol(closure, $3.value, $3.length, $5, 1, 1); }
+ ;
+
+/* Parse an expression, putting the lexer into the right mode. */
+parse_exp:
+ { script_push_lex_into_expression_mode(closure); }
+ exp
+ {
+ script_pop_lex_mode(closure);
+ $$ = $2;
+ }
+ ;
+
+/* An expression. */
+exp:
+ '(' exp ')'
+ { $$ = $2; }
+ | '-' exp %prec UNARY
+ { $$ = script_exp_unary_minus($2); }
+ | '!' exp %prec UNARY
+ { $$ = script_exp_unary_logical_not($2); }
+ | '~' exp %prec UNARY
+ { $$ = script_exp_unary_bitwise_not($2); }
+ | '+' exp %prec UNARY
+ { $$ = $2; }
+ | exp '*' exp
+ { $$ = script_exp_binary_mult($1, $3); }
+ | exp '/' exp
+ { $$ = script_exp_binary_div($1, $3); }
+ | exp '%' exp
+ { $$ = script_exp_binary_mod($1, $3); }
+ | exp '+' exp
+ { $$ = script_exp_binary_add($1, $3); }
+ | exp '-' exp
+ { $$ = script_exp_binary_sub($1, $3); }
+ | exp LSHIFT exp
+ { $$ = script_exp_binary_lshift($1, $3); }
+ | exp RSHIFT exp
+ { $$ = script_exp_binary_rshift($1, $3); }
+ | exp EQ exp
+ { $$ = script_exp_binary_eq($1, $3); }
+ | exp NE exp
+ { $$ = script_exp_binary_ne($1, $3); }
+ | exp LE exp
+ { $$ = script_exp_binary_le($1, $3); }
+ | exp GE exp
+ { $$ = script_exp_binary_ge($1, $3); }
+ | exp '<' exp
+ { $$ = script_exp_binary_lt($1, $3); }
+ | exp '>' exp
+ { $$ = script_exp_binary_gt($1, $3); }
+ | exp '&' exp
+ { $$ = script_exp_binary_bitwise_and($1, $3); }
+ | exp '^' exp
+ { $$ = script_exp_binary_bitwise_xor($1, $3); }
+ | exp '|' exp
+ { $$ = script_exp_binary_bitwise_or($1, $3); }
+ | exp ANDAND exp
+ { $$ = script_exp_binary_logical_and($1, $3); }
+ | exp OROR exp
+ { $$ = script_exp_binary_logical_or($1, $3); }
+ | exp '?' exp ':' exp
+ { $$ = script_exp_trinary_cond($1, $3, $5); }
+ | INTEGER
+ { $$ = script_exp_integer($1); }
+ | STRING
+ { $$ = script_exp_string($1.value, $1.length); }
+ | MAX_K '(' exp ',' exp ')'
+ { $$ = script_exp_function_max($3, $5); }
+ | MIN_K '(' exp ',' exp ')'
+ { $$ = script_exp_function_min($3, $5); }
+ | DEFINED '(' STRING ')'
+ { $$ = script_exp_function_defined($3.value, $3.length); }
+ | SIZEOF_HEADERS
+ { $$ = script_exp_function_sizeof_headers(); }
+ | ALIGNOF '(' STRING ')'
+ { $$ = script_exp_function_alignof($3.value, $3.length); }
+ | SIZEOF '(' STRING ')'
+ { $$ = script_exp_function_sizeof($3.value, $3.length); }
+ | ADDR '(' STRING ')'
+ { $$ = script_exp_function_addr($3.value, $3.length); }
+ | LOADADDR '(' STRING ')'
+ { $$ = script_exp_function_loadaddr($3.value, $3.length); }
+ | ORIGIN '(' STRING ')'
+ { $$ = script_exp_function_origin($3.value, $3.length); }
+ | LENGTH '(' STRING ')'
+ { $$ = script_exp_function_length($3.value, $3.length); }
+ | CONSTANT '(' STRING ')'
+ { $$ = script_exp_function_constant($3.value, $3.length); }
+ | ABSOLUTE '(' exp ')'
+ { $$ = script_exp_function_absolute($3); }
+ | ALIGN_K '(' exp ')'
+ { $$ = script_exp_function_align(script_exp_string(".", 1), $3); }
+ | ALIGN_K '(' exp ',' exp ')'
+ { $$ = script_exp_function_align($3, $5); }
+ | BLOCK '(' exp ')'
+ { $$ = script_exp_function_align(script_exp_string(".", 1), $3); }
+ | DATA_SEGMENT_ALIGN '(' exp ',' exp ')'
+ { $$ = script_exp_function_data_segment_align($3, $5); }
+ | DATA_SEGMENT_RELRO_END '(' exp ',' exp ')'
+ { $$ = 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_exp_function_segment_start($3.value, $3.length, $5);
+ }
+ | ASSERT_K '(' exp ',' STRING ')'
+ { $$ = script_exp_function_assert($3, $5.value, $5.length); }
+ ;
+
+/* Handle the --defsym option. */
+defsym_expr:
+ STRING '=' parse_exp
+ { script_set_symbol(closure, $1.value, $1.length, $3, 0, 0); }
+ ;
+
+/* A version script. Not yet implemented. */
+version_script:
+ ;
+
+/* Some statements require a terminator, which may be a semicolon or a
+ comma. */
+end:
+ ';'
+ | ','
;
/* An optional comma. */