From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail.loongson.cn (mail.loongson.cn [114.242.206.163]) by sourceware.org (Postfix) with ESMTP id 9EB323858404 for ; Fri, 22 Dec 2023 11:43:04 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 9EB323858404 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=loongson.cn Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=loongson.cn ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 9EB323858404 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=114.242.206.163 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1703245387; cv=none; b=BNpTywakoahZ887D6fcQK18XCJhChnGEb9Cc/aWPdrI9/RAJl1NhCoUlQYJ1A2fflxzifl0M7Hq9iWSfFGEmmZy4jiHh9rq9Q7bKYWXBKnCkCkQAC8xxdAhuNIM1PlniO3zMZiM8pQmgMgEJf0Ancj8+f6cKLFy/3IXg0qkeWWo= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1703245387; c=relaxed/simple; bh=3qBcPyafAFKEEx005qi1VRK0uL+6o7Wix6obbiafguc=; h=From:To:Subject:Date:Message-Id:MIME-Version; b=DCIgKVfFXEmc++E9vPJfZhl3YlB49amCic1Y8pl+/nJ/uAeOQ531Xdbe0CsIzSmfFhckSERfcSwHqXKaiRGeoysaqo/F3z8dsY6uXZXy5BwKEh4X9hqmh2n6NBF4e6SsTZPhi59hZEG4RQ0wcPN6LOeaHIGjEu/cpLZFLBaGzjc= ARC-Authentication-Results: i=1; server2.sourceware.org Received: from loongson.cn (unknown [10.2.6.5]) by gateway (Coremail) with SMTP id _____8Bx6uhFdoVlGtUDAA--.19149S3; Fri, 22 Dec 2023 19:43:01 +0800 (CST) Received: from 5.5.5 (unknown [10.2.6.5]) by localhost.localdomain (Coremail) with SMTP id AQAAf8Cxvr40doVl7YkFAA--.20311S7; Fri, 22 Dec 2023 19:43:01 +0800 (CST) From: Lulu Cai To: binutils@sourceware.org Cc: xuchenghua@loongson.cn, chenglulu@loongson.cn, liuzhensong@loongson.cn, mengqinggang@loongson.cn, xry111@xry111.site, i.swmail@xen0n.name, maskray@google.com, luweining@loongson.cn, wanglei@loongson.cn, hejinyang@loongson.cn, Lulu Cai Subject: [PATCH v5 3/5] LoongArch: Add tls transition support. Date: Fri, 22 Dec 2023 19:42:41 +0800 Message-Id: <20231222114243.1836112-4-cailulu@loongson.cn> X-Mailer: git-send-email 2.39.3 In-Reply-To: <20231222114243.1836112-1-cailulu@loongson.cn> References: <20231222114243.1836112-1-cailulu@loongson.cn> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-CM-TRANSID:AQAAf8Cxvr40doVl7YkFAA--.20311S7 X-CM-SenderInfo: xfdlz3tox6z05rqj20fqof0/1tbiAQANB2WE8i4JjQAAsy X-Coremail-Antispam: 1Uk129KBj93XoWxKrWUXFW3XFyxCFy3Xr1kJFc_yoWfKr47pr WYv3yDKF4UuF47Wry8Xa45Z3WYq3yxurWxtasxtrZ0krs7Xry8Xrsxtr12va1rCw1vqryS vayru3W7Wa18A3XCm3ZEXasCq-sJn29KB7ZKAUJUUUU8529EdanIXcx71UUUUU7KY7ZEXa sCq-sGcSsGvfJ3Ic02F40EFcxC0VAKzVAqx4xG6I80ebIjqfuFe4nvWSU5nxnvy29KBjDU 0xBIdaVrnRJUUUk2b4IE77IF4wAFF20E14v26r1j6r4UM7CY07I20VC2zVCF04k26cxKx2 IYs7xG6rWj6s0DM7CIcVAFz4kK6r1Y6r17M28lY4IEw2IIxxk0rwA2F7IY1VAKz4vEj48v e4kI8wA2z4x0Y4vE2Ix0cI8IcVAFwI0_Xr0_Ar1l84ACjcxK6xIIjxv20xvEc7CjxVAFwI 0_Gr0_Cr1l84ACjcxK6I8E87Iv67AKxVW8Jr0_Cr1UM28EF7xvwVC2z280aVCY1x0267AK xVW8Jr0_Cr1UM2AIxVAIcxkEcVAq07x20xvEncxIr21l57IF6xkI12xvs2x26I8E6xACxx 1l5I8CrVACY4xI64kE6c02F40Ex7xfMcIj6xIIjxv20xvE14v26r1q6rW5McIj6I8E87Iv 67AKxVW8JVWxJwAm72CE4IkC6x0Yz7v_Jr0_Gr1lF7xvr2IYc2Ij64vIr41l42xK82IYc2 Ij64vIr41l4I8I3I0E4IkC6x0Yz7v_Jr0_Gr1lx2IqxVAqx4xG67AKxVWUJVWUGwC20s02 6x8GjcxK67AKxVWUGVWUWwC2zVAF1VAY17CE14v26r1q6r43MIIYrxkI7VAKI48JMIIF0x vE2Ix0cI8IcVAFwI0_Gr0_Xr1lIxAIcVC0I7IYx2IY6xkF7I0E14v26r4j6F4UMIIF0xvE 42xK8VAvwI8IcIk0rVWUJVWUCwCI42IY6I8E87Iv67AKxVW8JVWxJwCI42IY6I8E87Iv6x kF7I0E14v26r4j6r4UJbIYCTnIWIevJa73UjIFyTuYvjxUcCD7UUUUU X-Spam-Status: No, score=-12.4 required=5.0 tests=BAYES_00,GIT_PATCH_0,KAM_DMARC_STATUS,KAM_STOCKGEN,SPF_HELO_NONE,SPF_PASS,TXREP,T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org List-Id: Transitions between DESC->IE/LE and IE->LE are supported now. 1. For DESC -> LE: pcalau12i $a0,%desc_pc_hi20(var) => lu12i.w $a0,%le_hi20(var) addi.d $a0,$a0,%desc_pc_lo12(var) => ori $a0,$a0,%le_lo12(var) ld.d $a1,$a0,%desc_ld(var) => NOP jirl $ra,$a1,%desc_call(var) => NOP add.d $a0,$a0,$tp 2. For DESC -> IE: pcalau12i $a0,%desc_pc_hi20(var) => pcalau12i $a0,%ie_pc_hi20(var) addi.d $a0,$a0,%desc_pc_lo12(var) => ld.d $a0,$a0,%ie_pc_lo12(var) ld.d $a1,$a0,%desc_ld(var) => NOP jirl $ra,$a1,%desc_call(var) => NOP add.d $a0,$a0,$tp 3. For IE -> LE: pcalau12i $a0,%ie_pc_hi20(var) => lu12i.w $a0,%le_hi20(var) ld.d $a0,$a0,%ie_pc_lo12(var) => ori $a0,$a0,%le_lo12(var) add.d $a0,$a0,$tp 4. When a tls variable is accessed using both DESC and IE, DESC transitions to IE and uses the same GOT entry as IE. --- bfd/elfnn-loongarch.c | 216 ++++++++++++++++++++++++++++++++++++- include/opcode/loongarch.h | 6 ++ 2 files changed, 221 insertions(+), 1 deletion(-) diff --git a/bfd/elfnn-loongarch.c b/bfd/elfnn-loongarch.c index 95a39148f73..1347d13d2e2 100644 --- a/bfd/elfnn-loongarch.c +++ b/bfd/elfnn-loongarch.c @@ -145,6 +145,16 @@ struct loongarch_elf_link_hash_table #define elf_backend_rela_normal 1 #define elf_backend_default_execstack 0 +#define IS_LOONGARCH_TLS_DESC_RELOC(R_TYPE) \ + ((R_TYPE) == R_LARCH_TLS_DESC_PC_HI20 \ + || (R_TYPE) == R_LARCH_TLS_DESC_PC_LO12 \ + || (R_TYPE) == R_LARCH_TLS_DESC_LD \ + || (R_TYPE) == R_LARCH_TLS_DESC_CALL) + +#define IS_LOONGARCH_TLS_IE_RELOC(R_TYPE) \ + ((R_TYPE) == R_LARCH_TLS_IE_PC_HI20 \ + || (R_TYPE) == R_LARCH_TLS_IE_PC_LO12) + /* Generate a PLT header. */ static bool @@ -593,6 +603,10 @@ loongarch_elf_record_tls_and_got_reference (bfd *abfd, char *new_tls_type = &_bfd_loongarch_elf_tls_type (abfd, h, symndx); *new_tls_type |= tls_type; + + /* If a symbol is accessed by both IE and DESC, relax DESC to IE. */ + if ((*new_tls_type & GOT_TLS_IE) && (*new_tls_type & GOT_TLS_GDESC)) + *new_tls_type &= ~ (GOT_TLS_GDESC); if ((*new_tls_type & GOT_NORMAL) && (*new_tls_type & ~GOT_NORMAL)) { _bfd_error_handler (_("%pB: `%s' accessed both as normal and " @@ -605,6 +619,104 @@ loongarch_elf_record_tls_and_got_reference (bfd *abfd, return true; } +static unsigned int +loongarch_reloc_got_type (unsigned int r_type) +{ + switch (r_type) + { + case R_LARCH_TLS_DESC_PC_HI20: + case R_LARCH_TLS_DESC_PC_LO12: + case R_LARCH_TLS_DESC_LD: + case R_LARCH_TLS_DESC_CALL: + return GOT_TLS_GDESC; + + case R_LARCH_TLS_IE_PC_HI20: + case R_LARCH_TLS_IE_PC_LO12: + return GOT_TLS_IE; + + default: + break; + } + return GOT_UNKNOWN; +} + +/* Return true if tls type transition can be performed. */ +static bool +loongarch_can_relax_tls (struct bfd_link_info *info, unsigned int r_type, + struct elf_link_hash_entry *h, bfd *input_bfd, + unsigned long r_symndx) +{ + char symbol_tls_type; + unsigned int reloc_got_type; + + if (! (IS_LOONGARCH_TLS_DESC_RELOC (r_type) + || IS_LOONGARCH_TLS_IE_RELOC (r_type))) + return false; + + symbol_tls_type = _bfd_loongarch_elf_tls_type (input_bfd, h, r_symndx); + reloc_got_type = loongarch_reloc_got_type (r_type); + + if (symbol_tls_type == GOT_TLS_IE && GOT_TLS_GD_ANY_P (reloc_got_type)) + return true; + + if (! bfd_link_executable (info)) + return false; + + if (h && h->root.type == bfd_link_hash_undefweak) + return false; + + return true; +} + +/* The type of relocation that can be transitioned. */ +static unsigned int +loongarch_tls_transition_without_check (struct bfd_link_info *info, + unsigned int r_type, + struct elf_link_hash_entry *h) +{ + bool local_exec = bfd_link_executable (info) + && SYMBOL_REFERENCES_LOCAL (info, h); + + switch (r_type) + { + case R_LARCH_TLS_DESC_PC_HI20: + return (local_exec + ? R_LARCH_TLS_LE_HI20 + : R_LARCH_TLS_IE_PC_HI20); + + case R_LARCH_TLS_DESC_PC_LO12: + return (local_exec + ? R_LARCH_TLS_LE_LO12 + : R_LARCH_TLS_IE_PC_LO12); + + case R_LARCH_TLS_DESC_LD: + case R_LARCH_TLS_DESC_CALL: + return R_LARCH_NONE; + + case R_LARCH_TLS_IE_PC_HI20: + return local_exec ? R_LARCH_TLS_LE_HI20 : r_type; + + case R_LARCH_TLS_IE_PC_LO12: + return local_exec ? R_LARCH_TLS_LE_LO12 : r_type; + + default: + break; + } + + return r_type; +} + +static unsigned int +loongarch_tls_transition (struct bfd_link_info *info, unsigned int r_type, + struct elf_link_hash_entry *h, bfd *input_bfd, + unsigned long r_symndx) +{ + if (! loongarch_can_relax_tls (info, r_type, h, input_bfd,r_symndx)) + return r_type; + + return loongarch_tls_transition_without_check (info, r_type, h); +} + /* Look through the relocs for a section during the first phase, and allocate space in the global offset table or procedure linkage table. */ @@ -706,6 +818,7 @@ loongarch_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, int need_dynreloc = 0; int only_need_pcrel = 0; + r_type = loongarch_tls_transition (info, r_type, h, abfd, r_symndx); switch (r_type) { case R_LARCH_GOT_PC_HI20: @@ -2403,6 +2516,96 @@ loongarch_reloc_is_fatal (struct bfd_link_info *info, relocation += 0x100000000; \ }) +/* Transition instruction sequence to relax instruction sequence. */ +static bool +loongarch_tls_relax (bfd *abfd, asection *sec, Elf_Internal_Rela *rel, + int r_type, struct elf_link_hash_entry *h, + struct bfd_link_info *info) +{ + bool local_exec = bfd_link_executable (info) + && SYMBOL_REFERENCES_LOCAL (info, h); + bfd_byte *contents = elf_section_data (sec)->this_hdr.contents; + unsigned long insn; + + switch (r_type) + { + case R_LARCH_TLS_DESC_PC_HI20: + if (local_exec) + /* DESC -> LE relaxation: + pcalalau12i $a0,%desc_pc_hi20(var) => + lu12i.w $a0,%le_hi20(var) + */ + bfd_put (32, abfd, LARCH_LU12I_W | LARCH_RD_A0, + contents + rel->r_offset); + + /* DESC -> IE relaxation: + pcalalau12i $a0,%desc_pc_hi20(var) => + pcalalau12i $a0,%ie_pc_hi20(var) + */ + return true; + + case R_LARCH_TLS_DESC_PC_LO12: + if (local_exec) + { + /* DESC -> LE relaxation: + addi.d $a0,$a0,%desc_pc_lo12(var) => + ori $a0,$a0,le_lo12(var) + */ + insn = LARCH_ORI | LARCH_RD_RJ_A0; + bfd_put (32, abfd, LARCH_ORI | LARCH_RD_RJ_A0, + contents + rel->r_offset); + } + else + { + /* DESC -> IE relaxation: + addi.d $a0,$a0,%desc_pc_lo12(var) => + ld.d $a0,$a0,%%ie_pc_lo12 + */ + bfd_put (32, abfd, LARCH_LD_D | LARCH_RD_RJ_A0, + contents + rel->r_offset); + } + return true; + + case R_LARCH_TLS_DESC_LD: + case R_LARCH_TLS_DESC_CALL: + /* DESC -> LE/IE relaxation: + ld.d $ra,$a0,%desc_ld(var) => NOP + jirl $ra,$ra,%desc_call(var) => NOP + */ + bfd_put (32, abfd, LARCH_NOP, contents + rel->r_offset); + return true; + + case R_LARCH_TLS_IE_PC_HI20: + if (local_exec) + { + /* IE -> LE relaxation: + pcalalau12i $rd,%ie_pc_hi20(var) => + lu12i.w $rd,%le_hi20(var) + */ + insn = bfd_getl32 (contents + rel->r_offset); + bfd_put (32, abfd, LARCH_LU12I_W | (insn & 0x1f), + contents + rel->r_offset); + } + return true; + + case R_LARCH_TLS_IE_PC_LO12: + if (local_exec) + { + /* IE -> LE relaxation: + ld.d $rd,$rj,%%ie_pc_lo12 => + ori $rd,$rj,le_lo12(var) + */ + insn = bfd_getl32 (contents + rel->r_offset); + bfd_put (32, abfd, LARCH_ORI | (insn & 0x3ff), + contents + rel->r_offset); + } + return true; + } + + return false; +} + + static int loongarch_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info, bfd *input_bfd, asection *input_section, @@ -2426,7 +2629,7 @@ loongarch_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info, relend = relocs + input_section->reloc_count; for (rel = relocs; rel < relend; rel++) { - int r_type = ELFNN_R_TYPE (rel->r_info); + unsigned int r_type = ELFNN_R_TYPE (rel->r_info); unsigned long r_symndx = ELFNN_R_SYM (rel->r_info); bfd_vma pc = sec_addr (input_section) + rel->r_offset; reloc_howto_type *howto = NULL; @@ -2436,6 +2639,7 @@ loongarch_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info, const char *name; bfd_reloc_status_type r = bfd_reloc_ok; bool is_ie, is_desc, is_undefweak, unresolved_reloc, defined_local; + unsigned int relaxed_r_type; bool resolved_local, resolved_dynly, resolved_to_const; char tls_type; bfd_vma relocation, off, ie_off, desc_off; @@ -2567,6 +2771,16 @@ loongarch_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info, BFD_ASSERT (!resolved_local || defined_local); + relaxed_r_type = loongarch_tls_transition (info, r_type, h, input_bfd, r_symndx); + if (relaxed_r_type != r_type) + { + howto = loongarch_elf_rtype_to_howto (input_bfd, relaxed_r_type); + BFD_ASSERT (howto != NULL); + + if (loongarch_tls_relax (input_bfd, input_section, rel, r_type, h, info)) + r_type = relaxed_r_type; + } + is_desc = false; is_ie = false; switch (r_type) diff --git a/include/opcode/loongarch.h b/include/opcode/loongarch.h index da936f7945a..32ff4d8a0f1 100644 --- a/include/opcode/loongarch.h +++ b/include/opcode/loongarch.h @@ -42,6 +42,12 @@ extern "C" ((value) < (-(1 << ((bits) - 1) << align)) \ || (value) > ((((1 << ((bits) - 1)) - 1) << align))) + #define LARCH_LU12I_W 0x14000000 + #define LARCH_ORI 0x03800000 + #define LARCH_LD_D 0x28c00000 + #define LARCH_RD_A0 0x04 + #define LARCH_RD_RJ_A0 0x084 + typedef uint32_t insn_t; struct loongarch_opcode -- 2.43.0