当我尝试为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;
答案 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块中调用的函数的信息。