Linux
下的so
文件通常是作为动态链接库使用的,但其实so
文件跟可执行程序一样都是ELF
格式,所以应该都是可以直接执行的。
Linux
下编译可以执行的so
文件如下:
1 2 3 4 5 6 7 8 |
#include <stdio.h> #include <stdlib.h> void lib_entry() { printf("Entry point of the service library\n"); exit(0); } |
注意,lib_entry()
必须以exit(0)
结束,否则会导致进程退出失败。
使用如下命令编译源代码:
1 |
$ gcc -shared service.c -o libservice.so -Wl,-e,lib_entry -fPIC |
-Wl
表示传递给链接器ld
的参数,分隔的逗号会被替换成空格。-e,lib_entry
就指明了入口函数。
而对于Android
来说,只需要在Android.mk
文件中增加LOCAL_LDLIBS += -Wl,-e,lib_entry
就可以达到相同的目的了。
需要注意的问题
1.这个入口函数是否可以传递类型int main(int argc,char* argv[])
这样的参数进去?
答案是不能,那么启动参数从哪里读取呢? 答案就是从/proc/$pid/cmdline
中手工解析获取。
2.入口函数并没有初始化C
库的代码,在调用代码时候为什么没有崩溃?
正常情况下,可执行程序的入口函数实际上是C
库的的入口函数,然后C库自身初始化完成,解析参数后调用我们自己实现的入口函数。按照常规逻辑,如果没有初始化C
库,那么调用C
库函数的时候,几乎肯定是会崩溃的。
反编译正常的可执行程序,应该都能看到C库的初始化函数,而指定了入口的,基本上都没有这个函数的调用。
但是在Linux
下面ld.so
会帮我们初始化一次C
库,而我们又是被ld.so
加载起来的,因此理论上,我们不需要再次初始化C
库了。