This is the mail archive of the
binutils@sources.redhat.com
mailing list for the binutils project.
Re: RFC and PATCH - Defining variables in the linker scriptwithout defining them as symbols on the file
- From: Guilherme Destefani <gd at helixbrasil dot com dot br>
- To: Zack Weinberg <zack at codesourcery dot com>
- Cc: binutils <binutils at sources dot redhat dot com>
- Date: Thu, 08 Jul 2004 20:43:55 -0300
- Subject: Re: RFC and PATCH - Defining variables in the linker scriptwithout defining them as symbols on the file
- References: <1089293120.1270.19.camel@smeagol.perkons.com.br> <87658yqvko.fsf@codesourcery.com>
On Thu, 2004-07-08 at 14:04, Zack Weinberg wrote:
> Guilherme Destefani <gd@helixbrasil.com.br> writes:
>
> > This patch add to the linker a command like PROVIDE(var=value), named
> > TEMPORARY(var=value) that can be used to define variables just for
> > temporary use, so those variables won't be sent to the file as a symbol.
>
> Ooh, nifty. Would you please investigate adding the ability to set
> these variables from the command line?
Yes, follows a patch to do it too.
> The desired semantic is that
> TEMPORARY(var=value) gets overriden by --some-switch var=value, but
> whether or not that happens, /var/ is available for calculation in
> the linker script. (--defsym symbols can't be used for arbitrary
> calculation.)
While testing if it's working, I found out that if I have a script with
those lines inside SECTIONS{
lixo = lixo_1;
TEMPORARY( lixo_1 = 0x1);
}
I have as result:
make ok;readelf -a ok|grep lixo
cc -Wl,-T -Wl,script -Wl,--deftmp -Wl,lixo1=0x19 -Wl,--deftmp
-Wl,lixo2=0x29 ok.c -o ok
49: 00000001 0 NOTYPE GLOBAL DEFAULT ABS lixo
59: 00000000 0 NOTYPE GLOBAL DEFAULT UND lixo_1
As you can see, lixo_1 ends up as undefined.
The parser accept the variable, but in the tree used to construct the
sentence lixo = lixo_1; lixo_1 is not defined yet. Why the parser accept
a variable that wasn't defined yet?
But if the order is inverted, like this:
SECTIONS{
TEMPORARY( lixo_1 = 0x1);
lixo = lixo_1;
}
The result looks just fine:
make ok;readelf -a ok|grep lixo
cc -Wl,-T -Wl,script -Wl,--deftmp -Wl,lixo1=0x19 -Wl,--deftmp
-Wl,lixo2=0x29 ok.c -o ok
49: 00000001 0 NOTYPE GLOBAL DEFAULT ABS lixo
Why the order of declaration/use force the symbol to be undefined?
The tree isn't evaluated just when needed?
It is OK to left a small amount of memory allocated, like this patch and
the lang_memory_region_list does?
> zw
>
2004-07-07 Guilherme Destefani <gd@helixbrasil.com>
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 <name> 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 <name> 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 @@
<DEFSYMEXP>{FILENAMECHAR1}{SYMBOLCHARN}* { yylval.name = xstrdup (yytext); return NAME; }
<DEFSYMEXP>"=" { RTOKEN('='); }
+<DEFTMPEXP>"-" { RTOKEN('-');}
+<DEFTMPEXP>"+" { RTOKEN('+');}
+<DEFTMPEXP>{FILENAMECHAR1}{SYMBOLCHARN}* { yylval.name = xstrdup (yytext); return NAME; }
+<DEFTMPEXP>"=" { RTOKEN('='); }
+
<MRI,EXPRESSION>"$"([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;
}
-<SCRIPT,DEFSYMEXP,MRI,BOTH,EXPRESSION>((("$"|0[xX])([0-9A-Fa-f])+)|(([0-9])+))(M|K|m|k)? {
+<SCRIPT,DEFSYMEXP,DEFTMPEXP,MRI,BOTH,EXPRESSION>((("$"|0[xX])([0-9A-Fa-f])+)|(([0-9])+))(M|K|m|k)? {
char *s = yytext;
int ibase = 0;
@@ -269,6 +277,7 @@
<BOTH,SCRIPT>"INPUT" { RTOKEN(INPUT);}
<EXPRESSION,BOTH,SCRIPT>"GROUP" { RTOKEN(GROUP);}
<EXPRESSION,BOTH,SCRIPT>"DEFINED" { RTOKEN(DEFINED);}
+<EXPRESSION,BOTH,SCRIPT>"TEMPORARY" { RTOKEN(TEMPORARY); }
<BOTH,SCRIPT>"CREATE_OBJECT_SYMBOLS" { RTOKEN(CREATE_OBJECT_SYMBOLS);}
<BOTH,SCRIPT>"CONSTRUCTORS" { RTOKEN( CONSTRUCTORS);}
<BOTH,SCRIPT>"FORCE_COMMON_ALLOCATION" { RTOKEN(FORCE_COMMON_ALLOCATION);}
@@ -442,7 +451,7 @@
}
<SCRIPT,MRI,VERS_START,VERS_SCRIPT,VERS_NODE>. lex_warn_invalid (" in script", yytext);
-<EXPRESSION,DEFSYMEXP,BOTH>. lex_warn_invalid (" in expression", yytext);
+<EXPRESSION,DEFSYMEXP,DEFTMPEXP,BOTH>. 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)