X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=ld%2Fldgram.y;h=6c46c854473d63618c9416fbe0c32913f8558f1d;hb=2da6aac335bbbc38795735152a59fe9693083601;hp=0640afee315a879555805ab8e4d9dc3ec84d103b;hpb=27baca7182ea8cdc7a259b163aa327a0a297e755;p=deliverable%2Fbinutils-gdb.git diff --git a/ld/ldgram.y b/ld/ldgram.y index 0640afee31..6c46c85447 100644 --- a/ld/ldgram.y +++ b/ld/ldgram.y @@ -1,5 +1,6 @@ -/* A YACC grammer to parse a superset of the AT&T linker scripting languaue. - Copyright (C) 1991, 1993 Free Software Foundation, Inc. +/* A YACC grammar to parse a superset of the AT&T linker scripting language. + Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, + 2001, 2002, 2003 Free Software Foundation, Inc. Written by Steve Chamberlain of Cygnus Support (steve@cygnus.com). This file is part of GNU ld. @@ -16,7 +17,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software -Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ %{ /* @@ -28,32 +29,34 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "bfd.h" #include "sysdep.h" #include "bfdlink.h" -#include "ld.h" +#include "ld.h" #include "ldexp.h" #include "ldver.h" #include "ldlang.h" -#include "ldemul.h" #include "ldfile.h" +#include "ldemul.h" #include "ldmisc.h" #include "ldmain.h" #include "mri.h" +#include "ldctor.h" #include "ldlex.h" +#ifndef YYDEBUG #define YYDEBUG 1 +#endif -static int typebits; +static enum section_type sectype; lang_memory_region_type *region; +bfd_boolean ldgram_want_filename = TRUE; +FILE *saved_script_handle = NULL; +bfd_boolean force_make_executable = FALSE; -char *current_file; -boolean ldgram_want_filename = true; -boolean had_script = false; -boolean force_make_executable = false; - -boolean ldgram_in_script = false; -boolean ldgram_had_equals = false; - +bfd_boolean ldgram_in_script = FALSE; +bfd_boolean ldgram_had_equals = FALSE; +bfd_boolean ldgram_had_keep = FALSE; +char *ldgram_vers_current_lang = NULL; #define ERROR_NAME_MAX 20 static char *error_names[ERROR_NAME_MAX]; @@ -63,19 +66,51 @@ static int error_index; %} %union { bfd_vma integer; + struct big_int + { + bfd_vma integer; + char *str; + } bigint; + fill_type *fill; char *name; + const char *cname; + struct wildcard_spec wildcard; + struct wildcard_list *wildcard_list; + struct name_list *name_list; int token; union etree_union *etree; + struct phdr_info + { + bfd_boolean filehdr; + bfd_boolean phdrs; + union etree_union *at; + union etree_union *flags; + } phdr; + struct lang_nocrossref *nocrossref; + struct lang_output_section_phdr_list *section_phdr; + struct bfd_elf_version_deps *deflist; + struct bfd_elf_version_expr *versyms; + struct bfd_elf_version_tree *versnode; } -%type exp opt_exp_with_type mustbe_exp opt_at -%type fill_opt -%type memspec_opt -%token INT -%token NAME -%type length - -%right PLUSEQ MINUSEQ MULTEQ DIVEQ '=' LSHIFTEQ RSHIFTEQ ANDEQ OREQ +%type exp opt_exp_with_type mustbe_exp opt_at phdr_type phdr_val +%type opt_exp_without_type opt_subalign +%type fill_opt fill_exp +%type exclude_name_list +%type file_NAME_list +%type memspec_opt casesymlist +%type memspec_at_opt +%type wildcard_name +%type wildcard_spec +%token INT +%token NAME LNAME +%type length +%type phdr_qualifiers +%type nocrossref_list +%type phdr_opt +%type opt_nocrossrefs + +%right PLUSEQ MINUSEQ MULTEQ DIVEQ '=' LSHIFTEQ RSHIFTEQ ANDEQ OREQ %right '?' ':' %left OROR %left ANDAND @@ -90,33 +125,43 @@ static int error_index; %left '*' '/' '%' %right UNARY -%token END +%token END %left '(' -%token ALIGN_K BLOCK QUAD LONG SHORT BYTE -%token SECTIONS +%token ALIGN_K BLOCK BIND QUAD SQUAD LONG SHORT BYTE +%token SECTIONS PHDRS SORT DATA_SEGMENT_ALIGN DATA_SEGMENT_END %token '{' '}' %token SIZEOF_HEADERS OUTPUT_FORMAT FORCE_COMMON_ALLOCATION OUTPUT_ARCH +%token INHIBIT_COMMON_ALLOCATION %token SIZEOF_HEADERS %token INCLUDE %token MEMORY DEFSYMEND %token NOLOAD DSECT COPY INFO OVERLAY -%token NAME DEFINED TARGET_K SEARCH_DIR MAP ENTRY -%token SIZEOF NEXT ADDR -%token STARTUP HLL SYSLIB FLOAT NOFLOAT +%token NAME LNAME DEFINED TARGET_K SEARCH_DIR MAP ENTRY +%token NEXT +%token SIZEOF ADDR LOADADDR MAX_K MIN_K +%token STARTUP HLL SYSLIB FLOAT NOFLOAT NOCROSSREFS %token ORIGIN FILL -%token LENGTH CREATE_OBJECT_SYMBOLS INPUT OUTPUT CONSTRUCTORS -%token ALIGNMOD AT -%type assign_op +%token LENGTH CREATE_OBJECT_SYMBOLS INPUT GROUP OUTPUT CONSTRUCTORS +%token ALIGNMOD AT SUBALIGN PROVIDE +%type assign_op atype attributes_opt %type filename -%token CHIP LIST SECT ABSOLUTE LOAD NEWLINE ENDWORD ORDER NAMEWORD +%token CHIP LIST SECT ABSOLUTE LOAD NEWLINE ENDWORD ORDER NAMEWORD ASSERT_K %token FORMAT PUBLIC DEFSYMEND BASE ALIAS TRUNCATE REL -%token INPUT_SCRIPT INPUT_MRI_SCRIPT INPUT_DEFSYM +%token INPUT_SCRIPT INPUT_MRI_SCRIPT INPUT_DEFSYM CASE EXTERN START +%token VERS_TAG VERS_IDENTIFIER +%token GLOBAL LOCAL VERSIONK INPUT_VERSION_SCRIPT +%token KEEP +%token EXCLUDE_FILE +%type vers_defns +%type vers_tag +%type verdep %% -file: +file: INPUT_SCRIPT script_file | INPUT_MRI_SCRIPT mri_script_file + | INPUT_VERSION_SCRIPT version_script_file | INPUT_DEFSYM defsym_expr ; @@ -131,15 +176,19 @@ defsym_expr: ldlex_popstate(); lang_add_assignment(exp_assop($3,$2,$4)); } + ; -/* SYNTAX WITHIN AN MRI SCRIPT FILE */ +/* SYNTAX WITHIN AN MRI SCRIPT FILE */ mri_script_file: - { ldlex_mri_script(); - PUSH_ERROR("MRI style script"); + { + ldlex_mri_script (); + PUSH_ERROR (_("MRI style script")); } mri_script_lines - { ldlex_popstate(); - POP_ERROR(); + { + ldlex_popstate (); + mri_draw_tree (); + POP_ERROR (); } ; @@ -149,26 +198,25 @@ mri_script_lines: ; mri_script_command: - CHIP exp + CHIP exp | CHIP exp ',' exp | NAME { - einfo("%P%F: unrecognised keyword in MRI style script '%s'\n",$1); + einfo(_("%P%F: unrecognised keyword in MRI style script '%s'\n"),$1); } | LIST { - write_map = true; config.map_filename = "-"; } | ORDER ordernamelist - | ENDWORD - | PUBLIC NAME '=' exp + | ENDWORD + | PUBLIC NAME '=' exp { mri_public($2, $4); } - | PUBLIC NAME ',' exp + | PUBLIC NAME ',' exp { mri_public($2, $4); } - | PUBLIC NAME exp + | PUBLIC NAME exp { mri_public($2, $3); } | FORMAT NAME { mri_format($2); } - | SECT NAME ',' exp + | SECT NAME ',' exp { mri_output_section($2, $4);} | SECT NAME exp { mri_output_section($2, $3);} @@ -176,20 +224,32 @@ mri_script_command: { 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); } + | NAMEWORD NAME + { mri_name($2); } | ALIAS NAME ',' NAME { mri_alias($2,$4,0);} | ALIAS NAME ',' INT - { mri_alias($2,0,(int) $4);} + { mri_alias ($2, 0, (int) $4.integer); } | BASE exp { mri_base($2); } - | TRUNCATE INT - { mri_truncate((unsigned int) $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); } | ; @@ -212,6 +272,21 @@ mri_abs_name_list: { mri_only_load($3); } ; +casesymlist: + /* empty */ { $$ = NULL; } + | NAME + | casesymlist ',' NAME + ; + +extern_name_list: + NAME + { ldlang_add_undef ($1); } + | extern_name_list NAME + { ldlang_add_undef ($2); } + | extern_name_list ',' NAME + { ldlang_add_undef ($3); } + ; + script_file: { ldlex_both(); @@ -233,29 +308,47 @@ ifile_list: 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); } + { ldfile_add_library_path ($3, FALSE); } | OUTPUT '(' filename ')' { lang_add_output($3, 1); } | OUTPUT_FORMAT '(' NAME ')' - { lang_add_output_format($3, 1); } + { 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); } + { ldfile_set_output_arch ($3, bfd_arch_unknown); } | FORCE_COMMON_ALLOCATION - { command_line.force_common_definition = true ; } + { 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 - { ldfile_open_command_file($2); } ifile_list END + | INCLUDE filename + { ldlex_script (); ldfile_open_command_file($2); } + ifile_list END + { ldlex_popstate (); } + | NOCROSSREFS '(' nocrossref_list ')' + { + lang_add_nocrossref ($3); + } + | EXTERN '(' extern_name_list ')' ; input_list: @@ -268,6 +361,15 @@ input_list: | input_list 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_list ',' LNAME + { lang_add_input_file($3,lang_input_file_is_l_enum, + (char *)NULL); } + | input_list LNAME + { lang_add_input_file($2,lang_input_file_is_l_enum, + (char *)NULL); } ; sections: @@ -282,65 +384,150 @@ sec_or_group_p1: statement_anywhere: ENTRY '(' NAME ')' - { lang_add_entry($3); } + { lang_add_entry ($3, FALSE); } | assignment end + | ASSERT_K {ldlex_expression ();} '(' exp ',' NAME ')' + { ldlex_popstate (); + lang_add_assignment (exp_assert ($4, $6)); } ; -file_NAME_list: +/* The '*' and '?' cases are there because the lexer returns them as + separate tokens rather than as NAME. */ +wildcard_name: NAME - { lang_add_wild($1, current_file); } - | file_NAME_list opt_comma NAME - { lang_add_wild($3, current_file); } + { + $$ = $1; + } + | '*' + { + $$ = "*"; + } + | '?' + { + $$ = "?"; + } ; -input_section_spec: +wildcard_spec: + wildcard_name + { + $$.name = $1; + $$.sorted = FALSE; + $$.exclude_name_list = NULL; + } + | EXCLUDE_FILE '(' exclude_name_list ')' wildcard_name + { + $$.name = $5; + $$.sorted = FALSE; + $$.exclude_name_list = $3; + } + | SORT '(' wildcard_name ')' + { + $$.name = $3; + $$.sorted = TRUE; + $$.exclude_name_list = NULL; + } + | SORT '(' EXCLUDE_FILE '(' exclude_name_list ')' wildcard_name ')' + { + $$.name = $7; + $$.sorted = TRUE; + $$.exclude_name_list = $5; + } + ; + +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 - { - lang_add_wild((char *)NULL, $1); - } - | '[' { - current_file = (char *)NULL; + struct wildcard_spec tmp; + tmp.name = $1; + tmp.exclude_name_list = NULL; + tmp.sorted = FALSE; + lang_add_wild (&tmp, NULL, ldgram_had_keep); } - file_NAME_list - ']' - | NAME + | '[' file_NAME_list ']' { - current_file =$1; + lang_add_wild (NULL, $2, ldgram_had_keep); } - '(' file_NAME_list ')' - | '*' + | wildcard_spec '(' file_NAME_list ')' { - current_file = (char *)NULL; + lang_add_wild (&$1, $3, ldgram_had_keep); } - '(' file_NAME_list ')' + ; + +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); + lang_add_attribute(lang_object_symbols_statement_enum); } | ';' | CONSTRUCTORS { - - lang_add_attribute(lang_constructors_statement_enum); + + lang_add_attribute(lang_constructors_statement_enum); + } + | SORT '(' CONSTRUCTORS ')' + { + constructors_sorted = TRUE; + lang_add_attribute (lang_constructors_statement_enum); } | input_section_spec - | length '(' exp ')' + | length '(' mustbe_exp ')' { - lang_add_data((int) $1,$3); + lang_add_data ((int) $1, $3); } - - | FILL '(' exp ')' + + | FILL '(' fill_exp ')' { - lang_add_fill - (exp_get_value_int($3, - 0, - "fill value", - lang_first_phase_enum)); + lang_add_fill ($3); } ; @@ -348,7 +535,7 @@ statement_list: statement_list statement | statement ; - + statement_list_opt: /* empty */ | statement_list @@ -357,6 +544,8 @@ statement_list_opt: length: QUAD { $$ = $1; } + | SQUAD + { $$ = $1; } | LONG { $$ = $1; } | SHORT @@ -365,18 +554,21 @@ length: { $$ = $1; } ; -fill_opt: - '=' mustbe_exp +fill_exp: + mustbe_exp { - $$ = exp_get_value_int($2, - 0, - "fill value", - lang_first_phase_enum); + $$ = exp_get_fill ($1, + 0, + "fill value", + lang_first_phase_enum); } - | { $$ = 0; } ; - +fill_opt: + '=' fill_exp + { $$ = $2; } + | { $$ = (fill_type *) 0; } + ; assign_op: PLUSEQ @@ -405,14 +597,20 @@ end: ';' | ',' assignment: NAME '=' mustbe_exp { - lang_add_assignment(exp_assop($2,$1,$3)); + 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))); + 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)); } - ; @@ -431,33 +629,46 @@ memory_spec_list: ; -memory_spec: NAME - { region = lang_memory_region_lookup($1); } +memory_spec: NAME + { region = lang_memory_region_lookup ($1, TRUE); } attributes_opt ':' origin_spec opt_comma length_spec + {} + ; - ; origin_spec: +origin_spec: ORIGIN '=' mustbe_exp { region->current = region->origin = exp_get_vma($3, 0L,"origin", lang_first_phase_enum); } - ; length_spec: + ; + +length_spec: LENGTH '=' mustbe_exp { region->length = exp_get_vma($3, ~((bfd_vma)0), "length", lang_first_phase_enum); } - + ; attributes_opt: - '(' NAME ')' - { - lang_set_flags(®ion->flags, $2); - } - | - + /* 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: @@ -489,11 +700,35 @@ low_level_library: floating_point_support: FLOAT - { lang_float(true); } + { lang_float(TRUE); } | NOFLOAT - { lang_float(false); } + { 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 @@ -555,7 +790,7 @@ exp : | DEFINED '(' NAME ')' { $$ = exp_nameop(DEFINED, $3); } | INT - { $$ = exp_intop($1); } + { $$ = exp_bigintop ($1.integer, $1.str); } | SIZEOF_HEADERS { $$ = exp_nameop(SIZEOF_HEADERS,0); } @@ -563,66 +798,400 @@ exp : { $$ = 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); } + | ALIGN_K '(' exp ',' exp ')' + { $$ = exp_binop(ALIGN_K,$3,$5); } + | DATA_SEGMENT_ALIGN '(' exp ',' exp ')' + { $$ = exp_binop (DATA_SEGMENT_ALIGN, $3, $5); } + | DATA_SEGMENT_END '(' exp ')' + { $$ = exp_unop(DATA_SEGMENT_END, $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; } + | { $$ = 0; } + ; + opt_at: AT '(' exp ')' { $$ = $3; } | { $$ = 0; } ; +opt_subalign: + SUBALIGN '(' exp ')' { $$ = $3; } + | { $$ = 0; } + ; + section: NAME { ldlex_expression(); } - opt_exp_with_type - opt_at { ldlex_popstate(); } + opt_exp_with_type + opt_at + opt_subalign { ldlex_popstate (); ldlex_script (); } '{' { - lang_enter_output_section_statement($1,$3,typebits,0,0,0,$4); + lang_enter_output_section_statement($1, $3, + sectype, + 0, $5, $4); } - statement_list_opt - '}' {ldlex_expression();} memspec_opt fill_opt + statement_list_opt + '}' { ldlex_popstate (); ldlex_expression (); } + memspec_opt memspec_at_opt phdr_opt fill_opt { - ldlex_popstate(); - lang_leave_output_section_statement($12, $11); + ldlex_popstate (); + lang_leave_output_section_statement ($15, $12, $14, $13); } -opt_comma - + 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_assop ('=', ".", $3)); + } + '{' sec_or_group_p1 '}' ; type: - NOLOAD { typebits = SEC_NEVER_LOAD; } - | DSECT { typebits = 0; } - | COPY { typebits = 0; } - | INFO { typebits = 0; } - | OVERLAY { typebits = 0; } - | { typebits = SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS; } + 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 ':' { $$ = $1; typebits =0;} - | exp '(' type ')' ':' { $$ = $1; } - | ':' { $$= (etree_type *)NULL; typebits = 0; } - | '(' type ')' ':' { $$= (etree_type *)NULL; } + 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*"; } + | { $$ = 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"), + 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"), $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 '}' ';' + { + 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); + } + | vers_defns ';' VERS_IDENTIFIER + { + $$ = lang_new_vers_pattern ($1, $3, ldgram_vers_current_lang); + } + | vers_defns ';' EXTERN NAME '{' + { + $$ = ldgram_vers_current_lang; + ldgram_vers_current_lang = $4; + } + vers_defns opt_semicolon '}' + { + $$ = $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; + } + ; + +opt_semicolon: + /* empty */ + | ';' + ; + %% void -yyerror(arg) +yyerror(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]); + einfo ("%P%F:%S: %s in %s\n", arg, error_names[error_index-1]); else - einfo("%P%F: %S %s\n", arg); + einfo ("%P%F:%S: %s\n", arg); }