This is the mail archive of the
mailing list for the binutils project.
Re: [1/9][RFC][DWARF] Reserve three DW_OP numbers in vendor extension space
On 15/11/16 19:25, Richard Earnshaw (lists) wrote:
On 15/11/16 16:48, Jiong Wang wrote:
On 15/11/16 16:18, Jakub Jelinek wrote:
I know nothing about the aarch64 return address signing, would all 3
2 usually appear together without any separate pc advance, or are they
going to appear frequently and at different pcs?
I think it's the latter, the DW_OP_AARCH64_paciasp and
DW_OP_AARCH64_paciasp_deref are going to appear frequently and at
For example, the following function prologue, there are three
at 0x0, 0x4, 0x8.
After the first instruction at 0x0, LR/X30 will be mangled. The
mangle LR register using SP as salt and write back the value into LR.
We then generate
DW_OP_AARCH64_paciasp to notify any unwinder that the original LR is
mangled in this
way so they can unwind the original value properly.
After the second instruction at 0x4, The mangled value of LR/X30 will
be pushed on
to stack, unlike usual .cfi_offset, the unwind rule for LR/X30 becomes:
first fetch the
mangled value from stack offset -16, then do whatever to restore the
from the mangled value. This is represented by
0x0 paciasp (this instruction sign return address register LR/X30)
.cfi_val_expression 30, DW_OP_AARCH64_paciasp
0x4 stp x29, x30, [sp, -32]!
.cfi_val_expression 30, DW_OP_AARCH64_paciasp_deref, -16
.cfi_offset 29, -32
0x8 add x29, sp, 0
Now I'm confused.
I was thinking that we needed one opcode for the sign operation in the
prologue and one for the unsign/validate operation in the epilogue (to
support non-call exceptions.
IMO, non-call exceptions is fine, it looks to me doesn't need extra
description as for non-call exceptions (exceptions thrown from signal
handler) the key point is how to unwind across signal frame. For libgcc EH
unwinder, when normal unwinding failed, it will fall back to architecture
unwinding hook which restore some information from signal frame which is just
on top of the signal handler's frame.
I can see AArch64 implementation will setup return address column like the
following logic where "sc->pc" is initialized by kernel and it's not signed
therefore should sucess on further unwinding.
(_Unwind_Ptr) (sc->pc) - new_cfa;
But why do we need a separate code to say
that a previously signed value has now been pushed on the stack? Surely
that's just a normal store operation that can be tracked through the
unwinding state machine.
I was thinking the same thing, but found it doesn't work. My understanding
of frame unwinding described at DWARF specification is: there are two steps
for frame unwinding. The first step is to calculate register restore rules.
Unwinder scans register rules from function start to the unwinding PC, one
rule will be *overridden* by the next for the same register, there is *no
inheritance*. The second step is then to evaluate all the final rules
collected at the unwinding PC. According to the rule, either fetch the value
from stack or evaluate the value on DWARF expression stack etc.
I also had tried to modify ".cfi_val_expression" at offset 0x4 in above
example into ".cfi_offset 30, -24", libgcc EH unwinder just doesn't work.
I was expecting the third opcode to be needed for the special operations
that are not frequently used by the compiler.
The two operations DW_OP_AARCH64_paciasp and DW_OP_AARCH64_paciasp_deref were
designed as shortcut operations when LR is signed with A key and using
function's CFA as salt. This is the default behaviour of return address
signing so is expected to be used for most of the time. DW_OP_AARCH64_pauth
is designed as a generic operation that allow describing pointer signing on
any value using any salt and key in case we can't use the shortcut operations
we can use this.