1

Win64 プラットフォーム用のパスカル ユニットをコンパイルしようとすると、エラーが発生します。メソッドには ASM ブロックが含まれています。Win64 プラットフォームで動作させる方法がわかりません:

方法 1:

Function TSparseList.ForAll( ApplyFunction: Pointer {TSPAApply} ): Integer; Assembler;
Asm
        MOV     EAX,[EAX].TSparseList.FList
        JMP     TSparsePointerArray.ForAll
End;

方法 2:

Function TSparsePointerArray.ForAll( ApplyFunction: Pointer {TSPAApply} ):
  Integer;
Var
  itemP: PAnsiChar; { Pointer to item in section } { patched by ccy }
  item: Pointer;
  i, callerBP: Cardinal;
  j, index: Integer;
Begin
  { Scan section directory and scan each section that exists,
    calling the apply function for each non-nil item.
    The apply function must be a far local function in the scope of
    the procedure P calling ForAll.  The trick of setting up the stack
    frame (taken from TurboVision's TCollection.ForEach) allows the
    apply function access to P's arguments and local variables and,
    if P is a method, the instance variables and methods of P's class '}
  Result := 0;
  i := 0;
  Asm
    mov   eax,[ebp]                     { Set up stack frame for local }
    mov   callerBP,eax
  End;
  While ( i < slotsInDir ) And ( Result = 0 ) Do
  Begin
    itemP := secDir^[i];
    If itemP <> Nil Then
    Begin
      j := 0;
      index := i Shl SecShift;
      While ( j < FSectionSize ) And ( Result = 0 ) Do
      Begin
        item := PPointer( itemP )^;
        If item <> Nil Then
          { ret := ApplyFunction(index, item.Ptr); }
          Asm
            mov   eax,index
            mov   edx,item
            push  callerBP
            call  ApplyFunction
            pop   ecx
            mov   @Result,eax
          End;
        Inc( itemP, SizeOf( Pointer ) );
        Inc( j );
        Inc( index )
      End
    End;
    Inc( i )
  End;
End;
4

3 に答える 3

8

私は x64 命令の詳細に精通していないので、アセンブリ コードを 64 ビットをサポートするように書き直すことはできませんが、Embarcadero の 64 ビット コンパイラでは現在、Pascal とアセンブリを混在させることはできません。同じ機能で。すべて Pascal またはすべてアセンブリの関数のみを記述でき、混合はまったくできません (Pascal 関数はアセンブリ関数を呼び出すことができ、その逆も可能ですが、x86 のように共存することはできません)。したがって、メソッドを書き直す必要があります。

于 2011-12-06T03:33:11.563 に答える
6

x64ASMでメソッド全体を書き直すことができる場合があります。asm .. endRemyが言ったように、内にいくつかのブロックをネストできないため、メソッド全体を書き直す必要がありますbegin .. end

本当の問題は、呼び出し規約がWin32モードとWin64モードで同じではないということです。レジスターは変更されます(つまり、64ビットでSSE2レジスターが含まれるようになります)が、主な問題は、呼び出し再インジェクターがパラメーターの数を認識しているという事実です。パラメーターごとにスタックにスペースを割り当てる必要があります。

関数TSPAApplyに多数の固定パラメーターがある場合は、それをプレーンパスカルバージョンに変換できます。これは、すべてよりも安全です。

type
  TSPAApply = function(index: integer; item: pointer);

Function TSparseList.ForAll( ApplyFunction: Pointer {TSPAApply} ): Integer; 
begin
  result := FList.ForAll(ApplyFunction);
End;

Function TSparsePointerArray.ForAll( ApplyFunction: Pointer {TSPAApply} ):
  Integer;
Var
  itemP: PPointer; 
  i: Cardinal;
  j, index: Integer;
Begin
  Result := 0;
  i := 0;
  While ( i < slotsInDir ) And ( Result = 0 ) Do
  Begin
    itemP := secDir^[i];
    If itemP <> Nil Then
    Begin
      j := 0;
      index := i Shl SecShift;
      While ( j < FSectionSize ) And ( Result = 0 ) Do
      Begin
        If itemP^ <> Nil Then
          result := TSPAApply(ApplyFunction)(index,itemP^.Ptr);
        Inc( itemP );
        Inc( j );
        Inc( index )
      End
    End;
    Inc( i )
  End;
End;

TMethodただし、より一般的なOOPの方法として、リストに依存することをお勧めします。ここでは、コードのリファクタリングを行うことをお勧めします。

于 2011-12-06T06:17:58.033 に答える
1

試す

Function TSparseList.ForAll( ApplyFunction: Pointer {TSPAApply} ): Integer; Assembler;
Asm
        MOV     RAX,[RAX].TSparseList.FList
        JMP     TSparsePointerArray.ForAll
End;

ポインタは x64 では 64 ビットであるため、64 ビット レジスタ全体を占有します。「A」レジスタは、それぞれ 8/16/32/64 ビットの AL/AX/EAX/RAX です。

2 番目の関数については、asm ブロックで呼び出されている関数について詳しく知る必要があります。

于 2012-01-18T13:56:48.710 に答える