Zig "translate c" doesn't translate main function - c

I created a C file:
int main() {
return 1;
}
I used Zig's translate-c command line option to generate a zig file, and I only get some global variable declarations like
pub const __GCC_ATOMIC_TEST_AND_SET_TRUEVAL = 1;
pub const __FLT16_MAX_EXP__ = 15;
pub const __BIGGEST_ALIGNMENT__ = 16;
pub const __SIZEOF_FLOAT__ = 4;
pub const __INT64_FMTd__ = c"ld";
pub const __STDC_VERSION__ = c_long(201112);
... // and many
And no main function is found. But if I change the function name to myFunction like this:
int myFunction(int a) {
return a;
}
A function appears when I re-generate it:
pub export fn myFunction(a: c_int) c_int {
return a;
}
Am I missing something? What's the rule of zig's translate-c function?

When this question was asked, translate-c did not yet support functions with unspecified parameters. This was visible by using --verbose-cimport:
test.c:1:5: warning: unsupported type: 'FunctionNoProto'
test.c:1:5: warning: unable to resolve prototype of function 'main'
In C, if you leave the parameters empty, it's not actually zero parameters, it's unspecified. You have to use void to mean "no parameters".
So that's why the second example worked - because the parameter list was not empty.
However as of e280dce3, Zig supports translating C functions with unspecified parameters, and the example from the question turns into this Zig code:
pub export fn main() c_int {
return 1;
}

Related

Use C variable from Rust without unsafe

I can expose a C function to Rust code via the FFI as follows:
use std::os::raw::c_int;
mod c {
#[link(name="...")]
extern "C" {
pub fn add(a: c_int, b: c_int) -> c_int;
}
}
pub fn add(a: c_int, b: c_int) -> c_int {
unsafe {
c::add(a, b)
}
}
Now I can call add from Rust without having to wrap it in another unsafe block. But what if I want to do the same for a variable? I.e.:
use std::os::raw::c_int;
mod c {
#[link(name="...")]
extern "C" {
pub static VAR: c_int;
}
}
pub static VAR: c_int = unsafe { c::VAR };
This results in a compiler error: "cannot read from extern static". What is the correct way (if there is one) to do this?
It should be unsafe when it is indeed unsafe, although you can make a static borrow of the imported global variable.
static VAR: &i32 = unsafe { &c::VAR };

How do I make a struct for FFI that contains a nullable function pointer?

I have an existing C program that loads shared library plugins. The main C program interacts with those plugins through a C struct containing integers, strings, function pointers, etc. How can I create such a plugin from Rust?
Note that the (real) C program cannot be changed, nor can the API be changed, those are fixed, existing things, so this is not a question about "how best to support plugins in Rust", it's how can Rust make *.so files which interoperate with an existing C program.
Here's a simplified example of a C program + C plugin:
/* gcc -g -Wall test.c -o test -ldl
./test ./test-api.so
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <inttypes.h>
#include <dlfcn.h>
struct api {
uint64_t i64;
int i;
const char *name; /* can be NULL */
void (*load) (void); /* must not be NULL */
void (*hello) (const char *str); /* can be NULL */
};
int
main (int argc, char *argv[])
{
void *dl = dlopen (argv[1], RTLD_NOW);
if (!dl) { fprintf (stderr, "%s: %s\n", argv[1], dlerror ()); exit (1); }
struct api *(*get_api) (void) = dlsym (dl, "get_api");
printf ("calling get_api ...\n");
struct api *api = get_api ();
printf ("api->i64 = %" PRIi64 "\n", api->i64);
printf ("api->i = %d\n", api->i);
if (api->name)
printf ("api->name = %s\n", api->name);
printf ("calling api->load ...\n");
api->load ();
if (api->hello) {
printf ("calling api->hello ...\n");
api->hello ("world");
}
printf ("exiting\n");
exit (0);
}
/* gcc -g -shared -fPIC -Wall test-api.c -o test-api.so */
#include <stdio.h>
#include <stdint.h>
static void
load (void)
{
printf ("this is the load function in the plugin\n");
}
static void
hello (const char *str)
{
printf ("hello %s\n", str);
}
static struct api {
uint64_t i64;
int i;
const char *name;
void (*load) (void);
void (*hello) (const char *str);
} api = {
1042,
42,
"this is the plugin",
load,
hello,
};
struct api *
get_api (void)
{
return &api;
}
Here's what I wrote in Rust to try to get a plugin, but it doesn't compile:
extern crate libc;
use libc::*;
use std::ffi::*;
use std::ptr;
use std::os::raw::c_int;
#[repr(C)]
pub struct api {
i64: uint64_t,
i: c_int,
name: *const c_char,
load: extern fn (),
hello: extern fn (), // XXX
}
extern fn hello_load () {
println! ("hello this is the load method");
}
#[no_mangle]
pub extern fn get_api () -> *const api {
println! ("hello from the plugin");
let api = Box::new (api {
i64: 4201,
i: 24,
name: CString::new("hello").unwrap().into_raw(), // XXX memory leak?
load: hello_load,
hello: std::ptr::null_mut,
});
return Box::into_raw(api); // XXX memory leak?
}
This is compiled using Cargo.toml containing:
[package]
name = "embed"
version = "0.1.0"
[dependencies]
libc = "0.2"
[lib]
name = "embed"
crate-type = ["cdylib"]
The error is:
error[E0308]: mismatched types
--> src/lib.rs:32:16
|
32 | hello: std::ptr::null_mut,
| ^^^^^^^^^^^^^^^^^^ expected "C" fn, found "Rust" fn
|
= note: expected type `extern "C" fn()`
found type `fn() -> *mut _ {std::ptr::null_mut::<_>}`
error: aborting due to previous error
I didn't get to try loading the module but when I tried this before with the real program the fields were all wrong indicating something much more fundamental was wrong.
tl;dr Use Option to represent nullable function pointers and None for null.
The error message is confusing, first, because std::ptr::null_mut isn't a pointer; it's a generic function that returns a pointer, and you haven't called it. So Rust is seeing you pass a function that has the wrong signature and calling convention, and complaining about that.
But once you fix that, you'll get this error instead:
error[E0308]: mismatched types
--> src/lib.rs:29:16
|
29 | hello: std::ptr::null_mut(),
| ^^^^^^^^^^^^^^^^^^^^ expected fn pointer, found *-ptr
|
= note: expected type `extern "C" fn()`
found type `*mut _`
Function pointers and object pointers are not compatible (this is also the case in C), so you can't cast between them. null_mut returns an object pointer, so you need to find another way to create a null function pointer.
Function pointers (values of type fn(...) -> _) have another interesting property: unlike raw pointers (*const _ and *mut _), they can't be null. You don't need an unsafe block to call a function via pointer, and so creating a null function pointer is unsafe, like creating a null reference.
How do you make something nullable? Wrap it in Option:
#[repr(C)]
pub struct api {
// ...
load: Option<extern fn ()>,
hello: Option<extern fn ()>, // assuming hello can also be null
}
And populate it with Some(function) or None:
let api = Box::new (api {
// ...
load: Some(hello_load),
hello: None,
});
It's not usually a good idea to use enums, including Option, in a repr(C) struct, because C doesn't have an enum equivalent and so you don't know what you're going to get on the other side. But in the case of Option<T> where T is something non-nullable, None is represented by the null value, so it should be okay.
The use of Option to represent a nullable function pointer for FFI is documented in the Unsafe Code Guidelines:
null values are not supported by the Rust function pointer types -- just like references, the expectation is that you use Option to create nullable pointers. Option<fn(Args...) -> Ret> will have the exact same ABI as fn(Args...) -> Ret, but additionally allows null pointer values.

error in kernel source code of linux?

I modified the kernel source code r8169.c and calculating the timestamp as below:
s64 a;
EXPORT_SYMBOL(a);
a = time();
I did not add the original timestamp function call
I am using the variable a in another source file in kernel: ip_input.c
extern s64 a;
s64 b,c;
b= time();
c = b-a;
I receive this error:
ERROR: undefined reference to a
How to solve it?
From the incomplete source code, I guess that
s64 a;
EXPORT_SYMBOL(a);
a = time();
is inside a function and therefore, a cannot be exported, because it is local to that function.
To use a outside of this module, you must define it with file scope, e.g.
s64 a;
EXPORT_SYMBOL(a);
void some_function()
{
a = time();
}
This allows the symbol for a to be exported and then used in another module.
r8169.c is a module, whereas ip_input.c is in the main kernel. The main kernel cannot import symbols from a module. The fix for this is to declare your variable within ip_input.c, and import it from r8169.c. You also have to use file scope as Olaf mentioned.
ip_input.c:
s64 a, b, c;
EXPORT_SYMBOL(a);
void someFunc() {
b=time();
c=b-a;
}
r8169.c:
extern s64 a;
void someFunc() {
a=time();
}

How do I implement access specifiers in C?

I was trying to implement access specifier (not sure if that is called access specifier)
The purpose is to make a function (func2) callable only at one place(inside func1).
int func1 ()
{
// Make func2 callable only here`
#define FUNC2_CALLABLE
func2();
#undef FUNC2_CALLABLE
}
#ifdef FUNC2_CALLABLE
int func2 ()
{
return 1;
}
#endif // FUNC2_CALLABLE
func2 should be callable only from func1 and not from any other place in the code.
Does the above code serve the purpose ? Any alternative suggestions
< Edit 1 >
How about doing it this way
int func2()
{
#ifdef FUNC2_CALLABLE
return 1;
#endif
}
Will this work ?
< / Edit 1>
That will give you a linker error of func2 not found (func2 won't be defined if you use that).
I think you might be looking for static.
static int fake(int x) { return x * 2; }
int doSomething(int x) { int tmp = fake(x); doOtherThings(); }
The fake would not exist outside of the compilation unit (file basically).
As for allowing a function to only be called from another function, that doesn't make much sense. Just inline the code if that's your end goal.
There is no real way to do it. The best that can be done in standard C is to make func2 static and define it close to the bottom of the source file:
static int func2 ()
{
return 1;
}
int func1 ()
{
func2();
}
(end of file)
Maybe you can use static keyword .
But the function with static is accessible for all the code in the same file. Other files cannot access it.

Hide struct definition in static library

I need to provide a C static library to the client and need to be able to make a struct definition unavailable. On top of that I need to be able to execute code before the main at library initialization using a global variable.
Here's my code:
private.h
#ifndef PRIVATE_H
#define PRIVATE_H
typedef struct TEST test;
#endif
private.c (this should end up in a static library)
#include "private.h"
#include <stdio.h>
struct TEST
{
TEST()
{
printf("Execute before main and have to be unavailable to the user.\n");
}
int a; // Can be modified by the user
int b; // Can be modified by the user
int c; // Can be modified by the user
} TEST;
main.c
test t;
int main( void )
{
t.a = 0;
t.b = 0;
t.c = 0;
return 0;
}
Obviously this code doesn't work... but show what I need to do... Anybody knows how to make this work? I google quite a bit but can't find an answer, any help would be greatly appreciated.
TIA!
If you're using gcc you can use the constructor attribute,
void runs_before_main(void) __attribute__((constructor))
{
...
}
From the gcc documentation
The constructor attribute causes the
function to be called automatically
be- fore execution enters main ().
Similarly, the destructor attribute
causes the function to be called
automatically after main () has
completed or exit () has been called.
Functions with these attributes are
useful for initializing data that will
be used implicitly during the
execution of the program.
You may provide an optional integer
priority to control the order in which
constructor and destructor functions
are run. A constructor with a smaller
priority number runs before a
constructor with a larger priority
number; the opposite relationship
holds for destructors. So, if you have
a constructor that allocates a
resource and a destructor that
deallocates the same resource, both
functions typically have the same
priority. The priorities for
constructor and destructor functions
are the same as those specified for
namespace-scope C++ objects
If you want to hide a struct from users, declare the struct in a header but define it in the c file, passing around pointers. As an example:
// foo.h
typedef struct private_foo foo;
foo * create_foo(void);
void free_foo(foo * f);
// foo.c
struct private_foo {
int i;
}
foo * create_foo(void){
foo * f = malloc(sizeof(*foo));
if (f) f->i = 1;
return f;
}
...
foo->i can then not be accessed outside foo.c.
If you want the client code to be able to use "t.a = ...", then you cannot hide the struct definition. What you want is called an opaque type, that will look something like this:
public.h:
struct foo;
set_a( struct foo *, int );
struct foo * new_foo(void);
main.c:
#include <public.h>
int main( void )
{
struct foo *k;
k = new_foo();
set_a( k, 5 );
}
The structure definition is only available to the library. If you do not make the library source code available, it is possible to completely hide it from the users of the library.
There is no portable way in C to ensure your code will run before main(). What I would do is just maintain an initialised flag in your library, set to false, and then refuse to do anything until your init function has been called.
As in:
static int initialised = 0;
int init (void) {
// do something.
initialised = 1;
return ERR_OK;
}
int all_other_functions (void) {
if (!init)
return ERR_NOT_INITED;
// do something.
return ERR_OK;
}

Resources