From e5756efb6d46f569d2e99d19f726b32b84f58bd7 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Wed, 9 Jan 2008 19:57:45 +0000 Subject: Support assignments and expressions in linker scripts. --- gold/yyscript.y | 228 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 220 insertions(+), 8 deletions(-) (limited to 'gold/yyscript.y') 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 . 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 @@ -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 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. */ -- cgit v1.1