Removing the prologue of a function written in pure assembly - delphi

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?

Related

Delphi correct signature for LowLevelKeyboardProc()

I´m writing a global keyboard hook in Delphi 2007 and Windows 10. I´ve found different signatures for a Delphi LowLevelKeyboardProc callback. Someones like this and windows documentation (https://learn.microsoft.com/es-es/previous-versions/windows/desktop/legacy/ms644985(v=vs.85))
LowLevelKeyboardProc() never is executed
prompt that lparam is a pointer to a TKBDLLHOOKSTRUCT record.
Other ones however (http://www.delphifaq.com/faq/delphi_windows_API/f512.shtml and https://www.swissdelphicenter.ch/en/showcode.php?id=1722), show
function KeyHookFunc(Code, VirtualKey, KeyStroke: Integer): LRESULT; stdcall;
completely ignoring the TKBDLLHOOKSTRUCT record pointer.
Which one is correct?
I'm guessing the first one is the correct one but I need to be sure. I´ve been using such signature but when I call another Function in the same unit (and DLL) passing lParam it causes Access Violation when accessing it. All functions and procedures within the DLL use stdcall
All of the callback declarations are correct, although the latter two links do not give examples of LowLevelKeyboardProc but KeyboardProc. IOW, they are not low level keyboard hooks.
Note the latter two wouldn't work in 64 bits due to Integer usage instead of WPARAM, LPARAM and LRESULT.

what happens if you call dll explicit, without declaring in the procedure call its stdcall;

Testing this code:
procedure fii(i:integer);
var
Hbar: Thandle;
Foo: procedure (X: Integer); //i removed the stdcall here!
begin
Hbar := LoadLibrary('BAR.DLL');
if Hbar >= 32 then { success }
begin
Foo := GetProcAddress(HBar, 'FOO');
...
Foo(i); // if we debug trace this to the call of the dll we get not desired value
...
FreeLibrary(HBar);
end
else
MessageDlg('Error: could not find BAR.DLL', mtError, [mbOk], 0)
end.
What will happen if we dropped the stdcall in 32 bit or 64 bit ?
The answer is , the value $18f2dc passed into x. If its a string, it will point to position of $18f2dc ,and try to extract the string garbage from there.
This happens because Delphi just pass Pointer(s) in the code.
It could changed from run to run and not be $18f2dc, but its a 3 byte that are passed. (if you pass int its $18f2dc in decimal 1635036).
Does this number has a unique meaning?
Why is stdcall needed?
What will happen if we dropped the stdcall in 32 bit?
When no calling convention is specified, then the default of register is used. Since this does not match the true calling convention, then garbage will be passed in the parameters.
In this particular case, the function that you call expects the parameters to be passed on the stack. The function will therefore read an integer from the stack. On the other hand, the calling code assumes register calling convention and puts the argument in the EAX register. Because the calling code did not push the argument onto the stack, the function gets what just happens to be on the stack when the function is called.
To be honest, there's not really much point in trying to reasons about ABI(Application Binary Interface - the interface between two program modules) mismatches like this. You would really try to reason about what would happen if you declared a different number of arguments on each side of the interop(Interoperability - property of a product or system, whose interfaces are completely understood, to work with other products or systems) boundary, and that's really little different from using the wrong calling convention. With binary interop you just have to make sure that everything is matching: argument types, return value types, function names, calling convention, the values passed to the function, etc.
What will happen if we dropped the stdcall in 64 bit?
There is a single calling convention for the Windows x64 platform. The calling convention directives are ignored by the compiler.
Although the 64 bit compiler ignores these directives it is still good practise to include them. That way your code will work when you compile it for 32 bit.

How to write Delphi compile-time functions

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.

Using SmartPointer as result data type in function requires invoke call explicitly

I am using the SmartPointer in http://members.adug.org.au/2011/12/05/smart-pointers/
I defined a IStringList:
type
IStringList = ISmartPtr<TStringList>;
I may then use as follow without memory leak prompt:
var S: IStringList;
begin
S := TSmartPtr<TStringList>.Create();
S.Add('abc');
end;
If I use the IStringList as result data type in a function:
function GetList: IStringList;
begin
Result := TSmartPtr<TStringList>.Create();
Result.Add('abc'); // E2010
end;
I get a compiler error:
[dcc32 Error] Unit2.pas(31): E2010 Incompatible types: 'SmartPointer.ISmartPtr<System.Classes.TStringList>' and 'Procedure of object'
A workaround solution would be:
Result.Invoke.Add('abc');
But that defeat the purpose of syntax cleanliness of using SmartPointer. Is there a solution?
It's quite an interesting one. For whatever reason, the compiler treats Result differently from other variables. I see no good reason for that, so this feels like a compiler bug.
I see a few workarounds:
Declare a local variable, use that, and finish the function by assigning that local variable to Result.
Using parens to call the function: Result().Add('abc').
Using a better smart pointer. For instance, a smart pointer that is not based on method invocation would be a good start. A generic record with an implicit conversion operator would presumably work.
Find a version of the compiler without the bug, if indeed it is a compiler bug.
Give up on smart pointers and write traditional style code. Every time I contemplate using smart pointers in Delphi I conclude that I'd rather see the explicit try/finally blocks and understand when my objects are created and destroyed.
FWIW, you can greatly simplify the issue by stripping out the smart pointer code, and removing the generic types. Here is the cleanest SSCCE that I can concoct:
{$APPTYPE CONSOLE}
type
TFunc = reference to function: TObject;
procedure Foo;
var
F: TFunc;
begin
F.ClassName; // compiles
end;
function Bar: TFunc;
begin
Result().ClassName; // compiles
Result.ClassName; // [dcc32 Error] E2003 Undeclared identifier: 'ClassName'
end;
begin
end.
I'm now convinced that this is a compiler bug.
It is presumably related to the rather unusual language feature of Delphi that means the function call parentheses can be omitted for a function that has no parameters. This convenience sometimes brings with it ambiguity. However, in this case there is no ambiguity. The . operator has no meaning when applied to a TFunc<TObject> and so the only way to interpret these statements is that the function is called, and the . operator applied to the returned value.
Bug report: QC123218.
{ I'm not allowed to comment... -.-' Feel free making it one. }
I'm afraid there is no way without defeating the purpose of smart pointers. I tried to solve your problem as part of trying to find a way to assign an anonymous method to an interface variable or parameter (SO question from July 2013). Coming back to it every now and then or asking around didn't help in finding a solution.

Porting mozilla's NSModule to Delphi

In extension to this question, I guess I'll best show what I've got so far.
What I'm trying to do is create a Firefox extension with Delphi, that'll work with the Firefox versions of the future that will use an exported NSModule structure, and no longer an NSGetModule function.
Main questions I'm struggling with for the moment is:
Is the code below correct? I may be wrong with how the pointers and arrays of records work.
How to debug this? If I build it and it runs then I'm kind of sure it'll work, but in debugging my library I can only check if my init code does its job. (and for now, Firefox 3.6 doesn't seem to pick up my #mozilla.org/network/protocol;1?name=xxm contract)
The code I'm trying to port is here:
http://mxr.mozilla.org/mozilla-central/source/xpcom/components/Module.h
type
TConstructorProcPtr=function(aOuter:nsISupports;const aIID:TGUID;var aResult:pointer):nsresult;
TLoadFuncPrt=function:nsresult;
TUnloadFuncPrt=procedure;
TCIDEntry=record
cid:TGUID;
service:boolean;
getFactoryProc:pointer;//TGetFactoryProcPtr;
constructorProc:TConstructorProcPtr;
end;
TContractIDEntry=record
contractid:PChar;
cid:TGUID;//PGUID?
end;
TCategoryEntry=record
category,entry,value:PChar;
end;
TXPCOMModule=packed record
kVersion:integer;//=1;
mVersion:cardinal;//kModuleVersion
mCIDs:^TCIDEntry;//pointer to first in array, last should be nil
mContractIDs:^TContractIDEntry;//pointer to first in array, last should be nil
mCategoryEntries:^TCategoryEntry;//pointer to first in array, last should be nil
getFactoryProcPtr:pointer;//TGetFactoryProcPtr;
loadProc:TLoadFuncPrt;
unloadProd:TUnloadFuncPrt;
end;
You almost certainly need the cdecl calling convention on all your procedure- and function-pointer declarations:
TConstructorProcPtr = function(aOuter: nsISupports; const aIID: TGUID; var aResult: Pointer): nsresult; cdecl;
TLoadFuncPrt = function: nsresult; cdecl;
TUnloadFuncPrt = procedure; cdecl;
I assume you've declared nsISupports as a Delphi interface. Otherwise, you need to make sure the aOuter parameter above is a pointer as it is in the C++ code.
For TContractIDEntry, and all the other places where you use PChar, I advise you to use PAnsiChar instead. The size of Delphi's Char type changed a couple of years ago, but the C++ char is and always will be one byte, so use Delphi's one-byte character type explicitly. Also, your comment wondering whether to declare the cid field as a PGUID was correct; asterisk means pointer.
TContractIDEntry = record
contractid: PAnsiChar;
cid: PGUID;
end;
The kVersion field should not be a member of the record you declare. In C++, it's a static member, which means it occupies no space in the structure itself; it's shared by all instances of that type. It's equivalent to a class field in a Delphi class, but I don't think records offer that feature. Make it a unit-level variable instead of a field.

Resources