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