Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to hide a global variable, which is visible across multiple files?

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.

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.

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

like image 203
ysap Avatar asked Mar 15 '13 14:03

ysap


3 Answers

You want the visibility attribute extension of GCC.

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...)

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.

See also the -fvisibility code generation option of GCC.

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.


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).

like image 60
Basile Starynkevitch Avatar answered Sep 26 '22 21:09

Basile Starynkevitch


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.

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.

like image 39
unwind Avatar answered Sep 24 '22 21:09

unwind


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;

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

like image 29
teppic Avatar answered Sep 22 '22 21:09

teppic