如何将LTO与符号版本控制相结合

Nik*_*tio 7 c linker gcc lto

我想使用符号版本控制和链接时优化(LTO)编译共享库.但是,只要我打开LTO,一些导出的符号就会消失.这是一个最小的例子:

首先定义函数fun的两个实现:

$ cat fun.c 
#include <stdio.h>

int fun1(void);
int fun2(void);

__asm__(".symver fun1,fun@v1");
int fun1() {
    printf("fun1 called\n");
    return 1;
}

__asm__(".symver fun2,fun@@v2");
int fun2() {
    printf("fun2 called\n");
    return 2;
}
Run Code Online (Sandbox Code Playgroud)

创建版本脚本以确保仅导出乐趣:

$ cat versionscript 
v1 {
    global:
        fun;
    local:
        *;
};
v2 {
    global:
        fun;
} v1;
Run Code Online (Sandbox Code Playgroud)

第一次尝试,没有LTO编译:

$ gcc -o fun.o -Wall -Wextra -O2 -fPIC -c fun.c
$ gcc -o libfun.so.1 -shared -fPIC -Wl,--version-script,versionscript fun.o
$ nm -D --with-symbol-versions libfun.so.1 | grep fun
00000000000006b0 T fun@@v2
0000000000000690 T fun@v1
Run Code Online (Sandbox Code Playgroud)

......完全应该如此.但是如果我用LTO编译:

$ gcc -o fun.o -Wall -Wextra -flto -O2 -fPIC -c fun.c
$ gcc -o libfun.so.1 -flto -shared -fPIC -Wl,--version-script,versionscript fun.o
$ nm -D --with-symbol-versions libfun.so.1 | grep fun
Run Code Online (Sandbox Code Playgroud)

..不再导出符号.

我究竟做错了什么?

Flo*_*mer 4

WHOPR 驱动程序设计对正在发生的事情给出了一些强烈的暗示。函数定义fun1fun2不根据版本脚本导出。LTO 插件能够使用此信息,并且由于 GCC 不会查看指令asm,因此它对指令一无所知.symver,因此删除了函数定义。

目前,添加__attribute__ ((externally_visible))是解决此问题的方法。您还需要使用 进行构建-flto-partition=none,以便.symver指令不会意外地出现在与函数定义不同的中间汇编程序文件中(在该文件中不会产生所需的效果)。

GCC PR 48200跟踪编译器级别符号版本控制的增强请求,这也可能解决此问题。