Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
gas: aarch64: add experimental support for SCFI
[Changes in V5] - Use aarch64_zero_register_p () to detect zero reg. Get rid of bool sp_allowed_p argument of ginsn_dw2_regnum (). Also update the handling for case AARCH64_OPND_CLASS_MODIFIED_REG and return opnd->addr.base_regno. - Do not generate GINSN_TYPE_LOAD / GINSN_TYPE_STORE for memory operations tagged with subclass flag F_SUBCLASS_OTHER in both aarch64_ginsn_ldstp () and aarch64_ginsn_ldstr (). Examples of such insns include prfm, stg*, ldpsw. - Restructure code in aarch64_ginsn_ldstp () and aarch64_ginsn_ldstr () to move the compensating action of ginsn_ind next to the creation of ginsn_ind itself. Update code comments. - Carve out two different functions for mov: aarch64_ginsn_mov_imm () and aarch64_ginsn_mov_reg (). - Use conditionals instead of asserts to handle "b 4" and "cbz x0, 4", or even "b symbol+1" and "cbz x0, symbol+1" in aarch64_ginsn_branch_uncond () and aarch64_ginsn_branch_cond (). - Now that addg, subg are sub-classified with F_SUBCLASS_OTHER, add a comment in addsum_imm case block around the same. - In aarch64_ginsn_unhandled (), carve out the check for sve_misc into its own conditional block. - Use aarch64_opcode_subclass_p () consistently. - In aarch64_ginsn_safe_to_skip_p (), detect irg op (for whitelisting) by means of subclass to make the code more robust as in future, new ops may be added with destination Rd_SP. - Punt on W and S loads and stores, since they cannot implement a full save & restore for CFI purposes. - Include ginsn generation for ldstnapair_offs iclass. This was ignored until now, but it seems these ops can be used for save / restore ops. - Other minor code and code comment fixes. [End of changes in V5] [Changes in V4] - Use data types uniformly. Use 'unsigned int' instead of 'uint32_t' for DWARF register numbers. Use offsetT where applicable. - Minor code restructuring in aarch64_ginsn_safe_to_skip_p (). Move common code out of switch case. - Add FP/Advanced SIMD registers to callee-saved registers too. Updated commit log to include some of the details. - Check for opnd type AARCH64_OPND_QLF_W or AARCH64_OPND_QLF_S_S in aarch64_ginsn_ldstp () to detect 32-bit word operations. - Skip generating ginsns for movk, movz, movn. These do more work than just simple mov; Skip generating ginsn altogether for these. - ginsn_dw2_regnum () is now switch case on opnd_class. Each case exposed by the current set of ginsn creation logic is handled. - Skip Z register usage altogether for now. Skip sve_misc iclass but error out if callee-saved FP/Advanced SIMD registers or stack management are involved. [End of changes in V4] [No changes in V3] [Changes in V2] - Factored out the ginsn creation functionality from tc-aarch64.c into tc-aarch64-ginsn.c. - The switch case in aarch64_ginsn_new now is based on iclass rather than (earlier) opcode. - Rename aarch64_ginsn_jump / aarch64_ginsn_jump_cond to aarch64_ginsn_branch_uncond / aarch64_ginsn_branch_cond respectively. - Explicitly whitelist irg insn. - Other minor code comment and readability fixes. [End of changes in V2] For synthesizing CFI (SCFI) for hand-written asm, the SCFI machinery in GAS works on the generic GAS insns (ginsns). This patch adds support in the aarch64 backend to create ginsns for a subset of the supported machine instructions. The subset includes the minimal necessary instructions to ensure SCFI correctness: - Any potential register saves and unsaves. Hence, process instructions belonging to a variety of iclasses involving str, ldr, stp, ldp. - Any change of flow instructions. This includes all conditional and unconditional branches, call (bl, blr, etc.) and return. - Most importantly, any instruction that could affect the two registers of interest: REG_SP, REG_FP. This set includes all pre-indexed and post-indexed memory operations, with writeback, on the stack. This set must also include other instructions (e.g., arithmetic insns) where the destination register is one of the afore-mentioned registers. With respect to callee-saved registers in Aarch64, FP/Advanced SIMD registers D8-D15 are included along with the relevant GPRs. Calculating offsets for loads and stores especially for Q registers needs special attention here. As an example, str q8, [sp, #16] On big-endian: STR Qn stores as a 128-bit integer (MSB first), hence, should record D8 as being saved at sp+24 rather than sp+16. On little-endian: should record D8 as being saved at sp+16 D8-D15 are the low 64 bits of Q8-Q15, and of Z8-Z15 if SVE is used; hence, they remain "interesting" for SCFI purposes in such cases. A CFI save slot always represents the low 64 bits, regardless of whether a save occurs on D, Q or Z registers. Currently, the ginsn creation machinery can handle D and Q registers on little-endian and big-endian. Apart from creating ginsn, another key responsibility of the backend is to make sure there are safeguards in place to detect and alert if an instruction of interest may have been skipped. This is done via aarch64_ginsn_unhandled () (similar to the x86 backend). This function , hence, is also intended to alert when future ISA changes may otherwise render SCFI results incorrect, because of missing ginsns for the newly added machine instructions. At this time, becuase of the complexities wrt endianness in handling Z register usage, skip sve_misc opclass altogether for now. The SCFI machinery will error out (using the aarch64_ginsn_unhandled () code path) though if Z register usage affects correctness. The current SCFI machinery does not currently synthesize the PAC-related, aarch64-specific CFI directives: .cfi_b_key_frame. The support for this is planned for near future. SCFI is enabled for ELF targets only. gas/ * config/tc-aarch64-ginsn.c: New file. * config/tc-aarch64.c (md_assemble): Include tc-aarch64-ginsn.c file. Invoke aarch64_ginsn_new. * config/tc-aarch64.h (TARGET_USE_GINSN): Define for SCFI enablement. (TARGET_USE_SCFI): Likewise. (SCFI_MAX_REG_ID): New definition. (REG_FP): Likewise. (REG_LR): Likewise. (REG_SP): Likewise. (SCFI_INIT_CFA_OFFSET): Likewise. (SCFI_CALLEE_SAVED_REG_P): Likewise. (aarch64_scfi_callee_saved_p): New declaration.
- Loading branch information