简体   繁体   English

魔术与C ++,va_arg在64位架构上无法正常工作

[英]magic with c++, va_arg doesn't work on 64 bit architecture with double properly

I've a very interesting question, nobody of my friends and colleagues can't help me. 我有一个非常有趣的问题,我的朋友和同事们谁也帮不了我。 So, let's have a look to the next c++ code: 因此,让我们看一下下一个c ++代码:

#include <stdio.h>
#include <stdarg.h>
typedef void* VirtualMethodTable;
void funcM(void* __this, ...);
__interface Ix
{
    void __cdecl qq(long a, long b, double x, long c);
};
struct tagInterface
{
    tagInterface()
    {
        VirtualMethodTable* VMT = new VirtualMethodTable[1];
        VMT[0] = (void*)&funcM; //here's funcM assignment
        this->VMT = VMT;
    }
    ~tagInterface(){ delete[] VMT; }
    VirtualMethodTable* VMT;
};
void func1(long a, long b, double x, long c)
{
    //some_logic
}
void funcM(void* __this, ...)
{
    va_list marker;
    va_start(marker, __this);
    marker -= sizeof(__this); // line 1
    tagInterface* inst = va_arg(marker, tagInterface*); //line 2
    //we can comment line 1 and line 2 and it still will work as earlier (doesn't work)
    long l1 = va_arg(marker, long);
    long l2 = va_arg(marker, long);
    double d = va_arg(marker, double);//d = 4.343564450161e-311#DEN, not 3.3
    long l4 = va_arg(marker, long);
    func1(l1, l2, d, l4);
    va_end(marker);
}
long main()
{   
    tagInterface x;
    Ix* ins = (Ix*)((void*)&x);
    long p1 = 1;
    long p2 = 2;
    double p3 = 3.3;
    long p4 = 4;
    ins->qq(p1, p2, p3, p4); //it will call funcM 
}

It works fine on the Win32 architecture (visual studio 2013, win7x64) 它在Win32架构上正常工作(Visual Studio 2013,Win7x64)
But when I start it on x64 the "d" variable in the function funcM have "4.343564450161e-311#DEN" value 但是,当我在x64上启动它时,函数funcM中的“ d”变量具有“ 4.343564450161e-311#DEN”的值
Other variables like "l1","l2","l4", "inst" initiate normally. 其他变量如“ l1”,“ l2”,“ l4”,“ inst”通常会启动。
Although, I've tried to work with 'float', it doesn't work too! 虽然,我尝试过使用“ float”,但它也不起作用!
I've searched through all va_arg stack overflow questions and didn't find an answer! 我搜索了所有va_arg堆栈溢出问题,但未找到答案!
So where have I wrong? 那我在哪里错了?
Thank you! 谢谢!
UPDATE 1.: 更新1 .:
yeah, its not work because of "conceptual stack doesn't match the physical stack" 是的,由于“概念堆栈与物理堆栈不匹配”而无法使用
The "d" variable goes through xmm3 register and va_arg trying to work with xmm0. “ d”变量通过xmm3寄存器和va_arg尝试与xmm0一起使用。
Hope smbd sometime will find it's useful! 希望smbd有时会发现它有用!
UPDATE 2. Solution of problem! 更新2.解决问题!
In case of 64-bit programs, the calling convention is different: the values are not always passed via stack: https://msdn.microsoft.com/en-us/library/zthk2dkh.aspx . 如果是64位程序,则调用约定是不同的:值并不总是通过堆栈传递: https : //msdn.microsoft.com/en-us/library/zthk2dkh.aspx Some of them are passed via registers. 其中一些通过寄存器传递。 Therefore, va_list (which works with stack and is suitable for variable-argument functions) cannot be used here. 因此,此处不能使用va_list(与堆栈一起使用,并且适用于可变参数函数)。
Try this workaround: 尝试以下解决方法:

struct ClassIx
{
       virtual void __cdecl qq(...);
};
ClassIx* ins = (ClassIx*)((void*)&x);
ins->qq(p1, p2, p3, p4); //it will call funcM


by Viorel_ from MSDN: 来自MSDN的Viorel_:
https://social.msdn.microsoft.com/Forums/en-US/7a2d9bb5-2b83-4bc5-a018-d7b460fa5550/magic-with-c-vaarg-doesnt-work-on-64-bit-architecture-with-double-properly?forum=vcgeneral https://social.msdn.microsoft.com/Forums/zh-CN/7a2d9bb5-2b83-4bc5-a018-d7b460fa5550/magic-with-c-vaarg-doesnt-work-on-64-bit-architecture-with-适当的论坛?

va_arg functions must be declared and called as such. va_arg函数必须这样声明和调用。 You don't call a va_arg function, you call void __cdecl Ix::qq(long a, long b, double x, long c); 您不调用va_arg函数,而是调用void __cdecl Ix::qq(long a, long b, double x, long c); .

Part of the problem muight be "I just push parametres on the stack". 问题的一部分可能是“我只是将参数推入堆栈”。 The stack doesn't exist. 堆栈不存在。 There's a conceptual C++ call stack (the list of all functions that have been called, but did not yet return, in chronological order, with their arguments) and a physical x64 stack (RBP/RSP registers). 有一个概念性的C ++调用堆栈(已按时间顺序调用的但尚未返回的所有函数的列表及其参数)和一个物理x64堆栈(RBP / RSP寄存器)。

Your problem is that the conceptual stack doesn't match the physical stack. 您的问题是概念堆栈与物理堆栈不匹配。 Not all function parameters are on the physical stack. 并非所有功能参数都在物理堆栈上。 The var_arg mechanism has to dynamically figure out where the function parameters are, though, and that may mean that parameters to variadic functions are on the physical stack. var_arg机构具有动态地找出其中的功能的参数是,虽然,这可能意味着参数来参数可变型函数物理栈上。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM