Is it possible to get function pointers to functions that have a prefix? At first I thought the names of c functions were lost during compilation. But then, dlsym returns the pointer to a function of a specified name.
So if there a way to do something like:
void * handle = dlopen(0, RTLD_NOW|RTLD_GLOBAL);
*(void **)(&fptr);
while(fptr = dlsym(handle, "prefix*")) {
fptr(args);
}
Why not just do something like this:
#include <stdio.h>
void funcA(int n) { printf("funcA: %d\n", n); }
void funcB(int n) { printf("funcB: %d\n", n); }
void funcC(int n) { printf("funcC: %d\n", n); }
void (*funcs[3]) (int n) = {
funcA,
funcB,
funcC
};
int main() {
int i;
for (i = 0; i < sizeof funcs / sizeof *funcs; ++i)
funcs[i](i);
return 0;
}
well this isn't a built-in way, and I don't think there is a built-in way... you could parse nm, but that is yucky.
but if you are building a plug in arch you can use an already known symbol to get all of the symbols.
lib.c
char ** functions()
{
static char * f[3] = {"function1","function2",NULL};
return f;
}
void function1()
{
printf("function1\n");
}
void function2()
{
printf("function2\n");
}
main.c
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
#include <errno.h>
typedef char ** (*functions)(void);
typedef void (*voidFunc)(void);
int main(int argc, const char * argv[])
{
void * ref = dlopen("/abs/path/to/libExample.dylib", RTLD_LAZY | RTLD_LOCAL);
if (!ref)
{
printf("filed to open dylib: %i",errno);
}
functions f = dlsym(ref, "functions");
if (f)
{
char** fnames = f();
char * fname = NULL;
for (int i = 0; 1 ; i++)
{
fname = fnames[i];
if (fname) {
voidFunc g = dlsym(ref, fname);
if (g)
{
g();
}
}else{
break;
}
}
}
dlclose(ref);
return EXIT_SUCCESS;
}
outputs:
function1
function2
Program ended with exit code: 0
not a linux way, but on OS X there is a some extra stuff that would probably be easier:
/*
* Structure filled in by dladdr().
*/
typedef struct dl_info {
const char *dli_fname; /* Pathname of shared object */
void *dli_fbase; /* Base address of shared object */
const char *dli_sname; /* Name of nearest symbol */
void *dli_saddr; /* Address of nearest symbol */
} Dl_info;
extern int dladdr(const void *, Dl_info *);
Related
The trampoline function in the program below works properly. I think the program below results in stack overflow because the functions thunk_f and thunk1 call each other indefinitely, resulting in the creation of new stack frames. However, I want to write a program that behaves more similarly to a nonterminating loop, as trampolines should prevent stack overflow.
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
void trampoline(void *(*func)()) {
while (func) {
void *call = func();
func = (void *(*)())call;
}
}
void *thunk1(int *param);
void *thunk_f(int *param);
void *thunk1(int *param)
{
++*param;
trampoline(thunk_f(param));
return NULL;
}
void *thunk_f(int *param)
{
return thunk1(param);
}
int main(int argc, char **argv)
{
int a = 4;
trampoline(thunk1(&a));
printf("%d\n", a);
}
You are using the trampoline incorrectly: rather than letting it invoke your thunk_f function, you call it with the result of the thunk_f function.
As a result, you are getting a stack overflow. You can avoid the stack overflow (but not the infinite loop) by returning thunk_f instead of calling it:
void *thunk1(int *param)
{
++*param;
return thunk_f;
}
And calling trampoline in main correctly:
int main(int argc, char **argv)
{
int a = 4;
trampoline(thunk1, &a);
printf("%d\n", a);
}
And of course this requires that trampoline gets an additional argument, to pass the &a parameter on:
void trampoline(void *(*func)(int *), int *arg) {
while (func) {
void *call = func(arg);
func = (void *(*)())call;
}
}
This works — but as noted, it’s just an infinite loop without output. To see what’s happening, put the printf inside thunk1:
void *thunk1(int *param)
{
printf("%d\n", ++*param);
return thunk_f;
}
Lastly, I should probably note that this is invalid C, because it’s illegal to convert between a object pointer and a function pointer (always compile with pedantic warnings!). To make the code legal, wrap the function pointer into an object:
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
struct f {
struct f (*p)(void *);
};
void trampoline(struct f f, void *args) {
while (f.p) {
f = (f.p)(args);
}
}
struct f thunk1(void *param);
struct f thunk_f(void *param);
struct f thunk1(void *param) {
printf("%d\n", ++*((int *) param));
return (struct f) {thunk_f};
}
struct f thunk_f(void *param) {
return thunk1(param);
}
int main() {
int a = 4;
trampoline((struct f) {thunk1}, &a);
}
I want to pass multiple arguments to a function using a void pointer.
void* function(void *params)
{
//casting pointers
//doing something
}
int main()
{
int a = 0
int b = 10;
char x = 'S';
void function(???);
return 0;
}
I know that I have to cast them to a certain variable in my function but I do not know how I can pass my 3 arguments as one void pointer to my function.
I have searched for this problem know quite some time but I could not find anything that would help me.
You could do it like this:
struct my_struct
{
int a;
int b;
char x;
}
void * function(void * pv)
{
struct my_strcut * ps = pv; /* Implicitly converting the void-pointer
/* passed in to a pointer to a struct. */
/* Use ps->a, ps->b and ps->x here. */
return ...; /* NULL or any pointer value valid outside this function */
}
Use it like this
int main(void)
{
struct my_struct s = {42, -1, 'A'};
void * pv = function(&s);
}
Following up on the OP's update:
struct my_struct_foo
{
void * pv1;
void * pv2;
}
struct my_struct_bar
{
int a;
int b;
}
void * function(void * pv)
{
struct my_strcut_foo * ps_foo = pv;
struct my_struct_bar * ps_bar = ps_foo->pv1;
/* Use ps_foo->..., ps_bar->... here. */
return ...; /* NULL or any pointer value valid outside this function */
}
Use it like this
int main(void)
{
struct my_struct_bar s_bar = {42, -1};
struct my_struct_foo s_foo = {&s_bar, NULL};
void * pv = function(&s_foo);
}
The void* is used as a pointer to a "generic" type. Hence, you need to create a wrapping type, cast convert to void* to invoke the function, and cast convert back to your type in the function's body.
#include <stdio.h>
struct args { int a, b; char X; };
void function(void *params)
{
struct args *arg = params;
printf("%d\n", arg->b);
}
int main()
{
struct args prm;
prm.a = 0;
prm.b = 10;
prm.X = 'S';
function(&prm);
return 0;
}
Everything seems to work fine while dynamically creating the array
but core dumped while trying to print it backwards.
It managed to print only the last string and then segmentation fault.
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
void init_array(void ***pt, int *ptlen) {
*pt=NULL;
*ptlen=0;
}
void trim_array(void ***pt, int *ptlen, int len) {
*pt=(void**)realloc(*pt, len*sizeof(void*));
*ptlen=len;
}
void write_array(void ***pt, int *ptlen, int pos, void *v) {
if (pos >= *ptlen)
trim_array(pt, ptlen, pos+1);
*pt[pos]=v;
}
void *read_array(void ***pt, int *ptlen, int pos) {
return(*pt[pos]);
}
void destroy_array(void ***pt, int *ptlen) {
trim_array(pt, ptlen, 0);
*pt=NULL;
}
int main(int argc, char *argv[]) {
void **t;
int tlen;
void ***pt = &t;
int *ptlen = &tlen;
char s[256],*p; int i;
init_array(pt, ptlen);
i = 0;
do {
printf("give name:\n");
scanf("%255s",s);
write_array(pt, ptlen, i, (void*)strdup(s));
i++;
} while (strcmp(s,"end"));
for (--i; i>=0; i--) {
p = (char*)read_array(pt, ptlen, i);
printf("%s\n",p);
free(p);
}
destroy_array(pt, ptlen);
return(0);
}
The [] operator has a higher precedence than the * operator. You need to change:
*pt[pos]
to:
(*pt)[pos]
in both places where it occurs.
This error is a direct result of writing almost deliberately confusing code with runaway indirection. You'd save yourself a lot of trouble and make things much easier if you wrapped a lot of this stuff in a struct and created some proper interface functions for it.
Something like this would be a bit better form (although "array" is not really a great name for this data structure):
main.c:
#define _POSIX_C_SOURCE 200809L
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include "array.h"
#define MAX_BUFFER_LEN 255
int main(void) {
Array myarray = array_init(10, true);
/* Loop for input until user enters "end" */
char buffer[MAX_BUFFER_LEN];
while ( true ) {
printf("Give name: ");
fflush(stdout);
/* Get input and remove trailing '\n' if necessary */
fgets(buffer, MAX_BUFFER_LEN, stdin);
size_t last = strlen(buffer) - 1;
if ( buffer[last] == '\n' ) {
buffer[last] = '\0';
}
/* Terminate loop on "end" without adding to array... */
if ( !strcmp(buffer, "end") ) {
break;
}
/* ...or append input to array and continue loop */
array_append(myarray, strdup(buffer));
};
/* Output contents of array */
size_t n = array_size(myarray);
for ( size_t i = 0; i < n; ++i ) {
char * data = array_getdata(myarray, i);
printf("%zu: %s\n", i + 1, data);
}
/* Clean up and exit */
array_destroy(myarray);
return EXIT_SUCCESS;
}
array.h:
#ifndef ARRAY_TYPE_H
#define ARRAY_TYPE_H
#include <stdbool.h>
typedef struct array_type * Array; /* Opaque type for user */
Array array_init(const size_t capacity, const bool free_on_delete);
void array_append(Array array, void * data);
size_t array_size(const Array array);
void * array_getdata(Array array, const size_t index);
void array_deletetop(Array array);
void array_destroy(Array array);
#endif /* ARRAY_TYPE_H */
array.c:
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include "array.h"
/* Struct definition is visible only to implementation */
struct array_type {
void ** elements;
size_t capacity;
size_t top;
bool free_on_delete;
};
/* Static functions used by the implementation */
static bool array_isfull(Array array) {
return (array->top + 1) == array->capacity;
}
static void array_resize(Array array, const size_t new_capacity) {
array->capacity = new_capacity;
array->elements = realloc(array->elements,
array->capacity * sizeof (*array->elements));
if ( array->elements == NULL ) {
fputs("Error allocating memory.", stderr);
exit(EXIT_FAILURE);
}
}
/* Interface functions */
Array array_init(const size_t capacity, const bool free_on_delete) {
struct array_type * new_array = malloc(sizeof *new_array);
if ( new_array == NULL ) {
fputs("Error allocating memory.", stderr);
exit(EXIT_FAILURE);
}
new_array->elements = malloc(capacity * sizeof (*new_array->elements));
if ( new_array->elements == NULL ) {
fputs("Error allocating memory.", stderr);
exit(EXIT_FAILURE);
}
new_array->capacity = capacity;
new_array->top = 0;
new_array->free_on_delete = free_on_delete;
return new_array;
}
void array_append(Array array, void * data) {
if ( array_isfull(array) ) {
array_resize(array, array->capacity * 2);
}
array->elements[array->top++] = data;
}
size_t array_size(const Array array) {
return array->top;
}
void * array_getdata(Array array, const size_t index) {
return array->elements[index];
}
void array_deletetop(Array array) {
if ( array->free_on_delete ) {
free(array->elements[array->top - 1]);
}
array->elements[--array->top] = NULL;
}
void array_destroy(Array array) {
while ( array->top > 0 ) {
array_deletetop(array);
}
free(array->elements);
free(array);
}
Sample output:
paul#local:~/src/c/scratch/array$ ./array
Give name: Dave Dee
Give name: Dozy
Give name: Beaky
Give name: Mick
Give name: Titch
Give name: end
1: Dave Dee
2: Dozy
3: Beaky
4: Mick
5: Titch
paul#local:~/src/c/scratch/array$
file stack.h
typedef struct
{
void *elems;
int elem_size;
int log_len;
int alloc_len;
void (*free_fn)(void *);
} stack;
void stack_new(stack *s, int elem_size, void (*free_fn)(void *));
void stack_dispose(stack *s);
void stack_push(stack *s, void *value);
void stack_pop(stack *s, void *address);
and the implementation file stack.c
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#define assert(condition) if(!condition) printf("assert fail\n");exit(0)
void strfree(void *elem);
int main()
{
stack s;
int i;
char *copy, *top;
const char *friends[] = {"joe", "castiel", "lily"};
stack_new(&s, sizeof(char *), strfree);
for(i=0; i<3; i++)
{
copy = strdup(friends[i]);
stack_push(&s, &cp);
}
for(i=0; i<=3; i++)
{
stack_pop(&s, &top);
printf("%s\n", top);
}
stack_dispose(&s);
return 1;
}
void strfree(void *elem)
{
free(*(char **)elem);
}
void stack_new(stack *s, int elem_size, void (*free_fn)(void *))
{
assert(elem_size > 0);
s->alloc_len = 4;
s->free_fn = free_fn;
s->log_len = 0;
s->elem_size = elem_size;
s->elems = malloc(s->alloc_len * s->elem_size);
assert(s->elems != NULL);
}
void stack_dispose(stack *s)
{
int i;
if(s->free_fn)
{
for(i=0; i<s->log_len; i++)
{
s->free_fn((char *)s->elems + i * s->elem_size);
}
}
free(s->elems);
}
void stack_push(stack *s, void *v)
{
if(s->log_len == s->alloc_len)
{
s->alloc_len *= 2;
s->elems = realloc(s->elems, s->alloc_len*s->elem_size);
assert(s->elems != NULL);
}
memcpy((char *)s->elems+s->log_len*s->elem_size, v, s->elem_size);
s->log_len++;
}
void stack_pop(stack *s, void *address)
{
assert(s->log_len > 0);
void *source = (char *)s->elems + (s->log_len - 1) * s->elem_size;
memcpy(address, source, s->elem_size);
s->log_len--;
}
So it compiles but it doesn't run.
It has a warning about comparison between pointer and integer which comes from the code
assert(s->elems != NULL);
It is broken somewhere, it will not print out the three names defined here
const char *friends[] = {"joe", "castiel", "lily"};
I know the code is bit of too much, but I really wish to get some help, I'm at my wits end here.
One problem is your assert macro:
#define assert(condition) if(!condition) printf("assert fail\n");exit(0)
The exit(0); is executed regardless of whether the condition is true or false (look at the generated code again). If you want assertions, use the standard #include <assert.h>.
Your first identified problem is with:
assert(s->elems != NULL);
Given the definition, this is equivalent to:
if (!s->elems != NULL)
printf("assert fail\n");
exit(0);
The !s->elems is an integer, either 0 or 1, compared with a null pointer constant. Hence the warning. When writing macros, enclose arguments in parentheses. At minimum:
#define assert(condition) if(!(condition)){printf("assert fail\n");exit(1);}
This still isn't a good macro, but at least it will get rid of the first compilation error, and your stack_new() won't exit when it is called just because it is called. Note that it is conventional to exit with a non-zero status when there is a problem — exiting with zero indicates success.
Run your code in a debugger using GDB to see what it is doing line by line. Google "gdb cheat sheet" to get started and compile your code with -g.
Please give me some examples of jump table usage. I have seen this example on wikipedia:
#include <stdio.h>
#include <stdlib.h>
typedef void (*Handler)(void); /* A pointer to a handler function */
/* The functions */
void func3 (void) { printf( "3\n" ); }
void func2 (void) { printf( "2\n" ); }
void func1 (void) { printf( "1\n" ); }
void func0 (void) { printf( "0\n" ); }
Handler jump_table[4] = {func0, func1, func2, func3};
int main (int argc, char **argv) {
int value;
/* Convert first argument to 0-3 integer (Hash) */
value = atoi(argv[1]) % 4;
if (value < 0) {
value *= -1;
}
/* Call appropriate function (func0 thru func3) */
jump_table[value]();
}
But I was wondering if there is an alternate way of calling the function instead of using index as shown, in the above case it is jump_table[value]();
What I want to achieve is, instead of using the index is there a way to use the name of the function itself.
For example, say we have all the function pointers in a struct.
typedef struct _funcptrs
{
void func1();
void func2();
} funcptrs;
and now when I want to call the function can I do something like funcptrs.func1() ?
You can certainly create a struct containing pointers to functions. There are even good reasons to do so.
For one example, consider the interface between an operating system and a device driver of some sort. Simplifying a lot, this might look something on this order:
struct device {
int (*open)(unsigned mode);
int (*close)(void);
int (*read)(void *buffer, size_t size);
int (*write)(void *buffer, size_t size);
};
Then an individual device driver would create a struct of this type, and initialize the individual pointers to refer to the functions relevant to a particular device:
struct device serial_port = {
open_serial,
close_serial,
read_serial,
write_serial
};
struct device ethernet_adapter = {
open_net,
close_net,
read_net,
write_net
};
struct device keyboard = {
open_keyboard,
close_keyboard,
read_keyboard,
NULL // we'll assume no writing to the keyboard...
};
Then some higher-level function can receive one of these, and open/close/read/write some device without having to know the exact identity of the device involved. Of course, for a real OS, it gets a bit more complex than this but the general idea is (or at least can be) fairly similar.
Certainly, but you need to declare them as function pointers and initialize them first. Though this defeats the purpose of a jump table if you have to spell out the function name.
e.g.
#include <stdio.h>
void func1 (void) { printf( "1\n" ); }
void func0 (void) { printf( "0\n" ); }
typedef struct
{
void (*func0)(void);
void (*func1)(void);
} funcptrs;
int main(int argc, char *argv[])
{
funcptrs funcs = { func0, func1 };
funcs.func1();
return 0;
}
If you need to call the function by having the name of the function as a string, you need to create a mapping between the functions name and a function pointer, then search the table for that function, and call it.
#include <stdio.h>
#include <string.h>
void func1 (void) { printf( "1\n" ); }
void func0 (void) { printf( "0\n" ); }
#define DEFUN(name) { #name, name }
typedef struct
{
const char *name;
void (*func)(void);
} funcptrs;
void call(funcptrs *ptrs, const char *name)
{
int i;
for(i = 0; ptrs[i].name; i++) {
if(strcmp(ptrs[i].name, name) == 0) {
ptrs[i].func();
break;
}
}
}
int main(int argc, char *argv[])
{
funcptrs funcs[] = {DEFUN(func0), DEFUN(func1), {NULL,NULL}};
call(funcs, "func0");
return 0;
}
You can use an enum to represent the indices of your array and give them meaningful names for you.
#include <stdio.h>
#include <stdlib.h>
typedef void (*Handler)(void); /* A pointer to a handler function */
/* The functions */
void func3 (void) { printf( "3\n" ); }
void func2 (void) { printf( "2\n" ); }
void func1 (void) { printf( "1\n" ); }
void func0 (void) { printf( "0\n" ); }
enum{
FUNC0,
FUNC1,
FUNC2,
FUNC3
};
Handler jump_table[4] = {func0, func1, func2, func3};
int main (int argc, char **argv) {
/* Call appropriate function (func0 thru func3) */
jump_table[FUNC0]();
jump_table[FUNC1]();
jump_table[FUNC2]();
jump_table[FUNC3]();
return 0;
}
This will output
0
1
2
3