天天看点

Linux上制作可执行的共享库示例

Linux上制作可执行的共享库示例

x.cpp为共享库libx.so的实现,b.cpp为可执行b的实现。

x.cpp文件内容:

#include

// 使用C++作为编译器

void woo()

{

    printf("woo\n");

}

// foo作为共享库的入口,必须为C函数

extern "C" foo()

    printf("foo\n");

    exit(0); // 请注意这里必须调用,否则输出foo后会有段错误

b.cpp文件内容:

int main()

    extern void woo();

    extern "C" void foo();

    woo();

    foo();

    return 0;

编译x.cpp为可执行的共享库:

g++ -g -o libx.so -fPIE -pie -nostartfiles -Wl,-e,foo -rdynamic x.cpp

-fPIE -pie是保证共享库可以执行,其中-fPIE编译参数,表示生成与位置无关的可执行代码(-fPIC只是生成与位置无关的非可执行代码),-pid是链接参数;-Wl,-e,foo指定共享库的入口函数,相当于可执行程序的main函数;如果没有-nostartfiles,则链接时会报main函数未定义;-rdynamic也是必须的,否则编译b.cpp时会报找不到foo定义;如需查看详细的编译链接过程,加上-v参数。请注意不能包含<b>-shared</b>参数,否则运行共享库时直接段错误。

编译b.cpp为可执行文件:

g++ -g -o b -L. -lx  b.cpp

成功之后,libx.so和b都是可执行的了,其中libx.so的入口是foo,而b的入口是main函数。

当使用选项-fpie或-fPIE时,生成的共享库不会为静态成员变量或全局变量在GOT中创建对应的条目(通过objdump -x -R或readelf命令可以查看)。选项-fpie/-fPIE与-fpic/ -fPIC的用法很相似,区别在于前者总是将生成的位置无关代码看作是属于程序本身,并直接链接进该可执行程序,而非存入全局偏移表GOT中。

GCC MAN描述:

-fpie

-fPIE

   These options are similar to -fpic and -fPIC, but generated position independent code can be only linked into executables.  Usually these options are

   used when -pie GCC option will be used during linking.

-fpic

-fPIC

   Generate position-independent code (PIC) suitable for use in a shared library.

   Such code accesses all constant addresses through a global offset table (GOT).  The dynamic loader resolves the GOT entries when the program starts (the dynamic loader is not part of GCC, it is part of the operating system).

   If the GOT size for the linked executable exceeds a machine-specific maximum size, you get an error message from the linker indicating that -fpic does not work; in that case, recompile with -fPIC instead.

-pie

   Produce a position independent executable on targets which support it.  For predictable results, you must also specify the same set of options that were

   used to generate code (-fpie, -fPIE, or model suboptions) when you specify this option.

-rdynamic

   Pass the flag -export-dynamic to the ELF linker, on targets that support it. This instructs the linker to add all symbols, not only used ones, to the

   dynamic symbol table. This option is needed for some uses of "dlopen" or to allow obtaining backtraces from within a program.

-Wl的使用

-Wl表示后面的参数传递给链接器,其中l是linker的意思。

链接时指定共享库的搜索路径(类似于设置LD_LIBRARY_PATH):

-Wl,-rpath=/usr/local/abc:/data/abc

以上也可以分开写:

-Wl,-rpath=/usr/local/abc -Wl,-rpath=/data/abc

部分库链接它的静态库,部分库链接它的共享库:

-Wl,-static -lb -Wl,-call_shared -la -lz

指定链接器:

-Wl,-dynamic-linker /lib/ld-linux.so.2 -e _so_start

指定导出的符号:

-Wl,--export-dynamic,--version-script,exports.lds

exports.lds的格式可以为:

global:

foo;

};

指定共享库的soname:

-Wl,--export-dynamic,--version-script,exports.lds,-soname=libqhttpd.so

-rpath 增加共享库搜索路径

--retain-symbols-file表示不丢弃未定义的符号和需要重定位的符号

--export-dynamic 创建一个动态连接的可执行程序时, 把所有的符号加到动态符号表中