https://gcc.gnu.org/bugzilla/show_bug.cgi?id=125084

--- Comment #1 from JingYao Zhang <220245569 at seu dot edu.cn> ---
Gentle ping on this issue. To make this easier to review without unpacking the
attachment, we re-verified this on current GCC 16.2 / 17 trunk
(x86_64-linux-gnu) and pinpointed the exact root cause and 1-line fix:

### Root Cause in `gcc/config/i386/predicates.md`

In `ix86_endbr_immediate_operand` (`gcc/config/i386/predicates.md`), the 64-bit
scan loop currently checks whole-word equality (`imm == val`):

```c
  if (TARGET_LP64)
    {
      unsigned HOST_WIDE_INT imm = UINTVAL (op);
      unsigned HOST_WIDE_INT val = TARGET_64BIT ? 0xfa1e0ff3 : 0xfb1e0ff3;
      for (; imm >= val; imm >>= 8)
        if (imm == val)
          return true;
      return false;
    }
```

Because `imm == val` compares the entire remaining 64-bit word against the
32-bit `val` (`0xfa1e0ff3`, little-endian `f3 0f 1e fa`), any 64-bit immediate
that contains `f3 0f 1e fa` at byte offset `k` AND has any non-zero byte at
offset `>= k + 4` (for example `0x1fa1e0ff3abULL`) keeps `imm > val` at the
matching shift position and returns `false`. As a result,
`ix86_cannot_force_const_mem` does not spill the constant to `.rodata`, and
`movabsq $0x1fa1e0ff3ab, %rax` emits an unintended `endbr64` (`f3 0f 1e fa`) at
`movabs + 3` in `.text`.

### Proposed Fix

Masking `imm` to 32 bits at each byte step (both in the `TARGET_LP64` loop and
the 32-bit loop below it):

```c
      for (; imm >= val; imm >>= 8)
        if ((imm & 0xffffffffULL) == val)
          return true;
```

ensures that embedded `ENDBR64`/`ENDBR32` byte sequences are detected
regardless of whether upper bytes are non-zero. Please let us know if you would
like us to send this patch to `gcc-patches`.

Reply via email to