Issue 149808
Summary Wrong stack adjustments around __tls_get_addr on SPARC
Labels new issue
Assignees
Reporter rorth
    On 64-bit Solaris/SPARC, several `libomp` testcases `FAIL` apparently randomly.  The failure mode is always the same: the tests `SEGV` like this:
```
Thread 58 received signal SIGSEGV, Segmentation fault.
[Switching to Thread 56 (LWP 56)]
0xffffffff7edcba04 in mmap () from /lib/64/libc.so.1
(gdb) 
(gdb) 
(gdb) bt
#0 0xffffffff7edcba04 in mmap () from /lib/64/libc.so.1
#1  0xffffffff7edae65c in lmalloc () from /lib/64/libc.so.1
Backtrace stopped: previous frame inner to this frame (corrupt stack?)
(gdb) display/i $pc
1: x/i $pc
=> 0xffffffff7edcba04 <mmap+16>:	bcs  0xffffffff7ecc8230 <_cerror>
 0xffffffff7edcba08 <mmap+20>:	nop 
```
This happens both in `Release` and `Debug` builds, but not in a 1-stage build with `gcc-14`.

It has turned out that `clang` has a bug with thread-local storage: in `libomp.so` there's
```
   c56b4:       9c 03 bf ff     add  %sp, -1, %sp
   c56b8: 33 00 00 01     sethi  %hi(0x400), %i1
   c56bc:       b2 06 62 c0 add  %i1, 0x2c0, %i1    ! 6c0 <_DYNAMIC+0x5a0>
   c56c0:       90 06 80 19 add  %i2, %i1, %o0
   c56c4:       40 04 9f bf     call  1ed5c0 <__tls_get_addr@plt>
   c56c8:       01 00 00 00     nop 
   c56cc: 9c 03 a0 01     inc  %sp
```
which creates an unaligned stack.  While Solaris `__tls_get_addr` in `libc` doesn't use `%sp` itself, it calls into `slow_tls_get_addr` which does, and also sometimes calls `lmalloc`.  The stack corruption also causes the broken backtrace above, which made investigating this difficult.

This is not an issue on Linux/sparc64 where `__tls_get_addr` lives in `ld-linux.so.2` and doesn't use `%sp` at all.

Similarly, all other `call`s in `__kmp_launch_worker` are also wrapped in similar stack adjustments.  However, those don't create unaligned stacks, e.g.
```
   c5754:       40 04 9e c3     call  1ed260 <__kmp_str_buf_print@plt>
   c5758:       94 10 00 19     mov  %i1, %o2
 c575c:       f8 5f 00 00     ldx  [ %i4 ], %i4
   c5760:       02 cf 00 07 brz  %i4, c577c <_ZL19__kmp_launch_workerPv+0x128>
   c5764:       9c 03 a0 30     add  %sp, 0x30, %sp
```
but always are by 48 bytes.

When building `libomp` with `gcc`, however, none of these adjustments occur, and neither do the `SEGV`s.

I could trace the 1-byte adjustments to `llvm/lib/Target/Sparc/SparcISelLowering.cpp` (`SparcTargetLowering::LowerGlobalTLSAddress`), which has
```
    Chain = DAG.getCALLSEQ_START(Chain, 1, 0, DL);
```
changing that to `... (Chain, 0, 0, DL)`, there aren't any 1-byte adjustments any longer and all supported `libomp` tests `PASS`.

However, those stack adjustments remain, but are clearly unnecessary.  I could trace them all the way back to
```
commit cb1dca602c436c80c6923e106c9a9d8fc2353e8c
Author: Venkatraman Govindaraju <venka...@cs.wisc.edu>
Date:   Sun Sep 22 06:48:52 2013 +0000

    [Sparc] Add support for TLS in sparc.
```
but could not patch submission other than the actual commit, so there's no justification whatsoever.  My knowledge of the backend is practically non-existant, so I'm at a loss how to get rid of those adjustments.

@koachan Any suggestions?
_______________________________________________
llvm-bugs mailing list
llvm-bugs@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-bugs

Reply via email to