gas: synthesize CFI for hand-written asm
This patch adds support in GAS to generate generic GAS instructions (a.k.a., the ginsn) for the x86 backend (AMD64 ABI only at this time). Using this ginsn infrastructure, GAS can also synthesize CFI for hand-written asm for x86_64. A ginsn is a target-independent representation of the machine instructions. One machine instruction may need one or more ginsn. Since the current use-case of ginsn is to synthesize CFI, the x86 target generates ginsns necessary for the following machine instructions only: - All change of flow instructions, including all conditional and unconditional branches, call and return from functions. - All register saves and unsaves to the stack. - All instructions affecting the two registers that could potentially be used as the base register for CFA tracking. For SCFI, the base register for CFA tracking is limited to REG_SP and REG_FP only for now. The representation of ginsn is kept simple: - GAS instruction has GINSN_NUM_SRC_OPNDS (defined to be 2 at this time) number of source operands and one destination operand at this time. - GAS instruction uses DWARF register numbers in its representation and does not track register size. - GAS instructions carry location information (file name and line number). - GAS instructions are ID's with a natural number in order of their addtion to the list. This can be used as a proxy for the static program order of the corresponding machine instructions. Note that, GAS instruction (ginsn) format does not support GINSN_TYPE_PUSH and GINSN_TYPE_POP. Some architectures, like aarch64, do not have push and pop instructions, but rather STP/LDP instructions. Further these instructions have a variety of addressing modes, like pre-indexing and post-indexing etc. Among other things, one of differences in these addressing modes is _when_ the base pointer is updated with the result of the address calculation : before or after the memory operation. To best support such needs, the generic instructions like GINSN_TYPE_LDS, GINSN_TYPE_STS (load and store to stack) together with GINSN_TYPE_ADD, and GINSN_TYPE_SUB may be used. The functionality provided in ginsn.c and scfi.c is compiled in when a target defines TARGET_USE_SCFI and TARGET_USE_GINSN. This can be revisited later when there are other use-cases of creating ginsn's in GAS, apart from the current use-case of synthesizing CFI for hand-written asm. Support is added only for AMD64 ABI at this time. If the user specifies, --scfi --32, GAS issues an error: "Fatal error: Synthesizing CFI is not supported for this ABI" 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 - Hand-written asm block must end with a .size foo, .-foo Further, the SCFI machinery employs some heuristics / rules. These heuristics imply certain restrictions on how the hand-written asm is done by the programmer. For example: - 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. - 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. gas/ * Makefile.am: Add new files. * Makefile.in: Regenerated. * as.c (defined): Guard with both TARGET_USE_SCFI and TARGET_USE_GINSN. * config/obj-elf.c (obj_elf_size): Invoke ginsn_data_end. (obj_elf_type): Invoke ginsn_data_begin. * config/tc-i386.c (ginsn_new): New functionality to generate ginsns. (x86_scfi_callee_saved_p): New function. (ginsn_dw2_regnum): Likewise. (ginsn_set_where): Likewise. (x86_ginsn_alu): Likewise. (x86_ginsn_move): Likewise. (x86_ginsn_lea): Likewise. (x86_ginsn_jump): Likewise. (x86_ginsn_jump_cond): Likewise. (md_assemble): Invoke ginsn_new. (s_insn): Likewise. (i386_target_format): Add hard error for usage of --scfi with non AMD64 ABIs. * config/tc-i386.h (TARGET_USE_GINSN): New definition. (TARGET_USE_SCFI): Likewise. (SCFI_NUM_REGS): Likewise. (REG_FP): Likewise. (REG_SP): Likewise. (SCFI_INIT_CFA_OFFSET): Likewise. (SCFI_CALLEE_SAVED_REG_P): Likewise. (x86_scfi_callee_saved_p): Likewise. * subsegs.h (struct frch_ginsn_data): New forward declaration. (struct frchain): New member for ginsn data. * symbols.c: Invoke ginsn_frob_label to convey user-defined labels to ginsn infrastructure. * ginsn.c: New file. * ginsn.h: New file. * scfi.c: New file. * scfi.h: New file.
Loading
Please register or sign in to comment