[PATCH] ld: fix ABSOLUTE for general expressions

Alan Modra amodra@gmail.com
Fri Sep 30 16:34:00 GMT 2016

On Thu, Sep 29, 2016 at 02:29:30PM +0100, Kyrill Tkachov wrote:
> Hi Alan,
> On 20/07/16 03:44, Alan Modra wrote:
> >Like all changes that affect script expressions there is quite a good
> >chance that someone is relying on the old behaviour.  For example,
> >Jakub called the maxpage3b behaviour a "feature" in
> >https://sourceware.org/ml/binutils/2007-01/msg00181.html
> >Well, that one seems quite clearly a bug to me.  I'm actually more
> >worried about "absolute (<number>)" inside output section statements,
> >ie. the behaviour that Tristan thinks should be changed.  Oh well,
> >let's see who screams.
> I noticed this patch breaks linking of an arm defconfig Linux kernel.
> It fails with:
> arm-none-linux-gnueabihf-ld: HYP init code too big or misaligned
> This is with a linux-4.7.4 kernel configured with:
> make ARCH=arm defconfig

So the assert is as follows, now:

ASSERT (((__hyp_idmap_text_end - (__hyp_idmap_text_start & ~ (((0x1 << 0xc) - 0x1)))) <= (0x1 << 0xc)), HYP init code too big or misaligned)

Previously, the pagemask and pagesize expressions would have been

In both cases the operands of the & expression are a relative symbol
value (both symbols are .text + 0x1000) and an absolute value.  Note
there is a difference between an absolute value and a plain number.
An absolute value has a section while the number doesn't.  So the
operands of the & have different sections, and in such cases both are
converted to absolute.  Which is good, because you want to mask the
absolute value of the symbol, 0xc0301000, not its section relative
value.  However, the somewhat insane expression evaluation rules say
that the result of the & is a plain number.  So the subtraction
operands are a section relative symbol value and a number.  The
subtraction keeps the section, resulting in
.text + 0xffffffff3fd00000.  Which might look odd, but is zero if
converted to absolute.

On the right hand side of <=, 0x1 << 0xc is evaluated to 0x1000 but
becomes a plain number, whereas the old folded result was an absolute
value.  With an absolute value the left hand side of the <= is
converted to absolute before evaluation, resulting in "0 <= 0x1000".
A plain number does not cause the conversion resulting in a comparison
of offsets, "0xffffffff3fd00000 <= 0x1000".

I'm not sure how to fix this insanity in ld without breaking some
other horrible user scripts.

Alan Modra
Australia Development Lab, IBM

More information about the Binutils mailing list