X86程序集 - 处理IDIV指令

时间:2012-04-27 00:20:40

标签: c assembly compiler-construction x86

我目前正在编写一个简单的C编译器,它将.c文件作为输入并生成汇编代码(X86,AT& T语法)。 一切都很好,但是当我尝试执行IDIVQ指令时,我得到一个浮点异常。这是我的意见:

int mymain(int x){
  int d;
  int e;
  d = 3;
  e = 6 / d;
  return e;
}

这是我生成的代码:

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

根据http://www.cs.virginia.edu/~evans/cs216/guides/x86.html idivq%rbx 应在%rax 中产生6 / d(商)。但是我得到了一个浮点异常,我似乎无法找到问题。

非常感谢任何帮助!

2 个答案:

答案 0 :(得分:23)

Mysticials的第一部分回答是正确的,idiv执行128/64位除法,因此保持被除数的高64位的rdx的值不得包含随机值。但零延伸是错误的方法。

如果您有签名变量,则需要签名rax扩展为rdx:rax。在AT& T中有cqto转换quad到oct ),在Intel语法中有cqo的特定指令。 AFAIK更新版本的气体接受这两个名称。

movq    %rdx, %rbx
cqto                  # sign extend rax to rdx:rax
idivq   %rbx

答案 1 :(得分:11)

idivq指令用操作数除以128位整数(rdx:rax)。

  • rax保留被除数的低64位。
  • rdx保留被除数的高64位。

当商不符合64位时,它将抛出该浮点异常。

所以你需要做的是归零rdx

movq    %rdx, %rbx
xorq    %rdx, %rdx    # zero "rdx"
idivq   %rbx

如果您正在处理有符号整数,则还需要将rax扩展为rdx:rax,这意味着将rax符号位复制到rdx的每个位,用cqo别名cqto完成:

movq    %rdx, %rbx
cqo
idivq   %rbx