diff options
Diffstat (limited to 'cmake/elfinfo/GnuLd.g4')
-rw-r--r-- | cmake/elfinfo/GnuLd.g4 | 1500 |
1 files changed, 1500 insertions, 0 deletions
diff --git a/cmake/elfinfo/GnuLd.g4 b/cmake/elfinfo/GnuLd.g4 new file mode 100644 index 0000000..da7b01f --- /dev/null +++ b/cmake/elfinfo/GnuLd.g4 @@ -0,0 +1,1500 @@ +grammar GnuLd; + +/* +TODO: check right associative annotations +*/ + +/* +%token <bigint> INT +%token <name> NAME LNAME +*/ + +/* +%right UNARY +%token END +%left <token> '(' +*/ + + +file: + /*INPUT_SCRIPT*/ script_file + | /*INPUT_MRI_SCRIPT*/ mri_script_file + | /*INPUT_VERSION_SCRIPT*/ version_script_file + | /*INPUT_DYNAMIC_LIST*/ dynamic_list_file + | /*INPUT_DEFSYM*/ defsym_expr + ; + +filename: NAME; + + +defsym_expr: +// { ldlex_defsym(); } + NAME '=' exp +// { +// ldlex_popstate(); +// lang_add_assignment (exp_defsym ($2, $4)); +// } + ; + +/* SYNTAX WITHIN AN MRI SCRIPT FILE */ +mri_script_file: +// { +// ldlex_mri_script (); +// PUSH_ERROR (_("MRI style script")); +// } + mri_script_lines +// { +// ldlex_popstate (); +// mri_draw_tree (); +// POP_ERROR (); +// } + ; + +mri_script_lines: + mri_script_lines mri_script_command NEWLINE + | + ; + +mri_script_command: + CHIP exp + | CHIP exp ',' exp + | NAME /*{ + einfo(_("%P%F: unrecognised keyword in MRI style script '%s'\n"),$1); + }*/ + | LIST /*{ + config.map_filename = "-"; + }*/ + | ORDER ordernamelist + | ENDWORD + | PUBLIC NAME '=' exp + // { mri_public($2, $4); } + | PUBLIC NAME ',' exp + // { mri_public($2, $4); } + | PUBLIC NAME exp + // { mri_public($2, $3); } + | FORMAT NAME + // { mri_format($2); } + | SECT NAME ',' exp + // { mri_output_section($2, $4);} + | SECT NAME exp + // { mri_output_section($2, $3);} + | SECT NAME '=' exp + // { mri_output_section($2, $4);} + | ALIGN_K NAME '=' exp + // { mri_align($2,$4); } + | ALIGN_K NAME ',' exp + // { mri_align($2,$4); } + | ALIGNMOD NAME '=' exp + // { mri_alignmod($2,$4); } + | ALIGNMOD NAME ',' exp + // { mri_alignmod($2,$4); } + | ABSOLUTE mri_abs_name_list + | LOAD mri_load_name_list + | NAMEWORD NAME + // { mri_name($2); } + | ALIAS NAME ',' NAME + // { mri_alias($2,$4,0);} + | ALIAS NAME ',' INT + // { mri_alias ($2, 0, (int) $4.integer); } + | BASE exp + // { mri_base($2); } + | TRUNCATE INT + // { mri_truncate ((unsigned int) $2.integer); } + | CASE casesymlist + | EXTERN extern_name_list + | INCLUDE filename + // { ldlex_script (); ldfile_open_command_file($2); } + mri_script_lines END + // { ldlex_popstate (); } + | START NAME + // { lang_add_entry ($2, FALSE); } + | + ; + +ordernamelist: + ordernamelist ',' NAME // { mri_order($3); } + | ordernamelist NAME // { mri_order($2); } + | + ; + +mri_load_name_list: + NAME + // { mri_load($1); } + | mri_load_name_list ',' NAME // { mri_load($3); } + ; + +mri_abs_name_list: + NAME + // { mri_only_load($1); } + | mri_abs_name_list ',' NAME + // { mri_only_load($3); } + ; + +casesymlist: + /* empty */ // { $$ = NULL; } + | NAME + | casesymlist ',' NAME + ; + +/* Parsed as expressions so that commas separate entries */ +extern_name_list: + // { ldlex_expression (); } + extern_name_list_body + // { ldlex_popstate (); } + ; + +extern_name_list_body: + NAME + // { ldlang_add_undef ($1, FALSE); } + | extern_name_list_body NAME + // { ldlang_add_undef ($2, FALSE); } + | extern_name_list_body ',' NAME + // { ldlang_add_undef ($3, FALSE); } + ; + +script_file: + // { ldlex_both(); } + ifile_list + // { ldlex_popstate(); } + ; + +ifile_list: + ifile_list ifile_p1 + | + ; + + +ifile_p1: + memory + | sections + | phdrs + | startup + | high_level_library + | low_level_library + | floating_point_support + | statement_anywhere + | version + | ';' + | TARGET_K '(' NAME ')' + // { lang_add_target($3); } + | SEARCH_DIR '(' filename ')' + // { ldfile_add_library_path ($3, FALSE); } + | OUTPUT '(' filename ')' + // { lang_add_output($3, 1); } + | OUTPUT_FORMAT '(' NAME ')' + // { lang_add_output_format ($3, (char *) NULL, + // (char *) NULL, 1); } + | OUTPUT_FORMAT '(' NAME ',' NAME ',' NAME ')' + // { lang_add_output_format ($3, $5, $7, 1); } + | OUTPUT_ARCH '(' NAME ')' + // { ldfile_set_output_arch ($3, bfd_arch_unknown); } + | FORCE_COMMON_ALLOCATION + // { command_line.force_common_definition = TRUE ; } + | INHIBIT_COMMON_ALLOCATION + // { command_line.inhibit_common_definition = TRUE ; } + | INPUT '(' input_list ')' + | GROUP + // { lang_enter_group (); } + '(' input_list ')' + // { lang_leave_group (); } + | MAP '(' filename ')' + // { lang_add_map($3); } + | INCLUDE filename + // { ldlex_script (); ldfile_open_command_file($2); } + ifile_list END + // { ldlex_popstate (); } + | NOCROSSREFS '(' nocrossref_list ')' + // { + // lang_add_nocrossref ($3); + // } + | NOCROSSREFS_TO '(' nocrossref_list ')' + // { + // lang_add_nocrossref_to ($3); + // } + | EXTERN '(' extern_name_list ')' + | INSERT_K AFTER NAME + // { lang_add_insert ($3, 0); } + | INSERT_K BEFORE NAME + // { lang_add_insert ($3, 1); } + | REGION_ALIAS '(' NAME ',' NAME ')' + // { lang_memory_region_alias ($3, $5); } + | LD_FEATURE '(' NAME ')' + // { lang_ld_feature ($3); } + ; + +input_list: + // { ldlex_inputlist(); } + input_list1 + // { ldlex_popstate(); } + ; + +input_list1: + NAME + // { lang_add_input_file($1,lang_input_file_is_search_file_enum, + // (char *)NULL); } + | input_list1 ',' NAME + // { lang_add_input_file($3,lang_input_file_is_search_file_enum, + // (char *)NULL); } + | input_list1 NAME + // { lang_add_input_file($2,lang_input_file_is_search_file_enum, + // (char *)NULL); } + | LNAME + // { lang_add_input_file($1,lang_input_file_is_l_enum, + // (char *)NULL); } + | input_list1 ',' LNAME + // { lang_add_input_file($3,lang_input_file_is_l_enum, + // (char *)NULL); } + | input_list1 LNAME + // { lang_add_input_file($2,lang_input_file_is_l_enum, + // (char *)NULL); } + | AS_NEEDED '(' + // { $<integer>$ = input_flags.add_DT_NEEDED_for_regular; + // input_flags.add_DT_NEEDED_for_regular = TRUE; } + // input_list1 ')' + // { input_flags.add_DT_NEEDED_for_regular = $<integer>3; } + | input_list1 ',' AS_NEEDED '(' + // { $<integer>$ = input_flags.add_DT_NEEDED_for_regular; + // input_flags.add_DT_NEEDED_for_regular = TRUE; } + // input_list1 ')' + // { input_flags.add_DT_NEEDED_for_regular = $<integer>5; } + | input_list1 AS_NEEDED '(' + // { $<integer>$ = input_flags.add_DT_NEEDED_for_regular; + // input_flags.add_DT_NEEDED_for_regular = TRUE; } + // input_list1 ')' + // { input_flags.add_DT_NEEDED_for_regular = $<integer>4; } + ; + +sections: + SECTIONS '{' sec_or_group_p1 '}' + ; + +sec_or_group_p1: + sec_or_group_p1 section + | sec_or_group_p1 statement_anywhere + | + ; + +statement_anywhere: + ENTRY '(' NAME ')' + // { lang_add_entry ($3, FALSE); } + | assignment end + | ASSERT_K /*{ldlex_expression ();}*/ '(' exp ',' NAME ')' + // { ldlex_popstate (); + // lang_add_assignment (exp_assert ($4, $6)); } + ; + +/* The '*' and '?' cases are there because the lexer returns them as + separate tokens rather than as NAME. */ +wildcard_name: + NAME + // { + // $$ = $1; + // } + | '*' + // { + // $$ = "*"; + // } + | '?' + // { + // $$ = "?"; + // } + ; + +wildcard_spec: + wildcard_name +// { +// $$.name = $1; +// $$.sorted = none; +// $$.exclude_name_list = NULL; +// $$.section_flag_list = NULL; +// } + | EXCLUDE_FILE '(' exclude_name_list ')' wildcard_name +// { +// $$.name = $5; +// $$.sorted = none; +// $$.exclude_name_list = $3; +// $$.section_flag_list = NULL; +// } + | SORT_BY_NAME '(' wildcard_name ')' +// { +// $$.name = $3; +// $$.sorted = by_name; +// $$.exclude_name_list = NULL; +// $$.section_flag_list = NULL; +// } + | SORT_BY_ALIGNMENT '(' wildcard_name ')' +// { +// $$.name = $3; +// $$.sorted = by_alignment; +// $$.exclude_name_list = NULL; +// $$.section_flag_list = NULL; +// } + | SORT_NONE '(' wildcard_name ')' +// { +// $$.name = $3; +// $$.sorted = by_none; +// $$.exclude_name_list = NULL; +// $$.section_flag_list = NULL; +// } + | SORT_BY_NAME '(' SORT_BY_ALIGNMENT '(' wildcard_name ')' ')' +// { +// $$.name = $5; +// $$.sorted = by_name_alignment; +// $$.exclude_name_list = NULL; +// $$.section_flag_list = NULL; +// } + | SORT_BY_NAME '(' SORT_BY_NAME '(' wildcard_name ')' ')' +// { +// $$.name = $5; +// $$.sorted = by_name; +// $$.exclude_name_list = NULL; +// $$.section_flag_list = NULL; +// } + | SORT_BY_ALIGNMENT '(' SORT_BY_NAME '(' wildcard_name ')' ')' +// { +// $$.name = $5; +// $$.sorted = by_alignment_name; +// $$.exclude_name_list = NULL; +// $$.section_flag_list = NULL; +// } + | SORT_BY_ALIGNMENT '(' SORT_BY_ALIGNMENT '(' wildcard_name ')' ')' +// { +// $$.name = $5; +// $$.sorted = by_alignment; +// $$.exclude_name_list = NULL; +// $$.section_flag_list = NULL; +// } + | SORT_BY_NAME '(' EXCLUDE_FILE '(' exclude_name_list ')' wildcard_name ')' +// { +// $$.name = $7; +// $$.sorted = by_name; +// $$.exclude_name_list = $5; +// $$.section_flag_list = NULL; +// } + | SORT_BY_INIT_PRIORITY '(' wildcard_name ')' +// { +// $$.name = $3; +// $$.sorted = by_init_priority; +// $$.exclude_name_list = NULL; +// $$.section_flag_list = NULL; +// } + ; + +sect_flag_list: NAME +// { +// struct flag_info_list *n; +// n = ((struct flag_info_list *) xmalloc (sizeof *n)); +// if ($1[0] == '!') +// { +// n->with = without_flags; +// n->name = &$1[1]; +// } +// else +// { +// n->with = with_flags; +// n->name = $1; +// } +// n->valid = FALSE; +// n->next = NULL; +// $$ = n; +// } + | sect_flag_list '&' NAME +// { +// struct flag_info_list *n; +// n = ((struct flag_info_list *) xmalloc (sizeof *n)); +// if ($3[0] == '!') +// { +// n->with = without_flags; +// n->name = &$3[1]; +// } +// else +// { +// n->with = with_flags; +// n->name = $3; +// } +// n->valid = FALSE; +// n->next = $1; +// $$ = n; +// } + ; + +sect_flags: + /*not used by antlr: INPUT_SECTION_FLAGS*/ '(' sect_flag_list ')' +// { +// struct flag_info *n; +// n = ((struct flag_info *) xmalloc (sizeof *n)); +// n->flag_list = $3; +// n->flags_initialized = FALSE; +// n->not_with_flags = 0; +// n->only_with_flags = 0; +// $$ = n; +// } + ; + +exclude_name_list: + exclude_name_list wildcard_name +// { +// struct name_list *tmp; +// tmp = (struct name_list *) xmalloc (sizeof *tmp); +// tmp->name = $2; +// tmp->next = $1; +// $$ = tmp; +// } + | + wildcard_name +// { +// struct name_list *tmp; +// tmp = (struct name_list *) xmalloc (sizeof *tmp); +// tmp->name = $1; +// tmp->next = NULL; +// $$ = tmp; +// } + ; + +file_NAME_list: + file_NAME_list opt_comma wildcard_spec +// { +// struct wildcard_list *tmp; +// tmp = (struct wildcard_list *) xmalloc (sizeof *tmp); +// tmp->next = $1; +// tmp->spec = $3; +// $$ = tmp; +// } + | + wildcard_spec +// { +// struct wildcard_list *tmp; +// tmp = (struct wildcard_list *) xmalloc (sizeof *tmp); +// tmp->next = NULL; +// tmp->spec = $1; +// $$ = tmp; +// } + ; + +input_section_spec_no_keep: + NAME +// { +// struct wildcard_spec tmp; +// tmp.name = $1; +// tmp.exclude_name_list = NULL; +// tmp.sorted = none; +// tmp.section_flag_list = NULL; +// lang_add_wild (&tmp, NULL, ldgram_had_keep); +// } + | sect_flags NAME +// { +// struct wildcard_spec tmp; +// tmp.name = $2; +// tmp.exclude_name_list = NULL; +// tmp.sorted = none; +// tmp.section_flag_list = $1; +// lang_add_wild (&tmp, NULL, ldgram_had_keep); +// } + | '[' file_NAME_list ']' +// { +// lang_add_wild (NULL, $2, ldgram_had_keep); +// } + | sect_flags '[' file_NAME_list ']' +// { +// struct wildcard_spec tmp; +// tmp.name = NULL; +// tmp.exclude_name_list = NULL; +// tmp.sorted = none; +// tmp.section_flag_list = $1; +// lang_add_wild (&tmp, $3, ldgram_had_keep); +// } + | wildcard_spec '(' file_NAME_list ')' +// { +// lang_add_wild (&$1, $3, ldgram_had_keep); +// } + | sect_flags wildcard_spec '(' file_NAME_list ')' +// { +// $2.section_flag_list = $1; +// lang_add_wild (&$2, $4, ldgram_had_keep); +// } + ; + +input_section_spec: + input_section_spec_no_keep + | KEEP '(' +// { ldgram_had_keep = TRUE; } + input_section_spec_no_keep ')' +// { ldgram_had_keep = FALSE; } + ; + +statement: + assignment end + | CREATE_OBJECT_SYMBOLS +// { +// lang_add_attribute(lang_object_symbols_statement_enum); +// } + | ';' + | CONSTRUCTORS +// { +// +// lang_add_attribute(lang_constructors_statement_enum); +// } + | SORT_BY_NAME '(' CONSTRUCTORS ')' +// { +// constructors_sorted = TRUE; +// lang_add_attribute (lang_constructors_statement_enum); +// } + | input_section_spec + | length '(' mustbe_exp ')' +// { +// lang_add_data ((int) $1, $3); +// } + + | FILL '(' fill_exp ')' +// { +// lang_add_fill ($3); +// } + | ASSERT_K /*{ldlex_expression ();}*/ '(' exp ',' NAME ')' end +// { ldlex_popstate (); +// lang_add_assignment (exp_assert ($4, $6)); } + | INCLUDE filename +// { ldlex_script (); ldfile_open_command_file($2); } + statement_list_opt END +// { ldlex_popstate (); } + ; + +statement_list: + statement_list statement + | statement + ; + +statement_list_opt: + /* empty */ + | statement_list + ; + +length: + QUAD +// { $$ = $1; } + | SQUAD +// { $$ = $1; } + | LONG +// { $$ = $1; } + | SHORT +// { $$ = $1; } + | BYTE +// { $$ = $1; } + ; + +fill_exp: + mustbe_exp +// { +// $$ = exp_get_fill ($1, 0, "fill value"); +// } + ; + +fill_opt: + '=' fill_exp + // { $$ = $2; } + | // { $$ = (fill_type *) 0; } + ; + +assign_op: + PLUSEQ +// { $$ = '+'; } + | MINUSEQ +// { $$ = '-'; } + | MULTEQ +// { $$ = '*'; } + | DIVEQ +// { $$ = '/'; } + | LSHIFTEQ +// { $$ = LSHIFT; } + | RSHIFTEQ +// { $$ = RSHIFT; } + | ANDEQ +// { $$ = '&'; } + | OREQ +// { $$ = '|'; } + + ; + +end: ';' | ',' + ; + + +assignment: + NAME '=' mustbe_exp +// { +// lang_add_assignment (exp_assign ($1, $3, FALSE)); +// } + | NAME assign_op mustbe_exp +// { +// lang_add_assignment (exp_assign ($1, +// exp_binop ($2, +// exp_nameop (NAME, +// $1), +// $3), FALSE)); +// } + | HIDDEN_ '(' NAME '=' mustbe_exp ')' +// { +// lang_add_assignment (exp_assign ($3, $5, TRUE)); +// } + | PROVIDE '(' NAME '=' mustbe_exp ')' +// { +// lang_add_assignment (exp_provide ($3, $5, FALSE)); +// } + | PROVIDE_HIDDEN '(' NAME '=' mustbe_exp ')' +// { +// lang_add_assignment (exp_provide ($3, $5, TRUE)); +// } + ; + + +opt_comma: + ',' | ; + + +memory: + MEMORY '{' memory_spec_list_opt '}' + ; + +memory_spec_list_opt: memory_spec_list | ; + +memory_spec_list: + memory_spec_list opt_comma memory_spec + | memory_spec + ; + + +memory_spec: NAME +// { region = lang_memory_region_lookup ($1, TRUE); } + attributes_opt ':' + origin_spec opt_comma length_spec +// {} + | INCLUDE filename +// { ldlex_script (); ldfile_open_command_file($2); } + memory_spec_list_opt END +// { ldlex_popstate (); } + ; + +origin_spec: + ORIGIN '=' mustbe_exp +// { +// region->origin_exp = $3; +// region->current = region->origin; +// } + ; + +length_spec: + LENGTH '=' mustbe_exp +// { +// region->length_exp = $3; +// } + ; + +attributes_opt: + /* empty */ + /* { *//* dummy action to avoid bison 1.25 error message *//* } + |*/ '(' attributes_list ')' + ; + +attributes_list: + attributes_string + | attributes_list attributes_string + ; + +attributes_string: + NAME # attributeNormal +// { lang_set_flags (region, $1, 0); } + | '!' NAME # attributeInverted +// { lang_set_flags (region, $2, 1); } + ; + +/* +This would be best but the tokenizer would have to be made context sensitive which is too much work given how +easy it is to check the flags after parsing. + +attributes_string : + attribute + | '!' attribute # attributeInverted + ; + +attribute: 'r' | 'w' | 'x' | 'a' | 'i' | 'l' ; +*/ +startup: + STARTUP '(' filename ')' +// { lang_startup($3); } + ; + +high_level_library: + HLL '(' high_level_library_NAME_list ')' + | HLL '(' ')' +// { ldemul_hll((char *)NULL); } + ; + +high_level_library_NAME_list: + high_level_library_NAME_list opt_comma filename +// { ldemul_hll($3); } + | filename +// { ldemul_hll($1); } + + ; + +low_level_library: + SYSLIB '(' low_level_library_NAME_list ')' + ; low_level_library_NAME_list: + low_level_library_NAME_list opt_comma filename +// { ldemul_syslib($3); } + | + ; + +floating_point_support: + FLOAT +// { lang_float(TRUE); } + | NOFLOAT +// { lang_float(FALSE); } + ; + +nocrossref_list: + /* empty */ +// { +// $$ = NULL; +// } + | NAME nocrossref_list +// { +// struct lang_nocrossref *n; +// +// n = (struct lang_nocrossref *) xmalloc (sizeof *n); +// n->name = $1; +// n->next = $2; +// $$ = n; +// } + | NAME ',' nocrossref_list +// { +// struct lang_nocrossref *n; +// +// n = (struct lang_nocrossref *) xmalloc (sizeof *n); +// n->name = $1; +// n->next = $3; +// $$ = n; +// } + ; + +mustbe_exp: // { ldlex_expression (); } + exp + // { ldlex_popstate (); $$=$2;} + ; + +exp : + '-' exp # expNegate // TODO: %prec UNARY +// { $$ = exp_unop ('-', $2); } + | '(' exp ')' # expParen +// { $$ = $2; } + | NEXT '(' exp ')' # expNextParen // TODO: %prec UNARY +// { $$ = exp_unop ((int) $1,$3); } + | '!' exp # expInvert // TODO: %prec UNARY +// { $$ = exp_unop ('!', $2); } + | '+' exp # expPlus // TODO: %prec UNARY +// { $$ = $2; } + | '~' exp # expMinus // TODO: %prec UNARY +// { $$ = exp_unop ('~', $2);} + | exp '*' exp # expMul +// { $$ = exp_binop ('*', $1, $3); } + | exp '/' exp # expDiv +// { $$ = exp_binop ('/', $1, $3); } + | exp '%' exp # expMod +// { $$ = exp_binop ('%', $1, $3); } + | exp '+' exp # expAdd +// { $$ = exp_binop ('+', $1, $3); } + | exp '-' exp # expSub +// { $$ = exp_binop ('-' , $1, $3); } + | exp LSHIFT exp # expLshift +// { $$ = exp_binop (LSHIFT , $1, $3); } + | exp RSHIFT exp # expRshift +// { $$ = exp_binop (RSHIFT , $1, $3); } + | exp EQ exp # expEq +// { $$ = exp_binop (EQ , $1, $3); } + | exp NE exp # expNe +// { $$ = exp_binop (NE , $1, $3); } + | exp LE exp # expLe +// { $$ = exp_binop (LE , $1, $3); } + | exp GE exp # expGe +// { $$ = exp_binop (GE , $1, $3); } + | exp '<' exp # expGt +// { $$ = exp_binop ('<' , $1, $3); } + | exp '>' exp # expLt +// { $$ = exp_binop ('>' , $1, $3); } + | exp '&' exp # expAnd +// { $$ = exp_binop ('&' , $1, $3); } + | exp '^' exp # expXor +// { $$ = exp_binop ('^' , $1, $3); } + | exp '|' exp # expOr +// { $$ = exp_binop ('|' , $1, $3); } + | exp '?' exp ':' exp # expTrinary +// { $$ = exp_trinop ('?' , $1, $3, $5); } + | exp ANDAND exp # expAndand +// { $$ = exp_binop (ANDAND , $1, $3); } + | exp OROR exp # expOror +// { $$ = exp_binop (OROR , $1, $3); } + | DEFINED '(' NAME ')' # expDefined +// { $$ = exp_nameop (DEFINED, $3); } + | INT # expInt +// { $$ = exp_bigintop ($1.integer, $1.str); } + | SIZEOF_HEADERS # expSizeofHeaders +// { $$ = exp_nameop (SIZEOF_HEADERS,0); } + | ALIGNOF '(' NAME ')' # expAlignof +// { $$ = exp_nameop (ALIGNOF,$3); } + | SIZEOF '(' NAME ')' # expSizeof +// { $$ = exp_nameop (SIZEOF,$3); } + | ADDR '(' NAME ')' # expAddr +// { $$ = exp_nameop (ADDR,$3); } + | LOADADDR '(' NAME ')' # expLoadaddr +// { $$ = exp_nameop (LOADADDR,$3); } + | CONSTANT '(' NAME ')' # expConstant +// { $$ = exp_nameop (CONSTANT,$3); } + | ABSOLUTE '(' exp ')' # expAbsolute +// { $$ = exp_unop (ABSOLUTE, $3); } + | ALIGN_K '(' exp ')' # expAlign +// { $$ = exp_unop (ALIGN_K,$3); } + | ALIGN_K '(' exp ',' exp ')' # expAlign2 +// { $$ = exp_binop (ALIGN_K,$3,$5); } + | DATA_SEGMENT_ALIGN '(' exp ',' exp ')' # expDataSegmentAlign +// { $$ = exp_binop (DATA_SEGMENT_ALIGN, $3, $5); } + | DATA_SEGMENT_RELRO_END '(' exp ',' exp ')' # expDataSegmentRelRoEnd +// { $$ = exp_binop (DATA_SEGMENT_RELRO_END, $5, $3); + | DATA_SEGMENT_END '(' exp ')' # expDataSegmentEnd +// { $$ = exp_unop (DATA_SEGMENT_END, $3); } + | SEGMENT_START '(' NAME ',' exp ')' # expSegmentStart +// { /* The operands to the expression node are +// placed in the opposite order from the way +// in which they appear in the script as +// that allows us to reuse more code in +// fold_binary. */ +// $$ = exp_binop (SEGMENT_START, +// $5, +// exp_nameop (NAME, $3)); } + | BLOCK '(' exp ')' # expBlock +// { $$ = exp_unop (ALIGN_K,$3); } + | NAME # expName +// { $$ = exp_nameop (NAME,$1); } + | MAX_K '(' exp ',' exp ')' # expMax +// { $$ = exp_binop (MAX_K, $3, $5 ); } + | MIN_K '(' exp ',' exp ')' # expMin +// { $$ = exp_binop (MIN_K, $3, $5 ); } + | ASSERT_K '(' exp ',' NAME ')' # expAssert +// { $$ = exp_assert ($3, $5); } + | ORIGIN '(' NAME ')' # expOrigin +// { $$ = exp_nameop (ORIGIN, $3); } + | LENGTH '(' NAME ')' # expLengthExp +// { $$ = exp_nameop (LENGTH, $3); } + | LOG2CEIL '(' exp ')' # expLog2ceil +// { $$ = exp_unop (LOG2CEIL, $3); } + ; + + +memspec_at_opt: + AT '>' NAME // { $$ = $3; } + | // { $$ = 0; } + ; + +opt_at: + AT '(' exp ')' // { $$ = $3; } + | // { $$ = 0; } + ; + +opt_align: + ALIGN_K '(' exp ')' // { $$ = $3; } + | // { $$ = 0; } + ; + +opt_align_with_input: + ALIGN_WITH_INPUT // { $$ = ALIGN_WITH_INPUT; } + | // { $$ = 0; } + ; + +opt_subalign: + SUBALIGN '(' exp ')' // { $$ = $3; } + | // { $$ = 0; } + ; + +sect_constraint: + ONLY_IF_RO // { $$ = ONLY_IF_RO; } + | ONLY_IF_RW // { $$ = ONLY_IF_RW; } + | SPECIAL // { $$ = SPECIAL; } + | // { $$ = 0; } + ; + +section: NAME // { ldlex_expression(); } + opt_exp_with_type + opt_at + opt_align + opt_align_with_input + opt_subalign // { ldlex_popstate (); ldlex_script (); } + sect_constraint + '{' +// { +// lang_enter_output_section_statement($1, $3, +// sectype, +// $5, $7, $4, $9, $6); +// } + statement_list_opt + '}' // { ldlex_popstate (); ldlex_expression (); } + memspec_opt memspec_at_opt phdr_opt fill_opt +// { +// ldlex_popstate (); +// lang_leave_output_section_statement ($18, $15, $17, $16); +// } + opt_comma + {} + | OVERLAY +// { ldlex_expression (); } + opt_exp_without_type opt_nocrossrefs opt_at opt_subalign +// { ldlex_popstate (); ldlex_script (); } + '{' +// { +// lang_enter_overlay ($3, $6); +// } + overlay_section + '}' +// { ldlex_popstate (); ldlex_expression (); } + memspec_opt memspec_at_opt phdr_opt fill_opt +// { +// ldlex_popstate (); +// lang_leave_overlay ($5, (int) $4, +// $16, $13, $15, $14); +// } + opt_comma + | /* The GROUP case is just enough to support the gcc + svr3.ifile script. It is not intended to be full + support. I'm not even sure what GROUP is supposed + to mean. */ + GROUP // { ldlex_expression (); } + opt_exp_with_type +// { +// ldlex_popstate (); +// lang_add_assignment (exp_assign (".", $3, FALSE)); +// } + '{' sec_or_group_p1 '}' + | INCLUDE filename + // { ldlex_script (); ldfile_open_command_file($2); } + sec_or_group_p1 END + // { ldlex_popstate (); } + ; + +type: + NOLOAD // { sectype = noload_section; } + | DSECT // { sectype = noalloc_section; } + | COPY // { sectype = noalloc_section; } + | INFO // { sectype = noalloc_section; } + | OVERLAY // { sectype = noalloc_section; } + ; + +atype: + '(' type ')' + | /* EMPTY */ // { sectype = normal_section; } + | '(' ')' // { sectype = normal_section; } + ; + +opt_exp_with_type: + exp atype ':' // { $$ = $1; } + | atype ':' // { $$ = (etree_type *)NULL; } + | /* The BIND cases are to support the gcc svr3.ifile + script. They aren't intended to implement full + support for the BIND keyword. I'm not even sure + what BIND is supposed to mean. */ + BIND '(' exp ')' atype ':' // { $$ = $3; } + | BIND '(' exp ')' BLOCK '(' exp ')' atype ':' + // { $$ = $3; } + ; + +opt_exp_without_type: + exp ':' // { $$ = $1; } + | ':' // { $$ = (etree_type *) NULL; } + ; + +opt_nocrossrefs: + /* empty */ +// { $$ = 0; } + | NOCROSSREFS +// { $$ = 1; } + ; + +memspec_opt: + '>' NAME + // { $$ = $2; } + | // { $$ = DEFAULT_MEMORY_REGION; } + ; + +phdr_opt: + /* empty */ +// { +// $$ = NULL; +// } + | phdr_opt ':' NAME +// { +// struct lang_output_section_phdr_list *n; +// +// n = ((struct lang_output_section_phdr_list *) +// xmalloc (sizeof *n)); +// n->name = $3; +// n->used = FALSE; +// n->next = $1; +// $$ = n; +// } + ; + +overlay_section: + /* empty */ + | overlay_section + NAME +// { +// ldlex_script (); +// lang_enter_overlay_section ($2); +// } + '{' statement_list_opt '}' +// { ldlex_popstate (); ldlex_expression (); } + phdr_opt fill_opt +// { +// ldlex_popstate (); +// lang_leave_overlay_section ($9, $8); +// } + opt_comma + ; + +phdrs: + PHDRS '{' phdr_list '}' + ; + +phdr_list: + /* empty */ + | phdr_list phdr + ; + +phdr: + NAME // { ldlex_expression (); } + phdr_type phdr_qualifiers // { ldlex_popstate (); } + ';' +// { +// lang_new_phdr ($1, $3, $4.filehdr, $4.phdrs, $4.at, +// $4.flags); +// } + ; + +phdr_type: + exp +// { +// $$ = $1; +// +// if ($1->type.node_class == etree_name +// && $1->type.node_code == NAME) +// { +// const char *s; +// unsigned int i; +// static const char * const phdr_types[] = +// { +// "PT_NULL", "PT_LOAD", "PT_DYNAMIC", +// "PT_INTERP", "PT_NOTE", "PT_SHLIB", +// "PT_PHDR", "PT_TLS" +// }; +// +// s = $1->name.name; +// for (i = 0; +// i < sizeof phdr_types / sizeof phdr_types[0]; +// i++) +// if (strcmp (s, phdr_types[i]) == 0) +// { +// $$ = exp_intop (i); +// break; +// } +// if (i == sizeof phdr_types / sizeof phdr_types[0]) +// { +// if (strcmp (s, "PT_GNU_EH_FRAME") == 0) +// $$ = exp_intop (0x6474e550); +// else if (strcmp (s, "PT_GNU_STACK") == 0) +// $$ = exp_intop (0x6474e551); +// else +// { +// einfo (_("\ +//%X%P:%S: unknown phdr type `%s' (try integer literal)\n"), +// NULL, s); +// $$ = exp_intop (0); +// } +// } +// } +// } + ; + +phdr_qualifiers: + /* empty */ +// { +// memset (&$$, 0, sizeof (struct phdr_info)); +// } + | NAME phdr_val phdr_qualifiers +// { +// $$ = $3; +// if (strcmp ($1, "FILEHDR") == 0 && $2 == NULL) +// $$.filehdr = TRUE; +// else if (strcmp ($1, "PHDRS") == 0 && $2 == NULL) +// $$.phdrs = TRUE; +// else if (strcmp ($1, "FLAGS") == 0 && $2 != NULL) +// $$.flags = $2; +// else +// einfo (_("%X%P:%S: PHDRS syntax error at `%s'\n"), +// NULL, $1); +// } + | AT '(' exp ')' phdr_qualifiers +// { +// $$ = $5; +// $$.at = $3; +// } + ; + +phdr_val: + /* empty */ +// { +// $$ = NULL; +// } + | '(' exp ')' +// { +// $$ = $2; +// } + ; + +dynamic_list_file: +// { +// ldlex_version_file (); +// PUSH_ERROR (_("dynamic list")); +// } + dynamic_list_nodes +// { +// ldlex_popstate (); +// POP_ERROR (); +// } + ; + +dynamic_list_nodes: + dynamic_list_node + | dynamic_list_nodes dynamic_list_node + ; + +dynamic_list_node: + '{' dynamic_list_tag '}' ';' + ; + +dynamic_list_tag: + vers_defns ';' +// { +// lang_append_dynamic_list ($1); +// } + ; + +/* This syntax is used within an external version script file. */ + +version_script_file: +// { +// ldlex_version_file (); +// PUSH_ERROR (_("VERSION script")); +// } + vers_nodes +// { +// ldlex_popstate (); +// POP_ERROR (); +// } + ; + +/* This is used within a normal linker script file. */ + +version: +// { +// ldlex_version_script (); +// } + VERSIONK '{' vers_nodes '}' +// { +// ldlex_popstate (); +// } + ; + +vers_nodes: + vers_node + | vers_nodes vers_node + ; + +vers_node: + '{' vers_tag '}' ';' +// { +// lang_register_vers_node (NULL, $2, NULL); +// } + | VERS_TAG '{' vers_tag '}' ';' +// { +// lang_register_vers_node ($1, $3, NULL); +// } + | VERS_TAG '{' vers_tag '}' verdep ';' +// { +// lang_register_vers_node ($1, $3, $5); +// } + ; + +verdep: + VERS_TAG +// { +// $$ = lang_add_vers_depend (NULL, $1); +// } + | verdep VERS_TAG +// { +// $$ = lang_add_vers_depend ($1, $2); +// } + ; + +vers_tag: + /* empty */ +// { +// $$ = lang_new_vers_node (NULL, NULL); +// } + | vers_defns ';' +// { +// $$ = lang_new_vers_node ($1, NULL); +// } + | GLOBAL ':' vers_defns ';' +// { +// $$ = lang_new_vers_node ($3, NULL); +// } + | LOCAL ':' vers_defns ';' +// { +// $$ = lang_new_vers_node (NULL, $3); +// } + | GLOBAL ':' vers_defns ';' LOCAL ':' vers_defns ';' +// { +// $$ = lang_new_vers_node ($3, $7); +// } + ; + +vers_defns: + VERS_IDENTIFIER +// { +// $$ = lang_new_vers_pattern (NULL, $1, ldgram_vers_current_lang, FALSE); +// } + | NAME +// { +// $$ = lang_new_vers_pattern (NULL, $1, ldgram_vers_current_lang, TRUE); +// } + | vers_defns ';' VERS_IDENTIFIER +// { +// $$ = lang_new_vers_pattern ($1, $3, ldgram_vers_current_lang, FALSE); +// } + | vers_defns ';' NAME +// { +// $$ = lang_new_vers_pattern ($1, $3, ldgram_vers_current_lang, TRUE); +// } + | vers_defns ';' EXTERN NAME '{' +// { +// $<name>$ = ldgram_vers_current_lang; +// ldgram_vers_current_lang = $4; +// } + vers_defns opt_semicolon '}' +// { +// struct bfd_elf_version_expr *pat; +// for (pat = $7; pat->next != NULL; pat = pat->next); +// pat->next = $1; +// $$ = $7; +// ldgram_vers_current_lang = $<name>6; +// } + | EXTERN NAME '{' +// { +// $<name>$ = ldgram_vers_current_lang; +// ldgram_vers_current_lang = $2; +// } + vers_defns opt_semicolon '}' +// { +// $$ = $5; +// ldgram_vers_current_lang = $<name>4; +// } + | GLOBAL +// { +// $$ = lang_new_vers_pattern (NULL, "global", ldgram_vers_current_lang, FALSE); +// } + | vers_defns ';' GLOBAL +// { +// $$ = lang_new_vers_pattern ($1, "global", ldgram_vers_current_lang, FALSE); +// } + | LOCAL +// { +// $$ = lang_new_vers_pattern (NULL, "local", ldgram_vers_current_lang, FALSE); +// } + | vers_defns ';' LOCAL +// { +// $$ = lang_new_vers_pattern ($1, "local", ldgram_vers_current_lang, FALSE); +// } + | EXTERN +// { +// $$ = lang_new_vers_pattern (NULL, "extern", ldgram_vers_current_lang, FALSE); +// } + | vers_defns ';' EXTERN +// { +// $$ = lang_new_vers_pattern ($1, "extern", ldgram_vers_current_lang, FALSE); +// } + ; + +opt_semicolon: + /* empty */ + | ';' + ; + +//%token <token> +LBRACE : '{'; +RBRACE : '}'; + +// <integer> +// <token> assign_op atype attributes_opt sect_constraint opt_align_with_input +// <name> filename +//%type <versyms> vers_defns +//%type <versnode> vers_tag +//%type <deflist> verdep + +ABSOLUTE : 'ABSOLUTE'; +ADDR : 'ADDR'; +AFTER : 'AFTER'; +ALIAS : 'ALIAS'; +ALIGN : 'ALIGN'; +ALIGN_K : 'ALIGN'; +ALIGNMOD : 'ALIGNMOD'; +ALIGNOF : 'ALIGNOF'; +ALIGN_WITH_INPUT : 'ALIGN_WITH_INPUT'; +AS_NEEDED : 'AS_NEEDED'; +ASSERT_K : 'ASSERT'; +AT : 'AT'; +BASE : 'BASE'; +BEFORE : 'BEFORE'; +BIND : 'BIND'; +BLOCK : 'BLOCK'; +BYTE : 'BYTE'; +CASE : 'CASE'; +CHIP : 'CHIP'; +CONSTANT : 'CONSTANT'; +CONSTRUCTORS : 'CONSTRUCTORS'; +COPY : 'COPY'; +CREATE_OBJECT_SYMBOLS : 'CREATE_OBJECT_SYMBOLS'; +DATA_SEGMENT_ALIGN : 'DATA_SEGMENT_ALIGN'; +DATA_SEGMENT : 'DATA_SEGMENT'; +DATA_SEGMENT_END : 'DATA_SEGMENT_END'; +DATA_SEGMENT_RELRO_END : 'DATA_SEGMENT_RELRO_END'; +DEFINED : 'DEFINED'; +DEFSYMEND : 'DEFSYMEND'; +DSECT : 'DSECT'; +ENDWORD : 'ENDWORD'; +ENTRY : 'ENTRY'; +EXCLUDE_FILE : 'EXCLUDE_FILE'; +EXTERN : 'EXTERN'; +FILL : 'FILL'; +FLOAT : 'FLOAT'; +FORCE_COMMON_ALLOCATION : 'FORCE_COMMON_ALLOCATION'; +FORMAT : 'FORMAT'; +GLOBAL : 'GLOBAL'; +GROUP : 'GROUP'; +HIDDEN_ : 'HIDDEN'; +HLL : 'HLL'; +INCLUDE : 'INCLUDE'; +INFO : 'INFO'; +INHIBIT_COMMON_ALLOCATION : 'INHIBIT_COMMON_ALLOCATION'; +//INPUT_DEFSYM : 'INPUT_DEFSYM'; +//INPUT_DYNAMIC_LIST : 'INPUT_DYNAMIC_LIST'; +INPUT : 'INPUT'; +//INPUT_MRI_SCRIPT : 'INPUT_MRI_SCRIPT'; +//INPUT_SCRIPT : 'INPUT_SCRIPT'; +//INPUT_SECTION_FLAGS : 'INPUT_SECTION_FLAGS'; +//INPUT_VERSION_SCRIPT : 'INPUT_VERSION_SCRIPT'; +INSERT_K : 'INSERT'; +KEEP : 'KEEP'; +LD_FEATURE : 'LD_FEATURE'; +LENGTH : 'LENGTH'; +LIST : 'LIST'; +LOADADDR : 'LOADADDR'; +LOAD : 'LOAD'; +LOCAL : 'LOCAL'; +LOG2CEIL : 'LOG2CEIL'; +LONG : 'LONG'; +MAP : 'MAP'; +MAX_K : 'MAX'; +MEMORY : 'MEMORY'; +MIN_K : 'MIN'; +NAMEWORD : 'NAMEWORD'; +NEWLINE : 'NEWLINE'; +NEXT : 'NEXT'; +NOCROSSREFS : 'NOCROSSREFS'; +NOCROSSREFS_TO : 'NOCROSSREFS_TO'; +NOFLOAT : 'NOFLOAT'; +NOLOAD : 'NOLOAD'; +ONLY_IF_RO : 'ONLY_IF_RO'; +ONLY_IF_RW : 'ONLY_IF_RW'; +ORDER : 'ORDER'; +ORIGIN : 'ORIGIN'; // TODO: or 'org' or 'o'. +OUTPUT_ARCH : 'OUTPUT_ARCH'; +OUTPUT_FORMAT : 'OUTPUT_FORMAT'; +OUTPUT : 'OUTPUT'; +OVERLAY : 'OVERLAY'; +PHDRS : 'PHDRS'; +PROVIDE_HIDDEN : 'PROVIDE_HIDDEN'; +PROVIDE : 'PROVIDE'; +PUBLIC : 'PUBLIC'; +QUAD : 'QUAD'; +REGION_ALIAS : 'REGION_ALIAS'; +REL : 'REL'; +SEARCH_DIR : 'SEARCH_DIR'; +SECTIONS : 'SECTIONS'; +SECT : 'SECT'; +SEGMENT_START : 'SEGMENT_START'; +SHORT : 'SHORT'; +SIZEOF_HEADERS : 'SIZEOF_HEADERS'; +SIZEOF : 'SIZEOF'; +SORT_BY_ALIGNMENT : 'SORT_BY_ALIGNMENT'; +SORT_BY_INIT_PRIORITY : 'SORT_BY_INIT_PRIORITY'; +SORT_BY_NAME : 'SORT_BY_NAME'; +SORT_NONE : 'SORT_NONE'; +SPECIAL : 'SPECIAL'; +SQUAD : 'SQUAD'; +START : 'START'; +STARTUP : 'STARTUP'; +SUBALIGN : 'SUBALIGN'; +SYSLIB : 'SYSLIB'; +TARGET_K : 'TARGET'; +TRUNCATE : 'TRUNCATE'; +VERS_IDENTIFIER : 'VERS_IDENTIFIER'; +VERSIONK : 'VERSIONK'; +VERS_TAG : 'VERS_TAG'; + +/* +Names are very liberal, they can be full strings and start with a dot. +*/ + +NAME : [\._a-zA-Z][_a-zA-Z0-9]*; + +// TODO: ld supports some really fancy expressions here, like "0101010b", "ffH", "ffx", "$Aa" etc +//INT : '0x' [0-9a-fA-F]+ +// | [0-9]+; +INT : INT_NUMBER INT_SIZE?; +INT_NUMBER : INT_HEX + | INT_DECIMAL; +INT_HEX : '0x' [0-9a-fA-F]+; +INT_DECIMAL : [0-9]+; +INT_SIZE : 'M' | 'm' | 'K' | 'k'; + +END : 'END'; + +LNAME : '-l' NAME; +PLUSEQ : '+='; +MINUSEQ : '-='; +MULTEQ : '*='; +DIVEQ : '/='; +LSHIFTEQ : '<<='; +RSHIFTEQ : '>>='; +ANDEQ : '&='; +OREQ : '|='; +LSHIFT : '<<'; +RSHIFT : '>>'; +EQ : '='; +NE : '!='; +LE : '<='; +GE : '>='; +ANDAND : '&&'; +OROR : '||'; + +BlockComment + : '/*' .*? '*/' -> skip + ; + +WS : [ \t\r\n]+ -> skip ; |