https://gcc.gnu.org/bugzilla/show_bug.cgi?id=126290
Bug ID: 126290
Summary: x86-64 -fPIC drops `register asm` operands of an `asm`
when a `__thread` address is another operand
Product: gcc
Version: 17.0
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: rtl-optimization
Assignee: unassigned at gcc dot gnu.org
Reporter: ammarfaizi2 at gnuweeb dot org
Target Milestone: ---
When an inline assembly statement uses local register variables alongside a
thread-local (`__thread`) variable in PIC, GCC generates an implicit call to
`__tls_get_addr`. This hidden function call clobbers the specifically assigned
registers, passing garbage values to the assembly block.
Godbolt Link: https://godbolt.org/z/T7xdET554
-------------------------------------------
Reproducer:
```
#define _GNU_SOURCE
#include <sys/socket.h>
static long __recvfrom(int fd, void *buf, size_t len, int flags,
struct sockaddr *src_addr, socklen_t *addrlen)
{
register long r10 __asm__("r10") = flags;
register struct sockaddr *r8 __asm__("r8") = src_addr;
register socklen_t *r9 __asm__("r9") = addrlen;
long ret = 45; /* __NR_recvfrom */
__asm__ volatile(
"syscall"
: "+a"(ret) /* %rax */
: "D"(fd), /* %rdi */
"S"(buf), /* %rsi */
"d"(len), /* %rdx */
"r"(r10),
"r"(r8),
"r"(r9)
: "rcx", "r11", "memory");
return ret;
}
long test(int fd, struct sockaddr *src_addr, socklen_t *addrlen)
{
static __thread char b1[8];
return __recvfrom(fd, b1, 8, MSG_PEEK, src_addr, addrlen);
}
```
-------------------------------------------
GCC (-O2 -fPIC), wrong. Notice the `call __tls_get_addr@PLT` occurs without
`%r10`, `%r8`, or `%r9` being loaded before the `syscall`.
```
test:
pushq %rbx
movl %edi, %ebx
leaq b1.0@tlsld(%rip), %rdi
call __tls_get_addr@PLT
movl $8, %edx
movl %ebx, %edi
leaq b1.0@dtpoff(%rax), %rsi
movl $45, %eax
syscall
popq %rbx
ret
b1.0:
.zero 8
```
-------------------------------------------
Clang (-O2 -fPIC), correct. Notice `%r10`, `%r8`, and `%r9` are safely loaded
after the `__tls_get_addr` call.
```
test:
pushq %rbp
pushq %r14
pushq %rbx
movq %rdx, %rbx
movq %rsi, %r14
movl %edi, %ebp
leaq test.b1@TLSLD(%rip), %rdi
callq __tls_get_addr@PLT
leaq test.b1@DTPOFF(%rax), %rsi
movl $8, %edx
movl $2, %r10d
movl $45, %eax
movq %r14, %r8
movq %rbx, %r9
movl %ebp, %edi
syscall
popq %rbx
popq %r14
popq %rbp
retq
test.b1:
.zero 8
```
-------------------------------------------