#include <stdio.h>
#include <dlfcn.h>

int main(int argc, char **argv) {
	void *handle;
/*	double (*cosine)(double); */
	int (*square)(int);
	const char *error;
/*	handle = dlopen ("/lib/libm.so.5", RTLD_LAZY); */
	handle = dlopen ("./shared.so", RTLD_LAZY);
	if (!handle) {
		fputs (dlerror(), stderr);
		exit(1);
	}

	square = dlsym(handle, "square");
	if ((error = dlerror()) != NULL)  {
		fputs(error, stderr);
		exit(1);
	}

/*	printf ("%f\n", (*cosine)(2.0)); */
	printf ("%d\n", (*square)(1));
	printf ("%d\n", (*square)(2));
	printf ("%d\n", (*square)(3));
	dlclose(handle);
}

/*
       void *dlopen (const char *filename, int flag);
       const char *dlerror(void);
       void *dlsym(void *handle, char *symbol);
       int dlclose (void *handle);

       Special symbols: _init, _fini.

Globals visible if (shlibs: opened with RTLD_GLOBAL flag)
(executable: linked with "-rdynamic")

       flag: RTLD_LAZY, resolve as executed, or
	     RTLD_NOW, resolve before return
 Optionally, | RTLD_GLOBAL: external syms available later libraries.

on dlopen, it invokes "_init"
If dlopen fails for any reason, it returns NULL.  -- call dlerror()
dlsym  takes  a  "handle", return address 
dlclose decrease refcount.  If 0, call _fini

                     gcc -rdynamic -o foo foo.c -ldl
*/
