Biohazrd icon indicating copy to clipboard operation
Biohazrd copied to clipboard

Add support for variable arguments (non-va_list)

Open PathogenDavid opened this issue 3 years ago • 3 comments

No attempt at supporting variable arguments was made in the original prototype. Supporting these will be non-trivial because if I remember right, the runtime doesn't officially support P/Invoke with variable arguments outside of Windows.

PathogenDavid avatar Sep 04 '20 18:09 PathogenDavid

If I remember how va_list works internally, supporting it should be relatively simple. So a good starting point should be to support that, which should cover any C++ libraries that provide both a variable arguments function and a va_list function. (And if I am correctly remembering how variable arguments works under the hood, supporting it first is likely needed to support them anyway.)

PathogenDavid avatar Sep 04 '20 18:09 PathogenDavid

Some notes from quick-and-dirty messing with implementing vargs manually to test ImGui:

CRT puts most of the implementation of vargs in macros in vadefs.h for x86:

    #define _INTSIZEOF(n)          ((sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1))

    #define __crt_va_start_a(ap, v) ((void)(ap = (va_list)_ADDRESSOF(v) + _INTSIZEOF(v)))
    #define __crt_va_arg(ap, t)     (*(t*)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)))
    #define __crt_va_end(ap)        ((void)(ap = (va_list)0))

For x64:

    void __cdecl __va_start(va_list* , ...);

    #define __crt_va_start_a(ap, x) ((void)(__va_start(&ap, x)))
    #define __crt_va_arg(ap, t)                                               \
        ((sizeof(t) > sizeof(__int64) || (sizeof(t) & (sizeof(t) - 1)) != 0) \
            ? **(t**)((ap += sizeof(__int64)) - sizeof(__int64))             \
            :  *(t* )((ap += sizeof(__int64)) - sizeof(__int64)))
    #define __crt_va_end(ap)        ((void)(ap = (va_list)0))

I couldn't dig up __va_start in the reference source for x64, but quick tests seem to suggest it works the same way as x86.

In general, things are always/usually word-aligned. Floating point numbers are always promoted to doubles. (Including on x86?)


Here's what manually using va_list looks like in the InfectedImGui sample:

https://github.com/InfectedLibraries/InfectedImGui/blob/aaabb2ba2b3bc74d20cdd9ff8ccb02ad1ac6d796/InfectedImGui.Sample/Program.cs#L166-L167

Recommending people just pass in tuples might actually be a pretty solid strategy here. However we do need to explore whether this is viable for all ABIs or not. It might be a good idea to provide an analyzer to do printf-like parameter validation for these scenarios.

PathogenDavid avatar Oct 12 '20 22:10 PathogenDavid

I broke out va_list support to https://github.com/InfectedLibraries/Biohazrd/issues/164 as it's much simpler than "proper" variable arguments.

PathogenDavid avatar Feb 22 '21 03:02 PathogenDavid