6

私は問題があります。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;

私はアセンブリでプログラムしたことがありません.ポートがどうなるか、またはどのように変更するかを知っている人はいますか.

4

3 に答える 3

10

私は Win64 アセンブラーの第一人者ではありませんが、次の翻訳はうまくいきました (64 ビット フリー パスカルでテスト済み)。

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.
于 2012-12-14T10:18:10.777 に答える
6

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;

x64の優れた点の1つは、使用可能なレジスタがはるかに多く、その多くが揮発性であるということです。したがって、そのスクラッチスペースを利用して、メインメモリにまったく触れないようにすることができます。結果を返すには、明らかにメインメモリに触れる必要があります。

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;

これは、ECXで渡されるサブリーフ値0を想定しています。繰り返しますが、それを通過したい場合、それは十分に簡単です:

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;
于 2012-12-14T14:41:14.983 に答える
-1

私はCPUIDを使ったことがないので、それが何をするのかよくわかりません。しかし、常識とWikipedia(それらの情報源で十分であれば)からの私のアドバイスは次のとおりです。


1) 「アセンブラ」を削除してみてください。キーワード - 廃止され
ました 1.1) オプションで「登録」を削除します。- これはデフォルトであり、パラメーターなしの機能にはほとんど価値がありません。また、ウィキペディアによると、Win64 では効果がありません。

2) 可能であれば - これを のように言い換えてprocedure GetCID (out data: TCPUID);ください。関数が必要な場合 - inlinePascal でラッパーを作成したい - 定義を単純明快に保つためです。これは、作成者にとって良いアドバイスです。自動化されていないものは単純に保ち、シンタックス シュガーの自動化は Pascal に任せてください。特に、経験がなく、単純でないトリックで混乱し、壊れたコードを入力する可能性がある場合はなおさらです。キスの原則。

3) push ebx/pop ebx
を削除します。 3.1) push edi/popedi も削除すると思います。しかし、安全のために - 私はそれらをに変更しましpush rdipop rdi

この記事では、一部のレジスタを保存または保存 する必要があるとは述べていません/en/Assembly_Procedures_and_Functions

4) mov edi, eax-> mov rdi, rcx
4.1)cld追加の安全対策として、コマンドの後にコマンドを追加することができます。しかし、それは過度に慎重で冗長であるべきです。

x64にはx86モードと同じCPUIDの規則があるように見えるので、残りは同じである必要があります-http ://en.wikipedia.org/wiki/CPUID#EAX.3D1: _Processor_Info_and_Feature_Bitsでx64モードについて言及していません

要約すると、次のようになります

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;
于 2012-12-14T09:26:31.680 に答える