Cra*_*ger 5 linker gcc llvm ld linker-scripts
TL;DR:我可以使用 GNUld
链接器--version-script
或其他一些方法将具有hidden
可见性(由于-fvisibility=hidden
或显式__attribute__
)的选定符号提升回default
可见性,以便它们在共享库的全局符号表中可用?
有什么方法可以告诉 gnu ld version-scriptHIDDEN
将global:
version-script 部分中的符号提升为DEFAULT
可见性?
对于一个相当奇怪的系统,我需要链接一个共享库,以便所有非静态函数符号都具有默认可见性,但所有其他符号都获得“隐藏”可见性,除非用适当的可见性属性明确注释。
如果有办法告诉gcc
类似(无效的虚构语法)-fvisibility=hidden -fvisibility-functions=default
,那就太完美了。
使用 gcc 编译 -fvisibility=hidden
将使所有未注释的符号隐藏可见性。
所以我想我会使用链接器版本脚本将在 ELF 对象中具有全局范围和隐藏可见性的函数提升为默认(全局)可见性。
但是,当在链接器版本脚本global
部分中命名符号时,GNU LD 似乎不会更改可见性属性。该local
部分中的符号被隐藏,但该部分中已经隐藏的符号global
不会被提升为default
.
给定简化对象(宏扩展等):
/* Public global variables are annotated */
extern int exportvar __attribute__ ((visibility ("default")));
int exportvar;
/* Internal ones are not annotated */
extern int nonexportvar;
int nonexportvar;
/* Nor are static vars obviously */
static int nonexportvar;
/* For various weird reasons we can't annotate functions with visibility information */
extern void exportfunc(void);
void exportfunc(void) {
};
static void staticfunc(void) {
};
Run Code Online (Sandbox Code Playgroud)
使用链接脚本:
链接器脚本片段linker-script
:
{
global:
exportfunc;
exportvar;
local:
*;
};
Run Code Online (Sandbox Code Playgroud)
构建使用Makefile
(去标签化以便于复制/粘贴):
.RECIPEPREFIX=~
USE_LLVM?=0
VERBOSE_SYMS?=
EXTRA_CFLAGS?=
LINK_FLAGS?=
# Don't optimise so we retain the unused statics etc in this
# demo code.
EXTRA_CFLAGS+=-O0
ifneq (,$(LINKER_SCRIPT))
LINK_FLAGS+=--version-script=$(LINKER_SCRIPT)
endif
ifeq (1,$(USE_LLVM))
CC=clang -c $(EXTRA_CFLAGS)
LINK_SHARED=ld.lld -shared $(LINK_SHARED)
else
CC=gcc -c $(EXTRA_CFLAGS)
COMMA:=,
LINK_SHARED=gcc -shared $(addprefix -Wl$(COMMA),$(LINK_FLAGS))
endif
all: clean demo.so dumpsyms
clean:
~ @rm -f demo.o demo.so
demo.o: demo.c
~ $(CC) -o $@ $<
demo.so: demo.o
~ $(LINK_SHARED) -o $@ $<
# Show object file and full symbol table if VERBOSE_SYMS=1
ifneq (,$(VERBOSE_SYMS))
dumpsyms: demo.o demo.so
~ @echo
~ @echo "demo.o:"
~ @readelf --syms demo.o | egrep '(Symbol table|exportvar|nonexportvar|staticvar|exportfunc|nonexportfunc)'
~ @echo
~ @echo "demo.so:"
~ @readelf --syms demo.so | egrep '(Symbol table|exportvar|nonexportvar|staticvar|exportfunc|staticfunc)'
~ @echo
else
# Only show dynamic symbols by default
dumpsyms: demo.o demo.so
~ @echo
~ @echo "demo.so:"
~ @readelf --dyn-syms demo.so | egrep '(Symbol table|exportvar|nonexportvar|staticvar|exportfunc|nonexportfunc)'
~ @echo
endif
Run Code Online (Sandbox Code Playgroud)
$ make
gcc -c -O0 -o demo.o demo.c
gcc -Wall -O0 -shared -o demo.so demo.o
demo.so:
Symbol table '.dynsym' contains 8 entries:
5: 00000000000010f9 7 FUNC GLOBAL DEFAULT 11 exportfunc
6: 0000000000004028 4 OBJECT GLOBAL DEFAULT 21 nonexportvar
7: 0000000000004024 4 OBJECT GLOBAL DEFAULT 21 exportvar
Run Code Online (Sandbox Code Playgroud)
make LINKER_SCRIPT=linker-script
gcc -c -O0 -o demo.o demo.c
gcc -Wall -O0 -Wl,--version-script=linker-script -shared -o demo.so demo.o
demo.so:
Symbol table '.dynsym' contains 7 entries:
5: 0000000000004024 4 OBJECT GLOBAL DEFAULT 21 exportvar
6: 00000000000010f9 7 FUNC GLOBAL DEFAULT 11 exportfunc
Run Code Online (Sandbox Code Playgroud)
nonexportvar
已按预期从动态符号表中消失。
-fvisibility=hidden
和没有链接器脚本$ make EXTRA_CFLAGS="-fvisibility=hidden"
gcc -c -fvisibility=hidden -o demo.o demo.c
gcc -Wall -fvisibility=hidden -shared -o demo.so demo.o
demo.so:
Symbol table '.dynsym' contains 6 entries:
5: 0000000000004024 4 OBJECT GLOBAL DEFAULT 21 exportvar
Run Code Online (Sandbox Code Playgroud)
exportfunc
在导出符号表中不可见。这是意料之中的,因为没有链接描述文件会覆盖可见性。
-fvisibility=hidden
和链接脚本我们可以使用链接描述文件使隐藏的函数符号可见吗?
$ make EXTRA_CFLAGS="-fvisibility=hidden" LINKER_SCRIPT=linker-script
gcc -c -fvisibility=hidden -o demo.o demo.c
gcc -Wall -fvisibility=hidden -Wl,--version-script=linker-script -shared -o demo.so demo.o
demo.so:
Symbol table '.dynsym' contains 6 entries:
5: 0000000000004024 4 OBJECT GLOBAL DEFAULT 21 exportvar
Run Code Online (Sandbox Code Playgroud)
……好像没有。
为什么?
$ make EXTRA_CFLAGS="-fvisibility=hidden" LINKER_SCRIPT=linker-script VERBOSE_SYMS=1
gcc -c -fvisibility=hidden -o demo.o demo.c
gcc -Wall -fvisibility=hidden -Wl,--version-script=linker-script -shared -o demo.so demo.o
demo.o:
Symbol table '.symtab' contains 13 entries:
5: 0000000000000008 4 OBJECT LOCAL DEFAULT 3 staticvar
10: 0000000000000000 4 OBJECT GLOBAL DEFAULT 3 exportvar
11: 0000000000000004 4 OBJECT GLOBAL HIDDEN 3 nonexportvar
12: 0000000000000000 7 FUNC GLOBAL HIDDEN 1 exportfunc
demo.so:
Symbol table '.dynsym' contains 6 entries:
5: 0000000000004024 4 OBJECT GLOBAL DEFAULT 21 exportvar
Symbol table '.symtab' contains 52 entries:
33: 000000000000402c 4 OBJECT LOCAL DEFAULT 21 staticvar
39: 00000000000010f9 7 FUNC LOCAL DEFAULT 11 exportfunc
42: 0000000000004028 4 OBJECT LOCAL DEFAULT 21 nonexportvar
50: 0000000000004024 4 OBJECT GLOBAL DEFAULT 21 exportvar
Run Code Online (Sandbox Code Playgroud)
它看起来像GNUld
转向GLOBAL HIDDEN
符号在.o
进入LOCAL DEFAULT
的符号.so
。
链接描述文件在这里似乎没有效果;无论有没有它,结果都是一样的。
有什么办法可以告诉链接器版本脚本HIDDEN
将global
部分中的符号提升为DEFAULT
可见性吗?
不幸的是,我不能放弃默认情况下对函数可见的要求,而所有其他符号只有在明确注释时才应该可见。我需要匹配 Windows 构建的行为,该构建使用生成的.def
文件在使用时导出所有函数__declspec__("dllexport")
仅导出选定的其他符号。
由于代码库的大小、复杂性、共享控制等,我无法通过合适的属性宏来注释每个函数。
我无法枚举所有要手动导出的符号并维护一个手写的链接器脚本;代码库有太多不同的配置、版本和构建选项。
如果有帮助,我可以使用不同的广泛可用的编译器和工具链,并且工具链版本不是问题。我试过使用 LLVMclang
并ld.lld
得到相同的结果。
帮助?想法?
归档时间: |
|
查看次数: |
653 次 |
最近记录: |