Recent

Author Topic: RET 4 at the end of nested assembler procedure of assembler procedure  (Read 3700 times)

Avinash

  • Full Member
  • ***
  • Posts: 117
I tried to use the FormatStr function from Virtual Pascal package. But it didn't work correctly. Its structure is simple:

Code: Pascal  [Select][+][-]
  1. -Mtp
  2. {$CALLING PASCAL}
  3.  
  4. procedure FormatStr(...); assembler;
  5.  
  6.   procedure Convert; assembler; nostackframe;
  7.   asm
  8.        ...
  9.        ...
  10.     @@Done:
  11.   end;
  12.  
  13. asm
  14.      ...
  15.      ...
  16.      Call  Convert
  17.      ...
  18.      ...
  19.   @@Done:
  20. end;
  21.  

Since the malfunction of the function itself is improbable, I tried to understand the reason by looking at the generated assembler sources (fpc -a -Anasmwin32). Ultimately, I realized that the problem was in the automatically generated RET 4 statement at the end of the nested procedure.
After I added «anticipating» RET in the source, everything began to work as it should:

Code: Pascal  [Select][+][-]
  1. -Mtp
  2. {$CALLING PASCAL}
  3.  
  4. procedure FormatStr(...); assembler;
  5.  
  6.   procedure Convert; assembler; nostackframe;
  7.   asm
  8.        ...
  9.        ...
  10.     @@Done:
  11.        RET
  12.   end;
  13.  
  14. asm
  15.      ...
  16.      ...
  17.      Call  Convert
  18.      ...
  19.      ...
  20.   @@Done:
  21. end;
  22.  

Apparently, FPC expects that the nested procedure always has a frame pointer parameter, but this cannot be the case in pure assembler procedures. This behavior is counterintuitive. You take a known working code, but it does not work.

Jonas Maebe

  • Hero Member
  • *****
  • Posts: 1058
Re: RET 4 at the end of nested assembler procedure of assembler procedure
« Reply #1 on: January 19, 2020, 01:16:16 pm »
Quote
This behavior is counterintuitive. You take a known working code, but it does not work.
The problem is that this kind of details are not documented anywhere by Borland/Codegear/Embarcadero afaik, so it is very hard to get them all exactly the same from the start. And once you implement them differently in a shipping release and then change them afterwards, you will probably start breaking other working code (code that was written for FPC according to the behaviour implemented in FPC, possibly even in mode Delphi).

If you know of a complete description of when exactly the frame pointer should be passed (and how) for each calling convention, please do share it. Fixing one part after the other means that every time you change a detail, you risk breaking code. So it's better to do it all at once.

Edit: although in this case, it may actually be a plain code generation bug, because the frame pointer should actually be removed by the calling routine and not the callee. So the code generator should indeed probably generate a plain "ret" there on exit.
« Last Edit: January 19, 2020, 02:08:45 pm by Jonas Maebe »

jamie

  • Hero Member
  • *****
  • Posts: 6077
Re: RET 4 at the end of nested assembler procedure of assembler procedure
« Reply #2 on: January 19, 2020, 03:41:13 pm »
This does remind me of an issue I had porting code from Delphi..

I had a local nested procedure declared as Stdcall to be used as a CallBack, it works fine in Delphi but in fpc, this is ignored and thus forced me to place the call outside the main body of the block.

  So yes, there are issues with nested procedures to be used on a more serious level. I would of thought the compiler would simply know the difference and not allow the inner actions of the pascal type frame to be accessible while doing this, but no, it just simply refuses to comply.

 Basically the calling conventions are ignored..
The only true wisdom is knowing you know nothing

Jonas Maebe

  • Hero Member
  • *****
  • Posts: 1058
Re: RET 4 at the end of nested assembler procedure of assembler procedure
« Reply #3 on: January 19, 2020, 03:47:21 pm »
  So yes, there are issues with nested procedures to be used on a more serious level. I would of thought the compiler would simply know the difference and not allow the inner actions of the pascal type frame to be accessible while doing this, but no, it just simply refuses to comply.

 Basically the calling conventions are ignored..
That is incorrect. What happens is that Delphi passes the framepointer in a way that completely ingnores the calling convention. This in turn means that the routine can be used both with and without a framepointer parameter (including as a callback to something that doesn't know about nested routines, as long as you don't access any local variables from the local routine).

Jonas Maebe

  • Hero Member
  • *****
  • Posts: 1058
Re: RET 4 at the end of nested assembler procedure of assembler procedure
« Reply #4 on: January 19, 2020, 04:02:20 pm »
Ultimately, I realized that the problem was in the automatically generated RET 4 statement at the end of the nested procedure.
It turns out this bug is already fixed in the upcoming FPC 3.2.0 release.

jamie

  • Hero Member
  • *****
  • Posts: 6077
Re: RET 4 at the end of nested assembler procedure of assembler procedure
« Reply #5 on: January 19, 2020, 09:58:11 pm »
Its about time you DEV's put your coffee cup down and make those fingers work on the keyboard!

 I hope there was a lot of noise while in progress? Because long ago we decreed that unless the computer is making a lot of noise, be it the printer,drives or coder at the keyboard banging away, No Work was getting done!

 Have a nice day!  :)

The only true wisdom is knowing you know nothing

PascalDragon

  • Hero Member
  • *****
  • Posts: 5444
  • Compiler Developer
Re: RET 4 at the end of nested assembler procedure of assembler procedure
« Reply #6 on: January 20, 2020, 09:25:45 am »
Its about time you DEV's put your coffee cup down and make those fingers work on the keyboard!
What's that supposed to mean? :o We are hard at work with FPC so please refrain from such comments.

lucamar

  • Hero Member
  • *****
  • Posts: 4219
Re: RET 4 at the end of nested assembler procedure of assembler procedure
« Reply #7 on: January 20, 2020, 12:32:51 pm »
Its about time you DEV's put your coffee cup down and make those fingers work on the keyboard!
What's that supposed to mean? :o We are hard at work with FPC so please refrain from such comments.

I think it is just a joke so don't take it too seriously. Maybe not in too good taste but I can perfectly imagine someone mockingly saying something like that at the start of a monday to try to "energize" the sleepy air at work. :D
Turbo Pascal 3 CP/M - Amstrad PCW 8256 (512 KB !!!) :P
Lazarus/FPC 2.0.8/3.0.4 & 2.0.12/3.2.0 - 32/64 bits on:
(K|L|X)Ubuntu 12..18, Windows XP, 7, 10 and various DOSes.

jamie

  • Hero Member
  • *****
  • Posts: 6077
Re: RET 4 at the end of nested assembler procedure of assembler procedure
« Reply #8 on: January 20, 2020, 11:04:03 pm »
That's called a language barrier .. :D

It's a pat on the back!  :)
The only true wisdom is knowing you know nothing

Avinash

  • Full Member
  • ***
  • Posts: 117
btw not fixed

you will get an Runtime error 216 here with $CALLING PASCAL or STDCALL

if you uncomment the «ret» then works

Code: Pascal  [Select][+][-]
  1. {$ASMMODE INTEL}
  2. {$CALLING STDCALL}
  3. {.$CALLING PASCAL}
  4.  
  5.   procedure Test; assembler;
  6.  
  7.     procedure Nested; assembler;
  8.     asm
  9.       //ret;
  10.     end;
  11.  
  12.   asm
  13.     Call Nested;
  14.   end;
  15.  
  16. begin
  17.   Test;
  18.   WriteLn('TEST');
  19. end.

PascalDragon

  • Hero Member
  • *****
  • Posts: 5444
  • Compiler Developer
Re: RET 4 at the end of nested assembler procedure of assembler procedure
« Reply #10 on: June 06, 2021, 01:04:50 pm »
btw not fixed

you will get an Runtime error 216 here with $CALLING PASCAL or STDCALL

if you uncomment the «ret» then works

What Jonas said here still applies even if he said that from his point of view it seemed to be fixed.

 

TinyPortal © 2005-2018