[Bug target/93704] New: SPARC GCC emits R_SPARC_TLS_GD_CALL code not understood by Solaris linker
vita.batrla at gmail dot com
gcc-bugzilla@gcc.gnu.org
Wed Feb 12 12:18:00 GMT 2020
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=93704
Bug ID: 93704
Summary: SPARC GCC emits R_SPARC_TLS_GD_CALL code not
understood by Solaris linker
Product: gcc
Version: 9.2.0
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: target
Assignee: unassigned at gcc dot gnu.org
Reporter: vita.batrla at gmail dot com
Target Milestone: ---
In the ELF Handling for Thread-Local Storage document [1] in section 4.1.3
SPARC General Dynamic TLS Model on page 20-21, following code sequence is
defined for GD relocations:
General Dynamic Model Code Sequence Initial Relocation Symbol
0x00 sethi %hi(@dtlndx(x)), %o0 R_SPARC_TLS_GD_HI22 x
0x04 add %o0,%lo(@dtlndx(x)), %o0 R_SPARC_TLS_GD_LO10 x
0x08 add %l7,%o0, %o0 R_SPARC_TLS_GD_ADD x
0x0c call __tls_get_addr R_SPARC_TLS_GD_CALL x
With comment:
> The code sequence must appear in the code as is. It is not possible to move
> the second add instruction in the delay slot of the call instruction since
> the linker would not recognize the instruction sequence. (2)
and note (2):
> This is at least what Sun’s documentation says and apparently how Sun’s
> linker works. Given the relocations which show exactly what the instructions
> do this seems not really necessary.
However, GCC 7/9 emits this sequence in .o file:
2c: 11 00 00 00 sethi %hi(0), %o0
2c: R_SPARC_TLS_GD_HI22 __gcov_indirect_call_callee
30: 90 02 20 00 add %o0, 0, %o0 ! 0 <main>
30: R_SPARC_TLS_GD_LO10 __gcov_indirect_call_callee
34: 40 00 00 00 call 34 <main+0x34>
34: R_SPARC_TLS_GD_CALL __gcov_indirect_call_callee
38: 90 05 c0 08 add %l7, %o0, %o0
38: R_SPARC_TLS_GD_ADD __gcov_indirect_call_callee
It is apparent that the compiler generated the GD TLS sequence in different
order than the TLS document suggests. It placed the second add instruction in
the branch delay slot of call instruction, which is against the document
statement:
"It is not possible to move the second add instruction in the delay slot of the
call instruction"
This relaxed order generated by GCC is no doubt more efficient, however, it is
not understood by Solaris linker, which converts the call instruction during
GD->IE transition to add instruction: 'add %g7, %o0, %o0' (opcode: 90 01 c0
08). The problem is that the original instruction in branch delay slot was
supposed to execute before instruction on branch target (it calculates input
argument for call instruction target), but after it is converted to add
instruction, branch is gone and so is its delay slot and instructions execute
in program order. This corrupts value in %o0 register as both instructions
write to it but execute in different than originally supposed order and
corrupted %o0 causes SIGSEGV (if lucky) in subsequent attempt to use it in
memory de-reference to get value of a TLS variable.
More information about the Gcc-bugs
mailing list