我一直在寻找对此的支持pam_cap.so
,并找到了这个问题。正如@EmployedRussian 在他们自己帖子的后续文章中指出的那样,接受的答案在某个时候停止工作。花了一段时间才弄清楚如何让这项工作再次发挥作用,所以这里有一个工作示例。
这个工作示例涉及 5 个文件,以显示一些相应的测试是如何工作的。
首先,考虑这个简单的程序(调用它empty.c
):
int main(int argc, char **argv) { return 0; }
编译它,我们可以看到它是如何解析我系统上的动态符号的,如下所示:
$ gcc -o empty empty.c
$ objcopy --dump-section .interp=/dev/stdout empty ; echo
/lib64/ld-linux-x86-64.so.2
$ DL_LOADER=/lib64/ld-linux-x86-64.so.2
最后一行设置了一个 shell 变量以供以后使用。
以下是构建我的示例共享库的两个文件:
/* multi.h */
void multi_main(void);
void multi(const char *caller);
和
/* multi.c */
#include <stdio.h>
#include <stdlib.h>
#include "multi.h"
void multi(const char *caller) {
printf("called from %s\n", caller);
}
__attribute__((force_align_arg_pointer))
void multi_main(void) {
multi(__FILE__);
exit(42);
}
const char dl_loader[] __attribute__((section(".interp"))) =
DL_LOADER ;
(2021-11-13 更新:强制对齐是为了帮助__i386__
代码与 SSE 兼容- 没有它,我们很难调试glibc
SIGSEGV
崩溃。)
我们可以如下编译运行它:
$ gcc -fPIC -shared -o multi.so -DDL_LOADER="\"${DL_LOADER}\"" multi.c -Wl,-e,multi_main
$ ./multi.so
called from multi.c
$ echo $?
42
因此,这是一个.so
可以作为独立二进制文件执行的程序。接下来,我们验证它是否可以作为共享对象加载。
/* opener.c */
#include <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv) {
void *handle = dlopen("./multi.so", RTLD_NOW);
if (handle == NULL) {
perror("no multi.so load");
exit(1);
}
void (*multi)(const char *) = dlsym(handle, "multi");
multi(__FILE__);
}
也就是说,我们动态加载共享对象并从中运行一个函数:
$ gcc -o opener opener.c -ldl
$ ./opener
called from opener.c
最后,我们链接到这个共享对象:
/* main.c */
#include "multi.h"
int main(int argc, char **argv) {
multi(__FILE__);
}
我们编译和运行它的地方如下:
$ gcc main.c -o main multi.so
$ LD_LIBRARY_PATH=./ ./main
called from main.c
(注意,因为multi.so
不在标准系统库位置,我们需要覆盖运行时使用LD_LIBRARY_PATH
环境变量查找共享对象文件的位置。)