/* This module handles expression trees.
- Copyright (C) 1991-2014 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.
bfd_hash_lookup (&definedness_table, name, FALSE, FALSE));
}
-/* Update the definedness state of NAME. */
+/* Update the definedness state of NAME. Return FALSE if script symbol
+ is multiply defining a strong symbol in an object. */
-static void
+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);
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. */
+ must be defined by an object file or by the linker target code. */
+ ret = TRUE;
if (!defentry->by_script
- && h->type != bfd_link_hash_undefined
- && h->type != bfd_link_hash_common
- && h->type != bfd_link_hash_new)
- defentry->by_object = 1;
+ && (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
else if (expld.dataseg.phase == exp_dataseg_none)
{
expld.dataseg.phase = exp_dataseg_align_seen;
- expld.dataseg.min_base = expld.dot;
expld.dataseg.base = expld.result.value;
expld.dataseg.pagesize = commonpage;
expld.dataseg.maxpagesize = maxpage;
break;
case DATA_SEGMENT_RELRO_END:
+ /* Operands swapped! DATA_SEGMENT_RELRO_END(offset,exp)
+ has offset in expld.result and exp in lhs. */
expld.dataseg.relro = exp_dataseg_relro_end;
+ expld.dataseg.relro_offset = expld.result.value;
if (expld.phase == lang_first_phase_enum
|| expld.section != bfd_abs_section_ptr)
expld.result.valid_p = FALSE;
case LENGTH:
{
- lang_memory_region_type *mem;
-
- mem = lang_memory_region_lookup (tree->name.name, FALSE);
- if (mem != NULL)
- new_number (mem->length);
- else
- einfo (_("%F%S: undefined MEMORY region `%s'"
- " referenced in expression\n"),
- tree, tree->name.name);
+ 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_number (mem->length);
+ else
+ einfo (_("%F%S: undefined MEMORY region `%s'"
+ " referenced in expression\n"),
+ tree, tree->name.name);
+ }
}
break;
}
/* Return true if TREE is '.'. */
-
+
static bfd_boolean
is_dot (const etree_type *tree)
{
/* 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
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_defined
- && (h->u.def.section->flags
- & SEC_LINKER_CREATED) != 0)))
+ || !(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;
}
}
tree->assign.dst);
}
- /* FIXME: Should we worry if the symbol is already
- defined? */
- 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)
{