0 x86 assembly nasm cpu-registers x87
我试图了解FPU,但我很困惑。问题是,当我从了解这里,FPU都有自己的堆栈。但例如在以下代码(NASM)中:
global _main
extern _printf
section .data
hellomessage db `Hello World!\n`, 10, 0
numone dd 1.2
digitsign db '%f', 0xA, 0
section .text
_main:
;Greet the user
push hellomessage
call _printf
add esp,4
sub esp, 8
fld dword[numone]
fstp qword[esp]
push digitsign
call _printf
add esp, 12
ret
Run Code Online (Sandbox Code Playgroud)
我必须要sub esp, 8为“腾出空间”的行double,否则程序会崩溃。但是通过这样做,我更改了“常规堆栈”的指针,这与我关于两个独立堆栈的想法没有任何意义。
我确定我不了解某些内容,但是我不知道这是什么。
x87加载/存储使用与其他所有操作相同的内存地址。x87堆栈是寄存器st0..st7,根本不是内存。
请参阅SIMPLY FPU:第一章。1 FPU内部的说明,以获取有关x87寄存器堆栈的详细信息。
fstp qword[esp]将8个字节存储到常规调用堆栈中,如mov [esp], eax/ mov [esp+4], edx那样。 与x87加载/存储指令一起使用时,寻址模式不会改变含义! 即您的进程只有一个地址空间。
因此,如果您删除了sub esp, 8,fstp则会覆盖您的寄信人地址。
然后在函数末尾,add esp, 12将esp指向该字节的8个字节留在上面,因此ret会在EIP中弹出一些垃圾,然后在尝试从该错误地址中获取代码时进行段错误,或者将其中的字节解码为段错误的指令。
在main回寄地址上方,您会找到argc,然后再选择char **argv。它是指向指针数组的指针,因此将其用作返回地址将意味着您将指针值作为代码执行。(如果我说得对。)
使用调试器可以一步一步查看寄存器和内存的情况。
注意,add esp,4/ sub esp, 8有点愚蠢。 add esp, +4 - 8(即add esp, -4)将是一种通过一条指令进行自我记录的方式。