How to write Delphi compile-time functions - delphi

Delphi - can I write my own compile-time functions for const and var declarations, executable at compiler time.
Standard Delphi lib contain routines like Ord(), Chr(), Trunc(), Round(), High() etc, used for constant initialization.
Can I write my own, to execute routine at compile-time and use the result as constant?

You cannot write your own intrinsic functions. Because that requires compiler magic.
However there may be other options to achieve your goal.
Preprocessor
The only way is to use a preprocessor.
There are several: http://wiki.delphi-jedi.org/wiki/JEDI_Pre_Processor
The Delphi preprocessor
http://sourceforge.net/p/dpp32/wiki/Home/history
Andreas Hausladen has just open sourced his own work in this respect.
It's not really a preprocessor, but a language extender.
https://github.com/ahausladen/DLangExtensions
The problem with preprocessors is that it kills the link between the original (prior to pre-processing) source code and the source code that Delphi compiles.
This means that you will not have debug info for your original source.
(unless you rewrite the map file).
Inlining
Depending on what you want to do you can use inlining to achieve almost the same efficiency as an intrinsic function.
See: https://stackoverflow.com/a/6401833/650492
Construct your statements using intrinsic functions
If you have a code block consisting of instrinsic functions, the complete result will be evaluated at compile time, making the total construct work as if it was a intrinsic function.
Note the following (silly) example:
function FitsInRegister<T>: Boolean; inline;
begin
if GetTypeKind(T) in [tkString, tkUString] then result:= false
else
{$IFDEF CPU32BITS}
Result:= SizeOf(T) <= 4;
{$ELSEIF CPU64BITS}
Result:= SizeOf(T) <= 8;
{$ENDIF}
end;
Because it is inline and it only uses intrinsic functions (and compiler directives), the function will be resolved at compiletime to a constant and not generate any code.

Can I write my own, to execute routine at compile-time and use the result as constant?
No you cannot. These functions are built in to the compiler and if offers no extension mechanism to allow third parties to supply built in functions.

Related

How to add type-specific code for generics in Delphi

Is there any efficient way to add type specific code for delphi generics ?
For example something like this:
function TGT<T>.GetSize(a: T): integer;
begin
{$IF TypeInfo(T)=TypeInfo(String)}
result := Length(A);
{$ELSE}
result := SizeOf(A);
{$IFEND}
end;
function TGT<T>.Compare(a,b: T): integer;
begin
{$IF TypeInfo(T)=TypeInfo(String)}
result := AnsiCompareText(a,b);
{$ELSE}
result := a-b;
{$IFEND}
end;
So i need to implement some parts of the code in different ways depending on type.
For example if i implement Sort routine i would like to use direct comparison of values of integer/double/etc types (it is more efficient than calling of interface methods like delphi's standard generic containers do) and function AnsiCompareText for String type.
There some examples how to do it, but all of them based on check like this:
if TypeInfo(T)=TypeInfo(String) then xxx else if TypeInfo(T)=TypeInfo(Integer) then xxx
Problem here is that Delphi will check it in run-time only, that is (again) not so efficient.
I would like to make compiler to do all checks in compile-time and use only code specific for selected type.
Well, you certainly cannot hope to do anything like that with conditional compilation. Remember that conditional compilation for generics are handled in the generic compilation phase rather than the instantiation phase. And so you cannot expect different instantiations to be compiled with different branches of your conditional statement.
And you certainly can never get the compiler to accept Length(a) where the type of a is parametrised, because there is no way to specify a constraint that would allow the use of Length.
The only option is a run-time check.

How to call a procedure or function when we are not aware of the parameters?

My application has to provide the ability of calling different functions and procedures from external DLLs. So we don't know parameters' count and their types. What should I do to do this?
Let me explain it more. My application is a RAD tool and it has its own scripting and syntax... I want to let users to use ANY dll file and call any function or procedure they want. I can't use the simple method of calling dll (LoadLibrary and then GetProcAddress) because I don't know what type the GetProcAddress refers to ( var Proc:procedure (A:??;B:??;...) ).
I have a Delphi implementation in the scripting functionality of my ZGameEditor-project, search for "TExpExternalFuncCall.Execute" in the file below:
http://code.google.com/p/zgameeditor/source/browse/trunk/ZExpressions.pas
Tested and working under Windows (x86 and x64), Linux, Android (ARM) and OS X (x86). Handles stdcall and cdecl calling conventions.
But libFFI is probably way more general than my implementation so I would recommended that approach.
This is a simple example that works on my machine, but I am not an expert on the subject.
procedure TForm4.Button1Click(Sender: TObject);
var
hmod: HMODULE;
paddr: pointer;
c1, c2, ret: cardinal;
begin
c1 := 400; //frequency
c2 := 2000; // duration
hmod := LoadLibrary('kernel32'); // Of course, the name of the DLL is taken from the script
if hmod <> 0 then
try
paddr := GetProcAddress(hmod, 'Beep'); // ...as is the name of the exported function
if paddr <> nil then
begin
// The script is told that this function requires two cardinals as
// arguments. Let's call them c1 and c2. We will assume stdcall
// calling convention. We will assume a 32-bit return value; this
// we will store in ret.
asm
push c2
push c1
call [paddr]
mov ret, eax
end;
end;
finally
FreeLibrary(hmod);
end;
end;
What you are describing is known as a Foreign Function Interface (FFI) and is not for the feint of heart.
I would not recommend that you attempt to develop your own FFI from scratch. A very common choice of FFI is libffi.
The Wikipedia page for libffi lists the following projects as users of libffi:
Python, Dalvik, F-Script, PyPy,
PyObjC, RubyCocoa, JRuby, Rubinius,
MacRuby, gcj, GNU Smalltalk, IcedTea,
Cycript, Pawn, Squeak, Java Native
Access, PLT Scheme, Embeddable
Common Lisp and Mozilla.
I personally make extensive use of libffi through a Python/ctypes interface to my Delphi DLL, although thankfully Python/ctypes wraps it up at quite a high level.
If I were setting off down the route you describe, I would strongly consider using libffi. If you take that route you'll have to do some work to be able to use it from Delphi since it is written in C/asm.
As David H says, about FFI, it's hardly for the faint of heart.
However, you could use the source code, for example, to the Python ctypes extension modules for FFI, as a source of information on how libFFI (ctypes) is bound to a particular syntax (in this case python). THe python source code, and its standard modules, are very readable.
Here is an example of using the libraries David mentions, in Python:
http://code.activestate.com/recipes/146847/
Since the sources for python (in C) are available, and since Python itself can be an extension in Delphi, you could use that to start with. If you are up to writing your own complete dynamic language (as part of your RAD tool), then you are up to the challenge of FFI too.
I am personally not up for the challenge of inventing a complete, workable programming language and all its libraries, from scratch, so I prefer to hybridize what I know, together. Native code in C or Delphi, and dynamic scripts in Python. You can combine all three easily into a single application, as needed.

Removing the prologue of a function written in pure assembly

I am using Delphi 2010. Is it possible to tell Delphi to not generate a prologue for a function? I'm writing some pure assembly functions like this:
procedure SomeAssembly; stdcall;
begin
asm
...
end;
end;
and I would like to tell Delphi not to generate a prologue and epilogue for this function, like C++'s __declspec(naked) feature.
And so no one wastes their time, I don't need help getting these functions to work with the prologue; I can already do that. It's just a large inconvenience and will make maintenance an huge hassle. I'll have to manually inspect the prologues generated by the compiler to see their length, and if that changes, my program will crash.
I also know I can write the function as a series of bytes in a byte array, but that would be even worse than having to go find the length of Delphi's prologue.
Delphi doesn't generate prologues or epilogues for functions having no arguments and declared with the register calling convention. If you want functions without prologues, declare them as zero-argument, register-calling-convention functions. Also, skip the begin-end block and go straight into assembly.
procedure SomeAssembly; // register; (implied)
asm
// ...
end;
Since you're effectively lying about the nature of the functions, calling them may be tricky. If you've implemented a function as though it received parameters and used a different calling convention, then you'll have to make sure the compiler knows about that at the call site. To do that, declare a function pointer that reflects the "real" type of your function instead of the declared type. For example, if your function is really a two-argument stdcall function, declare something like this:
type
TSomeAssemblyFunc = function (Arg1: Integer; Arg2: PAnsiChar): Boolean; stdcall;
var
SomeAssemblyProc: TSomeAssemblyProc;
Now, assign that variable so it points at your function:
SomeAssemblyProc := TSomeAssemblyProc(#SomeAssembly);
if SomeAssembly(2, 'foo') then ...
In addition to skipping the prologue and epilogue, the compiler will generate the incorrect RET instruction for this function (because of the different calling convention), so you'll have to make sure you say ret 8 in your code instead of letting the compiler's default ret instruction occur.
Finding the length of Delphi's prologue is trivial, if you have a working debugger:
Set a breakpoint at the start of the function.
Call the function.
When the debugger stops at the breakpoint, switch to the CPU view.
Look at the instructions that make up the prologue.
Count the bytes displayed beside those instructions.
According to the this embarcadero docwiki you can skip the surrounding begin and end and the compiler will skip some of it's stuff. But if you really want pure assembler, why not put your function into a separate assembler file, assemble it with tasm (the exe is named tasm32) and link to it. You'll then use the assembler directive in the delphi code.
Doesn't
procedure SomeAssembly; stdcall;
asm
...
end;
do the trick?

converting a c++ pointer cast to delphi

actually i am converting a c++ code to delphi, but i have problem to translate this line
PIMAGE_NT_HEADERS header = (BYTE *)lib + ((PIMAGE_DOS_HEADER)lib)->e_lfanew;
to delphi (this is my result at the moment)
var
lib : THandle;
header : PImageNtHeaders;
begin
//....
//.....
header := Pointer(PByte(lib) + PImageDosHeader(lib)._lfanew);
end;
but the compiler gives me this message operator not applicable to this operand type
can you help me to translate this line.
header := Pointer(Integer(PByte(lib)) + PImageDosHeader(lib)._lfanew);
You might be able to sidestep a lot of this. If you're looking for PE image header routines, look up the ImageHlp unit from the RTL, and the JclPeImage unit from the JCL. They've got lots of prebuilt code to make image and image header header work easier.
the _lfanew member is most likely an offset so it needs to be an integer or DWORD instead of a pointer. Just guessing as I don't use Delhpi but have you tried :-
header := Pointer(PByte(lib) + (DWORD)(PImageDosHeader(lib)._lfanew));
A web search came up with the following : http://www.cheesydoodle.com/?p=175
This code is Delphi based and is using the same library you are. You will most likely find a solution hidden in this code listing on CheesyDoodle.
Pointer arithmetic is much more limited in delphi, and direct addition is not allowed. You'll have to use the Inc function on your pointers.
example(source ):
program PointerArithmetic;
{$APPTYPE CONSOLE}
uses
SysUtils;
procedureWritePointer(P: PDouble);
begin
Writeln(Format('%8p', [P]));
end;
var
P: PDouble;
begin
P := Pointer($50000);
WritePointer(P);
Inc(P); // 00050008 = 00050000 + 1*SizeOf(Double)
WritePointer(P);
Inc(P, 6); // 00050038 = 00050000 + 7*Sizeof(Double)
WritePointer(P);
Dec(P, 4); // 00050018 = 00050000 + 3*Sizeof(Double)
WritePointer(P);
Readln;
end.
What you are working on is called RVA (Relative Virtual Address). Basic formula is
Address = Base + Displacement. Naturally, Address and Base are untyped pointers while Displacement is signed integer. Object Pascal disallows pointer arithmetics, so typecasting is required.
So:
var
Address, Base: Pointer;
Displacement: Integer;
{ ... }
Address := Pointer(Cardinal(Base) + Displacement);
{ or, in your case }
var
Module: HMODULE; { opaque type designates module handle and equals to load address }
NTHeaders: PImageNtHeaders;
begin
NTHeaders := Pointer(Cardinal(Module) + PImageDosHeader(Module)^._lfanew);
if NTHeaders^.Signature = ......
I don't work in Delphi day-to-day, but I suspect the error is due to one of two things:
Pointer math is not enabled. Delphi, by default, does not allow you to to C-style pointer manipulation, eg adding a number to a pointer to get another pointer - remember Delphi is a 'safe' language. To enable this, turn on pointer math using the {$POINTERMATH ON} directive. This forum posting has some more info too.
This is the bit I can't remember because it's been a while: You may not be able to add pointers of different types - remember the size of what the pointer points to is different. Without knowing what _lfanew is I can't give you more information. If this is the case, get everything in bytes and add those.
You may want to use the Inc function too, to convert your code to be more Delphi-like. Inc will increment a typed pointer by the size of the structure that pointer points to, not by one byte. Pointer math generally is not quite C-style :) I think it's better though, since it's type-aware.
Edit: I noticed Martin Broadhurst's comment on your question pointing out this is probably parsing a PE image. If so, look up the Jedi Code Library's PE image unit. I've never used it but I know it exists, and it's a translation of the C headers. It may include helper functions too. Using it might mean rewriting code rather than converting it, but you'll probably get cleaner, more Delphi-style code at the end.

Does Delphi compiler perform optimization?

I am using Delphi 7 IDE. Does Delphi compiler optimize codes, just like what the C++ compiler is doing in this following link?
http://msdn.microsoft.com/en-us/library/aa366877(VS.85).aspx
WCHAR szPassword[MAX_PATH];
// Retrieve the password
if (GetPasswordFromUser(szPassword, MAX_PATH))
UsePassword(szPassword);
// Clear the password from memory
SecureZeroMemory(szPassword, sizeof(szPassword));
If ZeroMemory were called in this example instead of SecureZeroMemory, the compiler could optimize the call because the szPassword buffer is not read from before it goes out of scope. The password would remain on the application stack where it could be captured in a crash dump or probed by a malicious application.
Yes, of course Delphi performs optimizations. However, it does not perform the optimization that the SecureZeroMemory function is meant to circumvent. There is no need to use that function in Delphi; just use plain old ZeroMemory, or even FillChar. They're not macros, and they don't do anything that Delphi recognizes as being unused assignment statements that could get optimized out.
Delphi performs code optimization by default, you can disable it in Project > Options > Compiler.
The Delphi help provide a few tips of what type of optimizations are used:
The $O directive controls code optimization. In the {$O+} state, the compiler performs a number of code optimizations, such as placing variables in CPU registers, eliminating common subexpressions, and generating induction variables.
It also states that "the compiler performs no "unsafe" optimizations", but in the sense that they won't alter the execution path, not from a security point of view.
Delphi certainly optimizes code (it is a modern, and excellent, compiler). Another example of optimization deleting lines is:
SomeFunction(); // Set breakpoint here, then step (F10)
myInt := 7; // Next line will not hit this...
myInt := 13; // ...but will instead skip to here
I like to ensure optimization is in the correct state (and not accidentally left switched on or off) by adding {$I MyProjectOptions.inc} in every .pas file in my project. This goes just below the unit name (right at the top of the file). In "MyProjectOptions.inc" you simply add this code:
// Is this a debug or non-debug build?
{$IF Defined(DEBUG)}
{$O-} // Turn optimization off
{$ELSEIF Defined(NDEBUG)}
{$O+} // Ensure optimisation is on
{$IFEND}
Finally, ensure you have defined "DEBUG" and "NDEBUG" (or your equivalent in older versions of Delphi) in the Conditional defines section of Project > Options > Diectories/Conditionals.
I don't believe the compiler will ever eliminate apparently dead code like this. I have never had trouble setting breakpoints on code that could have been eliminated as redundant.
For some scenarios, the compiler can detect if the code is unreachable and eliminate the code.
For instance, the compiler correctly eliminates the "unreachable" portion of the code below.
It will not generate code for that line so:
So there are no blue bullets indicating there is code
Breakpoints put on that line will be marked visually as 'not reachable'
Just tested in Delphi XE, but older Delphi versions have similar behaviour.
program Project1;
{$APPTYPE CONSOLE}
uses
SysUtils;
procedure Test;
begin
if (True = False) then
Writeln('Unreachable')
else
Writeln('Reachable');
end;
begin
try
Test();
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.
It takes quite some while to learn when (or when not) the optimizer on code level and liker level kicks in.
For instance: When you have optimizations turned on, the compiler will also eliminate variables as soon as they are not used.
Sometimes, it even eliminates global symbols.
Danny Thorpe (former Delphi Compiler engineer and Chief Scientist) once wrote a magic method Touch that prevents this.
Just call this Touch method at the end of your method to fool the optimizer during debugging:
procedure Touch(var arg);
begin
end;
--jeroen

Resources