繁体   English   中英

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

[英]Delphi XE2: Convert a ASM method for Win64 platform

当我尝试为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和大会在相同的功能。 您只能编写全Pascal或所有Assembly函数,完全不能混合(Pascal函数可以调用Assembly函数,反之亦然,但是它们不能像x86中那样共存)。 因此,您将不得不重写您的方法。

您可能可以在x64 ASM中重写整个方法。 正如Remy所说,您将需要重写整个方法,因为您不能在begin .. end嵌套一些asm .. end块。

真正的问题是,在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;

但是,您最好依靠TMethod列表,以获得更通用的OOP方法。 在这里,一些代码重构将是一个好主意。

尝试

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块中被调用的功能。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM