Function Hooks and Calling Convention

Playing with function hooks, I've found two issues that draw my ire. FYI, this is more of a partial experience report than a question. For an example, let us discuss the kernel function "pci_register_driver", which is actually a macro and thus not handled by the function hooks. The first step in fixing this is a CPP section: #c inline int pci_register_driver2(pci_dev_t d) { pci_register_driver(d); } #endc So I'd call this experience number 1 - it is entirely possible to automatically generate wrapper functions for macros ( {#macro ...}? or even {#fun ...} handling macros too). Perhaps there's not enough interest for anyone to make this change but I expect this to come up more and more often. I'll note that this is very similar to the issue of importing pure macros (macros that don't wrap a function call), which would be a nice feature. I can now write the hook and c2hs will parse things ok: {#fun pci_register_driver2 as ^ {id `PCIDriver' } -> `Int' id#} generating a foreign import: foreign import ccall safe "pci.chs.h pci_register_driver2" pciRegisterDriver'_ :: ((PCIDriver) -> (IO CInt)) And all seems well... except that I'm aiming to use this in interfacing with the Linux kernel. The generated *.chs.h file will/must be compiled into an object file using the Linux build system, which defaults to a regparm3 calling convention. Why does c2hs automatically assume its a ccall? I could really use an opportunity to insert an alternate convention. In the end the solution I have is to manually write the above C section and the foreign import call using a regparm3 calling convention. This isn't to say c2hs isn't used - its still hugely helpful (so long as the headers remain easy to convert to ANSI C), but just my quick experience. Thomas

On Mon, 2009-09-21 at 17:45 -0700, Thomas DuBuisson wrote:
Playing with function hooks, I've found two issues that draw my ire. FYI, this is more of a partial experience report than a question.
Great, thanks.
For an example, let us discuss the kernel function "pci_register_driver", which is actually a macro and thus not handled by the function hooks. The first step in fixing this is a CPP section: #c inline int pci_register_driver2(pci_dev_t d) { pci_register_driver(d); } #endc
So I'd call this experience number 1 - it is entirely possible to automatically generate wrapper functions for macros ( {#macro ...}? or even {#fun ...} handling macros too).
Right. I'm not sure you can make it inline however, at least not in any meaningful way.
Perhaps there's not enough interest for anyone to make this change but I expect this to come up more and more often.
Yes it happens quite a bit.
I'll note that this is very similar to the issue of importing pure macros (macros that don't wrap a function call), which would be a nice feature.
Right, since the wrapper C function would end up containing the code of the macro, so it doesn't matter if it's a function call or some other code.
I can now write the hook and c2hs will parse things ok:
{#fun pci_register_driver2 as ^ {id `PCIDriver' } -> `Int' id#}
generating a foreign import:
foreign import ccall safe "pci.chs.h pci_register_driver2" pciRegisterDriver'_ :: ((PCIDriver) -> (IO CInt))
And all seems well... except that I'm aiming to use this in interfacing with the Linux kernel. The generated *.chs.h file will/must be compiled into an object file using the Linux build system, which defaults to a regparm3 calling convention.
So the other problem is that it only makes a .h file, not a .c file. Really you want to be able to inject things into the header that c2hs reads, and separately into a .c file. In a Cabal build you'd then want Cabal to compile the .c file and include it into the result. For your project you obviously have to handle the .c file yourself.
Why does c2hs automatically assume its a ccall? I could really use an opportunity to insert an alternate convention.
Right, it only knows about ccall. It would be possible to extend c2hs to understand the C attributes which declare that the function is regparam. Though actually that might not help for the kernel headers because I think they do not declare the regparam calling convention and just rely on gcc flags when compiling.
In the end the solution I have is to manually write the above C section and the foreign import call using a regparm3 calling convention. This isn't to say c2hs isn't used - its still hugely helpful (so long as the headers remain easy to convert to ANSI C), but just my quick experience.
BTW, what do you mean about ANSI C? Language.C and by extension c2hs should be able to handle all the GNU C constructs. That's not to say c2hs takes them into account of course, but it shouldn't fall over. So yes, I think all these issues are solvable. As usual the difficulty is finding enough people with enough time to actually do the work. I think c2hs could become the standard Haskell ffi binding tool, taking over from hsc2hs, but it needs a bit of love. Duncan

Oops - didn't reply to the list!
So the other problem is that it only makes a .h file, not a .c file. Really you want to be able to inject things into the header that c2hs reads, and separately into a .c file. In a Cabal build you'd then want Cabal to compile the .c file and include it into the result. For your project you obviously have to handle the .c file yourself.
Yep - none of this will get polished to a Cabal level and none of it would be easy to polish.
Though actually that might not help for the kernel headers because I think they do not declare the regparam calling convention and just rely on gcc flags when compiling.
You are correct - the call convention has to be declared manually. There is no reasonable way for c2hs to learn it.
In the end the solution I have is to manually write the above C section and the foreign import call using a regparm3 calling convention. This isn't to say c2hs isn't used - its still hugely helpful (so long as the headers remain easy to convert to ANSI C), but just my quick experience.
BTW, what do you mean about ANSI C?
I meant there exists at least one aspect (perhaps a bug) to the kernel
headers that cause an error when c2hs tries to parse the headers. In
the FC11 2.6.30 headers they use an enum when declaring an extern
function prototype - without declaring the enum (timers.h). The
solution is to #include
So yes, I think all these issues are solvable. As usual the difficulty is finding enough people with enough time to actually do the work. I think c2hs could become the standard Haskell ffi binding tool, taking over from hsc2hs, but it needs a bit of love.
FWIW, hsc2hs is entirely unusable for this work as it builds a .c file that will generate the .hs file. I couldn't get this to work for kernel bindings as one build (the generating .c file) needs things like stdlibs while the other (the kernel) absolutely can not have such things. All sorts of conflicts occur, such as redefinition of basic type by the kernel headers. Thomas
participants (2)
-
Duncan Coutts
-
Thomas DuBuisson