aboutsummaryrefslogtreecommitdiff
path: root/ld
diff options
context:
space:
mode:
authorNick Clifton <nickc@redhat.com>2005-05-17 14:35:21 +0000
committerNick Clifton <nickc@redhat.com>2005-05-17 14:35:21 +0000
commit3b83e13a450c5ecc419369bf0e413a895cb52608 (patch)
tree3d75763cf719ec8aadcd1cf7be88e91e0155ae17 /ld
parentc3357c6410a943a30157dff506e9496061957750 (diff)
downloadgdb-3b83e13a450c5ecc419369bf0e413a895cb52608.zip
gdb-3b83e13a450c5ecc419369bf0e413a895cb52608.tar.gz
gdb-3b83e13a450c5ecc419369bf0e413a895cb52608.tar.bz2
* ldlang.c (Scan_for_self_assignment): Check an assignment tree to
see if the same value is being used on the rhs as on the lhs. (print_assignment): Call scan_for_self_assignment and if it returns true, do no display the result of the computation but instead just the final value of the symbol on the lhs. * ld.texinfo: Document this behaviour and provide an example of when it will happen.
Diffstat (limited to 'ld')
-rw-r--r--ld/ChangeLog10
-rw-r--r--ld/ld.texinfo30
-rw-r--r--ld/ldlang.c88
3 files changed, 119 insertions, 9 deletions
diff --git a/ld/ChangeLog b/ld/ChangeLog
index a7d5865..342b939 100644
--- a/ld/ChangeLog
+++ b/ld/ChangeLog
@@ -1,3 +1,13 @@
+2005-05-17 Nick Clifton <nickc@redhat.com>
+
+ * ldlang.c (Scan_for_self_assignment): Check an assignment tree to
+ see if the same value is being used on the rhs as on the lhs.
+ (print_assignment): Call scan_for_self_assignment and if it
+ returns true, do no display the result of the computation but
+ instead just the final value of the symbol on the lhs.
+ * ld.texinfo: Document this behaviour and provide an example of
+ when it will happen.
+
2005-05-15 Daniel Jacobowitz <dan@codesourcery.com>
* Makefile.am (AM_MAKEINFOFLAGS): Define.
diff --git a/ld/ld.texinfo b/ld/ld.texinfo
index 7860e25..e66ec66 100644
--- a/ld/ld.texinfo
+++ b/ld/ld.texinfo
@@ -675,12 +675,40 @@ information about the link, including the following:
@itemize @bullet
@item
-Where object files and symbols are mapped into memory.
+Where object files are mapped into memory.
@item
How common symbols are allocated.
@item
All archive members included in the link, with a mention of the symbol
which caused the archive member to be brought in.
+@item
+The values assigned to symbols.
+
+Note - symbols whose values are computed by an expression which
+involves a reference to a previous value of the same symbol may not
+have correct result displayed in the link map. This is because the
+linker discards intermediate results and only retains the final value
+of an expression. Under such circumstances the linker will display
+the final value enclosed by square brackets. Thus for example a
+linker script containing:
+
+@smallexample
+ foo = 1
+ foo = foo * 4
+ foo = foo + 8
+@end smallexample
+
+will produce the following output in the link map if the @option{-M}
+option is used:
+
+@smallexample
+ 0x00000001 foo = 0x1
+ [0x0000000c] foo = (foo * 0x4)
+ [0x0000000c] foo = (foo + 0x8)
+@end smallexample
+
+See @ref{Expressions} for more information about expressions in linker
+scripts.
@end itemize
@kindex -n
diff --git a/ld/ldlang.c b/ld/ldlang.c
index c6c6007..19b986a 100644
--- a/ld/ldlang.c
+++ b/ld/ldlang.c
@@ -3133,12 +3133,63 @@ print_output_section_statement
output_section_statement);
}
+/* Scan for the use of the destination in the right hand side
+ of an expression. In such cases we will not compute the
+ correct expression, since the value of DST that is used on
+ the right hand side will be its final value, not its value
+ just before this expression is evaluated. */
+
+static bfd_boolean
+scan_for_self_assignment (const char * dst, etree_type * rhs)
+{
+ if (rhs == NULL || dst == NULL)
+ return FALSE;
+
+ switch (rhs->type.node_class)
+ {
+ case etree_binary:
+ return scan_for_self_assignment (dst, rhs->binary.lhs)
+ || scan_for_self_assignment (dst, rhs->binary.rhs);
+
+ case etree_trinary:
+ return scan_for_self_assignment (dst, rhs->trinary.lhs)
+ || scan_for_self_assignment (dst, rhs->trinary.rhs);
+
+ case etree_assign:
+ case etree_provided:
+ case etree_provide:
+ if (strcmp (dst, rhs->assign.dst) == 0)
+ return TRUE;
+ return scan_for_self_assignment (dst, rhs->assign.src);
+
+ case etree_unary:
+ return scan_for_self_assignment (dst, rhs->unary.child);
+
+ case etree_value:
+ if (rhs->value.str)
+ return strcmp (dst, rhs->value.str) == 0;
+ return FALSE;
+
+ case etree_name:
+ if (rhs->name.name)
+ return strcmp (dst, rhs->name.name) == 0;
+ return FALSE;
+
+ default:
+ break;
+ }
+
+ return FALSE;
+}
+
+
static void
print_assignment (lang_assignment_statement_type *assignment,
lang_output_section_statement_type *output_section)
{
- int i;
- int is_dot;
+ unsigned int i;
+ bfd_boolean is_dot;
+ bfd_boolean computation_is_valid = TRUE;
etree_type *tree;
etree_value_type result;
@@ -3147,14 +3198,17 @@ print_assignment (lang_assignment_statement_type *assignment,
if (assignment->exp->type.node_class == etree_assert)
{
- is_dot = 0;
+ is_dot = FALSE;
tree = assignment->exp->assert_s.child;
+ computation_is_valid = TRUE;
}
else
{
const char *dst = assignment->exp->assign.dst;
- is_dot = dst[0] == '.' && dst[1] == 0;
+
+ is_dot = (dst[0] == '.' && dst[1] == 0);
tree = assignment->exp->assign.src;
+ computation_is_valid = is_dot || (scan_for_self_assignment (dst, tree) == FALSE);
}
result = exp_fold_tree (tree, output_section, lang_final_phase_enum,
@@ -3163,11 +3217,29 @@ print_assignment (lang_assignment_statement_type *assignment,
{
bfd_vma value;
- value = result.value + result.section->bfd_section->vma;
+ if (computation_is_valid)
+ {
+ value = result.value + result.section->bfd_section->vma;
- minfo ("0x%V", value);
- if (is_dot)
- print_dot = value;
+ minfo ("0x%V", value);
+ if (is_dot)
+ print_dot = value;
+ }
+ else
+ {
+ struct bfd_link_hash_entry *h;
+
+ h = bfd_link_hash_lookup (link_info.hash, assignment->exp->assign.dst,
+ FALSE, FALSE, TRUE);
+ if (h)
+ {
+ value = h->u.def.value + result.section->bfd_section->vma;
+
+ minfo ("[0x%V]", value);
+ }
+ else
+ minfo ("[unresolved]");
+ }
}
else
{