binutils/
authorAlan Modra <amodra@gmail.com>
Thu, 19 Aug 2010 05:51:50 +0000 (05:51 +0000)
committerAlan Modra <amodra@gmail.com>
Thu, 19 Aug 2010 05:51:50 +0000 (05:51 +0000)
* NEWS: Mention change in linker script expression evaluation.
ld/
* ld.texinfo (Expression Section): Detail expression evaluation.
(Builtin Functions <ADDR>): Correct.
(Builtin Functions <LOADADDR>): Don't mention LOADADDR normally
the same as ADDR.
(Builtin Functions <SEGMENT_START>): Typo fix.
* ldexp.c (new_number): New function.
(make_abs, exp_get_abs_int): Cope with NULL expld.result.section.
(fold_unary <'~', '!', '-'>): Don't make_abs.
(fold_binary): Simplify result section logic.  Return NULL section
for logical ops.
(fold_binary <SEGMENT_START>): Use new_rel_from_abs to set value to
a consistent result.
(fold_name <SIZEOF_HEADERS>): Return new_number, not new_abs.
(fold_name <DEFINED, SIZEOF, ALIGNOF, LENGTH, CONSTANT>): Likewise.
(fold_name <NAME>): No need to handle absolute symbols differently
from relative ones.
(fold_name <ORIGIN>): Don't return valid result when
lang_first_phase_enum.  Return new_rel_from_abs, not new_abs.
(exp_fold_tree_1 <etree_value>): Return new_number, not new_rel.
(exp_fold_tree_1): Ajust for NULL expld.result.section.  When assigning
a plain number to dot, assume the value is relative to expld.section.
Make terms not in an output section, absolute.
* ldlang.c (print_assignment): Fix style nit.
(lang_size_sections_1): Cope with NULL expld.result.section.
(lang_do_assignments_1): Likewise.
ld/testsuite/
* ld-scripts/memory.t: Remove ORIGIN fudge.

binutils/ChangeLog
binutils/NEWS
ld/ChangeLog
ld/ld.texinfo
ld/ldexp.c
ld/ldlang.c
ld/testsuite/ChangeLog
ld/testsuite/ld-scripts/memory.t

index 4ec74da..624bab1 100644 (file)
@@ -1,3 +1,7 @@
+2010-08-19  Alan Modra  <amodra@gmail.com>
+
+       * NEWS: Mention change in linker script expression evaluation.
+
 2010-08-13  Dan Rosenberg  <dan.j.rosenberg@gmail.com>
 
        PR binutils/11889
index 92f894d..a1ba9ac 100644 (file)
@@ -1,5 +1,8 @@
 -*- text -*-
 
+* Linker script expression evaluation is somewhat more sane.  This may
+  break scripts that depend on quirks of the old expression evaluation.
+
 * Add support for the TMS320C6000 (TI C6X) processor family.
 
 * Readelf can now display ARM unwind tables (.ARM.exidx / .ARM.extab) using
index 30cb4eb..e0873ae 100644 (file)
@@ -1,3 +1,31 @@
+2010-08-19  Alan Modra  <amodra@gmail.com>
+
+       * ld.texinfo (Expression Section): Detail expression evaluation.
+       (Builtin Functions <ADDR>): Correct.
+       (Builtin Functions <LOADADDR>): Don't mention LOADADDR normally
+       the same as ADDR.
+       (Builtin Functions <SEGMENT_START>): Typo fix.
+       * ldexp.c (new_number): New function.
+       (make_abs, exp_get_abs_int): Cope with NULL expld.result.section.
+       (fold_unary <'~', '!', '-'>): Don't make_abs.
+       (fold_binary): Simplify result section logic.  Return NULL section
+       for logical ops.
+       (fold_binary <SEGMENT_START>): Use new_rel_from_abs to set value to
+       a consistent result.
+       (fold_name <SIZEOF_HEADERS>): Return new_number, not new_abs.
+       (fold_name <DEFINED, SIZEOF, ALIGNOF, LENGTH, CONSTANT>): Likewise.
+       (fold_name <NAME>): No need to handle absolute symbols differently
+       from relative ones.
+       (fold_name <ORIGIN>): Don't return valid result when
+       lang_first_phase_enum.  Return new_rel_from_abs, not new_abs.
+       (exp_fold_tree_1 <etree_value>): Return new_number, not new_rel.
+       (exp_fold_tree_1): Ajust for NULL expld.result.section.  When assigning
+       a plain number to dot, assume the value is relative to expld.section.
+       Make terms not in an output section, absolute.
+       * ldlang.c (print_assignment): Fix style nit.
+       (lang_size_sections_1): Cope with NULL expld.result.section.
+       (lang_do_assignments_1): Likewise.
+
 2010-08-12  Alan Modra  <amodra@gmail.com>
 
        * ldexp.c (new_rel): Remove "str".  Update all call sites.
index 8928350..7470c53 100644 (file)
@@ -5447,23 +5447,82 @@ address}.
 @cindex absolute and relocatable symbols
 @cindex relocatable and absolute symbols
 @cindex symbols, relocatable and absolute
-When the linker evaluates an expression, the result is either absolute
-or relative to some section.  A relative expression is expressed as a
-fixed offset from the base of a section.
+Addresses and symbols may be section relative, or absolute.  A section
+relative symbol is relocatable.  If you request relocatable output
+using the @samp{-r} option, a further link operation may change the
+value of a section relative symbol.  On the other hand, an absolute
+symbol will retain the same value throughout any further link
+operations.
+
+Some terms in linker expressions are addresses.  This is true of all
+symbols and for builtin functions that return an address, such as
+@code{ADDR}, @code{LOADADDR}, @code{ORIGIN} and @code{SEGMENT_START}.
+Other terms are simply numbers, or are builtin functions that return a
+non-address value, such as @code{LENGTH}.
+
+When the linker evaluates an expression, the result depends on where
+the expression is located in a linker script.  Expressions appearing
+outside an output section definitions are evaluated with all terms
+first being converted to absolute addresses before applying operators,
+and evaluate to an absolute address result.  Expressions appearing
+inside an output section definition are evaluated with more complex
+rules, but the aim is to treat terms as relative addresses and produce
+a relative address result.  In particular, an assignment of a number
+to a symbol results in a symbol relative to the output section with an
+offset given by the number.  So, in the following simple example,
 
-The position of the expression within the linker script determines
-whether it is absolute or relative.  An expression which appears within
-an output section definition is relative to the base of the output
-section.  An expression which appears elsewhere will be absolute.
+@smallexample
+@group
+SECTIONS
+  @{
+    . = 0x100;
+    __executable_start = 0x100;
+    .data :
+    @{
+      . = 0x10;
+      __data_start = 0x10;
+      *(.data)
+    @}
+    @dots{}
+  @}
+@end group
+@end smallexample
 
-A symbol set to a relative expression will be relocatable if you request
-relocatable output using the @samp{-r} option.  That means that a
-further link operation may change the value of the symbol.  The symbol's
-section will be the section of the relative expression.
+both @code{.} and @code{__executable_start} are set to the absolute
+address 0x100 in the first two assignments, then both @code{.} and
+@code{__data_start} are set to 0x10 relative to the @code{.data}
+section in the second two assignments.
 
-A symbol set to an absolute expression will retain the same value
-through any further link operation.  The symbol will be absolute, and
-will not have any particular associated section.
+For expressions appearing inside an output section definition
+involving numbers, relative addresses and absolute addresses, ld
+follows these rules to evaluate terms:
+
+@itemize @bullet
+@item
+Unary operations on a relative address, and binary operations on two
+relative addresses in the same section or between one relative address
+and a number, apply the operator to the offset part of the address(es).
+@item
+Unary operations on an absolute address, and binary operations on one
+or more absolute addresses or on two relative addresses not in the
+same section, first convert any non-absolute term to an absolute
+address before applying the operator.
+@end itemize
+
+The result section of each sub-expression is as follows:
+
+@itemize @bullet
+@item
+An operation involving only numbers results in a number.
+@item
+The result of comparisons, @samp{&&} and @samp{||} is also a number.
+@item
+The result of other operations on relative addresses (after above
+conversions) is a relative address in the same section as the operand(s).
+@item
+The result of other operations on absolute addresses (after above
+conversions) is an absolute address.
+@end itemize
 
 You can use the builtin function @code{ABSOLUTE} to force an expression
 to be absolute when it would otherwise be relative.  For example, to
@@ -5479,6 +5538,9 @@ SECTIONS
 If @samp{ABSOLUTE} were not used, @samp{_edata} would be relative to the
 @samp{.data} section.
 
+Using @code{LOADADDR} also forces an expression absolute, since this
+particular builtin function returns an absolute address.
+
 @node Builtin Functions
 @subsection Builtin Functions
 @cindex functions in expressions
@@ -5497,10 +5559,12 @@ normally section relative.  @xref{Expression Section}.
 @item ADDR(@var{section})
 @kindex ADDR(@var{section})
 @cindex section address in expression
-Return the absolute address (the VMA) of the named @var{section}.  Your
+Return the address (VMA) of the named @var{section}.  Your
 script must previously have defined the location of that section.  In
-the following example, @code{symbol_1} and @code{symbol_2} are assigned
-identical values:
+the following example, @code{start_of_output_1}, @code{symbol_1} and
+@code{symbol_2} are assigned equivalent values, except that
+@code{symbol_1} will be relative to the @code{.output1} section while
+the other two will be absolute:
 @smallexample
 @group
 SECTIONS @{ @dots{}
@@ -5664,9 +5728,7 @@ Return the length of the memory region named @var{memory}.
 @item LOADADDR(@var{section})
 @kindex LOADADDR(@var{section})
 @cindex section load address in expression
-Return the absolute LMA of the named @var{section}.  This is normally
-the same as @code{ADDR}, but it may be different if the @code{AT}
-attribute is used in the output section definition (@pxref{Output
+Return the absolute LMA of the named @var{section}.  (@pxref{Output
 Section LMA}).
 
 @kindex MAX
@@ -5696,7 +5758,7 @@ value has been given for this segment (with a command-line @samp{-T}
 option) that value will be returned; otherwise the value will be
 @var{default}.  At present, the @samp{-T} command-line option can only
 be used to set the base address for the ``text'', ``data'', and
-``bss'' sections, but you use @code{SEGMENT_START} with any segment
+``bss'' sections, but you can use @code{SEGMENT_START} with any segment
 name.
 
 @item SIZEOF(@var{section})
index 050227d..0549f19 100644 (file)
@@ -138,7 +138,8 @@ exp_print_token (token_code_type code, int infix_p)
 static void
 make_abs (void)
 {
-  expld.result.value += expld.result.section->vma;
+  if (expld.result.section != NULL)
+    expld.result.value += expld.result.section->vma;
   expld.result.section = bfd_abs_section_ptr;
 }
 
@@ -190,6 +191,15 @@ exp_relop (asection *section, bfd_vma value)
 }
 
 static void
+new_number (bfd_vma value)
+{
+  expld.result.valid_p = TRUE;
+  expld.result.value = value;
+  expld.result.str = NULL;
+  expld.result.section = NULL;
+}
+
+static void
 new_rel (bfd_vma value, asection *section)
 {
   expld.result.valid_p = TRUE;
@@ -227,17 +237,14 @@ fold_unary (etree_type *tree)
          break;
 
        case '~':
-         make_abs ();
          expld.result.value = ~expld.result.value;
          break;
 
        case '!':
-         make_abs ();
          expld.result.value = !expld.result.value;
          break;
 
        case '-':
-         make_abs ();
          expld.result.value = -expld.result.value;
          break;
 
@@ -293,6 +300,7 @@ fold_binary (etree_type *tree)
     {
       const char *segment_name;
       segment_type *seg;
+
       /* Check to see if the user has overridden the default
         value.  */
       segment_name = tree->binary.rhs->name.name;
@@ -305,9 +313,7 @@ fold_binary (etree_type *tree)
              einfo (_("%P: warning: address of `%s' isn't multiple of maximum page size\n"),
                     segment_name);
            seg->used = TRUE;
-           expld.result.value = seg->value;
-           expld.result.str = NULL;
-           expld.result.section = expld.section;
+           new_rel_from_abs (seg->value);
            break;
          }
       return;
@@ -319,32 +325,20 @@ fold_binary (etree_type *tree)
 
   if (expld.result.valid_p)
     {
-      /* If the values are from different sections, or this is an
-        absolute expression, make both the source arguments
-        absolute.  However, adding or subtracting an absolute
-        value from a relative value is meaningful, and is an
-        exception.  */
-      if (expld.section != bfd_abs_section_ptr
-         && lhs.section == bfd_abs_section_ptr
-         && tree->type.node_code == '+')
+      if (lhs.section != expld.result.section)
        {
-         /* Keep the section of the rhs term.  */
-         expld.result.value = lhs.value + expld.result.value;
-         return;
-       }
-      else if (expld.section != bfd_abs_section_ptr
-              && expld.result.section == bfd_abs_section_ptr
-              && (tree->type.node_code == '+'
-                  || tree->type.node_code == '-'))
-       {
-         /* Keep the section of the lhs term.  */
-         expld.result.section = lhs.section;
-       }
-      else if (expld.result.section != lhs.section
-              || expld.section == bfd_abs_section_ptr)
-       {
-         make_abs ();
-         lhs.value += lhs.section->vma;
+         /* If the values are from different sections, and neither is
+            just a number, make both the source arguments absolute.  */
+         if (expld.result.section != NULL
+             && lhs.section != NULL)
+           {
+             make_abs ();
+             lhs.value += lhs.section->vma;
+           }
+
+         /* If the rhs is just a number, keep the lhs section.  */
+         else if (expld.result.section == NULL)
+           expld.result.section = lhs.section;
        }
 
       switch (tree->type.node_code)
@@ -366,26 +360,32 @@ fold_binary (etree_type *tree)
          break;
 
 #define BOP(x, y) \
-           case x:                                                     \
-             expld.result.value = lhs.value y expld.result.value;      \
-             break;
+       case x:                                                 \
+         expld.result.value = lhs.value y expld.result.value;  \
+         break;
+
+#define BOPN(x, y) \
+       case x:                                                 \
+         expld.result.value = lhs.value y expld.result.value;  \
+         expld.result.section = NULL;                          \
+         break;
 
          BOP ('+', +);
          BOP ('*', *);
          BOP ('-', -);
          BOP (LSHIFT, <<);
          BOP (RSHIFT, >>);
-         BOP (EQ, ==);
-         BOP (NE, !=);
-         BOP ('<', <);
-         BOP ('>', >);
-         BOP (LE, <=);
-         BOP (GE, >=);
          BOP ('&', &);
          BOP ('^', ^);
          BOP ('|', |);
-         BOP (ANDAND, &&);
-         BOP (OROR, ||);
+         BOPN (EQ, ==);
+         BOPN (NE, !=);
+         BOPN ('<', <);
+         BOPN ('>', >);
+         BOPN (LE, <=);
+         BOPN (GE, >=);
+         BOPN (ANDAND, &&);
+         BOPN (OROR, ||);
 
        case MAX_K:
          if (lhs.value > expld.result.value)
@@ -499,7 +499,7 @@ fold_name (etree_type *tree)
             The bfd function may cache incorrect data.  */
          if (expld.phase != lang_mark_phase_enum)
            hdr_size = bfd_sizeof_headers (link_info.output_bfd, &link_info);
-         new_abs (hdr_size);
+         new_number (hdr_size);
        }
       break;
 
@@ -516,14 +516,12 @@ fold_name (etree_type *tree)
                                            &link_info,
                                            tree->name.name,
                                            FALSE, FALSE, TRUE);
-         expld.result.value = (h != NULL
-                               && (h->type == bfd_link_hash_defined
-                                   || h->type == bfd_link_hash_defweak
-                                   || h->type == bfd_link_hash_common)
-                               && (def_iteration == lang_statement_iteration
-                                   || def_iteration == -1));
-         expld.result.section = expld.section;
-         expld.result.valid_p = TRUE;
+         new_number (h != NULL
+                     && (h->type == bfd_link_hash_defined
+                         || h->type == bfd_link_hash_defweak
+                         || h->type == bfd_link_hash_common)
+                     && (def_iteration == lang_statement_iteration
+                         || def_iteration == -1));
        }
       break;
 
@@ -545,24 +543,19 @@ fold_name (etree_type *tree)
          else if (h->type == bfd_link_hash_defined
                   || h->type == bfd_link_hash_defweak)
            {
-             if (bfd_is_abs_section (h->u.def.section))
-               new_abs (h->u.def.value);
-             else
-               {
-                 asection *output_section;
+             asection *output_section;
 
-                 output_section = h->u.def.section->output_section;
-                 if (output_section == NULL)
-                   {
-                     if (expld.phase != lang_mark_phase_enum)
-                       einfo (_("%X%S: unresolvable symbol `%s'"
-                                " referenced in expression\n"),
-                              tree->name.name);
-                   }
-                 else
-                   new_rel (h->u.def.value + h->u.def.section->output_offset,
-                            output_section);
+             output_section = h->u.def.section->output_section;
+             if (output_section == NULL)
+               {
+                 if (expld.phase != lang_mark_phase_enum)
+                   einfo (_("%X%S: unresolvable symbol `%s'"
+                            " referenced in expression\n"),
+                          tree->name.name);
                }
+             else
+               new_rel (h->u.def.value + h->u.def.section->output_offset,
+                        output_section);
            }
          else if (expld.phase == lang_final_phase_enum
                   || expld.assigning_to_dot)
@@ -633,7 +626,7 @@ fold_name (etree_type *tree)
              if (expld.phase == lang_final_phase_enum)
                einfo (_("%F%S: undefined section `%s' referenced in expression\n"),
                       tree->name.name);
-             new_abs (0);
+             new_number (0);
            }
          else if (os->processed_vma)
            {
@@ -645,7 +638,7 @@ fold_name (etree_type *tree)
              else
                val = (bfd_vma)1 << os->bfd_section->alignment_power;
              
-             new_abs (val);
+             new_number (val);
            }
        }
       break;
@@ -656,7 +649,7 @@ fold_name (etree_type *tree)
         
         mem = lang_memory_region_lookup (tree->name.name, FALSE);  
         if (mem != NULL) 
-          new_abs (mem->length);
+          new_number (mem->length);
         else          
           einfo (_("%F%S: undefined MEMORY region `%s'"
                   " referenced in expression\n"), tree->name.name);
@@ -664,23 +657,24 @@ fold_name (etree_type *tree)
       break;
 
     case ORIGIN:
-      {
-        lang_memory_region_type *mem;
+      if (expld.phase != lang_first_phase_enum)
+       {
+         lang_memory_region_type *mem;
         
-        mem = lang_memory_region_lookup (tree->name.name, FALSE);  
-        if (mem != NULL) 
-          new_abs (mem->origin);
-        else          
-          einfo (_("%F%S: undefined MEMORY region `%s'"
-                  " referenced in expression\n"), tree->name.name);
-      }
+         mem = lang_memory_region_lookup (tree->name.name, FALSE);  
+         if (mem != NULL) 
+           new_rel_from_abs (mem->origin);
+         else          
+           einfo (_("%F%S: undefined MEMORY region `%s'"
+                    " referenced in expression\n"), tree->name.name);
+       }
       break;
 
     case CONSTANT:
       if (strcmp (tree->name.name, "MAXPAGESIZE") == 0)
-       new_abs (config.maxpagesize);
+       new_number (config.maxpagesize);
       else if (strcmp (tree->name.name, "COMMONPAGESIZE") == 0)
-       new_abs (config.commonpagesize);
+       new_number (config.commonpagesize);
       else
        einfo (_("%F%S: unknown constant `%s' referenced in expression\n"),
               tree->name.name);
@@ -704,7 +698,7 @@ exp_fold_tree_1 (etree_type *tree)
   switch (tree->type.node_class)
     {
     case etree_value:
-      new_rel (tree->value.value, expld.section);
+      new_number (tree->value.value);
       expld.result.str = tree->value.str;
       break;
 
@@ -767,7 +761,11 @@ exp_fold_tree_1 (etree_type *tree)
                {
                  bfd_vma nextdot;
 
-                 nextdot = expld.result.value + expld.result.section->vma;
+                 nextdot = expld.result.value;
+                 if (expld.result.section != NULL)
+                   nextdot += expld.result.section->vma;
+                 else
+                   nextdot += expld.section->vma;
                  if (nextdot < expld.dot
                      && expld.section != bfd_abs_section_ptr)
                    einfo (_("%F%S cannot move location counter backwards"
@@ -818,6 +816,8 @@ exp_fold_tree_1 (etree_type *tree)
              lang_update_definedness (tree->assign.dst, h);
              h->type = bfd_link_hash_defined;
              h->u.def.value = expld.result.value;
+             if (expld.result.section == NULL)
+               expld.result.section = expld.section;
              h->u.def.section = expld.result.section;
              if (tree->type.node_class == etree_provide)
                tree->type.node_class = etree_provided;
@@ -856,6 +856,12 @@ exp_fold_tree_1 (etree_type *tree)
       memset (&expld.result, 0, sizeof (expld.result));
       break;
     }
+
+  /* Any value not inside an output section statement is an
+     absolute value.  */
+  if (expld.result.valid_p
+      && expld.section == bfd_abs_section_ptr)
+    make_abs ();
 }
 
 void
@@ -1186,7 +1192,8 @@ exp_get_abs_int (etree_type *tree, int def, char *name)
 
       if (expld.result.valid_p)
        {
-         expld.result.value += expld.result.section->vma;
+         if (expld.result.section != NULL)
+           expld.result.value += expld.result.section->vma;
          return expld.result.value;
        }
       else if (name != NULL && expld.phase != lang_mark_phase_enum)
index 41ab2ee..2b9971a 100644 (file)
@@ -3916,7 +3916,7 @@ print_assignment (lang_assignment_statement_type *assignment,
        {
          value = expld.result.value;
 
-         if (expld.result.section)
+         if (expld.result.section != NULL)
            value += expld.result.section->vma;
 
          minfo ("0x%V", value);
@@ -3933,7 +3933,7 @@ print_assignment (lang_assignment_statement_type *assignment,
            {
              value = h->u.def.value;
 
-             if (expld.result.section)
+             if (expld.result.section != NULL)
                value += expld.result.section->vma;
 
              minfo ("[0x%V]", value);
@@ -4718,7 +4718,11 @@ lang_size_sections_1
                exp_fold_tree (os->addr_tree, bfd_abs_section_ptr, &dot);
 
                if (expld.result.valid_p)
-                 dot = expld.result.value + expld.result.section->vma;
+                 {
+                   dot = expld.result.value;
+                   if (expld.result.section != NULL)
+                     dot += expld.result.section->vma;
+                 }
                else if (expld.phase != lang_mark_phase_enum)
                  einfo (_("%F%S: non constant or forward reference"
                           " address expression for section %s\n"),
@@ -5397,8 +5401,11 @@ lang_do_assignments_1 (lang_statement_union_type *s,
        case lang_data_statement_enum:
          exp_fold_tree (s->data_statement.exp, bfd_abs_section_ptr, &dot);
          if (expld.result.valid_p)
-           s->data_statement.value = (expld.result.value
-                                      + expld.result.section->vma);
+           {
+             s->data_statement.value = expld.result.value;
+             if (expld.result.section != NULL)
+               s->data_statement.value += expld.result.section->vma;
+           }
          else
            einfo (_("%F%P: invalid data statement\n"));
          {
index c15a44e..dd7ee77 100644 (file)
@@ -1,3 +1,7 @@
+2010-08-19  Alan Modra  <amodra@gmail.com>
+
+       * ld-scripts/memory.t: Remove ORIGIN fudge.
+
 2010-08-13  H.J. Lu  <hongjiu.lu@intel.com>
 
        PR ld/11913
index 6623b28..129bd7c 100644 (file)
@@ -15,19 +15,7 @@ SECTIONS
   . = 0;
   .text :
   {
-    /* The value returned by the ORIGIN operator is a constant.
-       However it is being assigned to a symbol declared within
-       a section.  Therefore the symbol is section-relative and
-       its value will include the offset of that section from
-       the start of memory.  ie the declaration:
-          text_start = ORIGIN (TEXTMEM);
-       here will result in text_start having a value of 0x200.
-       Hence we need to subtract the absolute value of the
-       location counter at this point in order to give text_start
-       a value that is truely absolute, and which coincidentally
-       will allow the tests in script.exp to work.  */
-       
-    text_start = ORIGIN(TEXTMEM) - ABSOLUTE (.);
+    text_start = ORIGIN (TEXTMEM);
     *(.text)
     *(.pr)
     text_end = .;