Delphi XE2: convertir une méthode ASM pour la plate-forme Win64
-
28-10-2019 - |
Question
Lorsque j'essaye de compiler une unité pascal pour la plate-forme Win64, je rencontre des erreurs.Les méthodes contiennent un bloc ASM.Je n'ai aucune idée de comment le faire fonctionner pour la plate-forme Win64:
Méthode 1:
Function TSparseList.ForAll( ApplyFunction: Pointer {TSPAApply} ): Integer; Assembler;
Asm
MOV EAX,[EAX].TSparseList.FList
JMP TSparsePointerArray.ForAll
End;
Méthode 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;
La solution
Je ne connais pas les particularités des instructions x64, je ne peux donc pas m'empêcher de réécrire le code d'assemblage pour prendre en charge 64 bits, mais je peux vous dire que le compilateur 64 bits d'Embarcadero ne le fait pas vous permet actuellement de mélanger Pascal et Assembly dans la même fonction.Vous ne pouvez écrire que des fonctions tout-Pascal ou tout-assemblage, pas de mixage du tout (une fonction Pascal peut appeler une fonction Assembly et vice versa, mais elles ne peuvent pas coexister ensemble comme dans x86).Vous devrez donc réécrire vos méthodes.
Autres conseils
Vous pourrez peut-être réécrire toute la méthode en ASM x64.Comme Rémy l'a dit, vous devrez réécrire toute la méthode, car vous ne pouvez pas imbriquer certains blocs asm .. end
dans begin .. end
.
Le vrai problème est que les conventions d'appel ne sont pas les mêmes en mode Win32 et Win64.Les registres changent (c'est-à-dire qu'ils sont 64 bits et doivent maintenant inclure les registres SSE2), mais le problème principal est lié au fait que votre ré-injecteur d'appel connaîtra le nombre de paramètres: un espace doit être alloué sur la pile pour chaque paramètre.
Si votre fonction TSPAApply
a un certain nombre de paramètres fixes, vous pouvez la convertir en une version pascal simple - ce qui est plus sûr que tout.
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;
Mais vous devriez mieux vous fier à une liste TMethod
, pour une manière OOP plus générique de le faire.Une refactorisation du code serait une bonne idée, ici.
Essayez
Function TSparseList.ForAll( ApplyFunction: Pointer {TSPAApply} ): Integer; Assembler;
Asm
MOV RAX,[RAX].TSparseList.FList
JMP TSparsePointerArray.ForAll
End;
Les pointeurs sont 64 bits sur x64, ils occuperont donc un registre 64 bits complet. Le registre "A" est AL / AX / EAX / RAX pour 8/16/32/64 bits respectivement.
Pour la deuxième fonction, j'aurais besoin d'en savoir plus sur la fonction appelée dans le bloc asm.