- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
作为编译器项目的一部分,我必须为 x86 编写 GNU 汇编器代码来比较浮点值。我试图找到有关如何在线执行此操作的资源,据我了解,它的工作原理如下:
假设我要比较的两个值是浮点堆栈上的唯一值,则 fcomi 指令将比较这些值并设置 CPU 标志,以便 je
, jne
, jl
, ... 可以使用指令。
我这么问是因为这只有时有效。例如:
.section .data
msg: .ascii "Hallo\n\0"
f1: .float 10.0
f2: .float 9.0
.globl main
.type main, @function
main:
flds f1
flds f2
fcomi
jg leb
pushl $msg
call printf
addl $4, %esp
leb:
pushl $0
call exit
不会打印“Hallo”,尽管我认为它应该,并且如果你切换 f1 和 f2 它仍然不会,这是一个逻辑矛盾。然而, je
和 jne
似乎工作正常。
我做错了什么?
PS:fcomip 只弹出一个值还是同时弹出两个值?
最佳答案
TL:DR:使用上方/下方条件(如无符号整数)来测试比较结果。
对于各种historical reasons (映射 from FP status word to FLAGS via fcom
/ fstsw
/ sahf
与 fcomi
(PPro 中的新功能)匹配),FP 比较集合 CF,而不是 OF/SF。另请参阅http://www.ray.masmcode.com/tutorial/fpuchap7.htm
现代 SSE/SSE2 标量与 FLAGS 进行比较 follow this as well ,与 [u]comis
/sd
。 (与 SIMD 比较不同,SIMD 比较有一个谓词作为指令的一部分,作为立即数,因为它们只为每个元素生成一个全零/全一结果,而不是一组标志。)
这一切都来自 Intel 64 and IA-32 Architectures Software Developer's Manuals 第二卷.
FCOMI
仅设置 CMP
所做的部分标志。您的代码有 %st(0) == 9
和 %st(1) == 10
。 (因为它们加载的是一个堆栈),引用第2A卷第3-348页的表格,您可以看到这种情况是“ST0 < ST(i)”,因此它将清除ZF和PF并设置CF。同时在第 pg 上。 3-544 卷。在图 2A 中,您可以看出 JG
的意思是“如果更大则跳短(ZF=0 且 SF=OF)”。换句话说,它正在测试符号、溢出和零标志,但 FCOMI
不会设置符号或溢出!
根据您希望跳转的条件,您应该查看可能的比较结果并决定何时跳转。
+--------------------+---+---+---+| Comparison results | Z | P | C |+--------------------+---+---+---+| ST0 > ST(i) | 0 | 0 | 0 || ST0 < ST(i) | 0 | 0 | 1 || ST0 = ST(i) | 1 | 0 | 0 || unordered | 1 | 1 | 1 | one or both operands were NaN.+--------------------+---+---+---+
I've made this small table to make it easier to figure out:
+--------------+---+---+-----+------------------------------------+| Test | Z | C | Jcc | Notes |+--------------+---+---+-----+------------------------------------+| ST0 < ST(i) | X | 1 | JB | ZF will never be set when CF = 1 || ST0 <= ST(i) | 1 | 1 | JBE | Either ZF or CF is ok || ST0 == ST(i) | 1 | X | JE | CF will never be set in this case || ST0 != ST(i) | 0 | X | JNE | || ST0 >= ST(i) | X | 0 | JAE | As long as CF is clear we are good || ST0 > ST(i) | 0 | 0 | JA | Both CF and ZF must be clear |+--------------+---+---+-----+------------------------------------+Legend: X: don't care, 0: clear, 1: set
In other words the condition codes match those for using unsigned comparisons. The same goes if you're using FMOVcc
.
If either (or both) operand to fcomi
is NaN, it sets ZF=1 PF=1 CF=1
. (FP compares have 4 possible results: >
, <
, ==
, or unordered). If you care what your code does with NaNs, you may need an extra jp
or jnp
. But not always: for example, ja
is only true if CF=0 and ZF=0, so it will be not-taken in the unordered case. If you want the unordered case to take the same execution path as below or equal, then ja
is all you need.
Here you should use JA
if you want it to print (ie. if (!(f2 > f1)) { puts("hello"); }
) and JBE
if you don't (corresponds to if (!(f2 <= f1)) { puts("hello"); }
). (Note this might be a little confusing due to the fact that we only print if we don't jump).
Regarding your second question: by default fcomi
doesn't pop anything. You want its close cousin fcomip
which pops %st0
. You should always clear the fpu register stack after usage, so all in all your program ends up like this assuming you want the message printed:
.section .rodata
msg: .ascii "Hallo\n\0"
f1: .float 10.0
f2: .float 9.0
.globl main
.type main, @function
main:
flds f1
flds f2
fcomip
fstp %st(0) # to clear stack
ja leb # won't jump, jbe will
pushl $msg
call printf
addl $4, %esp
leb:
pushl $0
call exit
关于x86 汇编器 : floating point compare,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7057501/
某些 AMD64/x86 命令需要立即值作为操作数(例如 imm8)。是否可以使用存储在某个寄存器中的值(例如 ah)来代替这个硬编码值? 例如: 如果我想移动 xmm 寄存器,可以使用 pslldq
您好,我正在修改汇编级编程。我有以下代码 mov al, 'H' call my_function my_function: mov ah,0x0e ;
x86 汇编程序例程通常以以下序言开始: push ebp ; Save ebp mov ebp, esp ; Set
这个问题已经有答案了: What is the purpose of XORing a register with itself? [duplicate] (7 个回答) 已关闭 2 年前。 我们有时
如果您不了解二进制,我知道 BCD 是更直观的数据类型。但我不知道为什么要使用这种编码,它好像没有多大意义,因为它浪费以 4 位表示(当表示大于 9 时)。 另外,我认为 x86 仅支持直接添加和替换
x86 汇编程序例程通常以以下序言开始: push ebp ; Save ebp mov ebp, esp ; Set
var a int[1]; var aa int[1]; aa = a; 假设我们想在 java jvm 中编译这样的东西。看起来人们只会做一个 ldc 1 newarray int astor
是否有任何编写 MIPS 汇编器的引用指南或教程? 最佳答案 如果您希望实际编写汇编程序,您需要知道您正在编写的平台的可执行文件的格式(例如 ELF ),那么您需要使用 MIPS instructio
我想写一个简单的 M.A.R.I.E.计算表达式 A x B + C x D 的程序. 现在,关于 Marie 汇编语言的信息并不多。我不确定是否有乘法?如果没有,我是否必须循环或其他东西才能使其成倍
我想知道为 NASM 编写汇编代码的格式是什么。有什么地方教的吗?我尝试在 NASM 上运行 MASM32 文件,但我认为它无法识别指令。 最佳答案 总是有 the manual . 关于linux
我想要的是类似 g++ 的东西,我可以在其中输入: compiler_name my_assembly_code.extention ...并让它编译我的汇编代码。它是 32 位还是 64 位并不重要
我正在为 8086 开发一个汇编程序。我的问题是如何将十六进制操作码转换为可执行文件,如 .EXE、.ELF、.COM、a.out 等。为此寻找链接/资源,汇编程序应该执行链接过程还是由操作系统自动?
我想编写 64 位 Windows 程序集(最好使用 NASM)。我在谷歌上看起来很不错,但似乎找不到 64 位 Windows 编译器。一些站点提到了 ml64,但它似乎不再包含在 VC++ 中。我
使用 GNU Binutils 声明汇编代码时,例如: .long MY_Label .long MY_Second_label 即使操作码和其他信息在地址空间中将它们分开,也可以在进行十六进制转储时
似乎单元测试这些天变得风靡一时,我知道你们中的许多人会想:“那么为什么不直接使用语言 X 和框架 Y 呢?”但我提出这个想法更多是为了证明概念,或者是出于对我早年计算机编程的怀念。 我正在研究使用 N
作为编译器项目的一部分,我必须为 x86 编写 GNU 汇编器代码来比较浮点值。我试图找到有关如何在线执行此操作的资源,据我了解,它的工作原理如下: 假设我要比较的两个值是浮点堆栈上的唯一值,则 fc
操作系统:Windows 10 CPU:英特尔酷睿 i5-5300U 架构:x64 我刚刚开始学习汇编语言。我使用了在线编译器,但今天我下载了NASM。我尝试编写这个将 10 乘以 15 的简单代码:
查看以下代码: (ebp-0x8 -> int) (ebp-0x4 -> int*) => 0x80483f3 : mov DWORD PTR [ebp-0x8],0x0 0x80483
我需要编写一个类似 CorFlags 的应用程序。如果我有程序集文件的路径,我该如何读取它的 CorFlags? 我特别需要知道程序集是 Any-CPU 还是仅 x86 我想避免使用反射加载程序集,因
查看以下代码: (ebp-0x8 -> int) (ebp-0x4 -> int*) => 0x80483f3 : mov DWORD PTR [ebp-0x8],0x0 0x80483
我是一名优秀的程序员,十分优秀!