Skip to content
Commit aa22267c authored by Indu Bhagat's avatar Indu Bhagat
Browse files

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.
parent b1457a94
Loading
Loading
Loading
Loading
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment