[PATCH 0/2] Add SCFI support for aarch64

Indu Bhagat indu.bhagat@oracle.com
Thu Apr 11 07:44:05 GMT 2024


Hello,

This patch series extends GAS support for SCFI to aarch64.

Since Binutils 2.42, GAS has experimental support for synthesizing CFI (SCFI)
for hand-written asm for the x86 backend.  This is invoked via
--scfi=experimental on the hand-written asm.  SCFI aims to relieve users from
the overhead of writing and maintaining CFI directives in hand-written asm.

One of the ways of hardening the SCFI feature in GAS is to extend support to
another major architecture.  This would also allow exercising SCFI on more
workloads.

Background
-----------
Some background notes on SCFI are present on the wiki
https://sourceware.org/binutils/wiki/gas/SCFI.  I will refrain from repeating
some of that content here for sake of brevity.

Additionally, the commit log for the first commit which added the support on
x86 may also be helpful in reviewing this series.
 - gas: x86: synthesize CFI for hand-written asm
   c7defc5386cc53a4abbb7c53a924cdac3f16aa33

For synthesizing (DWARF) CFI, the SCFI machinery requires the programmer
to adhere to some pre-requisites for their asm:
   - Hand-written asm block must begin with a .type   foo, %function
It is highly recommended to, additionally, also ensure that:
   - Hand-written asm block ends with a .size foo, .-foo

ginsns, SCFI constraints, etc.
------------------------------
ginsn is an acronym for generic GAS instruction.  This is intended to be
architecture-neutral abstraction that can be used to convey and keep semantic
information about machine instructions in an arch-neutral way in GAS.  ginsn
specification and associated interfaces can be seen in gas/ginsn.c and
gas/ginsn.h.

The SCFI algorithm itself is implemented as a couple of passes.  The following
is a gross over-simplification of the overall process; simplified to hopefully
aid the review process:

 - Create the GCFG (control flow graph) of the ginsns.
 - Process each basic block and make a note of how each instruction changes the
   SCFI state (CFA, callee-saved registers, RA).  This is done via two passes:
   forward_flow_scfi_state () and backward_flow_scfi_state ().
 - Translate SCFI ops to equivalent DWARF CFI ops or directives.

The above is implemented in gas/scfi.h and gas/scfi.c.  Also see the
gas/scfidw2gen.h and gas/scfidw2gen.c where SCFI ops are processed to finally
create the DWARF CFI directives.

Lastly, I think stating some specifics of SCFI core algorithm itself may be
helpful for the review process: Basically the SCFI machinery encodes some rules
specified in the standard ABI calling convention (e.g., set of callee-saved
registers,  how the return address is managed etc).  Apart from the rules, the
SCFI machinery employs some heuristics.  Few examples of heuristics:

   - The base register for CFA tracking may be either REG_SP or REG_FP.
   - If the base register for CFA tracking is REG_SP, the precise amount of
     stack usage (and hence, the value of REG_SP) must be known at all times.
   - If using dynamic stack allocation, the function must switch to
     FP-based CFA.  This means using instructions like the following (in
     AMD64) in prologue:
        pushq   %rbp
        movq    %rsp, %rbp
     and analogous instructions in epilogue.  In case of aarch64, this simply
     means creation of the frame record.
   - Save and Restore of callee-saved registers must be symmetrical.
     However, the SCFI machinery at this time only warns if any such
     asymmetry is seen.

These heuristics/rules are architecture-independent and are meant to
employed for all architectures/ABIs using SCFI in the future.

The SCFI paper published sometime ago
(https://sourceware.org/pipermail/binutils/2023-September/129558.html) may be a
useful resource to get additional understanding of the above.  

Known limitations 
-----------------
These are planned to be worked on in the near future:

 - The current SCFI machinery does not currently synthesize the PAC-related
   aarch64-specific CFI directives: .cfi_b_key_frame.  Other opcodes used when
   pointer authentication is enabled also need to be handled (braa, brab,
   retaa, etc.).

 - Supporting the following pattern:
   mov x16,4266
   add sp, x16, sp
   ...

 - Not a limitation per se, but a note that ATM, that predicated insns are
   skipped from ginsn translation.  IIUC, these instructions are not such that
   can be used alongside stack management ops. To be double-checked.

Thanks,

Indu Bhagat (2):
  gas: aarch64: add experimental support for SCFI
  gas: aarch64: testsuite: add new tests for SCFI

 gas/config/tc-aarch64.c                       | 744 ++++++++++++++++++
 gas/config/tc-aarch64.h                       |  20 +
 gas/testsuite/gas/scfi/README                 |   2 +-
 gas/testsuite/gas/scfi/aarch64/ginsn-cofi-1.l |  30 +
 gas/testsuite/gas/scfi/aarch64/ginsn-cofi-1.s |  16 +
 gas/testsuite/gas/scfi/aarch64/ginsn-ldst-1.l |  40 +
 gas/testsuite/gas/scfi/aarch64/ginsn-ldst-1.s |  21 +
 gas/testsuite/gas/scfi/aarch64/ginsn-misc-1.l |  32 +
 gas/testsuite/gas/scfi/aarch64/ginsn-misc-1.s |  15 +
 .../gas/scfi/aarch64/scfi-aarch64.exp         |  60 ++
 gas/testsuite/gas/scfi/aarch64/scfi-cb-1.d    |  20 +
 gas/testsuite/gas/scfi/aarch64/scfi-cb-1.l    |   2 +
 gas/testsuite/gas/scfi/aarch64/scfi-cb-1.s    |  14 +
 gas/testsuite/gas/scfi/aarch64/scfi-cfg-1.d   |  31 +
 gas/testsuite/gas/scfi/aarch64/scfi-cfg-1.l   |   2 +
 gas/testsuite/gas/scfi/aarch64/scfi-cfg-1.s   |  46 ++
 gas/testsuite/gas/scfi/aarch64/scfi-cfg-2.d   |  40 +
 gas/testsuite/gas/scfi/aarch64/scfi-cfg-2.l   |   2 +
 gas/testsuite/gas/scfi/aarch64/scfi-cfg-2.s   |  42 +
 gas/testsuite/gas/scfi/aarch64/scfi-cfg-3.d   |  32 +
 gas/testsuite/gas/scfi/aarch64/scfi-cfg-3.l   |   2 +
 gas/testsuite/gas/scfi/aarch64/scfi-cfg-3.s   |  34 +
 .../gas/scfi/aarch64/scfi-cond-br-1.d         |  20 +
 .../gas/scfi/aarch64/scfi-cond-br-1.l         |   2 +
 .../gas/scfi/aarch64/scfi-cond-br-1.s         |  13 +
 gas/testsuite/gas/scfi/aarch64/scfi-diag-1.l  |   2 +
 gas/testsuite/gas/scfi/aarch64/scfi-diag-1.s  |   6 +
 gas/testsuite/gas/scfi/aarch64/scfi-diag-2.l  |   3 +
 gas/testsuite/gas/scfi/aarch64/scfi-diag-2.s  |  25 +
 gas/testsuite/gas/scfi/aarch64/scfi-ldrp-1.d  |  59 ++
 gas/testsuite/gas/scfi/aarch64/scfi-ldrp-1.l  |   2 +
 gas/testsuite/gas/scfi/aarch64/scfi-ldrp-1.s  |  52 ++
 gas/testsuite/gas/scfi/aarch64/scfi-ldrp-2.d  |  33 +
 gas/testsuite/gas/scfi/aarch64/scfi-ldrp-2.l  |   2 +
 gas/testsuite/gas/scfi/aarch64/scfi-ldrp-2.s  |  26 +
 gas/testsuite/gas/scfi/aarch64/scfi-strp-1.d  |  39 +
 gas/testsuite/gas/scfi/aarch64/scfi-strp-1.l  |   2 +
 gas/testsuite/gas/scfi/aarch64/scfi-strp-1.s  |  37 +
 gas/testsuite/gas/scfi/aarch64/scfi-strp-2.d  |  35 +
 gas/testsuite/gas/scfi/aarch64/scfi-strp-2.l  |   2 +
 gas/testsuite/gas/scfi/aarch64/scfi-strp-2.s  |  30 +
 .../gas/scfi/aarch64/scfi-unsupported-1.l     |   4 +
 .../gas/scfi/aarch64/scfi-unsupported-1.s     |  31 +
 43 files changed, 1671 insertions(+), 1 deletion(-)
 create mode 100644 gas/testsuite/gas/scfi/aarch64/ginsn-cofi-1.l
 create mode 100644 gas/testsuite/gas/scfi/aarch64/ginsn-cofi-1.s
 create mode 100644 gas/testsuite/gas/scfi/aarch64/ginsn-ldst-1.l
 create mode 100644 gas/testsuite/gas/scfi/aarch64/ginsn-ldst-1.s
 create mode 100644 gas/testsuite/gas/scfi/aarch64/ginsn-misc-1.l
 create mode 100644 gas/testsuite/gas/scfi/aarch64/ginsn-misc-1.s
 create mode 100644 gas/testsuite/gas/scfi/aarch64/scfi-aarch64.exp
 create mode 100644 gas/testsuite/gas/scfi/aarch64/scfi-cb-1.d
 create mode 100644 gas/testsuite/gas/scfi/aarch64/scfi-cb-1.l
 create mode 100644 gas/testsuite/gas/scfi/aarch64/scfi-cb-1.s
 create mode 100644 gas/testsuite/gas/scfi/aarch64/scfi-cfg-1.d
 create mode 100644 gas/testsuite/gas/scfi/aarch64/scfi-cfg-1.l
 create mode 100644 gas/testsuite/gas/scfi/aarch64/scfi-cfg-1.s
 create mode 100644 gas/testsuite/gas/scfi/aarch64/scfi-cfg-2.d
 create mode 100644 gas/testsuite/gas/scfi/aarch64/scfi-cfg-2.l
 create mode 100644 gas/testsuite/gas/scfi/aarch64/scfi-cfg-2.s
 create mode 100644 gas/testsuite/gas/scfi/aarch64/scfi-cfg-3.d
 create mode 100644 gas/testsuite/gas/scfi/aarch64/scfi-cfg-3.l
 create mode 100644 gas/testsuite/gas/scfi/aarch64/scfi-cfg-3.s
 create mode 100644 gas/testsuite/gas/scfi/aarch64/scfi-cond-br-1.d
 create mode 100644 gas/testsuite/gas/scfi/aarch64/scfi-cond-br-1.l
 create mode 100644 gas/testsuite/gas/scfi/aarch64/scfi-cond-br-1.s
 create mode 100644 gas/testsuite/gas/scfi/aarch64/scfi-diag-1.l
 create mode 100644 gas/testsuite/gas/scfi/aarch64/scfi-diag-1.s
 create mode 100644 gas/testsuite/gas/scfi/aarch64/scfi-diag-2.l
 create mode 100644 gas/testsuite/gas/scfi/aarch64/scfi-diag-2.s
 create mode 100644 gas/testsuite/gas/scfi/aarch64/scfi-ldrp-1.d
 create mode 100644 gas/testsuite/gas/scfi/aarch64/scfi-ldrp-1.l
 create mode 100644 gas/testsuite/gas/scfi/aarch64/scfi-ldrp-1.s
 create mode 100644 gas/testsuite/gas/scfi/aarch64/scfi-ldrp-2.d
 create mode 100644 gas/testsuite/gas/scfi/aarch64/scfi-ldrp-2.l
 create mode 100644 gas/testsuite/gas/scfi/aarch64/scfi-ldrp-2.s
 create mode 100644 gas/testsuite/gas/scfi/aarch64/scfi-strp-1.d
 create mode 100644 gas/testsuite/gas/scfi/aarch64/scfi-strp-1.l
 create mode 100644 gas/testsuite/gas/scfi/aarch64/scfi-strp-1.s
 create mode 100644 gas/testsuite/gas/scfi/aarch64/scfi-strp-2.d
 create mode 100644 gas/testsuite/gas/scfi/aarch64/scfi-strp-2.l
 create mode 100644 gas/testsuite/gas/scfi/aarch64/scfi-strp-2.s
 create mode 100644 gas/testsuite/gas/scfi/aarch64/scfi-unsupported-1.l
 create mode 100644 gas/testsuite/gas/scfi/aarch64/scfi-unsupported-1.s

-- 
2.43.0



More information about the Binutils mailing list