Assembly 使用数组中的值加载FPU堆栈后,从FPU堆栈加载的结果错误

Assembly 使用数组中的值加载FPU堆栈后,从FPU堆栈加载的结果错误,assembly,x86-16,inline-assembly,turbo-c,x87,Assembly,X86 16,Inline Assembly,Turbo C,X87,我正在编写内联x86汇编代码,将用C语言定义的数组的内容复制到x87 FPU堆栈中,以执行进一步的操作。从FPU堆栈检索时,存储在FPU堆栈顶部的值是不同的 我试图查看编译器生成的反汇编;参考Turbo C++ 3手册;查阅了8086至奔腾汇编编程手册,但未能找到解决此问题的方法 我的代码是: #include<stdio.h> void main() { float array[10] = { 1.13,1.98,1.67,1.19},sum; asm{ lea

我正在编写内联x86汇编代码,将用C语言定义的数组的内容复制到x87 FPU堆栈中,以执行进一步的操作。从FPU堆栈检索时,存储在FPU堆栈顶部的值是不同的

我试图查看编译器生成的反汇编;参考Turbo C++ 3手册;查阅了8086至奔腾汇编编程手册,但未能找到解决此问题的方法

我的代码是:

#include<stdio.h>

void main()
{
    float array[10] = { 1.13,1.98,1.67,1.19},sum;
asm{
    lea ax,[array]
    push ax
    fld dword ptr[bp-8]
    fstp sum
}
printf("%f", sum);
}
#包括
void main()
{
浮点数组[10]={1.13,1.98,1.67,1.19},和;
asm{
lea ax,[阵列]
推斧
德沃德飞行训练队[bp-8]
fstp总和
}
printf(“%f”,总和);
}
它编译时没有错误,但运行时得到-786.997,而不是预期的结果1.67。

在这段代码中:

    lea ax,[array]
    push ax
    fld dword ptr[bp-8]
    fstp sum
您正在将
数组的地址
加载到AX中,而不是值。然后将AX中的
数组
的地址推送到堆栈上。然后,您的
FLD
指令尝试从相对于BP的固定偏移量读取数据。正如@Jester所指出的,您不应该依赖堆栈上的数据作为与BP的特定偏移量,因为它取决于Turbo-C的代码生成器以及东西在堆栈上的位置

如果要读取数组的第三个元素,可以加载数组的地址,然后访问各个元素的地址。将
数组
的地址加载到BX、SI或DI寄存器中,因为它们可以用作中的基址(AX不能)

您的代码可能看起来像:

#include<stdio.h>

void main()
{
    float array[] = { 1.13,1.98,1.67,1.19 }, sum;
    asm{
        lea bx,[array]      /* Load address of array into BX */
        fld dword ptr[bx+8] /* Load the value at 3rd element. Each float is 4 bytes
                               in 16-bit Turbo-C thus [bx+8] is the third element */
        fstp [sum]          /* Store top of stack ST(0) to SUM and pop top of stack */
    }
    printf("%f", sum);
}
#包括
void main()
{
浮点数组[]={1.13,1.98,1.67,1.19},和;
asm{
lea bx,[array]/*将数组地址加载到bx中*/
fld dword ptr[bx+8]/*加载第三个元素的值。每个浮点为4字节
因此,在16位Turbo-C中[bx+8]是第三个元素*/
fstp[sum]/*将栈顶ST(0)存储到sum并弹出栈顶*/
}
printf(“%f”,总和);
}
将浮点数组从最高数组元素到最低数组元素求和的代码可能如下所示:

#include<stdio.h>

void main()
{
    float array[] = { 1.13,1.98,1.67,1.19 }, sum;
    const int array_size_b = sizeof (array);
                            /* Size of array in bytes */
    asm {
        lea bx,[array]      /* Load address of array into BX */
        mov si, [array_size_b]
                            /* SI = byte offset to element just past end of array */
        fldz                /* Push an initial SUM value (0.0) on the FPU stack */
    }
    sumloop:
    asm {
        fadd dword ptr[bx+si-4]
                            /* Add current float to SUM on top of FPU stack */
        sub si, 4           /* Set index to previous float in array */
        jnz sumloop         /* If not start of array go back and process next element */

        fstp [sum]          /* Retrieve SUM from top of FPU stack&store in variable sum */
    }
    printf("%f", sum);
}
#包括
void main()
{
浮点数组[]={1.13,1.98,1.67,1.19},和;
常量int数组_size_b=sizeof(数组);
/*数组的大小(字节)*/
asm{
lea bx,[array]/*将数组地址加载到bx中*/
mov si[阵列大小]
/*SI=刚好超过数组末尾的元素的字节偏移量*/
fldz/*在FPU堆栈上推送一个初始和值(0.0)*/
}
sumloop:
asm{
fadd dword ptr[bx+si-4]
/*将当前浮点值添加到FPU堆栈顶部的总和*/
子si,4/*将索引设置为数组中的前一个浮点值*/
jnz sumloop/*如果不是数组的开始,则返回并处理下一个元素*/
fstp[sum]/*从FPU堆栈顶部检索sum并存储在变量sum中*/
}
printf(“%f”,总和);
}
按相反顺序处理元素简化了检查是否已处理整个阵列的逻辑。从第一个元素到最后一个元素都可以通过以下方式完成:

#include<stdio.h>

void main()
{
    float array[] = { 1.13,1.98,1.67,1.19 }, sum;
    const int array_size_b = sizeof (array);
    asm {
        lea bx,[array]       /* Load address of array into BX */
        xor si, si           /* SI = index into array = 0 = first element */
        mov cx, [array_size_b]
                             /* CX = byte offset of element just past end of array */
        fldz                 /* Push an initial SUM value (0.0) on the FPU stack */
    }
    sumloop:
    asm {
        fadd dword ptr[bx+si]/* Add the current float to SUM on top of FPU stack */
        add si, 4            /* Advance index to next float in array */
        cmp si, cx           /* Has the index reached the end of array? */
        jl sumloop           /* If not end of array go back and process next element */

        fstp [sum]           /* Retrieve SUM from top of FPU stack&store in variable sum */
    }
    printf("%f", sum);
}
#包括
void main()
{
浮点数组[]={1.13,1.98,1.67,1.19},和;
常量int数组_size_b=sizeof(数组);
asm{
lea bx,[array]/*将数组地址加载到bx中*/
xor si,si/*si=数组索引=0=第一个元素*/
mov cx[阵列大小]
/*CX=刚过数组末尾的元素的字节偏移量*/
fldz/*在FPU堆栈上推送一个初始和值(0.0)*/
}
sumloop:
asm{
fadd dword ptr[bx+si]/*将当前浮点值添加到FPU堆栈顶部的总和*/
将si,4/*高级索引添加到数组中的下一个浮点*/
cmp si,cx/*索引是否已到达数组末尾*/
jl sumloop/*如果不是数组的结尾,则返回并处理下一个元素*/
fstp[sum]/*从FPU堆栈顶部检索sum并存储在变量sum中*/
}
printf(“%f”,总和);
}

观察
在使用x87 FPU(浮点单元)的处理器上,实际上有两种类型的堆栈。SS:SP指向的调用堆栈和x87 FPU寄存器堆栈。如果将某些内容推送到调用堆栈上,则弹出顶部元素的FPU堆栈指令只会从FPU寄存器堆栈中弹出。如果您用“代码>推斧< /Cords>推压堆栈上的某个东西,则不平衡调用堆栈,当内联程序集完成时,您应该考虑重新平衡它。您可以使用
pop ax
来执行此操作或
添加sp,2

做一个你从来都不
pop
push ax
似乎是一个麻烦的处方。而且你不能依赖数组的地址是
bp-8
。你在为什么编译器编程?@fuz:他们在使用turbo-c++3.0,根据问题你解决了你的问题吗?SS:SP堆栈的一个更明确的术语是“调用堆栈”与x87堆栈寄存器。