This is the mail archive of the binutils@sources.redhat.com mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: RFC and PATCH - Defining variables in the linker scriptwithout defining them as symbols on the file


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)

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]