]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commit
gas: aarch64: Fixing expression calculation using C64 symbols
authorMatthew Malcomson <matthew.malcomson@arm.com>
Thu, 29 Jul 2021 14:08:33 +0000 (15:08 +0100)
committerMatthew Malcomson <matthew.malcomson@arm.com>
Thu, 29 Jul 2021 14:08:33 +0000 (15:08 +0100)
commitd30dd5cf4f30b12a10fbd2214f4a6c5210900d42
treebc493c75f25833c737a00466f6647d535a9b30b7
parent8f2cd6521f047358e4b72bcafa77e47f1d15d52a
gas: aarch64: Fixing expression calculation using C64 symbols

Expressions involving function symbols should take into account the fact
that the LSB of C64 functions is set (while the LSB of labels is not
set).
The main motivating example of this is `capinit` expressions of the form
  f+((.Ltmp0+1)-f)
where `f` is a function and `.Ltmp0` is a label.
These should result in a CAPINIT relocation of the form
`f + <constant multiple of 4>` since the `+1` on the `.Ltmp0` should
cancel out the LSB that is set on `f`.

This is slightly different to the handling of a set LSB for THUMB
functions, since in THUMB the LSB is not kept when computing relations.
For THUMB expressions using the function are emitted as relocations to
let the linker apply the adjustment.

To implement this, we have two options (we choose the second):
  - Handle the LSB in the target hook `md_optimize_expr` (similar to how
    the arm backend handles expressions involving THUMB functions).
  - Set the LSB on the value assigned to the symbol in `tc_frob_label`.

The approach using the `md_optimize_expr` hook would involve adding one
to the expression that describes an operand, when that operand is a
C64 function symbol with no addend.  Then returning `FALSE` from that
hook in order to let the generic code handle the expression from then
on.

We would only want to do this when there is no addend to avoid applying
this adjustment multiple times in an expression (e.g. when a
subexpression reduces to a function symbol plus addend).
This adjustment would also want to avoid doing this to any expression
that would end up as a relocation involving that function symbol, since
then the artificial adjustment would be propagated to the relocation
(resulting in an expression like `f - 63` where the addend has been
adjusted to account for the LSB in `f`, but the linker will account for
the LSB in `f` itself).
Such avoidance is simple enough for expressions like `O_add` since we
can always avoid them, but it is more awkward to tell for `O_subtract`
expressions where some expressions can be reduced to a constant while
others will end up as a relocation.

Another difficulty with this approach is that the value of an expression
can be different depending on the relative location of the `type`
directive to the expression in the assembly source.  If the directive is
before an expression then the expression will account for the LSB but if
the directive is after the expression it will not.
While behaviour depending on the location of the `type` directive is a
tricky problem and has problems in the Morello LLVM compiler as well,
these behaviours do not match the behaviour of Morello LLVM.

The second approach is to adjust a symbols value in `tc_frob_label` if
it is a C64 function.  This will automatically mean that all symbol
expressions use this LSB correctly.
This approach does still have difficulties with relative locations of
the `type` directive, but here the behaviour matches Morello LLVM.  The
important factor in this case is whether the `type` directive is before
or after the function symbols label.  If the function label is before
the `type` directive then *all* expressions using the function label
will not account for the LSB, otherwise all expressions will utilise it.

There are two known differences with the Morello LLVM behaviour when
taking this approach.

The first is around calculating an expression of the form `operand - f`.
If `operand` is known, then both GAS and LLVM will account for the LSB
of `f`, but if `operand` is not known at the time this expression is
found then GAS will account for the LSB in the final relocation put into
the binary while Morello LLVM will not.  This is a Morello LLVM bug.

The second is that Morello LLVM does not allow expressions of the form
`f > altlabel` while GAS does.  In this case we have chosen to account
for the LSB, so that even if `f` and `altlabel` are defined in the same
place, if `f` is a C64 function symbol and `altlabel` is not then `f >
altlabel` will evaluate to true.
gas/config/tc-aarch64.c
gas/testsuite/gas/aarch64/morello-function-lsb.d [new file with mode: 0644]
gas/testsuite/gas/aarch64/morello-function-lsb.s [new file with mode: 0644]