It turned out to be much easier. It’s enough to use curly braces to explicitly tell the compiler to use the specified registers. I’m not sure if this is a 100% guarantee, but it works for me.
asm volatile(
\\cpuid
: [a]"={eax}"(a),[b]"={ebx}"(b),[c]"={ecx}"(c),[d]"={edx}"(d)
: [id]"{eax}"(leaf)
);