简体   繁体   English

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

[英]How to combine LTO with symbol versioning

I would like to compile a shared library using both symbol versioning and link-time optimization (LTO).我想使用符号版本控制和链接时优化 (LTO) 来编译共享库。 However, as soon as I turn on LTO, some of the exported symbols vanish.但是,一旦我打开 LTO,一些导出的符号就会消失。 Here is a minimal example:这是一个最小的例子:

Start by defining two implementations of a function fun :首先定义函数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;
}

Create a version script to ensure that only fun is exported:创建一个版本脚本以确保只导出fun

$ cat versionscript 
v1 {
    global:
        fun;
    local:
        *;
};
v2 {
    global:
        fun;
} v1;

First attempt, compile without LTO:第一次尝试,在没有 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

..exactly as it should be. ..应该是这样。 But if I compile with LTO:但是如果我用 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

..no symbols exported anymore. ..不再导出符号。

What am I doing wrong?我做错了什么?

WHOPR Driver Design gives some strong hints to what is going on. WHOPR 驱动程序设计为正在发生的事情提供了一些强有力的提示。 The function definitions fun1 and fun2 are not exported according to the version script.函数定义fun1fun2不会根据版本脚本导出。 The LTO plugin is able to use this information, and since GCC does not peek into the asm directives, it knows nothing about the .symver directive, and therefore removes the function definition. LTO 插件能够使用此信息,并且由于 GCC 不会查看asm指令,因此它对.symver指令一无所知,因此删除了函数定义。

For now, adding __attribute__ ((externally_visible)) is the workaround for this.目前,添加__attribute__ ((externally_visible))是解决此问题的方法。 You also need to build with -flto-partition=none , so that the .symver directives do not land by accident in a different intermediate assembler file than the function definition (where it will not have the desired effect).您还需要使用-flto-partition=none进行构建,以便.symver指令不会意外地出现在与函数定义不同的中间汇编程序文件中(它不会产生预期的效果)。

GCC PR 48200 tracks an enhancement request for symbol versioning at the compiler level, which would likely address this issue as well. GCC PR 48200在编译器级别跟踪符号版本控制的增强请求,这也可能解决此问题。

It looks like my externally_visible fix works.看起来我的externally_visible修复有效。 This is:这是:

#define DLLEXPORT __attribute__((visibility("default"),externally_visible))

DLLEXPORT int fun1(void);

Also see: https://gcc.gnu.org/onlinedocs/gccint/WHOPR.html另见: https : //gcc.gnu.org/onlinedocs/gccint/WHOPR.html

But I think your versionscript is wrong.但我认为你的版本脚本是错误的。

If I take out the visibility overrides and change your versionscript by adding fun1 and fun2 then it works.如果我删除可见性覆盖并通过添加fun1fun2更改您的版本fun1 ,那么它就可以工作了。 Like:像:

v1 {
    global:
        fun; fun1;
    local:
        *;
};
v2 {
    global:
        fun; fun2;
} v1;

The symbol alias targets have to be visible as well as the alias.符号别名目标必须与别名一样可见。

I just hit the same problem - so thank you for asking this.我刚刚遇到了同样的问题 - 所以谢谢你提出这个问题。 However I've found it to be more clean to use __attribute__((used)) .但是我发现使用__attribute__((used))更干净。 Since gcc is not scanning the top level assembler, it can't figure out that fun1 and fun2 are being used ... so it removes them.由于 gcc 没有扫描顶级汇编程序,它无法确定正在使用fun1fun2 ......所以它删除了它们。 So it looks to me that changing definition to:所以在我看来,将定义更改为:

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

should be sufficient.应该足够了。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM