Hardcode host-specific name for LTO plugin
[platform/upstream/binutils.git] / ld / ldexp.c
index 5f4e974..5c4f8dd 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-2014 Free Software Foundation, Inc.
    Written by Steve Chamberlain of Cygnus Support <sac@cygnus.com>.
 
    This file is part of the GNU Binutils.
@@ -81,6 +79,7 @@ exp_print_token (token_code_type code, int infix_p)
     { GE, ">=" },
     { LSHIFT, "<<" },
     { RSHIFT, ">>" },
+    { LOG2CEIL, "LOG2CEIL" },
     { ALIGN_K, "ALIGN" },
     { BLOCK, "BLOCK" },
     { QUAD, "QUAD" },
@@ -135,6 +134,28 @@ exp_print_token (token_code_type code, int infix_p)
 }
 
 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)
 {
   if (expld.result.section != NULL)
@@ -242,6 +263,10 @@ fold_unary (etree_type *tree)
          make_abs ();
          break;
 
+       case LOG2CEIL:
+         make_log2ceil ();
+         break;
+
        case '~':
          expld.result.value = ~expld.result.value;
          break;
@@ -312,7 +337,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
@@ -550,13 +575,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 lang_definedness_hash_entry *def;
 
          h = bfd_wrapped_link_hash_lookup (link_info.output_bfd,
                                            &link_info,
@@ -566,15 +588,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 = lang_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)
-       expld.assign_name = NULL;
+       {
+         /* Self-assignment is only allowed for absolute symbols
+            defined in a linker script.  */
+         struct bfd_link_hash_entry *h;
+         struct lang_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 = lang_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)
@@ -697,7 +737,7 @@ 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
@@ -708,11 +748,11 @@ fold_name (etree_type *tree)
     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);
@@ -723,11 +763,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);
@@ -750,6 +790,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 lang_definedness_hash_entry *def;
+
+  return (tree->type.node_class == etree_name
+         && tree->type.node_code == NAME
+         && (def = lang_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)
 {
@@ -814,6 +937,20 @@ exp_fold_tree_1 (etree_type *tree)
              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)
@@ -864,7 +1001,10 @@ exp_fold_tree_1 (etree_type *tree)
              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_common
+                     && !(h->type == bfd_link_hash_defined
+                          && (h->u.def.section->flags
+                              & SEC_LINKER_CREATED) != 0)))
                {
                  /* Do nothing.  The symbol was never referenced, or was
                     defined by some object.  */