## 1. GMP version and provenance

GMP **6.3.0** (reported by the `gmp` PHP extension via the `GMP_VERSION` macro).

**Prepackaged / patched: YES — this is a build-time-embedded GMP, statically linked into a third-party prebuilt PHP 8.5.0 binary.** I did NOT build GMP myself; it was compiled and statically linked by the software distributor (Beyond Code / php.new, the "herd-lite" static PHP builds). I cannot verify whether the distributor applied local patches to the GMP source; I have only the shipped static object. This is important: the GMP code appears to have been compiled with **ADX/BMI2 enabled at build time** in a manner that produces the ADX instruction stream, and the distributor's shipping configuration evidently does not gate this path on a runtime CPUID check (or the build enables it unconditionally for the target build machine's CPU).

## 2. Test program to reproduce the bug

Self-contained PHP script (uses only the bundled PHP `gmp` extension; no phpseclib or other library required):

```php
<?php
$a = gmp_init(str_repeat('12345678901234567890', 40), 10); // ~800 decimal digits
$b = gmp_init(str_repeat('98765432109876543210', 40), 10);
$r = gmp_mul($a, $b);
echo gmp_strval($r, 10), "\n";
```

**How to run:** with the affected static PHP binary (GMP 6.3.0 statically linked),

```
/path/to/php repro_gmp.php
```

and observe the result. On the affected machine this exits with:

```
Illegal instruction
(exit code 132 / killed by SIGILL)
```

Note: this tests the public `mpz_mul` path which reaches the low-level `mpn_mul` → `mpn_mul_basecase` → `mpn_mul_1` (vector×single-word) code that faults. GMP developers can reproduce the same fault with an equivalent C program using the public API:

```c
#include <gmp.h>
int main(void) {
    mpz_t a, r;
    mpz_inits(a, r, 0);
    mpz_set_str(a, "12345678901234567890...", 10); /* ~800+ digits to force the large path */
    mpz_mul(r, a, a);
    mpz_out_str(stdout, 10, r);
    mpz_clears(a, r, 0);
    return 0;
}
```
Compile with `gcc -O3 -o t t.c -lgmp` and run on the affected CPU.

*(I confirmed the exact fault with the shipped binary: `Illegal instruction`, exit 132.)*

## 3. What is wrong

This is a **crash**, not incorrect results. The process is killed by **SIGILL** while executing an **ADCX (ADX ISA) instruction in GMP's big-number multiply**, on a CPU that does not support the ADX extension.

The faulting instruction, seen at two addresses of the same GMP vector×single-word multiply (`mpn_mul_1`) routine family, is:

```
19dd420:  66 4d 0f 38 f6 c8    adcx   %r8,%r9        ; SIGILL here
19dff29:  66 4d 0f 38 f6 c3    adcx   %r11,%r8       ; (same routine family)
```

Surrounding code uses the BMI2 `mulx` instruction (which this CPU supports) and the ADX `adcx`/`adox` instructions (which this CPU does **not** support).

**Root cause:** The ADX code path was selected/compiled into the shipped binary even though the target CPU lacks the `adx` CPUID flag. GMP must select the ADX variants only after a positive runtime CPUID check for ADX, or the distributor's static build must be configured without ADX. On this CPU the mix (BMI2 present, ADX absent) is exactly what makes the fault reachable — plain `mulq` fallback would have been correct.

## 4. Backtrace

From GDB (the binary is stripped, so frames show raw addresses, but the unwind chain is informative — it goes GMP low-level multiply → PHP `gmp` extension → PHP Zend engine):

```
Program received signal SIGILL, Illegal instruction.
0x00000000019dd420 in ?? ()
#0  0x00000000019dd420 in ?? ()      ; mpn_mul_1 ADX loop (adcx %r8,%r9)
#1  0x00000000019e1fb7 in ?? ()      ; GMP multiply code region
#2  0x00000000019dbc02 in ?? ()      ; GMP multiply code region
#3  0x0000000000584402 in ?? ()      ; PHP gmp extension (gmp_mul)
#4  0x0000000000588786 in ?? ()
#5  0x0000000000ab41a1 in ?? ()
#6  0x0000000000ab2c50 in ?? ()
...
#10 0x00000000004445ac in ?? ()      ; PHP Zend engine
```

*(Per GMP's request I am not attaching the core dump, the executable, or a strace.)*

## 5. Configure options used to build GMP

**Not applicable / unavailable for my report.** I did not build GMP. It is statically embedded in a third-party PHP build, so I do not have the distributor's GMP `configure` invocation, and there is no `config.log`, `config.m4`, or `mpn/tmp-*.s` accessible to me. What I can state from inspection of the shipped binary:

- It was built for **x86_64** against a **musl** libc static toolchain (the PHP binary is `x86_64-linux-musl-gcc`, static, stripped).
- The GMP arithmetic object code **contains ADX (`adcx`/`adox`) and BMI2 (`mulx`) instruction streams**, i.e. an ADX-enabled code path was generated and shipped.
- The enabling must have assumed an ADX-capable CPU or failed to gate on runtime CPUID; the observed behavior indicates ADX instructions are reachable on this non-ADX CPU.

## 6. Output from `configure` (stdout)

Not available — GMP was not configured by me; it is embedded in a third-party binary. No configure output exists in my environment.

## 7. Compiler and version

The shipped GMP/PHP was compiled with the distributor's toolchain **`x86_64-linux-musl-gcc`** (version not disclosed by the binary). For reference, the local machine's compiler (not used for this GMP) is:

```
gcc version 13.3.0 (Ubuntu 13.3.0-6ubuntu2~24.04)
```

## 8. `uname -a`

```
Linux mmd 6.14.8-2-pve #1 SMP PREEMPT_DYNAMIC PMX 6.14.8-2 (2025-07-22T10:04Z) x86_64 x86_64 x86_64 GNU/Linux
```

## 9. `config.guess` / `configfsf.guess`

Not run — GMP was not built locally. For reference the machine self-identifies as `x86_64-pc-linux-gnu`-class.

## 10. Verify the CPU (the crux of the bug)

```
grep -m1 "model name" /proc/cpuinfo
  Intel(R) Core(TM) i7-4790 CPU @ 3.60GHz   (Haswell)

grep -m1 flags /proc/cpuinfo
  ... bmi1 bmi2 avx2 sse4_2 ...   (BMI2/MULX present)
  ... adx ...                     (ADX is ABSENT)
```

**Intel i7-4790 (Haswell) has BMI2 (so `mulx` is legal) but does NOT have ADX (so `adcx`/`adox` are illegal) — exactly the combination that trips this code path.**

---

## Summary for the GMP maintainers

GMP's ADX-based multiply is being executed on hardware that lacks ADX. Even though this surfaced through a third-party static PHP build, the underlying correctness concern is GMP's: **the ADX code path must only be selected/used when a runtime CPUID check confirms the `ADX` bit.** If the shipped configuration was supposed to enforce this, then the correct fix is to ensure ADX gating (or build without `-madx`/ADX) so that non-ADX CPUs like Haswell fall back to the plain `mulq` path rather than faulting.

---

*Reproducer script referenced in section 2 saved separately as `repro_gmp.php`.*

