[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