[英]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)
寄存器約束必須告訴塊使用浮點寄存器。
您需要使用-fno-math-errno
將內置實際內聯為fsqrt
或sqrtss
,而不使用回退來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.