public inbox for binutils@sourceware.org
 help / color / mirror / Atom feed
From: Indu Bhagat <indu.bhagat@oracle.com>
To: binutils@sourceware.org, Richard.Earnshaw@arm.com,
	richard.sandiford@arm.com
Subject: Re: [PATCH,V6 8/9] gas: aarch64: add experimental support for SCFI
Date: Thu, 18 Jul 2024 13:01:16 -0700	[thread overview]
Message-ID: <9beab368-2187-445e-abb8-6dfa7f504c48@oracle.com> (raw)
In-Reply-To: <mpta5if7zht.fsf@arm.com>

On 7/18/24 3:42 AM, Richard Sandiford wrote:
> Indu Bhagat <indu.bhagat@oracle.com> writes:
>> [...]
>> +/* Generate ginsn for addsub instructions with reg opnd.  */
>> +
>> +static ginsnS *
>> +aarch64_ginsn_addsub_reg (const symbolS *insn_end_sym)
>> +{
>> +  ginsnS *ginsn = NULL;
>> +  bool add_p, sub_p;
>> +  unsigned int dst_reg, src1_reg, src2_reg;
>> +  aarch64_opnd_info *dst, *src1, *src2;
>> +  ginsnS *(*ginsn_func) (const symbolS *, bool,
>> +			 enum ginsn_src_type, unsigned int, offsetT,
>> +			 enum ginsn_src_type, unsigned int, offsetT,
>> +			 enum ginsn_dst_type, unsigned int, offsetT);
>> +
>> +  aarch64_inst *base = &inst.base;
>> +  const aarch64_opcode *opcode = base->opcode;
>> +
>> +  add_p = aarch64_opcode_subclass_p (opcode, F_ARITH_ADD);
>> +  sub_p = aarch64_opcode_subclass_p (opcode, F_ARITH_SUB);
>> +  gas_assert (add_p || sub_p);
>> +  ginsn_func = add_p ? ginsn_new_add : ginsn_new_sub;
>> +
>> +  gas_assert (aarch64_num_of_operands (opcode) == 3);
>> +  dst = &base->operands[0];
>> +  src1 = &base->operands[1];
>> +  src2 = &base->operands[2];
>> +
>> +  dst_reg = ginsn_dw2_regnum (dst);
>> +  src1_reg = ginsn_dw2_regnum (src1);
>> +  src2_reg = ginsn_dw2_regnum (src2);
> 
> I think we should check ginsn_dw2_regnum_invalid_p on all three of these,
> since:
> 
> 	add	xzr, xzr, xzr
> 
> is a thing.
> 

I saw these appearing as opcode->iclass of addsub_shift.  So I did not 
add any check to the addsub_reg. But perhaps they could be modeled as 
addsub_reg later. I have added a

   if (ginsn_dw2_regnum_invalid_p (dst_reg)
       || ginsn_dw2_regnum_invalid_p (src1_reg) 

       || ginsn_dw2_regnum_invalid_p (src2_reg)) 

     return ginsn;

to aarch64_ginsn_addsub_reg.  Thanks.

>> [...]
>> +/* Generate ginsn for the load pair and store pair instructions.  */
>> +
>> +static ginsnS *
>> +aarch64_ginsn_ldstp (const symbolS *insn_end_sym)
>> +{
>> +  ginsnS *ginsn = NULL;
>> +  ginsnS *ginsn_ind = NULL;
>> +  ginsnS *ginsn_mem1 = NULL;
>> +  ginsnS *ginsn_mem2 = NULL;
>> +  unsigned int opnd_reg, addr_reg;
>> +  offsetT offset, mem_offset;
>> +  unsigned int width = 8;
>> +  bool load_p = false;
>> +  bool store_p = false;
>> +  bool other_p = false;
>> +
>> +  aarch64_opnd_info *opnd1, *opnd2, *addr;
>> +  aarch64_inst *base = &inst.base;
>> +  const aarch64_opcode *opcode = base->opcode;
>> +
>> +  /* This function is for handling ldp / stp ops only.  */
>> +  gas_assert (opcode->iclass == ldstpair_indexed
>> +	      || opcode->iclass == ldstnapair_offs
>> +	      || opcode->iclass == ldstpair_off);
>> +  gas_assert (aarch64_num_of_operands (opcode) == 3);
>> +
>> +  opnd1 = &base->operands[0];
>> +  opnd2 = &base->operands[1];
>> +  addr = &base->operands[2];
>> +
>> +  load_p = aarch64_opcode_subclass_p (opcode, F_LDST_LOAD);
>> +  store_p = aarch64_opcode_subclass_p (opcode, F_LDST_STORE);
>> +  other_p = aarch64_opcode_subclass_p (opcode, F_SUBCLASS_OTHER);
>> +  gas_assert (load_p || store_p || other_p);
>> +
>> +  addr_reg = ginsn_dw2_regnum (addr);
>> +  gas_assert (!addr->addr.offset.is_reg);
>> +  mem_offset = addr->addr.offset.imm;
>> +
>> +  offset = mem_offset;
>> +  /* Handle address calculation.  */
>> +  if ((addr->addr.preind || addr->addr.postind) && addr->addr.writeback)
>> +    {
>> +      /* Pre-indexed store, e.g., stp x29, x30, [sp, -128]!
>> +	 Pre-indexed addressing is like offset addressing, except that
>> +	 the base pointer is updated as a result of the instruction.
>> +
>> +	 Post-indexed store, e.g., stp     x29, x30, [sp],128
>> +	 Post-index addressing is useful for popping off the stack.  The
>> +	 instruction loads the value from the location pointed at by the stack
>> +	 pointer, and then moves the stack pointer on to the next full location
>> +	 in the stack.  */
>> +      ginsn_ind = ginsn_new_add (insn_end_sym, false,
>> +				 GINSN_SRC_REG, addr_reg, 0,
>> +				 GINSN_SRC_IMM, 0, mem_offset,
>> +				 GINSN_DST_REG, addr_reg, 0);
>> +      ginsn_set_where (ginsn_ind);
>> +
>> +      /* With post-index addressing, the value is loaded from the address in
>> +	 the base pointer, and then the pointer is updated.  With pre-index
>> +	 addressing, the addr computation has already been explicitly done.  */
>> +      offset = 0;
>> +    }
>> +
>> +  /* Insns like ldpsw (marked with subclass F_SUBCLASS_OTHER) do not need to
>> +     generate any load or store for SCFI purposes.  Next, enforce that for CFI
>> +     purposes, the width of save / restore operation has to be 8 bytes or more.
>> +     However, the address processing component may have updated the stack
>> +     pointer.  At least, emit that ginsn and return.  Also note,
>> +     TBD_GINSN_GEN_NOT_SCFI.  */
>> +  if (other_p || aarch64_get_qualifier_esize (opnd1->qualifier) < 8)
>> +    return ginsn_ind;
>> +
>> +  /* Save / restore of WZR is not of interest for SCFI.  */
>> +  opnd_reg = ginsn_dw2_regnum (opnd1);
>> +  if (ginsn_dw2_regnum_invalid_p (opnd_reg))
>> +    return ginsn_ind;
> 
> Sorry for not noticing earlier, but I think this should protect
> the individual ginsn_new_*s below.  E.g.:
> 
> 	stp	xzr, x19, [sp, #16]
> 	stp	x19, xzr, [sp, #16]
> 
> are at least vaguely plausible SCFI sequences.  E.g. the second one
> might combine a register save with a variable initialisation.
> 
> The combination is less plausible for loads, but still technically
> possible.
> 

Ah thanks for pointing these out. I didnt check to see that these were 
possible.

I will update aarch64_ginsn_ldstp () to handle these ops.

>> [...]
>> +/* Generate ginsn for mov instructions with reg opnd.  */
>> +
>> +static ginsnS *
>> +aarch64_ginsn_mov_reg (const symbolS *insn_end_sym)
>> +{
>> +  ginsnS *ginsn = NULL;
>> +  unsigned int src_reg = 0, dst_reg;
>> +  aarch64_opnd_info *src, *dst;
>> +  offsetT src_imm = 0;
>> +  enum ginsn_src_type src_type;
>> +
>> +  aarch64_inst *base = &inst.base;
>> +  const aarch64_opcode *opcode = base->opcode;
>> +
>> +  gas_assert (aarch64_num_of_operands (opcode) == 2);
>> +
>> +  dst = &base->operands[0];
>> +  src = &base->operands[1];
>> +
>> +  dst_reg = ginsn_dw2_regnum (dst);
>> +  src_reg = ginsn_dw2_regnum (src);
>> +  src_type = GINSN_SRC_REG;
>> +
>> +  /* FIXME Explicitly bar these GINSN_TYPE_MOV at this time.  This can be
>> +     removed later when SCFI machinery is more robust to deal with
>> +     GINSN_DW2_REGNUM_INVALID.  */
>> +  if (ginsn_dw2_regnum_invalid_p (dst_reg))
>> +    return ginsn;
> 
> We should probably check src_reg too, for:
> 
> 	mov	x1, xzr
> 

Right. Added the check for src_reg.

> (This could be modelled as a mov-immediate though, as a later follow-on.)
> 
> (I think it's ok to check ginsn_dw2_regnum_invalid_p after every call to
> ginsn_dw2_regnum if you prefer, even if the operand doesn't allow WZR/XZR.)
> 

Yes. I am finally seeing that this is better to do. I _think_ I have 
taken care of this in each function now..

>> +
>> +  ginsn = ginsn_new_mov (insn_end_sym, false,
>> +			 src_type, src_reg, src_imm,
>> +			 GINSN_DST_REG, dst_reg, 0);
>> +  ginsn_set_where (ginsn);
>> +
>> +  return ginsn;
>> +}
>> +
>> +/* Generate ginsn for mov instructions with imm opnd.  */
>> +
>> +static ginsnS *
>> +aarch64_ginsn_mov_imm (const symbolS *insn_end_sym)
>> +{
>> +  ginsnS *ginsn = NULL;
>> +  unsigned int src_reg = 0, dst_reg;
>> +  aarch64_opnd_info *src, *dst;
>> +  offsetT src_imm = 0;
>> +  enum ginsn_src_type src_type;
>> +
>> +  aarch64_inst *base = &inst.base;
>> +  const aarch64_opcode *opcode = base->opcode;
>> +
>> +  gas_assert (aarch64_num_of_operands (opcode) == 2);
>> +
>> +  dst = &base->operands[0];
>> +  src = &base->operands[1];
>> +
>> +  dst_reg = ginsn_dw2_regnum (dst);
>> +
>> +  /* For some mov ops, e.g., movn, movk, or movz, there may optionally be more
>> +     work than just a simple mov.  Skip handling these mov altogether and let
>> +     the aarch64_ginsn_unhandled () alert if these insns affect SCFI
>> +     correctness.  TBD_GINSN_GEN_NOT_SCFI.  */
>> +  if (src->type == AARCH64_OPND_HALF)
>> +    return ginsn;
>> +
>> +  /* FIXME Explicitly bar these GINSN_TYPE_MOV at this time.  This can be
>> +     removed later when SCFI machinery is more robust to deal with
>> +     GINSN_DW2_REGNUM_INVALID.  */
>> +  if (ginsn_dw2_regnum_invalid_p (dst_reg))
>> +    return ginsn;
> 
> Very minor, but IMO it'd be more easy to follow if this was partnered
> with the ginsn_dw2_regnum call.
> 

Makes sense. Moved ginsn_dw2_regnum and ginsn_dw2_regnum_invalid_p close 
to each other.

> LGTM otherwise.
> 
> Thanks,
> Richard


  reply	other threads:[~2024-07-18 20:01 UTC|newest]

Thread overview: 16+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-07-18  8:21 [PATCH,V6 0/9] Add experimental SCFI support for aarch64 Indu Bhagat
2024-07-18  8:21 ` [PATCH,V6 1/9] gas: scfi: make scfi_state_restore_reg function more precise Indu Bhagat
2024-07-18  8:21 ` [PATCH,V6 2/9] include: opcodes: aarch64: define new subclasses Indu Bhagat
2024-07-18  8:21 ` [PATCH,V6 3/9] opcodes: aarch64: add flags to denote subclasses of ldst insns Indu Bhagat
2024-07-18 10:20   ` Richard Sandiford
2024-07-18 16:26     ` Indu Bhagat
2024-07-18 17:56       ` Richard Sandiford
2024-07-18  8:21 ` [PATCH,V6 4/9] opcodes: aarch64: add flags to denote subclasses of arithmetic insns Indu Bhagat
2024-07-18  8:21 ` [PATCH,V6 5/9] opcodes: aarch64: add flags to denote subclasses of uncond branches Indu Bhagat
2024-07-18  8:21 ` [PATCH,V6 6/9] opcodes: aarch64: denote subclasses for insns of iclass dp_2src Indu Bhagat
2024-07-18  8:21 ` [PATCH,V6 7/9] opcodes: aarch64: enforce checks on subclass flags in aarch64-gen.c Indu Bhagat
2024-07-18  8:21 ` [PATCH,V6 8/9] gas: aarch64: add experimental support for SCFI Indu Bhagat
2024-07-18 10:42   ` Richard Sandiford
2024-07-18 20:01     ` Indu Bhagat [this message]
2024-07-18  8:21 ` [PATCH,V6 9/9] gas: aarch64: testsuite: add new tests " Indu Bhagat
2024-07-18 10:50 ` [PATCH,V6 0/9] Add experimental SCFI support for aarch64 Richard Sandiford

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=9beab368-2187-445e-abb8-6dfa7f504c48@oracle.com \
    --to=indu.bhagat@oracle.com \
    --cc=Richard.Earnshaw@arm.com \
    --cc=binutils@sourceware.org \
    --cc=richard.sandiford@arm.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).