[2.43] LoongArch: Fix broken DESC => IE transition for 2.43 branch

Message ID 20241219052302.43674-1-xry111@xry111.site
State New
Headers
Series [2.43] LoongArch: Fix broken DESC => IE transition for 2.43 branch |

Checks

Context Check Description
linaro-tcwg-bot/tcwg_binutils_build--master-arm fail Patch failed to apply
linaro-tcwg-bot/tcwg_binutils_build--master-aarch64 fail Patch failed to apply

Commit Message

Xi Ruoyao Dec. 19, 2024, 5:23 a.m. UTC
  If code compiled with -fPIC -mtls-dialect=desc is linked into a PDE or
PIE, and the code refers to external DSO symbols, we can produce broken
link unit as check_relocs expects DESC => IE transition to happen and
emits a TLS IE entry in the GOT, but a too early "continue" in
relax_section actually jumps over the DESC => IE transition so the code
sequence is unchanged and still expecting a TLS descriptor (instead of
an IE entry) in the GOT.

The bug is already fixed in master branch by commit 5c3d09c1855b
("LoongArch: Optimize the relaxation process") so this fix is only
needed for the 2.43 branch.

Reported-by: Icenowy Zheng <uwu@icenowy.me>
Closes: https://gcc.gnu.org/PR118114
Signed-off-by: Xi Ruoyao <xry111@xry111.site>
---
 bfd/elfnn-loongarch.c | 43 ++++++++++++++++++++++---------------------
 1 file changed, 22 insertions(+), 21 deletions(-)


base-commit: 834b779ad28c3cecb5ad91a1ab2af3c8453c3b3a
  

Comments

Icenowy Zheng Dec. 19, 2024, 9:04 a.m. UTC | #1
在 2024-12-19星期四的 13:23 +0800,Xi Ruoyao写道:
> If code compiled with -fPIC -mtls-dialect=desc is linked into a PDE
> or
> PIE, and the code refers to external DSO symbols, we can produce
> broken
> link unit as check_relocs expects DESC => IE transition to happen and
> emits a TLS IE entry in the GOT, but a too early "continue" in
> relax_section actually jumps over the DESC => IE transition so the
> code
> sequence is unchanged and still expecting a TLS descriptor (instead
> of
> an IE entry) in the GOT.
> 
> The bug is already fixed in master branch by commit 5c3d09c1855b
> ("LoongArch: Optimize the relaxation process") so this fix is only
> needed for the 2.43 branch.
> 
> Reported-by: Icenowy Zheng <uwu@icenowy.me>

My original case (which is compiling a full-featured Mesa) fails in
another way after applying this patch -- originally it fails because
intel_clc gets segfault (which uses std::call_once to initialize LLVM),
now it fails when linking some .so files (including libgallium).

Here's the backtrace:

```
#0  loongarch_can_trans_tls (input_bfd=<optimized out>,
info=0x555558f60b78 <link_info>, h=0x0, r_symndx=<optimized out>,
r_type=<optimized out>)
    at /var/cache/acbs/build/acbs._4a9gw_q/binutils-2.43.1/bfd/elfnn-
loongarch.c:787
#1  0x00007ffff01b44fc in loongarch_tls_transition
(input_bfd=0x55558ed785e0, info=0x555558f60b78 <link_info>, h=0x0,
r_symndx=98, r_type=111)
    at /var/cache/acbs/build/acbs._4a9gw_q/binutils-2.43.1/bfd/elfnn-
loongarch.c:844
#2  loongarch_elf_check_relocs (abfd=<optimized out>,
info=0x555558f60b78 <link_info>, sec=0x55558e1d71d8, relocs=<optimized
out>)
    at /var/cache/acbs/build/acbs._4a9gw_q/binutils-2.43.1/bfd/elfnn-
loongarch.c:985
#3  0x00007ffff01eb828 in _bfd_elf_link_iterate_on_relocs
(abfd=0x55558ed785e0, info=0x555558f60b78 <link_info>,
action=0x7ffff01b4040 <loongarch_elf_check_relocs>)
    at /var/cache/acbs/build/acbs._4a9gw_q/binutils-
2.43.1/bfd/elflink.c:4257
#4  0x0000555558ed39c0 in lang_check_relocs () at
/var/cache/acbs/build/acbs._4a9gw_q/binutils-2.43.1/ld/ldlang.c:8071
#5  lang_process () at /var/cache/acbs/build/acbs._4a9gw_q/binutils-
2.43.1/ld/ldlang.c:8383
#6  0x0000555558eb8564 in main (argc=<optimized out>, argv=<optimized
out>) at /var/cache/acbs/build/acbs._4a9gw_q/binutils-
2.43.1/ld/ldmain.c:529
```

> Closes: https://gcc.gnu.org/PR118114
> Signed-off-by: Xi Ruoyao <xry111@xry111.site>
> ---
>  bfd/elfnn-loongarch.c | 43 ++++++++++++++++++++++-------------------
> --
>  1 file changed, 22 insertions(+), 21 deletions(-)
> 
> diff --git a/bfd/elfnn-loongarch.c b/bfd/elfnn-loongarch.c
> index 312707bb00b..1c34797c2e1 100644
> --- a/bfd/elfnn-loongarch.c
> +++ b/bfd/elfnn-loongarch.c
> @@ -5326,7 +5326,7 @@ loongarch_elf_relax_section (bfd *abfd,
> asection *sec,
>      {
>        char symtype;
>        bfd_vma symval;
> -      asection *sym_sec;
> +      asection *sym_sec = NULL;
>        bool local_got = false;
>        Elf_Internal_Rela *rel = relocs + i;
>        struct elf_link_hash_entry *h = NULL;
> @@ -5418,14 +5418,33 @@ loongarch_elf_relax_section (bfd *abfd,
> asection *sec,
>               symval = h->root.u.def.value;
>               sym_sec = h->root.u.def.section;
>             }
> -         else
> -           continue;
>  
>           if (h && LARCH_REF_LOCAL (info, h))
>             local_got = true;
>           symtype = h->type;
>         }
>  
> +      /* If the conditions for tls type transition are met, type
> +        transition is performed instead of relax.
> +        During the transition from DESC->IE/LE, there are 2
> situations
> +        depending on the different configurations of the
> relax/norelax
> +        option.
> +        If the -relax option is used, the extra nops will be
> removed,
> +        and this transition is performed in pass 0.
> +        If the --no-relax option is used, nop will be retained, and
> +        this transition is performed in pass 1.  */
> +      if (IS_LOONGARCH_TLS_TRANS_RELOC (r_type)
> +         && (i + 1 != sec->reloc_count)
> +         && ELFNN_R_TYPE (rel[1].r_info) == R_LARCH_RELAX
> +         && loongarch_can_trans_tls (abfd, info, h, r_symndx,
> r_type))
> +       {
> +         loongarch_tls_perform_trans (abfd, sec, rel, h, info);
> +         r_type = ELFNN_R_TYPE (rel->r_info);
> +       }
> +
> +      if (!sym_sec)
> +       continue;
> +
>        if (sym_sec->sec_info_type == SEC_INFO_TYPE_MERGE
>            && (sym_sec->flags & SEC_MERGE))
>         {
> @@ -5453,24 +5472,6 @@ loongarch_elf_relax_section (bfd *abfd,
> asection *sec,
>  
>        symval += sec_addr (sym_sec);
>  
> -      /* If the conditions for tls type transition are met, type
> -        transition is performed instead of relax.
> -        During the transition from DESC->IE/LE, there are 2
> situations
> -        depending on the different configurations of the
> relax/norelax
> -        option.
> -        If the -relax option is used, the extra nops will be
> removed,
> -        and this transition is performed in pass 0.
> -        If the --no-relax option is used, nop will be retained, and
> -        this transition is performed in pass 1.  */
> -      if (IS_LOONGARCH_TLS_TRANS_RELOC (r_type)
> -         && (i + 1 != sec->reloc_count)
> -         && ELFNN_R_TYPE (rel[1].r_info) == R_LARCH_RELAX
> -         && loongarch_can_trans_tls (abfd, info, h, r_symndx,
> r_type))
> -       {
> -         loongarch_tls_perform_trans (abfd, sec, rel, h, info);
> -         r_type = ELFNN_R_TYPE (rel->r_info);
> -       }
> -
>        switch (r_type)
>         {
>         case R_LARCH_ALIGN:
> 
> base-commit: 834b779ad28c3cecb5ad91a1ab2af3c8453c3b3a
  
Xi Ruoyao Dec. 19, 2024, 9:18 a.m. UTC | #2
On Thu, 2024-12-19 at 17:04 +0800, Icenowy Zheng wrote:
> 在 2024-12-19星期四的 13:23 +0800,Xi Ruoyao写道:
> > If code compiled with -fPIC -mtls-dialect=desc is linked into a PDE
> > or
> > PIE, and the code refers to external DSO symbols, we can produce
> > broken
> > link unit as check_relocs expects DESC => IE transition to happen and
> > emits a TLS IE entry in the GOT, but a too early "continue" in
> > relax_section actually jumps over the DESC => IE transition so the
> > code
> > sequence is unchanged and still expecting a TLS descriptor (instead
> > of
> > an IE entry) in the GOT.
> > 
> > The bug is already fixed in master branch by commit 5c3d09c1855b
> > ("LoongArch: Optimize the relaxation process") so this fix is only
> > needed for the 2.43 branch.
> > 
> > Reported-by: Icenowy Zheng <uwu@icenowy.me>
> 
> My original case (which is compiling a full-featured Mesa) fails in
> another way after applying this patch -- originally it fails because
> intel_clc gets segfault (which uses std::call_once to initialize LLVM),
> now it fails when linking some .so files (including libgallium).
> 
> Here's the backtrace:
> 
> ```
> #0  loongarch_can_trans_tls (input_bfd=<optimized out>,
> info=0x555558f60b78 <link_info>, h=0x0, r_symndx=<optimized out>,
> r_type=<optimized out>)
>     at /var/cache/acbs/build/acbs._4a9gw_q/binutils-2.43.1/bfd/elfnn-
> loongarch.c:787

I guess (not sure) it's fixed by

commit 28489a70d4660d67e71d75e82286a6e1a7003b93
Author: Xin Wang <yw987194828@gmail.com>
Date:   Fri Sep 6 09:00:12 2024 +0800

    LoongArch: Add elfNN_loongarch_mkobject to initialize LoongArch tdata

This is already backported to 2.43 branch as commit
c40337b1784d81c615a5dd9fd391f6677e52c6d8.
  
Icenowy Zheng Dec. 19, 2024, 10:46 a.m. UTC | #3
在 2024-12-19星期四的 17:18 +0800,Xi Ruoyao写道:
> On Thu, 2024-12-19 at 17:04 +0800, Icenowy Zheng wrote:
> > 在 2024-12-19星期四的 13:23 +0800,Xi Ruoyao写道:
> > > If code compiled with -fPIC -mtls-dialect=desc is linked into a
> > > PDE
> > > or
> > > PIE, and the code refers to external DSO symbols, we can produce
> > > broken
> > > link unit as check_relocs expects DESC => IE transition to happen
> > > and
> > > emits a TLS IE entry in the GOT, but a too early "continue" in
> > > relax_section actually jumps over the DESC => IE transition so
> > > the
> > > code
> > > sequence is unchanged and still expecting a TLS descriptor
> > > (instead
> > > of
> > > an IE entry) in the GOT.
> > > 
> > > The bug is already fixed in master branch by commit 5c3d09c1855b
> > > ("LoongArch: Optimize the relaxation process") so this fix is
> > > only
> > > needed for the 2.43 branch.
> > > 
> > > Reported-by: Icenowy Zheng <uwu@icenowy.me>
> > 
> > My original case (which is compiling a full-featured Mesa) fails in
> > another way after applying this patch -- originally it fails
> > because
> > intel_clc gets segfault (which uses std::call_once to initialize
> > LLVM),
> > now it fails when linking some .so files (including libgallium).
> > 
> > Here's the backtrace:
> > 
> > ```
> > #0  loongarch_can_trans_tls (input_bfd=<optimized out>,
> > info=0x555558f60b78 <link_info>, h=0x0, r_symndx=<optimized out>,
> > r_type=<optimized out>)
> >     at /var/cache/acbs/build/acbs._4a9gw_q/binutils-
> > 2.43.1/bfd/elfnn-
> > loongarch.c:787
> 
> I guess (not sure) it's fixed by
> 
> commit 28489a70d4660d67e71d75e82286a6e1a7003b93
> Author: Xin Wang <yw987194828@gmail.com>
> Date:   Fri Sep 6 09:00:12 2024 +0800
> 
>     LoongArch: Add elfNN_loongarch_mkobject to initialize LoongArch
> tdata
> 

Yes, picking this patch makes everything normal now.

So, for the original patch in the mail's subject,

Tested-By: Icenowy Zheng <uwu@icenowy.me>

Thanks!
Icenowy

> This is already backported to 2.43 branch as commit
> c40337b1784d81c615a5dd9fd391f6677e52c6d8.
>
  
Lulu Cai Dec. 27, 2024, 6:12 a.m. UTC | #4
When I apply this patch on the 2.43 branch and compile with gcc 15, the 
following warning is triggered.

binutils-gdb/bfd/elfnn-loongarch.c: In function 
‘loongarch_elf_relax_section’:
binutils-gdb/bfd/elfnn-loongarch.c:5471:16: error: ‘symval’ may be used 
uninitialized [-Werror=maybe-uninitialized]
5471 | symval += rel->r_addend;
| ~~~~~~~^~~~~~~~~~~~~~~~~
binutils-gdb/bfd/elfnn-loongarch.c:5328:15: note: ‘symval’ was declared here
5328 | bfd_vma symval;
| ^~~~~~
cc1: all warnings being treated as errors

On 12/19/24 1:23 PM, Xi Ruoyao wrote:
> If code compiled with -fPIC -mtls-dialect=desc is linked into a PDE or
> PIE, and the code refers to external DSO symbols, we can produce broken
> link unit as check_relocs expects DESC => IE transition to happen and
> emits a TLS IE entry in the GOT, but a too early "continue" in
> relax_section actually jumps over the DESC => IE transition so the code
> sequence is unchanged and still expecting a TLS descriptor (instead of
> an IE entry) in the GOT.
>
> The bug is already fixed in master branch by commit 5c3d09c1855b
> ("LoongArch: Optimize the relaxation process") so this fix is only
> needed for the 2.43 branch.
>
> Reported-by: Icenowy Zheng <uwu@icenowy.me>
> Closes: https://gcc.gnu.org/PR118114
> Signed-off-by: Xi Ruoyao <xry111@xry111.site>
> ---
>   bfd/elfnn-loongarch.c | 43 ++++++++++++++++++++++---------------------
>   1 file changed, 22 insertions(+), 21 deletions(-)
>
> diff --git a/bfd/elfnn-loongarch.c b/bfd/elfnn-loongarch.c
> index 312707bb00b..1c34797c2e1 100644
> --- a/bfd/elfnn-loongarch.c
> +++ b/bfd/elfnn-loongarch.c
> @@ -5326,7 +5326,7 @@ loongarch_elf_relax_section (bfd *abfd, asection *sec,
>       {
>         char symtype;
>         bfd_vma symval;
> -      asection *sym_sec;
> +      asection *sym_sec = NULL;
>         bool local_got = false;
>         Elf_Internal_Rela *rel = relocs + i;
>         struct elf_link_hash_entry *h = NULL;
> @@ -5418,14 +5418,33 @@ loongarch_elf_relax_section (bfd *abfd, asection *sec,
>   	      symval = h->root.u.def.value;
>   	      sym_sec = h->root.u.def.section;
>   	    }
> -	  else
> -	    continue;
>   
>   	  if (h && LARCH_REF_LOCAL (info, h))
>   	    local_got = true;
>   	  symtype = h->type;
>   	}
>   
> +      /* If the conditions for tls type transition are met, type
> +	 transition is performed instead of relax.
> +	 During the transition from DESC->IE/LE, there are 2 situations
> +	 depending on the different configurations of the relax/norelax
> +	 option.
> +	 If the -relax option is used, the extra nops will be removed,
> +	 and this transition is performed in pass 0.
> +	 If the --no-relax option is used, nop will be retained, and
> +	 this transition is performed in pass 1.  */
> +      if (IS_LOONGARCH_TLS_TRANS_RELOC (r_type)
> +	  && (i + 1 != sec->reloc_count)
> +	  && ELFNN_R_TYPE (rel[1].r_info) == R_LARCH_RELAX
> +	  && loongarch_can_trans_tls (abfd, info, h, r_symndx, r_type))
> +	{
> +	  loongarch_tls_perform_trans (abfd, sec, rel, h, info);
> +	  r_type = ELFNN_R_TYPE (rel->r_info);
> +	}
> +
> +      if (!sym_sec)
> +	continue;
> +
>         if (sym_sec->sec_info_type == SEC_INFO_TYPE_MERGE
>   	   && (sym_sec->flags & SEC_MERGE))
>   	{
> @@ -5453,24 +5472,6 @@ loongarch_elf_relax_section (bfd *abfd, asection *sec,
>   
>         symval += sec_addr (sym_sec);
>   
> -      /* If the conditions for tls type transition are met, type
> -	 transition is performed instead of relax.
> -	 During the transition from DESC->IE/LE, there are 2 situations
> -	 depending on the different configurations of the relax/norelax
> -	 option.
> -	 If the -relax option is used, the extra nops will be removed,
> -	 and this transition is performed in pass 0.
> -	 If the --no-relax option is used, nop will be retained, and
> -	 this transition is performed in pass 1.  */
> -      if (IS_LOONGARCH_TLS_TRANS_RELOC (r_type)
> -	  && (i + 1 != sec->reloc_count)
> -	  && ELFNN_R_TYPE (rel[1].r_info) == R_LARCH_RELAX
> -	  && loongarch_can_trans_tls (abfd, info, h, r_symndx, r_type))
> -	{
> -	  loongarch_tls_perform_trans (abfd, sec, rel, h, info);
> -	  r_type = ELFNN_R_TYPE (rel->r_info);
> -	}
> -
>         switch (r_type)
>   	{
>   	case R_LARCH_ALIGN:
>
> base-commit: 834b779ad28c3cecb5ad91a1ab2af3c8453c3b3a
  
Xi Ruoyao Dec. 27, 2024, 6:28 a.m. UTC | #5
On Fri, 2024-12-27 at 14:12 +0800, Lulu Cai wrote:
> When I apply this patch on the 2.43 branch and compile with gcc 15, the 
> following warning is triggered.
> 
> binutils-gdb/bfd/elfnn-loongarch.c: In function 
> ‘loongarch_elf_relax_section’:
> binutils-gdb/bfd/elfnn-loongarch.c:5471:16: error: ‘symval’ may be used 
> uninitialized [-Werror=maybe-uninitialized]
> 5471 | symval += rel->r_addend;
> > ~~~~~~~^~~~~~~~~~~~~~~~~
> binutils-gdb/bfd/elfnn-loongarch.c:5328:15: note: ‘symval’ was declared here
> 5328 | bfd_vma symval;
> > ^~~~~~
> cc1: all warnings being treated as errors

Hmm it seems a compiler bug...  Whenever we set sym_sec to non-NULL,
symval is also set.  And line 5471 should be skipped with the "continue"
at line 5446 then if sym_sec is NULL.

I'll initialize the variable in v2 but also send a GCC bug report.

> On 12/19/24 1:23 PM, Xi Ruoyao wrote:
> > If code compiled with -fPIC -mtls-dialect=desc is linked into a PDE or
> > PIE, and the code refers to external DSO symbols, we can produce broken
> > link unit as check_relocs expects DESC => IE transition to happen and
> > emits a TLS IE entry in the GOT, but a too early "continue" in
> > relax_section actually jumps over the DESC => IE transition so the code
> > sequence is unchanged and still expecting a TLS descriptor (instead of
> > an IE entry) in the GOT.
> > 
> > The bug is already fixed in master branch by commit 5c3d09c1855b
> > ("LoongArch: Optimize the relaxation process") so this fix is only
> > needed for the 2.43 branch.
> > 
> > Reported-by: Icenowy Zheng <uwu@icenowy.me>
> > Closes: https://gcc.gnu.org/PR118114
> > Signed-off-by: Xi Ruoyao <xry111@xry111.site>
> > ---
> >   bfd/elfnn-loongarch.c | 43 ++++++++++++++++++++++---------------------
> >   1 file changed, 22 insertions(+), 21 deletions(-)
> > 
> > diff --git a/bfd/elfnn-loongarch.c b/bfd/elfnn-loongarch.c
> > index 312707bb00b..1c34797c2e1 100644
> > --- a/bfd/elfnn-loongarch.c
> > +++ b/bfd/elfnn-loongarch.c
> > @@ -5326,7 +5326,7 @@ loongarch_elf_relax_section (bfd *abfd, asection *sec,
> >       {
> >         char symtype;
> >         bfd_vma symval;
> > -      asection *sym_sec;
> > +      asection *sym_sec = NULL;
> >         bool local_got = false;
> >         Elf_Internal_Rela *rel = relocs + i;
> >         struct elf_link_hash_entry *h = NULL;
> > @@ -5418,14 +5418,33 @@ loongarch_elf_relax_section (bfd *abfd, asection *sec,
> >   	      symval = h->root.u.def.value;
> >   	      sym_sec = h->root.u.def.section;
> >   	    }
> > -	  else
> > -	    continue;
> >   
> >   	  if (h && LARCH_REF_LOCAL (info, h))
> >   	    local_got = true;
> >   	  symtype = h->type;
> >   	}
> >   
> > +      /* If the conditions for tls type transition are met, type
> > +	 transition is performed instead of relax.
> > +	 During the transition from DESC->IE/LE, there are 2 situations
> > +	 depending on the different configurations of the relax/norelax
> > +	 option.
> > +	 If the -relax option is used, the extra nops will be removed,
> > +	 and this transition is performed in pass 0.
> > +	 If the --no-relax option is used, nop will be retained, and
> > +	 this transition is performed in pass 1.  */
> > +      if (IS_LOONGARCH_TLS_TRANS_RELOC (r_type)
> > +	  && (i + 1 != sec->reloc_count)
> > +	  && ELFNN_R_TYPE (rel[1].r_info) == R_LARCH_RELAX
> > +	  && loongarch_can_trans_tls (abfd, info, h, r_symndx, r_type))
> > +	{
> > +	  loongarch_tls_perform_trans (abfd, sec, rel, h, info);
> > +	  r_type = ELFNN_R_TYPE (rel->r_info);
> > +	}
> > +
> > +      if (!sym_sec)
> > +	continue;
> > +
> >         if (sym_sec->sec_info_type == SEC_INFO_TYPE_MERGE
> >   	   && (sym_sec->flags & SEC_MERGE))
> >   	{
> > @@ -5453,24 +5472,6 @@ loongarch_elf_relax_section (bfd *abfd, asection *sec,
> >   
> >         symval += sec_addr (sym_sec);
> >   
> > -      /* If the conditions for tls type transition are met, type
> > -	 transition is performed instead of relax.
> > -	 During the transition from DESC->IE/LE, there are 2 situations
> > -	 depending on the different configurations of the relax/norelax
> > -	 option.
> > -	 If the -relax option is used, the extra nops will be removed,
> > -	 and this transition is performed in pass 0.
> > -	 If the --no-relax option is used, nop will be retained, and
> > -	 this transition is performed in pass 1.  */
> > -      if (IS_LOONGARCH_TLS_TRANS_RELOC (r_type)
> > -	  && (i + 1 != sec->reloc_count)
> > -	  && ELFNN_R_TYPE (rel[1].r_info) == R_LARCH_RELAX
> > -	  && loongarch_can_trans_tls (abfd, info, h, r_symndx, r_type))
> > -	{
> > -	  loongarch_tls_perform_trans (abfd, sec, rel, h, info);
> > -	  r_type = ELFNN_R_TYPE (rel->r_info);
> > -	}
> > -
> >         switch (r_type)
> >   	{
> >   	case R_LARCH_ALIGN:
> > 
> > base-commit: 834b779ad28c3cecb5ad91a1ab2af3c8453c3b3a
> 
>
  

Patch

diff --git a/bfd/elfnn-loongarch.c b/bfd/elfnn-loongarch.c
index 312707bb00b..1c34797c2e1 100644
--- a/bfd/elfnn-loongarch.c
+++ b/bfd/elfnn-loongarch.c
@@ -5326,7 +5326,7 @@  loongarch_elf_relax_section (bfd *abfd, asection *sec,
     {
       char symtype;
       bfd_vma symval;
-      asection *sym_sec;
+      asection *sym_sec = NULL;
       bool local_got = false;
       Elf_Internal_Rela *rel = relocs + i;
       struct elf_link_hash_entry *h = NULL;
@@ -5418,14 +5418,33 @@  loongarch_elf_relax_section (bfd *abfd, asection *sec,
 	      symval = h->root.u.def.value;
 	      sym_sec = h->root.u.def.section;
 	    }
-	  else
-	    continue;
 
 	  if (h && LARCH_REF_LOCAL (info, h))
 	    local_got = true;
 	  symtype = h->type;
 	}
 
+      /* If the conditions for tls type transition are met, type
+	 transition is performed instead of relax.
+	 During the transition from DESC->IE/LE, there are 2 situations
+	 depending on the different configurations of the relax/norelax
+	 option.
+	 If the -relax option is used, the extra nops will be removed,
+	 and this transition is performed in pass 0.
+	 If the --no-relax option is used, nop will be retained, and
+	 this transition is performed in pass 1.  */
+      if (IS_LOONGARCH_TLS_TRANS_RELOC (r_type)
+	  && (i + 1 != sec->reloc_count)
+	  && ELFNN_R_TYPE (rel[1].r_info) == R_LARCH_RELAX
+	  && loongarch_can_trans_tls (abfd, info, h, r_symndx, r_type))
+	{
+	  loongarch_tls_perform_trans (abfd, sec, rel, h, info);
+	  r_type = ELFNN_R_TYPE (rel->r_info);
+	}
+
+      if (!sym_sec)
+	continue;
+
       if (sym_sec->sec_info_type == SEC_INFO_TYPE_MERGE
 	   && (sym_sec->flags & SEC_MERGE))
 	{
@@ -5453,24 +5472,6 @@  loongarch_elf_relax_section (bfd *abfd, asection *sec,
 
       symval += sec_addr (sym_sec);
 
-      /* If the conditions for tls type transition are met, type
-	 transition is performed instead of relax.
-	 During the transition from DESC->IE/LE, there are 2 situations
-	 depending on the different configurations of the relax/norelax
-	 option.
-	 If the -relax option is used, the extra nops will be removed,
-	 and this transition is performed in pass 0.
-	 If the --no-relax option is used, nop will be retained, and
-	 this transition is performed in pass 1.  */
-      if (IS_LOONGARCH_TLS_TRANS_RELOC (r_type)
-	  && (i + 1 != sec->reloc_count)
-	  && ELFNN_R_TYPE (rel[1].r_info) == R_LARCH_RELAX
-	  && loongarch_can_trans_tls (abfd, info, h, r_symndx, r_type))
-	{
-	  loongarch_tls_perform_trans (abfd, sec, rel, h, info);
-	  r_type = ELFNN_R_TYPE (rel->r_info);
-	}
-
       switch (r_type)
 	{
 	case R_LARCH_ALIGN: