From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 7867) id 00674385841F; Mon, 25 Dec 2023 03:47:02 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 00674385841F Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable From: liu & zhensong To: bfd-cvs@sourceware.org Subject: [binutils-gdb] LoongArch: Add tls transition support. X-Act-Checkin: binutils-gdb X-Git-Author: Lulu Cai X-Git-Refname: refs/heads/master X-Git-Oldrev: 4f248d61eb9d319b552e3e0b2db862928c2c1971 X-Git-Newrev: 3898e04b8e4be8744f876ba475b5b2a07ca61ee6 Message-Id: <20231225034703.00674385841F@sourceware.org> Date: Mon, 25 Dec 2023 03:47:02 +0000 (GMT) X-BeenThere: binutils-cvs@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Binutils-cvs mailing list List-Unsubscribe: , List-Archive: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 25 Dec 2023 03:47:03 -0000 https://sourceware.org/git/gitweb.cgi?p=3Dbinutils-gdb.git;h=3D3898e04b8e4b= e8744f876ba475b5b2a07ca61ee6 commit 3898e04b8e4be8744f876ba475b5b2a07ca61ee6 Author: Lulu Cai Date: Sun Nov 26 14:25:26 2023 +0800 LoongArch: Add tls transition support. =20 Transitions between DESC->IE/LE and IE->LE are supported now. 1. For DESC -> LE: pcalau12i $a0,%desc_pc_hi20(var) =3D> lu12i.w $a0,%le_hi20(var) addi.d $a0,$a0,%desc_pc_lo12(var) =3D> ori $a0,$a0,%le_lo12(var) ld.d $a1,$a0,%desc_ld(var) =3D> NOP jirl $ra,$a1,%desc_call(var) =3D> NOP add.d $a0,$a0,$tp 2. For DESC -> IE: pcalau12i $a0,%desc_pc_hi20(var) =3D> pcalau12i $a0,%ie_pc_hi2= 0(var) addi.d $a0,$a0,%desc_pc_lo12(var) =3D> ld.d $a0,$a0,%ie_pc_lo12= (var) ld.d $a1,$a0,%desc_ld(var) =3D> NOP jirl $ra,$a1,%desc_call(var) =3D> NOP add.d $a0,$a0,$tp 3. For IE -> LE: pcalau12i $a0,%ie_pc_hi20(var) =3D> lu12i.w $a0,%le_hi20(var) ld.d $a0,$a0,%ie_pc_lo12(var) =3D> ori $a0,$a0,%le_lo12(var) add.d $a0,$a0,$tp 4. When a tls variable is accessed using both DESC and IE, DESC transit= ions to IE and uses the same GOT entry as IE. Diff: --- 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 =20 +#define IS_LOONGARCH_TLS_DESC_RELOC(R_TYPE) \ + ((R_TYPE) =3D=3D R_LARCH_TLS_DESC_PC_HI20 \ + || (R_TYPE) =3D=3D R_LARCH_TLS_DESC_PC_LO12 \ + || (R_TYPE) =3D=3D R_LARCH_TLS_DESC_LD \ + || (R_TYPE) =3D=3D R_LARCH_TLS_DESC_CALL) + +#define IS_LOONGARCH_TLS_IE_RELOC(R_TYPE) \ + ((R_TYPE) =3D=3D R_LARCH_TLS_IE_PC_HI20 \ + || (R_TYPE) =3D=3D R_LARCH_TLS_IE_PC_LO12) + /* Generate a PLT header. */ =20 static bool @@ -593,6 +603,10 @@ loongarch_elf_record_tls_and_got_reference (bfd *abfd, =20 char *new_tls_type =3D &_bfd_loongarch_elf_tls_type (abfd, h, symndx); *new_tls_type |=3D 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 &=3D ~ (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; } =20 +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 =3D _bfd_loongarch_elf_tls_type (input_bfd, h, r_symndx); + reloc_got_type =3D loongarch_reloc_got_type (r_type); + + if (symbol_tls_type =3D=3D GOT_TLS_IE && GOT_TLS_GD_ANY_P (reloc_got_typ= e)) + return true; + + if (! bfd_link_executable (info)) + return false; + + if (h && h->root.type =3D=3D 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 =3D 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 =3D 0; int only_need_pcrel =3D 0; =20 + r_type =3D 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 +=3D 0x100000000; \ }) =20 +/* 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 =3D bfd_link_executable (info) + && SYMBOL_REFERENCES_LOCAL (info, h); + bfd_byte *contents =3D 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) =3D> + 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) =3D> + 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) =3D> + ori $a0,$a0,le_lo12(var) + */ + insn =3D 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) =3D> + 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) =3D> NOP + jirl $ra,$ra,%desc_call(var) =3D> 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) =3D> + lu12i.w $rd,%le_hi20(var) + */ + insn =3D 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 =3D> + ori $rd,$rj,le_lo12(var) + */ + insn =3D 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 *inf= o, bfd *input_bfd, asection *input_section, @@ -2426,7 +2629,7 @@ loongarch_elf_relocate_section (bfd *output_bfd, stru= ct bfd_link_info *info, relend =3D relocs + input_section->reloc_count; for (rel =3D relocs; rel < relend; rel++) { - int r_type =3D ELFNN_R_TYPE (rel->r_info); + unsigned int r_type =3D ELFNN_R_TYPE (rel->r_info); unsigned long r_symndx =3D ELFNN_R_SYM (rel->r_info); bfd_vma pc =3D sec_addr (input_section) + rel->r_offset; reloc_howto_type *howto =3D NULL; @@ -2436,6 +2639,7 @@ loongarch_elf_relocate_section (bfd *output_bfd, stru= ct bfd_link_info *info, const char *name; bfd_reloc_status_type r =3D 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, str= uct bfd_link_info *info, =20 BFD_ASSERT (!resolved_local || defined_local); =20 + relaxed_r_type =3D loongarch_tls_transition (info, r_type, h, input_= bfd, r_symndx); + if (relaxed_r_type !=3D r_type) + { + howto =3D loongarch_elf_rtype_to_howto (input_bfd, relaxed_r_type); + BFD_ASSERT (howto !=3D NULL); + + if (loongarch_tls_relax (input_bfd, input_section, rel, r_type, h, info)) + r_type =3D relaxed_r_type; + } + is_desc =3D false; is_ie =3D 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))) =20 + #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; =20 struct loongarch_opcode