实现可执行的so文件

Linux下的so文件通常是作为动态链接库使用的,但其实so文件跟可执行程序一样都是ELF格式,所以应该都是可以直接执行的。 在Linux下的很多so库文件都是可以直接执行的,不过通常只是打印出编译信息。例如:

/lib64/ld-linux-x86-64.so.2

还有

/lib/x86_64-linux-gnu/libpthread.so.0

还有

/lib/x86_64-linux-gnu/libc.so.6

特别说明一下,我的系统为Ubuntu 10.04 64bit版本。

要让一个so文件可直接执行,只需要在编译时指定入口函数即可,否则强制执行一个so文件会导致出core。gcc和g++,即C和C++在实现步骤上略有不同。

gcc编译

例如有源文件service.c

#include <stdio.h>
#include <stdlib.h>

const char service_interp[] __attribute__((section(".interp"))) = "/lib64/ld-linux-x86-64.so.2";

void lib_service()
{
    printf("This is a service of the shared library\n");
} 

void lib_entry()
{
    printf("Entry point of the service library\n");
    exit(0);
}

注意,service_interp变量指明了ld.so的位置,不同的Linux系统略有不同,函数lib_entry()必须以exit(0)结束。 编译指令:

gcc -shared service.c -o libservice.so -Wl,-e,lib_entry -fPIC

-Wl表示传递给链接器ld的参数,分隔的逗号会被替换成空格。-e,lib_entry就指明了入口函数。 编译生成的libservice.so就可以直接执行了:

ubuntu:/tmp/service$ ./libservice.so 
Entry point of the service library

当然,这丝毫不会影响libservice.so作为动态链接库的功能。

g++编译

上面的例子是编译C代码,如果要编译C++代码,基本没有什么不同,除了使用g++外,就是得注意函数名的重构问题。 有两种处理方式,其一,使用extern "C"迫使函数名保持原样,其二,先使用g++ -c将代码编译成.o文件, 再使用readelf -s service.o来查看重构之后的函数名,在编译时使用重构后的函数名,例如:-Wl,-e,_Z10test_entryv

再值得注意一点的是,入口函数及其所调用的函数不能使用C++的输入输出类,即不能使用cout、cin之类,否则就会core。 使用C函数进行输入输出操作是没有问题的,我觉得这个问题是可以解决的,但我目前没有找到问题在哪,先留个TODO在此。

总结

将程序的核心逻辑进行so化是有相当多好处的,比如可以进行多实例部署,可以将词典资源抽离出来,可以加快服务拉起, 可以充分利用机器资源等。而给so文件直接可执行的功能,就可以方便地了解so文件编译信息、版本信息、使用方法等。

P.S.在此感谢此文How to make executable shared libraries

发表于 2014年07月09日 16:13   评论:0   阅读:6058  



回到顶部

首页 | 关于我 | 关于本站 | 站内留言 | rss
python logo   django logo   tornado logo