使用 FFI 导入编译的 Haskell 库在导入 GHCI 时无效
我在 Ubuntu 10.04 中使用 GHC 6.12.1
当我尝试使用 FFI 语法进行静态存储时,只有在解释模式(即 GHCI)下运行的模块才能正常工作。编译的模块具有无效指针,并且不起作用。我想知道是否有人可以重现该问题,这是否是我的代码或 GHC 中的错误,以及(如果是后者)这是否是一个已知问题。
我使用 sys_siglist 是因为它存在于我系统上的标准库中,但我不认为实际使用的存储很重要(我在编写 libidn 的绑定时发现了这一点)。如果有帮助,sys_siglist
在
中定义为:
extern __const char *__const sys_siglist[_NSIG];
我认为这种类型可能是问题所在,所以我也尝试将其包装在普通的 C 过程中:
#include<stdio.h>
const char **test_ffi_import()
{
printf("C think sys_siglist = %X\n", sys_siglist);
return sys_siglist;
}
但是,导入不会改变结果,并且 printf()
调用会打印与 show siglist_a
相同的指针值。
我怀疑这与静态和动态库加载有关。
更新:#haskell 中的某人建议这可能是 64 位特定的;如果有人尝试复制它,你能在评论中提到你的架构以及它是否有效吗?
代码如下:
-- A.hs
{-# LANGUAGE ForeignFunctionInterface #-}
module A where
import Foreign
import Foreign.C
foreign import ccall "&sys_siglist"
siglist_a :: Ptr CString
--
-- B.hs
{-# LANGUAGE ForeignFunctionInterface #-}
module B where
import Foreign
import Foreign.C
foreign import ccall "&sys_siglist"
siglist_b :: Ptr CString
--
-- Main.hs
{-# LANGUAGE ForeignFunctionInterface #-}
module Main where
import Foreign
import Foreign.C
import A
import B
foreign import ccall "&sys_siglist"
siglist_main :: Ptr CString
main = do
putStrLn $ "siglist_a = " ++ show siglist_a
putStrLn $ "siglist_b = " ++ show siglist_b
putStrLn $ "siglist_main = " ++ show siglist_main
peekSiglist "a " siglist_a
peekSiglist "b " siglist_b
peekSiglist "main" siglist_main
peekSiglist name siglist = do
ptr <- peekElemOff siglist 2
str <- maybePeek peekCString ptr
putStrLn $ "siglist_" ++ name ++ "[2] = " ++ show str
我期望类似这样的输出,其中所有指针值相同且有效:
$ runhaskell Main.hs
siglist_a = 0x00007f53a948fe00
siglist_b = 0x00007f53a948fe00
siglist_main = 0x00007f53a948fe00
siglist_a [2] = Just "Interrupt"
siglist_b [2] = Just "Interrupt"
siglist_main[2] = Just "Interrupt"
但是,如果我编译 A.hs (使用 ghc -c A.hs ),那么输出更改为:
$ runhaskell Main.hs
siglist_a = 0x0000000040378918
siglist_b = 0x00007fe7c029ce00
siglist_main = 0x00007fe7c029ce00
siglist_a [2] = Nothing
siglist_b [2] = Just "Interrupt"
siglist_main[2] = Just "Interrupt"
I am using GHC 6.12.1, in Ubuntu 10.04
When I try to use the FFI syntax for static storage, only modules running in interpreted mode (ie GHCI) work properly. Compiled modules have invalid pointers, and do not work. I'd like to know whether anybody can reproduce the problem, whether this an error in my code or GHC, and (if the latter) whether it's a known issue.
I'm using sys_siglist
because it's present in a standard library on my system, but I don't believe the actual storage used matters (I discovered this while writing a binding to libidn). If it helps, sys_siglist
is defined in <signal.h>
as:
extern __const char *__const sys_siglist[_NSIG];
I thought this type might be the problem, so I also tried wrapping it in a plain C procedure:
#include<stdio.h>
const char **test_ffi_import()
{
printf("C think sys_siglist = %X\n", sys_siglist);
return sys_siglist;
}
However, importing that doesn't change the result, and the printf()
call prints the same pointer value as show siglist_a
.
My suspicion is that it's something to do with static and dynamic library loading.
Update: somebody in #haskell suggested this might be 64-bit specific; if anybody tries to reproduce it, can you mention your architecture and whether it worked in a comment?
Code as follows:
-- A.hs
{-# LANGUAGE ForeignFunctionInterface #-}
module A where
import Foreign
import Foreign.C
foreign import ccall "&sys_siglist"
siglist_a :: Ptr CString
--
-- B.hs
{-# LANGUAGE ForeignFunctionInterface #-}
module B where
import Foreign
import Foreign.C
foreign import ccall "&sys_siglist"
siglist_b :: Ptr CString
--
-- Main.hs
{-# LANGUAGE ForeignFunctionInterface #-}
module Main where
import Foreign
import Foreign.C
import A
import B
foreign import ccall "&sys_siglist"
siglist_main :: Ptr CString
main = do
putStrLn $ "siglist_a = " ++ show siglist_a
putStrLn $ "siglist_b = " ++ show siglist_b
putStrLn $ "siglist_main = " ++ show siglist_main
peekSiglist "a " siglist_a
peekSiglist "b " siglist_b
peekSiglist "main" siglist_main
peekSiglist name siglist = do
ptr <- peekElemOff siglist 2
str <- maybePeek peekCString ptr
putStrLn $ "siglist_" ++ name ++ "[2] = " ++ show str
I would expect something like this output, where all pointer values identical and valid:
$ runhaskell Main.hs
siglist_a = 0x00007f53a948fe00
siglist_b = 0x00007f53a948fe00
siglist_main = 0x00007f53a948fe00
siglist_a [2] = Just "Interrupt"
siglist_b [2] = Just "Interrupt"
siglist_main[2] = Just "Interrupt"
However, if I compile A.hs (with ghc -c A.hs
), then the output changes to:
$ runhaskell Main.hs
siglist_a = 0x0000000040378918
siglist_b = 0x00007fe7c029ce00
siglist_main = 0x00007fe7c029ce00
siglist_a [2] = Nothing
siglist_b [2] = Just "Interrupt"
siglist_main[2] = Just "Interrupt"
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您遇到了此错误。使用
-fPIC
编译代码来解决该问题。You are encountering this bug. Compile your code with
-fPIC
to workaround it.我无法在 Linux x86 上使用 6.10.4 或 6.12.1 重现此问题。 (请编辑您的问题以确认您看到的架构是 x86-64)
I can not reproduce this with either 6.10.4 or 6.12.1 on Linux x86. (please edit your question to confirm the architecture you see this on is x86-64)