Bug 13671 - gld creates i386 relocations not supported by Solaris ld.so.1
Summary: gld creates i386 relocations not supported by Solaris ld.so.1
Status: RESOLVED FIXED
Alias: None
Product: binutils
Classification: Unclassified
Component: ld (show other bugs)
Version: 2.30
: P2 normal
Target Milestone: 2.41
Assignee: Not yet assigned to anyone
URL: https://sourceware.org/pipermail/binu...
Keywords:
Depends on:
Blocks:
 
Reported: 2012-02-07 18:27 UTC by Rainer Orth
Modified: 2023-01-20 08:11 UTC (History)
1 user (show)

See Also:
Host: i386-pc-solaris2*
Target: i386-pc-solaris2*
Build: i386-pc-solaris2*
Last reconfirmed:


Attachments
A patch (597 bytes, patch)
2018-02-10 13:16 UTC, H.J. Lu
Details | Diff
assembler output (757 bytes, text/plain)
2018-02-11 19:40 UTC, Rainer Orth
Details
Augmented patch (933 bytes, patch)
2023-01-10 15:24 UTC, Rainer Orth
Details | Diff
Augmented patch, incorporating review comments (1.01 KB, patch)
2023-01-11 14:34 UTC, Rainer Orth
Details | Diff
Augmented^2 patch (1.12 KB, patch)
2023-01-13 12:23 UTC, Rainer Orth
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Rainer Orth 2012-02-07 18:27:44 UTC
Recently, Solaris/x86 gcc bootstrap with gas, gld, and Go support included
started to fail when the Go backend, go1, couldn't be executed:

ld.so.1: go1: fatal: relocation error: R_386_UNKNOWN37: file /var/gcc/regression/trunk/10-gcc-gas-gld/build/gcc/go1: symbol _ZSt15__once_callable: offset size (0 bytes) is not supported
gccgo: internal compiler error: Killed (program go1)

In <sys/elf_386.h>, I find that R_386_UNKNOWN37 is R_386_TLS_TPOFF32, which is
not supported even on Solaris 11.  This relocation is not in the input objects.

In <sys/elf_386.h> I find the following correspondance:

#define      R_386_UNKNOWN24         24		R_386_TLS_GD_32
#define      R_386_UNKNOWN25         25		R_386_TLS_GD_PUSH
#define      R_386_UNKNOWN26         26		R_386_TLS_GD_CALL
#define      R_386_UNKNOWN27         27		R_386_TLS_GD_POP
#define      R_386_UNKNOWN28         28		R_386_TLS_LDM_32
#define      R_386_UNKNOWN29         29		R_386_TLS_LDM_PUSH
#define      R_386_UNKNOWN30         30		R_386_TLS_LDM_CALL
#define      R_386_UNKNOWN31         31		R_386_TLS_LDM_POP
#define      R_386_UNKNOWN33         33		R_386_TLS_IE_32
#define      R_386_UNKNOWN34         34		R_386_TLS_LE_32
#define      R_386_UNKNOWN37         37		R_386_TLS_TPOFF32

If I read bfd/elf32-i386.c correctly, only the last three can be generated by
gld on its own.  Given that Solaris ld.so.1 cannot handle them, they shouldn't
be generated when targetting Solaris/x86.

  Rainer
Comment 1 Rainer Orth 2018-02-07 19:49:18 UTC
I just had the same problem again (this time with gas/gld 2.30) on Solaris 11.4/x86:

I tried to build gcc mainline with --enable-host-shared --enable-languages=jit,
but running cc1 fails:

/var/gcc/regression/trunk/11.4-gcc-gas-gld/build/./gcc/xgcc -B/var/gcc/regression/trunk/11.4-gcc-gas-gld/build/./gcc/ -xc -nostdinc /dev/null -S -o /dev/null -fself-test=/vol/gcc/src/hg/trunk/solaris/gcc/testsuite/selftests
ld.so.1: cc1: fatal: relocation error: R_386_UNKNOWN37: file /var/gcc/regression/trunk/11.4-gcc-gas-gld/build/gcc/cc1: symbol __gmpfr_emin: offset size (0 bytes) is not supported
xgcc: fatal error: Killed signal terminated program cc1
compilation terminated.
make[3]: *** [Makefile:1972: s-selftest-c] Error 1

R_386_UNKNOWN37 above is R_386_TLS_TPOFF32, and the current (Solaris 11.4)
<sys/elf_i386.h> has

#define	R_386_UNKNOWN24		24
#define	R_386_UNKNOWN25		25
#define	R_386_UNKNOWN26		26
#define	R_386_UNKNOWN27		27
#define	R_386_UNKNOWN28		28
#define	R_386_UNKNOWN29		29
#define	R_386_UNKNOWN30		30
#define	R_386_UNKNOWN31		31

#define	R_386_UNKNOWN37		37	/* reserved for future expansion */
#define	R_386_SIZE32		38	/* reserved for future expansion */
#define	R_386_TLS_GOTDESC	39	/* reserved for future expansion */
#define	R_386_TLS_DESC_CALL 	40	/* reserved for future expansion */
#define	R_386_TLS_DESC		41	/* reserved for future expansion */
#define	R_386_IRELATIVE		42	/* GNU/Linux specific (STT_GNU_IFUNC) */

  Rainer
Comment 2 H.J. Lu 2018-02-07 20:12:46 UTC
These TLS transitions should be disabled for Solaris.
Does Solaris support Linux TLS relocations without
TLS transitions?
Comment 3 Rainer Orth 2018-02-07 20:18:51 UTC
> --- Comment #2 from H.J. Lu <hjl.tools at gmail dot com> ---
> These TLS transitions should be disabled for Solaris.
> Does Solaris support Linux TLS relocations without
> TLS transitions?

The full docs on what Solaris does support wrt. relocs is here:

https://docs.oracle.com/cd/E37838_01/html/E36783/chapter6-54839.html#scrolltoc

And there's also a section on TLS:

https://docs.oracle.com/cd/E37838_01/html/E36783/man-tlsam.html#scrolltoc
Comment 4 H.J. Lu 2018-02-07 22:22:18 UTC
I don't think ld supports Solaris/x86 TLS.
Comment 5 Rainer Orth 2018-02-07 22:28:19 UTC
I don't think it needs to: gcc is careful only to emit those tls relocs
that the whole toolchain (assembler + linker) can handle.  See
TARGET_SUN_TLS, HAVE_AS_IX86_TLSLDMPLT, and HAVE_AS_IX86_TLSGDPLT.  So
far gcc bootstraps with gas and gld work just fine: this is one of the
first cases where gld emits relocs Solaris ld.so.1 cannot handle.
Comment 6 H.J. Lu 2018-02-07 23:08:45 UTC
(In reply to Rainer Orth from comment #5)
> I don't think it needs to: gcc is careful only to emit those tls relocs
> that the whole toolchain (assembler + linker) can handle.  See
> TARGET_SUN_TLS, HAVE_AS_IX86_TLSLDMPLT, and HAVE_AS_IX86_TLSGDPLT.  So
> far gcc bootstraps with gas and gld work just fine: this is one of the
> first cases where gld emits relocs Solaris ld.so.1 cannot handle.

Please provide one separate testcase in assembly code for each instance
where ld creates dynamic relocs Solaris ld.so.1 cannot handle.
Comment 7 Rainer Orth 2018-02-08 12:40:33 UTC
> --- Comment #6 from H.J. Lu <hjl.tools at gmail dot com> ---
[...]
> Please provide one separate testcase in assembly code for each instance
> where ld creates dynamic relocs Solaris ld.so.1 cannot handle.

I'm trying, but I have a hard time even for the case at hand:

There's not only one, but a couple of those relocs in cc1:

Relocation Section:  .rel.dyn
   index  type                offset     value  section      symbol
[...]
   [189]  R_386_UNKNOWN37  0x9c79cf4         0  .got         __gmpfr_emin
   [390]  R_386_UNKNOWN37  0x9c7a01c         0  .got         __gmpfr_default_rounding_mode
   [430]  R_386_UNKNOWN37  0x9c7a0bc         0  .got         __gmpfr_cache_const_log2
   [432]  R_386_UNKNOWN37  0x9c7a0c4         0  .got         __gmpfr_flags
   [546]  R_386_UNKNOWN37  0x9c7a28c         0  .got         __gmpfr_cache_const_catalan
  [1069]  R_386_UNKNOWN37  0x9c7aab8         0  .got         __gmpfr_cache_const_euler
  [1225]  R_386_UNKNOWN37  0x9c7ad28         0  .got         __gmpfr_emax
  [1330]  R_386_UNKNOWN37  0x9c7aecc         0  .got         __gmpfr_default_fp_bit_precision
  [1467]  R_386_UNKNOWN37  0x9c7b0f0         0  .got         __gmpfr_cache_const_pi

The definitions are from libmpfr.a (built with --disable-shared
--with-pic), e.g.

   [22]      0   0x4  TLS  GLOB  D    0 .tbss          __gmpfr_flags

In the gld-linked cc1, I find

Symbol Table Section:  .dynsym
   [5850]       0x6c     0x4  TLS  GLOB  D    1 .tbss             __gmpfr_flags

Global Offset Table Section:  .got
   [584]  0x9c7a0c4         0  R_386_UNKNOWN37     __gmpfr_flags

Relocation Section:  .rel.dyn
   [432]  R_386_UNKNOWN37  0x9c7a0c4         0  .got         __gmpfr_flags

while in the ld-linked cc1, there is only:

Symbol Table Section:  .dynsym
   [14735]       0x6c     0x4  TLS  GLOB  D    1 .tbss            __gmpfr_flags

The toolchains are otherwise identical, both using gas 2.30 with either
Solaris ld or gld 2.30, both trees configured with --enable-host-shared,
no (relevant) differences in auto-host.h.

In the ld-linked cc1, there are no got entries for __gmpfr_* symbols at
all.

So far, I've not managed to create a testcase from this.
Comment 8 H.J. Lu 2018-02-08 22:24:22 UTC
Does it look like a testcase?

[hjl@gnu-bdx-1 solaris-1]$ cat x.c
extern __thread int __gmpfr_flags;

int
_start (void)
{
  return __gmpfr_flags;
}
[hjl@gnu-bdx-1 solaris-1]$ cat y.c
__thread int __gmpfr_flags;
[hjl@gnu-bdx-1 solaris-1]$ make
gcc -m32 -fPIC   -c -o x.o x.c
gcc -m32 -fPIC   -c -o y.o y.c
./ld -m elf_i386_sol2 -shared -o y.so y.o
./ld -m elf_i386_sol2 -o x x.o y.so
readelf -r x

Relocation section '.rel.dyn' at offset 0x224 contains 1 entry:
 Offset     Info    Type            Sym.Value  Sym. Name
08049338  00000225 R_386_TLS_TPOFF32 00000000   __gmpfr_flags
[hjl@gnu-bdx-1 solaris-1]$
Comment 9 H.J. Lu 2018-02-08 23:13:50 UTC
There are many Linux TLS tests under ld/testsuite/ld-i386.  But they run
only for Linux targets.  Please figure out:

1. Which TLS code sequences are also generated by Solaris GCC.
2. Among them, which TLS transitions for Linux should be disabled
for Solaris.
Comment 10 Rainer Orth 2018-02-09 17:01:58 UTC
As a first step, I've enabled ld-i386/tls.exp and ld-x86_64/tls.exp on
Solaris/x86 and ran the respective tests.  The x86_64 tests all PASS,
while for i386 I see the known failure case:

FAIL: TLS GD/LD -> IE transition without PLT

Running: tmpdir/tls-1d > tmpdir/tls-1d.out
ld.so.1: tls-1d: fatal: relocation error: R_386_UNKNOWN37: file tmpdir/tls-1d: symbol gd: offset size (0 bytes) is not supported

FAIL: TLS GD/LD -> IE transition without PLT (-z now)

same error
Comment 11 H.J. Lu 2018-02-10 13:16:13 UTC
Created attachment 10801 [details]
A patch

Please try this.
Comment 12 Rainer Orth 2018-02-11 19:39:43 UTC
While it fixes the two failing ld testcases, during a gcc mainline
bootstrap I get man errors:

FAIL: gcc.dg/pr47793.c (test for excess errors)
Excess errors:
/vol/gcc/bin/gld-2.30.51-tls: BFD (GNU Binutils) 2.30.51.20180211 internal error, aborting at /vol/src/gnu/binutils/binutils/local/bfd/elf32-i386.c:3169 in elf_i386_relocate_section

The ld invocation boils down to

ld -m elf_i386_sol2 -o ./pr47793.exe /usr/lib/crt1.o pr47793.o -lgcov -lgcc -lc
Comment 13 Rainer Orth 2018-02-11 19:40:31 UTC
Created attachment 10807 [details]
assembler output
Comment 14 H.J. Lu 2018-02-11 20:02:16 UTC
(In reply to Rainer Orth from comment #12)
> While it fixes the two failing ld testcases, during a gcc mainline
> bootstrap I get man errors:
> 
> FAIL: gcc.dg/pr47793.c (test for excess errors)
> Excess errors:
> /vol/gcc/bin/gld-2.30.51-tls: BFD (GNU Binutils) 2.30.51.20180211 internal
> error, aborting at
> /vol/src/gnu/binutils/binutils/local/bfd/elf32-i386.c:3169 in
> elf_i386_relocate_section
> 
> The ld invocation boils down to
> 
> ld -m elf_i386_sol2 -o ./pr47793.exe /usr/lib/crt1.o pr47793.o -lgcov -lgcc
> -lc

Please provide all linker inputs so that I
can reproduce i it on Linux.
Comment 15 Rainer Orth 2018-02-12 14:34:56 UTC
> --- Comment #14 from H.J. Lu <hjl.tools at gmail dot com> ---
[...]
> Please provide all linker inputs so that I
> can reproduce i it on Linux.

Now available at

	https://www.cebitec.uni-bielefeld.de/~ro/files/pr13671.tar.bz2
Comment 16 H.J. Lu 2018-02-13 00:19:51 UTC
[hjl@gnu-6 solaris-1]$ cat dummy.s
	.text
	.global _start
_start:
	movl	foo@indntpoff, %eax
	.globl	bar
	.type	bar, @function
bar:
	leal	foo@tlsgd(,%ebx,1), %eax
	call	___tls_get_addr@PLT
	movl	(%eax), %eax
	.globl	foo
	.section	.tbss,"awT",@nobits
	.align 4
	.type	foo, @object
	.size	foo, 4
foo:
	.zero	4
[hjl@gnu-6 solaris-1]$ gcc -c -m32 dummy.s
[hjl@gnu-6 solaris-1]$ ./ld -m elf_i386_sol2   dummy.o 
./ld: BFD (GNU Binutils) 2.30.51.20180212 internal error, aborting at /export/gnu/import/git/sources/binutils-gdb/bfd/elf32-i386.c:3169 in elf_i386_relocate_section

./ld: Please report this bug.

[hjl@gnu-6 solaris-1]$ ld -m elf_i386   dummy.o 
[hjl@gnu-6 solaris-1]$
Comment 17 H.J. Lu 2018-02-13 00:45:53 UTC
Please try users/hjl/solaris branch at

https://github.com/hjl-tools/binutils-gdb
Comment 18 Rainer Orth 2018-02-14 14:01:34 UTC
> --- Comment #17 from H.J. Lu <hjl.tools at gmail dot com> ---
> Please try users/hjl/solaris branch at
>
> https://github.com/hjl-tools/binutils-gdb

Any reason not to keep that branch in the binutils-git repo on
sourceware?  That's where I looked initially, confusing the hell out of
me ;-)

Fortunately, a lot of failures are gone, but still a couple remain, all
from g++.dg/tree-prof and gcc.dg/tree-prof tests, which SEGV, e.g.

FAIL: gcc.dg/tree-prof/crossmodule-indircall-1.c execution,    -fprofile-generate -D_PROFILE_GENERATE

Thread 2 received signal SIGSEGV, Segmentation fault.
[Switching to Thread 1 (LWP 1)]
0x080491c9 in __gcov_indirect_call_profiler_v2 (value=151663852, 
    cur_func=0x8048f10 <add>)
    at /vol/gcc/src/hg/trunk/local/libgcc/libgcov-profiler.c:335
335       if (cur_func == __gcov_indirect_call_callee
=> 0x8049019 <__gcov_indirect_call_profiler_v2+41>:     cmp    %edx,(%eax)
(gdb) p/x $eax
$1 = 0x66caa44

That address is indeed unmapped and below the text segment.

(gdb) where
#0  0x080491c9 in __gcov_indirect_call_profiler_v2 (value=151663852, 
    cur_func=0x8048f10 <add>)
    at /vol/gcc/src/hg/trunk/local/libgcc/libgcov-profiler.c:335
#1  0x08048f41 in add ()
#2  0x08048e5c in main ()

elfdump -r complains about the executable:

crossmodule-indircall-1.x01: bad relocation entry: R_386_TLS_TPOFF: relocation requires symbol
crossmodule-indircall-1.x01: bad relocation entry: R_386_TLS_TPOFF: relocation requires symbol

    [3]  R_386_TLS_TPOFF  0x804d22c       0x4  .got    
    [4]  R_386_TLS_TPOFF  0x804d230         0  .got    
   [11]  R_386_JMP_SLOT   0x804d1c8 0x80489f6  .got    ___tls_get_addr

It happens even when I build without -flto:

$ ld -m elf_i386_sol2 -o crossmodule-indircall-1.x01 /usr/lib/crt1.o crossmodule-indircall-1.o crossmodule-indircall-1a.o -lm -lgcov -lgcc -lc /usr/lib/crtn.o

Input files at

	https://www.cebitec.uni-bielefeld.de/~ro/files/crossmodule-indircall-1.tar.bz2
Comment 19 H.J. Lu 2018-02-14 14:18:30 UTC
(In reply to Rainer Orth from comment #18)
> > --- Comment #17 from H.J. Lu <hjl.tools at gmail dot com> ---
> > Please try users/hjl/solaris branch at
> >
> > https://github.com/hjl-tools/binutils-gdb
> 
> Any reason not to keep that branch in the binutils-git repo on
> sourceware?  That's where I looked initially, confusing the hell out of
> me ;-)

It is easier to update a branch on github.

> Fortunately, a lot of failures are gone, but still a couple remain, all
> from g++.dg/tree-prof and gcc.dg/tree-prof tests, which SEGV, e.g.
> 
> FAIL: gcc.dg/tree-prof/crossmodule-indircall-1.c execution,   
> -fprofile-generate -D_PROFILE_GENERATE
> 
> Thread 2 received signal SIGSEGV, Segmentation fault.
> [Switching to Thread 1 (LWP 1)]
> 0x080491c9 in __gcov_indirect_call_profiler_v2 (value=151663852, 
>     cur_func=0x8048f10 <add>)
>     at /vol/gcc/src/hg/trunk/local/libgcc/libgcov-profiler.c:335
> 335       if (cur_func == __gcov_indirect_call_callee
> => 0x8049019 <__gcov_indirect_call_profiler_v2+41>:     cmp    %edx,(%eax)
> (gdb) p/x $eax
> $1 = 0x66caa44
> 
> That address is indeed unmapped and below the text segment.
> 
> (gdb) where
> #0  0x080491c9 in __gcov_indirect_call_profiler_v2 (value=151663852, 
>     cur_func=0x8048f10 <add>)
>     at /vol/gcc/src/hg/trunk/local/libgcc/libgcov-profiler.c:335
> #1  0x08048f41 in add ()
> #2  0x08048e5c in main ()
> 
> elfdump -r complains about the executable:
> 
> crossmodule-indircall-1.x01: bad relocation entry: R_386_TLS_TPOFF:
> relocation requires symbol
> crossmodule-indircall-1.x01: bad relocation entry: R_386_TLS_TPOFF:
> relocation requires symbol

What doe Solaris ld generate?

>     [3]  R_386_TLS_TPOFF  0x804d22c       0x4  .got    
>     [4]  R_386_TLS_TPOFF  0x804d230         0  .got    
>    [11]  R_386_JMP_SLOT   0x804d1c8 0x80489f6  .got    ___tls_get_addr
> 
> It happens even when I build without -flto:
> 
> $ ld -m elf_i386_sol2 -o crossmodule-indircall-1.x01 /usr/lib/crt1.o
> crossmodule-indircall-1.o crossmodule-indircall-1a.o -lm -lgcov -lgcc -lc
> /usr/lib/crtn.o
> 
> Input files at
> 
> 	https://www.cebitec.uni-bielefeld.de/~ro/files/crossmodule-indircall-1.tar.
> bz2
Comment 20 Rainer Orth 2018-02-14 14:46:46 UTC
> --- Comment #19 from H.J. Lu <hjl.tools at gmail dot com> ---
[...]

> What doe Solaris ld generate?

Here are the initial sections of with either linker:

* gas-gld:

08048ff0 <__gcov_indirect_call_profiler_v2>:
 8048ff0:       55                      push   %ebp
 8048ff1:       89 e5                   mov    %esp,%ebp
 8048ff3:       57                      push   %edi
 8048ff4:       56                      push   %esi
 8048ff5:       53                      push   %ebx
 8048ff6:       e8 8d ff ff ff          call   8048f88 <__x86.get_pc_thunk.bx>
 8048ffb:       81 c3 99 3f 00 00       add    $0x3f99,%ebx
 8049001:       83 ec 1c                sub    $0x1c,%esp
 8049004:       8b 7d 08                mov    0x8(%ebp),%edi
 8049007:       8b 75 0c                mov    0xc(%ebp),%esi
 804900a:       65 a1 00 00 00 00       mov    %gs:0x0,%eax
 8049010:       03 83 8c 00 00 00       add    0x8c(%ebx),%eax
 8049016:       8b 55 10                mov    0x10(%ebp),%edx
 8049019:       39 10                   cmp    %edx,(%eax)

* gas-ld:

08052230 <__gcov_indirect_call_profiler_v2>:
 8052230:       55                      push   %ebp
 8052231:       89 e5                   mov    %esp,%ebp
 8052233:       57                      push   %edi
 8052234:       56                      push   %esi
 8052235:       53                      push   %ebx
 8052236:       e8 6e fb ff ff          call   8051da9 <__x86.get_pc_thunk.bx>
 805223b:       81 c3 4d 2b 01 00       add    $0x12b4d,%ebx
 8052241:       83 ec 1c                sub    $0x1c,%esp
 8052244:       8b 7d 08                mov    0x8(%ebp),%edi
 8052247:       8b 75 0c                mov    0xc(%ebp),%esi
 805224a:       65 a1 00 00 00 00       mov    %gs:0x0,%eax
 8052250:       05 fc ff ff ff          add    $0xfffffffc,%eax
 8052255:       90                      nop
 8052256:       8b 55 10                mov    0x10(%ebp),%edx
 8052259:       39 10                   cmp    %edx,(%eax)

The full executable is at

	https://www.cebitec.uni-bielefeld.de/~ro/files/crossmodule-indircall-1-ld.tar.bz2
Comment 21 H.J. Lu 2018-02-14 18:34:00 UTC
(In reply to Rainer Orth from comment #20)

> The full executable is at
> 
> 	https://www.cebitec.uni-bielefeld.de/~ro/files/crossmodule-indircall-1-ld.
> tar.bz2

I didn't see R_386_TLS_TPOFF.  What happened to

00000030  00000b12 R_386_TLS_GD           00000004   __gcov_indirect_call_callee

in input file?
Comment 22 Rainer Orth 2018-02-15 10:15:48 UTC
> --- Comment #21 from H.J. Lu <hjl.tools at gmail dot com> ---
[...]
> I didn't see R_386_TLS_TPOFF.  What happened to
>
> 00000030  00000b12 R_386_TLS_GD           00000004  __gcov_indirect_call_callee
>
> in input file?

This:

_gcov_indirect_call_profiler_v2.o has

  1a:   8d 04 1d 00 00 00 00    lea    0x0(,%ebx,1),%eax
  21:   e8 fc ff ff ff          call   22 <__gcov_indirect_call_profiler_v2+0x22>

with the R_386_TLS_GD reloc above; the executable has

 805224a:       65 a1 00 00 00 00       mov    %gs:0x0,%eax
 8052250:       05 fc ff ff ff          add    $0xfffffffc,%eax
 8052255:       90                      nop

without any relocs.

Btw., please note that I'll be on an extended vacation starting
tomorrow, with little or no net access for a month.
Comment 23 H.J. Lu 2018-02-17 17:45:17 UTC
I updated users/hjl/solaris branch.  But I have no idea if elf_i386_tpoff
is correct for Solaris.
Comment 24 Rainer Orth 2023-01-10 15:22:47 UTC
Sorry for dropping the ball on this one for so long.

However, some time ago the issue broke the gcc trunk build with D included since
d21 didn't run due to the unsupported reloc.

I've now refreshed your patch and had to make two amendements:

When linking GCC's gcc.dg/torture/tls/run-ie.c without and with -fPIC, the assertion would fire in two cases that seem legit:

* r_type = R_386_TLS_IE, r_type_tls = R_386_TLS_LE
* r_type = R_386_TLS_GOTIE, r_type_tls =  R_386_TLS_LE

If I let those two in, the gcc bootstrap finishes successfully and the testsuite
run shows no regressions compared to a gas/ld build.
Comment 25 Rainer Orth 2023-01-10 15:24:13 UTC
Created attachment 14568 [details]
Augmented patch
Comment 26 H.J. Lu 2023-01-10 20:38:06 UTC
(In reply to Rainer Orth from comment #25)
> Created attachment 14568 [details]
> Augmented patch

@@ -2853,9 +2866,18 @@ elf_i386_relocate_section (bfd *output_b
 					 relend, h, r_symndx, true))
 	    return false;
 
-	  if (r_type_tls == R_386_TLS_LE_32)
+	  if (r_type_tls == R_386_TLS_LE_32
+	      || (r_type_tls == R_386_TLS_LE
+		  && htab->elf.target_os == is_solaris))

Please add and check "expected_tls_le".
 	    {
-	      BFD_ASSERT (! unresolved_reloc);
+	      /* NB: Solaris only supports R_386_TLS_GD->R_386_TLS_LE.  */
+	      BFD_ASSERT (! unresolved_reloc
+			  && (htab->elf.target_os != is_solaris
+			      || (htab->elf.target_os == is_solaris
+				  && (r_type == R_386_TLS_GD
+				      || r_type == R_386_TLS_IE
+				      || r_type == R_386_TLS_GOTIE)
+				  && r_type_tls == R_386_TLS_LE)));

No need to check R_386_TLS_LE here with "expected_tls_le".
Comment 27 Rainer Orth 2023-01-11 14:34:01 UTC
Created attachment 14577 [details]
Augmented patch, incorporating review comments

Like so?  I wonder if it would be possible to move the declaration of
expected_tls_le to its use.  Given that binutils now requires C99, that would
certainly be clearer, but differ in style from the rest of the file.

Tested on i386-pc-solaris2.11 and i686-pc-linux-gnu as well as a full all-languages
gcc bootstrap.

As an additional experiment, I've enabled ld-i386/tls.exp on Solaris/x86.  Before
this patch, only two tests FAIL:

FAIL: TLS GD/LD -> IE transition without PLT
FAIL: TLS GD/LD -> IE transition without PLT (-z now)

The error is the expected

Running: tmpdir/tls-1d > tmpdir/tls-1d.out
ld.so.1: tls-1d: fatal: relocation error: R_386_UNKNOWN37: file tmpdir/tls-1d: symbol gd: offset size (0 bytes) is not supported

With the patch, those two tests continue to FAIL.  However, the error is different:

/var/gcc/binutils/i386/obj/binutils-2.40-branch-local/ld/tmpdir/ld/collect-ld: warning: /usr/lib/crtn.o: missing .note.GNU-stack section implies executable stack
/var/gcc/binutils/i386/obj/binutils-2.40-branch-local/ld/tmpdir/ld/collect-ld: NOTE: This behaviour is deprecated and will be removed in a future version of the linker
/var/gcc/binutils/i386/obj/binutils-2.40-branch-local/ld/tmpdir/ld/collect-ld: BFD (GNU Binutils) 2.39.90.20230111 assertion fail /vol/src/gnu/binutils/hg/binutils-2.40-branch/local/bfd/elf32-i386.c:3377
/var/gcc/binutils/i386/obj/binutils-2.40-branch-local/ld/tmpdir/ld/collect-ld: BFD (GNU Binutils) 2.39.90.20230111 assertion fail /vol/src/gnu/binutils/hg/binutils-2.40-branch/local/bfd/elf32-i386.c:3377
/var/gcc/binutils/i386/obj/binutils-2.40-branch-local/ld/tmpdir/ld/collect-ld: BFD (GNU Binutils) 2.39.90.20230111 assertion fail /vol/src/gnu/binutils/hg/binutils-2.40-branch/local/bfd/elf32-i386.c:3377
collect2: error: ld returned 1 exit status

On top of that, there are four new failures

+FAIL: TLS GD/LD -> LE transition without PLT (dynamic)
+FAIL: TLS GD/LD -> LE transition without PLT (dynamic, -z now)
+FAIL: TLS GD/LD -> LE transition without PLT (PIE)
+FAIL: TLS GD/LD -> LE transition without PLT (PIE, -z now)

which show the same error.
Comment 28 H.J. Lu 2023-01-12 18:31:46 UTC
(In reply to Rainer Orth from comment #27)
> Created attachment 14577 [details]
> Augmented patch, incorporating review comments

expected_tls_le should be unsigned int.   The check will be

if (r_type_tls == expected_tls_le)

> Like so?  I wonder if it would be possible to move the declaration of
> expected_tls_le to its use.  Given that binutils now requires C99, that would
> certainly be clearer, but differ in style from the rest of the file.
> 
> Tested on i386-pc-solaris2.11 and i686-pc-linux-gnu as well as a full
> all-languages
> gcc bootstrap.
> 
> As an additional experiment, I've enabled ld-i386/tls.exp on Solaris/x86. 
> Before
> this patch, only two tests FAIL:
> 
> FAIL: TLS GD/LD -> IE transition without PLT
> FAIL: TLS GD/LD -> IE transition without PLT (-z now)
> 
> The error is the expected
> 
> Running: tmpdir/tls-1d > tmpdir/tls-1d.out
> ld.so.1: tls-1d: fatal: relocation error: R_386_UNKNOWN37: file
> tmpdir/tls-1d: symbol gd: offset size (0 bytes) is not supported
> 
> With the patch, those two tests continue to FAIL.  However, the error is
> different:
> 
> /var/gcc/binutils/i386/obj/binutils-2.40-branch-local/ld/tmpdir/ld/collect-
> ld: warning: /usr/lib/crtn.o: missing .note.GNU-stack section implies
> executable stack
> /var/gcc/binutils/i386/obj/binutils-2.40-branch-local/ld/tmpdir/ld/collect-
> ld: NOTE: This behaviour is deprecated and will be removed in a future
> version of the linker
> /var/gcc/binutils/i386/obj/binutils-2.40-branch-local/ld/tmpdir/ld/collect-
> ld: BFD (GNU Binutils) 2.39.90.20230111 assertion fail
> /vol/src/gnu/binutils/hg/binutils-2.40-branch/local/bfd/elf32-i386.c:3377
> /var/gcc/binutils/i386/obj/binutils-2.40-branch-local/ld/tmpdir/ld/collect-
> ld: BFD (GNU Binutils) 2.39.90.20230111 assertion fail
> /vol/src/gnu/binutils/hg/binutils-2.40-branch/local/bfd/elf32-i386.c:3377
> /var/gcc/binutils/i386/obj/binutils-2.40-branch-local/ld/tmpdir/ld/collect-
> ld: BFD (GNU Binutils) 2.39.90.20230111 assertion fail
> /vol/src/gnu/binutils/hg/binutils-2.40-branch/local/bfd/elf32-i386.c:3377
> collect2: error: ld returned 1 exit status
> 
> On top of that, there are four new failures
> 
> +FAIL: TLS GD/LD -> LE transition without PLT (dynamic)
> +FAIL: TLS GD/LD -> LE transition without PLT (dynamic, -z now)
> +FAIL: TLS GD/LD -> LE transition without PLT (PIE)
> +FAIL: TLS GD/LD -> LE transition without PLT (PIE, -z now)
> 
> which show the same error.

So TLS doesn't work for Solaris.
Comment 29 Rainer Orth 2023-01-13 12:23:44 UTC
Created attachment 14590 [details]
Augmented^2 patch
Comment 30 Rainer Orth 2023-01-13 12:27:44 UTC
(In reply to H.J. Lu from comment #28)
> (In reply to Rainer Orth from comment #27)
> > Created attachment 14577 [details]
> > Augmented patch, incorporating review comments
> 
> expected_tls_le should be unsigned int.   The check will be
> 
> if (r_type_tls == expected_tls_le)

Ah, I misunderstood.  Patch updated.

> > /var/gcc/binutils/i386/obj/binutils-2.40-branch-local/ld/tmpdir/ld/collect-
> > ld: BFD (GNU Binutils) 2.39.90.20230111 assertion fail
> > /vol/src/gnu/binutils/hg/binutils-2.40-branch/local/bfd/elf32-i386.c:3377
> > collect2: error: ld returned 1 exit status
> > 
> > On top of that, there are four new failures
> > 
> > +FAIL: TLS GD/LD -> LE transition without PLT (dynamic)
> > +FAIL: TLS GD/LD -> LE transition without PLT (dynamic, -z now)
> > +FAIL: TLS GD/LD -> LE transition without PLT (PIE)
> > +FAIL: TLS GD/LD -> LE transition without PLT (PIE, -z now)
> > 
> > which show the same error.
> 
> So TLS doesn't work for Solaris.

I don't think so.  On the contrary, I'd expect an assertion

	      BFD_ASSERT (r_type == R_386_TLS_LE_32)'

to trigger on Solaris with a patch whose primary purpose is to avoid the emission
of R_386_TLS_LE_32.  I've adjusted the assertion to

	      BFD_ASSERT (r_type == expected_tls_le);

and now (with ld-i386/tls.exp enabled on Solaris), all those tests PASS there
and still do on Linux/i686.
Comment 31 H.J. Lu 2023-01-16 19:38:43 UTC
(In reply to Rainer Orth from comment #29)
> Created attachment 14590 [details]
> Augmented^2 patch

LGTM.  Please send it to the binutils mailing list.  Thanks.
Comment 32 Rainer Orth 2023-01-17 11:26:38 UTC
(In reply to H.J. Lu from comment #31)
> (In reply to Rainer Orth from comment #29)
> > Created attachment 14590 [details]
> > Augmented^2 patch
> 
> LGTM.  Please send it to the binutils mailing list.  Thanks.

Done now.  Thanks a lot for the fix and your patience.
Comment 33 Sourceware Commits 2023-01-19 21:55:17 UTC
The master branch has been updated by H.J. Lu <hjl@sourceware.org>:

https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=1bb82b89ae9d884016e55f2ade99c74fcc92a581

commit 1bb82b89ae9d884016e55f2ade99c74fcc92a581
Author: Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE>
Date:   Thu Jan 19 13:48:58 2023 -0800

    i386: Don't emit unsupported TLS relocs on Solaris
    
    Emit R_386_TLS_LE and R_386_TLS_IE, instead of R_386_TLS_LE_32 and
    R_386_TLS_IE_32, on Solaris.
    
            PR ld/13671
            * elf32-i386.c (elf_i386_tls_transition): Only emit R_386_TLS_LE,
            R_386_TLS_IE on Solaris.
            (elf_i386_relocate_section): Only use R_386_TLS_GD->R_386_TLS_LE
            transition on Solaris.
    
    Co-Authored-By: H.J. Lu <hjl.tools@gmail.com>
Comment 34 Rainer Orth 2023-01-20 08:11:40 UTC
Fixed for binutils 2.41.