Delphi XE2:为Win64平台转换ASM方法

Delphi XE2:为Win64平台转换ASM方法,delphi,delphi-xe2,win64,Delphi,Delphi Xe2,Win64,当我试图为Win64平台编译pascal单元时,我遇到了错误。这些方法包含ASM块。我不知道如何使其适用于Win64平台: 方法1: Function TSparseList.ForAll( ApplyFunction: Pointer {TSPAApply} ): Integer; Assembler; Asm MOV EAX,[EAX].TSparseList.FList JMP TSparsePointerArray.ForAll End;

当我试图为Win64平台编译pascal单元时,我遇到了错误。这些方法包含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;

我不熟悉x64指令的细节,因此我无法帮助重写汇编代码以支持64位,但我可以告诉您,Embarcadero的64位编译器目前不允许在同一个函数中混合使用Pascal和assembly。您只能编写所有Pascal或所有汇编函数,Pascal函数不能调用汇编函数,反之亦然,但它们不能像x86中那样共存。因此,您必须重写您的方法。

我不熟悉x64指令的细节,因此我无法帮助您重写汇编代码以支持64位,但我可以告诉您,Embarcadero的64位编译器目前不允许您在同一个函数中混合使用Pascal和assembly。您只能编写所有Pascal或所有汇编函数,Pascal函数不能调用汇编函数,反之亦然,但它们不能像x86中那样共存。因此,您必须重写您的方法。

您可以在x64 ASM中重写整个方法。正如Remy所说,您需要重写整个方法,因为您不能嵌套一些asm。。开始内的结束块。。结束

真正的问题是在Win32和Win64模式下调用约定不同。寄存器更改,即它们是64位的,现在应包括SSE2寄存器,但主要问题是您的调用重新注入器应知道参数的数量:必须在堆栈上为每个参数分配一些空间

如果你的TSPAApply函数有很多固定参数,你可以把它转换成一个普通的pascal版本,这比任何东西都安全

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;

但是,为了获得更通用的OOP方法,您最好依赖于TMethod列表。在这里进行一些代码重构是个好主意。

您可以在x64 ASM中重写整个方法。正如Remy所说,您需要重写整个方法,因为您不能嵌套一些asm。。开始内的结束块。。结束

真正的问题是在Win32和Win64模式下调用约定不同。寄存器更改,即它们是64位的,现在应包括SSE2寄存器,但主要问题是您的调用重新注入器应知道参数的数量:必须在堆栈上为每个参数分配一些空间

如果你的TSPAApply函数有很多固定参数,你可以把它转换成一个普通的pascal版本,这比任何东西都安全

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;
但是,为了获得更通用的OOP方法,您最好依赖于TMethod列表。在这里,一些代码重构是个好主意。

试试看

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

对于第二个函数,我需要了解更多有关asm块中调用的函数的信息。

试试看

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


对于第二个函数,我需要更多地了解在asm块中调用的函数。

值得注意的是,不能在同一个例程中混合使用asm和Pascal的主要原因是避免导致堆栈帧问题;它们在Win64上的要求要比在Win32上严格得多。因此,使用asm技巧设置假堆栈帧的代码可能是您无论如何都不想复制的。@MarcusAdams x86操作码在没有修改的情况下无法在x64上工作,如果您使用其中的一些指针。但是一些非常基本的32位代码可能在x64中工作,比如函数IncrementA:integer:integer;asm公司eax end;。但是周志阳的代码不起作用,因为它依赖于调用约定和指针。同样有趣的是,AFAIK的x64后端FPC能够在begin..end中嵌套asm块。对于一个自2006年以来支持x64的开源编译器来说还不错;我刚刚发现它很棒。值得注意的是,不能在同一个例程中混合使用ASM和Pascal的主要原因是避免造成堆栈帧问题;它们在Win64上的要求要比在Win32上严格得多。因此,使用asm技巧设置假堆栈帧的代码可能是您无论如何都不想复制的。@MarcusAdams x86操作码在没有修改的情况下无法在x64上工作,如果您使用其中的一些指针。但是一些非常基本的32位代码可能在x64中工作,比如函数IncrementA:integer:integer;asm公司eax end;。但是周志阳的代码不起作用,因为它依赖于调用约定和指针。同样有趣的是,AFAIK的x64后端FPC能够在begin..end中嵌套asm块。对于自2006年以来支持x64的开源编译器来说,这还不错
! ; 我刚刚发现,伟大的.Plain Pascal也更独立于平台。想想Firemonkey/FPC吧。@Chaucheyang当然,我并不是说它可以直接工作,因为我对你自己的代码知之甚少。这个TSPAApply函数原型是什么?它叫什么名字?什么意思不起作用?我给了你一些重新分解现有代码的想法。当您的源代码几乎没有输入时,我们无法创造奇迹。如果您使用匿名方法,您将能够像原始代码一样使用局部变量。它需要最新版本的Delphi编译器,即XE2。在本例中,您可以使用类似版本的纯pascal代码,纯pascal也更独立于平台。想想Firemonkey/FPC吧。@Chaucheyang当然,我并不是说它可以直接工作,因为我对你自己的代码知之甚少。这个TSPAApply函数原型是什么?它叫什么名字?什么意思不起作用?我给了你一些重新分解现有代码的想法。当您的源代码几乎没有输入时,我们无法创造奇迹。如果您使用匿名方法,您将能够像原始代码一样使用局部变量。它需要最新版本的Delphi编译器,即XE2。在本例中,您可以使用类似版本的纯pascal代码。