簡體   English   中英

Linux內核模塊中x87內聯匯編中的操作數類型不匹配

[英]Operand type mismatch in x87 inline assembly in a Linux kernel module

我真的想在Linux內核模塊中使用浮點運算,只是為了它。 我不想做任何花哨的事情,只需使用x87 trig指令和/或sqrt指令,然后將結果賦值給變量。 就是這樣。 到目前為止,我已經嘗試過:

float sqroot(float arg){
    float returnValue;
    asm(
     "fld %1\n"
     "fsqrt\n"
     "fst %0"
     :"=r"(returnValue) 
     : "r"(arg)
    );
    return returnValue;
}

這失敗了,產生了以下錯誤:

Error: operand type mismatch for `fld'
Error: operand type mismatch for `fst'

任何和所有幫助將不勝感激。

使用內核模塊中的x87將“正常工作”,但會靜默破壞用戶空間x87 / MMX狀態。 為什么我能夠在Linux內核模塊中執行浮點運算?

需要 kernel_fpu_begin() / kernel_fpu_end()來保證安全。


而不是從內聯asm加載/存儲,請求輸入並在x87寄存器堆棧的頂部生成輸出,並讓編譯器在需要時發出加載/存儲指令。 編譯器已經知道如何做到這一點,你只需要為sqrt指令本身使用內聯asm,你可以用這種方式向編譯器描述:

static inline
float sqroot(float arg) {
    asm("fsqrt"  : "+t"(arg) );
    return arg;
}

在Godbolt編譯器資源管理器中查看編譯器生成的asm)

寄存器約束必須告訴塊使用浮點寄存器。


或者完全避免內聯asm,使用可以內聯的GNU C內置函數

您需要使用-fno-math-errno將內置實際內聯為fsqrtsqrtss ,而不使用回退來call sqrtf以獲取將導致NaN的輸入。

static inline
float sqroot_builtin(float arg) {
    return __builtin_sqrtf(arg);
}

對於x86-64,我們得到sqrtss %xmm0, %xmm0 / ret而對於i386,我們得到fld / fsqrt / ret (參見上面的Godbolt鏈接)。 恆定傳播通過__builtin_sqrt和其他優化工作。


編輯:納入@ iwillnotexist-idontexist的觀點(重新加載)。

另外,如果是我,我會在聲明中添加static inline並將其放在頭文件中。 這將允許編譯器更智能地管理寄存器並避免堆棧幀開銷。

(我也很想將float改為double 。否則,你將丟棄實際浮點指令中使用的額外精度。雖然如果你最終經常將值存儲為float ,那么將會有一個額外的cvtpd2ps指令cvtpd2ps ,如果你將參數傳遞給printf ,例如,這實際上避免cvtps2pd 。)

但Linux內核kprintf都沒有double轉換。

如果使用-mfpmath=387 (32位代碼的默認值)進行編譯, -mfpmath=387內聯后值將保留在80位x87寄存器中。 但是,對於使用64位默認值-mfpmath=sse的64位代碼,這將導致在加載回XMM寄存器時舍入為float

kernel_fpu_begin()保存完整的FPU狀態,並且避免使用SSE寄存器,只使用x87不會使它或最終的FPU恢復時更便宜地返回用戶空間。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM