2012-04-27 47 views
21

我目前正在編寫一個簡單的C編譯器,它將.c文件作爲輸入並生成彙編代碼(X86,AT & T語法)。 Everyting是好的,但是當我嘗試執行IDIVQ指令時,我得到一個浮點異常。這裏是我輸入:X86程序集 - 處理IDIV指令

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.htmlidivq%RBX應該產生%RAX 6/d(商)。但是我得到一個浮點異常,我似乎無法找到問題。

任何幫助將不勝感激!

+0

與這個問題無關,但是你應該在沒有調整esp寄存器的情況下執行'movq%rdi,-40(%rbp)'嗎?或者是因爲x64'紅色區域'而行嗎? – 2012-04-27 00:51:36

回答

23

的第一部分Mysticials的答案是正確的,idiv做128/64位除法,所以rdx,其中保留來自股息的高64位不得包含一個隨機值。但零延伸是錯誤的方式。

當你有簽署變量,你需要標誌延長raxrdx:rax。在Intel語法中有AT & T和cqo的具體說明,cqto轉換四倍至十進制)。 AFAIK更新版本的氣體接受這兩個名字。

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

+1有趣,我是如何忽略簽名部分的。 – Mysticial 2012-04-27 12:31:35

+0

的確,我正在運行我的測試,並在處理簽名值時遇到錯誤。我以前沒有看過這個指令,但現在似乎解決了這個問題。謝謝! – 2012-04-27 13:11:26

+0

@Mysticial甚至發生在最好的:-) – hirschhornsalz 2012-04-27 13:45:37

11

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

  • rax包含較低的64位股息。
  • rdx保留股息的高64位。

當商不符合64位時,它會拋出該浮點異常。

所以,你需要做的是零rdx

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

如果你正在處理的有符號整數,您還需要簽署延長raxrdx:rax,這意味着複製rax符號位到rdx每一位,並與CQO別名cqto完成:

movq %rdx, %rbx 
cqo 
idivq %rbx 
+5

清零rdx將使用正數,但在負rax的情況下可能需要rdx = -1 ......是不是? – marekb 2012-04-27 06:55:30

+5

我認爲marekb是正確的 - 不應該將'xorq' instrcution作爲'cqo'指令來將'rax'擴展爲'rdx:rax'嗎? – 2012-04-27 07:56:41

+0

在這種情況下,與簽名打字:我認爲是的。 – 2012-04-27 12:16:14