1

当我尝试为 Win64 平台编译一个帕斯卡单元时,我遇到了错误。这些方法包含 ASM 块。我不知道如何使它适用于 Win64 平台:

方法一:

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

方法二:

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 和 Assembly在同一个函数中。您只能编写全 Pascal 或全汇编函数,根本不能混合(Pascal 函数可以调用汇编函数,反之亦然,但它们不能像 x86 那样共存)。所以你将不得不重写你的方法。

于 2011-12-06T03:33:11.563 回答
6

您也许可以在 x64 ASM 中重写整个方法。正如 Remy 所说,你需要重写整个方法,因为你不能asm .. endbegin .. 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。

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

于 2012-01-18T13:56:48.710 回答