2004-07-07 Guilherme Destefani Adding linker script command TEMPORARY and option --deftmp that overrides script defined variables Useful to use a temporary symbol just for calculation, that's not stored in the bfd backend --- ld/ld.h 2004-01-14 21:07:52.000000000 +0000 +++ ld/ld.h 2004-07-08 22:47:45.000000000 +0000 @@ -231,6 +231,8 @@ /* Non-zero if we are processing a --defsym from the command line. */ extern int parsing_defsym; +/* Non-zero if we are processing a --deftmp from the command line. */ +extern int parsing_deftmp; extern int yyparse (void); extern void add_cref (const char *, bfd *, asection *, bfd_vma); --- ld/ld.texinfo 2004-04-12 19:56:35.000000000 +0000 +++ ld/ld.texinfo 2004-07-08 22:47:45.000000000 +0000 @@ -1089,6 +1089,21 @@ space between @var{symbol}, the equals sign (``@key{=}''), and @var{expression}. +@kindex --deftmp @var{symbol}=@var{exp} +@item --deftmp @var{symbol}=@var{expression} +Define a temporary symbol overriding the value of the @var{symbol} just in the +linker script, but without changing the value of the @var{symbol} on the file. +You may use this option as many times as necessary to define multiple +temporary symbols in the command line. A limited form of arithmetic +is supported for the @var{expression} in this context: you may give a +hexadecimal constant or the name of an existing symbol, or use @code{+} +and @code{-} to add or subtract hexadecimal constants or symbols. +If you need more elaborate expressions, consider +using the linker command language from a script (@pxref{Assignments,, +Assignment: Symbol Definitions}). @emph{Note:} there should be no white +space between @var{symbol}, the equals sign (``@key{=}''), and +@var{expression}. + @cindex demangling, from command line @kindex --demangle[=@var{style}] @kindex --no-demangle @@ -2632,6 +2647,7 @@ @menu * Simple Assignments:: Simple Assignments * PROVIDE:: PROVIDE +* TEMPORARY:: TEMPORARY @end menu @node Simple Assignments @@ -2724,6 +2740,16 @@ If the program references @samp{etext} but does not define it, the linker will use the definition in the linker script. +@node TEMPORARY +@subsection TEMPORARY +@cindex TEMPORARY +In some cases, it is desirable for a linker script to use a name + just to hold a value without sending a symbol to the bfd backend. +The @code{TEMPORARY} keyword may be used to define that type of variable. +The syntax is: +@code{TEMPORARY(@var{symbol} = @var{expression})}. + + @node SECTIONS @section SECTIONS Command @kindex SECTIONS --- ld/ldexp.c 2004-07-08 22:48:38.997245672 +0000 +++ ld/ldexp.c 2004-07-08 22:47:45.000000000 +0000 @@ -491,7 +491,8 @@ bfd_vma dot) { etree_value_type result; - + temporary_variable_list_type *temporary; + result.valid_p = FALSE; switch (tree->type.node_code) @@ -529,6 +530,10 @@ if (allocation_done != lang_first_phase_enum) result = new_rel_from_section (dot, current_section); } + else if ( (temporary = lang_temporary_lookup(tree->name.name) ) ) + { + result = new_abs(temporary->value); + } else if (allocation_done != lang_first_phase_enum) { struct bfd_link_hash_entry *h; @@ -692,6 +697,8 @@ case etree_assign: case etree_provide: case etree_provided: + case etree_temporary_from_argument: + case etree_temporary_from_script: if (tree->assign.dst[0] == '.' && tree->assign.dst[1] == 0) { /* Assignment to dot can only be done during allocation. */ @@ -733,6 +740,16 @@ current_section, allocation_done, dot, dotp); if (result.valid_p) + { + if (tree->type.node_class == etree_temporary_from_argument) + { + lang_temporary_set (tree->assign.dst, result.value, temporary_from_argument_enum); + } + else if (tree->type.node_class == etree_temporary_from_script) + { + lang_temporary_set (tree->assign.dst, result.value, temporary_from_script_enum); + } + else { bfd_boolean create; struct bfd_link_hash_entry *h; @@ -769,6 +786,7 @@ tree->type.node_class = etree_provided; } } + } } break; @@ -906,6 +924,21 @@ return n; } +/* Handle TEMPORARY. */ + +etree_type * +exp_temporary (const char *dst, etree_type *src, short type) +{ + etree_type *n; + + n = stat_alloc (sizeof (n->assign)); + n->assign.type.node_code = '='; + n->assign.type.node_class = type; + n->assign.src = src; + n->assign.dst = dst; + return n; +} + /* Handle ASSERT. */ etree_type * @@ -961,6 +994,12 @@ exp_print_tree (tree->assign.src); fprintf (config.map_file, ")"); break; + case etree_temporary_from_argument: + case etree_temporary_from_script: + fprintf (config.map_file, "TEMPORARY (%s, ", tree->assign.dst); + exp_print_tree (tree->assign.src); + fprintf (config.map_file, ")"); + break; case etree_binary: fprintf (config.map_file, "("); exp_print_tree (tree->binary.lhs); --- ld/ldexp.h 2004-07-08 22:48:38.998245520 +0000 +++ ld/ldexp.h 2004-07-08 22:47:45.000000000 +0000 @@ -40,6 +40,8 @@ etree_assign, etree_provide, etree_provided, + etree_temporary_from_argument, + etree_temporary_from_script, etree_undef, etree_unspec, etree_value, @@ -128,6 +130,8 @@ (int, const char *, etree_type *); etree_type *exp_provide (const char *, etree_type *); +etree_type *exp_temporary + (const char *, etree_type *, short); etree_type *exp_assert (etree_type *, const char *); void exp_print_tree --- ld/ldgram.y 2004-07-08 22:48:38.987247192 +0000 +++ ld/ldgram.y 2004-07-08 22:47:44.000000000 +0000 @@ -147,7 +147,7 @@ %type filename %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 CASE EXTERN START +%token INPUT_SCRIPT INPUT_MRI_SCRIPT INPUT_DEFSYM INPUT_DEFTMP CASE EXTERN START TEMPORARY %token VERS_TAG VERS_IDENTIFIER %token GLOBAL LOCAL VERSIONK INPUT_VERSION_SCRIPT %token KEEP ONLY_IF_RO ONLY_IF_RW @@ -163,6 +163,7 @@ | INPUT_MRI_SCRIPT mri_script_file | INPUT_VERSION_SCRIPT version_script_file | INPUT_DEFSYM defsym_expr + | INPUT_DEFTMP deftmp_expr ; @@ -178,6 +179,15 @@ } ; +deftmp_expr: + { ldlex_deftmp(); } + NAME '=' exp + { + ldlex_popstate(); + lang_add_assignment(exp_temporary ($2, $4, etree_temporary_from_argument)); + } + ; + /* SYNTAX WITHIN AN MRI SCRIPT FILE */ mri_script_file: { @@ -611,6 +621,10 @@ { lang_add_assignment (exp_provide ($3, $5)); } + | TEMPORARY '(' NAME '=' mustbe_exp ')' + { + lang_add_assignment (exp_temporary ($3, $5, etree_temporary_from_script)); + } ; --- ld/ldlang.c 2004-07-08 22:48:39.014243088 +0000 +++ ld/ldlang.c 2004-07-08 22:47:45.000000000 +0000 @@ -658,6 +658,61 @@ return lang_output_section_statement_lookup_1 (name, 0); } +/* A temporary variable can be used to store a value without + saving it on the bfd backends + The syntax to declare a a temporary variable is: + TEMPORARAY ( VARNAME = EXPRESSION ); + Then the value can be used later on like any other symbol. + The linker use a liked list to store those values in memory. +*/ + +static temporary_variable_list_type *lang_temporary_list = NULL; +static temporary_variable_list_type **lang_temporary_list_tail = &lang_temporary_list; + +temporary_variable_list_type *lang_temporary_lookup(char const *const name) +{ + temporary_variable_list_type *temp; + + if (name == NULL) + return NULL; + + for (temp = lang_temporary_list; temp != NULL; temp = temp->next) + if (strcmp (temp->name, name) == 0) + break; + return temp; +} + +temporary_variable_list_type *lang_temporary_set(char const *const name, bfd_vma value, short type) +{ + temporary_variable_list_type *temp; + + if (! name[0] ) + return NULL; + + /*Try to reuse element already defined*/ + if ( (temp = lang_temporary_lookup (name)) ){ + /*A temporary variable from a script can't + update the variable from the command line*/ + if (temp->type <= type) + free (temp->name); + else return temp; /*Otherwise just ignore assignment from script*/ + } + else + { + /*Allocate a new element and link it to list*/ + temp = xmalloc(sizeof(temporary_variable_list_type)); + temp->next = NULL; + + *lang_temporary_list_tail = temp; + lang_temporary_list_tail = &temp->next; + } + + temp->name = xstrdup(name); + temp->value = value; + temp->type = type; + return temp; +} + static void lang_map_flags (flagword flag) { --- ld/ldlang.h 2004-07-08 22:48:36.090687536 +0000 +++ ld/ldlang.h 2004-07-08 22:47:45.000000000 +0000 @@ -103,6 +103,19 @@ const char *name; } lang_output_statement_type; +/* Used to store temporary link script variables in memory*/ +typedef struct temporary_variable_list_struct +{ + struct temporary_variable_list_struct *next; + bfd_vma value; + char *name; + enum temporary_variable_enum + { + temporary_from_script_enum, + temporary_from_argument_enum + } type; +} temporary_variable_list_type; + /* Section types specified in a linker script. */ enum section_type @@ -428,6 +441,10 @@ (const char *const, bfd_boolean); extern lang_memory_region_type *lang_memory_region_default (asection *); +extern temporary_variable_list_type *lang_temporary_lookup + (char const *const); +extern temporary_variable_list_type *lang_temporary_set + (char const *const, bfd_vma, short); extern void lang_map (void); extern void lang_set_flags --- ld/ldlex.h 2004-01-14 21:07:52.000000000 +0000 +++ ld/ldlex.h 2004-07-08 22:47:45.000000000 +0000 @@ -30,7 +30,8 @@ input_script, input_mri_script, input_version_script, - input_defsym + input_defsym, + input_deftmp } input_type; extern input_type parser_input; @@ -47,6 +48,7 @@ extern void ldlex_version_script (void); extern void ldlex_version_file (void); extern void ldlex_defsym (void); +extern void ldlex_deftmp (void); extern void ldlex_expression (void); extern void ldlex_both (void); extern void ldlex_command (void); --- ld/ldlex.l 2004-07-08 22:48:38.986247344 +0000 +++ ld/ldlex.l 2004-07-08 22:47:44.000000000 +0000 @@ -81,6 +81,7 @@ SCRIPT definitely in a script BOTH either EXPRESSION or SCRIPT DEFSYMEXP in an argument to -defsym + DEFTMPEXP in an argument to -deftmp MRI in an MRI script VERS_START starting a Sun style mapfile VERS_SCRIPT a Sun style mapfile @@ -114,6 +115,7 @@ %s EXPRESSION %s BOTH %s DEFSYMEXP +%s DEFTMPEXP %s MRI %s VERS_START %s VERS_SCRIPT @@ -131,6 +133,7 @@ case input_mri_script: return INPUT_MRI_SCRIPT; break; case input_version_script: return INPUT_VERSION_SCRIPT; break; case input_defsym: return INPUT_DEFSYM; break; + case input_deftmp: return INPUT_DEFTMP; break; default: abort (); } } @@ -143,6 +146,11 @@ {FILENAMECHAR1}{SYMBOLCHARN}* { yylval.name = xstrdup (yytext); return NAME; } "=" { RTOKEN('='); } +"-" { RTOKEN('-');} +"+" { RTOKEN('+');} +{FILENAMECHAR1}{SYMBOLCHARN}* { yylval.name = xstrdup (yytext); return NAME; } +"=" { RTOKEN('='); } + "$"([0-9A-Fa-f])+ { yylval.integer = bfd_scan_vma (yytext + 1, 0, 16); yylval.bigint.str = NULL; @@ -174,7 +182,7 @@ yylval.bigint.str = NULL; return INT; } -((("$"|0[xX])([0-9A-Fa-f])+)|(([0-9])+))(M|K|m|k)? { +((("$"|0[xX])([0-9A-Fa-f])+)|(([0-9])+))(M|K|m|k)? { char *s = yytext; int ibase = 0; @@ -269,6 +277,7 @@ "INPUT" { RTOKEN(INPUT);} "GROUP" { RTOKEN(GROUP);} "DEFINED" { RTOKEN(DEFINED);} +"TEMPORARY" { RTOKEN(TEMPORARY); } "CREATE_OBJECT_SYMBOLS" { RTOKEN(CREATE_OBJECT_SYMBOLS);} "CONSTRUCTORS" { RTOKEN( CONSTRUCTORS);} "FORCE_COMMON_ALLOCATION" { RTOKEN(FORCE_COMMON_ALLOCATION);} @@ -442,7 +451,7 @@ } . lex_warn_invalid (" in script", yytext); -. lex_warn_invalid (" in expression", yytext); +. lex_warn_invalid (" in expression", yytext); %% @@ -571,6 +580,13 @@ } void +ldlex_deftmp (void) +{ + *(state_stack_p)++ = yy_start; + BEGIN (DEFTMPEXP); +} + +void ldlex_expression (void) { *(state_stack_p)++ = yy_start; --- ld/ldmisc.c 2004-01-14 21:07:52.000000000 +0000 +++ ld/ldmisc.c 2004-07-08 22:47:45.000000000 +0000 @@ -205,6 +205,8 @@ /* Print script file and linenumber. */ if (parsing_defsym) fprintf (fp, "--defsym %s", lex_string); + else if (parsing_deftmp) + fprintf (fp, "--deftmp %s", lex_string); else if (ldfile_input_filename != NULL) fprintf (fp, "%s:%u", ldfile_input_filename, lineno); else --- ld/lexsup.c 2004-04-12 19:56:36.000000000 +0000 +++ ld/lexsup.c 2004-07-08 22:47:45.000000000 +0000 @@ -59,6 +59,8 @@ /* Non-zero if we are processing a --defsym from the command line. */ int parsing_defsym = 0; +/* Non-zero if we are processing a --deftmp from the command line. */ +int parsing_deftmp = 0; /* Codes used for the long options with no short synonyms. 150 isn't special; it's just an arbitrary non-ASCII char value. */ @@ -68,6 +70,7 @@ OPTION_CALL_SHARED, OPTION_CREF, OPTION_DEFSYM, + OPTION_DEFTMP, OPTION_DEMANGLE, OPTION_DEMANGLER, OPTION_DYNAMIC_LINKER, @@ -314,6 +317,8 @@ '\0', NULL, N_("Output cross reference table"), TWO_DASHES }, { {"defsym", required_argument, NULL, OPTION_DEFSYM}, '\0', N_("SYMBOL=EXPRESSION"), N_("Define a symbol"), TWO_DASHES }, + { {"deftmp", required_argument, NULL, OPTION_DEFTMP}, + '\0', N_("SYMBOL=EXPRESSION"), N_("Define a temporary script variable"), TWO_DASHES }, { {"demangle", optional_argument, NULL, OPTION_DEMANGLE}, '\0', N_("[=STYLE]"), N_("Demangle symbol names [using STYLE]"), TWO_DASHES }, { {"demangler", no_argument, NULL, OPTION_DEMANGLER}, @@ -664,6 +669,15 @@ parsing_defsym = 0; lex_string = NULL; break; + case OPTION_DEFTMP: + lex_string = optarg; + lex_redirect (optarg); + parser_input = input_deftmp; + parsing_deftmp = 1; + yyparse (); + parsing_deftmp = 0; + lex_string = NULL; + break; case OPTION_DEMANGLE: demangling = TRUE; if (optarg != NULL)