在x86上如何将双精度传递给函数

时间:2017-02-25 20:50:49

标签: c++ windows debugging

我有以下函数需要3个双参数。在我的调试器内部达到此功能的中断时。检查函数的参数我没有看到3个双参数。

在x86平台上是存储在堆栈中的函数的双参数吗?

下面是windbg中的函数和反汇编。为什么我在windbg中看不到作为Args to Child传递给函数的值?

    vector<double> calculate_quadratic(double a, double b, double c)
    {
        double discriminant = (b * b) - 4 * a * c;
        vector<double>result;

        try
        {
            if (discriminant < 0)
                throw Bad_Value{};
            else
            {
                double d = sqrt(discriminant);
                double px = (-b + d) / (2 * a);
                double nx = (-b - d) / (2 * a);

                result.push_back(px);
                result.push_back(nx);
            }
        }
        catch (Bad_Value)
        {
            cerr << "invalid value" << endl;
        }

        return result;
    } 


     0:000> kb
     # ChildEBP RetAddr  Args to Child
    00 003dfd2c 0126ad86 003dfe30 00000000 3ff00000 quadratic!calculate_quadratic
    01 003dfe84 0126ba6e 00000001 0043d080 0043dd18 quadratic!main+0xc6
    02 003dfe98 0126b8d0 ac1dec02 00000000 00000000 quadratic!invoke_main+0x1e
    03 003dfef0 0126b76d 003dff00 0126ba88 003dff0c quadratic!__scrt_common_main_seh+0x150
    04 003dfef8 0126ba88 003dff0c 772c336a 7efde000 quadratic!__scrt_common_main+0xd
    05 003dff00 772c336a 7efde000 003dff4c 777f9f72 quadratic!mainCRTStartup+0x8
    06 003dff0c 777f9f72 7efde000 77465726 00000000 kernel32!BaseThreadInitThunk+0xe
    07 003dff4c 777f9f45 01261127 7efde000 00000000 ntdll!__RtlUserThreadStart+0x70
    08 003dff64 00000000 01261127 7efde000 00000000 ntdll!_RtlUserThreadStart+0x1b

    0:000> r
    eax=003dfe30 ebx=003dfd48 ecx=acd07c23 edx=582e27d8 esi=003dfd50 edi=003dfd4c
    eip=01268f70 esp=003dfd30 ebp=003dfe84 iopl=0         nv up ei pl nz ac po nc
    cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000212
    quadratic!calculate_quadratic:
    01268f70 push    ebp

    0:000> dv /t /v
    003dfd38          double a = 1
    003dfd40          double b = -3
    003dfd48          double c = 2
    003dfd0c          double discriminant = 1.7499487580265442e+127
    003dfcf4          struct Vector<double> result = struct Vector<double>

倾倒顶部框架的ChildEBP我现在可以按相反的顺序看到堆栈上的参数 - 在这种情况下,我使用了10次,表示为 4024000000000000

0:000> kb
 # ChildEBP RetAddr  Args to Child
00 004cfac4 0017ad86 004cfbc8 00000000 40240000 quadratic!calculate_quadratic

0:000> dd 004cfac4
004cfac4  5a23da80 0017ad86 004cfbc8 00000000
004cfad4  40240000 00000000 40240000 00000000
004cfae4  40240000 ed0a64cf 00000000 00000000

0:000> .formats 4024000000000000
Evaluate expression:
  Hex:     40240000`00000000
  Decimal: 4621819117588971520
  Octal:   0400440000000000000000
  Binary:  01000000 00100100 00000000 00000000 00000000 00000000 00000000 00000000
  Chars:   @$......
  Time:    Fri Dec 18 11:22:38.897 16246 (UTC - 5:00)
  Float:   low 0 high 2.5625
  Double:  10

2 个答案:

答案 0 :(得分:3)

C / C ++的默认调用约定是cdecl。在此调用约定中,当为x86构建时,参数以相反的顺序在堆栈上传递。当然,编译器选项或函数装饰可以覆盖此行为。

查看您的WinDBG输出,前三个堆栈条目(args to child)是:

003dfe30 00000000 3ff00000

由于double是64位宽,因此您只需要查看一半的参数。第一个条目看起来是EAX的内容...也许编译器优化已经在断点击中时将EAX推送到堆栈?下一个值是00000000 3ff00000,它是3ff0000000000000 = 1(IEEE754)的LE,最左边的参数,以及在cdecl中传递给堆栈的最后一个。

答案 1 :(得分:0)

如何传递参数是依赖于编译器的,并且通常可以通过选项或编译器指令进行更改。

如果用于传递浮点参数,大多数x86编译器将使用x87 FPU堆栈(ST0-ST7寄存器)或SSE寄存器(XMM0-XMM7)。在MSVC上,这由/ arch和/ fp选项控制。