Assembly 我能从EAX/RAX中得到一个整数到FPU寄存器,比如st0吗?

Assembly 我能从EAX/RAX中得到一个整数到FPU寄存器,比如st0吗?,assembly,x86,nasm,fpu,Assembly,X86,Nasm,Fpu,我目前在大学里从事一个小型汇编项目。现在我的问题是,是否有可能从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 ;

我目前在大学里从事一个小型汇编项目。现在我的问题是,是否有可能从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
通常,通过在函数开始时在堆栈框架中为此类传输分配一些存储空间,可以避免对堆栈指针的胡乱操作。

例如(对于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
不应出现输入/输出,只需清除退出即可。使用调试器进行检查,单步执行每条指令,并观察堆栈(由rsp指向)内存区域、x87 FPU“堆栈”(
st0..st7
值)以及
结果
地址处的内存


编辑:

我的理解是,每个浮点操作都必须由FPU完成

绝对不是,如果你这么认为,你仍然没有掌握计算机的全部原理。计算机中的一切都被编码为比特序列(值0或1)。所以,当你的陈述被翻译成这个基本前提时,你的陈述是“我这里有一个位模式,那里有另一个位模式,一个定义良好的操作,描述了某个操作应该产生哪一个第三位模式,但如果我没有FPU,我就做不到”——这听起来合乎逻辑吗

手动相乘两个IEEE-754“double”值需要大量的工作(数十条x86指令),您需要提取这些值的指数和尾数部分,分别相乘尾数和指数,然后对值进行规格化/钳制,并将有效的IEEE-754“double”类型结果合成回64位,但如果没有FPU,它肯定是可行的,这就是在80486DX和奔腾CPU使硬件FPU变得通用之前,x87的软件仿真一直在做的事情(80486SX和以前的80286和80386没有内置x87,它作为单独的昂贵协处理器芯片出售)。在386年代,大多数人确实使用x87的软件模拟器来运行需要FPU的专用软件

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


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

是的。对于旧的x87代码
push-rax
fild-qword[rsp]
add-rsp,8
,但如果CPU确实支持64b,它必须(?)也有某种SSE,所以使用x87很奇怪…为什么?你所说的SEE是什么意思D@J.B.SSE是自奔腾III以来最新的浮点单元。这是您通常在64位代码中使用的。wiki关于SSE和类似的CPU扩展:使用SSE2
cvtsi2sd xmm0,rax
并忘记x87,除非您需要80位FP(64位尾数)。如果我在主堆栈上有一个64位的double,并且我想将该值获取到st0,那么是否允许在RAX中弹出64位值以通过st0中的此方法获取该值?或者是否存在另一个“直接”方法?或者我可以用pop st0作为例子吗?@J.B.好吧,我回答的第一步是将
rax
中的值存储在堆栈上,所以我不确定通过将值从堆栈移动到
rax
然后大概返回堆栈来实现什么。你可以只做
fld qword[rsp]
[rsp]
安装到x87堆栈上。有关可用指令的全面列表,请参阅英特尔手册。@J.B.没有此类指令;
pop
仅以
pop r64
pop r16
pop segr
pop r/m64
的形式存在。在询问您是否可以执行某项操作之前,请尝试检查手册,如果您询问的指令是存在的。堆栈溢出实际上不能代替您阅读手册。@J.B.地址是整数,根据经验,您希望将它们保存在通用寄存器中,如
rax
rbx
,等等。假设您要加载的数据地址在
rax
中,您只需编写
fld qword[rax]
从该地址加载双精度。在开始编程x87 FPU之前,熟悉x86汇编的基本原理可能是个好主意。谢谢!这非常有用;)我的陈述有点错误。我只是想说,没有其他简单的方法可以将两个浮点相乘numbers@J.B.嗯,您可以使用SSE浮点单位。它的使用稍微简单一些。@J.B.另外,它还取决于您所说的“浮点”是什么意思数字,如果您指的是IEEE-754编码,那么是的,x87和SSE是x86-64上最简单的方式。但是您可以以不同的方式编码浮点值,例如以“定点”方式,或者使用一些自定义打包方案作为单独的数字(通常由SQL或任意精度数学库中的“十进制”类型使用),则代码在没有x87或SSE的情况下可能会更简单,例如,“定点”方式是专门为没有硬件FPU的CPU设计的,或者当您只需要具有固定粒度的特定值范围时。