使用可见性或链接器隐藏/删除精灵符号,无需共享库

问题描述 投票:0回答:0

我想在 C 库/文件的正常使用中隐藏一些符号,以防止名称冲突并避免 API 的可能扩展(Hyrum 定律)。静态符号是隐藏的(但我的用例是多文件,所以我不能使用它们)。可见性有点工作——但显然只有当你使用共享库时(我的用例不可能)。

我试过使用版本链接器脚本来隐藏除我想公开的符号之外的所有符号,但它似乎并没有真正影响链接(即使随后将它变成共享库)。

--功能部分无济于事--功能在内部使用。 -fwhole-program 可能会工作,如果它不是硬连线只公开 main.

#!/bin/sh
set -ex

cat > foo.c <<EOF
extern void exportfunc_nonattr(void);
extern void exportfunc_default(void) __attribute__ ((visibility ("default")));
extern void exportfunc_internal(void) __attribute__ ((visibility ("internal")));
extern void exportfunc_hidden(void) __attribute__ ((visibility ("hidden")));
extern void exportfunc_protected(void) __attribute__ ((visibility ("protected")));
void func_nonattr(void);
void func_default(void) __attribute__ ((visibility ("default")));
void func_internal(void) __attribute__ ((visibility ("internal")));
void func_hidden(void) __attribute__ ((visibility ("hidden")));
void func_protected(void) __attribute__ ((visibility ("protected")));
static void staticfunc(void);

void exportfunc_nonattr(void) {}
void exportfunc_default(void) {}
void exportfunc_internal(void) {}
void exportfunc_hidden(void) {}
void exportfunc_protected(void) {}
void func_nonattr(void) {}
void func_default(void) {}
void func_internal(void) {}
void func_hidden(void) {}
void func_protected(void) {}
void staticfunc(void) {}
EOF
cat > food.c <<EOF
extern void exportfunc_nonattr(void);
extern void exportfunc_default(void) __attribute__ ((visibility ("default")));
extern void exportfunc_internal(void) __attribute__ ((visibility ("internal")));
extern void exportfunc_hidden(void) __attribute__ ((visibility ("hidden")));
extern void exportfunc_protected(void) __attribute__ ((visibility ("protected")));
void func_nonattr(void);
void func_default(void) __attribute__ ((visibility ("default")));
void func_internal(void) __attribute__ ((visibility ("internal")));
void func_hidden(void) __attribute__ ((visibility ("hidden")));
void func_protected(void) __attribute__ ((visibility ("protected")));
#ifdef TRY_STATIC
static void staticfunc(void);
#endif

int main(int argc, char **argv, char **envp)
{
    exportfunc_nonattr();
    exportfunc_default();
    exportfunc_internal();
    exportfunc_hidden();
    exportfunc_protected();
    func_nonattr();
    func_default();
    func_internal();
    func_hidden();
    func_protected();
#ifdef TRY_STATIC
    staticfunc();
#endif
}
EOF
cat > foo.script <<EOF
{
  global:
    exportfunc_default;
  local:
    *;
};
EOF

: Compile test source
gcc -c -o foo.o foo.c
gcc -fvisibility=internal -c -o foo-internal.o foo.c

# Try different ways to permute the produced object files (with and without internal visibility): shared library, garbage collection, linker scripts
for f in foo foo-internal; do
  : === Direct link $f
  gcc -o foo-exec food.c $f.o
  : === Linker Script $f
  ld -O3 -i --version-script foo.script -o $f-script.o $f.o
  gcc -o foo-exec food.c ./$f-script.o && ./foo-exec
  : === Garbage collected linker script $f
  ld -O3 -x -i --gc-sections -e exportfunc_default --version-script foo.script -o $f-gcscript.o $f.o
  gcc -o foo-exec food.c ./$f-gcscript.o && ./foo-exec
done

作为送给真正想要共享库的人的礼物,以下命令(如果在循环内的上述 shell 脚本中插入)将使隐藏、受保护和内部符号的“未定义引用”链接失败。如果使用 -fvisibility 编译,则 nonattr 变体也是未定义的。

  echo === Shared library
  gcc -shared -o lib$f.so $f.o
  gcc -o foo-exec food.c -L. -l$f && ./foo-exec
  echo  === Garbage collected shared library
  gcc -Wl,--gc-sections -shared -o lib$f-gc.so $f.o
  gcc -o foo-exec food.c -L. -l$f-gc && ./foo-exec
c gcc linker ld linker-scripts
© www.soinside.com 2019 - 2024. All rights reserved.