Removing the prologue of a function written in a clean assembly

I am using Delphi 2010. Is it possible to tell Delphi not to generate a prolog for a function? I write some pure build functions as follows:

procedure SomeAssembly; stdcall; begin asm ... end; end; 

and I would like to say that Delphi will not generate prolog and epilogue for this function, for example, C ++ __declspec(naked) .

And therefore, no one is wasting time; I do not need help for these functions to work with the prologue; I can do it already. This is just a big inconvenience and will make maintenance a huge hassle. I will have to manually check the prologs generated by the compiler to see their length, and if that changes, my program will crash.

I also know that I can write a function as a series of bytes in an array of bytes, but that would be even worse than having to find the length of the Delphi prolog.

+7
source share
3 answers

Delphi does not generate prologs or epilogues for functions that have no arguments and are declared using a register registry agreement. If you need functions without prologs, declare them as arguments with a null argument, call registration functions. Also, skip the begin - end block and go straight to the assembly.

 procedure SomeAssembly; // register; (implied) asm // ... end; 

Since you are effectively lying about the nature of functions, calling them can be difficult. If you implemented a function as if it were receiving parameters and using a different calling convention, you need to make sure that the compiler knows about it on the call site. To do this, declare a pointer to a function that reflects the "real" type of your function instead of the declared type. For example, if your function is really a function with two stdcall arguments, declare something like this:

 type TSomeAssemblyFunc = function (Arg1: Integer; Arg2: PAnsiChar): Boolean; stdcall; var SomeAssemblyProc: TSomeAssemblyProc; 

Now assign this variable so that it points to your function:

 SomeAssemblyProc := TSomeAssemblyProc(@SomeAssembly); if SomeAssembly(2, 'foo') then ... 

In addition to skipping the prolog and epilogue, the compiler will generate an invalid RET instruction for this function (due to a different calling convention), so you need to make sure you say ret 8 in your code instead of giving the compiler's default RET command .


Finding the length of the Delphi prolog is trivial if you have a working debugger:

  • Set a breakpoint at the beginning of the function.
  • Call the function.
  • When the debugger stops at a breakpoint, switch to the CPU view.
  • See the instructions that make up the prologue.
  • Count the bytes displayed next to these instructions.
+19
source

According to this embarcadero docwiki, you can skip the surrounding begin and end , and the compiler will skip some of them. But if you really need pure assembler, why not put your function in a separate assembler file, build it with tasm (exe is called tasm32) and a link to it. Then you will use the assembler directive in the delphi code.

+1
source

not

 procedure SomeAssembly; stdcall; asm ... end; 

do the trick?

0
source

All Articles