移植汇编x86处理器的ID代码到AMD64(Porting Assembler x86 CPU ID

2019-08-04 02:24发布

我有个问题。 我有以下这是写在ASM x86的Delphi代码。 我需要端口这AMD64?

type
 TCPUID = array[1..4] of Longint;

function GetCID : TCPUID; assembler; register;
asm
  push  ebx
  push  edi
  mov   edi, eax
  mov   eax, 1
  dw    $A20F
  stosd
  mov   eax, ebx
  stosd
  mov   eax, ecx
  stosd
  mov   eax, edx
  stosd
  pop   edi
  pop   ebx
end;

我从来没有在装配程序,没有人知道是什么端口会或者我怎么会去改变它。

Answer 1:

我不是Win64的汇编大师,但接下来的翻译工作对我来说(在64位的Free Pascal测试):

program project1;

{$mode delphi}
{$asmmode intel}

type
 TCPUID = array[1..4] of Longint;

function GetCID: TCPUID;
asm
  push  rbx
  push  rdi
  mov   rdi, rcx
  mov   eax, 1
  cpuid
  mov   [rdi],eax
  add   rdi,4
  mov   [rdi],ebx
  add   rdi,4
  mov   [rdi],ecx
  add   rdi,4
  mov   [rdi],edx
  pop   rdi
  pop   rbx
end;

var ID: TCPUID;

begin
  ID:= GetCID;
  Writeln(ID[1], '-', ID[2], '-', ID[3], '-', ID[4]);
  Readln;
end.


Answer 2:

这里是我的版本,x86和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;

一个约64的好处之一是,有可用更大量的寄存器,其中有许多是挥发性的。 因此,我们可以利用该暂存空间,避免在所有触摸主内存。 嗯,显然我们必须触摸主内存返回结果。

由于RBX是非易失性的 ,我们保持它的价值。 所有这一切,我们修改其他寄存器易变,因此我们没有必要保留它们。 我想不出任何办法,进一步简化这一点。

这可以容易地扩展到允许输入到CPUID作为参数传递:

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;

这呈现为0的子叶值,在ECX通过。 同样,如果你想传递的是,这是很容易做到:

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;


Answer 3:

我从未与CPUID工作,所以我不知道肯定它做什么。 但是从常识和维基百科(如果这些资源就足够了),我的建议是:

尝试
1)删除 “汇编;” 关键字 - 过时
1.1)任选地除去“寄存器;” - 这是在默认情况下并具有无参数的功能没有什么价值。 维基百科也告诉在Win64中没有任何影响。

2)如果可能的话-改写这个作为procedure GetCID (out data: TCPUID); 。 如果需要的功能-我宁愿做inline帕斯卡尔包装-只是为了保持定义简单明了。 这就是创作一个很好的建议 - 让没有自动化的东西简单化,离开语法糖自动化帕斯卡,尤其是当你没有经验,没有任何简单的技巧可以迷惑你,使你键入断码。 KISS原则。

3)除去推EBX /弹出EBX
3.1)我认为推EDI / popedi被同时删除。 不过要论安全方面-我会改变他们push rdipop rdi

本文不告诉某些寄存器应该被保存或保存: http://en.wikipedia.org/wiki/X86_calling_conventions#x86-64_calling_conventions
也不是说要求是在告诉http://docwiki.embarcadero.com/RADStudio/XE3/en/Assembly_Procedures_and_Functions

4) mov edi, eax - > mov rdi, rcx
4.1),您可以添加cld后,接下来,它的命令,作为一个额外的安全措施。 但应该畏首畏尾和冗余。

其余的应该是相同的,因为它似乎64有CPUID为x86的模式相同的约定-没有mentio NOF 64位模式下http://en.wikipedia.org/wiki/CPUID#EAX.3D1:_Processor_Info_and_Feature_Bits

概括起来应该像

type
 TCPUID = packed array[1..4] of INT32;

function GetCID : TCPUID; inline;
begin
  GetCID_Implementation(Result);
end;

procedure GetCID_Implementation (out buffer: TCPUID);
asm
  mov   rdi, rcx  // mov edi, eax
  // RCX/EAX is Delphi/Windows pointer to 1st parameter
  // RDI/EDI is CPU pointer to output buffer

//  cld  - optionally, should not be needed
//  state of cld should be preserved by all other functions

  xor   eax, eax  // shorter way for eax := 1
  inc   eax

  dw    $A20F     // call CPUID(eax==1),
// output (according to wikipedia) is in eax,edx,ecx,ebx  32-bit registers

  stosd           // *( (INT32*)RDI )++ := eax
  mov   eax, ebx  // xchg eax, ebx would be shorter,on that
  stosd
  mov   eax, ecx  // but Delphi XE2 is broken with xchg eax
  stosd
  mov   eax, edx
  stosd
end;


文章来源: Porting Assembler x86 CPU ID code to AMD64