From patchwork Fri Jul 13 16:10:59 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Christophe Lyon X-Patchwork-Id: 141919 Delivered-To: patch@linaro.org Received: by 2002:a2e:9754:0:0:0:0:0 with SMTP id f20-v6csp988514ljj; Fri, 13 Jul 2018 09:13:43 -0700 (PDT) X-Google-Smtp-Source: AAOMgpdIb5LIp29BhEjvP6XSuFs2ZwVIqOFRDRHLPStR0Ws65l6HOO3K2ZU58W4FntM68GDvyRgy X-Received: by 2002:a63:9856:: with SMTP id l22-v6mr6845832pgo.208.1531498423348; Fri, 13 Jul 2018 09:13:43 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1531498423; cv=none; d=google.com; s=arc-20160816; b=BZi/H6NQYyF8dio+xl42UcQ0BdWWYkKe48Oe6yQrXEEM0GD5Ft78PKRVApdnoa0lD7 vA8YzTVwFHEuhNe0gQ1verVq7GO21blYltcUbEFPWiY2VJUUqF5q+R0ho/8ymxMict79 AUv6s1DwUqt1AiXk7SWYrvbcWzG/QQNouAl0DMxmkI1PYkLID5SVOo32A10y+15vp/Fo D1mk11X17lWMu3O4l0TtJsyEP28bHyPiqTRkMWuCDXtNP7kgvRcWy6V+GEv50xGSvYYY FM0VsmHxlEhZ/75kyMYLBfef6CEsmbpmrc9F7TGuLmtTGkFna10G4W61IcJ769ymqx4Q +lUA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:delivered-to:sender:list-help :list-post:list-archive:list-unsubscribe:list-id:precedence :mailing-list:dkim-signature:domainkey-signature :arc-authentication-results; bh=SwYY9/uIXdwrmL5l4zJSlLTTSl3Ufspm1/FOZHYubTQ=; b=gTYVzLsheJZgH5eyUNopYOukQ53x0plHnr5blDhmarKMsXgw5p66911Tspg0vJzyAI 1ciOOWhRGvLH3V80tGdv9W5s1955fGHuDozZX3Ch+2Eodqtdj6+ThOtRlAS7/AyOGAyf mQ3Nx9AIY9zzQreqBuii2owlOg/2Gu5054mzRxbfp8dcXYdqPWjDdJrW97cvL7gLCXvR xti7zDdb2TMbk/FkBnkihV8Ou4L0owFIHyolMyZdkfUBGX8vf0QwIiKhSAmGNQqjTQv7 WWqx5GMqLB81KufhTNB8UxZ/hUtugm8OUusKp6sdtNLbAlA8ovDOTCwHDO9+TorSWDja uKTg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@gcc.gnu.org header.s=default header.b="lVLmU7/X"; spf=pass (google.com: domain of gcc-patches-return-481514-patch=linaro.org@gcc.gnu.org designates 209.132.180.131 as permitted sender) smtp.mailfrom="gcc-patches-return-481514-patch=linaro.org@gcc.gnu.org" Return-Path: Received: from sourceware.org (server1.sourceware.org. [209.132.180.131]) by mx.google.com with ESMTPS id 23-v6si24060356pge.589.2018.07.13.09.13.42 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 13 Jul 2018 09:13:43 -0700 (PDT) Received-SPF: pass (google.com: domain of gcc-patches-return-481514-patch=linaro.org@gcc.gnu.org designates 209.132.180.131 as permitted sender) client-ip=209.132.180.131; Authentication-Results: mx.google.com; dkim=pass header.i=@gcc.gnu.org header.s=default header.b="lVLmU7/X"; spf=pass (google.com: domain of gcc-patches-return-481514-patch=linaro.org@gcc.gnu.org designates 209.132.180.131 as permitted sender) smtp.mailfrom="gcc-patches-return-481514-patch=linaro.org@gcc.gnu.org" DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-type:content-transfer-encoding; q=dns; s= default; b=xZpIwsDeKW/QRDAJ2dG36YikjXb2ZaaaFpZxhseKN6tnsXSHQfQNW o+h/TBAqkPz0OPJJCWwop/pu9YGmW4y1V7bn2YAddVin7GGBTEMP7LFqEbuvI/nI KMpxESWNfBzGmaxrvBgdNZ2+Zi04jIfsxLEoDMIeeS8vCor4MMo0FY= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-type:content-transfer-encoding; s=default; bh=WEdRntnNEk7ChVsDs/7bzfeHED0=; b=lVLmU7/XMUVGilGlNdZs5lLIKGVh HB7hyjIQHAux/YlOdKtmlBiRWghdbWwJpy3X4pRYhFrKnTFCKoBfaijAWQiVw/oG xb+wmLQL0Nq2Pebmg/lkDkHINhq8kSxkfiku0Rx+ftYQZRY9dkvHu6jInSKg7G5X ZRpTe1H2Hs0hUds= Received: (qmail 19283 invoked by alias); 13 Jul 2018 16:13:29 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 19273 invoked by uid 89); 13 Jul 2018 16:13:28 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-26.1 required=5.0 tests=BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, KAM_STOCKGEN, RCVD_IN_DNSWL_LOW, SPF_PASS autolearn=ham version=3.3.2 spammy=rr, Thumb X-HELO: mx07-00178001.pphosted.com Received: from mx07-00178001.pphosted.com (HELO mx07-00178001.pphosted.com) (62.209.51.94) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Fri, 13 Jul 2018 16:13:23 +0000 Received: from pps.filterd (m0046037.ppops.net [127.0.0.1]) by mx07-.pphosted.com (8.16.0.21/8.16.0.21) with SMTP id w6DG991u005186; Fri, 13 Jul 2018 18:13:21 +0200 Received: from beta.dmz-eu.st.com (beta.dmz-eu.st.com [164.129.1.35]) by mx07-00178001.pphosted.com with ESMTP id 2k6y3vr2bj-1 (version=TLSv1 cipher=ECDHE-RSA-AES256-SHA bits=256 verify=NOT); Fri, 13 Jul 2018 18:13:21 +0200 Received: from zeta.dmz-eu.st.com (zeta.dmz-eu.st.com [164.129.230.9]) by beta.dmz-eu.st.com (STMicroelectronics) with ESMTP id 6BB1331; Fri, 13 Jul 2018 16:13:20 +0000 (GMT) Received: from Webmail-eu.st.com (sfhdag5node1.st.com [10.75.127.13]) by zeta.dmz-eu.st.com (STMicroelectronics) with ESMTP id 43739A6A5; Fri, 13 Jul 2018 16:13:20 +0000 (GMT) Received: from gnb.st.com (10.75.127.48) by SFHDAG5NODE1.st.com (10.75.127.13) with Microsoft SMTP Server (TLS) id 15.0.1347.2; Fri, 13 Jul 2018 18:13:19 +0200 From: To: CC: Subject: [ARM/FDPIC v2 04/21] [ARM] FDPIC: Add support for FDPIC for arm architecture Date: Fri, 13 Jul 2018 18:10:59 +0200 Message-ID: <20180713161136.29104-5-christophe.lyon@st.com> In-Reply-To: <20180713161136.29104-1-christophe.lyon@st.com> References: <20180713161136.29104-1-christophe.lyon@st.com> MIME-Version: 1.0 X-IsSubscribed: yes From: Christophe Lyon 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 Mickaël Guêné * 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. Change-Id: Icee8484772f97ac6f3a9574df4aa4f25a8196786 -- 2.6.3 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"); + } + 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. */ +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; + } + } + 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)); + } + } + 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")] + 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" [