/* A YACC grammar to parse a superset of the AT&T linker scripting language.
- Copyright (C) 1991-2021 Free Software Foundation, Inc.
+ Copyright (C) 1991-2023 Free Software Foundation, Inc.
Written by Steve Chamberlain of Cygnus Support (steve@cygnus.com).
This file is part of the GNU Binutils.
#endif
static enum section_type sectype;
+static etree_type *sectype_value;
static lang_memory_region_type *region;
static bool ldgram_had_keep = false;
%right UNARY
%token END
%left <token> '('
-%token <token> ALIGN_K BLOCK BIND QUAD SQUAD LONG SHORT BYTE
-%token SECTIONS PHDRS INSERT_K AFTER BEFORE
+%token <token> ALIGN_K BLOCK BIND QUAD SQUAD LONG SHORT BYTE ASCIZ
+%token SECTIONS PHDRS INSERT_K AFTER BEFORE LINKER_VERSION
%token DATA_SEGMENT_ALIGN DATA_SEGMENT_RELRO_END DATA_SEGMENT_END
%token SORT_BY_NAME SORT_BY_ALIGNMENT SORT_NONE
%token SORT_BY_INIT_PRIORITY
%token LD_FEATURE
%token NOLOAD DSECT COPY INFO OVERLAY
%token READONLY
+%token TYPE
%token DEFINED TARGET_K SEARCH_DIR MAP ENTRY
%token <integer> NEXT
%token SIZEOF ALIGNOF ADDR LOADADDR MAX_K MIN_K
| CASE casesymlist
| EXTERN extern_name_list
| INCLUDE filename
- { ldlex_script (); ldfile_open_command_file($2); }
+ { ldfile_open_command_file ($2); }
mri_script_lines END
- { ldlex_popstate (); }
| START NAME
{ lang_add_entry ($2, false); }
|
| 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
+ NAME
{ ldlang_add_undef ($1, false); }
- | extern_name_list_body NAME
+ | extern_name_list NAME
{ ldlang_add_undef ($2, false); }
- | extern_name_list_body ',' NAME
+ | extern_name_list ',' NAME
{ ldlang_add_undef ($3, false); }
;
| MAP '(' filename ')'
{ lang_add_map($3); }
| INCLUDE filename
- { ldlex_script (); ldfile_open_command_file($2); }
+ { ldfile_open_command_file ($2); }
ifile_list END
- { ldlex_popstate (); }
| NOCROSSREFS '(' nocrossref_list ')'
{
lang_add_nocrossref ($3);
{
lang_add_nocrossref_to ($3);
}
- | EXTERN '(' extern_name_list ')'
+ | EXTERN '(' { ldlex_expression (); } extern_name_list ')'
+ { ldlex_popstate (); }
| INSERT_K AFTER NAME
{ lang_add_insert ($3, 0); }
| INSERT_K BEFORE NAME
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_maybe_exclude:
{
lang_add_data ((int) $1, $3);
}
-
+ | ASCIZ NAME
+ {
+ lang_add_string ($2);
+ }
| FILL '(' fill_exp ')'
{
lang_add_fill ($3);
}
+ | LINKER_VERSION
+ {
+ lang_add_version_string ();
+ }
| ASSERT_K
{ ldlex_expression (); }
'(' exp ',' NAME ')' separator
}
| INCLUDE filename
{
- ldlex_script ();
ldfile_open_command_file ($2);
}
statement_list_opt END
- { ldlex_popstate (); }
;
statement_list:
fill_exp:
mustbe_exp
{
- $$ = exp_get_fill ($1, 0, "fill value");
+ $$ = exp_get_fill ($1, 0, _("fill value"));
}
;
origin_spec opt_comma length_spec
{}
| INCLUDE filename
- { ldlex_script (); ldfile_open_command_file($2); }
+ { ldfile_open_command_file ($2); }
memory_spec_list_opt END
- { ldlex_popstate (); }
;
origin_spec:
length_spec:
LENGTH '=' mustbe_exp
{
+ if (yychar == NAME)
+ {
+ yyclearin;
+ ldlex_backup ();
+ }
region->length_exp = $3;
}
;
{
ldlex_popstate ();
ldlex_wild ();
- lang_enter_output_section_statement($1, $3, sectype,
- $5, $7, $4,
- $8, $6);
+ lang_enter_output_section_statement ($1, $3, sectype,
+ sectype_value, $5, $7, $4, $8, $6);
}
'{'
statement_list_opt
{ ldlex_popstate (); }
memspec_opt memspec_at_opt phdr_opt fill_opt
{
+ /* fill_opt may have switched the lexer into
+ expression state, and back again, but in
+ order to find the end of the fill
+ expression the parser must look ahead one
+ token. If it is a NAME, throw it away as
+ it will have been lexed in the wrong
+ state. */
+ if (yychar == NAME)
+ {
+ yyclearin;
+ ldlex_backup ();
+ }
lang_leave_output_section_statement ($17, $14,
$16, $15);
}
'}'
memspec_opt memspec_at_opt phdr_opt fill_opt
{
+ if (yychar == NAME)
+ {
+ yyclearin;
+ ldlex_backup ();
+ }
lang_leave_overlay ($5, (int) $4,
$15, $12, $14, $13);
}
'{' sec_or_group_p1 '}'
| INCLUDE filename
{
- ldlex_script ();
ldfile_open_command_file ($2);
}
sec_or_group_p1 END
- { ldlex_popstate (); }
;
type:
| COPY { sectype = noalloc_section; }
| INFO { sectype = noalloc_section; }
| OVERLAY { sectype = noalloc_section; }
+ | READONLY '(' TYPE '=' exp ')' { sectype = typed_readonly_section; sectype_value = $5; }
| READONLY { sectype = readonly_section; }
- ;
+ | TYPE '=' exp { sectype = type_section; sectype_value = $3; }
+ ;
atype:
'(' type ')'
{ ldlex_popstate (); }
phdr_opt fill_opt
{
+ if (yychar == NAME)
+ {
+ yyclearin;
+ ldlex_backup ();
+ }
lang_leave_overlay_section ($9, $8);
}
opt_comma
$$ = exp_intop (0x6474e550);
else if (strcmp (s, "PT_GNU_STACK") == 0)
$$ = exp_intop (0x6474e551);
+ else if (strcmp (s, "PT_GNU_RELRO") == 0)
+ $$ = exp_intop (0x6474e552);
+ else if (strcmp (s, "PT_GNU_PROPERTY") == 0)
+ $$ = exp_intop (0x6474e553);
else
{
einfo (_("\
einfo (_("%P:%s: file format not recognized; treating as linker script\n"),
ldlex_filename ());
if (error_index > 0 && error_index < ERROR_NAME_MAX)
- einfo ("%F%P:%pS: %s in %s\n", NULL, arg, error_names[error_index - 1]);
+ einfo (_("%F%P:%pS: %s in %s\n"), NULL, arg, error_names[error_index - 1]);
else
einfo ("%F%P:%pS: %s\n", NULL, arg);
}