# DF-5597 — ioapic_irqinfo stride invariant (sizeof == 1<<IOAPIC_IRQI_SZSHIFT) is enforced only by a comment

## What

`genassym.c:276-277` emits BOTH stride facts into assym.s:

```c
ASSYM(IOAPIC_IRQI_SIZE, sizeof(struct ioapic_irqinfo));   /* compiler truth */
ASSYM(IOAPIC_IRQI_SZSHIFT, IOAPIC_IRQI_SZSHIFT);          /* hand constant  */
```

but nothing at build time relates them. The hand constant
(`sys/platform/pc64/apic/ioapic_abi.h:58`, `#define IOAPIC_IRQI_SZSHIFT 4`)
is guarded only by a comment (ioapic_abi.h:50-51: *"Keep size of
ioapic_irqinfo power of 2 / Update IOAPIC_IRQI_SZSHIFT after changing
ioapic_irqinfo size"*). There is no CTASSERT/_Static_assert anywhere in the
apic subsystem (verified by grep).

The two consumers use **different** facts of the same contract:

- `sys/platform/pc64/apic/ioapic_ipl.s:80,97` — `shll $IOAPIC_IRQI_SZSHIFT, %eax`
  (indexes `ioapic_irqs[]` with the hand constant)
- `sys/platform/pc64/apic/apic_vector.s:55-59` — `IOAPIC_IRQI_SIZE * (irq_num)
  + IOAPIC_IRQI_{ADDR,IDX,FLAGS}` (indexes with sizeof)

If a field is ever added to `struct ioapic_irqinfo` (the plausible future
edit: an owner-cpumask for IRQ balancing) and SZSHIFT is not bumped,
ioapic_ipl.s computes wrong element addresses for `ioapic_irqs[]` —
mask/unmask IMCR writes land on the wrong IOAPIC redirection entries —
while apic_vector.s stays correct. The build stays green; the divergence is
silent. (Today the invariant holds: live assym.s shows
`IOAPIC_IRQI_SIZE 0x10` == `1 << IOAPIC_IRQI_SZSHIFT 0x4`.)

## Reproduce

- `./run.sh` (after `cc`): `ioapic_drift.c` without -D → invariant HOLDS
  (16 == 16, matching the shipped kernel's assym.s);
  with `-DDRIFT` (one added `uint32_t` field) → 24 != 16, and the two
  assembly consumers would index the array differently (IRQ 100:
  offset 1600 vs 2400) — with **no build error today**.
- `guard_ok.c` / `guard_drift.c`: the proposed `_Static_assert` compiles
  clean on the current layout and **fails the build** on the drifted
  layout (`guard_drift.log`: `error: static assertion failed`).

## Fix

One `_Static_assert` in ioapic_abi.h right under the SZSHIFT define —
see `fix.diff`.
