Here's my version, for both x86 and x64:
function GetCPUID: TCPUID;
asm
{$IF Defined(CPUX86)}
push ebx
push edi
mov edi, eax
mov eax, 1
xor ecx,ecx
cpuid
mov [edi+$0], eax
mov [edi+$4], ebx
mov [edi+$8], ecx
mov [edi+$c], edx
pop edi
pop ebx
{$ELSEIF Defined(CPUX64)}
mov r8, rbx
mov r9, rcx
mov eax, 1
cpuid
mov [r9+$0], eax
mov [r9+$4], ebx
mov [r9+$8], ecx
mov [r9+$c], edx
mov rbx, r8
{$IFEND}
end;
One of the nice things about x64 is that there are a lot more registers available, many of which are volatile. So we can make use of that scratch space and avoid touching main memory at all. Well obviously we have to touch main memory to return the result.
Since RBX is nonvolatile we preserve its value. All the other registers that we modify are volatile and so we need not preserve them. I can't think of any way to simplify this further.
This can readily be extended to allow the input to CPUID
to be passed as an argument:
function GetCPUID(ID: Integer): TCPUID;
asm
{$IF Defined(CPUX86)}
push ebx
push edi
mov edi, edx
xor ecx,ecx
cpuid
mov [edi+$0], eax
mov [edi+$4], ebx
mov [edi+$8], ecx
mov [edi+$c], edx
pop edi
pop ebx
{$ELSEIF Defined(CPUX64)}
mov r8, rbx
mov r9, rcx
mov eax, edx
cpuid
mov [r9+$0], eax
mov [r9+$4], ebx
mov [r9+$8], ecx
mov [r9+$c], edx
mov rbx, r8
{$ELSE}
{$Message Fatal 'GetCPUID has not been implemented for this architecture.'}
{$IFEND}
end;
This assumes a sub-leaf value of 0, passed in ECX. Again, if you wish to pass that, it is easy enough:
function GetCPUID(Leaf, Subleaf: Integer): TCPUID;
asm
{$IF Defined(CPUX86)}
push ebx
push edi
mov edi, ecx
mov ecx, edx
cpuid
mov [edi+$0], eax
mov [edi+$4], ebx
mov [edi+$8], ecx
mov [edi+$c], edx
pop edi
pop ebx
{$ELSEIF Defined(CPUX64)}
mov r9,rcx
mov ecx,r8d
mov r8,rbx
mov eax,edx
cpuid
mov [r9+$0], eax
mov [r9+$4], ebx
mov [r9+$8], ecx
mov [r9+$c], edx
mov rbx, r8
{$ELSE}
{$Message Fatal 'GetCPUID has not been implemented for this architecture.'}
{$IFEND}
end;