Calling library function eats up the stack. Why? - delphi

Sorry, probably this one is also easy for Delphi programmers, but it is not for me. I have a library function I am calling, and basically it eats my stack. It does so by pushing the variables for the function into the stack, but somehow Delphi does not pop them from the stack. So after the function ends I land in nowhere. Funny enough i can just do "pop eax" as many as I have parameters, and it works. Can anyone shed light on whats happening?
The working code goes like this:
function LoadIntoMemory(sdiPath: String): Integer;
var
retValue: Integer;
begin
retValue := file_open(PAnsichar(AnsiString(sdiPath)), #filedata, #filedatasize);
asm
pop eax
pop eax
pop eax
end;
end;
As said, without popping from the stack it crashes.
The function itself is from a C DLL, linked statically like this:
function file_open (filename: PAnsichar; filedata: PPAnsichar; filedatasize: PLongInt): Integer; stdcall; external 'libLib';
linking dynamically does not alter the behaviour.

OK, I have it now. Sorry for probably easy RTFM questions. I should have used cdecl; instead of stdcall. Only wished all these Delphi DLL linking tutorials would have mentioned it somewhere.
http://docwiki.embarcadero.com/RADStudio/XE4/en/Procedures_and_Functions

This is a calling convention mis-match. The callee is cdecl and the caller uses stdcall. The key difference is who cleans the stack. For stdcall it is the callee and for cdecl it is the caller.
This explains what you have observed. The actual function is cdecl. And so the does not clean the stack. But your calling code believes the function is stdcall and so expects the callee to clean the stack. Thus, neither side cleans it.
More details here: http://en.m.wikipedia.org/wiki/X86_calling_conventions

Related

D7: Read var-arguments after call proc with asm 32-bit stdcall

Hello using code below to call a function with asm and after call read the result. That works fine. Now,- how to read the argument changes afterwards, best regards
//push arguments:
for i:=lst.cnt downto 0 do begin //reverse order
ia:=longword(lst.fList^[i]);
asm push ia end; //push 32-Bit argument
end;
asm
call proc //call the routine
mov ia, eax //get result right after the call
end;
//how to read variable arguments here ?
edit:
The initial code has run for some time without any issues, even when using the loop. The reason for this question came, when i had to call a winapi routine like this:
function GetWindowRect(hWnd: HWND; var lpRect: TRect): BOOL; stdcall;
external user32 name 'GetWindowRect';
It has declared a variable record argument "lpRect" (size: 16 bytes). I was trying to (push) these 4 integers before call, and then read them after call. Turns out just passing a pointer to the data actually worked in this case.
Conclusion: So there is no such thing variable arguments, only pointers to value or record. Thanks for any inputs helped getting to this conclusion
If you pass the parameters by value, then list.fList^[i] contains the pointer to the value.
Just unreference and use it, for instance PInteger(list.fList^[i])^ for an integer parameter passed by reference (as var).
But note that your code is pretty awful, and using push within the loop is very risky. It would also need to follow the calling convention - a proc function defined with default Delphi register passes its first parameters into eax/ecx/edx. Check this reference material - your question seems to indicate that you are a bit confused with how it works.

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.

Delphi access violation inside TLanguages utility

For some reason, trying to create a TLanguages object provided by the SysUtils header by using the singleton or by calling the constructor directly is causing trouble in the wild, where some users report this error (X varies):
Access violation at address X. Write of address X (at address X)
... when the following seemingly innocent line of code is executed:
TLanguages.Create;
To clarify, this is not related to context. I can put this line in any place I like (as the only line of code of an empty program for example), but the problem remains.
The weird part is that this class is part of Delphi's standard headers, which should not fail (right?).
constructor TLanguages.Create;
type
TCallbackThunk = packed record
POPEDX: Byte;
MOVEAX: Byte;
SelfPtr: Pointer;
PUSHEAX: Byte;
PUSHEDX: Byte;
JMP: Byte;
JmpOffset: Integer;
end;
var
Callback: TCallbackThunk;
begin
inherited Create;
Callback.POPEDX := $5A;
Callback.MOVEAX := $B8;
Callback.SelfPtr := Self;
Callback.PUSHEAX := $50;
Callback.PUSHEDX := $52;
Callback.JMP := $E9;
Callback.JmpOffset := Integer(#TLanguages.LocalesCallback) - Integer(#Callback.JMP) - 5;
EnumSystemLocales(TFNLocaleEnumProc(#Callback), LCID_SUPPORTED);
end;
The constructor attempts to use a member function as the EnumSystemLocales callback, which seems to be causing the crashes, because copying the TLanguages.LocalesCallback function to global scope and passing that to EnumSystemLocales works perfectly fine.
The struct contains the following Intel x86 assembly, where each item is given by its opcode:
pop edx
mov eax Self
push eax
push edx
jmp JmpOffset
Can anyone explain how the trick works and tell me why it's not working as expected?
It appears to be a known issue with older Delphi versions, related to DEP, as I guessed in comments to the question. It's clear that the code in the RTL cannot work when DEP is enabled.
Here's a link to confirm the theory: http://codecentral.embarcadero.com/Item/23411
Although that CodeCentral article includes code to fix the problem in Delphi 5, it looks like it will work in Delphi 7 too. The fix works by hooking the SysUtils.Languages function. So make sure you always use that rather than calling TLanguages.Create yourself, for obvious reasons.

I need the prototype for calling RtlQueryProcessHeapInformation

I need to call RtlQueryProcessHeapInformation in Delphi.
RtlQueryProcessHeapInformation is a function exported from ntdll.dll.
I don't have a prototype for this function. I get "Undeclared identifier" error.
asm
...
xchg ebx, eax
pop ebp
call RtlQueryProcessHeapInformation
dec ebp
...
end;
Thank you for your help.
A bit of websearch leads to this page or this one which indicate that the function looks like this:
NTSTATUS NTAPI RtlQueryProcessHeapInformation(
IN OUT PRTL_DEBUG_INFORMATION Buffer
);
You already know what NTSTATUS from your previous question. As for NTAPI, that's __stdcall. So that means the function declaration in Delphi is:
function RtlQueryProcessHeapInformation(
Buffer: PRTL_DEBUG_INFORMATION
): NTSTATUS; stdcall; external 'ntdll.dll';
The page I link to also includes a declaration for PRTL_DEBUG_INFORMATION and I'm sure you can translate that yourself. You'll still have to reverse engineer what the parameters mean since this is an implementation private, undocumented function.
This is the second question that you have asked that has been almost identical. In both questions you present the question as being an assembler question. But it's not. In both questions you needed to work out the declaration of the function, and how to import it from the external DLL. What you should take away from this is that when you need to call a function in another DLL you can do one of two things:
Import it implicitly with the external code that I have shown in both your questions. This is the simpler approach.
Use LoadLibrary and GetProcAddress to explicitly import it. This is the more laborious approach.
Please don't take this the wrong way – I'm just trying to show you what you need to know to be able to solve such problems for yourself.

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?

Resources