【问题标题】:How to add two numbers, integer and a float in NASM?如何在 NASM 中添加两个数字,整数和浮点数?
【发布时间】:2017-02-11 22:09:54
【问题描述】:

我有这段代码假设添加两个数字,一个浮点数(3.25)和一个整数(2)。

已编辑:

extern _printf, _scanf
global _main
section .bss
  num1: resb 4
section .data
  format_num: db "%f", 10, 0
section .text
_main:

  mov dword [num1], __float32__(3.25)
  add num1,  2

  sub esp, 8
  fld dword [num1]
  mov dword [num1], eax
  fstp qword [esp]
  push format_num
  call _printf
  add esp, 12

ret

我得到的输出是:

test.asm:11:error: 操作码和操作数的组合无效

我期望的输出是:

5.250000

【问题讨论】:

  • 在存储任何内容之前从 num1 加载 0,然后将该 0 放在堆栈上。顺便说一句,您不必对浮点加载和存储执行此操作。
  • @harold 我编辑了问题,谢谢,我还有一个错误。
  • 好的,现在你正在尝试添加一个常量
  • @harold 是的,你是对的。
  • 即使你解决了这个问题,它也不会给你 5.25,因为你正在重新解释将 float 转换为 int,然后进行普通的位向量加法。所以你会得到 0x40500002,解释为 3.250000476837158。

标签: gcc assembly x86 nasm x87


【解决方案1】:

x87 FPU 的一个很好的教程超出了 Stackoverflow 的范围,但我可以推荐 MASM forums 上的那个。另一个好的来源是Intel Instruction Set Reference。特别是大多数以F 开头的函数都是与 x87 浮点单元 (FPU) 相关的指令。

一般来说,您不能只将浮点值添加到整数。它们是两种不同的表示。您可以做的是将整数转换为浮点值,然后用它进行浮点计算。特别是以FI 开头的指令是浮点运算,涉及将整数内存操作数转换为浮点数。

给猫剥皮的方法有很多,但是如果您查看上面链接的 FPU 教程,您可能会意识到这样做是一种简单的方法:

sub esp, 8           ; Allocate space on stack to store integer
mov dword [esp], 2   ; Move the 32-bit integer value onto stack temporarily
fild dword [esp]     ; Load integer 2 from stack into top of FPU stack at st(0)
                     ;    Converting it to 2.0 in the process
mov dword [esp], __float32__(3.25)
                     ; Move 3.25 onto stack temporarily
fadd dword [esp]     ; Add 3.25 to st(0). Result in st(0). So st(0)=5.25
fstp qword [esp]     ; Store 64-bit double to stack for printf and pop FPU stack.

我没有使用全局变量将值临时存储在主内存中,而是使用我们保留的堆栈空间作为临时暂存区来加载/操作 x87 FPU。

如果您使用的 CPU 支持 SSE2 指令集(这包括任何处于 32 位模式的 X86-64 处理器),那么您还有其他选择。一种是使用 SIMD 指令和寄存器进行 32 位和 64 位浮点运算。使用指令集参考,您会发现一些有用的指令,例如:

  • cvtsi2sd : 将 Dword 整数转换为标量双精度 FP 值
  • cvtss2sd : 将标量单精度 FP 值转换为标量双精度 FP 值
  • addsd:添加标量双精度浮点值
  • movsd:移动标量双精度浮点值

标量单精度 FP 值是 32 位浮点数。标量双精度是 64 位双精度。

sub esp, 8
mov dword [esp], 2      ; Load integer 2 (32-bit signed value) onto stack temporarily
cvtsi2sd xmm0, [esp]    ; Convert 2 on stack to 64-bit float and store in XMM0
mov dword [esp], __float32__(3.25)
                        ; Load 32-bit float value of 3.25 onto stack
cvtss2sd xmm1, [esp]    ; Load 32-bit single and convert it to 64-bit double. Store in XMM1
addsd xmm0, xmm1        ; Add 64-bit float in XMM0 and XMM1 store XMM0
movsd qword [esp], xmm0 ; Move 64-bit float back onto stack to be printed by printf

【讨论】:

  • 虽然fld1+faddp 比之前的示例代码更快,但更快(也更明显)的方法是使用fld 加载常量2.0。它只会消耗二进制文件中的一小部分空间。
【解决方案2】:

解决办法是:

extern _printf
global _main
section .bss
  num1: resb 4
  num2: resb 4
section .data
  format_float: db "The result is %f", 10, 0
_main:

  mov dword [num1], 2
  mov dword [num2], __float32__(3.25)

  sub esp, 8
  fild dword [num1]
  fadd dword [num2]
  fstp qword [esp]
  push format_float
  call _printf
  add esp, 12

ret

我得到的输出是:

5.250000

fild 将 2 作为 2.0000000 推入 ST0,然后 fadd 可以添加两个浮点数。结果是一个浮点数。 int + float = float.

对不起,我的英语不好。

【讨论】:

    猜你喜欢
    • 2014-08-23
    • 2013-02-14
    • 1970-01-01
    • 1970-01-01
    • 2013-07-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多