我可以从我的 EAX/RAX 得到一个 int 到 FPU 的寄存器,比如 st0 吗?

Can I get a int from my EAX/RAX to a register of the FPU like st0?

我目前正在大学从事一个小型汇编程序项目。现在我的问题是,是否有可能从我的 EAX/RAX 寄存器到我的 FPU 寄存器之一(如 st0)获得用户提供的乘法 (int) 的 skalar?我正在使用 NASM 语法。

谢谢

没有办法直接将整数寄存器的内容传送到x87浮点寄存器,必须通过内存。典型代码如下所示:

PUSH RAX         ; push RAX on the stack
FILD QWORD [RSP] ; load eight byte integer onto FP stack
ADD RSP,8        ; release storage from stack

您通常可以通过在函数开头为堆栈帧中的此类传输分配一些存储空间来避免 fiddle 处理堆栈指针。

示例(64b linux 和 NASM)用于您在 fuz 的回答下的评论中的计算:

; file: x87test.asm
section .data
    some_value  dq 1234.5678    ; double value

section .bss
    result      resq    1       ; reserve memory for result double
    result2     resq    1       ; reserve memory for second result (code variant 2)

section .text
    global _start
    _start:
        ; initializations of example
        finit                       ; initialize FPU
        ; store "factor" into the stack
        mov     rax,__float64__(51.6)
        push    rax
        ; "value" is already in memory at address `some_value`

        ; load the FPU-stack with factor and value
        fld     qword [some_value]  ; st0 = value
        fld     qword [rsp]         ; st0 = factor, st1 = value
        add     rsp, 8              ; release the CPU stack space occupied by factor (by "push rax")

        ; Do the calculation with st0 and st1
        fmulp   st1                 ; st0 = st0 * st1 with "pop" (the FP stack holds only "st0")
            ; "fmul" without "p" would keep the "st1" intact (value) and st0 = product
        fstp    qword [result]      ; "pop" st0 into memory at "result" address

        ;--------------------------------------------------------------------------------------------
        ; other variant, skipping the load of second value, as the FMUL can use memory argument too
        ; store "factor" into the stack
        mov     rax,__float64__(7.89)
        push    rax

        ; load the FPU-stack with value
        fld     qword [some_value]  ; st0 = value
        fmul    qword [rsp]         ; st0 = value * factor
        add     rsp, 8              ; release the CPU stack space occupied by factor (by "push rax")
        fstp    qword [result2]     ; "pop" st0 into memory at "result2" address

        ;--------------------------------------------------------------------------------------------
        ; exit back to linux
        mov     eax, 60
        xor     edi, edi
        syscall

构建并执行:

nasm -f elf64 x87test.asm -l x87test.lst -w+all
ld -b elf64-x86-64 -o x87test x87test.o
./x87test

不应该发生 input/output,只需干净退出。检查调试器,单步执行每条指令,并观察堆栈(由 rsp 指向)内存区域和 x87 FPU "stack"(st0 .. st7 值),以及 [=14 处的内存=] 地址.


编辑:

I have the understanding that every floatingpoint operation has to be done by the FPU.

绝对不是,如果你这么想,你还是漏掉了计算机的全部原理。计算机中的所有内容都被编码为位序列(值 0 或 1)。因此,当翻译成这个基本前提时,您的陈述是 "I have one bit pattern here, other bit pattern there, a well defined operation describing which third bit pattern some operation should produce, but I can't do it if I don't have FPU" - 听起来合乎逻辑吗?

手动将两个 IEEE-754 "double" 值相乘需要大量工作(数十条 x86 指令),您需要提取这些值的指数和尾数部分,分别将尾数和指数相乘,然后normalize/clamp 值并将有效的 IEEE-754 "double" 类型结果组合成 64 位,但没有 FPU 绝对可行,这就是 x87 的软件仿真在 80486DX 和 Pentium 之前一直所做的 CPUs 使硬件 FPU 变得普遍(80486SX 和前身 80286 和 80386 没有内置 x87,它作为单独的昂贵协处理器芯片出售)。在386时代,大多数人确实使用x87的SW仿真器来运行需要FPU的专用软件。

问题是,如果你了解某些东西(输入信息)是如何以位编码的,以及你想要什么作为输出信息(以位编码),你就可以描述一些位操作运算的算法,将输入值到输出值,然后你可以通过任何符合图灵的 CPU 来实现这种算法(尽管对于一些非常有限的系统,如 8 位 CPUs,创建 IEEE-754 double* 可能是主要的 PITA*双重计算,因为它可能需要数百条指令,或者如果内存太有限而无法同时容纳这么多位,您甚至可能 运行 资源不足。

x87 FPU 只是浮点运算的硬件加速解决方案,它不是唯一可能的计算方法。