Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/assembly/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Assembly 程序集x86 FPU-堆栈混乱_Assembly_X86_Nasm_Cpu Registers_X87 - Fatal编程技术网

Assembly 程序集x86 FPU-堆栈混乱

Assembly 程序集x86 FPU-堆栈混乱,assembly,x86,nasm,cpu-registers,x87,Assembly,X86,Nasm,Cpu Registers,X87,我正在努力理解FPU,我很困惑。问题是,据我所知,FPU有自己的堆栈。但例如,在本代码(NASM)中: 我必须让子esp,8行为双精度腾出空间,否则程序崩溃。但通过这样做,我改变了“常规堆栈”的指针,这与我的两个独立堆栈的想法不符 我肯定我不明白什么,但我不知道这是什么 FPU有一个“寄存器堆栈”(而不是RAM中的堆栈) 本质上;有8个寄存器(我们称它们为FPU\u R0,FPU\u R1,…,FPU\u R7)和8个名称(假设它们是st0,st1,…,st7),还有一个“FPU堆栈顶部”值确定

我正在努力理解FPU,我很困惑。问题是,据我所知,FPU有自己的堆栈。但例如,在本代码(NASM)中:

我必须让
子esp,8
行为
双精度
腾出空间,否则程序崩溃。但通过这样做,我改变了“常规堆栈”的指针,这与我的两个独立堆栈的想法不符

我肯定我不明白什么,但我不知道这是什么

FPU有一个“寄存器堆栈”(而不是RAM中的堆栈)

本质上;有8个寄存器(我们称它们为
FPU\u R0
FPU\u R1
,…,
FPU\u R7
)和8个名称(假设它们是
st0
st1
,…,
st7
),还有一个“FPU堆栈顶部”值确定哪个名称用于哪个寄存器

您可以将新值推送到FPU寄存器堆栈上。例如:

    fld qword [A]     ;st0 = FPU_R7 = A
    fld qword [B]     ;st0 = FPU_R6 = B, st1 = FPU_R7 = A
    fld qword [C]     ;st0 = FPU_R5 = C, st1 = FPU_R6 = B, st2 = FPU_R7 = A
                      ;st0 = FPU_R5 = C, st1 = FPU_R6 = B, st2 = FPU_R7 = A
    fstp qword [C]    ;st0 = FPU_R6 = B, st1 = FPU_R7 = A
    fstp qword [B]    ;st0 = FPU_R7 = A
    fstp qword [A]
可以从FPU寄存器堆栈中弹出值。例如:

    fld qword [A]     ;st0 = FPU_R7 = A
    fld qword [B]     ;st0 = FPU_R6 = B, st1 = FPU_R7 = A
    fld qword [C]     ;st0 = FPU_R5 = C, st1 = FPU_R6 = B, st2 = FPU_R7 = A
                      ;st0 = FPU_R5 = C, st1 = FPU_R6 = B, st2 = FPU_R7 = A
    fstp qword [C]    ;st0 = FPU_R6 = B, st1 = FPU_R7 = A
    fstp qword [B]    ;st0 = FPU_R7 = A
    fstp qword [A]

x87加载/存储使用与其他所有操作相同的内存地址。 x87堆栈是寄存器st0..st7,而不是内存

有关x87寄存器堆栈的详细信息,请参阅

fstp qword[esp]
将8个字节存储到常规调用堆栈中,如
mov[esp],eax
/
mov[esp+4],edx
与x87加载/存储指令一起使用时,寻址模式不会改变其含义即,您的进程只有一个地址空间


因此,如果您删除
子esp,8
,您的
fstp
将覆盖您的回信地址

然后在函数结束时,
add esp,12
将使
esp
指向8个字节以上,因此
ret
将向EIP中弹出一些垃圾,然后您在尝试从该错误地址提取代码时将其分段,或者将其中的字节解码为分段错误的指令

main
的返回地址上方,您将找到
argc
,然后找到
char**argv
。它是指向指针数组的指针,因此使用它作为返回地址意味着您将指针值作为代码执行。(如果我没弄错的话。)

使用调试器查看单步执行时寄存器和内存发生的情况。



请注意,
添加esp,4
/
子esp,8
有点傻
AddESP,+4-8
(即,
AddESP,-4
)将是一种使用一条指令实现这一点的自记录方式。

,因为您使用了从FPU堆栈传输到CPU堆栈的
fstp qword[esp]
。所以你们需要CPU堆栈上的空间。我认为这个答案不值得否决。第一句是对OP的困惑的回答,其余的是演示x87堆栈是如何工作的(它是一个寄存器堆栈,与内存中的调用堆栈无关。)这不是一个很好的答案,这就是为什么我写了自己的;它几乎没有回答这个问题。但它所说的一切实际上都是正确的。(呃,除了st0在几个注释中被重复。我认为您有一个复制/粘贴+编辑错误,并且忘记了增加您的变量名)。展示
fmulst3
或其他东西也不错。这个答案是完整答案的重要部分,谁否决了这个,为什么?它没有从OPs问题中解释关于常规堆栈的任何内容,但正确地解释了FPU“堆栈”部分,其本身在技术上应该足以消除OPs的混淆并解决其问题。(关于这个答案的质量,甚至显示
fst
fstp
之间的差异也有一定的意义)(编辑2:我也没有得到OP的否决票,这有点低,因为在第一次阅读FPU后可能会感到困惑,但问题是相当清楚的,以显示困惑是什么,以及尝试了什么)这个答案当然不值得投反对票。虽然它没有彼得·科德斯的完整,但我会投票表决。尽管如此,我还是非常感谢@Brendan在这方面花费的时间和精力:)问题是为什么需要
子esp
,而不是FPU堆栈如何工作。这个答案并没有提供任何洞察。但这本身并没有错。