summaryrefslogtreecommitdiff
path: root/ld/ldexp.c
diff options
context:
space:
mode:
authorAlan Modra <amodra@gmail.com>2016-10-04 10:41:26 +1030
committerAlan Modra <amodra@gmail.com>2016-10-04 10:41:26 +1030
commit9ad39107ca6e4efcda0f48a6abf528844a2f11aa (patch)
tree92e5e540dc59caa5c66b91b06d55c9af0e97615c /ld/ldexp.c
parent128d08b1587e537667c3079cc01915a94964e5a0 (diff)
downloadbinutils-gdb-9ad39107ca6e4efcda0f48a6abf528844a2f11aa.tar.gz
Fold arithmetic integer expressions
Commit b751e639 regressed arm linux kernel builds, that have an ASSERT (((__hyp_idmap_text_end - (__hyp_idmap_text_start & ~ (((0x1 << 0xc) - 0x1)))) <= (0x1 << 0xc)), HYP init code too big or misaligned) Due to some insanity in ld expression evaluation, the integer values 0x1 and 0xc above are treated as absolute addresses (ie. they have an associated section, *ABS*, see exp_fold_tree_1 case etree_value) while the expression (0x1 << 0xc) has a plain number result. The left hand side of the inequality happens to evaluate to a "negative" .text section relative value. Comparing a section relative value against an absolute value works since the section relative value is first converted to absolute. Comparing a section relative value against a number just compares the offsets, which fails since the "negative" offset is really a very large positive number. This patch works around the problem by folding integer expressions, so the assert again becomes ASSERT (((__hyp_idmap_text_end - (__hyp_idmap_text_start & 0xfffffffffffff000)) <= 0x1000), HYP init code too big or misaligned) * ldexp.c (exp_value_fold): New function. (exp_unop, exp_binop, exp_trinop): Use it.
Diffstat (limited to 'ld/ldexp.c')
-rw-r--r--ld/ldexp.c29
1 files changed, 29 insertions, 0 deletions
diff --git a/ld/ldexp.c b/ld/ldexp.c
index a560643fb33..9f88144b678 100644
--- a/ld/ldexp.c
+++ b/ld/ldexp.c
@@ -1252,6 +1252,19 @@ exp_fold_tree_no_dot (etree_type *tree)
exp_fold_tree_1 (tree);
}
+static void
+exp_value_fold (etree_type *tree)
+{
+ exp_fold_tree_no_dot (tree);
+ if (expld.result.valid_p)
+ {
+ tree->type.node_code = INT;
+ tree->value.value = expld.result.value;
+ tree->value.str = NULL;
+ tree->type.node_class = etree_value;
+ }
+}
+
etree_type *
exp_binop (int code, etree_type *lhs, etree_type *rhs)
{
@@ -1263,6 +1276,12 @@ exp_binop (int code, etree_type *lhs, etree_type *rhs)
new_e->binary.lhs = lhs;
new_e->binary.rhs = rhs;
new_e->type.node_class = etree_binary;
+ if (lhs->type.node_class == etree_value
+ && rhs->type.node_class == etree_value
+ && code != ALIGN_K
+ && code != DATA_SEGMENT_ALIGN
+ && code != DATA_SEGMENT_RELRO_END)
+ exp_value_fold (new_e);
return new_e;
}
@@ -1278,6 +1297,10 @@ exp_trinop (int code, etree_type *cond, etree_type *lhs, etree_type *rhs)
new_e->trinary.cond = cond;
new_e->trinary.rhs = rhs;
new_e->type.node_class = etree_trinary;
+ if (cond->type.node_class == etree_value
+ && lhs->type.node_class == etree_value
+ && rhs->type.node_class == etree_value)
+ exp_value_fold (new_e);
return new_e;
}
@@ -1291,6 +1314,12 @@ exp_unop (int code, etree_type *child)
new_e->unary.type.lineno = child->type.lineno;
new_e->unary.child = child;
new_e->unary.type.node_class = etree_unary;
+ if (child->type.node_class == etree_value
+ && code != ALIGN_K
+ && code != ABSOLUTE
+ && code != NEXT
+ && code != DATA_SEGMENT_END)
+ exp_value_fold (new_e);
return new_e;
}