ChangeLog rotatation and copyright year update
[deliverable/binutils-gdb.git] / ld / ldexp.c
index bf0e00b17965e0ffc13040976622ade9173300aa..f2c8620a4651aa2604b66291513db4c69697ad76 100644 (file)
@@ -1,7 +1,5 @@
 /* This module handles expression trees.
-   Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
-   2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
-   Free Software Foundation, Inc.
+   Copyright (C) 1991-2015 Free Software Foundation, Inc.
    Written by Steve Chamberlain of Cygnus Support <sac@cygnus.com>.
 
    This file is part of the GNU Binutils.
@@ -50,6 +48,19 @@ segment_type *segments;
 
 struct ldexp_control expld;
 
+/* This structure records symbols for which we need to keep track of
+   definedness for use in the DEFINED () test.  */
+
+struct definedness_hash_entry
+{
+  struct bfd_hash_entry root;
+  unsigned int by_object : 1;
+  unsigned int by_script : 1;
+  unsigned int iteration : 1;
+};
+
+static struct bfd_hash_table definedness_table;
+
 /* Print the string representation of the given token.  Surround it
    with spaces if INFIX_P is TRUE.  */
 
@@ -59,7 +70,7 @@ exp_print_token (token_code_type code, int infix_p)
   static const struct
   {
     token_code_type code;
-    char * name;
+    const char * name;
   }
   table[] =
   {
@@ -81,6 +92,7 @@ exp_print_token (token_code_type code, int infix_p)
     { GE, ">=" },
     { LSHIFT, "<<" },
     { RSHIFT, ">>" },
+    { LOG2CEIL, "LOG2CEIL" },
     { ALIGN_K, "ALIGN" },
     { BLOCK, "BLOCK" },
     { QUAD, "QUAD" },
@@ -134,6 +146,28 @@ exp_print_token (token_code_type code, int infix_p)
     fputc (' ', config.map_file);
 }
 
+static void
+make_log2ceil (void)
+{
+  bfd_vma value = expld.result.value;
+  bfd_vma result = -1;
+  bfd_boolean round_up = FALSE;
+
+  do
+    {
+      result++;
+      /* If more than one bit is set in the value we will need to round up.  */
+      if ((value > 1) && (value & 1))
+       round_up = TRUE;
+    }
+  while (value >>= 1);
+
+  if (round_up)
+    result += 1;
+  expld.result.section = NULL;
+  expld.result.value = result;
+}
+
 static void
 make_abs (void)
 {
@@ -213,10 +247,82 @@ new_rel (bfd_vma value, asection *section)
 static void
 new_rel_from_abs (bfd_vma value)
 {
+  asection *s = expld.section;
+
+  if (s == bfd_abs_section_ptr && expld.phase == lang_final_phase_enum)
+    s = section_for_dot ();
   expld.result.valid_p = TRUE;
-  expld.result.value = value - expld.section->vma;
+  expld.result.value = value - s->vma;
   expld.result.str = NULL;
-  expld.result.section = expld.section;
+  expld.result.section = s;
+}
+
+/* New-function for the definedness hash table.  */
+
+static struct bfd_hash_entry *
+definedness_newfunc (struct bfd_hash_entry *entry,
+                    struct bfd_hash_table *table ATTRIBUTE_UNUSED,
+                    const char *name ATTRIBUTE_UNUSED)
+{
+  struct definedness_hash_entry *ret = (struct definedness_hash_entry *) entry;
+
+  if (ret == NULL)
+    ret = (struct definedness_hash_entry *)
+      bfd_hash_allocate (table, sizeof (struct definedness_hash_entry));
+
+  if (ret == NULL)
+    einfo (_("%P%F: bfd_hash_allocate failed creating symbol %s\n"), name);
+
+  ret->by_object = 0;
+  ret->by_script = 0;
+  ret->iteration = 0;
+  return &ret->root;
+}
+
+/* Called during processing of linker script script expressions.
+   For symbols assigned in a linker script, return a struct describing
+   where the symbol is defined relative to the current expression,
+   otherwise return NULL.  */
+
+static struct definedness_hash_entry *
+symbol_defined (const char *name)
+{
+  return ((struct definedness_hash_entry *)
+         bfd_hash_lookup (&definedness_table, name, FALSE, FALSE));
+}
+
+/* Update the definedness state of NAME.  Return FALSE if script symbol
+   is multiply defining a strong symbol in an object.  */
+
+static bfd_boolean
+update_definedness (const char *name, struct bfd_link_hash_entry *h)
+{
+  bfd_boolean ret;
+  struct definedness_hash_entry *defentry
+    = (struct definedness_hash_entry *)
+    bfd_hash_lookup (&definedness_table, name, TRUE, FALSE);
+
+  if (defentry == NULL)
+    einfo (_("%P%F: bfd_hash_lookup failed creating symbol %s\n"), name);
+
+  /* If the symbol was already defined, and not by a script, then it
+     must be defined by an object file or by the linker target code.  */
+  ret = TRUE;
+  if (!defentry->by_script
+      && (h->type == bfd_link_hash_defined
+         || h->type == bfd_link_hash_defweak
+         || h->type == bfd_link_hash_common))
+    {
+      defentry->by_object = 1;
+      if (h->type == bfd_link_hash_defined
+         && h->u.def.section->output_section != NULL
+         && !h->linker_def)
+       ret = FALSE;
+    }
+
+  defentry->by_script = 1;
+  defentry->iteration = lang_statement_iteration;
+  return ret;
 }
 
 static void
@@ -238,6 +344,10 @@ fold_unary (etree_type *tree)
          make_abs ();
          break;
 
+       case LOG2CEIL:
+         make_log2ceil ();
+         break;
+
        case '~':
          expld.result.value = ~expld.result.value;
          break;
@@ -308,7 +418,7 @@ fold_binary (etree_type *tree)
       /* Check to see if the user has overridden the default
         value.  */
       segment_name = tree->binary.rhs->name.name;
-      for (seg = segments; seg; seg = seg->next) 
+      for (seg = segments; seg; seg = seg->next)
        if (strcmp (seg->name, segment_name) == 0)
          {
            if (!seg->used
@@ -546,13 +656,10 @@ fold_name (etree_type *tree)
       break;
 
     case DEFINED:
-      if (expld.phase == lang_first_phase_enum)
-       lang_track_definedness (tree->name.name);
-      else
+      if (expld.phase != lang_first_phase_enum)
        {
          struct bfd_link_hash_entry *h;
-         int def_iteration
-           = lang_symbol_definition_iteration (tree->name.name);
+         struct definedness_hash_entry *def;
 
          h = bfd_wrapped_link_hash_lookup (link_info.output_bfd,
                                            &link_info,
@@ -562,12 +669,33 @@ fold_name (etree_type *tree)
                      && (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));
+                     && ((def = symbol_defined (tree->name.name)) == NULL
+                         || def->by_object
+                         || def->iteration == (lang_statement_iteration & 1)));
        }
       break;
 
     case NAME:
+      if (expld.assign_name != NULL
+         && strcmp (expld.assign_name, tree->name.name) == 0)
+       {
+         /* Self-assignment is only allowed for absolute symbols
+            defined in a linker script.  */
+         struct bfd_link_hash_entry *h;
+         struct definedness_hash_entry *def;
+
+         h = bfd_wrapped_link_hash_lookup (link_info.output_bfd,
+                                           &link_info,
+                                           tree->name.name,
+                                           FALSE, FALSE, TRUE);
+         if (!(h != NULL
+               && (h->type == bfd_link_hash_defined
+                   || h->type == bfd_link_hash_defweak)
+               && h->u.def.section == bfd_abs_section_ptr
+               && (def = symbol_defined (tree->name.name)) != NULL
+               && def->iteration == (lang_statement_iteration & 1)))
+           expld.assign_name = NULL;
+       }
       if (expld.phase == lang_first_phase_enum)
        ;
       else if (tree->name.name[0] == '.' && tree->name.name[1] == 0)
@@ -606,7 +734,8 @@ fold_name (etree_type *tree)
                         output_section);
            }
          else if (expld.phase == lang_final_phase_enum
-                  || expld.assigning_to_dot)
+                  || (expld.phase != lang_mark_phase_enum
+                      && expld.assigning_to_dot))
            einfo (_("%F%S: undefined symbol `%s'"
                     " referenced in expression\n"),
                   tree, tree->name.name);
@@ -680,7 +809,7 @@ fold_name (etree_type *tree)
                       tree, tree->name.name);
              new_number (0);
            }
-         else if (os->processed_vma)
+         else if (os->bfd_section != NULL)
            {
              bfd_vma val;
 
@@ -689,20 +818,22 @@ fold_name (etree_type *tree)
                       / bfd_octets_per_byte (link_info.output_bfd));
              else
                val = (bfd_vma)1 << os->bfd_section->alignment_power;
-             
+
              new_number (val);
            }
+         else
+           new_number (0);
        }
       break;
 
     case LENGTH:
       {
         lang_memory_region_type *mem;
-        
-        mem = lang_memory_region_lookup (tree->name.name, FALSE);  
-        if (mem != NULL) 
+
+        mem = lang_memory_region_lookup (tree->name.name, FALSE);
+        if (mem != NULL)
           new_number (mem->length);
-        else          
+        else
           einfo (_("%F%S: undefined MEMORY region `%s'"
                   " referenced in expression\n"),
                 tree, tree->name.name);
@@ -713,11 +844,11 @@ fold_name (etree_type *tree)
       if (expld.phase != lang_first_phase_enum)
        {
          lang_memory_region_type *mem;
-        
-         mem = lang_memory_region_lookup (tree->name.name, FALSE);  
-         if (mem != NULL) 
+
+         mem = lang_memory_region_lookup (tree->name.name, FALSE);
+         if (mem != NULL)
            new_rel_from_abs (mem->origin);
-         else          
+         else
            einfo (_("%F%S: undefined MEMORY region `%s'"
                     " referenced in expression\n"),
                   tree, tree->name.name);
@@ -740,6 +871,89 @@ fold_name (etree_type *tree)
     }
 }
 
+/* Return true if TREE is '.'.  */
+static bfd_boolean
+is_dot (const etree_type *tree)
+{
+  return (tree->type.node_class == etree_name
+         && tree->type.node_code == NAME
+         && tree->name.name[0] == '.'
+         && tree->name.name[1] == 0);
+}
+
+/* Return true if TREE is a constant equal to VAL.  */
+
+static bfd_boolean
+is_value (const etree_type *tree, bfd_vma val)
+{
+  return (tree->type.node_class == etree_value
+         && tree->value.value == val);
+}
+
+/* Return true if TREE is an absolute symbol equal to VAL defined in
+   a linker script.  */
+
+static bfd_boolean
+is_sym_value (const etree_type *tree, bfd_vma val)
+{
+  struct bfd_link_hash_entry *h;
+  struct definedness_hash_entry *def;
+
+  return (tree->type.node_class == etree_name
+         && tree->type.node_code == NAME
+         && (def = symbol_defined (tree->name.name)) != NULL
+         && def->by_script
+         && def->iteration == (lang_statement_iteration & 1)
+         && (h = bfd_wrapped_link_hash_lookup (link_info.output_bfd,
+                                               &link_info,
+                                               tree->name.name,
+                                               FALSE, FALSE, TRUE)) != NULL
+         && h->type == bfd_link_hash_defined
+         && h->u.def.section == bfd_abs_section_ptr
+         && h->u.def.value == val);
+}
+
+/* Return true if TREE is ". != 0".  */
+
+static bfd_boolean
+is_dot_ne_0 (const etree_type *tree)
+{
+  return (tree->type.node_class == etree_binary
+         && tree->type.node_code == NE
+         && is_dot (tree->binary.lhs)
+         && is_value (tree->binary.rhs, 0));
+}
+
+/* Return true if TREE is ". = . + 0" or ". = . + sym" where sym is an
+   absolute constant with value 0 defined in a linker script.  */
+
+static bfd_boolean
+is_dot_plus_0 (const etree_type *tree)
+{
+  return (tree->type.node_class == etree_binary
+         && tree->type.node_code == '+'
+         && is_dot (tree->binary.lhs)
+         && (is_value (tree->binary.rhs, 0)
+             || is_sym_value (tree->binary.rhs, 0)));
+}
+
+/* Return true if TREE is "ALIGN (. != 0 ? some_expression : 1)".  */
+
+static bfd_boolean
+is_align_conditional (const etree_type *tree)
+{
+  if (tree->type.node_class == etree_unary
+      && tree->type.node_code == ALIGN_K)
+    {
+      tree = tree->unary.child;
+      return (tree->type.node_class == etree_trinary
+             && is_dot_ne_0 (tree->trinary.cond)
+             && is_value (tree->trinary.rhs, 1));
+    }
+  return 0;
+}
+
 static void
 exp_fold_tree_1 (etree_type *tree)
 {
@@ -797,20 +1011,27 @@ exp_fold_tree_1 (etree_type *tree)
          if (tree->type.node_class != etree_assign)
            einfo (_("%F%S can not PROVIDE assignment to"
                     " location counter\n"), tree);
-         /* After allocation, assignment to dot should not be done inside
-            an output section since allocation adds a padding statement
-            that effectively duplicates the assignment.  */
-         if (expld.phase == lang_mark_phase_enum
-             || expld.phase == lang_allocating_phase_enum
-             || ((expld.phase == lang_assigning_phase_enum
-                  || expld.phase == lang_final_phase_enum)
-                 && expld.section == bfd_abs_section_ptr))
+         if (expld.phase != lang_first_phase_enum)
            {
              /* Notify the folder that this is an assignment to dot.  */
              expld.assigning_to_dot = TRUE;
              exp_fold_tree_1 (tree->assign.src);
              expld.assigning_to_dot = FALSE;
 
+             /* If we are assigning to dot inside an output section
+                arrange to keep the section, except for certain
+                expressions that evaluate to zero.  We ignore . = 0,
+                . = . + 0, and . = ALIGN (. != 0 ? expr : 1).  */
+             if (expld.phase == lang_mark_phase_enum
+                 && expld.section != bfd_abs_section_ptr
+                 && !(expld.result.valid_p
+                      && expld.result.value == 0
+                      && (is_value (tree->assign.src, 0)
+                          || is_sym_value (tree->assign.src, 0)
+                          || is_dot_plus_0 (tree->assign.src)
+                          || is_align_conditional (tree->assign.src))))
+               expld.section->flags |= SEC_KEEP;
+
              if (!expld.result.valid_p)
                {
                  if (expld.phase != lang_mark_phase_enum)
@@ -819,8 +1040,14 @@ exp_fold_tree_1 (etree_type *tree)
                }
              else if (expld.dotp == NULL)
                einfo (_("%F%S assignment to location counter"
-                        " invalid outside of SECTION\n"), tree);
-             else
+                        " invalid outside of SECTIONS\n"), tree);
+
+             /* After allocation, assignment to dot should not be
+                done inside an output section since allocation adds a
+                padding statement that effectively duplicates the
+                assignment.  */
+             else if (expld.phase <= lang_allocating_phase_enum
+                      || expld.section == bfd_abs_section_ptr)
                {
                  bfd_vma nextdot;
 
@@ -846,8 +1073,6 @@ exp_fold_tree_1 (etree_type *tree)
        }
       else
        {
-         etree_type *name;
-
          struct bfd_link_hash_entry *h = NULL;
 
          if (tree->type.node_class == etree_provide)
@@ -855,38 +1080,34 @@ exp_fold_tree_1 (etree_type *tree)
              h = bfd_link_hash_lookup (link_info.hash, tree->assign.dst,
                                        FALSE, FALSE, TRUE);
              if (h == NULL
-                 || (h->type != bfd_link_hash_new
-                     && h->type != bfd_link_hash_undefined
-                     && h->type != bfd_link_hash_common))
+                 || !(h->type == bfd_link_hash_new
+                      || h->type == bfd_link_hash_undefined
+                      || h->linker_def))
                {
-                 /* Do nothing.  The symbol was never referenced, or was
-                    defined by some object.  */
+                 /* Do nothing.  The symbol was never referenced, or
+                    was defined in some object file.  Undefined weak
+                    symbols stay undefined.  */
                  break;
                }
            }
 
-         name = tree->assign.src;
-         if (name->type.node_class == etree_trinary)
-           {
-             exp_fold_tree_1 (name->trinary.cond);
-             if (expld.result.valid_p)
-               name = (expld.result.value
-                       ? name->trinary.lhs : name->trinary.rhs);
-           }
-
-         if (name->type.node_class == etree_name
-             && name->type.node_code == NAME
-             && strcmp (tree->assign.dst, name->name.name) == 0)
-           /* Leave it alone.  Do not replace a symbol with its own
-              output address, in case there is another section sizing
-              pass.  Folding does not preserve input sections.  */
-           break;
-
+         expld.assign_name = tree->assign.dst;
          exp_fold_tree_1 (tree->assign.src);
-         if (expld.result.valid_p
+         /* expld.assign_name remaining equal to tree->assign.dst
+            below indicates the evaluation of tree->assign.src did
+            not use the value of tree->assign.dst.  We don't allow
+            self assignment until the final phase for two reasons:
+            1) Expressions are evaluated multiple times.  With
+            relaxation, the number of times may vary.
+            2) Section relative symbol values cannot be correctly
+            converted to absolute values, as is required by many
+            expressions, until final section sizing is complete.  */
+         if ((expld.result.valid_p
+              && (expld.phase == lang_final_phase_enum
+                  || expld.assign_name != NULL))
              || (expld.phase <= lang_mark_phase_enum
                  && tree->type.node_class == etree_assign
-                 && tree->assign.hidden))
+                 && tree->assign.defsym))
            {
              if (h == NULL)
                {
@@ -897,19 +1118,27 @@ exp_fold_tree_1 (etree_type *tree)
                           tree->assign.dst);
                }
 
-             /* FIXME: Should we worry if the symbol is already
-                defined?  */
-             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;
+             if (!update_definedness (tree->assign.dst, h) && 0)
+               {
+                 /* Symbol was already defined.  For now this error
+                    is disabled because it causes failures in the ld
+                    testsuite: ld-elf/var1, ld-scripts/defined5, and
+                    ld-scripts/pr14962.  Some of these no doubt
+                    reflect scripts used in the wild.  */
+                 (*link_info.callbacks->multiple_definition)
+                   (&link_info, h, link_info.output_bfd,
+                    expld.result.section, expld.result.value);
+               }
+             h->type = bfd_link_hash_defined;
+             h->u.def.value = expld.result.value;
              h->u.def.section = expld.result.section;
              if (tree->type.node_class == etree_provide)
                tree->type.node_class = etree_provided;
 
              /* Copy the symbol type if this is a simple assignment of
-                one symbol to another.  This could be more general
+                one symbol to another.  This could be more general
                 (e.g. a ?: operator with NAMEs in each branch).  */
              if (tree->assign.src->type.node_class == etree_name)
                {
@@ -931,6 +1160,7 @@ exp_fold_tree_1 (etree_type *tree)
                  && h->type == bfd_link_hash_new)
                h->type = bfd_link_hash_undefined;
            }
+         expld.assign_name = NULL;
        }
       break;
 
@@ -1048,6 +1278,7 @@ static etree_type *
 exp_assop (const char *dst,
           etree_type *src,
           enum node_tree_enum class,
+          bfd_boolean defsym,
           bfd_boolean hidden)
 {
   etree_type *n;
@@ -1059,20 +1290,25 @@ exp_assop (const char *dst,
   n->assign.type.node_class = class;
   n->assign.src = src;
   n->assign.dst = dst;
+  n->assign.defsym = defsym;
   n->assign.hidden = hidden;
   return n;
 }
 
+/* Handle linker script assignments and HIDDEN.  */
+
 etree_type *
-exp_assign (const char *dst, etree_type *src)
+exp_assign (const char *dst, etree_type *src, bfd_boolean hidden)
 {
-  return exp_assop (dst, src, etree_assign, FALSE);
+  return exp_assop (dst, src, etree_assign, FALSE, hidden);
 }
 
+/* Handle --defsym command-line option.  */
+
 etree_type *
 exp_defsym (const char *dst, etree_type *src)
 {
-  return exp_assop (dst, src, etree_assign, TRUE);
+  return exp_assop (dst, src, etree_assign, TRUE, FALSE);
 }
 
 /* Handle PROVIDE.  */
@@ -1080,7 +1316,7 @@ exp_defsym (const char *dst, etree_type *src)
 etree_type *
 exp_provide (const char *dst, etree_type *src, bfd_boolean hidden)
 {
-  return exp_assop (dst, src, etree_provide, hidden);
+  return exp_assop (dst, src, etree_provide, FALSE, hidden);
 }
 
 /* Handle ASSERT.  */
@@ -1145,6 +1381,17 @@ exp_print_tree (etree_type *tree)
        case DATA_SEGMENT_ALIGN:
        case DATA_SEGMENT_RELRO_END:
          function_like = TRUE;
+         break;
+       case SEGMENT_START:
+         /* Special handling because arguments are in reverse order and
+            the segment name is quoted.  */
+         exp_print_token (tree->type.node_code, FALSE);
+         fputs (" (\"", config.map_file);
+         exp_print_tree (tree->binary.rhs);
+         fputs ("\", ", config.map_file);
+         exp_print_tree (tree->binary.lhs);
+         fputc (')', config.map_file);
+         return;
        }
       if (function_like)
        {
@@ -1310,3 +1557,21 @@ align_n (bfd_vma value, bfd_vma align)
   value = (value + align - 1) / align;
   return value * align;
 }
+
+void
+ldexp_init (void)
+{
+  /* The value "13" is ad-hoc, somewhat related to the expected number of
+     assignments in a linker script.  */
+  if (!bfd_hash_table_init_n (&definedness_table,
+                             definedness_newfunc,
+                             sizeof (struct definedness_hash_entry),
+                             13))
+    einfo (_("%P%F: can not create hash table: %E\n"));
+}
+
+void
+ldexp_finish (void)
+{
+  bfd_hash_table_free (&definedness_table);
+}
This page took 0.032602 seconds and 4 git commands to generate.