Linux系统下共享对象文件和可执行文件的格式都是ELF格式,它们并没有什么本质 上的区别。共享对象文件也是可以执行的。例如Linux下动态链接器ld-linux.so就 是共享对象文件,它也可以像可执行文件一样执行;Glibc库函数也是一样。
共享对象文件要执行有2个问题要解决:
最好用一个简单的例子来讲解这2个问题如何解决。示例代码如下:
#include // for printf() #include // for exit() void fun() { printf("This is fun./n"); exit(0); }
该代码保存在fun.c文件中。
第一个问题容易解决。要编译成PIC代码,只需要传递gcc选项-fpic即 可:
$ gcc -fpic -shared -Wl,-e,fun -o fun.so fun.c
其中-Wl,-e,fun是通知链接器生成的对象文件的入口地址是fun
。执行文件fun.so会得到如下结果:
$ ./fun.so Segmentation fault (core dumped)
之所以这样是因为在fun.c中调用了C语言库函数printf()
,但 没有对这个外部符号正确地重定位(由于没有.interp段,操作系统认为这个文件不需 要动态链接库重定位),因而引用了非法地址,所以产生了段错误。通过下面的命令 可以查看fun.so文件没有.interp段。
$ readelf -l ./fun.so | grep interp $
结果没有输出,说明fun.so文件中确实不存在.interp段。
要生成.interp段,可以在某个源文件中加入下面一句:
const char __invoke_dynamic_linker__[] __attribute__ ((section (".interp"))) = RUNTIME_LINKER;
这正是glibc的做法。这句代码在glibc的elf/interp.c文件中。 这也是为什么glibc库函数有.interp段的原因。 RUNTIME_LINKER就是动态链接库的名字,取决于目标机器。我们也可以用这种方式来解决这个问题,代码如下:
#include <stdio.h> // for printf() #include <stdlib.h> // for exit() const char __invoke_dynamic_linker[] __attribute__ ((section (".interp"))) = "/lib/ld-linux.so.2"; void fun() { printf("This is fun./n"); exit(0); }
注意我用/lib/ld-linux.so.2
替代了RUNTIME_LINKER,因为它就是linux上的 动态链接器,在/lib目录下。
用如下方式编译并执行:
$ gcc -fpic -shared -o fun.so -Wl,-e,fun fun.c $ ./fun.so
终于大功告成。
本文方法来 自这个帖子的回帖。
Updated: 2011-03-04 17:48