12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151 |
- /* yyscript.y -- linker script grammar for gold. */
- /* Copyright (C) 2006-2022 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 HIDDEN
- %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_INIT_PRIORITY
- %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();
- }
- }
- | SORT_BY_INIT_PRIORITY '(' wildcard_name ')'
- {
- $$.name = $3;
- $$.sort = SORT_WILDCARD_BY_INIT_PRIORITY;
- }
- ;
- /* 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);
- }
- | HIDDEN '(' string '=' parse_exp ')'
- { script_set_symbol(closure, $3.value, $3.length, $5, 0, 1); }
- | 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 */
- ;
- %%
|