在linux上有需要动态库是可以直接运行的,例如libc.so,可以直接运行,它会打印出版本等信息。我查了一些资料,要写一个可运行的动态库,至少需要做:
- 指定一个开始地址,即entry point,通过gcc -e参数指定。
- 如果依赖了其他库,需要指定解释器。(.interp section)。
对于第二点,到底要不要指定解释器,我目前了解的信息是,如果开始函数只调用了系统函数,不依赖其他库,就不用指定。因为解释器是用来解释依赖库的。
在我的机器上恰好有这么一个库libonlod.so,可执行:
查看解释器,没有interp section:
于是,我参考其代码,也想写一个不需要指定解释器的可执行的动态库。我的代码test.cpp源码如下:
#include <sys/uio.h>
#include <linux/unistd.h>
#include <unistd.h>
//指定解释器
extern const char elf_interpreter[] __attribute__((section(".interp"))) = "/lib64/ld-linux-x86-64.so.2";
int my_do_syscall3(int num, long a1, long a2, long a3)
{
int rc;
__asm__ __volatile__(
"syscall"
: "=a" (rc)
: "0"((long)num), "D"(a1), "S"(a2), "d"(a3)
: "r11","rcx","memory"
);
return rc;
}
#define my_syscall3(call, a1, a2, a3) \
my_do_syscall3(__NR_##call, (a1), (a2), (a3))
extern "C" void func()
{
struct iovec v[1];
static const char msg0[] = "Hello so\n";
v[0].iov_base = (void*) msg0;
v[0].iov_len = sizeof(msg0)-1;
my_syscall3(writev, STDOUT_FILENO, (long) v, 1);
my_syscall3(exit, 0, 0, 0);
return 0;
}
在上述代码中,我是指定了解释器的。编译指定如下:
gcc -fPIC -shared -e func test.cpp -o libtest.so
编译后执行结果:
[compile@localhost executable_so]$ ./libtest.so
Hello so
接下来,我把添加解释器的部分注释掉,也就是不指定解释器
// 注释掉 指定解释器
// extern const char elf_interpreter[] __attribute__((section(".interp"))) = "/lib64/ld-linux-x86-64.so.2";
然后重新编译,执行,程序挂掉。
我觉得我上面的代码只用到了系统调用,为什么不能执行呢?
我的操作系统是:CentOS Linux release 7.6.1810 (Core)
gcc版本:gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-44)