📄 ldgram.y
字号:
| RSHIFTEQ { $$ = RSHIFT; } | ANDEQ { $$ = '&'; } | OREQ { $$ = '|'; } ;end: ';' | ',' ;assignment: NAME '=' mustbe_exp { lang_add_assignment (exp_assop ($2, $1, $3)); } | NAME assign_op mustbe_exp { lang_add_assignment (exp_assop ('=', $1, exp_binop ($2, exp_nameop (NAME, $1), $3))); } | PROVIDE '(' NAME '=' mustbe_exp ')' { lang_add_assignment (exp_provide ($3, $5)); } ;opt_comma: ',' | ;memory: MEMORY '{' memory_spec memory_spec_list '}' ;memory_spec_list: memory_spec_list memory_spec | memory_spec_list ',' memory_spec | ;memory_spec: NAME { region = lang_memory_region_lookup($1); } attributes_opt ':' origin_spec opt_comma length_spec ;origin_spec: ORIGIN '=' mustbe_exp { region->current = region->origin = exp_get_vma($3, 0L,"origin", lang_first_phase_enum);} ;length_spec: LENGTH '=' mustbe_exp { region->length = exp_get_vma($3, ~((bfd_vma)0), "length", lang_first_phase_enum); } ;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 { lang_set_flags (region, $1, 0); } | '!' NAME { lang_set_flags (region, $2, 1); } ;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 %prec UNARY { $$ = exp_unop('-', $2); } | '(' exp ')' { $$ = $2; } | NEXT '(' exp ')' %prec UNARY { $$ = exp_unop((int) $1,$3); } | '!' exp %prec UNARY { $$ = exp_unop('!', $2); } | '+' exp %prec UNARY { $$ = $2; } | '~' exp %prec UNARY { $$ = exp_unop('~', $2);} | exp '*' exp { $$ = exp_binop('*', $1, $3); } | exp '/' exp { $$ = exp_binop('/', $1, $3); } | exp '%' exp { $$ = exp_binop('%', $1, $3); } | exp '+' exp { $$ = exp_binop('+', $1, $3); } | exp '-' exp { $$ = exp_binop('-' , $1, $3); } | exp LSHIFT exp { $$ = exp_binop(LSHIFT , $1, $3); } | exp RSHIFT exp { $$ = exp_binop(RSHIFT , $1, $3); } | exp EQ exp { $$ = exp_binop(EQ , $1, $3); } | exp NE exp { $$ = exp_binop(NE , $1, $3); } | exp LE exp { $$ = exp_binop(LE , $1, $3); } | exp GE exp { $$ = exp_binop(GE , $1, $3); } | exp '<' exp { $$ = exp_binop('<' , $1, $3); } | exp '>' exp { $$ = exp_binop('>' , $1, $3); } | exp '&' exp { $$ = exp_binop('&' , $1, $3); } | exp '^' exp { $$ = exp_binop('^' , $1, $3); } | exp '|' exp { $$ = exp_binop('|' , $1, $3); } | exp '?' exp ':' exp { $$ = exp_trinop('?' , $1, $3, $5); } | exp ANDAND exp { $$ = exp_binop(ANDAND , $1, $3); } | exp OROR exp { $$ = exp_binop(OROR , $1, $3); } | DEFINED '(' NAME ')' { $$ = exp_nameop(DEFINED, $3); } | INT { $$ = exp_intop($1); } | SIZEOF_HEADERS { $$ = exp_nameop(SIZEOF_HEADERS,0); } | SIZEOF '(' NAME ')' { $$ = exp_nameop(SIZEOF,$3); } | ADDR '(' NAME ')' { $$ = exp_nameop(ADDR,$3); } | LOADADDR '(' NAME ')' { $$ = exp_nameop(LOADADDR,$3); } | ABSOLUTE '(' exp ')' { $$ = exp_unop(ABSOLUTE, $3); } | ALIGN_K '(' exp ')' { $$ = exp_unop(ALIGN_K,$3); } | BLOCK '(' exp ')' { $$ = exp_unop(ALIGN_K,$3); } | NAME { $$ = exp_nameop(NAME,$1); } | MAX_K '(' exp ',' exp ')' { $$ = exp_binop (MAX_K, $3, $5 ); } | MIN_K '(' exp ',' exp ')' { $$ = exp_binop (MIN_K, $3, $5 ); } | ASSERT_K '(' exp ',' NAME ')' { $$ = exp_assert ($3, $5); } ;memspec_at_opt: AT '>' NAME { $$ = $3; } | { $$ = "*default*"; } ;opt_at: AT '(' exp ')' { $$ = $3; } | { $$ = 0; } ;section: NAME { ldlex_expression(); } opt_exp_with_type opt_at { ldlex_popstate (); ldlex_script (); } '{' { lang_enter_output_section_statement($1, $3, sectype, 0, 0, 0, $4); } statement_list_opt '}' { ldlex_popstate (); ldlex_expression (); } memspec_opt memspec_at_opt phdr_opt fill_opt { ldlex_popstate (); lang_leave_output_section_statement ($14, $11, $13, $12); } opt_comma | OVERLAY { ldlex_expression (); } opt_exp_without_type opt_nocrossrefs opt_at { ldlex_popstate (); ldlex_script (); } '{' { lang_enter_overlay ($3, $5, (int) $4); } overlay_section '}' { ldlex_popstate (); ldlex_expression (); } memspec_opt memspec_at_opt phdr_opt fill_opt { ldlex_popstate (); lang_leave_overlay ($15, $12, $14, $13); } 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_assop ('=', ".", $3)); } '{' sec_or_group_p1 '}' ;type: NOLOAD { sectype = noload_section; } | DSECT { sectype = dsect_section; } | COPY { sectype = copy_section; } | INFO { sectype = info_section; } | OVERLAY { sectype = overlay_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*"; } ;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" }; 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; } } } ;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"), $1); } | AT '(' exp ')' phdr_qualifiers { $$ = $5; $$.at = $3; } ;phdr_val: /* empty */ { $$ = NULL; } | '(' exp ')' { $$ = $2; } ;/* 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 '{' 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_regex (NULL, $1, ldgram_vers_current_lang); } | vers_defns ';' VERS_IDENTIFIER { $$ = lang_new_vers_regex ($1, $3, ldgram_vers_current_lang); } | EXTERN NAME '{' { $<name>$ = ldgram_vers_current_lang; ldgram_vers_current_lang = $2; } vers_defns '}' { $$ = $5; ldgram_vers_current_lang = $<name>4; } ;%%voidyyerror(arg) const char *arg;{ if (ldfile_assumed_script) einfo (_("%P:%s: file format not recognized; treating as linker script\n"), ldfile_input_filename); if (error_index > 0 && error_index < ERROR_NAME_MAX) einfo ("%P%F:%S: %s in %s\n", arg, error_names[error_index-1]); else einfo ("%P%F:%S: %s\n", arg);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -