您可以将每个函数作为一个模块(Windows 的共享对象或 dll)带有已知名称的单个符号,然后在运行时只需扫描目录以查找.sos or .dll加载每个并创建一个指向该符号的指针,假设您有N模块,其中i第一个模块源代码是
模块.i.c
int function(char *parameter)
{
// Do whatever you want here
return THE_RETURN_VALUE;
}
然后你编译每个.c文件到共享对象中,我将使用 Linux 进行说明,在 Windows 上您可以做类似的事情,并且 Linux 解决方案适用于 POSIX 系统,因此它涵盖了很多内容
首先生成模块.i.c包含此脚本的文件
#!/bin/bash
for i in {0..100};
do
cat > module.$i.c <<EOT
#include <stdlib.h>
int
function(char *parameter)
{
// Deal with parameter
return $i;
}
EOT
done
现在创建一个Makefile像这个
CC = gcc
LDFLAGS =
CFLAGS = -Wall -Werror -g3 -O0
FUNCTIONS = $(patsubst %.c,%.so, $(wildcard *.*.c))
all: $(FUNCTIONS)
$(CC) $(CFLAGS) $(LDFLAGS) main.c -o main -ldl
%.so: %.c
$(CC) -shared $(CFLAGS) $(LDFLAGS) $< -o $@
clean:
@rm -fv *.so *.o main
以及将加载模块的程序(我们假设它们与可执行文件位于同一目录中)
#include <stdlib.h>
#include <dirent.h>
#include <string.h>
#include <stdio.h>
#include <dlfcn.h>
int
main(void)
{
DIR *dir;
struct dirent *entry;
dir = opendir(".");
if (dir == NULL)
return -1;
while ((entry = readdir(dir)) != NULL)
{
void *handle;
char path[PATH_MAX];
int (*function)(char *);
if (strstr(entry->d_name, ".so") == NULL)
continue;
if (snprintf(path, sizeof(path), "./%s", entry->d_name) >= sizeof(path))
continue;
handle = dlopen(path, RTLD_LAZY);
if (handle == NULL)
continue; // Better: report the error with `dlerror()'
function = (int (*)(char *)) dlsym(handle, "function");
if (function != NULL)
fprintf(stdout, "function: %d\n", function("example"));
else
fprintf(stderr, "symbol-not-found: %s\n", entry->d_name);
dlclose(handle);
}
closedir(dir);
return 0;
}
在 Windows 上,想法是相同的,尽管您无法像上面的代码那样遍历目录,并且需要使用LoadLibrary() https://msdn.microsoft.com/en-us/library/windows/desktop/ms684175%28v=vs.85%29.aspx代替dlopen()
,并替换dlsym()
具有适当的功能。
但同样的想法也可行。
有关如何保护您加载的模块及其文件夹的更多信息,请参阅这个问题 https://stackoverflow.com/questions/34722352/how-can-i-secure-the-plugins-i-load