123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143 |
- /* yyscript.y -- linker script grammar for gold. */
- /* Copyright (C) 2006-2015 Free Software Foundation, Inc.
- Written by Ian Lance Taylor <iant@google.com>.
- This file is part of gold.
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
- MA 02110-1301, USA. */
- /* This is a bison grammar to parse a subset of the original GNU ld
- linker script language. */
- %{
- #include "config.h"
- #include <stddef.h>
- #include <stdint.h>
- #include <stdlib.h>
- #include <string.h>
- #include "script-c.h"
- %}
- /* We need to use a pure parser because we might be multi-threaded.
- We pass some arguments through the parser to the lexer. */
- %pure-parser
- %parse-param {void* closure}
- %lex-param {void* closure}
- /* Since we require bison anyhow, we take advantage of it. */
- %error-verbose
- /* The values associated with tokens. */
- %union {
- /* A string. */
- struct Parser_string string;
- /* A number. */
- uint64_t integer;
- /* An expression. */
- Expression_ptr expr;
- /* An output section header. */
- 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_sections wildcard_sections;
- /* A single wildcard specification. */
- 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;
- struct Version_tree* versnode;
- enum Script_section_type section_type;
- }
- /* Operators, including a precedence table for expressions. */
- %right PLUSEQ MINUSEQ MULTEQ DIVEQ '=' LSHIFTEQ RSHIFTEQ ANDEQ OREQ
- %right '?' ':'
- %left OROR
- %left ANDAND
- %left '|'
- %left '^'
- %left '&'
- %left EQ NE
- %left '<' '>' LE GE
- %left LSHIFT RSHIFT
- %left '+' '-'
- %left '*' '/' '%'
- /* A fake operator used to indicate unary operator precedence. */
- %right UNARY
- /* Constants. */
- %token <string> STRING
- %token <string> QUOTED_STRING
- %token <integer> INTEGER
- /* Keywords. This list is taken from ldgram.y and ldlex.l in the old
- GNU linker, with the keywords which only appear in MRI mode
- removed. Not all these keywords are actually used in this grammar.
- In most cases the keyword is recognized as the token name in upper
- case. The comments indicate where this is not the case. */
- %token ABSOLUTE
- %token ADDR
- %token ALIGN_K /* ALIGN */
- %token ALIGNOF
- %token ASSERT_K /* ASSERT */
- %token AS_NEEDED
- %token AT
- %token BIND
- %token BLOCK
- %token BYTE
- %token CONSTANT
- %token CONSTRUCTORS
- %token COPY
- %token CREATE_OBJECT_SYMBOLS
- %token DATA_SEGMENT_ALIGN
- %token DATA_SEGMENT_END
- %token DATA_SEGMENT_RELRO_END
- %token DEFINED
- %token DSECT
- %token ENTRY
- %token EXCLUDE_FILE
- %token EXTERN
- %token FILL
- %token FLOAT
- %token FORCE_COMMON_ALLOCATION
- %token GLOBAL /* global */
- %token GROUP
- %token HLL
- %token INCLUDE
- %token INHIBIT_COMMON_ALLOCATION
- %token INFO
- %token INPUT
- %token KEEP
- %token LEN
- %token LENGTH /* LENGTH, l, len */
- %token LOADADDR
- %token LOCAL /* local */
- %token LONG
- %token MAP
- %token MAX_K /* MAX */
- %token MEMORY
- %token MIN_K /* MIN */
- %token NEXT
- %token NOCROSSREFS
- %token NOFLOAT
- %token NOLOAD
- %token ONLY_IF_RO
- %token ONLY_IF_RW
- %token ORG
- %token ORIGIN /* ORIGIN, o, org */
- %token OUTPUT
- %token OUTPUT_ARCH
- %token OUTPUT_FORMAT
- %token OVERLAY
- %token PHDRS
- %token PROVIDE
- %token PROVIDE_HIDDEN
- %token QUAD
- %token SEARCH_DIR
- %token SECTIONS
- %token SEGMENT_START
- %token SHORT
- %token SIZEOF
- %token SIZEOF_HEADERS /* SIZEOF_HEADERS, sizeof_headers */
- %token SORT_BY_ALIGNMENT
- %token SORT_BY_NAME
- %token SPECIAL
- %token SQUAD
- %token STARTUP
- %token SUBALIGN
- %token SYSLIB
- %token TARGET_K /* TARGET */
- %token TRUNCATE
- %token VERSIONK /* VERSION */
- /* Keywords, part 2. These are keywords that are unique to gold,
- and not present in the old GNU linker. As before, unless the
- comments say otherwise, the keyword is recognized as the token
- name in upper case. */
- %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
- %token PARSING_DYNAMIC_LIST
- %token PARSING_SECTIONS_BLOCK
- %token PARSING_SECTION_COMMANDS
- %token PARSING_MEMORY_DEF
- /* Non-terminal types, where needed. */
- %type <expr> parse_exp exp
- %type <expr> opt_at opt_align opt_subalign opt_fill
- %type <output_section_header> section_header opt_address_and_section_type
- %type <section_type> section_type
- %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 memory_attr
- %type <phdr_info> phdr_info
- %type <versyms> vers_defns
- %type <versnode> vers_tag
- %type <deplist> verdep
- %type <string> string
- %%
- /* 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
- | PARSING_DYNAMIC_LIST dynamic_list_expr
- | PARSING_SECTIONS_BLOCK sections_block
- | PARSING_SECTION_COMMANDS section_cmds
- | PARSING_MEMORY_DEF memory_defs
- ;
- /* A file contains a list of commands. */
- linker_script:
- linker_script file_cmd
- | /* empty */
- ;
- /* A command which may appear at top level of a linker script. */
- file_cmd:
- EXTERN '(' extern_name_list ')'
- | 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 ')'
- | MEMORY '{' memory_defs '}'
- | OPTION '(' string ')'
- { script_parse_option(closure, $3.value, $3.length); }
- | OUTPUT_FORMAT '(' string ')'
- {
- if (!script_check_output_format(closure, $3.value, $3.length,
- NULL, 0, NULL, 0))
- YYABORT;
- }
- | OUTPUT_FORMAT '(' string ',' string ',' string ')'
- {
- if (!script_check_output_format(closure, $3.value, $3.length,
- $5.value, $5.length,
- $7.value, $7.length))
- YYABORT;
- }
- | PHDRS '{' phdrs_defs '}'
- | SEARCH_DIR '(' string ')'
- { script_add_search_dir(closure, $3.value, $3.length); }
- | SECTIONS '{'
- { script_start_sections(closure); }
- sections_block '}'
- { script_finish_sections(closure); }
- | TARGET_K '(' string ')'
- { script_set_target(closure, $3.value, $3.length); }
- | VERSIONK '{'
- { script_push_lex_into_version_mode(closure); }
- version_script '}'
- { script_pop_lex_mode(closure); }
- | ENTRY '(' string ')'
- { script_set_entry(closure, $3.value, $3.length); }
- | assignment end
- | ASSERT_K '(' parse_exp ',' string ')'
- { script_add_assertion(closure, $3, $5.value, $5.length); }
- | INCLUDE string
- { script_include_directive(PARSING_LINKER_SCRIPT, closure,
- $2.value, $2.length); }
- | ignore_cmd
- | ';'
- ;
- /* Top level commands which we ignore. The GNU linker uses these to
- select the output format, but we don't offer a choice. Ignoring
- these is more-or-less OK since most scripts simply explicitly
- choose the default. */
- ignore_cmd:
- OUTPUT_ARCH '(' string ')'
- ;
- /* A list of external undefined symbols. We put the lexer into
- expression mode so that commas separate names; this is what the GNU
- linker does. */
- extern_name_list:
- { script_push_lex_into_expression_mode(closure); }
- extern_name_list_body
- { script_pop_lex_mode(closure); }
- ;
- extern_name_list_body:
- string
- { script_add_extern(closure, $1.value, $1.length); }
- | extern_name_list_body string
- { script_add_extern(closure, $2.value, $2.length); }
- | extern_name_list_body ',' string
- { script_add_extern(closure, $3.value, $3.length); }
- ;
- /* A list of input file names. */
- input_list:
- input_list_element
- | input_list opt_comma input_list_element
- ;
- /* An input file name. */
- input_list_element:
- string
- { script_add_file(closure, $1.value, $1.length); }
- | '-' STRING
- { script_add_library(closure, $2.value, $2.length); }
- | AS_NEEDED
- { script_start_as_needed(closure); }
- '(' input_list ')'
- { script_end_as_needed(closure); }
- ;
- /* Commands in a SECTIONS block. */
- sections_block:
- sections_block section_block_cmd
- | /* empty */
- ;
- /* A command which may appear within a SECTIONS block. */
- section_block_cmd:
- ENTRY '(' string ')'
- { script_set_entry(closure, $3.value, $3.length); }
- | assignment end
- | ASSERT_K '(' parse_exp ',' string ')'
- { script_add_assertion(closure, $3, $5.value, $5.length); }
- | INCLUDE string
- { script_include_directive(PARSING_SECTIONS_BLOCK, closure,
- $2.value, $2.length); }
- | string section_header
- { script_start_output_section(closure, $1.value, $1.length, &$2); }
- '{' section_cmds '}' section_trailer
- { script_finish_output_section(closure, &$7); }
- ;
- /* The header of an output section in a SECTIONS block--everything
- after the name. */
- 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.address;
- $$.section_type = $2.section_type;
- $$.load_address = $3;
- $$.align = $4;
- $$.subalign = $5;
- $$.constraint = $7;
- }
- ;
- /* The optional address followed by the optional section type. This
- is a separate nonterminal to avoid a shift/reduce conflict on
- '(' in section_header. */
- opt_address_and_section_type:
- ':'
- {
- $$.address = NULL;
- $$.section_type = SCRIPT_SECTION_TYPE_NONE;
- }
- | '(' ')' ':'
- {
- $$.address = NULL;
- $$.section_type = SCRIPT_SECTION_TYPE_NONE;
- }
- | exp ':'
- {
- $$.address = $1;
- $$.section_type = SCRIPT_SECTION_TYPE_NONE;
- }
- | exp '(' ')' ':'
- {
- $$.address = $1;
- $$.section_type = SCRIPT_SECTION_TYPE_NONE;
- }
- | '(' section_type ')' ':'
- {
- $$.address = NULL;
- $$.section_type = $2;
- }
- | exp '(' section_type ')' ':'
- {
- $$.address = $1;
- $$.section_type = $3;
- }
- ;
- /* We only support NOLOAD. */
- section_type:
- NOLOAD
- { $$ = SCRIPT_SECTION_TYPE_NOLOAD; }
- | DSECT
- {
- yyerror(closure, "DSECT section type is unsupported");
- $$ = SCRIPT_SECTION_TYPE_DSECT;
- }
- | COPY
- {
- yyerror(closure, "COPY section type is unsupported");
- $$ = SCRIPT_SECTION_TYPE_COPY;
- }
- | INFO
- {
- yyerror(closure, "INFO section type is unsupported");
- $$ = SCRIPT_SECTION_TYPE_INFO;
- }
- | OVERLAY
- {
- yyerror(closure, "OVERLAY section type is unsupported");
- $$ = SCRIPT_SECTION_TYPE_OVERLAY;
- }
- ;
- /* The address at which an output section should be loaded. */
- opt_at:
- /* empty */
- { $$ = NULL; }
- | AT '(' exp ')'
- { $$ = $3; }
- ;
- /* The alignment of an output section. */
- opt_align:
- /* empty */
- { $$ = NULL; }
- | ALIGN_K '(' exp ')'
- { $$ = $3; }
- ;
- /* The input section alignment within an output section. */
- opt_subalign:
- /* empty */
- { $$ = NULL; }
- | SUBALIGN '(' exp ')'
- { $$ = $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:
- opt_memspec opt_at_memspec opt_phdr opt_fill opt_comma
- {
- $$.fill = $4;
- $$.phdrs = $3;
- }
- ;
- /* A memory specification for an output section. */
- opt_memspec:
- '>' string
- { script_set_section_region(closure, $2.value, $2.length, 1); }
- | /* empty */
- ;
- /* A memory specification for where to load an output section. */
- opt_at_memspec:
- AT '>' string
- { script_set_section_region(closure, $3.value, $3.length, 0); }
- | /* empty */
- ;
- /* The program segment an output section should go into. */
- opt_phdr:
- opt_phdr ':' string
- { $$ = script_string_list_push_back($1, $3.value, $3.length); }
- | /* empty */
- { $$ = NULL; }
- ;
- /* The value to use to fill an output section. FIXME: This does not
- handle a string of arbitrary length. */
- opt_fill:
- '=' parse_exp
- { $$ = $2; }
- | /* empty */
- { $$ = NULL; }
- ;
- /* Commands which may appear within the description of an output
- section in a SECTIONS block. */
- section_cmds:
- /* empty */
- | section_cmds section_cmd
- ;
- /* A command which may appear within the description of an output
- section in a SECTIONS block. */
- section_cmd:
- assignment end
- | input_section_spec
- | data_length '(' parse_exp ')'
- { script_add_data(closure, $1, $3); }
- | ASSERT_K '(' parse_exp ',' string ')'
- { script_add_assertion(closure, $3, $5.value, $5.length); }
- | FILL '(' parse_exp ')'
- { script_add_fill(closure, $3); }
- | CONSTRUCTORS
- {
- /* The GNU linker uses CONSTRUCTORS for the a.out object
- file format. It does nothing when using ELF. Since
- some ELF linker scripts use it although it does
- nothing, we accept it and ignore it. */
- }
- | SORT_BY_NAME '(' CONSTRUCTORS ')'
- | INCLUDE string
- { script_include_directive(PARSING_SECTION_COMMANDS, closure,
- $2.value, $2.length); }
- | ';'
- ;
- /* The length of data which may appear within the description of an
- output section in a SECTIONS block. */
- data_length:
- QUAD
- { $$ = QUAD; }
- | SQUAD
- { $$ = SQUAD; }
- | LONG
- { $$ = LONG; }
- | SHORT
- { $$ = SHORT; }
- | BYTE
- { $$ = BYTE; }
- ;
- /* An input section specification. This may appear within the
- description of an output section in a SECTIONS block. */
- input_section_spec:
- input_section_no_keep
- { script_add_input_section(closure, &$1, 0); }
- | KEEP '(' input_section_no_keep ')'
- { script_add_input_section(closure, &$3, 1); }
- ;
- /* An input section specification within a KEEP clause. */
- input_section_no_keep:
- string
- {
- $$.file.name = $1;
- $$.file.sort = SORT_WILDCARD_NONE;
- $$.input_sections.sections = NULL;
- $$.input_sections.exclude = NULL;
- }
- | wildcard_file '(' wildcard_sections ')'
- {
- $$.file = $1;
- $$.input_sections = $3;
- }
- ;
- /* A wildcard file specification. */
- wildcard_file:
- wildcard_name
- {
- $$.name = $1;
- $$.sort = SORT_WILDCARD_NONE;
- }
- | SORT_BY_NAME '(' wildcard_name ')'
- {
- $$.name = $3;
- $$.sort = SORT_WILDCARD_BY_NAME;
- }
- ;
- /* A list of wild card section specifications. */
- wildcard_sections:
- wildcard_sections opt_comma wildcard_section
- {
- $$.sections = script_string_sort_list_add($1.sections, &$3);
- $$.exclude = $1.exclude;
- }
- | wildcard_section
- {
- $$.sections = script_new_string_sort_list(&$1);
- $$.exclude = NULL;
- }
- | wildcard_sections opt_comma EXCLUDE_FILE '(' exclude_names ')'
- {
- $$.sections = $1.sections;
- $$.exclude = script_string_list_append($1.exclude, $5);
- }
- | EXCLUDE_FILE '(' exclude_names ')'
- {
- $$.sections = NULL;
- $$.exclude = $3;
- }
- ;
- /* A single wild card specification. */
- wildcard_section:
- wildcard_name
- {
- $$.name = $1;
- $$.sort = SORT_WILDCARD_NONE;
- }
- | SORT_BY_NAME '(' wildcard_section ')'
- {
- $$.name = $3.name;
- switch ($3.sort)
- {
- case SORT_WILDCARD_NONE:
- $$.sort = SORT_WILDCARD_BY_NAME;
- break;
- case SORT_WILDCARD_BY_NAME:
- case SORT_WILDCARD_BY_NAME_BY_ALIGNMENT:
- break;
- case SORT_WILDCARD_BY_ALIGNMENT:
- case SORT_WILDCARD_BY_ALIGNMENT_BY_NAME:
- $$.sort = SORT_WILDCARD_BY_NAME_BY_ALIGNMENT;
- break;
- default:
- abort();
- }
- }
- | SORT_BY_ALIGNMENT '(' wildcard_section ')'
- {
- $$.name = $3.name;
- switch ($3.sort)
- {
- case SORT_WILDCARD_NONE:
- $$.sort = SORT_WILDCARD_BY_ALIGNMENT;
- break;
- case SORT_WILDCARD_BY_ALIGNMENT:
- case SORT_WILDCARD_BY_ALIGNMENT_BY_NAME:
- break;
- case SORT_WILDCARD_BY_NAME:
- case SORT_WILDCARD_BY_NAME_BY_ALIGNMENT:
- $$.sort = SORT_WILDCARD_BY_ALIGNMENT_BY_NAME;
- break;
- default:
- abort();
- }
- }
- ;
- /* A list of file names to exclude. */
- exclude_names:
- exclude_names opt_comma wildcard_name
- { $$ = script_string_list_push_back($1, $3.value, $3.length); }
- | wildcard_name
- { $$ = script_new_string_list($1.value, $1.length); }
- ;
- /* A single wildcard name. We recognize '*' and '?' specially since
- they are expression tokens. */
- wildcard_name:
- string
- { $$ = $1; }
- | '*'
- {
- $$.value = "*";
- $$.length = 1;
- }
- | '?'
- {
- $$.value = "?";
- $$.length = 1;
- }
- ;
- /* A list of MEMORY definitions. */
- memory_defs:
- memory_defs opt_comma memory_def
- | /* empty */
- ;
- /* A single MEMORY definition. */
- memory_def:
- string memory_attr ':' memory_origin '=' parse_exp opt_comma memory_length '=' parse_exp
- { script_add_memory(closure, $1.value, $1.length, $2, $6, $10); }
- |
- INCLUDE string
- { script_include_directive(PARSING_MEMORY_DEF, closure,
- $2.value, $2.length); }
- |
- ;
- /* The (optional) attributes of a MEMORY region. */
- memory_attr:
- '(' string ')'
- { $$ = script_parse_memory_attr(closure, $2.value, $2.length, 0); }
- | /* Inverted attributes. */
- '(' '!' string ')'
- { $$ = script_parse_memory_attr(closure, $3.value, $3.length, 1); }
- | /* empty */
- { $$ = 0; }
- ;
- memory_origin:
- ORIGIN
- |
- ORG
- |
- 'o'
- ;
- memory_length:
- LENGTH
- |
- LEN
- |
- 'l'
- ;
- /* 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
- { 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_symbol(closure, $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(closure, $3.value, $3.length); }
- | LENGTH '(' string ')'
- { $$ = script_exp_function_length(closure, $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_data_segment_align(closure);
- $$ = script_exp_function_data_segment_align($3, $5);
- }
- | DATA_SEGMENT_RELRO_END '(' exp ',' exp ')'
- {
- 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_exp_function_segment_start($3.value, $3.length, $5);
- /* We need to take note of any SEGMENT_START expressions
- because they change the behaviour of -Ttext, -Tdata and
- -Tbss options. */
- script_saw_segment_start_expression(closure);
- }
- | 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); }
- ;
- /* 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
- ;
- vers_nodes:
- vers_node
- | vers_nodes vers_node
- ;
- vers_node:
- '{' vers_tag '}' ';'
- {
- script_register_vers_node (closure, NULL, 0, $2, NULL);
- }
- | string '{' vers_tag '}' ';'
- {
- script_register_vers_node (closure, $1.value, $1.length, $3,
- NULL);
- }
- | string '{' vers_tag '}' verdep ';'
- {
- script_register_vers_node (closure, $1.value, $1.length, $3, $5);
- }
- ;
- verdep:
- string
- {
- $$ = script_add_vers_depend (closure, NULL, $1.value, $1.length);
- }
- | verdep string
- {
- $$ = script_add_vers_depend (closure, $1, $2.value, $2.length);
- }
- ;
- vers_tag:
- /* empty */
- { $$ = script_new_vers_node (closure, NULL, NULL); }
- | vers_defns ';'
- { $$ = script_new_vers_node (closure, $1, NULL); }
- | GLOBAL ':' vers_defns ';'
- { $$ = script_new_vers_node (closure, $3, NULL); }
- | LOCAL ':' vers_defns ';'
- { $$ = script_new_vers_node (closure, NULL, $3); }
- | GLOBAL ':' vers_defns ';' LOCAL ':' vers_defns ';'
- { $$ = script_new_vers_node (closure, $3, $7); }
- ;
- /* Here is one of the rare places we care about the distinction
- between STRING and QUOTED_STRING. For QUOTED_STRING, we do exact
- matching on the pattern, so we pass in true for the exact_match
- parameter. For STRING, we do glob matching and pass in false. */
- vers_defns:
- STRING
- {
- $$ = script_new_vers_pattern (closure, NULL, $1.value,
- $1.length, 0);
- }
- | QUOTED_STRING
- {
- $$ = script_new_vers_pattern (closure, NULL, $1.value,
- $1.length, 1);
- }
- | vers_defns ';' STRING
- {
- $$ = script_new_vers_pattern (closure, $1, $3.value,
- $3.length, 0);
- }
- | vers_defns ';' QUOTED_STRING
- {
- $$ = script_new_vers_pattern (closure, $1, $3.value,
- $3.length, 1);
- }
- | /* Push string on the language stack. */
- EXTERN string '{'
- { version_script_push_lang (closure, $2.value, $2.length); }
- vers_defns opt_semicolon '}'
- {
- $$ = $5;
- version_script_pop_lang(closure);
- }
- | /* Push string on the language stack. This is more complicated
- than the other cases because we need to merge the linked-list
- state from the pre-EXTERN defns and the post-EXTERN defns. */
- vers_defns ';' EXTERN string '{'
- { version_script_push_lang (closure, $4.value, $4.length); }
- vers_defns opt_semicolon '}'
- {
- $$ = script_merge_expressions ($1, $7);
- version_script_pop_lang(closure);
- }
- | EXTERN // "extern" as a symbol name
- {
- $$ = script_new_vers_pattern (closure, NULL, "extern",
- sizeof("extern") - 1, 1);
- }
- | vers_defns ';' EXTERN
- {
- $$ = script_new_vers_pattern (closure, $1, "extern",
- sizeof("extern") - 1, 1);
- }
- ;
- /* A string can be either a STRING or a QUOTED_STRING. Almost all the
- time we don't care, and we use this rule. */
- string:
- STRING
- { $$ = $1; }
- | QUOTED_STRING
- { $$ = $1; }
- ;
- /* Some statements require a terminator, which may be a semicolon or a
- comma. */
- end:
- ';'
- | ','
- ;
- /* An optional semicolon. */
- opt_semicolon:
- ';'
- | /* empty */
- ;
- /* An optional comma. */
- opt_comma:
- ','
- | /* empty */
- ;
- %%
|