Call a C function that accepts a const pointer to struct from Nim - ffi

I am using GNU argparse from Nim using its foreign function interface.
In <argp.h> there is function argp_parse which is declared as follows
extern error_t argp_parse (const struct argp *__restrict __argp,
int __argc, char **__restrict __argv,
unsigned __flags, int *__restrict __arg_index,
void *__restrict __input);
the tricky part are the const and __restrict before the first parameter, in Nim I wrote this code
type
ArgpChild {.importc: "struct argp_child"} = object
argp : ptr[Argp]
flags : cint
header : cstring
group : cint
Argp* {.importc: "struct argp", header: "<argp.h>"} = object
options : ptr[ArgpOption]
parser : pointer #proc (key : cint, arg: cstring, state : ptr[ArgpState]) : Error
args_doc : cstring
doc : cstring
children : ArgpChild
help_filter : pointer #proc(key : int, text : cstring, input: pointer) : cstring
argp_domain : cstring
ArgpOption* {.importc: "struct argp_option"} = object
name : cstring
key : cint
arg : cstring
flags : cint
doc : cstring
group : cint
ArgpState {.importc: "struct argp_state"} = object
input : pointer
Error* = enum
ARGP_KEY_ARG = 0,
ARGP_ERR_UNKNOWN = 7,
ARGP_KEY_END = 0x1000001
proc argp_parse*(argp : Argp, argc : cint, argv : cstringArray, flags: cuint, arg_index: ptr[cint], input : pointer) : Error {.importc: "argp_parse".}
the problem is that the Nim compiler (with c backend) generates this line for argp_parse function (note the missing const and __restrict keywords before the first parameter)
N_CDECL(Error177010, argp_parse)(struct argp* argp0, int argc0, NCSTRING* argv0, unsigned int flags0, int* argindex0, void* input0);
then, when gcc handles that file, it complains yelling "conflicting types for ‘argp_parse’", I guess this is because it finds two definitions of the same functions with different types in the first parameter.
Is there any way to force the Nim compiler to add the const (and maybe __restrict) keyword before a function parameter when using the c backend?

Nim will support a restrict pragma in the future that will allow you to specify such parameters. This is evident from the latest todo.txt in the Nim's repository.
In the meantime, there is one possible work-around for this. Instead of using the importc pragma, you can use the emit pragma:
proc argp_parse*(argp: Argp,
argc: cint,
argv: cstringArray,
flags: cuint,
arg_index: ptr[cint],
input: pointer): Error =
{.emit: "argp_parse(`argp`, `argc`, `argv`, `flags`, `arg_index`, `input`);".}
This will create a regular non-imported proc that just forwards the call the argp_parse function.

The correct fix is simply to add header:
when defined case_bad: # error: conflicting types for 'strlen'
proc c_strlen(a: cstring): csize_t {.importc: "strlen".}
else: # ok
proc c_strlen(a: cstring): csize_t {.importc: "strlen", header: "<string.h>".}
echo c_strlen("abc")

Related

Use C functions in Idris

Idris can compile .idr to C-code (JS, NodeJS). Is it possible to do so in reverse direction - compile C-code to Idris format? Or, maybe, to use C functions direct in Idris code?
Sure! Take a look at the foreign function interface (FFI). Based on your compilation target (f.e. C, JavaScript, …) you can use the native functions like this example call of void *fileOpen(char *path, char *mode) inside the IO monad:
do_fopen : String -> String -> IO Ptr
do_fopen f m
= foreign FFI_C "fileOpen" (String -> String -> IO Ptr) f m

compiling linux 0.0.1 => error: ‘asm’ operand has impossible constraints __asm__("cld\n"

I'm trying to compile linux kernel 0.0.1 from source code on my 64 bit intel machine.
Only to fill in the boot and main I had to modify all makefiles to get a 32-bit compilation.
So, this is the output of make:
In file included from traps.c:7:0:
../include/string.h:128:22: warning: conflicting types for built-in function ‘strchr’
extern inline char * strchr(const char * s,char c)
^
../include/string.h:145:22: warning: conflicting types for built-in function ‘strrchr’
extern inline char * strrchr(const char * s,char c)
^
../include/string.h:379:22: warning: conflicting types for built-in function ‘memchr’
extern inline void * memchr(const void * cs,char c,int count)
^
../include/string.h:395:22: warning: conflicting types for built-in function ‘memset’
extern inline void * memset(void * s,char c,int count)
^
In file included from traps.c:11:0:
../include/linux/kernel.h:5:1: warning: function return types not compatible due to ‘volatile’
volatile void panic(const char * str);
^
../include/linux/kernel.h:5:1: warning: function return types not compatible due to ‘volatile’
../include/linux/kernel.h:5:1: warning: function return types not compatible due to ‘volatile’
In file included from traps.c:7:0:
../include/string.h: In function ‘strcpy’:
../include/string.h:29:1: error: ‘asm’ operand has impossible constraints
__asm__("cld\n"
^
Makefile:24: set di istruzioni per l'obiettivo "traps.o" non riuscito
The portion of code of string.h is the following:
extern inline char * strcpy(char * dest,const char *src)
{
__asm__("cld\n"
"1:\tlodsb\n\t"
"stosb\n\t"
"testb %%al,%%al\n\t"
"jne 1b"
::"S" (src),"D" (dest):"si","di","ax");
return dest;
}
I don't know why the original code doesn't compile.
Until now I successfully compiled: boot and init subdir.
Many Thanks
I think that the problem is that the register clobber list overlaps with the inputs.
That is, the "S" stands for register esi while "D" stands for register edi; but then the clobber list contains "si" and "di" that are the lower 16 bit pieces of those registers. Maybe old GCC versions ignored that, but newer ones do not allow overlaps.
From the docs here:
Clobber descriptions may not in any way overlap with an input or output operand.
Solution, just remove them from the list:
...
::"S" (src),"D" (dest) :"ax", "cc");
BTW, I also added the clobber to "cc" because that assembly modifies the e flag.

Rust calling C, static const in C code

I have used rust-bindgen to generate rust interface code.
Now in the C code you can find this:
extern const struct mps_key_s _mps_key_ARGS_END;
#define MPS_KEY_ARGS_END (&_mps_key_ARGS_END)
Note that in the hole rest of the code _mps_key_ARGS_END does not appear again.
The macro MPS_KEY_ARGS_END gets used regularly amung other simular mps_key_s.
Now the code produced by rust-bindgen is this:
pub static _mps_key_ARGS_END: Struct_mps_key_s;
Now in C code here is a example usage:
extern void _mps_args_set_key(mps_arg_s args[MPS_ARGS_MAX], unsigned i,
mps_key_t key);
_mps_args_set_key(args, 0, MPS_KEY_ARGS_END);
In rust it looks like this:
pub fn _mps_args_set_key(args: [mps_arg_s, ..32u], i: ::libc::c_uint,
key: mps_key_t);
Now I try to call it like this:
_mps_args_set_key(args, 0 as u32, _mps_key_ARGS_END );
But I get a error:
error: mismatched types: expected *const Struct_mps_key_s, found
Struct_mps_key_s (expected *-ptr, found enum Struct_mps_key_s)
I am not a good C programmer, and I dont even understand where these C static even get there values from.
Thanks for your help.
Edit:
Update based on the answer of Chris Morgan.
I added this code (note, I replaced *const mps_key_s with mps_key_t):
pub static MPS_KEY_ARGS_END: mps_key_t = &_mps_key_ARGS_END;
Just for some extra information on why Im using mps_key_t, in C:
typedef const struct mps_key_s *mps_key_t;
In rust:
pub type mps_key_t = *const Struct_mps_key_s;
This seams seam to work better then befor but now Im getting a bad crash:
error: internal compiler error: unexpected failure note: the compiler
hit an unexpected failure path. this is a bug. note: we would
appreciate a bug report:
http://doc.rust-lang.org/complement-bugreport.html note: run with
RUST_BACKTRACE=1 for a backtrace task 'rustc' failed at 'expected
item, found foreign item _mps_key_ARGS_END::_mps_key_ARGS_END
(id=1102)',
/home/rustbuild/src/rust-buildbot/slave/nightly-linux/build/src/libsyntax/ast_map/mod.rs:327
#define MPS_KEY_ARGS_END (&_mps_key_ARGS_END)
The & part indicates that it is taking a pointer to the object, that the type of MPS_KEY_ARGS_END will be mps_key_s const*. In Rust, that is *const mps_key_s (a raw pointer), and can be achieved in the same way as in C, &_mps_key_ARGS_END. You can define MPS_KEY_ARGS_END in a way that you can use conveniently like this:
static MPS_KEY_ARGS_END: *const mps_key_s = &_mps_key_ARGS_END;

ANTLR4 C Grammar Not Supporting __cdecl?

I am running ANTLR 4.2 and using the canonical C grammar from:
https://github.com/antlr/grammars-v4/tree/master/c
I am doing the following steps: (using batch files from the ANTLR4 book)
antlr C.g4
javac C*.java
grun C compilationUnit -tokens test.c
Where test.c has the following code:
PASSING:
typedef
void
(*EFI_SET_MEM) (
void *Buffer,
UINTN Size,
UINT8 Value
);
FAILING:
error is: line 3:9 no viable alternative at input 'typedefvoid(__cdecl*'
typedef
void
(__cdecl *EFI_SET_MEM) (
void *Buffer,
UINTN Size,
UINT8 Value
);
The only difference is __cdecl. I tried several changes to fix this, e.g.:
functionSpecifier
: ('inline'
| '_Noreturn'
| '__inline__' // GCC extension
| '__cdecl'
| '__stdcall')
| gccAttributeSpecifier
| '__declspec' '(' Identifier ')'
;
...but this is not working. Any ideas on how to fix this problem? Since what I'm doing doesn't care about the calling convention, creating this lexer rule makes the problem go away:
Cdecl
: '__cdecl'
-> skip
;
I still wish I had a real solution.
__cdecl is used in C++ to declare an interface as using the C-calling convention for linkage (explicitly with undecorated names and the like). __cdecl is C++ (and I believe specific to certain compilers on top of that), not C, so the C grammar doesn't specify it.
I'm not sure why your proposed fix isn't working, tho.

idt_table undefined! warning when compiling kernel module

I'm trying to use gate_desc *idt_table in a kernel module. The set_trap_gate() function defined in desc.h uses this pointer. In desc.h is also a definition : extern gate_desc idt_table[].
I tried different things:
use idt_table in my module without definition or affectation
affect idt_table with my (valid) idt_table address
I get either an id_table undefined warning during compilation or incomplete type for idt_table.
creating a new var named for instance gate_desc *it = (gate_desc *)#; And copy the set_trap_gate, set_gate, write_idt_entry, pack_gate functions from sched.h to my module file (renaming them, and using it instead of idt_table). This compiles fine but when inserting my module I get an unknown symbol in module (ret -1) error.
(there is no reference in my module to idt_table, and the functions I use from sched do use my variable).
I tried to see where in the files included by sched.h was defined idt_table, but couldn't find it!
Does someone know how I could use, the idt_table pointer from sched.h (affecting it with the corrct address) or create a new pointer?
Theoretically, you could implement a non-init-section set_trap_gate() via:
void set_trap_gate(int n, void *addr)
{
struct { uint16_t lim; struct desc_struct *idt_table; }
__attribute__((packed)) idt;
__asm__ ("sidt %0" : : "m"(idt) : "memory");
_set_gate(idt.idt_table + n, 15, 0, addr);
}
But that'd be CPU-local, i.e. it's not guaranteed to modify any other IDT but the one of the CPU it's running on. Also, it might fall foul of writeprotected memory.
What exactly is it you're trying to achieve ?

Resources