-
-
Save tailriver/30bf0c943325330b7b6a to your computer and use it in GitHub Desktop.
| #include <stdio.h> | |
| #include <stdlib.h> | |
| #include <string.h> | |
| #include <dlfcn.h> | |
| int main(int argc, char** argv) | |
| { | |
| void *handle; | |
| void (*func_print_name)(const char*); | |
| if (argc != 2) { | |
| fprintf(stderr, "Usage: %s animal_type\n", argv[0]); | |
| return EXIT_FAILURE; | |
| } | |
| if (strcmp(argv[1], "dog") == 0) { | |
| handle = dlopen("./libdog.so", RTLD_LAZY); | |
| } else if (strcmp(argv[1], "cat") == 0) { | |
| handle = dlopen("./libcat.so", RTLD_LAZY); | |
| } else { | |
| fprintf(stderr, "Error: unknown animal type: %s\n", argv[1]); | |
| return EXIT_FAILURE; | |
| } | |
| if (!handle) { | |
| /* fail to load the library */ | |
| fprintf(stderr, "Error: %s\n", dlerror()); | |
| return EXIT_FAILURE; | |
| } | |
| *(void**)(&func_print_name) = dlsym(handle, "print_name"); | |
| if (!func_print_name) { | |
| /* no such symbol */ | |
| fprintf(stderr, "Error: %s\n", dlerror()); | |
| dlclose(handle); | |
| return EXIT_FAILURE; | |
| } | |
| func_print_name(argv[1]); | |
| dlclose(handle); | |
| return EXIT_SUCCESS; | |
| } |
| #pragma once | |
| void print_name(const char* type); |
| #include "animal.h" | |
| #include <stdio.h> | |
| void print_name(const char* type) | |
| { | |
| printf("Tama is a %s.\n", type); | |
| } |
| #include "animal.h" | |
| #include <stdio.h> | |
| void print_name(const char* type) | |
| { | |
| printf("Pochi is a %s.\n", type); | |
| } |
| app = dlopen_sample | |
| lib = libcat.so libdog.so | |
| CFLAGS = -Wall -ansi -pedantic | |
| LDFLAGS = -ldl | |
| all: $(app) $(lib) | |
| lib%.so: %.c | |
| $(CC) -shared -fPIC $(CFLAGS) -o $@ $< | |
| clean: | |
| $(RM) $(app) $(lib) | |
| run: all | |
| ./$(app) cat | |
| ./$(app) dog | |
| -./$(app) bear | |
| $(lib): animal.h |
@cirosantili I like yours betters (not that this one is bad!)
Awesome! BTW, Tama and Pochi reminds me of an anime. Something like Death march kara hajimaru.
I am not able to compile the code. I am getting error. Please help.
[s]$ gcc dlopen_sample.c -o a
/tmp/cc3t29je.o: In function main': dlopen_sample.c:(.text+0x67): undefined reference to dlopen'
dlopen_sample.c:(.text+0x98): undefined reference to dlopen' dlopen_sample.c:(.text+0xd8): undefined reference to dlerror'
dlopen_sample.c:(.text+0x110): undefined reference to dlsym' dlopen_sample.c:(.text+0x121): undefined reference to dlerror'
dlopen_sample.c:(.text+0x149): undefined reference to dlclose' dlopen_sample.c:(.text+0x170): undefined reference to dlclose'
collect2: error: ld returned 1 exit status
[s]$
@apurba-101010 You need to link libdl.so, so add -ldl (see LDFLAGS in my Makefile).
default LDFLAGS with wrong position, add code in Makefile like this:
dlopen_sample: dlopen_sample.c
Why need (void*)(&func_print_name) = dlsym(handle, "print_name");
When can use func_print_name = (void()(const char))(dlsym(handle, "print_name")); ?
Sorry for my English.
Why need (void*)(&func_print_name) = dlsym(handle, "print_name"); When can use func_print_name = (void()(const char))(dlsym(handle, "print_name")); ?
Sorry for my English.
@TKNgu From the man https://man7.org/linux/man-pages/man3/dlopen.3.html emphasis mine:
cosine = (double (*)(double)) dlsym(handle, "cos");
/* According to the ISO C standard, casting between function
pointers and 'void *', as done above, produces undefined results.
POSIX.1-2001 and POSIX.1-2008 accepted this state of affairs and
proposed the following workaround:
*(void **) (&cosine) = dlsym(handle, "cos");
This (clumsy) cast conforms with the ISO C standard and will
avoid any compiler warnings.
The 2013 Technical Corrigendum 1 to POSIX.1-2008 improved matters
by requiring that conforming implementations support casting
'void *' to a function pointer. Nevertheless, some compilers
(e.g., gcc with the '-pedantic' option) may complain about the
cast used in this program. */
Now you know a thing or two.
Thx for your example but just there is an addition; you can add the lines below to your Makefile to resolve the "undefined reference" error:
$(app):
$(CC) $(app).c -fPIC $(CFLAGS) $(LDFLAGS) -o $@ $<
This code relies on unspecified behavior according to POSIX standard: at least one of RTLD_GLOBAL and RTLD_LOCAL should be specified in dlopen().
Here is another minimal runnable example: https://github.com/cirosantilli/cpp-cheat/blob/81ab30c55634db24216e89ada1e0f271cac074e7/shared-library/basic/dlopen.c