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

时间:2011-12-06 03:21:44

标签: 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;

方法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;

3 个答案:

答案 0 :(得分:8)

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

答案 1 :(得分:6)

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

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

如果您的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方式。一些代码重构在这里是个好主意。

答案 2 :(得分: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。

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