如何隐藏跨多个文件可见的全局变量?

时间:2022-10-06 23:38:12

I am writing a C (shared) library. It started out as a single translation unit, in which I could define a couple of static global variables, to be hidden from external modules.

我正在写一个C(共享)库。它最初只是一个翻译单元,我可以在其中定义几个静态全局变量,以便从外部模块中隐藏。

Now that the library has grown, I want to break the module into a couple of smaller source files. The problem is that now I have two options for the mentioned globals:

现在库已经增长了,我想把模块分成几个较小的源文件。问题是现在我有两个选项用于提到的全局变量:

  1. Have private copies at each source file and somehow sync their values via function calls - this will get very ugly very fast.

    在每个源文件上都有私有副本,并通过函数调用以某种方式同步它们的值 - 这将非常快速地变得非常丑陋。

  2. Remove the static definition, so the variables are shared across all translation units using extern - but now application code that is linked against the library can access these globals, if the required declaration is made there.

    删除静态定义,因此使用extern在所有翻译单元之间共享变量 - 但是现在,如果在那里进行了所需的声明,则链接到库的应用程序代码可以访问这些全局变量。

So, is there a neat way for making private global variable shared across multiple, specific translation units?

那么,是否有一种巧妙的方法可以在多个特定的翻译单元之间共享私有全局变量?

4 个解决方案

#1


6  

You want the visibility attribute extension of GCC.

您需要GCC的visibility属性扩展。

Practically, something like:

实际上,类似于:

 #define MODULE_VISIBILITY  __attribute__ ((visibility ("hidden")))
 #define PUBLIC_VISIBILITY  __attribute__ ((visibility ("default")))

(You probably want to #ifdef the above macros, using some configuration tricks à la autoconfand other autotools; on other systems you would just have empty definitions like #define PUBLIC_VISIBILITY /*empty*/ etc...)

(你可能想要#ifdef上面的宏,使用autoconf和其他autotools的一些配置技巧;在其他系统上你只有#define PUBLIC_VISIBILITY / * empty * / etc等空定义...)

Then, declare a variable:

然后,声明一个变量:

int module_var  MODULE_VISIBILITY;

or a function

或功能

void module_function (int) MODULE_VISIBILITY;

Then you can use module_var or call module_function inside your shared library, but not outside.

然后,您可以在共享库中使用module_var或调用module_function,但不能在外部使用。

See also the -fvisibility code generation option of GCC.

另请参阅GCC的-fvisibility代码生成选项。

BTW, you could also compile your whole library with -Dsomeglobal=alongname3419a6 and use someglobal as usual; to really find it your user would need to pass the same preprocessor definition to the compiler, and you can make the name alongname3419a6 random and improbable enough to make the collision improbable.

顺便说一下,你也可以用-Dsomeglobal = alongname3419a6编译你的整个图书馆并像往常一样使用someglobal;要真正找到它,您的用户需要将相同的预处理器定义传递给编译器,并且您可以使名称沿着3419a6随机且不太可能使碰撞不可能。


PS. This visibility is specific to GCC (and probably to ELF shared libraries such as those on Linux). It won't work without GCC or outside of shared libraries.... so is quite Linux specific (even if some few other systems, perhaps Solaris with GCC, have it). Probably some other compilers (clang from LLVM) might support also that on Linux for shared libraries (not static ones). Actually, the real hiding (to the several compilation units of a single shared library) is done mostly by the linker (because the ELF shared libraries permit that).

PS。这种可见性特定于GCC(可能还有ELF共享库,例如Linux上的那些)。如果没有GCC或共享库之外它将无法工作....因此非常适合Linux(即使其他一些系统,也许是带有GCC的Solaris)。可能一些其他编译器(来自LLVM的clang)也可能支持Linux上的共享库(不是静态库)。实际上,真正的隐藏(对单个共享库的几个编译单元)主要由链接器完成(因为ELF共享库允许)。

#2


4  

The easiest ("old-school") solution is to simply not declare the variable in the intended public header.

最简单的(“老派”)解决方案是简单地不在预期的公共标题中声明变量。

Split your libraries header into "header.h" and "header-internal.h", and declare internal stuff in the latter one.

将库头拆分为“header.h”和“header-internal.h”,并在后者中声明内部内容。

Of course, you should also take care to protect your library-global variable's name so that it doesn't collide with user code; presumably you already have a prefix that you use for the functions for this purpose.

当然,您还应该注意保护库全局变量的名称,以免它与用户代码冲突;大概你已经有了一个用于此功能的前缀。

You can also wrap the variable(s) in a struct, to make it cleaner since then only one actual symbol is globally visible.

您还可以将变量包装在结构中,以使其更清晰,因为只有一个实际符号是全局可见的。

#3


2  

You can obfuscate things with disguised structs, if you really want to hide the information as best as possible. e.g. in a header file,

如果您真的想尽可能隐藏信息,可以使用伪装结构来混淆事物。例如在头文件中,

struct data_s {
   void *v;
};

And somewhere in your source:

在你的来源的某个地方:

struct data_s data;
struct gbs {
   // declare all your globals here
} gbss;

and then:

data.v = &gbss;

data.v =&gbss;

You can then access all the globals via: ((struct gbs *)data.v)->

然后,您可以通过以下方式访问所有全局变量:((struct gbs *)data.v) - >

#4


0  

I know that this will not be what you literally intended, but you can leave the global variables static and divide them into multiple source files.

我知道这不是你想要的,但是你可以将全局变量保持为静态并将它们分成多个源文件。

Copy the functions that write to the corresponding static variable in the same source file also declared static.

将写入相应静态变量的函数复制到同样声明为static的源文件中。

Declare functions that read the static variable so that external source files of the same module can read it's value.

声明读取静态变量的函数,以便同一模块的外部源文件可以读取它的值。

In a way making it less global. If possible, best logic for breaking big files into smaller ones, is to make that decision based on the data.

从某种程度上说,它不那么全球化。如果可能,将大文件分解为较小文件的最佳逻辑是根据数据做出决定。

If it is not possible to do it this way than you can bump all the global variables into one source file as static and access them from the other source files of the module by functions, making it official so if someone is manipulating your global variables at least you know how. But then it probably is better to use @unwind's method.

如果不可能这样做,那么你可以将所有全局变量作为静态压缩到一个源文件中,并通过函数从模块的其他源文件访问它们,使其成为官方所以如果有人在操纵你的全局变量至少你知道怎么做。但是,使用@ unwind的方法可能更好。

#1


6  

You want the visibility attribute extension of GCC.

您需要GCC的visibility属性扩展。

Practically, something like:

实际上,类似于:

 #define MODULE_VISIBILITY  __attribute__ ((visibility ("hidden")))
 #define PUBLIC_VISIBILITY  __attribute__ ((visibility ("default")))

(You probably want to #ifdef the above macros, using some configuration tricks à la autoconfand other autotools; on other systems you would just have empty definitions like #define PUBLIC_VISIBILITY /*empty*/ etc...)

(你可能想要#ifdef上面的宏,使用autoconf和其他autotools的一些配置技巧;在其他系统上你只有#define PUBLIC_VISIBILITY / * empty * / etc等空定义...)

Then, declare a variable:

然后,声明一个变量:

int module_var  MODULE_VISIBILITY;

or a function

或功能

void module_function (int) MODULE_VISIBILITY;

Then you can use module_var or call module_function inside your shared library, but not outside.

然后,您可以在共享库中使用module_var或调用module_function,但不能在外部使用。

See also the -fvisibility code generation option of GCC.

另请参阅GCC的-fvisibility代码生成选项。

BTW, you could also compile your whole library with -Dsomeglobal=alongname3419a6 and use someglobal as usual; to really find it your user would need to pass the same preprocessor definition to the compiler, and you can make the name alongname3419a6 random and improbable enough to make the collision improbable.

顺便说一下,你也可以用-Dsomeglobal = alongname3419a6编译你的整个图书馆并像往常一样使用someglobal;要真正找到它,您的用户需要将相同的预处理器定义传递给编译器,并且您可以使名称沿着3419a6随机且不太可能使碰撞不可能。


PS. This visibility is specific to GCC (and probably to ELF shared libraries such as those on Linux). It won't work without GCC or outside of shared libraries.... so is quite Linux specific (even if some few other systems, perhaps Solaris with GCC, have it). Probably some other compilers (clang from LLVM) might support also that on Linux for shared libraries (not static ones). Actually, the real hiding (to the several compilation units of a single shared library) is done mostly by the linker (because the ELF shared libraries permit that).

PS。这种可见性特定于GCC(可能还有ELF共享库,例如Linux上的那些)。如果没有GCC或共享库之外它将无法工作....因此非常适合Linux(即使其他一些系统,也许是带有GCC的Solaris)。可能一些其他编译器(来自LLVM的clang)也可能支持Linux上的共享库(不是静态库)。实际上,真正的隐藏(对单个共享库的几个编译单元)主要由链接器完成(因为ELF共享库允许)。

#2


4  

The easiest ("old-school") solution is to simply not declare the variable in the intended public header.

最简单的(“老派”)解决方案是简单地不在预期的公共标题中声明变量。

Split your libraries header into "header.h" and "header-internal.h", and declare internal stuff in the latter one.

将库头拆分为“header.h”和“header-internal.h”,并在后者中声明内部内容。

Of course, you should also take care to protect your library-global variable's name so that it doesn't collide with user code; presumably you already have a prefix that you use for the functions for this purpose.

当然,您还应该注意保护库全局变量的名称,以免它与用户代码冲突;大概你已经有了一个用于此功能的前缀。

You can also wrap the variable(s) in a struct, to make it cleaner since then only one actual symbol is globally visible.

您还可以将变量包装在结构中,以使其更清晰,因为只有一个实际符号是全局可见的。

#3


2  

You can obfuscate things with disguised structs, if you really want to hide the information as best as possible. e.g. in a header file,

如果您真的想尽可能隐藏信息,可以使用伪装结构来混淆事物。例如在头文件中,

struct data_s {
   void *v;
};

And somewhere in your source:

在你的来源的某个地方:

struct data_s data;
struct gbs {
   // declare all your globals here
} gbss;

and then:

data.v = &gbss;

data.v =&gbss;

You can then access all the globals via: ((struct gbs *)data.v)->

然后,您可以通过以下方式访问所有全局变量:((struct gbs *)data.v) - >

#4


0  

I know that this will not be what you literally intended, but you can leave the global variables static and divide them into multiple source files.

我知道这不是你想要的,但是你可以将全局变量保持为静态并将它们分成多个源文件。

Copy the functions that write to the corresponding static variable in the same source file also declared static.

将写入相应静态变量的函数复制到同样声明为static的源文件中。

Declare functions that read the static variable so that external source files of the same module can read it's value.

声明读取静态变量的函数,以便同一模块的外部源文件可以读取它的值。

In a way making it less global. If possible, best logic for breaking big files into smaller ones, is to make that decision based on the data.

从某种程度上说,它不那么全球化。如果可能,将大文件分解为较小文件的最佳逻辑是根据数据做出决定。

If it is not possible to do it this way than you can bump all the global variables into one source file as static and access them from the other source files of the module by functions, making it official so if someone is manipulating your global variables at least you know how. But then it probably is better to use @unwind's method.

如果不可能这样做,那么你可以将所有全局变量作为静态压缩到一个源文件中,并通过函数从模块的其他源文件访问它们,使其成为官方所以如果有人在操纵你的全局变量至少你知道怎么做。但是,使用@ unwind的方法可能更好。