The headline may not be entirely clear.
I'm using two source files (one in C, one in Haskell) to compile a shared library (.so). I want some of the functions in one file to be callable from functions in the other file. However, I don't want them to be callable from the program that loads the library.
If I declare them static, the other file's code can't see them.
Is there a way to accomplish this? Does it require configuring the linker or altering the .so file after the fact?
CodePudding user response:
You can/should do this with a linker script when creating the .so
But, first, look at info gcc
and the -fvisibility=
section [included below].
You can also use __attribute__((visibility("...")))
on each function.
For example, if most of the functions are internal (and only a few are part of the public API), you could use a default visibility of hidden and add explicit attributes to the public functions.
From info gcc
:
-fvisibility=[default|internal|hidden|protected]
Set the default ELF image symbol visibility to the specified option--all symbols are marked with this unless overridden within the code. Using this feature can very substantially improve linking and load times of shared object libraries, produce more optimized code, provide near-perfect API export and prevent symbol clashes. It is strongly recommended that you use this in any shared objects you distribute.
Despite the nomenclature, default
always means public; i.e.,
available to be linked against from outside the shared object.
protected
and internal
are pretty useless in real-world usage
so the only other commonly used option is hidden
. The default if
-fvisibility
isn't specified is default
, i.e., make every
symbol public.
A good explanation of the benefits offered by ensuring ELF symbols
have the correct visibility is given by "How To Write Shared
Libraries" by Ulrich Drepper (which can be found at
https://www.akkadia.org/drepper/)--however a superior solution
made possible by this option to marking things hidden when the
default is public is to make the default hidden and mark things
public. This is the norm with DLLs on Windows and with
-fvisibility=hidden
and __attribute__ ((visibility("default")))
instead of __declspec(dllexport)
you get almost identical
semantics with identical syntax. This is a great boon to those
working with cross-platform projects.
For those adding visibility support to existing code, you may find
#pragma GCC visibility
of use. This works by you enclosing the
declarations you wish to set visibility for with (for example)
#pragma GCC visibility push(hidden)
and #pragma GCC visibility pop
. Bear in mind that symbol visibility should be viewed as
part of the API interface contract and thus all new code should
always specify visibility when it is not the default; i.e.,
declarations only for use within the local DSO should always be
marked explicitly as hidden as so to avoid PLT indirection
overheads--making this abundantly clear also aids readability and
self-documentation of the code. Note that due to ISO C
specification requirements, operator new
and operator delete
must always be of default visibility.
Be aware that headers from outside your project, in particular
system headers and headers from any other library you use, may not
be expecting to be compiled with visibility other than the default.
You may need to explicitly say #pragma GCC visibility push(default)
before including any such headers.
extern
declarations are not affected by -fvisibility
, so a lot
of code can be recompiled with -fvisibility=hidden
with no
modifications. However, this means that calls to extern
functions with no explicit visibility use the PLT, so it is more
effective to use __attribute ((visibility))
and/or #pragma GCC visibility
to tell the compiler which extern
declarations should
be treated as hidden.
Note that -fvisibility
does affect C vague linkage entities.
This means that, for instance, an exception class that is be thrown
between DSOs must be explicitly marked with default visibility so
that the type_info
nodes are unified between the DSOs.
An overview of these techniques, their benefits and how to use them is at https://gcc.gnu.org/wiki/Visibility