Skip to content

Replace the ioctl generation pipeline with bindgen clang_macro_fallback#182

Open
zRedShift wants to merge 3 commits into
sunfishcode:mainfrom
zRedShift:clang-macro-fallback
Open

Replace the ioctl generation pipeline with bindgen clang_macro_fallback#182
zRedShift wants to merge 3 commits into
sunfishcode:mainfrom
zRedShift:clang-macro-fallback

Conversation

@zRedShift
Copy link
Copy Markdown

@zRedShift zRedShift commented Mar 16, 2026

Replace the ioctl generation pipeline with bindgen clang_macro_fallback

This removes the old gen/ioctl/generate.sh + list.c path and generates ioctl constants directly through bindgen.

The old setup depended on cross-compilers, qemu, and a hand-maintained ioctl list. The new one keeps everything in the normal bindgen flow by letting clang evaluate _IO/_IOR/_IOW/_IOWR macros during generation.

What changed

gen/modules/ioctl.h now includes the relevant UAPI headers directly.

For the ioctl module, bindgen runs twice:

  • once normally, which gives the plain #define constants
  • once with clang_macro_fallback(), which also evaluates function-like macros

The difference between those two outputs tells us which constants came from macro expansion. Those results are then filtered so we keep actual ioctls and drop the obvious non-ioctl fallout.

The generated ioctl names are also used as the blocklist for the other modules, replacing the old generated.txt.

For m68k, the ioctl bindgen pass uses a small ABI shim so Clang matches GCC/Linux m68k layout for plain __u64 and __s64, while preserving Linux's explicit __aligned_u64 alignment.

Output changes

Compared to the currently shipped bindings:

  • no existing exported ioctl names are dropped
  • each architecture picks up a few hundred additional ioctls that were never listed in list.c
  • sparc, sparc64, and hexagon now get generated ioctl bindings instead of none
  • x32 gets 180 corrected values because the old pipeline used x86_64 layout assumptions
  • m68k keeps GCC-compatible values for existing exported ioctls and now gains the additional ioctls found through macro fallback

There are also four compatibility definitions kept in gen/include/ioctl-addendum.h:

  • REISERFS_IOC_UNPACK
  • CM_IOCGATR
  • CM_IOSDBGLVL
  • MEYEIOC_SYNC

These came from headers that are no longer present in current kernel UAPI, but they were part of previously shipped bindings because the old generated ioctl.h had their values baked in. Keeping them here preserves the existing crate API.

Breaking changes

This should be released as 0.13.0.

Known breaking changes:

  • FIEMAP_MAX_OFFSET becomes i32 instead of u32 on 32-bit architectures. The bit pattern is unchanged, but the Rust type changes.
  • SIOCGSTAMP_OLD and SIOCGSTAMPNS_OLD move from net to ioctl
  • on mips, TIOCGETP, TIOCGLTC, TIOCSETN, TIOCSETP, and TIOCSLTC move from general to ioctl

Stub headers

A few minimal libc stubs were added under gen/include/ for -nostdinc generation:

  • sys/types.h
  • sys/time.h
  • sys/socket.h
  • empty stubs for stdlib.h, string.h, and sys/ioctl.h

Validation

I compared the generated ioctl exports against the currently shipped bindings to catch accidental removals and checked the expected value changes on x32.

For m68k, I built a local C-only m68k-linux-gnu GCC and validated the ioctl constants with compile-time assertions against Linux v6.17 installed headers. This caught the Clang m68k unsigned long long alignment mismatch; the final shim keeps GCC-compatible plain __u64/__s64 layout without breaking explicit __aligned_u64 ioctls such as KCOV_REMOTE_ENABLE and PPPIOCGL2TPSTATS.

I also regenerated the bindings with system libclang and ran the host Rust checks for the general/ioctl feature combinations. A local m68k-unknown-linux-gnu -Zbuild-std Rust target check is currently blocked by a nightly rustc/LLVM crash while compiling compiler_builtins, before this crate is built.

Replace the generate.sh + list.c cross-compilation pipeline with
bindgen's clang_macro_fallback feature. This eliminates the need for
cross-compilers, qemu, and pre-generated ioctl text files.

A two-pass approach (with and without fallback) identifies function-like
macro results, which are then filtered by name prefix and value range to
separate real ioctls from non-ioctl macros (v4l2_fourcc, BLK_TC_ACT, etc.).
Object-like constants use plain prefix matching for legacy ioctl families.

Fixes x32 and m68k ioctl values that had incorrect struct sizes in the
old pipeline. Adds ~200-300 new ioctls per arch, and enables sparc and
hexagon which previously had no ioctl support.
@zRedShift zRedShift force-pushed the clang-macro-fallback branch from db0f4a7 to 46ff54a Compare May 29, 2026 17:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant