1 回答
TA贡献1786条经验 获得超11个赞
该错误是您执行此操作:
fstp dword[b]
这会覆盖的值b,因此,下次调用该函数时,常量是错误的。在整个程序的输出中,这显示为最右边的评估是唯一正确的评估,因为编译器printf从右到左评估了参数。(可以按任意顺序对多参数函数的参数求值。)
您应该使用该.rodata部分作为常量。那么程序将崩溃而不是覆盖常量。
您可以避免使用fdivr而不是来存储和重新加载中间值fdiv。
hyp:
fld DWORD PTR [b]
fsub DWORD PTR [esp+4]
fdivr DWORD PTR [a]
fadd DWORD PTR [c]
ret
或者,执行Forth程序员会做的事情,并在其他所有内容之前加载常量1,因此在需要时将其保存在ST(1)中。这使您可以使用fld1而不是将1.0放入内存中。
hyp:
fld1
fld DWORD PTR [b]
fsub DWORD PTR [esp+4]
fdivp
fadd DWORD PTR [c]
ret
您不需要发出finit,因为ABI保证在流程启动期间已经完成了此操作。您不需要为此函数设置EBP,因为它不会调用任何函数(该术语的术语是“叶子过程”),也不需要堆栈上的任何暂存空间。
如果您使用的是现代CPU,另一种选择是使用较新的SSE2指令。这将为您提供普通的寄存器,而不是操作数堆栈,并且还意味着计算实际上是全部完成,float而不是80位扩展,这可能非常重要-一些复杂的数值算法,如果它们的浮点精度高于整数,则会出错。设计师期望的。但是,由于您使用的是32位ELF ABI,因此返回值仍需要在ST(0)中结束,并且SSE和x87寄存器之间没有直接移动指令,因此必须遍历内存。抱歉,我不知道如何用Intel语法编写SSE2指令。
hyp:
subl $4, %esp
movss b, %xmm1
subss 8(%esp), %xmm1
movss a, %xmm0
divss %xmm1, %xmm0
addss c, %xmm0
movss %xmm0, (%esp)
flds (%esp)
addl $4, %esp
ret
在64位ELF ABI中,在XMM0中有浮点返回值(默认情况下也将参数传递到寄存器中),这就是
hyp:
movss b(%rip), %xmm1
subss %xmm0, %xmm1
movss a(%rip), %xmm0
divss %xmm1, %xmm0
addss c(%rip), %xmm0
ret
- 1 回答
- 0 关注
- 246 浏览
添加回答
举报