Borland Pascal incompatibility in calling of methods and local procedures lazarus / 62-General ---------------------------------------------------------------------- Avinash · 2021-05-19 11:52 In the mechanics of old programs using Turbo Vision there were calls to constructors, methods, and local functions through pointers. For this procedural types are used that explicitly include usually hidden parameters, such as frame and @Self pointers, which must be pushed onto the stack in the order the called procedures expects. While compiling the old code I found that the FPC does not follow the Borland Pascal calling convention (although it is described in the language manual), and it turns out that procedures expect a different order than the old code explicitly places parameters in. Suppose we have a constructor, a method, or a local procedure with three parameters, this is the order in which the variables will be passed to them. 1. Nested procedure  procedure Parent;    procedure Nested (A, B, C: Integer);    begin end;  begin    Nested(arg111, arg222, arg333);  end;                                   FPC                    FPC       Borland Pascal       {$CALLING PASCAL}      {$CALLING STDCALL}     ------------------    -------------------    --------------------        push  arg111           push  EBP              push  arg333        push  arg222           push  arg111           push  arg222        push  arg333           push  arg222           push  arg111        push  EBP              push  arg333           push  EBP        CALL  NESTED           CALL  NESTED           CALL  NESTED Nothing is compatible. The Free Pascal Programmer’s Guide claims on page 85 (without specifying the calling convention) that the frame pointer is passed last, just before the call. 2. Calling a constructor with three parameters:                                   FPC                    FPC       Borland Pascal       {$CALLING PASCAL}      {$CALLING STDCALL}     ------------------    -------------------    --------------------        push  arg111           push  SELF             push  arg333        push  arg222           push  VMT              push  arg222        push  arg333           push  arg111           push  arg111        push  VMT              push  arg222           push  VMT        push  SELF             push  arg333           push  SELF        CALL  CONSTRUCTOR      CALL  CONSTRUCTOR      CALL  CONSTRUCTOR 3. Calling a method of an object:                                   FPC                    FPC       Borland Pascal       {$CALLING PASCAL}      {$CALLING STDCALL}     ------------------    -------------------    --------------------        push  arg111           push  SELF             push  arg333        push  arg222           push  arg111           push  arg222        push  arg333           push  arg222           push  arg111        push  SELF             push  arg333           push  SELF        CALL  METHOD           CALL  METHOD           CALL  METHOD ---------------------------------------------------------------------- marcov · 2021-05-19 12:38 Last if your are right-to-left, iow the pseudo params are always first. Note that FPC also has IS NESTED to allow that construct without assembler. (though probably TV doesn't yet) ---------------------------------------------------------------------- PascalDragon · 2021-05-20 07:30 Quote from: Avinash on May 19, 2021, 01:52:56 pmIn the mechanics of old programs using Turbo Vision there were calls to constructors, methods, and local functions through pointers. For this procedural types are used that explicitly include usually hidden parameters, such as frame and @Self pointers, which must be pushed onto the stack in the order the called procedures expects. While compiling the old code I found that the FPC does not follow the Borland Pascal calling convention (although it is described in the language manual), and it turns out that procedures expect a different order than the old code explicitly places parameters in. Borland Pascal (in contrast to Turbo Pascal) is not considered a relevant target for compatibility. ---------------------------------------------------------------------- marcov · 2021-05-20 09:35 I think PascalDragon was thrown off by your "PUSH Ebp" in the BP column, thinking that BP was some 32-bit TP. I assume both the "push ebp" and PascalDragon's 32-bit assumption are minor mistakes. But yeah, we don't emulate TP's 16-bit calling conventions for nested functions on 32-bit Pascal.  Hidden parameters are generally hidden "first" parameters, not last. If you have a found a place in the documentation that says we do that, please file a bug for it. Also in general, calling conventions are generated more about what contemporary compilers (and ABIs) do and specify. For the FPC's 16-bit MSDOS target that might be different, but you'd have to ask the maintainer that, I'm not that deep into its details.