获取椭圆函数参数而无需初始参数

Getting ellipses function parameters without an initial argument

本文关键字:参数 函数 获取      更新时间:2023-10-16

所以我一直在为脚本语言制作自定义解析器,我希望能够仅通过椭圆参数。我不需要或不需要初始变量,但是Microsoft和C似乎想要其他东西。仅供参考,请参阅底部以获取信息。

我已经查看了va_*定义

#define _crt_va_start(ap,v)  ( ap = (va_list)_ADDRESSOF(v) + _INTSIZEOF(v) )
#define _crt_va_arg(ap,t)    ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
#define _crt_va_end(ap)      ( ap = (va_list)0 )

我不想要的部分是va_start中的v。作为有点背景,我在Goasm中胜任,我知道堆栈是如何工作的,所以我知道这里发生了什么。我想知道是否有一种方法可以获取功能堆栈基础而无需使用内联装配。

我有的想法:

#define im_va_start(ap) (__asm { mov [ap], ebp })

和等等...但是我真的觉得那很混乱,我做错了。

struct function_table {
    const char* fname;
    (void)(*fptr)(...);
    unsigned char maxArgs;
};
function_table mytable[] = {
{ "MessageBox", &tMessageBoxA, 4 } };

...通过const char*对其进行分类的某些函数传递给mytable中的匹配函数,并使用参数调用tmessageboxa。另外,Maxargs参数只是为了检查是否正在发送有效数量的参数。我有个人原因不想将其发送到功能中,但是与此同时,我们可以说这是因为我很好奇。

这只是一个例子。自定义库是我要实施的,因此不仅会调用Winapi的东西。

void tMessageBoxA(...) {
// stuff to load args passed
MessageBoxA(arg1, arg2, arg3, arg4);
}

我正在使用__cdecl呼叫约定,我查找了可靠地将指针指向堆栈底部(不是顶部)的方法,但我似乎找不到任何东西。另外,我不担心功能安全性或打字。


编辑:感谢输入,似乎不可能。

我的修复程序最终成为

    #define im_va_start(ap) {
        __asm push eax
        __asm mov eax, ebp
        __asm add eax, 8h
        __asm mov ap, eax
        __asm pop eax
    }

,然后我可以像正常一样继续。

至于我为什么需要它,我正在做一些(唯一)读取:不安全的技巧,并使用带有指向上述函数的指针的结构数组。由于每个功能都是唯一的,而且大多数来自我的自定义库,因此它们具有……不同的行为。我真的不知道该如何解释,但是完成POC时我会释放来源。

我并不是真的担心便携性,所以必须工作。另外,为了计算我所做的args:

#define im_va_count(ap, num, t) {
for(num = 0; *(t*)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) > 0; ++num){ }
--num;
im_va_start(argptr);
}

对我有用。如果有人有兴趣...

不幸的是,这是不可能的,C标准说:

一个函数可以带有不同类型的参数数量。作为 在6.9.1中所述,其参数列表包含一个或多个参数。

...不算为"一个或多个参数"。此外,

在对未命名参数的任何访问之前,应调用va_start宏。

应该称其为

va_start(va_list, parmN)

和那个

参数 parmN是变量中最右边参数的标识符 函数定义中的参数列表(, ...之前的参数列表)。

您可以看到,在标准C 中的省略号之前,您将无法在没有至少一个参数的情况下具有变异功能。不可支配的装配技巧是您可以来的。