/* This module handles expression trees.
- Copyright (C) 1991-2015 Free Software Foundation, Inc.
+ Copyright (C) 1991-2016 Free Software Foundation, Inc.
Written by Steve Chamberlain of Cygnus Support <sac@cygnus.com>.
This file is part of the GNU Binutils.
struct ldexp_control expld;
/* This structure records symbols for which we need to keep track of
- definedness for use in the DEFINED () test. */
+ definedness for use in the DEFINED () test. It is also used in
+ making absolute symbols section relative late in the link. */
struct definedness_hash_entry
{
struct bfd_hash_entry root;
+
+ /* If this symbol was assigned from "dot" outside of an output
+ section statement, the section we'd like it relative to. */
+ asection *final_sec;
+
+ /* Symbol was defined by an object file. */
unsigned int by_object : 1;
+
+ /* Symbols was defined by a script. */
unsigned int by_script : 1;
+
+ /* Low bit of iteration count. Symbols with matching iteration have
+ been defined in this pass over the script. */
unsigned int iteration : 1;
};
if (expld.result.section != NULL)
expld.result.value += expld.result.section->vma;
expld.result.section = bfd_abs_section_ptr;
+ expld.rel_from_abs = FALSE;
}
static void
{
asection *s = expld.section;
- if (s == bfd_abs_section_ptr && expld.phase == lang_final_phase_enum)
- s = section_for_dot ();
+ expld.rel_from_abs = TRUE;
expld.result.valid_p = TRUE;
expld.result.value = value - s->vma;
expld.result.str = NULL;
defentry->by_script = 1;
defentry->iteration = lang_statement_iteration;
+ defentry->final_sec = bfd_abs_section_ptr;
+ if (expld.phase == lang_final_phase_enum
+ && expld.rel_from_abs
+ && expld.result.section == bfd_abs_section_ptr)
+ defentry->final_sec = section_for_dot ();
return ret;
}
}
/* Return true if TREE is '.'. */
-
+
static bfd_boolean
is_dot (const etree_type *tree)
{
&& is_dot_ne_0 (tree->trinary.cond)
&& is_value (tree->trinary.rhs, 1));
}
- return 0;
+ return FALSE;
+}
+
+/* Subroutine of exp_fold_tree_1 for copying a symbol type. */
+
+static void
+try_copy_symbol_type (struct bfd_link_hash_entry * h, etree_type *src)
+{
+ if (src->type.node_class == etree_name)
+ {
+ struct bfd_link_hash_entry *hsrc;
+
+ hsrc = bfd_link_hash_lookup (link_info.hash, src->name.name,
+ FALSE, FALSE, TRUE);
+ if (hsrc)
+ bfd_copy_link_hash_symbol_type (link_info.output_bfd, h,
+ hsrc);
+ }
}
static void
/* 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). */
+ . = . + 0, and . = ALIGN (. != 0 ? expr : 1).
+ We can't ignore all expressions that evaluate to zero
+ because an otherwise empty section might have padding
+ added by an alignment expression that changes with
+ relaxation. Such a section might have zero size
+ before relaxation and so be stripped incorrectly. */
if (expld.phase == lang_mark_phase_enum
&& expld.section != bfd_abs_section_ptr
&& !(expld.result.valid_p
if (h == NULL
|| !(h->type == bfd_link_hash_new
|| h->type == bfd_link_hash_undefined
+ || h->type == bfd_link_hash_undefweak
|| h->linker_def))
{
/* Do nothing. The symbol was never referenced, or
- was defined in some object file. Undefined weak
- symbols stay undefined. */
+ was defined in some object file. Note that
+ undefweak symbols are defined by PROVIDE. This
+ is to support glibc use of __rela_iplt_start and
+ similar weak references. */
break;
}
}
h->type = bfd_link_hash_defined;
h->u.def.value = expld.result.value;
h->u.def.section = expld.result.section;
+ h->linker_def = 0;
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
- (e.g. a ?: operator with NAMEs in each branch). */
+ one symbol to another. Also, handle the case of a foldable
+ ternary conditional with names on either side. */
if (tree->assign.src->type.node_class == etree_name)
+ try_copy_symbol_type (h, tree->assign.src);
+ else if (tree->assign.src->type.node_class == etree_trinary)
{
- struct bfd_link_hash_entry *hsrc;
-
- hsrc = bfd_link_hash_lookup (link_info.hash,
- tree->assign.src->name.name,
- FALSE, FALSE, TRUE);
- if (hsrc)
- bfd_copy_link_hash_symbol_type (link_info.output_bfd, h,
- hsrc);
+ exp_fold_tree_1 (tree->assign.src->trinary.cond);
+ if (expld.result.valid_p)
+ {
+ if (expld.result.value
+ && tree->assign.src->trinary.lhs->type.node_class
+ == etree_name)
+ try_copy_symbol_type (h, tree->assign.src->trinary.lhs);
+
+ if (!expld.result.value
+ && tree->assign.src->trinary.rhs->type.node_class
+ == etree_name)
+ try_copy_symbol_type (h, tree->assign.src->trinary.rhs);
+ }
}
}
else if (expld.phase == lang_final_phase_enum)
void
exp_fold_tree (etree_type *tree, asection *current_section, bfd_vma *dotp)
{
+ expld.rel_from_abs = FALSE;
expld.dot = *dotp;
expld.dotp = dotp;
expld.section = current_section;
void
exp_fold_tree_no_dot (etree_type *tree)
{
+ expld.rel_from_abs = FALSE;
expld.dot = 0;
expld.dotp = NULL;
expld.section = bfd_abs_section_ptr;
einfo (_("%P%F: can not create hash table: %E\n"));
}
+/* Convert absolute symbols defined by a script from "dot" (also
+ SEGMENT_START or ORIGIN) outside of an output section statement,
+ to section relative. */
+
+static bfd_boolean
+set_sym_sections (struct bfd_hash_entry *bh, void *inf ATTRIBUTE_UNUSED)
+{
+ struct definedness_hash_entry *def = (struct definedness_hash_entry *) bh;
+ if (def->final_sec != bfd_abs_section_ptr)
+ {
+ struct bfd_link_hash_entry *h;
+ h = bfd_link_hash_lookup (link_info.hash, bh->string,
+ FALSE, FALSE, TRUE);
+ if (h != NULL
+ && h->type == bfd_link_hash_defined
+ && h->u.def.section == bfd_abs_section_ptr)
+ {
+ h->u.def.value -= def->final_sec->vma;
+ h->u.def.section = def->final_sec;
+ }
+ }
+ return TRUE;
+}
+
+void
+ldexp_finalize_syms (void)
+{
+ bfd_hash_traverse (&definedness_table, set_sym_sections, NULL);
+}
+
void
ldexp_finish (void)
{