I am currently writing a simple C compiler, that takes a .c file as input and generates assembly code (X86, AT&T syntax). Everyting is good, but when I try to execute a IDIVQ instruction, I get a floating-point exception. Here's my input:
我目前正在编写一个简单的C编译器,它接受. C文件作为输入并生成汇编代码(X86, AT&T语法)。一切都很好,但是当我尝试执行IDIVQ指令时,会得到一个浮点异常。这是我的输入:
int mymain(int x){
int d;
int e;
d = 3;
e = 6 / d;
return e;
}
And here is my generated code:
这是我生成的代码:
mymain:
.LFB1:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
movq %rsp, %rbp
.cfi_offset 6, -16
.cfi_def_cfa_register 6
movq %rdi, -40(%rbp)
movq $3, -8(%rbp)
movq $6, %rax
movq -8(%rbp), %rdx
movq %rdx, %rbx
idivq %rbx
movq %rax, -16(%rbp)
movq -16(%rbp), %rax
leave
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE1:
.size mymain, .-mymain
According to http://www.cs.virginia.edu/~evans/cs216/guides/x86.html, idivq %rbx should produce 6/d (the quotient) in %rax. But I'm getting a floating-point exception, and I can't seem to find the problem.
根据http://www.cs.virginia.edu/~evans/cs216/guides/x86.html, idivq %rbx应该在%rax中产生6/d(商)。但是我有一个浮点异常,我似乎找不到问题所在。
Any help will be much appreciated!
如有任何帮助,我们将不胜感激!
2 个解决方案
#1
23
The first part of Mysticials answer is correct, idiv
does a 128/64 bit division, so the value of rdx
, which holds the upper 64 bit from the dividend must not contain a random value. But a zero extension is the wrong way to go.
神秘的答案的第一部分是正确的,idiv做了128/64位的除法,所以rdx的值,它持有股息的上64位,不能包含一个随机值。但是0的扩展是错误的。
As you have signed variables, you need to sign extend rax
to rdx:rax
. There is a specific instruction for this, cqto
(convert quad to oct) in AT&T and cqo
in Intel syntax. AFAIK newer versions of gas accept both names.
当你有符号变量时,你需要将rax扩展到rdx:rax。这里有一个具体的指令,cqto(转换quad到oct)在AT&T和cqo在Intel语法。AFAIK新版本的气体接受这两个名字。
movq %rdx, %rbx
cqto # sign extend rax to rdx:rax
idivq %rbx
#2
11
The idivq
instruction divides a 128-bit integer (rdx:rax
) by the operand.
idivq指令将128位整数(rdx:rax)除以操作数。
-
rax
holds the lower 64-bits of the dividend. - rax持有较低的64位股息。
-
rdx
holds the upper 64-bits of the dividend. - rdx拥有股息的上64位。
When the quotient doesn't fit into 64-bits, it will throw that floating-point exception.
当商不适合64位时,它将抛出浮点异常。
So what you need to do is to zero rdx
:
所以你需要做的是把rdx:
movq %rdx, %rbx
xorq %rdx, %rdx # zero "rdx"
idivq %rbx
If you are dealing with signed integers, you also need to sign extend rax
to rdx:rax
, that means copying the rax
sign bit to every bit of rdx
and is accomplished with cqo alias cqto:
如果要处理有符号的整数,还需要将rax符号扩展到rdx:rax,这意味着将rax符号位复制到每一个rdx,并使用cqo别名cqto完成:
movq %rdx, %rbx
cqo
idivq %rbx
#1
23
The first part of Mysticials answer is correct, idiv
does a 128/64 bit division, so the value of rdx
, which holds the upper 64 bit from the dividend must not contain a random value. But a zero extension is the wrong way to go.
神秘的答案的第一部分是正确的,idiv做了128/64位的除法,所以rdx的值,它持有股息的上64位,不能包含一个随机值。但是0的扩展是错误的。
As you have signed variables, you need to sign extend rax
to rdx:rax
. There is a specific instruction for this, cqto
(convert quad to oct) in AT&T and cqo
in Intel syntax. AFAIK newer versions of gas accept both names.
当你有符号变量时,你需要将rax扩展到rdx:rax。这里有一个具体的指令,cqto(转换quad到oct)在AT&T和cqo在Intel语法。AFAIK新版本的气体接受这两个名字。
movq %rdx, %rbx
cqto # sign extend rax to rdx:rax
idivq %rbx
#2
11
The idivq
instruction divides a 128-bit integer (rdx:rax
) by the operand.
idivq指令将128位整数(rdx:rax)除以操作数。
-
rax
holds the lower 64-bits of the dividend. - rax持有较低的64位股息。
-
rdx
holds the upper 64-bits of the dividend. - rdx拥有股息的上64位。
When the quotient doesn't fit into 64-bits, it will throw that floating-point exception.
当商不适合64位时,它将抛出浮点异常。
So what you need to do is to zero rdx
:
所以你需要做的是把rdx:
movq %rdx, %rbx
xorq %rdx, %rdx # zero "rdx"
idivq %rbx
If you are dealing with signed integers, you also need to sign extend rax
to rdx:rax
, that means copying the rax
sign bit to every bit of rdx
and is accomplished with cqo alias cqto:
如果要处理有符号的整数,还需要将rax符号扩展到rdx:rax,这意味着将rax符号位复制到每一个rdx,并使用cqo别名cqto完成:
movq %rdx, %rbx
cqo
idivq %rbx