From ead2f1961fc653861a151a033c3cd0657c50af16 Mon Sep 17 00:00:00 2001 From: Trygve Laugstøl Date: Sun, 3 Jul 2016 11:22:26 +0200 Subject: LD file Antlr4 grammar. Generates a lexer and parser for Java. --- cmake/elfinfo/.gitignore | 4 + cmake/elfinfo/GnuLd.g4 | 1500 ++++++++++++++++++++ cmake/elfinfo/Makefile.grammar | 53 + cmake/elfinfo/grun.sh | 14 + cmake/elfinfo/lds/d2000.ld | 85 ++ cmake/elfinfo/lds/stm32.ld | 62 + cmake/elfinfo/pom.xml | 34 + .../src/main/java/io/trygvis/ld/LdScript.java | 483 +++++++ 8 files changed, 2235 insertions(+) create mode 100644 cmake/elfinfo/GnuLd.g4 create mode 100644 cmake/elfinfo/Makefile.grammar create mode 100755 cmake/elfinfo/grun.sh create mode 100644 cmake/elfinfo/lds/d2000.ld create mode 100644 cmake/elfinfo/lds/stm32.ld create mode 100644 cmake/elfinfo/pom.xml create mode 100644 cmake/elfinfo/src/main/java/io/trygvis/ld/LdScript.java diff --git a/cmake/elfinfo/.gitignore b/cmake/elfinfo/.gitignore index 485dee6..a2d5086 100644 --- a/cmake/elfinfo/.gitignore +++ b/cmake/elfinfo/.gitignore @@ -1 +1,5 @@ .idea +*.iml +*.iws +*.jar +/antlr 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 INT +%token NAME LNAME +*/ + +/* +%right UNARY +%token END +%left '(' +*/ + + +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 '(' + // { $$ = input_flags.add_DT_NEEDED_for_regular; + // input_flags.add_DT_NEEDED_for_regular = TRUE; } + // input_list1 ')' + // { input_flags.add_DT_NEEDED_for_regular = $3; } + | input_list1 ',' AS_NEEDED '(' + // { $$ = input_flags.add_DT_NEEDED_for_regular; + // input_flags.add_DT_NEEDED_for_regular = TRUE; } + // input_list1 ')' + // { input_flags.add_DT_NEEDED_for_regular = $5; } + | input_list1 AS_NEEDED '(' + // { $$ = input_flags.add_DT_NEEDED_for_regular; + // input_flags.add_DT_NEEDED_for_regular = TRUE; } + // input_list1 ')' + // { input_flags.add_DT_NEEDED_for_regular = $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 '{' +// { +// $$ = 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 = $6; +// } + | EXTERN NAME '{' +// { +// $$ = ldgram_vers_current_lang; +// ldgram_vers_current_lang = $2; +// } + vers_defns opt_semicolon '}' +// { +// $$ = $5; +// ldgram_vers_current_lang = $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 +LBRACE : '{'; +RBRACE : '}'; + +// +// assign_op atype attributes_opt sect_constraint opt_align_with_input +// filename +//%type vers_defns +//%type vers_tag +//%type 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 ; diff --git a/cmake/elfinfo/Makefile.grammar b/cmake/elfinfo/Makefile.grammar new file mode 100644 index 0000000..13eb13d --- /dev/null +++ b/cmake/elfinfo/Makefile.grammar @@ -0,0 +1,53 @@ +GRAMMAR=GnuLd.g4 +G4_PACKAGE ?= io.trygvis.ld.antlr +PACKAGE_PATH = $(subst .,/,$(G4_PACKAGE)) + +G4_JAVA=\ + $(patsubst %.g4,antlr/$(PACKAGE_PATH)/%Lexer.java,$(GRAMMAR)) + +# $(patsubst %.g4,antlr/$(PACKAGE_PATH)/%Parser.java,$(GRAMMAR)) \ +# $(patsubst %.g4,antlr/$(PACKAGE_PATH)/%Listener.java,$(GRAMMAR)) \ +# $(patsubst %.g4,antlr/$(PACKAGE_PATH)/%BaseListener.java,$(GRAMMAR)) + +G4_CLASSES=$(patsubst antlr/%.java,target/classes/%.class,$(G4_JAVA)) + +ANTLR_URL=http://repo1.maven.org/maven2/org/antlr/antlr4/4.5.3/antlr4-4.5.3.jar +ANTLR_RUNTIME_URL=http://repo1.maven.org/maven2/org/antlr/antlr4-runtime/4.5.3/antlr4-runtime-4.5.3.jar +ANTLR_JAR=$(notdir $(ANTLR_URL)) +ANTLR_RUNTIME_JAR=$(notdir $(ANTLR_RUNTIME_URL)) + +all: meta-java + +meta-java: $(G4_JAVA) + +meta-classes: $(G4_CLASSES) + +info: + @echo "ANTLR_JAR $(ANTLR_JAR)" + @echo "GRAMMAR $(GRAMMAR)" + @echo "G4_JAVA $(G4_JAVA)" + @echo "G4_CLASSES $(G4_CLASSES)" + +target/classes antlr: + mkdir -p $@ + +download: $(ANTLR_JAR) $(ANTLR_RUNTIME_JAR) + +$(ANTLR_JAR): + wget $(ANTLR_URL) + +$(ANTLR_RUNTIME_JAR): + wget $(ANTLR_RUNTIME_URL) + +$(G4_JAVA): $(GRAMMAR) | antlr $(ANTLR_JAR) + java -cp $(ANTLR_JAR) org.antlr.v4.Tool \ + -visitor \ + -o antlr/$(PACKAGE_PATH) \ + $(patsubst %,-package %,$(G4_PACKAGE)) \ + $< + +$(G4_CLASSES): $(G4_JAVA) | target/classes + javac -d target/classes -cp $(ANTLR_JAR) $(wildcard antlr/$(PACKAGE_PATH)/*.java) + +clean: + rm -rf target/classes antlr diff --git a/cmake/elfinfo/grun.sh b/cmake/elfinfo/grun.sh new file mode 100755 index 0000000..ccd4743 --- /dev/null +++ b/cmake/elfinfo/grun.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +url="http://repo1.maven.org/maven2/org/antlr/antlr4/4.5.3/antlr4-4.5.3.jar" +jar="$(basename $url)" + +if [[ ! -r "$jar" ]] +then + wget "$url" +fi + +CLASSPATH="$CLASSPATH:$jar" +CLASSPATH="$CLASSPATH:target/classes" +export CLASSPATH +exec java org.antlr.v4.gui.TestRig "$@" diff --git a/cmake/elfinfo/lds/d2000.ld b/cmake/elfinfo/lds/d2000.ld new file mode 100644 index 0000000..ef253c6 --- /dev/null +++ b/cmake/elfinfo/lds/d2000.ld @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2015, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of the Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INTEL CORPORATION OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +ENTRY(_start) + +MEMORY +{ + flash(r) : ORIGIN = 0x00180000, LENGTH = 32K + data(rw) : ORIGIN = 0x00200000, LENGTH = 4K + /* Place IDT at the bottom of SRAM, 52 gate wide */ + esram_idt (rw) : ORIGIN = 0x00280000, LENGTH = 0x1A0 + esram(rw) : ORIGIN = 0x002801A0, LENGTH = 8K - 1K - 0x1A0 + stack(rw) : ORIGIN = 0x00281C00, LENGTH = 1K +} + +/* IDT definition */ +__idt_start = ORIGIN(esram_idt); +__idt_end = __idt_start + LENGTH(esram_idt); + +SECTIONS +{ + .text : + { + *(.text.entry) + *(.text) + *(.text.last) + *(.text.*) + } >flash + + .rodata : + { + *(.rdata*) + *(.rodata*) + } >flash + + .data : + { + *(.data*) + } >esram AT>flash + + .bss : + { + *(.bss*) + *(COMMON) + } >esram AT>esram + + /* Symbols for C runtime init code. */ + __data_lma = LOADADDR(.data); + __data_vma = ADDR(.data); + __data_size = SIZEOF(.data); + __bss_start = ADDR(.bss); + __bss_end = __bss_start + SIZEOF(.bss); + + /* Heap */ + __heap = .; + __heap_end = ORIGIN(stack); + + .comment 0 : { *(.comment) } +} diff --git a/cmake/elfinfo/lds/stm32.ld b/cmake/elfinfo/lds/stm32.ld new file mode 100644 index 0000000..bafd520 --- /dev/null +++ b/cmake/elfinfo/lds/stm32.ld @@ -0,0 +1,62 @@ +ENTRY(_Reset_Handler) + +MEMORY +{ + FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 64K + RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 20k + MEMORY_B1 (rx) : ORIGIN = 0x60000000, LENGTH = 0K +} + +_estack = ORIGIN(RAM) + LENGTH(RAM); + +SECTIONS +{ + /* Put the ISR section at the start of the flash area */ + .isr : + { + /* The first word has to be the initial stack pointer */ + LONG(__initial_stack_pointer); + KEEP(*/init_high.cpp.obj(.isr_vectors)) + } >FLASH + ASSERT(SIZEOF(.isr) > 100, "The isr_vectors section is too small") + ASSERT(SIZEOF(.isr) < 1000, "The isr_vectors section is too big") + ASSERT(ADDR(.isr) == ORIGIN(FLASH), "The isr_vectors section was not placed at the start of the flash area") + + .text : + { + *(.text) + KEEP(*(.text.*)) + *(.rodata*) + } >FLASH + + .init_arrays : + { + _init_array_start = .; + KEEP(*(.init_array)) + KEEP(*(SORT_BY_INIT_PRIORITY(.init_array.*))) + _init_array_end = .; + } >FLASH + + . = ORIGIN(RAM); + + .data ALIGN(4) : + { + *(.data) + *(.data.*) + } >RAM AT >FLASH + + .bss ALIGN(4) (NOLOAD) : + { + *(.bss) + *(.bss.*) + } >RAM + + _copy_data_store = ADDR(.data); + _copy_data_store_end = _copy_data_store + SIZEOF(.data); + _copy_data_load = LOADADDR(.data); + + _bss_start = ADDR(.bss); + _bss_end = _bss_start + SIZEOF(.bss); + + __initial_stack_pointer = ORIGIN(RAM) + LENGTH(RAM) - 1; +} diff --git a/cmake/elfinfo/pom.xml b/cmake/elfinfo/pom.xml new file mode 100644 index 0000000..bb46e6f --- /dev/null +++ b/cmake/elfinfo/pom.xml @@ -0,0 +1,34 @@ + + 4.0.0 + io.trygvis.ld + ld + 1.0-SNAPSHOT + + + org.antlr + antlr4 + 4.5.3 + + + org.antlr + antlr4-runtime + 4.5.3 + + + com.google.code.findbugs + jsr305 + 3.0.1 + + + + + + maven-compiler-plugin + + 1.8 + 1.8 + + + + + diff --git a/cmake/elfinfo/src/main/java/io/trygvis/ld/LdScript.java b/cmake/elfinfo/src/main/java/io/trygvis/ld/LdScript.java new file mode 100644 index 0000000..f827a8b --- /dev/null +++ b/cmake/elfinfo/src/main/java/io/trygvis/ld/LdScript.java @@ -0,0 +1,483 @@ +package io.trygvis.ld; + +import io.trygvis.ld.antlr.GnuLdBaseVisitor; +import io.trygvis.ld.antlr.GnuLdLexer; +import io.trygvis.ld.antlr.GnuLdParser; +import org.antlr.v4.runtime.ANTLRFileStream; +import org.antlr.v4.runtime.BufferedTokenStream; +import org.antlr.v4.runtime.tree.ParseTreeProperty; + +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +public class LdScript { + + public enum MemoryAttribute { + R, W, X, A, I, + } + + public static class MemoryArea { + private final BigInteger MEGA = BigInteger.valueOf(1024 * 1024); + private final BigInteger KILO = BigInteger.valueOf(1024); + + String name; + BigInteger origin; + BigInteger length; + Set attributes; + + @Override + public String toString() { + return "MemoryArea{" + + "name='" + name + '\'' + + ", origin=" + origin + + ", length=" + length + + ", attributes='" + attributes + '\'' + + '}'; + } + + public String prettyOrigin() { + if (origin == null) { + return ""; + } + String hex = origin.toString(16); + + return "0x" + ("00000000").substring(0, 8 - hex.length()) + hex; + } + + public String prettyLength() { + if (length == null) { + return ""; + } + + if (length.compareTo(MEGA) >= 0 && length.mod(MEGA).equals(BigInteger.ZERO)) { + return length.divide(MEGA) + "M"; + } + + if (length.compareTo(KILO) >= 0 && length.mod(KILO).equals(BigInteger.ZERO)) { + return length.divide(KILO) + "k"; + } + + return String.valueOf(length); + } + + public String prettyAttributes() { + String s = ""; + for (MemoryAttribute attribute : attributes) { + s += attribute.name().toLowerCase(); + } + return s; + } + } + + public static class Section { + String name; + } + + public static void main(String[] args) throws Exception { + try { + work(args); + } catch (Exception e) { + e.printStackTrace(System.out); + } + } + + private static void work(String[] args) throws Exception { + args = new String[]{"lds/d2000.ld"}; + + GnuLdLexer lexer = new GnuLdLexer(new ANTLRFileStream(args[0])); + GnuLdParser parser = new GnuLdParser(new BufferedTokenStream(lexer)); + +// ElfInfoGnuLdBaseListener listener = new ElfInfoGnuLdBaseListener(); +// parser.addParseListener(listener); +// +// parser.file(); +// +// for (Section section : listener.sections) { +// System.out.println("section.name = " + section.name); +// } + + ElfinfoGnuLdBaseVisitor visitor = new ElfinfoGnuLdBaseVisitor(); + visitor.visit(parser.file()); + + System.out.println("--------------------------------------------------------"); + for (MemoryArea area : visitor.memoryAreas) { + System.out.println(" " + area.name + "(" + area.prettyAttributes() + ") : ORIGIN = " + area.prettyOrigin() + ", LENGTH=" + area.prettyLength()); + } + } + + private static class ElfinfoExprGnuLdBaseVisitor extends GnuLdBaseVisitor { + private BigInteger value; + private ParseTreeProperty es = new ParseTreeProperty<>(); + + public static BigInteger evaluate(GnuLdParser.Mustbe_expContext ctx) { + ElfinfoExprGnuLdBaseVisitor v = new ElfinfoExprGnuLdBaseVisitor(); + v.visitMustbe_exp(ctx); + return v.value(); + } + + @Override + public ElfinfoExprGnuLdBaseVisitor visitExpLt(GnuLdParser.ExpLtContext ctx) { + return visitChildren(ctx); + } + + @Override + public ElfinfoExprGnuLdBaseVisitor visitExpBlock(GnuLdParser.ExpBlockContext ctx) { + return visitChildren(ctx); + + } + + @Override + public ElfinfoExprGnuLdBaseVisitor visitExpAbsolute(GnuLdParser.ExpAbsoluteContext ctx) { + return visitChildren(ctx); + + } + + @Override + public ElfinfoExprGnuLdBaseVisitor visitExpLog2ceil(GnuLdParser.ExpLog2ceilContext ctx) { + return visitChildren(ctx); + + } + + @Override + public ElfinfoExprGnuLdBaseVisitor visitExpAddr(GnuLdParser.ExpAddrContext ctx) { + return visitChildren(ctx); + + } + + @Override + public ElfinfoExprGnuLdBaseVisitor visitExpDataSegmentEnd(GnuLdParser.ExpDataSegmentEndContext ctx) { + return visitChildren(ctx); + } + + @Override + public ElfinfoExprGnuLdBaseVisitor visitExpSub(GnuLdParser.ExpSubContext ctx) { + System.out.println("ElfinfoGnuLdBaseVisitor.visitExpSub"); + + ElfinfoExprGnuLdBaseVisitor ret = visitChildren(ctx); + BigInteger a = es.removeFrom(ctx.exp(0)); + BigInteger b = es.removeFrom(ctx.exp(1)); + + BigInteger x = a.subtract(b); + + es.put(ctx, x); + return ret; + } + + @Override + public ElfinfoExprGnuLdBaseVisitor visitExpDefined(GnuLdParser.ExpDefinedContext ctx) { + return visitChildren(ctx); + } + + @Override + public ElfinfoExprGnuLdBaseVisitor visitExpMod(GnuLdParser.ExpModContext ctx) { + return visitChildren(ctx); + } + + @Override + public ElfinfoExprGnuLdBaseVisitor visitExpInvert(GnuLdParser.ExpInvertContext ctx) { + return visitChildren(ctx); + } + + @Override + public ElfinfoExprGnuLdBaseVisitor visitExpAlign(GnuLdParser.ExpAlignContext ctx) { + return visitChildren(ctx); + } + + @Override + public ElfinfoExprGnuLdBaseVisitor visitExpMul(GnuLdParser.ExpMulContext ctx) { + return visitChildren(ctx); + } + + @Override + public ElfinfoExprGnuLdBaseVisitor visitExpAnd(GnuLdParser.ExpAndContext ctx) { + return visitChildren(ctx); + } + + @Override + public ElfinfoExprGnuLdBaseVisitor visitExpXor(GnuLdParser.ExpXorContext ctx) { + return visitChildren(ctx); + } + + @Override + public ElfinfoExprGnuLdBaseVisitor visitExpParen(GnuLdParser.ExpParenContext ctx) { + return visitChildren(ctx); + } + + @Override + public ElfinfoExprGnuLdBaseVisitor visitExpMinus(GnuLdParser.ExpMinusContext ctx) { + return visitChildren(ctx); + } + + @Override + public ElfinfoExprGnuLdBaseVisitor visitExpDiv(GnuLdParser.ExpDivContext ctx) { + return visitChildren(ctx); + } + + @Override + public ElfinfoExprGnuLdBaseVisitor visitExpGe(GnuLdParser.ExpGeContext ctx) { + return visitChildren(ctx); + } + + @Override + public ElfinfoExprGnuLdBaseVisitor visitExpMin(GnuLdParser.ExpMinContext ctx) { + return visitChildren(ctx); + } + + @Override + public ElfinfoExprGnuLdBaseVisitor visitExpAlign2(GnuLdParser.ExpAlign2Context ctx) { + return visitChildren(ctx); + } + + @Override + public ElfinfoExprGnuLdBaseVisitor visitExpNegate(GnuLdParser.ExpNegateContext ctx) { + return visitChildren(ctx); + } + + @Override + public ElfinfoExprGnuLdBaseVisitor visitExpName(GnuLdParser.ExpNameContext ctx) { + return visitChildren(ctx); + } + + @Override + public ElfinfoExprGnuLdBaseVisitor visitExpOr(GnuLdParser.ExpOrContext ctx) { + return visitChildren(ctx); + } + + @Override + public ElfinfoExprGnuLdBaseVisitor visitExpTrinary(GnuLdParser.ExpTrinaryContext ctx) { + return visitChildren(ctx); + } + + @Override + public ElfinfoExprGnuLdBaseVisitor visitExpOror(GnuLdParser.ExpOrorContext ctx) { + return visitChildren(ctx); + } + + @Override + public ElfinfoExprGnuLdBaseVisitor visitExpDataSegmentAlign(GnuLdParser.ExpDataSegmentAlignContext ctx) { + return visitChildren(ctx); + } + + @Override + public ElfinfoExprGnuLdBaseVisitor visitExpLengthExp(GnuLdParser.ExpLengthExpContext ctx) { + return visitChildren(ctx); + } + + @Override + public ElfinfoExprGnuLdBaseVisitor visitExpAdd(GnuLdParser.ExpAddContext ctx) { + return visitChildren(ctx); + } + + @Override + public ElfinfoExprGnuLdBaseVisitor visitExpLoadaddr(GnuLdParser.ExpLoadaddrContext ctx) { + return visitChildren(ctx); + } + + @Override + public ElfinfoExprGnuLdBaseVisitor visitExpGt(GnuLdParser.ExpGtContext ctx) { + return visitChildren(ctx); + } + + @Override + public ElfinfoExprGnuLdBaseVisitor visitExpOrigin(GnuLdParser.ExpOriginContext ctx) { + return visitChildren(ctx); + } + + @Override + public ElfinfoExprGnuLdBaseVisitor visitExpEq(GnuLdParser.ExpEqContext ctx) { + return visitChildren(ctx); + } + + @Override + public ElfinfoExprGnuLdBaseVisitor visitExpMax(GnuLdParser.ExpMaxContext ctx) { + return visitChildren(ctx); + } + + @Override + public ElfinfoExprGnuLdBaseVisitor visitExpLshift(GnuLdParser.ExpLshiftContext ctx) { + return visitChildren(ctx); + } + + @Override + public ElfinfoExprGnuLdBaseVisitor visitExpSizeofHeaders(GnuLdParser.ExpSizeofHeadersContext ctx) { + return visitChildren(ctx); + } + + @Override + public ElfinfoExprGnuLdBaseVisitor visitExpLe(GnuLdParser.ExpLeContext ctx) { + return visitChildren(ctx); + } + + @Override + public ElfinfoExprGnuLdBaseVisitor visitExpNe(GnuLdParser.ExpNeContext ctx) { + return visitChildren(ctx); + } + + @Override + public ElfinfoExprGnuLdBaseVisitor visitExpAndand(GnuLdParser.ExpAndandContext ctx) { + return visitChildren(ctx); + } + + @Override + public ElfinfoExprGnuLdBaseVisitor visitExpRshift(GnuLdParser.ExpRshiftContext ctx) { + return visitChildren(ctx); + } + + @Override + public ElfinfoExprGnuLdBaseVisitor visitExpNextParen(GnuLdParser.ExpNextParenContext ctx) { + return visitChildren(ctx); + } + + @Override + public ElfinfoExprGnuLdBaseVisitor visitExpAlignof(GnuLdParser.ExpAlignofContext ctx) { + return visitChildren(ctx); + } + + @Override + public ElfinfoExprGnuLdBaseVisitor visitExpSegmentStart(GnuLdParser.ExpSegmentStartContext ctx) { + return visitChildren(ctx); + } + + @Override + public ElfinfoExprGnuLdBaseVisitor visitExpInt(GnuLdParser.ExpIntContext ctx) { + System.out.println("ElfinfoGnuLdBaseVisitor.visitExpInt"); + + String str = ctx.INT().getText().toLowerCase(); + int base = 10; + if (str.startsWith("0x")) { + base = 16; + str = str.substring(2); + } + + int factor = 1; + if (str.endsWith("k")) { + factor = 1024; + str = str.substring(0, str.length() - 1); + } else if (str.endsWith("k")) { + factor = 1024 * 1024; + str = str.substring(0, str.length() - 1); + } + + BigInteger i = new BigInteger(str, base); + if (factor > 1) { + i = i.multiply(BigInteger.valueOf(factor)); + } + System.out.println("ctx = " + ctx); + System.out.println("i = " + i); + es.put(ctx, i); + + return this; + } + + @Override + public ElfinfoExprGnuLdBaseVisitor visitExpConstant(GnuLdParser.ExpConstantContext ctx) { + return visitChildren(ctx); + } + + @Override + public ElfinfoExprGnuLdBaseVisitor visitExpPlus(GnuLdParser.ExpPlusContext ctx) { + return visitChildren(ctx); + } + + @Override + public ElfinfoExprGnuLdBaseVisitor visitExpSizeof(GnuLdParser.ExpSizeofContext ctx) { + return visitChildren(ctx); + } + + @Override + public ElfinfoExprGnuLdBaseVisitor visitExpDataSegmentRelRoEnd(GnuLdParser.ExpDataSegmentRelRoEndContext ctx) { + return visitChildren(ctx); + } + + @Override + public ElfinfoExprGnuLdBaseVisitor visitExpAssert(GnuLdParser.ExpAssertContext ctx) { + return visitChildren(ctx); + } + + @Override + public ElfinfoExprGnuLdBaseVisitor visitMustbe_exp(GnuLdParser.Mustbe_expContext ctx) { + ElfinfoExprGnuLdBaseVisitor ret = visitChildren(ctx); + + value = es.removeFrom(ctx.exp()); + es.put(ctx, value); + + return ret; + } + + public BigInteger value() { + if (value != null) { + return value; + } + + throw new RuntimeException("Something bad happened, probably an unevaluated expression part."); + } + } + + private static class ElfinfoGnuLdBaseVisitor extends GnuLdBaseVisitor { + public List memoryAreas = new ArrayList<>(); + + public List
sections = new ArrayList<>(); + + ParseTreeProperty es = new ParseTreeProperty<>(); + + @Override + public ElfinfoGnuLdBaseVisitor visitMemory_spec(GnuLdParser.Memory_specContext ctx) { + System.out.println("ElfinfoGnuLdBaseVisitor.visitMemory_spec"); + visitChildren(ctx); + + if (attributesInverted) { + // not quite sure how this is supposed to work yet + throw new RuntimeException("Inverted memory region attributes is not implemented yet."); + } + + MemoryArea ma = new MemoryArea(); + ma.name = ctx.NAME().getText(); + ma.attributes = attributes; + ma.origin = ElfinfoExprGnuLdBaseVisitor.evaluate(ctx.origin_spec().mustbe_exp()); + ma.length = ElfinfoExprGnuLdBaseVisitor.evaluate(ctx.length_spec().mustbe_exp()); + System.out.println(ma); + memoryAreas.add(ma); + return this; + } + + MemoryAttribute attribute; + boolean attributesInverted; + Set attributes; + + @Override + public ElfinfoGnuLdBaseVisitor visitAttributes_opt(GnuLdParser.Attributes_optContext ctx) { + System.out.println("ElfinfoGnuLdBaseVisitor.visitAttributes_opt"); + attributes = new HashSet<>(); + return visitChildren(ctx); + } + + @Override + public ElfinfoGnuLdBaseVisitor visitAttributeNormal(GnuLdParser.AttributeNormalContext ctx) { + System.out.println("ElfinfoGnuLdBaseVisitor.visitAttributeNormal"); + String name = ctx.NAME().getText(); + System.out.println("ctx.ATTRIBUTE().getText() = " + name); + for (int i = 0; i < name.length(); i++) { + attribute = MemoryAttribute.valueOf(String.valueOf(Character.toUpperCase(name.charAt(i)))); + attributes.add(attribute); + } + attributesInverted = false; + return visitChildren(ctx); + } + + @Override + public ElfinfoGnuLdBaseVisitor visitAttributeInverted(GnuLdParser.AttributeInvertedContext ctx) { + System.out.println("ElfinfoGnuLdBaseVisitor.visitAttributeInverted"); + if (!attributes.isEmpty()) { + throw new RuntimeException("Attributes for memory areas can only be attributesInverted (with '!') as the first character in a specification; foo(!rw), not foo(x!rw)."); + } + String name = ctx.NAME().getText(); + System.out.println("ctx.ATTRIBUTE().getText() = " + name); + + attributesInverted = true; + return visitChildren(ctx); + } + } +} -- cgit v1.2.3