Skip to content

Incompatibility in Inline TLS Assembly on Alpine 3.22 with zend_jit_ir.c #18743

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
thecaliskan opened this issue Jun 3, 2025 · 4 comments · May be fixed by #18779
Open

Incompatibility in Inline TLS Assembly on Alpine 3.22 with zend_jit_ir.c #18743

thecaliskan opened this issue Jun 3, 2025 · 4 comments · May be fixed by #18779

Comments

@thecaliskan
Copy link

thecaliskan commented Jun 3, 2025

Description

When building PHP on Alpine Linux 3.22 with musl and targeting 32-bit or 64-bit x86 platforms, a regression is observed related to inline assembly in ext/opcache/jit/zend_jit_ir.c, specifically:

This error does not occur on Alpine 3.21 using the same compilation toolchain. The issue stems from the @TLSGD usage which implicitly expects %rdi on x86_64 or %eax on i386, depending on the TLS model.

ext/opcache/jit/zend_jit_ir.c:3459: Error: @TLSGD operator requires %rdi' as dest register`

Environment

  • Alpine Linux 3.22
  • GCC (via build-base)
  • musl libc
  • Target: x86_64 or i386
  • Affected file: ext/opcache/jit/zend_jit_ir.c

Related PR / Reference

PHP Version

8.4.7-zts
8.3.21-zts
8.2.28-zts
8.1.32-zts

Operating System

Alpine 3.22

@arnaud-lb
Copy link
Member

Thank you for reporting this. This is the same root cause as #15074 (see #15074 (comment)), and will be fixed by #18660 (specifically ba04798).

@nielsdos
Copy link
Member

nielsdos commented Jun 3, 2025

@arnaud-lb But this can be fixed on lower branches, and I think we should.
For this particular issue the following suffices (on PHP-8.3) (but would need to generalise to other platforms too ofc as we would need to change other code paths with the same assembly too):

diff --git a/ext/opcache/jit/zend_jit_x86.dasc b/ext/opcache/jit/zend_jit_x86.dasc
index 1f1abb59a1c..6ea8521ba6d 100644
--- a/ext/opcache/jit/zend_jit_x86.dasc
+++ b/ext/opcache/jit/zend_jit_x86.dasc
@@ -2910,7 +2910,7 @@ static int zend_jit_setup(void)
 
 		__asm__(
 			"leaq _tsrm_ls_cache@tlsgd(%%rip), %0\n"
-			: "=a" (ti));
+			: "=D" (ti));
 		tsrm_tls_offset = ti[1];
 		tsrm_tls_index = ti[0] * 8;
 #elif defined(__FreeBSD__)

@arnaud-lb
Copy link
Member

@nielsdos I agree, and it's great that there is a simpler fix, as ba04798 felt a bit risky for release branches.

The change you propose looks good to me. We don't need to use the entire code sequence as in ba04798, because gas is only checking a single instruction, and ld will only check the entire sequence when building opcache statically, which is not allowed in release branches.

Glibc seems unaffected as we use @gottpoff, for which gas doesn't check the destination register: https://github.com/bminor/binutils-gdb/blob/ec181e1710e37007a8d95c284609bfaa5868d086/gas/config/tc-i386.c#L6869

Do you want to take care of this or shall I?

@nielsdos
Copy link
Member

nielsdos commented Jun 5, 2025

Thanks for the link, I'm on it.

nielsdos added a commit to nielsdos/php-src that referenced this issue Jun 5, 2025
GAS started checking the relocation for tlsgd: it must use the %rdi
register. However, the inline assembly now uses %rax instead.
Fix it by changing the "=a" output register to "=D".
Source: https://github.com/bminor/binutils-gdb/blob/ec181e1710e37007a8d95c284609bfaa5868d086/gas/config/tc-i386.c#L6793

gottpoff is unaffected.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants