Delphi asm to purepascal

I am trying to port my Delphi 5 code to Delphi XE7-WIN64 and I am facing a mixed assembly code issue in the next block. Also I am new to asm.

procedure IterateMenus(Func: Pointer; Menu1, Menu2: TElMenuItem);
var
  I, J: Integer;
  IIndex, JIndex: Byte;
  Menu1Size, Menu2Size: Integer;
  Done: Boolean;

  function Iterate(var I: Integer; MenuItem: TElMenuItem; AFunc: Pointer): Boolean;
  var
    Item: TMenuItem;
  begin
    if MenuItem = nil then Exit;
    Result := False;
    while not Result and (I < MenuItem.Count) do
    begin
      Item := MenuItem[I];
      if Item.GroupIndex > IIndex then Break;
      asm
        MOV     EAX,Item
        MOV     EDX,[EBP+8]
        PUSH    DWORD PTR [EDX]
        CALL    DWORD PTR AFunc
        ADD     ESP,4
        MOV     Result,AL
      end;
      Inc(I);
    end;
  end;

begin
  I := 0;
  J := 0;
  Menu1Size := 0;
  Menu2Size := 0;
  if Menu1 <> nil then
    Menu1Size := Menu1.Count;
  if Menu2 <> nil then
    Menu2Size := Menu2.Count;
  Done := False;
  while not Done and ((I < Menu1Size) or (J < Menu2Size)) do
  begin
    IIndex := High(Byte);
    JIndex := High(Byte);
    if (I < Menu1Size) then
      IIndex := Menu1[I].GroupIndex;
    if (J < Menu2Size) then
      JIndex := Menu2[J].GroupIndex;
    if IIndex <= JIndex then
      Done := Iterate(I, Menu1, Func)
    else
    begin
      IIndex := JIndex;
      Done := Iterate(J, Menu2, Func);
    end;
    while (I < Menu1Size) and (Menu1[I].GroupIndex <= IIndex) do
      Inc(I);
    while (J < Menu2Size) and (Menu2[J].GroupIndex <= IIndex) do
      Inc(J);
  end;
end;

      

I am trying to convert an asm block to purepascal since delphi x64 does not allow mixed code and asm is not programmable.

As I understand it, the address of the element is moved to EAX, Then I get nothing. Where did EBP come from? What are ESP and AL? The above code snippet is from ELmenus.pas by ELPack.

So what will be the PurePascal version of the asm codeblock?

For func I found this

procedure TElMenuItem.UpdateItems;

  function UpdateItem(MenuItem: TElMenuItem): Boolean;
  begin
    Result := False;
    IterateMenus(@UpdateItem, MenuItem.FMerged, MenuItem);
    MenuItem.SubItemChanged(MenuItem, MenuItem, True);
  end;

begin
  IterateMenus(@UpdateItem, FMerged, Self);
end;

procedure TElMenuItem.PopulateMenu;
var
  MenuRightToLeft: Boolean;

  function AddIn(MenuItem: TElMenuItem): Boolean;
  begin
    MenuItem.AppendTo(FHandle, MenuRightToLeft);
    Result := False;
  end;

begin    // all menu items use BiDiMode of their root menu
  {$ifdef VCL_4_USED}
  MenuRightToLeft := (FMenu <> nil) and FMenu.IsRightToLeft;
  {$else}
  MenuRightToLeft := false;
  {$endif}
  IterateMenus(@AddIn, FMerged, Self);
end;

      

+3


source to share


2 answers


I'm guessing the original programmer wrote weird code to get around Delphi not supporting local function pointers. (This is a limitation that annoyed me sometimes.)

The following should work. (Although I'm not sharp enough with my asm to be sure. I first checked the asm code by going through the debugger in D5 to confirm that the string was CALL DWORD PTR AFunc

passing the values ​​I expect.)

1) Delcare, introduce a function pointer and move the UpdateItem so that it is no longer local.

type
  TMenuOperation = function (AMenuItem: TElMenuItem): Boolean;
  //Or if you want to move the UpdateItem to a method of a class..
  //TMenuOperation = function (AMenuItem: TElMenuItem): Boolean of object;

      



2) Make the following changes:

procedure IterateMenus(Func: Pointer; Menu1, Menu2: TElMenuItem);
//becomes
procedure IterateMenus(Func: TMenuOperation; Menu1, Menu2: TElMenuItem);

//...

  function Iterate(var I: Integer; MenuItem: TElMenuItem; AFunc: Pointer): Boolean;
  var
    Item: TMenuItem;
  //becomes
  function Iterate(var I: Integer; MenuItem: TElMenuItem; AFunc: TMenuOperation): Boolean;
  var
    Item: TElMenuItem;

  //...

      Item := MenuItem[I];
      //becomes
      Item := MenuItem[I] as TElMenuItem;

      

3) Finally, the assembler block will become:

Result := AFunc(Item);

      

+4


source


This asm code calls a method on Item

. I would say that whoever wrote the code needs a review. It's like they don't know about method pointers.

The way I'll go about doing this is to look for the code that calls the function and see what is passed as an argument Func

. This is what is called by the block asm

. Change the argument type Func

to the appropriate procedural type and replace the block with a asm

call to this method pointer.


OK, now I can see the source code is playing fast and fluently with local procedures. You have to make the Func

type of the anonymous method:



Func: TFunc<TElMenuItem, Boolean>;

      

Then convert the local functions to anonymous ones.


A common approach to updating Delphi versions is to update third-party libraries at the same time. If you did, I guess you wouldn't need to port the 15 year old library code.

+3


source







All Articles