Question

When I attempt to compile a pascal unit for Win64 platform, I encounter errors. The methods contain ASM block. I have no ideas how to make it works for Win64 platform:

Method 1:

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

Method 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;
Was it helpful?

Solution

I'm not familiar with the particulars of x64 instructions, so I can't help with rewriting the assembly code to support 64-bit, but I can tell you that Embarcadero's 64-bit compiler does not currently allow you to mix Pascal and Assembly in the same function. You can only write all-Pascal or all-Assembly functions, no mixing at all (a Pascal function can call an Assembly function and vice versa, but they cannot coexist together like in x86). So you will have to rewrite your methods.

OTHER TIPS

You may be able to rewrite the whole method in x64 ASM. As Remy told, you'll need to rewrite the whole method, since you can't nest some asm .. end blocks within begin .. end.

The real issue is that calling conventions are not the same in Win32 and Win64 mode. Registers changes (i.e. they are 64 bit and now shall include SSE2 registers), but the main problem is about the fact that your call re-injector shall know the number of parameters: some space must be allocated on the stack for every parameter.

If your TSPAApply function has a number of fixed parameters, you could convert it to a plain pascal version - which is safer than everything.

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;

But you should better rely on a TMethod list, for a more generic OOP way of doing it. Some code refactoring would be a good idea, here.

Try

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

Pointers are 64-bit on x64, so will occupy a full 64-bit register. The "A" register is AL/AX/EAX/RAX for 8/16/32/64-bits respectively.

For the second function, I'd need to know more about the function being called in the asm block.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top