+ | { $$ = 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);
+ }