Normally, in Delphi one would declare a function with a variable number of arguments using the ‘array of const’ method. However, for compatibility with code written in C, there’s an much-unknown ‘varargs’ directive that can be added to a function declaration (I learned this while reading Rudy’s excellent ‘Pitfalls of convering‘ document).
As an example, one could have a function in C, declared like this :
void printf(const char *fmt, ...)
In Delphi, this would become :
procedure printf(const fmt: PChar); varargs;
My question is : How can I get to the contents of the stack when implementing a method which is defined with the ‘varargs’ directive?
I would expect that some tooling for this exists, like Dephi translations of the va_start(), va_arg() and va_end() functions, but I can’t find this anywhere.
Please help!
PS: Please don’t drift off in discussions about the ‘why’ or the ‘array of const’ alternative – I need this to write C-like patches for functions inside Xbox games (see the Delphi Xbox emulator project ‘Dxbx’ on sourceforge for details).
OK, I see the clarification in your question to mean that you need to implement a C import in Delphi. In that case, you need to implement varargs yourself.
The basic knowledge needed is the C calling convention on the x86: the stack grows downwards, and C pushes arguments from right to left. Thus, a pointer to the last declared argument, after it is incremented by the size of the last declared argument, will point to the tail argument list. From then, it’s simply a matter of reading the argument out and incrementing the pointer by an appropriate size to move deeper into the stack. The x86 stack in 32-bit mode is 4-byte aligned generally, and this also means that bytes and words are passed as 32-bit integers.
Anyhow, here’s a helper record in a demo program that shows how to read out data. Note that Delphi seems to be passing Extended types in a very odd way; however, you likely won’t have to worry about that, as 10-byte floats aren’t generally widely used in C, and aren’t even implemented in the latest MS C, IIRC.