Forum > General

RET 4 at the end of nested assembler procedure of assembler procedure

(1/3) > >>

Avinash:
I tried to use the FormatStr function from Virtual Pascal package. But it didn't work correctly. Its structure is simple:


--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ----Mtp{$CALLING PASCAL} procedure FormatStr(...); assembler;   procedure Convert; assembler; nostackframe;  asm       ...       ...    @@Done:  end; asm     ...     ...     Call  Convert     ...     ...  @@Done:end; 
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  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ----Mtp{$CALLING PASCAL} procedure FormatStr(...); assembler;   procedure Convert; assembler; nostackframe;  asm       ...       ...    @@Done:       RET  end; asm     ...     ...     Call  Convert     ...     ...  @@Done:end; 
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:

--- Quote ---This behavior is counterintuitive. You take a known working code, but it does not work.

--- End quote ---
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.

jamie:
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..

Jonas Maebe:

--- Quote from: jamie on January 19, 2020, 03:41:13 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..

--- End quote ---
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:

--- Quote from: Avinash on January 19, 2020, 10:28:41 am ---Ultimately, I realized that the problem was in the automatically generated RET 4 statement at the end of the nested procedure.

--- End quote ---
It turns out this bug is already fixed in the upcoming FPC 3.2.0 release.

Navigation

[0] Message Index

[#] Next page

Go to full version