[ARM/FDPIC v2 04/21] [ARM] FDPIC: Add support for FDPIC for arm architecture

Richard Earnshaw (lists) Richard.Earnshaw@arm.com
Tue Sep 4 15:29:00 GMT 2018


On 29/08/18 11:46, Kyrill Tkachov wrote:
> Hi Christophe,
> 
> On 13/07/18 17:10, christophe.lyon@st.com wrote:
>> From: Christophe Lyon <christophe.lyon@linaro.org>
>>
>> The FDPIC register is hard-coded to r9, as defined in the ABI.
>>
>> We have to disable tailcall optimizations if we don't know if the
>> target function is in the same module. If not, we have to set r9 to
>> the value associated with the target module.
>>
>> When generating a symbol address, we have to take into account whether
>> it is a pointer to data or to a function, because different
>> relocations are needed.
>>
>> 2018-XX-XX  Christophe Lyon  <christophe.lyon@st.com>
>>         Mickaël Guêné <mickael.guene@st.com>
>>
>>         * config/arm/arm-c.c (__FDPIC__): Define new pre-processor macro
>>         in FDPIC mode.
>>         * config/arm/arm-protos.h (arm_load_function_descriptor): Declare
>>         new function.
>>         * config/arm/arm.c (arm_option_override): Define pic register to
>>         FDPIC_REGNUM.
>>         (arm_function_ok_for_sibcall) Disable sibcall optimization if we
>>         have no decl or go through PLT.
>>         (arm_load_pic_register): Handle TARGET_FDPIC.
>>         (arm_is_segment_info_known): New function.
>>         (arm_pic_static_addr): Add support for FDPIC.
>>         (arm_load_function_descriptor): New function.
>>         (arm_assemble_integer): Add support for FDPIC.
>>         * config/arm/arm.h (PIC_OFFSET_TABLE_REG_CALL_CLOBBERED):
>>         Define. (FDPIC_REGNUM): New define.
>>         * config/arm/arm.md (call): Add support for FDPIC.
>>         (call_value): Likewise.
>>         (*restore_pic_register_after_call): New pattern.
>>         (untyped_call): Disable if FDPIC.
>>         (untyped_return): Likewise.
>>         * config/arm/unspecs.md (UNSPEC_PIC_RESTORE): New.
>>
> 
> In general, you can use SYMBOL_REF_P to check RTXes for SYMBOL_REF code.
> 
>> Change-Id: Icee8484772f97ac6f3a9574df4aa4f25a8196786
>>
>> diff --git a/gcc/config/arm/arm-c.c b/gcc/config/arm/arm-c.c
>> index 4471f79..90733cc 100644
>> --- a/gcc/config/arm/arm-c.c
>> +++ b/gcc/config/arm/arm-c.c
>> @@ -202,6 +202,8 @@ arm_cpu_builtins (struct cpp_reader* pfile)
>>        builtin_define ("__ARM_EABI__");
>>      }
>>
>> +  def_or_undef_macro (pfile, "__FDPIC__", TARGET_FDPIC);
>> +
>>    def_or_undef_macro (pfile, "__ARM_ARCH_EXT_IDIV__", TARGET_IDIV);
>>    def_or_undef_macro (pfile, "__ARM_FEATURE_IDIV", TARGET_IDIV);
>>
>> diff --git a/gcc/config/arm/arm-protos.h b/gcc/config/arm/arm-protos.h
>> index 8537262..edebeb7 100644
>> --- a/gcc/config/arm/arm-protos.h
>> +++ b/gcc/config/arm/arm-protos.h
>> @@ -134,6 +134,7 @@ extern int arm_max_const_double_inline_cost (void);
>>  extern int arm_const_double_inline_cost (rtx);
>>  extern bool arm_const_double_by_parts (rtx);
>>  extern bool arm_const_double_by_immediates (rtx);
>> +extern rtx arm_load_function_descriptor (rtx funcdesc);
>>  extern void arm_emit_call_insn (rtx, rtx, bool);
>>  bool detect_cmse_nonsecure_call (tree);
>>  extern const char *output_call (rtx *);
>> diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
>> index c70be36..44c3b08 100644
>> --- a/gcc/config/arm/arm.c
>> +++ b/gcc/config/arm/arm.c
>> @@ -3466,6 +3466,14 @@ arm_option_override (void)
>>    if (flag_pic && TARGET_VXWORKS_RTP)
>>      arm_pic_register = 9;
>>
>> +  /* If in FDPIC mode then force arm_pic_register to be r9.  */
>> +  if (TARGET_FDPIC)
>> +    {
>> +      arm_pic_register = FDPIC_REGNUM;
>> +      if (TARGET_ARM_ARCH < 7)
>> +       error ("FDPIC mode is not supported on architectures older
>> than 7");
> 
> Armv7 rather than 7 please.
> 

What about R and M profiles, especially armv8-m.base?

R.

>> +    }
>> +
>>    if (arm_pic_register_string != NULL)
>>      {
>>        int pic_register = decode_reg_name (arm_pic_register_string);
>> @@ -7247,6 +7255,21 @@ arm_function_ok_for_sibcall (tree decl, tree exp)
>>    if (cfun->machine->sibcall_blocked)
>>      return false;
>>
>> +  if (TARGET_FDPIC)
>> +    {
>> +      /* In FDPIC, never tailcall something for which we have no decl:
>> +        the target function could be in a different module, requiring
>> +        a different FDPIC register value.  */
>> +      if (decl == NULL)
>> +       return false;
>> +
>> +      /* Don't tailcall if we go through the PLT since the FDPIC
>> +        register is then corrupted and we don't restore it after
>> +        static function calls.  */
>> +      if (!targetm.binds_local_p (decl))
>> +       return false;
>> +    }
>> +
>>    /* Never tailcall something if we are generating code for Thumb-1.  */
>>    if (TARGET_THUMB1)
>>      return false;
>> @@ -7625,7 +7648,9 @@ arm_load_pic_register (unsigned long saved_regs
>> ATTRIBUTE_UNUSED)
>>  {
>>    rtx l1, labelno, pic_tmp, pic_rtx, pic_reg;
>>
>> -  if (crtl->uses_pic_offset_table == 0 || TARGET_SINGLE_PIC_BASE)
>> +  if (crtl->uses_pic_offset_table == 0
>> +      || TARGET_SINGLE_PIC_BASE
>> +      || TARGET_FDPIC)
>>      return;
>>
>>    gcc_assert (flag_pic);
>> @@ -7693,28 +7718,170 @@ arm_load_pic_register (unsigned long
>> saved_regs ATTRIBUTE_UNUSED)
>>    emit_use (pic_reg);
>>  }
>>
>> +/* Try to know if the object will go in text or data segment. This is
>> +   used in FDPIC mode, to decide which relocations to use when
>> +   accessing ORIG. */
> 
> Please also document IS_READONLY. I'm guessing it's set to whether
> ORIG is a read-only location?
> 
>> +static bool
>> +arm_is_segment_info_known (rtx orig, bool *is_readonly)
>> +{
>> +  bool res = false;
>> +
>> +  *is_readonly = false;
>> +
>> +  if (GET_CODE (orig) == LABEL_REF)
>> +    {
>> +      res = true;
>> +      *is_readonly = true;
>> +    }
>> +  else if (GET_CODE (orig) == SYMBOL_REF)
>> +    {
>> +      if (CONSTANT_POOL_ADDRESS_P (orig))
>> +       {
>> +         res = true;
>> +         *is_readonly = true;
>> +       }
>> +      else if (SYMBOL_REF_LOCAL_P (orig)
>> +              && !SYMBOL_REF_EXTERNAL_P (orig)
>> +              && SYMBOL_REF_DECL (orig)
>> +              && (!DECL_P (SYMBOL_REF_DECL (orig))
>> +                  || !DECL_COMMON (SYMBOL_REF_DECL (orig))))
>> +       {
>> +         tree decl = SYMBOL_REF_DECL (orig);
>> +         tree init = (TREE_CODE (decl) == VAR_DECL)
>> +           ? DECL_INITIAL (decl) : (TREE_CODE (decl) == CONSTRUCTOR)
>> +           ? decl : 0;
>> +         int reloc = 0;
>> +         bool named_section, readonly;
>> +
>> +         if (init && init != error_mark_node)
>> +           reloc = compute_reloc_for_constant (init);
>> +
>> +         named_section = TREE_CODE (decl) == VAR_DECL
>> +           && lookup_attribute ("section", DECL_ATTRIBUTES (decl));
>> +         readonly = decl_readonly_section (decl, reloc);
>> +
>> +         if (named_section)
>> +           {
>> +             /* We don't know where the link script will put this
>> section.  */
>> +             res = false;
>> +           }
>> +         else if (!readonly)
>> +           {
>> +             res = true;
>> +             *is_readonly = false;
>> +           }
>> +         else
>> +           {
>> +             res = true;
>> +             *is_readonly = true;
>> +           }
> 
> This is a bit too verbose.
> Can we have:
> 
> res = !named_section;
> if (!named_section)
>   *is_readonly = readonly;
> 
> instead.
> 
>> +       }
>> +      else
>> +       {
>> +         /* We don't know.  */
>> +         res = false;
>> +       }
>> +    }
>> +  else
>> +    gcc_unreachable ();
>> +
>> +  return res;
>> +}
>> +
>>  /* Generate code to load the address of a static var when flag_pic is
>> set.  */
> 
>>  static rtx_insn *
>>  arm_pic_static_addr (rtx orig, rtx reg)
>>  {
>>    rtx l1, labelno, offset_rtx;
>> +  rtx_insn *insn;
>>
>>    gcc_assert (flag_pic);
>>
>> -  /* We use an UNSPEC rather than a LABEL_REF because this label
>> -     never appears in the code stream.  */
>> -  labelno = GEN_INT (pic_labelno++);
>> -  l1 = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, labelno), UNSPEC_PIC_LABEL);
>> -  l1 = gen_rtx_CONST (VOIDmode, l1);
>> +  if (TARGET_FDPIC
>> +      && GET_CODE (orig) == SYMBOL_REF
>> +      && !SYMBOL_REF_FUNCTION_P (orig))
>> +    {
>> +      bool is_readonly;
>> +
>> +      if (!arm_is_segment_info_known (orig, &is_readonly))
>> +       {
>> +         /* We don't know where orig is stored, so we have be
>> +            pessimistic and use GOT relocation.  */
>> +         rtx pat;
>> +         rtx mem;
>> +         rtx pic_reg = gen_rtx_REG (Pmode, FDPIC_REGNUM);
>>
>> -  /* On the ARM the PC register contains 'dot + 8' at the time of the
>> -     addition, on the Thumb it is 'dot + 4'.  */
>> -  offset_rtx = plus_constant (Pmode, l1, TARGET_ARM ? 8 : 4);
>> -  offset_rtx = gen_rtx_UNSPEC (Pmode, gen_rtvec (2, orig, offset_rtx),
>> -                               UNSPEC_SYMBOL_OFFSET);
>> -  offset_rtx = gen_rtx_CONST (Pmode, offset_rtx);
>> +         pat = gen_calculate_pic_address (reg, pic_reg, orig);
>>
>> -  return emit_insn (gen_pic_load_addr_unified (reg, offset_rtx,
>> labelno));
>> +         /* Make the MEM as close to a constant as possible.  */
>> +         mem = SET_SRC (pat);
>> +         gcc_assert (MEM_P (mem) && !MEM_VOLATILE_P (mem));
>> +         MEM_READONLY_P (mem) = 1;
>> +         MEM_NOTRAP_P (mem) = 1;
>> +
>> +         insn = emit_insn (pat);
>> +       }
>> +      else if (is_readonly)
>> +       {
>> +         /* We can use PC-relative access.  */
>> +         /* We use an UNSPEC rather than a LABEL_REF because this label
>> +            never appears in the code stream.  */
>> +         labelno = GEN_INT (pic_labelno++);
>> +         l1 = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, labelno),
>> UNSPEC_PIC_LABEL);
>> +         l1 = gen_rtx_CONST (VOIDmode, l1);
>> +
>> +         /* On the ARM the PC register contains 'dot + 8' at the time
>> of the
>> +            addition, on the Thumb it is 'dot + 4'.  */
>> +         offset_rtx = plus_constant (Pmode, l1, TARGET_ARM ? 8 : 4);
>> +         offset_rtx = gen_rtx_UNSPEC (Pmode, gen_rtvec (2, orig,
>> offset_rtx),
>> + UNSPEC_SYMBOL_OFFSET);
>> +         offset_rtx = gen_rtx_CONST (Pmode, offset_rtx);
>> +
>> +         insn = emit_insn (gen_pic_load_addr_unified (reg, offset_rtx,
>> + labelno));
>> +       }
>> +      else
>> +       {
>> +         /* We use the GOTOFF relocation.  */
>> +         rtx pic_reg = gen_rtx_REG (Pmode, FDPIC_REGNUM);
>> +
>> +         rtx l1 = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, orig),
>> UNSPEC_PIC_SYM);
>> +         emit_insn (gen_movsi (reg, l1));
>> +         insn = emit_insn (gen_addsi3 (reg, reg, pic_reg));
>> +       }
>> +    }
>> +  else
>> +    {
>> +      if (TARGET_FDPIC
>> +         && GET_CODE (orig) == SYMBOL_REF
>> +         && SYMBOL_REF_FUNCTION_P (orig))
>> +       {
>> +         rtx pic_reg = gen_rtx_REG (Pmode, FDPIC_REGNUM);
>> +
>> +         rtx l1 = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, orig),
>> UNSPEC_PIC_SYM);
>> +         emit_insn (gen_movsi (reg, l1));
>> +         insn = emit_insn (gen_addsi3 (reg, reg, pic_reg));
>> +       }
>> +      else
>> +       {
>> +         /* We use an UNSPEC rather than a LABEL_REF because this label
>> +            never appears in the code stream.  */
>> +         labelno = GEN_INT (pic_labelno++);
>> +         l1 = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, labelno),
>> UNSPEC_PIC_LABEL);
>> +         l1 = gen_rtx_CONST (VOIDmode, l1);
>> +
>> +         /* On the ARM the PC register contains 'dot + 8' at the time
>> of the
>> +            addition, on the Thumb it is 'dot + 4'.  */
>> +         offset_rtx = plus_constant (Pmode, l1, TARGET_ARM ? 8 : 4);
>> +         offset_rtx = gen_rtx_UNSPEC (Pmode, gen_rtvec (2, orig,
>> offset_rtx),
>> + UNSPEC_SYMBOL_OFFSET);
>> +         offset_rtx = gen_rtx_CONST (Pmode, offset_rtx);
>> +
>> +         insn = emit_insn (gen_pic_load_addr_unified (reg, offset_rtx,
>> + labelno));
>> +       }
> 
> This code is duplicated. Please refactor it.
> 
>> +    }
>> +  return insn;
>>  }
>>
>>  /* Return nonzero if X is valid as an ARM state addressing register.  */
>> @@ -15929,9 +16096,36 @@ get_jump_table_size (rtx_jump_table_data *insn)
>>    return 0;
>>  }
>>
>> +/* Emit insns to load the function address from FUNCDESC (an FDPIC
>> +   function descriptor) into a register and the GOT address into the
>> +   FDPIC register, returning an rtx for the register holding the
>> +   function address.  */
>> +
>> +rtx
>> +arm_load_function_descriptor (rtx funcdesc)
>> +{
>> +  rtx fnaddr_reg = gen_reg_rtx (Pmode);
>> +  rtx pic_reg = gen_rtx_REG (Pmode, FDPIC_REGNUM);
>> +  rtx fnaddr = gen_rtx_MEM (Pmode, funcdesc);
>> +  rtx gotaddr = gen_rtx_MEM (Pmode, plus_constant (Pmode, funcdesc, 4));
>> +  rtx par = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (3));
>> +
>> +  emit_move_insn (fnaddr_reg, fnaddr);
>> +  /* The ABI requires the entry point address to be loaded first, so
>> +     prevent the load from being moved after that of the GOT
>> +     address.  */
>> +  XVECEXP (par, 0, 0) = gen_rtx_UNSPEC (VOIDmode,
>> +                                       gen_rtvec (2, pic_reg, gotaddr),
>> +                                       UNSPEC_PIC_RESTORE);
>> +  XVECEXP (par, 0, 1) = gen_rtx_USE (VOIDmode, gen_rtx_REG (Pmode,
>> FDPIC_REGNUM));
>> +  XVECEXP (par, 0, 2) = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG
>> (Pmode, FDPIC_REGNUM));
>> +  emit_insn (par);
>> +
>> +  return fnaddr_reg;
>> +}
>> +
>>  /* Return the maximum amount of padding that will be inserted before
>>     label LABEL.  */
>> -
>>  static HOST_WIDE_INT
>>  get_label_padding (rtx label)
>>  {
>> @@ -22876,9 +23070,37 @@ arm_assemble_integer (rtx x, unsigned int
>> size, int aligned_p)
>>                    && (!SYMBOL_REF_LOCAL_P (x)
>>                        || (SYMBOL_REF_DECL (x)
>>                            ? DECL_WEAK (SYMBOL_REF_DECL (x)) : 0))))
>> -           fputs ("(GOT)", asm_out_file);
>> +           {
>> +             if (TARGET_FDPIC && SYMBOL_REF_FUNCTION_P (x))
>> +               fputs ("(GOTFUNCDESC)", asm_out_file);
>> +             else
>> +               fputs ("(GOT)", asm_out_file);
>> +           }
>>            else
>> -           fputs ("(GOTOFF)", asm_out_file);
>> +           {
>> +             if (TARGET_FDPIC && SYMBOL_REF_FUNCTION_P (x))
>> +               fputs ("(GOTOFFFUNCDESC)", asm_out_file);
>> +             else
>> +               {
>> +                 bool is_readonly;
>> +
>> +                 if (arm_is_segment_info_known (x, &is_readonly))
>> +                   fputs ("(GOTOFF)", asm_out_file);
>> +                 else
>> +                   fputs ("(GOT)", asm_out_file);
>> +               }
>> +           }
>> +       }
>> +
>> +      /* For FDPIC we also have to mark symbol for .data section.  */
>> +      if (TARGET_FDPIC
>> +         && NEED_GOT_RELOC
>> +         && flag_pic
>> +         && !making_const_table
>> +         && GET_CODE (x) == SYMBOL_REF)
>> +       {
>> +         if (SYMBOL_REF_FUNCTION_P (x))
>> +           fputs ("(FUNCDESC)", asm_out_file);
>>          }
>>        fputc ('\n', asm_out_file);
>>        return true;
>> diff --git a/gcc/config/arm/arm.h b/gcc/config/arm/arm.h
>> index 34894c0..4671d64 100644
>> --- a/gcc/config/arm/arm.h
>> +++ b/gcc/config/arm/arm.h
>> @@ -871,6 +871,9 @@ extern int arm_arch_cmse;
>>     Pascal), so the following is not true.  */
>>  #define STATIC_CHAIN_REGNUM     12
>>
>> +/* r9 is the FDPIC register (base register for GOT and FUNCDESC
>> accesses).  */
>> +#define FDPIC_REGNUM           9
>> +
>>  /* Define this to be where the real frame pointer is if it is not
>> possible to
>>     work out the offset between the frame pointer and the automatic
>> variables
>>     until after register allocation has taken place. FRAME_POINTER_REGNUM
>> @@ -1927,6 +1930,10 @@ extern unsigned arm_pic_register;
>>     data addresses in memory.  */
>>  #define PIC_OFFSET_TABLE_REGNUM arm_pic_register
>>
>> +/* For FDPIC, the FDPIC register is call-clobbered (otherwise PLT
>> +   entries would need to handle saving and restoring it). */
>> +#define PIC_OFFSET_TABLE_REG_CALL_CLOBBERED TARGET_FDPIC
>> +
>>  /* We can't directly access anything that contains a symbol,
>>     nor can we indirect via the constant pool.  One exception is
>>     UNSPEC_TLS, which is always PIC.  */
>> diff --git a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md
>> index 361a026..a699a60 100644
>> --- a/gcc/config/arm/arm.md
>> +++ b/gcc/config/arm/arm.md
>> @@ -8031,6 +8031,23 @@
>>      rtx callee, pat;
>>      tree addr = MEM_EXPR (operands[0]);
>>
>> +    /* Force FDPIC register (r9) before call.  */
>> +    if (TARGET_FDPIC)
>> +      {
>> +       /* No need to update r9 if calling a static function.
>> +          In other words: set r9 for indirect or non-local calls.  */
>> +       callee = XEXP (operands[0], 0);
>> +       if (GET_CODE (callee) != SYMBOL_REF
>> +           || !SYMBOL_REF_LOCAL_P (callee)
>> +           || arm_is_long_call_p (SYMBOL_REF_DECL (callee)))
>> +         {
>> +           emit_insn (gen_blockage ());
>> +           rtx pic_reg = gen_rtx_REG (Pmode, FDPIC_REGNUM);
>> +           emit_move_insn (pic_reg, get_hard_reg_initial_val (Pmode,
>> FDPIC_REGNUM));
>> +           emit_insn (gen_rtx_USE (VOIDmode, pic_reg));
>> +        }
>> +      }
>> +
>>      /* In an untyped call, we can get NULL for operand 2. */
>>      if (operands[2] == NULL_RTX)
>>        operands[2] = const0_rtx;
>> @@ -8044,6 +8061,13 @@
>>          : !REG_P (callee))
>>        XEXP (operands[0], 0) = force_reg (Pmode, callee);
>>
>> +    if (TARGET_FDPIC && GET_CODE (XEXP (operands[0], 0)) != SYMBOL_REF)
>> +      {
>> +       /* Indirect call: set r9 with FDPIC value of callee.  */
>> +       XEXP (operands[0], 0)
>> +         = arm_load_function_descriptor (XEXP (operands[0], 0));
>> +      }
>> +
>>      if (detect_cmse_nonsecure_call (addr))
>>        {
>>          pat = gen_nonsecure_call_internal (operands[0], operands[1],
>> @@ -8055,10 +8079,38 @@
>>          pat = gen_call_internal (operands[0], operands[1], operands[2]);
>>          arm_emit_call_insn (pat, XEXP (operands[0], 0), false);
>>        }
>> +
>> +    /* Restore FDPIC register (r9) after call.  */
>> +    if (TARGET_FDPIC)
>> +      {
>> +       /* No need to update r9 if calling a static function.  */
>> +       if (GET_CODE (callee) != SYMBOL_REF
>> +           || !SYMBOL_REF_LOCAL_P (callee)
>> +           || arm_is_long_call_p (SYMBOL_REF_DECL (callee)))
>> +         {
>> +           rtx pic_reg = gen_rtx_REG (Pmode, FDPIC_REGNUM);
>> +           emit_move_insn (pic_reg, get_hard_reg_initial_val (Pmode,
>> FDPIC_REGNUM));
>> +           emit_insn (gen_rtx_USE (VOIDmode, pic_reg));
>> +           emit_insn (gen_blockage ());
>> +         }
>> +      }
>>      DONE;
>>    }"
>>  )
>>
>> +(define_insn "*restore_pic_register_after_call"
>> +  [(parallel [(unspec [(match_operand:SI 0 "s_register_operand" "=r,r")
>> +                      (match_operand:SI 1 "general_operand" "r,m")]
> 
> I know this is created explicitly and RTL passes are unlikely to mess
> with the operands but still
> please use nonimmediate_operand here to disallow any operands that are
> not accepted by the constraints.
> 
>> +              UNSPEC_PIC_RESTORE)
>> +             (use (match_dup 0))
>> +             (clobber (match_dup 0))])
>> +  ]
>> +  ""
>> +  "@
>> +  mov\t%0, %1
>> +  ldr\t%0, %1"
>> +)
>> +
>>  (define_expand "call_internal"
>>    [(parallel [(call (match_operand 0 "memory_operand" "")
>>                      (match_operand 1 "general_operand" ""))
>> @@ -8119,6 +8171,30 @@
>>      rtx pat, callee;
>>      tree addr = MEM_EXPR (operands[1]);
>>
>> +    /* Force FDPIC register (r9) before call.  */
>> +    if (TARGET_FDPIC)
>> +      {
>> +       /* No need to update the FDPIC register (r9) if calling a
>> static function.
>> +          In other words: set r9 for indirect or non-local calls.  */
>> +       callee = XEXP (operands[1], 0);
>> +       if (GET_CODE (callee) != SYMBOL_REF
>> +           || !SYMBOL_REF_LOCAL_P (callee)
>> +           || arm_is_long_call_p (SYMBOL_REF_DECL (callee)))
>> +         {
>> +           rtx par = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (3));
>> +
>> +           XVECEXP (par, 0, 0) = gen_rtx_UNSPEC (VOIDmode,
>> +               gen_rtvec (2, gen_rtx_REG (Pmode, FDPIC_REGNUM),
>> +                          get_hard_reg_initial_val (Pmode,
>> FDPIC_REGNUM)),
>> +               UNSPEC_PIC_RESTORE);
>> +           XVECEXP (par, 0, 1)
>> +             = gen_rtx_USE (VOIDmode, gen_rtx_REG (Pmode,
>> FDPIC_REGNUM));
>> +           XVECEXP (par, 0, 2)
>> +             = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (Pmode,
>> FDPIC_REGNUM));
>> +           emit_insn (par);
>> +         }
>> +      }
>> +
>>      /* In an untyped call, we can get NULL for operand 2. */
>>      if (operands[3] == 0)
>>        operands[3] = const0_rtx;
>> @@ -8132,6 +8208,14 @@
>>          : !REG_P (callee))
>>        XEXP (operands[1], 0) = force_reg (Pmode, callee);
>>
>> +    if (TARGET_FDPIC
>> +       && GET_CODE (XEXP (operands[1], 0)) != SYMBOL_REF)
>> +      {
>> +       /* Indirect call: set r9 with FDPIC value of callee.  */
>> +       XEXP (operands[1], 0)
>> +         = arm_load_function_descriptor (XEXP (operands[1], 0));
>> +      }
>> +
>>      if (detect_cmse_nonsecure_call (addr))
>>        {
>>          pat = gen_nonsecure_call_value_internal (operands[0],
>> operands[1],
>> @@ -8144,6 +8228,28 @@
>>                                         operands[2], operands[3]);
>>          arm_emit_call_insn (pat, XEXP (operands[1], 0), false);
>>        }
>> +    /* Restore FDPIC register (r9) after call.  */
>> +    if (TARGET_FDPIC)
>> +      {
>> +       /* No need to update r9 if calling a static function.  */
>> +       if (GET_CODE (callee) != SYMBOL_REF
>> +           || !SYMBOL_REF_LOCAL_P (callee)
>> +           || arm_is_long_call_p (SYMBOL_REF_DECL (callee)))
>> +         {
>> +           rtx par = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (3));
>> +
>> +           XVECEXP (par, 0, 0) = gen_rtx_UNSPEC (VOIDmode,
>> +               gen_rtvec (2, gen_rtx_REG (Pmode, FDPIC_REGNUM),
>> +                          get_hard_reg_initial_val (Pmode,
>> FDPIC_REGNUM)),
>> +               UNSPEC_PIC_RESTORE);
>> +           XVECEXP (par, 0, 1)
>> +             = gen_rtx_USE (VOIDmode, gen_rtx_REG (Pmode,
>> FDPIC_REGNUM));
>> +           XVECEXP (par, 0, 2)
>> +             = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (Pmode,
>> FDPIC_REGNUM));
>> +           emit_insn (par);
>> +         }
>> +      }
>> +
>>      DONE;
>>    }"
>>  )
>> @@ -8486,7 +8592,7 @@
>>                      (const_int 0))
>>                (match_operand 1 "" "")
>>                (match_operand 2 "" "")])]
>> -  "TARGET_EITHER"
>> +  "TARGET_EITHER && !TARGET_FDPIC"
>>    "
>>    {
>>      int i;
>> @@ -8553,7 +8659,7 @@
>>  (define_expand "untyped_return"
>>    [(match_operand:BLK 0 "memory_operand" "")
>>     (match_operand 1 "" "")]
>> -  "TARGET_EITHER"
>> +  "TARGET_EITHER && !TARGET_FDPIC"
>>    "
>>    {
>>      int i;
>> diff --git a/gcc/config/arm/unspecs.md b/gcc/config/arm/unspecs.md
>> index b05f85e..5506e2d 100644
>> --- a/gcc/config/arm/unspecs.md
>> +++ b/gcc/config/arm/unspecs.md
>> @@ -86,6 +86,7 @@
>>    UNSPEC_PROBE_STACK    ; Probe stack memory reference
>>    UNSPEC_NONSECURE_MEM ; Represent non-secure memory in ARMv8-M with
>>                          ; security extension
>> +  UNSPEC_PIC_RESTORE   ; Use to restore fdpic register
>>  ])
>>
>>  (define_c_enum "unspec" [
>> -- 
>> 2.6.3
>>
> 



More information about the Gcc-patches mailing list